Refactor bot frame handling

This commit is contained in:
RGreenlees 2024-03-19 17:46:09 +00:00 committed by pierow
parent f2ee8e1dbe
commit 50e5a0702e
6 changed files with 105 additions and 121 deletions

View File

@ -794,6 +794,12 @@ typedef struct AVH_AI_PLAYER
int ExperiencePointsAvailable = 0; // How much experience the bot has to spend
AvHMessageID NextCombatModeUpgrade = MESSAGE_NULL;
float ThinkDelta = 0.0f; // How long since this bot last ran AIPlayerThink
float LastThinkTime = 0.0f; // When the bot last ran AIPlayerThink
float ServerUpdateDelta = 0.0f; // How long since we last called RunPlayerMove
float LastServerUpdateTime = 0.0f; // When we last called RunPlayerMove
} AvHAIPlayer;

View File

@ -1175,8 +1175,10 @@ void UTIL_PopulateBaseNavProfiles()
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_WALLCLIMB, 1.0f);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LIFT, 3.0f);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_DUCKJUMP | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_DUCKJUMP | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_DUCKJUMP | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH;
@ -1192,12 +1194,8 @@ void UTIL_PopulateBaseNavProfiles()
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LIFT, 3.0f);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_DUCKJUMP);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_DUCKJUMP | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY | SAMPLE_POLYFLAGS_WALLCLIMB);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_DUCKJUMP | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY | SAMPLE_POLYFLAGS_WALLCLIMB);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH;
BaseNavProfiles[LERK_BASE_NAV_PROFILE].bFlyingProfile = true;
@ -1211,9 +1209,8 @@ void UTIL_PopulateBaseNavProfiles()
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LIFT, 3.0f);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH;
BaseNavProfiles[FADE_BASE_NAV_PROFILE].bFlyingProfile = false;
@ -1228,10 +1225,8 @@ void UTIL_PopulateBaseNavProfiles()
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LIFT, 3.0f);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].NavMeshIndex = ONOS_NAV_MESH;
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].bFlyingProfile = false;
@ -1246,12 +1241,8 @@ void UTIL_PopulateBaseNavProfiles()
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LIFT, 3.0f);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_NOONOS);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_DUCKJUMP | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY | SAMPLE_POLYFLAGS_WALLCLIMB | SAMPLE_POLYFLAGS_NOONOS);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_DUCKJUMP | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY | SAMPLE_POLYFLAGS_WALLCLIMB | SAMPLE_POLYFLAGS_NOONOS);
BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].NavMeshIndex = BUILDING_NAV_MESH;
BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
@ -3106,7 +3097,7 @@ DoorTrigger* UTIL_GetNearestDoorTrigger(const Vector Location, nav_door* Door, C
return NearestTrigger;
}
void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom, const Vector MoveTo)
void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom, const Vector MoveTo, unsigned int MovementFlags)
{
if (pBot->BotNavInfo.CurrentPathPoint >= pBot->BotNavInfo.CurrentPath.size()) { return; }
@ -3135,8 +3126,7 @@ void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom
if (FNullEnt(BlockingBreakableEdict))
{
BlockingBreakableEdict = UTIL_GetBreakableBlockingPathPoint(pBot, pBot->Edict->v.origin, CurrentPathNode.Location, SAMPLE_POLYAREA_GROUND, nullptr);
BlockingBreakableEdict = UTIL_GetBreakableBlockingPathPoint(pBot, &CurrentPathNode, nullptr);
}
if (FNullEnt(BlockingBreakableEdict))
@ -3146,8 +3136,7 @@ void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom
for (int i = (pBot->BotNavInfo.CurrentPathPoint + 1); i < pBot->BotNavInfo.CurrentPath.size(); i++)
{
bot_path_node ThisPathNode = pBot->BotNavInfo.CurrentPath[i];
BlockingBreakableEdict = UTIL_GetBreakableBlockingPathPoint(pBot, ThisPathNode.FromLocation, ThisPathNode.Location, SAMPLE_POLYAREA_GROUND, nullptr);
BlockingBreakableEdict = UTIL_GetBreakableBlockingPathPoint(pBot, &ThisPathNode, nullptr);
NumIterations++;
@ -3172,7 +3161,7 @@ void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom
{
if (IsPlayerSkulk(pBot->Edict))
{
DesiredWeapon = (BlockingBreakableEdict->v.health <= 10) ? WEAPON_SKULK_PARASITE : WEAPON_SKULK_BITE;
DesiredWeapon = (BlockingBreakableEdict->v.health <= 30) ? WEAPON_SKULK_PARASITE : WEAPON_SKULK_BITE;
}
}
@ -3302,7 +3291,7 @@ void NewMove(AvHAIPlayer* pBot)
}
// While moving, check to make sure we're not obstructed by a func_breakable, e.g. vent or window.
CheckAndHandleBreakableObstruction(pBot, MoveFrom, MoveTo);
CheckAndHandleBreakableObstruction(pBot, MoveFrom, MoveTo, CurrentNavFlags);
if (CurrentNavFlags != SAMPLE_POLYFLAGS_LIFT)
{
@ -5579,12 +5568,12 @@ void UpdateBotStuck(AvHAIPlayer* pBot)
}
else
{
pBot->BotNavInfo.StuckInfo.TotalStuckTime += fminf(AIMGR_GetBotDeltaTime(), 0.016f);
pBot->BotNavInfo.StuckInfo.TotalStuckTime += pBot->ThinkDelta;
}
}
else
{
pBot->BotNavInfo.StuckInfo.TotalStuckTime += fminf(AIMGR_GetBotDeltaTime(), 0.016f);
pBot->BotNavInfo.StuckInfo.TotalStuckTime += pBot->ThinkDelta;
}
if (pBot->BotNavInfo.StuckInfo.TotalStuckTime > 0.25f)
@ -6285,7 +6274,7 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
pBot->desiredMovementDir = UTIL_GetForwardVector2D(pEdict->v.v_angle);
CheckAndHandleBreakableObstruction(pBot, MoveFrom, CurrentMoveDest);
CheckAndHandleBreakableObstruction(pBot, MoveFrom, CurrentMoveDest, SAMPLE_POLYFLAGS_WALK);
CheckAndHandleDoorObstruction(pBot);

