mirror of
https://github.com/ENSL/NS.git
synced 2024-11-22 04:31:12 +00:00
Base system Enhancements
* Nearly finished base system * Bots attacking structures no longer confused by "super chambers"
This commit is contained in:
parent
6f263d400b
commit
9ee01c0d64
6 changed files with 336 additions and 109 deletions
|
@ -601,6 +601,8 @@ void AICOMM_UpdatePlayerOrders(AvHAIPlayer* pBot)
|
||||||
// Either the base isn't established (has comm chair and infantry portals), or the active comm chair isn't in the base (we're relocating)
|
// Either the base isn't established (has comm chair and infantry portals), or the active comm chair isn't in the base (we're relocating)
|
||||||
int NumDesiredBuilders = ThisBase->bIsBaseEstablished ? 1 : 2;
|
int NumDesiredBuilders = ThisBase->bIsBaseEstablished ? 1 : 2;
|
||||||
|
|
||||||
|
NumDesiredBuilders = imini(NumDesiredBuilders, NumPlayersOnTeam);
|
||||||
|
|
||||||
int NumBuilders = ThisBase->NumBuilders + AICOMM_GetNumPlayersAssignedToOrderLocation(pBot, ThisBase->BaseLocation, ORDERPURPOSE_BUILD_MAINBASE);
|
int NumBuilders = ThisBase->NumBuilders + AICOMM_GetNumPlayersAssignedToOrderLocation(pBot, ThisBase->BaseLocation, ORDERPURPOSE_BUILD_MAINBASE);
|
||||||
|
|
||||||
if (NumBuilders < NumDesiredBuilders)
|
if (NumBuilders < NumDesiredBuilders)
|
||||||
|
@ -1180,7 +1182,7 @@ Vector AICOMM_GetNextScanLocation(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
AvHAIBuildableStructure SiegeTurret;
|
AvHAIBuildableStructure SiegeTurret;
|
||||||
|
|
||||||
for (auto it = pBot->Bases.begin(); it != pBot->Bases.begin(); it++)
|
for (auto it = pBot->Bases.begin(); it != pBot->Bases.end(); it++)
|
||||||
{
|
{
|
||||||
AvHAIMarineBase* ThisBase = &(*it);
|
AvHAIMarineBase* ThisBase = &(*it);
|
||||||
|
|
||||||
|
@ -1211,9 +1213,9 @@ Vector AICOMM_GetNextScanLocation(AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
if (EnemyType == AVH_CLASS_TYPE_ALIEN)
|
if (EnemyType == AVH_CLASS_TYPE_ALIEN)
|
||||||
{
|
{
|
||||||
const AvHAIHiveDefinition* SiegedHive = AITAC_GetActiveHiveNearestLocation(EnemyTeam, it->BaseLocation);
|
const AvHAIHiveDefinition* SiegedHive = AITAC_GetActiveHiveNearestLocation(EnemyTeam, ThisBase->BaseLocation);
|
||||||
|
|
||||||
if (SiegedHive && vDist2DSq(SiegedHive->Location, it->BaseLocation) < sqrf(BALANCE_VAR(kSiegeTurretRange)))
|
if (SiegedHive && vDist2DSq(SiegedHive->Location, ThisBase->BaseLocation) < sqrf(BALANCE_VAR(kSiegeTurretRange)))
|
||||||
{
|
{
|
||||||
bool bAlreadyScanning = AITAC_ItemExistsInLocation(SiegedHive->Location, DEPLOYABLE_ITEM_SCAN, TEAM_IND, AI_REACHABILITY_NONE, 0.0f, UTIL_MetresToGoldSrcUnits(10.0f), false);
|
bool bAlreadyScanning = AITAC_ItemExistsInLocation(SiegedHive->Location, DEPLOYABLE_ITEM_SCAN, TEAM_IND, AI_REACHABILITY_NONE, 0.0f, UTIL_MetresToGoldSrcUnits(10.0f), false);
|
||||||
|
|
||||||
|
@ -1326,13 +1328,41 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
// This is important, make sure we always prioritise setting up the infantry portals in our base before we do anything else
|
// This is important, make sure we always prioritise setting up the infantry portals in our base before we do anything else
|
||||||
// If we don't have enough resources to drop an infantry portal with resources to spare, then don't allow the commander to do anything else
|
// If we don't have enough resources to drop an infantry portal with resources to spare, then don't allow the commander to do anything else
|
||||||
if (MainBase && !MainBase->bIsBaseEstablished)
|
if (MainBase)
|
||||||
|
{
|
||||||
|
bool bMustPrioritise = !MainBase->bIsBaseEstablished;
|
||||||
|
|
||||||
|
if (!bMustPrioritise)
|
||||||
|
{
|
||||||
|
vector<AvHAIBuildableStructure> BaseStructures = AICOMM_GetBaseStructures(MainBase);
|
||||||
|
|
||||||
|
bool bHasArmoury = false;
|
||||||
|
bool bHasTF = true;
|
||||||
|
int NumSentries = 0;
|
||||||
|
|
||||||
|
int DesiredInfPortals = (int)ceilf((float)AIMGR_GetNumPlayersOnTeam(BotTeam) / 4.0f);
|
||||||
|
int NumInfantryPortals = 0;
|
||||||
|
|
||||||
|
for (auto it = BaseStructures.begin(); it != BaseStructures.end(); it++)
|
||||||
|
{
|
||||||
|
if (it->StructureType == STRUCTURE_MARINE_INFANTRYPORTAL) { NumInfantryPortals++; }
|
||||||
|
else if (it->StructureType & (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY)) { bHasArmoury = true; }
|
||||||
|
else if (it->StructureType & (STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY)) { bHasTF = true; }
|
||||||
|
else if (it->StructureType == STRUCTURE_MARINE_TURRET) { NumSentries++; }
|
||||||
|
}
|
||||||
|
|
||||||
|
bMustPrioritise = !bHasArmoury || !bHasTF || NumInfantryPortals < DesiredInfPortals || NumSentries < 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bMustPrioritise)
|
||||||
{
|
{
|
||||||
bool bSuccess = AICOMM_BuildOutBase(pBot, MainBase);
|
bool bSuccess = AICOMM_BuildOutBase(pBot, MainBase);
|
||||||
|
|
||||||
if (bSuccess) { return true; }
|
if (bSuccess) { return true; }
|
||||||
|
|
||||||
return pBot->Player->GetResources() < BALANCE_VAR(kInfantryPortalCost) * 1.5f;
|
// We can't build anything in our base right now, but don't build anything elsewhere unless we have at least 30 resources so we can put down infrastructure when needed
|
||||||
|
if (pBot->Player->GetResources() < BALANCE_VAR(kInfantryPortalCost) * 1.5f) { return true; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AvHAIResourceNode* CappableNode = AICOMM_GetNearestResourceNodeCapOpportunity(BotTeam, CommChair->v.origin);
|
const AvHAIResourceNode* CappableNode = AICOMM_GetNearestResourceNodeCapOpportunity(BotTeam, CommChair->v.origin);
|
||||||
|
@ -2393,6 +2423,24 @@ bool AICOMM_CheckForNextRecycleAction(AvHAIPlayer* pBot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (ThisBase->BaseType != MARINE_BASE_MAINBASE)
|
||||||
|
{
|
||||||
|
for (auto structIt = ThisBase->PlacedStructures.begin(); structIt != ThisBase->PlacedStructures.end(); structIt++)
|
||||||
|
{
|
||||||
|
AvHAIBuildableStructure ThisStructure = AITAC_GetDeployableStructureByEntIndex(pBot->Player->GetTeam(), (*structIt));
|
||||||
|
|
||||||
|
if (ThisStructure.IsValid() && !(ThisStructure.StructureStatusFlags & STRUCTURE_STATUS_RECYCLING))
|
||||||
|
{
|
||||||
|
// Don't allow any infantry portals to be scattered elsewhere outside the base
|
||||||
|
if (ThisStructure.StructureType == STRUCTURE_MARINE_INFANTRYPORTAL)
|
||||||
|
{
|
||||||
|
bool bSuccess = AICOMM_RecycleStructure(pBot, &ThisStructure);
|
||||||
|
|
||||||
|
if (bSuccess) { return true; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -3377,7 +3425,14 @@ void AICOMM_PopulateBaseList(AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
AvHAIBuildableStructure ThisTF = (*it);
|
AvHAIBuildableStructure ThisTF = (*it);
|
||||||
|
|
||||||
AvHAIMarineBase* NewOutpost = AICOMM_AddNewBase(pBot, ThisTF.Location, MARINE_BASE_GUARDPOST);
|
MarineBaseType NewBaseType = MARINE_BASE_GUARDPOST;
|
||||||
|
|
||||||
|
if (vDist2DSq(ThisTF.Location, AITAC_GetTeamOriginalStartLocation(BotTeam)) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
|
||||||
|
{
|
||||||
|
NewBaseType = MARINE_BASE_OUTPOST;
|
||||||
|
}
|
||||||
|
|
||||||
|
AvHAIMarineBase* NewOutpost = AICOMM_AddNewBase(pBot, ThisTF.Location, NewBaseType);
|
||||||
|
|
||||||
if (!NewOutpost) { continue; }
|
if (!NewOutpost) { continue; }
|
||||||
|
|
||||||
|
@ -3418,14 +3473,25 @@ void AICOMM_PopulateBaseList(AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
const AvHAIHiveDefinition* NearestHive = AITAC_GetHiveNearestLocation(ThisTF.Location);
|
const AvHAIHiveDefinition* NearestHive = AITAC_GetHiveNearestLocation(ThisTF.Location);
|
||||||
|
|
||||||
if (NearestHive && vDist2DSq(NearestHive->Location, ThisTF.Location) <= sqrf(UTIL_MetresToGoldSrcUnits(25.0f)))
|
float DistToHive = vDist2DSq(NearestHive->Location, ThisTF.Location);
|
||||||
|
|
||||||
|
if (NearestHive && DistToHive <= sqrf(UTIL_MetresToGoldSrcUnits(25.0f)))
|
||||||
{
|
{
|
||||||
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_ALIEN)
|
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_ALIEN)
|
||||||
{
|
{
|
||||||
|
// Player was sieging a hive
|
||||||
if (NearestHive->Status != HIVE_STATUS_UNBUILT)
|
if (NearestHive->Status != HIVE_STATUS_UNBUILT)
|
||||||
{
|
{
|
||||||
NewOutpost->BaseType = MARINE_BASE_SIEGE;
|
NewOutpost->BaseType = MARINE_BASE_SIEGE;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This is an outpost in an empty hive
|
||||||
|
if (DistToHive <= sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
|
||||||
|
{
|
||||||
|
NewOutpost->BaseType = MARINE_BASE_OUTPOST;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3435,6 +3501,7 @@ void AICOMM_PopulateBaseList(AvHAIPlayer* pBot)
|
||||||
EnemyStuffFilter.DeployableTypes = (STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY);
|
EnemyStuffFilter.DeployableTypes = (STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY);
|
||||||
EnemyStuffFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
EnemyStuffFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
||||||
|
|
||||||
|
// Player was sieging a bunch of stuff
|
||||||
if (AITAC_GetNumDeployablesNearLocation(NearestHive->FloorLocation, &EnemyStuffFilter) > 0)
|
if (AITAC_GetNumDeployablesNearLocation(NearestHive->FloorLocation, &EnemyStuffFilter) > 0)
|
||||||
{
|
{
|
||||||
NewOutpost->BaseType = MARINE_BASE_SIEGE;
|
NewOutpost->BaseType = MARINE_BASE_SIEGE;
|
||||||
|
@ -3736,7 +3803,7 @@ void AICOMM_UpdateSiegeBaseStatus(AvHAIPlayer* pBot, AvHAIMarineBase* Base)
|
||||||
EnemyStuffFilter.DeployableTeam = EnemyTeam;
|
EnemyStuffFilter.DeployableTeam = EnemyTeam;
|
||||||
EnemyStuffFilter.MaxSearchRadius = BALANCE_VAR(kSiegeTurretRange);
|
EnemyStuffFilter.MaxSearchRadius = BALANCE_VAR(kSiegeTurretRange);
|
||||||
|
|
||||||
bool bStillStuffToSiege = AITAC_DeployableExistsAtLocation(ZERO_VECTOR, &EnemyStuffFilter);
|
bool bStillStuffToSiege = AITAC_DeployableExistsAtLocation(Base->BaseLocation, &EnemyStuffFilter);
|
||||||
|
|
||||||
const AvHAIHiveDefinition* NearestHive = AITAC_GetHiveNearestLocation(Base->BaseLocation);
|
const AvHAIHiveDefinition* NearestHive = AITAC_GetHiveNearestLocation(Base->BaseLocation);
|
||||||
|
|
||||||
|
@ -3747,7 +3814,7 @@ void AICOMM_UpdateSiegeBaseStatus(AvHAIPlayer* pBot, AvHAIMarineBase* Base)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!NearestHive)
|
if (!NearestHive || NearestHive->Status == HIVE_STATUS_UNBUILT)
|
||||||
{
|
{
|
||||||
Base->bRecycleBase = true;
|
Base->bRecycleBase = true;
|
||||||
Base->bIsActive = false;
|
Base->bIsActive = false;
|
||||||
|
@ -3760,10 +3827,6 @@ void AICOMM_UpdateSiegeBaseStatus(AvHAIPlayer* pBot, AvHAIMarineBase* Base)
|
||||||
{
|
{
|
||||||
Base->bRecycleBase = true;
|
Base->bRecycleBase = true;
|
||||||
Base->bIsActive = false;
|
Base->bIsActive = false;
|
||||||
} else if (NearestHive->Status != HIVE_STATUS_UNBUILT)
|
|
||||||
{
|
|
||||||
Base->bRecycleBase = false;
|
|
||||||
Base->bIsActive = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3887,13 +3950,28 @@ void AICOMM_DeployBases(AvHAIPlayer* pBot)
|
||||||
BotSay(pBot, true, 1.0f, NewMsg);
|
BotSay(pBot, true, 1.0f, NewMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentMainBase->BaseType = MARINE_BASE_OUTPOST;
|
||||||
|
AICOMM_AddNewBase(pBot, CurrentChairLocation, MARINE_BASE_MAINBASE);
|
||||||
|
|
||||||
|
char NewMsg[128];
|
||||||
|
if (AICOMM_GetRelocationMessage(CurrentChairLocation, NewMsg))
|
||||||
|
{
|
||||||
|
BotSay(pBot, true, 1.0f, NewMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Vector NewBaseLocation = AITAC_FindNewTeamRelocationPoint(BotTeam);
|
Vector NewBaseLocation = AITAC_FindNewTeamRelocationPoint(BotTeam);
|
||||||
|
|
||||||
if (!vIsZero(NewBaseLocation))
|
if (!vIsZero(NewBaseLocation) && vDist2DSq(NewBaseLocation, CurrentMainBase->BaseLocation) > sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
|
||||||
{
|
{
|
||||||
// Turn our starting base into an outpost, and lay down a new main base elsewhere
|
// Turn our starting base into an outpost, and lay down a new main base elsewhere
|
||||||
CurrentMainBase->BaseType = MARINE_BASE_OUTPOST;
|
CurrentMainBase->BaseType = MARINE_BASE_OUTPOST;
|
||||||
|
@ -3904,6 +3982,7 @@ void AICOMM_DeployBases(AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
BotSay(pBot, true, 1.0f, NewMsg);
|
BotSay(pBot, true, 1.0f, NewMsg);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3921,7 +4000,7 @@ void AICOMM_DeployBases(AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
BotSay(pBot, true, 1.0f, NewMsg);
|
BotSay(pBot, true, 1.0f, NewMsg);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4068,26 +4147,38 @@ void AICOMM_ManageActiveBases(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
bool AICOMM_GetRelocationMessage(Vector RelocationPoint, char* MessageBuffer)
|
bool AICOMM_GetRelocationMessage(Vector RelocationPoint, char* MessageBuffer)
|
||||||
{
|
{
|
||||||
const AvHAIHiveDefinition* RelocationHive = AITAC_GetHiveNearestLocation(RelocationPoint);
|
const AvHAIHiveDefinition* NearestHive = AITAC_GetHiveNearestLocation(RelocationPoint);
|
||||||
|
|
||||||
if (!RelocationHive || strlen(RelocationHive->HiveName) == 0)
|
string LocationName;
|
||||||
|
|
||||||
|
if (NearestHive && vDist2DSq(RelocationPoint, NearestHive->FloorLocation) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
|
||||||
{
|
{
|
||||||
sprintf(MessageBuffer, "We're relocating, get ready");
|
LocationName = string(NearestHive->HiveName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LocationName = AITAC_GetLocationName(RelocationPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LocationName.empty())
|
||||||
|
{
|
||||||
|
sprintf(MessageBuffer, "Get ready to relocate");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int MsgIndex = irandrange(0, 2);
|
int MsgIndex = irandrange(0, 2);
|
||||||
|
|
||||||
switch (MsgIndex)
|
switch (MsgIndex)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
sprintf(MessageBuffer, "We're relocating to %s, lads", RelocationHive->HiveName);
|
sprintf(MessageBuffer, "We're relocating to %s, lads", LocationName.c_str());
|
||||||
return true;
|
return true;
|
||||||
case 1:
|
case 1:
|
||||||
sprintf(MessageBuffer, "Relocate to %s, go go go", RelocationHive->HiveName);
|
sprintf(MessageBuffer, "Relocate to %s, go go go", LocationName.c_str());
|
||||||
return true;
|
return true;
|
||||||
case 2:
|
case 2:
|
||||||
sprintf(MessageBuffer, "I'm relocating to %s", RelocationHive->HiveName);
|
sprintf(MessageBuffer, "I'm relocating to %s", LocationName.c_str());
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
sprintf(MessageBuffer, "We're relocating, get ready");
|
sprintf(MessageBuffer, "We're relocating, get ready");
|
||||||
|
@ -4279,6 +4370,103 @@ bool AICOMM_IsHiveFullySecured(AvHAIPlayer* CommanderBot, const AvHAIHiveDefinit
|
||||||
return ((!bPhaseGatesAvailable || bHasPhaseGate) && bHasTurretFactory && (!bIncludeElectrical || bTurretFactoryElectrified) && NumTurrets >= 5 && bSecuredResNode);
|
return ((!bPhaseGatesAvailable || bHasPhaseGate) && bHasTurretFactory && (!bIncludeElectrical || bTurretFactoryElectrified) && NumTurrets >= 5 && bSecuredResNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AICOMM_IsMainBaseInTrouble(AvHAIPlayer* pBot, AvHAIMarineBase* Base)
|
||||||
|
{
|
||||||
|
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||||
|
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
|
||||||
|
|
||||||
|
Vector BaseLocation = AITAC_GetTeamStartingLocation(BotTeam);
|
||||||
|
|
||||||
|
vector<AvHAIBuildableStructure> BaseStructures = AICOMM_GetBaseStructures(Base);
|
||||||
|
|
||||||
|
bool bHasInfantryPortals = false;
|
||||||
|
bool bCriticalStructureUnderAttack = false;
|
||||||
|
bool bAnyStructureUnderAttack = false;
|
||||||
|
|
||||||
|
for (auto it = BaseStructures.begin(); it != BaseStructures.end(); it++)
|
||||||
|
{
|
||||||
|
AvHAIBuildableStructure ThisStructure = (*it);
|
||||||
|
|
||||||
|
if (ThisStructure.StructureStatusFlags & STRUCTURE_STATUS_UNDERATTACK)
|
||||||
|
{
|
||||||
|
bAnyStructureUnderAttack = true;
|
||||||
|
|
||||||
|
if (ThisStructure.StructureType == STRUCTURE_MARINE_COMMCHAIR || ThisStructure.StructureType == STRUCTURE_MARINE_INFANTRYPORTAL)
|
||||||
|
{
|
||||||
|
bCriticalStructureUnderAttack = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bAnyStructureUnderAttack) { return false; }
|
||||||
|
|
||||||
|
float EnemyStrength = 0.0f;
|
||||||
|
float DefenderStrength = 0.0f;
|
||||||
|
|
||||||
|
vector<AvHPlayer*> DefendingPlayers = AITAC_GetAllPlayersOfTeamInArea(BotTeam, Base->BaseLocation, UTIL_MetresToGoldSrcUnits(20.0f), true, nullptr, AVH_USER3_COMMANDER_PLAYER);
|
||||||
|
|
||||||
|
for (auto it = DefendingPlayers.begin(); it != DefendingPlayers.end(); it++)
|
||||||
|
{
|
||||||
|
AvHPlayer* ThisPlayer = (*it);
|
||||||
|
edict_t* PlayerEdict = ThisPlayer->edict();
|
||||||
|
|
||||||
|
float ThisPlayerValue = 1.0f;
|
||||||
|
|
||||||
|
if (PlayerHasHeavyArmour(PlayerEdict))
|
||||||
|
{
|
||||||
|
ThisPlayerValue += 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PlayerHasSpecialWeapon(ThisPlayer))
|
||||||
|
{
|
||||||
|
ThisPlayerValue += 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefenderStrength += ThisPlayerValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_MARINE)
|
||||||
|
{
|
||||||
|
vector<AvHPlayer*> AttackingPlayers = AITAC_GetAllPlayersOfTeamInArea(EnemyTeam, Base->BaseLocation, UTIL_MetresToGoldSrcUnits(10.0f), false, nullptr, AVH_USER3_COMMANDER_PLAYER);
|
||||||
|
|
||||||
|
for (auto it = AttackingPlayers.begin(); it != AttackingPlayers.end(); it++)
|
||||||
|
{
|
||||||
|
AvHPlayer* ThisPlayer = (*it);
|
||||||
|
edict_t* PlayerEdict = ThisPlayer->edict();
|
||||||
|
|
||||||
|
float ThisPlayerValue = 1.0f;
|
||||||
|
|
||||||
|
if (PlayerHasHeavyArmour(PlayerEdict))
|
||||||
|
{
|
||||||
|
ThisPlayerValue += 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PlayerHasSpecialWeapon(ThisPlayer))
|
||||||
|
{
|
||||||
|
ThisPlayerValue += 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefenderStrength += ThisPlayerValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int NumSkulks = AITAC_GetNumPlayersOfTeamAndClassInArea(EnemyTeam, BaseLocation, UTIL_MetresToGoldSrcUnits(10.0f), false, nullptr, AVH_USER3_ALIEN_PLAYER1);
|
||||||
|
int NumFades = AITAC_GetNumPlayersOfTeamAndClassInArea(EnemyTeam, BaseLocation, UTIL_MetresToGoldSrcUnits(10.0f), false, nullptr, AVH_USER3_ALIEN_PLAYER4);
|
||||||
|
int NumOnos = AITAC_GetNumPlayersOfTeamAndClassInArea(EnemyTeam, BaseLocation, UTIL_MetresToGoldSrcUnits(10.0f), false, nullptr, AVH_USER3_ALIEN_PLAYER5);
|
||||||
|
|
||||||
|
EnemyStrength = (NumSkulks * 0.8f) + (NumFades * 2) + (NumOnos * 2.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EnemyStrength >= 3.0f && EnemyStrength >= DefenderStrength * 3.0f)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool AICOMM_ShouldBeacon(AvHAIPlayer* pBot)
|
bool AICOMM_ShouldBeacon(AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
if (pBot->Player->GetResources() < BALANCE_VAR(kDistressBeaconCost)) { return false; }
|
if (pBot->Player->GetResources() < BALANCE_VAR(kDistressBeaconCost)) { return false; }
|
||||||
|
@ -4295,57 +4483,12 @@ bool AICOMM_ShouldBeacon(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
if (!Observatory.IsValid()) { return false; }
|
if (!Observatory.IsValid()) { return false; }
|
||||||
|
|
||||||
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
|
for (auto it = pBot->Bases.begin(); it != pBot->Bases.end(); it++)
|
||||||
|
|
||||||
Vector BaseLocation = AITAC_GetTeamStartingLocation(BotTeam);
|
|
||||||
|
|
||||||
DeployableSearchFilter BaseStructureFilter;
|
|
||||||
BaseStructureFilter.DeployableTypes = (STRUCTURE_MARINE_INFANTRYPORTAL | STRUCTURE_MARINE_COMMCHAIR);
|
|
||||||
BaseStructureFilter.DeployableTeam = BotTeam;
|
|
||||||
BaseStructureFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
|
||||||
BaseStructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
|
||||||
|
|
||||||
vector<AvHAIBuildableStructure> BaseStructures = AITAC_FindAllDeployables(BaseLocation, &BaseStructureFilter);
|
|
||||||
|
|
||||||
bool bHasInfantryPortals = false;
|
|
||||||
bool bBaseUnderAttack = false;
|
|
||||||
|
|
||||||
for (auto it = BaseStructures.begin(); it != BaseStructures.end(); it++)
|
|
||||||
{
|
{
|
||||||
AvHAIBuildableStructure ThisStructure = (*it);
|
if (it->BaseType == MARINE_BASE_MAINBASE)
|
||||||
|
|
||||||
if (ThisStructure.StructureStatusFlags & STRUCTURE_STATUS_UNDERATTACK)
|
|
||||||
{
|
{
|
||||||
bBaseUnderAttack = true;
|
return AICOMM_IsMainBaseInTrouble(pBot, &(*it));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ThisStructure.StructureType == STRUCTURE_MARINE_INFANTRYPORTAL)
|
|
||||||
{
|
|
||||||
bHasInfantryPortals = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bBaseUnderAttack && bHasInfantryPortals) { return false; }
|
|
||||||
|
|
||||||
int EnemyStrength = 0;
|
|
||||||
int DefenderStrength = AITAC_GetNumPlayersOfTeamInArea(BotTeam, BaseLocation, UTIL_MetresToGoldSrcUnits(10.0f), false, nullptr, AVH_USER3_COMMANDER_PLAYER);
|
|
||||||
|
|
||||||
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_MARINE)
|
|
||||||
{
|
|
||||||
EnemyStrength = AITAC_GetNumPlayersOfTeamInArea(EnemyTeam, BaseLocation, UTIL_MetresToGoldSrcUnits(10.0f), false, nullptr, AVH_USER3_COMMANDER_PLAYER);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int NumSkulks = AITAC_GetNumPlayersOfTeamAndClassInArea(EnemyTeam, BaseLocation, UTIL_MetresToGoldSrcUnits(10.0f), false, nullptr, AVH_USER3_ALIEN_PLAYER1);
|
|
||||||
int NumFades = AITAC_GetNumPlayersOfTeamAndClassInArea(EnemyTeam, BaseLocation, UTIL_MetresToGoldSrcUnits(10.0f), false, nullptr, AVH_USER3_ALIEN_PLAYER4);
|
|
||||||
int NumOnos = AITAC_GetNumPlayersOfTeamAndClassInArea(EnemyTeam, BaseLocation, UTIL_MetresToGoldSrcUnits(10.0f), false, nullptr, AVH_USER3_ALIEN_PLAYER5);
|
|
||||||
|
|
||||||
EnemyStrength = NumSkulks + (NumFades * 2) + (NumOnos * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EnemyStrength >= 3 && EnemyStrength >= DefenderStrength * 3)
|
|
||||||
{
|
|
||||||
return AICOMM_ResearchTech(pBot, &Observatory, RESEARCH_DISTRESSBEACON);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -4479,10 +4622,63 @@ bool AICOMM_ShouldCommanderRelocate(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
if (!CurrentMainBase->bIsActive || CurrentMainBase->bRecycleBase) { return true; }
|
if (!CurrentMainBase->bIsActive || CurrentMainBase->bRecycleBase) { return true; }
|
||||||
|
|
||||||
|
bool bMainBaseIsAtChair = vDist2DSq(CurrentCommChair->v.origin, CurrentMainBase->BaseLocation) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f));
|
||||||
|
|
||||||
|
// We're not able to relocate after 90 seconds, best find somewhere else or we're in trouble
|
||||||
|
if (AIMGR_GetMatchLength() > 90.0f && !CurrentMainBase->bIsBaseEstablished && !bMainBaseIsAtChair)
|
||||||
|
{
|
||||||
|
return (CurrentMainBase->NumBuilders == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AITAC_IsRelocationEnabled() && AIMGR_GetMatchLength() < 90.0f)
|
||||||
|
{
|
||||||
|
// We've not tried relocating yet
|
||||||
|
if (bMainBaseIsAtChair) { return true; }
|
||||||
|
|
||||||
|
const AvHAIHiveDefinition* RelocationHive = AITAC_GetHiveNearestLocation(CurrentMainBase->BaseLocation);
|
||||||
|
|
||||||
|
// The hive we were planning to relocate to has somehow started being built within 90 seconds of start. Not sure how, but we better not move there now
|
||||||
|
if (RelocationHive && vDist2DSq(RelocationHive->FloorLocation, CurrentMainBase->BaseLocation) < sqrf(UTIL_MetresToGoldSrcUnits(15.0f)))
|
||||||
|
{
|
||||||
|
if (RelocationHive->Status != HIVE_STATUS_UNBUILT) { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// The enemy beat us to it and has started setting up shop in that location
|
||||||
|
DeployableSearchFilter EnemyStuffFilter;
|
||||||
|
EnemyStuffFilter.DeployableTeam = EnemyTeam;
|
||||||
|
EnemyStuffFilter.DeployableTypes = (STRUCTURE_MARINE_COMMCHAIR | STRUCTURE_MARINE_INFANTRYPORTAL | STRUCTURE_MARINE_TURRETFACTORY);
|
||||||
|
EnemyStuffFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||||
|
EnemyStuffFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||||
|
EnemyStuffFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
||||||
|
|
||||||
|
// Those marine bastards stole our spot!
|
||||||
|
if (AITAC_DeployableExistsAtLocation(CurrentMainBase->BaseLocation, &EnemyStuffFilter)) { return true; }
|
||||||
|
|
||||||
|
EnemyStuffFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
|
||||||
|
|
||||||
|
// Those alien bastards stole our spot!
|
||||||
|
if (AITAC_GetNumDeployablesNearLocation(CurrentMainBase->BaseLocation, &EnemyStuffFilter) > 1) { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If we have an established main base, then only relocate if it's fucked. This means:
|
||||||
|
// Base is not at the original start, or we can't beacon to save the base
|
||||||
|
// Critical structures are under attack (comm chair or infantry portals)
|
||||||
|
// The number of enemies is overwhelming and we're doomed
|
||||||
if (CurrentMainBase->bIsBaseEstablished)
|
if (CurrentMainBase->bIsBaseEstablished)
|
||||||
{
|
{
|
||||||
bool bHasObservatory = false;
|
if (CurrentMainBase->NumBuilders > 0) { return false; }
|
||||||
|
|
||||||
|
DeployableSearchFilter ObsFilter;
|
||||||
|
ObsFilter.DeployableTeam = Team;
|
||||||
|
ObsFilter.DeployableTypes = STRUCTURE_MARINE_OBSERVATORY;
|
||||||
|
ObsFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||||
|
ObsFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||||
|
|
||||||
|
bool bCanBeacon = AITAC_DeployableExistsAtLocation(ZERO_VECTOR, &ObsFilter);
|
||||||
|
|
||||||
bool bCriticalStructureAttacked = false;
|
bool bCriticalStructureAttacked = false;
|
||||||
|
bool bBaseIsAtStart = vDist2DSq(CurrentMainBase->BaseLocation, AITAC_GetTeamOriginalStartLocation(Team)) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f));
|
||||||
|
|
||||||
vector<AvHAIBuildableStructure> BaseStructures = AICOMM_GetBaseStructures(CurrentMainBase);
|
vector<AvHAIBuildableStructure> BaseStructures = AICOMM_GetBaseStructures(CurrentMainBase);
|
||||||
|
|
||||||
|
@ -4492,11 +4688,6 @@ bool AICOMM_ShouldCommanderRelocate(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
if ((ThisStructure->StructureStatusFlags & STRUCTURE_STATUS_RECYCLING) || !(ThisStructure->StructureStatusFlags & STRUCTURE_STATUS_COMPLETED)) { continue; }
|
if ((ThisStructure->StructureStatusFlags & STRUCTURE_STATUS_RECYCLING) || !(ThisStructure->StructureStatusFlags & STRUCTURE_STATUS_COMPLETED)) { continue; }
|
||||||
|
|
||||||
if (ThisStructure->StructureType == STRUCTURE_MARINE_OBSERVATORY)
|
|
||||||
{
|
|
||||||
bHasObservatory = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ThisStructure->StructureStatusFlags & STRUCTURE_STATUS_UNDERATTACK)
|
if (ThisStructure->StructureStatusFlags & STRUCTURE_STATUS_UNDERATTACK)
|
||||||
{
|
{
|
||||||
if (ThisStructure->StructureType == STRUCTURE_MARINE_COMMCHAIR || ThisStructure->StructureType == STRUCTURE_MARINE_INFANTRYPORTAL)
|
if (ThisStructure->StructureType == STRUCTURE_MARINE_COMMCHAIR || ThisStructure->StructureType == STRUCTURE_MARINE_INFANTRYPORTAL)
|
||||||
|
@ -4506,21 +4697,11 @@ bool AICOMM_ShouldCommanderRelocate(AvHAIPlayer* pBot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bHasObservatory || !bCriticalStructureAttacked) { return false; }
|
if (!bCriticalStructureAttacked) { return false; }
|
||||||
|
|
||||||
return CurrentMainBase->NumEnemies > (CurrentMainBase->NumBuilders * 2);
|
if (bBaseIsAtStart && bCanBeacon) { return false; }
|
||||||
}
|
|
||||||
|
|
||||||
// We're not able to relocate after 90 seconds, best find somewhere else or we're in trouble
|
return AICOMM_IsMainBaseInTrouble(pBot, CurrentMainBase);
|
||||||
if (AIMGR_GetMatchLength() > 90.0f && !CurrentMainBase->bIsBaseEstablished)
|
|
||||||
{
|
|
||||||
if (CurrentMainBase->NumBuilders > 0) { return false; }
|
|
||||||
return vDist2DSq(CurrentCommChair->v.origin, CurrentMainBase->BaseLocation) > sqrf(UTIL_MetresToGoldSrcUnits(10.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AITAC_IsRelocationEnabled() && AIMGR_GetMatchLength() < 90.0f)
|
|
||||||
{
|
|
||||||
return vDist2DSq(CurrentCommChair->v.origin, CurrentMainBase->BaseLocation) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -3620,9 +3620,9 @@ void AIPlayerSetMarineSweeperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
|
||||||
{
|
{
|
||||||
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||||
|
|
||||||
Vector CommChairLocation = AITAC_GetCommChairLocation(BotTeam);
|
Vector CommChairLocation = AITAC_GetTeamStartingLocation(BotTeam);
|
||||||
|
|
||||||
// Always built IPs first, so we don't end up getting wiped right at the start
|
// Always build IPs first, so we don't end up getting wiped right at the start
|
||||||
|
|
||||||
DeployableSearchFilter StructureFilter;
|
DeployableSearchFilter StructureFilter;
|
||||||
StructureFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL;
|
StructureFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "AvHAIPlayerUtil.h"
|
#include "AvHAIPlayerUtil.h"
|
||||||
#include "AvHAIPlayer.h"
|
#include "AvHAIPlayer.h"
|
||||||
#include "AvHAIHelper.h"
|
#include "AvHAIHelper.h"
|
||||||
|
#include "AvHAIWeaponHelper.h"
|
||||||
|
|
||||||
#include "AvHPlayerUpgrade.h"
|
#include "AvHPlayerUpgrade.h"
|
||||||
#include "AvHAIMath.h"
|
#include "AvHAIMath.h"
|
||||||
|
@ -636,7 +637,10 @@ bool PlayerHasEquipment(edict_t* Player)
|
||||||
bool PlayerHasSpecialWeapon(const AvHPlayer* Player)
|
bool PlayerHasSpecialWeapon(const AvHPlayer* Player)
|
||||||
{
|
{
|
||||||
if (!IsPlayerMarine(Player)) { return false; }
|
if (!IsPlayerMarine(Player)) { return false; }
|
||||||
return !PlayerHasWeapon(Player, WEAPON_MARINE_MG);
|
|
||||||
|
AvHAIWeapon PrimaryWeaponType = UTIL_GetPlayerPrimaryWeapon(Player);
|
||||||
|
|
||||||
|
return PrimaryWeaponType != WEAPON_INVALID && PrimaryWeaponType != WEAPON_MARINE_MG;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UTIL_PlayerHasLOSToEntity(const edict_t* Player, const edict_t* Target, const float MaxRange, const bool bUseHullSweep)
|
bool UTIL_PlayerHasLOSToEntity(const edict_t* Player, const edict_t* Target, const float MaxRange, const bool bUseHullSweep)
|
||||||
|
|
|
@ -1090,6 +1090,20 @@ Vector AITAC_GetFloorLocationForHive(const AvHAIHiveDefinition* Hive)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string AITAC_GetLocationName(Vector Location)
|
||||||
|
{
|
||||||
|
string Result;
|
||||||
|
|
||||||
|
string theLocationName;
|
||||||
|
if (AvHSHUGetNameOfLocation(GetGameRules()->GetInfoLocations(), Location, theLocationName))
|
||||||
|
{
|
||||||
|
UTIL_LocalizeText(theLocationName.c_str(), theLocationName);
|
||||||
|
Result = theLocationName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
void AITAC_PopulateHiveData()
|
void AITAC_PopulateHiveData()
|
||||||
{
|
{
|
||||||
Hives.clear();
|
Hives.clear();
|
||||||
|
@ -1114,17 +1128,16 @@ void AITAC_PopulateHiveData()
|
||||||
|
|
||||||
NewHive.FloorLocation = UTIL_GetFloorUnderEntity(NewHive.HiveEdict); // Some hives are suspended in the air, this is the floor location directly beneath it
|
NewHive.FloorLocation = UTIL_GetFloorUnderEntity(NewHive.HiveEdict); // Some hives are suspended in the air, this is the floor location directly beneath it
|
||||||
|
|
||||||
string HiveName;
|
string HiveName = AITAC_GetLocationName(NewHive.Location);
|
||||||
|
|
||||||
string theLocationName;
|
if (HiveName.empty())
|
||||||
if (AvHSHUGetNameOfLocation(GetGameRules()->GetInfoLocations(), NewHive.Location, theLocationName))
|
|
||||||
{
|
{
|
||||||
UTIL_LocalizeText(theLocationName.c_str(), theLocationName);
|
sprintf(NewHive.HiveName, "Hive");
|
||||||
HiveName = theLocationName;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
sprintf(NewHive.HiveName, HiveName.c_str(), "%s");
|
sprintf(NewHive.HiveName, HiveName.c_str(), "%s");
|
||||||
|
}
|
||||||
|
|
||||||
Hives.push_back(NewHive);
|
Hives.push_back(NewHive);
|
||||||
|
|
||||||
|
@ -1228,6 +1241,15 @@ Vector AITAC_GetTeamRelocationPoint(AvHTeamNumber Team)
|
||||||
return (Team == GetGameRules()->GetTeamANumber()) ? TeamARelocationPoint : TeamBRelocationPoint;
|
return (Team == GetGameRules()->GetTeamANumber()) ? TeamARelocationPoint : TeamBRelocationPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector AITAC_GetTeamOriginalStartLocation(AvHTeamNumber Team)
|
||||||
|
{
|
||||||
|
AvHTeam* TeamRef = AIMGR_GetTeamRef(Team);
|
||||||
|
|
||||||
|
if (!TeamRef) { return ZERO_VECTOR; }
|
||||||
|
|
||||||
|
return TeamRef->GetStartingLocation();
|
||||||
|
}
|
||||||
|
|
||||||
Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team)
|
Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team)
|
||||||
{
|
{
|
||||||
if (vIsZero(TeamAStartingLocation) || vIsZero(TeamBStartingLocation))
|
if (vIsZero(TeamAStartingLocation) || vIsZero(TeamBStartingLocation))
|
||||||
|
|
|
@ -64,9 +64,13 @@ const AvHAIHiveDefinition* AITAC_GetNonEmptyHiveNearestLocation(const Vector Sea
|
||||||
Vector AITAC_GetCommChairLocation(AvHTeamNumber Team);
|
Vector AITAC_GetCommChairLocation(AvHTeamNumber Team);
|
||||||
edict_t* AITAC_GetCommChair(AvHTeamNumber Team);
|
edict_t* AITAC_GetCommChair(AvHTeamNumber Team);
|
||||||
|
|
||||||
|
Vector AITAC_GetTeamOriginalStartLocation(AvHTeamNumber Team);
|
||||||
Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team);
|
Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team);
|
||||||
Vector AITAC_GetTeamRelocationPoint(AvHTeamNumber Team);
|
Vector AITAC_GetTeamRelocationPoint(AvHTeamNumber Team);
|
||||||
|
|
||||||
|
// Returns the name of the supplied location on the map. This will be the same as what appears in the bottom left of the player's screen
|
||||||
|
string AITAC_GetLocationName(Vector Location);
|
||||||
|
|
||||||
AvHAIResourceNode* AITAC_GetRandomResourceNode(AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags);
|
AvHAIResourceNode* AITAC_GetRandomResourceNode(AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags);
|
||||||
|
|
||||||
AvHAIDroppedItem AITAC_FindClosestItemToLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance);
|
AvHAIDroppedItem AITAC_FindClosestItemToLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance);
|
||||||
|
|
|
@ -1797,13 +1797,32 @@ void BotProgressAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
}
|
}
|
||||||
|
|
||||||
MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL);
|
MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BotAttackResult AttackResult = PerformAttackLOSCheck(pBot, Weapon, Task->TaskTarget);
|
BotAttackResult AttackResult = PerformAttackLOSCheck(pBot, Weapon, Task->TaskTarget);
|
||||||
|
|
||||||
|
if (AttackResult == ATTACK_BLOCKED)
|
||||||
|
{
|
||||||
|
TraceResult hit;
|
||||||
|
|
||||||
|
Vector StartTrace = pBot->CurrentEyePosition;
|
||||||
|
|
||||||
|
Vector AttackDir = UTIL_GetVectorNormal(UTIL_GetCentreOfEntity(Task->TaskTarget) - StartTrace);
|
||||||
|
|
||||||
|
Vector EndTrace = pBot->CurrentEyePosition + (AttackDir * UTIL_MetresToGoldSrcUnits(50.0f));
|
||||||
|
|
||||||
|
UTIL_TraceLine(StartTrace, EndTrace, dont_ignore_monsters, dont_ignore_glass, pBot->Edict->v.pContainingEntity, &hit);
|
||||||
|
|
||||||
|
if (!FNullEnt(hit.pHit) && hit.pHit->v.team == AIMGR_GetEnemyTeam(pBot->Player->GetTeam()) && vDist2DSq(hit.pHit->v.origin, Task->TaskTarget->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(2.0f)))
|
||||||
|
{
|
||||||
|
AttackResult = ATTACK_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (AttackResult == ATTACK_SUCCESS)
|
if (AttackResult == ATTACK_SUCCESS)
|
||||||
{
|
{
|
||||||
// If we were ducking before then keep ducking
|
// If we were ducking before then keep ducking
|
||||||
|
@ -1838,17 +1857,14 @@ void BotProgressAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
|
|
||||||
Vector RightDir = UTIL_GetCrossProduct(EnemyOrientation, UP_VECTOR);
|
Vector RightDir = UTIL_GetCrossProduct(EnemyOrientation, UP_VECTOR);
|
||||||
|
|
||||||
pBot->desiredMovementDir = (pBot->BotNavInfo.bZig) ? UTIL_GetVectorNormal2D(RightDir) : UTIL_GetVectorNormal2D(-RightDir);
|
Vector EvasiveDir = GetZigZagDirection(pBot, Task->TaskTarget, nullptr);
|
||||||
|
|
||||||
// Let's get ziggy with it
|
if (!vIsZero(EvasiveDir))
|
||||||
if (gpGlobals->time > pBot->BotNavInfo.NextZigTime)
|
|
||||||
{
|
{
|
||||||
pBot->BotNavInfo.bZig = !pBot->BotNavInfo.bZig;
|
pBot->desiredMovementDir = EvasiveDir;
|
||||||
pBot->BotNavInfo.NextZigTime = gpGlobals->time + frandrange(0.5f, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
BotMovementInputs(pBot);
|
BotMovementInputs(pBot);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue