Improved commander placement and tactical refresh

This commit is contained in:
RGreenlees 2024-02-12 22:48:03 +00:00 committed by pierow
parent 9e0b42dbf4
commit 261caa1c55
10 changed files with 241 additions and 148 deletions

View File

@ -911,17 +911,19 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
StructureFilter.DeployableTeam = TeamNumber;
StructureFilter.ReachabilityFlags = AI_REACHABILITY_MARINE;
StructureFilter.ReachabilityTeam = TeamNumber;
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
int NumInfantryPortals = AITAC_GetNumDeployablesNearLocation(CommChair->v.origin, &StructureFilter);
if (NumInfantryPortals < 2)
{
bool bSuccess = AICOMM_BuildInfantryPortal(pBot, CommChair);
bool bEnemyInBase = NumInfantryPortals > 1 && AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
bool bSuccess = !bEnemyInBase && AICOMM_BuildInfantryPortal(pBot, CommChair);
return (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kInfantryPortalCost) + 5);
}
StructureFilter.DeployableTypes = STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY;
StructureFilter.DeployableTypes = (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY);
AvHAIBuildableStructure* BaseArmoury = AITAC_FindClosestDeployableToLocation(CommChair->v.origin, &StructureFilter);
@ -929,7 +931,6 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
{
StructureFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL;
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
AvHAIBuildableStructure* NearestInfantryPortal = AITAC_FindClosestDeployableToLocation(CommChair->v.origin, &StructureFilter);
@ -982,7 +983,9 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!vIsZero(BuildLocation))
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation);
bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f));
bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation);
return (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kPhaseGateCost) + 5);
}
}
@ -1017,7 +1020,9 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!vIsZero(BuildLocation))
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMSLAB, BuildLocation);
bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f));
bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMSLAB, BuildLocation);
return (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kArmsLabCost) + 5);
}
}
@ -1032,7 +1037,9 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!vIsZero(BuildLocation))
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_OBSERVATORY, BuildLocation);
bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f));
bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_OBSERVATORY, BuildLocation);
return (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kObservatoryCost) + 5);
}
}
@ -1096,10 +1103,10 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!vIsZero(BuildLocation))
{
if (AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PROTOTYPELAB, BuildLocation))
{
return true;
}
bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f));
bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PROTOTYPELAB, BuildLocation);
return (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kPrototypeLabCost) + 5);
}
}
@ -1718,6 +1725,8 @@ const AvHAIResourceNode* AICOMM_GetNearestResourceNodeCapOpportunity(const AvHTe
if (!AITAC_AnyPlayerOnTeamWithLOS(Team, (ResNode->Location + Vector(0.0f, 0.0f, 32.0f)), UTIL_MetresToGoldSrcUnits(5.0f))) { continue; }
if (AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(Team), (ResNode->Location + Vector(0.0f, 0.0f, 32.0f)), UTIL_MetresToGoldSrcUnits(10.0f))) { continue; }
float ThisDist = vDist2DSq(ResNode->Location, SearchLocation);
if (!Result || ThisDist < MinDist)
@ -1805,12 +1814,16 @@ bool AICOMM_PerformNextSiegeHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinit
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
}
if (ExistingPG && !(ExistingPG->StructureStatusFlags & STRUCTURE_STATUS_COMPLETED)) { return false; }
if (!ExistingTF)
{
if (vDist2DSq(NextBuildPosition, HiveToSiege->Location) > sqrf(UTIL_MetresToGoldSrcUnits(20.0f))) { return true; }
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
}
if (ExistingTF && !(ExistingTF->StructureStatusFlags & STRUCTURE_STATUS_COMPLETED)) { return false; }
StructureFilter.DeployableTypes = STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY;
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);

View File

