mirror of
https://github.com/ENSL/NS.git
synced 2024-11-10 07:11:38 +00:00
Bug fixes + Pierow's dynamic load spread
This commit is contained in:
parent
50e5a0702e
commit
c75d7ec80b
12 changed files with 470 additions and 160 deletions
|
@ -479,6 +479,11 @@ void AICOMM_UpdatePlayerOrders(AvHAIPlayer* pBot)
|
|||
int NumPlayersOnTeam = AITAC_GetNumActivePlayersOnTeam(pBot->Player->GetTeam());
|
||||
int DesiredPlayers = imini(2, (int)ceilf((float)NumPlayersOnTeam *0.5f));
|
||||
|
||||
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
|
||||
|
||||
Vector TeamStartingLocation = AITAC_GetTeamStartingLocation(BotTeam);
|
||||
|
||||
const AvHAIHiveDefinition* SiegedHive = AITAC_GetNearestHiveUnderActiveSiege(pBot->Player->GetTeam(), AITAC_GetCommChairLocation(pBot->Player->GetTeam()));
|
||||
|
||||
if (SiegedHive)
|
||||
|
@ -501,10 +506,7 @@ void AICOMM_UpdatePlayerOrders(AvHAIPlayer* pBot)
|
|||
|
||||
if (AICOMM_ShouldCommanderPrioritiseNodes(pBot))
|
||||
{
|
||||
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
|
||||
|
||||
Vector TeamStartingLocation = AITAC_GetTeamStartingLocation(BotTeam);
|
||||
|
||||
DeployableSearchFilter ResNodeFilter;
|
||||
ResNodeFilter.ReachabilityTeam = pBot->Player->GetTeam();
|
||||
|
@ -570,7 +572,7 @@ void AICOMM_UpdatePlayerOrders(AvHAIPlayer* pBot)
|
|||
|
||||
if (NumAssignedPlayers < DesiredPlayers)
|
||||
{
|
||||
float ThisDist = vDist2DSq(AITAC_GetCommChairLocation(pBot->Player->GetTeam()), ThisHive->Location);
|
||||
float ThisDist = vDist2DSq(TeamStartingLocation, ThisHive->Location);
|
||||
|
||||
if (!EmptyHive || ThisDist < MinDist)
|
||||
{
|
||||
|
@ -594,6 +596,61 @@ void AICOMM_UpdatePlayerOrders(AvHAIPlayer* pBot)
|
|||
}
|
||||
}
|
||||
|
||||
if (!AITAC_ResearchIsComplete(BotTeam, TECH_RESEARCH_PHASETECH)) { return; }
|
||||
|
||||
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_ALIEN)
|
||||
{
|
||||
AvHAIHiveDefinition* HiveSiegeOpportunity = nullptr;
|
||||
|
||||
float MinDist = 0.0f;
|
||||
|
||||
for (auto it = Hives.begin(); it != Hives.end(); it++)
|
||||
{
|
||||
AvHAIHiveDefinition* ThisHive = (*it);
|
||||
if (ThisHive->Status == HIVE_STATUS_UNBUILT) { continue; }
|
||||
|
||||
DeployableSearchFilter ExistingSiegeFilter;
|
||||
ExistingSiegeFilter.DeployableTeam = BotTeam;
|
||||
ExistingSiegeFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||
ExistingSiegeFilter.DeployableTypes = (STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY);
|
||||
ExistingSiegeFilter.ReachabilityTeam = BotTeam;
|
||||
ExistingSiegeFilter.ReachabilityFlags = AI_REACHABILITY_MARINE;
|
||||
ExistingSiegeFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(25.0f);
|
||||
|
||||
AvHAIBuildableStructure SiegeStructure = AITAC_FindClosestDeployableToLocation(ThisHive->Location, &ExistingSiegeFilter);
|
||||
|
||||
if (SiegeStructure.IsValid())
|
||||
{
|
||||
HiveSiegeOpportunity = ThisHive;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
float ThisDist = vDist2DSq(ThisHive->FloorLocation, TeamStartingLocation);
|
||||
|
||||
if (!HiveSiegeOpportunity || ThisDist < MinDist)
|
||||
{
|
||||
HiveSiegeOpportunity = ThisHive;
|
||||
MinDist = ThisDist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (HiveSiegeOpportunity)
|
||||
{
|
||||
for(int i = 0; i < (DesiredPlayers - MinNumAssignedPlayers); i++)
|
||||
{
|
||||
edict_t* NewAssignee = AICOMM_GetPlayerWithNoOrderNearestLocation(pBot, HiveSiegeOpportunity->FloorLocation);
|
||||
|
||||
if (!FNullEnt(NewAssignee))
|
||||
{
|
||||
AICOMM_AssignNewPlayerOrder(pBot, NewAssignee, HiveSiegeOpportunity->HiveEdict, ORDERPURPOSE_SIEGE_HIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
edict_t* AICOMM_GetPlayerWithNoOrderNearestLocation(AvHAIPlayer* pBot, Vector SearchLocation)
|
||||
|
@ -1843,87 +1900,120 @@ bool AICOMM_PerformNextSiegeHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinit
|
|||
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(25.0f);
|
||||
|
||||
Vector SiegeLocation = ZERO_VECTOR;
|
||||
AvHAIBuildableStructure ExistingPG;
|
||||
|
||||
StructureFilter.DeployableTypes = STRUCTURE_MARINE_PHASEGATE;
|
||||
AvHAIBuildableStructure ExistingPG = AITAC_FindClosestDeployableToLocation(HiveToSiege->Location, &StructureFilter);
|
||||
|
||||
StructureFilter.DeployableTypes = (STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY);
|
||||
AvHAIBuildableStructure ExistingTF = AITAC_FindClosestDeployableToLocation(HiveToSiege->Location, &StructureFilter);
|
||||
|
||||
StructureFilter.DeployableTypes = (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY);
|
||||
AvHAIBuildableStructure ExistingArmoury = AITAC_FindClosestDeployableToLocation(HiveToSiege->Location, &StructureFilter);
|
||||
|
||||
edict_t* NearestBuilder = nullptr;
|
||||
|
||||
if (AITAC_PhaseGatesAvailable(CommanderTeam))
|
||||
// We only build one of these at a time, so we don't drop a bunch of structures and then our intrepid sieger gets killed and the aliens nom them all
|
||||
if (ExistingPG.IsValid())
|
||||
{
|
||||
StructureFilter.DeployableTypes = STRUCTURE_MARINE_PHASEGATE;
|
||||
|
||||
ExistingPG = AITAC_FindClosestDeployableToLocation(HiveToSiege->Location, &StructureFilter);
|
||||
|
||||
if (ExistingPG.IsValid())
|
||||
if (ExistingPG.IsCompleted())
|
||||
{
|
||||
SiegeLocation = ExistingPG.Location;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StructureFilter.DeployableTypes = STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY;
|
||||
|
||||
AvHAIBuildableStructure ExistingTF = AITAC_FindClosestDeployableToLocation(HiveToSiege->Location, &StructureFilter);
|
||||
|
||||
if (vIsZero(SiegeLocation))
|
||||
{
|
||||
if (ExistingTF.IsValid())
|
||||
{
|
||||
SiegeLocation = ExistingTF.Location;
|
||||
NearestBuilder = AITAC_GetClosestPlayerOnTeamWithLOS(CommanderTeam, ExistingPG.Location, UTIL_MetresToGoldSrcUnits(5.0f), pBot->Edict);
|
||||
}
|
||||
else
|
||||
{
|
||||
NearestBuilder = AITAC_GetNearestHiddenPlayerInLocation(CommanderTeam, HiveToSiege->Location, UTIL_MetresToGoldSrcUnits(20.0f));
|
||||
|
||||
if (FNullEnt(NearestBuilder)) { return false; }
|
||||
|
||||
SiegeLocation = NearestBuilder->v.origin;
|
||||
// Don't do anything else until we've finished building the phase gate
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (FNullEnt(NearestBuilder))
|
||||
if (ExistingTF.IsValid())
|
||||
{
|
||||
NearestBuilder = AITAC_GetNearestHiddenPlayerInLocation(CommanderTeam, SiegeLocation, UTIL_MetresToGoldSrcUnits(20.0f));
|
||||
if (ExistingTF.IsCompleted())
|
||||
{
|
||||
if (vIsZero(SiegeLocation))
|
||||
{
|
||||
SiegeLocation = ExistingTF.Location;
|
||||
}
|
||||
|
||||
if (FNullEnt(NearestBuilder))
|
||||
{
|
||||
NearestBuilder = AITAC_GetClosestPlayerOnTeamWithLOS(CommanderTeam, ExistingTF.Location, UTIL_MetresToGoldSrcUnits(5.0f), pBot->Edict);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't do anything else until we've finished building the turret factory
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FNullEnt(NearestBuilder))
|
||||
{
|
||||
NearestBuilder = AITAC_GetNearestHiddenPlayerInLocation(CommanderTeam, HiveToSiege->Location, UTIL_MetresToGoldSrcUnits(20.0f));
|
||||
}
|
||||
}
|
||||
|
||||
if (FNullEnt(NearestBuilder)) { return false; }
|
||||
|
||||
Vector NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), SiegeLocation, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
bool bPhaseGatesAvailable = AITAC_PhaseGatesAvailable(CommanderTeam);
|
||||
|
||||
if (vIsZero(NextBuildPosition))
|
||||
if (vIsZero(SiegeLocation))
|
||||
{
|
||||
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), SiegeLocation, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
SiegeLocation = NearestBuilder->v.origin;
|
||||
}
|
||||
|
||||
if (vIsZero(NextBuildPosition))
|
||||
AvHAIDeployableStructureType NextStructure = STRUCTURE_NONE;
|
||||
|
||||
if (!ExistingPG.IsValid() && bPhaseGatesAvailable)
|
||||
{
|
||||
NextStructure = STRUCTURE_MARINE_PHASEGATE;
|
||||
}
|
||||
else if (!ExistingTF.IsValid())
|
||||
{
|
||||
NextStructure = STRUCTURE_MARINE_TURRETFACTORY;
|
||||
}
|
||||
else if (!ExistingArmoury.IsValid())
|
||||
{
|
||||
NextStructure = STRUCTURE_MARINE_ARMOURY;
|
||||
}
|
||||
|
||||
if (NextStructure != STRUCTURE_NONE)
|
||||
{
|
||||
Vector NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), SiegeLocation, 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(3.0f));
|
||||
bool bSuccess = AICOMM_DeployStructure(pBot, NextStructure, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
|
||||
|
||||
if (bSuccess) { return true; }
|
||||
}
|
||||
|
||||
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), SiegeLocation, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
|
||||
if (!vIsZero(NextBuildPosition))
|
||||
{
|
||||
bool bSuccess = AICOMM_DeployStructure(pBot, NextStructure, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
|
||||
|
||||
if (bSuccess) { return true; }
|
||||
}
|
||||
|
||||
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), SiegeLocation, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
|
||||
if (!vIsZero(NextBuildPosition))
|
||||
{
|
||||
bool bSuccess = AICOMM_DeployStructure(pBot, NextStructure, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
|
||||
|
||||
if (bSuccess) { return true; }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ExistingPG.IsValid())
|
||||
{
|
||||
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
|
||||
}
|
||||
if (!ExistingTF.IsValid()) { return false; }
|
||||
|
||||
if (ExistingPG.IsValid() && !(ExistingPG.StructureStatusFlags & STRUCTURE_STATUS_COMPLETED)) { return false; }
|
||||
|
||||
if (!ExistingTF.IsValid())
|
||||
{
|
||||
if (vDist2DSq(NextBuildPosition, HiveToSiege->Location) > sqrf(UTIL_MetresToGoldSrcUnits(20.0f))) { return true; }
|
||||
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
|
||||
}
|
||||
|
||||
if (ExistingTF.IsValid() && !(ExistingTF.StructureStatusFlags & STRUCTURE_STATUS_COMPLETED)) { return false; }
|
||||
|
||||
StructureFilter.DeployableTypes = STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY;
|
||||
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
||||
|
||||
AvHAIBuildableStructure ExistingArmoury = AITAC_FindClosestDeployableToLocation(SiegeLocation, &StructureFilter);
|
||||
|
||||
if (!ExistingArmoury.IsValid())
|
||||
{
|
||||
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
|
||||
}
|
||||
if ((ExistingTF.StructureStatusFlags & STRUCTURE_STATUS_RESEARCHING)) { return false; }
|
||||
|
||||
if (ExistingTF.StructureType != STRUCTURE_MARINE_ADVTURRETFACTORY)
|
||||
{
|
||||
|
@ -1935,27 +2025,35 @@ bool AICOMM_PerformNextSiegeHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinit
|
|||
|
||||
int NumSiegeTurrets = AITAC_GetNumDeployablesNearLocation(ExistingTF.Location, &StructureFilter);
|
||||
|
||||
if (NumSiegeTurrets == 0 || (NumSiegeTurrets < 5 && UTIL_IsStructureElectrified(ExistingTF.edict)))
|
||||
if (NumSiegeTurrets == 0 || (NumSiegeTurrets < 3 && UTIL_IsStructureElectrified(ExistingTF.edict)))
|
||||
{
|
||||
SiegeLocation = ExistingTF.Location;
|
||||
Vector NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingTF.Location, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
|
||||
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingTF.Location, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
|
||||
if (vIsZero(NextBuildPosition))
|
||||
if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) <= sqrf(BALANCE_VAR(kSiegeTurretRange)))
|
||||
{
|
||||
// Reduce radius to avoid putting it on the other side of a wall or something
|
||||
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingTF.Location, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_SIEGETURRET, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
|
||||
|
||||
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), ExistingTF.Location, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
}
|
||||
if (bSuccess) { return true; }
|
||||
}
|
||||
|
||||
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingTF.Location, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
|
||||
if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) <= sqrf(BALANCE_VAR(kSiegeTurretRange)))
|
||||
{
|
||||
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_SIEGETURRET, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
|
||||
|
||||
if (bSuccess) { return true; }
|
||||
}
|
||||
|
||||
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), ExistingTF.Location, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
|
||||
if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) <= sqrf(BALANCE_VAR(kSiegeTurretRange)))
|
||||
{
|
||||
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_SIEGETURRET, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
|
||||
|
||||
if (bSuccess) { return true; }
|
||||
}
|
||||
|
||||
// Don't put the turret out of siege range
|
||||
if (vDist2DSq(NextBuildPosition, HiveToSiege->Location) > sqrf(kSiegeTurretRange)) { return true; }
|
||||
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_SIEGETURRET, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
|
||||
}
|
||||
|
||||
if (!UTIL_IsStructureElectrified(ExistingTF.edict))
|
||||
|
@ -2013,14 +2111,29 @@ bool AICOMM_PerformNextSecureHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefini
|
|||
{
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), OutpostLocation, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
|
||||
if (vIsZero(BuildLocation))
|
||||
if (!vIsZero(BuildLocation))
|
||||
{
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), OutpostLocation, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
|
||||
|
||||
if (bSuccess) { return true; }
|
||||
}
|
||||
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), OutpostLocation, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
|
||||
if (!vIsZero(BuildLocation))
|
||||
{
|
||||
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
|
||||
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
|
||||
|
||||
if (bSuccess) { return true; }
|
||||
}
|
||||
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), HiveToSecure->FloorLocation, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
|
||||
if (!vIsZero(BuildLocation))
|
||||
{
|
||||
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
|
||||
|
||||
if (bSuccess) { return true; }
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -2036,16 +2149,34 @@ bool AICOMM_PerformNextSecureHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefini
|
|||
|
||||
if (!ExistingTF.IsValid())
|
||||
{
|
||||
// First, try and put the TF near any existing phasegate (if it exists)
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), OutpostLocation, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
|
||||
if (vIsZero(BuildLocation))
|
||||
{
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), OutpostLocation, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
}
|
||||
|
||||
if (!vIsZero(BuildLocation))
|
||||
{
|
||||
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
|
||||
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
|
||||
|
||||
if (bSuccess) { return true; }
|
||||
}
|
||||
|
||||
// That failed, now try expanding the radius a bit and ignoring reachability
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), OutpostLocation, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
|
||||
if (!vIsZero(BuildLocation))
|
||||
{
|
||||
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
|
||||
|
||||
if (bSuccess) { return true; }
|
||||
}
|
||||
|
||||
// That failed too, try putting it anywhere near the hive location
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), HiveToSecure->FloorLocation, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
|
||||
if (!vIsZero(BuildLocation))
|
||||
{
|
||||
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
|
||||
|
||||
if (bSuccess) { return true; }
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -2059,11 +2190,22 @@ bool AICOMM_PerformNextSecureHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefini
|
|||
|
||||
if (NumTurrets < 5)
|
||||
{
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingTF.Location, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingTF.Location, (BALANCE_VAR(kCommandStationBuildDistance) * 0.8f));
|
||||
|
||||
if (!vIsZero(BuildLocation))
|
||||
{
|
||||
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
|
||||
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
|
||||
|
||||
if (bSuccess) { return true; }
|
||||
}
|
||||
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), ExistingTF.Location, (BALANCE_VAR(kCommandStationBuildDistance) * 0.8f));
|
||||
|
||||
if (!vIsZero(BuildLocation))
|
||||
{
|
||||
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
|
||||
|
||||
if (bSuccess) { return true; }
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -147,7 +147,7 @@ void CONFIG_ParseConfigFile()
|
|||
BotSkillLevels[3].alien_bot_view_speed = 2.0f;
|
||||
|
||||
|
||||
string BotConfigFile = string(getModDirectory()) + "/nsbots.cfg";
|
||||
string BotConfigFile = string(getModDirectory()) + "/nsbots.ini";
|
||||
|
||||
const char* filename = BotConfigFile.c_str();
|
||||
|
||||
|
@ -429,9 +429,117 @@ void CONFIG_ParseConfigFile()
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ALERT(at_console, "nsbots.ini was not found in the NS mod folder. You can regenerate it with the console command 'sv_regenbotini'");
|
||||
}
|
||||
}
|
||||
|
||||
BotFillTiming CONFIG_GetBotFillTiming()
|
||||
{
|
||||
return CurrentBotFillTiming;
|
||||
}
|
||||
|
||||
void CONFIG_RegenerateIniFile()
|
||||
{
|
||||
string BotConfigFile = string(getModDirectory()) + "/nsbots.ini";
|
||||
|
||||
const char* filename = BotConfigFile.c_str();
|
||||
|
||||
FILE* NewConfigFile = fopen(filename, "w+");
|
||||
|
||||
if (!NewConfigFile)
|
||||
{
|
||||
ALERT(at_console, "Unable to write to %s, please ensure the user has privileges\n", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(NewConfigFile, "### General bot settings ###\n\n");
|
||||
|
||||
fprintf(NewConfigFile, "# What prefix to put in front of a bot's name (can leave blank)\n");
|
||||
fprintf(NewConfigFile, "prefix=[BOT]\n\n");
|
||||
|
||||
fprintf(NewConfigFile, "# When should the server start adding bots? Note: bots will always be added after round start regardless\n");
|
||||
fprintf(NewConfigFile, "# 0 = On map load (after 5 second grace period)\n");
|
||||
fprintf(NewConfigFile, "# 1 = When all humans have joined a team (i.e. no more humans left in ready room)\n");
|
||||
fprintf(NewConfigFile, "# 2 = When the round has started (after countdown)\n");
|
||||
fprintf(NewConfigFile, "BotFillTiming = 1\n\n\n");
|
||||
|
||||
|
||||
fprintf(NewConfigFile, "### Skill Settings ###\n\n");
|
||||
|
||||
fprintf(NewConfigFile, "# Bot skill settings. You can define as many settings as you like and reference them by name\n");
|
||||
fprintf(NewConfigFile, "# Format is BotSkillName = name, followed by one of the following:\n");
|
||||
fprintf(NewConfigFile, "# ReactionTime = How quickly in seconds the bot will react to sighting enemies\n");
|
||||
fprintf(NewConfigFile, "# AimSkill = How accurately the bot can lock sights on you after seeing you (0.0 - 1.0)\n");
|
||||
fprintf(NewConfigFile, "# MovementTracking = How accurately the bot can follow a moving target (0.0 - 1.0)\n");
|
||||
fprintf(NewConfigFile, "# ViewSpeed = How fast the bot can swivel its view (0.1 - 2.0)\n");
|
||||
fprintf(NewConfigFile, "# Set the difficulty using the 'mp_botskill' cvar (0 - 3)\n\n");
|
||||
|
||||
fprintf(NewConfigFile, "BotSkillLevel=0\n");
|
||||
fprintf(NewConfigFile, "MarineReactionTime=0.5\n");
|
||||
fprintf(NewConfigFile, "MarineAimSkill=0.1\n");
|
||||
fprintf(NewConfigFile, "MarineMovementTracking=0.1\n");
|
||||
fprintf(NewConfigFile, "MarineViewSpeed=0.5\n");
|
||||
fprintf(NewConfigFile, "AlienReactionTime=0.5\n");
|
||||
fprintf(NewConfigFile, "AlienAimSkill=0.2\n");
|
||||
fprintf(NewConfigFile, "AlienMovementTracking=0.2\n");
|
||||
fprintf(NewConfigFile, "AlienViewSpeed=0.75\n\n");
|
||||
|
||||
fprintf(NewConfigFile, "BotSkillLevel=1\n");
|
||||
fprintf(NewConfigFile, "MarineReactionTime=0.2\n");
|
||||
fprintf(NewConfigFile, "MarineAimSkill=0.5\n");
|
||||
fprintf(NewConfigFile, "MarineMovementTracking=0.4\n");
|
||||
fprintf(NewConfigFile, "MarineViewSpeed=1.0\n");
|
||||
fprintf(NewConfigFile, "AlienReactionTime=0.2\n");
|
||||
fprintf(NewConfigFile, "AlienAimSkill=0.5\n");
|
||||
fprintf(NewConfigFile, "AlienMovementTracking=0.5\n");
|
||||
fprintf(NewConfigFile, "AlienViewSpeed=1.3\n\n");
|
||||
|
||||
fprintf(NewConfigFile, "BotSkillLevel=2\n");
|
||||
fprintf(NewConfigFile, "MarineReactionTime=0.2\n");
|
||||
fprintf(NewConfigFile, "MarineAimSkill=0.6\n");
|
||||
fprintf(NewConfigFile, "MarineMovementTracking=0.6\n");
|
||||
fprintf(NewConfigFile, "MarineViewSpeed=1.5\n");
|
||||
fprintf(NewConfigFile, "AlienReactionTime=0.2\n");
|
||||
fprintf(NewConfigFile, "AlienAimSkill=0.8\n");
|
||||
fprintf(NewConfigFile, "AlienMovementTracking=0.8\n");
|
||||
fprintf(NewConfigFile, "AlienViewSpeed=1.5\n\n");
|
||||
|
||||
fprintf(NewConfigFile, "BotSkillLevel=3\n");
|
||||
fprintf(NewConfigFile, "MarineReactionTime=0.1\n");
|
||||
fprintf(NewConfigFile, "MarineAimSkill=1.0\n");
|
||||
fprintf(NewConfigFile, "MarineMovementTracking=1.0\n");
|
||||
fprintf(NewConfigFile, "MarineViewSpeed=2.0\n");
|
||||
fprintf(NewConfigFile, "AlienReactionTime=0.1\n");
|
||||
fprintf(NewConfigFile, "AlienAimSkill=1.0\n");
|
||||
fprintf(NewConfigFile, "AlienMovementTracking=1.0\n");
|
||||
fprintf(NewConfigFile, "AlienViewSpeed=2.0\n\n");
|
||||
|
||||
fprintf(NewConfigFile, "# Desired team sizes. Only used if bot fill mode is 'fillteams'\n");
|
||||
fprintf(NewConfigFile, "# Format is TeamSize=mapname:nummarines/numaliens\n");
|
||||
fprintf(NewConfigFile, "# 'default' will be used if playing a map not listed below\n");
|
||||
fprintf(NewConfigFile, "TeamSize=default:7/7\n");
|
||||
fprintf(NewConfigFile, "TeamSize=ns_machina:8/8\n");
|
||||
fprintf(NewConfigFile, "TeamSize=ns_ragnarok:8/8\n");
|
||||
fprintf(NewConfigFile, "TeamSize=co_faceoff:4/4\n");
|
||||
fprintf(NewConfigFile, "TeamSize=co_core:4/4\n");
|
||||
fprintf(NewConfigFile, "TeamSize=co_pulse:6/6\n");
|
||||
fprintf(NewConfigFile, "TeamSize=co_ulysses:6/6\n");
|
||||
fprintf(NewConfigFile, "TeamSize=co_niveus:5/5\n");
|
||||
fprintf(NewConfigFile, "TeamSize=co_kestrel:5/5\n\n\n");
|
||||
|
||||
|
||||
fprintf(NewConfigFile, "### Alien Settings ###\n\n");
|
||||
|
||||
fprintf(NewConfigFile, "# Preferred chamber sequence. Valid entries are 'defense', 'movement' and 'sensory'. Separate sequence with forward slash\n");
|
||||
fprintf(NewConfigFile, "# You can also use ? for random, so if you want movement always first but then defense and sensory at random, use\n");
|
||||
fprintf(NewConfigFile, "# ChamberSequence:movement/?/?\n");
|
||||
fprintf(NewConfigFile, "# Or if you want sensory always last, but movement and defence random, use\n");
|
||||
fprintf(NewConfigFile, "# ChamberSequence=?/?/sensory\n");
|
||||
fprintf(NewConfigFile, "ChamberSequence=defense/movement/sensory\n");
|
||||
|
||||
fflush(NewConfigFile);
|
||||
fclose(NewConfigFile);
|
||||
|
||||
}
|
|
@ -58,6 +58,6 @@ bot_skill CONFIG_GetBotSkillLevel();
|
|||
|
||||
BotFillTiming CONFIG_GetBotFillTiming();
|
||||
|
||||
|
||||
void CONFIG_RegenerateIniFile();
|
||||
|
||||
#endif
|
|
@ -352,6 +352,7 @@ typedef struct _AVH_AI_BUILDABLE_STRUCTURE
|
|||
bool bReachabilityMarkedDirty = false; // If true, reachability flags will be recalculated for this structure
|
||||
|
||||
bool IsValid() { return !FNullEnt(edict) && !edict->free && !(edict->v.flags & EF_NODRAW) && edict->v.deadflag == DEAD_NO; }
|
||||
bool IsCompleted() { return (StructureStatusFlags & STRUCTURE_STATUS_COMPLETED); }
|
||||
|
||||
} AvHAIBuildableStructure;
|
||||
|
||||
|
|
|
@ -1706,7 +1706,7 @@ dtStatus FindFlightPathToPoint(const nav_profile &NavProfile, Vector FromLocatio
|
|||
|
||||
if (CurrFlags == SAMPLE_POLYFLAGS_JUMP || CurrFlags == SAMPLE_POLYFLAGS_WALLCLIMB || CurrFlags == SAMPLE_POLYFLAGS_FLY)
|
||||
{
|
||||
float MaxHeight = (CurrFlags == SAMPLE_POLYFLAGS_JUMP) ? fmaxf(PrevPoint.z, NextPathPoint.z) + 60.0f : UTIL_FindZHeightForWallClimb(path.back().Location, NextPathPoint, head_hull);
|
||||
float MaxHeight = (CurrFlags == SAMPLE_POLYFLAGS_JUMP) ? fmaxf(PrevPoint.z, NextPathPoint.z) + 60.0f : UTIL_FindZHeightForWallClimb(PrevPoint, NextPathPoint, head_hull);
|
||||
|
||||
NextPathNode.requiredZ = MaxHeight;
|
||||
NextPathNode.Location = PrevPoint;
|
||||
|
@ -1752,7 +1752,7 @@ dtStatus FindFlightPathToPoint(const nav_profile &NavProfile, Vector FromLocatio
|
|||
}
|
||||
|
||||
bot_path_node FinalInitialPathNode;
|
||||
FinalInitialPathNode.FromLocation = path.back().Location;
|
||||
FinalInitialPathNode.FromLocation = (path.size() > 0) ? path.back().Location : FromLocation;
|
||||
FinalInitialPathNode.Location = ToLocation;
|
||||
FinalInitialPathNode.area = SAMPLE_POLYAREA_GROUND;
|
||||
FinalInitialPathNode.flag = SAMPLE_POLYFLAGS_WALLCLIMB;
|
||||
|
@ -5920,7 +5920,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
|
|||
pBot->BotNavInfo.NextForceRecalc = 0.0f;
|
||||
pBot->BotNavInfo.bNavProfileChanged = false;
|
||||
|
||||
if (dtStatusSucceed(PathFindingStatus))
|
||||
if (dtStatusSucceed(PathFindingStatus) && BotNavInfo->CurrentPath.size() > 0)
|
||||
{
|
||||
pBot->BotNavInfo.StuckInfo.bPathFollowFailed = false;
|
||||
ClearBotStuckMovement(pBot);
|
||||
|
@ -6107,7 +6107,7 @@ Vector FindClosestNavigablePointToDestination(const nav_profile& NavProfile, con
|
|||
|
||||
dtStatus PathFindingResult = FindPathClosestToPoint(NavProfile, FromLocation, ToLocation, Path, MaxAcceptableDistance);
|
||||
|
||||
if (dtStatusSucceed(PathFindingResult))
|
||||
if (dtStatusSucceed(PathFindingResult) && Path.size() > 0)
|
||||
{
|
||||
return Path.back().Location;
|
||||
}
|
||||
|
@ -6897,7 +6897,7 @@ bool BotRecalcPath(AvHAIPlayer* pBot, const Vector Destination)
|
|||
|
||||
dtStatus FoundPath = FindPathClosestToPoint(pBot, pBot->BotNavInfo.MoveStyle, pBot->CurrentFloorPosition, ValidNavmeshPoint, pBot->BotNavInfo.CurrentPath, max_ai_use_reach);
|
||||
|
||||
if (dtStatusSucceed(FoundPath))
|
||||
if (dtStatusSucceed(FoundPath) && pBot->BotNavInfo.CurrentPath.size() > 0)
|
||||
{
|
||||
pBot->BotNavInfo.TargetDestination = Destination;
|
||||
pBot->BotNavInfo.ActualMoveDestination = pBot->BotNavInfo.CurrentPath.back().Location;
|
||||
|
@ -8433,7 +8433,7 @@ void NAV_SetMoveMovementTask(AvHAIPlayer* pBot, Vector MoveLocation, DoorTrigger
|
|||
vector<bot_path_node> Path;
|
||||
dtStatus PathStatus = FindPathClosestToPoint(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, MoveLocation, Path, 200.0f);
|
||||
|
||||
if (dtStatusSucceed(PathStatus))
|
||||
if (dtStatusSucceed(PathStatus) && Path.size() > 0)
|
||||
{
|
||||
MoveTask->TaskLocation = Path.back().Location;
|
||||
}
|
||||
|
@ -8452,7 +8452,7 @@ void NAV_SetTouchMovementTask(AvHAIPlayer* pBot, edict_t* EntityToTouch, DoorTri
|
|||
vector<bot_path_node> Path;
|
||||
dtStatus PathStatus = FindPathClosestToPoint(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UTIL_GetCentreOfEntity(EntityToTouch), Path, 200.0f);
|
||||
|
||||
if (dtStatusSucceed(PathStatus))
|
||||
if (dtStatusSucceed(PathStatus) && Path.size() > 0)
|
||||
{
|
||||
MoveTask->TaskLocation = Path.back().Location;
|
||||
}
|
||||
|
|
|
@ -3413,8 +3413,11 @@ void AIPlayerSetMarineCapperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|
|||
|
||||
void AIPlayerSetMarineAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||
{
|
||||
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
|
||||
|
||||
// Go attack sieged hive
|
||||
const AvHAIHiveDefinition* ActiveSiegeHive = AITAC_GetNearestHiveUnderActiveSiege(pBot->Player->GetTeam(), pBot->Edict->v.origin);
|
||||
const AvHAIHiveDefinition* ActiveSiegeHive = AITAC_GetNearestHiveUnderActiveSiege(BotTeam, pBot->Edict->v.origin);
|
||||
|
||||
if (ActiveSiegeHive)
|
||||
{
|
||||
|
@ -3434,7 +3437,9 @@ void AIPlayerSetMarineAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
|
|||
AvHAIHiveDefinition* ThisHive = (*it);
|
||||
if (ThisHive->Status != HIVE_STATUS_UNBUILT) { continue; }
|
||||
|
||||
int NumMarinesSecuring = AITAC_GetNumPlayersOfTeamInArea(pBot->Player->GetTeam(), ThisHive->Location, UTIL_MetresToGoldSrcUnits(15.0f), false, pBot->Edict, AVH_USER3_COMMANDER_PLAYER);
|
||||
if (AICOMM_IsHiveFullySecured(pBot, ThisHive, false)) { continue; }
|
||||
|
||||
int NumMarinesSecuring = AITAC_GetNumPlayersOfTeamInArea(BotTeam, ThisHive->Location, UTIL_MetresToGoldSrcUnits(15.0f), false, pBot->Edict, AVH_USER3_COMMANDER_PLAYER);
|
||||
|
||||
if (NumMarinesSecuring < 2)
|
||||
{
|
||||
|
@ -3461,15 +3466,39 @@ void AIPlayerSetMarineAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
|
|||
|
||||
// Go to a good siege location if phase gates available
|
||||
|
||||
if (AITAC_PhaseGatesAvailable(pBot->Player->GetTeam()))
|
||||
if (AITAC_PhaseGatesAvailable(BotTeam))
|
||||
{
|
||||
const AvHAIHiveDefinition* ActiveHive = AITAC_GetActiveHiveNearestLocation(AIMGR_GetEnemyTeam(pBot->Player->GetTeam()), pBot->Edict->v.origin);
|
||||
const AvHAIHiveDefinition* ActiveHive = AITAC_GetActiveHiveNearestLocation(AIMGR_GetEnemyTeam(BotTeam), pBot->Edict->v.origin);
|
||||
|
||||
if (ActiveHive)
|
||||
{
|
||||
if (Task->TaskType != TASK_MOVE)
|
||||
DeployableSearchFilter EnemyDefences;
|
||||
EnemyDefences.DeployableTeam = EnemyTeam;
|
||||
EnemyDefences.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
|
||||
EnemyDefences.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||
EnemyDefences.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
|
||||
|
||||
if (!AITAC_DeployableExistsAtLocation(ActiveHive->FloorLocation, &EnemyDefences) && AITAC_GetNumPlayersOnTeamWithLOS(EnemyTeam, ActiveHive->Location, UTIL_MetresToGoldSrcUnits(10.0f), nullptr) < 3)
|
||||
{
|
||||
AITASK_SetMoveTask(pBot, Task, UTIL_GetRandomPointOnNavmeshInDonut(pBot->BotNavInfo.NavProfile, ActiveHive->FloorLocation, UTIL_MetresToGoldSrcUnits(10.0f), UTIL_MetresToGoldSrcUnits(20.0f)), false);
|
||||
AITASK_SetAttackTask(pBot, Task, ActiveHive->HiveEdict, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Task->TaskType != TASK_GUARD || vDist2DSq(Task->TaskLocation, ActiveHive->Location) > sqrf(UTIL_MetresToGoldSrcUnits(20.0f)))
|
||||
{
|
||||
Vector GuardLocation = UTIL_GetRandomPointOnNavmeshInDonut(pBot->BotNavInfo.NavProfile, ActiveHive->FloorLocation, UTIL_MetresToGoldSrcUnits(15.0f), UTIL_MetresToGoldSrcUnits(25.0f));
|
||||
|
||||
if (!vIsZero(GuardLocation))
|
||||
{
|
||||
|
||||
Task->TaskType = TASK_GUARD;
|
||||
Task->TaskLength = 60.0f;
|
||||
Task->TaskLocation = GuardLocation;
|
||||
Task->bTaskIsUrgent = false;
|
||||
Task->TaskStartedTime = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
|
@ -413,24 +413,12 @@ void AIMGR_AddAIPlayerToTeam(int Team)
|
|||
int NewBotIndex = -1;
|
||||
edict_t* BotEnt = nullptr;
|
||||
|
||||
// If game has ended, don't allow new bots to be added
|
||||
if (GetGameRules()->GetVictoryTeam() != TEAM_IND)
|
||||
// If bots aren't enabled or the game has ended, don't allow new bots to be added
|
||||
if (!AIMGR_IsBotEnabled() || GetGameRules()->GetVictoryTeam() != TEAM_IND)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NavmeshLoaded())
|
||||
{
|
||||
CONFIG_ParseConfigFile();
|
||||
|
||||
const char* theCStrLevelName = STRING(gpGlobals->mapname);
|
||||
|
||||
if (!loadNavigationData(theCStrLevelName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ActiveAIPlayers.size() >= gpGlobals->maxClients)
|
||||
{
|
||||
ALERT(at_console, "Bot limit reached, cannot add more\n");
|
||||
|
@ -594,7 +582,6 @@ void AIMGR_UpdateAIPlayers()
|
|||
static int CurrentBotSkill = 1;
|
||||
|
||||
static int UpdateIndex = 0;
|
||||
static int FrameSpread = 3;
|
||||
|
||||
CurrTime = gpGlobals->time;
|
||||
|
||||
|
@ -614,8 +601,6 @@ void AIMGR_UpdateAIPlayers()
|
|||
CurrentBotSkill = cvarBotSkill;
|
||||
}
|
||||
|
||||
bool bHasCommander = false;
|
||||
|
||||
if (bHasRoundStarted)
|
||||
{
|
||||
AvHTeamNumber TeamANumber = GetGameRules()->GetTeamANumber();
|
||||
|
@ -641,6 +626,15 @@ void AIMGR_UpdateAIPlayers()
|
|||
}
|
||||
}
|
||||
|
||||
int NumCommanders = AIMGR_GetNumAICommanders();
|
||||
int NumRegularBots = AIMGR_GetNumAIPlayers() - NumCommanders;
|
||||
|
||||
int NumBotsThinkThisFrame = 0;
|
||||
|
||||
int BotsPerFrame = ceil(BOT_THINK_RATE_HZ * NumRegularBots * FrameDelta);
|
||||
|
||||
int BotIndex = 0;
|
||||
|
||||
for (auto BotIt = ActiveAIPlayers.begin(); BotIt != ActiveAIPlayers.end();)
|
||||
{
|
||||
// If bot has been kicked from the server then remove from active AI player list
|
||||
|
@ -652,45 +646,35 @@ void AIMGR_UpdateAIPlayers()
|
|||
|
||||
AvHAIPlayer* bot = &(*BotIt);
|
||||
|
||||
if (IsPlayerCommander(bot->Edict))
|
||||
{
|
||||
bHasCommander = true;
|
||||
}
|
||||
|
||||
if (bSkillChanged)
|
||||
{
|
||||
const bot_skill NewSkillSettings = CONFIG_GetBotSkillLevel();
|
||||
memcpy(&bot->BotSkillSettings, &NewSkillSettings, sizeof(bot_skill));
|
||||
}
|
||||
|
||||
int BotIndex = distance(ActiveAIPlayers.begin(), BotIt);
|
||||
|
||||
BotUpdateViewRotation(bot, FrameDelta);
|
||||
|
||||
if (bHasRoundStarted)
|
||||
{
|
||||
if (IsPlayerCommander(bot->Edict))
|
||||
{
|
||||
if (UpdateIndex == FrameSpread)
|
||||
if (UpdateIndex == -1)
|
||||
{
|
||||
AIPlayerThink(bot);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (UpdateIndex != FrameSpread)
|
||||
if (UpdateIndex > -1 && BotIndex >= UpdateIndex && NumBotsThinkThisFrame < BotsPerFrame)
|
||||
{
|
||||
int BotModulo = BotIndex % FrameSpread;
|
||||
|
||||
if (BotModulo == UpdateIndex)
|
||||
{
|
||||
AIPlayerThink(bot);
|
||||
}
|
||||
AIPlayerThink(bot);
|
||||
NumBotsThinkThisFrame++;
|
||||
}
|
||||
BotIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_DEDICATED_SERVER() || (CurrTime - bot->LastServerUpdateTime) >= BOT_MIN_FRAME_TIME)
|
||||
if (IS_DEDICATED_SERVER() || (CurrTime - bot->LastServerUpdateTime) >= BOT_SERVER_UPDATE_RATE)
|
||||
{
|
||||
UpdateBotChat(bot);
|
||||
|
||||
|
@ -707,12 +691,26 @@ void AIMGR_UpdateAIPlayers()
|
|||
BotIt++;
|
||||
}
|
||||
|
||||
UpdateIndex++;
|
||||
|
||||
if (UpdateIndex > FrameSpread || (!bHasCommander && UpdateIndex == FrameSpread))
|
||||
if (UpdateIndex < 0)
|
||||
{
|
||||
UpdateIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateIndex += NumBotsThinkThisFrame;
|
||||
}
|
||||
|
||||
if (UpdateIndex >= NumRegularBots)
|
||||
{
|
||||
if (NumCommanders > 0)
|
||||
{
|
||||
UpdateIndex = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
PrevTime = CurrTime;
|
||||
|
||||
|
@ -723,6 +721,21 @@ int AIMGR_GetNumAIPlayers()
|
|||
return ActiveAIPlayers.size();
|
||||
}
|
||||
|
||||
int AIMGR_GetNumAICommanders()
|
||||
{
|
||||
int Result = 0;
|
||||
|
||||
for (auto it = ActiveAIPlayers.begin(); it != ActiveAIPlayers.end(); it++)
|
||||
{
|
||||
if (it->Player->GetUser3() == AVH_USER3_COMMANDER_PLAYER)
|
||||
{
|
||||
Result++;
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
AvHTeamNumber AIMGR_GetTeamANumber()
|
||||
{
|
||||
return GetGameRules()->GetTeamANumber();
|
||||
|
@ -1001,8 +1014,6 @@ void AIMGR_NewMap()
|
|||
|
||||
AITAC_ClearMapAIData(true);
|
||||
|
||||
CONFIG_ParseConfigFile();
|
||||
|
||||
AIMGR_BotPrecache();
|
||||
|
||||
bHasRoundStarted = false;
|
||||
|
@ -1030,6 +1041,8 @@ void AIMGR_LoadNavigationData()
|
|||
// Don't reload the nav mesh if it's already loaded
|
||||
if (NavmeshLoaded()) { return; }
|
||||
|
||||
CONFIG_ParseConfigFile();
|
||||
|
||||
const char* theCStrLevelName = STRING(gpGlobals->mapname);
|
||||
|
||||
if (!loadNavigationData(theCStrLevelName))
|
||||
|
@ -1189,6 +1202,11 @@ void AIMGR_UpdateAIMapData()
|
|||
}
|
||||
}
|
||||
|
||||
void AIMGR_RegenBotIni()
|
||||
{
|
||||
CONFIG_RegenerateIniFile();
|
||||
}
|
||||
|
||||
void AIMGR_BotPrecache()
|
||||
{
|
||||
m_spriteTexture = PRECACHE_MODEL("sprites/zbeam6.spr");
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
#include "../AvHConstants.h"
|
||||
#include "AvHAIPlayer.h"
|
||||
|
||||
// Max rate bot can run its logic, default is 1/60th second. WARNING: Increasing the rate past 100hz causes bots to move and turn slowly due to GoldSrc limits!
|
||||
static const double BOT_MIN_FRAME_TIME = (1.0 / 100.0);
|
||||
// The rate at which the bot will call RunPlayerMove in, default is 100hz. WARNING: Increasing the rate past 100hz causes bots to move and turn slowly due to GoldSrc limits!
|
||||
static const double BOT_SERVER_UPDATE_RATE = (1.0 / 100.0);
|
||||
// The rate in hz (times per second) at which the bot will call AIPlayerThink, default is 10 times per second.
|
||||
static const int BOT_THINK_RATE_HZ = 10;
|
||||
// Once the first human player has joined the game, how long to wait before adding bots
|
||||
static const float AI_GRACE_PERIOD = 5.0f;
|
||||
// Max time to wait before spawning players if none connect (e.g. empty dedicated server)
|
||||
|
@ -43,9 +45,13 @@ vector<AvHPlayer*> AIMGR_GetAllPlayersOnTeam(AvHTeamNumber Team);
|
|||
int AIMGR_GetNumPlayersOnTeam(AvHTeamNumber Team);
|
||||
// How many AI players are in the game (does NOT include third-party bots like RCBot/Whichbot)
|
||||
int AIMGR_GetNumAIPlayers();
|
||||
// How many bot commanders we have (across both teams)
|
||||
int AIMGR_GetNumAICommanders();
|
||||
// Returns true if an AI player is on the requested team (does NOT include third-party bots like RCBot/Whichbot)
|
||||
int AIMGR_AIPlayerExistsOnTeam(AvHTeamNumber Team);
|
||||
|
||||
void AIMGR_RegenBotIni();
|
||||
|
||||
void AIMGR_UpdateAIMapData();
|
||||
bool AIMGR_ShouldStartPlayerBalancing();
|
||||
|
||||
|
|
|
@ -4188,7 +4188,7 @@ vector<AvHPlayer*> AITAC_GetAllPlayersOnTeamWithLOS(AvHTeamNumber Team, const Ve
|
|||
return Results;
|
||||
}
|
||||
|
||||
bool AITAC_GetNumPlayersOnTeamWithLOS(AvHTeamNumber Team, const Vector& Location, float SearchRadius, edict_t* IgnorePlayer)
|
||||
int AITAC_GetNumPlayersOnTeamWithLOS(AvHTeamNumber Team, const Vector& Location, float SearchRadius, edict_t* IgnorePlayer)
|
||||
{
|
||||
int Result = 0;
|
||||
|
||||
|
|
|
@ -86,7 +86,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);
|
||||
int 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);
|
||||
|
||||
|
|
|
@ -915,7 +915,7 @@ bool AITASK_IsMarineSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask*
|
|||
{
|
||||
AvHAIBuildableStructure Structure = (*it);
|
||||
|
||||
if (Structure.StructureType == STRUCTURE_MARINE_TURRETFACTORY)
|
||||
if (Structure.StructureType == STRUCTURE_MARINE_PHASEGATE)
|
||||
{
|
||||
bHasPhaseGate = true;
|
||||
}
|
||||
|
@ -2806,7 +2806,7 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat
|
|||
|
||||
dtStatus SearchResult = FindPathClosestToPoint(NavProfile, ThisHive->FloorLocation, GuardLocation, path, 500.0f);
|
||||
|
||||
if (dtStatusSucceed(SearchResult))
|
||||
if (dtStatusSucceed(SearchResult) && path.size() > 0)
|
||||
{
|
||||
Vector FinalApproachDir = UTIL_GetVectorNormal2D(path.back().Location - prev(prev(path.end()))->Location);
|
||||
Vector ProspectiveNewGuardLoc = GuardLocation - (FinalApproachDir * 300.0f);
|
||||
|
@ -2822,7 +2822,7 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat
|
|||
|
||||
dtStatus SearchResult = FindPathClosestToPoint(NavProfile, AITAC_GetTeamStartingLocation(EnemyTeam), GuardLocation, path, 500.0f);
|
||||
|
||||
if (dtStatusSucceed(SearchResult))
|
||||
if (dtStatusSucceed(SearchResult) && path.size() > 0)
|
||||
{
|
||||
Vector FinalApproachDir = UTIL_GetVectorNormal2D(path.back().Location - prev(prev(path.end()))->Location);
|
||||
Vector ProspectiveNewGuardLoc = GuardLocation - (FinalApproachDir * 300.0f);
|
||||
|
@ -2839,7 +2839,7 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat
|
|||
{
|
||||
dtStatus SearchResult = FindPathClosestToPoint(NavProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), GuardLocation, path, 500.0f);
|
||||
|
||||
if (dtStatusSucceed(SearchResult))
|
||||
if (dtStatusSucceed(SearchResult) && path.size() > 0)
|
||||
{
|
||||
Vector FinalApproachDir = UTIL_GetVectorNormal2D(path.back().Location - prev(prev(path.end()))->Location);
|
||||
Vector ProspectiveNewGuardLoc = GuardLocation - (FinalApproachDir * 300.0f);
|
||||
|
@ -3264,19 +3264,20 @@ void AITASK_SetBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Stru
|
|||
|
||||
if (FNullEnt(StructureToBuild) || UTIL_StructureIsFullyBuilt(StructureToBuild)) { return; }
|
||||
|
||||
if (Task->TaskType == TASK_BUILD && Task->TaskTarget == StructureToBuild) { return; }
|
||||
if (Task->TaskType == TASK_BUILD && Task->TaskTarget == StructureToBuild)
|
||||
{
|
||||
Task->bTaskIsUrgent = bIsUrgent;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get as close as possible to desired location
|
||||
Vector BuildLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(StructureToBuild), 80.0f);
|
||||
Vector BuildLocation = UTIL_ProjectPointToNavmesh(StructureToBuild->v.origin);
|
||||
|
||||
if (BuildLocation != g_vecZero)
|
||||
{
|
||||
Task->TaskType = TASK_BUILD;
|
||||
Task->TaskTarget = StructureToBuild;
|
||||
Task->TaskLocation = BuildLocation;
|
||||
Task->bTaskIsUrgent = bIsUrgent;
|
||||
Task->StructureType = GetStructureTypeFromEdict(StructureToBuild);
|
||||
}
|
||||
Task->TaskType = TASK_BUILD;
|
||||
Task->TaskTarget = StructureToBuild;
|
||||
Task->TaskLocation = (!vIsZero(BuildLocation)) ? BuildLocation : UTIL_GetFloorUnderEntity(StructureToBuild);
|
||||
Task->bTaskIsUrgent = bIsUrgent;
|
||||
Task->StructureType = GetStructureTypeFromEdict(StructureToBuild);
|
||||
}
|
||||
|
||||
void AITASK_SetCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const AvHAIResourceNode* NodeRef, const bool bIsUrgent)
|
||||
|
|
|
@ -416,6 +416,11 @@ AvHGamerules::AvHGamerules() : mTeamA(TEAM_ONE), mTeamB(TEAM_TWO)
|
|||
}
|
||||
});
|
||||
|
||||
REGISTER_SERVER_FUNCTION("sv_regenbotini", []()
|
||||
{
|
||||
AIMGR_RegenBotIni();
|
||||
});
|
||||
|
||||
g_VoiceGameMgr.Init(&gVoiceHelper, gpGlobals->maxClients);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
Loading…
Reference in a new issue