Re-implement commander AI

This commit is contained in:
RGreenlees 2023-12-26 23:21:48 +00:00 committed by pierow
parent 7440810699
commit b78629738d
18 changed files with 2205 additions and 121 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,56 @@
//
// EvoBot - Neoptolemus' Natural Selection bot, based on Botman's HPB bot template
//
// bot_navigation.h
//
// Handles all bot path finding and movement
//
#pragma once
#ifndef AVH_AI_COMMANDER_H
#define AVH_AI_COMMANDER_H
#include "AvHAIConstants.h"
bool AICOMM_DeployStructure(AvHAIPlayer* pBot, const AvHAIDeployableStructureType StructureToDeploy, const Vector Location);
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);
bool AICOMM_RecycleStructure(AvHAIPlayer* pBot, AvHAIBuildableStructure* StructureToRecycle);
bool AICOMM_IssueMovementOrder(AvHAIPlayer* pBot, edict_t* Recipient, const Vector MoveLocation);
bool AICOMM_IssueBuildOrder(AvHAIPlayer* pBot, edict_t* Recipient, edict_t* TargetStructure);
bool AICOMM_IssueSecureHiveOrder(AvHAIPlayer* pBot, edict_t* Recipient, const AvHAIHiveDefinition* HiveToSecure);
bool AICOMM_IssueSiegeHiveOrder(AvHAIPlayer* pBot, edict_t* Recipient, const AvHAIHiveDefinition* HiveToSiege, const Vector SiegePosition);
bool AICOMM_IssueSecureResNodeOrder(AvHAIPlayer* pBot, edict_t* Recipient, const AvHAIResourceNode* ResNode);
void AICOMM_ClearAction(commander_action* Action);
bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot, commander_action* Action);
bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot);
bool AICOMM_CheckForNextResearchAction(AvHAIPlayer* pBot, commander_action* Action);
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, commander_action* Action);
bool AICOMM_PerformNextSiegeHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinition* HiveToSiege, commander_action* Action);
bool AICOMM_PerformNextSecureHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinition* HiveToSiege, commander_action* Action);
ai_commander_request* AICOMM_GetExistingRequestForPlayer(AvHAIPlayer* pBot, edict_t* Requestor);
void AICOMM_CheckNewRequests(AvHAIPlayer* pBot);
bool AICOMM_IsRequestValid(ai_commander_request* Request);
bool AICOMM_IsHiveFullySecured(AvHAIPlayer* CommanderBot, const AvHAIHiveDefinition* Hive);
bool AICOMM_ShouldCommanderLeaveChair(AvHAIPlayer* pBot);
const AvHAIResourceNode* AICOMM_GetNearestResourceNodeCapOpportunity(const AvHTeamNumber Team, const Vector SearchLocation);
const AvHAIHiveDefinition* AICOMM_GetHiveSiegeOpportunityNearestLocation(AvHAIPlayer* CommanderBot, const Vector SearchLocation);
#endif // AVH_AI_COMMANDER_H

View file

@ -90,7 +90,7 @@ typedef enum _AI_REACHABILITY_STATUS
AI_REACHABILITY_ONOS = 1u << 3,
AI_REACHABILITY_WELDER = 1u << 4,
AI_REACHABILITY_ALL = 0xFFFF
AI_REACHABILITY_ALL = -1
} AvHAIReachabilityStatus;
typedef enum
@ -101,8 +101,9 @@ typedef enum
STRUCTURE_STATUS_RECYCLING = 1 << 2,
STRUCTURE_STATUS_PARASITED = 1 << 3,
STRUCTURE_STATUS_UNDERATTACK = 1 << 4,
STRUCTURE_STATUS_RESEARCHING = 1 << 5,
STRUCTURE_STATUS_ALL = 0x7FFFFFFF
STRUCTURE_STATUS_ALL = -1
} AvHAIStructureStatus;
typedef enum
@ -134,7 +135,7 @@ typedef enum
SEARCH_ALL_ALIEN_STRUCTURES = 0xFC000,
SEARCH_ANY_RES_TOWER = (STRUCTURE_MARINE_RESTOWER | STRUCTURE_ALIEN_RESTOWER),
SEARCH_ALL_STRUCTURES = 0x7FFFFFFF
SEARCH_ALL_STRUCTURES = -1
} AvHAIDeployableStructureType;
@ -157,7 +158,7 @@ typedef enum
DEPLOYABLE_ITEM_WEAPONS = 0xF80,
DEPLOYABLE_ITEM_EQUIPMENT = 0x6,
DEPLOYABLE_ITEM_ALL = 0x7FFFFFFF
DEPLOYABLE_ITEM_ALL = -1
} AvHAIDeployableItemType;
// Type of goal the commander wants to achieve
@ -513,6 +514,7 @@ typedef struct _COMMANDER_ACTION
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;
@ -520,18 +522,27 @@ typedef struct _COMMANDER_ACTION
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 = -1; // 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.)
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
AvHTechID ResearchId = TECH_NULL; // What research to perform if research action
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 struct _AI_COMMANDER_REQUEST
{
bool bNewRequest = false; // Is this a new request just come in?
edict_t* Requestor = nullptr; // Who sent the request?
AvHMessageID RequestType = MESSAGE_NULL; // What did they request?
bool bResponded = false; // Have we already responded to this request?
float RequestTime = 0.0f; // When the request came in
} ai_commander_request;
typedef struct AVH_AI_PLAYER
{
AvHPlayer* Player = nullptr;
@ -588,6 +599,8 @@ typedef struct AVH_AI_PLAYER
commander_action RecycleAction;
commander_action* CurrentAction;
vector<ai_commander_request> ActiveRequests;
float next_commander_action_time = 0.0f;
bot_msg ChatMessages[5]; // Bot can have up to 5 chat messages pending

View file

@ -2679,7 +2679,7 @@ void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom
Vector ClosestPoint = UTIL_GetClosestPointOnEntityToLocation(pBot->Edict->v.origin, BlockingBreakableEdict);
AvHAIWeapon DesiredWeapon = UTIL_GetBotPrimaryWeapon(pBot);
AvHAIWeapon DesiredWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player);
if (IsPlayerMarine(pBot->Player))
{
@ -2716,7 +2716,7 @@ void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom
pBot->DesiredMoveWeapon = DesiredWeapon;
if (GetBotCurrentWeapon(pBot) == DesiredWeapon)
if (GetPlayerCurrentWeapon(pBot->Player) == DesiredWeapon)
{
pBot->Button |= IN_ATTACK;
}
@ -3757,7 +3757,6 @@ bool IsBotOffPath(const AvHAIPlayer* pBot)
return (vEquals(PointOnPath, MoveTo, 2.0f) && !IsPlayerClimbingWall(pBot->Edict) && pBot->CollisionHullTopLocation.z < MoveTo.z);
}
// Give us a chance to land before deciding we're off the path
if (!pBot->BotNavInfo.IsOnGround) { return false; }
@ -3845,7 +3844,7 @@ void BlinkClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector End
pBot->DesiredMoveWeapon = WEAPON_FADE_BLINK;
// Wait until we have blink equipped before proceeding
if (GetBotCurrentWeapon(pBot) != WEAPON_FADE_BLINK) { return; }
if (GetPlayerCurrentWeapon(pBot->Player) != WEAPON_FADE_BLINK) { return; }
// Only blink if we're below the target climb height
if (pEdict->v.origin.z < RequiredClimbHeight)

View file

