Tweaked level load sequence

This commit is contained in:
RGreenlees 2024-03-16 17:34:52 +00:00 committed by pierow
parent b518693f5c
commit 6883eb33b3
12 changed files with 1090 additions and 603 deletions

File diff suppressed because it is too large Load diff

View file

@ -344,6 +344,8 @@ typedef struct _AVH_AI_BUILDABLE_STRUCTURE
StructurePurpose Purpose = STRUCTURE_PURPOSE_NONE;
bool bReachabilityMarkedDirty = false; // If true, reachability flags will be recalculated for this structure
bool IsValid() { return !FNullEnt(edict) && !edict->free && !(edict->v.flags & EF_NODRAW) && edict->v.deadflag == DEAD_NO; }
} AvHAIBuildableStructure;
// Any kind of pickup that has been dropped either by the commander or by a player
@ -735,7 +737,7 @@ typedef struct AVH_AI_PLAYER
AvHAICombatStrategy CurrentCombatStrategy = COMBAT_STRATEGY_ATTACK;
edict_t* CurrentEnemyRef = nullptr;
vector<AvHAIBuildableStructure*> DangerTurrets;
vector<AvHAIBuildableStructure> DangerTurrets;
AvHAIPlayerTask* CurrentTask = nullptr; // Bot's current task they're performing
AvHAIPlayerTask PrimaryBotTask;

View file

@ -3405,28 +3405,28 @@ void StructureBlockedMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vect
BlockingFilter.DeployableTeam = AIMGR_GetEnemyTeam(pBot->Player->GetTeam());
BlockingFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(3.0f);
vector<AvHAIBuildableStructure*> BlockingStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &BlockingFilter);
vector<AvHAIBuildableStructure> BlockingStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &BlockingFilter);
AvHAIBuildableStructure* CulpritStructure = nullptr;
AvHAIBuildableStructure CulpritStructure;
float MinDist = 0.0f;
for (auto it = BlockingStructures.begin(); it != BlockingStructures.end(); it++)
{
AvHAIBuildableStructure* ThisStructure = (*it);
AvHAIBuildableStructure ThisStructure = (*it);
float ThisDist = vDistanceFromLine2DSq(StartPoint, EndPoint, ThisStructure->Location);
float ThisDist = vDistanceFromLine2DSq(StartPoint, EndPoint, ThisStructure.Location);
if (!CulpritStructure || ThisDist < MinDist)
if (FNullEnt(CulpritStructure.edict) || ThisDist < MinDist)
{
CulpritStructure = ThisStructure;
}
}
if (CulpritStructure)
if (CulpritStructure.IsValid())
{
BotMoveLookAt(pBot, CulpritStructure->Location);
BotMoveLookAt(pBot, CulpritStructure.Location);
AvHAIWeapon AttackWeapon = (IsPlayerAlien(pBot->Edict)) ? BotAlienChooseBestWeaponForStructure(pBot, CulpritStructure->edict) : BotMarineChooseBestWeaponForStructure(pBot, CulpritStructure->edict);
AvHAIWeapon AttackWeapon = (IsPlayerAlien(pBot->Edict)) ? BotAlienChooseBestWeaponForStructure(pBot, CulpritStructure.edict) : BotMarineChooseBestWeaponForStructure(pBot, CulpritStructure.edict);
if (GetPlayerCurrentWeapon(pBot->Player) != AttackWeapon)
{
@ -3434,7 +3434,7 @@ void StructureBlockedMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vect
}
else
{
BotShootTarget(pBot, AttackWeapon, CulpritStructure->edict);
BotShootTarget(pBot, AttackWeapon, CulpritStructure.edict);
}
}
}
@ -4161,26 +4161,26 @@ void PhaseGateMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndP
PGFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(2.0f);
PGFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
AvHAIBuildableStructure* NearestPhaseGate = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &PGFilter);
AvHAIBuildableStructure NearestPhaseGate = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &PGFilter);
if (!NearestPhaseGate) { return; }
if (!NearestPhaseGate.IsValid()) { return; }
if (IsPlayerInUseRange(pBot->Edict, NearestPhaseGate->edict))
if (IsPlayerInUseRange(pBot->Edict, NearestPhaseGate.edict))
{
BotMoveLookAt(pBot, NearestPhaseGate->edict->v.origin);
BotMoveLookAt(pBot, NearestPhaseGate.edict->v.origin);
pBot->desiredMovementDir = g_vecZero;
BotUseObject(pBot, NearestPhaseGate->edict, false);
BotUseObject(pBot, NearestPhaseGate.edict, false);
if (vDist2DSq(pBot->Edict->v.origin, NearestPhaseGate->edict->v.origin) < sqrf(16.0f))
if (vDist2DSq(pBot->Edict->v.origin, NearestPhaseGate.edict->v.origin) < sqrf(16.0f))
{
pBot->desiredMovementDir = UTIL_GetForwardVector2D(NearestPhaseGate->edict->v.angles);
pBot->desiredMovementDir = UTIL_GetForwardVector2D(NearestPhaseGate.edict->v.angles);
}
return;
}
else
{
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(NearestPhaseGate->edict->v.origin - pBot->Edict->v.origin);
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(NearestPhaseGate.edict->v.origin - pBot->Edict->v.origin);
}
}

View file

