Compare commits

..

No commits in common. "develop" and "v3.3b9" have entirely different histories.

43 changed files with 1703 additions and 5524 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.

View file

@ -14,10 +14,6 @@ MaxAIMatchTime=90
# 2 = When the round has started (after countdown)
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 ###

View file

@ -842,8 +842,6 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
}
bool bOffMeshChanged = false;
if (m_nupdate == 0)
{
for (int i = 0; i < m_params.maxOffMeshConnections; ++i)
@ -856,7 +854,6 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
navmesh->baseOffMeshLinks(con);
navmesh->GlobalOffMeshLinks(con);
con->state = DT_OFFMESH_CLEAN;
bOffMeshChanged = true;
}
if (con->state == DT_OFFMESH_REMOVING)
@ -872,7 +869,7 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
}
if (upToDate)
*upToDate = m_nupdate == 0 && m_nreqs == 0 && m_nOffMeshReqs == 0 && !bOffMeshChanged;
*upToDate = m_nupdate == 0 && m_nreqs == 0 && m_nOffMeshReqs == 0;
return status;
}

File diff suppressed because it is too large Load diff

View file

@ -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
AvHAIBuildableStructure* AICOMM_DeployStructure(AvHAIPlayer* pBot, const AvHAIDeployableStructureType StructureToDeploy, const Vector Location, StructurePurpose Purpose = STRUCTURE_PURPOSE_GENERAL, bool bPlacedByHuman = false);
bool AICOMM_DeployStructure(AvHAIPlayer* pBot, const AvHAIDeployableStructureType StructureToDeploy, const Vector Location, StructurePurpose Purpose = STRUCTURE_PURPOSE_GENERAL);
bool AICOMM_DeployItem(AvHAIPlayer* pBot, const AvHAIDeployableItemType ItemToDeploy, const Vector Location);
bool AICOMM_UpgradeStructure(AvHAIPlayer* pBot, AvHAIBuildableStructure* StructureToUpgrade);
bool AICOMM_ResearchTech(AvHAIPlayer* pBot, AvHAIBuildableStructure* StructureToResearch, AvHMessageID Research);
@ -27,29 +27,34 @@ bool AICOMM_IssueSiegeHiveOrder(AvHAIPlayer* pBot, edict_t* Recipient, const AvH
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, Vector OrderLocation, 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);
void AICOMM_UpdatePlayerOrders(AvHAIPlayer* pBot);
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);
void AICOMM_IssueOrderForAssignedJob(AvHAIPlayer* pBot, ai_commander_order* Order);
void AICOMM_ClearAction(commander_action* Action);
bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot);
bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot);
bool AICOMM_CheckForNextRecycleAction(AvHAIPlayer* pBot);
bool AICOMM_CheckForNextResearchAction(AvHAIPlayer* pBot);
bool AICOMM_CheckForNextSupplyAction(AvHAIPlayer* pBot);
Vector AICOMM_GetNextScanLocation(AvHAIPlayer* pBot);
void AICOMM_SetDropHealthAction(AvHAIPlayer* pBot, commander_action* Action, edict_t* Recipient);
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);
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);
void AICOMM_CheckNewRequests(AvHAIPlayer* pBot);
bool AICOMM_IsRequestValid(ai_commander_request* Request);
@ -66,30 +71,4 @@ bool AICOMM_ShouldBeacon(AvHAIPlayer* pBot);
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

View file

@ -12,17 +12,12 @@ BotFillTiming CurrentBotFillTiming = FILLTIMING_ALLHUMANS;
float MaxAIMatchTimeMinutes = 90.0f;
float RelocationChance = 0.1f;
std::unordered_map<std::string, TeamSizeDefinitions> TeamSizeMap;
bot_skill BotSkillLevels[4];
std::vector<AvHMessageID> ChamberSequence;
std::default_random_engine rng;
bool bRNGSeeded = false;
string DefaultBotNames[MAX_PLAYERS] = { "MrRobot",
"Wall-E",
"BeepBoop",
@ -95,16 +90,6 @@ bool CONFIG_IsOnosAllowed()
return avh_botallowonos.value > 0;
}
bool CONFIG_IsRelocationAllowed()
{
return RelocationChance > 0.0f;
}
float CONFIG_GetRelocationChance()
{
return RelocationChance;
}
float CONFIG_GetMaxStuckTime()
{
return avh_botmaxstucktime.value;
@ -187,6 +172,8 @@ void CONFIG_PopulateBotNames()
if (BotNames.size() > 2)
{
auto rng = std::default_random_engine{};
rng.seed(time(0));
std::shuffle(begin(BotNames), end(BotNames), rng);
}
@ -200,6 +187,8 @@ void CONFIG_PopulateBotNames()
if (DefaultNames.size() > 2)
{
auto rng = std::default_random_engine{};
rng.seed(time(0));
std::shuffle(begin(DefaultNames), end(DefaultNames), rng);
}
@ -273,13 +262,9 @@ void CONFIG_ParseConfigFile()
ChamberSequence.push_back(ALIEN_BUILD_MOVEMENT_CHAMBER);
ChamberSequence.push_back(ALIEN_BUILD_SENSORY_CHAMBER);
if (!bRNGSeeded)
{
srand(time(0));
rng.seed(time(0));
bRNGSeeded = true;
}
std::srand(time(0));
auto rng = std::default_random_engine{};
rng.seed(time(0));
std::shuffle(std::begin(ChamberSequence), std::end(ChamberSequence), rng);
string BotConfigFile = string(getModDirectory()) + "/nsbots.ini";
@ -343,14 +328,6 @@ void CONFIG_ParseConfigFile()
continue;
}
if (!stricmp(keyChar, "RelocationChance"))
{
float RelocationValue = std::stof(value.c_str());
RelocationChance = RelocationValue;
continue;
}
if (!stricmp(keyChar, "MaxAIMatchTime"))
{
float MaxMinutes = std::stof(value.c_str());
@ -664,11 +641,7 @@ void CONFIG_RegenerateIniFile()
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, "# 2 = When the round has started (after countdown)\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, "BotFillTiming=1\n\n\n");
fprintf(NewConfigFile, "### Skill Settings ###\n\n");

View file

@ -43,9 +43,6 @@ bool CONFIG_IsLerkAllowed();
bool CONFIG_IsFadeAllowed();
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)
float CONFIG_GetMaxStuckTime();

