Marine and alien tactical bug fixes

This commit is contained in:
RGreenlees 2024-02-16 23:36:59 +00:00 committed by pierow
parent 16e4f14863
commit 680aa8dbdb
13 changed files with 317 additions and 60 deletions

View file

@ -1086,7 +1086,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
}
StructureFilter.DeployableTypes = STRUCTURE_MARINE_PROTOTYPELAB;
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f);
StructureFilter.IncludeStatusFlags = STRUCTURE_STATUS_NONE;
StructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
@ -2065,12 +2065,56 @@ bool AICOMM_CheckForNextRecycleAction(AvHAIPlayer* pBot)
{
AvHAIHiveDefinition* Hive = (*HiveIt);
// If the hive is still active or growing, then clearly we should keep any siege bases
if (Hive->Status != HIVE_STATUS_UNBUILT) { continue; }
// If the hive is empty, but we've not secured it yet, then keep any siege bases nearby in case we need to re-siege later
DeployableSearchFilter SecuringStructuresFilter;
SecuringStructuresFilter.DeployableTypes = (STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_TURRET);
SecuringStructuresFilter.DeployableTeam = pBot->Player->GetTeam();
SecuringStructuresFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
SecuringStructuresFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
SecuringStructuresFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
vector<AvHAIBuildableStructure*> NearbySecuringStructures = AITAC_FindAllDeployables(Hive->Location, &SecuringStructuresFilter);
bool bHiveHasPG = false;
bool bHiveHasTF = false;
bool bHiveHasTurret = false;
for (auto SecureIt = NearbySecuringStructures.begin(); SecureIt != NearbySecuringStructures.end(); SecureIt++)
{
AvHAIBuildableStructure* Structure = (*SecureIt);
if (Structure->Purpose == STRUCTURE_PURPOSE_SIEGE)
{
if (Structure->StructureType == STRUCTURE_MARINE_PHASEGATE)
{
bHiveHasPG = true;
}
if (Structure->StructureType == STRUCTURE_MARINE_TURRETFACTORY || Structure->StructureType == STRUCTURE_MARINE_ADVTURRETFACTORY)
{
bHiveHasTF = true;
}
if (Structure->StructureType == STRUCTURE_MARINE_TURRET)
{
bHiveHasTurret = true;
}
}
}
bool bHiveIsSecureEnough = (bHiveHasPG && bHiveHasTF && bHiveHasTurret);
if (!bHiveIsSecureEnough) { continue; }
// Ok, hive is secured by us, now we can check if there are any siege objects to be got rid of
DeployableSearchFilter RedundantFilter;
RedundantFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
RedundantFilter.DeployableTeam = pBot->Player->GetTeam();
RedundantFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
RedundantFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(25.0f);
RedundantFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(30.0f);
vector<AvHAIBuildableStructure*> NearbyStructures = AITAC_FindAllDeployables(Hive->Location, &RedundantFilter);

View file

@ -224,6 +224,11 @@ bool IsEdictStructure(const edict_t* edict)
return (GetDeployableObjectTypeFromEdict(edict) != STRUCTURE_NONE);
}
bool IsEdictHive(const edict_t* edict)
{
return (GetDeployableObjectTypeFromEdict(edict) != STRUCTURE_ALIEN_HIVE);
}
bool IsDamagingStructure(const edict_t* StructureEdict)
{
return IsDamagingStructure(GetStructureTypeFromEdict(StructureEdict));

View file

@ -25,6 +25,7 @@ Vector UTIL_GetClosestPointOnEntityToLocation(const Vector Location, edict_t* En
AvHAIDeployableStructureType IUSER3ToStructureType(const int inIUSER3);
bool IsEdictStructure(const edict_t* edict);
bool IsEdictHive(const edict_t* edict);
AvHAIDeployableStructureType GetStructureTypeFromEdict(const edict_t* StructureEdict);

View file

@ -2004,7 +2004,7 @@ bool HasBotReachedPathPoint(const AvHAIPlayer* pBot)
Vector ClosestPointToPath = vClosestPointOnLine2D(MoveFrom, MoveTo, pEdict->v.origin);
bool bDestIsDirectlyReachable = UTIL_PointIsDirectlyReachable(CurrentPos, MoveTo);
bool bAtOrPastDestination = vEquals2D(ClosestPointToPath, MoveTo, 1.0f) && bDestIsDirectlyReachable;
bool bAtOrPastDestination = vEquals2D(ClosestPointToPath, MoveTo, 8.0f) && bDestIsDirectlyReachable;
dtPolyRef BotPoly = pBot->BotNavInfo.CurrentPoly;
dtPolyRef DestinationPoly = pBot->BotNavInfo.CurrentPathPoint->poly;
@ -3916,14 +3916,14 @@ bool IsBotOffPath(const AvHAIPlayer* pBot)
bool bAtMoveEnd = vEquals(PointOnPath, MoveTo, GetPlayerRadius(pBot->Player));
if (bAtMoveEnd && fabs(pBot->CurrentFloorPosition.z - MoveTo.z) > PlayerHeight)
if (bAtMoveEnd && fabsf(pBot->CurrentFloorPosition.z - MoveTo.z) > PlayerHeight)
{
return true;
}
float MaxDist = (bAtMoveStart || bAtMoveEnd) ? 50.0f : 200.0f;
if (vDistanceFromLine2D(MoveFrom, MoveTo, pBot->CurrentFloorPosition) > sqrf(MaxDist))
if (vDistanceFromLine2D(MoveFrom, MoveTo, pBot->CurrentFloorPosition) > MaxDist)
{
return true;
}
@ -5744,6 +5744,12 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
SkipAheadInFlightPath(pBot);
}
if (!UTIL_QuickTrace(pBot->Edict, pBot->Edict->v.origin, BotNavInfo->CurrentPathPoint->Location + Vector(0.0f, 0.0f, 5.0f)))
{
ClearBotPath(pBot);
return;
}
CurrentMoveDest = BotNavInfo->CurrentPathPoint->Location;
Vector MoveFrom = BotNavInfo->CurrentPathPoint->FromLocation;
@ -7702,7 +7708,7 @@ void UTIL_UpdateDoorTriggers(nav_door* Door)
{
if (it->LastToggleState != TS_GOING_UP && it->LastToggleState != TS_GOING_DOWN)
{
it->NextActivationTime = gpGlobals->time + it->ActivationDelay;
it->NextActivationTime = gpGlobals->time + fmaxf(it->ActivationDelay + 1.0f, 1.0f);
}
it->LastToggleState = (TOGGLE_STATE)it->ToggleEnt->GetToggleState();

View file

@ -368,7 +368,7 @@ void BotSay(AvHAIPlayer* pBot, bool bTeamSay, float Delay, char* textToSay)
bool BotReloadWeapons(AvHAIPlayer* pBot)
{
// Aliens and commander don't reload
if (!IsPlayerMarine(pBot->Edict) || !IsPlayerActiveInGame(pBot->Edict)) { return false; }
if (!IsPlayerMarine(pBot->Edict) || !IsPlayerActiveInGame(pBot->Edict) || IsPlayerReloading(pBot->Player)) { return false; }
AvHAIWeapon PrimaryWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player);
AvHAIWeapon SecondaryWeapon = GetBotMarineSecondaryWeapon(pBot);
@ -3314,6 +3314,11 @@ void AIPlayerSetMarineBombardierPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask*
void AIPlayerSetWantsAndNeedsMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
{
if (BotReloadWeapons(pBot)) { return; }
}
if (Task->TaskType == TASK_RESUPPLY || Task->TaskType == TASK_GET_HEALTH || Task->TaskType == TASK_GET_AMMO) { return; }
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
@ -3818,11 +3823,12 @@ void AIPlayerNSAlienThink(AvHAIPlayer* pBot)
AIPlayerSetPrimaryAlienTask(pBot, &pBot->PrimaryBotTask);
AIPlayerSetSecondaryAlienTask(pBot, &pBot->SecondaryBotTask);
AIPlayerSetWantsAndNeedsAlienTask(pBot, &pBot->WantsAndNeedsTask);
}
pBot->CurrentTask = AIPlayerGetNextTask(pBot);
if (pBot->LastCombatTime > 5.0f)
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
{
if (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_DEFENCE) && AITAC_IsAlienUpgradeAvailableForTeam(pBot->Player->GetTeam(), HIVE_TECH_DEFENCE))
{
@ -4148,11 +4154,24 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
int NumMissingChambers = 0;
// Do we have any missing upgrade chambers (should have 3 of each if we can build them)
AvHAIDeployableStructureType MissingStructure = AITAC_GetNextMissingUpgradeChamberForTeam(BotTeam);
AvHAIDeployableStructureType MissingStructure = AITAC_GetNextMissingUpgradeChamberForTeam(BotTeam, NumMissingChambers);
bool bShouldBuildMissingStructure = false;
if (MissingStructure != STRUCTURE_NONE)
{
int NumBuilders = AITASK_GetNumBotsWithBuildTask(BotTeam, MissingStructure, pBot->Edict);
if (NumBuilders < NumMissingChambers)
{
bShouldBuildMissingStructure = true;
}
}
// If we do have a missing upgrade chamber, built it at the nearest hive or resource node that we own, whichever is nearest
if (MissingStructure != STRUCTURE_NONE)
if (bShouldBuildMissingStructure)
{
if (Task->TaskType == TASK_BUILD && Task->StructureType == MissingStructure) { return; }
@ -4221,7 +4240,7 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
AvHAIHiveDefinition* HiveToSecure = nullptr;
float MaxDist = 0.0f;
float MinDist = 0.0f;
for (auto it = AllHives.begin(); it != AllHives.end(); it++)
{
@ -4291,12 +4310,12 @@ 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), ThisHive->FloorLocation);
float ThisDist = vDist2DSq(pBot->Edict->v.origin, ThisHive->FloorLocation);
if (ThisDist > MaxDist)
if (!HiveToSecure || ThisDist < MinDist)
{
HiveToSecure = ThisHive;
MaxDist = ThisDist;
MinDist = ThisDist;
}
}
@ -4318,7 +4337,7 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
vector<AvHAIBuildableStructure*> AllMatchingTowers = AITAC_FindAllDeployables(pBot->Edict->v.origin, &ResNodeFilter);
edict_t* TowerToReinforce = nullptr;
float MinDist = 0.0f;
MinDist = 0.0f;
for (auto it = AllMatchingTowers.begin(); it != AllMatchingTowers.end(); it++)
{
@ -4327,7 +4346,7 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
DeployableSearchFilter ExistingReinforcementFilter;
ExistingReinforcementFilter.DeployableTeam = BotTeam;
ExistingReinforcementFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
ExistingReinforcementFilter.DeployableTypes = SEARCH_ALL_ALIEN_STRUCTURES;
ExistingReinforcementFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
vector<AvHAIBuildableStructure*> AllReinforcingStructures = AITAC_FindAllDeployables(ThisResTower->Location, &ExistingReinforcementFilter);
@ -4584,6 +4603,8 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
return;
}
if (Task->TaskType == TASK_EVOLVE) { return; }
if (!IsPlayerOnos(pBot->Edict) && pBot->Player->GetResources() >= BALANCE_VAR(kOnosCost))
{
int NumOnos = AITAC_GetNumPlayersOnTeamOfClass(BotTeam, AVH_USER3_ALIEN_PLAYER5, pBot->Edict);
@ -4622,6 +4643,14 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
if (NearestSiegedHive)
{
// Check if we're already trying to break a siege attempt, so we don't get torn between multiple potentials
if (Task->TaskType == TASK_ATTACK)
{
const AvHAIHiveDefinition* HiveNearestAttackTarget = AITAC_GetNearestTeamHive(BotTeam, Task->TaskTarget->v.origin, false);
if (HiveNearestAttackTarget && vDist2DSq(HiveNearestAttackTarget->Location, Task->TaskTarget->v.origin) <= sqrf(UTIL_MetresToGoldSrcUnits(25.0f))) { return; }
}
DeployableSearchFilter EnemyStuffFilter;
EnemyStuffFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
EnemyStuffFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
@ -4681,6 +4710,14 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
// If we're up against marines, look out for any siege stuff
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_MARINE)
{
// Check if we're already trying to break a siege attempt, so we don't get torn between multiple potentials
if (Task->TaskType == TASK_ATTACK)
{
const AvHAIHiveDefinition* HiveNearestAttackTarget = AITAC_GetNearestTeamHive(BotTeam, Task->TaskTarget->v.origin, false);
if (HiveNearestAttackTarget && vDist2DSq(HiveNearestAttackTarget->Location, Task->TaskTarget->v.origin) <= sqrf(UTIL_MetresToGoldSrcUnits(25.0f))) { return; }
}
vector<AvHAIHiveDefinition*> AllTeamHives = AITAC_GetAllTeamHives(BotTeam, false);
for (auto it = AllTeamHives.begin(); it != AllTeamHives.end(); it++)
@ -4689,7 +4726,6 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
DeployableSearchFilter EnemyStuffFilter;
EnemyStuffFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
EnemyStuffFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
EnemyStuffFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
EnemyStuffFilter.DeployableTeam = EnemyTeam;
EnemyStuffFilter.ReachabilityTeam = BotTeam;
@ -4814,8 +4850,10 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
FriendlyStuffFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
FriendlyStuffFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
if (AITAC_DeployableExistsAtLocation(ThisHive->FloorLocation, &FriendlyStuffFilter)) { continue; }
// Don't guard a hive if some defences are already present
if (AITAC_GetNumDeployablesNearLocation(ThisHive->FloorLocation, &FriendlyStuffFilter) >= 2) { continue; }
// Only guard empty hives if a gorge is in there
if (AITAC_GetNumPlayersOfTeamAndClassInArea(BotTeam, ThisHive->FloorLocation, UTIL_MetresToGoldSrcUnits(20.0f), false, pBot->Edict, AVH_USER3_ALIEN_PLAYER2) == 0) { continue; }
bool bNeedsExtraGuards = true;
@ -4876,6 +4914,14 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
}
else if (HiveToSecure)
{
// Check if we're already trying to clear out a hive
if (Task->TaskType == TASK_ATTACK)
{
const AvHAIHiveDefinition* HiveNearestAttackTarget = AITAC_GetNearestTeamHive(BotTeam, Task->TaskTarget->v.origin, false);
if (HiveNearestAttackTarget && vDist2DSq(HiveNearestAttackTarget->Location, Task->TaskTarget->v.origin) <= sqrf(UTIL_MetresToGoldSrcUnits(15.0f))) { return; }
}
EnemyStuffFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
// Don't attack electrified structures as skulk
@ -5343,8 +5389,58 @@ void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
return;
}
AITASK_ClearBotTask(pBot, Task);
}
void AIPlayerSetWantsAndNeedsAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
float CurrentHealth = GetPlayerOverallHealthPercent(pBot->Edict);
if (Task->TaskType == TASK_GET_HEALTH)
{
Task->bTaskIsUrgent = Task->bTaskIsUrgent || CurrentHealth < 0.4f;
return;
}
if (CurrentHealth >= 1.0f) { return; }
bool bCanSelfHeal = (PlayerHasWeapon(pBot->Player, WEAPON_GORGE_HEALINGSPRAY) || PlayerHasWeapon(pBot->Player, WEAPON_FADE_METABOLIZE));
if (CurrentHealth < 0.95f && bCanSelfHeal && gpGlobals->time - pBot->LastCombatTime > 5.0f)
{
pBot->DesiredCombatWeapon = (PlayerHasWeapon(pBot->Player, WEAPON_FADE_METABOLIZE)) ? WEAPON_FADE_METABOLIZE : WEAPON_GORGE_HEALINGSPRAY;
if (GetPlayerCurrentWeapon(pBot->Player) == pBot->DesiredCombatWeapon)
{
pBot->Button |= IN_ATTACK;
}
}
// Only look for gorges as a healing source if we're something with low health like a skulk or lerk, or we have over 50% health. Don't use gorges if we're near death as an Onos or it will take forever...
edict_t* NearestHealingSource = AITAC_AlienFindNearestHealingSource(pBot->Player->GetTeam(), pBot->Edict->v.origin, pBot->Edict, (IsPlayerSkulk(pBot->Edict) || IsPlayerLerk(pBot->Edict) || CurrentHealth > 0.5f));
if (FNullEnt(NearestHealingSource)) { return; }
float GetHealthThreshold = 0.6f;
// If we're right by a healing source, then might as well heal up, set the "find health" threshold to 90% or less health
if (vDist2DSq(pBot->Edict->v.origin, NearestHealingSource->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
{
GetHealthThreshold = 0.9f;
}
else
{
// If we can heal ourselves, then don't go running for the hive/DCs/Gorge unless we're very low
if (bCanSelfHeal)
{
GetHealthThreshold = 0.4f;
}
}
if (CurrentHealth < GetHealthThreshold)
{
AITASK_SetGetHealthTask(pBot, Task, NearestHealingSource, true);
}
}
bool AlienCombatThink(AvHAIPlayer* pBot)
@ -6066,7 +6162,7 @@ bool FadeCombatThink(AvHAIPlayer* pBot)
bool bInHealingRange = (DistFromHealingSourceSq <= sqrf(DesiredDistFromHealingSource));
if (!bInHealingRange)
if (!bInHealingRange && GetPlayerOverallHealthPercent(pBot->Edict) < 0.5f)
{
MoveTo(pBot, UTIL_GetEntityGroundLocation(NearestHealingSource), MOVESTYLE_NORMAL, DesiredDistFromHealingSource);
@ -6078,11 +6174,24 @@ bool FadeCombatThink(AvHAIPlayer* pBot)
BotLeap(pBot, pBot->BotNavInfo.CurrentPathPoint->Location);
}
}
else
{
if (PlayerHasWeapon(pBot->Player, WEAPON_FADE_METABOLIZE))
{
pBot->DesiredCombatWeapon = WEAPON_FADE_METABOLIZE;
if (GetPlayerCurrentWeapon(pBot->Player) == WEAPON_FADE_METABOLIZE)
{
pBot->Button |= IN_ATTACK;
}
}
}
return true;
}
if (bOutOfEnemyLOS)
// If we're not in immediate danger, and we're either healing up at the source, or we can metabolize, then wait a bit and catch our breath
if (bOutOfEnemyLOS && (bInHealingRange || PlayerHasWeapon(pBot->Player, WEAPON_FADE_METABOLIZE)))
{
BotLookAt(pBot, TrackedEnemyRef->LastLOSPosition);
if (PlayerHasWeapon(pBot->Player, WEAPON_FADE_METABOLIZE))
@ -6100,10 +6209,21 @@ bool FadeCombatThink(AvHAIPlayer* pBot)
if (!UTIL_PlayerHasLOSToLocation(TrackedEnemyRef->EnemyEdict, UTIL_GetEntityGroundLocation(NearestHealingSource) + Vector(0.0f, 0.0f, 16.0f), UTIL_MetresToGoldSrcUnits(30.0f)))
{
MoveTo(pBot, UTIL_GetEntityGroundLocation(NearestHealingSource), MOVESTYLE_NORMAL, DesiredDistFromHealingSource);
if (PlayerHasWeapon(pBot->Player, WEAPON_FADE_METABOLIZE))
{
pBot->DesiredCombatWeapon = WEAPON_FADE_METABOLIZE;
if (GetPlayerCurrentWeapon(pBot->Player) == WEAPON_FADE_METABOLIZE)
{
pBot->Button |= IN_ATTACK;
}
}
return true;
}
// If the enemy can see the healing source, then we must go on the attack
// If the enemy can see the healing source, then we must go on the attack as we're cornered
bShouldBreakRetreat = true;
}
}