@ -1501,12 +1501,12 @@ void BotUpdateView(AvHAIPlayer* pBot)
EnemyTurretFilter.MaxSearchRadius = BALANCE_VAR(kTurretRange);
}
vector<AvHAIBuildableStructure*> EligibleTurrets = AITAC_FindAllDeployables(pBot->Edict->v.origin, &EnemyTurretFilter);
vector<AvHAIBuildableStructure> EligibleTurrets = AITAC_FindAllDeployables(pBot->Edict->v.origin, &EnemyTurretFilter);
for (auto it = EligibleTurrets.begin(); it != EligibleTurrets.end(); it++)
{
AvHAIBuildableStructure* ThisTurret = (*it);
AvHTurret* TurretRef = dynamic_cast<AvHTurret*>(ThisTurret->EntityRef);
AvHAIBuildableStructure ThisTurret = (*it);
AvHTurret* TurretRef = dynamic_cast<AvHTurret*>(ThisTurret.EntityRef);
if (TurretRef && TurretRef->GetIsValidTarget(pBot->Player))
{
@ -1807,11 +1807,11 @@ void CustomThink(AvHAIPlayer* pBot)
MineStructureFilter.ReachabilityTeam = pBot->Player->GetTeam();
MineStructureFilter.ReachabilityFlags = AI_REACHABILITY_MARINE;
AvHAIBuildableStructure* NearestIP = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &MineStructureFilter);
AvHAIBuildableStructure NearestIP = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &MineStructureFilter);
if (NearestIP)
if (NearestIP.IsValid())
{
AITASK_SetMineStructureTask(pBot, &pBot->PrimaryBotTask, NearestIP->edict, true);
AITASK_SetMineStructureTask(pBot, &pBot->PrimaryBotTask, NearestIP.edict, true);
}
}
@ -2855,20 +2855,20 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
NearestArmoury.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
NearestArmoury.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
AvHAIBuildableStructure* NearestArmouryRef = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &NearestArmoury);
AvHAIBuildableStructure NearestArmouryRef = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &NearestArmoury);
if (NearestArmouryRef && !IsAreaAffectedBySpores(NearestArmouryRef->Location))
if (NearestArmouryRef.IsValid() && !IsAreaAffectedBySpores(NearestArmouryRef.Location))
{
if (!TrackedEnemyRef->bHasLOS || (IsPlayerAlien(pBot->Edict) && vDist2DSq(NearestArmouryRef->Location, CurrentEnemy->v.origin) > sqrf(UTIL_MetresToGoldSrcUnits(10.0f))))
if (!TrackedEnemyRef->bHasLOS || (IsPlayerAlien(pBot->Edict) && vDist2DSq(NearestArmouryRef.Location, CurrentEnemy->v.origin) > sqrf(UTIL_MetresToGoldSrcUnits(10.0f))))
{
if (IsPlayerInUseRange(pBot->Edict, NearestArmouryRef->edict))
if (IsPlayerInUseRange(pBot->Edict, NearestArmouryRef.edict))
{
BotUseObject(pBot, NearestArmouryRef->edict, true);
BotUseObject(pBot, NearestArmouryRef.edict, true);
return true;
}
}
MoveTo(pBot, NearestArmouryRef->Location, MOVESTYLE_NORMAL);
MoveTo(pBot, NearestArmouryRef.Location, MOVESTYLE_NORMAL);
}
else
@ -3198,22 +3198,22 @@ void AIPlayerSetMarineSweeperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
StructureFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
StructureFilter.ExcludeStatusFlags = (STRUCTURE_STATUS_RECYCLING | STRUCTURE_STATUS_COMPLETED);
AvHAIBuildableStructure* UnbuiltIP = AITAC_FindClosestDeployableToLocation(CommChairLocation, &StructureFilter);
AvHAIBuildableStructure UnbuiltIP = AITAC_FindClosestDeployableToLocation(CommChairLocation, &StructureFilter);
if (UnbuiltIP)
if (UnbuiltIP.IsValid())
{
AITASK_SetBuildTask(pBot, Task, UnbuiltIP->edict, true);
AITASK_SetBuildTask(pBot, Task, UnbuiltIP.edict, true);
return;
}
StructureFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
AvHAIBuildableStructure* UnbuiltStructure = AITAC_FindClosestDeployableToLocation(CommChairLocation, &StructureFilter);
AvHAIBuildableStructure UnbuiltStructure = AITAC_FindClosestDeployableToLocation(CommChairLocation, &StructureFilter);
if (UnbuiltStructure)
if (UnbuiltStructure.IsValid())
{
AITASK_SetBuildTask(pBot, Task, UnbuiltStructure->edict, true);
AITASK_SetBuildTask(pBot, Task, UnbuiltStructure.edict, true);
return;
}
@ -3227,11 +3227,11 @@ void AIPlayerSetMarineSweeperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
AttackedStructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f);
AttackedStructureFilter.bConsiderPhaseDistance = true;
AvHAIBuildableStructure* AttackedStructure = AITAC_FindClosestDeployableToLocation(CommChairLocation, &AttackedStructureFilter);
AvHAIBuildableStructure AttackedStructure = AITAC_FindClosestDeployableToLocation(CommChairLocation, &AttackedStructureFilter);
if (AttackedStructure)
if (AttackedStructure.IsValid())
{
AITASK_SetDefendTask(pBot, Task, AttackedStructure->edict, true);
AITASK_SetDefendTask(pBot, Task, AttackedStructure.edict, true);
return;
}
@ -3239,11 +3239,11 @@ void AIPlayerSetMarineSweeperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
{
AttackedStructureFilter.IncludeStatusFlags = STRUCTURE_STATUS_DAMAGED;
AvHAIBuildableStructure* AttackedStructure = AITAC_FindClosestDeployableToLocation(CommChairLocation, &AttackedStructureFilter);
AvHAIBuildableStructure AttackedStructure = AITAC_FindClosestDeployableToLocation(CommChairLocation, &AttackedStructureFilter);
if (AttackedStructure)
if (AttackedStructure.IsValid())
{
AITASK_SetWeldTask(pBot, Task, AttackedStructure->edict, true);
AITASK_SetWeldTask(pBot, Task, AttackedStructure.edict, true);
return;
}
}
@ -3265,34 +3265,34 @@ void AIPlayerSetMarineSweeperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
return;
}
AvHAIBuildableStructure* NearestPG = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &StructureFilter);
AvHAIBuildableStructure NearestPG = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &StructureFilter);
vector<AvHAIBuildableStructure*> AllPG = AITAC_FindAllDeployables(pBot->Edict->v.origin, &StructureFilter);
vector<AvHAIBuildableStructure> AllPG = AITAC_FindAllDeployables(pBot->Edict->v.origin, &StructureFilter);
AvHAIBuildableStructure* RandomPG = nullptr;
AvHAIBuildableStructure RandomPG;
int HighestRand = 0;
for (auto it = AllPG.begin(); it != AllPG.end(); it++)
{
AvHAIBuildableStructure* ThisStruct = (*it);
AvHAIBuildableStructure ThisStruct = (*it);
if (ThisStruct == NearestPG) { continue; }
if (ThisStruct.edict == NearestPG.edict) { continue; }
int ThisRand = irandrange(0, 100);
if (!RandomPG || ThisRand > HighestRand)
if (FNullEnt(RandomPG.edict) || ThisRand > HighestRand)
{
RandomPG = ThisStruct;
HighestRand = ThisRand;
}
}
if (RandomPG)
if (RandomPG.IsValid())
{
if (Task->TaskType != TASK_GUARD)
{
Task->TaskType = TASK_GUARD;
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(pBot->BotNavInfo.NavProfile, RandomPG->Location, UTIL_MetresToGoldSrcUnits(5.0f));
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(pBot->BotNavInfo.NavProfile, RandomPG.Location, UTIL_MetresToGoldSrcUnits(5.0f));
Task->bTaskIsUrgent = false;
Task->TaskLength = frandrange(20.0f, 30.0f);
}
@ -3481,15 +3481,15 @@ void AIPlayerSetWantsAndNeedsCOMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Ta
NearestArmouryFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
NearestArmouryFilter.MaxSearchRadius = SearchRadius;
AvHAIBuildableStructure* NearestArmoury = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &NearestArmouryFilter);
AvHAIBuildableStructure NearestArmoury = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &NearestArmouryFilter);
// We really need some health or ammo, hit the armoury
if (NearestArmoury)
if (NearestArmoury.IsValid())
{
Task->TaskType = TASK_RESUPPLY;
Task->bTaskIsUrgent = true;
Task->TaskLocation = NearestArmoury->Location;
Task->TaskTarget = NearestArmoury->edict;
Task->TaskLocation = NearestArmoury.Location;
Task->TaskTarget = NearestArmoury.edict;
return;
}
}
@ -3540,15 +3540,15 @@ void AIPlayerSetWantsAndNeedsMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
NearestArmouryFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
NearestArmouryFilter.MaxSearchRadius = (bTaskIsUrgent) ? UTIL_MetresToGoldSrcUnits(20.0f) : UTIL_MetresToGoldSrcUnits(5.0f);
AvHAIBuildableStructure* NearestArmoury = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &NearestArmouryFilter);
AvHAIBuildableStructure NearestArmoury = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &NearestArmouryFilter);
// We really need some health or ammo, either hit the armoury, or ask for a resupply
if (NearestArmoury)
if (NearestArmoury.IsValid())
{
Task->TaskType = TASK_RESUPPLY;
Task->bTaskIsUrgent = true;
Task->TaskLocation = NearestArmoury->Location;
Task->TaskTarget = NearestArmoury->edict;
Task->TaskLocation = NearestArmoury.Location;
Task->TaskTarget = NearestArmoury.edict;
return;
}
else
@ -3758,24 +3758,24 @@ void AIPlayerSetSecondaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (pBot->DangerTurrets.size() > 0)
{
AvHAIBuildableStructure* NearestDangerTurret = nullptr;
AvHAIBuildableStructure NearestDangerTurret;
float MinDist = 0.0f;
for (auto it = pBot->DangerTurrets.begin(); it != pBot->DangerTurrets.end(); it++)
{
float ThisDist = vDist2DSq(pBot->Edict->v.origin, (*it)->Location);
float ThisDist = vDist2DSq(pBot->Edict->v.origin, (*it).Location);
if (!NearestDangerTurret || ThisDist < MinDist)
if (FNullEnt(NearestDangerTurret.edict) || ThisDist < MinDist)
{
NearestDangerTurret = (*it);
}
}
if (NearestDangerTurret)
if (NearestDangerTurret.IsValid())
{
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_ALIEN)
{
AITASK_SetAttackTask(pBot, Task, NearestDangerTurret->edict, true);
AITASK_SetAttackTask(pBot, Task, NearestDangerTurret.edict, true);
return;
}
else
@ -3789,16 +3789,16 @@ void AIPlayerSetSecondaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
EnemyTFFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
EnemyTFFilter.ReachabilityTeam = BotTeam;
AvHAIBuildableStructure* EnemyTF = AITAC_FindClosestDeployableToLocation(NearestDangerTurret->Location, &EnemyTFFilter);
AvHAIBuildableStructure EnemyTF = AITAC_FindClosestDeployableToLocation(NearestDangerTurret.Location, &EnemyTFFilter);
if (EnemyTF)
if (EnemyTF.IsValid())
{
AITASK_SetAttackTask(pBot, Task, EnemyTF->edict, true);
AITASK_SetAttackTask(pBot, Task, EnemyTF.edict, true);
return;
}
else
{
AITASK_SetAttackTask(pBot, Task, NearestDangerTurret->edict, true);
AITASK_SetAttackTask(pBot, Task, NearestDangerTurret.edict, true);
return;
}
}
@ -3814,39 +3814,39 @@ void AIPlayerSetSecondaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
UnbuiltFilter.ExcludeStatusFlags = (STRUCTURE_STATUS_RECYCLING | STRUCTURE_STATUS_COMPLETED);
UnbuiltFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f);
AvHAIBuildableStructure* UnbuiltIP = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &UnbuiltFilter);
AvHAIBuildableStructure UnbuiltIP = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &UnbuiltFilter);
if (UnbuiltIP)
if (UnbuiltIP.IsValid())
{
float ThisDist = vDist2D(UnbuiltIP->Location, pBot->Edict->v.origin);
int NumBuilders = AITAC_GetNumPlayersOfTeamInArea(BotTeam, UnbuiltIP->Location, ThisDist - 5.0f, false, pBot->Edict, AVH_USER3_COMMANDER_PLAYER);
float ThisDist = vDist2D(UnbuiltIP.Location, pBot->Edict->v.origin);
int NumBuilders = AITAC_GetNumPlayersOfTeamInArea(BotTeam, UnbuiltIP.Location, ThisDist - 5.0f, false, pBot->Edict, AVH_USER3_COMMANDER_PLAYER);
if (NumBuilders < 1)
{
AITASK_SetBuildTask(pBot, Task, UnbuiltIP->edict, true);
AITASK_SetBuildTask(pBot, Task, UnbuiltIP.edict, true);
return;
}
}
UnbuiltFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
vector <AvHAIBuildableStructure*> BuildableStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &UnbuiltFilter);
vector<AvHAIBuildableStructure> BuildableStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &UnbuiltFilter);
AvHAIBuildableStructure* NearestStructure = nullptr;
AvHAIBuildableStructure NearestStructure;
float MinDist = 0.0f;
for (auto it = BuildableStructures.begin(); it != BuildableStructures.end(); it++)
{
float ThisDist = vDist2D((*it)->Location, pBot->Edict->v.origin);
float ThisDist = vDist2D((*it).Location, pBot->Edict->v.origin);
int NumBuilders = AITAC_GetNumPlayersOfTeamInArea(BotTeam, (*it)->Location, ThisDist - 5.0f, false, pBot->Edict, AVH_USER3_COMMANDER_PLAYER);
int NumBuilders = AITAC_GetNumPlayersOfTeamInArea(BotTeam, (*it).Location, ThisDist - 5.0f, false, pBot->Edict, AVH_USER3_COMMANDER_PLAYER);
// Two builders if we're not in the marine base, one to guard and keep lookout while the other builds
int NumDesiredBuilders = (vDist2DSq((*it)->Location, AITAC_GetCommChairLocation(BotTeam)) < sqrf(UTIL_MetresToGoldSrcUnits(15.0f))) ? 1 : 2;
int NumDesiredBuilders = (vDist2DSq((*it).Location, AITAC_GetCommChairLocation(BotTeam)) < sqrf(UTIL_MetresToGoldSrcUnits(15.0f))) ? 1 : 2;
if (NumBuilders < NumDesiredBuilders)
{
if (!NearestStructure || ThisDist < MinDist)
if (FNullEnt(NearestStructure.edict) || ThisDist < MinDist)
{
NearestStructure = (*it);
MinDist = ThisDist;
@ -3854,9 +3854,9 @@ void AIPlayerSetSecondaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
}
if (NearestStructure)
if (NearestStructure.IsValid())
{
AITASK_SetBuildTask(pBot, Task, NearestStructure->edict, true);
AITASK_SetBuildTask(pBot, Task, NearestStructure.edict, true);
return;
}
@ -3920,13 +3920,13 @@ void AIPlayerSetSecondaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
WeldableStructures.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f);
WeldableStructures.bConsiderPhaseDistance = true;
AvHAIBuildableStructure* NearestDamagedStructure = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &WeldableStructures);
AvHAIBuildableStructure NearestDamagedStructure = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &WeldableStructures);
if (NearestDamagedStructure)
if (NearestDamagedStructure.IsValid())
{
bool bIsUrgent = (NearestDamagedStructure->healthPercent < 0.5f);
bool bIsUrgent = (NearestDamagedStructure.healthPercent < 0.5f);
AITASK_SetWeldTask(pBot, Task, NearestDamagedStructure->edict, bIsUrgent);
AITASK_SetWeldTask(pBot, Task, NearestDamagedStructure.edict, bIsUrgent);
return;
}
@ -3952,8 +3952,8 @@ void AIPlayerSetSecondaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
MineableStructures.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f);
MineableStructures.bConsiderPhaseDistance = true;
vector<AvHAIBuildableStructure*> AllMineableStructures = AITAC_FindAllDeployables(AITAC_GetTeamStartingLocation(BotTeam), &MineableStructures);
AvHAIBuildableStructure* StructureToMine = nullptr;
vector<AvHAIBuildableStructure> AllMineableStructures = AITAC_FindAllDeployables(AITAC_GetTeamStartingLocation(BotTeam), &MineableStructures);
AvHAIBuildableStructure StructureToMine;
DeployableSearchFilter MineFilter;
MineFilter.DeployableTypes = STRUCTURE_MARINE_DEPLOYEDMINE;
@ -3964,15 +3964,15 @@ void AIPlayerSetSecondaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
for (auto it = AllMineableStructures.begin(); it != AllMineableStructures.end(); it++)
{
AvHAIBuildableStructure* ThisStructure = (*it);
AvHAIBuildableStructure ThisStructure = (*it);
int NumMines = AITAC_GetNumDeployablesNearLocation(ThisStructure->Location, &MineFilter);
int NumMines = AITAC_GetNumDeployablesNearLocation(ThisStructure.Location, &MineFilter);
if (NumMines < 4)
{
float ThisDist = AITAC_GetPhaseDistanceBetweenPoints(ThisStructure->Location, AITAC_GetTeamStartingLocation(BotTeam));
float ThisDist = AITAC_GetPhaseDistanceBetweenPoints(ThisStructure.Location, AITAC_GetTeamStartingLocation(BotTeam));
if (!StructureToMine || ThisDist > FarDist)
if (FNullEnt(StructureToMine.edict) || ThisDist > FarDist)
{
StructureToMine = ThisStructure;
FarDist = ThisDist;
@ -3980,9 +3980,9 @@ void AIPlayerSetSecondaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
}
if (StructureToMine)
if (StructureToMine.IsValid())
{
AITASK_SetMineStructureTask(pBot, Task, StructureToMine->edict, true);
AITASK_SetMineStructureTask(pBot, Task, StructureToMine.edict, true);
}
}
@ -4509,11 +4509,11 @@ void AIPlayerSetPrimaryCOMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
EnemyStuffFilter.ReachabilityTeam = BotTeam;
EnemyStuffFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
AvHAIBuildableStructure* EnemyStructure = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &EnemyStuffFilter);
AvHAIBuildableStructure EnemyStructure = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &EnemyStuffFilter);
if (EnemyStructure)
if (EnemyStructure.IsValid())
{
AITASK_SetAttackTask(pBot, Task, EnemyStructure->edict, false);
AITASK_SetAttackTask(pBot, Task, EnemyStructure.edict, false);
return;
}
else
@ -4575,26 +4575,26 @@ void AIPlayerSetSecondaryCOMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
AttackedStructuresFilter.IncludeStatusFlags = STRUCTURE_STATUS_UNDERATTACK;
AttackedStructuresFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(30.0f);
vector<AvHAIBuildableStructure*> AllAttackedStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &AttackedStructuresFilter);
vector<AvHAIBuildableStructure> AllAttackedStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &AttackedStructuresFilter);
AvHAIBuildableStructure* StructureToDefend = nullptr;
AvHAIBuildableStructure StructureToDefend;
float MinDist = 0.0f;
for (auto it = AllAttackedStructures.begin(); it != AllAttackedStructures.end(); it++)
{
AvHAIBuildableStructure* ThisStructure = (*it);
AvHAIBuildableStructure ThisStructure = (*it);
float ThisDist = vDist2D(pBot->Edict->v.origin, ThisStructure->edict->v.origin);
float ThisDist = vDist2D(pBot->Edict->v.origin, ThisStructure.edict->v.origin);
int NumAttackers = AITAC_GetNumPlayersOnTeamWithLOS(EnemyTeam, ThisStructure->Location, UTIL_MetresToGoldSrcUnits(15.0f), nullptr);
int NumAttackers = AITAC_GetNumPlayersOnTeamWithLOS(EnemyTeam, ThisStructure.Location, UTIL_MetresToGoldSrcUnits(15.0f), nullptr);
if (NumAttackers == 0) { continue; }
int NumExistingDefenders = AITAC_GetNumPlayersOfTeamInArea(BotTeam, ThisStructure->Location, ThisDist - 10.0f, false, pBot->Edict, AVH_USER3_COMMANDER_PLAYER);
int NumExistingDefenders = AITAC_GetNumPlayersOfTeamInArea(BotTeam, ThisStructure.Location, ThisDist - 10.0f, false, pBot->Edict, AVH_USER3_COMMANDER_PLAYER);
if (NumExistingDefenders < 2)
{
if (!StructureToDefend || ThisDist < MinDist)
if (FNullEnt(StructureToDefend.edict) || ThisDist < MinDist)
{
StructureToDefend = ThisStructure;
MinDist = ThisDist;
@ -4602,9 +4602,9 @@ void AIPlayerSetSecondaryCOMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
}
if (StructureToDefend)
if (StructureToDefend.IsValid())
{
AITASK_SetDefendTask(pBot, Task, StructureToDefend->edict, true);
AITASK_SetDefendTask(pBot, Task, StructureToDefend.edict, true);
return;
}
@ -4618,33 +4618,33 @@ void AIPlayerSetSecondaryCOMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
DamagedStructuresFilter.IncludeStatusFlags = STRUCTURE_STATUS_DAMAGED;
DamagedStructuresFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f);
AvHAIBuildableStructure* StructureToRepair = nullptr;
vector<AvHAIBuildableStructure*> AllDamagedStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &DamagedStructuresFilter);
AvHAIBuildableStructure StructureToRepair;
vector<AvHAIBuildableStructure> AllDamagedStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &DamagedStructuresFilter);
MinDist = 0.0f;
for (auto it = AllDamagedStructures.begin(); it != AllDamagedStructures.end(); it++)
{
AvHAIBuildableStructure* ThisStructure = (*it);
AvHAIBuildableStructure ThisStructure = (*it);
if (ThisStructure->StructureType == STRUCTURE_MARINE_COMMCHAIR && ThisStructure->healthPercent < 0.7f)
if (ThisStructure.StructureType == STRUCTURE_MARINE_COMMCHAIR && ThisStructure.healthPercent < 0.7f)
{
StructureToRepair = ThisStructure;
break;
}
float ThisDist = vDist2DSq(ThisStructure->Location, pBot->Edict->v.origin);
float ThisDist = vDist2DSq(ThisStructure.Location, pBot->Edict->v.origin);
if (!StructureToRepair || ThisDist < MinDist)
if (FNullEnt(StructureToRepair.edict) || ThisDist < MinDist)
{
StructureToRepair = ThisStructure;
MinDist = ThisDist;
}
}
if (StructureToRepair)
if (StructureToRepair.IsValid())
{
AITASK_SetWeldTask(pBot, Task, StructureToRepair->edict, true);
AITASK_SetWeldTask(pBot, Task, StructureToRepair.edict, true);
return;
}
@ -4654,17 +4654,17 @@ void AIPlayerSetSecondaryCOMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
NearbyArmouryFilter.ReachabilityTeam = BotTeam;
NearbyArmouryFilter.ReachabilityFlags = AI_REACHABILITY_MARINE;
AvHAIBuildableStructure* NearestEasyAccessArmoury = AITAC_FindClosestDeployableToLocation(ZERO_VECTOR, &NearbyArmouryFilter);
AvHAIBuildableStructure NearestEasyAccessArmoury = AITAC_FindClosestDeployableToLocation(ZERO_VECTOR, &NearbyArmouryFilter);
if (!NearestEasyAccessArmoury)
if (!NearestEasyAccessArmoury.IsValid())
{
NearbyArmouryFilter.ReachabilityFlags = AI_REACHABILITY_WELDER;
AvHAIBuildableStructure* NearestWeldableAccessArmoury = AITAC_FindClosestDeployableToLocation(ZERO_VECTOR, &NearbyArmouryFilter);
AvHAIBuildableStructure NearestWeldableAccessArmoury = AITAC_FindClosestDeployableToLocation(ZERO_VECTOR, &NearbyArmouryFilter);
if (NearestWeldableAccessArmoury)
if (NearestWeldableAccessArmoury.IsValid())
{
AITASK_SetMoveTask(pBot, Task, NearestWeldableAccessArmoury->Location, true);
AITASK_SetMoveTask(pBot, Task, NearestWeldableAccessArmoury.Location, true);
return;
}
}
@ -4769,11 +4769,11 @@ void AIPlayerSetPrimaryCOAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
EnemyStuffFilter.ReachabilityTeam = BotTeam;
EnemyStuffFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
AvHAIBuildableStructure* EnemyStructure = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &EnemyStuffFilter);
AvHAIBuildableStructure EnemyStructure = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &EnemyStuffFilter);
if (EnemyStructure)
if (EnemyStructure.IsValid())
{
AITASK_SetAttackTask(pBot, Task, EnemyStructure->edict, false);
AITASK_SetAttackTask(pBot, Task, EnemyStructure.edict, false);
return;
}
@ -5296,7 +5296,7 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
ExistingReinforcementFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
ExistingReinforcementFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
vector<AvHAIBuildableStructure*> AllReinforcingStructures = AITAC_FindAllDeployables(ThisHive->FloorLocation, &ExistingReinforcementFilter);
vector<AvHAIBuildableStructure> AllReinforcingStructures = AITAC_FindAllDeployables(ThisHive->FloorLocation, &ExistingReinforcementFilter);
int NumOCs = 0;
int NumDCs = 0;
@ -5305,7 +5305,7 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
for (auto it = AllReinforcingStructures.begin(); it != AllReinforcingStructures.end(); it++)
{
switch ((*it)->StructureType)
switch ((*it).StructureType)
{
case STRUCTURE_ALIEN_OFFENCECHAMBER:
NumOCs++;
@ -5353,21 +5353,21 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
ResNodeFilter.ReachabilityTeam = BotTeam;
ResNodeFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
vector<AvHAIBuildableStructure*> AllMatchingTowers = AITAC_FindAllDeployables(pBot->Edict->v.origin, &ResNodeFilter);
vector<AvHAIBuildableStructure> AllMatchingTowers = AITAC_FindAllDeployables(pBot->Edict->v.origin, &ResNodeFilter);
edict_t* TowerToReinforce = nullptr;
MinDist = 0.0f;
for (auto it = AllMatchingTowers.begin(); it != AllMatchingTowers.end(); it++)
{
AvHAIBuildableStructure* ThisResTower = (*it);
AvHAIBuildableStructure ThisResTower = (*it);
DeployableSearchFilter ExistingReinforcementFilter;
ExistingReinforcementFilter.DeployableTeam = BotTeam;
ExistingReinforcementFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
ExistingReinforcementFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
vector<AvHAIBuildableStructure*> AllReinforcingStructures = AITAC_FindAllDeployables(ThisResTower->Location, &ExistingReinforcementFilter);
vector<AvHAIBuildableStructure> AllReinforcingStructures = AITAC_FindAllDeployables(ThisResTower.Location, &ExistingReinforcementFilter);
int NumOCs = 0;
int NumDCs = 0;
@ -5376,7 +5376,7 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
for (auto it = AllReinforcingStructures.begin(); it != AllReinforcingStructures.end(); it++)
{
switch ((*it)->StructureType)
switch ((*it).StructureType)
{
case STRUCTURE_ALIEN_OFFENCECHAMBER:
NumOCs++;
@ -5400,11 +5400,11 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|| (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_MOVEMENT_CHAMBER) && NumMCs < 1)
|| (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_SENSORY_CHAMBER) && NumSCs < 1))
{
float ThisDist = vDist2DSq(AITAC_GetTeamStartingLocation(EnemyTeam), ThisResTower->Location);
float ThisDist = vDist2DSq(AITAC_GetTeamStartingLocation(EnemyTeam), ThisResTower.Location);
if (!TowerToReinforce || ThisDist < MinDist)
{
TowerToReinforce = ThisResTower->edict;
TowerToReinforce = ThisResTower.edict;
MinDist = ThisDist;
}
}
@ -5679,49 +5679,49 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
EnemyStuffFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
EnemyStuffFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(25.0f);
vector<AvHAIBuildableStructure*> AllSiegingStructures = AITAC_FindAllDeployables(NearestSiegedHive->Location, &EnemyStuffFilter);
vector<AvHAIBuildableStructure> AllSiegingStructures = AITAC_FindAllDeployables(NearestSiegedHive->Location, &EnemyStuffFilter);
AvHAIBuildableStructure* StructureToTarget = nullptr;
AvHAIBuildableStructure StructureToTarget;
float MinDist = 0.0f;
for (auto it = AllSiegingStructures.begin(); it != AllSiegingStructures.end(); it++)
{
AvHAIBuildableStructure* ThisStructure = (*it);
AvHAIBuildableStructure ThisStructure = (*it);
// Always go for the phase gate first to prevent reinforcements
if (ThisStructure->StructureType == STRUCTURE_MARINE_PHASEGATE)
if (ThisStructure.StructureType == STRUCTURE_MARINE_PHASEGATE)
{
StructureToTarget = ThisStructure;
continue;
}
// Then go for any turret factories, especially advanced ones to cut off siege turrets
if (ThisStructure->StructureType == STRUCTURE_MARINE_ADVTURRETFACTORY)
if (ThisStructure.StructureType == STRUCTURE_MARINE_ADVTURRETFACTORY)
{
StructureToTarget = ThisStructure;
continue;
}
if (ThisStructure->StructureType == STRUCTURE_MARINE_TURRETFACTORY)
if (ThisStructure.StructureType == STRUCTURE_MARINE_TURRETFACTORY)
{
StructureToTarget = ThisStructure;
continue;
}
// Pick up anything else
float ThisDist = vDist2DSq(ThisStructure->Location, pBot->Edict->v.origin);
float ThisDist = vDist2DSq(ThisStructure.Location, pBot->Edict->v.origin);
if (!StructureToTarget || ThisDist < MinDist)
if (FNullEnt(StructureToTarget.edict) || ThisDist < MinDist)
{
StructureToTarget = ThisStructure;
MinDist = ThisDist;
}
}
if (StructureToTarget)
if (StructureToTarget.IsValid())
{
AITASK_SetAttackTask(pBot, Task, StructureToTarget->edict, true);
AITASK_SetAttackTask(pBot, Task, StructureToTarget.edict, true);
return;
}
}
@ -5751,53 +5751,53 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
EnemyStuffFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
EnemyStuffFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(25.0f);
vector<AvHAIBuildableStructure*> AllSiegingStructures = AITAC_FindAllDeployables(ThisHive->Location, &EnemyStuffFilter);
vector<AvHAIBuildableStructure> AllSiegingStructures = AITAC_FindAllDeployables(ThisHive->Location, &EnemyStuffFilter);
AvHAIBuildableStructure* StructureToTarget = nullptr;
AvHAIBuildableStructure StructureToTarget;
float MinDist = 0.0f;
for (auto it = AllSiegingStructures.begin(); it != AllSiegingStructures.end(); it++)
{
AvHAIBuildableStructure* ThisStructure = (*it);
AvHAIBuildableStructure ThisStructure = (*it);
// Always go for the phase gate first to prevent reinforcements
if (ThisStructure->StructureType == STRUCTURE_MARINE_PHASEGATE)
if (ThisStructure.StructureType == STRUCTURE_MARINE_PHASEGATE)
{
StructureToTarget = ThisStructure;
continue;
}
// Then go for any turret factories, especially advanced ones to cut off siege turrets
if (ThisStructure->StructureType == STRUCTURE_MARINE_ADVTURRETFACTORY)
if (ThisStructure.StructureType == STRUCTURE_MARINE_ADVTURRETFACTORY)
{
StructureToTarget = ThisStructure;
continue;
}
if (ThisStructure->StructureType == STRUCTURE_MARINE_TURRETFACTORY)
if (ThisStructure.StructureType == STRUCTURE_MARINE_TURRETFACTORY)
{
StructureToTarget = ThisStructure;
continue;
}
// Pick up anything else
float ThisDist = vDist2DSq(ThisStructure->Location, pBot->Edict->v.origin);
float ThisDist = vDist2DSq(ThisStructure.Location, pBot->Edict->v.origin);
if (!StructureToTarget || ThisDist < MinDist)
if (FNullEnt(StructureToTarget.edict) || ThisDist < MinDist)
{
StructureToTarget = ThisStructure;
MinDist = ThisDist;
}
}
if (StructureToTarget)
if (StructureToTarget.IsValid())
{
int NumAttackers = AITAC_GetNumPlayersOfTeamInArea(BotTeam, StructureToTarget->Location, UTIL_MetresToGoldSrcUnits(10.0f), false, pBot->Edict, AVH_USER3_ALIEN_PLAYER2);
int NumAttackers = AITAC_GetNumPlayersOfTeamInArea(BotTeam, StructureToTarget.Location, UTIL_MetresToGoldSrcUnits(10.0f), false, pBot->Edict, AVH_USER3_ALIEN_PLAYER2);
if (NumAttackers < 2)
{
AITASK_SetAttackTask(pBot, Task, StructureToTarget->edict, true);
AITASK_SetAttackTask(pBot, Task, StructureToTarget.edict, true);
return;
}
}
@ -5949,48 +5949,48 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
EnemyStuffFilter.ExcludeStatusFlags = STRUCTURE_STATUS_ELECTRIFIED;
}
vector<AvHAIBuildableStructure*> AllEnemyThings = AITAC_FindAllDeployables(HiveToSecure->FloorLocation, &EnemyStuffFilter);
vector<AvHAIBuildableStructure> AllEnemyThings = AITAC_FindAllDeployables(HiveToSecure->FloorLocation, &EnemyStuffFilter);
AvHAIBuildableStructure* StructureToAttack = nullptr;
AvHAIBuildableStructure StructureToAttack;
for (auto it = AllEnemyThings.begin(); it != AllEnemyThings.end(); it++)
{
AvHAIBuildableStructure* ThisStructure = (*it);
AvHAIBuildableStructure ThisStructure = (*it);
// First prioritise phase gates or alien OCs
if (ThisStructure->StructureType == STRUCTURE_MARINE_PHASEGATE || ThisStructure->StructureType == STRUCTURE_ALIEN_OFFENCECHAMBER)
if (ThisStructure.StructureType == STRUCTURE_MARINE_PHASEGATE || ThisStructure.StructureType == STRUCTURE_ALIEN_OFFENCECHAMBER)
{
if (!StructureToAttack || StructureToAttack->StructureType != ThisStructure->StructureType || vDist2DSq(pBot->Edict->v.origin, ThisStructure->Location) < vDist2DSq(pBot->Edict->v.origin, StructureToAttack->Location))
if (FNullEnt(StructureToAttack.edict) || StructureToAttack.StructureType != ThisStructure.StructureType || vDist2DSq(pBot->Edict->v.origin, ThisStructure.Location) < vDist2DSq(pBot->Edict->v.origin, StructureToAttack.Location))
{
StructureToAttack = ThisStructure;
continue;
}
}
if (StructureToAttack && (StructureToAttack->StructureType == STRUCTURE_MARINE_PHASEGATE || ThisStructure->StructureType == STRUCTURE_ALIEN_OFFENCECHAMBER)) { continue; }
if (!FNullEnt(StructureToAttack.edict) && (StructureToAttack.StructureType == STRUCTURE_MARINE_PHASEGATE || ThisStructure.StructureType == STRUCTURE_ALIEN_OFFENCECHAMBER)) { continue; }
// Then prioritise turret factories
if (ThisStructure->StructureType == STRUCTURE_MARINE_TURRETFACTORY || ThisStructure->StructureType == STRUCTURE_MARINE_ADVTURRETFACTORY)
if (ThisStructure.StructureType == STRUCTURE_MARINE_TURRETFACTORY || ThisStructure.StructureType == STRUCTURE_MARINE_ADVTURRETFACTORY)
{
if (!StructureToAttack || StructureToAttack->StructureType != ThisStructure->StructureType || vDist2DSq(pBot->Edict->v.origin, ThisStructure->Location) < vDist2DSq(pBot->Edict->v.origin, StructureToAttack->Location))
if (FNullEnt(StructureToAttack.edict) || StructureToAttack.StructureType != ThisStructure.StructureType || vDist2DSq(pBot->Edict->v.origin, ThisStructure.Location) < vDist2DSq(pBot->Edict->v.origin, StructureToAttack.Location))
{
StructureToAttack = ThisStructure;
continue;
}
}
if (StructureToAttack && (StructureToAttack->StructureType == STRUCTURE_MARINE_TURRETFACTORY || ThisStructure->StructureType == STRUCTURE_MARINE_ADVTURRETFACTORY)) { continue; }
if (!FNullEnt(StructureToAttack.edict) && (StructureToAttack.StructureType == STRUCTURE_MARINE_TURRETFACTORY || ThisStructure.StructureType == STRUCTURE_MARINE_ADVTURRETFACTORY)) { continue; }
// Then target any other structures
if (!StructureToAttack || vDist2DSq(pBot->Edict->v.origin, ThisStructure->Location) < vDist2DSq(pBot->Edict->v.origin, StructureToAttack->Location))
if (FNullEnt(StructureToAttack.edict) || vDist2DSq(pBot->Edict->v.origin, ThisStructure.Location) < vDist2DSq(pBot->Edict->v.origin, StructureToAttack.Location))
{
StructureToAttack = ThisStructure;
}
}
if (StructureToAttack)
if (StructureToAttack.IsValid())
{
AITASK_SetAttackTask(pBot, Task, StructureToAttack->edict, false);
AITASK_SetAttackTask(pBot, Task, StructureToAttack.edict, false);
return;
}
}
@ -6003,11 +6003,11 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
EnemyInfPortalFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
EnemyInfPortalFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
AvHAIBuildableStructure* EnemyInfPortal = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &EnemyInfPortalFilter);
AvHAIBuildableStructure EnemyInfPortal = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &EnemyInfPortalFilter);
if (EnemyInfPortal)
if (EnemyInfPortal.IsValid())
{
AITASK_SetAttackTask(pBot, Task, EnemyInfPortal->edict, false);
AITASK_SetAttackTask(pBot, Task, EnemyInfPortal.edict, false);
return;
}
@ -6109,7 +6109,7 @@ void AIPlayerSetAlienHarasserPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
Vector EnemyBaseLocation = AITAC_GetTeamStartingLocation(EnemyTeam);
AvHAIBuildableStructure* EnemyStructureToAttack = nullptr;
AvHAIBuildableStructure EnemyStructureToAttack;
bool bEnemyIsMarines = (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_MARINE);
@ -6125,9 +6125,9 @@ void AIPlayerSetAlienHarasserPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
EnemyStructureToAttack = AITAC_FindClosestDeployableToLocation(EnemyBaseLocation, &EnemyStructureFilter);
}
if (EnemyStructureToAttack)
if (EnemyStructureToAttack.IsValid())
{
AITASK_SetAttackTask(pBot, Task, EnemyStructureToAttack->edict, false);
AITASK_SetAttackTask(pBot, Task, EnemyStructureToAttack.edict, false);
return;
}
@ -6188,24 +6188,24 @@ void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (pBot->DangerTurrets.size() > 0)
{
AvHAIBuildableStructure* NearestDangerTurret = nullptr;
AvHAIBuildableStructure NearestDangerTurret;
float MinDist = 0.0f;
for (auto it = pBot->DangerTurrets.begin(); it != pBot->DangerTurrets.end(); it++)
{
float ThisDist = vDist2DSq(pBot->Edict->v.origin, (*it)->Location);
float ThisDist = vDist2DSq(pBot->Edict->v.origin, (*it).Location);
if (!NearestDangerTurret || ThisDist < MinDist)
if (FNullEnt(NearestDangerTurret.edict) || ThisDist < MinDist)
{
NearestDangerTurret = (*it);
}
}
if (NearestDangerTurret)
if (NearestDangerTurret.IsValid())
{
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_ALIEN)
{
AITASK_SetAttackTask(pBot, Task, NearestDangerTurret->edict, true);
AITASK_SetAttackTask(pBot, Task, NearestDangerTurret.edict, true);
return;
}
else
@ -6224,16 +6224,16 @@ void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
EnemyTFFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
EnemyTFFilter.ReachabilityTeam = BotTeam;
AvHAIBuildableStructure* EnemyTF = AITAC_FindClosestDeployableToLocation(NearestDangerTurret->Location, &EnemyTFFilter);
AvHAIBuildableStructure EnemyTF = AITAC_FindClosestDeployableToLocation(NearestDangerTurret.Location, &EnemyTFFilter);
if (EnemyTF)
if (EnemyTF.IsValid())
{
AITASK_SetAttackTask(pBot, Task, EnemyTF->edict, true);
AITASK_SetAttackTask(pBot, Task, EnemyTF.edict, true);
return;
}
else
{
AITASK_SetAttackTask(pBot, Task, NearestDangerTurret->edict, true);
AITASK_SetAttackTask(pBot, Task, NearestDangerTurret.edict, true);
return;
}
}
@ -6278,7 +6278,7 @@ void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
DamagedStructuresFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
DamagedStructuresFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
vector<AvHAIBuildableStructure*> AllNearbyStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &DamagedStructuresFilter);
vector<AvHAIBuildableStructure> AllNearbyStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &DamagedStructuresFilter);
edict_t* StructureToHeal = nullptr;
@ -6286,14 +6286,14 @@ void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
for (auto it = AllNearbyStructures.begin(); it != AllNearbyStructures.end(); it++)
{
AvHAIBuildableStructure* ThisStructure = (*it);
AvHAIBuildableStructure ThisStructure = (*it);
if (ThisStructure && ThisStructure->healthPercent < 0.99f)
if (!FNullEnt(ThisStructure.edict) && ThisStructure.healthPercent < 0.99f)
{
float ThisDist = vDist2DSq(pBot->Edict->v.origin, ThisStructure->Location);
float ThisDist = vDist2DSq(pBot->Edict->v.origin, ThisStructure.Location);
if (FNullEnt(StructureToHeal) || ThisDist < MinDist)
{
StructureToHeal = ThisStructure->edict;
StructureToHeal = ThisStructure.edict;
MinDist = ThisDist;
}
}
@ -6429,26 +6429,26 @@ void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
AttackedStructuresFilter.IncludeStatusFlags = STRUCTURE_STATUS_UNDERATTACK;
AttackedStructuresFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(30.0f);
vector<AvHAIBuildableStructure*> AllAttackedStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &AttackedStructuresFilter);
vector<AvHAIBuildableStructure> AllAttackedStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &AttackedStructuresFilter);
AvHAIBuildableStructure* StructureToDefend = nullptr;
AvHAIBuildableStructure StructureToDefend;
MinDist = 0.0f;
for (auto it = AllAttackedStructures.begin(); it != AllAttackedStructures.end(); it++)
{
AvHAIBuildableStructure* ThisStructure = (*it);
AvHAIBuildableStructure ThisStructure = (*it);
float ThisDist = vDist2D(pBot->Edict->v.origin, ThisStructure->edict->v.origin);
float ThisDist = vDist2D(pBot->Edict->v.origin, ThisStructure.edict->v.origin);
int NumAttackers = AITAC_GetNumPlayersOnTeamWithLOS(EnemyTeam, ThisStructure->Location, UTIL_MetresToGoldSrcUnits(15.0f), nullptr);
int NumAttackers = AITAC_GetNumPlayersOnTeamWithLOS(EnemyTeam, ThisStructure.Location, UTIL_MetresToGoldSrcUnits(15.0f), nullptr);
if (NumAttackers == 0) { continue; }
int NumExistingDefenders = AITAC_GetNumPlayersOfTeamInArea(BotTeam, ThisStructure->Location, ThisDist - 10.0f, false, pBot->Edict, AVH_USER3_ALIEN_PLAYER2);
int NumExistingDefenders = AITAC_GetNumPlayersOfTeamInArea(BotTeam, ThisStructure.Location, ThisDist - 10.0f, false, pBot->Edict, AVH_USER3_ALIEN_PLAYER2);
if (NumExistingDefenders < 2)
{
if (!StructureToDefend || ThisDist < MinDist)
if (FNullEnt(StructureToDefend.edict) || ThisDist < MinDist)
{
StructureToDefend = ThisStructure;
MinDist = ThisDist;
@ -6456,9 +6456,9 @@ void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
}
if (StructureToDefend)
if (StructureToDefend.IsValid())
{
AITASK_SetDefendTask(pBot, Task, StructureToDefend->edict, true);
AITASK_SetDefendTask(pBot, Task, StructureToDefend.edict, true);
return;
}

View file

@ -1046,8 +1046,7 @@ void AIMGR_NewMap()
AIStartedTime = gpGlobals->time;
LastAIPlayerCountUpdate = 0.0f;
ALERT(at_console, "AI Manager New Map\n");
AITAC_ClearMapAIData(true);
if (NavmeshLoaded())
@ -1057,13 +1056,6 @@ void AIMGR_NewMap()
CONFIG_ParseConfigFile();
const char* theCStrLevelName = STRING(gpGlobals->mapname);
if (!loadNavigationData(theCStrLevelName))
{
return;
}
AIMGR_BotPrecache();
bHasRoundStarted = false;
@ -1071,6 +1063,19 @@ void AIMGR_NewMap()
bPlayerSpawned = false;
}
void AIMGR_LoadNavigationData()
{
// Don't reload the nav mesh if it's already loaded
if (NavmeshLoaded()) { return; }
const char* theCStrLevelName = STRING(gpGlobals->mapname);
if (!loadNavigationData(theCStrLevelName))
{
ALERT(at_console, "Failed to load navigation data for %s\n");
}
}
AvHAIPlayer* AIMGR_GetAICommander(AvHTeamNumber Team)
{
AvHPlayer* ActiveCommander = GetGameRules()->GetTeam(Team)->GetCommanderPlayer();

View file

@ -68,6 +68,7 @@ int AIMGR_GetNumAIPlayersWithRoleOnTeam(AvHTeamNumber Team, AvHAIBotRole Role, A
int AIMGR_GetNumHumansOfClassOnTeam(AvHTeamNumber Team, AvHUser3 PlayerType);
void AIMGR_LoadNavigationData();
void AIMGR_ReloadNavigationData();
AvHAIPlayer* AIMGR_GetAICommander(AvHTeamNumber Team);

View file

@ -1153,7 +1153,6 @@ void AIPlayer_Say(edict_t* pEntity, int teamonly, const char* Msg)
int j;
char* p;
char text[256];
char szTemp[256];
bool theTalkerInReadyRoom = theTalkingPlayer->GetInReadyRoom();
// We can get a raw string now, without the "say " prepended

View file

@ -66,13 +66,97 @@ edict_t* LastSeenLerkTeamB = nullptr; // Track who went lerk on team B last time
float LastSeenLerkTeamATime = 0.0f;
float LastSeenLerkTeamBTime = 0.0f;
std::vector<AvHAIBuildableStructure*> AITAC_FindAllDeployables(const Vector& Location, const DeployableSearchFilter* Filter)
std::vector<AvHAIBuildableStructure> AITAC_FindAllDeployables(const Vector& Location, const DeployableSearchFilter* Filter)
{
std::vector<AvHAIBuildableStructure> Result;
AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber();
AvHTeamNumber TeamB = GetGameRules()->GetTeamBNumber();
float CurrMinDist = 0.0f;
float MinDistSq = sqrf(Filter->MinSearchRadius);
float MaxDistSq = sqrf(Filter->MaxSearchRadius);
bool bUseMinDist = MinDistSq > 0.1f;
bool bUseMaxDist = MaxDistSq > 0.1f;
if (Filter->DeployableTeam == TeamA || Filter->DeployableTeam == TEAM_IND)
{
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 (Filter->ReachabilityFlags != AI_REACHABILITY_NONE)
{
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (!(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
}
if (it.second.StructureType & Filter->DeployableTypes)
{
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq))
{
Result.push_back(it.second);
}
}
}
}
if (Filter->DeployableTeam == TeamB || Filter->DeployableTeam == TEAM_IND)
{
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 (Filter->ReachabilityFlags != AI_REACHABILITY_NONE)
{
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (!(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
}
if (it.second.StructureType & Filter->DeployableTypes)
{
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq))
{
Result.push_back(it.second);
}
}
}
}
return Result;
}
std::vector<AvHAIBuildableStructure*> AITAC_FindAllDeployablesByRef(const Vector& Location, const DeployableSearchFilter* Filter)
{
std::vector<AvHAIBuildableStructure*> Result;
AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber();
AvHTeamNumber TeamB = GetGameRules()->GetTeamBNumber();
float CurrMinDist = 0.0f;
float MinDistSq = sqrf(Filter->MinSearchRadius);
@ -224,7 +308,82 @@ bool AITAC_DeployableExistsAtLocation(const Vector& Location, const DeployableSe
return false;
}
AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocation(const Vector& Location, const DeployableSearchFilter* Filter)
AvHAIBuildableStructure AITAC_FindClosestDeployableToLocation(const Vector& Location, const DeployableSearchFilter* Filter)
{
AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber();
AvHTeamNumber TeamB = GetGameRules()->GetTeamBNumber();
AvHAIBuildableStructure Result;
float CurrMinDist = 0.0f;
float MinDistSq = sqrf(Filter->MinSearchRadius);
float MaxDistSq = sqrf(Filter->MaxSearchRadius);
bool bUseMinDist = MinDistSq > 0.1f;
bool bUseMaxDist = MaxDistSq > 0.1f;
if (Filter->DeployableTeam == TeamA || Filter->DeployableTeam == TEAM_IND)
{
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; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && (FNullEnt(Result.edict) || DistSq < CurrMinDist))
{
Result = it.second;
CurrMinDist = DistSq;
}
}
}
if (Filter->DeployableTeam == TeamB || Filter->DeployableTeam == TEAM_IND)
{
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; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && (FNullEnt(Result.edict) || DistSq < CurrMinDist))
{
Result = it.second;
CurrMinDist = DistSq;
}
}
}
return Result;
}
AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocationByRef(const Vector& Location, const DeployableSearchFilter* Filter)
{
AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber();
AvHTeamNumber TeamB = GetGameRules()->GetTeamBNumber();
@ -299,12 +458,87 @@ AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocation(const Vector& Loc
return Result;
}
AvHAIBuildableStructure* AITAC_FindFurthestDeployableFromLocation(const Vector& Location, const DeployableSearchFilter* Filter)
AvHAIBuildableStructure AITAC_FindFurthestDeployableFromLocation(const Vector& Location, const DeployableSearchFilter* Filter)
{
AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber();
AvHTeamNumber TeamB = GetGameRules()->GetTeamBNumber();
AvHAIBuildableStructure* Result = NULL;
AvHAIBuildableStructure Result;
float CurrMinDist = 0.0f;
float MinDistSq = sqrf(Filter->MinSearchRadius);
float MaxDistSq = sqrf(Filter->MaxSearchRadius);
bool bUseMinDist = MinDistSq > 0.1f;
bool bUseMaxDist = MaxDistSq > 0.1f;
if (Filter->DeployableTeam == TeamA || Filter->DeployableTeam == TEAM_IND)
{
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; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && DistSq > CurrMinDist)
{
Result = it.second;
CurrMinDist = DistSq;
}
}
}
if (Filter->DeployableTeam == TeamB || Filter->DeployableTeam == TEAM_IND)
{
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; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && DistSq > CurrMinDist)
{
Result = it.second;
CurrMinDist = DistSq;
}
}
}
return Result;
}
AvHAIBuildableStructure* AITAC_FindFurthestDeployableFromLocationByRef(const Vector& Location, const DeployableSearchFilter* Filter)
{
AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber();
AvHTeamNumber TeamB = GetGameRules()->GetTeamBNumber();
AvHAIBuildableStructure* Result = nullptr;
float CurrMinDist = 0.0f;
float MinDistSq = sqrf(Filter->MinSearchRadius);
@ -497,6 +731,25 @@ bool AITAC_ItemExistsInLocation(const Vector& Location, const AvHAIDeployableIte
return false;
}
AvHAIBuildableStructure AITAC_GetDeployableFromEdict(const edict_t* Structure)
{
AvHAIBuildableStructure Result;
if (FNullEnt(Structure)) { return Result; }
int EntIndex = ENTINDEX(Structure);
if (EntIndex < 0) { return Result; }
AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber();
AvHTeamNumber TeamB = GetGameRules()->GetTeamBNumber();
Result = (Structure->v.team == TeamA) ? TeamAStructureMap[EntIndex] : TeamBStructureMap[EntIndex];
return Result;
}
AvHAIBuildableStructure* AITAC_GetDeployableRefFromEdict(const edict_t* Structure)
{
if (FNullEnt(Structure)) { return nullptr; }
@ -512,12 +765,95 @@ AvHAIBuildableStructure* AITAC_GetDeployableRefFromEdict(const edict_t* Structur
}
AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter)
AvHAIBuildableStructure AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter)
{
AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber();
AvHTeamNumber TeamB = GetGameRules()->GetTeamBNumber();
AvHAIBuildableStructure* Result = NULL;
AvHAIBuildableStructure Result;
float CurrMinDist = 0.0f;
float MinDistSq = sqrf(Filter->MinSearchRadius);
float MaxDistSq = sqrf(Filter->MaxSearchRadius);
bool bUseMinDist = MinDistSq > 0.1f;
bool bUseMaxDist = MaxDistSq > 0.1f;
if (Filter->DeployableTeam == TeamA || Filter->DeployableTeam == TEAM_IND)
{
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; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureType & Filter->DeployableTypes)
{
if (!UTIL_PointIsDirectlyReachable(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, it.second.Location)) { continue; }
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && (!Result.IsValid() || DistSq < CurrMinDist))
{
Result = it.second;
CurrMinDist = DistSq;
}
}
}
}
if (Filter->DeployableTeam == TeamB || Filter->DeployableTeam == TEAM_IND)
{
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; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureType & Filter->DeployableTypes)
{
if (!UTIL_PointIsDirectlyReachable(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, it.second.Location)) { continue; }
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && (!Result.IsValid() || DistSq < CurrMinDist))
{
Result = it.second;
CurrMinDist = DistSq;
}
}
}
}
return Result;
}
AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachableByRef(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter)
{
AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber();
AvHTeamNumber TeamB = GetGameRules()->GetTeamBNumber();
AvHAIBuildableStructure* Result = nullptr;
float CurrMinDist = 0.0f;
float MinDistSq = sqrf(Filter->MinSearchRadius);
@ -848,11 +1184,11 @@ Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team)
IFFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
IFFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
AvHAIBuildableStructure* InfantryPortal = AITAC_FindClosestDeployableToLocation(ZERO_VECTOR, &IFFilter);
AvHAIBuildableStructure InfantryPortal = AITAC_FindClosestDeployableToLocation(ZERO_VECTOR, &IFFilter);
if (InfantryPortal)
if (InfantryPortal.IsValid())
{
TeamAStartingLocation = InfantryPortal->Location;
TeamAStartingLocation = InfantryPortal.Location;
}
else
{
@ -890,11 +1226,11 @@ Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team)
IFFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
IFFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
AvHAIBuildableStructure* InfantryPortal = AITAC_FindClosestDeployableToLocation(ZERO_VECTOR, &IFFilter);
AvHAIBuildableStructure InfantryPortal = AITAC_FindClosestDeployableToLocation(ZERO_VECTOR, &IFFilter);
if (InfantryPortal)
if (InfantryPortal.IsValid())
{
TeamBStartingLocation = InfantryPortal->Location;
TeamBStartingLocation = InfantryPortal.Location;
}
else
{
@ -1387,12 +1723,12 @@ void AITAC_RefreshResourceNodes()
DeployableSearchFilter TowerFilter;
TowerFilter.DeployableTypes = (STRUCTURE_MARINE_RESTOWER | STRUCTURE_ALIEN_RESTOWER);
AvHAIBuildableStructure* OccupyingTower = AITAC_FindClosestDeployableToLocation(it->Location, &TowerFilter);
AvHAIBuildableStructure OccupyingTower = AITAC_FindClosestDeployableToLocation(it->Location, &TowerFilter);
if (OccupyingTower)
if (OccupyingTower.IsValid())
{
it->ActiveTowerEntity = OccupyingTower->edict;
it->OwningTeam = OccupyingTower->EntityRef->GetTeamNumber();
it->ActiveTowerEntity = OccupyingTower.edict;
it->OwningTeam = OccupyingTower.EntityRef->GetTeamNumber();
}
}
else
@ -2218,25 +2554,25 @@ void AITAC_OnStructureCompleted(AvHAIBuildableStructure* NewStructure)
Filter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
// Get all other completed phase gates for this team and add bidirectional connections to them
std::vector<AvHAIBuildableStructure*> OtherPhaseGates = AITAC_FindAllDeployables(NewStructure->Location, &Filter);
std::vector<AvHAIBuildableStructure> OtherPhaseGates = AITAC_FindAllDeployables(NewStructure->Location, &Filter);
SamplePolyFlags NewFlag = ((AvHTeamNumber)NewStructure->edict->v.team == GetGameRules()->GetTeamANumber()) ? SAMPLE_POLYFLAGS_TEAM1PHASEGATE : SAMPLE_POLYFLAGS_TEAM2PHASEGATE;
for (auto pg = OtherPhaseGates.begin(); pg != OtherPhaseGates.end(); pg++)
{
// Don't add off-mesh connections to ourselves!
if ((*pg) == NewStructure) { continue; }
if (pg->edict == NewStructure->edict) { continue; }
AvHAIBuildableStructure* OtherPhaseGate = (*pg);
AvHAIBuildableStructure OtherPhaseGate = (*pg);
AvHAIOffMeshConnection NewConnection;
NewConnection.FromLocation = NewStructure->Location;
NewConnection.ToLocation = OtherPhaseGate->Location;
NewConnection.ToLocation = OtherPhaseGate.Location;
NewConnection.ConnectionFlags = NewFlag;
NewConnection.TargetObject = OtherPhaseGate->edict;
NewConnection.TargetObject = OtherPhaseGate.edict;
memset(&NewConnection.ConnectionRefs[0], 0, sizeof(NewConnection.ConnectionRefs));
UTIL_AddOffMeshConnection(NewStructure->Location, OtherPhaseGate->Location, SAMPLE_POLYAREA_PHASEGATE, NewFlag, true, &NewConnection);
UTIL_AddOffMeshConnection(NewStructure->Location, OtherPhaseGate.Location, SAMPLE_POLYAREA_PHASEGATE, NewFlag, true, &NewConnection);
NewStructure->OffMeshConnections.push_back(NewConnection);
@ -2312,12 +2648,12 @@ void AITAC_OnStructureDestroyed(AvHAIBuildableStructure* DestroyedStructure)
Filter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
// Get all other completed phase gates for this team and remove any connections going to this structure
std::vector<AvHAIBuildableStructure*> OtherPhaseGates = AITAC_FindAllDeployables(DestroyedStructure->Location, &Filter);
std::vector<AvHAIBuildableStructure*> OtherPhaseGates = AITAC_FindAllDeployablesByRef(DestroyedStructure->Location, &Filter);
for (auto it = OtherPhaseGates.begin(); it != OtherPhaseGates.end(); it++)
{
// Don't check for off-mesh connections from ourselves!
if ((*it) == DestroyedStructure) { continue; }
if ((*it)->edict == DestroyedStructure->edict) { continue; }
AvHAIBuildableStructure* OtherPhaseGate = (*it);
@ -2531,21 +2867,21 @@ float AITAC_GetPhaseDistanceBetweenPoints(const Vector StartPoint, const Vector
PGFilter.MaxSearchRadius = DirectDist;
AvHAIBuildableStructure* StartPhase = AITAC_FindClosestDeployableToLocation(StartPoint, &PGFilter);
AvHAIBuildableStructure StartPhase = AITAC_FindClosestDeployableToLocation(StartPoint, &PGFilter);
if (!StartPhase)
if (!StartPhase.IsValid())
{
return DirectDist;
}
AvHAIBuildableStructure* EndPhase = AITAC_FindClosestDeployableToLocation(EndPoint, &PGFilter);
AvHAIBuildableStructure EndPhase = AITAC_FindClosestDeployableToLocation(EndPoint, &PGFilter);
if (!EndPhase || EndPhase == StartPhase)
if (FNullEnt(EndPhase.edict) || EndPhase.edict == StartPhase.edict)
{
return DirectDist;
}
float PhaseDist = vDist2DSq(StartPoint, StartPhase->edict->v.origin) + vDist2DSq(EndPoint, EndPhase->edict->v.origin);
float PhaseDist = vDist2DSq(StartPoint, StartPhase.edict->v.origin) + vDist2DSq(EndPoint, EndPhase.edict->v.origin);
PhaseDist = sqrtf(PhaseDist);
@ -2689,11 +3025,11 @@ bool UTIL_IsBuildableStructureStillReachable(AvHAIPlayer* pBot, const edict_t* S
AvHAIDeployableStructureType StructureType = GetStructureTypeFromEdict(Structure);
if (StructureType == STRUCTURE_ALIEN_HIVE || StructureType == STRUCTURE_NONE) { return true; }
AvHAIBuildableStructure* StructureRef = AITAC_GetDeployableRefFromEdict(Structure);
AvHAIBuildableStructure StructureRef = AITAC_GetDeployableFromEdict(Structure);
if (!StructureRef) { return false; }
if (!StructureRef.IsValid()) { return false; }
unsigned int TeamReachability = (pBot->Edict->v.team == GetGameRules()->GetTeamANumber()) ? StructureRef->TeamAReachabilityFlags : StructureRef->TeamBReachabilityFlags;
unsigned int TeamReachability = (pBot->Edict->v.team == GetGameRules()->GetTeamANumber()) ? StructureRef.TeamAReachabilityFlags : StructureRef.TeamBReachabilityFlags;
return (TeamReachability & pBot->BotNavInfo.NavProfile.ReachabilityFlag);
}
@ -3436,13 +3772,13 @@ Vector UTIL_GetNextMinePosition2(edict_t* StructureToMine)
MineFilter.DeployableTypes = STRUCTURE_MARINE_DEPLOYEDMINE;
MineFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(3.0f);
vector<AvHAIBuildableStructure*> SurroundingMines = AITAC_FindAllDeployables(StructureToMine->v.origin, &MineFilter);
vector<AvHAIBuildableStructure> SurroundingMines = AITAC_FindAllDeployables(StructureToMine->v.origin, &MineFilter);
for (auto it = SurroundingMines.begin(); it != SurroundingMines.end(); it++)
{
AvHAIBuildableStructure* ThisMine = (*it);
AvHAIBuildableStructure ThisMine = (*it);
Vector Dir = UTIL_GetVectorNormal2D(ThisMine->Location - StructureToMine->v.origin);
Vector Dir = UTIL_GetVectorNormal2D(ThisMine.Location - StructureToMine->v.origin);
if (UTIL_GetDotProduct2D(FwdVector, Dir) > 0.7f)
{
@ -3540,13 +3876,13 @@ Vector UTIL_GetNextMinePosition(edict_t* StructureToMine)
MineFilter.DeployableTypes = STRUCTURE_MARINE_DEPLOYEDMINE;
MineFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(3.0f);
vector<AvHAIBuildableStructure*> SurroundingMines = AITAC_FindAllDeployables(StructureToMine->v.origin, &MineFilter);
vector<AvHAIBuildableStructure> SurroundingMines = AITAC_FindAllDeployables(StructureToMine->v.origin, &MineFilter);
for (auto it = SurroundingMines.begin(); it != SurroundingMines.end(); it++)
{
AvHAIBuildableStructure* ThisMine = (*it);
AvHAIBuildableStructure ThisMine = (*it);
Vector Dir = UTIL_GetVectorNormal2D(ThisMine->Location - StructureToMine->v.origin);
Vector Dir = UTIL_GetVectorNormal2D(ThisMine.Location - StructureToMine->v.origin);
if (UTIL_GetDotProduct2D(FwdVector, Dir) > 0.7f)
{
@ -3909,7 +4245,7 @@ edict_t* AITAC_GetCommChair(AvHTeamNumber Team)
ChairFilter.DeployableTeam = Team;
ChairFilter.ReachabilityTeam = TEAM_IND;
vector<AvHAIBuildableStructure*> CommChairs = AITAC_FindAllDeployables(ZERO_VECTOR, &ChairFilter);
vector<AvHAIBuildableStructure> CommChairs = AITAC_FindAllDeployables(ZERO_VECTOR, &ChairFilter);
edict_t* MainCommChair = nullptr;
edict_t* BackupChair = nullptr;
@ -3917,7 +4253,7 @@ edict_t* AITAC_GetCommChair(AvHTeamNumber Team)
// If the team has more than one comm chair, pick the one in use
for (auto it = CommChairs.begin(); it != CommChairs.end(); it++)
{
AvHCommandStation* ChairRef = dynamic_cast<AvHCommandStation*>((*it)->EntityRef);
AvHCommandStation* ChairRef = dynamic_cast<AvHCommandStation*>((*it).EntityRef);
// Idle animation will be 3 if the chair is in use (closed animation). See AvHCommandStation::GetIdleAnimation
if (ChairRef && ChairRef->GetIdleAnimation() == 3)
@ -4044,14 +4380,14 @@ const AvHAIHiveDefinition* AITAC_GetNearestHiveUnderActiveSiege(AvHTeamNumber Si
SiegeFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
SiegeFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
AvHAIBuildableStructure* AdvTF = AITAC_FindClosestDeployableToLocation(it->Location, &SiegeFilter);
AvHAIBuildableStructure AdvTF = AITAC_FindClosestDeployableToLocation(it->Location, &SiegeFilter);
if (!AdvTF) { continue; }
if (!AdvTF.IsValid()) { continue; }
SiegeFilter.DeployableTypes = STRUCTURE_MARINE_SIEGETURRET;
SiegeFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
bool bSTExists = AITAC_DeployableExistsAtLocation(AdvTF->Location, &SiegeFilter);
bool bSTExists = AITAC_DeployableExistsAtLocation(AdvTF.Location, &SiegeFilter);
if (bSTExists)
{
@ -4642,7 +4978,7 @@ bool AITAC_IsAlienBuilderNeeded(AvHAIPlayer* pBot)
ExistingReinforcementFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
ExistingReinforcementFilter.DeployableTypes = SEARCH_ALL_ALIEN_STRUCTURES;
vector<AvHAIBuildableStructure*> AllReinforcingStructures = AITAC_FindAllDeployables(ThisHive->FloorLocation, &ExistingReinforcementFilter);
vector<AvHAIBuildableStructure> AllReinforcingStructures = AITAC_FindAllDeployables(ThisHive->FloorLocation, &ExistingReinforcementFilter);
int NumOCs = 0;
int NumDCs = 0;
@ -4651,7 +4987,7 @@ bool AITAC_IsAlienBuilderNeeded(AvHAIPlayer* pBot)
for (auto it = AllReinforcingStructures.begin(); it != AllReinforcingStructures.end(); it++)
{
switch ((*it)->StructureType)
switch ((*it).StructureType)
{
case STRUCTURE_ALIEN_OFFENCECHAMBER:
NumOCs++;
@ -4716,7 +5052,7 @@ bool AITAC_IsAlienBuilderNeeded(AvHAIPlayer* pBot)
ExistingReinforcementFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
ExistingReinforcementFilter.DeployableTypes = SEARCH_ALL_ALIEN_STRUCTURES;
vector<AvHAIBuildableStructure*> AllReinforcingStructures = AITAC_FindAllDeployables(ThisNode->Location, &ExistingReinforcementFilter);
vector<AvHAIBuildableStructure> AllReinforcingStructures = AITAC_FindAllDeployables(ThisNode->Location, &ExistingReinforcementFilter);
int NumOCs = 0;
int NumDCs = 0;
@ -4725,7 +5061,7 @@ bool AITAC_IsAlienBuilderNeeded(AvHAIPlayer* pBot)
for (auto it = AllReinforcingStructures.begin(); it != AllReinforcingStructures.end(); it++)
{
switch ((*it)->StructureType)
switch ((*it).StructureType)
{
case STRUCTURE_ALIEN_OFFENCECHAMBER:
NumOCs++;
@ -4852,22 +5188,22 @@ edict_t* AITAC_AlienFindNearestHealingSource(AvHTeamNumber Team, Vector SearchLo
DCFilter.DeployableTypes = STRUCTURE_ALIEN_DEFENCECHAMBER;
DCFilter.MaxSearchRadius = (!FNullEnt(Result)) ? MinDist : 0.0f; // We should always have a result, unless we have no hives left. That's our benchmark: only look for DCs closer than the hive
vector<AvHAIBuildableStructure*> AllDCs = AITAC_FindAllDeployables(SearchLocation, &DCFilter);
vector<AvHAIBuildableStructure> AllDCs = AITAC_FindAllDeployables(SearchLocation, &DCFilter);
for (auto it = AllDCs.begin(); it != AllDCs.end(); it++)
{
AvHAIBuildableStructure* ThisDC = (*it);
AvHAIBuildableStructure ThisDC = (*it);
float ThisDist = vDist2DSq(ThisDC->Location, SearchLocation);
float ThisDist = vDist2DSq(ThisDC.Location, SearchLocation);
// Factor healing radius into the distance checks, we don't have to be sat on top of the DC to heal
ThisDist -= BALANCE_VAR(kHiveHealRadius) * 0.75f;
// We're already in healing distance of a DC, that's our healing source
if (ThisDist <= 0.0f) { return ThisDC->edict; }
if (ThisDist <= 0.0f) { return ThisDC.edict; }
if (FNullEnt(Result) || ThisDist < MinDist)
{
Result = ThisDC->edict;
Result = ThisDC.edict;
MinDist = ThisDist;
}
}

View file

@ -21,11 +21,16 @@ static const float structure_inventory_refresh_rate = 0.2f;
static const float item_inventory_refresh_rate = 0.2f;
bool AITAC_DeployableExistsAtLocation(const Vector& Location, const DeployableSearchFilter* Filter);
std::vector<AvHAIBuildableStructure*> AITAC_FindAllDeployables(const Vector& Location, const DeployableSearchFilter* Filter);
AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocation(const Vector& Location, const DeployableSearchFilter* Filter);
AvHAIBuildableStructure* AITAC_FindFurthestDeployableFromLocation(const Vector& Location, const DeployableSearchFilter* Filter);
std::vector<AvHAIBuildableStructure> AITAC_FindAllDeployables(const Vector& Location, const DeployableSearchFilter* Filter);
std::vector<AvHAIBuildableStructure*> AITAC_FindAllDeployablesByRef(const Vector& Location, const DeployableSearchFilter* Filter);
AvHAIBuildableStructure AITAC_FindClosestDeployableToLocation(const Vector& Location, const DeployableSearchFilter* Filter);
AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocationByRef(const Vector& Location, const DeployableSearchFilter* Filter);
AvHAIBuildableStructure AITAC_FindFurthestDeployableFromLocation(const Vector& Location, const DeployableSearchFilter* Filter);
AvHAIBuildableStructure* AITAC_FindFurthestDeployableFromLocationByRef(const Vector& Location, const DeployableSearchFilter* Filter);
AvHAIBuildableStructure AITAC_GetDeployableFromEdict(const edict_t* Structure);
AvHAIBuildableStructure* AITAC_GetDeployableRefFromEdict(const edict_t* Structure);
AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter);
AvHAIBuildableStructure AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter);
AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachableByRef(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter);
int AITAC_GetNumDeployablesNearLocation(const Vector& Location, const DeployableSearchFilter* Filter);
void AITAC_PopulateHiveData();
void AITAC_RefreshHiveData();

View file

@ -91,11 +91,11 @@ void AITASK_OnCompleteCommanderTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
EnemyResTowerFilter.ReachabilityTeam = (AvHTeamNumber)pBot->Edict->v.team;
EnemyResTowerFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
AvHAIBuildableStructure* NearbyAlienTower = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &EnemyResTowerFilter);
AvHAIBuildableStructure NearbyAlienTower = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &EnemyResTowerFilter);
if (NearbyAlienTower)
if (NearbyAlienTower.IsValid())
{
const AvHAIResourceNode* NodeRef = AITAC_GetNearestResourceNodeToLocation(NearbyAlienTower->Location);
const AvHAIResourceNode* NodeRef = AITAC_GetNearestResourceNodeToLocation(NearbyAlienTower.Location);
if (NodeRef)
{
AITASK_SetCapResNodeTask(pBot, Task, NodeRef, false);
@ -820,7 +820,7 @@ bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTas
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
StructureFilter.DeployableTeam = pBot->Player->GetTeam();
vector<AvHAIBuildableStructure*> AllNearbyStructures = AITAC_FindAllDeployables(Task->TaskTarget->v.origin, &StructureFilter);
vector<AvHAIBuildableStructure> AllNearbyStructures = AITAC_FindAllDeployables(Task->TaskTarget->v.origin, &StructureFilter);
bool bUnfinishedStructureExists = false;
int NumOffenceChambers = 0;
@ -830,11 +830,11 @@ bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTas
for (auto it = AllNearbyStructures.begin(); it != AllNearbyStructures.end(); it++)
{
AvHAIBuildableStructure* ThisStructure = (*it);
AvHAIBuildableStructure ThisStructure = (*it);
if (!(ThisStructure->StructureStatusFlags & STRUCTURE_STATUS_COMPLETED)) { bUnfinishedStructureExists = true; }
if (!(ThisStructure.StructureStatusFlags & STRUCTURE_STATUS_COMPLETED)) { bUnfinishedStructureExists = true; }
switch (ThisStructure->StructureType)
switch (ThisStructure.StructureType)
{
case STRUCTURE_ALIEN_OFFENCECHAMBER:
NumOffenceChambers++;
@ -909,25 +909,25 @@ bool AITASK_IsMarineSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask*
SearchFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
SearchFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
vector<AvHAIBuildableStructure*> HiveStructures = AITAC_FindAllDeployables(HiveToSecure->FloorLocation, &SearchFilter);
vector<AvHAIBuildableStructure> HiveStructures = AITAC_FindAllDeployables(HiveToSecure->FloorLocation, &SearchFilter);
for (auto it = HiveStructures.begin(); it != HiveStructures.end(); it++)
{
AvHAIBuildableStructure* Structure = (*it);
AvHAIBuildableStructure Structure = (*it);
if (Structure->StructureType == STRUCTURE_MARINE_TURRETFACTORY)
if (Structure.StructureType == STRUCTURE_MARINE_TURRETFACTORY)
{
bHasPhaseGate = true;
}
if (Structure->StructureType == STRUCTURE_MARINE_TURRETFACTORY || Structure->StructureType == STRUCTURE_MARINE_ADVTURRETFACTORY)
if (Structure.StructureType == STRUCTURE_MARINE_TURRETFACTORY || Structure.StructureType == STRUCTURE_MARINE_ADVTURRETFACTORY)
{
bHasTurretFactory = true;
SearchFilter.DeployableTypes = STRUCTURE_MARINE_TURRET;
SearchFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(8.0f);
NumTurrets = AITAC_GetNumDeployablesNearLocation(Structure->Location, &SearchFilter);
NumTurrets = AITAC_GetNumDeployablesNearLocation(Structure.Location, &SearchFilter);
}
@ -1343,11 +1343,11 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
UnfinishedFilter.DeployableTypes = SEARCH_ALL_ALIEN_STRUCTURES;
UnfinishedFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
AvHAIBuildableStructure* UnfinishedStructure = AITAC_FindClosestDeployableToLocation(ReinforceLocation, &UnfinishedFilter);
AvHAIBuildableStructure UnfinishedStructure = AITAC_FindClosestDeployableToLocation(ReinforceLocation, &UnfinishedFilter);
if (UnfinishedStructure)
if (UnfinishedStructure.IsValid())
{
AIPlayerBuildStructure(pBot, UnfinishedStructure->edict);
AIPlayerBuildStructure(pBot, UnfinishedStructure.edict);
return;
}
}
@ -1362,11 +1362,11 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
EnemyStructureFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
EnemyStructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
AvHAIBuildableStructure* EnemyStructure = AITAC_FindClosestDeployableToLocation(ReinforceLocation, &EnemyStructureFilter);
AvHAIBuildableStructure EnemyStructure = AITAC_FindClosestDeployableToLocation(ReinforceLocation, &EnemyStructureFilter);
if (EnemyStructure)
if (EnemyStructure.IsValid())
{
BotAttackNonPlayerTarget(pBot, EnemyStructure->edict);
BotAttackNonPlayerTarget(pBot, EnemyStructure.edict);
return;
}
@ -1738,12 +1738,12 @@ void BotProgressDefendTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
return;
}
AvHAIBuildableStructure* StructureRef = AITAC_GetDeployableRefFromEdict(Task->TaskTarget);
AvHAIBuildableStructure StructureRef = AITAC_GetDeployableFromEdict(Task->TaskTarget);
if (!StructureRef) { return; }
if (!StructureRef.IsValid()) { return; }
// If the structure we're defending was damaged just now, look at it so we can see who is attacking
if (gpGlobals->time - StructureRef->lastDamagedTime < 5.0f)
if (gpGlobals->time - StructureRef.lastDamagedTime < 5.0f)
{
if (UTIL_QuickTrace(pBot->Edict, pBot->CurrentEyePosition, UTIL_GetCentreOfEntity(Task->TaskTarget)))
{
@ -2001,11 +2001,11 @@ void AlienProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
UnfinishedFilter.ExcludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
UnfinishedFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
AvHAIBuildableStructure* UnfinishedStructure = AITAC_FindClosestDeployableToLocation(Task->TaskLocation, &UnfinishedFilter);
AvHAIBuildableStructure UnfinishedStructure = AITAC_FindClosestDeployableToLocation(Task->TaskLocation, &UnfinishedFilter);
if (UnfinishedStructure)
if (UnfinishedStructure.IsValid())
{
AIPlayerBuildStructure(pBot, UnfinishedStructure->edict);
AIPlayerBuildStructure(pBot, UnfinishedStructure.edict);
return;
}
}
@ -2240,11 +2240,11 @@ void AlienProgressCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
PGFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
PGFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
AvHAIBuildableStructure* PG = AITAC_FindClosestDeployableToLocation(ResNodeIndex->Location, &PGFilter);
AvHAIBuildableStructure PG = AITAC_FindClosestDeployableToLocation(ResNodeIndex->Location, &PGFilter);
if (PG)
if (PG.IsValid())
{
BotAttackNonPlayerTarget(pBot, PG->edict);
BotAttackNonPlayerTarget(pBot, PG.edict);
return;
}
}
@ -2301,11 +2301,11 @@ void AlienProgressCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
EnemyStructureFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
EnemyStructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
AvHAIBuildableStructure* AttackTarget = AITAC_FindClosestDeployableToLocation(ResNodeIndex->Location, &EnemyStructureFilter);
AvHAIBuildableStructure AttackTarget = AITAC_FindClosestDeployableToLocation(ResNodeIndex->Location, &EnemyStructureFilter);
if (AttackTarget)
if (AttackTarget.IsValid())
{
BotAttackNonPlayerTarget(pBot, AttackTarget->edict);
BotAttackNonPlayerTarget(pBot, AttackTarget.edict);
return;
}
}
@ -2505,43 +2505,43 @@ void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
StructureFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
StructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
vector<AvHAIBuildableStructure*> BuildableStructures = AITAC_FindAllDeployables(Hive->FloorLocation, &StructureFilter);
vector<AvHAIBuildableStructure> BuildableStructures = AITAC_FindAllDeployables(Hive->FloorLocation, &StructureFilter);
bool bKeyStructureBuilt = false;
AvHAIBuildableStructure* StructureToBuild = nullptr;
AvHAIBuildableStructure StructureToBuild;
float MinDist = 0.0f;
for (auto it = BuildableStructures.begin(); it != BuildableStructures.end(); it++)
{
AvHAIBuildableStructure* ThisStructure = (*it);
AvHAIBuildableStructure ThisStructure = (*it);
if ((ThisStructure->StructureStatusFlags & STRUCTURE_STATUS_COMPLETED) && (ThisStructure->StructureType & (STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_PHASEGATE)))
if ((ThisStructure.StructureStatusFlags & STRUCTURE_STATUS_COMPLETED) && (ThisStructure.StructureType & (STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_PHASEGATE)))
{
bKeyStructureBuilt = true;
}
if (ThisStructure->StructureStatusFlags & STRUCTURE_STATUS_COMPLETED) { continue; }
if (ThisStructure.StructureStatusFlags & STRUCTURE_STATUS_COMPLETED) { continue; }
// Phase gates always take priority, so just go and build it if there is one
if (ThisStructure->StructureType == STRUCTURE_MARINE_PHASEGATE)
if (ThisStructure.StructureType == STRUCTURE_MARINE_PHASEGATE)
{
AIPlayerBuildStructure(pBot, ThisStructure->edict);
AIPlayerBuildStructure(pBot, ThisStructure.edict);
return;
}
float ThisDist = vDist2DSq(pBot->Edict->v.origin, ThisStructure->Location);
float ThisDist = vDist2DSq(pBot->Edict->v.origin, ThisStructure.Location);
if (!StructureToBuild || ThisDist < MinDist)
if (FNullEnt(StructureToBuild.edict) || ThisDist < MinDist)
{
StructureToBuild = ThisStructure;
MinDist = ThisDist;
}
}
if (StructureToBuild)
if (StructureToBuild.IsValid())
{
AIPlayerBuildStructure(pBot, StructureToBuild->edict);
AIPlayerBuildStructure(pBot, StructureToBuild.edict);
return;
}
@ -2579,11 +2579,11 @@ void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
EnemyStructures.ReachabilityTeam = BotTeam;
EnemyStructures.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
AvHAIBuildableStructure* EnemyStructure = AITAC_FindClosestDeployableToLocation(Hive->FloorLocation, &EnemyStructures);
AvHAIBuildableStructure EnemyStructure = AITAC_FindClosestDeployableToLocation(Hive->FloorLocation, &EnemyStructures);
if (EnemyStructure)
if (EnemyStructure.IsValid())
{
BotAttackNonPlayerTarget(pBot, EnemyStructure->edict);
BotAttackNonPlayerTarget(pBot, EnemyStructure.edict);
return;
}
}
@ -2638,11 +2638,11 @@ void MarineProgressCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
EnemyStructureFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
EnemyStructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
AvHAIBuildableStructure* EnemyStructure = AITAC_FindClosestDeployableToLocation(Task->TaskLocation, &EnemyStructureFilter);
AvHAIBuildableStructure EnemyStructure = AITAC_FindClosestDeployableToLocation(Task->TaskLocation, &EnemyStructureFilter);
if (EnemyStructure)
if (EnemyStructure.IsValid())
{
BotAttackNonPlayerTarget(pBot, EnemyStructure->edict);
BotAttackNonPlayerTarget(pBot, EnemyStructure.edict);
return;
}
}
@ -2661,13 +2661,13 @@ void MarineProgressCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
EnemyStructureFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
EnemyStructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
AvHAIBuildableStructure* EnemyStructure = AITAC_FindClosestDeployableToLocation(Task->TaskLocation, &EnemyStructureFilter);
AvHAIBuildableStructure EnemyStructure = AITAC_FindClosestDeployableToLocation(Task->TaskLocation, &EnemyStructureFilter);
if (EnemyStructure)
if (EnemyStructure.IsValid())
{
// Cancel the waiting timeout since we have something useful to do
Task->TaskLength = 0.0f;
BotAttackNonPlayerTarget(pBot, EnemyStructure->edict);
BotAttackNonPlayerTarget(pBot, EnemyStructure.edict);
return;
}
else

View file

@ -1454,6 +1454,21 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
{
AIDEBUG_DrawOffMeshConnections(10.0f);
theSuccess = true;
}
else if (FStrEq(pcmd, "ai_saysomething"))
{
vector<AvHAIPlayer*> AIPlayers = AIMGR_GetAllAIPlayers();
for (auto it = AIPlayers.begin(); it != AIPlayers.end(); it++)
{
AvHAIPlayer* thisBot = (*it);
{
BotSay(thisBot, false, 1.0f, "Regular Chat");
BotSay(thisBot, true, 2.0f, "Team Chat");
}
}
theSuccess = true;
}
else if( FStrEq( pcmd, kcRemoveUpgrade) )

View file

@ -2323,6 +2323,11 @@ void AvHGamerules::PostWorldPrecacheReset(bool inNewMap)
// Must happen after processing spawn entities
this->RecalculateMapMode();
if (avh_botsenabled.value > 0)
{
AIMGR_LoadNavigationData();
}
// Loop through all players that are playing and respawn them
bool theJustResetGameAtCountdownStart = false;