Bots attack turrets

This commit is contained in:
RGreenlees 2024-02-21 17:21:23 +00:00 committed by pierow
parent 2789e7a57c
commit 3add6092d9
10 changed files with 417 additions and 57 deletions

View file

@ -104,6 +104,7 @@ typedef enum
STRUCTURE_STATUS_UNDERATTACK = 1 << 4,
STRUCTURE_STATUS_RESEARCHING = 1 << 5,
STRUCTURE_STATUS_DAMAGED = 1 << 6,
STRUCTURE_STATUS_DISABLED = 1 << 7, // For marine turrets when there's no TF
STRUCTURE_STATUS_ALL = -1
} AvHAIStructureStatus;
@ -715,6 +716,8 @@ typedef struct AVH_AI_PLAYER
AvHAICombatStrategy CurrentCombatStrategy = COMBAT_STRATEGY_ATTACK;
edict_t* CurrentEnemyRef = nullptr;
vector<AvHAIBuildableStructure*> DangerTurrets;
AvHAIPlayerTask* CurrentTask = nullptr; // Bot's current task they're performing
AvHAIPlayerTask PrimaryBotTask;
AvHAIPlayerTask SecondaryBotTask;

View file

@ -243,7 +243,7 @@ bool IsDamagingStructure(AvHAIDeployableStructureType StructureType)
switch (StructureType)
{
case STRUCTURE_ALIEN_OFFENCECHAMBER:
case STRUCTURE_MARINE_TURRETFACTORY:
case STRUCTURE_MARINE_TURRET:
return true;
default:
return false;

View file

@ -14,6 +14,7 @@
#include "../AvHGamerules.h"
#include "../AvHMessage.h"
#include "../AvHTurret.h"
extern nav_mesh NavMeshes[MAX_NAV_MESHES]; // Array of nav meshes. Currently only 3 are used (building, onos, and regular)
extern nav_profile BaseNavProfiles[MAX_NAV_PROFILES]; // Array of nav profiles
@ -1312,7 +1313,8 @@ void BotUpdateView(AvHAIPlayer* pBot)
bool bHasLOSToAnyEnemy = false;
int EnemyTeam = 0;
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
pBot->ViewForwardVector = UTIL_GetForwardVector(pBot->Edict->v.v_angle);
@ -1475,7 +1477,41 @@ void BotUpdateView(AvHAIPlayer* pBot)
}
}
if (!bHasLOSToAnyEnemy)
pBot->DangerTurrets.clear();
bool bIsInRangeOfEnemyTurret = false;
DeployableSearchFilter EnemyTurretFilter;
EnemyTurretFilter.DeployableTeam = EnemyTeam;
EnemyTurretFilter.ExcludeStatusFlags = (STRUCTURE_STATUS_RECYCLING | STRUCTURE_STATUS_DISABLED);
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_ALIEN)
{
EnemyTurretFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
EnemyTurretFilter.MaxSearchRadius = 700.0f; // For some reason, offence chambers have a hard-coded range
}
else
{
EnemyTurretFilter.DeployableTypes = STRUCTURE_MARINE_TURRET;
EnemyTurretFilter.MaxSearchRadius = BALANCE_VAR(kTurretRange);
}
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);
if (TurretRef && TurretRef->GetIsValidTarget(pBot->Player))
{
bIsInRangeOfEnemyTurret = true;
pBot->DangerTurrets.push_back(ThisTurret);
}
}
if (!bHasLOSToAnyEnemy && !bIsInRangeOfEnemyTurret)
{
pBot->LastSafeLocation = pBot->Edict->v.origin;
}
@ -1792,13 +1828,6 @@ void DroneThink(AvHAIPlayer* pBot)
BotProgressTask(pBot, &pBot->PrimaryBotTask);
}
AIDEBUG_DrawBotPath(pBot);
if (pBot->BotNavInfo.CurrentPathPoint != pBot->BotNavInfo.CurrentPath.end())
{
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->BotNavInfo.CurrentPathPoint->Location, 0, 255, 255);
}
}
void SetNewAIPlayerRole(AvHAIPlayer* pBot, AvHAIBotRole NewRole)
@ -3347,6 +3376,53 @@ void AIPlayerSetMarineBombardierPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask*
}
void AIPlayerSetWantsAndNeedsCOMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
{
if (BotReloadWeapons(pBot)) { return; }
}
if (Task->TaskType == TASK_RESUPPLY) { return; }
bool bNeedsHealth = pBot->Edict->v.health < (pBot->Edict->v.max_health * 0.9f);
bool bNeedsAmmo = UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) < (UTIL_GetPlayerPrimaryMaxAmmoReserve(pBot->Player) * 0.9f);
if (bNeedsHealth || bNeedsAmmo)
{
bool bTaskIsUrgent = (pBot->Edict->v.health < (pBot->Edict->v.max_health * 0.7f)) || (UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) < UTIL_GetPlayerPrimaryWeaponMaxClipSize(pBot->Player));
float SearchRadius = (bTaskIsUrgent) ? UTIL_MetresToGoldSrcUnits(20.0f) : UTIL_MetresToGoldSrcUnits(5.0f);
// If we're completely out of primary weapon ammo then always head back regardless of where we are in the map
if (UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) == 0 && UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) == 0)
{
SearchRadius = 0.0f;
}
DeployableSearchFilter NearestArmouryFilter;
NearestArmouryFilter.DeployableTypes = (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY);
NearestArmouryFilter.DeployableTeam = pBot->Player->GetTeam();
NearestArmouryFilter.ReachabilityTeam = pBot->Player->GetTeam();
NearestArmouryFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
NearestArmouryFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
NearestArmouryFilter.MaxSearchRadius = SearchRadius;
AvHAIBuildableStructure* NearestArmoury = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &NearestArmouryFilter);
// We really need some health or ammo, hit the armoury
if (NearestArmoury)
{
Task->TaskType = TASK_RESUPPLY;
Task->bTaskIsUrgent = true;
Task->TaskLocation = NearestArmoury->Location;
Task->TaskTarget = NearestArmoury->edict;
return;
}
}
}
void AIPlayerSetWantsAndNeedsMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
@ -3604,6 +3680,56 @@ void AIPlayerSetSecondaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
if (pBot->DangerTurrets.size() > 0)
{
AvHAIBuildableStructure* NearestDangerTurret = nullptr;
float MinDist = 0.0f;
for (auto it = pBot->DangerTurrets.begin(); it != pBot->DangerTurrets.end(); it++)
{
float ThisDist = vDist2DSq(pBot->Edict->v.origin, (*it)->Location);
if (!NearestDangerTurret || ThisDist < MinDist)
{
NearestDangerTurret = (*it);
}
}
if (NearestDangerTurret)
{
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_ALIEN)
{
AITASK_SetAttackTask(pBot, Task, NearestDangerTurret->edict, true);
return;
}
else
{
DeployableSearchFilter EnemyTFFilter;
EnemyTFFilter.DeployableTeam = EnemyTeam;
EnemyTFFilter.DeployableTypes = (STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY);
EnemyTFFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
EnemyTFFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
EnemyTFFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
EnemyTFFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
EnemyTFFilter.ReachabilityTeam = BotTeam;
AvHAIBuildableStructure* EnemyTF = AITAC_FindClosestDeployableToLocation(NearestDangerTurret->Location, &EnemyTFFilter);
if (EnemyTF)
{
AITASK_SetAttackTask(pBot, Task, EnemyTF->edict, true);
return;
}
else
{
AITASK_SetAttackTask(pBot, Task, NearestDangerTurret->edict, true);
return;
}
}
}
}
// Find any nearby unbuilt structures
DeployableSearchFilter UnbuiltFilter;
@ -4243,6 +4369,7 @@ void AIPlayerCOMarineThink(AvHAIPlayer* pBot)
AIPlayerSetPrimaryCOMarineTask(pBot, &pBot->PrimaryBotTask);
AIPlayerSetSecondaryCOMarineTask(pBot, &pBot->SecondaryBotTask);
AIPlayerSetWantsAndNeedsCOMarineTask(pBot, &pBot->WantsAndNeedsTask);
}
pBot->CurrentTask = AIPlayerGetNextTask(pBot);
@ -4285,6 +4412,7 @@ void AIPlayerCOAlienThink(AvHAIPlayer* pBot)
AIPlayerSetPrimaryCOAlienTask(pBot, &pBot->PrimaryBotTask);
AIPlayerSetSecondaryCOAlienTask(pBot, &pBot->SecondaryBotTask);
AIPlayerSetWantsAndNeedsAlienTask(pBot, &pBot->WantsAndNeedsTask);
}
pBot->CurrentTask = AIPlayerGetNextTask(pBot);
@ -4621,7 +4749,7 @@ void AIPlayerSetSecondaryCOAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
float ThisDist = vDist2D(pBot->Edict->v.origin, TheHive->FloorLocation);
int NumExistingDefenders = AITAC_GetNumPlayersOfTeamInArea(BotTeam, TheHive->FloorLocation, ThisDist - 10.0f, false, pBot->Edict, AVH_USER3_COMMANDER_PLAYER);
int NumExistingDefenders = AITAC_GetNumPlayersOfTeamInArea(BotTeam, TheHive->FloorLocation, ThisDist - 10.0f, false, pBot->Edict, AVH_USER3_ALIEN_PLAYER2);
if (NumExistingDefenders < MaxDefenders)
{
@ -4630,30 +4758,54 @@ void AIPlayerSetSecondaryCOAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
}
if (TheHive->HealthPercent < 1.0f && IsPlayerGorge(pBot->Edict))
if (IsPlayerGorge(pBot->Edict))
{
Task->TaskType = TASK_HEAL;
Task->TaskTarget = TheHive->HiveEdict;
Task->bTaskIsUrgent = true;
return;
edict_t* TeamMateToHeal = nullptr;
vector<AvHPlayer*> AllNearbyTeammates = AITAC_GetAllPlayersOfTeamInArea(BotTeam, pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f), false, pBot->Edict, AVH_USER3_ALIEN_PLAYER2);
float MinDist = 0.0f;
for (auto it = AllNearbyTeammates.begin(); it != AllNearbyTeammates.end(); it++)
{
edict_t* ThisPlayer = (*it)->edict();
if (!FNullEnt(ThisPlayer) && IsPlayerActiveInGame(ThisPlayer) && GetPlayerOverallHealthPercent(ThisPlayer) < 0.99f)
{
float ThisDist = vDist2DSq(pBot->Edict->v.origin, ThisPlayer->v.origin);
if (FNullEnt(TeamMateToHeal) || ThisDist < MinDist)
{
TeamMateToHeal = ThisPlayer;
}
}
}
if (!FNullEnt(TeamMateToHeal))
{
Task->TaskType = TASK_HEAL;
Task->TaskTarget = TeamMateToHeal;
Task->bTaskIsUrgent = true;
return;
}
if (TheHive->HealthPercent < 1.0f)
{
Task->TaskType = TASK_HEAL;
Task->TaskTarget = TheHive->HiveEdict;
Task->bTaskIsUrgent = true;
return;
}
}
if (TheHive->HealthPercent < 0.8f)
if (pBot->BotRole == BOT_ROLE_SWEEPER && !IsPlayerGorge(pBot->Edict) && TheHive->HealthPercent < 0.8f)
{
if (IsPlayerGorge(pBot->Edict) || (pBot->BotRole == BOT_ROLE_SWEEPER && pBot->ExperiencePointsAvailable >= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_TWO)))
if (pBot->ExperiencePointsAvailable >= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_TWO))
{
if (!IsPlayerGorge(pBot->Edict))
{
AITASK_SetEvolveTask(pBot, Task, TheHive->HiveEdict, ALIEN_LIFEFORM_TWO, true);
return;
}
else
{
Task->TaskType = TASK_HEAL;
Task->TaskTarget = TheHive->HiveEdict;
Task->bTaskIsUrgent = true;
return;
}
}
}
@ -4700,18 +4852,6 @@ void AIPlayerDMThink(AvHAIPlayer* pBot)
void AIPlayerThink(AvHAIPlayer* pBot)
{
if (pBot == AIMGR_GetDebugAIPlayer())
{
bool bBreak = true;
AIDEBUG_DrawBotPath(pBot);
if (pBot->BotNavInfo.CurrentPathPoint != pBot->BotNavInfo.CurrentPath.end())
{
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->BotNavInfo.CurrentPathPoint->Location, 0, 255, 255);
}
}
switch (GetGameRules()->GetMapMode())
{
case MAP_MODE_NS:
@ -4728,18 +4868,6 @@ void AIPlayerThink(AvHAIPlayer* pBot)
void TestNavThink(AvHAIPlayer* pBot)
{
if (pBot == AIMGR_GetDebugAIPlayer())
{
bool bBreak = true; // Add a break point here if you want to debug a specific bot
AIDEBUG_DrawBotPath(pBot);
if (pBot->BotNavInfo.CurrentPathPoint != pBot->BotNavInfo.CurrentPath.end())
{
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->BotNavInfo.CurrentPathPoint->Location, 0, 255, 255);
}
}
AITASK_BotUpdateAndClearTasks(pBot);
pBot->CurrentTask = &pBot->PrimaryBotTask;
@ -4807,13 +4935,22 @@ void TestNavThink(AvHAIPlayer* pBot)
}
else
{
AvHAIResourceNode* RandomNode = AITAC_GetRandomResourceNode((AvHTeamNumber)pBot->Edict->v.team, pBot->BotNavInfo.NavProfile.ReachabilityFlag);
Vector RandomPoint = ZERO_VECTOR;
if (!RandomNode) { return; }
if (GetGameRules()->GetMapMode() == MAP_MODE_NS)
{
AvHAIResourceNode* RandomNode = AITAC_GetRandomResourceNode((AvHTeamNumber)pBot->Edict->v.team, pBot->BotNavInfo.NavProfile.ReachabilityFlag);
Vector RandomPoint = RandomNode->Location;
if (!RandomNode) { return; }
if (RandomPoint != ZERO_VECTOR && UTIL_PointIsReachable(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, RandomPoint, max_player_use_reach))
Vector RandomPoint = RandomNode->Location;
}
else
{
RandomPoint = UTIL_GetRandomPointOnNavmeshInRadius(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(100.0f));
}
if (!vIsZero(RandomPoint) && UTIL_PointIsReachable(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, RandomPoint, max_player_use_reach))
{
AITASK_SetMoveTask(pBot, &pBot->PrimaryBotTask, RandomPoint, true);
}
@ -5970,6 +6107,60 @@ void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
if (pBot->DangerTurrets.size() > 0)
{
AvHAIBuildableStructure* NearestDangerTurret = nullptr;
float MinDist = 0.0f;
for (auto it = pBot->DangerTurrets.begin(); it != pBot->DangerTurrets.end(); it++)
{
float ThisDist = vDist2DSq(pBot->Edict->v.origin, (*it)->Location);
if (!NearestDangerTurret || ThisDist < MinDist)
{
NearestDangerTurret = (*it);
}
}
if (NearestDangerTurret)
{
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_ALIEN)
{
AITASK_SetAttackTask(pBot, Task, NearestDangerTurret->edict, true);
return;
}
else
{
DeployableSearchFilter EnemyTFFilter;
EnemyTFFilter.DeployableTeam = EnemyTeam;
EnemyTFFilter.DeployableTypes = (STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY);
EnemyTFFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
EnemyTFFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
if (pBot->Player->GetUser3() == AVH_USER3_ALIEN_PLAYER1 || pBot->Player->GetUser3() == AVH_USER3_ALIEN_PLAYER3)
{
EnemyTFFilter.ExcludeStatusFlags |= STRUCTURE_STATUS_ELECTRIFIED;
}
EnemyTFFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
EnemyTFFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
EnemyTFFilter.ReachabilityTeam = BotTeam;
AvHAIBuildableStructure* EnemyTF = AITAC_FindClosestDeployableToLocation(NearestDangerTurret->Location, &EnemyTFFilter);
if (EnemyTF)
{
AITASK_SetAttackTask(pBot, Task, EnemyTF->edict, true);
return;
}
else
{
AITASK_SetAttackTask(pBot, Task, NearestDangerTurret->edict, true);
return;
}
}
}
}
if (IsPlayerGorge(pBot->Edict))
{
edict_t* TeamMateToHeal = nullptr;
@ -6198,6 +6389,39 @@ void AIPlayerSetWantsAndNeedsAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
float CurrentHealth = GetPlayerOverallHealthPercent(pBot->Edict);
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
if (PlayerHasWeapon(pBot->Player, WEAPON_LERK_PRIMALSCREAM) && !pBot->Player->GetIsScreaming())
{
vector<AvHPlayer*> NearbyAllies = AITAC_GetAllPlayersOfTeamInArea(pBot->Player->GetTeam(), pBot->Edict->v.origin, BALANCE_VAR(kPrimalScreamRange), false, pBot->Edict, AVH_USER3_ALIEN_PLAYER2);
int NumBuffTargets = 0;
for (auto it = NearbyAllies.begin(); it != NearbyAllies.end(); it++)
{
AvHPlayer* ThisPlayer = (*it);
edict_t* ThisPlayerEdict = ThisPlayer->edict();
if (AITAC_AnyPlayerOnTeamWithLOS(EnemyTeam, ThisPlayerEdict->v.origin, UTIL_MetresToGoldSrcUnits(10.0f)))
{
NumBuffTargets++;
}
}
if (NumBuffTargets > 0)
{
pBot->DesiredCombatWeapon = WEAPON_LERK_PRIMALSCREAM;
if (GetPlayerCurrentWeapon(pBot->Player) == WEAPON_LERK_PRIMALSCREAM)
{
pBot->Button |= IN_ATTACK;
}
return;
}
}
if (Task->TaskType == TASK_GET_HEALTH)
{
Task->bTaskIsUrgent = Task->bTaskIsUrgent || CurrentHealth < 0.4f;
@ -6814,6 +7038,7 @@ bool LerkCombatThink(AvHAIPlayer* pBot)
enemy_status* TrackedEnemyRef = &pBot->TrackedEnemies[pBot->CurrentEnemy];
if (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_RETREAT)
{
edict_t* NearestHealingSource = AITAC_AlienFindNearestHealingSource(pBot->Player->GetTeam(), pBot->Edict->v.origin, pBot->Edict, true);
@ -6886,6 +7111,18 @@ bool LerkCombatThink(AvHAIPlayer* pBot)
if (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_ATTACK)
{
if (PlayerHasWeapon(pBot->Player, WEAPON_LERK_PRIMALSCREAM) && !pBot->Player->GetIsScreaming())
{
pBot->DesiredCombatWeapon = WEAPON_LERK_SPORES;
if (GetPlayerCurrentWeapon(pBot->Player) == WEAPON_LERK_PRIMALSCREAM)
{
pBot->Button |= IN_ATTACK;
}
return true;
}
AvHAIWeapon DesiredWeapon = WEAPON_LERK_BITE;
if (vDist2DSq(pBot->Edict->v.origin, CurrentEnemy->v.origin) > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))

View file

@ -31,6 +31,7 @@ bool bHasRoundStarted = false;
bool bMapDataInitialised = false;
bool bTestNavigation = false;
bool bDroneMode = false;
extern int m_spriteTexture;
@ -614,6 +615,18 @@ void AIMGR_UpdateAIPlayers()
{
BotDeltaTime = ThinkDelta;
if (bot == AIMGR_GetDebugAIPlayer())
{
bool bBreak = true; // Add a break point here if you want to debug a specific bot
AIDEBUG_DrawBotPath(bot);
if (bot->BotNavInfo.CurrentPathPoint != bot->BotNavInfo.CurrentPath.end())
{
UTIL_DrawLine(INDEXENT(1), bot->Edict->v.origin, bot->BotNavInfo.CurrentPathPoint->Location, 0, 255, 255);
}
}
if (bHasRoundStarted && ShouldBotThink(bot))
{
if (bot->bIsInactive)
@ -625,15 +638,18 @@ void AIMGR_UpdateAIPlayers()
UpdateBotChat(bot);
if (bTestNavigation)
if (bDroneMode)
{
DroneThink(bot);
}
else if (bTestNavigation)
{
TestNavThink(bot);
}
else
{
AIPlayerThink(bot);
}
}
EndBotFrame(bot);
@ -1053,6 +1069,12 @@ AvHAIPlayer* AIMGR_GetDebugAIPlayer()
void AIMGR_SetDebugAIPlayer(edict_t* AIPlayer)
{
if (FNullEnt(AIPlayer))
{
DebugAIPlayer = nullptr;
return;
}
for (auto it = ActiveAIPlayers.begin(); it != ActiveAIPlayers.end(); it++)
{
if (it->Edict == AIPlayer)
@ -1061,14 +1083,34 @@ void AIMGR_SetDebugAIPlayer(edict_t* AIPlayer)
return;
}
}
DebugAIPlayer = nullptr;
}
void AIMGR_SetTestNavMode(bool bNewValue)
{
if (bNewValue)
{
bDroneMode = false;
}
bTestNavigation = bNewValue;
}
void AIMGR_SetDroneMode(bool bNewValue)
{
if (bNewValue)
{
bTestNavigation = false;
}
bDroneMode = bNewValue;
}
bool AIMGR_GetTestNavMode()
{
return bTestNavigation;
}
bool AIMGR_GetDroneMode()
{
return bTestNavigation;
}

View file

@ -90,4 +90,7 @@ void AIMGR_SetDebugAIPlayer(edict_t* AIPlayer);
void AIMGR_SetTestNavMode(bool bNewValue);
bool AIMGR_GetTestNavMode();
void AIMGR_SetDroneMode(bool bNewValue);
bool AIMGR_GetDroneMode();
#endif

View file

@ -23,6 +23,7 @@
#include "../AvHServerUtil.h"
#include "../AvHSharedUtil.h"
#include "../AvHMarineEquipment.h"
#include "../AvHTurret.h"
#include <float.h>
@ -2037,6 +2038,16 @@ AvHAIBuildableStructure* AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
NewFlags |= STRUCTURE_STATUS_RESEARCHING;
}
if (StructureType == STRUCTURE_MARINE_TURRET)
{
AvHTurret* TurretRef = dynamic_cast<AvHTurret*>(BaseBuildable);
if (TurretRef && !TurretRef->GetEnabledState())
{
NewFlags |= STRUCTURE_STATUS_DISABLED;
}
}
float NewHealthPercent = (BuildingEdict->v.health / BuildingEdict->v.max_health);
if (NewHealthPercent < BuildingMap[EntIndex].healthPercent)

View file

@ -13,6 +13,7 @@
#include "../AvHAlienWeaponConstants.h"
#include "../AvHGamerules.h"
#include "../AvHWeldable.h"
#include "../AvHTurret.h"
extern nav_mesh NavMeshes[MAX_NAV_MESHES]; // Array of nav meshes. Currently only 3 are used (building, onos, and regular)
extern nav_profile BaseNavProfiles[MAX_NAV_PROFILES]; // Array of nav profiles
@ -1604,6 +1605,26 @@ void BotProgressAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
Weapon = BotAlienChooseBestWeaponForStructure(pBot, Task->TaskTarget);
}
if (IsPlayerMarine(pBot->Player) && IsDamagingStructure(Task->TaskTarget) && !IsMeleeWeapon(Weapon))
{
if (GetPlayerCurrentWeaponClipAmmo(pBot->Player) == 0 || IsPlayerReloading(pBot->Player))
{
BotReloadWeapons(pBot);
AvHTurret* TurretRef = dynamic_cast<AvHTurret*>(CBaseEntity::Instance(Task->TaskTarget));
if (TurretRef && TurretRef->GetIsValidTarget(pBot->Player))
{
if (vIsZero(pBot->LastSafeLocation))
{
pBot->LastSafeLocation = AITAC_GetTeamStartingLocation(pBot->Player->GetTeam());
}
MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL);
}
}
}
BotAttackResult AttackResult = PerformAttackLOSCheck(pBot, Weapon, Task->TaskTarget);
if (AttackResult == ATTACK_SUCCESS)
@ -1616,6 +1637,24 @@ void BotProgressAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
BotShootTarget(pBot, Weapon, Task->TaskTarget);
if (IsDamagingStructure(Task->TaskTarget))
{
Vector EnemyOrientation = UTIL_GetVectorNormal2D(Task->TaskTarget->v.origin - pBot->Edict->v.origin);
Vector RightDir = UTIL_GetCrossProduct(EnemyOrientation, UP_VECTOR);
pBot->desiredMovementDir = (pBot->BotNavInfo.bZig) ? UTIL_GetVectorNormal2D(RightDir) : UTIL_GetVectorNormal2D(-RightDir);
// Let's get ziggy with it
if (gpGlobals->time > pBot->BotNavInfo.NextZigTime)
{
pBot->BotNavInfo.bZig = !pBot->BotNavInfo.bZig;
pBot->BotNavInfo.NextZigTime = gpGlobals->time + frandrange(0.5f, 1.0f);
}
BotMovementInputs(pBot);
}
return;
}

