Crash fixes

This commit is contained in:
RGreenlees 2024-03-01 20:32:51 +00:00 committed by pierow
parent d1d1e1f746
commit 0df89d9abe
7 changed files with 133 additions and 26 deletions

View file

@ -936,9 +936,11 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
StructureFilter.ReachabilityTeam = TeamNumber;
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
edict_t* BaseBuilder = AITAC_GetNearestHiddenPlayerInLocation(TeamNumber, CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
int NumInfantryPortals = AITAC_GetNumDeployablesNearLocation(CommChair->v.origin, &StructureFilter);
if (NumInfantryPortals < 2)
if (NumInfantryPortals < 2 && !FNullEnt(BaseBuilder))
{
bool bEnemyInBase = NumInfantryPortals > 1 && AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
@ -950,9 +952,11 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
AvHAIBuildableStructure* BaseArmoury = AITAC_FindClosestDeployableToLocation(CommChair->v.origin, &StructureFilter);
if (!BaseArmoury)
{
if (!BaseArmoury && !FNullEnt(BaseBuilder))
{
StructureFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL;
AvHAIBuildableStructure* NearestInfantryPortal = AITAC_FindClosestDeployableToLocation(CommChair->v.origin, &StructureFilter);
@ -1014,7 +1018,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
bool bPhaseNearBase = AITAC_DeployableExistsAtLocation(CommChair->v.origin, &StructureFilter);
if (!bPhaseNearBase)
if (!bPhaseNearBase && !FNullEnt(BaseBuilder))
{
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
@ -1051,7 +1055,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
bool bHasArmsLab = AITAC_DeployableExistsAtLocation(CommChair->v.origin, &StructureFilter);
if (!bHasArmsLab)
if (!bHasArmsLab && !FNullEnt(BaseBuilder))
{
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
@ -1068,7 +1072,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
bool bHasObservatory = AITAC_DeployableExistsAtLocation(CommChair->v.origin, &StructureFilter);
if (!bHasObservatory)
if (!bHasObservatory && !FNullEnt(BaseBuilder))
{
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
@ -1129,7 +1133,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
bool bHasPrototypeLab = AITAC_DeployableExistsAtLocation(CommChair->v.origin, &StructureFilter);
if (!bHasPrototypeLab && bHasAdvArmoury)
if (!bHasPrototypeLab && bHasAdvArmoury && !FNullEnt(BaseBuilder))
{
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInDonutIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), BaseArmoury->Location, UTIL_MetresToGoldSrcUnits(3.0f), UTIL_MetresToGoldSrcUnits(5.0f));
@ -1325,7 +1329,12 @@ bool AICOMM_CheckForNextSupplyAction(AvHAIPlayer* pBot)
bool bNeedsMines = false;
int DesiredMines = 0;
if (NumMinesInPlay < 2)
DeployableSearchFilter MineFilter;
MineFilter.DeployableTypes = STRUCTURE_MARINE_DEPLOYEDMINE;
int NumDeployedMines = AITAC_GetNumDeployablesNearLocation(ZERO_VECTOR, &MineFilter);
if (NumMinesInPlay < 2 && NumDeployedMines < 32)
{
int UnminedStructures = 0;

View file

@ -2138,6 +2138,13 @@ bool HasBotReachedPathPoint(const AvHAIPlayer* pBot)
return false;
}
bool HasBotCompletedLadderMove(AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd)
{
if (IsPlayerOnLadder(pBot->Edict)) { return false; }
return UTIL_PointIsDirectlyReachable(pBot->CollisionHullBottomLocation, MoveEnd);
}
void CheckAndHandleDoorObstruction(AvHAIPlayer* pBot)
{
edict_t* BlockingDoorEdict = UTIL_GetDoorBlockingPathPoint(pBot->Edict->v.origin, pBot->BotNavInfo.CurrentPathPoint->Location, pBot->BotNavInfo.CurrentPathPoint->flag, nullptr);
@ -3258,7 +3265,7 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
CurrentLadderNormal = UTIL_GetNearestLadderNormal(pBot->CollisionHullBottomLocation + Vector(0.0f, 0.0f, 5.0f));
}
//CurrentLadderNormal = UTIL_GetVectorNormal2D(CurrentLadderNormal);
CurrentLadderNormal = UTIL_GetVectorNormal2D(CurrentLadderNormal);
if (vIsZero(CurrentLadderNormal))
{
@ -5541,6 +5548,8 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
}
else
{
BotNavInfo->CurrentPathPoint = BotNavInfo->CurrentPath.end();
pBot->BotNavInfo.StuckInfo.bPathFollowFailed = true;
if (!UTIL_PointIsOnNavmesh(pBot->CollisionHullBottomLocation, pBot->BotNavInfo.NavProfile) && !vIsZero(BotNavInfo->LastNavMeshPosition))
@ -6385,7 +6394,8 @@ void HandlePlayerAvoidance(AvHAIPlayer* pBot, const Vector MoveDestination)
// Don't handle player avoidance if climbing a wall, ladder or in the air, as it will mess up the move and cause them to get stuck most likely
if (pBot->Player->IsOnLadder() || IsPlayerClimbingWall(pBot->Edict) || !pBot->BotNavInfo.IsOnGround) { return; }
float avoidDistSq = sqrf(50.0f);
float MyRadius = GetPlayerRadius(pBot->Edict);
const Vector BotLocation = pBot->Edict->v.origin;
const Vector MoveDir = UTIL_GetVectorNormal2D((MoveDestination - pBot->Edict->v.origin));
@ -6395,6 +6405,10 @@ void HandlePlayerAvoidance(AvHAIPlayer* pBot, const Vector MoveDestination)
if (!FNullEnt(OtherPlayer) && OtherPlayer != pBot->Edict && IsPlayerActiveInGame(OtherPlayer))
{
float OtherPlayerRadius = GetPlayerRadius(OtherPlayer);
float avoidDistSq = sqrf(MyRadius + OtherPlayerRadius + 16.0f);
// Don't do avoidance for a player if they're moving in broadly the same direction as us
Vector OtherMoveDir = GetPlayerAttemptedMoveDirection(OtherPlayer);
@ -6418,26 +6432,41 @@ void HandlePlayerAvoidance(AvHAIPlayer* pBot, const Vector MoveDestination)
int modifier = vPointOnLine(pBot->Edict->v.origin, MoveDestination, OtherPlayer->v.origin);
float OtherPersonDistFromLine = vDistanceFromLine2D(pBot->Edict->v.origin, MoveDestination, OtherPlayer->v.origin);
if (modifier == 0) { modifier = 1; }
Vector PreferredMoveDir = (MoveRightVector * modifier);
float TraceLength = OtherPersonDistFromLine + (fmaxf(MyRadius, OtherPlayerRadius) * 2.0f);
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->Edict->v.origin + (PreferredMoveDir * TraceLength), 0, 128, 0);
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->Edict->v.origin - (PreferredMoveDir * TraceLength), 255, 0, 0);
// First see if we have enough room to move in our preferred avoidance direction
if (UTIL_TraceNav(pBot->BotNavInfo.NavProfile, BotLocation, BotLocation + (PreferredMoveDir * 32.0f), 2.0f))
if (UTIL_TraceNav(pBot->BotNavInfo.NavProfile, BotLocation, BotLocation + (PreferredMoveDir * TraceLength), 0.0f))
{
pBot->desiredMovementDir = PreferredMoveDir;
return;
}
// Then try the opposite direction
if (UTIL_TraceNav(pBot->BotNavInfo.NavProfile, BotLocation, BotLocation - (PreferredMoveDir * 32.0f), 2.0f))
if (UTIL_TraceNav(pBot->BotNavInfo.NavProfile, BotLocation, BotLocation - (PreferredMoveDir * TraceLength), 0.0f))
{
pBot->desiredMovementDir = -PreferredMoveDir;
return;
}
// Back up since we can't go either side
if (UTIL_GetDotProduct2D(MoveDir, OtherMoveDir) < 0.0f)
bool bCanBackUp = UTIL_TraceNav(pBot->BotNavInfo.NavProfile, BotLocation, BotLocation - (MoveDir * (MyRadius * 2.0f)), 0.0f);
if (!bCanBackUp)
{
bCanBackUp = UTIL_QuickHullTrace(pBot->Edict, pBot->Edict->v.origin, pBot->Edict->v.origin - (MoveDir * (MyRadius * 2.0f)), head_hull);
}
// Back up since we can't go either side, but only if we can back up. Otherwise, we push forward and demand the OTHER guy back up
if (UTIL_GetDotProduct2D(MoveDir, OtherMoveDir) < 0.0f && bCanBackUp)
{
pBot->desiredMovementDir = MoveDir * -1.0f;
}

View file

@ -227,6 +227,28 @@ float GetPlayerRadius(const AvHPlayer* Player)
}
}
float GetPlayerRadius(const edict_t* Player)
{
if (!Player) { return 0.0f; }
int hullnum = GetPlayerHullIndex(Player);
switch (hullnum)
{
case human_hull:
case head_hull:
return 16.0f;
break;
case large_hull:
return 32.0f;
break;
default:
return 16.0f;
break;
}
}
bool CanPlayerCrouch(const edict_t* Player)
{
if (FNullEnt(Player) || Player->free || !IsEdictPlayer(Player)) { return false; }

View file

@ -91,6 +91,7 @@ int GetPlayerCombatLevel(const AvHPlayer* Player);
// Returns the player radius based on their current state
float GetPlayerRadius(const AvHPlayer* Player);
float GetPlayerRadius(const edict_t* Player);
// Returns the hull index that should be used for this player when performing hull traces. Depends on if player is crouching right now or not
int GetPlayerHullIndex(const edict_t* Player);

View file

@ -85,6 +85,8 @@ std::vector<AvHAIBuildableStructure*> AITAC_FindAllDeployables(const Vector& Loc
{
for (auto& it : TeamAStructureMap)
{
if (FNullEnt(it.second.edict) || it.second.edict->v.deadflag != DEAD_NO || (it.second.edict->v.effects & EF_NODRAW)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
@ -116,6 +118,8 @@ std::vector<AvHAIBuildableStructure*> AITAC_FindAllDeployables(const Vector& Loc
{
for (auto& it : TeamBStructureMap)
{
if (FNullEnt(it.second.edict) || it.second.edict->v.deadflag != DEAD_NO || (it.second.edict->v.effects & EF_NODRAW)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
@ -161,6 +165,8 @@ bool AITAC_DeployableExistsAtLocation(const Vector& Location, const DeployableSe
{
for (auto& it : TeamAStructureMap)
{
if (FNullEnt(it.second.edict) || it.second.edict->v.deadflag != DEAD_NO || (it.second.edict->v.effects & EF_NODRAW)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
@ -189,6 +195,8 @@ bool AITAC_DeployableExistsAtLocation(const Vector& Location, const DeployableSe
{
for (auto& it : TeamBStructureMap)
{
if (FNullEnt(it.second.edict) || it.second.edict->v.deadflag != DEAD_NO || (it.second.edict->v.effects & EF_NODRAW)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
@ -234,6 +242,8 @@ AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocation(const Vector& Loc
{
for (auto& it : TeamAStructureMap)
{
if (FNullEnt(it.second.edict) || it.second.edict->v.deadflag != DEAD_NO || (it.second.edict->v.effects & EF_NODRAW)) { continue; }
if (!(it.second.StructureType & Filter->DeployableTypes)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
@ -261,6 +271,8 @@ AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocation(const Vector& Loc
{
for (auto& it : TeamBStructureMap)
{
if (FNullEnt(it.second.edict) || it.second.edict->v.deadflag != DEAD_NO || (it.second.edict->v.effects & EF_NODRAW)) { continue; }
if (!(it.second.StructureType & Filter->DeployableTypes)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
@ -305,6 +317,8 @@ AvHAIBuildableStructure* AITAC_FindFurthestDeployableFromLocation(const Vector&
{
for (auto& it : TeamAStructureMap)
{
if (FNullEnt(it.second.edict) || it.second.edict->v.deadflag != DEAD_NO || (it.second.edict->v.effects & EF_NODRAW)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (!(it.second.StructureType & Filter->DeployableTypes)) { continue; }
@ -332,6 +346,8 @@ AvHAIBuildableStructure* AITAC_FindFurthestDeployableFromLocation(const Vector&
{
for (auto& it : TeamBStructureMap)
{
if (FNullEnt(it.second.edict) || it.second.edict->v.deadflag != DEAD_NO || (it.second.edict->v.effects & EF_NODRAW)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (!(it.second.StructureType & Filter->DeployableTypes)) { continue; }
@ -382,6 +398,8 @@ AvHAIDroppedItem* AITAC_FindClosestItemToLocation(const Vector& Location, const
for (auto& it : MarineDroppedItemMap)
{
if (FNullEnt(it.second.edict) || it.second.edict->v.deadflag != DEAD_NO || (it.second.edict->v.effects & EF_NODRAW)) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (SearchingTeam != TEAM_IND)
@ -418,6 +436,8 @@ int AITAC_GetNumItemsInLocation(const Vector& Location, const AvHAIDeployableIte
for (auto& it : MarineDroppedItemMap)
{
if (FNullEnt(it.second.edict) || it.second.edict->v.deadflag != DEAD_NO || (it.second.edict->v.effects & EF_NODRAW)) { continue; }
if (it.second.ItemType != ItemType) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -452,6 +472,8 @@ bool AITAC_ItemExistsInLocation(const Vector& Location, const AvHAIDeployableIte
for (auto& it : MarineDroppedItemMap)
{
if (FNullEnt(it.second.edict) || it.second.edict->v.deadflag != DEAD_NO || (it.second.edict->v.effects & EF_NODRAW)) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (SearchingTeam != TEAM_IND)
@ -508,6 +530,8 @@ AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer
{
for (auto& it : TeamAStructureMap)
{
if (FNullEnt(it.second.edict) || it.second.edict->v.deadflag != DEAD_NO || (it.second.edict->v.effects & EF_NODRAW)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
@ -539,6 +563,8 @@ AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer
{
for (auto& it : TeamBStructureMap)
{
if (FNullEnt(it.second.edict) || it.second.edict->v.deadflag != DEAD_NO || (it.second.edict->v.effects & EF_NODRAW)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
@ -586,6 +612,8 @@ int AITAC_GetNumDeployablesNearLocation(const Vector& Location, const Deployable
{
for (auto& it : TeamAStructureMap)
{
if (FNullEnt(it.second.edict) || it.second.edict->v.deadflag != DEAD_NO || (it.second.edict->v.effects & EF_NODRAW)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
@ -614,6 +642,8 @@ int AITAC_GetNumDeployablesNearLocation(const Vector& Location, const Deployable
{
for (auto& it : TeamBStructureMap)
{
if (FNullEnt(it.second.edict) || it.second.edict->v.deadflag != DEAD_NO || (it.second.edict->v.effects & EF_NODRAW)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
@ -948,6 +978,8 @@ Vector AITAC_GetCommChairLocation(AvHTeamNumber Team)
void AITAC_RefreshReachabilityForItem(AvHAIDroppedItem* Item)
{
if (FNullEnt(Item->edict) || Item->edict->v.deadflag != DEAD_NO || (Item->edict->v.effects & EF_NODRAW)) { return; }
if (Item->ItemType == DEPLOYABLE_ITEM_SCAN)
{
Item->TeamAReachabilityFlags = AI_REACHABILITY_ALL;
@ -1634,7 +1666,7 @@ void AITAC_RefreshBuildableStructures()
for (auto it = TeamAStructureMap.begin(); it != TeamAStructureMap.end();)
{
if (it->second.LastSeen < StructureRefreshFrame)
if (it->second.LastSeen < StructureRefreshFrame || FNullEnt(it->second.edict) || it->second.edict->v.deadflag != DEAD_NO || (it->second.edict->v.effects & EF_NODRAW))
{
AITAC_OnStructureDestroyed(&it->second);
it = TeamAStructureMap.erase(it);
@ -1652,7 +1684,7 @@ void AITAC_RefreshBuildableStructures()
for (auto it = TeamBStructureMap.begin(); it != TeamBStructureMap.end();)
{
if (it->second.LastSeen < StructureRefreshFrame)
if (it->second.LastSeen < StructureRefreshFrame || FNullEnt(it->second.edict) || it->second.edict->v.deadflag != DEAD_NO || (it->second.edict->v.effects & EF_NODRAW))
{
AITAC_OnStructureDestroyed(&it->second);
it = TeamBStructureMap.erase(it);
@ -1777,7 +1809,7 @@ void AITAC_UpdateMarineItem(CBaseEntity* Item, AvHAIDeployableItemType ItemType)
edict_t* ItemEdict = Item->edict();
if (FNullEnt(ItemEdict)) { return; }
if (FNullEnt(ItemEdict) || ItemEdict->v.deadflag != DEAD_NO || (ItemEdict->v.effects & EF_NODRAW)) { return; }
// All items except scans are of interest only if they're collectable. Without this check, marines will attempt to grab weapons from other players.
if (ItemType != DEPLOYABLE_ITEM_SCAN)
@ -1835,6 +1867,8 @@ void AITAC_RefreshReachabilityForStructure(AvHAIBuildableStructure* Structure)
AITAC_RefreshHiveData();
}
if (!Structure || FNullEnt(Structure->edict) || Structure->edict->v.deadflag != DEAD_NO || (Structure->edict->v.effects & EF_NODRAW)) { return; }
if (Structure->StructureType == STRUCTURE_MARINE_DEPLOYEDMINE)
{
Structure->TeamAReachabilityFlags = AI_REACHABILITY_ALL;
@ -2125,6 +2159,8 @@ AvHAIBuildableStructure* AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
void AITAC_OnStructureCreated(AvHAIBuildableStructure* NewStructure)
{
if (!NewStructure || FNullEnt(NewStructure->edict) || NewStructure->edict->v.deadflag != DEAD_NO || (NewStructure->edict->v.effects & EF_NODRAW)) { return; }
UTIL_AddStructureTemporaryObstacles(NewStructure);
AvHTeamNumber StructureTeam = (AvHTeamNumber)NewStructure->edict->v.team;
@ -2146,6 +2182,8 @@ void AITAC_OnStructureCreated(AvHAIBuildableStructure* NewStructure)
void AITAC_OnStructureCompleted(AvHAIBuildableStructure* NewStructure)
{
if (!NewStructure || FNullEnt(NewStructure->edict) || NewStructure->edict->v.deadflag != DEAD_NO || (NewStructure->edict->v.effects & EF_NODRAW)) { return; }
if (NewStructure->StructureType == STRUCTURE_MARINE_PHASEGATE)
{
DeployableSearchFilter Filter;
@ -2217,6 +2255,8 @@ void AITAC_RemovePhaseGateConnections(AvHAIBuildableStructure* SourceGate, AvHAI
void AITAC_OnStructureBeginRecycling(AvHAIBuildableStructure* RecyclingStructure)
{
if (!RecyclingStructure || FNullEnt(RecyclingStructure->edict) || RecyclingStructure->edict->v.deadflag != DEAD_NO || (RecyclingStructure->edict->v.effects & EF_NODRAW)) { return; }
// For phase gates, treat them like they've been destroyed
if (RecyclingStructure->StructureType == STRUCTURE_MARINE_PHASEGATE)
{
@ -2226,6 +2266,8 @@ void AITAC_OnStructureBeginRecycling(AvHAIBuildableStructure* RecyclingStructure
void AITAC_OnStructureDestroyed(AvHAIBuildableStructure* DestroyedStructure)
{
if (!DestroyedStructure || FNullEnt(DestroyedStructure->edict)) { return; }
UTIL_RemoveStructureTemporaryObstacles(DestroyedStructure);
if (DestroyedStructure->StructureType == STRUCTURE_MARINE_PHASEGATE)

View file

@ -15,10 +15,10 @@
#include "AvHAIConstants.h"
// How frequently to update the global list of built structures (in seconds). 0 = every frame
static const float structure_inventory_refresh_rate = 0.2f;
static const float structure_inventory_refresh_rate = 0.0f;
// How frequently to update the global list of dropped marine items (in seconds). 0 = every frame
static const float item_inventory_refresh_rate = 0.1f;
static const float item_inventory_refresh_rate = 0.0f;
bool AITAC_DeployableExistsAtLocation(const Vector& Location, const DeployableSearchFilter* Filter);
std::vector<AvHAIBuildableStructure*> AITAC_FindAllDeployables(const Vector& Location, const DeployableSearchFilter* Filter);

View file

@ -383,7 +383,7 @@ bool AITASK_IsMoveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
bool AITASK_IsWeldTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (!Task) { return false; }
if (FNullEnt(Task->TaskTarget)) { return false; }
if (!Task->TaskTarget || FNullEnt(Task->TaskTarget) || (Task->TaskTarget->v.effects & EF_NODRAW) || Task->TaskTarget->v.deadflag != DEAD_NO) { return false; }
if (Task->TaskTarget == pBot->Edict) { return false; }
if (!PlayerHasWeapon(pBot->Player, WEAPON_MARINE_WELDER))
{
@ -469,7 +469,9 @@ bool AITASK_IsWeaponPickupTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
bool AITASK_IsAttackTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (FNullEnt(Task->TaskTarget) || (vIsZero(Task->TaskTarget->v.origin) && vIsZero(Task->TaskLocation))) { return false; }
if (!Task->TaskTarget || FNullEnt(Task->TaskTarget) || (Task->TaskTarget->v.effects & EF_NODRAW) || Task->TaskTarget->v.deadflag != DEAD_NO) { return false; }
if ((vIsZero(Task->TaskTarget->v.origin) && vIsZero(Task->TaskLocation))) { return false; }
if ((Task->TaskTarget->v.effects & EF_NODRAW) || (Task->TaskTarget->v.deadflag != DEAD_NO)) { return false; }
@ -531,7 +533,9 @@ bool AITASK_IsGuardTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
bool AITASK_IsMineStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (FNullEnt(Task->TaskTarget) || UTIL_StructureIsRecycling(Task->TaskTarget)) { return false; }
if (!Task->TaskTarget || FNullEnt(Task->TaskTarget) || (Task->TaskTarget->v.effects & EF_NODRAW) || Task->TaskTarget->v.deadflag != DEAD_NO) { return false; }
if (UTIL_StructureIsRecycling(Task->TaskTarget)) { return false; }
if (!PlayerHasWeapon(pBot->Player, WEAPON_MARINE_MINES)) { return false; }
@ -776,7 +780,7 @@ bool AITASK_IsMarineCapResNodeTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask*
bool AITASK_IsDefendTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (FNullEnt(Task->TaskTarget) || Task->TaskTarget->v.deadflag != DEAD_NO) { return false; }
if (!Task->TaskTarget || FNullEnt(Task->TaskTarget) || (Task->TaskTarget->v.effects & EF_NODRAW) || Task->TaskTarget->v.deadflag != DEAD_NO) { return false; }
if (GetStructureTypeFromEdict(Task->TaskTarget) == STRUCTURE_NONE) { return false; }
@ -797,7 +801,7 @@ bool AITASK_IsDefendTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (FNullEnt(Task->TaskTarget) || Task->TaskTarget->v.deadflag != DEAD_NO) { return false; }
if (!Task->TaskTarget || FNullEnt(Task->TaskTarget) || (Task->TaskTarget->v.effects & EF_NODRAW) || Task->TaskTarget->v.deadflag != DEAD_NO) { return false; }
if (!FNullEnt(Task->TaskSecondaryTarget) && !UTIL_StructureIsFullyBuilt(Task->TaskSecondaryTarget)) { return true; }
@ -984,7 +988,7 @@ bool AITASK_IsAlienGetHealthTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* T
bool AITASK_IsAlienHealTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (FNullEnt(Task->TaskTarget) || Task->TaskTarget->v.deadflag != DEAD_NO) { return false; }
if (!Task->TaskTarget || FNullEnt(Task->TaskTarget) || (Task->TaskTarget->v.effects & EF_NODRAW) || Task->TaskTarget->v.deadflag != DEAD_NO) { return false; }
if (!IsPlayerGorge(pBot->Edict)) { return false; }
@ -3082,7 +3086,7 @@ void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Targe
void AITASK_SetAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const bool bIsUrgent)
{
// Don't set the task if the target is invalid, dead or on the same team as the bot (can't picture a situation where you want them to teamkill...)
if (FNullEnt(Target) || (Target->v.deadflag != DEAD_NO) || Target->v.team == pBot->Edict->v.team)
if (!Target || FNullEnt(Target) || (Target->v.deadflag != DEAD_NO) || Target->v.team == pBot->Edict->v.team)
{
AITASK_ClearBotTask(pBot, Task);
return;