First pass at combat mode

This commit is contained in:
RGreenlees 2024-02-21 11:10:35 +00:00 committed by pierow
parent 4fe93a7fd6
commit 2789e7a57c
9 changed files with 909 additions and 99 deletions

View File

@ -20,7 +20,10 @@ bool AICOMM_DeployStructure(AvHAIPlayer* pBot, const AvHAIDeployableStructureTyp
WelderProfile.Filters.addIncludeFlags(SAMPLE_POLYFLAGS_WELD);
// Don't allow the commander to place a structure somewhere unreachable to marines
if (!UTIL_PointIsReachable(WelderProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), Location, max_player_use_reach)) { return false; }
if (!UTIL_PointIsReachable(WelderProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), Location, max_player_use_reach))
{
return false;
}
AvHMessageID StructureID = UTIL_StructureTypeToImpulseCommand(StructureToDeploy);
@ -28,7 +31,10 @@ bool AICOMM_DeployStructure(AvHAIPlayer* pBot, const AvHAIDeployableStructureTyp
BuildLocation.z += 4.0f;
// This would be rejected if a human was trying to build here, so don't let the bot do it
if (!AvHSHUGetIsSiteValidForBuild(StructureID, &BuildLocation)) { return false; }
if (!AvHSHUGetIsSiteValidForBuild(StructureID, &BuildLocation))
{
return false;
}
string theErrorMessage;
int theCost = 0;
@ -477,7 +483,7 @@ void AICOMM_UpdatePlayerOrders(AvHAIPlayer* pBot)
if (SiegedHive)
{
int NumAssignedPlayers = AICOMM_GetNumPlayersAssignedToOrder(pBot, SiegedHive->HiveEntity->edict(), ORDERPURPOSE_SIEGE_HIVE);
int NumAssignedPlayers = AICOMM_GetNumPlayersAssignedToOrder(pBot, SiegedHive->HiveEdict, ORDERPURPOSE_SIEGE_HIVE);
if (NumAssignedPlayers < DesiredPlayers)
{
@ -487,7 +493,7 @@ void AICOMM_UpdatePlayerOrders(AvHAIPlayer* pBot)
if (!FNullEnt(NewAssignee))
{
AICOMM_AssignNewPlayerOrder(pBot, NewAssignee, SiegedHive->HiveEntity->edict(), ORDERPURPOSE_SIEGE_HIVE);
AICOMM_AssignNewPlayerOrder(pBot, NewAssignee, SiegedHive->HiveEdict, ORDERPURPOSE_SIEGE_HIVE);
}
}
}
@ -560,7 +566,7 @@ void AICOMM_UpdatePlayerOrders(AvHAIPlayer* pBot)
if (ThisHive->Status != HIVE_STATUS_UNBUILT) { continue; }
if (AICOMM_IsHiveFullySecured(pBot, ThisHive, false)) { continue; }
int NumAssignedPlayers = AICOMM_GetNumPlayersAssignedToOrder(pBot, ThisHive->HiveEntity->edict(), ORDERPURPOSE_SECURE_HIVE);
int NumAssignedPlayers = AICOMM_GetNumPlayersAssignedToOrder(pBot, ThisHive->HiveEdict, ORDERPURPOSE_SECURE_HIVE);
if (NumAssignedPlayers < DesiredPlayers)
{
@ -583,7 +589,7 @@ void AICOMM_UpdatePlayerOrders(AvHAIPlayer* pBot)
if (!FNullEnt(NewAssignee))
{
AICOMM_AssignNewPlayerOrder(pBot, NewAssignee, EmptyHive->HiveEntity->edict(), ORDERPURPOSE_SECURE_HIVE);
AICOMM_AssignNewPlayerOrder(pBot, NewAssignee, EmptyHive->HiveEdict, ORDERPURPOSE_SECURE_HIVE);
}
}
}
@ -913,19 +919,33 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
Vector BuildLocation = ZERO_VECTOR;
bool bSuccess = false;
bool bFoundLocation = false;
if (NearestInfantryPortal)
{
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestInfantryPortal->Location, UTIL_MetresToGoldSrcUnits(5.0f));
if (!vIsZero(BuildLocation))
{
bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation);
bFoundLocation = true;
}
}
if (vIsZero(BuildLocation))
if (!bSuccess)
{
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
if (!vIsZero(BuildLocation))
{
bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation);
bFoundLocation = true;
}
}
if (!vIsZero(BuildLocation))
if (bFoundLocation)
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation);
return (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kArmoryCost) + 5);
}
}
@ -1977,42 +1997,51 @@ bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair)
if (ExistingInfantryPortal)
{
BuildLocation = UTIL_GetRandomPointOnNavmeshInDonutIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingInfantryPortal->edict->v.origin, UTIL_MetresToGoldSrcUnits(2.0f), UTIL_MetresToGoldSrcUnits(3.0f));
if (!vIsZero(BuildLocation))
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation);
if (bSuccess) { return true; }
}
}
if (vIsZero(BuildLocation))
Vector SearchPoint = ZERO_VECTOR;
DeployableSearchFilter ResNodeFilter;
ResNodeFilter.ReachabilityFlags = AI_REACHABILITY_MARINE;
ResNodeFilter.ReachabilityTeam = pBot->Player->GetTeam();
const AvHAIResourceNode* ResNode = AITAC_FindNearestResourceNodeToLocation(CommChair->v.origin, &ResNodeFilter);
if (ResNode)
{
Vector SearchPoint = ZERO_VECTOR;
DeployableSearchFilter ResNodeFilter;
ResNodeFilter.ReachabilityFlags = AI_REACHABILITY_MARINE;
ResNodeFilter.ReachabilityTeam = pBot->Player->GetTeam();
const AvHAIResourceNode* ResNode = AITAC_FindNearestResourceNodeToLocation(CommChair->v.origin, &ResNodeFilter);
if (ResNode)
{
SearchPoint = ResNode->Location;
}
else
{
return false;
}
Vector NearestPointToChair = FindClosestNavigablePointToDestination(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), SearchPoint, CommChair->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
if (NearestPointToChair != ZERO_VECTOR)
{
float Distance = vDist2D(NearestPointToChair, CommChair->v.origin);
float RandomDist = UTIL_MetresToGoldSrcUnits(5.0f) - Distance;
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestPointToChair, RandomDist);
}
else
{
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
}
SearchPoint = ResNode->Location;
}
else
{
return false;
}
Vector NearestPointToChair = FindClosestNavigablePointToDestination(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), SearchPoint, CommChair->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
if (!vIsZero(NearestPointToChair))
{
float Distance = vDist2D(NearestPointToChair, CommChair->v.origin);
float RandomDist = UTIL_MetresToGoldSrcUnits(5.0f) - Distance;
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestPointToChair, RandomDist);
if (!vIsZero(BuildLocation))
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation);
if (bSuccess) { return true; }
}
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
if (vIsZero(BuildLocation)) { return false; }