View file

@ -88,6 +88,7 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
void AIPlayerSetAlienHarasserPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
void AIPlayerSetWantsAndNeedsAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
void BotSwitchToWeapon(AvHAIPlayer* pBot, AvHAIWeapon NewWeaponSlot);

View file

@ -30,6 +30,8 @@ float AIStartedTime = 0.0f; // Used to give 5-second grace period before adding
bool bHasRoundStarted = false;
bool bMapDataInitialised = false;
bool bTestNavigation = false;
extern int m_spriteTexture;
Vector DebugVector1 = ZERO_VECTOR;
@ -623,7 +625,15 @@ void AIMGR_UpdateAIPlayers()
UpdateBotChat(bot);
DroneThink(bot);
if (bTestNavigation)
{
TestNavThink(bot);
}
else
{
DroneThink(bot);
}
EndBotFrame(bot);
@ -1051,4 +1061,14 @@ void AIMGR_SetDebugAIPlayer(edict_t* AIPlayer)
return;
}
}
}
void AIMGR_SetTestNavMode(bool bNewValue)
{
bTestNavigation = bNewValue;
}
bool AIMGR_GetTestNavMode()
{
return bTestNavigation;
}

View file

@ -87,4 +87,7 @@ void AIMGR_ClearBotData();
AvHAIPlayer* AIMGR_GetDebugAIPlayer();
void AIMGR_SetDebugAIPlayer(edict_t* AIPlayer);
void AIMGR_SetTestNavMode(bool bNewValue);
bool AIMGR_GetTestNavMode();
#endif

