mirror of
https://github.com/ENSL/NS.git
synced 2025-03-14 06:34:33 +00:00
Improved bot stuck detection
This commit is contained in:
parent
16f34dc987
commit
a747ed0187
12 changed files with 1177 additions and 249 deletions
|
@ -61,9 +61,11 @@ bool AICOMM_DeployItem(AvHAIPlayer* pBot, const AvHAIDeployableItemType ItemToDe
|
|||
|
||||
if (!AvHSHUGetIsSiteValidForBuild(StructureID, &BuildLocation)) { return false; }
|
||||
|
||||
bool theSuccess = (AvHSUBuildTechForPlayer(StructureID, BuildLocation, pBot->Player) != NULL);
|
||||
CBaseEntity* NewItem = AvHSUBuildTechForPlayer(StructureID, BuildLocation, pBot->Player);
|
||||
|
||||
if (!theSuccess) { return false; }
|
||||
if (!NewItem) { return false; }
|
||||
|
||||
AITAC_UpdateMarineItem(NewItem, ItemToDeploy);
|
||||
|
||||
pBot->Player->PayPurchaseCost(theCost);
|
||||
|
||||
|
@ -85,6 +87,20 @@ bool AICOMM_ResearchTech(AvHAIPlayer* pBot, AvHAIBuildableStructure* StructureTo
|
|||
|
||||
if (!StructureToResearch->EntityRef->GetIsTechnologyAvailable(Research)) { return false; }
|
||||
|
||||
AvHTeam* CommanderTeamRef = AIMGR_GetTeamRef(pBot->Player->GetTeam());
|
||||
|
||||
if (!CommanderTeamRef) { return false; }
|
||||
|
||||
AvHResearchManager& theResearchManager = CommanderTeamRef->GetResearchManager();
|
||||
|
||||
bool theIsResearchable = false;
|
||||
int theResearchCost = 0.0f;
|
||||
float theResearchTime = 0.0f;
|
||||
|
||||
theResearchManager.GetResearchInfo(Research, theIsResearchable, theResearchCost, theResearchTime);
|
||||
|
||||
if (pBot->Player->GetResources() < theResearchCost) { return false; }
|
||||
|
||||
pBot->Player->SetSelection(StructureIndex, true);
|
||||
|
||||
pBot->Button |= IN_ATTACK2;
|
||||
|
@ -388,6 +404,7 @@ bool AICOMM_ShouldCommanderPrioritiseNodes(AvHAIPlayer* pBot)
|
|||
|
||||
int NumOwnedNodes = 0;
|
||||
int NumEligibleNodes = 0;
|
||||
int NumFreeNodes = 0;
|
||||
|
||||
// First get ours and the enemy's ownership of all eligible nodes (we can reach them, and they're in the enemy base)
|
||||
vector<AvHAIResourceNode*> AllNodes = AITAC_GetAllReachableResourceNodes(BotTeam);
|
||||
|
@ -399,6 +416,11 @@ bool AICOMM_ShouldCommanderPrioritiseNodes(AvHAIPlayer* pBot)
|
|||
// We don't care about the node at marine spawn or enemy hives, ignore then in our calculations
|
||||
if (ThisNode->OwningTeam == EnemyTeam && ThisNode->bIsBaseNode) { continue; }
|
||||
|
||||
if (ThisNode->OwningTeam == TEAM_IND)
|
||||
{
|
||||
NumFreeNodes++;
|
||||
}
|
||||
|
||||
NumEligibleNodes++;
|
||||
|
||||
if (ThisNode->OwningTeam == BotTeam) { NumOwnedNodes++; }
|
||||
|
@ -408,7 +430,7 @@ bool AICOMM_ShouldCommanderPrioritiseNodes(AvHAIPlayer* pBot)
|
|||
|
||||
if (NumNodesLeft == 0) { return false; }
|
||||
|
||||
return NumOwnedNodes < 3 || NumNodesLeft > 3;
|
||||
return NumOwnedNodes < 3 || NumFreeNodes > 3;
|
||||
|
||||
}
|
||||
|
||||
|
@ -587,8 +609,11 @@ edict_t* AICOMM_GetPlayerWithNoOrderNearestLocation(AvHAIPlayer* pBot, Vector Se
|
|||
for (auto it = PlayerList.begin(); it != PlayerList.end();)
|
||||
{
|
||||
AvHPlayer* PlayerRef = (*it);
|
||||
AvHAIPlayer* AIPlayerRef = AIMGR_GetBotRefFromPlayer(PlayerRef);
|
||||
|
||||
if (!IsPlayerActiveInGame(PlayerRef->edict()))
|
||||
// Don't give orders to incapacitated players, or if the bot is currently playing a defensive role. Stops the commander sending everyone out
|
||||
// and leaving nobody at base
|
||||
if (!IsPlayerActiveInGame(PlayerRef->edict()) || (AIPlayerRef && AIPlayerRef->BotRole == BOT_ROLE_SWEEPER))
|
||||
{
|
||||
it = PlayerList.erase(it);
|
||||
}
|
||||
|
@ -1093,9 +1118,76 @@ bool AICOMM_CheckForNextSupplyAction(AvHAIPlayer* pBot)
|
|||
{
|
||||
AvHTeamNumber CommanderTeam = pBot->Player->GetTeam();
|
||||
|
||||
// First thing: if our base is damaged and there's nobody able to weld, drop a welder so we don't let the base die
|
||||
bool bBaseIsDamaged = false;
|
||||
|
||||
DeployableSearchFilter DamagedBaseStructures;
|
||||
DamagedBaseStructures.DeployableTypes = (STRUCTURE_MARINE_COMMCHAIR | STRUCTURE_MARINE_INFANTRYPORTAL);
|
||||
DamagedBaseStructures.DeployableTeam = CommanderTeam;
|
||||
DamagedBaseStructures.ReachabilityTeam = CommanderTeam;
|
||||
DamagedBaseStructures.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
|
||||
DamagedBaseStructures.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||
DamagedBaseStructures.IncludeStatusFlags = STRUCTURE_STATUS_DAMAGED;
|
||||
DamagedBaseStructures.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||
DamagedBaseStructures.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
|
||||
|
||||
bBaseIsDamaged = AITAC_DeployableExistsAtLocation(AITAC_GetCommChairLocation(CommanderTeam), &DamagedBaseStructures);
|
||||
|
||||
if (bBaseIsDamaged)
|
||||
{
|
||||
AvHAIDroppedItem* NearestWelder = AITAC_FindClosestItemToLocation(AITAC_GetCommChairLocation(CommanderTeam), DEPLOYABLE_ITEM_WELDER, CommanderTeam, AI_REACHABILITY_MARINE, 0.0f, UTIL_MetresToGoldSrcUnits(15.0f), false);
|
||||
bool bPlayerHasWelder = false;
|
||||
|
||||
if (!NearestWelder)
|
||||
{
|
||||
vector<AvHPlayer*> PlayersAtBase = AITAC_GetAllPlayersOfTeamInArea(CommanderTeam, AITAC_GetCommChairLocation(CommanderTeam), UTIL_MetresToGoldSrcUnits(15.0f), false, pBot->Edict, AVH_USER3_COMMANDER_PLAYER);
|
||||
|
||||
for (auto it = PlayersAtBase.begin(); it != PlayersAtBase.end(); it++)
|
||||
{
|
||||
AvHPlayer* ThisPlayer = (*it);
|
||||
|
||||
if (PlayerHasWeapon(ThisPlayer, WEAPON_MARINE_WELDER))
|
||||
{
|
||||
bPlayerHasWelder = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!NearestWelder && !bPlayerHasWelder)
|
||||
{
|
||||
DeployableSearchFilter ArmouryFilter;
|
||||
ArmouryFilter.DeployableTypes = (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY);
|
||||
ArmouryFilter.DeployableTeam = CommanderTeam;
|
||||
ArmouryFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||
ArmouryFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||
|
||||
AvHAIBuildableStructure* NearestArmoury = AITAC_FindClosestDeployableToLocation(AITAC_GetTeamStartingLocation(CommanderTeam), &ArmouryFilter);
|
||||
|
||||
if (NearestArmoury)
|
||||
{
|
||||
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), NearestArmoury->Location, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
bool bSuccess = AICOMM_DeployItem(pBot, DEPLOYABLE_ITEM_WELDER, DeployLocation);
|
||||
|
||||
return bSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Now work out how many welders we want on the team generally
|
||||
|
||||
int NumDesiredWelders = 1;
|
||||
|
||||
if (!AICOMM_ShouldCommanderPrioritiseNodes(pBot))
|
||||
{
|
||||
NumDesiredWelders = (int)ceilf((float)AIMGR_GetNumPlayersOnTeam(CommanderTeam) * 0.3f);
|
||||
return false;
|
||||
}
|
||||
|
||||
int NumTeamWelders = AITAC_GetNumWeaponsInPlay(CommanderTeam, WEAPON_MARINE_WELDER);
|
||||
|
||||
// Add additional welders to the team if we have hives or resource nodes which can only be reached with a welder
|
||||
|
||||
vector<AvHAIResourceNode*> AllNodes = AITAC_GetAllResourceNodes();
|
||||
|
||||
for (auto it = AllNodes.begin(); it != AllNodes.end(); it++)
|
||||
|
@ -1127,7 +1219,7 @@ bool AICOMM_CheckForNextSupplyAction(AvHAIPlayer* pBot)
|
|||
}
|
||||
}
|
||||
|
||||
NumDesiredWelders = imini(NumDesiredWelders, (AIMGR_GetNumPlayersOnTeam(CommanderTeam) / 2));
|
||||
NumDesiredWelders = imini(NumDesiredWelders, (int)(ceilf((float)AIMGR_GetNumPlayersOnTeam(CommanderTeam) * 0.5f)));
|
||||
|
||||
if (NumTeamWelders < NumDesiredWelders)
|
||||
{
|
||||
|
@ -1149,9 +1241,7 @@ bool AICOMM_CheckForNextSupplyAction(AvHAIPlayer* pBot)
|
|||
}
|
||||
|
||||
// Don't drop stuff if we badly need resource nodes
|
||||
if (AICOMM_ShouldCommanderPrioritiseNodes(pBot)) { return false; }
|
||||
|
||||
if (pBot->Player->GetResources() < 30) { return false; }
|
||||
if (AICOMM_ShouldCommanderPrioritiseNodes(pBot) && pBot->Player->GetResources() < 20) { return false; }
|
||||
|
||||
|
||||
int NumDesiredShotguns = (int)ceilf(AIMGR_GetNumPlayersOnTeam(CommanderTeam) * 0.33f);
|
||||
|
@ -1232,9 +1322,94 @@ bool AICOMM_CheckForNextSupplyAction(AvHAIPlayer* pBot)
|
|||
}
|
||||
}
|
||||
|
||||
if (AITAC_ResearchIsComplete(CommanderTeam, TECH_RESEARCH_HEAVYARMOR))
|
||||
{
|
||||
if (!AITAC_ResearchIsComplete(CommanderTeam, TECH_RESEARCH_HEAVYARMOR)) { return false; }
|
||||
|
||||
DeployableSearchFilter StructureFilter;
|
||||
StructureFilter.DeployableTypes = STRUCTURE_MARINE_ADVARMOURY;
|
||||
StructureFilter.DeployableTeam = CommanderTeam;
|
||||
StructureFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||
StructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||
|
||||
AvHAIBuildableStructure* NearestAdvArmoury = AITAC_FindClosestDeployableToLocation(AITAC_GetTeamStartingLocation(CommanderTeam), &StructureFilter);
|
||||
|
||||
StructureFilter.DeployableTypes = STRUCTURE_MARINE_PROTOTYPELAB;
|
||||
AvHAIBuildableStructure* NearestPrototypeLab = AITAC_FindClosestDeployableToLocation(AITAC_GetTeamStartingLocation(CommanderTeam), &StructureFilter);
|
||||
|
||||
if (!NearestAdvArmoury || !NearestPrototypeLab) { return false; }
|
||||
|
||||
AvHAIDroppedItem* ExistingHA = AITAC_FindClosestItemToLocation(NearestPrototypeLab->Location, DEPLOYABLE_ITEM_HEAVYARMOUR, CommanderTeam, AI_REACHABILITY_MARINE, 0.0f, UTIL_MetresToGoldSrcUnits(5.0f), false);
|
||||
AvHAIDroppedItem* ExistingHMG = AITAC_FindClosestItemToLocation(NearestAdvArmoury->Location, DEPLOYABLE_ITEM_HMG, CommanderTeam, AI_REACHABILITY_MARINE, 0.0f, UTIL_MetresToGoldSrcUnits(5.0f), false);
|
||||
AvHAIDroppedItem* ExistingWelder = AITAC_FindClosestItemToLocation(NearestAdvArmoury->Location, DEPLOYABLE_ITEM_WELDER, CommanderTeam, AI_REACHABILITY_MARINE, 0.0f, UTIL_MetresToGoldSrcUnits(5.0f), false);
|
||||
|
||||
if (ExistingHA && ExistingHMG && ExistingWelder) { return false; }
|
||||
|
||||
vector<edict_t*> NearbyPlayers = AITAC_GetAllPlayersOfClassInArea(CommanderTeam, NearestAdvArmoury->Location, UTIL_MetresToGoldSrcUnits(10.0f), false, pBot->Edict, AVH_USER3_MARINE_PLAYER);
|
||||
|
||||
bool bDropWeapon = false;
|
||||
bool bDropWelder = false;
|
||||
|
||||
for (auto it = NearbyPlayers.begin(); it != NearbyPlayers.end(); it++)
|
||||
{
|
||||
edict_t* PlayerEdict = (*it);
|
||||
AvHPlayer* PlayerRef = dynamic_cast<AvHPlayer*>(CBaseEntity::Instance(PlayerEdict));
|
||||
if (!PlayerEdict) { continue; }
|
||||
|
||||
if (PlayerHasHeavyArmour(PlayerEdict) || PlayerHasJetpack(PlayerEdict))
|
||||
{
|
||||
if (PlayerHasWeapon(PlayerRef, WEAPON_MARINE_MG) || UTIL_GetPlayerPrimaryWeapon(PlayerRef) == WEAPON_INVALID)
|
||||
{
|
||||
bDropWeapon = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!PlayerHasWeapon(PlayerRef, WEAPON_MARINE_WELDER))
|
||||
{
|
||||
bDropWelder = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ExistingHA && !bDropWelder && !bDropWeapon)
|
||||
{
|
||||
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestPrototypeLab->Location, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
|
||||
if (vIsZero(DeployLocation))
|
||||
{
|
||||
DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), NearestPrototypeLab->Location, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
}
|
||||
|
||||
bool bSuccess = AICOMM_DeployItem(pBot, DEPLOYABLE_ITEM_HEAVYARMOUR, DeployLocation);
|
||||
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
if (bDropWeapon && !ExistingHMG)
|
||||
{
|
||||
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestAdvArmoury->Location, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
|
||||
if (vIsZero(DeployLocation))
|
||||
{
|
||||
DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), NearestAdvArmoury->Location, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
}
|
||||
|
||||
bool bSuccess = AICOMM_DeployItem(pBot, DEPLOYABLE_ITEM_HMG, DeployLocation);
|
||||
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
if (bDropWelder && !ExistingWelder)
|
||||
{
|
||||
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestAdvArmoury->Location, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
|
||||
if (vIsZero(DeployLocation))
|
||||
{
|
||||
DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), NearestAdvArmoury->Location, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
}
|
||||
|
||||
bool bSuccess = AICOMM_DeployItem(pBot, DEPLOYABLE_ITEM_WELDER, DeployLocation);
|
||||
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -1649,17 +1824,17 @@ bool AICOMM_PerformNextSiegeHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinit
|
|||
{
|
||||
SiegeLocation = ExistingTF->Location;
|
||||
|
||||
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), SiegeLocation, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingTF->Location, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
|
||||
if (vIsZero(NextBuildPosition))
|
||||
{
|
||||
// Reduce radius to avoid putting it on the other side of a wall or something
|
||||
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), SiegeLocation, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingTF->Location, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
|
||||
if (vIsZero(NextBuildPosition))
|
||||
{
|
||||
// Fall-back, this could end up putting the structure in dodgy spots but better than not placing it at all
|
||||
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), SiegeLocation, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), ExistingTF->Location, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -103,6 +103,7 @@ typedef enum
|
|||
STRUCTURE_STATUS_PARASITED = 1 << 3,
|
||||
STRUCTURE_STATUS_UNDERATTACK = 1 << 4,
|
||||
STRUCTURE_STATUS_RESEARCHING = 1 << 5,
|
||||
STRUCTURE_STATUS_DAMAGED = 1 << 6,
|
||||
|
||||
STRUCTURE_STATUS_ALL = -1
|
||||
} AvHAIStructureStatus;
|
||||
|
@ -536,6 +537,14 @@ typedef struct _AVH_AI_PLAYER_MOVE_TASK
|
|||
bool bPathGenerated = false;
|
||||
} AvHAIPlayerMoveTask;
|
||||
|
||||
typedef struct _AVH_AI_STUCK_TRACKER
|
||||
{
|
||||
Vector LastBotPosition = g_vecZero;
|
||||
Vector MoveDestination = g_vecZero;
|
||||
float TotalStuckTime = 0.0f; // Total time the bot has spent stuck
|
||||
|
||||
} AvHAIPlayerStuckTracker;
|
||||
|
||||
// Contains the bot's current navigation info, such as current path
|
||||
typedef struct _NAV_STATUS
|
||||
{
|
||||
|
@ -559,8 +568,6 @@ typedef struct _NAV_STATUS
|
|||
|
||||
Vector StuckCheckMoveLocation = g_vecZero; // Where is the bot trying to go that we're checking if they're stuck?
|
||||
Vector UnstuckMoveLocation = g_vecZero; // If the bot is unable to find a path, blindly move here to try and fix the problem
|
||||
Vector UnstuckMoveStartLocation = g_vecZero; // So the bot can track where it was when it started the unstuck movement
|
||||
float UnstuckMoveLocationStartTime = 0.0f; // When did the bot start trying to move to UnstuckMoveLocation? Give up after certain amount of time
|
||||
|
||||
float LandedTime = 0.0f; // When the bot last landed after a fall/jump.
|
||||
float LeapAttemptedTime = 0.0f; // When the bot last attempted to leap/blink. Avoid spam that sends it flying around too fast
|
||||
|
@ -583,6 +590,8 @@ typedef struct _NAV_STATUS
|
|||
nav_profile NavProfile;
|
||||
bool bNavProfileChanged = false;
|
||||
|
||||
AvHAIPlayerStuckTracker StuckInfo;
|
||||
|
||||
unsigned int SpecialMovementFlags = 0; // Any special movement flags required for this path (e.g. needs a welder, needs a jetpack etc.)
|
||||
|
||||
AvHAIPlayerMoveTask MovementTask;
|
||||
|
|
|
@ -158,9 +158,9 @@ Vector UTIL_GetFloorUnderEntity(const edict_t* Edict)
|
|||
|
||||
TraceResult hit;
|
||||
|
||||
Vector EntityCentre = UTIL_GetCentreOfEntity(Edict);
|
||||
Vector EntityCentre = UTIL_GetCentreOfEntity(Edict) + Vector(0.0f, 0.0f, 1.0f);
|
||||
|
||||
UTIL_TraceHull(EntityCentre, (EntityCentre - Vector(0.0f, 0.0f, 1000.0f)), ignore_monsters, GetPlayerHullIndex(Edict), Edict->v.pContainingEntity, &hit);
|
||||
UTIL_TraceHull(EntityCentre, (EntityCentre - Vector(0.0f, 0.0f, 1000.0f)), ignore_monsters, head_hull, Edict->v.pContainingEntity, &hit);
|
||||
|
||||
if (hit.flFraction < 1.0f)
|
||||
{
|
||||
|
|
|
@ -442,6 +442,8 @@ unsigned int UTIL_AddTemporaryObstacle(unsigned int NavMeshIndex, const Vector L
|
|||
|
||||
void UTIL_AddStructureTemporaryObstacles(AvHAIBuildableStructure* Structure)
|
||||
{
|
||||
if (Structure->StructureType == STRUCTURE_MARINE_DEPLOYEDMINE) { return; }
|
||||
|
||||
bool bCollideWithPlayers = UTIL_ShouldStructureCollide(Structure->StructureType);
|
||||
|
||||
float Radius = UTIL_GetStructureRadiusForObstruction(Structure->StructureType);
|
||||
|
@ -3821,6 +3823,7 @@ void LiftMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint)
|
|||
void PhaseGateMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint)
|
||||
{
|
||||
DeployableSearchFilter PGFilter;
|
||||
PGFilter.DeployableTeam = pBot->Player->GetTeam();
|
||||
PGFilter.DeployableTypes = STRUCTURE_MARINE_PHASEGATE;
|
||||
PGFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(2.0f);
|
||||
PGFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||
|
@ -3945,7 +3948,7 @@ bool IsBotOffPath(const AvHAIPlayer* pBot)
|
|||
{
|
||||
Vector ExactJumpTarget = UTIL_GetGroundLocation(MoveTo);
|
||||
|
||||
if (pBot->BotNavInfo.IsOnGround && (MoveTo.z - pBot->CurrentFloorPosition.z) > max_player_jump_height)
|
||||
if (pBot->BotNavInfo.IsOnGround && (ExactJumpTarget.z - pBot->CurrentFloorPosition.z) > max_player_jump_height)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -4256,6 +4259,7 @@ void MoveDirectlyTo(AvHAIPlayer* pBot, const Vector Destination)
|
|||
|
||||
HandlePlayerAvoidance(pBot, Destination);
|
||||
BotMovementInputs(pBot);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -4952,12 +4956,6 @@ bool AbortCurrentMove(AvHAIPlayer* pBot, const Vector NewDestination)
|
|||
{
|
||||
if (pBot->BotNavInfo.CurrentPath.size() == 0 || pBot->BotNavInfo.NavProfile.bFlyingProfile) { return true; }
|
||||
|
||||
if (IsBotPermaStuck(pBot))
|
||||
{
|
||||
BotSuicide(pBot);
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector MoveFrom = pBot->BotNavInfo.CurrentPathPoint->FromLocation;
|
||||
Vector MoveTo = pBot->BotNavInfo.CurrentPathPoint->Location;
|
||||
unsigned int flag = pBot->BotNavInfo.CurrentPathPoint->flag;
|
||||
|
@ -5092,20 +5090,37 @@ bool AbortCurrentMove(AvHAIPlayer* pBot, const Vector NewDestination)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool IsBotPermaStuck(AvHAIPlayer* pBot)
|
||||
void UpdateBotStuck(AvHAIPlayer* pBot)
|
||||
{
|
||||
if (MAX_BOT_STUCK_TIME <= 0.1f) { return false; }
|
||||
|
||||
if (vIsZero(pBot->LastPosition) || vDist3DSq(pBot->Edict->v.origin, pBot->LastPosition) > sqrf(32.0f))
|
||||
if (vIsZero(pBot->desiredMovementDir))
|
||||
{
|
||||
pBot->TimeSinceLastMovement = 0.0f;
|
||||
pBot->LastPosition = pBot->Edict->v.origin;
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
pBot->TimeSinceLastMovement += AIMGR_GetBotDeltaTime();
|
||||
bool bIsFollowingPath = (pBot->BotNavInfo.CurrentPath.size() > 0 && pBot->BotNavInfo.CurrentPathPoint != pBot->BotNavInfo.CurrentPath.end());
|
||||
|
||||
return (pBot->TimeSinceLastMovement >= 30.0f);
|
||||
bool bDist3D = pBot->BotNavInfo.NavProfile.bFlyingProfile || (bIsFollowingPath && (pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_LADDER || pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_WALLCLIMB));
|
||||
|
||||
float DistFromLastPoint = (bDist3D) ? vDist3DSq(pBot->Edict->v.origin, pBot->BotNavInfo.StuckInfo.LastBotPosition) : vDist2DSq(pBot->Edict->v.origin, pBot->BotNavInfo.StuckInfo.LastBotPosition);
|
||||
|
||||
if (DistFromLastPoint >= sqrf(8.0f))
|
||||
{
|
||||
pBot->BotNavInfo.StuckInfo.TotalStuckTime = 0.0f;
|
||||
pBot->BotNavInfo.StuckInfo.LastBotPosition = pBot->Edict->v.origin;
|
||||
}
|
||||
else
|
||||
{
|
||||
pBot->BotNavInfo.StuckInfo.TotalStuckTime += AIMGR_GetBotDeltaTime();
|
||||
}
|
||||
|
||||
if (pBot->BotNavInfo.StuckInfo.TotalStuckTime > 0.25f)
|
||||
{
|
||||
BotJump(pBot);
|
||||
if (!IsPlayerSkulk(pBot->Edict))
|
||||
{
|
||||
pBot->Button |= IN_DUCK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetBaseNavProfile(AvHAIPlayer* pBot)
|
||||
|
@ -5355,7 +5370,7 @@ void OnosUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle)
|
|||
|
||||
bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle MoveStyle, const float MaxAcceptableDist)
|
||||
{
|
||||
if (vIsZero(Destination) || (vDist2D(pBot->Edict->v.origin, Destination) <= 8.0f && (fabs(pBot->CollisionHullBottomLocation.z - Destination.z) < 50.0f)))
|
||||
if (vIsZero(Destination) || (vDist2D(pBot->Edict->v.origin, Destination) <= 6.0f && (fabs(pBot->CollisionHullBottomLocation.z - Destination.z) < 50.0f)))
|
||||
{
|
||||
ClearBotMovement(pBot);
|
||||
return true;
|
||||
|
@ -5449,12 +5464,6 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
|
|||
}
|
||||
}
|
||||
|
||||
if (IsBotPermaStuck(pBot))
|
||||
{
|
||||
BotSuicide(pBot);
|
||||
return false;
|
||||
}
|
||||
|
||||
ClearBotPath(pBot);
|
||||
return false;
|
||||
}
|
||||
|
@ -5494,12 +5503,6 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
|
|||
}
|
||||
}
|
||||
|
||||
if (IsBotPermaStuck(pBot))
|
||||
{
|
||||
BotSuicide(pBot);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pBot->Edict->v.flags & FL_INWATER)
|
||||
{
|
||||
BotFollowSwimPath(pBot);
|
||||
|
@ -5633,7 +5636,11 @@ void SkipAheadInFlightPath(AvHAIPlayer* pBot)
|
|||
|
||||
void BotFollowFlightPath(AvHAIPlayer* pBot)
|
||||
{
|
||||
if (pBot->BotNavInfo.CurrentPath.size() == 0) { return; }
|
||||
if (pBot->BotNavInfo.CurrentPath.size() == 0)
|
||||
{
|
||||
ClearBotStuck(pBot);
|
||||
return;
|
||||
}
|
||||
|
||||
nav_status* BotNavInfo = &pBot->BotNavInfo;
|
||||
edict_t* pEdict = pBot->Edict;
|
||||
|
@ -5680,15 +5687,6 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
|
|||
|
||||
Vector MoveDir = UTIL_GetVectorNormal(CurrentMoveDest - MoveFrom);
|
||||
|
||||
if (IsBotStuck(pBot, CurrentMoveDest))
|
||||
{
|
||||
if (BotNavInfo->TotalStuckTime > 3.0f)
|
||||
{
|
||||
ClearBotPath(pBot);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
float CurrentSpeed = vSize3D(pEdict->v.velocity);
|
||||
|
||||
if (vDist2DSq(pEdict->v.origin, MoveFrom) > sqrf(100.0f) && vDist2DSq(pEdict->v.origin, CurrentMoveDest) > sqrf(100.0f))
|
||||
|
@ -5854,6 +5852,7 @@ void BotFollowPath(AvHAIPlayer* pBot)
|
|||
nav_status* BotNavInfo = &pBot->BotNavInfo;
|
||||
edict_t* pEdict = pBot->Edict;
|
||||
|
||||
|
||||
// If we've reached our current path point
|
||||
if (HasBotReachedPathPoint(pBot))
|
||||
{
|
||||
|
@ -5877,33 +5876,8 @@ void BotFollowPath(AvHAIPlayer* pBot)
|
|||
|
||||
Vector MoveTo = BotNavInfo->CurrentPathPoint->Location;
|
||||
|
||||
unsigned int CurrentFlag = BotNavInfo->CurrentPathPoint->flag;
|
||||
|
||||
bool bIsUsingPhaseGate = (CurrentFlag == SAMPLE_POLYFLAGS_TEAM1PHASEGATE || CurrentFlag == SAMPLE_POLYFLAGS_TEAM2PHASEGATE);
|
||||
|
||||
NewMove(pBot);
|
||||
|
||||
if (!bIsUsingPhaseGate && IsBotStuck(pBot, MoveTo))
|
||||
{
|
||||
if (BotNavInfo->TotalStuckTime > 3.0f)
|
||||
{
|
||||
ClearBotPath(pBot);
|
||||
return;
|
||||
}
|
||||
|
||||
// If onos, ducking is usually a good way to get unstuck...
|
||||
if (IsPlayerOnos(pBot->Edict))
|
||||
{
|
||||
pBot->Button |= IN_DUCK;
|
||||
}
|
||||
|
||||
if (!IsPlayerClimbingWall(pBot->Edict) && !IsPlayerOnLadder(pBot->Edict))
|
||||
{
|
||||
PerformUnstuckMove(pBot, MoveTo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PerformUnstuckMove(AvHAIPlayer* pBot, const Vector MoveDestination)
|
||||
|
@ -5971,9 +5945,17 @@ void PerformUnstuckMove(AvHAIPlayer* pBot, const Vector MoveDestination)
|
|||
bool IsBotStuck(AvHAIPlayer* pBot, const Vector MoveDestination)
|
||||
{
|
||||
// If invalid move destination then bail out
|
||||
if (vIsZero(MoveDestination) || vIsZero(pBot->desiredMovementDir)) { return false; }
|
||||
if (vIsZero(MoveDestination) || vDist2DSq(pBot->Edict->v.origin, MoveDestination) < sqrf(32.0f))
|
||||
{
|
||||
pBot->BotNavInfo.LastStuckCheckTime = gpGlobals->time;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_LIFT) { return false; }
|
||||
if (pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_LIFT || pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_TEAM1PHASEGATE || pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_TEAM2PHASEGATE)
|
||||
{
|
||||
pBot->BotNavInfo.LastStuckCheckTime = gpGlobals->time;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If moving to a new destination set a new distance baseline. We do not reset the stuck timer
|
||||
if (MoveDestination != pBot->BotNavInfo.StuckCheckMoveLocation)
|
||||
|
@ -5985,7 +5967,7 @@ bool IsBotStuck(AvHAIPlayer* pBot, const Vector MoveDestination)
|
|||
}
|
||||
|
||||
// If first time performing a stuck check, set a baseline time and return false
|
||||
if (pBot->BotNavInfo.LastStuckCheckTime == 0.0f)
|
||||
if (pBot->BotNavInfo.LastStuckCheckTime == 0.0f || gpGlobals->time - pBot->BotNavInfo.LastStuckCheckTime > 3.0f)
|
||||
{
|
||||
pBot->BotNavInfo.LastStuckCheckTime = gpGlobals->time;
|
||||
return false;
|
||||
|
@ -6381,8 +6363,6 @@ void ClearBotStuck(AvHAIPlayer* pBot)
|
|||
pBot->BotNavInfo.LastStuckCheckTime = gpGlobals->time;
|
||||
pBot->BotNavInfo.TotalStuckTime = 0.0f;
|
||||
pBot->BotNavInfo.UnstuckMoveLocation = g_vecZero;
|
||||
pBot->BotNavInfo.UnstuckMoveLocationStartTime = 0.0f;
|
||||
pBot->BotNavInfo.UnstuckMoveStartLocation = g_vecZero;
|
||||
pBot->BotNavInfo.StuckCheckMoveLocation = g_vecZero;
|
||||
}
|
||||
|
||||
|
@ -6677,8 +6657,6 @@ void ClearBotPath(AvHAIPlayer* pBot)
|
|||
void ClearBotStuckMovement(AvHAIPlayer* pBot)
|
||||
{
|
||||
pBot->BotNavInfo.UnstuckMoveLocation = g_vecZero;
|
||||
pBot->BotNavInfo.UnstuckMoveLocationStartTime = 0.0f;
|
||||
pBot->BotNavInfo.UnstuckMoveStartLocation = g_vecZero;
|
||||
}
|
||||
|
||||
void BotMovementInputs(AvHAIPlayer* pBot)
|
||||
|
|
|
@ -309,6 +309,8 @@ bool BotRecalcPath(AvHAIPlayer* pBot, const Vector Destination);
|
|||
*/
|
||||
bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle MoveStyle, const float MaxAcceptableDist = max_ai_use_reach);
|
||||
|
||||
void UpdateBotStuck(AvHAIPlayer* pBot);
|
||||
|
||||
// Used by the MoveTo command, handles the bot's movement and inputs to follow a path it has calculated for itself
|
||||
void BotFollowPath(AvHAIPlayer* pBot);
|
||||
void BotFollowFlightPath(AvHAIPlayer* pBot);
|
||||
|
@ -316,8 +318,6 @@ void BotFollowSwimPath(AvHAIPlayer* pBot);
|
|||
|
||||
void SkipAheadInFlightPath(AvHAIPlayer* pBot);
|
||||
|
||||
// If the bot has been unable to move more than 32 units in the last MaxStuckTime seconds (must be trying to move somewhere) then returns true
|
||||
bool IsBotPermaStuck(AvHAIPlayer* pBot);
|
||||
|
||||
// Walks directly towards the destination. No path finding, just raw movement input. Will detect obstacles and try to jump/duck under them.
|
||||
void MoveDirectlyTo(AvHAIPlayer* pBot, const Vector Destination);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -597,7 +597,7 @@ void AIMGR_UpdateAIPlayers()
|
|||
|
||||
UpdateBotChat(bot);
|
||||
|
||||
AIPlayerThink(bot);
|
||||
DroneThink(bot);
|
||||
|
||||
BotUpdateDesiredViewRotation(bot);
|
||||
}
|
||||
|
@ -659,6 +659,11 @@ AvHTeamNumber AIMGR_GetTeamBNumber()
|
|||
return GetGameRules()->GetTeamANumber();
|
||||
}
|
||||
|
||||
AvHTeam* AIMGR_GetTeamRef(const AvHTeamNumber Team)
|
||||
{
|
||||
return GetGameRules()->GetTeam(Team);
|
||||
}
|
||||
|
||||
vector<AvHPlayer*> AIMGR_GetAllPlayersOnTeam(AvHTeamNumber Team)
|
||||
{
|
||||
vector<AvHPlayer*> Result;
|
||||
|
|
|
@ -72,6 +72,8 @@ AvHClassType AIMGR_GetTeamType(const AvHTeamNumber Team);
|
|||
AvHTeamNumber AIMGR_GetTeamANumber();
|
||||
AvHTeamNumber AIMGR_GetTeamBNumber();
|
||||
|
||||
AvHTeam* AIMGR_GetTeamRef(const AvHTeamNumber Team);
|
||||
|
||||
// Returns all NS AI players. Does not include third-party bots
|
||||
vector<AvHAIPlayer*> AIMGR_GetAllAIPlayers();
|
||||
// Returns all NS AI players on the requested team. Does not include third-party bots
|
||||
|
|
|
@ -1760,6 +1760,13 @@ void AITAC_RefreshReachabilityForStructure(AvHAIBuildableStructure* Structure)
|
|||
AITAC_RefreshHiveData();
|
||||
}
|
||||
|
||||
if (Structure->StructureType == STRUCTURE_MARINE_DEPLOYEDMINE)
|
||||
{
|
||||
Structure->TeamAReachabilityFlags = AI_REACHABILITY_ALL;
|
||||
Structure->TeamBReachabilityFlags = AI_REACHABILITY_ALL;
|
||||
return;
|
||||
}
|
||||
|
||||
Structure->bReachabilityMarkedDirty = false;
|
||||
|
||||
Structure->TeamAReachabilityFlags = AI_REACHABILITY_NONE;
|
||||
|
@ -1891,23 +1898,47 @@ AvHAIBuildableStructure* AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
|
|||
{
|
||||
if (!Structure || (Structure->pev->effects & EF_NODRAW) || (Structure->pev->deadflag != DEAD_NO)) { return nullptr; }
|
||||
|
||||
AvHBaseBuildable* BaseBuildable = dynamic_cast<AvHBaseBuildable*>(Structure);
|
||||
edict_t* BuildingEdict = Structure->edict();
|
||||
|
||||
if (!BaseBuildable) { return nullptr; }
|
||||
|
||||
edict_t* BuildingEdict = BaseBuildable->edict();
|
||||
|
||||
AvHAIDeployableStructureType StructureType = UTIL_IUSER3ToStructureType(BaseBuildable->pev->iuser3);
|
||||
AvHAIDeployableStructureType StructureType = UTIL_IUSER3ToStructureType(BuildingEdict->v.iuser3);
|
||||
|
||||
if (StructureType == STRUCTURE_NONE) { return nullptr; }
|
||||
|
||||
int EntIndex = BaseBuildable->entindex();
|
||||
int EntIndex = ENTINDEX(BuildingEdict);
|
||||
|
||||
if (EntIndex < 0) { return nullptr; }
|
||||
|
||||
AvHTeamNumber TeamANumber = GetGameRules()->GetTeamANumber();
|
||||
AvHTeamNumber TeamBNumber = GetGameRules()->GetTeamBNumber();
|
||||
|
||||
std::unordered_map<int, AvHAIBuildableStructure>& BuildingMap = (BaseBuildable->GetTeamNumber() == TeamANumber) ? TeamAStructureMap : TeamBStructureMap;
|
||||
std::unordered_map<int, AvHAIBuildableStructure>& BuildingMap = ((AvHTeamNumber)BuildingEdict->v.team == TeamANumber) ? TeamAStructureMap : TeamBStructureMap;
|
||||
|
||||
if (StructureType == STRUCTURE_MARINE_DEPLOYEDMINE)
|
||||
{
|
||||
BuildingMap[EntIndex].StructureType = StructureType;
|
||||
if (BuildingMap[EntIndex].LastSeen == 0)
|
||||
{
|
||||
BuildingMap[EntIndex].Location = BuildingEdict->v.origin;
|
||||
BuildingMap[EntIndex].edict = BuildingEdict;
|
||||
BuildingMap[EntIndex].healthPercent = 1.0f;
|
||||
BuildingMap[EntIndex].EntityRef = nullptr;
|
||||
BuildingMap[EntIndex].StructureStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||
BuildingMap[EntIndex].TeamAReachabilityFlags = AI_REACHABILITY_ALL;
|
||||
BuildingMap[EntIndex].TeamBReachabilityFlags = AI_REACHABILITY_ALL;
|
||||
AITAC_OnStructureCreated(&BuildingMap[EntIndex]);
|
||||
}
|
||||
|
||||
BuildingMap[EntIndex].LastSeen = StructureRefreshFrame;
|
||||
|
||||
return &BuildingMap[EntIndex];
|
||||
}
|
||||
|
||||
AvHBaseBuildable* BaseBuildable = dynamic_cast<AvHBaseBuildable*>(Structure);
|
||||
|
||||
if (!BaseBuildable)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BuildingMap[EntIndex].StructureType = StructureType;
|
||||
|
||||
|
@ -1980,6 +2011,11 @@ AvHAIBuildableStructure* AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
|
|||
|
||||
BuildingMap[EntIndex].healthPercent = NewHealthPercent;
|
||||
|
||||
if (BuildingMap[EntIndex].healthPercent < 0.99f && BaseBuildable->GetIsBuilt())
|
||||
{
|
||||
NewFlags |= STRUCTURE_STATUS_DAMAGED;
|
||||
}
|
||||
|
||||
if (gpGlobals->time - BuildingMap[EntIndex].lastDamagedTime < 10.0f)
|
||||
{
|
||||
NewFlags |= STRUCTURE_STATUS_UNDERATTACK;
|
||||
|
@ -2008,7 +2044,7 @@ void AITAC_OnStructureCreated(AvHAIBuildableStructure* NewStructure)
|
|||
|
||||
UTIL_AddStructureTemporaryObstacles(NewStructure);
|
||||
|
||||
AvHTeamNumber StructureTeam = NewStructure->EntityRef->GetTeamNumber();
|
||||
AvHTeamNumber StructureTeam = (AvHTeamNumber)NewStructure->edict->v.team;
|
||||
|
||||
AITAC_RefreshReachabilityForStructure(NewStructure);
|
||||
|
||||
|
@ -2018,9 +2054,9 @@ void AITAC_OnStructureCreated(AvHAIBuildableStructure* NewStructure)
|
|||
|
||||
if (!Team) { return; }
|
||||
|
||||
if (Team->GetTeamType() == AVH_CLASS_TYPE_ALIEN)
|
||||
if (Team->GetTeamType() == AVH_CLASS_TYPE_ALIEN || NewStructure->StructureType == STRUCTURE_MARINE_DEPLOYEDMINE)
|
||||
{
|
||||
AITAC_LinkAlienStructureToPlayer(NewStructure);
|
||||
AITAC_LinkStructureToPlayer(NewStructure);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2156,7 +2192,7 @@ void AITAC_OnStructureDestroyed(AvHAIBuildableStructure* DestroyedStructure)
|
|||
}
|
||||
}
|
||||
|
||||
void AITAC_LinkAlienStructureToPlayer(AvHAIBuildableStructure* NewStructure)
|
||||
void AITAC_LinkStructureToPlayer(AvHAIBuildableStructure* NewStructure)
|
||||
{
|
||||
vector<AvHAIPlayer*> AllTeamPlayers = AIMGR_GetAIPlayersOnTeam((AvHTeamNumber)NewStructure->edict->v.team);
|
||||
|
||||
|
@ -2370,6 +2406,8 @@ float UTIL_GetStructureRadiusForObstruction(AvHAIDeployableStructureType Structu
|
|||
return 60.0f;
|
||||
case STRUCTURE_MARINE_TURRET:
|
||||
return 30.0f;
|
||||
case STRUCTURE_MARINE_DEPLOYEDMINE:
|
||||
return 12.0f;
|
||||
default:
|
||||
return 40.0f;
|
||||
|
||||
|
@ -3120,24 +3158,18 @@ Vector UTIL_GetNextMinePosition(edict_t* StructureToMine)
|
|||
bool bBack = false;
|
||||
bool bLeft = false;
|
||||
|
||||
int NumMines = 0;
|
||||
DeployableSearchFilter MineFilter;
|
||||
MineFilter.DeployableTeam = StructureTeam;
|
||||
MineFilter.DeployableTypes = STRUCTURE_MARINE_DEPLOYEDMINE;
|
||||
MineFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(3.0f);
|
||||
|
||||
AvHTeamNumber TeamANumber = GetGameRules()->GetTeamANumber();
|
||||
AvHTeamNumber TeamBNumber = GetGameRules()->GetTeamBNumber();
|
||||
vector<AvHAIBuildableStructure*> SurroundingMines = AITAC_FindAllDeployables(StructureToMine->v.origin, &MineFilter);
|
||||
|
||||
std::unordered_map<int, AvHAIBuildableStructure>& BuildingMap = (StructureTeam == TeamANumber) ? TeamAStructureMap : TeamBStructureMap;
|
||||
|
||||
for (auto& it : BuildingMap)
|
||||
for (auto it = SurroundingMines.begin(); it != SurroundingMines.end(); it++)
|
||||
{
|
||||
unsigned int TeamReachabilityFlag = (StructureTeam == TeamANumber) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
|
||||
AvHAIBuildableStructure* ThisMine = (*it);
|
||||
|
||||
if (it.second.StructureType != STRUCTURE_MARINE_DEPLOYEDMINE || !(TeamReachabilityFlag & AI_REACHABILITY_MARINE)) { continue; }
|
||||
|
||||
if (vDist2DSq(StructureToMine->v.origin, it.second.Location) > sqrf(UTIL_MetresToGoldSrcUnits(2.0f))) { continue; }
|
||||
|
||||
NumMines++;
|
||||
|
||||
Vector Dir = UTIL_GetVectorNormal2D(it.second.Location - StructureToMine->v.origin);
|
||||
Vector Dir = UTIL_GetVectorNormal2D(ThisMine->Location - StructureToMine->v.origin);
|
||||
|
||||
if (UTIL_GetDotProduct2D(FwdVector, Dir) > 0.7f)
|
||||
{
|
||||
|
@ -3158,7 +3190,6 @@ Vector UTIL_GetNextMinePosition(edict_t* StructureToMine)
|
|||
{
|
||||
bLeft = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
float Size = fmaxf(StructureToMine->v.size.x, StructureToMine->v.size.y);
|
||||
|
@ -3212,7 +3243,7 @@ Vector UTIL_GetNextMinePosition(edict_t* StructureToMine)
|
|||
}
|
||||
}
|
||||
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInDonut(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], StructureToMine->v.origin, Size, Size + 16.0f);
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), StructureToMine->v.origin, Size);
|
||||
|
||||
return BuildLocation;
|
||||
}
|
||||
|
@ -3415,6 +3446,35 @@ bool AITAC_AnyPlayerOnTeamHasLOSToLocation(AvHTeamNumber Team, const Vector& Loc
|
|||
return false;
|
||||
}
|
||||
|
||||
vector<AvHPlayer*> AITAC_GetAllPlayersOnTeamWithLOS(AvHTeamNumber Team, const Vector& Location, float SearchRadius, edict_t* IgnorePlayer)
|
||||
{
|
||||
vector<AvHPlayer*> Results;
|
||||
|
||||
float distSq = sqrf(SearchRadius);
|
||||
|
||||
for (int i = 1; i <= gpGlobals->maxClients; i++)
|
||||
{
|
||||
edict_t* PlayerEdict = INDEXENT(i);
|
||||
|
||||
if (!FNullEnt(PlayerEdict) && PlayerEdict != IgnorePlayer && PlayerEdict->v.team == Team && IsPlayerActiveInGame(PlayerEdict))
|
||||
{
|
||||
float ThisDist = vDist2DSq(PlayerEdict->v.origin, Location);
|
||||
|
||||
if (ThisDist <= distSq && UTIL_QuickTrace(PlayerEdict, GetPlayerEyePosition(PlayerEdict), Location))
|
||||
{
|
||||
AvHPlayer* PlayerRef = dynamic_cast<AvHPlayer*>(CBaseEntity::Instance(PlayerEdict));
|
||||
|
||||
if (PlayerRef)
|
||||
{
|
||||
Results.push_back(PlayerRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Results;
|
||||
}
|
||||
|
||||
bool AITAC_GetNumPlayersOnTeamWithLOS(AvHTeamNumber Team, const Vector& Location, float SearchRadius, edict_t* IgnorePlayer)
|
||||
{
|
||||
int Result = 0;
|
||||
|
@ -3591,6 +3651,9 @@ const AvHAIHiveDefinition* AITAC_GetNearestHiveUnderActiveSiege(AvHTeamNumber Si
|
|||
AvHAIHiveDefinition* Result = nullptr;
|
||||
float MinDist = 0.0f;
|
||||
|
||||
// Only marines can siege, so return nothing if the enemy are not marines
|
||||
if (AIMGR_GetTeamType(SiegingTeam) != AVH_CLASS_TYPE_MARINE) { return nullptr; }
|
||||
|
||||
for (auto it = Hives.begin(); it != Hives.end(); it++)
|
||||
{
|
||||
if (it->Status == HIVE_STATUS_UNBUILT) { continue; }
|
||||
|
|
|
@ -45,7 +45,7 @@ void AITAC_OnStructureCompleted(AvHAIBuildableStructure* NewStructure);
|
|||
void AITAC_OnStructureBeginRecycling(AvHAIBuildableStructure* RecyclingStructure);
|
||||
void AITAC_OnStructureDestroyed(AvHAIBuildableStructure* DestroyedStructure);
|
||||
void AITAC_LinkDeployedItemToAction(AvHAIPlayer* CommanderBot, const AvHAIDroppedItem* NewItem);
|
||||
void AITAC_LinkAlienStructureToPlayer(AvHAIBuildableStructure* NewStructure);
|
||||
void AITAC_LinkStructureToPlayer(AvHAIBuildableStructure* NewStructure);
|
||||
|
||||
float AITAC_GetPhaseDistanceBetweenPoints(const Vector StartPoint, const Vector EndPoint);
|
||||
|
||||
|
@ -80,6 +80,7 @@ AvHMessageID UTIL_ItemTypeToImpulseCommand(const AvHAIDeployableItemType ItemTyp
|
|||
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);
|
||||
bool AITAC_GetNumPlayersOnTeamWithLOS(AvHTeamNumber Team, const Vector& Location, float SearchRadius, edict_t* IgnorePlayer);
|
||||
vector<AvHPlayer*> AITAC_GetAllPlayersOnTeamWithLOS(AvHTeamNumber Team, const Vector& Location, float SearchRadius, edict_t* IgnorePlayer);
|
||||
bool AITAC_ShouldBotBeCautious(AvHAIPlayer* pBot);
|
||||
|
||||
// Clears out the marine and alien buildable structure maps, resource node and hive lists, and the marine item list
|
||||
|
|
|
@ -1129,39 +1129,25 @@ void BotProgressPickupTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
|
||||
void BotProgressMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||
{
|
||||
float DistToPlaceLocation = vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation);
|
||||
|
||||
if (DistToPlaceLocation < sqrf(UTIL_MetresToGoldSrcUnits(3.0f)))
|
||||
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING)
|
||||
{
|
||||
pBot->DesiredCombatWeapon = WEAPON_MARINE_MINES;
|
||||
}
|
||||
|
||||
if (!FNullEnt(Task->TaskSecondaryTarget))
|
||||
{
|
||||
Task->TaskLocation = g_vecZero;
|
||||
Task->TaskSecondaryTarget = nullptr;
|
||||
Task->BuildAttempts = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Task->bIsWaitingForBuildLink)
|
||||
if (pBot->ActiveBuildInfo.BuildStatus != BUILD_ATTEMPT_NONE)
|
||||
{
|
||||
|
||||
if (gpGlobals->time - Task->LastBuildAttemptTime > 1.0f)
|
||||
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED)
|
||||
{
|
||||
Task->bIsWaitingForBuildLink = false;
|
||||
if (Task->BuildAttempts > 3)
|
||||
{
|
||||
float Size = fmaxf(Task->TaskTarget->v.size.x, Task->TaskTarget->v.size.y);
|
||||
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], Task->TaskTarget->v.origin, Size + 8.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector Dir = UTIL_GetVectorNormal2D(Task->TaskLocation - Task->TaskTarget->v.origin);
|
||||
Task->TaskLocation = Task->TaskLocation + (Dir * 8.0f);
|
||||
}
|
||||
float Size = fmaxf(Task->TaskTarget->v.size.x, Task->TaskTarget->v.size.y);
|
||||
Size += 8.0f;
|
||||
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInDonut(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), Task->TaskTarget->v.origin, Size, Size + 8.0f);
|
||||
}
|
||||
return;
|
||||
else
|
||||
{
|
||||
Task->TaskLocation = ZERO_VECTOR;
|
||||
}
|
||||
|
||||
pBot->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_NONE;
|
||||
}
|
||||
|
||||
if (vIsZero(Task->TaskLocation))
|
||||
|
@ -1173,22 +1159,23 @@ void BotProgressMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
AITASK_ClearBotTask(pBot, Task);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (DistToPlaceLocation < sqrf(16.0f))
|
||||
{
|
||||
Vector MoveDir = UTIL_GetVectorNormal2D(Task->TaskLocation - pBot->Edict->v.origin);
|
||||
MoveDirectlyTo(pBot, Task->TaskLocation - (MoveDir * 28.0f));
|
||||
return;
|
||||
}
|
||||
|
||||
if (DistToPlaceLocation > sqrf(32.0f))
|
||||
float DistToPlaceLocation = vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation);
|
||||
|
||||
if (DistToPlaceLocation < sqrf(UTIL_MetresToGoldSrcUnits(3.0f)))
|
||||
{
|
||||
pBot->DesiredCombatWeapon = WEAPON_MARINE_MINES;
|
||||
}
|
||||
|
||||
|
||||
if (DistToPlaceLocation > sqrf(8.0f))
|
||||
{
|
||||
MoveTo(pBot, Task->TaskLocation, MOVESTYLE_NORMAL);
|
||||
return;
|
||||
}
|
||||
|
||||
BotLookAt(pBot, Task->TaskLocation);
|
||||
BotDirectLookAt(pBot, Task->TaskLocation);
|
||||
|
||||
if (GetPlayerCurrentWeapon(pBot->Player) == WEAPON_MARINE_MINES)
|
||||
{
|
||||
|
@ -1197,9 +1184,11 @@ void BotProgressMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
if (LookDot > 0.95f)
|
||||
{
|
||||
pBot->Button |= IN_ATTACK;
|
||||
Task->LastBuildAttemptTime = gpGlobals->time;
|
||||
Task->BuildAttempts++;
|
||||
Task->bIsWaitingForBuildLink = true;
|
||||
pBot->ActiveBuildInfo.AttemptedLocation = Task->TaskLocation;
|
||||
pBot->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_PENDING;
|
||||
pBot->ActiveBuildInfo.BuildAttemptTime = gpGlobals->time;
|
||||
pBot->ActiveBuildInfo.AttemptedStructureType = STRUCTURE_MARINE_DEPLOYEDMINE;
|
||||
pBot->ActiveBuildInfo.NumAttempts++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1921,11 +1910,6 @@ void AlienProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!vIsZero(Task->TaskLocation))
|
||||
{
|
||||
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, Task->TaskLocation);
|
||||
}
|
||||
|
||||
// We tried and failed to place the structure
|
||||
if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED)
|
||||
{
|
||||
|
@ -2393,12 +2377,21 @@ void BotProgressWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
|
||||
if (IsPlayerInUseRange(pBot->Edict, Task->TaskTarget))
|
||||
{
|
||||
Vector BBMin = Task->TaskTarget->v.absmin;
|
||||
Vector BBMax = Task->TaskTarget->v.absmax;
|
||||
Vector AimLocation = UTIL_GetCentreOfEntity(Task->TaskTarget);
|
||||
|
||||
vScaleBB(BBMin, BBMax, 0.75f);
|
||||
// If we're targeting a func_weldable, then the centre of the entity might be in a wall or out of reach
|
||||
// so instead aim at the closest point on the func_weldable to us.
|
||||
if (!IsEdictPlayer(Task->TaskTarget) && !IsEdictStructure(Task->TaskTarget))
|
||||
{
|
||||
Vector BBMin = Task->TaskTarget->v.absmin;
|
||||
Vector BBMax = Task->TaskTarget->v.absmax;
|
||||
|
||||
BotLookAt(pBot, vClosestPointOnBB(pBot->CurrentEyePosition, BBMin, BBMax));
|
||||
vScaleBB(BBMin, BBMax, 0.75f);
|
||||
|
||||
AimLocation = vClosestPointOnBB(pBot->CurrentEyePosition, BBMin, BBMax);
|
||||
}
|
||||
|
||||
BotLookAt(pBot, AimLocation);
|
||||
pBot->DesiredCombatWeapon = WEAPON_MARINE_WELDER;
|
||||
|
||||
if (GetPlayerCurrentWeapon(pBot->Player) != WEAPON_MARINE_WELDER)
|
||||
|
|
|
@ -386,6 +386,7 @@ float GetMaxIdealWeaponRange(const AvHAIWeapon Weapon)
|
|||
case WEAPON_SKULK_PARASITE:
|
||||
case WEAPON_SKULK_LEAP:
|
||||
case WEAPON_ONOS_CHARGE:
|
||||
case WEAPON_GORGE_SPIT:
|
||||
return UTIL_MetresToGoldSrcUnits(20.0f);
|
||||
case WEAPON_MARINE_HMG:
|
||||
case WEAPON_MARINE_GRENADE:
|
||||
|
|
Loading…
Reference in a new issue