View File

@ -189,12 +189,12 @@ typedef enum _AVHAIBOTROLE
BOT_ROLE_FIND_RESOURCES, // Will hunt for uncapped resource nodes and cap them. Will attack enemy resource towers
BOT_ROLE_SWEEPER, // Defensive role to protect infrastructure and build at base. Will patrol to keep outposts secure
BOT_ROLE_ASSAULT, // Will go to attack the hive and other alien structures
BOT_ROLE_ASSAULT, // Will go to attack the enemy base. In combat mode, used for Fade-focus aliens
// Marine-only Roles
BOT_ROLE_COMMAND, // Will attempt to take command
BOT_ROLE_BOMBARDIER, // Bot is armed with a GL and wants to wreck your shit
BOT_ROLE_BOMBARDIER, // Bot is armed with a GL and wants to wreck your shit. In combat mode, used for Onos-focus aliens
// Alien-only roles
@ -248,11 +248,13 @@ typedef struct _RESOURCE_NODE
typedef struct _HIVE_DEFINITION_T
{
AvHHive* HiveEntity = nullptr; // Hive entity reference
edict_t* HiveEdict = nullptr; // Hive edict reference
Vector Location = g_vecZero; // Origin of the hive
Vector FloorLocation = g_vecZero; // Some hives are suspended in the air, this is the floor location directly beneath it
HiveStatusType Status = HIVE_STATUS_UNBUILT; // Can be unbuilt, in progress, or fully built
AvHMessageID TechStatus = MESSAGE_NULL; // What tech (if any) is assigned to this hive right now
bool bIsUnderAttack = false; // Is the hive currently under attack? Becomes false if not taken damage for more than 10 seconds
float HealthPercent = 0.0f; // If the hive is built and active, what its health currently is
AvHAIResourceNode* HiveResNodeRef = nullptr; // Which resource node (indexes into ResourceNodes array) belongs to this hive?
unsigned int ObstacleRefs[MAX_NAV_MESHES]; // When in progress or built, will place an obstacle so bots don't try to walk through it
float NextFloorLocationCheck = 0.0f; // When should the closest navigable point to the hive be calculated? Used to delay the check after a hive is built
@ -759,6 +761,7 @@ typedef struct AVH_AI_PLAYER
AvHAIBotRole BotRole = BOT_ROLE_NONE;
int ExperiencePointsAvailable = 0; // How much experience the bot has to spend
AvHMessageID NextCombatModeUpgrade = MESSAGE_NULL;
} AvHAIPlayer;

View File

