mirror of
https://github.com/ENSL/NS.git
synced 2025-03-14 06:34:33 +00:00
Marine and alien tactical bug fixes
This commit is contained in:
parent
16e4f14863
commit
680aa8dbdb
13 changed files with 317 additions and 60 deletions
|
@ -1086,7 +1086,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
|
|||
}
|
||||
|
||||
StructureFilter.DeployableTypes = STRUCTURE_MARINE_PROTOTYPELAB;
|
||||
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
|
||||
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f);
|
||||
StructureFilter.IncludeStatusFlags = STRUCTURE_STATUS_NONE;
|
||||
StructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||
|
||||
|
@ -2065,12 +2065,56 @@ bool AICOMM_CheckForNextRecycleAction(AvHAIPlayer* pBot)
|
|||
{
|
||||
AvHAIHiveDefinition* Hive = (*HiveIt);
|
||||
|
||||
// If the hive is still active or growing, then clearly we should keep any siege bases
|
||||
if (Hive->Status != HIVE_STATUS_UNBUILT) { continue; }
|
||||
|
||||
// If the hive is empty, but we've not secured it yet, then keep any siege bases nearby in case we need to re-siege later
|
||||
DeployableSearchFilter SecuringStructuresFilter;
|
||||
SecuringStructuresFilter.DeployableTypes = (STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_TURRET);
|
||||
SecuringStructuresFilter.DeployableTeam = pBot->Player->GetTeam();
|
||||
SecuringStructuresFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||
SecuringStructuresFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||
SecuringStructuresFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
|
||||
|
||||
vector<AvHAIBuildableStructure*> NearbySecuringStructures = AITAC_FindAllDeployables(Hive->Location, &SecuringStructuresFilter);
|
||||
|
||||
bool bHiveHasPG = false;
|
||||
bool bHiveHasTF = false;
|
||||
bool bHiveHasTurret = false;
|
||||
|
||||
for (auto SecureIt = NearbySecuringStructures.begin(); SecureIt != NearbySecuringStructures.end(); SecureIt++)
|
||||
{
|
||||
AvHAIBuildableStructure* Structure = (*SecureIt);
|
||||
|
||||
if (Structure->Purpose == STRUCTURE_PURPOSE_SIEGE)
|
||||
{
|
||||
if (Structure->StructureType == STRUCTURE_MARINE_PHASEGATE)
|
||||
{
|
||||
bHiveHasPG = true;
|
||||
}
|
||||
|
||||
if (Structure->StructureType == STRUCTURE_MARINE_TURRETFACTORY || Structure->StructureType == STRUCTURE_MARINE_ADVTURRETFACTORY)
|
||||
{
|
||||
bHiveHasTF = true;
|
||||
}
|
||||
|
||||
if (Structure->StructureType == STRUCTURE_MARINE_TURRET)
|
||||
{
|
||||
bHiveHasTurret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool bHiveIsSecureEnough = (bHiveHasPG && bHiveHasTF && bHiveHasTurret);
|
||||
|
||||
if (!bHiveIsSecureEnough) { continue; }
|
||||
|
||||
// Ok, hive is secured by us, now we can check if there are any siege objects to be got rid of
|
||||
DeployableSearchFilter RedundantFilter;
|
||||
RedundantFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
|
||||
RedundantFilter.DeployableTeam = pBot->Player->GetTeam();
|
||||
RedundantFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||
RedundantFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(25.0f);
|
||||
RedundantFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(30.0f);
|
||||
|
||||
vector<AvHAIBuildableStructure*> NearbyStructures = AITAC_FindAllDeployables(Hive->Location, &RedundantFilter);
|
||||
|
||||
|
|
|
@ -224,6 +224,11 @@ bool IsEdictStructure(const edict_t* edict)
|
|||
return (GetDeployableObjectTypeFromEdict(edict) != STRUCTURE_NONE);
|
||||
}
|
||||
|
||||
bool IsEdictHive(const edict_t* edict)
|
||||
{
|
||||
return (GetDeployableObjectTypeFromEdict(edict) != STRUCTURE_ALIEN_HIVE);
|
||||
}
|
||||
|
||||
bool IsDamagingStructure(const edict_t* StructureEdict)
|
||||
{
|
||||
return IsDamagingStructure(GetStructureTypeFromEdict(StructureEdict));
|
||||
|
|
|
@ -25,6 +25,7 @@ Vector UTIL_GetClosestPointOnEntityToLocation(const Vector Location, edict_t* En
|
|||
AvHAIDeployableStructureType IUSER3ToStructureType(const int inIUSER3);
|
||||
|
||||
bool IsEdictStructure(const edict_t* edict);
|
||||
bool IsEdictHive(const edict_t* edict);
|
||||
|
||||
AvHAIDeployableStructureType GetStructureTypeFromEdict(const edict_t* StructureEdict);
|
||||
|
||||
|
|
|
@ -2004,7 +2004,7 @@ bool HasBotReachedPathPoint(const AvHAIPlayer* pBot)
|
|||
Vector ClosestPointToPath = vClosestPointOnLine2D(MoveFrom, MoveTo, pEdict->v.origin);
|
||||
|
||||
bool bDestIsDirectlyReachable = UTIL_PointIsDirectlyReachable(CurrentPos, MoveTo);
|
||||
bool bAtOrPastDestination = vEquals2D(ClosestPointToPath, MoveTo, 1.0f) && bDestIsDirectlyReachable;
|
||||
bool bAtOrPastDestination = vEquals2D(ClosestPointToPath, MoveTo, 8.0f) && bDestIsDirectlyReachable;
|
||||
|
||||
dtPolyRef BotPoly = pBot->BotNavInfo.CurrentPoly;
|
||||
dtPolyRef DestinationPoly = pBot->BotNavInfo.CurrentPathPoint->poly;
|
||||
|
@ -3916,14 +3916,14 @@ bool IsBotOffPath(const AvHAIPlayer* pBot)
|
|||
|
||||
bool bAtMoveEnd = vEquals(PointOnPath, MoveTo, GetPlayerRadius(pBot->Player));
|
||||
|
||||
if (bAtMoveEnd && fabs(pBot->CurrentFloorPosition.z - MoveTo.z) > PlayerHeight)
|
||||
if (bAtMoveEnd && fabsf(pBot->CurrentFloorPosition.z - MoveTo.z) > PlayerHeight)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
float MaxDist = (bAtMoveStart || bAtMoveEnd) ? 50.0f : 200.0f;
|
||||
|
||||
if (vDistanceFromLine2D(MoveFrom, MoveTo, pBot->CurrentFloorPosition) > sqrf(MaxDist))
|
||||
if (vDistanceFromLine2D(MoveFrom, MoveTo, pBot->CurrentFloorPosition) > MaxDist)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -5744,6 +5744,12 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
|
|||
SkipAheadInFlightPath(pBot);
|
||||
}
|
||||
|
||||
if (!UTIL_QuickTrace(pBot->Edict, pBot->Edict->v.origin, BotNavInfo->CurrentPathPoint->Location + Vector(0.0f, 0.0f, 5.0f)))
|
||||
{
|
||||
ClearBotPath(pBot);
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentMoveDest = BotNavInfo->CurrentPathPoint->Location;
|
||||
Vector MoveFrom = BotNavInfo->CurrentPathPoint->FromLocation;
|
||||
|
||||
|
@ -7702,7 +7708,7 @@ void UTIL_UpdateDoorTriggers(nav_door* Door)
|
|||
{
|
||||
if (it->LastToggleState != TS_GOING_UP && it->LastToggleState != TS_GOING_DOWN)
|
||||
{
|
||||
it->NextActivationTime = gpGlobals->time + it->ActivationDelay;
|
||||
it->NextActivationTime = gpGlobals->time + fmaxf(it->ActivationDelay + 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
it->LastToggleState = (TOGGLE_STATE)it->ToggleEnt->GetToggleState();
|
||||
|
|
|
@ -368,7 +368,7 @@ void BotSay(AvHAIPlayer* pBot, bool bTeamSay, float Delay, char* textToSay)
|
|||
bool BotReloadWeapons(AvHAIPlayer* pBot)
|
||||
{
|
||||
// Aliens and commander don't reload
|
||||
if (!IsPlayerMarine(pBot->Edict) || !IsPlayerActiveInGame(pBot->Edict)) { return false; }
|
||||
if (!IsPlayerMarine(pBot->Edict) || !IsPlayerActiveInGame(pBot->Edict) || IsPlayerReloading(pBot->Player)) { return false; }
|
||||
|
||||
AvHAIWeapon PrimaryWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player);
|
||||
AvHAIWeapon SecondaryWeapon = GetBotMarineSecondaryWeapon(pBot);
|
||||
|
@ -3314,6 +3314,11 @@ void AIPlayerSetMarineBombardierPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask*
|
|||
|
||||
void AIPlayerSetWantsAndNeedsMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||
{
|
||||
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
|
||||
{
|
||||
if (BotReloadWeapons(pBot)) { return; }
|
||||
}
|
||||
|
||||
if (Task->TaskType == TASK_RESUPPLY || Task->TaskType == TASK_GET_HEALTH || Task->TaskType == TASK_GET_AMMO) { return; }
|
||||
|
||||
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||
|
@ -3818,11 +3823,12 @@ void AIPlayerNSAlienThink(AvHAIPlayer* pBot)
|
|||
|
||||
AIPlayerSetPrimaryAlienTask(pBot, &pBot->PrimaryBotTask);
|
||||
AIPlayerSetSecondaryAlienTask(pBot, &pBot->SecondaryBotTask);
|
||||
AIPlayerSetWantsAndNeedsAlienTask(pBot, &pBot->WantsAndNeedsTask);
|
||||
}
|
||||
|
||||
pBot->CurrentTask = AIPlayerGetNextTask(pBot);
|
||||
|
||||
if (pBot->LastCombatTime > 5.0f)
|
||||
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
|
||||
{
|
||||
if (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_DEFENCE) && AITAC_IsAlienUpgradeAvailableForTeam(pBot->Player->GetTeam(), HIVE_TECH_DEFENCE))
|
||||
{
|
||||
|
@ -4148,11 +4154,24 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|
|||
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
|
||||
|
||||
int NumMissingChambers = 0;
|
||||
|
||||
// Do we have any missing upgrade chambers (should have 3 of each if we can build them)
|
||||
AvHAIDeployableStructureType MissingStructure = AITAC_GetNextMissingUpgradeChamberForTeam(BotTeam);
|
||||
AvHAIDeployableStructureType MissingStructure = AITAC_GetNextMissingUpgradeChamberForTeam(BotTeam, NumMissingChambers);
|
||||
bool bShouldBuildMissingStructure = false;
|
||||
|
||||
if (MissingStructure != STRUCTURE_NONE)
|
||||
{
|
||||
int NumBuilders = AITASK_GetNumBotsWithBuildTask(BotTeam, MissingStructure, pBot->Edict);
|
||||
|
||||
if (NumBuilders < NumMissingChambers)
|
||||
{
|
||||
bShouldBuildMissingStructure = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If we do have a missing upgrade chamber, built it at the nearest hive or resource node that we own, whichever is nearest
|
||||
if (MissingStructure != STRUCTURE_NONE)
|
||||
if (bShouldBuildMissingStructure)
|
||||
{
|
||||
if (Task->TaskType == TASK_BUILD && Task->StructureType == MissingStructure) { return; }
|
||||
|
||||
|
@ -4221,7 +4240,7 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|
|||
|
||||
AvHAIHiveDefinition* HiveToSecure = nullptr;
|
||||
|
||||
float MaxDist = 0.0f;
|
||||
float MinDist = 0.0f;
|
||||
|
||||
for (auto it = AllHives.begin(); it != AllHives.end(); it++)
|
||||
{
|
||||
|
@ -4291,12 +4310,12 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|
|||
|| (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_MOVEMENT_CHAMBER) && NumMCs < 1)
|
||||
|| (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_SENSORY_CHAMBER) && NumSCs < 1))
|
||||
{
|
||||
float ThisDist = vDist2DSq(AITAC_GetTeamStartingLocation(EnemyTeam), ThisHive->FloorLocation);
|
||||
float ThisDist = vDist2DSq(pBot->Edict->v.origin, ThisHive->FloorLocation);
|
||||
|
||||
if (ThisDist > MaxDist)
|
||||
if (!HiveToSecure || ThisDist < MinDist)
|
||||
{
|
||||
HiveToSecure = ThisHive;
|
||||
MaxDist = ThisDist;
|
||||
MinDist = ThisDist;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4318,7 +4337,7 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|
|||
vector<AvHAIBuildableStructure*> AllMatchingTowers = AITAC_FindAllDeployables(pBot->Edict->v.origin, &ResNodeFilter);
|
||||
|
||||
edict_t* TowerToReinforce = nullptr;
|
||||
float MinDist = 0.0f;
|
||||
MinDist = 0.0f;
|
||||
|
||||
for (auto it = AllMatchingTowers.begin(); it != AllMatchingTowers.end(); it++)
|
||||
{
|
||||
|
@ -4327,7 +4346,7 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|
|||
DeployableSearchFilter ExistingReinforcementFilter;
|
||||
ExistingReinforcementFilter.DeployableTeam = BotTeam;
|
||||
ExistingReinforcementFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
|
||||
ExistingReinforcementFilter.DeployableTypes = SEARCH_ALL_ALIEN_STRUCTURES;
|
||||
ExistingReinforcementFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
|
||||
|
||||
vector<AvHAIBuildableStructure*> AllReinforcingStructures = AITAC_FindAllDeployables(ThisResTower->Location, &ExistingReinforcementFilter);
|
||||
|
||||
|
@ -4584,6 +4603,8 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|
|||
return;
|
||||
}
|
||||
|
||||
if (Task->TaskType == TASK_EVOLVE) { return; }
|
||||
|
||||
if (!IsPlayerOnos(pBot->Edict) && pBot->Player->GetResources() >= BALANCE_VAR(kOnosCost))
|
||||
{
|
||||
int NumOnos = AITAC_GetNumPlayersOnTeamOfClass(BotTeam, AVH_USER3_ALIEN_PLAYER5, pBot->Edict);
|
||||
|
@ -4622,6 +4643,14 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|
|||
|
||||
if (NearestSiegedHive)
|
||||
{
|
||||
// Check if we're already trying to break a siege attempt, so we don't get torn between multiple potentials
|
||||
if (Task->TaskType == TASK_ATTACK)
|
||||
{
|
||||
const AvHAIHiveDefinition* HiveNearestAttackTarget = AITAC_GetNearestTeamHive(BotTeam, Task->TaskTarget->v.origin, false);
|
||||
|
||||
if (HiveNearestAttackTarget && vDist2DSq(HiveNearestAttackTarget->Location, Task->TaskTarget->v.origin) <= sqrf(UTIL_MetresToGoldSrcUnits(25.0f))) { return; }
|
||||
}
|
||||
|
||||
DeployableSearchFilter EnemyStuffFilter;
|
||||
EnemyStuffFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
|
||||
EnemyStuffFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||
|
@ -4681,6 +4710,14 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|
|||
// If we're up against marines, look out for any siege stuff
|
||||
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_MARINE)
|
||||
{
|
||||
// Check if we're already trying to break a siege attempt, so we don't get torn between multiple potentials
|
||||
if (Task->TaskType == TASK_ATTACK)
|
||||
{
|
||||
const AvHAIHiveDefinition* HiveNearestAttackTarget = AITAC_GetNearestTeamHive(BotTeam, Task->TaskTarget->v.origin, false);
|
||||
|
||||
if (HiveNearestAttackTarget && vDist2DSq(HiveNearestAttackTarget->Location, Task->TaskTarget->v.origin) <= sqrf(UTIL_MetresToGoldSrcUnits(25.0f))) { return; }
|
||||
}
|
||||
|
||||
vector<AvHAIHiveDefinition*> AllTeamHives = AITAC_GetAllTeamHives(BotTeam, false);
|
||||
|
||||
for (auto it = AllTeamHives.begin(); it != AllTeamHives.end(); it++)
|
||||
|
@ -4689,7 +4726,6 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|
|||
|
||||
DeployableSearchFilter EnemyStuffFilter;
|
||||
EnemyStuffFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
|
||||
EnemyStuffFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||
EnemyStuffFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||
EnemyStuffFilter.DeployableTeam = EnemyTeam;
|
||||
EnemyStuffFilter.ReachabilityTeam = BotTeam;
|
||||
|
@ -4814,8 +4850,10 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|
|||
FriendlyStuffFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
|
||||
FriendlyStuffFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
|
||||
|
||||
if (AITAC_DeployableExistsAtLocation(ThisHive->FloorLocation, &FriendlyStuffFilter)) { continue; }
|
||||
// Don't guard a hive if some defences are already present
|
||||
if (AITAC_GetNumDeployablesNearLocation(ThisHive->FloorLocation, &FriendlyStuffFilter) >= 2) { continue; }
|
||||
|
||||
// Only guard empty hives if a gorge is in there
|
||||
if (AITAC_GetNumPlayersOfTeamAndClassInArea(BotTeam, ThisHive->FloorLocation, UTIL_MetresToGoldSrcUnits(20.0f), false, pBot->Edict, AVH_USER3_ALIEN_PLAYER2) == 0) { continue; }
|
||||
|
||||
bool bNeedsExtraGuards = true;
|
||||
|
@ -4876,6 +4914,14 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|
|||
}
|
||||
else if (HiveToSecure)
|
||||
{
|
||||
// Check if we're already trying to clear out a hive
|
||||
if (Task->TaskType == TASK_ATTACK)
|
||||
{
|
||||
const AvHAIHiveDefinition* HiveNearestAttackTarget = AITAC_GetNearestTeamHive(BotTeam, Task->TaskTarget->v.origin, false);
|
||||
|
||||
if (HiveNearestAttackTarget && vDist2DSq(HiveNearestAttackTarget->Location, Task->TaskTarget->v.origin) <= sqrf(UTIL_MetresToGoldSrcUnits(15.0f))) { return; }
|
||||
}
|
||||
|
||||
EnemyStuffFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
|
||||
|
||||
// Don't attack electrified structures as skulk
|
||||
|
@ -5343,8 +5389,58 @@ void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
return;
|
||||
}
|
||||
|
||||
AITASK_ClearBotTask(pBot, Task);
|
||||
}
|
||||
|
||||
void AIPlayerSetWantsAndNeedsAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||
{
|
||||
float CurrentHealth = GetPlayerOverallHealthPercent(pBot->Edict);
|
||||
|
||||
if (Task->TaskType == TASK_GET_HEALTH)
|
||||
{
|
||||
Task->bTaskIsUrgent = Task->bTaskIsUrgent || CurrentHealth < 0.4f;
|
||||
return;
|
||||
}
|
||||
|
||||
if (CurrentHealth >= 1.0f) { return; }
|
||||
|
||||
bool bCanSelfHeal = (PlayerHasWeapon(pBot->Player, WEAPON_GORGE_HEALINGSPRAY) || PlayerHasWeapon(pBot->Player, WEAPON_FADE_METABOLIZE));
|
||||
|
||||
if (CurrentHealth < 0.95f && bCanSelfHeal && gpGlobals->time - pBot->LastCombatTime > 5.0f)
|
||||
{
|
||||
pBot->DesiredCombatWeapon = (PlayerHasWeapon(pBot->Player, WEAPON_FADE_METABOLIZE)) ? WEAPON_FADE_METABOLIZE : WEAPON_GORGE_HEALINGSPRAY;
|
||||
|
||||
if (GetPlayerCurrentWeapon(pBot->Player) == pBot->DesiredCombatWeapon)
|
||||
{
|
||||
pBot->Button |= IN_ATTACK;
|
||||
}
|
||||
}
|
||||
|
||||
// Only look for gorges as a healing source if we're something with low health like a skulk or lerk, or we have over 50% health. Don't use gorges if we're near death as an Onos or it will take forever...
|
||||
edict_t* NearestHealingSource = AITAC_AlienFindNearestHealingSource(pBot->Player->GetTeam(), pBot->Edict->v.origin, pBot->Edict, (IsPlayerSkulk(pBot->Edict) || IsPlayerLerk(pBot->Edict) || CurrentHealth > 0.5f));
|
||||
|
||||
if (FNullEnt(NearestHealingSource)) { return; }
|
||||
|
||||
float GetHealthThreshold = 0.6f;
|
||||
|
||||
// If we're right by a healing source, then might as well heal up, set the "find health" threshold to 90% or less health
|
||||
if (vDist2DSq(pBot->Edict->v.origin, NearestHealingSource->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
|
||||
{
|
||||
GetHealthThreshold = 0.9f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we can heal ourselves, then don't go running for the hive/DCs/Gorge unless we're very low
|
||||
if (bCanSelfHeal)
|
||||
{
|
||||
GetHealthThreshold = 0.4f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (CurrentHealth < GetHealthThreshold)
|
||||
{
|
||||
AITASK_SetGetHealthTask(pBot, Task, NearestHealingSource, true);
|
||||
}
|
||||
}
|
||||
|
||||
bool AlienCombatThink(AvHAIPlayer* pBot)
|
||||
|
@ -6066,7 +6162,7 @@ bool FadeCombatThink(AvHAIPlayer* pBot)
|
|||
|
||||
bool bInHealingRange = (DistFromHealingSourceSq <= sqrf(DesiredDistFromHealingSource));
|
||||
|
||||
if (!bInHealingRange)
|
||||
if (!bInHealingRange && GetPlayerOverallHealthPercent(pBot->Edict) < 0.5f)
|
||||
{
|
||||
MoveTo(pBot, UTIL_GetEntityGroundLocation(NearestHealingSource), MOVESTYLE_NORMAL, DesiredDistFromHealingSource);
|
||||
|
||||
|
@ -6078,11 +6174,24 @@ bool FadeCombatThink(AvHAIPlayer* pBot)
|
|||
BotLeap(pBot, pBot->BotNavInfo.CurrentPathPoint->Location);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PlayerHasWeapon(pBot->Player, WEAPON_FADE_METABOLIZE))
|
||||
{
|
||||
pBot->DesiredCombatWeapon = WEAPON_FADE_METABOLIZE;
|
||||
|
||||
if (GetPlayerCurrentWeapon(pBot->Player) == WEAPON_FADE_METABOLIZE)
|
||||
{
|
||||
pBot->Button |= IN_ATTACK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bOutOfEnemyLOS)
|
||||
// If we're not in immediate danger, and we're either healing up at the source, or we can metabolize, then wait a bit and catch our breath
|
||||
if (bOutOfEnemyLOS && (bInHealingRange || PlayerHasWeapon(pBot->Player, WEAPON_FADE_METABOLIZE)))
|
||||
{
|
||||
BotLookAt(pBot, TrackedEnemyRef->LastLOSPosition);
|
||||
if (PlayerHasWeapon(pBot->Player, WEAPON_FADE_METABOLIZE))
|
||||
|
@ -6100,10 +6209,21 @@ bool FadeCombatThink(AvHAIPlayer* pBot)
|
|||
if (!UTIL_PlayerHasLOSToLocation(TrackedEnemyRef->EnemyEdict, UTIL_GetEntityGroundLocation(NearestHealingSource) + Vector(0.0f, 0.0f, 16.0f), UTIL_MetresToGoldSrcUnits(30.0f)))
|
||||
{
|
||||
MoveTo(pBot, UTIL_GetEntityGroundLocation(NearestHealingSource), MOVESTYLE_NORMAL, DesiredDistFromHealingSource);
|
||||
|
||||
if (PlayerHasWeapon(pBot->Player, WEAPON_FADE_METABOLIZE))
|
||||
{
|
||||
pBot->DesiredCombatWeapon = WEAPON_FADE_METABOLIZE;
|
||||
|
||||
if (GetPlayerCurrentWeapon(pBot->Player) == WEAPON_FADE_METABOLIZE)
|
||||
{
|
||||
pBot->Button |= IN_ATTACK;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the enemy can see the healing source, then we must go on the attack
|
||||
// If the enemy can see the healing source, then we must go on the attack as we're cornered
|
||||
bShouldBreakRetreat = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,6 +88,7 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|
|||
void AIPlayerSetAlienHarasserPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||
|
||||
void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||
void AIPlayerSetWantsAndNeedsAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||
|
||||
void BotSwitchToWeapon(AvHAIPlayer* pBot, AvHAIWeapon NewWeaponSlot);
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ float AIStartedTime = 0.0f; // Used to give 5-second grace period before adding
|
|||
bool bHasRoundStarted = false;
|
||||
bool bMapDataInitialised = false;
|
||||
|
||||
bool bTestNavigation = false;
|
||||
|
||||
extern int m_spriteTexture;
|
||||
|
||||
Vector DebugVector1 = ZERO_VECTOR;
|
||||
|
@ -623,7 +625,15 @@ void AIMGR_UpdateAIPlayers()
|
|||
|
||||
UpdateBotChat(bot);
|
||||
|
||||
DroneThink(bot);
|
||||
if (bTestNavigation)
|
||||
{
|
||||
TestNavThink(bot);
|
||||
}
|
||||
else
|
||||
{
|
||||
DroneThink(bot);
|
||||
}
|
||||
|
||||
|
||||
EndBotFrame(bot);
|
||||
|
||||
|
@ -1051,4 +1061,14 @@ void AIMGR_SetDebugAIPlayer(edict_t* AIPlayer)
|
|||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AIMGR_SetTestNavMode(bool bNewValue)
|
||||
{
|
||||
bTestNavigation = bNewValue;
|
||||
}
|
||||
|
||||
bool AIMGR_GetTestNavMode()
|
||||
{
|
||||
return bTestNavigation;
|
||||
}
|
|
@ -87,4 +87,7 @@ void AIMGR_ClearBotData();
|
|||
AvHAIPlayer* AIMGR_GetDebugAIPlayer();
|
||||
void AIMGR_SetDebugAIPlayer(edict_t* AIPlayer);
|
||||
|
||||
void AIMGR_SetTestNavMode(bool bNewValue);
|
||||
bool AIMGR_GetTestNavMode();
|
||||
|
||||
#endif
|
|
@ -2628,6 +2628,8 @@ bool AITAC_ElectricalResearchIsAvailable(edict_t* Structure)
|
|||
|
||||
AvHAIHiveDefinition* AITAC_GetHiveFromEdict(const edict_t* Edict)
|
||||
{
|
||||
if (Edict->v.iuser3 != AVH_USER3_HIVE) { return nullptr; }
|
||||
|
||||
for (auto it = Hives.begin(); it != Hives.end(); it++)
|
||||
{
|
||||
if (it->HiveEntity->edict() == Edict)
|
||||
|
@ -4428,7 +4430,7 @@ bool AITAC_IsAlienBuilderNeeded(AvHAIPlayer* pBot)
|
|||
|
||||
}
|
||||
|
||||
AvHAIDeployableStructureType AITAC_GetNextMissingUpgradeChamberForTeam(AvHTeamNumber Team)
|
||||
AvHAIDeployableStructureType AITAC_GetNextMissingUpgradeChamberForTeam(AvHTeamNumber Team, int& NumMissing)
|
||||
{
|
||||
if (AIMGR_GetTeamType(Team) != AVH_CLASS_TYPE_ALIEN) { return STRUCTURE_NONE; }
|
||||
|
||||
|
@ -4453,6 +4455,7 @@ AvHAIDeployableStructureType AITAC_GetNextMissingUpgradeChamberForTeam(AvHTeamNu
|
|||
|
||||
if (NumChambers < 3)
|
||||
{
|
||||
NumMissing = 3 - NumChambers;
|
||||
return ChamberTypeOne;
|
||||
}
|
||||
}
|
||||
|
@ -4465,6 +4468,7 @@ AvHAIDeployableStructureType AITAC_GetNextMissingUpgradeChamberForTeam(AvHTeamNu
|
|||
|
||||
if (NumChambers < 3)
|
||||
{
|
||||
NumMissing = 3 - NumChambers;
|
||||
return ChamberTypeTwo;
|
||||
}
|
||||
}
|
||||
|
@ -4477,6 +4481,7 @@ AvHAIDeployableStructureType AITAC_GetNextMissingUpgradeChamberForTeam(AvHTeamNu
|
|||
|
||||
if (NumChambers < 3)
|
||||
{
|
||||
NumMissing = 3 - NumChambers;
|
||||
return ChamberTypeThree;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -176,7 +176,7 @@ bool AITAC_IsAlienHarasserNeeded(AvHAIPlayer* pBot);
|
|||
|
||||
bool AITAC_ShouldBotBuildHive(AvHAIPlayer* pBot, AvHAIHiveDefinition** EligibleHive);
|
||||
|
||||
AvHAIDeployableStructureType AITAC_GetNextMissingUpgradeChamberForTeam(AvHTeamNumber Team);
|
||||
AvHAIDeployableStructureType AITAC_GetNextMissingUpgradeChamberForTeam(AvHTeamNumber Team, int& NumMissing);
|
||||
|
||||
void AITAC_OnTeamStartsModified();
|
||||
|
||||
|
|
|
@ -1035,14 +1035,6 @@ void BotProgressMoveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
{
|
||||
MoveDirectlyTo(pBot, Task->TaskLocation);
|
||||
}
|
||||
|
||||
if (IsPlayerMarine(pBot->Edict))
|
||||
{
|
||||
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
|
||||
{
|
||||
BotReloadWeapons(pBot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BotProgressTouchTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||
|
@ -1225,22 +1217,18 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
SearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
||||
}
|
||||
|
||||
AvHAIDeployableStructureType NextStructure = AITAC_GetNextMissingUpgradeChamberForTeam(BotTeam);
|
||||
AvHAIDeployableStructureType NextStructure = STRUCTURE_NONE;
|
||||
|
||||
DeployableSearchFilter StructureFilter;
|
||||
StructureFilter.DeployableTeam = BotTeam;
|
||||
StructureFilter.MaxSearchRadius = SearchRadius;
|
||||
StructureFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
|
||||
|
||||
if (NextStructure == STRUCTURE_NONE)
|
||||
int NumOCs = AITAC_GetNumDeployablesNearLocation(ReinforceLocation, &StructureFilter);
|
||||
|
||||
if (NumOCs < 3)
|
||||
{
|
||||
StructureFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
|
||||
|
||||
int NumOCs = AITAC_GetNumDeployablesNearLocation(ReinforceLocation, &StructureFilter);
|
||||
|
||||
if (NumOCs < 3)
|
||||
{
|
||||
NextStructure = STRUCTURE_ALIEN_OFFENCECHAMBER;
|
||||
}
|
||||
NextStructure = STRUCTURE_ALIEN_OFFENCECHAMBER;
|
||||
}
|
||||
|
||||
if (NextStructure == STRUCTURE_NONE)
|
||||
|
@ -1548,14 +1536,6 @@ void MarineProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
|
||||
MoveTo(pBot, Task->TaskTarget->v.origin, MOVESTYLE_NORMAL);
|
||||
|
||||
if (IsPlayerMarine(pBot->Edict))
|
||||
{
|
||||
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
|
||||
{
|
||||
BotReloadWeapons(pBot);
|
||||
}
|
||||
}
|
||||
|
||||
if (vDist2DSq(pBot->Edict->v.origin, Task->TaskTarget->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
|
||||
{
|
||||
BotLookAt(pBot, UTIL_GetCentreOfEntity(Task->TaskTarget));
|
||||
|
@ -1565,13 +1545,6 @@ void MarineProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
|
||||
void BotProgressGuardTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||
{
|
||||
if (IsPlayerMarine(pBot->Edict))
|
||||
{
|
||||
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
|
||||
{
|
||||
BotReloadWeapons(pBot);
|
||||
}
|
||||
}
|
||||
|
||||
if (vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation) > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
|
||||
{
|
||||
|
@ -2816,7 +2789,7 @@ AvHAIPlayer* GetFirstBotWithBuildTask(AvHTeamNumber Team, AvHAIDeployableStructu
|
|||
{
|
||||
AvHAIPlayer* Bot = (*it);
|
||||
|
||||
if (!IsPlayerActiveInGame(Bot->Edict)) { continue; }
|
||||
if (!IsPlayerActiveInGame(Bot->Edict) || Bot->Edict == IgnorePlayer) { continue; }
|
||||
|
||||
bool bPrimaryIsBuildTask = (Bot->PrimaryBotTask.TaskType == TASK_BUILD || Bot->PrimaryBotTask.TaskType == TASK_REINFORCE_STRUCTURE);
|
||||
bool bSecondaryIsBuildTask = (Bot->SecondaryBotTask.TaskType == TASK_BUILD || Bot->SecondaryBotTask.TaskType == TASK_REINFORCE_STRUCTURE);
|
||||
|
@ -2831,6 +2804,30 @@ AvHAIPlayer* GetFirstBotWithBuildTask(AvHTeamNumber Team, AvHAIDeployableStructu
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
int AITASK_GetNumBotsWithBuildTask(AvHTeamNumber Team, AvHAIDeployableStructureType StructureType, edict_t* IgnorePlayer)
|
||||
{
|
||||
vector<AvHAIPlayer*> AIPlayers = AIMGR_GetAIPlayersOnTeam(Team);
|
||||
int Result = 0;
|
||||
|
||||
for (auto it = AIPlayers.begin(); it != AIPlayers.end(); it++)
|
||||
{
|
||||
AvHAIPlayer* Bot = (*it);
|
||||
|
||||
if (!IsPlayerActiveInGame(Bot->Edict) || Bot->Edict == IgnorePlayer) { continue; }
|
||||
|
||||
bool bPrimaryIsBuildTask = (Bot->PrimaryBotTask.TaskType == TASK_BUILD || Bot->PrimaryBotTask.TaskType == TASK_REINFORCE_STRUCTURE);
|
||||
bool bSecondaryIsBuildTask = (Bot->SecondaryBotTask.TaskType == TASK_BUILD || Bot->SecondaryBotTask.TaskType == TASK_REINFORCE_STRUCTURE);
|
||||
|
||||
if ((bPrimaryIsBuildTask && Bot->PrimaryBotTask.StructureType == StructureType) || (bSecondaryIsBuildTask && Bot->SecondaryBotTask.StructureType == StructureType))
|
||||
{
|
||||
Result++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
AvHAIPlayer* GetFirstBotWithReinforceTask(AvHTeamNumber Team, edict_t* ReinforceStructure, edict_t* IgnorePlayer)
|
||||
{
|
||||
vector<AvHAIPlayer*> AIPlayers = AIMGR_GetAIPlayersOnTeam(Team);
|
||||
|
@ -2839,7 +2836,7 @@ AvHAIPlayer* GetFirstBotWithReinforceTask(AvHTeamNumber Team, edict_t* Reinforce
|
|||
{
|
||||
AvHAIPlayer* Bot = (*it);
|
||||
|
||||
if (!IsPlayerActiveInGame(Bot->Edict)) { continue; }
|
||||
if (!IsPlayerActiveInGame(Bot->Edict) || Bot->Edict == IgnorePlayer) { continue; }
|
||||
|
||||
if ((Bot->PrimaryBotTask.TaskType == TASK_REINFORCE_STRUCTURE && Bot->PrimaryBotTask.TaskTarget == ReinforceStructure) || (Bot->SecondaryBotTask.TaskType == TASK_REINFORCE_STRUCTURE && Bot->SecondaryBotTask.TaskTarget == ReinforceStructure))
|
||||
{
|
||||
|
@ -2948,6 +2945,47 @@ void AITASK_SetPickupTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Tar
|
|||
|
||||
}
|
||||
|
||||
void AITASK_SetGetHealthTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* HealingSource, const bool bIsUrgent)
|
||||
{
|
||||
if (Task->TaskType == TASK_GET_HEALTH && Task->TaskTarget == HealingSource)
|
||||
{
|
||||
Task->bTaskIsUrgent = bIsUrgent;
|
||||
return;
|
||||
}
|
||||
|
||||
AITASK_ClearBotTask(pBot, Task);
|
||||
|
||||
if (FNullEnt(HealingSource)) { return; }
|
||||
|
||||
Vector HealLocation = ZERO_VECTOR;
|
||||
AvHAIHiveDefinition* HiveRef = AITAC_GetHiveFromEdict(HealingSource);
|
||||
|
||||
if (HiveRef)
|
||||
{
|
||||
HealLocation = HiveRef->FloorLocation;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsEdictPlayer(HealingSource))
|
||||
{
|
||||
HealLocation = HealingSource->v.origin;
|
||||
}
|
||||
else
|
||||
{
|
||||
HealLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, HealingSource->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
}
|
||||
}
|
||||
|
||||
if (!vIsZero(HealLocation))
|
||||
{
|
||||
Task->TaskType = TASK_GET_HEALTH;
|
||||
Task->TaskTarget = HealingSource;
|
||||
Task->TaskLocation = HealLocation;
|
||||
Task->bTaskIsUrgent = bIsUrgent;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const bool bIsUrgent)
|
||||
{
|
||||
if (FNullEnt(Target) || (Target->v.deadflag != DEAD_NO))
|
||||
|
|
|
@ -68,6 +68,7 @@ void AITASK_SetSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t*
|
|||
void AITASK_SetMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, bool bIsUrgent);
|
||||
void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const bool bIsUrgent);
|
||||
void AITASK_SetPickupTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const bool bIsUrgent);
|
||||
void AITASK_SetGetHealthTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* HealingSource, const bool bIsUrgent);
|
||||
|
||||
void BotProgressTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);
|
||||
|
||||
|
@ -104,6 +105,7 @@ void BotGuardLocation(AvHAIPlayer* pBot, const Vector GuardLocation);
|
|||
void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocation);
|
||||
|
||||
bool BotWithBuildTaskExists(AvHTeamNumber Team, AvHAIDeployableStructureType StructureType);
|
||||
int AITASK_GetNumBotsWithBuildTask(AvHTeamNumber Team, AvHAIDeployableStructureType StructureType, edict_t* IgnorePlayer);
|
||||
AvHAIPlayer* GetFirstBotWithBuildTask(AvHTeamNumber Team, AvHAIDeployableStructureType StructureType, edict_t* IgnorePlayer);
|
||||
AvHAIPlayer* GetFirstBotWithReinforceTask(AvHTeamNumber Team, edict_t* ReinforceStructure, edict_t* IgnorePlayer);
|
||||
|
||||
|
|
|
@ -392,6 +392,18 @@ AvHGamerules::AvHGamerules() : mTeamA(TEAM_ONE), mTeamB(TEAM_TWO)
|
|||
AIMGR_RemoveAIPlayerFromTeam(DesiredTeam);
|
||||
});
|
||||
|
||||
REGISTER_SERVER_FUNCTION("sv_testainavigation", []()
|
||||
{
|
||||
if (avh_botsenabled.value == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool bNewTestValue = !AIMGR_GetTestNavMode();
|
||||
|
||||
AIMGR_SetTestNavMode(bNewTestValue);
|
||||
});
|
||||
|
||||
g_VoiceGameMgr.Init(&gVoiceHelper, gpGlobals->maxClients);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
Loading…
Reference in a new issue