@ -8,6 +8,7 @@
#include "AvHAIWeaponHelper.h"
#include "AvHAITactical.h"
#include "AvHAITask.h"
#include "AvHAICommander.h"
#include "../AvHMessage.h"
@ -134,7 +135,7 @@ void BotLookAt(AvHAIPlayer* pBot, edict_t* target)
Vector TargetVelocity = (TrackedEnemyRef) ? TrackedEnemyRef->LastSeenVelocity : pBot->LookTarget->v.velocity;
Vector TargetLocation = (TrackedEnemyRef) ? TrackedEnemyRef->LastSeenLocation : UTIL_GetCentreOfEntity(pBot->LookTarget);
AvHAIWeapon CurrentWeapon = GetBotCurrentWeapon(pBot);
AvHAIWeapon CurrentWeapon = GetPlayerCurrentWeapon(pBot->Player);
Vector NewLoc = UTIL_GetAimLocationToLeadTarget(pBot->CurrentEyePosition, TargetLocation, TargetVelocity, GetProjectileVelocityForWeapon(CurrentWeapon));
@ -196,9 +197,9 @@ bool BotUseObject(AvHAIPlayer* pBot, edict_t* Target, bool bContinuous)
return false;
}
AvHAIWeapon GetBotCurrentWeapon(const AvHAIPlayer* pBot)
AvHAIWeapon GetPlayerCurrentWeapon(const AvHPlayer* Player)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_pActiveItem);
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(Player->m_pActiveItem);
if (theBasePlayerWeapon)
{
@ -248,7 +249,7 @@ void BotLeap(AvHAIPlayer* pBot, const Vector TargetLocation)
AvHAIWeapon LeapWeapon = (IsPlayerSkulk(pBot->Edict)) ? WEAPON_SKULK_LEAP : WEAPON_FADE_BLINK;
if (GetBotCurrentWeapon(pBot) != LeapWeapon)
if (GetPlayerCurrentWeapon(pBot->Player) != LeapWeapon)
{
pBot->DesiredMoveWeapon = LeapWeapon;
return;
@ -415,11 +416,11 @@ void BotReloadWeapons(AvHAIPlayer* pBot)
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
{
AvHAIWeapon PrimaryWeapon = UTIL_GetBotPrimaryWeapon(pBot);
AvHAIWeapon PrimaryWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player);
AvHAIWeapon SecondaryWeapon = GetBotMarineSecondaryWeapon(pBot);
AvHAIWeapon CurrentWeapon = GetBotCurrentWeapon(pBot);
AvHAIWeapon CurrentWeapon = GetPlayerCurrentWeapon(pBot->Player);
if (WeaponCanBeReloaded(PrimaryWeapon) && BotGetPrimaryWeaponClipAmmo(pBot) < BotGetPrimaryWeaponMaxClipSize(pBot) && BotGetPrimaryWeaponAmmoReserve(pBot) > 0)
if (WeaponCanBeReloaded(PrimaryWeapon) && UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) < UTIL_GetPlayerPrimaryWeaponMaxClipSize(pBot->Player) && UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0)
{
pBot->DesiredCombatWeapon = PrimaryWeapon;
@ -590,7 +591,7 @@ void BotShootTarget(AvHAIPlayer* pBot, AvHAIWeapon AttackWeapon, edict_t* Target
{
if (FNullEnt(Target) || (Target->v.deadflag != DEAD_NO)) { return; }
AvHAIWeapon CurrentWeapon = GetBotCurrentWeapon(pBot);
AvHAIWeapon CurrentWeapon = GetPlayerCurrentWeapon(pBot->Player);
pBot->DesiredCombatWeapon = AttackWeapon;
@ -686,15 +687,15 @@ void BotShootTarget(AvHAIPlayer* pBot, AvHAIWeapon AttackWeapon, edict_t* Target
if (WeaponCanBeReloaded(CurrentWeapon))
{
bool bShouldReload = (BotGetCurrentWeaponReserveAmmo(pBot) > 0);
bool bShouldReload = (GetPlayerCurrentWeaponReserveAmmo(pBot->Player) > 0);
if (CurrentWeapon == WEAPON_MARINE_SHOTGUN && IsEdictStructure(Target))
{
bShouldReload = bShouldReload && ((float)BotGetCurrentWeaponClipAmmo(pBot) / (float)BotGetCurrentWeaponMaxClipAmmo(pBot) < 0.5f);
bShouldReload = bShouldReload && ((float)GetPlayerCurrentWeaponClipAmmo(pBot->Player) / (float)GetPlayerCurrentWeaponMaxClipAmmo(pBot->Player) < 0.5f);
}
else
{
bShouldReload = bShouldReload && BotGetCurrentWeaponClipAmmo(pBot) == 0;
bShouldReload = bShouldReload && GetPlayerCurrentWeaponClipAmmo(pBot->Player) == 0;
}
if (bShouldReload)
@ -790,7 +791,7 @@ void BotShootLocation(AvHAIPlayer* pBot, AvHAIWeapon AttackWeapon, const Vector
{
if (vIsZero(TargetLocation)) { return; }
AvHAIWeapon CurrentWeapon = GetBotCurrentWeapon(pBot);
AvHAIWeapon CurrentWeapon = GetPlayerCurrentWeapon(pBot->Player);
pBot->DesiredCombatWeapon = AttackWeapon;
@ -881,15 +882,15 @@ void BotShootLocation(AvHAIPlayer* pBot, AvHAIWeapon AttackWeapon, const Vector
if (WeaponCanBeReloaded(CurrentWeapon))
{
bool bShouldReload = (BotGetCurrentWeaponReserveAmmo(pBot) > 0);
bool bShouldReload = (GetPlayerCurrentWeaponReserveAmmo(pBot->Player) > 0);
if (CurrentWeapon == WEAPON_MARINE_SHOTGUN)
{
bShouldReload = bShouldReload && ((float)BotGetCurrentWeaponClipAmmo(pBot) / (float)BotGetCurrentWeaponMaxClipAmmo(pBot) < 0.5f);
bShouldReload = bShouldReload && ((float)GetPlayerCurrentWeaponClipAmmo(pBot->Player) / (float)GetPlayerCurrentWeaponMaxClipAmmo(pBot->Player) < 0.5f);
}
else
{
bShouldReload = bShouldReload && BotGetCurrentWeaponClipAmmo(pBot) == 0;
bShouldReload = bShouldReload && GetPlayerCurrentWeaponClipAmmo(pBot->Player) == 0;
}
if (bShouldReload)
@ -1486,6 +1487,11 @@ void StartNewBotFrame(AvHAIPlayer* pBot)
}
void CustomThink(AvHAIPlayer* pBot)
{
AICOMM_CommanderThink(pBot);
}
void DroneThink(AvHAIPlayer* pBot)
{
AITASK_BotUpdateAndClearTasks(pBot);
@ -1548,7 +1554,7 @@ void BotSwitchToWeapon(AvHAIPlayer* pBot, AvHAIWeapon NewWeaponSlot)
bool ShouldBotThink(AvHAIPlayer* pBot)
{
return IsPlayerActiveInGame(pBot->Edict) && !IsPlayerGestating(pBot->Edict);
return (IsPlayerActiveInGame(pBot->Edict) || IsPlayerCommander(pBot->Edict)) && !IsPlayerGestating(pBot->Edict);
}
void BotResumePlay(AvHAIPlayer* pBot)
@ -1583,4 +1589,14 @@ void UpdateCommanderOrders(AvHAIPlayer* pBot)
}
}
}
}
}
void BotStopCommanderMode(AvHAIPlayer* pBot)
{
// Thanks EterniumDev (Alien) for logic to allow commander AI to leave the chair and build structures when needed
if (IsPlayerCommander(pBot->Edict))
{
CLIENT_COMMAND(pBot->Edict, "stopcommandermode");
}
}

View file

@ -55,6 +55,7 @@ void StartNewBotFrame(AvHAIPlayer* pBot);
void TestNavThink(AvHAIPlayer* pBot);
void DroneThink(AvHAIPlayer* pBot);
void CustomThink(AvHAIPlayer* pBot);
void BotSwitchToWeapon(AvHAIPlayer* pBot, AvHAIWeapon NewWeaponSlot);
@ -64,4 +65,6 @@ void BotResumePlay(AvHAIPlayer* pBot);
void UpdateCommanderOrders(AvHAIPlayer* pBot);
void BotStopCommanderMode(AvHAIPlayer* pBot);
#endif

View file

@ -547,13 +547,13 @@ void AIMGR_UpdateAIPlayers()
UpdateBotChat(bot);
DroneThink(bot);
CustomThink(bot);
AIDEBUG_DrawPath(DebugPath, 0.0f);
AvHAIWeapon DesiredWeapon = (bot->DesiredMoveWeapon != WEAPON_NONE) ? bot->DesiredMoveWeapon : bot->DesiredCombatWeapon;
if (DesiredWeapon != WEAPON_NONE && GetBotCurrentWeapon(bot) != DesiredWeapon)
if (DesiredWeapon != WEAPON_NONE && GetPlayerCurrentWeapon(bot->Player) != DesiredWeapon)
{
BotSwitchToWeapon(bot, DesiredWeapon);
}

View file

@ -223,6 +223,7 @@ AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocation(const Vector& Loc
{
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (!(it.second.StructureType & Filter->DeployableTypes)) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -233,15 +234,12 @@ AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocation(const Vector& Loc
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureType & Filter->DeployableTypes)
{
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && (!Result || DistSq < CurrMinDist))
{
Result = &it.second;
CurrMinDist = DistSq;
}
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && (!Result || DistSq < CurrMinDist))
{
Result = &it.second;
CurrMinDist = DistSq;
}
}
}
@ -252,6 +250,7 @@ AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocation(const Vector& Loc
{
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (!(it.second.StructureType & Filter->DeployableTypes)) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -262,15 +261,83 @@ AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocation(const Vector& Loc
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureType & Filter->DeployableTypes)
{
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && (!Result || DistSq < CurrMinDist))
{
Result = &it.second;
CurrMinDist = DistSq;
}
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && (!Result || DistSq < CurrMinDist))
{
Result = &it.second;
CurrMinDist = DistSq;
}
}
}
return Result;
}
AvHAIBuildableStructure* AITAC_FindFurthestDeployableFromLocation(const Vector& Location, const DeployableSearchFilter* Filter)
{
AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber();
AvHTeamNumber TeamB = GetGameRules()->GetTeamBNumber();
AvHAIBuildableStructure* Result = NULL;
float CurrMinDist = 0.0f;
float MinDistSq = sqrf(Filter->MinSearchRadius);
float MaxDistSq = sqrf(Filter->MaxSearchRadius);
bool bUseMinDist = MinDistSq > 0.1f;
bool bUseMaxDist = MaxDistSq > 0.1f;
if (Filter->DeployableTeam == TeamA || Filter->DeployableTeam == TEAM_IND)
{
for (auto& it : TeamAStructureMap)
{
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (!(it.second.StructureType & Filter->DeployableTypes)) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && DistSq > CurrMinDist)
{
Result = &it.second;
CurrMinDist = DistSq;
}
}
}
if (Filter->DeployableTeam == TeamB || Filter->DeployableTeam == TEAM_IND)
{
for (auto& it : TeamBStructureMap)
{
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (!(it.second.StructureType & Filter->DeployableTypes)) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && DistSq > CurrMinDist)
{
Result = &it.second;
CurrMinDist = DistSq;
}
}
}
@ -326,6 +393,75 @@ AvHAIDroppedItem* AITAC_FindClosestItemToLocation(const Vector& Location, const
return Result;
}
int AITAC_GetNumItemsInLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance)
{
int Result = 0;
float MinDistSq = sqrf(MinRadius);
float MaxDistSq = sqrf(MaxRadius);
bool bUseMinDist = MinDistSq > 0.1f;
bool bUseMaxDist = MaxDistSq > 0.1f;
for (auto& it : MarineDroppedItemMap)
{
if (it.second.ItemType != ItemType) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (SearchingTeam != TEAM_IND)
{
StructureReachabilityFlags = (SearchingTeam == GetGameRules()->GetTeamANumber()) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & ReachabilityFlags)) { continue; }
float DistSq = (bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq))
{
Result++;
}
}
return Result;
}
bool AITAC_ItemExistsInLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance)
{
float MinDistSq = sqrf(MinRadius);
float MaxDistSq = sqrf(MaxRadius);
bool bUseMinDist = MinDistSq > 0.1f;
bool bUseMaxDist = MaxDistSq > 0.1f;
for (auto& it : MarineDroppedItemMap)
{
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (SearchingTeam != TEAM_IND)
{
StructureReachabilityFlags = (SearchingTeam == GetGameRules()->GetTeamANumber()) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & ReachabilityFlags)) { continue; }
if (it.second.ItemType != ItemType) { continue; }
float DistSq = (bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq))
{
return true;
}
}
return false;
}
AvHAIBuildableStructure* AITAC_GetDeployableRefFromEdict(const edict_t* Structure)
{
if (FNullEnt(Structure)) { return nullptr; }
@ -1470,7 +1606,6 @@ void AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
{
BuildingMap[EntIndex].EntityRef = BaseBuildable;
BuildingMap[EntIndex].edict = BuildingEdict;
BuildingMap[EntIndex].StructureType = StructureType;
BuildingMap[EntIndex].OffMeshConnections.clear();
@ -1494,6 +1629,8 @@ void AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
AITAC_OnStructureCreated(&BuildingMap[EntIndex]);
}
BuildingMap[EntIndex].StructureType = StructureType;
if (vIsZero(BuildingMap[EntIndex].Location) || !vEquals(BaseBuildable->pev->origin, BuildingMap[EntIndex].Location, 5.0f))
{
AITAC_RefreshReachabilityForStructure(&BuildingMap[EntIndex]);
@ -1530,6 +1667,11 @@ void AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
NewFlags |= STRUCTURE_STATUS_RECYCLING;
}
if (BaseBuildable->GetIsResearching())
{
NewFlags |= STRUCTURE_STATUS_RESEARCHING;
}
float NewHealthPercent = (BuildingEdict->v.health / BuildingEdict->v.max_health);
if (NewHealthPercent < BuildingMap[EntIndex].healthPercent)
@ -2030,6 +2172,40 @@ bool UTIL_StructureIsResearching(edict_t* Structure, const AvHMessageID Research
return (StructureRef && StructureRef->GetIsResearching() && Structure->v.iuser2 == (int)Research);
}
bool AITAC_MarineResearchIsAvailable(const AvHTeamNumber Team, const AvHMessageID Research)
{
AvHTeam* PlayerTeam = GetGameRules()->GetTeam(Team);
if (!PlayerTeam) { return false; }
AvHMessageID Message = Research;
return PlayerTeam->GetResearchManager().GetIsMessageAvailable(Message);
}
bool AITAC_ElectricalResearchIsAvailable(edict_t* Structure)
{
if (FNullEnt(Structure)) { return false; }
if (UTIL_IsStructureElectrified(Structure)) { return false; }
AvHAIDeployableStructureType StructureTypeToElectrify = GetStructureTypeFromEdict(Structure);
AvHAIDeployableStructureType ElectrifyableStructureTypes = (AvHAIDeployableStructureType)(STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY | STRUCTURE_MARINE_RESTOWER);
if (!(ElectrifyableStructureTypes & StructureTypeToElectrify)) { return false; }
DeployableSearchFilter TFFilter;
TFFilter.DeployableTypes = STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY;
TFFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
TFFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
TFFilter.DeployableTeam = (AvHTeamNumber)Structure->v.team;
if (!AITAC_DeployableExistsAtLocation(AITAC_GetCommChairLocation((AvHTeamNumber)Structure->v.team), &TFFilter)) { return false; }
return (Structure->v.iuser4 & MASK_UPGRADE_1);
}
AvHAIHiveDefinition* AITAC_GetHiveFromEdict(const edict_t* Edict)
{
for (auto it = Hives.begin(); it != Hives.end(); it++)
@ -2497,6 +2673,41 @@ AvHMessageID UTIL_StructureTypeToImpulseCommand(const AvHAIDeployableStructureTy
return MESSAGE_NULL;
}
AvHMessageID UTIL_ItemTypeToImpulseCommand(const AvHAIDeployableItemType ItemType)
{
switch (ItemType)
{
case DEPLOYABLE_ITEM_HEAVYARMOUR:
return BUILD_HEAVY;
case DEPLOYABLE_ITEM_JETPACK:
return BUILD_JETPACK;
case DEPLOYABLE_ITEM_CATALYSTS:
return BUILD_CAT;
case DEPLOYABLE_ITEM_SCAN:
return BUILD_SCAN;
case DEPLOYABLE_ITEM_HEALTHPACK:
return BUILD_HEALTH;
case DEPLOYABLE_ITEM_AMMO:
return BUILD_AMMO;
case DEPLOYABLE_ITEM_MINES:
return BUILD_MINES;
case DEPLOYABLE_ITEM_WELDER:
return BUILD_WELDER;
case DEPLOYABLE_ITEM_SHOTGUN:
return BUILD_SHOTGUN;
case DEPLOYABLE_ITEM_HMG:
return BUILD_HMG;
case DEPLOYABLE_ITEM_GRENADELAUNCHER:
return BUILD_GRENADE_GUN;
default:
return MESSAGE_NULL;
}
return MESSAGE_NULL;
}
edict_t* AITAC_GetClosestPlayerOnTeamWithLOS(AvHTeamNumber Team, const Vector& Location, float SearchRadius, edict_t* IgnorePlayer)
{
float distSq = sqrf(SearchRadius);
@ -2663,7 +2874,7 @@ AvHAIDeployableStructureType UTIL_GetChamberTypeForHiveTech(AvHMessageID HiveTec
return STRUCTURE_NONE;
}
bool UTIL_ResearchIsComplete(const AvHTeamNumber Team, const AvHTechID Research)
bool AITAC_ResearchIsComplete(const AvHTeamNumber Team, const AvHTechID Research)
{
AvHTeam* TeamRef = GetGameRules()->GetTeam(Team);
@ -2672,4 +2883,200 @@ bool UTIL_ResearchIsComplete(const AvHTeamNumber Team, const AvHTechID Research)
AvHResearchManager ResearchManager = TeamRef->GetResearchManager();
return ResearchManager.GetTechNodes().GetIsTechResearched(Research);
}
bool AITAC_PhaseGatesAvailable(const AvHTeamNumber Team)
{
DeployableSearchFilter ObsFilter;
ObsFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
ObsFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
ObsFilter.DeployableTypes = STRUCTURE_MARINE_OBSERVATORY;
ObsFilter.DeployableTeam = Team;
bool bObsExists = AITAC_DeployableExistsAtLocation(AITAC_GetTeamStartingLocation(Team), &ObsFilter);
return bObsExists && AITAC_ResearchIsComplete(Team, TECH_RESEARCH_PHASETECH);
}
int AITAC_GetNumDeadPlayersOnTeam(const AvHTeamNumber Team)
{
AvHTeam* TeamRef = GetGameRules()->GetTeam(Team);
if (!TeamRef) { return 0; }
return TeamRef->GetPlayerCount(true);
}
bool AITAC_StructureCanBeUpgraded(edict_t* Structure)
{
// We can't upgrade a structure if it's not built, destroyed, or already doing something
if (FNullEnt(Structure)
|| Structure->v.deadflag != DEAD_NO
|| !UTIL_StructureIsFullyBuilt(Structure)
|| UTIL_StructureIsRecycling(Structure)
|| UTIL_StructureIsResearching(Structure)
|| UTIL_StructureIsUpgrading(Structure))
{
return false;
}
return (GetStructureTypeFromEdict(Structure) == STRUCTURE_MARINE_ARMOURY || GetStructureTypeFromEdict(Structure) == STRUCTURE_MARINE_TURRETFACTORY);
}
const AvHAIHiveDefinition* AITAC_GetNearestHiveUnderActiveSiege(AvHTeamNumber SiegingTeam, const Vector SearchLocation)
{
AvHAIHiveDefinition* Result = nullptr;
float MinDist = 0.0f;
for (auto it = Hives.begin(); it != Hives.end(); it++)
{
if (it->Status == HIVE_STATUS_UNBUILT) { continue; }
DeployableSearchFilter SiegeFilter;
SiegeFilter.DeployableTypes = STRUCTURE_MARINE_ADVTURRETFACTORY;
SiegeFilter.DeployableTeam = SiegingTeam;
SiegeFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f);
SiegeFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
SiegeFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
AvHAIBuildableStructure* AdvTF = AITAC_FindClosestDeployableToLocation(it->Location, &SiegeFilter);
if (!AdvTF) { continue; }
SiegeFilter.DeployableTypes = STRUCTURE_MARINE_SIEGETURRET;
SiegeFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
bool bSTExists = AITAC_DeployableExistsAtLocation(AdvTF->Location, &SiegeFilter);
if (bSTExists)
{
float ThisDist = vDist2DSq(SearchLocation, it->Location);
if (!Result || ThisDist < MinDist)
{
Result = &(*it);
MinDist = ThisDist;
}
}
}
return Result;
}
edict_t* AITAC_GetMarineEligibleToBuildSiege(AvHTeamNumber Team, const AvHAIHiveDefinition* Hive)
{
if (!Hive) { return nullptr; }
edict_t* Result = nullptr;
vector<AvHPlayer*> TeamPlayers = AITAC_GetAllPlayersOnTeam(Team);
float MinDist = 0.0f;
for (auto it = TeamPlayers.begin(); it != TeamPlayers.end(); it++)
{
edict_t* PlayerEdict = (*it)->edict();
// Find a player who is alive and not currently sighted by the enemy
if (!IsPlayerActiveInGame(PlayerEdict) || (PlayerEdict->v.iuser4 & MASK_VIS_SIGHTED)) { continue; }
float ThisDist = vDist2DSq(PlayerEdict->v.origin, Hive->Location);
if (ThisDist < sqrf(UTIL_MetresToGoldSrcUnits(25.0f)) && !UTIL_QuickTrace(PlayerEdict, GetPlayerEyePosition(PlayerEdict), Hive->Location))
{
if (FNullEnt(Result) || ThisDist < MinDist)
{
Result = PlayerEdict;
MinDist = ThisDist;
}
}
}
return Result;
}
edict_t* AITAC_GetNearestHiddenPlayerInLocation(AvHTeamNumber Team, const Vector Location, const float MaxRadius)
{
edict_t* Result = nullptr;
float MaxRadiusSq = sqrf(MaxRadius);
vector<AvHPlayer*> TeamPlayers = AITAC_GetAllPlayersOnTeam(Team);
float MinDist = 0.0f;
for (auto it = TeamPlayers.begin(); it != TeamPlayers.end(); it++)
{
edict_t* PlayerEdict = (*it)->edict();
// Find a player who is alive and not currently sighted by the enemy
if (!IsPlayerActiveInGame(PlayerEdict) || (PlayerEdict->v.iuser4 & MASK_VIS_SIGHTED)) { continue; }
float ThisDist = vDist2DSq(PlayerEdict->v.origin, Location);
if (ThisDist < MaxRadiusSq)
{
if (FNullEnt(Result) || ThisDist < MinDist)
{
Result = PlayerEdict;
MinDist = ThisDist;
}
}
}
return Result;
}
vector<AvHPlayer*> AITAC_GetAllPlayersOnTeam(AvHTeamNumber Team)
{
vector<AvHPlayer*> Result;
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
edict_t* PlayerEdict = INDEXENT(i);
if (!FNullEnt(PlayerEdict) && PlayerEdict->v.team == Team)
{
AvHPlayer* PlayerRef = dynamic_cast<AvHPlayer*>(CBaseEntity::Instance(PlayerEdict));
if (PlayerRef)
{
Result.push_back(PlayerRef);
}
}
}
return Result;
}
const vector<AvHAIResourceNode>& AITAC_GetAllResourceNodes()
{
return ResourceNodes;
}
const vector<AvHAIHiveDefinition>& AITAC_GetAllHives()
{
return Hives;
}
bool AITAC_AnyPlayerOnTeamWithLOS(AvHTeamNumber Team, const Vector& Location, float SearchRadius)
{
float distSq = sqrf(SearchRadius);
vector<AvHPlayer*> Players = AITAC_GetAllPlayersOnTeam(Team);
for (auto it = Players.begin(); it != Players.end(); it++)
{
edict_t* PlayerRef = (*it)->edict();
if (!IsPlayerActiveInGame(PlayerRef)) { continue; }
if (vDist2DSq(PlayerRef->v.origin, Location) <= distSq && UTIL_QuickTrace(PlayerRef, GetPlayerEyePosition(PlayerRef), Location))
{
return true;
}
}
return false;
}

View file

@ -23,6 +23,7 @@ static const float item_inventory_refresh_rate = 0.1f;
bool AITAC_DeployableExistsAtLocation(const Vector& Location, const DeployableSearchFilter* Filter);
std::vector<AvHAIBuildableStructure*> AITAC_FindAllDeployables(const Vector& Location, const DeployableSearchFilter* Filter);
AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocation(const Vector& Location, const DeployableSearchFilter* Filter);
AvHAIBuildableStructure* AITAC_FindFurthestDeployableFromLocation(const Vector& Location, const DeployableSearchFilter* Filter);
AvHAIBuildableStructure* AITAC_GetDeployableRefFromEdict(const edict_t* Structure);
AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter);
int AITAC_GetNumDeployablesNearLocation(const Vector& Location, const DeployableSearchFilter* Filter);
@ -57,6 +58,8 @@ Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team);
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);
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);
@ -67,6 +70,7 @@ int AITAC_GetNumHives();
void AITAC_OnNavMeshModified();
AvHMessageID UTIL_StructureTypeToImpulseCommand(const AvHAIDeployableStructureType StructureType);
AvHMessageID UTIL_ItemTypeToImpulseCommand(const AvHAIDeployableItemType ItemType);
edict_t* AITAC_GetClosestPlayerOnTeamWithLOS(AvHTeamNumber Team, const Vector& Location, float SearchRadius, edict_t* IgnorePlayer);
bool AITAC_AnyPlayerOnTeamHasLOSToLocation(AvHTeamNumber Team, const Vector& Location, float SearchRadius, edict_t* IgnorePlayer);
@ -94,6 +98,7 @@ unsigned char UTIL_GetAreaForObstruction(AvHAIDeployableStructureType StructureT
bool UTIL_IsStructureElectrified(edict_t* Structure);
bool UTIL_StructureIsFullyBuilt(edict_t* Structure);
bool UTIL_StructureIsRecycling(edict_t* Structure);
bool AITAC_StructureCanBeUpgraded(edict_t* Structure);
AvHAIHiveDefinition* AITAC_GetHiveFromEdict(const edict_t* Edict);
@ -118,6 +123,9 @@ bool UTIL_StructureIsResearching(edict_t* Structure);
bool UTIL_StructureIsResearching(edict_t* Structure, const AvHMessageID Research);
bool UTIL_StructureIsUpgrading(edict_t* Structure);
bool AITAC_MarineResearchIsAvailable(const AvHTeamNumber Team, const AvHMessageID Research);
bool AITAC_ElectricalResearchIsAvailable(edict_t* Structure);
Vector UTIL_GetNextMinePosition(edict_t* StructureToMine);
int UTIL_GetCostOfStructureType(AvHAIDeployableStructureType StructureType);
@ -125,6 +133,21 @@ edict_t* AITAC_GetNearestHumanAtLocation(const AvHTeamNumber Team, const Vector
AvHAIDeployableStructureType UTIL_GetChamberTypeForHiveTech(AvHMessageID HiveTech);
bool UTIL_ResearchIsComplete(const AvHTeamNumber Team, const AvHTechID Research);
bool AITAC_ResearchIsComplete(const AvHTeamNumber Team, const AvHTechID Research);
bool AITAC_PhaseGatesAvailable(const AvHTeamNumber Team);
int AITAC_GetNumDeadPlayersOnTeam(const AvHTeamNumber Team);
const AvHAIHiveDefinition* AITAC_GetNearestHiveUnderActiveSiege(AvHTeamNumber SiegingTeam, const Vector SearchLocation);
edict_t* AITAC_GetMarineEligibleToBuildSiege(AvHTeamNumber Team, const AvHAIHiveDefinition* Hive);
vector<AvHPlayer*> AITAC_GetAllPlayersOnTeam(AvHTeamNumber Team);
edict_t* AITAC_GetNearestHiddenPlayerInLocation(AvHTeamNumber Team, const Vector Location, const float MaxRadius);
const vector<AvHAIResourceNode>& AITAC_GetAllResourceNodes();
const vector<AvHAIHiveDefinition>& AITAC_GetAllHives();
bool AITAC_AnyPlayerOnTeamWithLOS(AvHTeamNumber Team, const Vector& Location, float SearchRadius);
#endif

View file

@ -148,7 +148,7 @@ bool AITASK_IsTaskUrgent(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
switch (Task->TaskType)
{
case TASK_GET_AMMO:
return (BotGetPrimaryWeaponAmmoReserve(pBot) == 0);
return (UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) == 0);
case TASK_GET_HEALTH:
return (IsPlayerMarine(pBot->Edict)) ? (pBot->Edict->v.health < 50.0f) : (GetPlayerOverallHealthPercent(pBot->Edict) < 50.0f);
case TASK_ATTACK:
@ -157,7 +157,7 @@ bool AITASK_IsTaskUrgent(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
case TASK_WELD:
return false;
case TASK_RESUPPLY:
return (pBot->Edict->v.health < 50.0f) || (BotGetPrimaryWeaponAmmoReserve(pBot) == 0);
return (pBot->Edict->v.health < 50.0f) || (UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) == 0);
case TASK_MOVE:
return AITASK_IsMoveTaskUrgent(pBot, Task);
case TASK_BUILD:
@ -420,7 +420,7 @@ bool AITASK_IsAmmoPickupTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (!UTIL_IsDroppedItemStillReachable(pBot, Task->TaskTarget)) { return false; }
return (vDist2DSq(pBot->Edict->v.origin, Task->TaskTarget->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(20.0f))) && (BotGetPrimaryWeaponAmmoReserve(pBot) < BotGetPrimaryWeaponMaxAmmoReserve(pBot));
return (vDist2DSq(pBot->Edict->v.origin, Task->TaskTarget->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(20.0f))) && (UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) < UTIL_GetPlayerPrimaryMaxAmmoReserve(pBot->Player));
}
bool AITASK_IsHealthPickupTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
@ -475,7 +475,7 @@ bool AITASK_IsAttackTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (StructureType == STRUCTURE_ALIEN_HIVE || StructureType == STRUCTURE_ALIEN_OFFENCECHAMBER)
{
if (BotGetPrimaryWeaponClipAmmo(pBot) <= 0 && BotGetPrimaryWeaponAmmoReserve(pBot) <= 0)
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) <= 0 && UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) <= 0)
{
return false;
}
@ -499,7 +499,7 @@ bool AITASK_IsResupplyTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (!UTIL_StructureIsFullyBuilt(Task->TaskTarget) || UTIL_StructureIsRecycling(Task->TaskTarget)) { return false; }
return ((pBot->Edict->v.health < pBot->Edict->v.max_health)
|| (BotGetPrimaryWeaponAmmoReserve(pBot) < BotGetPrimaryWeaponMaxAmmoReserve(pBot))
|| (UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) < UTIL_GetPlayerPrimaryMaxAmmoReserve(pBot->Player))
|| (BotGetSecondaryWeaponAmmoReserve(pBot) < BotGetSecondaryWeaponMaxAmmoReserve(pBot))
);
}
@ -1020,7 +1020,7 @@ void BotProgressPickupTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (Task->TaskType == TASK_GET_AMMO)
{
pBot->DesiredCombatWeapon = UTIL_GetBotPrimaryWeapon(pBot);
pBot->DesiredCombatWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player);
}
MoveTo(pBot, Task->TaskTarget->v.origin, MOVESTYLE_NORMAL);
@ -1040,11 +1040,11 @@ void BotProgressPickupTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
// Allows bots to drop their current primary weapon to pick up a new weapon
if (UTIL_DroppedItemIsPrimaryWeapon(ItemType))
{
AvHAIWeapon CurrentPrimaryWeapon = UTIL_GetBotPrimaryWeapon(pBot);
AvHAIWeapon CurrentPrimaryWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player);
if (CurrentPrimaryWeapon != WEAPON_NONE && CurrentPrimaryWeapon != UTIL_GetWeaponTypeFromEdict(Task->TaskTarget))
{
if (GetBotCurrentWeapon(pBot) != CurrentPrimaryWeapon)
if (GetPlayerCurrentWeapon(pBot->Player) != CurrentPrimaryWeapon)
{
pBot->DesiredCombatWeapon = CurrentPrimaryWeapon;
}
@ -1121,7 +1121,7 @@ void BotProgressMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
BotLookAt(pBot, Task->TaskLocation);
if (GetBotCurrentWeapon(pBot) == WEAPON_MARINE_MINES)
if (GetPlayerCurrentWeapon(pBot->Player) == WEAPON_MARINE_MINES)
{
float LookDot = UTIL_GetDotProduct(UTIL_GetForwardVector(pBot->Edict->v.v_angle), UTIL_GetVectorNormal(Task->TaskLocation - pBot->CurrentEyePosition));
@ -1410,9 +1410,9 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
void BotProgressResupplyTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (BotGetPrimaryWeaponAmmoReserve(pBot) < BotGetPrimaryWeaponMaxAmmoReserve(pBot))
if (UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) < UTIL_GetPlayerPrimaryMaxAmmoReserve(pBot->Player))
{
pBot->DesiredCombatWeapon = UTIL_GetBotPrimaryWeapon(pBot);
pBot->DesiredCombatWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player);
}
else
{
@ -1442,9 +1442,9 @@ void MarineProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
edict_t* pEdict = pBot->Edict;
if (BotGetPrimaryWeaponClipAmmo(pBot) > 0 || BotGetPrimaryWeaponAmmoReserve(pBot) > 0)
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 || UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0)
{
pBot->DesiredCombatWeapon = UTIL_GetBotPrimaryWeapon(pBot);
pBot->DesiredCombatWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player);
}
else
{
@ -1454,7 +1454,7 @@ void MarineProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
else
{
pBot->DesiredCombatWeapon = UTIL_GetBotPrimaryWeapon(pBot);
pBot->DesiredCombatWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player);
}
}
@ -1656,6 +1656,9 @@ void BotProgressDefendTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
void BotProgressTakeCommandTask(AvHAIPlayer* pBot)
{
// Don't take command if we already have a commander
if (pBot->Player->GetCommander()) { return; }
edict_t* CommChair = AITAC_GetCommChair(pBot->Player->GetTeam());
if (!CommChair) { return; }
@ -1775,7 +1778,7 @@ void AlienProgressGetHealthTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (PlayerHasWeapon(pBot->Player, WEAPON_FADE_METABOLIZE))
{
pBot->DesiredCombatWeapon = WEAPON_FADE_METABOLIZE;
if (GetBotCurrentWeapon(pBot) == WEAPON_FADE_METABOLIZE)
if (GetPlayerCurrentWeapon(pBot->Player) == WEAPON_FADE_METABOLIZE)
{
pBot->Button |= IN_ATTACK;
}
@ -1812,7 +1815,7 @@ void AlienProgressHealTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
pBot->DesiredCombatWeapon = WEAPON_GORGE_HEALINGSPRAY;
BotLookAt(pBot, UTIL_GetCentreOfEntity(Task->TaskTarget));
if (GetBotCurrentWeapon(pBot) == WEAPON_GORGE_HEALINGSPRAY)
if (GetPlayerCurrentWeapon(pBot->Player) == WEAPON_GORGE_HEALINGSPRAY)
{
pBot->Button |= IN_ATTACK;
}
@ -2086,7 +2089,7 @@ void AlienProgressCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
pBot->DesiredCombatWeapon = AttackWeapon;
if (GetBotCurrentWeapon(pBot) == AttackWeapon)
if (GetPlayerCurrentWeapon(pBot->Player) == AttackWeapon)
{
BotShootTarget(pBot, pBot->DesiredCombatWeapon, Task->TaskTarget);
return;
@ -2281,7 +2284,7 @@ void BotProgressWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
BotLookAt(pBot, vClosestPointOnBB(pBot->CurrentEyePosition, BBMin, BBMax));
pBot->DesiredCombatWeapon = WEAPON_MARINE_WELDER;
if (GetBotCurrentWeapon(pBot) != WEAPON_MARINE_WELDER)
if (GetPlayerCurrentWeapon(pBot->Player) != WEAPON_MARINE_WELDER)
{
return;
}
@ -2322,7 +2325,7 @@ void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (!TF || !(TF->StructureStatusFlags & STRUCTURE_STATUS_COMPLETED)) { bWaitForBuildingPlacement = true; }
bool bPhaseGatesAvailable = UTIL_ResearchIsComplete(pBot->Player->GetTeam(), TECH_PHASE_GATE);
bool bPhaseGatesAvailable = AITAC_ResearchIsComplete(pBot->Player->GetTeam(), TECH_PHASE_GATE);
if (bPhaseGatesAvailable && !bWaitForBuildingPlacement)
{
@ -2443,7 +2446,7 @@ void MarineProgressCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
pBot->DesiredCombatWeapon = AttackWeapon;
if (GetBotCurrentWeapon(pBot) == AttackWeapon)
if (GetPlayerCurrentWeapon(pBot->Player) == AttackWeapon)
{
//BotShootTarget(pBot, pBot->DesiredCombatWeapon, Task->TaskTarget);
}

View file

@ -16,9 +16,9 @@
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
int BotGetCurrentWeaponClipAmmo(const AvHAIPlayer* pBot)
int GetPlayerCurrentWeaponClipAmmo(const AvHPlayer* Player)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_pActiveItem);
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(Player->m_pActiveItem);
if (theBasePlayerWeapon)
{
@ -28,9 +28,9 @@ int BotGetCurrentWeaponClipAmmo(const AvHAIPlayer* pBot)
return 0;
}
int BotGetCurrentWeaponMaxClipAmmo(const AvHAIPlayer* pBot)
int GetPlayerCurrentWeaponMaxClipAmmo(const AvHPlayer* Player)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_pActiveItem);
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(Player->m_pActiveItem);
if (theBasePlayerWeapon)
{
@ -40,13 +40,13 @@ int BotGetCurrentWeaponMaxClipAmmo(const AvHAIPlayer* pBot)
return 0;
}
int BotGetCurrentWeaponReserveAmmo(const AvHAIPlayer* pBot)
int GetPlayerCurrentWeaponReserveAmmo(const AvHPlayer* Player)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_pActiveItem);
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(Player->m_pActiveItem);
if (theBasePlayerWeapon)
{
return pBot->Player->m_rgAmmo[theBasePlayerWeapon->m_iPrimaryAmmoType];
return Player->m_rgAmmo[theBasePlayerWeapon->m_iPrimaryAmmoType];
}
return 0;
@ -165,9 +165,21 @@ void InterruptReload(AvHAIPlayer* pBot)
pBot->Button |= IN_ATTACK;
}
AvHAIWeapon UTIL_GetBotPrimaryWeapon(const AvHAIPlayer* pBot)
AvHAIWeapon UTIL_GetPlayerPrimaryWeapon(const AvHPlayer* Player)
{
AvHBasePlayerWeapon* Weapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[1]);
AvHBasePlayerWeapon* Weapon = dynamic_cast<AvHBasePlayerWeapon*>(Player->m_rgpPlayerItems[1]);
if (Weapon)
{
return (AvHAIWeapon)Weapon->m_iId;
}
return WEAPON_INVALID;
}
AvHAIWeapon UTIL_GetPlayerSecondaryWeapon(const AvHPlayer* Player)
{
AvHBasePlayerWeapon* Weapon = dynamic_cast<AvHBasePlayerWeapon*>(Player->m_rgpPlayerItems[2]);
if (Weapon)
{
@ -206,9 +218,9 @@ AvHAIWeapon GetBotMarineSecondaryWeapon(const AvHAIPlayer* pBot)
return WEAPON_INVALID;
}
int BotGetPrimaryWeaponMaxAmmoReserve(AvHAIPlayer* pBot)
int UTIL_GetPlayerPrimaryMaxAmmoReserve(AvHPlayer* Player)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[1]);
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(Player->m_rgpPlayerItems[1]);
if (theBasePlayerWeapon)
{
@ -218,13 +230,37 @@ int BotGetPrimaryWeaponMaxAmmoReserve(AvHAIPlayer* pBot)
return 0;
}
int BotGetPrimaryWeaponAmmoReserve(AvHAIPlayer* pBot)
int UTIL_GetPlayerPrimaryAmmoReserve(AvHPlayer* Player)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[1]);
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(Player->m_rgpPlayerItems[1]);
if (theBasePlayerWeapon)
{
return pBot->Player->m_rgAmmo[theBasePlayerWeapon->m_iPrimaryAmmoType];
return Player->m_rgAmmo[theBasePlayerWeapon->m_iPrimaryAmmoType];
}
return 0;
}
int UTIL_GetPlayerSecondaryMaxAmmoReserve(AvHPlayer* Player)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(Player->m_rgpPlayerItems[2]);
if (theBasePlayerWeapon)
{
return theBasePlayerWeapon->iMaxAmmo1();
}
return 0;
}
int UTIL_GetPlayerSecondaryAmmoReserve(AvHPlayer* Player)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(Player->m_rgpPlayerItems[2]);
if (theBasePlayerWeapon)
{
return Player->m_rgAmmo[theBasePlayerWeapon->m_iPrimaryAmmoType];
}
return 0;
@ -242,9 +278,9 @@ int BotGetSecondaryWeaponAmmoReserve(AvHAIPlayer* pBot)
return 0;
}
int BotGetPrimaryWeaponClipAmmo(const AvHAIPlayer* pBot)
int UTIL_GetPlayerPrimaryWeaponClipAmmo(const AvHPlayer* Player)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[1]);
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(Player->m_rgpPlayerItems[1]);
if (theBasePlayerWeapon)
{
@ -266,9 +302,33 @@ int BotGetSecondaryWeaponClipAmmo(const AvHAIPlayer* pBot)
return 0;
}
int BotGetPrimaryWeaponMaxClipSize(const AvHAIPlayer* pBot)
int UTIL_GetPlayerPrimaryWeaponMaxClipSize(const AvHPlayer* Player)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[1]);
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(Player->m_rgpPlayerItems[1]);
if (theBasePlayerWeapon)
{
return theBasePlayerWeapon->iMaxClip();
}
return 0;
}
int UTIL_GetPlayerSecondaryWeaponClipAmmo(const AvHPlayer* Player)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(Player->m_rgpPlayerItems[2]);
if (theBasePlayerWeapon)
{
return theBasePlayerWeapon->m_iClip;
}
return 0;
}
int UTIL_GetPlayerSecondaryWeaponMaxClipSize(const AvHPlayer* Player)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(Player->m_rgpPlayerItems[2]);
if (theBasePlayerWeapon)
{
@ -471,9 +531,9 @@ AvHAIWeapon BotMarineChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target)
if (FNullEnt(target))
{
if (BotGetPrimaryWeaponClipAmmo(pBot) > 0 || BotGetPrimaryWeaponAmmoReserve(pBot) > 0)
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 || UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0)
{
return UTIL_GetBotPrimaryWeapon(pBot);
return UTIL_GetPlayerPrimaryWeapon(pBot->Player);
}
else if (BotGetSecondaryWeaponClipAmmo(pBot) > 0 || BotGetSecondaryWeaponAmmoReserve(pBot) > 0)
{
@ -481,7 +541,7 @@ AvHAIWeapon BotMarineChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target)
}
else
{
return UTIL_GetBotPrimaryWeapon(pBot);
return UTIL_GetPlayerPrimaryWeapon(pBot->Player);
}
}
@ -489,9 +549,9 @@ AvHAIWeapon BotMarineChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target)
{
float DistFromEnemy = vDist2DSq(pBot->Edict->v.origin, target->v.origin);
if (UTIL_GetBotPrimaryWeapon(pBot) == WEAPON_MARINE_GL)
if (UTIL_GetPlayerPrimaryWeapon(pBot->Player) == WEAPON_MARINE_GL)
{
if (BotGetPrimaryWeaponClipAmmo(pBot) > 0 && DistFromEnemy > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 && DistFromEnemy > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
{
return WEAPON_MARINE_GL;
}
@ -506,7 +566,7 @@ AvHAIWeapon BotMarineChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target)
if (DistFromEnemy <= sqrf(UTIL_MetresToGoldSrcUnits(2.0f)))
{
if (BotGetPrimaryWeaponClipAmmo(pBot) == 0)
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) == 0)
{
if (BotGetSecondaryWeaponClipAmmo(pBot) > 0)
{
@ -519,12 +579,12 @@ AvHAIWeapon BotMarineChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target)
}
else
{
return UTIL_GetBotPrimaryWeapon(pBot);
return UTIL_GetPlayerPrimaryWeapon(pBot->Player);
}
}
else
{
AvHAIWeapon PrimaryWeapon = UTIL_GetBotPrimaryWeapon(pBot);
AvHAIWeapon PrimaryWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player);
if (PrimaryWeapon == WEAPON_MARINE_SHOTGUN)
{
@ -536,7 +596,7 @@ AvHAIWeapon BotMarineChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target)
}
else
{
if (BotGetPrimaryWeaponClipAmmo(pBot) > 0 || BotGetPrimaryWeaponAmmoReserve(pBot) > 0)
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 || UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0)
{
return PrimaryWeapon;
}
@ -548,7 +608,7 @@ AvHAIWeapon BotMarineChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target)
}
else
{
if (BotGetPrimaryWeaponClipAmmo(pBot) > 0 || BotGetPrimaryWeaponAmmoReserve(pBot) > 0)
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 || UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0)
{
return PrimaryWeapon;
}
@ -569,7 +629,7 @@ AvHAIWeapon BotMarineChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target)
{
if (DistFromEnemy > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
{
if (BotGetPrimaryWeaponClipAmmo(pBot) > 0 || BotGetPrimaryWeaponAmmoReserve(pBot) > 0)
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 || UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0)
{
return PrimaryWeapon;
}
@ -583,7 +643,7 @@ AvHAIWeapon BotMarineChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target)
}
else
{
if (BotGetPrimaryWeaponClipAmmo(pBot) > 0 || (DistFromEnemy > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)) && BotGetPrimaryWeaponAmmoReserve(pBot) > 0))
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 || (DistFromEnemy > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)) && UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0))
{
return PrimaryWeapon;
}
@ -614,7 +674,7 @@ AvHAIWeapon BotAlienChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* tar
if (StructureType == STRUCTURE_NONE)
{
return UTIL_GetBotPrimaryWeapon(pBot);
return UTIL_GetPlayerPrimaryWeapon(pBot->Player);
}
if (PlayerHasWeapon(pBot->Player, WEAPON_GORGE_BILEBOMB))
@ -651,7 +711,7 @@ AvHAIWeapon BotAlienChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* tar
}
}
return UTIL_GetBotPrimaryWeapon(pBot);
return UTIL_GetPlayerPrimaryWeapon(pBot->Player);
}
AvHAIWeapon BotMarineChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* target)
@ -660,9 +720,9 @@ AvHAIWeapon BotMarineChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* ta
if (StructureType == STRUCTURE_NONE)
{
if (BotGetPrimaryWeaponClipAmmo(pBot) > 0 || BotGetPrimaryWeaponAmmoReserve(pBot) > 0)
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 || UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0)
{
return UTIL_GetBotPrimaryWeapon(pBot);
return UTIL_GetPlayerPrimaryWeapon(pBot->Player);
}
else if (BotGetSecondaryWeaponClipAmmo(pBot) > 0 || BotGetSecondaryWeaponAmmoReserve(pBot) > 0)
{
@ -676,9 +736,9 @@ AvHAIWeapon BotMarineChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* ta
if (StructureType == STRUCTURE_ALIEN_HIVE || StructureType == STRUCTURE_ALIEN_OFFENCECHAMBER)
{
if (BotGetPrimaryWeaponClipAmmo(pBot) > 0 || BotGetPrimaryWeaponAmmoReserve(pBot) > 0)
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 || UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0)
{
return UTIL_GetBotPrimaryWeapon(pBot);
return UTIL_GetPlayerPrimaryWeapon(pBot->Player);
}
else if (BotGetSecondaryWeaponClipAmmo(pBot) > 0 || BotGetSecondaryWeaponAmmoReserve(pBot) > 0)
{
@ -691,9 +751,9 @@ AvHAIWeapon BotMarineChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* ta
}
else
{
AvHAIWeapon PrimaryWeapon = UTIL_GetBotPrimaryWeapon(pBot);
AvHAIWeapon PrimaryWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player);
if ((PrimaryWeapon == WEAPON_MARINE_GL || PrimaryWeapon == WEAPON_MARINE_SHOTGUN) && (BotGetPrimaryWeaponClipAmmo(pBot) > 0 || BotGetPrimaryWeaponAmmoReserve(pBot) > 0))
if ((PrimaryWeapon == WEAPON_MARINE_GL || PrimaryWeapon == WEAPON_MARINE_SHOTGUN) && (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 || UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0))
{
return PrimaryWeapon;
}
@ -701,7 +761,7 @@ AvHAIWeapon BotMarineChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* ta
return WEAPON_MARINE_KNIFE;
}
return UTIL_GetBotPrimaryWeapon(pBot);
return UTIL_GetPlayerPrimaryWeapon(pBot->Player);
}
AvHAIWeapon GorgeGetBestWeaponForCombatTarget(AvHAIPlayer* pBot, edict_t* Target)
@ -875,7 +935,7 @@ AvHAIWeapon FadeGetBestWeaponForCombatTarget(AvHAIPlayer* pBot, edict_t* Target)
void BotReloadCurrentWeapon(AvHAIPlayer* pBot)
{
AvHAIWeapon CurrentWeapon = GetBotCurrentWeapon(pBot);
AvHAIWeapon CurrentWeapon = GetPlayerCurrentWeapon(pBot->Player);
if (!WeaponCanBeReloaded(CurrentWeapon)) { return; }

View file

@ -5,19 +5,25 @@
#include "AvHAIPlayer.h"
int BotGetCurrentWeaponClipAmmo(const AvHAIPlayer* pBot);
int BotGetCurrentWeaponMaxClipAmmo(const AvHAIPlayer* pBot);
int BotGetCurrentWeaponReserveAmmo(const AvHAIPlayer* pBot);
AvHAIWeapon GetBotCurrentWeapon(const AvHAIPlayer* pBot);
int GetPlayerCurrentWeaponClipAmmo(const AvHPlayer* Player);
int GetPlayerCurrentWeaponMaxClipAmmo(const AvHPlayer* Player);
int GetPlayerCurrentWeaponReserveAmmo(const AvHPlayer* Player);
AvHAIWeapon GetPlayerCurrentWeapon(const AvHPlayer* Player);
AvHBasePlayerWeapon* GetPlayerCurrentWeaponReference(const AvHPlayer* Player);
AvHAIWeapon UTIL_GetBotPrimaryWeapon(const AvHAIPlayer* pBot);
AvHAIWeapon UTIL_GetPlayerPrimaryWeapon(const AvHPlayer* Player);
AvHAIWeapon UTIL_GetPlayerSecondaryWeapon(const AvHPlayer* Player);
int BotGetPrimaryWeaponClipAmmo(const AvHAIPlayer* pBot);
int BotGetPrimaryWeaponMaxClipSize(const AvHAIPlayer* pBot);
int BotGetPrimaryWeaponAmmoReserve(AvHAIPlayer* pBot);
int BotGetPrimaryWeaponMaxAmmoReserve(AvHAIPlayer* pBot);
int UTIL_GetPlayerPrimaryWeaponClipAmmo(const AvHPlayer* Player);
int UTIL_GetPlayerPrimaryWeaponMaxClipSize(const AvHPlayer* Player);
int UTIL_GetPlayerPrimaryAmmoReserve(AvHPlayer* Player);
int UTIL_GetPlayerPrimaryMaxAmmoReserve(AvHPlayer* Player);
int UTIL_GetPlayerSecondaryWeaponClipAmmo(const AvHPlayer* Player);
int UTIL_GetPlayerSecondaryWeaponMaxClipSize(const AvHPlayer* Player);
int UTIL_GetPlayerSecondaryAmmoReserve(AvHPlayer* Player);
int UTIL_GetPlayerSecondaryMaxAmmoReserve(AvHPlayer* Player);
AvHAIWeapon GetBotMarineSecondaryWeapon(const AvHAIPlayer* pBot);
int BotGetSecondaryWeaponClipAmmo(const AvHAIPlayer* pBot);

View file

@ -113,6 +113,7 @@
#include "AIPlayers/AvHAIPlayerManager.h"
#include "AIPlayers/AvHAITask.h"
#include "AIPlayers/AvHAITactical.h"
#include "AIPlayers/AvHAICommander.h"
extern AvHParticleTemplateListServer gParticleTemplateList;
extern CVoiceGameMgr g_VoiceGameMgr;
@ -1497,9 +1498,58 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
theSuccess = true;
}
else if (FStrEq(pcmd, "testpathfind"))
else if (FStrEq(pcmd, "testcommanderbuild"))
{
AIDEBUG_TestPathFind();
AvHAIPlayer* AIComm = AIMGR_GetAICommander(theAvHPlayer->GetTeam());
if (AIComm)
{
Vector TraceStart = GetPlayerEyePosition(theAvHPlayer->edict()); // origin + pev->view_ofs
Vector LookDir = UTIL_GetForwardVector(theAvHPlayer->edict()->v.v_angle); // Converts view angles to normalized unit vector
Vector TraceEnd = TraceStart + (LookDir * 1000.0f);
TraceResult Hit;
UTIL_TraceLine(TraceStart, TraceEnd, ignore_monsters, theAvHPlayer->edict(), &Hit);
if (Hit.flFraction < 1.0f)
{
AICOMM_DeployStructure(AIComm, STRUCTURE_MARINE_ARMOURY, Hit.vecEndPos);
}
}
theSuccess = true;
}
else if (FStrEq(pcmd, "testresearchavailable"))
{
AvHTeam* PlayerTeam = GetGameRules()->GetTeam(theAvHPlayer->GetTeam());
if (PlayerTeam)
{
AvHMessageID Message = RESEARCH_ARMOR_ONE;
AvHMessageID Message2 = RESEARCH_ARMOR_TWO;
if (PlayerTeam->GetResearchManager().GetIsMessageAvailable(Message))
{
UTIL_SayText("Armour 1: TRUE\n", theAvHPlayer);
}
else
{
UTIL_SayText("Armour 1: FALSE\n", theAvHPlayer);
}
if (PlayerTeam->GetResearchManager().GetIsMessageAvailable(Message2))
{
UTIL_SayText("Armour 2: TRUE\n", theAvHPlayer);
}
else
{
UTIL_SayText("Armour 2: FALSE\n", theAvHPlayer);
}
}
theSuccess = true;
}