View file

@ -136,7 +136,7 @@ typedef enum
STRUCTURE_ALIEN_OFFENCECHAMBER = 1u << 19,
SEARCH_ALL_MARINE_STRUCTURES = 0xFFF,
SEARCH_ALL_ALIEN_STRUCTURES = (STRUCTURE_ALIEN_HIVE | STRUCTURE_ALIEN_RESTOWER | STRUCTURE_ALIEN_DEFENCECHAMBER | STRUCTURE_ALIEN_SENSORYCHAMBER | STRUCTURE_ALIEN_MOVEMENTCHAMBER | STRUCTURE_ALIEN_OFFENCECHAMBER),
SEARCH_ALL_ALIEN_STRUCTURES = 0xFC000,
SEARCH_ANY_RES_TOWER = (STRUCTURE_MARINE_RESTOWER | STRUCTURE_ALIEN_RESTOWER),
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)
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?
char HiveName[64] = {'\0'};
char HiveName[64];
} AvHAIHiveDefinition;
// A nav profile combines a nav mesh reference (indexed into NavMeshes) and filters to determine how a bot should find paths
@ -341,7 +341,6 @@ typedef struct _AVH_AI_GUARD_INFO
typedef struct _AVH_AI_BUILDABLE_STRUCTURE
{
AvHBaseBuildable* EntityRef = nullptr;
int EntIndex = -1;
edict_t* edict = nullptr; // Reference to structure edict
Vector Location = g_vecZero; // origin of the structure edict
float healthPercent = 0.0f; // Current health of the building
@ -357,11 +356,9 @@ 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
StructurePurpose Purpose = STRUCTURE_PURPOSE_NONE;
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 IsCompleted() { return (StructureStatusFlags & STRUCTURE_STATUS_COMPLETED); }
bool IsIdle() { return !(StructureStatusFlags & STRUCTURE_STATUS_RESEARCHING); }
} AvHAIBuildableStructure;
@ -375,8 +372,6 @@ typedef struct _DROPPED_MARINE_ITEM
unsigned int TeamBReachabilityFlags = AI_REACHABILITY_NONE;
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
bool IsValid() { return !FNullEnt(edict) && !edict->free && !(edict->v.flags & EF_NODRAW) && edict->v.deadflag == DEAD_NO; }
} 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
@ -420,7 +415,7 @@ typedef enum
TASK_REINFORCE_STRUCTURE,
TASK_SECURE_HIVE,
TASK_PLACE_MINE,
TASK_ASSAULT_MARINE_BASE
TASK_ATTACK_BASE
}
BotTaskType;
@ -474,31 +469,6 @@ enum NavDoorType
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
typedef struct _BOT_PATH_NODE
{
@ -637,7 +607,6 @@ 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
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
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?
@ -652,7 +621,7 @@ typedef struct _NAV_STATUS
float NextForceRecalc = 0.0f; // If set, then the bot will force-recalc its current path
bool bZig; // Is the bot zigging (moving RIGHT), or zagging (moving LEFT)?
bool bZig; // Is the bot zigging, or zagging?
float NextZigTime; // Controls how frequently they zig or zag
nav_profile NavProfile;
@ -665,16 +634,61 @@ typedef struct _NAV_STATUS
AvHAIPlayerMoveTask MovementTask;
} 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
{
ORDERPURPOSE_NONE,
ORDERPURPOSE_SECURE_HIVE,
ORDERPURPOSE_SIEGE_HIVE,
ORDERPURPOSE_SECURE_RESNODE,
ORDERPURPOSE_BUILD_MAINBASE,
ORDERPURPOSE_BUILD_SIEGE,
ORDERPURPOSE_BUILD_OUTPOST,
ORDERPURPOSE_BUILD_GUARDPOST
ORDERPURPOSE_SECURE_RESNODE
} AvHAIOrderPurpose;
typedef struct _AI_COMMANDER_ORDER
@ -768,14 +782,11 @@ typedef struct AVH_AI_PLAYER
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 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
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
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 ViewInterpolationSpeed = 0.0f; // How fast should the bot turn its view? Depends on distance to turn
float ViewInterpStartedTime = 0.0f; // Used for interpolation
@ -801,10 +812,6 @@ typedef struct AVH_AI_PLAYER
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;
typedef struct _AVH_AI_SQUAD
@ -813,7 +820,6 @@ typedef struct _AVH_AI_SQUAD
vector<AvHAIPlayer*> SquadMembers; // Which bots are assigned to this
Vector SquadGatherLocation = g_vecZero; // Where should the squad gather before attempting 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
bool bExecuteObjective = false; // Are we at the gather or execute phase?

View file