View file

@ -2628,6 +2628,8 @@ bool AITAC_ElectricalResearchIsAvailable(edict_t* Structure)
AvHAIHiveDefinition* AITAC_GetHiveFromEdict(const edict_t* Edict)
{
if (Edict->v.iuser3 != AVH_USER3_HIVE) { return nullptr; }
for (auto it = Hives.begin(); it != Hives.end(); it++)
{
if (it->HiveEntity->edict() == Edict)
@ -4428,7 +4430,7 @@ bool AITAC_IsAlienBuilderNeeded(AvHAIPlayer* pBot)
}
AvHAIDeployableStructureType AITAC_GetNextMissingUpgradeChamberForTeam(AvHTeamNumber Team)
AvHAIDeployableStructureType AITAC_GetNextMissingUpgradeChamberForTeam(AvHTeamNumber Team, int& NumMissing)
{
if (AIMGR_GetTeamType(Team) != AVH_CLASS_TYPE_ALIEN) { return STRUCTURE_NONE; }
@ -4453,6 +4455,7 @@ AvHAIDeployableStructureType AITAC_GetNextMissingUpgradeChamberForTeam(AvHTeamNu
if (NumChambers < 3)
{
NumMissing = 3 - NumChambers;
return ChamberTypeOne;
}
}
@ -4465,6 +4468,7 @@ AvHAIDeployableStructureType AITAC_GetNextMissingUpgradeChamberForTeam(AvHTeamNu
if (NumChambers < 3)
{
NumMissing = 3 - NumChambers;
return ChamberTypeTwo;
}
}
@ -4477,6 +4481,7 @@ AvHAIDeployableStructureType AITAC_GetNextMissingUpgradeChamberForTeam(AvHTeamNu
if (NumChambers < 3)
{
NumMissing = 3 - NumChambers;
return ChamberTypeThree;
}
}

View file

@ -176,7 +176,7 @@ bool AITAC_IsAlienHarasserNeeded(AvHAIPlayer* pBot);
bool AITAC_ShouldBotBuildHive(AvHAIPlayer* pBot, AvHAIHiveDefinition** EligibleHive);
AvHAIDeployableStructureType AITAC_GetNextMissingUpgradeChamberForTeam(AvHTeamNumber Team);
AvHAIDeployableStructureType AITAC_GetNextMissingUpgradeChamberForTeam(AvHTeamNumber Team, int& NumMissing);
void AITAC_OnTeamStartsModified();

View file

@ -1035,14 +1035,6 @@ void BotProgressMoveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
MoveDirectlyTo(pBot, Task->TaskLocation);
}
if (IsPlayerMarine(pBot->Edict))
{
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
{
BotReloadWeapons(pBot);
}
}
}
void BotProgressTouchTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
@ -1225,22 +1217,18 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
SearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
}
AvHAIDeployableStructureType NextStructure = AITAC_GetNextMissingUpgradeChamberForTeam(BotTeam);
AvHAIDeployableStructureType NextStructure = STRUCTURE_NONE;
DeployableSearchFilter StructureFilter;
StructureFilter.DeployableTeam = BotTeam;
StructureFilter.MaxSearchRadius = SearchRadius;
StructureFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
if (NextStructure == STRUCTURE_NONE)
int NumOCs = AITAC_GetNumDeployablesNearLocation(ReinforceLocation, &StructureFilter);
if (NumOCs < 3)
{
StructureFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
int NumOCs = AITAC_GetNumDeployablesNearLocation(ReinforceLocation, &StructureFilter);
if (NumOCs < 3)
{
NextStructure = STRUCTURE_ALIEN_OFFENCECHAMBER;
}
NextStructure = STRUCTURE_ALIEN_OFFENCECHAMBER;
}
if (NextStructure == STRUCTURE_NONE)
@ -1548,14 +1536,6 @@ void MarineProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
MoveTo(pBot, Task->TaskTarget->v.origin, MOVESTYLE_NORMAL);
if (IsPlayerMarine(pBot->Edict))
{
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
{
BotReloadWeapons(pBot);
}
}
if (vDist2DSq(pBot->Edict->v.origin, Task->TaskTarget->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
{
BotLookAt(pBot, UTIL_GetCentreOfEntity(Task->TaskTarget));
@ -1565,13 +1545,6 @@ void MarineProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
void BotProgressGuardTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (IsPlayerMarine(pBot->Edict))
{
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
{
BotReloadWeapons(pBot);
}
}
if (vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation) > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
{
@ -2816,7 +2789,7 @@ AvHAIPlayer* GetFirstBotWithBuildTask(AvHTeamNumber Team, AvHAIDeployableStructu
{
AvHAIPlayer* Bot = (*it);
if (!IsPlayerActiveInGame(Bot->Edict)) { continue; }
if (!IsPlayerActiveInGame(Bot->Edict) || Bot->Edict == IgnorePlayer) { continue; }
bool bPrimaryIsBuildTask = (Bot->PrimaryBotTask.TaskType == TASK_BUILD || Bot->PrimaryBotTask.TaskType == TASK_REINFORCE_STRUCTURE);
bool bSecondaryIsBuildTask = (Bot->SecondaryBotTask.TaskType == TASK_BUILD || Bot->SecondaryBotTask.TaskType == TASK_REINFORCE_STRUCTURE);
@ -2831,6 +2804,30 @@ AvHAIPlayer* GetFirstBotWithBuildTask(AvHTeamNumber Team, AvHAIDeployableStructu
return nullptr;
}
int AITASK_GetNumBotsWithBuildTask(AvHTeamNumber Team, AvHAIDeployableStructureType StructureType, edict_t* IgnorePlayer)
{
vector<AvHAIPlayer*> AIPlayers = AIMGR_GetAIPlayersOnTeam(Team);
int Result = 0;
for (auto it = AIPlayers.begin(); it != AIPlayers.end(); it++)
{
AvHAIPlayer* Bot = (*it);
if (!IsPlayerActiveInGame(Bot->Edict) || Bot->Edict == IgnorePlayer) { continue; }
bool bPrimaryIsBuildTask = (Bot->PrimaryBotTask.TaskType == TASK_BUILD || Bot->PrimaryBotTask.TaskType == TASK_REINFORCE_STRUCTURE);
bool bSecondaryIsBuildTask = (Bot->SecondaryBotTask.TaskType == TASK_BUILD || Bot->SecondaryBotTask.TaskType == TASK_REINFORCE_STRUCTURE);
if ((bPrimaryIsBuildTask && Bot->PrimaryBotTask.StructureType == StructureType) || (bSecondaryIsBuildTask && Bot->SecondaryBotTask.StructureType == StructureType))
{
Result++;
}
}
return Result;
}
AvHAIPlayer* GetFirstBotWithReinforceTask(AvHTeamNumber Team, edict_t* ReinforceStructure, edict_t* IgnorePlayer)
{
vector<AvHAIPlayer*> AIPlayers = AIMGR_GetAIPlayersOnTeam(Team);
@ -2839,7 +2836,7 @@ AvHAIPlayer* GetFirstBotWithReinforceTask(AvHTeamNumber Team, edict_t* Reinforce
{
AvHAIPlayer* Bot = (*it);
if (!IsPlayerActiveInGame(Bot->Edict)) { continue; }
if (!IsPlayerActiveInGame(Bot->Edict) || Bot->Edict == IgnorePlayer) { continue; }
if ((Bot->PrimaryBotTask.TaskType == TASK_REINFORCE_STRUCTURE && Bot->PrimaryBotTask.TaskTarget == ReinforceStructure) || (Bot->SecondaryBotTask.TaskType == TASK_REINFORCE_STRUCTURE && Bot->SecondaryBotTask.TaskTarget == ReinforceStructure))
{
@ -2948,6 +2945,47 @@ void AITASK_SetPickupTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Tar
}
void AITASK_SetGetHealthTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* HealingSource, const bool bIsUrgent)
{
if (Task->TaskType == TASK_GET_HEALTH && Task->TaskTarget == HealingSource)
{
Task->bTaskIsUrgent = bIsUrgent;
return;
}
AITASK_ClearBotTask(pBot, Task);
if (FNullEnt(HealingSource)) { return; }
Vector HealLocation = ZERO_VECTOR;
AvHAIHiveDefinition* HiveRef = AITAC_GetHiveFromEdict(HealingSource);
if (HiveRef)
{
HealLocation = HiveRef->FloorLocation;
}
else
{
if (IsEdictPlayer(HealingSource))
{
HealLocation = HealingSource->v.origin;
}
else
{
HealLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, HealingSource->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
}
}
if (!vIsZero(HealLocation))
{
Task->TaskType = TASK_GET_HEALTH;
Task->TaskTarget = HealingSource;
Task->TaskLocation = HealLocation;
Task->bTaskIsUrgent = bIsUrgent;
}
}
void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const bool bIsUrgent)
{
if (FNullEnt(Target) || (Target->v.deadflag != DEAD_NO))

View file

@ -68,6 +68,7 @@ void AITASK_SetSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t*
void AITASK_SetMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, bool bIsUrgent);
void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const bool bIsUrgent);
void AITASK_SetPickupTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const bool bIsUrgent);
void AITASK_SetGetHealthTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* HealingSource, const bool bIsUrgent);
void BotProgressTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
@ -104,6 +105,7 @@ void BotGuardLocation(AvHAIPlayer* pBot, const Vector GuardLocation);
void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocation);
bool BotWithBuildTaskExists(AvHTeamNumber Team, AvHAIDeployableStructureType StructureType);
int AITASK_GetNumBotsWithBuildTask(AvHTeamNumber Team, AvHAIDeployableStructureType StructureType, edict_t* IgnorePlayer);
AvHAIPlayer* GetFirstBotWithBuildTask(AvHTeamNumber Team, AvHAIDeployableStructureType StructureType, edict_t* IgnorePlayer);
AvHAIPlayer* GetFirstBotWithReinforceTask(AvHTeamNumber Team, edict_t* ReinforceStructure, edict_t* IgnorePlayer);

View file

@ -392,6 +392,18 @@ AvHGamerules::AvHGamerules() : mTeamA(TEAM_ONE), mTeamB(TEAM_TWO)
AIMGR_RemoveAIPlayerFromTeam(DesiredTeam);
});
REGISTER_SERVER_FUNCTION("sv_testainavigation", []()
{
if (avh_botsenabled.value == 0)
{
return;
}
bool bNewTestValue = !AIMGR_GetTestNavMode();
AIMGR_SetTestNavMode(bNewTestValue);
});
g_VoiceGameMgr.Init(&gVoiceHelper, gpGlobals->maxClients);
#ifdef DEBUG