View file

@ -1941,7 +1941,7 @@ void AvHCommandStation::CommandUse( CBaseEntity* pActivator, CBaseEntity* pCalle
AvHPlayer* thePlayer = dynamic_cast<AvHPlayer*>(pActivator);
// Mapper-placed CCs can be killed but they don't go away
if(thePlayer && !(thePlayer->pev->flags & FL_FAKECLIENT) && !this->GetHasBeenKilled() && thePlayer->GetIsAbleToAct())
if(thePlayer && !this->GetHasBeenKilled() && thePlayer->GetIsAbleToAct())
{
AvHTeam* theTeam = thePlayer->GetTeamPointer();
if(theTeam && (theTeam->GetTeamType() == AVH_CLASS_TYPE_MARINE))

View file

@ -486,6 +486,8 @@ public:
//
bool GetHasSeenATeam();
void GiveOrderToSelection(AvHOrder& inOrder);
private:
void AcquireOverwatchTarget();
bool AttemptToBuildAlienStructure(AvHMessageID inMessageID);
@ -509,7 +511,7 @@ private:
void GetSpeeds(int& outBaseSpeed, int& outUnemcumberedSpeed) const;
void GiveCombatUpgradesOnSpawn();
bool GiveOrderToSelection(AvHOrderType inOrder, Vector inNormRay);
void GiveOrderToSelection(AvHOrder& inOrder);
void GiveUpgrade(AvHMessageID inUpgrade);
void HandleOverwatch(void);
void HandleResearch();

View file

@ -196,6 +196,11 @@ void AvHResearchManager::SetTeamNumber(AvHTeamNumber inTeamNumber)
this->mTeamNumber = inTeamNumber;
}
bool AvHResearchManager::GetResearchDone(AvHTechID inTech)
{
return this->mTechNodes.GetIsTechResearched(inTech);
}
bool AvHResearchManager::SetResearchDone(AvHMessageID inTech, int inEntityIndex)
{
bool theFoundIt = false;

View file

@ -79,6 +79,8 @@ public:
void SetTeamNumber(AvHTeamNumber inTeamNumber);
void UpdateResearch();
bool GetResearchDone(AvHTechID inTech);
private:
bool SetResearchDone(AvHMessageID inTech, int inEntityIndex);

View file

@ -96,6 +96,7 @@ vec3_t AvHSHUGetRealLocation(const vec3_t& inLocation, const vec3_t& inMinBox, c
void AvHSHUGetFirstNonSolidPoint(float* inStartPos, float* inEndPos, float* outNonSolidPoint);
void AvHSHUGetFirstNonSolidPoint(const vec3_t& inStartPos, const vec3_t& inEndPos, vec3_t& outNonSolidPoint);
bool AvHSHUGetIsBuilding(AvHMessageID inMessageID);
bool AvHSHUGetIsMarineStructure(AvHUser3 inUser3);
bool AvHSHUGetIsBuildTech(AvHMessageID inMessageID);
bool AvHSHUGetIsWeaponFocusable(AvHWeaponID inWeaponID);
bool AvHSHUGetDoesTechCostEnergy(AvHMessageID inMessageID);