@ -342,17 +342,7 @@ void AIDEBUG_DrawPath(edict_t* OutputPlayer, vector<bot_path_node>& path, float
UTIL_DrawLine(OutputPlayer, FromLoc, ToLoc, DrawTime, 255, 128, 128);
break;
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;
}
}
@ -360,16 +350,9 @@ void AIDEBUG_DrawPath(edict_t* OutputPlayer, vector<bot_path_node>& path, float
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_COORD(start.x);
WRITE_COORD(start.y);
@ -395,18 +378,12 @@ void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end)
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);
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_COORD(start.x);
WRITE_COORD(start.y);
@ -432,18 +409,12 @@ 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)
{
if (FNullEnt(pEntity) || pEntity->free) { return; }
int timeTenthSeconds = (int)ceilf(drawTimeSeconds * 10.0f);
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_COORD(start.x);
WRITE_COORD(start.y);
@ -469,15 +440,9 @@ 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)
{
if (FNullEnt(pEntity) || pEntity->free)
{
MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY);
}
else
{
MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity);
}
if (FNullEnt(pEntity) || pEntity->free) { return; }
MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity);
WRITE_BYTE(TE_BEAMPOINTS);
WRITE_COORD(start.x);
WRITE_COORD(start.y);
@ -673,64 +638,11 @@ 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)
{
switch (TaskType)
{
case TASK_ATTACK:
return "Attack";
case TASK_BUILD:
return "Build";
@ -768,8 +680,8 @@ char* UTIL_TaskTypeToChar(const BotTaskType TaskType)
return "Touch Trigger";
case TASK_WELD:
return "Weld Target";
case TASK_ASSAULT_MARINE_BASE:
return "Assault Marine Base";
case TASK_ATTACK_BASE:
return "Attack Enemy Base";
default:
return "None";
}

View file

@ -60,7 +60,6 @@ void UTIL_ClearLocalizations();
void UTIL_LocalizeText(const char* InputText, string& OutputText);
char* UTIL_TaskTypeToChar(const BotTaskType TaskType);
char* UTIL_StructTypeToChar(const AvHAIDeployableStructureType StructureType);
char* UTIL_BotRoleToChar(const AvHAIBotRole Role);

File diff suppressed because it is too large Load diff

View file

@ -220,7 +220,7 @@ void NewMove(AvHAIPlayer* pBot);
// Returns true if the bot has completed the current movement along their path
bool HasBotReachedPathPoint(const AvHAIPlayer* pBot);
bool HasBotCompletedLadderMove(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 HasBotCompletedWalkMove(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 HasBotCompletedJumpMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
@ -495,8 +495,6 @@ nav_door* UTIL_GetNavDoorByEdict(const edict_t* DoorEdict);
nav_door* UTIL_GetClosestLiftToPoints(const Vector StartPoint, const Vector EndPoint);
AvHAIOffMeshConnection* UTIL_GetOffMeshConnectionForLift(nav_door* LiftRef);
bool UTIL_IsTileCacheUpToDate();
Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDistanceFromWall);
void UTIL_PopulateBaseNavProfiles();

File diff suppressed because it is too large Load diff

View file

@ -26,9 +26,9 @@ static const float f_ffwidth = f_ffheight * BOT_ASPECT_RATIO;
void BotJump(AvHAIPlayer* pBot);
void BotSuicide(AvHAIPlayer* pBot);
void BotLookAt(AvHAIPlayer* pBot, Vector NewLocation, bool bSnap = false);
void BotLookAt(AvHAIPlayer* pBot, edict_t* target, bool bSnap = false);
void BotMoveLookAt(AvHAIPlayer* pBot, const Vector target, bool bSnap = false);
void BotLookAt(AvHAIPlayer* pBot, Vector NewLocation);
void BotLookAt(AvHAIPlayer* pBot, edict_t* target);
void BotMoveLookAt(AvHAIPlayer* pBot, const Vector target);
void BotDirectLookAt(AvHAIPlayer* pBot, Vector target);
bool BotUseObject(AvHAIPlayer* pBot, edict_t* Target, bool bContinuous);
@ -159,8 +159,6 @@ void AIPlayerHearEnemy(AvHAIPlayer* pBot, edict_t* HeardEnemy, float SoundVolume
int BotGetNextEnemyTarget(AvHAIPlayer* pBot);
void OnBotTeleport(AvHAIPlayer* pBot);
AvHMessageID AlienGetDesiredUpgrade(AvHAIPlayer* pBot, HiveTechStatus DesiredTech);
AvHAICombatStrategy GetBotCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_status* CurrentEnemy);
@ -190,6 +188,4 @@ void DEBUG_PrintBotDebugInfo(edict_t* OutputPlayer, AvHAIPlayer* pBot);
void DEBUG_PrintTaskInfo(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

View file

@ -24,7 +24,6 @@ extern cvar_t avh_botusemapdefaults;
extern cvar_t avh_botcommandermode;
extern cvar_t avh_botdebugmode;
extern cvar_t avh_botskill;
extern cvar_t avh_limitteams;
float LastAIPlayerCountUpdate = 0.0f;
@ -225,11 +224,8 @@ void AIMGR_UpdateFillTeams()
bRemoveB = !bRemoveB;
}
}
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)
if (TeamSizeA < NumDesiredTeamA && TeamSizeA <= TeamSizeB)
{
// 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; }
@ -246,7 +242,7 @@ void AIMGR_UpdateFillTeams()
}
}
if (TeamSizeB < NumDesiredTeamB && bCanAddToTeamB)
if (TeamSizeB < NumDesiredTeamB && TeamSizeB <= TeamSizeA)
{
// 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; }
@ -644,10 +640,6 @@ void AIMGR_UpdateAIPlayers()
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 (IsPlayerCommander(bot->Edict))
@ -843,7 +835,7 @@ int AIMGR_GetNumAIPlayersWithRoleOnTeam(AvHTeamNumber Team, AvHAIBotRole Role, A
{
if (&(*it) == IgnoreAIPlayer) { continue; }
if (it->Player->GetTeam() == Team && IsPlayerActiveInGame((*it).Edict))
if (it->Player->GetTeam() == Team)
{
if (it->BotRole == Role)
{
@ -929,20 +921,15 @@ void AIMGR_ResetRound()
bool bTileCacheFullyUpdated = UTIL_UpdateTileCache();
int NumAttempts = 0;
while (!bTileCacheFullyUpdated && NumAttempts < 30)
while (!bTileCacheFullyUpdated)
{
bTileCacheFullyUpdated = UTIL_UpdateTileCache();
NumAttempts++;
}
bHasRoundStarted = false;
bMapDataInitialised = true;
CountdownStartedTime = 0.0f;
AITAC_DetermineRelocationEnabled();
}
void AIMGR_ReloadNavigationData()
@ -1320,64 +1307,6 @@ void AIMGR_SetDebugAIPlayer(edict_t* SpectatingPlayer, edict_t* AIPlayer)
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
void AIMGR_ReceiveCommanderRequest(AvHTeamNumber Team, edict_t* Requestor, const char* Request)
@ -1440,12 +1369,9 @@ void AIMGR_OnBotEnabled()
bool bTileCacheFullyUpdated = UTIL_UpdateTileCache();
int NumAttempts = 0;
while (!bTileCacheFullyUpdated && NumAttempts < 30)
while (!bTileCacheFullyUpdated)
{
bTileCacheFullyUpdated = UTIL_UpdateTileCache();
NumAttempts++;
}
}
// Figure out the current game status
@ -1664,9 +1590,4 @@ void AIMGR_SetFrameDelta(float NewValue)
float AIMGR_GetFrameDelta()
{
return CurrentFrameDelta;
}
float AIMGR_GetMatchLength()
{
return (gpGlobals->time - GetGameRules()->GetTimeGameStarted());
}

View file

@ -97,8 +97,6 @@ AvHClassType AIMGR_GetTeamType(const AvHTeamNumber Team);
AvHTeamNumber AIMGR_GetTeamANumber();
AvHTeamNumber AIMGR_GetTeamBNumber();
float AIMGR_GetMatchLength();
AvHTeam* AIMGR_GetTeamRef(const AvHTeamNumber Team);
// Returns all NS AI players. Does not include third-party bots
@ -137,6 +135,4 @@ void AIMGR_ProcessPendingSounds();
void AIMGR_SetFrameDelta(float NewValue);
float AIMGR_GetFrameDelta();
void AIDEBUG_DisplayTeamGoals();
#endif

View file

@ -2,7 +2,6 @@
#include "AvHAIPlayerUtil.h"
#include "AvHAIPlayer.h"
#include "AvHAIHelper.h"
#include "AvHAIWeaponHelper.h"
#include "AvHPlayerUpgrade.h"
#include "AvHAIMath.h"
@ -74,7 +73,6 @@ bool IsPlayerClimbingWall(const edict_t* Player)
bool IsPlayerInReadyRoom(const edict_t* Player)
{
if (FNullEnt(Player)) { return false; }
return Player->v.playerclass == PLAYMODE_READYROOM;
}
@ -154,7 +152,7 @@ bool IsPlayerOnLadder(const edict_t* Player)
Vector NearestPointOnLadder = UTIL_GetClosestPointOnEntityToLocation(Player->v.origin, NearestLadder);
Vector NearestPointOnPlayer = UTIL_GetClosestPointOnEntityToLocation(NearestPointOnLadder, Player);
return (vDist3DSq(NearestPointOnLadder, NearestPointOnPlayer) <= sqrf(2.0f));
return (vDist2DSq(NearestPointOnLadder, NearestPointOnPlayer) <= sqrf(4.0f));
}
return (Player->v.movetype == MOVETYPE_FLY);
@ -170,11 +168,6 @@ bool IsPlayerMotionTracked(const edict_t* Player)
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)
{
return (Player->v.fuser3 * 0.001f);
@ -642,10 +635,7 @@ bool PlayerHasEquipment(edict_t* Player)
bool PlayerHasSpecialWeapon(const AvHPlayer* Player)
{
if (!IsPlayerMarine(Player)) { return false; }
AvHAIWeapon PrimaryWeaponType = UTIL_GetPlayerPrimaryWeapon(Player);
return PrimaryWeaponType != WEAPON_INVALID && PrimaryWeaponType != WEAPON_MARINE_MG;
return !PlayerHasWeapon(Player, WEAPON_MARINE_MG);
}
bool UTIL_PlayerHasLOSToEntity(const edict_t* Player, const edict_t* Target, const float MaxRange, const bool bUseHullSweep)
@ -1001,38 +991,6 @@ Vector UTIL_GetNearestSurfaceNormal(Vector SearchLocation)
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)
{
TraceResult result;

View file

@ -67,8 +67,6 @@ bool IsPlayerGestating(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?
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
bool IsPlayerOnLadder(const edict_t* Player);
// Is the player an onos under the effect of charge?
@ -174,10 +172,6 @@ Vector UTIL_GetNearestLadderTopPoint(edict_t* pEdict);
Vector UTIL_GetNearestLadderTopPoint(const Vector SearchLocation);
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);
#endif

View file

@ -18,7 +18,6 @@
#include "AvHAIConstants.h"
#include "AvHAIPlayerManager.h"
#include "AvHAIConfig.h"
#include "AvHAICommander.h"
#include "AvHGamerules.h"
#include "AvHServerUtil.h"
@ -55,11 +54,6 @@ unsigned int ItemRefreshFrame = 0;
Vector TeamAStartingLocation = 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_profile BaseNavProfiles[MAX_NAV_PROFILES]; // Array of nav profiles
@ -74,9 +68,6 @@ float LastSeenLerkTeamBTime = 0.0f;
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> Result;
@ -633,24 +624,20 @@ AvHAIBuildableStructure* AITAC_FindFurthestDeployableFromLocationByRef(const Vec
return Result;
}
AvHAIDroppedItem AITAC_GetDroppedItemRefFromEdict(edict_t* ItemEdict)
AvHAIDroppedItem* AITAC_GetDroppedItemRefFromEdict(edict_t* ItemEdict)
{
AvHAIDroppedItem Result;
if (FNullEnt(ItemEdict)) { return Result; }
if (FNullEnt(ItemEdict)) { return nullptr; }
int EntIndex = ENTINDEX(ItemEdict);
if (EntIndex < 0) { return Result; }
if (EntIndex < 0) { return nullptr; }
Result = MarineDroppedItemMap[EntIndex];
return Result;
return &MarineDroppedItemMap[EntIndex];
}
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;
AvHAIDroppedItem* Result = NULL;
float CurrMinDist = 0.0f;
float MinDistSq = sqrf(MinRadius);
@ -676,9 +663,9 @@ AvHAIDroppedItem AITAC_FindClosestItemToLocation(const Vector& Location, const A
float DistSq = (bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && (!Result.IsValid() || DistSq < CurrMinDist))
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && (!Result || DistSq < CurrMinDist))
{
Result = it.second;
Result = &it.second;
CurrMinDist = DistSq;
}
@ -879,16 +866,6 @@ AvHAIBuildableStructure AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer*
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)
{
AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber();
@ -1090,20 +1067,6 @@ 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()
{
Hives.clear();
@ -1128,17 +1091,18 @@ void AITAC_PopulateHiveData()
NewHive.FloorLocation = UTIL_GetFloorUnderEntity(NewHive.HiveEdict); // Some hives are suspended in the air, this is the floor location directly beneath it
string HiveName = AITAC_GetLocationName(NewHive.Location);
string HiveName;
if (HiveName.empty())
string theLocationName;
if (AvHSHUGetNameOfLocation(GetGameRules()->GetInfoLocations(), NewHive.Location, theLocationName))
{
sprintf(NewHive.HiveName, "Hive");
}
else
{
sprintf(NewHive.HiveName, HiveName.c_str(), "%s");
UTIL_LocalizeText(theLocationName.c_str(), theLocationName);
HiveName = theLocationName;
}
sprintf(NewHive.HiveName, HiveName.c_str(), "%s");
Hives.push_back(NewHive);
END_FOR_ALL_ENTITIES(kesTeamHive)
@ -1146,11 +1110,6 @@ void AITAC_PopulateHiveData()
void AITAC_RefreshHiveData()
{
if (ResourceNodes.size() == 0)
{
AITAC_PopulateResourceNodes();
}
if (Hives.size() == 0)
{
AITAC_PopulateHiveData();
@ -1225,36 +1184,6 @@ 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)
{
if (vIsZero(TeamAStartingLocation) || vIsZero(TeamBStartingLocation))
@ -2492,7 +2421,6 @@ AvHAIBuildableStructure* AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
if (StructureRef->LastSeen == 0)
{
StructureRef->Location = BuildingEdict->v.origin;
StructureRef->EntIndex = EntIndex;
StructureRef->edict = BuildingEdict;
StructureRef->healthPercent = 1.0f;
StructureRef->EntityRef = nullptr;
@ -2521,7 +2449,6 @@ AvHAIBuildableStructure* AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
{
StructureRef->EntityRef = BaseBuildable;
StructureRef->edict = BuildingEdict;
StructureRef->EntIndex = EntIndex;
StructureRef->OffMeshConnections.clear();
StructureRef->Obstacles.clear();
@ -2658,7 +2585,7 @@ AvHAIBuildableStructure* AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
if (NearestHive)
{
if (NearestHive->Status == HIVE_STATUS_UNBUILT && vDist2DSq(NearestHive->FloorLocation, StructureRef->Location) < sqrf(UTIL_MetresToGoldSrcUnits(15.0f)))
if (NearestHive->Status == HIVE_STATUS_UNBUILT && vDist2DSq(NearestHive->FloorLocation, StructureRef->Location) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
{
StructureRef->Purpose = STRUCTURE_PURPOSE_FORTIFY;
}
@ -2938,12 +2865,9 @@ void AITAC_ClearMapAIData(bool bInitialMapLoad)
AITAC_ClearStructureNavData();
int NumAttempts = 0;
while (!bTileCacheUpToDate && NumAttempts < 30)
while (!bTileCacheUpToDate)
{
UTIL_UpdateTileCache();
NumAttempts++;
}
}
else
@ -3162,6 +3086,7 @@ bool UTIL_ShouldStructureCollide(AvHAIDeployableStructureType StructureType)
{
case STRUCTURE_MARINE_INFANTRYPORTAL:
case STRUCTURE_MARINE_PHASEGATE:
case STRUCTURE_MARINE_TURRET:
case STRUCTURE_MARINE_DEPLOYEDMINE:
return false;
default:
@ -4454,6 +4379,7 @@ edict_t* AITAC_GetCommChair(AvHTeamNumber Team)
ChairFilter.DeployableTypes = STRUCTURE_MARINE_COMMCHAIR;
ChairFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
ChairFilter.DeployableTeam = Team;
ChairFilter.ReachabilityTeam = TEAM_IND;
vector<AvHAIBuildableStructure> CommChairs = AITAC_FindAllDeployables(ZERO_VECTOR, &ChairFilter);
@ -4465,10 +4391,8 @@ edict_t* AITAC_GetCommChair(AvHTeamNumber Team)
{
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
if (ChairRef->GetIdleAnimation() == 3)
if (ChairRef && ChairRef->GetIdleAnimation() == 3)
{
MainCommChair = ChairRef->edict();
}
@ -4835,16 +4759,11 @@ bool AITAC_ShouldBotBuildHive(AvHAIPlayer* pBot, AvHAIHiveDefinition** EligibleH
HiveCost += BALANCE_VAR(kGorgeCost);
}
if (pBot->Player->GetResources() < HiveCost - 10) { return false; }
if (pBot->Player->GetResources() < HiveCost) { return false; }
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
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
int NumHeavyHitters = AITAC_GetNumPlayersOnTeamOfClass(BotTeam, AVH_USER3_ALIEN_PLAYER4, nullptr) + AITAC_GetNumPlayersOnTeamOfClass(BotTeam, AVH_USER3_ALIEN_PLAYER5, nullptr);
@ -4860,8 +4779,6 @@ bool AITAC_ShouldBotBuildHive(AvHAIPlayer* pBot, AvHAIHiveDefinition** EligibleH
{
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 (OtherBot->Player->GetResources() >= BALANCE_VAR(kHiveCost) * 0.8f && OtherBot->Player->GetUser3() < pBot->Player->GetUser3()) { return false; }
}
@ -5396,8 +5313,6 @@ edict_t* AITAC_AlienFindNearestHealingSource(AvHTeamNumber Team, Vector SearchLo
edict_t* Result = nullptr;
float MinDist = 0.0f;
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(Team);
vector<AvHAIHiveDefinition*> AllTeamHives = AITAC_GetAllTeamHives(Team, true);
for (auto it = AllTeamHives.begin(); it != AllTeamHives.end(); it++)
@ -5405,8 +5320,6 @@ edict_t* AITAC_AlienFindNearestHealingSource(AvHTeamNumber Team, Vector SearchLo
float ThisDist = vDist2DSq((*it)->Location, SearchLocation);
// 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;
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
if (ThisDist <= 0.0f) { return (*it)->HiveEdict; }
@ -5433,8 +5346,6 @@ 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
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
if (ThisDist <= 0.0f) { return ThisDC.edict; }
@ -5451,11 +5362,6 @@ 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"
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);
@ -5601,16 +5507,15 @@ bool AITAC_IsBotPursuingSquadObjective(AvHAIPlayer* pBot, AvHAISquad* Squad)
if (!IsPlayerActiveInGame(pBot->Edict) || pBot->Player->GetTeam() != Squad->SquadTeam) { return false; }
// Bot no longer has this squad's objective as its primary task
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; }
if (pBot->PrimaryBotTask.TaskType != Squad->SquadObjective || pBot->PrimaryBotTask.TaskTarget != Squad->SquadTarget) { return false; }
// Bot is focused on the job at hand
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
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;
Vector TaskLocation = (!FNullEnt(pBot->CurrentTask->TaskTarget)) ? pBot->CurrentTask->TaskTarget->v.origin : pBot->CurrentTask->TaskLocation;
return vDist2DSq(BotTaskLocation, SquadTaskLocation) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f));
return vDist2DSq(TaskLocation, Squad->SquadTarget->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f));
}
void AITAC_ManageSquads()
@ -5620,7 +5525,7 @@ void AITAC_ManageSquads()
for (auto pIt = it->SquadMembers.begin(); pIt != it->SquadMembers.end();)
{
AvHAIPlayer* ThisPlayer = (*pIt);
if (!ThisPlayer || FNullEnt(ThisPlayer->Edict) || !AITAC_IsBotPursuingSquadObjective(ThisPlayer, &(*it)))
if (!AITAC_IsBotPursuingSquadObjective(ThisPlayer, &(*it)))
{
pIt = it->SquadMembers.erase(pIt);
}
@ -5653,9 +5558,7 @@ void AITAC_UpdateSquads()
{
vector<bot_path_node> TravelPath;
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));
dtStatus PathFindResult = FindPathClosestToPoint(GetBaseNavProfile(ONOS_BASE_NAV_PROFILE), AITAC_GetTeamStartingLocation(it->SquadTeam), UTIL_GetEntityGroundLocation(it->SquadTarget), TravelPath, UTIL_MetresToGoldSrcUnits(20.0f));
if (dtStatusSucceed(PathFindResult))
{
@ -5663,12 +5566,9 @@ void AITAC_UpdateSquads()
{
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, TargetLocation) > sqrf(UTIL_MetresToGoldSrcUnits(20.0f)))
if (vDist2DSq(pIt->Location, it->SquadTarget->v.origin) > sqrf(UTIL_MetresToGoldSrcUnits(20.0f)))
{
DeployableSearchFilter EnemyStuff;
EnemyStuff.DeployableTeam = AIMGR_GetEnemyTeam(it->SquadTeam);
@ -5756,48 +5656,6 @@ AvHAISquad* AITAC_GetSquadForObjective(AvHAIPlayer* pBot, edict_t* TaskTarget, B
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()
{
ActiveSquads.clear();
@ -5837,468 +5695,4 @@ Vector AITAC_GetGatherLocationForSquad(AvHAISquad* Squad)
}
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;
}

View file

@ -31,8 +31,6 @@ AvHAIBuildableStructure AITAC_GetDeployableFromEdict(const edict_t* Structure);
AvHAIBuildableStructure* AITAC_GetDeployableRefFromEdict(const edict_t* Structure);
AvHAIBuildableStructure AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter);
AvHAIBuildableStructure* AITAC_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);
void AITAC_PopulateHiveData();
void AITAC_RefreshHiveData();
@ -64,20 +62,15 @@ const AvHAIHiveDefinition* AITAC_GetNonEmptyHiveNearestLocation(const Vector Sea
Vector AITAC_GetCommChairLocation(AvHTeamNumber Team);
edict_t* AITAC_GetCommChair(AvHTeamNumber Team);
Vector AITAC_GetTeamOriginalStartLocation(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);
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);
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);
@ -215,26 +208,6 @@ void AITAC_UpdateSquads();
void AITAC_ManageSquads();
void AITAC_ClearSquads();
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_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

View file

@ -395,8 +395,8 @@ bool AITASK_IsTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
return AITASK_IsAlienSecureHiveTaskStillValid(pBot, Task);
}
}
case TASK_ASSAULT_MARINE_BASE:
return AITASK_IsAssaultMarineBaseTaskStillValid(pBot, Task);
case TASK_ATTACK_BASE:
return true;
case TASK_DEFEND:
return AITASK_IsDefendTaskStillValid(pBot, Task);
case TASK_WELD:
@ -441,11 +441,11 @@ bool AITASK_IsWeldTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
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.IsValid())
if (NearestWelder)
{
Task->TaskSecondaryTarget = NearestWelder.edict;
Task->TaskSecondaryTarget = NearestWelder->edict;
}
else
{
@ -875,32 +875,12 @@ bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTas
if (bActiveHiveWithoutTechExists) { return true; }
int NumMissing = 0;
AvHAIDeployableStructureType MissingStructure = AITAC_GetNextMissingUpgradeChamberForTeam(BotTeam, NumMissing);
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;
StructureFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER | ALIEN_BUILD_DEFENSE_CHAMBER | ALIEN_BUILD_MOVEMENT_CHAMBER | ALIEN_BUILD_SENSORY_CHAMBER;
StructureFilter.MaxSearchRadius = (IsEdictHive(Task->TaskTarget)) ? UTIL_MetresToGoldSrcUnits(10.0f) : UTIL_MetresToGoldSrcUnits(5.0f);
StructureFilter.DeployableTeam = pBot->Player->GetTeam();
vector<AvHAIBuildableStructure> AllNearbyStructures = AITAC_FindAllDeployables(ReinforceLocation, &StructureFilter);
vector<AvHAIBuildableStructure> AllNearbyStructures = AITAC_FindAllDeployables(Task->TaskTarget->v.origin, &StructureFilter);
bool bUnfinishedStructureExists = false;
int NumOffenceChambers = 0;
@ -936,11 +916,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
if (NumOffenceChambers < 3
if (NumOffenceChambers < 2
|| (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_DEFENSE_CHAMBER) && NumDefenceChambers < 2)
|| (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_MOVEMENT_CHAMBER) && NumMovementChambers < 1)
|| (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_SENSORY_CHAMBER) && NumSensoryChambers < 1)
|| (IsPlayerGorge(pBot->Edict) && bUnfinishedStructureExists && vDist2DSq(pBot->Edict->v.origin, ReinforceLocation) <= sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
|| (IsPlayerGorge(pBot->Edict) && bUnfinishedStructureExists && vDist2DSq(pBot->Edict->v.origin, Task->TaskTarget->v.origin) <= sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
) { return true; }
// Otherwise, are there any enemy structures lying around we could clear out?
@ -954,9 +934,9 @@ bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTas
EnemyStuff.DeployableTeam = AIMGR_GetEnemyTeam(BotTeam);
EnemyStuff.ReachabilityTeam = BotTeam;
EnemyStuff.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
EnemyStuff.MaxSearchRadius = SearchRadius;
EnemyStuff.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
return AITAC_DeployableExistsAtLocation(ReinforceLocation, &EnemyStuff);
return AITAC_DeployableExistsAtLocation(Task->TaskTarget->v.origin, &EnemyStuff);
}
bool AITASK_IsAlienSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
@ -981,24 +961,6 @@ bool AITASK_IsAlienSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask*
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)
{
if (!Task || FNullEnt(Task->TaskTarget) || IsPlayerAlien(pBot->Edict)) { return false; }
@ -1006,7 +968,7 @@ bool AITASK_IsMarineSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask*
AvHAIHiveDefinition* HiveToSecure = AITAC_GetHiveFromEdict(Task->TaskTarget);
if (!HiveToSecure || HiveToSecure->Status != HIVE_STATUS_UNBUILT) { return false; }
// A marine bot will consider their "secure hive" task completed if the following structures have been fully built:
// Phase gate (only if tech available)
// Turret factory (regular or advanced)
@ -1015,12 +977,6 @@ bool AITASK_IsMarineSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask*
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 bHasPhaseGate = false;
@ -1290,9 +1246,9 @@ void BotProgressMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
}
float DistToPlaceLocation = vDist3DSq(pBot->Edict->v.origin, Task->TaskLocation);
float DistToPlaceLocation = vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation);
if (DistToPlaceLocation < sqrf(50.0f))
if (DistToPlaceLocation < sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
{
pBot->DesiredCombatWeapon = WEAPON_MARINE_MINES;
}
@ -1369,23 +1325,15 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (FNullEnt(Task->TaskTarget)) { return; }
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
{
pBot->Impulse = 0;
return;
}
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
// 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)
{
pBot->Impulse = 0;
Task->TaskStartedTime = gpGlobals->time;
Task->TaskLocation = ZERO_VECTOR;
Task->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_NONE;
}
if (gpGlobals->time - Task->TaskStartedTime < 0.5f) { return; }
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
Vector ReinforceLocation = UTIL_ProjectPointToNavmesh(UTIL_GetEntityGroundLocation(Task->TaskTarget), pBot->BotNavInfo.NavProfile);
@ -1407,7 +1355,7 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
DeployableSearchFilter StructureFilter;
StructureFilter.DeployableTeam = BotTeam;
StructureFilter.MaxSearchRadius = SearchRadius * 1.25f;
StructureFilter.MaxSearchRadius = SearchRadius;
StructureFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
int NumOCs = AITAC_GetNumDeployablesNearLocation(ReinforceLocation, &StructureFilter);
@ -1462,14 +1410,6 @@ 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 (vIsZero(Task->TaskLocation))
@ -1816,7 +1756,7 @@ void BotProgressAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
AvHTurret* TurretRef = dynamic_cast<AvHTurret*>(CBaseEntity::Instance(Task->TaskTarget));
if (TurretRef && TurretRef->GetIsValidTarget(pBot->Player) && !vIsZero(GetVisiblePointOnPlayerFromObserver(Task->TaskTarget, pBot->Edict)))
if (TurretRef && TurretRef->GetIsValidTarget(pBot->Player))
{
if (vIsZero(pBot->LastSafeLocation))
{
@ -1824,33 +1764,13 @@ void BotProgressAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL);
BotLookAt(pBot, Task->TaskTarget);
return;
}
return;
}
}
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 we were ducking before then keep ducking
@ -1885,13 +1805,16 @@ void BotProgressAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
Vector RightDir = UTIL_GetCrossProduct(EnemyOrientation, UP_VECTOR);
Vector EvasiveDir = GetZigZagDirection(pBot, Task->TaskTarget, nullptr);
pBot->desiredMovementDir = (pBot->BotNavInfo.bZig) ? UTIL_GetVectorNormal2D(RightDir) : UTIL_GetVectorNormal2D(-RightDir);
if (!vIsZero(EvasiveDir))
// Let's get ziggy with it
if (gpGlobals->time > pBot->BotNavInfo.NextZigTime)
{
pBot->desiredMovementDir = EvasiveDir;
BotMovementInputs(pBot);
pBot->BotNavInfo.bZig = !pBot->BotNavInfo.bZig;
pBot->BotNavInfo.NextZigTime = gpGlobals->time + frandrange(0.5f, 1.0f);
}
BotMovementInputs(pBot);
}
return;
@ -1987,34 +1910,9 @@ void BotProgressTakeCommandTask(AvHAIPlayer* pBot)
// Don't take command if we already have a commander
if (pBot->Player->GetCommander()) { return; }
edict_t* CommChair = nullptr;
edict_t* CommChair = AITAC_GetCommChair(pBot->Player->GetTeam());
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; }
if (!CommChair) { return; }
float DistFromChair = vDist2DSq(pBot->Edict->v.origin, CommChair->v.origin);
@ -2108,7 +2006,7 @@ void BotProgressEvolveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (FNullEnt(Task->TaskTarget))
{
Task->TaskLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), pBot->CurrentFloorPosition, 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))
{
@ -2126,11 +2024,11 @@ void BotProgressEvolveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
else
{
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], pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(Task->TaskTarget), UTIL_MetresToGoldSrcUnits(10.0f));
if (vIsZero(Task->TaskLocation))
{
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], UTIL_GetEntityGroundLocation(Task->TaskTarget), UTIL_MetresToGoldSrcUnits(10.0f));
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], Task->TaskLocation, UTIL_MetresToGoldSrcUnits(5.0f));
}
}
}
@ -2208,7 +2106,6 @@ void AlienProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
// We tried and failed to place the structure
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
{
pBot->Impulse = 0;
return;
}
@ -2222,8 +2119,6 @@ void AlienProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
edict_t* LinkedEdict = Task->ActiveBuildInfo.LinkedStructure->edict;
Task->TaskTarget = LinkedEdict;
if (UTIL_StructureIsFullyBuilt(LinkedEdict)) { return; }
if (IsPlayerInUseRange(pBot->Edict, LinkedEdict))
@ -2291,11 +2186,7 @@ void BotAlienPlaceChamber(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, AvHAIDeploya
{
if (vIsZero(Task->TaskLocation) || DesiredStructure == STRUCTURE_NONE) { return; }
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
{
pBot->Impulse = 0;
return;
}
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
float DistFromBuildLocation = vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation);
@ -2686,9 +2577,6 @@ void BotProgressTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
}
break;
case TASK_ASSAULT_MARINE_BASE:
BotProgressAssaultMarineBaseTask(pBot, Task);
break;
default:
break;
@ -2706,11 +2594,11 @@ void BotProgressWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
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.IsValid())
if (Welder)
{
Task->TaskSecondaryTarget = Welder.edict;
Task->TaskSecondaryTarget = Welder->edict;
}
}
@ -2810,9 +2698,6 @@ void AlienProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
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)
{
EnemyStuffFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
@ -2913,8 +2798,6 @@ void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
bool bKeyStructureBuilt = false;
AvHAIBuildableStructure KeyOutpostStructure;
AvHAIBuildableStructure StructureToBuild;
float MinDist = 0.0f;
@ -2924,7 +2807,6 @@ void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if ((ThisStructure.StructureStatusFlags & STRUCTURE_STATUS_COMPLETED) && (ThisStructure.StructureType & (STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_PHASEGATE)))
{
KeyOutpostStructure = ThisStructure;
bKeyStructureBuilt = true;
}
@ -2987,10 +2869,10 @@ void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
DeployableSearchFilter EnemyStructures;
EnemyStructures.DeployableTypes = SEARCH_ALL_STRUCTURES;
EnemyStructures.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
EnemyStructures.DeployableTeam = EnemyTeam;
EnemyStructures.ReachabilityTeam = BotTeam;
EnemyStructures.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
EnemyStructures.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
AvHAIBuildableStructure EnemyStructure = AITAC_FindClosestDeployableToLocation(Hive->FloorLocation, &EnemyStructures);
@ -3001,9 +2883,8 @@ void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
}
Vector OutpostLocation = (KeyOutpostStructure.IsValid()) ? KeyOutpostStructure.Location : Task->TaskLocation;
BotGuardLocation(pBot, OutpostLocation);
BotGuardLocation(pBot, Task->TaskLocation);
}
@ -3097,130 +2978,13 @@ 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
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->TaskLength = 30.0f;
}
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);
}
void BotGuardLocation(AvHAIPlayer* pBot, const Vector GuardLocation)
@ -3589,9 +3353,9 @@ void AITASK_SetPickupTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Tar
return;
}
AvHAIDroppedItem ItemToPickup = AITAC_GetDroppedItemRefFromEdict(Target);
AvHAIDroppedItem* ItemToPickup = AITAC_GetDroppedItemRefFromEdict(Target);
if (!ItemToPickup.IsValid())
if (!ItemToPickup)
{
AITASK_ClearBotTask(pBot, Task);
return;
@ -3605,7 +3369,7 @@ void AITASK_SetPickupTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Tar
return;
}
switch (ItemToPickup.ItemType)
switch (ItemToPickup->ItemType)
{
case DEPLOYABLE_ITEM_AMMO:
Task->TaskType = TASK_GET_AMMO;
@ -3685,16 +3449,16 @@ void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Targe
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.IsValid())
if (!NearestWelder)
{
AITASK_ClearBotTask(pBot, Task);
return;
}
else
{
Task->TaskSecondaryTarget = NearestWelder.edict;
Task->TaskSecondaryTarget = NearestWelder->edict;
}
}
@ -3806,13 +3570,7 @@ 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)
{
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; }
if (Task->TaskType == TASK_BUILD && Task->StructureType == StructureType && vDist2DSq(Task->TaskLocation, Location) < sqrf(UTIL_MetresToGoldSrcUnits(5.0f))) { return; }
AITASK_ClearBotTask(pBot, Task);
@ -4031,8 +3789,6 @@ void AITASK_SetReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task,
return;
}
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
AITASK_ClearBotTask(pBot, Task);
if (FNullEnt(Target) || Target->v.deadflag != DEAD_NO) { return; }
@ -4092,19 +3848,6 @@ void AITASK_SetMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict
Task->bTaskIsUrgent = bIsUrgent;
Task->TaskLocation = UTIL_GetNextMinePosition2(Target);
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;
}

View file

@ -47,8 +47,6 @@ bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTas
bool AITASK_IsMarineSecureHiveTaskStillValid(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_IsAlienHealTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
@ -69,7 +67,6 @@ void AITASK_SetReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task,
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_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_SetPickupTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const bool bIsUrgent);
void AITASK_SetGetHealthTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* HealingSource, const bool bIsUrgent);
@ -93,8 +90,6 @@ void MarineProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
void MarineProgressCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
void BotProgressWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
void BotProgressAssaultMarineBaseTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
void AIPlayerBuildStructure(AvHAIPlayer* pBot, edict_t* BuildTarget);
void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);