@ -6,8 +6,12 @@
#include "../AvHGamerules.h"
#include <unordered_map>
int m_spriteTexture;
std::unordered_map<const char*, std::string> LocalizedLocationsMap;
bool UTIL_CommanderTrace(const edict_t* pEdict, const Vector& start, const Vector& end)
{
TraceResult hit;
@ -492,4 +496,91 @@ void UTIL_DrawHUDText(edict_t* pEntity, char channel, float x, float y, unsigned
MESSAGE_END(); // end
return;
}
void UTIL_ClearLocalizations()
{
LocalizedLocationsMap.clear();
}
void UTIL_LocalizeText(const char* InputText, string& OutputText)
{
// Don't localize empty strings
if (!strcmp(InputText, ""))
{
OutputText = "";
}
char theInputString[1024];
sprintf(theInputString, "%s", InputText);
std::unordered_map<const char*, std::string>::const_iterator FoundLocalization = LocalizedLocationsMap.find(theInputString);
if (FoundLocalization != LocalizedLocationsMap.end())
{
OutputText = FoundLocalization->second;
return;
}
char filename[256];
std::string localizedString(theInputString);
string titlesPath = string(getModDirectory()) + "/titles.txt";
strcpy(filename, titlesPath.c_str());
std::ifstream cFile(filename);
if (cFile.is_open())
{
std::string line;
while (getline(cFile, line))
{
line.erase(std::remove_if(line.begin(), line.end(), isspace),
line.end());
if (line[0] == '/' || line.empty())
continue;
if (line.compare(theInputString) == 0)
{
getline(cFile, line);
getline(cFile, localizedString);
break;
}
}
}
char theOutputString[1024];
sprintf(theOutputString, "%s", localizedString.c_str());
string Delimiter = "Hive -";
auto delimiterPos = localizedString.find(Delimiter);
if (delimiterPos == std::string::npos)
{
Delimiter = "Hive Location -";
delimiterPos = localizedString.find(Delimiter);
}
if (delimiterPos == std::string::npos)
{
Delimiter = "Hive Location -";
delimiterPos = localizedString.find("Hive Location -");
}
if (delimiterPos != std::string::npos)
{
auto AreaName = localizedString.substr(delimiterPos + Delimiter.length());
AreaName.erase(0, AreaName.find_first_not_of(" \r\n\t\v\f"));
sprintf(theOutputString, "%s", AreaName.c_str());
}
OutputText = theOutputString;
LocalizedLocationsMap[InputText] = OutputText;
}

View File

@ -52,4 +52,7 @@ void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSec
void UTIL_DrawHUDText(edict_t* pEntity, char channel, float x, float y, unsigned char r, unsigned char g, unsigned char b, const char* string);
void UTIL_ClearLocalizations();
void UTIL_LocalizeText(const char* InputText, string& OutputText);
#endif

View File

@ -5161,11 +5161,19 @@ void UpdateBotStuck(AvHAIPlayer* pBot)
}
ClearBotPath(pBot);
}
if (!vIsZero(pBot->desiredMovementDir))
{
edict_t* BlockingEntity = UTIL_TraceEntity(pBot->Edict, pBot->Edict->v.origin, (pBot->Edict->v.origin + pBot->desiredMovementDir * 50.0f));
if (IsEdictStructure(BlockingEntity))
{
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(pBot->desiredMovementDir + UTIL_GetCrossProduct(pBot->desiredMovementDir, UP_VECTOR));
BotMovementInputs(pBot);
}
BotJump(pBot);
if (!IsPlayerSkulk(pBot->Edict))
@ -5235,11 +5243,15 @@ void UpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle)
{
pBot->BotNavInfo.NavProfile.Filters.removeExcludeFlags(SAMPLE_POLYFLAGS_TEAM2STRUCTURE);
pBot->BotNavInfo.NavProfile.Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM1STRUCTURE);
pBot->BotNavInfo.NavProfile.Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1STRUCTURE);
pBot->BotNavInfo.NavProfile.Filters.addIncludeFlags(SAMPLE_POLYFLAGS_TEAM2STRUCTURE);
}
else
{
pBot->BotNavInfo.NavProfile.Filters.removeExcludeFlags(SAMPLE_POLYFLAGS_TEAM1STRUCTURE);
pBot->BotNavInfo.NavProfile.Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM2STRUCTURE);
pBot->BotNavInfo.NavProfile.Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM2STRUCTURE);
pBot->BotNavInfo.NavProfile.Filters.addIncludeFlags(SAMPLE_POLYFLAGS_TEAM1STRUCTURE);
}
}
@ -8245,12 +8257,12 @@ void NAV_ProgressMovementTask(AvHAIPlayer* pBot)
{
if (IsPlayerInUseRange(pBot->Edict, MoveTask->TaskTarget))
{
Vector BBMin = MoveTask->TaskTarget->v.absmin;
Vector BBMax = MoveTask->TaskTarget->v.absmax;
Vector BBMin = MoveTask->TaskTarget->v.absmin + Vector(5.0f, 5.0f, 5.0f);
Vector BBMax = MoveTask->TaskTarget->v.absmax - Vector(5.0f, 5.0f, 5.0f);
vScaleBB(BBMin, BBMax, 0.75f);
BotLookAt(pBot, vClosestPointOnBB(pBot->CurrentEyePosition, BBMin, BBMax));
BotLookAt(pBot, vClosestPointOnBB(pBot->Edict->v.origin, BBMin, BBMax));
pBot->DesiredCombatWeapon = WEAPON_MARINE_WELDER;
if (GetPlayerCurrentWeapon(pBot->Player) != WEAPON_MARINE_WELDER)

View File

@ -1814,9 +1814,9 @@ void SetNewAIPlayerRole(AvHAIPlayer* pBot, AvHAIBotRole NewRole)
void UpdateAIPlayerCORole(AvHAIPlayer* pBot)
{
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
if (AIMGR_GetNumAIPlayersWithRoleOnTeam(pBot->Player->GetTeam(), BOT_ROLE_SWEEPER, pBot) == 0)
if (AIMGR_GetNumAIPlayersWithRoleOnTeam(BotTeam, BOT_ROLE_SWEEPER, pBot) == 0)
{
SetNewAIPlayerRole(pBot, BOT_ROLE_SWEEPER);
return;
@ -1826,21 +1826,30 @@ void UpdateAIPlayerCORole(AvHAIPlayer* pBot)
{
if (IsPlayerLerk(pBot->Edict))
{
SetNewAIPlayerRole(pBot, BOT_ROLE_SWEEPER);
SetNewAIPlayerRole(pBot, BOT_ROLE_HARASS);
return;
}
int NumLerks = AITAC_GetNumPlayersOnTeamOfClass(pBot->Player->GetTeam(), AVH_USER3_ALIEN_PLAYER3, pBot->Edict);
int NumHarassers = AIMGR_GetNumAIPlayersWithRoleOnTeam(pBot->Player->GetTeam(), BOT_ROLE_HARASS, pBot);
int NumLerks = AITAC_GetNumPlayersOnTeamOfClass(BotTeam, AVH_USER3_ALIEN_PLAYER3, pBot->Edict);
int NumHarassers = AIMGR_GetNumAIPlayersWithRoleOnTeam(BotTeam, BOT_ROLE_HARASS, pBot);
if (NumLerks + NumHarassers == 0)
{
SetNewAIPlayerRole(pBot, BOT_ROLE_SWEEPER);
SetNewAIPlayerRole(pBot, BOT_ROLE_HARASS);
return;
}
int MaxOnos = (int)(ceilf((float)(AIMGR_GetNumPlayersOnTeam(BotTeam) - 2)) * 0.3f);
if (AIMGR_GetNumAIPlayersWithRoleOnTeam(BotTeam, BOT_ROLE_BOMBARDIER, pBot) < MaxOnos)
{
SetNewAIPlayerRole(pBot, BOT_ROLE_BOMBARDIER);
return;
}
}
SetNewAIPlayerRole(pBot, BOT_ROLE_ASSAULT);
}
void UpdateAIPlayerDMRole(AvHAIPlayer* pBot)
@ -3268,7 +3277,7 @@ void AIPlayerSetMarineAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
if (ActiveSiegeHive)
{
AITASK_SetAttackTask(pBot, Task, ActiveSiegeHive->HiveEntity->edict(), false);
AITASK_SetAttackTask(pBot, Task, ActiveSiegeHive->HiveEdict, false);
return;
}
@ -3304,7 +3313,7 @@ void AIPlayerSetMarineAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
if (!vIsZero(ActualMoveLocation))
{
AITASK_SetSecureHiveTask(pBot, Task, NearestEmptyHive->HiveEntity->edict(), NearestEmptyHive->FloorLocation, false);
AITASK_SetSecureHiveTask(pBot, Task, NearestEmptyHive->HiveEdict, NearestEmptyHive->FloorLocation, false);
return;
}
}
@ -3834,7 +3843,7 @@ void AIPlayerNSAlienThink(AvHAIPlayer* pBot)
{
pBot->PrimaryBotTask.TaskType = TASK_BUILD;
pBot->PrimaryBotTask.StructureType = STRUCTURE_ALIEN_HIVE;
char msg[64];
char msg[128];
sprintf(msg, "I'm going to drop the hive at %s", HiveToBuild->HiveName);
BotSay(pBot, true, 1.0f, msg);
}
@ -3946,48 +3955,233 @@ AvHMessageID GetNextAIPlayerCOMarineUpgrade(AvHAIPlayer* pBot)
return RESEARCH_WEAPONS_ONE;
}
if (!pBot->Player->GetHasCombatModeUpgrade(BUILD_SHOTGUN))
{
return BUILD_SHOTGUN;
}
if (!pBot->Player->GetHasCombatModeUpgrade(BUILD_SHOTGUN))
{
return BUILD_SHOTGUN;
}
if (!pBot->Player->GetHasCombatModeUpgrade(BUILD_HMG))
{
return BUILD_HMG;
}
if (!pBot->Player->GetHasCombatModeUpgrade(RESEARCH_ARMOR_TWO))
{
return RESEARCH_ARMOR_TWO;
}
if (!pBot->Player->GetHasCombatModeUpgrade(RESEARCH_WEAPONS_TWO))
{
return RESEARCH_WEAPONS_TWO;
}
if (!pBot->Player->GetHasCombatModeUpgrade(BUILD_HEAVY))
{
return BUILD_HEAVY;
}
if (!pBot->Player->GetHasCombatModeUpgrade(RESEARCH_ARMOR_THREE))
{
return RESEARCH_ARMOR_TWO;
}
if (!pBot->Player->GetHasCombatModeUpgrade(RESEARCH_WEAPONS_THREE))
{
return RESEARCH_WEAPONS_TWO;
}
return MESSAGE_NULL;
}
AvHMessageID GetNextAIPlayerCOAlienUpgrade(AvHAIPlayer* pBot)
{
int NumPointsAvailable = pBot->ExperiencePointsAvailable;
if (IsPlayerGorge(pBot->Edict))
{
NumPointsAvailable += GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_TWO);
}
if (IsPlayerLerk(pBot->Edict))
{
NumPointsAvailable += GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_THREE);
}
if (IsPlayerFade(pBot->Edict))
{
NumPointsAvailable += GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_FOUR);
}
if (IsPlayerOnos(pBot->Edict))
{
NumPointsAvailable += GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_FIVE);
}
// Always start off getting carapace, to improve viability early game
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_EVOLUTION_ONE))
{
return ALIEN_EVOLUTION_ONE;
}
// Unlock leap for further viability early game
// If we are a harasser, always ensure we have enough resources to go lerk
if (pBot->BotRole == BOT_ROLE_HARASS)
{
if (NumPointsAvailable <= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_THREE))
{
return MESSAGE_NULL;
}
// Lerks need adrenaline
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_EVOLUTION_EIGHT))
{
return ALIEN_EVOLUTION_EIGHT;
}
// Unlock umbra
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_HIVE_TWO_UNLOCK))
{
return ALIEN_HIVE_TWO_UNLOCK;
}
// Get that sweet primal scream
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_HIVE_THREE_UNLOCK))
{
return ALIEN_HIVE_THREE_UNLOCK;
}
// Unlock focus
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_EVOLUTION_ELEVEN))
{
return ALIEN_EVOLUTION_ELEVEN;
}
// Unlock regeneration
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_EVOLUTION_TWO))
{
return ALIEN_EVOLUTION_TWO;
}
// Unlock celerity
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_EVOLUTION_SEVEN))
{
return ALIEN_EVOLUTION_SEVEN;
}
return MESSAGE_NULL;
}
if (pBot->BotRole == BOT_ROLE_SWEEPER)
{
// If we are a sweeper, always ensure we have enough resources to go gorge in case we want to heal the hive
if (NumPointsAvailable <= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_TWO))
{
return MESSAGE_NULL;
}
// Gorges need adrenaline
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_EVOLUTION_EIGHT))
{
return ALIEN_EVOLUTION_EIGHT;
}
// Regen
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_EVOLUTION_TWO))
{
return ALIEN_EVOLUTION_EIGHT;
}
// Celerity
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_EVOLUTION_SEVEN))
{
return ALIEN_EVOLUTION_EIGHT;
}
// Redemption
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_EVOLUTION_THREE))
{
return ALIEN_EVOLUTION_EIGHT;
}
// Focus
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_EVOLUTION_ELEVEN))
{
return ALIEN_EVOLUTION_EIGHT;
}
// Silence
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_EVOLUTION_NINE))
{
return ALIEN_EVOLUTION_EIGHT;
}
// Cloak
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_EVOLUTION_TEN))
{
return ALIEN_EVOLUTION_EIGHT;
}
return MESSAGE_NULL;
}
// ASSAULT and BOMBARDIER STUFF BELOW
// ASSAULT = jacked-up fade
// BOMBARDIER = Onos
// Unlock leap
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_HIVE_TWO_UNLOCK))
{
return ALIEN_HIVE_TWO_UNLOCK;
}
// If we are a sweeper, always ensure we have enough resources to go gorge in case we want to heal the hive
if (pBot->BotRole == BOT_ROLE_SWEEPER)
// If we're going assault then make sure we've saved up enough for fade
if (pBot->BotRole == BOT_ROLE_ASSAULT)
{
if (!IsPlayerGorge(pBot->Edict))
if (NumPointsAvailable <= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_FOUR))
{
if (pBot->ExperiencePointsAvailable <= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_TWO))
{
return MESSAGE_NULL;
}
return MESSAGE_NULL;
}
// Unlock adrenaline
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_EVOLUTION_EIGHT))
{
return ALIEN_EVOLUTION_EIGHT;
}
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_HIVE_THREE_UNLOCK))
{
return ALIEN_HIVE_THREE_UNLOCK;
}
}
// If we are a harasser, always ensure we have enough resources to go lerk
if (pBot->BotRole == BOT_ROLE_HARASS)
// As a bombardier, we can still go fade if we can't afford Onos yet, so calculate our points savings accordingly
if (pBot->BotRole == BOT_ROLE_BOMBARDIER)
{
if (!IsPlayerLerk(pBot->Edict))
if (NumPointsAvailable <= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_FIVE))
{
if (pBot->ExperiencePointsAvailable <= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_THREE))
{
return MESSAGE_NULL;
}
return MESSAGE_NULL;
}
// Unlock adrenaline
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_EVOLUTION_EIGHT))
{
return ALIEN_EVOLUTION_EIGHT;
}
// Unlock regeneration
if (!pBot->Player->GetHasCombatModeUpgrade(ALIEN_EVOLUTION_TWO))
{
return ALIEN_EVOLUTION_TWO;
}
}
return MESSAGE_NULL;
}
void AIPlayerCOThink(AvHAIPlayer* pBot)
@ -4012,9 +4206,462 @@ void AIPlayerCOThink(AvHAIPlayer* pBot)
UpdateAIPlayerCORole(pBot);
AvHMessageID NextCombatUpgrade = GetNextAIPlayerCOUpgrade(pBot);
if (IsPlayerMarine(pBot->Edict))
{
AIPlayerCOMarineThink(pBot);
}
else
{
AIPlayerCOAlienThink(pBot);
}
}
void AIPlayerCOMarineThink(AvHAIPlayer* pBot)
{
AvHMessageID NextCombatUpgrade = GetNextAIPlayerCOMarineUpgrade(pBot);
if (NextCombatUpgrade != MESSAGE_NULL)
{
int Cost = GetGameRules()->GetCostForMessageID(NextCombatUpgrade);
if (pBot->ExperiencePointsAvailable >= Cost)
{
if (gpGlobals->time - pBot->LastRequestTime > 1.0f)
{
pBot->Impulse = (int)NextCombatUpgrade;
pBot->LastRequestTime = gpGlobals->time;
return;
}
}
}
if (gpGlobals->time >= pBot->BotNextTaskEvaluationTime)
{
pBot->BotNextTaskEvaluationTime = gpGlobals->time + frandrange(0.2f, 0.5f);
AITASK_BotUpdateAndClearTasks(pBot);
AIPlayerSetPrimaryCOMarineTask(pBot, &pBot->PrimaryBotTask);
AIPlayerSetSecondaryCOMarineTask(pBot, &pBot->SecondaryBotTask);
}
pBot->CurrentTask = AIPlayerGetNextTask(pBot);
if (pBot->CurrentTask && pBot->CurrentTask->TaskType != TASK_NONE)
{
BotProgressTask(pBot, pBot->CurrentTask);
}
}
void AIPlayerCOAlienThink(AvHAIPlayer* pBot)
{
if (!pBot->CurrentTask) { pBot->CurrentTask = &pBot->PrimaryBotTask; }
AvHMessageID NextCombatUpgrade = GetNextAIPlayerCOAlienUpgrade(pBot);
if (NextCombatUpgrade != MESSAGE_NULL)
{
int Cost = GetGameRules()->GetCostForMessageID(NextCombatUpgrade);
if (pBot->ExperiencePointsAvailable >= Cost)
{
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
{
if (gpGlobals->time - pBot->LastRequestTime > 1.0f)
{
pBot->Impulse = (int)NextCombatUpgrade;
pBot->LastRequestTime = gpGlobals->time;
return;
}
}
}
}
if (gpGlobals->time >= pBot->BotNextTaskEvaluationTime)
{
pBot->BotNextTaskEvaluationTime = gpGlobals->time + frandrange(0.2f, 0.5f);
AITASK_BotUpdateAndClearTasks(pBot);
AIPlayerSetPrimaryCOAlienTask(pBot, &pBot->PrimaryBotTask);
AIPlayerSetSecondaryCOAlienTask(pBot, &pBot->SecondaryBotTask);
}
pBot->CurrentTask = AIPlayerGetNextTask(pBot);
if (pBot->CurrentTask && pBot->CurrentTask->TaskType != TASK_NONE)
{
BotProgressTask(pBot, pBot->CurrentTask);
}
}
void AIPlayerSetPrimaryCOMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
DeployableSearchFilter EnemyStuffFilter;
EnemyStuffFilter.DeployableTeam = EnemyTeam;
EnemyStuffFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
EnemyStuffFilter.ReachabilityTeam = BotTeam;
EnemyStuffFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
AvHAIBuildableStructure* EnemyStructure = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &EnemyStuffFilter);
if (EnemyStructure)
{
AITASK_SetAttackTask(pBot, Task, EnemyStructure->edict, false);
return;
}
else
{
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_ALIEN)
{
const AvHAIHiveDefinition* EnemyHive = AITAC_GetActiveHiveNearestLocation(EnemyTeam, pBot->Edict->v.origin);
if (EnemyHive)
{
AITASK_SetAttackTask(pBot, Task, EnemyHive->HiveEdict, false);
return;
}
}
}
vector<AvHPlayer*> AllEnemyPlayers = AIMGR_GetAllPlayersOnTeam(EnemyTeam);
edict_t* TargetPlayer = nullptr;
float MinDist = 0.0f;
for (auto it = AllEnemyPlayers.begin(); it != AllEnemyPlayers.end(); it++)
{
AvHPlayer* ThisPlayer = (*it);
if (!ThisPlayer) { continue; }
edict_t* PlayerEdict = ThisPlayer->edict();
if (!IsPlayerActiveInGame(PlayerEdict)) { continue; }
float ThisDist = vDist2DSq(PlayerEdict->v.origin, pBot->Edict->v.origin);
if (FNullEnt(TargetPlayer) || ThisDist < MinDist)
{
TargetPlayer = PlayerEdict;
MinDist = ThisDist;
}
}
if (!FNullEnt(TargetPlayer))
{
MoveTo(pBot, UTIL_GetEntityGroundLocation(TargetPlayer), MOVESTYLE_NORMAL);
}
}
void AIPlayerSetSecondaryCOMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
edict_t* CommChair = AITAC_GetCommChair(BotTeam);
DeployableSearchFilter AttackedStructuresFilter;
AttackedStructuresFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
AttackedStructuresFilter.DeployableTeam = BotTeam;
AttackedStructuresFilter.ReachabilityTeam = BotTeam;
AttackedStructuresFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
AttackedStructuresFilter.IncludeStatusFlags = STRUCTURE_STATUS_UNDERATTACK;
AttackedStructuresFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(30.0f);
vector<AvHAIBuildableStructure*> AllAttackedStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &AttackedStructuresFilter);
AvHAIBuildableStructure* StructureToDefend = nullptr;
float MinDist = 0.0f;
for (auto it = AllAttackedStructures.begin(); it != AllAttackedStructures.end(); it++)
{
AvHAIBuildableStructure* ThisStructure = (*it);
float ThisDist = vDist2D(pBot->Edict->v.origin, ThisStructure->edict->v.origin);
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);
if (NumExistingDefenders < 2)
{
if (!StructureToDefend || ThisDist < MinDist)
{
StructureToDefend = ThisStructure;
MinDist = ThisDist;
}
}
}
if (StructureToDefend)
{
AITASK_SetDefendTask(pBot, Task, StructureToDefend->edict, true);
return;
}
if (PlayerHasWeapon(pBot->Player, WEAPON_MARINE_WELDER))
{
DeployableSearchFilter DamagedStructuresFilter;
DamagedStructuresFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
DamagedStructuresFilter.DeployableTeam = BotTeam;
DamagedStructuresFilter.ReachabilityTeam = BotTeam;
DamagedStructuresFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
DamagedStructuresFilter.IncludeStatusFlags = STRUCTURE_STATUS_DAMAGED;
DamagedStructuresFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f);
AvHAIBuildableStructure* StructureToRepair = nullptr;
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);
if (ThisStructure->StructureType == STRUCTURE_MARINE_COMMCHAIR && ThisStructure->healthPercent < 0.7f)
{
StructureToRepair = ThisStructure;
break;
}
float ThisDist = vDist2DSq(ThisStructure->Location, pBot->Edict->v.origin);
if (!StructureToRepair || ThisDist < MinDist)
{
StructureToRepair = ThisStructure;
MinDist = ThisDist;
}
}
if (StructureToRepair)
{
AITASK_SetWeldTask(pBot, Task, StructureToRepair->edict, true);
return;
}
DeployableSearchFilter NearbyArmouryFilter;
NearbyArmouryFilter.DeployableTypes = (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY);
NearbyArmouryFilter.DeployableTeam = BotTeam;
NearbyArmouryFilter.ReachabilityTeam = BotTeam;
NearbyArmouryFilter.ReachabilityFlags = AI_REACHABILITY_MARINE;
AvHAIBuildableStructure* NearestEasyAccessArmoury = AITAC_FindClosestDeployableToLocation(ZERO_VECTOR, &NearbyArmouryFilter);
if (!NearestEasyAccessArmoury)
{
NearbyArmouryFilter.ReachabilityFlags = AI_REACHABILITY_WELDER;
AvHAIBuildableStructure* NearestWeldableAccessArmoury = AITAC_FindClosestDeployableToLocation(ZERO_VECTOR, &NearbyArmouryFilter);
if (NearestWeldableAccessArmoury)
{
AITASK_SetMoveTask(pBot, Task, NearestWeldableAccessArmoury->Location, true);
return;
}
}
}
AITASK_ClearBotTask(pBot, Task);
}
void AIPlayerSetPrimaryCOAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (IsPlayerGorge(pBot->Edict))
{
const AvHAIHiveDefinition* TheHive = AITAC_GetNearestTeamHive(pBot->Player->GetTeam(), pBot->Edict->v.origin, true);
if (TheHive)
{
AITASK_ClearBotTask(pBot, Task);
BotGuardLocation(pBot, TheHive->FloorLocation);
return;
}
}
if (Task->TaskType == TASK_ATTACK && vDist2DSq(Task->TaskTarget->v.origin, pBot->Edict->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
{
return;
}
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
if (pBot->BotRole == BOT_ROLE_HARASS)
{
if (!IsPlayerLerk(pBot->Edict) && pBot->ExperiencePointsAvailable >= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_THREE))
{
if (Task->TaskType != TASK_EVOLVE)
{
const AvHAIHiveDefinition* NearestHive = AITAC_GetActiveHiveNearestLocation(BotTeam, pBot->Edict->v.origin);
if (NearestHive)
{
AITASK_SetEvolveTask(pBot, Task, NearestHive->HiveEdict, ALIEN_LIFEFORM_THREE, true);
}
}
return;
}
}
if (pBot->BotRole == BOT_ROLE_ASSAULT)
{
if (!IsPlayerFade(pBot->Edict) && pBot->ExperiencePointsAvailable >= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_FOUR))
{
if (Task->TaskType != TASK_EVOLVE)
{
const AvHAIHiveDefinition* NearestHive = AITAC_GetActiveHiveNearestLocation(BotTeam, pBot->Edict->v.origin);
if (NearestHive)
{
AITASK_SetEvolveTask(pBot, Task, NearestHive->HiveEdict, ALIEN_LIFEFORM_FOUR, true);
}
}
return;
}
}
if (pBot->BotRole == BOT_ROLE_BOMBARDIER)
{
if (!IsPlayerOnos(pBot->Edict) && !IsPlayerFade(pBot->Edict))
{
AvHMessageID DesiredEvolution = MESSAGE_NULL;
if (pBot->ExperiencePointsAvailable >= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_FIVE))
{
DesiredEvolution = ALIEN_LIFEFORM_FIVE;
}
else if (pBot->ExperiencePointsAvailable >= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_FOUR))
{
DesiredEvolution = ALIEN_LIFEFORM_FOUR;
}
if (DesiredEvolution != MESSAGE_NULL)
{
if (Task->TaskType != TASK_EVOLVE)
{
const AvHAIHiveDefinition* NearestHive = AITAC_GetActiveHiveNearestLocation(BotTeam, pBot->Edict->v.origin);
if (NearestHive)
{
AITASK_SetEvolveTask(pBot, Task, NearestHive->HiveEdict, DesiredEvolution, true);
}
}
return;
}
}
}
DeployableSearchFilter EnemyStuffFilter;
EnemyStuffFilter.DeployableTeam = EnemyTeam;
EnemyStuffFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
EnemyStuffFilter.ReachabilityTeam = BotTeam;
EnemyStuffFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
AvHAIBuildableStructure* EnemyStructure = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &EnemyStuffFilter);
if (EnemyStructure)
{
AITASK_SetAttackTask(pBot, Task, EnemyStructure->edict, false);
return;
}
vector<AvHPlayer*> AllEnemyPlayers = AIMGR_GetAllPlayersOnTeam(EnemyTeam);
edict_t* TargetPlayer = nullptr;
float MinDist = 0.0f;
for (auto it = AllEnemyPlayers.begin(); it != AllEnemyPlayers.end(); it++)
{
AvHPlayer* ThisPlayer = (*it);
if (!ThisPlayer) { continue; }
edict_t* PlayerEdict = ThisPlayer->edict();
if (!IsPlayerActiveInGame(PlayerEdict)) { continue; }
float ThisDist = vDist2DSq(PlayerEdict->v.origin, pBot->Edict->v.origin);
if (FNullEnt(TargetPlayer) || ThisDist < MinDist)
{
TargetPlayer = PlayerEdict;
MinDist = ThisDist;
}
}
if (!FNullEnt(TargetPlayer))
{
MoveTo(pBot, UTIL_GetEntityGroundLocation(TargetPlayer), MOVESTYLE_NORMAL);
}
}
void AIPlayerSetSecondaryCOAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
const AvHAIHiveDefinition* TheHive = AITAC_GetNearestTeamHive(BotTeam, pBot->Edict->v.origin, true);
if (TheHive->bIsUnderAttack)
{
int NumAttackers = AITAC_GetNumPlayersOfTeamInArea(EnemyTeam, TheHive->FloorLocation, UTIL_MetresToGoldSrcUnits(15.0f), false, nullptr, AVH_USER3_NONE);
int MaxDefenders = imini(NumAttackers + 1, (int)floorf((float)AIMGR_GetNumPlayersOnTeam(BotTeam) * 0.5f));
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);
if (NumExistingDefenders < MaxDefenders)
{
AITASK_SetDefendTask(pBot, Task, TheHive->HiveEdict, true);
return;
}
}
if (TheHive->HealthPercent < 1.0f && IsPlayerGorge(pBot->Edict))
{
Task->TaskType = TASK_HEAL;
Task->TaskTarget = TheHive->HiveEdict;
Task->bTaskIsUrgent = true;
return;
}
if (TheHive->HealthPercent < 0.8f)
{
if (IsPlayerGorge(pBot->Edict) || (pBot->BotRole == BOT_ROLE_SWEEPER && 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;
}
}
}
AITASK_ClearBotTask(pBot, Task);
}
void AIPlayerDMThink(AvHAIPlayer* pBot)
{
pBot->CurrentEnemy = BotGetNextEnemyTarget(pBot);
@ -4259,7 +4906,7 @@ void AIPlayerReceiveMoveOrder(AvHAIPlayer* pBot, Vector Destination)
{
if (!AICOMM_IsHiveFullySecured(pBot, HiveRef, false))
{
AITASK_SetSecureHiveTask(pBot, &pBot->CommanderTask, HiveRef->HiveEntity->edict(), ActualMoveLocation, false);
AITASK_SetSecureHiveTask(pBot, &pBot->CommanderTask, HiveRef->HiveEdict, ActualMoveLocation, false);
pBot->CommanderTask.bIssuedByCommander = true;
return;
}
@ -4480,7 +5127,7 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
if (HiveToSecure)
{
AITASK_SetReinforceStructureTask(pBot, Task, HiveToSecure->HiveEntity->edict(), false);
AITASK_SetReinforceStructureTask(pBot, Task, HiveToSecure->HiveEdict, false);
return;
}
@ -4771,7 +5418,7 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
if (NearestHive)
{
AITASK_SetEvolveTask(pBot, Task, NearestHive->HiveEntity->edict(), ALIEN_LIFEFORM_FIVE, true);
AITASK_SetEvolveTask(pBot, Task, NearestHive->HiveEdict, ALIEN_LIFEFORM_FIVE, true);
return;
}
}
@ -4788,7 +5435,7 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
if (NearestHive)
{
AITASK_SetEvolveTask(pBot, Task, NearestHive->HiveEntity->edict(), ALIEN_LIFEFORM_FOUR, true);
AITASK_SetEvolveTask(pBot, Task, NearestHive->HiveEdict, ALIEN_LIFEFORM_FOUR, true);
return;
}
@ -5022,7 +5669,7 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
{
if ((*AIIt) == pBot) { continue; }
if ((*AIIt)->PrimaryBotTask.TaskType == TASK_GUARD && (*AIIt)->PrimaryBotTask.TaskTarget == ThisHive->HiveEntity->edict())
if ((*AIIt)->PrimaryBotTask.TaskType == TASK_GUARD && (*AIIt)->PrimaryBotTask.TaskTarget == ThisHive->HiveEdict)
{
if ((*AIIt)->Player->GetUser3() >= AVH_USER3_ALIEN_PLAYER3) { bNeedsExtraGuards = false; }
NumGuards++;
@ -5065,7 +5712,7 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
{
Task->TaskType = TASK_GUARD;
Task->TaskLocation = HiveToGuard->FloorLocation;
Task->TaskTarget = HiveToGuard->HiveEntity->edict();
Task->TaskTarget = HiveToGuard->HiveEdict;
return;
}
else if (HiveToSecure)
@ -5215,7 +5862,7 @@ void AIPlayerSetAlienHarasserPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
if (NearestHive)
{
AITASK_SetEvolveTask(pBot, Task, NearestHive->HiveEntity->edict(), ALIEN_LIFEFORM_THREE, true);
AITASK_SetEvolveTask(pBot, Task, NearestHive->HiveEdict, ALIEN_LIFEFORM_THREE, true);
return;
}
else
@ -5282,7 +5929,7 @@ void AIPlayerSetAlienHarasserPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
{
const AvHAIHiveDefinition* EnemyHive = AITAC_GetActiveHiveNearestLocation(EnemyTeam, pBot->Edict->v.origin);
AITASK_SetAttackTask(pBot, Task, EnemyHive->HiveEntity->edict(), false);
AITASK_SetAttackTask(pBot, Task, EnemyHive->HiveEdict, false);
return;
}
@ -5466,7 +6113,7 @@ void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (ThisBot != pBot && IsPlayerActiveInGame(ThisBot->Edict) && !IsPlayerGorge(ThisBot->Edict) && vDist2DSq(ThisBot->Edict->v.origin, ThisHive->FloorLocation) > sqrf(UTIL_MetresToGoldSrcUnits(15.0f)))
{
if (ThisBot->SecondaryBotTask.TaskType == TASK_DEFEND && ThisBot->SecondaryBotTask.TaskTarget == ThisHive->HiveEntity->edict())
if (ThisBot->SecondaryBotTask.TaskType == TASK_DEFEND && ThisBot->SecondaryBotTask.TaskTarget == ThisHive->HiveEdict)
{
int ThisDefenderStrength = 1;
@ -5500,7 +6147,7 @@ void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (HiveToDefend)
{
AITASK_SetDefendTask(pBot, Task, HiveToDefend->HiveEntity->edict(), true);
AITASK_SetDefendTask(pBot, Task, HiveToDefend->HiveEdict, true);
return;
}

View File

@ -63,6 +63,11 @@ void AIPlayerNSMarineThink(AvHAIPlayer* pBot);
void AIPlayerNSAlienThink(AvHAIPlayer* pBot);
// Think routine for the combat game mode
void AIPlayerCOThink(AvHAIPlayer* pBot);
void AIPlayerCOMarineThink(AvHAIPlayer* pBot);
void AIPlayerCOAlienThink(AvHAIPlayer* pBot);
// Think routine for the deathmatch game mode (e.g. when playing CS maps)
void AIPlayerDMThink(AvHAIPlayer* pBot);
@ -94,6 +99,11 @@ void AIPlayerSetAlienHarasserPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
void AIPlayerSetWantsAndNeedsAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
void AIPlayerSetPrimaryCOMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
void AIPlayerSetSecondaryCOMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
void AIPlayerSetPrimaryCOAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
void AIPlayerSetSecondaryCOAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
void BotSwitchToWeapon(AvHAIPlayer* pBot, AvHAIWeapon NewWeaponSlot);
bool ShouldBotThink(AvHAIPlayer* pBot);

View File

@ -6,6 +6,9 @@
// Contains gorge-related functions. Needs refactoring into helper function file
//
#include "AvHAITactical.h"
#include "AvHAINavigation.h"
#include "AvHAITask.h"
@ -28,7 +31,6 @@
#include <unordered_map>
vector<AvHAIResourceNode> ResourceNodes;
vector<AvHAIHiveDefinition> Hives;
@ -636,7 +638,7 @@ Vector AITAC_GetFloorLocationForHive(const AvHAIHiveDefinition* Hive)
{
if (!Hive) { return ZERO_VECTOR; }
Vector HiveFloorLoc = UTIL_GetFloorUnderEntity(Hive->HiveEntity->edict());
Vector HiveFloorLoc = UTIL_GetFloorUnderEntity(Hive->HiveEdict);
Vector NearestNavigableLoc = ZERO_VECTOR;
@ -672,23 +674,26 @@ void AITAC_PopulateHiveData()
AvHAIHiveDefinition NewHive;
NewHive.HiveEntity = theEntity;
NewHive.HiveEdict = theEntity->edict();
NewHive.Location = theEntity->pev->origin;
memset(&NewHive.ObstacleRefs, 0, sizeof(NewHive.ObstacleRefs));
AvHAIResourceNode* NearestNode = AITAC_GetNearestResourceNodeToLocation(theEntity->pev->origin);
if (NearestNode)
{
NewHive.HiveResNodeRef = NearestNode;
NearestNode->ParentHive = NewHive.HiveEntity->edict();
NearestNode->ParentHive = NewHive.HiveEdict;
}
NewHive.FloorLocation = UTIL_GetFloorUnderEntity(theEntity->edict()); // Some hives are suspended in the air, this is the floor location directly beneath it
NewHive.FloorLocation = UTIL_GetFloorUnderEntity(NewHive.HiveEdict); // Some hives are suspended in the air, this is the floor location directly beneath it
string HiveName;
string theLocationName;
if (AvHSHUGetNameOfLocation(GetGameRules()->GetInfoLocations(), NewHive.Location, theLocationName))
{
UTIL_LocalizeText(theLocationName.c_str(), theLocationName);
HiveName = theLocationName;
}
@ -719,6 +724,15 @@ void AITAC_RefreshHiveData()
AvHTeamNumber CurrentOwningTeam = theEntity->GetTeamNumber();
HiveStatusType CurrentStatus = (theEntity->GetIsActive() ? HIVE_STATUS_BUILT : (theEntity->GetIsSpawning() ? HIVE_STATUS_BUILDING : HIVE_STATUS_UNBUILT));
if (CurrentStatus == HIVE_STATUS_BUILT)
{
it->HealthPercent = (it->HiveEdict->v.health / it->HiveEdict->v.max_health);
}
else
{
it->HealthPercent = 1.0f;
}
bool bHiveDestroyed = (CurrentOwningTeam != it->OwningTeam) || (it->Status == HIVE_STATUS_BUILT && CurrentStatus != it->Status);
if (bHiveDestroyed)
@ -745,7 +759,7 @@ void AITAC_RefreshHiveData()
if (it->Status != HIVE_STATUS_UNBUILT && it->ObstacleRefs[REGULAR_NAV_MESH] == 0)
{
UTIL_AddTemporaryObstacles(UTIL_GetCentreOfEntity(it->HiveEntity->edict()) - Vector(0.0f, 0.0f, 25.0f), 125.0f, 300.0f, DT_AREA_NULL, it->ObstacleRefs);
UTIL_AddTemporaryObstacles(UTIL_GetCentreOfEntity(it->HiveEdict) - Vector(0.0f, 0.0f, 25.0f), 125.0f, 300.0f, DT_AREA_NULL, it->ObstacleRefs);
it->NextFloorLocationCheck = gpGlobals->time + 1.0f;
}
else if (it->Status == HIVE_STATUS_UNBUILT && it->ObstacleRefs[REGULAR_NAV_MESH] != 0)
@ -2061,8 +2075,6 @@ AvHAIBuildableStructure* AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
void AITAC_OnStructureCreated(AvHAIBuildableStructure* NewStructure)
{
if (!GetGameRules()->GetGameStarted()) { return; }
UTIL_AddStructureTemporaryObstacles(NewStructure);
AvHTeamNumber StructureTeam = (AvHTeamNumber)NewStructure->edict->v.team;
@ -2250,6 +2262,8 @@ void AITAC_LinkDeployedItemToAction(AvHAIPlayer* CommanderBot, const AvHAIDroppe
void AITAC_ClearMapAIData()
{
UTIL_ClearLocalizations();
ResourceNodes.clear();
AITAC_ClearHiveInfo();
@ -2632,7 +2646,7 @@ AvHAIHiveDefinition* AITAC_GetHiveFromEdict(const edict_t* Edict)
for (auto it = Hives.begin(); it != Hives.end(); it++)
{
if (it->HiveEntity->edict() == Edict)
if (it->HiveEdict == Edict)
{
return &(*it);
}
@ -4503,11 +4517,11 @@ edict_t* AITAC_AlienFindNearestHealingSource(AvHTeamNumber Team, Vector SearchLo
ThisDist -= BALANCE_VAR(kHiveHealRadius) * 0.75f;
// We're already in healing distance of a hive, that's our healing source
if (ThisDist <= 0.0f) { return (*it)->HiveEntity->edict(); }
if (ThisDist <= 0.0f) { return (*it)->HiveEdict; }
if (FNullEnt(Result) || ThisDist < MinDist)
{
Result = (*it)->HiveEntity->edict();
Result = (*it)->HiveEdict;
MinDist = ThisDist;
}
}

View File

@ -2384,12 +2384,13 @@ void BotProgressWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
// so instead aim at the closest point on the func_weldable to us.
if (!IsEdictPlayer(Task->TaskTarget) && !IsEdictStructure(Task->TaskTarget))
{
Vector BBMin = Task->TaskTarget->v.absmin;
Vector BBMax = Task->TaskTarget->v.absmax;
Vector BBMin = Task->TaskTarget->v.absmin + Vector(5.0f, 5.0f, 5.0f);
Vector BBMax = Task->TaskTarget->v.absmax - Vector(5.0f, 5.0f, 5.0f);
vScaleBB(BBMin, BBMax, 0.75f);
AimLocation = vClosestPointOnBB(pBot->CurrentEyePosition, BBMin, BBMax);
AimLocation = vClosestPointOnBB(pBot->Edict->v.origin, BBMin, BBMax);
}
BotLookAt(pBot, AimLocation);
@ -2625,7 +2626,7 @@ void BotGuardLocation(AvHAIPlayer* pBot, const Vector GuardLocation)
{
float DistFromGuardLocation = vDist2DSq(pBot->Edict->v.origin, GuardLocation);
if (DistFromGuardLocation > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
if (DistFromGuardLocation > sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
{
pBot->GuardInfo.GuardLocation = g_vecZero;
pBot->GuardInfo.GuardStartLookTime = 0.0f;
@ -2662,7 +2663,7 @@ void BotGuardLocation(AvHAIPlayer* pBot, const Vector GuardLocation)
if (gpGlobals->time > pBot->GuardInfo.ThisGuardStandTime)
{
pBot->GuardInfo.GuardStandPosition = UTIL_GetRandomPointOnNavmeshInRadius(pBot->BotNavInfo.NavProfile, GuardLocation, UTIL_MetresToGoldSrcUnits(4.0f));
pBot->GuardInfo.GuardStandPosition = UTIL_GetRandomPointOnNavmeshInRadius(pBot->BotNavInfo.NavProfile, GuardLocation, UTIL_MetresToGoldSrcUnits(5.0f));
pBot->GuardInfo.ThisGuardStandTime = gpGlobals->time + frandrange(5.0f, 10.0f);
}