View File

@ -257,7 +257,7 @@ DoorTrigger* UTIL_GetDoorTriggerByEntity(edict_t* TriggerEntity);
bool UTIL_TriggerHasBeenRecentlyActivated(edict_t* TriggerEntity);
// Will check for any func_breakable which might be in the way (e.g. window, vent) and make the bot aim and attack it to break it. Marines will switch to knife to break it.
void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom, const Vector MoveTo);
void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom, const Vector MoveTo, unsigned int MovementFlags);
void CheckAndHandleDoorObstruction(AvHAIPlayer* pBot);

View File

@ -1140,7 +1140,7 @@ void BotUpdateDesiredViewRotation(AvHAIPlayer* pBot)
// This simulates the fact that humans can't spin and lock their cross-hair exactly on the target, the further you have the spin, the more off your view will be first attempt
if (fabsf(maxDelta) >= 45.0f)
{
pBot->ViewInterpolationSpeed = 500.0f;
pBot->ViewInterpolationSpeed = 350.0f;
if (!bIsMoveLook)
{
@ -1169,7 +1169,7 @@ void BotUpdateDesiredViewRotation(AvHAIPlayer* pBot)
}
else if (fabsf(maxDelta) >= 25.0f)
{
pBot->ViewInterpolationSpeed = 250.0f;
pBot->ViewInterpolationSpeed = 175.0f;
if (!bIsMoveLook)
{
@ -1196,7 +1196,7 @@ void BotUpdateDesiredViewRotation(AvHAIPlayer* pBot)
}
else if (fabsf(maxDelta) >= 5.0f)
{
pBot->ViewInterpolationSpeed = 50.0f;
pBot->ViewInterpolationSpeed = 35.0f;
if (!bIsMoveLook)
{
@ -4966,6 +4966,39 @@ void AIPlayerDMThink(AvHAIPlayer* pBot)
void AIPlayerThink(AvHAIPlayer* pBot)
{
#ifdef DEBUG
if (pBot == AIMGR_GetDebugAIPlayer())
{
bool bBreak = true; // Add a break point here if you want to debug a specific bot
AIDEBUG_DrawBotPath(pBot);
if (pBot->BotNavInfo.CurrentPath.size() > 0 && pBot->BotNavInfo.CurrentPathPoint < pBot->BotNavInfo.CurrentPath.size())
{
bot_path_node CurrentPathNode = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint];
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, CurrentPathNode.FromLocation, 255, 0, 0);
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, CurrentPathNode.Location, 0, 128, 0);
}
if (pBot->CurrentTask && pBot->CurrentTask->TaskType != TASK_NONE)
{
if (!FNullEnt(pBot->CurrentTask->TaskTarget))
{
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->CurrentTask->TaskTarget->v.origin, 255, 0, 0);
}
if (!vIsZero(pBot->CurrentTask->TaskLocation))
{
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->CurrentTask->TaskLocation, 255, 0, 0);
}
}
}
#endif
pBot->ThinkDelta = fminf(gpGlobals->time - pBot->LastThinkTime, 0.1f);
pBot->LastThinkTime = gpGlobals->time;
bool bShouldThink = ShouldBotThink(pBot);
if (bShouldThink)

