mirror of
https://github.com/tribes2/engine.git
synced 2026-01-19 19:24:45 +00:00
236 lines
5.9 KiB
C++
236 lines
5.9 KiB
C++
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// V12 Engine
|
||
|
|
//
|
||
|
|
// Copyright (c) 2001 GarageGames.Com
|
||
|
|
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
#include "console/console.h"
|
||
|
|
#include "console/consoleInternal.h"
|
||
|
|
#include "ai/aiTask.h"
|
||
|
|
|
||
|
|
IMPLEMENT_CONOBJECT(AITask);
|
||
|
|
|
||
|
|
static void cAISetWeightFreq(SimObject *obj, S32, const char **argv)
|
||
|
|
{
|
||
|
|
AITask *task = static_cast<AITask*>(obj);
|
||
|
|
// task->setWeightFreq(dAtoi(argv[2]));
|
||
|
|
// LH - did this until proper optimizations are performed since calcWeight()
|
||
|
|
// was 10% of some profiles.
|
||
|
|
task->setWeightFreq(dAtoi(argv[2]) * 3);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void cAISetWeight(SimObject *obj, S32, const char **argv)
|
||
|
|
{
|
||
|
|
AITask *task = static_cast<AITask*>(obj);
|
||
|
|
task->setWeight(dAtoi(argv[2]));
|
||
|
|
}
|
||
|
|
|
||
|
|
static const char* cAIGetWeight(SimObject *obj, S32, const char **)
|
||
|
|
{
|
||
|
|
AITask *task = static_cast<AITask*>(obj);
|
||
|
|
S32 weight = task->getWeight();
|
||
|
|
|
||
|
|
char* returnBuffer = Con::getReturnBuffer(256);
|
||
|
|
dSprintf(returnBuffer, 256, "%d", weight);
|
||
|
|
return returnBuffer;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void cAIReWeight(SimObject *obj, S32, const char **)
|
||
|
|
{
|
||
|
|
AITask *task = static_cast<AITask*>(obj);
|
||
|
|
task->reWeight();
|
||
|
|
}
|
||
|
|
|
||
|
|
static void cAISetMonitorFreq(SimObject *obj, S32, const char **argv)
|
||
|
|
{
|
||
|
|
AITask *task = static_cast<AITask*>(obj);
|
||
|
|
task->setMonitorFreq(dAtoi(argv[2]));
|
||
|
|
}
|
||
|
|
|
||
|
|
static void cAIReMonitor(SimObject *obj, S32, const char **)
|
||
|
|
{
|
||
|
|
AITask *task = static_cast<AITask*>(obj);
|
||
|
|
task->reMonitor();
|
||
|
|
}
|
||
|
|
|
||
|
|
void AITask::consoleInit()
|
||
|
|
{
|
||
|
|
Con::addCommand("AITask", "setWeightFreq", cAISetWeightFreq, "ai.setWeightFreq(freq)", 3, 3);
|
||
|
|
Con::addCommand("AITask", "setWeight", cAISetWeight, "ai.setWeight(weight)", 3, 3);
|
||
|
|
Con::addCommand("AITask", "getWeight", cAIGetWeight, "ai.getWeight()", 2, 2);
|
||
|
|
Con::addCommand("AITask", "reWeight", cAIReWeight, "ai.reWeight()", 2, 2);
|
||
|
|
|
||
|
|
Con::addCommand("AITask", "setMonitorFreq", cAISetMonitorFreq, "ai.setMonitorFreq(freq)", 3, 3);
|
||
|
|
Con::addCommand("AITask", "reMonitor", cAIReMonitor, "ai.reMonitor()", 2, 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
AITask::AITask()
|
||
|
|
{
|
||
|
|
mWeightFreq = 30;
|
||
|
|
mMonitorFreq = 30;
|
||
|
|
mWeightCounter = 0;
|
||
|
|
mMonitorCounter = 0;
|
||
|
|
mWeight = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool AITask::onAdd()
|
||
|
|
{
|
||
|
|
if (! Parent::onAdd())
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//set the task namespace
|
||
|
|
const char *name = getName();
|
||
|
|
if(name && name[0] && getClassRep())
|
||
|
|
{
|
||
|
|
Namespace *parent = getClassRep()->getNameSpace();
|
||
|
|
Con::linkNamespaces(parent->mName, name);
|
||
|
|
mNameSpace = Con::lookupNamespace(name);
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void AITask::calcWeight(AIConnection *ai)
|
||
|
|
{
|
||
|
|
//make sure task is valid
|
||
|
|
if (! ai)
|
||
|
|
return;
|
||
|
|
|
||
|
|
//see if it's time to re-weight the task
|
||
|
|
// if (--mWeightCounter <= 0)
|
||
|
|
if (gCalcWeightSlicer.ready(mWeightCounter, mWeightFreq))
|
||
|
|
{
|
||
|
|
// mWeightCounter = mWeightFreq;
|
||
|
|
Con::executef(this, 2, "weight", avar("%d", ai->getId()));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void AITask::monitor(AIConnection *ai)
|
||
|
|
{
|
||
|
|
//make sure task is valid
|
||
|
|
if (! ai)
|
||
|
|
return;
|
||
|
|
|
||
|
|
if (--mMonitorCounter <= 0)
|
||
|
|
{
|
||
|
|
mMonitorCounter = mMonitorFreq;
|
||
|
|
Con::executef(this, 2, "monitor", avar("%d", ai->getId()));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void AITask::assume(AIConnection *ai)
|
||
|
|
{
|
||
|
|
//make sure task is valid
|
||
|
|
if (! ai)
|
||
|
|
return;
|
||
|
|
|
||
|
|
mMonitorCounter = 0;
|
||
|
|
Con::executef(this, 2, "assume", avar("%d", ai->getId()));
|
||
|
|
}
|
||
|
|
|
||
|
|
void AITask::retire(AIConnection *ai)
|
||
|
|
{
|
||
|
|
//make sure task is valid
|
||
|
|
if (! ai)
|
||
|
|
return;
|
||
|
|
|
||
|
|
Con::executef(this, 2, "retire", avar("%d", ai->getId()));
|
||
|
|
}
|
||
|
|
|
||
|
|
//-------------------------------------------------------------------------------------
|
||
|
|
|
||
|
|
AISlicer::AISlicer()
|
||
|
|
{
|
||
|
|
reset();
|
||
|
|
}
|
||
|
|
|
||
|
|
void AISlicer::init(U32 delay, S32 maxPerTic)
|
||
|
|
{
|
||
|
|
// mRand.setSeed(0x88);
|
||
|
|
mDelay = delay;
|
||
|
|
mLastTime = Sim::getCurrentTime();
|
||
|
|
// mCapPileUp = (getMax(maxPerTic - 1, 0) * mDelay);
|
||
|
|
maxPerTic;
|
||
|
|
mDebugTotal = 0;
|
||
|
|
mBudget = 2.0;
|
||
|
|
// mEnabled = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void AISlicer::reset()
|
||
|
|
{
|
||
|
|
init();
|
||
|
|
// mEnabled = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
#if 0
|
||
|
|
// Return true if this counter goes to zero AND sufficient time has elapsed. If
|
||
|
|
// the time hasn't elapsed - leave the counter. This should ensure that every
|
||
|
|
// body gets their shot without super-high frequency guys shutting out slow guys.
|
||
|
|
bool AISlicer::ready(S32& counter, S32 resetValue)
|
||
|
|
{
|
||
|
|
U32 T = Sim::getCurrentTime();
|
||
|
|
|
||
|
|
if (T - mLastTime >= mDelay && --counter <= 0)
|
||
|
|
{
|
||
|
|
// 1/4 of time, add stagger noise to those that won't really notice it
|
||
|
|
if (resetValue > 3)
|
||
|
|
resetValue += !(mRand.randI() & 3);
|
||
|
|
counter = resetValue;
|
||
|
|
|
||
|
|
// We want to allow multiple times per tic, but also to cap how much "reserve"
|
||
|
|
// readiness is allowed to pile up.
|
||
|
|
mLastTime = getMax(mLastTime + mDelay, T - mCapPileUp);
|
||
|
|
|
||
|
|
// Verify it's handling more than one per tick Ok
|
||
|
|
mDebugTotal++;
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
#else
|
||
|
|
|
||
|
|
// The above is very mis-conceived, let's try something a little better-
|
||
|
|
// Note mDelay is a millisecond amount, while counter & reset value are game ticks.
|
||
|
|
bool AISlicer::ready(S32& counter, S32 resetValue)
|
||
|
|
{
|
||
|
|
bool goodToGo = false;
|
||
|
|
|
||
|
|
counter--;
|
||
|
|
|
||
|
|
if (mBudget > 0)
|
||
|
|
{
|
||
|
|
if (counter < 0)
|
||
|
|
{
|
||
|
|
mBudget -= 1.0;
|
||
|
|
counter = resetValue;
|
||
|
|
goodToGo = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Budget keeps track of how many we currently are allowed to let through. We'd
|
||
|
|
// like to keep it to no more than one per mDelay milliseconds.
|
||
|
|
U32 T = Sim::getCurrentTime();
|
||
|
|
mBudget += (F32(T - mLastTime) / F32(mDelay));
|
||
|
|
mBudget = getMin(mBudget, 40.0f);
|
||
|
|
mLastTime = T;
|
||
|
|
|
||
|
|
// We have to let through tasks that have been waiting a while. Nothing will
|
||
|
|
// wait in vain for more than about 1.2 extra seconds-
|
||
|
|
if (counter < -37)
|
||
|
|
{
|
||
|
|
counter = resetValue;
|
||
|
|
goodToGo = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Track total to make sure we're getting about the percentage that we want.
|
||
|
|
mDebugTotal += goodToGo;
|
||
|
|
|
||
|
|
return goodToGo;
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif
|