@ -483,6 +483,16 @@ typedef struct _BOT_SKILL
} bot_skill;
typedef struct _AVH_AI_BUILD_ATTEMPT
{
AvHAIDeployableStructureType AttemptedStructureType = STRUCTURE_NONE;
Vector AttemptedLocation = g_vecZero;
int NumAttempts = 0;
BotBuildAttemptStatus BuildStatus = BUILD_ATTEMPT_NONE;
float BuildAttemptTime = 0.0f;
AvHAIBuildableStructure* LinkedStructure = nullptr;
} AvHAIBuildAttempt;
// A bot task is a goal the bot wants to perform, such as attacking a structure, placing a structure etc. NOT USED BY COMMANDER
typedef struct _AVH_AI_PLAYER_TASK
{
@ -500,19 +510,9 @@ typedef struct _AVH_AI_PLAYER_TASK
int BuildAttempts = 0; // How many attempts the Gorge has tried to place it, so it doesn't keep trying forever
AvHMessageID Evolution = MESSAGE_NULL; // Used by TASK_EVOLVE to determine what to evolve into
float TaskLength = 0.0f; // If a task has gone on longer than this time, it will be considered completed
AvHAIBuildAttempt ActiveBuildInfo; // If gorge, the current status of any recent attempt to place a structure
} AvHAIPlayerTask;
typedef struct _AVH_AI_BUILD_ATTEMPT
{
AvHAIDeployableStructureType AttemptedStructureType = STRUCTURE_NONE;
Vector AttemptedLocation = g_vecZero;
int NumAttempts = 0;
BotBuildAttemptStatus BuildStatus = BUILD_ATTEMPT_NONE;
float BuildAttemptTime = 0.0f;
AvHAIBuildableStructure* LinkedStructure = nullptr;
} AvHAIBuildAttempt;
typedef struct _DOOR_TRIGGER
{
CBaseEntity* Entity = nullptr;
@ -727,8 +727,6 @@ typedef struct AVH_AI_PLAYER
nav_status BotNavInfo; // Bot's movement information, their current path, where in the path they are etc.
AvHAIBuildAttempt ActiveBuildInfo; // If gorge, the current status of any recent attempt to place a structure
vector<ai_commander_request> ActiveRequests;
vector<ai_commander_order> ActiveOrders;

View File

@ -1838,7 +1838,8 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle,
if (CurrFlags == SAMPLE_POLYFLAGS_WALLCLIMB || CurrFlags == SAMPLE_POLYFLAGS_LADDER)
{
int HullNum = GetPlayerHullIndex(pBot->Edict, false);
float NewRequiredZ = UTIL_FindZHeightForWallClimb(path.back().Location, NextPathNode.Location, HullNum);
Vector FromLocation = (path.size() > 0) ? path.back().Location : pBot->CurrentFloorPosition;
float NewRequiredZ = UTIL_FindZHeightForWallClimb(FromLocation, NextPathNode.Location, HullNum);
NextPathNode.requiredZ = fmaxf(NewRequiredZ, NextPathNode.Location.z);
if (CurrFlags == SAMPLE_POLYFLAGS_LADDER)
@ -3054,27 +3055,38 @@ void GroundMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
void FallMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint)
{
Vector vForward = UTIL_GetVectorNormal2D(EndPoint - pBot->Edict->v.origin);
Vector vBotOrientation = UTIL_GetVectorNormal2D(EndPoint - pBot->Edict->v.origin);
Vector vForward = UTIL_GetVectorNormal2D(EndPoint - StartPoint);
if (vIsZero(vForward))
if (pBot->BotNavInfo.IsOnGround)
{
vForward = UTIL_GetVectorNormal2D(EndPoint - StartPoint);
if (vDist2DSq(pBot->Edict->v.origin, EndPoint) > sqrf(GetPlayerRadius(pBot->Player)))
{
pBot->desiredMovementDir = vBotOrientation;
}
else
{
pBot->desiredMovementDir = vForward;
}
bool bCanDuck = (IsPlayerMarine(pBot->Edict) || IsPlayerFade(pBot->Edict) || IsPlayerOnos(pBot->Edict));
if (!bCanDuck) { return; }
Vector HeadLocation = GetPlayerTopOfCollisionHull(pBot->Edict, false);
if (!UTIL_QuickTrace(pBot->Edict, HeadLocation, (HeadLocation + (pBot->desiredMovementDir * 50.0f))))
{
pBot->Button |= IN_DUCK;
}
}
else
{
pBot->desiredMovementDir = vBotOrientation;
}
pBot->desiredMovementDir = vForward;
if (UTIL_PointIsDirectlyReachable(pBot, EndPoint)) { return; }
bool bCanDuck = (IsPlayerMarine(pBot->Edict) || IsPlayerFade(pBot->Edict) || IsPlayerOnos(pBot->Edict));
if (!bCanDuck) { return; }
Vector HeadLocation = GetPlayerTopOfCollisionHull(pBot->Edict, false);
if (!UTIL_QuickTrace(pBot->Edict, HeadLocation, (HeadLocation + (pBot->desiredMovementDir * 50.0f))))
{
pBot->Button |= IN_DUCK;
}
}
void StructureBlockedMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint)
@ -3858,7 +3870,7 @@ bool IsBotOffPath(const AvHAIPlayer* pBot)
Vector vForward = UTIL_GetVectorNormal2D(MoveTo - MoveFrom);
Vector PointOnPath = vClosestPointOnLine2D(MoveFrom, MoveTo, pBot->CurrentFloorPosition);
Vector PointOnPath = vClosestPointOnLine2D(MoveFrom, MoveTo, pBot->Edict->v.origin);
if (pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_WALLCLIMB)
{
@ -3871,16 +3883,7 @@ bool IsBotOffPath(const AvHAIPlayer* pBot)
if (pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_WALK)
{
if (!UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, MoveTo))
{
Vector TraceEnd = MoveTo;
TraceEnd.z = pBot->Edict->v.origin.z;
if (!UTIL_QuickHullTrace(pBot->Edict, pBot->Edict->v.origin, TraceEnd, GetPlayerHullIndex(pBot->Edict)))
{
return true;
}
}
if (vDist2DSq(pBot->Edict->v.origin, PointOnPath) > sqrf(100.0f)) { return true; }
bool bAtMoveStart = vEquals(PointOnPath, MoveFrom, 2.0f);
@ -4964,7 +4967,7 @@ bool AbortCurrentMove(AvHAIPlayer* pBot, const Vector NewDestination)
if (flag == SAMPLE_POLYFLAGS_LIFT)
{
if (pBot->BotNavInfo.MovementTask.TaskType != MOVE_TASK_NONE)
if (pBot->BotNavInfo.MovementTask.TaskType != MOVE_TASK_NONE && !vEquals(NewDestination, pBot->BotNavInfo.MovementTask.TaskLocation))
{
if (NAV_IsMovementTaskStillValid(pBot))
{
@ -5132,7 +5135,7 @@ void UpdateBotStuck(AvHAIPlayer* pBot)
if (!vIsZero(pBot->desiredMovementDir))
{
//BotJump(pBot);
BotJump(pBot);
if (!IsPlayerSkulk(pBot->Edict))
{

View File

@ -1641,27 +1641,49 @@ void StartNewBotFrame(AvHAIPlayer* pBot)
}
// If we tried placing a building as gorge, and nothing has appeared within the expected time, then mark it as a failed attempt.
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
if (pBot->PrimaryBotTask.ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
{
if (pBot->ActiveBuildInfo.AttemptedStructureType == STRUCTURE_ALIEN_HIVE)
if (pBot->PrimaryBotTask.ActiveBuildInfo.AttemptedStructureType == STRUCTURE_ALIEN_HIVE)
{
// Give a 3-second grace period to check if the hive placement was successful
if ((gpGlobals->time - pBot->ActiveBuildInfo.BuildAttemptTime) > 3.0f)
if ((gpGlobals->time - pBot->PrimaryBotTask.ActiveBuildInfo.BuildAttemptTime) > 3.0f)
{
const AvHAIHiveDefinition* NearestHive = AITAC_GetHiveNearestLocation(pBot->ActiveBuildInfo.AttemptedLocation);
const AvHAIHiveDefinition* NearestHive = AITAC_GetHiveNearestLocation(pBot->PrimaryBotTask.ActiveBuildInfo.AttemptedLocation);
pBot->ActiveBuildInfo.BuildStatus = (NearestHive->Status != HIVE_STATUS_UNBUILT) ? BUILD_ATTEMPT_SUCCESS : BUILD_ATTEMPT_FAILED;
pBot->PrimaryBotTask.ActiveBuildInfo.BuildStatus = (NearestHive->Status != HIVE_STATUS_UNBUILT) ? BUILD_ATTEMPT_SUCCESS : BUILD_ATTEMPT_FAILED;
}
}
else
{
// All other structures should appear near-instantly
if ((gpGlobals->time - pBot->ActiveBuildInfo.BuildAttemptTime) > 0.5f)
if ((gpGlobals->time - pBot->PrimaryBotTask.ActiveBuildInfo.BuildAttemptTime) > 0.5f)
{
pBot->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_FAILED;
pBot->PrimaryBotTask.ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_FAILED;
}
}
}
// If we tried placing a building as gorge, and nothing has appeared within the expected time, then mark it as a failed attempt.
if (pBot->SecondaryBotTask.ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
{
if (pBot->SecondaryBotTask.ActiveBuildInfo.AttemptedStructureType == STRUCTURE_ALIEN_HIVE)
{
// Give a 3-second grace period to check if the hive placement was successful
if ((gpGlobals->time - pBot->SecondaryBotTask.ActiveBuildInfo.BuildAttemptTime) > 3.0f)
{
const AvHAIHiveDefinition* NearestHive = AITAC_GetHiveNearestLocation(pBot->SecondaryBotTask.ActiveBuildInfo.AttemptedLocation);
pBot->SecondaryBotTask.ActiveBuildInfo.BuildStatus = (NearestHive->Status != HIVE_STATUS_UNBUILT) ? BUILD_ATTEMPT_SUCCESS : BUILD_ATTEMPT_FAILED;
}
}
else
{
// All other structures should appear near-instantly
if ((gpGlobals->time - pBot->SecondaryBotTask.ActiveBuildInfo.BuildAttemptTime) > 0.5f)
{
pBot->SecondaryBotTask.ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_FAILED;
}
}
}
}
@ -2553,6 +2575,11 @@ void AIPlayerNSMarineThink(AvHAIPlayer* pBot)
return;
}
if (pBot->CurrentEnemy > -1)
{
if (MarineCombatThink(pBot)) { return; }
}
if (!pBot->CurrentTask) { pBot->CurrentTask = &pBot->PrimaryBotTask; }
if (gpGlobals->time >= pBot->BotNextTaskEvaluationTime)
@ -2568,11 +2595,6 @@ void AIPlayerNSMarineThink(AvHAIPlayer* pBot)
pBot->CurrentTask = AIPlayerGetNextTask(pBot);
if (pBot->CurrentEnemy > -1)
{
if (MarineCombatThink(pBot)) { return; }
}
if (pBot->CurrentTask && pBot->CurrentTask->TaskType != TASK_NONE)
{
BotProgressTask(pBot, pBot->CurrentTask);
@ -2983,6 +3005,8 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
BotShootTarget(pBot, DesiredCombatWeapon, CurrentEnemy);
}
return true;
}
return false;
@ -3732,7 +3756,7 @@ bool AIPlayerMustFinishCurrentTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return true; }
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return true; }
// If we're already capping a node, are at the node and there is an unfinished tower on there, then finish the job and don't move on yet
if (Task->TaskType == TASK_CAP_RESNODE)
@ -3773,7 +3797,15 @@ void AIPlayerNSAlienThink(AvHAIPlayer* pBot)
if (AITAC_ShouldBotBuildHive(pBot, &HiveToBuild))
{
BotAlienBuildHive(pBot, HiveToBuild);
if (pBot->PrimaryBotTask.TaskType != TASK_BUILD || pBot->PrimaryBotTask.StructureType != STRUCTURE_ALIEN_HIVE)
{
pBot->PrimaryBotTask.TaskType = TASK_BUILD;
pBot->PrimaryBotTask.StructureType = STRUCTURE_ALIEN_HIVE;
char msg[64];
sprintf(msg, "I'm going to drop the hive at %s", HiveToBuild->HiveName);
BotSay(pBot, true, 1.0f, msg);
}
BotAlienBuildHive(pBot, &pBot->PrimaryBotTask, HiveToBuild);
return;
}
@ -3858,6 +3890,16 @@ void AIPlayerThink(AvHAIPlayer* pBot)
bool bBreak = true;
AIDEBUG_DrawBotPath(pBot);
if (pBot->BotNavInfo.CurrentPathPoint != pBot->BotNavInfo.CurrentPath.end())
{
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->BotNavInfo.CurrentPathPoint->Location, 0, 255, 255);
}
}
if (pBot->PrimaryBotTask.TaskType == TASK_BUILD)
{
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->PrimaryBotTask.TaskLocation, 0, 255, 255);
}
switch (GetGameRules()->GetMapMode())
@ -4261,7 +4303,7 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
if (!TowerToReinforce || ThisDist < MinDist)
{
TowerToReinforce = ThisResTower->edict;
MaxDist = ThisDist;
MinDist = ThisDist;
}
}
}