View file

@ -742,7 +742,7 @@ AvHAIWeapon BotMarineChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* ta
{
AvHAIDeployableStructureType StructureType = GetStructureTypeFromEdict(target);
if (StructureType == STRUCTURE_NONE || StructureType == STRUCTURE_ALIEN_HIVE || IsDamagingStructure(StructureType))
if (StructureType == STRUCTURE_NONE || StructureType == STRUCTURE_ALIEN_HIVE || IsDamagingStructure(StructureType) || UTIL_IsStructureElectrified(target))
{
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 || UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0)
{

View file

@ -1505,6 +1505,10 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
{
AIMGR_SetDebugAIPlayer(SpectatedPlayer->edict());
}
else
{
AIMGR_SetDebugAIPlayer(nullptr);
}
theSuccess = true;
}

View file

@ -403,6 +403,27 @@ AvHGamerules::AvHGamerules() : mTeamA(TEAM_ONE), mTeamB(TEAM_TWO)
AIMGR_SetTestNavMode(bNewTestValue);
});
REGISTER_SERVER_FUNCTION("sv_aidronemode", []()
{
if (avh_botsenabled.value == 0)
{
return;
}
bool bNewTestValue = !AIMGR_GetDroneMode();
AIMGR_SetDroneMode(bNewTestValue);
});
REGISTER_SERVER_FUNCTION("sv_stopaidebug", []()
{
if (avh_botsenabled.value == 0)
{
return;
}
AIMGR_SetTestNavMode(false);
AIMGR_SetDroneMode(false);
});
g_VoiceGameMgr.Init(&gVoiceHelper, gpGlobals->maxClients);