mirror of
https://github.com/ENSL/NS.git
synced 2024-11-21 12:11:04 +00:00
Further bot improvements
* Player-requested structures are properly integrated into the base system to prevent duplicates and better anticipate player desires * Improved bot path finding for moving targets, hopefully they get caught less often on railings and stuff when pursuing a moving target * When bots teleport (e.g. phase gate, but any kind of teleport), they clear their stored unstuck locations so they don't try and backtrack when attempting to get unstuck
This commit is contained in:
parent
11512d9d28
commit
4102dabe05
4 changed files with 205 additions and 36 deletions
|
@ -3143,6 +3143,88 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
|
|||
Vector IdealDeployLocation = Requestor->v.origin + (UTIL_GetForwardVector2D(Requestor->v.angles) * ProjectDistance);
|
||||
Vector ProjectedDeployLocation = AdjustPointForPathfinding(IdealDeployLocation, GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE));
|
||||
|
||||
AvHAIMarineBase* BaseToDeployIn = nullptr;
|
||||
float MinDist = 0.0f;
|
||||
|
||||
for (auto it = pBot->Bases.begin(); it != pBot->Bases.end(); it++)
|
||||
{
|
||||
float DistFromBase = vDist2DSq(Requestor->v.origin, it->BaseLocation);
|
||||
|
||||
if (it->BaseType == MARINE_BASE_MAINBASE && DistFromBase < sqrf(UTIL_MetresToGoldSrcUnits(20.0f)))
|
||||
{
|
||||
BaseToDeployIn = &(*it);
|
||||
break;
|
||||
}
|
||||
|
||||
float DesiredDist = (it->BaseType == MARINE_BASE_GUARDPOST) ? BALANCE_VAR(kTurretFactoryBuildDistance) : UTIL_MetresToGoldSrcUnits(15.0f);
|
||||
|
||||
if (DistFromBase < sqrf(DesiredDist))
|
||||
{
|
||||
if (!BaseToDeployIn || DistFromBase < MinDist)
|
||||
{
|
||||
BaseToDeployIn = &(*it);
|
||||
MinDist = DistFromBase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We've requested a building away from any existing bases the commander is building
|
||||
if (!BaseToDeployIn && (NextRequest->RequestType == BUILD_PHASEGATE || NextRequest->RequestType == BUILD_TURRET_FACTORY))
|
||||
{
|
||||
|
||||
const AvHAIHiveDefinition* NearestHive = AITAC_GetHiveNearestLocation(Requestor->v.origin);
|
||||
float DesiredDistance = (NearestHive->Status != HIVE_STATUS_UNBUILT) ? sqrf(BALANCE_VAR(kSiegeTurretRange)) : sqrf(UTIL_MetresToGoldSrcUnits(10.0f));
|
||||
float DistFromHive = vDist2DSq(NearestHive->Location, Requestor->v.origin);
|
||||
|
||||
if (NearestHive && DistFromHive < DesiredDistance)
|
||||
{
|
||||
AvHAIMarineBase* ExistingBase = nullptr;
|
||||
|
||||
for (auto it = pBot->Bases.begin(); it != pBot->Bases.end(); it++)
|
||||
{
|
||||
if (!it->bIsActive || !it->bRecycleBase) { continue; }
|
||||
|
||||
if (NearestHive->Status != HIVE_STATUS_UNBUILT)
|
||||
{
|
||||
if (it->BaseType == MARINE_BASE_SIEGE && vEquals2D(it->SiegeTarget, NearestHive->Location))
|
||||
{
|
||||
if (!it->bBaseInitialised)
|
||||
{
|
||||
BaseToDeployIn = &(*it);
|
||||
BaseToDeployIn->BaseLocation = Requestor->v.origin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (it->BaseType == MARINE_BASE_OUTPOST && vDist2DSq(it->BaseLocation, NearestHive->FloorLocation) < UTIL_MetresToGoldSrcUnits(15.0f))
|
||||
{
|
||||
if (!it->bBaseInitialised)
|
||||
{
|
||||
BaseToDeployIn = &(*it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!BaseToDeployIn && NearestHive)
|
||||
{
|
||||
MarineBaseType NewBaseType = (NearestHive->Status != HIVE_STATUS_UNBUILT) ? MARINE_BASE_SIEGE : MARINE_BASE_OUTPOST;
|
||||
|
||||
BaseToDeployIn = AICOMM_AddNewBase(pBot, Requestor->v.origin, NewBaseType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseToDeployIn = AICOMM_AddNewBase(pBot, Requestor->v.origin, MARINE_BASE_GUARDPOST);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (!vIsZero(ProjectedDeployLocation))
|
||||
{
|
||||
if (NextRequest->RequestType == BUILD_INFANTRYPORTAL)
|
||||
|
@ -3195,9 +3277,20 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
|
|||
}
|
||||
}
|
||||
|
||||
AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, StructureToDeploy, ProjectedDeployLocation, STRUCTURE_PURPOSE_GENERAL, true);
|
||||
bool bSuccess = false;
|
||||
|
||||
if (DeployedStructure)
|
||||
if (BaseToDeployIn)
|
||||
{
|
||||
bSuccess = AICOMM_AddStructureToBase(pBot, StructureToDeploy, ProjectedDeployLocation, BaseToDeployIn);
|
||||
}
|
||||
else
|
||||
{
|
||||
AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, StructureToDeploy, ProjectedDeployLocation, STRUCTURE_PURPOSE_GENERAL, true);
|
||||
|
||||
bSuccess = DeployedStructure != nullptr;
|
||||
}
|
||||
|
||||
if (bSuccess)
|
||||
{
|
||||
NextRequest->bResponded = true;
|
||||
return true;
|
||||
|
@ -3208,9 +3301,21 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
|
|||
|
||||
if (!vIsZero(DeployLocation))
|
||||
{
|
||||
AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, StructureToDeploy, DeployLocation, STRUCTURE_PURPOSE_GENERAL);
|
||||
bool bSuccess = false;
|
||||
|
||||
if (DeployedStructure)
|
||||
if (BaseToDeployIn)
|
||||
{
|
||||
bSuccess = AICOMM_AddStructureToBase(pBot, StructureToDeploy, DeployLocation, BaseToDeployIn);
|
||||
}
|
||||
else
|
||||
{
|
||||
AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, StructureToDeploy, DeployLocation, STRUCTURE_PURPOSE_GENERAL, true);
|
||||
|
||||
bSuccess = DeployedStructure != nullptr;
|
||||
}
|
||||
|
||||
|
||||
if (bSuccess)
|
||||
{
|
||||
NextRequest->bResponded = true;
|
||||
return true;
|
||||
|
@ -3221,9 +3326,21 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
|
|||
|
||||
if (!vIsZero(DeployLocation))
|
||||
{
|
||||
AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, StructureToDeploy, DeployLocation, STRUCTURE_PURPOSE_GENERAL);
|
||||
bool bSuccess = false;
|
||||
|
||||
if (DeployedStructure)
|
||||
if (BaseToDeployIn)
|
||||
{
|
||||
bSuccess = AICOMM_AddStructureToBase(pBot, StructureToDeploy, DeployLocation, BaseToDeployIn);
|
||||
}
|
||||
else
|
||||
{
|
||||
AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, StructureToDeploy, DeployLocation, STRUCTURE_PURPOSE_GENERAL, true);
|
||||
|
||||
bSuccess = DeployedStructure != nullptr;
|
||||
}
|
||||
|
||||
|
||||
if (bSuccess)
|
||||
{
|
||||
NextRequest->bResponded = true;
|
||||
return true;
|
||||
|
@ -3744,6 +3861,8 @@ void AICOMM_UpdateGuardpostStatus(AvHAIPlayer* pBot, AvHAIMarineBase* Base)
|
|||
}
|
||||
}
|
||||
|
||||
Base->bRecycleBase = false;
|
||||
Base->bIsActive = true;
|
||||
|
||||
// Check how far we are into building this outpost. If we have a TF and at least 3 sentries then we can consider it "established"
|
||||
// even if it isn't finished yet
|
||||
|
@ -4040,7 +4159,11 @@ void AICOMM_DeployBases(AvHAIPlayer* pBot)
|
|||
|
||||
if (!AITAC_DeployableExistsAtLocation(ThisHive->FloorLocation, &EnemyStuffFilter))
|
||||
{
|
||||
AICOMM_AddNewBase(pBot, ThisHive->FloorLocation, MARINE_BASE_OUTPOST);
|
||||
Vector ProjectedPoint = UTIL_ProjectPointToNavmesh(ThisHive->FloorLocation, Vector(500.0f, 500.0f, 500.0f), GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE));
|
||||
if (!vIsZero(ProjectedPoint))
|
||||
{
|
||||
AICOMM_AddNewBase(pBot, ProjectedPoint, MARINE_BASE_OUTPOST);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4090,7 +4213,12 @@ void AICOMM_DeployBases(AvHAIPlayer* pBot)
|
|||
|
||||
if (!AITAC_DeployableExistsAtLocation(ThisPlayer->pev->origin, &EnemyStuffFilter))
|
||||
{
|
||||
AICOMM_AddNewBase(pBot, ThisPlayer->pev->origin, MARINE_BASE_SIEGE);
|
||||
// Make sure that our siege guy is somewhere we can build
|
||||
Vector ProjectedPoint = UTIL_ProjectPointToNavmesh(ThisPlayer->pev->origin, Vector(100.0f, 100.0f, 100.0f), GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE));
|
||||
if (!vIsZero(ProjectedPoint))
|
||||
{
|
||||
AICOMM_AddNewBase(pBot, ProjectedPoint, MARINE_BASE_SIEGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4162,7 +4290,6 @@ bool AICOMM_GetRelocationMessage(Vector RelocationPoint, char* MessageBuffer)
|
|||
sprintf(MessageBuffer, "Get ready to relocate");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int MsgIndex = irandrange(0, 2);
|
||||
|
||||
|
@ -4829,6 +4956,8 @@ bool AICOMM_BuildOutBase(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut)
|
|||
return AICOMM_BuildOutOutpost(pBot, BaseToBuildOut);
|
||||
case MARINE_BASE_MAINBASE:
|
||||
return AICOMM_BuildOutMainBase(pBot, BaseToBuildOut);
|
||||
case MARINE_BASE_GUARDPOST:
|
||||
return AICOMM_BuildOutGuardPost(pBot, BaseToBuildOut);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1166,6 +1166,7 @@ void UTIL_PopulateBaseNavProfiles()
|
|||
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_STRUCTUREBLOCK, 20.0f);
|
||||
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LADDER, 1.5f);
|
||||
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_WALLCLIMB, 1.0f);
|
||||
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALLDAMAGE, 1.0f);
|
||||
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LIFT, 3.0f);
|
||||
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
|
||||
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED);
|
||||
|
@ -1199,6 +1200,7 @@ void UTIL_PopulateBaseNavProfiles()
|
|||
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 2.0f);
|
||||
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_STRUCTUREBLOCK, 20.0f);
|
||||
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LADDER, 1.0f);
|
||||
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALLDAMAGE, 1.0f);
|
||||
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LIFT, 3.0f);
|
||||
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
|
||||
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED);
|
||||
|
@ -1215,6 +1217,7 @@ void UTIL_PopulateBaseNavProfiles()
|
|||
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 2.0f);
|
||||
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_STRUCTUREBLOCK, 20.0f);
|
||||
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LADDER, 1.5f);
|
||||
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALLDAMAGE, 1.0f);
|
||||
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LIFT, 3.0f);
|
||||
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
|
||||
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setExcludeFlags(SAMPLE_POLYFLAGS_DISABLED);
|
||||
|
@ -2085,17 +2088,48 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle,
|
|||
}
|
||||
|
||||
Vector FromLocation = pBot->CurrentFloorPosition;
|
||||
Vector FromFloorLocation = FromLocation;
|
||||
|
||||
// Add a slight bias towards trying to move forward if on a railing or other narrow bit of navigable terrain
|
||||
// rather than potentially dropping back off it the wrong way
|
||||
Vector GeneralDir = UTIL_GetVectorNormal2D(ToLocation - pBot->CurrentFloorPosition);
|
||||
Vector CheckLocation = FromLocation + (GeneralDir * 16.0f);
|
||||
|
||||
Vector FromFloorLocation = AdjustPointForPathfinding(CheckLocation);
|
||||
|
||||
if (vIsZero(FromFloorLocation))
|
||||
// If the bot currently has a path, then let's calculate the navigation from the "from" point rather than our exact position right now
|
||||
if (pBot->BotNavInfo.CurrentPathPoint < pBot->BotNavInfo.CurrentPath.size())
|
||||
{
|
||||
FromFloorLocation = AdjustPointForPathfinding(FromLocation);
|
||||
bot_path_node CurrentPathNode = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint];
|
||||
|
||||
if (CurrentPathNode.flag == SAMPLE_POLYFLAGS_WALK)
|
||||
{
|
||||
bool bFromReachable = UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, CurrentPathNode.Location);
|
||||
bool bToReachable = UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, CurrentPathNode.FromLocation);
|
||||
if (bFromReachable && bToReachable)
|
||||
{
|
||||
FromFloorLocation = pBot->CurrentFloorPosition;
|
||||
}
|
||||
else if (bFromReachable)
|
||||
{
|
||||
FromFloorLocation = CurrentPathNode.FromLocation;
|
||||
}
|
||||
else
|
||||
{
|
||||
FromFloorLocation = CurrentPathNode.Location;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FromFloorLocation = CurrentPathNode.FromLocation;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add a slight bias towards trying to move forward if on a railing or other narrow bit of navigable terrain
|
||||
// rather than potentially dropping back off it the wrong way
|
||||
Vector GeneralDir = UTIL_GetVectorNormal2D(ToLocation - pBot->CurrentFloorPosition);
|
||||
Vector CheckLocation = FromLocation + (GeneralDir * 16.0f);
|
||||
|
||||
Vector FromFloorLocation = AdjustPointForPathfinding(CheckLocation);
|
||||
|
||||
if (vIsZero(FromFloorLocation))
|
||||
{
|
||||
FromFloorLocation = AdjustPointForPathfinding(FromLocation);
|
||||
}
|
||||
}
|
||||
|
||||
nav_door* LiftReference = UTIL_GetLiftReferenceByEdict(pBot->Edict->v.groundentity);
|
||||
|
@ -6602,10 +6636,12 @@ bool NAV_MergeAndUpdatePath(AvHAIPlayer* pBot, std::vector<bot_path_node>& NewPa
|
|||
return true;
|
||||
}
|
||||
|
||||
// Start with the bot's current path point
|
||||
std::vector<bot_path_node>::iterator OldPathStart = (pBot->BotNavInfo.CurrentPath.begin() + pBot->BotNavInfo.CurrentPathPoint);
|
||||
std::vector<bot_path_node>::iterator OldPathEnd;
|
||||
std::vector<bot_path_node>::iterator NewPathStart;
|
||||
|
||||
// We skip ahead in the path until we reach the first non-walk node in our CURRENT path
|
||||
for (OldPathEnd = OldPathStart; OldPathEnd != pBot->BotNavInfo.CurrentPath.end(); OldPathEnd++)
|
||||
{
|
||||
if (OldPathEnd->flag != SAMPLE_POLYFLAGS_WALK)
|
||||
|
@ -6614,11 +6650,13 @@ bool NAV_MergeAndUpdatePath(AvHAIPlayer* pBot, std::vector<bot_path_node>& NewPa
|
|||
}
|
||||
}
|
||||
|
||||
// Our path is all walk, so we will return false which will basically cause us to cancel this path completely and adopt a new one
|
||||
if (OldPathEnd == pBot->BotNavInfo.CurrentPath.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// We have reached the next non-walk node in our CURRENT path, now we find the next non-walk path in a prospective NEW path
|
||||
for (NewPathStart = NewPath.begin(); NewPathStart != NewPath.end(); NewPathStart++)
|
||||
{
|
||||
if (NewPathStart->flag != SAMPLE_POLYFLAGS_WALK)
|
||||
|
@ -6627,16 +6665,19 @@ bool NAV_MergeAndUpdatePath(AvHAIPlayer* pBot, std::vector<bot_path_node>& NewPa
|
|||
}
|
||||
}
|
||||
|
||||
// New path is all walk, just embrace it and forget the old path
|
||||
if (NewPathStart == NewPath.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// The upcoming non-walk node in our current path and the upcoming non-walk node in our new path are different: we have a different path entirely so just get the new path instead
|
||||
if (OldPathEnd->flag != NewPathStart->flag || !vEquals(OldPathEnd->FromLocation, NewPathStart->FromLocation, 16.0f) || !vEquals(OldPathEnd->Location, NewPathStart->Location, 16.0f))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now we truncate the current path at the non-walk node, and append the new path from that point
|
||||
OldPathEnd = next(OldPathEnd);
|
||||
NewPathStart = next(NewPathStart);
|
||||
|
||||
|
|
|
@ -1714,7 +1714,14 @@ void StartNewBotFrame(AvHAIPlayer* pBot)
|
|||
ClearBotInputs(pBot);
|
||||
pBot->CurrentEyePosition = GetPlayerEyePosition(pEdict);
|
||||
|
||||
pBot->CurrentFloorPosition = UTIL_GetEntityGroundLocation(pEdict);
|
||||
Vector NewFloorPosition = UTIL_GetEntityGroundLocation(pEdict);
|
||||
|
||||
if (vDist2DSq(NewFloorPosition, pBot->CurrentFloorPosition) > sqrf(UTIL_MetresToGoldSrcUnits(3.0f)))
|
||||
{
|
||||
OnBotTeleport(pBot);
|
||||
}
|
||||
|
||||
pBot->CurrentFloorPosition = NewFloorPosition;
|
||||
|
||||
if (vDist3DSq(pBot->BotNavInfo.LastNavMeshCheckPosition, pBot->CurrentFloorPosition) > sqrf(16.0f))
|
||||
{
|
||||
|
@ -1887,23 +1894,7 @@ void EndBotFrame(AvHAIPlayer* pBot)
|
|||
|
||||
void CustomThink(AvHAIPlayer* pBot)
|
||||
{
|
||||
if (!IsPlayerAlien(pBot->Edict)) { return; }
|
||||
|
||||
int Enemy = BotGetNextEnemyTarget(pBot);
|
||||
|
||||
if (Enemy > -1)
|
||||
{
|
||||
AlienCombatThink(pBot);
|
||||
}
|
||||
else
|
||||
{
|
||||
edict_t* CommChair = AITAC_GetCommChair(AIMGR_GetEnemyTeam(pBot->Player->GetTeam()));
|
||||
|
||||
if (!FNullEnt(CommChair))
|
||||
{
|
||||
MoveTo(pBot, CommChair->v.origin, MOVESTYLE_NORMAL);
|
||||
}
|
||||
}
|
||||
MoveTo(pBot, UTIL_GetFloorUnderEntity(INDEXENT(1)), MOVESTYLE_NORMAL);
|
||||
|
||||
}
|
||||
|
||||
|
@ -8896,4 +8887,10 @@ void DEBUG_PrintBotDebugInfo(edict_t* OutputPlayer, AvHAIPlayer* pBot)
|
|||
|
||||
DEBUG_PrintTaskInfo(OutputPlayer, pBot);
|
||||
DEBUG_PrintCombatInfo(OutputPlayer, pBot);
|
||||
}
|
||||
|
||||
void OnBotTeleport(AvHAIPlayer* pBot)
|
||||
{
|
||||
ClearBotStuck(pBot);
|
||||
ClearBotStuckMovement(pBot);
|
||||
}
|
|
@ -159,6 +159,8 @@ void AIPlayerHearEnemy(AvHAIPlayer* pBot, edict_t* HeardEnemy, float SoundVolume
|
|||
|
||||
int BotGetNextEnemyTarget(AvHAIPlayer* pBot);
|
||||
|
||||
void OnBotTeleport(AvHAIPlayer* pBot);
|
||||
|
||||
AvHMessageID AlienGetDesiredUpgrade(AvHAIPlayer* pBot, HiveTechStatus DesiredTech);
|
||||
|
||||
AvHAICombatStrategy GetBotCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_status* CurrentEnemy);
|
||||
|
|
Loading…
Reference in a new issue