View File

@ -28,6 +28,7 @@ int BotNameIndex = 0;
float AIStartedTime = 0.0f; // Used to give 5-second grace period before adding bots
bool bHasRoundStarted = false;
bool bMapDataInitialised = false;
extern int m_spriteTexture;
@ -622,7 +623,7 @@ void AIMGR_UpdateAIPlayers()
UpdateBotChat(bot);
DroneThink(bot);
AIPlayerThink(bot);
EndBotFrame(bot);
@ -837,26 +838,19 @@ void AIMGR_ResetRound()
UTIL_PopulateDoors();
UTIL_PopulateWeldableObstacles();
ALERT(at_console, "AI Manager Reset Round\n");
bHasRoundStarted = false;
}
void AIMGR_RoundStarted()
{
AITAC_PopulateResourceNodes();
AITAC_PopulateHiveData();
AITAC_RefreshResourceNodes();
AITAC_RefreshHiveData();
UTIL_UpdateDoors(true);
UTIL_UpdateTileCache();
ALERT(at_console, "AI Manager Reset Round\n");
bHasRoundStarted = false;
bMapDataInitialised = true;
}
void AIMGR_RoundStarted()
{
bHasRoundStarted = true;
}
void AIMGR_ClearBotData()
@ -891,12 +885,16 @@ void AIMGR_NewMap()
{
if (avh_botsenabled.value == 0) { return; } // Do nothing if we're not using bots
bMapDataInitialised = false;
ActiveAIPlayers.clear();
AIStartedTime = gpGlobals->time;
LastAIPlayerCountUpdate = 0.0f;
ALERT(at_console, "AI Manager New Map\n");
AITAC_ClearMapAIData();
if (NavmeshLoaded())
{
UnloadNavigationData();
@ -1025,9 +1023,12 @@ vector<AvHPlayer*> AIMGR_GetNonAIPlayersOnTeam(AvHTeamNumber Team)
void AIMGR_UpdateAIMapData()
{
AITAC_UpdateMapAIData();
UTIL_UpdateTileCache();
AITAC_CheckNavMeshModified();
if (bMapDataInitialised && gpGlobals->time - AIStartedTime > AI_GRACE_PERIOD)
{
AITAC_UpdateMapAIData();
UTIL_UpdateTileCache();
AITAC_CheckNavMeshModified();
}
}
void AIMGR_BotPrecache()

View File

@ -1389,6 +1389,7 @@ AvHAIResourceNode* AITAC_GetRandomResourceNode(AvHTeamNumber SearchingTeam, cons
void AITAC_UpdateMapAIData()
{
AITAC_RefreshHiveData();
UTIL_UpdateDoors(false);
@ -2220,15 +2221,25 @@ void AITAC_LinkStructureToPlayer(AvHAIBuildableStructure* NewStructure)
{
AvHAIPlayer* Player = (*it);
if (Player->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING && Player->ActiveBuildInfo.AttemptedStructureType == NewStructure->StructureType)
if (Player->PrimaryBotTask.ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING && Player->PrimaryBotTask.ActiveBuildInfo.AttemptedStructureType == NewStructure->StructureType)
{
if (vDist2DSq(NewStructure->Location, Player->ActiveBuildInfo.AttemptedLocation) < sqrf(UTIL_MetresToGoldSrcUnits(2.0f)))
if (vDist2DSq(NewStructure->Location, Player->PrimaryBotTask.ActiveBuildInfo.AttemptedLocation) < sqrf(UTIL_MetresToGoldSrcUnits(2.0f)))
{
Player->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_SUCCESS;
Player->ActiveBuildInfo.LinkedStructure = NewStructure;
Player->PrimaryBotTask.ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_SUCCESS;
Player->PrimaryBotTask.ActiveBuildInfo.LinkedStructure = NewStructure;
}
}
if (Player->SecondaryBotTask.ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING && Player->SecondaryBotTask.ActiveBuildInfo.AttemptedStructureType == NewStructure->StructureType)
{
if (vDist2DSq(NewStructure->Location, Player->SecondaryBotTask.ActiveBuildInfo.AttemptedLocation) < sqrf(UTIL_MetresToGoldSrcUnits(2.0f)))
{
Player->SecondaryBotTask.ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_SUCCESS;
Player->SecondaryBotTask.ActiveBuildInfo.LinkedStructure = NewStructure;
}
}
}
}
@ -2996,6 +3007,32 @@ int AITAC_GetNumPlayersOfTeamInArea(const AvHTeamNumber Team, const Vector Searc
}
bool AITAC_AnyPlayersOfTeamInArea(const AvHTeamNumber Team, const Vector SearchLocation, const float SearchRadius, const bool bConsiderPhaseDist, const edict_t* IgnorePlayer, const AvHUser3 IgnoreClass)
{
float MaxRadiusSq = sqrf(SearchRadius);
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
edict_t* PlayerEdict = INDEXENT(i);
if (FNullEnt(PlayerEdict) || PlayerEdict->free || PlayerEdict == IgnorePlayer) { continue; }
AvHPlayer* PlayerRef = dynamic_cast<AvHPlayer*>(CBaseEntity::Instance(PlayerEdict));
if (PlayerRef != nullptr && GetPlayerActiveClass(PlayerRef) != IgnoreClass && (Team == TEAM_IND || PlayerRef->GetTeam() == Team) && IsPlayerActiveInGame(PlayerEdict))
{
float Dist = (bConsiderPhaseDist) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(PlayerEdict->v.origin, SearchLocation)) : vDist2DSq(PlayerEdict->v.origin, SearchLocation);
if (Dist <= MaxRadiusSq)
{
return true;
}
}
}
return false;
}
int AITAC_GetNumPlayersOnTeamOfClass(const AvHTeamNumber Team, const AvHUser3 SearchClass, const edict_t* IgnorePlayer)
{
int Result = 0;

View File

@ -122,6 +122,7 @@ AvHAIWeapon UTIL_GetWeaponTypeFromEdict(const edict_t* ItemEdict);
int AITAC_GetNumActivePlayersOnTeam(const AvHTeamNumber Team);
int AITAC_GetNumPlayersOfTeamInArea(const AvHTeamNumber Team, const Vector SearchLocation, const float SearchRadius, const bool bConsiderPhaseDist, const edict_t* IgnorePlayer, const AvHUser3 IgnoreClass);
bool AITAC_AnyPlayersOfTeamInArea(const AvHTeamNumber Team, const Vector SearchLocation, const float SearchRadius, const bool bConsiderPhaseDist, const edict_t* IgnorePlayer, const AvHUser3 IgnoreClass);
vector<AvHPlayer*> AITAC_GetAllPlayersOfTeamInArea(const AvHTeamNumber Team, const Vector SearchLocation, const float SearchRadius, const bool bConsiderPhaseDist, const edict_t* IgnorePlayer, const AvHUser3 IgnoreClass);
int AITAC_GetNumPlayersOfTeamAndClassInArea(const AvHTeamNumber Team, const Vector SearchLocation, const float SearchRadius, const bool bConsiderPhaseDist, const edict_t* IgnorePlayer, const AvHUser3 SearchClass);
int AITAC_GetNumPlayersOnTeamOfClass(const AvHTeamNumber Team, const AvHUser3 SearchClass, const edict_t* IgnorePlayer);

View File

@ -137,7 +137,7 @@ void AITASK_ClearBotTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
Task->BuildAttempts = 0;
Task->StructureType = STRUCTURE_NONE;
memset(&pBot->ActiveBuildInfo, 0, sizeof(AvHAIBuildAttempt));
memset(&Task->ActiveBuildInfo, 0, sizeof(AvHAIBuildAttempt));
}
bool AITASK_IsTaskUrgent(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
@ -585,11 +585,11 @@ bool AITASK_IsAlienBuildTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (Task->StructureType == STRUCTURE_NONE) { return false; }
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return true; }
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return true; }
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED && pBot->ActiveBuildInfo.NumAttempts >= 3) { return false; }
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED && Task->ActiveBuildInfo.NumAttempts >= 3) { return false; }
if (pBot->ActiveBuildInfo.LinkedStructure && (UTIL_StructureIsFullyBuilt(pBot->ActiveBuildInfo.LinkedStructure->edict) || !UTIL_IsBuildableStructureStillReachable(pBot, pBot->ActiveBuildInfo.LinkedStructure->edict))) { return false; }
if (Task->ActiveBuildInfo.LinkedStructure && (UTIL_StructureIsFullyBuilt(Task->ActiveBuildInfo.LinkedStructure->edict) || !UTIL_IsBuildableStructureStillReachable(pBot, Task->ActiveBuildInfo.LinkedStructure->edict))) { return false; }
if (Task->StructureType == STRUCTURE_ALIEN_HIVE)
{
@ -1129,14 +1129,14 @@ void BotProgressPickupTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
void BotProgressMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
{
return;
}
if (pBot->ActiveBuildInfo.BuildStatus != BUILD_ATTEMPT_NONE)
if (Task->ActiveBuildInfo.BuildStatus != BUILD_ATTEMPT_NONE)
{
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED)
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED)
{
float Size = fmaxf(Task->TaskTarget->v.size.x, Task->TaskTarget->v.size.y);
Size += 8.0f;
@ -1147,7 +1147,7 @@ void BotProgressMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
Task->TaskLocation = ZERO_VECTOR;
}
pBot->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_NONE;
Task->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_NONE;
}
if (vIsZero(Task->TaskLocation))
@ -1184,11 +1184,11 @@ void BotProgressMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (LookDot > 0.95f)
{
pBot->Button |= IN_ATTACK;
pBot->ActiveBuildInfo.AttemptedLocation = Task->TaskLocation;
pBot->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_PENDING;
pBot->ActiveBuildInfo.BuildAttemptTime = gpGlobals->time;
pBot->ActiveBuildInfo.AttemptedStructureType = STRUCTURE_MARINE_DEPLOYEDMINE;
pBot->ActiveBuildInfo.NumAttempts++;
Task->ActiveBuildInfo.AttemptedLocation = Task->TaskLocation;
Task->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_PENDING;
Task->ActiveBuildInfo.BuildAttemptTime = gpGlobals->time;
Task->ActiveBuildInfo.AttemptedStructureType = STRUCTURE_MARINE_DEPLOYEDMINE;
Task->ActiveBuildInfo.NumAttempts++;
}
}
}
@ -1199,13 +1199,13 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (FNullEnt(Task->TaskTarget)) { return; }
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
// We had a go, whether it succeeded or not we should try a new location
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED || pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_SUCCESS)
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED || Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_SUCCESS)
{
Task->TaskLocation = ZERO_VECTOR;
pBot->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_NONE;
Task->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_NONE;
}
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
@ -1312,7 +1312,7 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (pBot->Player->GetResources() >= ResourceCost)
{
BotAlienPlaceChamber(pBot, Task->TaskLocation, NextStructure);
BotAlienPlaceChamber(pBot, Task, NextStructure);
return;
}
}
@ -1872,7 +1872,7 @@ void AlienProgressHealTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
void AlienProgressBuildHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
{
return;
}
@ -1899,13 +1899,13 @@ void AlienProgressBuildHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
return;
}
BotAlienBuildHive(pBot, Hive);
BotAlienBuildHive(pBot, Task, Hive);
}
void AlienProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
// We tried and failed to place the structure
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
{
return;
}
@ -1916,9 +1916,9 @@ void AlienProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
return;
}
if (pBot->ActiveBuildInfo.LinkedStructure)
if (Task->ActiveBuildInfo.LinkedStructure)
{
edict_t* LinkedEdict = pBot->ActiveBuildInfo.LinkedStructure->edict;
edict_t* LinkedEdict = Task->ActiveBuildInfo.LinkedStructure->edict;
if (UTIL_StructureIsFullyBuilt(LinkedEdict)) { return; }
@ -1938,10 +1938,10 @@ void AlienProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
// We tried and failed to place the structure
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED)
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED)
{
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], Task->TaskLocation, UTIL_MetresToGoldSrcUnits(2.0f));
pBot->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_NONE;
Task->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_NONE;
}
int ResRequired = UTIL_GetCostOfStructureType(Task->StructureType);
@ -1980,34 +1980,35 @@ void AlienProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
return;
}
BotAlienPlaceChamber(pBot, Task->TaskLocation, Task->StructureType);
BotAlienPlaceChamber(pBot, Task, Task->StructureType);
}
void BotAlienPlaceChamber(AvHAIPlayer* pBot, Vector Location, AvHAIDeployableStructureType DesiredStructure)
void BotAlienPlaceChamber(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, AvHAIDeployableStructureType DesiredStructure)
{
if (vIsZero(Location) || DesiredStructure == STRUCTURE_NONE) { return; }
if (vIsZero(Task->TaskLocation) || DesiredStructure == STRUCTURE_NONE) { return; }
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
float DistFromBuildLocation = vDist2DSq(pBot->Edict->v.origin, Location);
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
float DistFromBuildLocation = vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation);
if (DistFromBuildLocation > sqrf(UTIL_MetresToGoldSrcUnits(1.0f)))
{
MoveTo(pBot, Location, MOVESTYLE_NORMAL);
MoveTo(pBot, Task->TaskLocation, MOVESTYLE_NORMAL);
return;
}
if (DistFromBuildLocation < sqrf(UTIL_MetresToGoldSrcUnits(0.5f)))
{
BotLookAt(pBot, Location);
Vector Orientation = UTIL_GetVectorNormal2D(pBot->Edict->v.origin - Location);
Vector NewMoveLoc = Location + (Orientation * UTIL_MetresToGoldSrcUnits(2.0f));
BotLookAt(pBot, Task->TaskLocation);
Vector Orientation = UTIL_GetVectorNormal2D(pBot->Edict->v.origin - Task->TaskLocation);
Vector NewMoveLoc = Task->TaskLocation + (Orientation * UTIL_MetresToGoldSrcUnits(2.0f));
MoveToWithoutNav(pBot, NewMoveLoc);
return;
}
Vector LookLocation = Location;
Vector LookLocation = Task->TaskLocation;
LookLocation.z += 10.0f;
BotLookAt(pBot, LookLocation);
@ -2035,15 +2036,15 @@ void BotAlienPlaceChamber(AvHAIPlayer* pBot, Vector Location, AvHAIDeployableStr
if (LookDot > 0.9f)
{
pBot->Impulse = UTIL_StructureTypeToImpulseCommand(DesiredStructure);
RegisterBotAlienBuildAttempt(pBot, Location, DesiredStructure);
RegisterBotAlienBuildAttempt(pBot, Task, Task->TaskLocation, DesiredStructure);
}
}
void BotAlienBuildResTower(AvHAIPlayer* pBot, const AvHAIResourceNode* NodeToCap)
void BotAlienBuildResTower(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const AvHAIResourceNode* NodeToCap)
{
if (NodeToCap->bIsOccupied) { return; }
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
float CurrDist = vDist2DSq(pBot->CurrentFloorPosition, NodeToCap->Location);
@ -2090,17 +2091,17 @@ void BotAlienBuildResTower(AvHAIPlayer* pBot, const AvHAIResourceNode* NodeToCap
if (LookDot > 0.9f)
{
pBot->Impulse = UTIL_StructureTypeToImpulseCommand(STRUCTURE_ALIEN_RESTOWER);
RegisterBotAlienBuildAttempt(pBot, NodeToCap->Location, STRUCTURE_ALIEN_RESTOWER);
RegisterBotAlienBuildAttempt(pBot, Task, NodeToCap->Location, STRUCTURE_ALIEN_RESTOWER);
}
}
void BotAlienBuildHive(AvHAIPlayer* pBot, const AvHAIHiveDefinition* HiveToBuild)
void BotAlienBuildHive(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const AvHAIHiveDefinition* HiveToBuild)
{
// Do nothing if the hive is already built / under construction
if (HiveToBuild->Status != HIVE_STATUS_UNBUILT) { return; }
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
if (vDist2DSq(pBot->Edict->v.origin, HiveToBuild->Location) > sqrf(UTIL_MetresToGoldSrcUnits(7.5f)))
{
@ -2139,7 +2140,7 @@ void BotAlienBuildHive(AvHAIPlayer* pBot, const AvHAIHiveDefinition* HiveToBuild
}
pBot->Impulse = UTIL_StructureTypeToImpulseCommand(STRUCTURE_ALIEN_HIVE);
RegisterBotAlienBuildAttempt(pBot, HiveToBuild->Location, STRUCTURE_ALIEN_HIVE);
RegisterBotAlienBuildAttempt(pBot, Task, HiveToBuild->Location, STRUCTURE_ALIEN_HIVE);
}
}
@ -2170,14 +2171,14 @@ void BotAlienHealTarget(AvHAIPlayer* pBot, edict_t* HealTarget)
}
void RegisterBotAlienBuildAttempt(AvHAIPlayer* pBot, Vector PlacementLocation, AvHAIDeployableStructureType DesiredStructure)
void RegisterBotAlienBuildAttempt(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, Vector PlacementLocation, AvHAIDeployableStructureType DesiredStructure)
{
pBot->ActiveBuildInfo.AttemptedLocation = PlacementLocation;
pBot->ActiveBuildInfo.BuildAttemptTime = gpGlobals->time;
pBot->ActiveBuildInfo.LinkedStructure = nullptr;
pBot->ActiveBuildInfo.NumAttempts++;
pBot->ActiveBuildInfo.AttemptedStructureType = DesiredStructure;
pBot->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_PENDING;
Task->ActiveBuildInfo.AttemptedLocation = PlacementLocation;
Task->ActiveBuildInfo.BuildAttemptTime = gpGlobals->time;
Task->ActiveBuildInfo.LinkedStructure = nullptr;
Task->ActiveBuildInfo.NumAttempts++;
Task->ActiveBuildInfo.AttemptedStructureType = DesiredStructure;
Task->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_PENDING;
}
void AlienProgressCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
@ -2252,7 +2253,7 @@ void AlienProgressCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
// We have enough resources to place the tower (includes cost of evolving to gorge if necessary)
if (pBot->Player->GetResources() >= NumResourcesRequired)
{
BotAlienBuildResTower(pBot, ResNodeIndex);
BotAlienBuildResTower(pBot, Task, ResNodeIndex);
return;
}
}

