mirror of
https://github.com/ENSL/NS.git
synced 2025-04-23 01:58:17 +00:00
Compare commits
32 commits
Author | SHA1 | Date | |
---|---|---|---|
|
be1aead879 | ||
|
cea65c1fdc | ||
|
b1bcdd2f70 | ||
|
290ad067eb | ||
|
a01d8a6708 | ||
|
0a15148352 | ||
|
4102dabe05 | ||
|
11512d9d28 | ||
|
733ad6eb04 | ||
|
2842aba0bb | ||
|
65155fb3f0 | ||
|
9ee01c0d64 | ||
|
6f263d400b | ||
|
0897cf15a0 | ||
|
73ff332b68 | ||
|
5b83a4c886 | ||
|
2b27b90f25 | ||
|
f427a9c052 | ||
|
ef7e7a9178 | ||
|
36318cd1d4 | ||
|
9a4a6b3660 | ||
|
9452b8a0c3 | ||
|
8fef7241a0 | ||
|
e17fba76ea | ||
|
91231ac069 | ||
|
c2e41c2011 | ||
|
5beb313546 | ||
|
c0bef7cb05 | ||
|
6ffc3d3258 | ||
|
d17cb601eb | ||
|
ff3b4afb1c | ||
|
fcddb5b6c3 |
43 changed files with 5519 additions and 1698 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -14,6 +14,10 @@ MaxAIMatchTime=90
|
||||||
# 2 = When the round has started (after countdown)
|
# 2 = When the round has started (after countdown)
|
||||||
BotFillTiming=1
|
BotFillTiming=1
|
||||||
|
|
||||||
|
# Chance the AI commander will try to relocate to an empty hive at match start
|
||||||
|
# Value is a decimal between 0.0 and 1.0, with 0 being never and 1 being always
|
||||||
|
# Note that setting relocation chance to 0.0 will also disable ANY relocation at any time
|
||||||
|
RelocationChance=0.2
|
||||||
|
|
||||||
### Skill Settings ###
|
### Skill Settings ###
|
||||||
|
|
||||||
|
|
|
@ -842,6 +842,8 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool bOffMeshChanged = false;
|
||||||
|
|
||||||
if (m_nupdate == 0)
|
if (m_nupdate == 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_params.maxOffMeshConnections; ++i)
|
for (int i = 0; i < m_params.maxOffMeshConnections; ++i)
|
||||||
|
@ -854,6 +856,7 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
|
||||||
navmesh->baseOffMeshLinks(con);
|
navmesh->baseOffMeshLinks(con);
|
||||||
navmesh->GlobalOffMeshLinks(con);
|
navmesh->GlobalOffMeshLinks(con);
|
||||||
con->state = DT_OFFMESH_CLEAN;
|
con->state = DT_OFFMESH_CLEAN;
|
||||||
|
bOffMeshChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (con->state == DT_OFFMESH_REMOVING)
|
if (con->state == DT_OFFMESH_REMOVING)
|
||||||
|
@ -869,7 +872,7 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (upToDate)
|
if (upToDate)
|
||||||
*upToDate = m_nupdate == 0 && m_nreqs == 0 && m_nOffMeshReqs == 0;
|
*upToDate = m_nupdate == 0 && m_nreqs == 0 && m_nOffMeshReqs == 0 && !bOffMeshChanged;
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
static const float MIN_COMMANDER_REMIND_TIME = 20.0f; // How frequently the commander can nag a player to do something, if they don't think they're doing it
|
static const float MIN_COMMANDER_REMIND_TIME = 20.0f; // How frequently the commander can nag a player to do something, if they don't think they're doing it
|
||||||
|
|
||||||
bool AICOMM_DeployStructure(AvHAIPlayer* pBot, const AvHAIDeployableStructureType StructureToDeploy, const Vector Location, StructurePurpose Purpose = STRUCTURE_PURPOSE_GENERAL);
|
AvHAIBuildableStructure* AICOMM_DeployStructure(AvHAIPlayer* pBot, const AvHAIDeployableStructureType StructureToDeploy, const Vector Location, StructurePurpose Purpose = STRUCTURE_PURPOSE_GENERAL, bool bPlacedByHuman = false);
|
||||||
bool AICOMM_DeployItem(AvHAIPlayer* pBot, const AvHAIDeployableItemType ItemToDeploy, const Vector Location);
|
bool AICOMM_DeployItem(AvHAIPlayer* pBot, const AvHAIDeployableItemType ItemToDeploy, const Vector Location);
|
||||||
bool AICOMM_UpgradeStructure(AvHAIPlayer* pBot, AvHAIBuildableStructure* StructureToUpgrade);
|
bool AICOMM_UpgradeStructure(AvHAIPlayer* pBot, AvHAIBuildableStructure* StructureToUpgrade);
|
||||||
bool AICOMM_ResearchTech(AvHAIPlayer* pBot, AvHAIBuildableStructure* StructureToResearch, AvHMessageID Research);
|
bool AICOMM_ResearchTech(AvHAIPlayer* pBot, AvHAIBuildableStructure* StructureToResearch, AvHMessageID Research);
|
||||||
|
@ -27,34 +27,29 @@ bool AICOMM_IssueSiegeHiveOrder(AvHAIPlayer* pBot, edict_t* Recipient, const AvH
|
||||||
bool AICOMM_IssueSecureResNodeOrder(AvHAIPlayer* pBot, edict_t* Recipient, const AvHAIResourceNode* ResNode);
|
bool AICOMM_IssueSecureResNodeOrder(AvHAIPlayer* pBot, edict_t* Recipient, const AvHAIResourceNode* ResNode);
|
||||||
|
|
||||||
void AICOMM_AssignNewPlayerOrder(AvHAIPlayer* pBot, edict_t* Assignee, edict_t* TargetEntity, AvHAIOrderPurpose OrderPurpose);
|
void AICOMM_AssignNewPlayerOrder(AvHAIPlayer* pBot, edict_t* Assignee, edict_t* TargetEntity, AvHAIOrderPurpose OrderPurpose);
|
||||||
|
void AICOMM_AssignNewPlayerOrder(AvHAIPlayer* pBot, edict_t* Assignee, Vector OrderLocation, AvHAIOrderPurpose OrderPurpose);
|
||||||
int AICOMM_GetNumPlayersAssignedToOrder(AvHAIPlayer* pBot, edict_t* TargetEntity, AvHAIOrderPurpose OrderPurpose);
|
int AICOMM_GetNumPlayersAssignedToOrder(AvHAIPlayer* pBot, edict_t* TargetEntity, AvHAIOrderPurpose OrderPurpose);
|
||||||
|
int AICOMM_GetNumPlayersAssignedToOrderType(AvHAIPlayer* pBot, AvHAIOrderPurpose OrderPurpose);
|
||||||
|
int AICOMM_GetNumPlayersAssignedToOrderLocation(AvHAIPlayer* pBot, Vector OrderLocation, AvHAIOrderPurpose OrderPurpose);
|
||||||
bool AICOMM_IsOrderStillValid(AvHAIPlayer* pBot, ai_commander_order* Order);
|
bool AICOMM_IsOrderStillValid(AvHAIPlayer* pBot, ai_commander_order* Order);
|
||||||
void AICOMM_UpdatePlayerOrders(AvHAIPlayer* pBot);
|
void AICOMM_UpdatePlayerOrders(AvHAIPlayer* pBot);
|
||||||
edict_t* AICOMM_GetPlayerWithNoOrderNearestLocation(AvHAIPlayer* pBot, Vector SearchLocation);
|
edict_t* AICOMM_GetPlayerWithNoOrderNearestLocation(AvHAIPlayer* pBot, Vector SearchLocation);
|
||||||
|
edict_t* AICOMM_GetPlayerWithoutSpecificOrderNearestLocation(AvHAIPlayer* pBot, Vector SearchLocation, AvHAIOrderPurpose OrderPurpose);
|
||||||
bool AICOMM_DoesPlayerOrderNeedReminder(AvHAIPlayer* pBot, ai_commander_order* Order);
|
bool AICOMM_DoesPlayerOrderNeedReminder(AvHAIPlayer* pBot, ai_commander_order* Order);
|
||||||
void AICOMM_IssueOrderForAssignedJob(AvHAIPlayer* pBot, ai_commander_order* Order);
|
void AICOMM_IssueOrderForAssignedJob(AvHAIPlayer* pBot, ai_commander_order* Order);
|
||||||
|
|
||||||
void AICOMM_ClearAction(commander_action* Action);
|
|
||||||
|
|
||||||
bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot);
|
bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot);
|
||||||
bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot);
|
bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot);
|
||||||
bool AICOMM_CheckForNextRecycleAction(AvHAIPlayer* pBot);
|
bool AICOMM_CheckForNextRecycleAction(AvHAIPlayer* pBot);
|
||||||
bool AICOMM_CheckForNextResearchAction(AvHAIPlayer* pBot);
|
bool AICOMM_CheckForNextResearchAction(AvHAIPlayer* pBot);
|
||||||
bool AICOMM_CheckForNextSupplyAction(AvHAIPlayer* pBot);
|
bool AICOMM_CheckForNextSupplyAction(AvHAIPlayer* pBot);
|
||||||
|
|
||||||
void AICOMM_SetDropHealthAction(AvHAIPlayer* pBot, commander_action* Action, edict_t* Recipient);
|
Vector AICOMM_GetNextScanLocation(AvHAIPlayer* pBot);
|
||||||
void AICOMM_SetDropAmmoAction(AvHAIPlayer* pBot, commander_action* Action, edict_t* Recipient);
|
|
||||||
void AICOMM_SetDeployStructureAction(AvHAIPlayer* pBot, commander_action* Action, AvHAIDeployableStructureType StructureToBuild, const Vector Location, bool bIsUrgent);
|
|
||||||
void AICOMM_SetDeployItemAction(AvHAIPlayer* pBot, commander_action* Action, AvHAIDeployableItemType ItemToBuild, const Vector Location, bool bIsUrgent);
|
|
||||||
|
|
||||||
void AICOMM_CommanderThink(AvHAIPlayer* pBot);
|
void AICOMM_CommanderThink(AvHAIPlayer* pBot);
|
||||||
|
|
||||||
const AvHAIHiveDefinition* AICOMM_GetEmptyHiveOpportunityNearestLocation(AvHAIPlayer* CommanderBot, const Vector SearchLocation);
|
const AvHAIHiveDefinition* AICOMM_GetEmptyHiveOpportunityNearestLocation(AvHAIPlayer* CommanderBot, const Vector SearchLocation);
|
||||||
|
|
||||||
bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair);
|
|
||||||
bool AICOMM_PerformNextSiegeHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinition* HiveToSiege);
|
|
||||||
bool AICOMM_PerformNextSecureHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinition* HiveToSecure);
|
|
||||||
|
|
||||||
ai_commander_request* AICOMM_GetExistingRequestForPlayer(AvHAIPlayer* pBot, edict_t* Requestor);
|
ai_commander_request* AICOMM_GetExistingRequestForPlayer(AvHAIPlayer* pBot, edict_t* Requestor);
|
||||||
void AICOMM_CheckNewRequests(AvHAIPlayer* pBot);
|
void AICOMM_CheckNewRequests(AvHAIPlayer* pBot);
|
||||||
bool AICOMM_IsRequestValid(ai_commander_request* Request);
|
bool AICOMM_IsRequestValid(ai_commander_request* Request);
|
||||||
|
@ -71,4 +66,30 @@ bool AICOMM_ShouldBeacon(AvHAIPlayer* pBot);
|
||||||
|
|
||||||
void AICOMM_ReceiveChatRequest(AvHAIPlayer* Commander, edict_t* Requestor, const char* Request);
|
void AICOMM_ReceiveChatRequest(AvHAIPlayer* Commander, edict_t* Requestor, const char* Request);
|
||||||
|
|
||||||
|
bool AICOMM_ShouldCommanderRelocate(AvHAIPlayer* pBot);
|
||||||
|
|
||||||
|
bool AICOMM_GetRelocationMessage(Vector RelocationPoint, char* MessageBuffer);
|
||||||
|
|
||||||
|
AvHAIMarineBase* AICOMM_AddNewBase(AvHAIPlayer* pBot, Vector NewBaseLocation, MarineBaseType NewBaseType);
|
||||||
|
bool AICOMM_AddStructureToBase(AvHAIPlayer* pBot, AvHAIDeployableStructureType StructureToDeploy, Vector BuildLocation, AvHAIMarineBase* BaseToAdd);
|
||||||
|
|
||||||
|
void AICOMM_ManageActiveBases(AvHAIPlayer* pBot);
|
||||||
|
bool AICOMM_IsMarineBaseValid(AvHAIMarineBase* Base);
|
||||||
|
void AICOMM_DeployBases(AvHAIPlayer* pBot);
|
||||||
|
vector<AvHAIBuildableStructure> AICOMM_GetBaseStructures(AvHAIMarineBase* Base);
|
||||||
|
|
||||||
|
void AICOMM_UpdateBaseStatus(AvHAIPlayer* pBot, AvHAIMarineBase* Base);
|
||||||
|
void AICOMM_UpdateSiegeBaseStatus(AvHAIPlayer* pBot, AvHAIMarineBase* Base);
|
||||||
|
void AICOMM_UpdateOutpostStatus(AvHAIPlayer* pBot, AvHAIMarineBase* Base);
|
||||||
|
void AICOMM_UpdateGuardpostStatus(AvHAIPlayer* pBot, AvHAIMarineBase* Base);
|
||||||
|
void AICOMM_UpdateMainBaseStatus(AvHAIPlayer* pBot, AvHAIMarineBase* Base);
|
||||||
|
|
||||||
|
bool AICOMM_BuildOutBase(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut);
|
||||||
|
bool AICOMM_BuildOutMainBase(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut);
|
||||||
|
bool AICOMM_BuildOutOutpost(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut);
|
||||||
|
bool AICOMM_BuildOutSiege(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut);
|
||||||
|
bool AICOMM_BuildOutGuardPost(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut);
|
||||||
|
|
||||||
|
AvHAIMarineBase* AICOMM_GetNearestBaseToLocation(AvHAIPlayer* pBot, Vector SearchLocation);
|
||||||
|
|
||||||
#endif // AVH_AI_COMMANDER_H
|
#endif // AVH_AI_COMMANDER_H
|
|
@ -12,12 +12,17 @@ BotFillTiming CurrentBotFillTiming = FILLTIMING_ALLHUMANS;
|
||||||
|
|
||||||
float MaxAIMatchTimeMinutes = 90.0f;
|
float MaxAIMatchTimeMinutes = 90.0f;
|
||||||
|
|
||||||
|
float RelocationChance = 0.1f;
|
||||||
|
|
||||||
std::unordered_map<std::string, TeamSizeDefinitions> TeamSizeMap;
|
std::unordered_map<std::string, TeamSizeDefinitions> TeamSizeMap;
|
||||||
|
|
||||||
bot_skill BotSkillLevels[4];
|
bot_skill BotSkillLevels[4];
|
||||||
|
|
||||||
std::vector<AvHMessageID> ChamberSequence;
|
std::vector<AvHMessageID> ChamberSequence;
|
||||||
|
|
||||||
|
std::default_random_engine rng;
|
||||||
|
bool bRNGSeeded = false;
|
||||||
|
|
||||||
string DefaultBotNames[MAX_PLAYERS] = { "MrRobot",
|
string DefaultBotNames[MAX_PLAYERS] = { "MrRobot",
|
||||||
"Wall-E",
|
"Wall-E",
|
||||||
"BeepBoop",
|
"BeepBoop",
|
||||||
|
@ -90,6 +95,16 @@ bool CONFIG_IsOnosAllowed()
|
||||||
return avh_botallowonos.value > 0;
|
return avh_botallowonos.value > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CONFIG_IsRelocationAllowed()
|
||||||
|
{
|
||||||
|
return RelocationChance > 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float CONFIG_GetRelocationChance()
|
||||||
|
{
|
||||||
|
return RelocationChance;
|
||||||
|
}
|
||||||
|
|
||||||
float CONFIG_GetMaxStuckTime()
|
float CONFIG_GetMaxStuckTime()
|
||||||
{
|
{
|
||||||
return avh_botmaxstucktime.value;
|
return avh_botmaxstucktime.value;
|
||||||
|
@ -172,8 +187,6 @@ void CONFIG_PopulateBotNames()
|
||||||
|
|
||||||
if (BotNames.size() > 2)
|
if (BotNames.size() > 2)
|
||||||
{
|
{
|
||||||
auto rng = std::default_random_engine{};
|
|
||||||
rng.seed(time(0));
|
|
||||||
std::shuffle(begin(BotNames), end(BotNames), rng);
|
std::shuffle(begin(BotNames), end(BotNames), rng);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,8 +200,6 @@ void CONFIG_PopulateBotNames()
|
||||||
|
|
||||||
if (DefaultNames.size() > 2)
|
if (DefaultNames.size() > 2)
|
||||||
{
|
{
|
||||||
auto rng = std::default_random_engine{};
|
|
||||||
rng.seed(time(0));
|
|
||||||
std::shuffle(begin(DefaultNames), end(DefaultNames), rng);
|
std::shuffle(begin(DefaultNames), end(DefaultNames), rng);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,9 +273,13 @@ void CONFIG_ParseConfigFile()
|
||||||
ChamberSequence.push_back(ALIEN_BUILD_MOVEMENT_CHAMBER);
|
ChamberSequence.push_back(ALIEN_BUILD_MOVEMENT_CHAMBER);
|
||||||
ChamberSequence.push_back(ALIEN_BUILD_SENSORY_CHAMBER);
|
ChamberSequence.push_back(ALIEN_BUILD_SENSORY_CHAMBER);
|
||||||
|
|
||||||
std::srand(time(0));
|
if (!bRNGSeeded)
|
||||||
auto rng = std::default_random_engine{};
|
{
|
||||||
|
srand(time(0));
|
||||||
rng.seed(time(0));
|
rng.seed(time(0));
|
||||||
|
bRNGSeeded = true;
|
||||||
|
}
|
||||||
|
|
||||||
std::shuffle(std::begin(ChamberSequence), std::end(ChamberSequence), rng);
|
std::shuffle(std::begin(ChamberSequence), std::end(ChamberSequence), rng);
|
||||||
|
|
||||||
string BotConfigFile = string(getModDirectory()) + "/nsbots.ini";
|
string BotConfigFile = string(getModDirectory()) + "/nsbots.ini";
|
||||||
|
@ -328,6 +343,14 @@ void CONFIG_ParseConfigFile()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!stricmp(keyChar, "RelocationChance"))
|
||||||
|
{
|
||||||
|
float RelocationValue = std::stof(value.c_str());
|
||||||
|
RelocationChance = RelocationValue;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!stricmp(keyChar, "MaxAIMatchTime"))
|
if (!stricmp(keyChar, "MaxAIMatchTime"))
|
||||||
{
|
{
|
||||||
float MaxMinutes = std::stof(value.c_str());
|
float MaxMinutes = std::stof(value.c_str());
|
||||||
|
@ -641,7 +664,11 @@ void CONFIG_RegenerateIniFile()
|
||||||
fprintf(NewConfigFile, "# 0 = On map load (after 5 second grace period)\n");
|
fprintf(NewConfigFile, "# 0 = On map load (after 5 second grace period)\n");
|
||||||
fprintf(NewConfigFile, "# 1 = When all humans have joined a team (i.e. no more humans left in ready room)\n");
|
fprintf(NewConfigFile, "# 1 = When all humans have joined a team (i.e. no more humans left in ready room)\n");
|
||||||
fprintf(NewConfigFile, "# 2 = When the round has started (after countdown)\n");
|
fprintf(NewConfigFile, "# 2 = When the round has started (after countdown)\n");
|
||||||
fprintf(NewConfigFile, "BotFillTiming=1\n\n\n");
|
fprintf(NewConfigFile, "BotFillTiming=1\n\n");
|
||||||
|
|
||||||
|
fprintf(NewConfigFile, "# Chance the AI Commander will try to relocate at the beginning of the game\n");
|
||||||
|
fprintf(NewConfigFile, "# Value is a decimal between 0.0 and 1.0, with 0 being never and 1 being always\n");
|
||||||
|
fprintf(NewConfigFile, "RelocationChance=0.1\n\n\n");
|
||||||
|
|
||||||
|
|
||||||
fprintf(NewConfigFile, "### Skill Settings ###\n\n");
|
fprintf(NewConfigFile, "### Skill Settings ###\n\n");
|
||||||
|
|
|
@ -43,6 +43,9 @@ bool CONFIG_IsLerkAllowed();
|
||||||
bool CONFIG_IsFadeAllowed();
|
bool CONFIG_IsFadeAllowed();
|
||||||
bool CONFIG_IsOnosAllowed();
|
bool CONFIG_IsOnosAllowed();
|
||||||
|
|
||||||
|
bool CONFIG_IsRelocationAllowed();
|
||||||
|
float CONFIG_GetRelocationChance();
|
||||||
|
|
||||||
// Returns the max time a bot is allowed to be stuck before suiciding (0 means forever)
|
// Returns the max time a bot is allowed to be stuck before suiciding (0 means forever)
|
||||||
float CONFIG_GetMaxStuckTime();
|
float CONFIG_GetMaxStuckTime();
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@ typedef enum
|
||||||
STRUCTURE_ALIEN_OFFENCECHAMBER = 1u << 19,
|
STRUCTURE_ALIEN_OFFENCECHAMBER = 1u << 19,
|
||||||
|
|
||||||
SEARCH_ALL_MARINE_STRUCTURES = 0xFFF,
|
SEARCH_ALL_MARINE_STRUCTURES = 0xFFF,
|
||||||
SEARCH_ALL_ALIEN_STRUCTURES = 0xFC000,
|
SEARCH_ALL_ALIEN_STRUCTURES = (STRUCTURE_ALIEN_HIVE | STRUCTURE_ALIEN_RESTOWER | STRUCTURE_ALIEN_DEFENCECHAMBER | STRUCTURE_ALIEN_SENSORYCHAMBER | STRUCTURE_ALIEN_MOVEMENTCHAMBER | STRUCTURE_ALIEN_OFFENCECHAMBER),
|
||||||
SEARCH_ANY_RES_TOWER = (STRUCTURE_MARINE_RESTOWER | STRUCTURE_ALIEN_RESTOWER),
|
SEARCH_ANY_RES_TOWER = (STRUCTURE_MARINE_RESTOWER | STRUCTURE_ALIEN_RESTOWER),
|
||||||
|
|
||||||
SEARCH_ALL_STRUCTURES = ((unsigned int)-1 & ~(STRUCTURE_MARINE_DEPLOYEDMINE))
|
SEARCH_ALL_STRUCTURES = ((unsigned int)-1 & ~(STRUCTURE_MARINE_DEPLOYEDMINE))
|
||||||
|
@ -274,7 +274,7 @@ typedef struct _HIVE_DEFINITION_T
|
||||||
AvHTeamNumber OwningTeam = TEAM_IND; // Which team owns this hive currently (TEAM_IND if empty)
|
AvHTeamNumber OwningTeam = TEAM_IND; // Which team owns this hive currently (TEAM_IND if empty)
|
||||||
unsigned int TeamAReachabilityFlags = AI_REACHABILITY_NONE; // Who on team A can reach this node?
|
unsigned int TeamAReachabilityFlags = AI_REACHABILITY_NONE; // Who on team A can reach this node?
|
||||||
unsigned int TeamBReachabilityFlags = AI_REACHABILITY_NONE; // Who on team B can reach this node?
|
unsigned int TeamBReachabilityFlags = AI_REACHABILITY_NONE; // Who on team B can reach this node?
|
||||||
char HiveName[64];
|
char HiveName[64] = {'\0'};
|
||||||
} AvHAIHiveDefinition;
|
} AvHAIHiveDefinition;
|
||||||
|
|
||||||
// A nav profile combines a nav mesh reference (indexed into NavMeshes) and filters to determine how a bot should find paths
|
// A nav profile combines a nav mesh reference (indexed into NavMeshes) and filters to determine how a bot should find paths
|
||||||
|
@ -341,6 +341,7 @@ typedef struct _AVH_AI_GUARD_INFO
|
||||||
typedef struct _AVH_AI_BUILDABLE_STRUCTURE
|
typedef struct _AVH_AI_BUILDABLE_STRUCTURE
|
||||||
{
|
{
|
||||||
AvHBaseBuildable* EntityRef = nullptr;
|
AvHBaseBuildable* EntityRef = nullptr;
|
||||||
|
int EntIndex = -1;
|
||||||
edict_t* edict = nullptr; // Reference to structure edict
|
edict_t* edict = nullptr; // Reference to structure edict
|
||||||
Vector Location = g_vecZero; // origin of the structure edict
|
Vector Location = g_vecZero; // origin of the structure edict
|
||||||
float healthPercent = 0.0f; // Current health of the building
|
float healthPercent = 0.0f; // Current health of the building
|
||||||
|
@ -356,9 +357,11 @@ typedef struct _AVH_AI_BUILDABLE_STRUCTURE
|
||||||
Vector LastSuccessfulCommanderAngle = g_vecZero; // Tracks the last commander input angle ("click" location) used to successfully place or select building
|
Vector LastSuccessfulCommanderAngle = g_vecZero; // Tracks the last commander input angle ("click" location) used to successfully place or select building
|
||||||
StructurePurpose Purpose = STRUCTURE_PURPOSE_NONE;
|
StructurePurpose Purpose = STRUCTURE_PURPOSE_NONE;
|
||||||
bool bReachabilityMarkedDirty = false; // If true, reachability flags will be recalculated for this structure
|
bool bReachabilityMarkedDirty = false; // If true, reachability flags will be recalculated for this structure
|
||||||
|
bool bPlacedByHuman = true; // This structure was placed by a human: AI commander will not recycle these unless it absolutely makes sense to
|
||||||
|
|
||||||
bool IsValid() { return !FNullEnt(edict) && !edict->free && !(edict->v.flags & EF_NODRAW) && edict->v.deadflag == DEAD_NO; }
|
bool IsValid() { return !FNullEnt(edict) && !edict->free && !(edict->v.flags & EF_NODRAW) && edict->v.deadflag == DEAD_NO; }
|
||||||
bool IsCompleted() { return (StructureStatusFlags & STRUCTURE_STATUS_COMPLETED); }
|
bool IsCompleted() { return (StructureStatusFlags & STRUCTURE_STATUS_COMPLETED); }
|
||||||
|
bool IsIdle() { return !(StructureStatusFlags & STRUCTURE_STATUS_RESEARCHING); }
|
||||||
|
|
||||||
} AvHAIBuildableStructure;
|
} AvHAIBuildableStructure;
|
||||||
|
|
||||||
|
@ -372,6 +375,8 @@ typedef struct _DROPPED_MARINE_ITEM
|
||||||
unsigned int TeamBReachabilityFlags = AI_REACHABILITY_NONE;
|
unsigned int TeamBReachabilityFlags = AI_REACHABILITY_NONE;
|
||||||
bool bReachabilityMarkedDirty = false; // Reachability needs to be recalculated
|
bool bReachabilityMarkedDirty = false; // Reachability needs to be recalculated
|
||||||
int LastSeen = 0; // Which refresh cycle was this last seen on? Used to determine if the item has been removed from play
|
int LastSeen = 0; // Which refresh cycle was this last seen on? Used to determine if the item has been removed from play
|
||||||
|
|
||||||
|
bool IsValid() { return !FNullEnt(edict) && !edict->free && !(edict->v.flags & EF_NODRAW) && edict->v.deadflag == DEAD_NO; }
|
||||||
} AvHAIDroppedItem;
|
} AvHAIDroppedItem;
|
||||||
|
|
||||||
// How far a bot can be from a useable object when trying to interact with it. Used also for melee attacks. We make it slightly less than actual to avoid edge cases
|
// How far a bot can be from a useable object when trying to interact with it. Used also for melee attacks. We make it slightly less than actual to avoid edge cases
|
||||||
|
@ -415,7 +420,7 @@ typedef enum
|
||||||
TASK_REINFORCE_STRUCTURE,
|
TASK_REINFORCE_STRUCTURE,
|
||||||
TASK_SECURE_HIVE,
|
TASK_SECURE_HIVE,
|
||||||
TASK_PLACE_MINE,
|
TASK_PLACE_MINE,
|
||||||
TASK_ATTACK_BASE
|
TASK_ASSAULT_MARINE_BASE
|
||||||
}
|
}
|
||||||
BotTaskType;
|
BotTaskType;
|
||||||
|
|
||||||
|
@ -469,6 +474,31 @@ enum NavDoorType
|
||||||
DOORTYPE_TRAIN // Door activated by touching a trigger_once or trigger_multiple
|
DOORTYPE_TRAIN // Door activated by touching a trigger_once or trigger_multiple
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The type of base a marine outpost could be. Used to help the AI establish and expand outposts across the map
|
||||||
|
enum MarineBaseType
|
||||||
|
{
|
||||||
|
MARINE_BASE_MAINBASE, // The main marine base, where the CC, infantry portals and stuff like arms labs go
|
||||||
|
MARINE_BASE_OUTPOST, // A permanent outpost designed to control an area of the map, but not the main marine base
|
||||||
|
MARINE_BASE_SIEGE, // A siege base designed to take down an enemy base
|
||||||
|
MARINE_BASE_GUARDPOST // A cut-down version of an outpost with just sentry turrets and an observatory
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _AI_MARINE_BASE
|
||||||
|
{
|
||||||
|
AvHTeamNumber BaseTeam = TEAM_IND;
|
||||||
|
MarineBaseType BaseType = MARINE_BASE_OUTPOST; // The purpose of the base. Determines what structures the commander will place
|
||||||
|
Vector BaseLocation = ZERO_VECTOR; // Where the base should be located. The base will be grown around this location
|
||||||
|
Vector SiegeTarget = ZERO_VECTOR; // For siege bases, this is where the siege base wants to blast stuff
|
||||||
|
vector<int> PlacedStructures; // Which structures are part of this base.
|
||||||
|
int NumBuilders = 0; // How many potential builders are there, able to construct stuff?
|
||||||
|
int NumEnemies = 0; // How many enemies are in and around the base?
|
||||||
|
bool bRecycleBase = false; // Should the commander pack up and remove this base?
|
||||||
|
bool bIsActive = true; // Should the commander actively build and maintain this base?
|
||||||
|
bool bBaseInitialised = false; // Has the commander started building this base? Will be true once a structure has been placed
|
||||||
|
bool bCanBeBuiltOut = false; // Can this base be built out currently?
|
||||||
|
bool bIsBaseEstablished = false; // Have enough key structures been placed to consider this "established", even if it's not finished yet?
|
||||||
|
} AvHAIMarineBase;
|
||||||
|
|
||||||
// Bot path node. A path will be several of these strung together to lead the bot to its destination
|
// Bot path node. A path will be several of these strung together to lead the bot to its destination
|
||||||
typedef struct _BOT_PATH_NODE
|
typedef struct _BOT_PATH_NODE
|
||||||
{
|
{
|
||||||
|
@ -607,6 +637,7 @@ typedef struct _NAV_STATUS
|
||||||
Vector UnstuckMoveLocation = g_vecZero; // If the bot is unable to find a path, blindly move here to try and fix the problem
|
Vector UnstuckMoveLocation = g_vecZero; // If the bot is unable to find a path, blindly move here to try and fix the problem
|
||||||
|
|
||||||
float LandedTime = 0.0f; // When the bot last landed after a fall/jump.
|
float LandedTime = 0.0f; // When the bot last landed after a fall/jump.
|
||||||
|
float AirStartedTime = 0.0f; // When the bot left the ground if in the air
|
||||||
float LeapAttemptedTime = 0.0f; // When the bot last attempted to leap/blink. Avoid spam that sends it flying around too fast
|
float LeapAttemptedTime = 0.0f; // When the bot last attempted to leap/blink. Avoid spam that sends it flying around too fast
|
||||||
bool bIsJumping = false; // Is the bot in the air from a jump? Will duck so it can duck-jump
|
bool bIsJumping = false; // Is the bot in the air from a jump? Will duck so it can duck-jump
|
||||||
bool IsOnGround = true; // Is the bot currently on the ground, or on a ladder?
|
bool IsOnGround = true; // Is the bot currently on the ground, or on a ladder?
|
||||||
|
@ -621,7 +652,7 @@ typedef struct _NAV_STATUS
|
||||||
|
|
||||||
float NextForceRecalc = 0.0f; // If set, then the bot will force-recalc its current path
|
float NextForceRecalc = 0.0f; // If set, then the bot will force-recalc its current path
|
||||||
|
|
||||||
bool bZig; // Is the bot zigging, or zagging?
|
bool bZig; // Is the bot zigging (moving RIGHT), or zagging (moving LEFT)?
|
||||||
float NextZigTime; // Controls how frequently they zig or zag
|
float NextZigTime; // Controls how frequently they zig or zag
|
||||||
|
|
||||||
nav_profile NavProfile;
|
nav_profile NavProfile;
|
||||||
|
@ -634,61 +665,16 @@ typedef struct _NAV_STATUS
|
||||||
AvHAIPlayerMoveTask MovementTask;
|
AvHAIPlayerMoveTask MovementTask;
|
||||||
} nav_status;
|
} nav_status;
|
||||||
|
|
||||||
// Type of goal the commander wants to achieve
|
|
||||||
typedef enum _COMMANDERACTIONTYPE
|
|
||||||
{
|
|
||||||
ACTION_NONE = 0,
|
|
||||||
ACTION_UPGRADE,
|
|
||||||
ACTION_RESEARCH,
|
|
||||||
ACTION_RECYCLE,
|
|
||||||
ACTION_GIVEORDER,
|
|
||||||
ACTION_DEPLOY // Deploy a structure or item into the map
|
|
||||||
|
|
||||||
} CommanderActionType;
|
|
||||||
|
|
||||||
// Some commander actions are multi-step (e.g. click to select building, release to complete selection, input recycle command etc). Tracks where the commander is in the process
|
|
||||||
typedef enum _COMMANDERACTIONSTEP
|
|
||||||
{
|
|
||||||
ACTION_STEP_NONE = 0,
|
|
||||||
ACTION_STEP_BEGIN_SELECT, // Click mouse button down to start select
|
|
||||||
ACTION_STEP_END_SELECT, // Release mouse button to complete select
|
|
||||||
|
|
||||||
} CommanderActionStep;
|
|
||||||
|
|
||||||
|
|
||||||
// Used by the AI commander instead of bot_task. Has data specifically to handle commander-specific stuff
|
|
||||||
typedef struct _COMMANDER_ACTION
|
|
||||||
{
|
|
||||||
bool bIsActive = false;
|
|
||||||
CommanderActionType ActionType = ACTION_NONE; // What action to perform (e.g. build, recycle, drop item etc)
|
|
||||||
CommanderActionStep ActionStep = ACTION_STEP_NONE; // Used for multi-stage processes such as selecting a building, issuing recycle command etc.
|
|
||||||
AvHAIDeployableStructureType StructureToBuild = STRUCTURE_NONE; // What structure to build if build action
|
|
||||||
AvHAIDeployableItemType ItemToPlace = DEPLOYABLE_ITEM_NONE;
|
|
||||||
int NumInstances = 0;
|
|
||||||
int NumDesiredInstances = 0;
|
|
||||||
StructurePurpose ActionPurpose = STRUCTURE_PURPOSE_NONE;
|
|
||||||
Vector BuildLocation = g_vecZero; // Where to build the structure
|
|
||||||
Vector DesiredCommanderLocation = g_vecZero; // To perform this action, where does the commander's view need to be? For building, usually directly above location, but could be off to side if obstructed by geometry
|
|
||||||
Vector LastAttemptedCommanderLocation = g_vecZero; // The position of the commander's view at the last action attempt
|
|
||||||
Vector LastAttemptedCommanderAngle = g_vecZero; // The click angle of the last action attempt
|
|
||||||
int AssignedPlayer = 0; // Which player index is assigned to perform the action (e.g. build structure)? Will send orders to that player (move here, build this structure etc.)
|
|
||||||
edict_t* StructureOrItem = nullptr; // Reference the structure edict. If a structure has been successfully placed but not yet fully built, it will be referenced here
|
|
||||||
edict_t* ActionTarget = nullptr; // Mostly used for dropping health packs and ammo for players where the drop location might be moving around
|
|
||||||
bool bHasAttemptedAction = false; // Has the commander tried placing a structure or item at the build location? If so, and it didn't appear, will try to adjust view around until it works
|
|
||||||
float StructureBuildAttemptTime = 0.0f; // When the commander tried placing a structure. Commander will wait a short while to confirm if the building appeared or if it should try again
|
|
||||||
int NumActionAttempts = 0; // Commander will give up after a certain number of attempts to place structure/item
|
|
||||||
AvHMessageID ResearchId = MESSAGE_NULL; // What research to perform if research action
|
|
||||||
bool bIsAwaitingBuildLink = false; // The AI has tried placing a structure or item and is waiting to confirm it worked or not
|
|
||||||
bool bIsActionUrgent = false;
|
|
||||||
|
|
||||||
} commander_action;
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
ORDERPURPOSE_NONE,
|
ORDERPURPOSE_NONE,
|
||||||
ORDERPURPOSE_SECURE_HIVE,
|
ORDERPURPOSE_SECURE_HIVE,
|
||||||
ORDERPURPOSE_SIEGE_HIVE,
|
ORDERPURPOSE_SIEGE_HIVE,
|
||||||
ORDERPURPOSE_SECURE_RESNODE
|
ORDERPURPOSE_SECURE_RESNODE,
|
||||||
|
ORDERPURPOSE_BUILD_MAINBASE,
|
||||||
|
ORDERPURPOSE_BUILD_SIEGE,
|
||||||
|
ORDERPURPOSE_BUILD_OUTPOST,
|
||||||
|
ORDERPURPOSE_BUILD_GUARDPOST
|
||||||
} AvHAIOrderPurpose;
|
} AvHAIOrderPurpose;
|
||||||
|
|
||||||
typedef struct _AI_COMMANDER_ORDER
|
typedef struct _AI_COMMANDER_ORDER
|
||||||
|
@ -782,11 +768,14 @@ typedef struct AVH_AI_PLAYER
|
||||||
|
|
||||||
float LastRequestTime = 0.0f; // When bot last used a voice line to request something. Prevents spam
|
float LastRequestTime = 0.0f; // When bot last used a voice line to request something. Prevents spam
|
||||||
|
|
||||||
|
float LastTeleportTime = 0.0f; // Last time the bot teleported somewhere
|
||||||
|
|
||||||
Vector DesiredLookDirection = g_vecZero; // What view angle is the bot currently turning towards
|
Vector DesiredLookDirection = g_vecZero; // What view angle is the bot currently turning towards
|
||||||
Vector InterpolatedLookDirection = g_vecZero; // Used to smoothly interpolate the bot's view rather than snap instantly like an aimbot
|
Vector InterpolatedLookDirection = g_vecZero; // Used to smoothly interpolate the bot's view rather than snap instantly like an aimbot
|
||||||
edict_t* LookTarget = nullptr; // Used to work out what view angle is needed to look at the desired entity
|
edict_t* LookTarget = nullptr; // Used to work out what view angle is needed to look at the desired entity
|
||||||
Vector LookTargetLocation = g_vecZero; // This is the bot's current desired look target. Could be an enemy (see LookTarget), or point of interest
|
Vector LookTargetLocation = g_vecZero; // This is the bot's current desired look target. Could be an enemy (see LookTarget), or point of interest
|
||||||
Vector MoveLookLocation = g_vecZero; // If the bot has to look somewhere specific for movement (e.g. up for a ladder or wall-climb), this will override LookTargetLocation so the bot doesn't get distracted and mess the move up
|
Vector MoveLookLocation = g_vecZero; // If the bot has to look somewhere specific for movement (e.g. up for a ladder or wall-climb), this will override LookTargetLocation so the bot doesn't get distracted and mess the move up
|
||||||
|
bool bSnapView = false; // Use for rapid, precise snapping of the bot's view to the target. Useful if the bot requires more precise view angles for movement or other reasons
|
||||||
float LastTargetTrackUpdate = 0.0f; // Add a delay to how frequently a bot can track a target's movements
|
float LastTargetTrackUpdate = 0.0f; // Add a delay to how frequently a bot can track a target's movements
|
||||||
float ViewInterpolationSpeed = 0.0f; // How fast should the bot turn its view? Depends on distance to turn
|
float ViewInterpolationSpeed = 0.0f; // How fast should the bot turn its view? Depends on distance to turn
|
||||||
float ViewInterpStartedTime = 0.0f; // Used for interpolation
|
float ViewInterpStartedTime = 0.0f; // Used for interpolation
|
||||||
|
@ -812,6 +801,10 @@ typedef struct AVH_AI_PLAYER
|
||||||
|
|
||||||
int DebugValue = 0; // Used for debugging the bot
|
int DebugValue = 0; // Used for debugging the bot
|
||||||
|
|
||||||
|
Vector RelocationSpot = ZERO_VECTOR; // If the bot is commanding and wants to relocate, then this is where they plan to go
|
||||||
|
|
||||||
|
vector<AvHAIMarineBase> Bases;
|
||||||
|
|
||||||
} AvHAIPlayer;
|
} AvHAIPlayer;
|
||||||
|
|
||||||
typedef struct _AVH_AI_SQUAD
|
typedef struct _AVH_AI_SQUAD
|
||||||
|
@ -820,6 +813,7 @@ typedef struct _AVH_AI_SQUAD
|
||||||
vector<AvHAIPlayer*> SquadMembers; // Which bots are assigned to this
|
vector<AvHAIPlayer*> SquadMembers; // Which bots are assigned to this
|
||||||
Vector SquadGatherLocation = g_vecZero; // Where should the squad gather before attempting the objective?
|
Vector SquadGatherLocation = g_vecZero; // Where should the squad gather before attempting the objective?
|
||||||
edict_t* SquadTarget = nullptr; // The target of the objective
|
edict_t* SquadTarget = nullptr; // The target of the objective
|
||||||
|
Vector ObjectiveLocation = g_vecZero;
|
||||||
BotTaskType SquadObjective = TASK_NONE; // What to do with the objective
|
BotTaskType SquadObjective = TASK_NONE; // What to do with the objective
|
||||||
bool bExecuteObjective = false; // Are we at the gather or execute phase?
|
bool bExecuteObjective = false; // Are we at the gather or execute phase?
|
||||||
|
|
||||||
|
|
|
@ -342,7 +342,17 @@ void AIDEBUG_DrawPath(edict_t* OutputPlayer, vector<bot_path_node>& path, float
|
||||||
UTIL_DrawLine(OutputPlayer, FromLoc, ToLoc, DrawTime, 255, 128, 128);
|
UTIL_DrawLine(OutputPlayer, FromLoc, ToLoc, DrawTime, 255, 128, 128);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
{
|
||||||
|
if (it->area == SAMPLE_POLYAREA_CROUCH)
|
||||||
|
{
|
||||||
|
UTIL_DrawLine(OutputPlayer, FromLoc, ToLoc, DrawTime, 255, 150, 150);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
UTIL_DrawLine(OutputPlayer, FromLoc, ToLoc, DrawTime);
|
UTIL_DrawLine(OutputPlayer, FromLoc, ToLoc, DrawTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -350,9 +360,16 @@ void AIDEBUG_DrawPath(edict_t* OutputPlayer, vector<bot_path_node>& path, float
|
||||||
|
|
||||||
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end)
|
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end)
|
||||||
{
|
{
|
||||||
if (FNullEnt(pEntity) || pEntity->free) { return; }
|
|
||||||
|
|
||||||
|
if (FNullEnt(pEntity) || pEntity->free)
|
||||||
|
{
|
||||||
|
MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity);
|
MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity);
|
||||||
|
}
|
||||||
|
|
||||||
WRITE_BYTE(TE_BEAMPOINTS);
|
WRITE_BYTE(TE_BEAMPOINTS);
|
||||||
WRITE_COORD(start.x);
|
WRITE_COORD(start.x);
|
||||||
WRITE_COORD(start.y);
|
WRITE_COORD(start.y);
|
||||||
|
@ -378,12 +395,18 @@ void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end)
|
||||||
|
|
||||||
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSeconds)
|
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSeconds)
|
||||||
{
|
{
|
||||||
if (FNullEnt(pEntity) || pEntity->free) { return; }
|
|
||||||
|
|
||||||
int timeTenthSeconds = (int)floorf(drawTimeSeconds * 10.0f);
|
int timeTenthSeconds = (int)floorf(drawTimeSeconds * 10.0f);
|
||||||
timeTenthSeconds = fmaxf(timeTenthSeconds, 1);
|
timeTenthSeconds = fmaxf(timeTenthSeconds, 1);
|
||||||
|
|
||||||
|
if (FNullEnt(pEntity) || pEntity->free)
|
||||||
|
{
|
||||||
|
MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity);
|
MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity);
|
||||||
|
}
|
||||||
|
|
||||||
WRITE_BYTE(TE_BEAMPOINTS);
|
WRITE_BYTE(TE_BEAMPOINTS);
|
||||||
WRITE_COORD(start.x);
|
WRITE_COORD(start.x);
|
||||||
WRITE_COORD(start.y);
|
WRITE_COORD(start.y);
|
||||||
|
@ -409,12 +432,18 @@ void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSec
|
||||||
|
|
||||||
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSeconds, int r, int g, int b)
|
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSeconds, int r, int g, int b)
|
||||||
{
|
{
|
||||||
if (FNullEnt(pEntity) || pEntity->free) { return; }
|
|
||||||
|
|
||||||
int timeTenthSeconds = (int)ceilf(drawTimeSeconds * 10.0f);
|
int timeTenthSeconds = (int)ceilf(drawTimeSeconds * 10.0f);
|
||||||
timeTenthSeconds = fmaxf(timeTenthSeconds, 1);
|
timeTenthSeconds = fmaxf(timeTenthSeconds, 1);
|
||||||
|
|
||||||
|
if (FNullEnt(pEntity) || pEntity->free)
|
||||||
|
{
|
||||||
|
MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity);
|
MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity);
|
||||||
|
}
|
||||||
|
|
||||||
WRITE_BYTE(TE_BEAMPOINTS);
|
WRITE_BYTE(TE_BEAMPOINTS);
|
||||||
WRITE_COORD(start.x);
|
WRITE_COORD(start.x);
|
||||||
WRITE_COORD(start.y);
|
WRITE_COORD(start.y);
|
||||||
|
@ -440,9 +469,15 @@ void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSec
|
||||||
|
|
||||||
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, int r, int g, int b)
|
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, int r, int g, int b)
|
||||||
{
|
{
|
||||||
if (FNullEnt(pEntity) || pEntity->free) { return; }
|
if (FNullEnt(pEntity) || pEntity->free)
|
||||||
|
{
|
||||||
|
MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity);
|
MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity);
|
||||||
|
}
|
||||||
|
|
||||||
WRITE_BYTE(TE_BEAMPOINTS);
|
WRITE_BYTE(TE_BEAMPOINTS);
|
||||||
WRITE_COORD(start.x);
|
WRITE_COORD(start.x);
|
||||||
WRITE_COORD(start.y);
|
WRITE_COORD(start.y);
|
||||||
|
@ -638,11 +673,64 @@ void UTIL_LocalizeText(const char* InputText, string& OutputText)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* UTIL_StructTypeToChar(const AvHAIDeployableStructureType StructureType)
|
||||||
|
{
|
||||||
|
switch (StructureType)
|
||||||
|
{
|
||||||
|
case STRUCTURE_MARINE_RESTOWER:
|
||||||
|
return "RT";
|
||||||
|
case STRUCTURE_MARINE_INFANTRYPORTAL:
|
||||||
|
return "IP";
|
||||||
|
case STRUCTURE_MARINE_TURRETFACTORY:
|
||||||
|
return "TF";
|
||||||
|
case STRUCTURE_MARINE_ADVTURRETFACTORY:
|
||||||
|
return "Adv TF";
|
||||||
|
case STRUCTURE_MARINE_ARMOURY:
|
||||||
|
return "Armoury";
|
||||||
|
case STRUCTURE_MARINE_ADVARMOURY:
|
||||||
|
return "Adv Armoury";
|
||||||
|
case STRUCTURE_MARINE_ARMSLAB:
|
||||||
|
return "Armslab";
|
||||||
|
case STRUCTURE_MARINE_PROTOTYPELAB:
|
||||||
|
return "ProtoLab";
|
||||||
|
case STRUCTURE_MARINE_OBSERVATORY:
|
||||||
|
return "Obs";
|
||||||
|
case STRUCTURE_MARINE_PHASEGATE:
|
||||||
|
return "PG";
|
||||||
|
case STRUCTURE_MARINE_TURRET:
|
||||||
|
return "Sentry";
|
||||||
|
case STRUCTURE_MARINE_SIEGETURRET:
|
||||||
|
return "Siege T";
|
||||||
|
case STRUCTURE_MARINE_COMMCHAIR:
|
||||||
|
return "CC";
|
||||||
|
case STRUCTURE_MARINE_DEPLOYEDMINE:
|
||||||
|
return "Mine";
|
||||||
|
|
||||||
|
case STRUCTURE_ALIEN_HIVE:
|
||||||
|
return "Hive";
|
||||||
|
case STRUCTURE_ALIEN_RESTOWER:
|
||||||
|
return "RT";
|
||||||
|
case STRUCTURE_ALIEN_DEFENCECHAMBER:
|
||||||
|
return "DC";
|
||||||
|
case STRUCTURE_ALIEN_SENSORYCHAMBER:
|
||||||
|
return "SC";
|
||||||
|
case STRUCTURE_ALIEN_MOVEMENTCHAMBER:
|
||||||
|
return "MC";
|
||||||
|
case STRUCTURE_ALIEN_OFFENCECHAMBER:
|
||||||
|
return "OC";
|
||||||
|
default:
|
||||||
|
return "None";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "None";
|
||||||
|
}
|
||||||
|
|
||||||
char* UTIL_TaskTypeToChar(const BotTaskType TaskType)
|
char* UTIL_TaskTypeToChar(const BotTaskType TaskType)
|
||||||
{
|
{
|
||||||
switch (TaskType)
|
switch (TaskType)
|
||||||
{
|
{
|
||||||
case TASK_ATTACK:
|
case TASK_ATTACK:
|
||||||
|
|
||||||
return "Attack";
|
return "Attack";
|
||||||
case TASK_BUILD:
|
case TASK_BUILD:
|
||||||
return "Build";
|
return "Build";
|
||||||
|
@ -680,8 +768,8 @@ char* UTIL_TaskTypeToChar(const BotTaskType TaskType)
|
||||||
return "Touch Trigger";
|
return "Touch Trigger";
|
||||||
case TASK_WELD:
|
case TASK_WELD:
|
||||||
return "Weld Target";
|
return "Weld Target";
|
||||||
case TASK_ATTACK_BASE:
|
case TASK_ASSAULT_MARINE_BASE:
|
||||||
return "Attack Enemy Base";
|
return "Assault Marine Base";
|
||||||
default:
|
default:
|
||||||
return "None";
|
return "None";
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ void UTIL_ClearLocalizations();
|
||||||
void UTIL_LocalizeText(const char* InputText, string& OutputText);
|
void UTIL_LocalizeText(const char* InputText, string& OutputText);
|
||||||
|
|
||||||
char* UTIL_TaskTypeToChar(const BotTaskType TaskType);
|
char* UTIL_TaskTypeToChar(const BotTaskType TaskType);
|
||||||
|
char* UTIL_StructTypeToChar(const AvHAIDeployableStructureType StructureType);
|
||||||
|
|
||||||
char* UTIL_BotRoleToChar(const AvHAIBotRole Role);
|
char* UTIL_BotRoleToChar(const AvHAIBotRole Role);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -220,7 +220,7 @@ void NewMove(AvHAIPlayer* pBot);
|
||||||
// Returns true if the bot has completed the current movement along their path
|
// Returns true if the bot has completed the current movement along their path
|
||||||
bool HasBotReachedPathPoint(const AvHAIPlayer* pBot);
|
bool HasBotReachedPathPoint(const AvHAIPlayer* pBot);
|
||||||
bool HasBotCompletedLadderMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
bool HasBotCompletedLadderMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
bool HasBotCompletedWalkMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
bool HasBotCompletedWalkMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, SamplePolyAreas MoveArea, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag, SamplePolyAreas NextMoveArea);
|
||||||
bool HasBotCompletedFallMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
bool HasBotCompletedFallMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
bool HasBotCompletedClimbMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, float RequiredClimbHeight, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
bool HasBotCompletedClimbMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, float RequiredClimbHeight, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
bool HasBotCompletedJumpMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
bool HasBotCompletedJumpMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
@ -495,6 +495,8 @@ nav_door* UTIL_GetNavDoorByEdict(const edict_t* DoorEdict);
|
||||||
nav_door* UTIL_GetClosestLiftToPoints(const Vector StartPoint, const Vector EndPoint);
|
nav_door* UTIL_GetClosestLiftToPoints(const Vector StartPoint, const Vector EndPoint);
|
||||||
AvHAIOffMeshConnection* UTIL_GetOffMeshConnectionForLift(nav_door* LiftRef);
|
AvHAIOffMeshConnection* UTIL_GetOffMeshConnectionForLift(nav_door* LiftRef);
|
||||||
|
|
||||||
|
bool UTIL_IsTileCacheUpToDate();
|
||||||
|
|
||||||
Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDistanceFromWall);
|
Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDistanceFromWall);
|
||||||
|
|
||||||
void UTIL_PopulateBaseNavProfiles();
|
void UTIL_PopulateBaseNavProfiles();
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -26,9 +26,9 @@ static const float f_ffwidth = f_ffheight * BOT_ASPECT_RATIO;
|
||||||
|
|
||||||
void BotJump(AvHAIPlayer* pBot);
|
void BotJump(AvHAIPlayer* pBot);
|
||||||
void BotSuicide(AvHAIPlayer* pBot);
|
void BotSuicide(AvHAIPlayer* pBot);
|
||||||
void BotLookAt(AvHAIPlayer* pBot, Vector NewLocation);
|
void BotLookAt(AvHAIPlayer* pBot, Vector NewLocation, bool bSnap = false);
|
||||||
void BotLookAt(AvHAIPlayer* pBot, edict_t* target);
|
void BotLookAt(AvHAIPlayer* pBot, edict_t* target, bool bSnap = false);
|
||||||
void BotMoveLookAt(AvHAIPlayer* pBot, const Vector target);
|
void BotMoveLookAt(AvHAIPlayer* pBot, const Vector target, bool bSnap = false);
|
||||||
void BotDirectLookAt(AvHAIPlayer* pBot, Vector target);
|
void BotDirectLookAt(AvHAIPlayer* pBot, Vector target);
|
||||||
|
|
||||||
bool BotUseObject(AvHAIPlayer* pBot, edict_t* Target, bool bContinuous);
|
bool BotUseObject(AvHAIPlayer* pBot, edict_t* Target, bool bContinuous);
|
||||||
|
@ -159,6 +159,8 @@ void AIPlayerHearEnemy(AvHAIPlayer* pBot, edict_t* HeardEnemy, float SoundVolume
|
||||||
|
|
||||||
int BotGetNextEnemyTarget(AvHAIPlayer* pBot);
|
int BotGetNextEnemyTarget(AvHAIPlayer* pBot);
|
||||||
|
|
||||||
|
void OnBotTeleport(AvHAIPlayer* pBot);
|
||||||
|
|
||||||
AvHMessageID AlienGetDesiredUpgrade(AvHAIPlayer* pBot, HiveTechStatus DesiredTech);
|
AvHMessageID AlienGetDesiredUpgrade(AvHAIPlayer* pBot, HiveTechStatus DesiredTech);
|
||||||
|
|
||||||
AvHAICombatStrategy GetBotCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_status* CurrentEnemy);
|
AvHAICombatStrategy GetBotCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_status* CurrentEnemy);
|
||||||
|
@ -188,4 +190,6 @@ void DEBUG_PrintBotDebugInfo(edict_t* OutputPlayer, AvHAIPlayer* pBot);
|
||||||
void DEBUG_PrintTaskInfo(edict_t* OutputPlayer, AvHAIPlayer* pBot);
|
void DEBUG_PrintTaskInfo(edict_t* OutputPlayer, AvHAIPlayer* pBot);
|
||||||
void DEBUG_PrintCombatInfo(edict_t* OutputPlayer, AvHAIPlayer* pBot);
|
void DEBUG_PrintCombatInfo(edict_t* OutputPlayer, AvHAIPlayer* pBot);
|
||||||
|
|
||||||
|
Vector GetZigZagDirection(AvHAIPlayer* pBot, edict_t* Enemy, bot_path_node* CurrentPathNode);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -24,6 +24,7 @@ extern cvar_t avh_botusemapdefaults;
|
||||||
extern cvar_t avh_botcommandermode;
|
extern cvar_t avh_botcommandermode;
|
||||||
extern cvar_t avh_botdebugmode;
|
extern cvar_t avh_botdebugmode;
|
||||||
extern cvar_t avh_botskill;
|
extern cvar_t avh_botskill;
|
||||||
|
extern cvar_t avh_limitteams;
|
||||||
|
|
||||||
float LastAIPlayerCountUpdate = 0.0f;
|
float LastAIPlayerCountUpdate = 0.0f;
|
||||||
|
|
||||||
|
@ -225,7 +226,10 @@ void AIMGR_UpdateFillTeams()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TeamSizeA < NumDesiredTeamA && TeamSizeA <= TeamSizeB)
|
bool bCanAddToTeamA = (GetGameRules()->GetCheatsEnabled() || TeamSizeA < TeamSizeB || TeamSizeA - TeamSizeB < avh_limitteams.value);
|
||||||
|
bool bCanAddToTeamB = (GetGameRules()->GetCheatsEnabled() || TeamSizeB < TeamSizeA || TeamSizeB - TeamSizeA < avh_limitteams.value);
|
||||||
|
|
||||||
|
if (TeamSizeA < NumDesiredTeamA && bCanAddToTeamA)
|
||||||
{
|
{
|
||||||
// Don't add a bot if we have any stuck in the ready room, wait for teams to resolve themselves
|
// Don't add a bot if we have any stuck in the ready room, wait for teams to resolve themselves
|
||||||
if (AIMGR_GetNumAIPlayersOnTeam(TEAM_IND) > 0) { return; }
|
if (AIMGR_GetNumAIPlayersOnTeam(TEAM_IND) > 0) { return; }
|
||||||
|
@ -242,7 +246,7 @@ void AIMGR_UpdateFillTeams()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TeamSizeB < NumDesiredTeamB && TeamSizeB <= TeamSizeA)
|
if (TeamSizeB < NumDesiredTeamB && bCanAddToTeamB)
|
||||||
{
|
{
|
||||||
// Don't add a bot if we have any stuck in the ready room, wait for teams to resolve themselves
|
// Don't add a bot if we have any stuck in the ready room, wait for teams to resolve themselves
|
||||||
if (AIMGR_GetNumAIPlayersOnTeam(TEAM_IND) > 0) { return; }
|
if (AIMGR_GetNumAIPlayersOnTeam(TEAM_IND) > 0) { return; }
|
||||||
|
@ -640,6 +644,10 @@ void AIMGR_UpdateAIPlayers()
|
||||||
|
|
||||||
BotUpdateViewRotation(bot, FrameDelta);
|
BotUpdateViewRotation(bot, FrameDelta);
|
||||||
|
|
||||||
|
// Need to reset this since impulses generally should only be called once at a time, so this
|
||||||
|
// prevents it from being called on consecutive frames if this bot isn't running its think routine every frame
|
||||||
|
bot->Impulse = 0;
|
||||||
|
|
||||||
if (bHasRoundStarted)
|
if (bHasRoundStarted)
|
||||||
{
|
{
|
||||||
if (IsPlayerCommander(bot->Edict))
|
if (IsPlayerCommander(bot->Edict))
|
||||||
|
@ -835,7 +843,7 @@ int AIMGR_GetNumAIPlayersWithRoleOnTeam(AvHTeamNumber Team, AvHAIBotRole Role, A
|
||||||
{
|
{
|
||||||
if (&(*it) == IgnoreAIPlayer) { continue; }
|
if (&(*it) == IgnoreAIPlayer) { continue; }
|
||||||
|
|
||||||
if (it->Player->GetTeam() == Team)
|
if (it->Player->GetTeam() == Team && IsPlayerActiveInGame((*it).Edict))
|
||||||
{
|
{
|
||||||
if (it->BotRole == Role)
|
if (it->BotRole == Role)
|
||||||
{
|
{
|
||||||
|
@ -921,15 +929,20 @@ void AIMGR_ResetRound()
|
||||||
|
|
||||||
bool bTileCacheFullyUpdated = UTIL_UpdateTileCache();
|
bool bTileCacheFullyUpdated = UTIL_UpdateTileCache();
|
||||||
|
|
||||||
while (!bTileCacheFullyUpdated)
|
int NumAttempts = 0;
|
||||||
|
|
||||||
|
while (!bTileCacheFullyUpdated && NumAttempts < 30)
|
||||||
{
|
{
|
||||||
bTileCacheFullyUpdated = UTIL_UpdateTileCache();
|
bTileCacheFullyUpdated = UTIL_UpdateTileCache();
|
||||||
|
NumAttempts++;
|
||||||
}
|
}
|
||||||
|
|
||||||
bHasRoundStarted = false;
|
bHasRoundStarted = false;
|
||||||
bMapDataInitialised = true;
|
bMapDataInitialised = true;
|
||||||
|
|
||||||
CountdownStartedTime = 0.0f;
|
CountdownStartedTime = 0.0f;
|
||||||
|
|
||||||
|
AITAC_DetermineRelocationEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIMGR_ReloadNavigationData()
|
void AIMGR_ReloadNavigationData()
|
||||||
|
@ -1307,6 +1320,64 @@ void AIMGR_SetDebugAIPlayer(edict_t* SpectatingPlayer, edict_t* AIPlayer)
|
||||||
|
|
||||||
DebugBots[PlayerIndex] = nullptr;
|
DebugBots[PlayerIndex] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AIDEBUG_DisplayTeamGoals()
|
||||||
|
{
|
||||||
|
AvHTeamNumber TeamANumber = AIMGR_GetTeamANumber();
|
||||||
|
AvHTeamNumber TeamBNumber = AIMGR_GetTeamBNumber();
|
||||||
|
|
||||||
|
vector<AvHAIPlayer*> Team1Players = AIMGR_GetAIPlayersOnTeam(TeamANumber);
|
||||||
|
vector<AvHAIPlayer*> Team2Players = AIMGR_GetAIPlayersOnTeam(TeamBNumber);
|
||||||
|
|
||||||
|
char buf[511];
|
||||||
|
char interbuf[164];
|
||||||
|
|
||||||
|
sprintf(buf, "Team A (%s)\n\n", (AIMGR_GetTeamType(TeamANumber) == AVH_CLASS_TYPE_MARINE) ? "Marines" : "Aliens");
|
||||||
|
|
||||||
|
for (auto it = Team1Players.begin(); it != Team1Players.end(); it++)
|
||||||
|
{
|
||||||
|
AvHAIPlayer* ThisPlayer = (*it);
|
||||||
|
|
||||||
|
if (!ThisPlayer->CurrentTask || !IsPlayerActiveInGame(ThisPlayer->Edict)) { continue; }
|
||||||
|
|
||||||
|
if (!FNullEnt(ThisPlayer->CurrentTask->TaskTarget))
|
||||||
|
{
|
||||||
|
sprintf(interbuf, "%s: %s (%s)\n", STRING(ThisPlayer->Player->pev->netname), UTIL_TaskTypeToChar(ThisPlayer->CurrentTask->TaskType), UTIL_StructTypeToChar(UTIL_IUSER3ToStructureType(ThisPlayer->CurrentTask->TaskTarget->v.iuser3)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprintf(interbuf, "%s: %s\n", STRING(ThisPlayer->Player->pev->netname), UTIL_TaskTypeToChar(ThisPlayer->CurrentTask->TaskType));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
strcat(buf, interbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTIL_DrawHUDText(INDEXENT(1), 0, 0.1, 0.1f, 255, 255, 255, buf);
|
||||||
|
|
||||||
|
sprintf(buf, "Team B (%s)\n\n", (AIMGR_GetTeamType(TeamBNumber) == AVH_CLASS_TYPE_MARINE) ? "Marines" : "Aliens");
|
||||||
|
|
||||||
|
for (auto it = Team2Players.begin(); it != Team2Players.end(); it++)
|
||||||
|
{
|
||||||
|
AvHAIPlayer* ThisPlayer = (*it);
|
||||||
|
|
||||||
|
if (!ThisPlayer->CurrentTask || !IsPlayerActiveInGame(ThisPlayer->Edict)) { continue; }
|
||||||
|
|
||||||
|
if (!FNullEnt(ThisPlayer->CurrentTask->TaskTarget))
|
||||||
|
{
|
||||||
|
sprintf(interbuf, "%s: %s (%s)\n", STRING(ThisPlayer->Player->pev->netname), UTIL_TaskTypeToChar(ThisPlayer->CurrentTask->TaskType), UTIL_StructTypeToChar(UTIL_IUSER3ToStructureType(ThisPlayer->CurrentTask->TaskTarget->v.iuser3)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprintf(interbuf, "%s: %s\n", STRING(ThisPlayer->Player->pev->netname), UTIL_TaskTypeToChar(ThisPlayer->CurrentTask->TaskType));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
strcat(buf, interbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTIL_DrawHUDText(INDEXENT(1), 1, 0.6, 0.1f, 255, 255, 255, buf);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void AIMGR_ReceiveCommanderRequest(AvHTeamNumber Team, edict_t* Requestor, const char* Request)
|
void AIMGR_ReceiveCommanderRequest(AvHTeamNumber Team, edict_t* Requestor, const char* Request)
|
||||||
|
@ -1369,9 +1440,12 @@ void AIMGR_OnBotEnabled()
|
||||||
|
|
||||||
bool bTileCacheFullyUpdated = UTIL_UpdateTileCache();
|
bool bTileCacheFullyUpdated = UTIL_UpdateTileCache();
|
||||||
|
|
||||||
while (!bTileCacheFullyUpdated)
|
int NumAttempts = 0;
|
||||||
|
|
||||||
|
while (!bTileCacheFullyUpdated && NumAttempts < 30)
|
||||||
{
|
{
|
||||||
bTileCacheFullyUpdated = UTIL_UpdateTileCache();
|
bTileCacheFullyUpdated = UTIL_UpdateTileCache();
|
||||||
|
NumAttempts++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Figure out the current game status
|
// Figure out the current game status
|
||||||
|
@ -1591,3 +1665,8 @@ float AIMGR_GetFrameDelta()
|
||||||
{
|
{
|
||||||
return CurrentFrameDelta;
|
return CurrentFrameDelta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float AIMGR_GetMatchLength()
|
||||||
|
{
|
||||||
|
return (gpGlobals->time - GetGameRules()->GetTimeGameStarted());
|
||||||
|
}
|
|
@ -97,6 +97,8 @@ AvHClassType AIMGR_GetTeamType(const AvHTeamNumber Team);
|
||||||
AvHTeamNumber AIMGR_GetTeamANumber();
|
AvHTeamNumber AIMGR_GetTeamANumber();
|
||||||
AvHTeamNumber AIMGR_GetTeamBNumber();
|
AvHTeamNumber AIMGR_GetTeamBNumber();
|
||||||
|
|
||||||
|
float AIMGR_GetMatchLength();
|
||||||
|
|
||||||
AvHTeam* AIMGR_GetTeamRef(const AvHTeamNumber Team);
|
AvHTeam* AIMGR_GetTeamRef(const AvHTeamNumber Team);
|
||||||
|
|
||||||
// Returns all NS AI players. Does not include third-party bots
|
// Returns all NS AI players. Does not include third-party bots
|
||||||
|
@ -135,4 +137,6 @@ void AIMGR_ProcessPendingSounds();
|
||||||
void AIMGR_SetFrameDelta(float NewValue);
|
void AIMGR_SetFrameDelta(float NewValue);
|
||||||
float AIMGR_GetFrameDelta();
|
float AIMGR_GetFrameDelta();
|
||||||
|
|
||||||
|
void AIDEBUG_DisplayTeamGoals();
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -2,6 +2,7 @@
|
||||||
#include "AvHAIPlayerUtil.h"
|
#include "AvHAIPlayerUtil.h"
|
||||||
#include "AvHAIPlayer.h"
|
#include "AvHAIPlayer.h"
|
||||||
#include "AvHAIHelper.h"
|
#include "AvHAIHelper.h"
|
||||||
|
#include "AvHAIWeaponHelper.h"
|
||||||
|
|
||||||
#include "AvHPlayerUpgrade.h"
|
#include "AvHPlayerUpgrade.h"
|
||||||
#include "AvHAIMath.h"
|
#include "AvHAIMath.h"
|
||||||
|
@ -73,6 +74,7 @@ bool IsPlayerClimbingWall(const edict_t* Player)
|
||||||
|
|
||||||
bool IsPlayerInReadyRoom(const edict_t* Player)
|
bool IsPlayerInReadyRoom(const edict_t* Player)
|
||||||
{
|
{
|
||||||
|
if (FNullEnt(Player)) { return false; }
|
||||||
return Player->v.playerclass == PLAYMODE_READYROOM;
|
return Player->v.playerclass == PLAYMODE_READYROOM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +154,7 @@ bool IsPlayerOnLadder(const edict_t* Player)
|
||||||
Vector NearestPointOnLadder = UTIL_GetClosestPointOnEntityToLocation(Player->v.origin, NearestLadder);
|
Vector NearestPointOnLadder = UTIL_GetClosestPointOnEntityToLocation(Player->v.origin, NearestLadder);
|
||||||
Vector NearestPointOnPlayer = UTIL_GetClosestPointOnEntityToLocation(NearestPointOnLadder, Player);
|
Vector NearestPointOnPlayer = UTIL_GetClosestPointOnEntityToLocation(NearestPointOnLadder, Player);
|
||||||
|
|
||||||
return (vDist2DSq(NearestPointOnLadder, NearestPointOnPlayer) <= sqrf(4.0f));
|
return (vDist3DSq(NearestPointOnLadder, NearestPointOnPlayer) <= sqrf(2.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (Player->v.movetype == MOVETYPE_FLY);
|
return (Player->v.movetype == MOVETYPE_FLY);
|
||||||
|
@ -168,6 +170,11 @@ bool IsPlayerMotionTracked(const edict_t* Player)
|
||||||
return (Player->v.iuser4 & MASK_VIS_DETECTED);
|
return (Player->v.iuser4 & MASK_VIS_DETECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsPlayerSOF(const edict_t* Player)
|
||||||
|
{
|
||||||
|
return (Player->v.iuser4 & MASK_SENSORY_NEARBY);
|
||||||
|
}
|
||||||
|
|
||||||
float GetPlayerEnergy(const edict_t* Player)
|
float GetPlayerEnergy(const edict_t* Player)
|
||||||
{
|
{
|
||||||
return (Player->v.fuser3 * 0.001f);
|
return (Player->v.fuser3 * 0.001f);
|
||||||
|
@ -635,7 +642,10 @@ bool PlayerHasEquipment(edict_t* Player)
|
||||||
bool PlayerHasSpecialWeapon(const AvHPlayer* Player)
|
bool PlayerHasSpecialWeapon(const AvHPlayer* Player)
|
||||||
{
|
{
|
||||||
if (!IsPlayerMarine(Player)) { return false; }
|
if (!IsPlayerMarine(Player)) { return false; }
|
||||||
return !PlayerHasWeapon(Player, WEAPON_MARINE_MG);
|
|
||||||
|
AvHAIWeapon PrimaryWeaponType = UTIL_GetPlayerPrimaryWeapon(Player);
|
||||||
|
|
||||||
|
return PrimaryWeaponType != WEAPON_INVALID && PrimaryWeaponType != WEAPON_MARINE_MG;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UTIL_PlayerHasLOSToEntity(const edict_t* Player, const edict_t* Target, const float MaxRange, const bool bUseHullSweep)
|
bool UTIL_PlayerHasLOSToEntity(const edict_t* Player, const edict_t* Target, const float MaxRange, const bool bUseHullSweep)
|
||||||
|
@ -991,6 +1001,38 @@ Vector UTIL_GetNearestSurfaceNormal(Vector SearchLocation)
|
||||||
return ClosestNormal;
|
return ClosestNormal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UTIL_QuickCollisionTrace(Vector StartTrace, Vector EndTrace)
|
||||||
|
{
|
||||||
|
trace_t TraceResult;
|
||||||
|
NS_TraceLine(StartTrace, EndTrace, 0, PM_WORLD_ONLY, -1, true, TraceResult);
|
||||||
|
return TraceResult.fraction >= 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector UTIL_GetLadderNormal(Vector SearchLocation, edict_t* Ladder)
|
||||||
|
{
|
||||||
|
if (FNullEnt(Ladder)) { return ZERO_VECTOR; }
|
||||||
|
|
||||||
|
if (vPointOverlaps3D(SearchLocation, Ladder->v.absmin, Ladder->v.absmax))
|
||||||
|
{
|
||||||
|
return UTIL_GetNearestSurfaceNormal(SearchLocation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vector CentrePoint = Ladder->v.absmin + (Ladder->v.size * 0.5f);
|
||||||
|
CentrePoint.z = SearchLocation.z;
|
||||||
|
|
||||||
|
trace_t TraceResult;
|
||||||
|
NS_TraceLine(SearchLocation, CentrePoint, 1, PM_WORLD_ONLY, -1, true, TraceResult);
|
||||||
|
|
||||||
|
if (TraceResult.fraction < 1.0f)
|
||||||
|
{
|
||||||
|
return TraceResult.plane.normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ZERO_VECTOR;
|
||||||
|
}
|
||||||
|
|
||||||
Vector UTIL_GetNearestLadderNormal(Vector SearchLocation)
|
Vector UTIL_GetNearestLadderNormal(Vector SearchLocation)
|
||||||
{
|
{
|
||||||
TraceResult result;
|
TraceResult result;
|
||||||
|
|
|
@ -67,6 +67,8 @@ bool IsPlayerGestating(const edict_t* Player);
|
||||||
bool IsPlayerParasited(const edict_t* Player);
|
bool IsPlayerParasited(const edict_t* Player);
|
||||||
// Is the player being marked through walls to enemies through being sighted by an ally or affected by motion tracking?
|
// Is the player being marked through walls to enemies through being sighted by an ally or affected by motion tracking?
|
||||||
bool IsPlayerMotionTracked(const edict_t* Player);
|
bool IsPlayerMotionTracked(const edict_t* Player);
|
||||||
|
// Is the player being marked through walls by a nearby sensory chamber or scent of fear?
|
||||||
|
bool IsPlayerSOF(const edict_t* Player);
|
||||||
// Is the player currently on a ladder? Always false for Skulks and Lerks as they can't climb ladders
|
// Is the player currently on a ladder? Always false for Skulks and Lerks as they can't climb ladders
|
||||||
bool IsPlayerOnLadder(const edict_t* Player);
|
bool IsPlayerOnLadder(const edict_t* Player);
|
||||||
// Is the player an onos under the effect of charge?
|
// Is the player an onos under the effect of charge?
|
||||||
|
@ -172,6 +174,10 @@ Vector UTIL_GetNearestLadderTopPoint(edict_t* pEdict);
|
||||||
Vector UTIL_GetNearestLadderTopPoint(const Vector SearchLocation);
|
Vector UTIL_GetNearestLadderTopPoint(const Vector SearchLocation);
|
||||||
Vector UTIL_GetNearestLadderBottomPoint(edict_t* pEdict);
|
Vector UTIL_GetNearestLadderBottomPoint(edict_t* pEdict);
|
||||||
|
|
||||||
|
Vector UTIL_GetLadderNormal(Vector SearchLocation, edict_t* Ladder);
|
||||||
|
|
||||||
|
bool UTIL_QuickCollisionTrace(Vector StartTrace, Vector EndTrace);
|
||||||
|
|
||||||
Vector UTIL_GetNearestSurfaceNormal(Vector SearchLocation);
|
Vector UTIL_GetNearestSurfaceNormal(Vector SearchLocation);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -18,6 +18,7 @@
|
||||||
#include "AvHAIConstants.h"
|
#include "AvHAIConstants.h"
|
||||||
#include "AvHAIPlayerManager.h"
|
#include "AvHAIPlayerManager.h"
|
||||||
#include "AvHAIConfig.h"
|
#include "AvHAIConfig.h"
|
||||||
|
#include "AvHAICommander.h"
|
||||||
|
|
||||||
#include "AvHGamerules.h"
|
#include "AvHGamerules.h"
|
||||||
#include "AvHServerUtil.h"
|
#include "AvHServerUtil.h"
|
||||||
|
@ -54,6 +55,11 @@ unsigned int ItemRefreshFrame = 0;
|
||||||
Vector TeamAStartingLocation = ZERO_VECTOR;
|
Vector TeamAStartingLocation = ZERO_VECTOR;
|
||||||
Vector TeamBStartingLocation = ZERO_VECTOR;
|
Vector TeamBStartingLocation = ZERO_VECTOR;
|
||||||
|
|
||||||
|
Vector TeamARelocationPoint = ZERO_VECTOR;
|
||||||
|
Vector TeamBRelocationPoint = ZERO_VECTOR;
|
||||||
|
|
||||||
|
bool bEnableRelocationAtStart = false; // For this round, should the AI commander try relocating at the start of the match?
|
||||||
|
|
||||||
extern nav_mesh NavMeshes[MAX_NAV_MESHES]; // Array of nav meshes. Currently only 3 are used (building, onos, and regular)
|
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
|
extern nav_profile BaseNavProfiles[MAX_NAV_PROFILES]; // Array of nav profiles
|
||||||
|
|
||||||
|
@ -68,6 +74,9 @@ float LastSeenLerkTeamBTime = 0.0f;
|
||||||
|
|
||||||
vector<AvHAISquad> ActiveSquads;
|
vector<AvHAISquad> ActiveSquads;
|
||||||
|
|
||||||
|
vector<AvHAIMarineBase> ActiveTeamABases; // If Team A are marines, any active bases they have established around the map
|
||||||
|
vector<AvHAIMarineBase> ActiveTeamBBases; // If Team B are marines, any active bases they have established around the map
|
||||||
|
|
||||||
std::vector<AvHAIBuildableStructure> AITAC_FindAllDeployables(const Vector& Location, const DeployableSearchFilter* Filter)
|
std::vector<AvHAIBuildableStructure> AITAC_FindAllDeployables(const Vector& Location, const DeployableSearchFilter* Filter)
|
||||||
{
|
{
|
||||||
std::vector<AvHAIBuildableStructure> Result;
|
std::vector<AvHAIBuildableStructure> Result;
|
||||||
|
@ -624,20 +633,24 @@ AvHAIBuildableStructure* AITAC_FindFurthestDeployableFromLocationByRef(const Vec
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
AvHAIDroppedItem* AITAC_GetDroppedItemRefFromEdict(edict_t* ItemEdict)
|
AvHAIDroppedItem AITAC_GetDroppedItemRefFromEdict(edict_t* ItemEdict)
|
||||||
{
|
{
|
||||||
if (FNullEnt(ItemEdict)) { return nullptr; }
|
AvHAIDroppedItem Result;
|
||||||
|
|
||||||
|
if (FNullEnt(ItemEdict)) { return Result; }
|
||||||
|
|
||||||
int EntIndex = ENTINDEX(ItemEdict);
|
int EntIndex = ENTINDEX(ItemEdict);
|
||||||
|
|
||||||
if (EntIndex < 0) { return nullptr; }
|
if (EntIndex < 0) { return Result; }
|
||||||
|
|
||||||
return &MarineDroppedItemMap[EntIndex];
|
Result = MarineDroppedItemMap[EntIndex];
|
||||||
|
|
||||||
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
AvHAIDroppedItem* AITAC_FindClosestItemToLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance)
|
AvHAIDroppedItem AITAC_FindClosestItemToLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance)
|
||||||
{
|
{
|
||||||
AvHAIDroppedItem* Result = NULL;
|
AvHAIDroppedItem Result;
|
||||||
float CurrMinDist = 0.0f;
|
float CurrMinDist = 0.0f;
|
||||||
|
|
||||||
float MinDistSq = sqrf(MinRadius);
|
float MinDistSq = sqrf(MinRadius);
|
||||||
|
@ -663,9 +676,9 @@ AvHAIDroppedItem* AITAC_FindClosestItemToLocation(const Vector& Location, const
|
||||||
|
|
||||||
float DistSq = (bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
|
float DistSq = (bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
|
||||||
|
|
||||||
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && (!Result || DistSq < CurrMinDist))
|
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && (!Result.IsValid() || DistSq < CurrMinDist))
|
||||||
{
|
{
|
||||||
Result = &it.second;
|
Result = it.second;
|
||||||
CurrMinDist = DistSq;
|
CurrMinDist = DistSq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -866,6 +879,16 @@ AvHAIBuildableStructure AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer*
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AvHAIBuildableStructure AITAC_GetDeployableStructureByEntIndex(AvHTeamNumber Team, int EntIndex)
|
||||||
|
{
|
||||||
|
return (Team == AIMGR_GetTeamANumber()) ? TeamAStructureMap[EntIndex] : TeamBStructureMap[EntIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
AvHAIBuildableStructure* AITAC_GetDeployableStructureRefByEntIndex(AvHTeamNumber Team, int EntIndex)
|
||||||
|
{
|
||||||
|
return (Team == AIMGR_GetTeamANumber()) ? &TeamAStructureMap[EntIndex] : &TeamBStructureMap[EntIndex];
|
||||||
|
}
|
||||||
|
|
||||||
AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachableByRef(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter)
|
AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachableByRef(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter)
|
||||||
{
|
{
|
||||||
AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber();
|
AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber();
|
||||||
|
@ -1067,6 +1090,20 @@ Vector AITAC_GetFloorLocationForHive(const AvHAIHiveDefinition* Hive)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string AITAC_GetLocationName(Vector Location)
|
||||||
|
{
|
||||||
|
string Result;
|
||||||
|
|
||||||
|
string theLocationName;
|
||||||
|
if (AvHSHUGetNameOfLocation(GetGameRules()->GetInfoLocations(), Location, theLocationName))
|
||||||
|
{
|
||||||
|
UTIL_LocalizeText(theLocationName.c_str(), theLocationName);
|
||||||
|
Result = theLocationName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
void AITAC_PopulateHiveData()
|
void AITAC_PopulateHiveData()
|
||||||
{
|
{
|
||||||
Hives.clear();
|
Hives.clear();
|
||||||
|
@ -1091,17 +1128,16 @@ void AITAC_PopulateHiveData()
|
||||||
|
|
||||||
NewHive.FloorLocation = UTIL_GetFloorUnderEntity(NewHive.HiveEdict); // 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 HiveName = AITAC_GetLocationName(NewHive.Location);
|
||||||
|
|
||||||
string theLocationName;
|
if (HiveName.empty())
|
||||||
if (AvHSHUGetNameOfLocation(GetGameRules()->GetInfoLocations(), NewHive.Location, theLocationName))
|
|
||||||
{
|
{
|
||||||
UTIL_LocalizeText(theLocationName.c_str(), theLocationName);
|
sprintf(NewHive.HiveName, "Hive");
|
||||||
HiveName = theLocationName;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
sprintf(NewHive.HiveName, HiveName.c_str(), "%s");
|
sprintf(NewHive.HiveName, HiveName.c_str(), "%s");
|
||||||
|
}
|
||||||
|
|
||||||
Hives.push_back(NewHive);
|
Hives.push_back(NewHive);
|
||||||
|
|
||||||
|
@ -1110,6 +1146,11 @@ void AITAC_PopulateHiveData()
|
||||||
|
|
||||||
void AITAC_RefreshHiveData()
|
void AITAC_RefreshHiveData()
|
||||||
{
|
{
|
||||||
|
if (ResourceNodes.size() == 0)
|
||||||
|
{
|
||||||
|
AITAC_PopulateResourceNodes();
|
||||||
|
}
|
||||||
|
|
||||||
if (Hives.size() == 0)
|
if (Hives.size() == 0)
|
||||||
{
|
{
|
||||||
AITAC_PopulateHiveData();
|
AITAC_PopulateHiveData();
|
||||||
|
@ -1184,6 +1225,36 @@ void AITAC_RefreshHiveData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector AITAC_GetTeamRelocationPoint(AvHTeamNumber Team)
|
||||||
|
{
|
||||||
|
Vector CurrentRelocationPoint = (Team == GetGameRules()->GetTeamANumber()) ? TeamARelocationPoint : TeamBRelocationPoint;
|
||||||
|
|
||||||
|
if (!AITAC_IsRelocationPointStillValid(Team, CurrentRelocationPoint))
|
||||||
|
{
|
||||||
|
CurrentRelocationPoint = AITAC_FindNewTeamRelocationPoint(Team);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Team == GetGameRules()->GetTeamANumber())
|
||||||
|
{
|
||||||
|
TeamARelocationPoint = CurrentRelocationPoint;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TeamBRelocationPoint = CurrentRelocationPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Team == GetGameRules()->GetTeamANumber()) ? TeamARelocationPoint : TeamBRelocationPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector AITAC_GetTeamOriginalStartLocation(AvHTeamNumber Team)
|
||||||
|
{
|
||||||
|
AvHTeam* TeamRef = AIMGR_GetTeamRef(Team);
|
||||||
|
|
||||||
|
if (!TeamRef) { return ZERO_VECTOR; }
|
||||||
|
|
||||||
|
return TeamRef->GetStartingLocation();
|
||||||
|
}
|
||||||
|
|
||||||
Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team)
|
Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team)
|
||||||
{
|
{
|
||||||
if (vIsZero(TeamAStartingLocation) || vIsZero(TeamBStartingLocation))
|
if (vIsZero(TeamAStartingLocation) || vIsZero(TeamBStartingLocation))
|
||||||
|
@ -2421,6 +2492,7 @@ AvHAIBuildableStructure* AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
|
||||||
if (StructureRef->LastSeen == 0)
|
if (StructureRef->LastSeen == 0)
|
||||||
{
|
{
|
||||||
StructureRef->Location = BuildingEdict->v.origin;
|
StructureRef->Location = BuildingEdict->v.origin;
|
||||||
|
StructureRef->EntIndex = EntIndex;
|
||||||
StructureRef->edict = BuildingEdict;
|
StructureRef->edict = BuildingEdict;
|
||||||
StructureRef->healthPercent = 1.0f;
|
StructureRef->healthPercent = 1.0f;
|
||||||
StructureRef->EntityRef = nullptr;
|
StructureRef->EntityRef = nullptr;
|
||||||
|
@ -2449,6 +2521,7 @@ AvHAIBuildableStructure* AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
|
||||||
{
|
{
|
||||||
StructureRef->EntityRef = BaseBuildable;
|
StructureRef->EntityRef = BaseBuildable;
|
||||||
StructureRef->edict = BuildingEdict;
|
StructureRef->edict = BuildingEdict;
|
||||||
|
StructureRef->EntIndex = EntIndex;
|
||||||
|
|
||||||
StructureRef->OffMeshConnections.clear();
|
StructureRef->OffMeshConnections.clear();
|
||||||
StructureRef->Obstacles.clear();
|
StructureRef->Obstacles.clear();
|
||||||
|
@ -2585,7 +2658,7 @@ AvHAIBuildableStructure* AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
|
||||||
|
|
||||||
if (NearestHive)
|
if (NearestHive)
|
||||||
{
|
{
|
||||||
if (NearestHive->Status == HIVE_STATUS_UNBUILT && vDist2DSq(NearestHive->FloorLocation, StructureRef->Location) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
|
if (NearestHive->Status == HIVE_STATUS_UNBUILT && vDist2DSq(NearestHive->FloorLocation, StructureRef->Location) < sqrf(UTIL_MetresToGoldSrcUnits(15.0f)))
|
||||||
{
|
{
|
||||||
StructureRef->Purpose = STRUCTURE_PURPOSE_FORTIFY;
|
StructureRef->Purpose = STRUCTURE_PURPOSE_FORTIFY;
|
||||||
}
|
}
|
||||||
|
@ -2865,9 +2938,12 @@ void AITAC_ClearMapAIData(bool bInitialMapLoad)
|
||||||
|
|
||||||
AITAC_ClearStructureNavData();
|
AITAC_ClearStructureNavData();
|
||||||
|
|
||||||
while (!bTileCacheUpToDate)
|
int NumAttempts = 0;
|
||||||
|
|
||||||
|
while (!bTileCacheUpToDate && NumAttempts < 30)
|
||||||
{
|
{
|
||||||
UTIL_UpdateTileCache();
|
UTIL_UpdateTileCache();
|
||||||
|
NumAttempts++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -3086,7 +3162,6 @@ bool UTIL_ShouldStructureCollide(AvHAIDeployableStructureType StructureType)
|
||||||
{
|
{
|
||||||
case STRUCTURE_MARINE_INFANTRYPORTAL:
|
case STRUCTURE_MARINE_INFANTRYPORTAL:
|
||||||
case STRUCTURE_MARINE_PHASEGATE:
|
case STRUCTURE_MARINE_PHASEGATE:
|
||||||
case STRUCTURE_MARINE_TURRET:
|
|
||||||
case STRUCTURE_MARINE_DEPLOYEDMINE:
|
case STRUCTURE_MARINE_DEPLOYEDMINE:
|
||||||
return false;
|
return false;
|
||||||
default:
|
default:
|
||||||
|
@ -4379,7 +4454,6 @@ edict_t* AITAC_GetCommChair(AvHTeamNumber Team)
|
||||||
ChairFilter.DeployableTypes = STRUCTURE_MARINE_COMMCHAIR;
|
ChairFilter.DeployableTypes = STRUCTURE_MARINE_COMMCHAIR;
|
||||||
ChairFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
ChairFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||||
ChairFilter.DeployableTeam = Team;
|
ChairFilter.DeployableTeam = Team;
|
||||||
ChairFilter.ReachabilityTeam = TEAM_IND;
|
|
||||||
|
|
||||||
vector<AvHAIBuildableStructure> CommChairs = AITAC_FindAllDeployables(ZERO_VECTOR, &ChairFilter);
|
vector<AvHAIBuildableStructure> CommChairs = AITAC_FindAllDeployables(ZERO_VECTOR, &ChairFilter);
|
||||||
|
|
||||||
|
@ -4391,8 +4465,10 @@ edict_t* AITAC_GetCommChair(AvHTeamNumber Team)
|
||||||
{
|
{
|
||||||
AvHCommandStation* ChairRef = dynamic_cast<AvHCommandStation*>((*it).EntityRef);
|
AvHCommandStation* ChairRef = dynamic_cast<AvHCommandStation*>((*it).EntityRef);
|
||||||
|
|
||||||
|
if (!ChairRef) { continue; }
|
||||||
|
|
||||||
// Idle animation will be 3 if the chair is in use (closed animation). See AvHCommandStation::GetIdleAnimation
|
// Idle animation will be 3 if the chair is in use (closed animation). See AvHCommandStation::GetIdleAnimation
|
||||||
if (ChairRef && ChairRef->GetIdleAnimation() == 3)
|
if (ChairRef->GetIdleAnimation() == 3)
|
||||||
{
|
{
|
||||||
MainCommChair = ChairRef->edict();
|
MainCommChair = ChairRef->edict();
|
||||||
}
|
}
|
||||||
|
@ -4759,11 +4835,16 @@ bool AITAC_ShouldBotBuildHive(AvHAIPlayer* pBot, AvHAIHiveDefinition** EligibleH
|
||||||
HiveCost += BALANCE_VAR(kGorgeCost);
|
HiveCost += BALANCE_VAR(kGorgeCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pBot->Player->GetResources() < HiveCost) { return false; }
|
if (pBot->Player->GetResources() < HiveCost - 10) { return false; }
|
||||||
|
|
||||||
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||||
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
|
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
|
||||||
|
|
||||||
|
AvHAIPlayer* ExistingBuilder = GetFirstBotWithBuildTask(BotTeam, STRUCTURE_ALIEN_HIVE, pBot->Edict);
|
||||||
|
|
||||||
|
// Another bot already plans to do it
|
||||||
|
if (ExistingBuilder && IsPlayerActiveInGame(ExistingBuilder->Edict)) { return false; }
|
||||||
|
|
||||||
// Prioritise getting at least one fade or Onos on the team before putting up a second hive, or we're likely to lose it pretty quickly
|
// Prioritise getting at least one fade or Onos on the team before putting up a second hive, or we're likely to lose it pretty quickly
|
||||||
int NumHeavyHitters = AITAC_GetNumPlayersOnTeamOfClass(BotTeam, AVH_USER3_ALIEN_PLAYER4, nullptr) + AITAC_GetNumPlayersOnTeamOfClass(BotTeam, AVH_USER3_ALIEN_PLAYER5, nullptr);
|
int NumHeavyHitters = AITAC_GetNumPlayersOnTeamOfClass(BotTeam, AVH_USER3_ALIEN_PLAYER4, nullptr) + AITAC_GetNumPlayersOnTeamOfClass(BotTeam, AVH_USER3_ALIEN_PLAYER5, nullptr);
|
||||||
|
|
||||||
|
@ -4779,6 +4860,8 @@ bool AITAC_ShouldBotBuildHive(AvHAIPlayer* pBot, AvHAIHiveDefinition** EligibleH
|
||||||
{
|
{
|
||||||
AvHAIPlayer* OtherBot = (*it);
|
AvHAIPlayer* OtherBot = (*it);
|
||||||
|
|
||||||
|
if (OtherBot == pBot) { continue; }
|
||||||
|
|
||||||
// If the other bot has enough resources to drop a hive, and they're a less expensive life form than us, let them do it.
|
// If the other bot has enough resources to drop a hive, and they're a less expensive life form than us, let them do it.
|
||||||
if (OtherBot->Player->GetResources() >= BALANCE_VAR(kHiveCost) * 0.8f && OtherBot->Player->GetUser3() < pBot->Player->GetUser3()) { return false; }
|
if (OtherBot->Player->GetResources() >= BALANCE_VAR(kHiveCost) * 0.8f && OtherBot->Player->GetUser3() < pBot->Player->GetUser3()) { return false; }
|
||||||
}
|
}
|
||||||
|
@ -5313,6 +5396,8 @@ edict_t* AITAC_AlienFindNearestHealingSource(AvHTeamNumber Team, Vector SearchLo
|
||||||
edict_t* Result = nullptr;
|
edict_t* Result = nullptr;
|
||||||
float MinDist = 0.0f;
|
float MinDist = 0.0f;
|
||||||
|
|
||||||
|
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(Team);
|
||||||
|
|
||||||
vector<AvHAIHiveDefinition*> AllTeamHives = AITAC_GetAllTeamHives(Team, true);
|
vector<AvHAIHiveDefinition*> AllTeamHives = AITAC_GetAllTeamHives(Team, true);
|
||||||
|
|
||||||
for (auto it = AllTeamHives.begin(); it != AllTeamHives.end(); it++)
|
for (auto it = AllTeamHives.begin(); it != AllTeamHives.end(); it++)
|
||||||
|
@ -5321,6 +5406,8 @@ edict_t* AITAC_AlienFindNearestHealingSource(AvHTeamNumber Team, Vector SearchLo
|
||||||
// Factor healing radius into the distance checks, we don't have to be right at the hive to heal
|
// Factor healing radius into the distance checks, we don't have to be right at the hive to heal
|
||||||
ThisDist -= BALANCE_VAR(kHiveHealRadius) * 0.75f;
|
ThisDist -= BALANCE_VAR(kHiveHealRadius) * 0.75f;
|
||||||
|
|
||||||
|
if (AITAC_AnyPlayerOnTeamHasLOSToLocation(EnemyTeam, (*it)->Location, UTIL_MetresToGoldSrcUnits(30.0f), nullptr)) { continue; }
|
||||||
|
|
||||||
// We're already in healing distance of a hive, that's our healing source
|
// We're already in healing distance of a hive, that's our healing source
|
||||||
if (ThisDist <= 0.0f) { return (*it)->HiveEdict; }
|
if (ThisDist <= 0.0f) { return (*it)->HiveEdict; }
|
||||||
|
|
||||||
|
@ -5346,6 +5433,8 @@ edict_t* AITAC_AlienFindNearestHealingSource(AvHTeamNumber Team, Vector SearchLo
|
||||||
// Factor healing radius into the distance checks, we don't have to be sat on top of the DC to heal
|
// Factor healing radius into the distance checks, we don't have to be sat on top of the DC to heal
|
||||||
ThisDist -= BALANCE_VAR(kHiveHealRadius) * 0.75f;
|
ThisDist -= BALANCE_VAR(kHiveHealRadius) * 0.75f;
|
||||||
|
|
||||||
|
if (AITAC_AnyPlayerOnTeamHasLOSToLocation(EnemyTeam, ThisDC.Location, UTIL_MetresToGoldSrcUnits(30.0f), nullptr)) { continue; }
|
||||||
|
|
||||||
// We're already in healing distance of a DC, that's our healing source
|
// We're already in healing distance of a DC, that's our healing source
|
||||||
if (ThisDist <= 0.0f) { return ThisDC.edict; }
|
if (ThisDist <= 0.0f) { return ThisDC.edict; }
|
||||||
|
|
||||||
|
@ -5362,6 +5451,11 @@ edict_t* AITAC_AlienFindNearestHealingSource(AvHTeamNumber Team, Vector SearchLo
|
||||||
{
|
{
|
||||||
float PlayerSearchDist = (!FNullEnt(Result)) ? MinDist : 0.0f; // As before, we only want players closer than our current "winner"
|
float PlayerSearchDist = (!FNullEnt(Result)) ? MinDist : 0.0f; // As before, we only want players closer than our current "winner"
|
||||||
FriendlyGorge = AITAC_GetNearestPlayerOfClassInArea(Team, SearchLocation, PlayerSearchDist, false, SearchingPlayer, AVH_USER3_ALIEN_PLAYER2);
|
FriendlyGorge = AITAC_GetNearestPlayerOfClassInArea(Team, SearchLocation, PlayerSearchDist, false, SearchingPlayer, AVH_USER3_ALIEN_PLAYER2);
|
||||||
|
|
||||||
|
if (!FNullEnt(FriendlyGorge))
|
||||||
|
{
|
||||||
|
if (AITAC_AnyPlayerOnTeamHasLOSToLocation(EnemyTeam, FriendlyGorge->v.origin, UTIL_MetresToGoldSrcUnits(30.0f), nullptr)) { FriendlyGorge = nullptr; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (!FNullEnt(FriendlyGorge) ? FriendlyGorge : Result);
|
return (!FNullEnt(FriendlyGorge) ? FriendlyGorge : Result);
|
||||||
|
@ -5507,15 +5601,16 @@ bool AITAC_IsBotPursuingSquadObjective(AvHAIPlayer* pBot, AvHAISquad* Squad)
|
||||||
if (!IsPlayerActiveInGame(pBot->Edict) || pBot->Player->GetTeam() != Squad->SquadTeam) { return false; }
|
if (!IsPlayerActiveInGame(pBot->Edict) || pBot->Player->GetTeam() != Squad->SquadTeam) { return false; }
|
||||||
|
|
||||||
// Bot no longer has this squad's objective as its primary task
|
// Bot no longer has this squad's objective as its primary task
|
||||||
if (pBot->PrimaryBotTask.TaskType != Squad->SquadObjective || pBot->PrimaryBotTask.TaskTarget != Squad->SquadTarget) { return false; }
|
if (pBot->PrimaryBotTask.TaskType != Squad->SquadObjective || (!FNullEnt(Squad->SquadTarget) && pBot->PrimaryBotTask.TaskTarget != Squad->SquadTarget) || (FNullEnt(Squad->SquadTarget) && !vEquals(pBot->PrimaryBotTask.TaskLocation, Squad->ObjectiveLocation))) { return false; }
|
||||||
|
|
||||||
// Bot is focused on the job at hand
|
// Bot is focused on the job at hand
|
||||||
if (!pBot->CurrentTask || pBot->CurrentTask == &pBot->PrimaryBotTask) { return true; }
|
if (!pBot->CurrentTask || pBot->CurrentTask == &pBot->PrimaryBotTask) { return true; }
|
||||||
|
|
||||||
// Bot isn't currently pursuing squad objective, so check if it's doing something in the vicinity
|
// Bot isn't currently pursuing squad objective, so check if it's doing something in the vicinity
|
||||||
Vector TaskLocation = (!FNullEnt(pBot->CurrentTask->TaskTarget)) ? pBot->CurrentTask->TaskTarget->v.origin : pBot->CurrentTask->TaskLocation;
|
Vector BotTaskLocation = (!FNullEnt(pBot->CurrentTask->TaskTarget)) ? pBot->CurrentTask->TaskTarget->v.origin : pBot->CurrentTask->TaskLocation;
|
||||||
|
Vector SquadTaskLocation = (!FNullEnt(Squad->SquadTarget)) ? Squad->SquadTarget->v.origin : Squad->ObjectiveLocation;
|
||||||
|
|
||||||
return vDist2DSq(TaskLocation, Squad->SquadTarget->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f));
|
return vDist2DSq(BotTaskLocation, SquadTaskLocation) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AITAC_ManageSquads()
|
void AITAC_ManageSquads()
|
||||||
|
@ -5525,7 +5620,7 @@ void AITAC_ManageSquads()
|
||||||
for (auto pIt = it->SquadMembers.begin(); pIt != it->SquadMembers.end();)
|
for (auto pIt = it->SquadMembers.begin(); pIt != it->SquadMembers.end();)
|
||||||
{
|
{
|
||||||
AvHAIPlayer* ThisPlayer = (*pIt);
|
AvHAIPlayer* ThisPlayer = (*pIt);
|
||||||
if (!AITAC_IsBotPursuingSquadObjective(ThisPlayer, &(*it)))
|
if (!ThisPlayer || FNullEnt(ThisPlayer->Edict) || !AITAC_IsBotPursuingSquadObjective(ThisPlayer, &(*it)))
|
||||||
{
|
{
|
||||||
pIt = it->SquadMembers.erase(pIt);
|
pIt = it->SquadMembers.erase(pIt);
|
||||||
}
|
}
|
||||||
|
@ -5558,7 +5653,9 @@ void AITAC_UpdateSquads()
|
||||||
{
|
{
|
||||||
vector<bot_path_node> TravelPath;
|
vector<bot_path_node> TravelPath;
|
||||||
|
|
||||||
dtStatus PathFindResult = FindPathClosestToPoint(GetBaseNavProfile(ONOS_BASE_NAV_PROFILE), AITAC_GetTeamStartingLocation(it->SquadTeam), UTIL_GetEntityGroundLocation(it->SquadTarget), TravelPath, UTIL_MetresToGoldSrcUnits(20.0f));
|
Vector TargetLocation = (!FNullEnt(it->SquadTarget)) ? UTIL_GetEntityGroundLocation(it->SquadTarget) : it->ObjectiveLocation;
|
||||||
|
|
||||||
|
dtStatus PathFindResult = FindPathClosestToPoint(GetBaseNavProfile(ONOS_BASE_NAV_PROFILE), AITAC_GetTeamStartingLocation(it->SquadTeam), TargetLocation, TravelPath, UTIL_MetresToGoldSrcUnits(20.0f));
|
||||||
|
|
||||||
if (dtStatusSucceed(PathFindResult))
|
if (dtStatusSucceed(PathFindResult))
|
||||||
{
|
{
|
||||||
|
@ -5566,9 +5663,12 @@ void AITAC_UpdateSquads()
|
||||||
{
|
{
|
||||||
if (pIt->area != SAMPLE_POLYAREA_GROUND || pIt->flag != SAMPLE_POLYFLAGS_WALK) { continue; }
|
if (pIt->area != SAMPLE_POLYAREA_GROUND || pIt->flag != SAMPLE_POLYFLAGS_WALK) { continue; }
|
||||||
|
|
||||||
|
if (!FNullEnt(it->SquadTarget))
|
||||||
|
{
|
||||||
if (UTIL_QuickTrace(nullptr, pIt->Location, it->SquadTarget->v.origin)) { continue; }
|
if (UTIL_QuickTrace(nullptr, pIt->Location, it->SquadTarget->v.origin)) { continue; }
|
||||||
|
}
|
||||||
|
|
||||||
if (vDist2DSq(pIt->Location, it->SquadTarget->v.origin) > sqrf(UTIL_MetresToGoldSrcUnits(20.0f)))
|
if (vDist2DSq(pIt->Location, TargetLocation) > sqrf(UTIL_MetresToGoldSrcUnits(20.0f)))
|
||||||
{
|
{
|
||||||
DeployableSearchFilter EnemyStuff;
|
DeployableSearchFilter EnemyStuff;
|
||||||
EnemyStuff.DeployableTeam = AIMGR_GetEnemyTeam(it->SquadTeam);
|
EnemyStuff.DeployableTeam = AIMGR_GetEnemyTeam(it->SquadTeam);
|
||||||
|
@ -5656,6 +5756,48 @@ AvHAISquad* AITAC_GetSquadForObjective(AvHAIPlayer* pBot, edict_t* TaskTarget, B
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AvHAISquad* AITAC_GetSquadForObjective(AvHAIPlayer* pBot, Vector TaskLocation, BotTaskType ObjectiveType)
|
||||||
|
{
|
||||||
|
AvHAISquad* JoinSquad = nullptr;
|
||||||
|
|
||||||
|
for (auto it = ActiveSquads.begin(); it != ActiveSquads.end(); it++)
|
||||||
|
{
|
||||||
|
if (it->SquadTeam == pBot->Player->GetTeam() && vEquals(it->ObjectiveLocation, TaskLocation) && it->SquadObjective == ObjectiveType)
|
||||||
|
{
|
||||||
|
auto element = std::find(it->SquadMembers.begin(), it->SquadMembers.end(), pBot);
|
||||||
|
|
||||||
|
if (element != it->SquadMembers.end())
|
||||||
|
{
|
||||||
|
return &(*it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!JoinSquad && !it->bExecuteObjective)
|
||||||
|
{
|
||||||
|
JoinSquad = &(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JoinSquad)
|
||||||
|
{
|
||||||
|
JoinSquad->SquadMembers.push_back(pBot);
|
||||||
|
return JoinSquad;
|
||||||
|
}
|
||||||
|
|
||||||
|
AvHAISquad NewSquad;
|
||||||
|
NewSquad.SquadTeam = pBot->Player->GetTeam();
|
||||||
|
NewSquad.ObjectiveLocation = TaskLocation;
|
||||||
|
NewSquad.SquadObjective = ObjectiveType;
|
||||||
|
NewSquad.bExecuteObjective = false;
|
||||||
|
NewSquad.SquadGatherLocation = ZERO_VECTOR;
|
||||||
|
|
||||||
|
ActiveSquads.push_back(NewSquad);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void AITAC_ClearSquads()
|
void AITAC_ClearSquads()
|
||||||
{
|
{
|
||||||
ActiveSquads.clear();
|
ActiveSquads.clear();
|
||||||
|
@ -5696,3 +5838,467 @@ Vector AITAC_GetGatherLocationForSquad(AvHAISquad* Squad)
|
||||||
|
|
||||||
return ZERO_VECTOR;
|
return ZERO_VECTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector AITAC_FindNewTeamRelocationPoint(AvHTeamNumber Team)
|
||||||
|
{
|
||||||
|
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(Team);
|
||||||
|
|
||||||
|
// Only relocate if:
|
||||||
|
// There is a hive to relocate to with a marine ready to build
|
||||||
|
// The current base is overrun and lost
|
||||||
|
// Or we decide we want to, and the current base isn't too built up
|
||||||
|
|
||||||
|
Vector CurrentTeamStartLocation = AITAC_GetTeamStartingLocation(Team);
|
||||||
|
|
||||||
|
const AvHAIHiveDefinition* RelocationHive = nullptr;
|
||||||
|
float MinDist = 0.0f;
|
||||||
|
|
||||||
|
vector<AvHAIHiveDefinition*> AllHives = AITAC_GetAllHives();
|
||||||
|
|
||||||
|
for (auto it = AllHives.begin(); it != AllHives.end(); it++)
|
||||||
|
{
|
||||||
|
const AvHAIHiveDefinition* ThisHive = (*it);
|
||||||
|
|
||||||
|
// Obviously don't relocate to an active enemy hive...
|
||||||
|
if (ThisHive->Status != HIVE_STATUS_UNBUILT) { continue; }
|
||||||
|
|
||||||
|
// Don't relocate if we're already located close to this hive
|
||||||
|
if (vDist2DSq(CurrentTeamStartLocation, ThisHive->FloorLocation) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f))) { continue; }
|
||||||
|
|
||||||
|
// Don't relocate if the enemy has a foothold here
|
||||||
|
DeployableSearchFilter EnemyStuff;
|
||||||
|
EnemyStuff.DeployableTeam = EnemyTeam;
|
||||||
|
EnemyStuff.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||||
|
EnemyStuff.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||||
|
EnemyStuff.DeployableTypes = (STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_COMMCHAIR | STRUCTURE_MARINE_INFANTRYPORTAL | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_ALIEN_OFFENCECHAMBER);
|
||||||
|
EnemyStuff.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
|
||||||
|
|
||||||
|
if (AITAC_DeployableExistsAtLocation(ThisHive->FloorLocation, &EnemyStuff)) { continue; }
|
||||||
|
|
||||||
|
const AvHAIHiveDefinition* NearestEnemyHive = AITAC_GetActiveHiveNearestLocation(EnemyTeam, ThisHive->FloorLocation);
|
||||||
|
|
||||||
|
float ThisDist = 0.0f;
|
||||||
|
|
||||||
|
// Either pick an empty hive furthest from the nearest enemy hive (if they have one)
|
||||||
|
// Or the closest one to us if the enemy don't (e.g. it's MvM)
|
||||||
|
|
||||||
|
if (NearestEnemyHive)
|
||||||
|
{
|
||||||
|
ThisDist = vDist2DSq(NearestEnemyHive->FloorLocation, ThisHive->FloorLocation);
|
||||||
|
|
||||||
|
if (!RelocationHive || ThisDist > MinDist)
|
||||||
|
{
|
||||||
|
RelocationHive = ThisHive;
|
||||||
|
MinDist = ThisDist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ThisDist = vDist2DSq(CurrentTeamStartLocation, ThisHive->FloorLocation);
|
||||||
|
|
||||||
|
if (!RelocationHive || ThisDist < MinDist)
|
||||||
|
{
|
||||||
|
RelocationHive = ThisHive;
|
||||||
|
MinDist = ThisDist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No hives to relocate to
|
||||||
|
if (!RelocationHive) { return ZERO_VECTOR; }
|
||||||
|
|
||||||
|
return RelocationHive->FloorLocation;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AITAC_IsRelocationPointStillValid(AvHTeamNumber RelocationTeam, Vector RelocationPoint)
|
||||||
|
{
|
||||||
|
if (vIsZero(RelocationPoint)) { return false; }
|
||||||
|
|
||||||
|
const AvHAIHiveDefinition* ThisHive = AITAC_GetHiveNearestLocation(RelocationPoint);
|
||||||
|
|
||||||
|
// Obviously don't relocate to an active enemy hive...
|
||||||
|
if (ThisHive->Status != HIVE_STATUS_UNBUILT) { return false; }
|
||||||
|
|
||||||
|
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(RelocationTeam);
|
||||||
|
|
||||||
|
// Don't relocate if the enemy has a foothold here
|
||||||
|
DeployableSearchFilter EnemyStuff;
|
||||||
|
EnemyStuff.DeployableTeam = EnemyTeam;
|
||||||
|
EnemyStuff.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||||
|
EnemyStuff.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||||
|
EnemyStuff.DeployableTypes = (STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_COMMCHAIR | STRUCTURE_MARINE_INFANTRYPORTAL | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_ALIEN_OFFENCECHAMBER);
|
||||||
|
EnemyStuff.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
|
||||||
|
|
||||||
|
if (AITAC_DeployableExistsAtLocation(ThisHive->FloorLocation, &EnemyStuff)) { return false; }
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AITAC_IsRelocationCompleted(AvHTeamNumber RelocationTeam, Vector RelocationPoint)
|
||||||
|
{
|
||||||
|
if (vIsZero(RelocationPoint)) { return true; }
|
||||||
|
|
||||||
|
// Don't relocate if the enemy has a foothold here
|
||||||
|
DeployableSearchFilter BaseStuffFilter;
|
||||||
|
BaseStuffFilter.DeployableTeam = RelocationTeam;
|
||||||
|
BaseStuffFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||||
|
BaseStuffFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||||
|
BaseStuffFilter.DeployableTypes = (STRUCTURE_MARINE_COMMCHAIR | STRUCTURE_MARINE_INFANTRYPORTAL);
|
||||||
|
BaseStuffFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
|
||||||
|
|
||||||
|
edict_t* RelocationChair = nullptr;
|
||||||
|
edict_t* CurrentCommChair = AITAC_GetCommChair(RelocationTeam);
|
||||||
|
int NumInfPortals = 0;
|
||||||
|
|
||||||
|
vector<AvHAIBuildableStructure> RelocationStructures = AITAC_FindAllDeployables(RelocationPoint, &BaseStuffFilter);
|
||||||
|
|
||||||
|
for (auto it = RelocationStructures.begin(); it != RelocationStructures.end(); it++)
|
||||||
|
{
|
||||||
|
if (it->StructureType == STRUCTURE_MARINE_COMMCHAIR)
|
||||||
|
{
|
||||||
|
RelocationChair = it->edict;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it->StructureType == STRUCTURE_MARINE_INFANTRYPORTAL)
|
||||||
|
{
|
||||||
|
NumInfPortals++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FNullEnt(RelocationChair) || NumInfPortals < 2) { return false; }
|
||||||
|
|
||||||
|
DeployableSearchFilter OldStuffFilter;
|
||||||
|
OldStuffFilter.DeployableTeam = RelocationTeam;
|
||||||
|
OldStuffFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||||
|
OldStuffFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
|
||||||
|
OldStuffFilter.MinSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f);
|
||||||
|
OldStuffFilter.PurposeFlags = STRUCTURE_PURPOSE_BASE;
|
||||||
|
|
||||||
|
vector<AvHAIBuildableStructure> AllOldStructures = AITAC_FindAllDeployables(RelocationPoint, &OldStuffFilter);
|
||||||
|
|
||||||
|
for (auto it = AllOldStructures.begin(); it != AllOldStructures.end(); it++)
|
||||||
|
{
|
||||||
|
if (it->edict != CurrentCommChair) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AITAC_IsRelocationAtStartEnabled()
|
||||||
|
{
|
||||||
|
return bEnableRelocationAtStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AITAC_DetermineRelocationEnabled()
|
||||||
|
{
|
||||||
|
bEnableRelocationAtStart = false;
|
||||||
|
|
||||||
|
if (CONFIG_IsRelocationAllowed())
|
||||||
|
{
|
||||||
|
float RandomRoll = frandrange(0.0f, 1.0f);
|
||||||
|
|
||||||
|
bEnableRelocationAtStart = (RandomRoll <= CONFIG_GetRelocationChance());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AITAC_IsMarineBaseValid(AvHAIMarineBase* Base)
|
||||||
|
{
|
||||||
|
if (Base->PlacedStructures.size() > 0) { return true; }
|
||||||
|
|
||||||
|
if ((Base->bRecycleBase || Base->bBaseInitialised) && Base->PlacedStructures.size() == 0) { return false; }
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AITAC_ManageActiveMarineBases()
|
||||||
|
{
|
||||||
|
for (auto it = ActiveTeamABases.begin(); it != ActiveTeamABases.end();)
|
||||||
|
{
|
||||||
|
for (auto structIt = it->PlacedStructures.begin(); structIt != it->PlacedStructures.end();)
|
||||||
|
{
|
||||||
|
AvHAIBuildableStructure StructureRef = TeamAStructureMap[*structIt];
|
||||||
|
|
||||||
|
if (!StructureRef.IsValid() || (StructureRef.StructureStatusFlags & STRUCTURE_STATUS_RECYCLING))
|
||||||
|
{
|
||||||
|
structIt = it->PlacedStructures.erase(structIt);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
structIt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AITAC_IsMarineBaseValid(&(*it)))
|
||||||
|
{
|
||||||
|
it = ActiveTeamABases.erase(it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = ActiveTeamBBases.begin(); it != ActiveTeamBBases.end();)
|
||||||
|
{
|
||||||
|
for (auto structIt = it->PlacedStructures.begin(); structIt != it->PlacedStructures.end();)
|
||||||
|
{
|
||||||
|
AvHAIBuildableStructure StructureRef = TeamBStructureMap[*structIt];
|
||||||
|
|
||||||
|
if (!StructureRef.IsValid() || (StructureRef.StructureStatusFlags & STRUCTURE_STATUS_RECYCLING))
|
||||||
|
{
|
||||||
|
structIt = it->PlacedStructures.erase(structIt);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
structIt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AITAC_IsMarineBaseValid(&(*it)))
|
||||||
|
{
|
||||||
|
it = ActiveTeamBBases.erase(it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AITAC_AddNewBase(AvHTeamNumber Team, Vector NewBaseLocation, MarineBaseType NewBaseType)
|
||||||
|
{
|
||||||
|
vector<AvHAIMarineBase>& BaseList = (Team == AIMGR_GetTeamANumber()) ? ActiveTeamABases : ActiveTeamBBases;
|
||||||
|
|
||||||
|
AvHAIMarineBase NewBase;
|
||||||
|
NewBase.BaseLocation = NewBaseLocation;
|
||||||
|
NewBase.BaseType = NewBaseType;
|
||||||
|
NewBase.BaseTeam = Team;
|
||||||
|
|
||||||
|
BaseList.push_back(NewBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AITAC_CanBuildOutBase(const AvHAIMarineBase* Base)
|
||||||
|
{
|
||||||
|
if (!Base || Base->bRecycleBase || !Base->bIsActive) { return false; }
|
||||||
|
|
||||||
|
switch (Base->BaseType)
|
||||||
|
{
|
||||||
|
case MARINE_BASE_MAINBASE:
|
||||||
|
return AITAC_CanBuildOutMainBase(Base);
|
||||||
|
case MARINE_BASE_OUTPOST:
|
||||||
|
return AITAC_CanBuildOutOutpost(Base);
|
||||||
|
case MARINE_BASE_SIEGE:
|
||||||
|
return AITAC_CanBuildOutSiege(Base);
|
||||||
|
case MARINE_BASE_GUARDPOST:
|
||||||
|
return AITAC_CanBuildOutGuardPost(Base);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AITAC_CanBuildOutMainBase(const AvHAIMarineBase* Base)
|
||||||
|
{
|
||||||
|
bool bHasCommChair = false;
|
||||||
|
int NumInfPortals = 0;
|
||||||
|
bool bHasArmoury = false;
|
||||||
|
bool bHasAdvArmoury = false;
|
||||||
|
bool bArmouryCompleted = false;
|
||||||
|
bool bHasArmsLab = false;
|
||||||
|
bool bArmsLabCompleted = false;
|
||||||
|
bool bHasProtoLab = false;
|
||||||
|
bool bHasObs = false;
|
||||||
|
bool bHasPhase = false;
|
||||||
|
bool bHasTF = false;
|
||||||
|
int NumTurrets = 0;
|
||||||
|
|
||||||
|
std::unordered_map<int, AvHAIBuildableStructure>& BuildingMap = (Base->BaseTeam == AIMGR_GetTeamANumber()) ? TeamAStructureMap : TeamBStructureMap;
|
||||||
|
|
||||||
|
for (auto it = Base->PlacedStructures.begin(); it != Base->PlacedStructures.end(); it++)
|
||||||
|
{
|
||||||
|
AvHAIBuildableStructure StructureRef = BuildingMap[*it];
|
||||||
|
|
||||||
|
switch (StructureRef.StructureType)
|
||||||
|
{
|
||||||
|
case STRUCTURE_MARINE_COMMCHAIR:
|
||||||
|
bHasCommChair = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_INFANTRYPORTAL:
|
||||||
|
NumInfPortals++;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_ARMOURY:
|
||||||
|
bArmouryCompleted = (StructureRef.StructureStatusFlags & STRUCTURE_STATUS_COMPLETED);
|
||||||
|
bHasArmoury = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_ADVARMOURY:
|
||||||
|
bArmouryCompleted = (StructureRef.StructureStatusFlags & STRUCTURE_STATUS_COMPLETED);
|
||||||
|
bHasArmoury = true;
|
||||||
|
bHasAdvArmoury = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_ARMSLAB:
|
||||||
|
bHasArmsLab = true;
|
||||||
|
bArmsLabCompleted = (StructureRef.StructureStatusFlags & STRUCTURE_STATUS_COMPLETED);
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_PROTOTYPELAB:
|
||||||
|
bHasProtoLab = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_OBSERVATORY:
|
||||||
|
bHasObs = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_PHASEGATE:
|
||||||
|
bHasPhase = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_TURRETFACTORY:
|
||||||
|
case STRUCTURE_MARINE_ADVTURRETFACTORY:
|
||||||
|
bHasTF = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_TURRET:
|
||||||
|
NumTurrets++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (!bHasCommChair
|
||||||
|
|| NumInfPortals < 2
|
||||||
|
|| !bHasArmoury
|
||||||
|
|| !bHasAdvArmoury
|
||||||
|
|| (!bHasArmsLab && bArmouryCompleted)
|
||||||
|
|| (!bHasProtoLab && bHasAdvArmoury && bArmsLabCompleted)
|
||||||
|
|| (!bHasObs && bArmouryCompleted)
|
||||||
|
|| (!bHasPhase && AITAC_ResearchIsComplete(Base->BaseTeam, TECH_RESEARCH_PHASETECH))
|
||||||
|
|| !bHasTF
|
||||||
|
|| NumTurrets < 5);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AITAC_CanBuildOutOutpost(const AvHAIMarineBase* Base)
|
||||||
|
{
|
||||||
|
bool bHasArmoury = false;
|
||||||
|
bool bHasObs = false;
|
||||||
|
bool bHasPhase = false;
|
||||||
|
bool bHasTF = false;
|
||||||
|
int NumTurrets = 0;
|
||||||
|
|
||||||
|
std::unordered_map<int, AvHAIBuildableStructure>& BuildingMap = (Base->BaseTeam == AIMGR_GetTeamANumber()) ? TeamAStructureMap : TeamBStructureMap;
|
||||||
|
|
||||||
|
for (auto it = Base->PlacedStructures.begin(); it != Base->PlacedStructures.end(); it++)
|
||||||
|
{
|
||||||
|
AvHAIBuildableStructure StructureRef = BuildingMap[*it];
|
||||||
|
|
||||||
|
switch (StructureRef.StructureType)
|
||||||
|
{
|
||||||
|
case STRUCTURE_MARINE_ARMOURY:
|
||||||
|
case STRUCTURE_MARINE_ADVARMOURY:
|
||||||
|
bHasArmoury = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_OBSERVATORY:
|
||||||
|
bHasObs = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_PHASEGATE:
|
||||||
|
bHasPhase = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_TURRETFACTORY:
|
||||||
|
case STRUCTURE_MARINE_ADVTURRETFACTORY:
|
||||||
|
bHasTF = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_TURRET:
|
||||||
|
NumTurrets++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (!bHasArmoury
|
||||||
|
|| !bHasObs
|
||||||
|
|| (!bHasPhase && AITAC_ResearchIsComplete(Base->BaseTeam, TECH_RESEARCH_PHASETECH))
|
||||||
|
|| !bHasTF
|
||||||
|
|| NumTurrets < 5);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AITAC_CanBuildOutSiege(const AvHAIMarineBase* Base)
|
||||||
|
{
|
||||||
|
bool bHasArmoury = false;
|
||||||
|
bool bHasObs = false;
|
||||||
|
bool bHasPhase = false;
|
||||||
|
bool bHasTF = false;
|
||||||
|
int NumTurrets = 0;
|
||||||
|
|
||||||
|
std::unordered_map<int, AvHAIBuildableStructure>& BuildingMap = (Base->BaseTeam == AIMGR_GetTeamANumber()) ? TeamAStructureMap : TeamBStructureMap;
|
||||||
|
|
||||||
|
for (auto it = Base->PlacedStructures.begin(); it != Base->PlacedStructures.end(); it++)
|
||||||
|
{
|
||||||
|
AvHAIBuildableStructure StructureRef = BuildingMap[*it];
|
||||||
|
|
||||||
|
switch (StructureRef.StructureType)
|
||||||
|
{
|
||||||
|
case STRUCTURE_MARINE_ARMOURY:
|
||||||
|
case STRUCTURE_MARINE_ADVARMOURY:
|
||||||
|
bHasArmoury = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_OBSERVATORY:
|
||||||
|
bHasObs = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_PHASEGATE:
|
||||||
|
bHasPhase = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_ADVTURRETFACTORY:
|
||||||
|
bHasTF = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_SIEGETURRET:
|
||||||
|
NumTurrets++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (!bHasArmoury
|
||||||
|
|| !bHasObs
|
||||||
|
|| (!bHasPhase && AITAC_ResearchIsComplete(Base->BaseTeam, TECH_RESEARCH_PHASETECH))
|
||||||
|
|| !bHasTF
|
||||||
|
|| NumTurrets < 3);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AITAC_CanBuildOutGuardPost(const AvHAIMarineBase* Base)
|
||||||
|
{
|
||||||
|
bool bHasObs = false;
|
||||||
|
bool bHasTF = false;
|
||||||
|
int NumTurrets = 0;
|
||||||
|
|
||||||
|
std::unordered_map<int, AvHAIBuildableStructure>& BuildingMap = (Base->BaseTeam == AIMGR_GetTeamANumber()) ? TeamAStructureMap : TeamBStructureMap;
|
||||||
|
|
||||||
|
for (auto it = Base->PlacedStructures.begin(); it != Base->PlacedStructures.end(); it++)
|
||||||
|
{
|
||||||
|
AvHAIBuildableStructure StructureRef = BuildingMap[*it];
|
||||||
|
|
||||||
|
switch (StructureRef.StructureType)
|
||||||
|
{
|
||||||
|
case STRUCTURE_MARINE_OBSERVATORY:
|
||||||
|
bHasObs = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_TURRETFACTORY:
|
||||||
|
case STRUCTURE_MARINE_ADVTURRETFACTORY:
|
||||||
|
bHasTF = true;
|
||||||
|
break;
|
||||||
|
case STRUCTURE_MARINE_TURRET:
|
||||||
|
NumTurrets++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (!bHasObs
|
||||||
|
|| !bHasTF
|
||||||
|
|| NumTurrets < 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<AvHAIMarineBase>& AITAC_GetTeamBases(AvHTeamNumber Team)
|
||||||
|
{
|
||||||
|
return (Team == AIMGR_GetTeamANumber()) ? ActiveTeamABases : ActiveTeamBBases;
|
||||||
|
}
|
|
@ -31,6 +31,8 @@ AvHAIBuildableStructure AITAC_GetDeployableFromEdict(const edict_t* Structure);
|
||||||
AvHAIBuildableStructure* AITAC_GetDeployableRefFromEdict(const edict_t* Structure);
|
AvHAIBuildableStructure* AITAC_GetDeployableRefFromEdict(const edict_t* Structure);
|
||||||
AvHAIBuildableStructure AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter);
|
AvHAIBuildableStructure AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter);
|
||||||
AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachableByRef(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter);
|
AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachableByRef(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter);
|
||||||
|
AvHAIBuildableStructure AITAC_GetDeployableStructureByEntIndex(AvHTeamNumber Team, int EntIndex);
|
||||||
|
AvHAIBuildableStructure* AITAC_GetDeployableStructureRefByEntIndex(AvHTeamNumber Team, int EntIndex);
|
||||||
int AITAC_GetNumDeployablesNearLocation(const Vector& Location, const DeployableSearchFilter* Filter);
|
int AITAC_GetNumDeployablesNearLocation(const Vector& Location, const DeployableSearchFilter* Filter);
|
||||||
void AITAC_PopulateHiveData();
|
void AITAC_PopulateHiveData();
|
||||||
void AITAC_RefreshHiveData();
|
void AITAC_RefreshHiveData();
|
||||||
|
@ -62,15 +64,20 @@ const AvHAIHiveDefinition* AITAC_GetNonEmptyHiveNearestLocation(const Vector Sea
|
||||||
Vector AITAC_GetCommChairLocation(AvHTeamNumber Team);
|
Vector AITAC_GetCommChairLocation(AvHTeamNumber Team);
|
||||||
edict_t* AITAC_GetCommChair(AvHTeamNumber Team);
|
edict_t* AITAC_GetCommChair(AvHTeamNumber Team);
|
||||||
|
|
||||||
|
Vector AITAC_GetTeamOriginalStartLocation(AvHTeamNumber Team);
|
||||||
Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team);
|
Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team);
|
||||||
|
Vector AITAC_GetTeamRelocationPoint(AvHTeamNumber Team);
|
||||||
|
|
||||||
|
// Returns the name of the supplied location on the map. This will be the same as what appears in the bottom left of the player's screen
|
||||||
|
string AITAC_GetLocationName(Vector Location);
|
||||||
|
|
||||||
AvHAIResourceNode* AITAC_GetRandomResourceNode(AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags);
|
AvHAIResourceNode* AITAC_GetRandomResourceNode(AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags);
|
||||||
|
|
||||||
AvHAIDroppedItem* AITAC_FindClosestItemToLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance);
|
AvHAIDroppedItem AITAC_FindClosestItemToLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance);
|
||||||
bool AITAC_ItemExistsInLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance);
|
bool AITAC_ItemExistsInLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance);
|
||||||
int AITAC_GetNumItemsInLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance);
|
int AITAC_GetNumItemsInLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance);
|
||||||
|
|
||||||
AvHAIDroppedItem* AITAC_GetDroppedItemRefFromEdict(edict_t* ItemEdict);
|
AvHAIDroppedItem AITAC_GetDroppedItemRefFromEdict(edict_t* ItemEdict);
|
||||||
|
|
||||||
Vector AITAC_GetRandomBuildHintInLocation(const unsigned int StructureType, const Vector SearchLocation, const float SearchRadius);
|
Vector AITAC_GetRandomBuildHintInLocation(const unsigned int StructureType, const Vector SearchLocation, const float SearchRadius);
|
||||||
|
|
||||||
|
@ -208,6 +215,26 @@ void AITAC_UpdateSquads();
|
||||||
void AITAC_ManageSquads();
|
void AITAC_ManageSquads();
|
||||||
void AITAC_ClearSquads();
|
void AITAC_ClearSquads();
|
||||||
AvHAISquad* AITAC_GetSquadForObjective(AvHAIPlayer* pBot, edict_t* TaskTarget, BotTaskType ObjectiveType);
|
AvHAISquad* AITAC_GetSquadForObjective(AvHAIPlayer* pBot, edict_t* TaskTarget, BotTaskType ObjectiveType);
|
||||||
|
AvHAISquad* AITAC_GetSquadForObjective(AvHAIPlayer* pBot, Vector TaskLocation, BotTaskType ObjectiveType);
|
||||||
Vector AITAC_GetGatherLocationForSquad(AvHAISquad* Squad);
|
Vector AITAC_GetGatherLocationForSquad(AvHAISquad* Squad);
|
||||||
|
|
||||||
|
Vector AITAC_FindNewTeamRelocationPoint(AvHTeamNumber Team);
|
||||||
|
bool AITAC_IsRelocationPointStillValid(AvHTeamNumber RelocationTeam, Vector RelocationPoint);
|
||||||
|
bool AITAC_IsRelocationCompleted(AvHTeamNumber RelocationTeam, Vector RelocationPoint);
|
||||||
|
|
||||||
|
bool AITAC_IsRelocationAtStartEnabled();
|
||||||
|
|
||||||
|
void AITAC_DetermineRelocationEnabled();
|
||||||
|
|
||||||
|
bool AITAC_IsMarineBaseValid(AvHAIMarineBase* Base);
|
||||||
|
void AITAC_ManageActiveMarineBases();
|
||||||
|
void AITAC_AddNewBase(AvHTeamNumber Team, Vector NewBaseLocation, MarineBaseType NewBaseType);
|
||||||
|
bool AITAC_CanBuildOutBase(const AvHAIMarineBase* Base);
|
||||||
|
bool AITAC_CanBuildOutMainBase(const AvHAIMarineBase* Base);
|
||||||
|
bool AITAC_CanBuildOutOutpost(const AvHAIMarineBase* Base);
|
||||||
|
bool AITAC_CanBuildOutSiege(const AvHAIMarineBase* Base);
|
||||||
|
bool AITAC_CanBuildOutGuardPost(const AvHAIMarineBase* Base);
|
||||||
|
|
||||||
|
vector<AvHAIMarineBase>& AITAC_GetTeamBases(AvHTeamNumber Team);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -395,8 +395,8 @@ bool AITASK_IsTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
return AITASK_IsAlienSecureHiveTaskStillValid(pBot, Task);
|
return AITASK_IsAlienSecureHiveTaskStillValid(pBot, Task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case TASK_ATTACK_BASE:
|
case TASK_ASSAULT_MARINE_BASE:
|
||||||
return true;
|
return AITASK_IsAssaultMarineBaseTaskStillValid(pBot, Task);
|
||||||
case TASK_DEFEND:
|
case TASK_DEFEND:
|
||||||
return AITASK_IsDefendTaskStillValid(pBot, Task);
|
return AITASK_IsDefendTaskStillValid(pBot, Task);
|
||||||
case TASK_WELD:
|
case TASK_WELD:
|
||||||
|
@ -441,11 +441,11 @@ bool AITASK_IsWeldTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
{
|
{
|
||||||
if (FNullEnt(Task->TaskSecondaryTarget))
|
if (FNullEnt(Task->TaskSecondaryTarget))
|
||||||
{
|
{
|
||||||
AvHAIDroppedItem* NearestWelder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, pBot->Player->GetTeam(), pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, 0.0f, true);
|
AvHAIDroppedItem NearestWelder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, pBot->Player->GetTeam(), pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, 0.0f, true);
|
||||||
|
|
||||||
if (NearestWelder)
|
if (NearestWelder.IsValid())
|
||||||
{
|
{
|
||||||
Task->TaskSecondaryTarget = NearestWelder->edict;
|
Task->TaskSecondaryTarget = NearestWelder.edict;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -875,12 +875,32 @@ bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTas
|
||||||
|
|
||||||
if (bActiveHiveWithoutTechExists) { return true; }
|
if (bActiveHiveWithoutTechExists) { return true; }
|
||||||
|
|
||||||
DeployableSearchFilter StructureFilter;
|
int NumMissing = 0;
|
||||||
StructureFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER | ALIEN_BUILD_DEFENSE_CHAMBER | ALIEN_BUILD_MOVEMENT_CHAMBER | ALIEN_BUILD_SENSORY_CHAMBER;
|
AvHAIDeployableStructureType MissingStructure = AITAC_GetNextMissingUpgradeChamberForTeam(BotTeam, NumMissing);
|
||||||
StructureFilter.MaxSearchRadius = (IsEdictHive(Task->TaskTarget)) ? UTIL_MetresToGoldSrcUnits(10.0f) : UTIL_MetresToGoldSrcUnits(5.0f);
|
|
||||||
StructureFilter.DeployableTeam = pBot->Player->GetTeam();
|
|
||||||
|
|
||||||
vector<AvHAIBuildableStructure> AllNearbyStructures = AITAC_FindAllDeployables(Task->TaskTarget->v.origin, &StructureFilter);
|
if (MissingStructure != STRUCTURE_NONE) { return true; }
|
||||||
|
|
||||||
|
Vector ReinforceLocation = Task->TaskTarget->v.origin;
|
||||||
|
float SearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
|
||||||
|
|
||||||
|
if (IsEdictHive(Task->TaskTarget))
|
||||||
|
{
|
||||||
|
AvHAIHiveDefinition* HiveToReinforce = AITAC_GetHiveFromEdict(Task->TaskTarget);
|
||||||
|
|
||||||
|
if (HiveToReinforce)
|
||||||
|
{
|
||||||
|
ReinforceLocation = HiveToReinforce->FloorLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeployableSearchFilter StructureFilter;
|
||||||
|
StructureFilter.DeployableTypes = SEARCH_ALL_ALIEN_STRUCTURES;
|
||||||
|
StructureFilter.MaxSearchRadius = SearchRadius * 1.25f;
|
||||||
|
StructureFilter.DeployableTeam = BotTeam;
|
||||||
|
|
||||||
|
vector<AvHAIBuildableStructure> AllNearbyStructures = AITAC_FindAllDeployables(ReinforceLocation, &StructureFilter);
|
||||||
|
|
||||||
bool bUnfinishedStructureExists = false;
|
bool bUnfinishedStructureExists = false;
|
||||||
int NumOffenceChambers = 0;
|
int NumOffenceChambers = 0;
|
||||||
|
@ -916,11 +936,11 @@ bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTas
|
||||||
|
|
||||||
// Task is still valid if we have any missing structures, or we're a gorge at the target site and there is an incomplete structure that we can finish off
|
// Task is still valid if we have any missing structures, or we're a gorge at the target site and there is an incomplete structure that we can finish off
|
||||||
|
|
||||||
if (NumOffenceChambers < 2
|
if (NumOffenceChambers < 3
|
||||||
|| (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_DEFENSE_CHAMBER) && NumDefenceChambers < 2)
|
|| (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_DEFENSE_CHAMBER) && NumDefenceChambers < 2)
|
||||||
|| (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_MOVEMENT_CHAMBER) && NumMovementChambers < 1)
|
|| (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_MOVEMENT_CHAMBER) && NumMovementChambers < 1)
|
||||||
|| (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_SENSORY_CHAMBER) && NumSensoryChambers < 1)
|
|| (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_SENSORY_CHAMBER) && NumSensoryChambers < 1)
|
||||||
|| (IsPlayerGorge(pBot->Edict) && bUnfinishedStructureExists && vDist2DSq(pBot->Edict->v.origin, Task->TaskTarget->v.origin) <= sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
|
|| (IsPlayerGorge(pBot->Edict) && bUnfinishedStructureExists && vDist2DSq(pBot->Edict->v.origin, ReinforceLocation) <= sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
|
||||||
) { return true; }
|
) { return true; }
|
||||||
|
|
||||||
// Otherwise, are there any enemy structures lying around we could clear out?
|
// Otherwise, are there any enemy structures lying around we could clear out?
|
||||||
|
@ -934,9 +954,9 @@ bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTas
|
||||||
EnemyStuff.DeployableTeam = AIMGR_GetEnemyTeam(BotTeam);
|
EnemyStuff.DeployableTeam = AIMGR_GetEnemyTeam(BotTeam);
|
||||||
EnemyStuff.ReachabilityTeam = BotTeam;
|
EnemyStuff.ReachabilityTeam = BotTeam;
|
||||||
EnemyStuff.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
|
EnemyStuff.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
|
||||||
EnemyStuff.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
|
EnemyStuff.MaxSearchRadius = SearchRadius;
|
||||||
|
|
||||||
return AITAC_DeployableExistsAtLocation(Task->TaskTarget->v.origin, &EnemyStuff);
|
return AITAC_DeployableExistsAtLocation(ReinforceLocation, &EnemyStuff);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AITASK_IsAlienSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
bool AITASK_IsAlienSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
|
@ -961,6 +981,24 @@ bool AITASK_IsAlienSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask*
|
||||||
return AITAC_DeployableExistsAtLocation(HiveToSecure->FloorLocation, &EnemyStuff);
|
return AITAC_DeployableExistsAtLocation(HiveToSecure->FloorLocation, &EnemyStuff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AITASK_IsAssaultMarineBaseTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
|
{
|
||||||
|
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||||
|
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
|
||||||
|
|
||||||
|
if (AIMGR_GetTeamType(EnemyTeam) != AVH_CLASS_TYPE_MARINE) { return false; }
|
||||||
|
|
||||||
|
DeployableSearchFilter StructureFilter;
|
||||||
|
StructureFilter.DeployableTeam = EnemyTeam;
|
||||||
|
StructureFilter.DeployableTypes = (STRUCTURE_MARINE_OBSERVATORY | STRUCTURE_MARINE_ARMSLAB | STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY | STRUCTURE_MARINE_INFANTRYPORTAL | STRUCTURE_MARINE_COMMCHAIR | STRUCTURE_MARINE_PROTOTYPELAB);
|
||||||
|
StructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||||
|
StructureFilter.ReachabilityTeam = BotTeam;
|
||||||
|
StructureFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
|
||||||
|
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
|
||||||
|
|
||||||
|
return AITAC_DeployableExistsAtLocation(Task->TaskLocation, &StructureFilter);
|
||||||
|
}
|
||||||
|
|
||||||
bool AITASK_IsMarineSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
bool AITASK_IsMarineSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
{
|
{
|
||||||
if (!Task || FNullEnt(Task->TaskTarget) || IsPlayerAlien(pBot->Edict)) { return false; }
|
if (!Task || FNullEnt(Task->TaskTarget) || IsPlayerAlien(pBot->Edict)) { return false; }
|
||||||
|
@ -977,6 +1015,12 @@ bool AITASK_IsMarineSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask*
|
||||||
|
|
||||||
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||||
|
|
||||||
|
// We've relocated to this hive, no need to secure now
|
||||||
|
if (vDist2DSq(AITAC_GetTeamStartingLocation(BotTeam), HiveToSecure->FloorLocation) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool bPhaseGatesAvailable = AITAC_PhaseGatesAvailable(BotTeam);
|
bool bPhaseGatesAvailable = AITAC_PhaseGatesAvailable(BotTeam);
|
||||||
|
|
||||||
bool bHasPhaseGate = false;
|
bool bHasPhaseGate = false;
|
||||||
|
@ -1246,9 +1290,9 @@ void BotProgressMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float DistToPlaceLocation = vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation);
|
float DistToPlaceLocation = vDist3DSq(pBot->Edict->v.origin, Task->TaskLocation);
|
||||||
|
|
||||||
if (DistToPlaceLocation < sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
|
if (DistToPlaceLocation < sqrf(50.0f))
|
||||||
{
|
{
|
||||||
pBot->DesiredCombatWeapon = WEAPON_MARINE_MINES;
|
pBot->DesiredCombatWeapon = WEAPON_MARINE_MINES;
|
||||||
}
|
}
|
||||||
|
@ -1325,15 +1369,23 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
{
|
{
|
||||||
if (FNullEnt(Task->TaskTarget)) { return; }
|
if (FNullEnt(Task->TaskTarget)) { return; }
|
||||||
|
|
||||||
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
|
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
|
||||||
|
{
|
||||||
|
pBot->Impulse = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// We had a go, whether it succeeded or not we should try a new location
|
// We had a go, whether it succeeded or not we should try a new location
|
||||||
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED || Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_SUCCESS)
|
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED || Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_SUCCESS)
|
||||||
{
|
{
|
||||||
|
pBot->Impulse = 0;
|
||||||
|
Task->TaskStartedTime = gpGlobals->time;
|
||||||
Task->TaskLocation = ZERO_VECTOR;
|
Task->TaskLocation = ZERO_VECTOR;
|
||||||
Task->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_NONE;
|
Task->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gpGlobals->time - Task->TaskStartedTime < 0.5f) { return; }
|
||||||
|
|
||||||
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||||
|
|
||||||
Vector ReinforceLocation = UTIL_ProjectPointToNavmesh(UTIL_GetEntityGroundLocation(Task->TaskTarget), pBot->BotNavInfo.NavProfile);
|
Vector ReinforceLocation = UTIL_ProjectPointToNavmesh(UTIL_GetEntityGroundLocation(Task->TaskTarget), pBot->BotNavInfo.NavProfile);
|
||||||
|
@ -1355,7 +1407,7 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
|
|
||||||
DeployableSearchFilter StructureFilter;
|
DeployableSearchFilter StructureFilter;
|
||||||
StructureFilter.DeployableTeam = BotTeam;
|
StructureFilter.DeployableTeam = BotTeam;
|
||||||
StructureFilter.MaxSearchRadius = SearchRadius;
|
StructureFilter.MaxSearchRadius = SearchRadius * 1.25f;
|
||||||
StructureFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
|
StructureFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
|
||||||
|
|
||||||
int NumOCs = AITAC_GetNumDeployablesNearLocation(ReinforceLocation, &StructureFilter);
|
int NumOCs = AITAC_GetNumDeployablesNearLocation(ReinforceLocation, &StructureFilter);
|
||||||
|
@ -1410,6 +1462,14 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (NextStructure == STRUCTURE_NONE)
|
||||||
|
{
|
||||||
|
int NumMissing = 0;
|
||||||
|
AvHAIDeployableStructureType MissingStructure = AITAC_GetNextMissingUpgradeChamberForTeam(BotTeam, NumMissing);
|
||||||
|
|
||||||
|
NextStructure = MissingStructure;
|
||||||
|
}
|
||||||
|
|
||||||
if (NextStructure != STRUCTURE_NONE)
|
if (NextStructure != STRUCTURE_NONE)
|
||||||
{
|
{
|
||||||
if (vIsZero(Task->TaskLocation))
|
if (vIsZero(Task->TaskLocation))
|
||||||
|
@ -1756,7 +1816,7 @@ void BotProgressAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
|
|
||||||
AvHTurret* TurretRef = dynamic_cast<AvHTurret*>(CBaseEntity::Instance(Task->TaskTarget));
|
AvHTurret* TurretRef = dynamic_cast<AvHTurret*>(CBaseEntity::Instance(Task->TaskTarget));
|
||||||
|
|
||||||
if (TurretRef && TurretRef->GetIsValidTarget(pBot->Player))
|
if (TurretRef && TurretRef->GetIsValidTarget(pBot->Player) && !vIsZero(GetVisiblePointOnPlayerFromObserver(Task->TaskTarget, pBot->Edict)))
|
||||||
{
|
{
|
||||||
if (vIsZero(pBot->LastSafeLocation))
|
if (vIsZero(pBot->LastSafeLocation))
|
||||||
{
|
{
|
||||||
|
@ -1764,13 +1824,33 @@ void BotProgressAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
}
|
}
|
||||||
|
|
||||||
MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL);
|
MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL);
|
||||||
return;
|
BotLookAt(pBot, Task->TaskTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BotAttackResult AttackResult = PerformAttackLOSCheck(pBot, Weapon, Task->TaskTarget);
|
BotAttackResult AttackResult = PerformAttackLOSCheck(pBot, Weapon, Task->TaskTarget);
|
||||||
|
|
||||||
|
if (AttackResult == ATTACK_BLOCKED)
|
||||||
|
{
|
||||||
|
TraceResult hit;
|
||||||
|
|
||||||
|
Vector StartTrace = pBot->CurrentEyePosition;
|
||||||
|
|
||||||
|
Vector AttackDir = UTIL_GetVectorNormal(UTIL_GetCentreOfEntity(Task->TaskTarget) - StartTrace);
|
||||||
|
|
||||||
|
Vector EndTrace = pBot->CurrentEyePosition + (AttackDir * UTIL_MetresToGoldSrcUnits(50.0f));
|
||||||
|
|
||||||
|
UTIL_TraceLine(StartTrace, EndTrace, dont_ignore_monsters, dont_ignore_glass, pBot->Edict->v.pContainingEntity, &hit);
|
||||||
|
|
||||||
|
if (!FNullEnt(hit.pHit) && hit.pHit->v.team == AIMGR_GetEnemyTeam(pBot->Player->GetTeam()) && vDist2DSq(hit.pHit->v.origin, Task->TaskTarget->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(2.0f)))
|
||||||
|
{
|
||||||
|
AttackResult = ATTACK_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (AttackResult == ATTACK_SUCCESS)
|
if (AttackResult == ATTACK_SUCCESS)
|
||||||
{
|
{
|
||||||
// If we were ducking before then keep ducking
|
// If we were ducking before then keep ducking
|
||||||
|
@ -1805,17 +1885,14 @@ void BotProgressAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
|
|
||||||
Vector RightDir = UTIL_GetCrossProduct(EnemyOrientation, UP_VECTOR);
|
Vector RightDir = UTIL_GetCrossProduct(EnemyOrientation, UP_VECTOR);
|
||||||
|
|
||||||
pBot->desiredMovementDir = (pBot->BotNavInfo.bZig) ? UTIL_GetVectorNormal2D(RightDir) : UTIL_GetVectorNormal2D(-RightDir);
|
Vector EvasiveDir = GetZigZagDirection(pBot, Task->TaskTarget, nullptr);
|
||||||
|
|
||||||
// Let's get ziggy with it
|
if (!vIsZero(EvasiveDir))
|
||||||
if (gpGlobals->time > pBot->BotNavInfo.NextZigTime)
|
|
||||||
{
|
{
|
||||||
pBot->BotNavInfo.bZig = !pBot->BotNavInfo.bZig;
|
pBot->desiredMovementDir = EvasiveDir;
|
||||||
pBot->BotNavInfo.NextZigTime = gpGlobals->time + frandrange(0.5f, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
BotMovementInputs(pBot);
|
BotMovementInputs(pBot);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1910,9 +1987,34 @@ void BotProgressTakeCommandTask(AvHAIPlayer* pBot)
|
||||||
// Don't take command if we already have a commander
|
// Don't take command if we already have a commander
|
||||||
if (pBot->Player->GetCommander()) { return; }
|
if (pBot->Player->GetCommander()) { return; }
|
||||||
|
|
||||||
edict_t* CommChair = AITAC_GetCommChair(pBot->Player->GetTeam());
|
edict_t* CommChair = nullptr;
|
||||||
|
|
||||||
if (!CommChair) { return; }
|
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||||
|
|
||||||
|
Vector RelocationPoint = pBot->RelocationSpot;
|
||||||
|
|
||||||
|
if (!vIsZero(RelocationPoint) && AITAC_IsRelocationCompleted(BotTeam, RelocationPoint))
|
||||||
|
{
|
||||||
|
DeployableSearchFilter RelocationChairFilter;
|
||||||
|
RelocationChairFilter.DeployableTeam = BotTeam;
|
||||||
|
RelocationChairFilter.DeployableTypes = STRUCTURE_MARINE_COMMCHAIR;
|
||||||
|
RelocationChairFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||||
|
RelocationChairFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||||
|
RelocationChairFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
||||||
|
|
||||||
|
AvHAIBuildableStructure RelocationChair = AITAC_FindClosestDeployableToLocation(RelocationPoint, &RelocationChairFilter);
|
||||||
|
|
||||||
|
if (RelocationChair.IsValid())
|
||||||
|
{
|
||||||
|
CommChair = RelocationChair.edict;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CommChair = AITAC_GetCommChair(BotTeam);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FNullEnt(CommChair)) { return; }
|
||||||
|
|
||||||
float DistFromChair = vDist2DSq(pBot->Edict->v.origin, CommChair->v.origin);
|
float DistFromChair = vDist2DSq(pBot->Edict->v.origin, CommChair->v.origin);
|
||||||
|
|
||||||
|
@ -2006,7 +2108,7 @@ void BotProgressEvolveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
{
|
{
|
||||||
if (FNullEnt(Task->TaskTarget))
|
if (FNullEnt(Task->TaskTarget))
|
||||||
{
|
{
|
||||||
Task->TaskLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), UTIL_GetEntityGroundLocation(Task->TaskTarget), UTIL_MetresToGoldSrcUnits(10.0f));
|
Task->TaskLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), pBot->CurrentFloorPosition, UTIL_MetresToGoldSrcUnits(10.0f));
|
||||||
|
|
||||||
if (vIsZero(Task->TaskLocation))
|
if (vIsZero(Task->TaskLocation))
|
||||||
{
|
{
|
||||||
|
@ -2024,11 +2126,11 @@ void BotProgressEvolveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Task->TaskLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(Task->TaskTarget), UTIL_MetresToGoldSrcUnits(10.0f));
|
Task->TaskLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), UTIL_GetEntityGroundLocation(Task->TaskTarget), UTIL_MetresToGoldSrcUnits(10.0f));
|
||||||
|
|
||||||
if (vIsZero(Task->TaskLocation))
|
if (vIsZero(Task->TaskLocation))
|
||||||
{
|
{
|
||||||
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], Task->TaskLocation, UTIL_MetresToGoldSrcUnits(5.0f));
|
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], UTIL_GetEntityGroundLocation(Task->TaskTarget), UTIL_MetresToGoldSrcUnits(10.0f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2106,6 +2208,7 @@ void AlienProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
// We tried and failed to place the structure
|
// We tried and failed to place the structure
|
||||||
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
|
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
|
||||||
{
|
{
|
||||||
|
pBot->Impulse = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2119,6 +2222,8 @@ void AlienProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
{
|
{
|
||||||
edict_t* LinkedEdict = Task->ActiveBuildInfo.LinkedStructure->edict;
|
edict_t* LinkedEdict = Task->ActiveBuildInfo.LinkedStructure->edict;
|
||||||
|
|
||||||
|
Task->TaskTarget = LinkedEdict;
|
||||||
|
|
||||||
if (UTIL_StructureIsFullyBuilt(LinkedEdict)) { return; }
|
if (UTIL_StructureIsFullyBuilt(LinkedEdict)) { return; }
|
||||||
|
|
||||||
if (IsPlayerInUseRange(pBot->Edict, LinkedEdict))
|
if (IsPlayerInUseRange(pBot->Edict, LinkedEdict))
|
||||||
|
@ -2186,7 +2291,11 @@ void BotAlienPlaceChamber(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, AvHAIDeploya
|
||||||
{
|
{
|
||||||
if (vIsZero(Task->TaskLocation) || DesiredStructure == STRUCTURE_NONE) { return; }
|
if (vIsZero(Task->TaskLocation) || DesiredStructure == STRUCTURE_NONE) { return; }
|
||||||
|
|
||||||
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
|
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
|
||||||
|
{
|
||||||
|
pBot->Impulse = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
float DistFromBuildLocation = vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation);
|
float DistFromBuildLocation = vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation);
|
||||||
|
|
||||||
|
@ -2577,6 +2686,9 @@ void BotProgressTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case TASK_ASSAULT_MARINE_BASE:
|
||||||
|
BotProgressAssaultMarineBaseTask(pBot, Task);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -2594,11 +2706,11 @@ void BotProgressWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AvHAIDroppedItem* Welder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, pBot->Player->GetTeam(), pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, 0.0f, true);
|
AvHAIDroppedItem Welder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, pBot->Player->GetTeam(), pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, 0.0f, true);
|
||||||
|
|
||||||
if (Welder)
|
if (Welder.IsValid())
|
||||||
{
|
{
|
||||||
Task->TaskSecondaryTarget = Welder->edict;
|
Task->TaskSecondaryTarget = Welder.edict;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2698,6 +2810,9 @@ void AlienProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
|
|
||||||
if (PhaseGate.IsValid())
|
if (PhaseGate.IsValid())
|
||||||
{
|
{
|
||||||
|
// If the phase gate is next to an electrified structure, and we are a skulk or lerk, then attack
|
||||||
|
// The electrified structure instead. I might change this to avoid it altogether, but there's nothing
|
||||||
|
// wrong with trying to chip away at the TF if you're a skulk
|
||||||
if (bAvoidElectrified)
|
if (bAvoidElectrified)
|
||||||
{
|
{
|
||||||
EnemyStuffFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
|
EnemyStuffFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
|
||||||
|
@ -2798,6 +2913,8 @@ void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
|
|
||||||
bool bKeyStructureBuilt = false;
|
bool bKeyStructureBuilt = false;
|
||||||
|
|
||||||
|
AvHAIBuildableStructure KeyOutpostStructure;
|
||||||
|
|
||||||
AvHAIBuildableStructure StructureToBuild;
|
AvHAIBuildableStructure StructureToBuild;
|
||||||
float MinDist = 0.0f;
|
float MinDist = 0.0f;
|
||||||
|
|
||||||
|
@ -2807,6 +2924,7 @@ void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
|
|
||||||
if ((ThisStructure.StructureStatusFlags & STRUCTURE_STATUS_COMPLETED) && (ThisStructure.StructureType & (STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_PHASEGATE)))
|
if ((ThisStructure.StructureStatusFlags & STRUCTURE_STATUS_COMPLETED) && (ThisStructure.StructureType & (STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_PHASEGATE)))
|
||||||
{
|
{
|
||||||
|
KeyOutpostStructure = ThisStructure;
|
||||||
bKeyStructureBuilt = true;
|
bKeyStructureBuilt = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2869,10 +2987,10 @@ void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
{
|
{
|
||||||
DeployableSearchFilter EnemyStructures;
|
DeployableSearchFilter EnemyStructures;
|
||||||
EnemyStructures.DeployableTypes = SEARCH_ALL_STRUCTURES;
|
EnemyStructures.DeployableTypes = SEARCH_ALL_STRUCTURES;
|
||||||
EnemyStructures.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
|
|
||||||
EnemyStructures.DeployableTeam = EnemyTeam;
|
EnemyStructures.DeployableTeam = EnemyTeam;
|
||||||
EnemyStructures.ReachabilityTeam = BotTeam;
|
EnemyStructures.ReachabilityTeam = BotTeam;
|
||||||
EnemyStructures.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
|
EnemyStructures.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
|
||||||
|
EnemyStructures.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
|
||||||
|
|
||||||
AvHAIBuildableStructure EnemyStructure = AITAC_FindClosestDeployableToLocation(Hive->FloorLocation, &EnemyStructures);
|
AvHAIBuildableStructure EnemyStructure = AITAC_FindClosestDeployableToLocation(Hive->FloorLocation, &EnemyStructures);
|
||||||
|
|
||||||
|
@ -2883,8 +3001,9 @@ void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector OutpostLocation = (KeyOutpostStructure.IsValid()) ? KeyOutpostStructure.Location : Task->TaskLocation;
|
||||||
|
|
||||||
BotGuardLocation(pBot, Task->TaskLocation);
|
BotGuardLocation(pBot, OutpostLocation);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2978,12 +3097,129 @@ void MarineProgressCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
// Empty res node with nothing to do but wait, stick around for 30 seconds and then move on if the commander doesn't drop an RT to build
|
// Empty res node with nothing to do but wait, stick around for 30 seconds and then move on if the commander doesn't drop an RT to build
|
||||||
if (Task->TaskLength == 0.0f)
|
if (Task->TaskLength == 0.0f)
|
||||||
{
|
{
|
||||||
|
const AvHAIResourceNode* ResNode = AITAC_GetNearestResourceNodeToLocation(Task->TaskLocation);
|
||||||
|
|
||||||
|
// If we're not at our destination yet, go there
|
||||||
|
if (vDist2DSq(pBot->Edict->v.origin, ResNode->Location) > sqrf(UTIL_MetresToGoldSrcUnits(1.0f)))
|
||||||
|
{
|
||||||
|
MoveTo(pBot, ResNode->Location, MOVESTYLE_NORMAL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Task->TaskStartedTime = gpGlobals->time;
|
Task->TaskStartedTime = gpGlobals->time;
|
||||||
Task->TaskLength = 30.0f;
|
Task->TaskLength = 30.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
BotGuardLocation(pBot, Task->TaskLocation);
|
BotGuardLocation(pBot, Task->TaskLocation);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BotProgressAssaultMarineBaseTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
|
{
|
||||||
|
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||||
|
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
|
||||||
|
|
||||||
|
if (AIMGR_GetTeamType(BotTeam) == AVH_CLASS_TYPE_ALIEN)
|
||||||
|
{
|
||||||
|
AvHAISquad* ActiveSquad = AITAC_GetSquadForObjective(pBot, Task->TaskLocation, Task->TaskType);
|
||||||
|
|
||||||
|
if (ActiveSquad && !ActiveSquad->bExecuteObjective && !vIsZero(ActiveSquad->SquadGatherLocation))
|
||||||
|
{
|
||||||
|
BotGuardLocation(pBot, ActiveSquad->SquadGatherLocation);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeployableSearchFilter EnemyStructureFilter;
|
||||||
|
EnemyStructureFilter.DeployableTeam = EnemyTeam;
|
||||||
|
EnemyStructureFilter.ReachabilityTeam = BotTeam;
|
||||||
|
EnemyStructureFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
|
||||||
|
EnemyStructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
|
||||||
|
EnemyStructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||||
|
|
||||||
|
|
||||||
|
// First go for any TFs, to eliminate defences
|
||||||
|
EnemyStructureFilter.DeployableTypes = (STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY);
|
||||||
|
|
||||||
|
vector<AvHAIBuildableStructure> Structures = AITAC_FindAllDeployables(Task->TaskLocation, &EnemyStructureFilter);
|
||||||
|
|
||||||
|
for (auto it = Structures.begin(); it != Structures.end(); it++)
|
||||||
|
{
|
||||||
|
float DistToStructure = vDist2D(pBot->Edict->v.origin, it->Location) - 5.0f;
|
||||||
|
|
||||||
|
if (AITAC_GetNumPlayersOfTeamInArea(BotTeam, it->Location, DistToStructure, false, pBot->Edict, AVH_USER3_NONE) < 2)
|
||||||
|
{
|
||||||
|
BotAttackNonPlayerTarget(pBot, it->edict);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// First go for any observatory, to prevent beacon
|
||||||
|
EnemyStructureFilter.DeployableTypes = STRUCTURE_MARINE_OBSERVATORY;
|
||||||
|
|
||||||
|
Structures = AITAC_FindAllDeployables(Task->TaskLocation, &EnemyStructureFilter);
|
||||||
|
|
||||||
|
for (auto it = Structures.begin(); it != Structures.end(); it++)
|
||||||
|
{
|
||||||
|
float DistToStructure = vDist2D(pBot->Edict->v.origin, it->Location) - 5.0f;
|
||||||
|
|
||||||
|
if (AITAC_GetNumPlayersOfTeamInArea(BotTeam, it->Location, DistToStructure, false, pBot->Edict, AVH_USER3_NONE) < 2)
|
||||||
|
{
|
||||||
|
BotAttackNonPlayerTarget(pBot, it->edict);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next go for any arms lab, to weaken the marines
|
||||||
|
EnemyStructureFilter.DeployableTypes = STRUCTURE_MARINE_ARMSLAB;
|
||||||
|
|
||||||
|
Structures = AITAC_FindAllDeployables(Task->TaskLocation, &EnemyStructureFilter);
|
||||||
|
|
||||||
|
for (auto it = Structures.begin(); it != Structures.end(); it++)
|
||||||
|
{
|
||||||
|
float DistToStructure = vDist2D(pBot->Edict->v.origin, it->Location) - 5.0f;
|
||||||
|
|
||||||
|
if (AITAC_GetNumPlayersOfTeamInArea(BotTeam, it->Location, DistToStructure, false, pBot->Edict, AVH_USER3_NONE) < 2)
|
||||||
|
{
|
||||||
|
BotAttackNonPlayerTarget(pBot, it->edict);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next go for any infantry portals, to prevent reinforcements
|
||||||
|
EnemyStructureFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL;
|
||||||
|
|
||||||
|
Structures = AITAC_FindAllDeployables(Task->TaskLocation, &EnemyStructureFilter);
|
||||||
|
|
||||||
|
for (auto it = Structures.begin(); it != Structures.end(); it++)
|
||||||
|
{
|
||||||
|
float DistToStructure = vDist2D(pBot->Edict->v.origin, it->Location) - 5.0f;
|
||||||
|
|
||||||
|
if (AITAC_GetNumPlayersOfTeamInArea(BotTeam, it->Location, DistToStructure, false, pBot->Edict, AVH_USER3_NONE) < 2)
|
||||||
|
{
|
||||||
|
BotAttackNonPlayerTarget(pBot, it->edict);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, any other structures
|
||||||
|
EnemyStructureFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
|
||||||
|
|
||||||
|
Structures = AITAC_FindAllDeployables(Task->TaskLocation, &EnemyStructureFilter);
|
||||||
|
|
||||||
|
for (auto it = Structures.begin(); it != Structures.end(); it++)
|
||||||
|
{
|
||||||
|
float DistToStructure = vDist2D(pBot->Edict->v.origin, it->Location) - 5.0f;
|
||||||
|
|
||||||
|
if (AITAC_GetNumPlayersOfTeamInArea(BotTeam, it->Location, DistToStructure, false, pBot->Edict, AVH_USER3_NONE) < 2)
|
||||||
|
{
|
||||||
|
BotAttackNonPlayerTarget(pBot, it->edict);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// nothing to attack, just hang around
|
||||||
|
BotGuardLocation(pBot, Task->TaskLocation);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3353,9 +3589,9 @@ void AITASK_SetPickupTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Tar
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AvHAIDroppedItem* ItemToPickup = AITAC_GetDroppedItemRefFromEdict(Target);
|
AvHAIDroppedItem ItemToPickup = AITAC_GetDroppedItemRefFromEdict(Target);
|
||||||
|
|
||||||
if (!ItemToPickup)
|
if (!ItemToPickup.IsValid())
|
||||||
{
|
{
|
||||||
AITASK_ClearBotTask(pBot, Task);
|
AITASK_ClearBotTask(pBot, Task);
|
||||||
return;
|
return;
|
||||||
|
@ -3369,7 +3605,7 @@ void AITASK_SetPickupTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Tar
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ItemToPickup->ItemType)
|
switch (ItemToPickup.ItemType)
|
||||||
{
|
{
|
||||||
case DEPLOYABLE_ITEM_AMMO:
|
case DEPLOYABLE_ITEM_AMMO:
|
||||||
Task->TaskType = TASK_GET_AMMO;
|
Task->TaskType = TASK_GET_AMMO;
|
||||||
|
@ -3449,16 +3685,16 @@ void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Targe
|
||||||
|
|
||||||
if (!PlayerHasWeapon(pBot->Player, WEAPON_MARINE_WELDER))
|
if (!PlayerHasWeapon(pBot->Player, WEAPON_MARINE_WELDER))
|
||||||
{
|
{
|
||||||
AvHAIDroppedItem* NearestWelder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, pBot->Player->GetTeam(), pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, 0.0f, true);
|
AvHAIDroppedItem NearestWelder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, pBot->Player->GetTeam(), pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, 0.0f, true);
|
||||||
|
|
||||||
if (!NearestWelder)
|
if (!NearestWelder.IsValid())
|
||||||
{
|
{
|
||||||
AITASK_ClearBotTask(pBot, Task);
|
AITASK_ClearBotTask(pBot, Task);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Task->TaskSecondaryTarget = NearestWelder->edict;
|
Task->TaskSecondaryTarget = NearestWelder.edict;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3570,7 +3806,13 @@ void AITASK_SetMoveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const Vector L
|
||||||
|
|
||||||
void AITASK_SetBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const AvHAIDeployableStructureType StructureType, const Vector Location, const bool bIsUrgent)
|
void AITASK_SetBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const AvHAIDeployableStructureType StructureType, const Vector Location, const bool bIsUrgent)
|
||||||
{
|
{
|
||||||
if (Task->TaskType == TASK_BUILD && Task->StructureType == StructureType && vDist2DSq(Task->TaskLocation, Location) < sqrf(UTIL_MetresToGoldSrcUnits(5.0f))) { return; }
|
if (Task->TaskType == TASK_BUILD && Task->StructureType == StructureType && vDist2DSq(Task->TaskLocation, Location) < sqrf(UTIL_MetresToGoldSrcUnits(1.0f)))
|
||||||
|
{
|
||||||
|
Task->bTaskIsUrgent = bIsUrgent;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
|
||||||
|
|
||||||
AITASK_ClearBotTask(pBot, Task);
|
AITASK_ClearBotTask(pBot, Task);
|
||||||
|
|
||||||
|
@ -3789,6 +4031,8 @@ void AITASK_SetReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
|
||||||
|
|
||||||
AITASK_ClearBotTask(pBot, Task);
|
AITASK_ClearBotTask(pBot, Task);
|
||||||
|
|
||||||
if (FNullEnt(Target) || Target->v.deadflag != DEAD_NO) { return; }
|
if (FNullEnt(Target) || Target->v.deadflag != DEAD_NO) { return; }
|
||||||
|
@ -3848,6 +4092,19 @@ void AITASK_SetMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict
|
||||||
Task->bTaskIsUrgent = bIsUrgent;
|
Task->bTaskIsUrgent = bIsUrgent;
|
||||||
Task->TaskLocation = UTIL_GetNextMinePosition2(Target);
|
Task->TaskLocation = UTIL_GetNextMinePosition2(Target);
|
||||||
Task->StructureType = STRUCTURE_MARINE_DEPLOYEDMINE;
|
Task->StructureType = STRUCTURE_MARINE_DEPLOYEDMINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AITASK_SetAssaultMarineBaseTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, Vector BaseLocation, bool bIsUrgent)
|
||||||
|
{
|
||||||
|
if (Task->TaskType == TASK_ASSAULT_MARINE_BASE && vEquals(BaseLocation, Task->TaskLocation))
|
||||||
|
{
|
||||||
|
Task->bTaskIsUrgent = bIsUrgent;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AITASK_ClearBotTask(pBot, Task);
|
||||||
|
|
||||||
|
Task->TaskType = TASK_ASSAULT_MARINE_BASE;
|
||||||
|
Task->TaskLocation = BaseLocation;
|
||||||
|
Task->bTaskIsUrgent = bIsUrgent;
|
||||||
}
|
}
|
|
@ -47,6 +47,8 @@ bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTas
|
||||||
bool AITASK_IsMarineSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
bool AITASK_IsMarineSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||||
bool AITASK_IsAlienSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
bool AITASK_IsAlienSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||||
|
|
||||||
|
bool AITASK_IsAssaultMarineBaseTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||||
|
|
||||||
bool AITASK_IsAlienGetHealthTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
bool AITASK_IsAlienGetHealthTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||||
bool AITASK_IsAlienHealTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
bool AITASK_IsAlienHealTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||||
|
|
||||||
|
@ -67,6 +69,7 @@ void AITASK_SetReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task,
|
||||||
void AITASK_SetReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const AvHAIDeployableStructureType FirstStructureType, bool bIsUrgent);
|
void AITASK_SetReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const AvHAIDeployableStructureType FirstStructureType, bool bIsUrgent);
|
||||||
void AITASK_SetSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const Vector WaitLocation, bool bIsUrgent);
|
void AITASK_SetSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const Vector WaitLocation, bool bIsUrgent);
|
||||||
void AITASK_SetMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, bool bIsUrgent);
|
void AITASK_SetMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, bool bIsUrgent);
|
||||||
|
void AITASK_SetAssaultMarineBaseTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, Vector BaseLocation, bool bIsUrgent);
|
||||||
void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const 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_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 AITASK_SetGetHealthTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* HealingSource, const bool bIsUrgent);
|
||||||
|
@ -90,6 +93,8 @@ void MarineProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||||
void MarineProgressCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
void MarineProgressCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||||
void BotProgressWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
void BotProgressWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||||
|
|
||||||
|
void BotProgressAssaultMarineBaseTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||||
|
|
||||||
void AIPlayerBuildStructure(AvHAIPlayer* pBot, edict_t* BuildTarget);
|
void AIPlayerBuildStructure(AvHAIPlayer* pBot, edict_t* BuildTarget);
|
||||||
|
|
||||||
void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||||
|
|
Loading…
Reference in a new issue