View File

@ -13,7 +13,6 @@
#include <time.h>
double last_think_time = 0.0;
float BotDeltaTime = 0.01666667f;
vector<AvHAIPlayer> ActiveAIPlayers;
@ -544,19 +543,16 @@ void AIMGR_AddAIPlayerToTeam(int Team)
}
byte BotThrottledMsec(AvHAIPlayer* inAIPlayer)
byte BotThrottledMsec(AvHAIPlayer* inAIPlayer, float CurrentTime)
{
// Thanks to The Storm (ePODBot) for this one, finally fixed the bot running speed!
int newmsec = (int)((gpGlobals->time - inAIPlayer->f_previous_command_time) * 1000);
int newmsec = (int)((CurrentTime - inAIPlayer->LastServerUpdateTime) * 1000);
if (newmsec > 255)
{
newmsec = 255;
}
// save the command time
inAIPlayer->f_previous_command_time = gpGlobals->time;
return (byte)newmsec;
}
@ -595,8 +591,6 @@ void AIMGR_UpdateAIPlayers()
static float PrevTime = 0.0f;
static float CurrTime = 0.0f;
static float LastThinkTime = 0.0f;
static int CurrentBotSkill = 1;
static int UpdateIndex = 0;
@ -609,13 +603,7 @@ void AIMGR_UpdateAIPlayers()
PrevTime = 0.0f;
}
if (CurrTime < LastThinkTime)
{
LastThinkTime = 0.0f;
}
float FrameDelta = CurrTime - PrevTime;
float ThinkDelta = CurrTime - LastThinkTime;
int cvarBotSkill = clampi((int)avh_botskill.value, 0, 3);
@ -627,6 +615,31 @@ void AIMGR_UpdateAIPlayers()
}
bool bHasCommander = false;
if (bHasRoundStarted)
{
AvHTeamNumber TeamANumber = GetGameRules()->GetTeamANumber();
AvHTeamNumber TeamBNumber = GetGameRules()->GetTeamBNumber();
AvHTeam* TeamA = GetGameRules()->GetTeam(TeamANumber);
AvHTeam* TeamB = GetGameRules()->GetTeam(TeamBNumber);
if (TeamA->GetTeamType() == AVH_CLASS_TYPE_MARINE)
{
if (TeamA->GetCommanderPlayer() && !(TeamA->GetCommanderPlayer()->pev->flags & FL_FAKECLIENT))
{
AIMGR_SetCommanderAllowedTime(TeamANumber, gpGlobals->time + 15.0f);
}
}
if (TeamB->GetTeamType() == AVH_CLASS_TYPE_MARINE)
{
if (TeamB->GetCommanderPlayer() && !(TeamB->GetCommanderPlayer()->pev->flags & FL_FAKECLIENT))
{
AIMGR_SetCommanderAllowedTime(TeamBNumber, gpGlobals->time + 15.0f);
}
}
}
for (auto BotIt = ActiveAIPlayers.begin(); BotIt != ActiveAIPlayers.end();)
{
@ -654,76 +667,18 @@ void AIMGR_UpdateAIPlayers()
BotUpdateViewRotation(bot, FrameDelta);
if (IS_DEDICATED_SERVER() || ThinkDelta >= BOT_MIN_FRAME_TIME)
if (bHasRoundStarted)
{
BotDeltaTime = ThinkDelta;
#ifdef DEBUG
if (bot == AIMGR_GetDebugAIPlayer())
if (IsPlayerCommander(bot->Edict))
{
bool bBreak = true; // Add a break point here if you want to debug a specific bot
AIDEBUG_DrawBotPath(bot);
if (bot->BotNavInfo.CurrentPath.size() > 0 && bot->BotNavInfo.CurrentPathPoint < bot->BotNavInfo.CurrentPath.size())
if (UpdateIndex == FrameSpread)
{
bot_path_node CurrentPathNode = bot->BotNavInfo.CurrentPath[bot->BotNavInfo.CurrentPathPoint];
UTIL_DrawLine(INDEXENT(1), bot->Edict->v.origin, CurrentPathNode.FromLocation, 255, 0, 0);
UTIL_DrawLine(INDEXENT(1), bot->Edict->v.origin, CurrentPathNode.Location, 0, 128, 0);
}
if (bot->CurrentTask && bot->CurrentTask->TaskType != TASK_NONE)
{
if (!FNullEnt(bot->CurrentTask->TaskTarget))
{
UTIL_DrawLine(INDEXENT(1), bot->Edict->v.origin, bot->CurrentTask->TaskTarget->v.origin, 255, 0, 0);
}
if (!vIsZero(bot->CurrentTask->TaskLocation))
{
UTIL_DrawLine(INDEXENT(1), bot->Edict->v.origin, bot->CurrentTask->TaskLocation, 255, 0, 0);
}
AIPlayerThink(bot);
}
}
#endif
if (bHasRoundStarted)
else
{
AvHTeamNumber TeamANumber = GetGameRules()->GetTeamANumber();
AvHTeamNumber TeamBNumber = GetGameRules()->GetTeamBNumber();
AvHTeam* TeamA = GetGameRules()->GetTeam(TeamANumber);
AvHTeam* TeamB = GetGameRules()->GetTeam(TeamBNumber);
if (TeamA->GetTeamType() == AVH_CLASS_TYPE_MARINE)
{
if (TeamA->GetCommanderPlayer() && !(TeamA->GetCommanderPlayer()->pev->flags & FL_FAKECLIENT))
{
AIMGR_SetCommanderAllowedTime(TeamANumber, gpGlobals->time + 15.0f);
}
}
if (TeamB->GetTeamType() == AVH_CLASS_TYPE_MARINE)
{
if (TeamB->GetCommanderPlayer() && !(TeamB->GetCommanderPlayer()->pev->flags & FL_FAKECLIENT))
{
AIMGR_SetCommanderAllowedTime(TeamBNumber, gpGlobals->time + 15.0f);
}
}
}
UpdateBotChat(bot);
if (bHasRoundStarted)
{
if (IsPlayerCommander(bot->Edict))
{
if (UpdateIndex == FrameSpread)
{
AIPlayerThink(bot);
}
}
else
if (UpdateIndex != FrameSpread)
{
int BotModulo = BotIndex % FrameSpread;
@ -733,32 +688,34 @@ void AIMGR_UpdateAIPlayers()
}
}
}
}
if (IS_DEDICATED_SERVER() || (CurrTime - bot->LastServerUpdateTime) >= BOT_MIN_FRAME_TIME)
{
UpdateBotChat(bot);
// Needed to correctly handle client prediction and physics calculations
byte adjustedmsec = BotThrottledMsec(bot);
byte adjustedmsec = BotThrottledMsec(bot, CurrTime);
// Simulate PM_PlayerMove so client prediction and stuff can be executed correctly.
RUN_AI_MOVE(bot->Edict, bot->Edict->v.v_angle, bot->ForwardMove,
bot->SideMove, bot->UpMove, bot->Button, bot->Impulse, adjustedmsec);
LastThinkTime = gpGlobals->time;
bot->LastServerUpdateTime = CurrTime;
}
BotIt++;
}
PrevTime = CurrTime;
UpdateIndex++;
if (UpdateIndex > FrameSpread || (!bHasCommander && UpdateIndex == FrameSpread))
{
UpdateIndex = 0;
}
}
float AIMGR_GetBotDeltaTime()
{
return BotDeltaTime;
PrevTime = CurrTime;
}
int AIMGR_GetNumAIPlayers()

View File

@ -28,8 +28,7 @@ void AIMGR_RemoveAIPlayerFromTeam(int Team);
void AIMGR_UpdateAIPlayers();
// Kicks all bots in the ready room (used at round end when everyone is booted back to the ready room)
void AIMGR_RemoveBotsInReadyRoom();
// Delta between last bot frame and this one (default is 60hz = 0.0166666)
float AIMGR_GetBotDeltaTime();
// Called every 0.2s to determine if bots need to be added/removed. Calls UpdateTeamBalance or UpdateFillTeams depending on auto-mode
void AIMGR_UpdateAIPlayerCounts();