View File

@ -109,11 +109,11 @@ AvHAIPlayer* GetFirstBotWithReinforceTask(AvHTeamNumber Team, edict_t* Reinforce
void UTIL_ClearGuardInfo(AvHAIPlayer* pBot);
void BotAlienPlaceChamber(AvHAIPlayer* pBot, Vector Location, AvHAIDeployableStructureType DesiredStructure);
void BotAlienBuildHive(AvHAIPlayer* pBot, const AvHAIHiveDefinition* HiveToBuild);
void BotAlienBuildResTower(AvHAIPlayer* pBot, const AvHAIResourceNode* NodeToCap);
void BotAlienPlaceChamber(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, AvHAIDeployableStructureType DesiredStructure);
void BotAlienBuildHive(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const AvHAIHiveDefinition* HiveToBuild);
void BotAlienBuildResTower(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const AvHAIResourceNode* NodeToCap);
void BotAlienHealTarget(AvHAIPlayer* pBot, edict_t* HealTarget);
void RegisterBotAlienBuildAttempt(AvHAIPlayer* pBot, Vector PlacementLocation, AvHAIDeployableStructureType DesiredStructure);
void RegisterBotAlienBuildAttempt(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, Vector PlacementLocation, AvHAIDeployableStructureType DesiredStructure);
#endif

View File

@ -3609,10 +3609,7 @@ void AvHGamerules::Think(void)
if (avh_botsenabled.value > 0)
{
if (this->GetGameStarted())
{
AIMGR_UpdateAIMapData();
}
AIMGR_UpdateAIMapData();
AIMGR_UpdateAIPlayers();
}