mirror of
https://github.com/ENSL/NS.git
synced 2024-11-10 15:21:54 +00:00
Fix grenade throwing, better combat
This commit is contained in:
parent
3a1a92c505
commit
a0700fcd4f
10 changed files with 503 additions and 40 deletions
|
@ -791,10 +791,8 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
if (NumInfantryPortals < 2)
|
if (NumInfantryPortals < 2)
|
||||||
{
|
{
|
||||||
if (AICOMM_BuildInfantryPortal(pBot, CommChair))
|
AICOMM_BuildInfantryPortal(pBot, CommChair);
|
||||||
{
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StructureFilter.DeployableTypes = STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY;
|
StructureFilter.DeployableTypes = STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY;
|
||||||
|
@ -823,10 +821,8 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
if (!vIsZero(BuildLocation))
|
if (!vIsZero(BuildLocation))
|
||||||
{
|
{
|
||||||
if (AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation))
|
AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation);
|
||||||
{
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -858,8 +854,9 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
|
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
|
||||||
|
|
||||||
if (AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation))
|
if (!vIsZero(BuildLocation))
|
||||||
{
|
{
|
||||||
|
AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -869,10 +866,8 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
if (CappableNode)
|
if (CappableNode)
|
||||||
{
|
{
|
||||||
if (AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_RESTOWER, CappableNode->Location))
|
AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_RESTOWER, CappableNode->Location);
|
||||||
{
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const AvHAIHiveDefinition* HiveToSecure = AICOMM_GetEmptyHiveOpportunityNearestLocation(pBot, AITAC_GetCommChairLocation(TeamNumber));
|
const AvHAIHiveDefinition* HiveToSecure = AICOMM_GetEmptyHiveOpportunityNearestLocation(pBot, AITAC_GetCommChairLocation(TeamNumber));
|
||||||
|
@ -1973,6 +1968,7 @@ bool AICOMM_ShouldCommanderLeaveChair(AvHAIPlayer* pBot)
|
||||||
const AvHAIHiveDefinition* AICOMM_GetEmptyHiveOpportunityNearestLocation(AvHAIPlayer* CommanderBot, const Vector SearchLocation)
|
const AvHAIHiveDefinition* AICOMM_GetEmptyHiveOpportunityNearestLocation(AvHAIPlayer* CommanderBot, const Vector SearchLocation)
|
||||||
{
|
{
|
||||||
AvHTeamNumber CommanderTeam = CommanderBot->Player->GetTeam();
|
AvHTeamNumber CommanderTeam = CommanderBot->Player->GetTeam();
|
||||||
|
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(CommanderTeam);
|
||||||
|
|
||||||
const AvHAIHiveDefinition* Result = nullptr;
|
const AvHAIHiveDefinition* Result = nullptr;
|
||||||
float MinDist = 0.0f;
|
float MinDist = 0.0f;
|
||||||
|
@ -2009,6 +2005,27 @@ const AvHAIHiveDefinition* AICOMM_GetEmptyHiveOpportunityNearestLocation(AvHAIPl
|
||||||
|
|
||||||
if (AITAC_GetNearestHiddenPlayerInLocation(CommanderTeam, SecureLocation, MarineDist) == nullptr) { continue; }
|
if (AITAC_GetNearestHiddenPlayerInLocation(CommanderTeam, SecureLocation, MarineDist) == nullptr) { continue; }
|
||||||
|
|
||||||
|
int NumEnemiesNearby = AITAC_GetNumPlayersOnTeamWithLOS(EnemyTeam, SecureLocation + Vector(0.0f, 0.0f, 10.0f), UTIL_MetresToGoldSrcUnits(15.0f), nullptr);
|
||||||
|
|
||||||
|
if (NumEnemiesNearby > 0) { continue; }
|
||||||
|
|
||||||
|
DeployableSearchFilter EnemyStuff;
|
||||||
|
EnemyStuff.DeployableTeam = EnemyTeam;
|
||||||
|
EnemyStuff.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||||
|
EnemyStuff.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||||
|
EnemyStuff.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
||||||
|
|
||||||
|
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_MARINE)
|
||||||
|
{
|
||||||
|
EnemyStuff.DeployableTypes = (STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EnemyStuff.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AITAC_DeployableExistsAtLocation(SecureLocation, &EnemyStuff)) { continue; }
|
||||||
|
|
||||||
float ThisDist = vDist2DSq(Hive->FloorLocation, SearchLocation);
|
float ThisDist = vDist2DSq(Hive->FloorLocation, SearchLocation);
|
||||||
|
|
||||||
if (!Result || ThisDist < MinDist)
|
if (!Result || ThisDist < MinDist)
|
||||||
|
|
|
@ -4933,7 +4933,7 @@ void UTIL_UpdateBotMovementStatus(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
bool AbortCurrentMove(AvHAIPlayer* pBot, const Vector NewDestination)
|
bool AbortCurrentMove(AvHAIPlayer* pBot, const Vector NewDestination)
|
||||||
{
|
{
|
||||||
if (pBot->BotNavInfo.CurrentPath.size() == 0) { return true; }
|
if (pBot->BotNavInfo.CurrentPath.size() == 0 || pBot->BotNavInfo.NavProfile.bFlyingProfile) { return true; }
|
||||||
|
|
||||||
if (IsBotPermaStuck(pBot))
|
if (IsBotPermaStuck(pBot))
|
||||||
{
|
{
|
||||||
|
@ -5764,8 +5764,6 @@ void SkipAheadInFlightPath(AvHAIPlayer* pBot)
|
||||||
// Early exit if we don't have a path, or we're already on the last path point
|
// Early exit if we don't have a path, or we're already on the last path point
|
||||||
if (BotNavInfo->CurrentPath.size() == 0 || BotNavInfo->CurrentPathPoint == prev(BotNavInfo->CurrentPath.end())) { return; }
|
if (BotNavInfo->CurrentPath.size() == 0 || BotNavInfo->CurrentPathPoint == prev(BotNavInfo->CurrentPath.end())) { return; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (UTIL_QuickHullTrace(pBot->Edict, pBot->Edict->v.origin, prev(BotNavInfo->CurrentPath.end())->Location, head_hull))
|
if (UTIL_QuickHullTrace(pBot->Edict, pBot->Edict->v.origin, prev(BotNavInfo->CurrentPath.end())->Location, head_hull))
|
||||||
{
|
{
|
||||||
pBot->BotNavInfo.CurrentPathPoint = prev(BotNavInfo->CurrentPath.end());
|
pBot->BotNavInfo.CurrentPathPoint = prev(BotNavInfo->CurrentPath.end());
|
||||||
|
@ -5897,7 +5895,14 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BotMoveLookAt(pBot, CurrentMoveDest);
|
Vector LookLocation = CurrentMoveDest;
|
||||||
|
|
||||||
|
if (pEdict->v.origin.z < BotNavInfo->CurrentPathPoint->requiredZ)
|
||||||
|
{
|
||||||
|
LookLocation.z += 32.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
BotMoveLookAt(pBot, LookLocation);
|
||||||
|
|
||||||
pBot->desiredMovementDir = UTIL_GetForwardVector2D(pEdict->v.v_angle);
|
pBot->desiredMovementDir = UTIL_GetForwardVector2D(pEdict->v.v_angle);
|
||||||
|
|
||||||
|
|
|
@ -978,10 +978,22 @@ void BotShootLocation(AvHAIPlayer* pBot, AvHAIWeapon AttackWeapon, const Vector
|
||||||
{
|
{
|
||||||
AvHBasePlayerWeapon* WeaponRef = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_pActiveItem);
|
AvHBasePlayerWeapon* WeaponRef = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_pActiveItem);
|
||||||
|
|
||||||
if (!WeaponRef->GetMustPressTriggerForEachShot() || WeaponRef->m_flNextPrimaryAttack <= 0.0f)
|
if (CurrentWeapon == WEAPON_MARINE_GRENADE)
|
||||||
{
|
{
|
||||||
pBot->Button |= IN_ATTACK;
|
if (!WeaponRef->m_flStartThrow && WeaponRef->m_flReleaseThrow == -1)
|
||||||
|
{
|
||||||
|
pBot->Button |= IN_ATTACK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!WeaponRef->GetMustPressTriggerForEachShot() || WeaponRef->m_flNextPrimaryAttack <= 0.0f)
|
||||||
|
{
|
||||||
|
pBot->Button |= IN_ATTACK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1041,6 +1053,24 @@ void BotEvolveLifeform(AvHAIPlayer* pBot, Vector DesiredEvolveLocation, AvHMessa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BotEvolveUpgrade(AvHAIPlayer* pBot, Vector DesiredEvolveLocation, AvHMessageID TargetUpgrade)
|
||||||
|
{
|
||||||
|
Vector EvolvePoint = UTIL_ProjectPointToNavmesh(DesiredEvolveLocation, GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE));
|
||||||
|
|
||||||
|
if (vIsZero(EvolvePoint))
|
||||||
|
{
|
||||||
|
EvolvePoint = DesiredEvolveLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vDist2DSq(pBot->Edict->v.origin, EvolvePoint) > sqrf(32.0f))
|
||||||
|
{
|
||||||
|
MoveTo(pBot, EvolvePoint, MOVESTYLE_NORMAL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pBot->Impulse = TargetUpgrade;
|
||||||
|
}
|
||||||
|
|
||||||
void BotUpdateDesiredViewRotation(AvHAIPlayer* pBot)
|
void BotUpdateDesiredViewRotation(AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
// We always prioritise MoveLookLocation if it is set so the bot doesn't screw up wall climbing or ladder movement
|
// We always prioritise MoveLookLocation if it is set so the bot doesn't screw up wall climbing or ladder movement
|
||||||
|
@ -1634,7 +1664,29 @@ void StartNewBotFrame(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
void CustomThink(AvHAIPlayer* pBot)
|
void CustomThink(AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
if (IsPlayerMarine(pBot->Player)) { return; }
|
if (IsPlayerMarine(pBot->Player))
|
||||||
|
{
|
||||||
|
if (PlayerHasWeapon(pBot->Player, WEAPON_MARINE_GRENADE))
|
||||||
|
{
|
||||||
|
if (!vIsZero(AIDEBUG_GetDebugVector1()))
|
||||||
|
{
|
||||||
|
BotThrowGrenadeAtTarget(pBot, AIDEBUG_GetDebugVector1());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pBot->DesiredCombatWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player);
|
||||||
|
}
|
||||||
|
|
||||||
|
AvHAIWeapon DesiredWeapon = (pBot->DesiredMoveWeapon != WEAPON_NONE) ? pBot->DesiredMoveWeapon : pBot->DesiredCombatWeapon;
|
||||||
|
|
||||||
|
if (DesiredWeapon != WEAPON_NONE && GetPlayerCurrentWeapon(pBot->Player) != DesiredWeapon)
|
||||||
|
{
|
||||||
|
BotSwitchToWeapon(pBot, DesiredWeapon);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!IsPlayerFade(pBot->Edict))
|
if (!IsPlayerFade(pBot->Edict))
|
||||||
{
|
{
|
||||||
|
@ -2455,11 +2507,11 @@ bool MarineCombatThink(AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
edict_t* pEdict = pBot->Edict;
|
edict_t* pEdict = pBot->Edict;
|
||||||
|
|
||||||
if (pBot->CurrentEnemy < 0) { return false; }
|
|
||||||
|
|
||||||
edict_t* CurrentEnemy = pBot->TrackedEnemies[pBot->CurrentEnemy].EnemyEdict;
|
edict_t* CurrentEnemy = pBot->TrackedEnemies[pBot->CurrentEnemy].EnemyEdict;
|
||||||
enemy_status* TrackedEnemyRef = &pBot->TrackedEnemies[pBot->CurrentEnemy];
|
enemy_status* TrackedEnemyRef = &pBot->TrackedEnemies[pBot->CurrentEnemy];
|
||||||
|
|
||||||
|
pBot->LastCombatTime = gpGlobals->time;
|
||||||
|
|
||||||
// ENEMY IS OUT OF SIGHT
|
// ENEMY IS OUT OF SIGHT
|
||||||
|
|
||||||
if (!TrackedEnemyRef->bHasLOS)
|
if (!TrackedEnemyRef->bHasLOS)
|
||||||
|
@ -2812,13 +2864,15 @@ void AIPlayerSetSecondaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
|
|
||||||
for (auto it = BuildableStructures.begin(); it != BuildableStructures.end(); it++)
|
for (auto it = BuildableStructures.begin(); it != BuildableStructures.end(); it++)
|
||||||
{
|
{
|
||||||
int NumBuilders = AITAC_GetNumPlayersOfTeamInArea(pBot->Player->GetTeam(), (*it)->Location, UTIL_MetresToGoldSrcUnits(5.0f), false, pBot->Edict, AVH_USER3_COMMANDER_PLAYER);
|
float ThisDist = vDist2D((*it)->Location, pBot->Edict->v.origin);
|
||||||
|
|
||||||
|
int NumBuilders = AITAC_GetNumPlayersOfTeamInArea(pBot->Player->GetTeam(), (*it)->Location, ThisDist - 5.0f, false, pBot->Edict, AVH_USER3_COMMANDER_PLAYER);
|
||||||
|
|
||||||
int NumDesiredBuilders = (vDist2DSq((*it)->Location, AITAC_GetCommChairLocation(pBot->Player->GetTeam())) < sqrf(UTIL_MetresToGoldSrcUnits(15.0f))) ? 1 : 2;
|
int NumDesiredBuilders = (vDist2DSq((*it)->Location, AITAC_GetCommChairLocation(pBot->Player->GetTeam())) < sqrf(UTIL_MetresToGoldSrcUnits(15.0f))) ? 1 : 2;
|
||||||
|
|
||||||
if (NumBuilders < NumDesiredBuilders)
|
if (NumBuilders < NumDesiredBuilders)
|
||||||
{
|
{
|
||||||
float ThisDist = vDist2DSq((*it)->Location, pBot->Edict->v.origin);
|
|
||||||
if (!NearestStructure || ThisDist < MinDist)
|
if (!NearestStructure || ThisDist < MinDist)
|
||||||
{
|
{
|
||||||
NearestStructure = (*it);
|
NearestStructure = (*it);
|
||||||
|
@ -2829,7 +2883,7 @@ void AIPlayerSetSecondaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
|
|
||||||
if (NearestStructure)
|
if (NearestStructure)
|
||||||
{
|
{
|
||||||
AITASK_SetBuildTask(pBot, Task, NearestStructure->edict, false);
|
AITASK_SetBuildTask(pBot, Task, NearestStructure->edict, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2866,6 +2920,27 @@ void AIPlayerNSAlienThink(AvHAIPlayer* pBot)
|
||||||
if (AlienCombatThink(pBot)) { return; }
|
if (AlienCombatThink(pBot)) { return; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pBot->LastCombatTime > 5.0f)
|
||||||
|
{
|
||||||
|
if (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_DEFENCE) && AITAC_IsAlienUpgradeAvailableForTeam(pBot->Player->GetTeam(), HIVE_TECH_DEFENCE))
|
||||||
|
{
|
||||||
|
BotEvolveUpgrade(pBot, pBot->Edict->v.origin, AlienGetDesiredUpgrade(pBot, HIVE_TECH_DEFENCE));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_MOVEMENT) && AITAC_IsAlienUpgradeAvailableForTeam(pBot->Player->GetTeam(), HIVE_TECH_MOVEMENT))
|
||||||
|
{
|
||||||
|
BotEvolveUpgrade(pBot, pBot->Edict->v.origin, AlienGetDesiredUpgrade(pBot, HIVE_TECH_MOVEMENT));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_SENSORY) && AITAC_IsAlienUpgradeAvailableForTeam(pBot->Player->GetTeam(), HIVE_TECH_SENSORY))
|
||||||
|
{
|
||||||
|
BotEvolveUpgrade(pBot, pBot->Edict->v.origin, AlienGetDesiredUpgrade(pBot, HIVE_TECH_SENSORY));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (pBot->CurrentTask && pBot->CurrentTask->TaskType != TASK_NONE)
|
if (pBot->CurrentTask && pBot->CurrentTask->TaskType != TASK_NONE)
|
||||||
{
|
{
|
||||||
BotProgressTask(pBot, pBot->CurrentTask);
|
BotProgressTask(pBot, pBot->CurrentTask);
|
||||||
|
@ -2877,6 +2952,26 @@ void AIPlayerNSAlienThink(AvHAIPlayer* pBot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AvHMessageID AlienGetDesiredUpgrade(AvHAIPlayer* pBot, HiveTechStatus DesiredTech)
|
||||||
|
{
|
||||||
|
if (DesiredTech == HIVE_TECH_DEFENCE)
|
||||||
|
{
|
||||||
|
return ALIEN_EVOLUTION_ONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DesiredTech == HIVE_TECH_MOVEMENT)
|
||||||
|
{
|
||||||
|
return ALIEN_EVOLUTION_SEVEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DesiredTech == HIVE_TECH_SENSORY)
|
||||||
|
{
|
||||||
|
return ALIEN_EVOLUTION_ELEVEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MESSAGE_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void AIPlayerCOThink(AvHAIPlayer* pBot)
|
void AIPlayerCOThink(AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -3165,6 +3260,7 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|
||||||
|
|
||||||
DeployableSearchFilter EnemyStructureFilter;
|
DeployableSearchFilter EnemyStructureFilter;
|
||||||
EnemyStructureFilter.DeployableTeam = EnemyTeam;
|
EnemyStructureFilter.DeployableTeam = EnemyTeam;
|
||||||
|
EnemyStructureFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||||
EnemyStructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
EnemyStructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||||
EnemyStructureFilter.DeployableTypes = StructureTypes;
|
EnemyStructureFilter.DeployableTypes = StructureTypes;
|
||||||
EnemyStructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
EnemyStructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
||||||
|
@ -3343,6 +3439,37 @@ void AIPlayerSetAlienCapperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
{
|
{
|
||||||
AvHAIResourceNode* ThisNode = (*it);
|
AvHAIResourceNode* ThisNode = (*it);
|
||||||
|
|
||||||
|
if (ThisNode->bIsBaseNode)
|
||||||
|
{
|
||||||
|
if (FNullEnt(ThisNode->ParentHive)) { continue; } // This node must belong to marine base, don't try to cap it
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FNullEnt(ThisNode->ParentHive))
|
||||||
|
{
|
||||||
|
AvHAIHiveDefinition* ParentHiveRef = AITAC_GetHiveFromEdict(ThisNode->ParentHive);
|
||||||
|
|
||||||
|
// Don't try to cap resource nodes in an enemy hive.
|
||||||
|
if (ParentHiveRef->OwningTeam == EnemyTeam) { continue; }
|
||||||
|
|
||||||
|
DeployableSearchFilter EnemyStructuresFilter;
|
||||||
|
EnemyStructuresFilter.DeployableTeam = EnemyTeam;
|
||||||
|
EnemyStructuresFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||||
|
EnemyStructuresFilter.ExcludeStatusFlags = (IsPlayerSkulk(pBot->Edict)) ? (STRUCTURE_STATUS_RECYCLING | STRUCTURE_STATUS_ELECTRIFIED) : STRUCTURE_STATUS_RECYCLING;
|
||||||
|
EnemyStructuresFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
|
||||||
|
|
||||||
|
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_MARINE)
|
||||||
|
{
|
||||||
|
EnemyStructuresFilter.DeployableTypes = (STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EnemyStructuresFilter.DeployableTypes = (STRUCTURE_ALIEN_OFFENCECHAMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enemy has started fortifying the hive we want to build a RT in, don't try to cap it
|
||||||
|
if (AITAC_DeployableExistsAtLocation(ThisNode->Location, &EnemyStructuresFilter)) { continue; }
|
||||||
|
}
|
||||||
|
|
||||||
edict_t* ExistingBuilder = AITAC_GetNearestPlayerOfClassInArea(BotTeam, ThisNode->Location, UTIL_MetresToGoldSrcUnits(5.0f), false, pBot->Edict, AVH_USER3_ALIEN_PLAYER2);
|
edict_t* ExistingBuilder = AITAC_GetNearestPlayerOfClassInArea(BotTeam, ThisNode->Location, UTIL_MetresToGoldSrcUnits(5.0f), false, pBot->Edict, AVH_USER3_ALIEN_PLAYER2);
|
||||||
|
|
||||||
if (!FNullEnt(ExistingBuilder) && vDist2DSq(ExistingBuilder->v.origin, ThisNode->Location) < vDist2DSq(pBot->Edict->v.origin, ThisNode->Location) && GetPlayerResources(ExistingBuilder) >= (BALANCE_VAR(kResourceTowerCost) * 0.8f)) { continue; }
|
if (!FNullEnt(ExistingBuilder) && vDist2DSq(ExistingBuilder->v.origin, ThisNode->Location) < vDist2DSq(pBot->Edict->v.origin, ThisNode->Location) && GetPlayerResources(ExistingBuilder) >= (BALANCE_VAR(kResourceTowerCost) * 0.8f)) { continue; }
|
||||||
|
@ -3396,22 +3523,37 @@ void AIPlayerSetAlienCapperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
{
|
{
|
||||||
AvHAIResourceNode* ThisNode = (*it);
|
AvHAIResourceNode* ThisNode = (*it);
|
||||||
|
|
||||||
// Don't attack nodes which are firmly owned by the enemy (i.e. in marine base, or part of an enemy alien team's active hive)
|
|
||||||
if (ThisNode->bIsBaseNode)
|
if (ThisNode->bIsBaseNode)
|
||||||
{
|
{
|
||||||
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
|
if (FNullEnt(ThisNode->ParentHive)) { continue; } // This node must belong to marine base, leave that tower alone
|
||||||
if (AIMGR_GetEnemyTeamType(BotTeam) == AVH_CLASS_TYPE_MARINE)
|
}
|
||||||
|
|
||||||
|
if (!FNullEnt(ThisNode->ParentHive))
|
||||||
|
{
|
||||||
|
AvHAIHiveDefinition* ParentHiveRef = AITAC_GetHiveFromEdict(ThisNode->ParentHive);
|
||||||
|
|
||||||
|
// Don't try to attack RTs inside enemy hives
|
||||||
|
if (ParentHiveRef->OwningTeam == EnemyTeam) { continue; }
|
||||||
|
|
||||||
|
// Don't attack an empty hive RT if the enemy has fortified the area
|
||||||
|
DeployableSearchFilter EnemyStructuresFilter;
|
||||||
|
EnemyStructuresFilter.DeployableTeam = EnemyTeam;
|
||||||
|
EnemyStructuresFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||||
|
EnemyStructuresFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||||
|
EnemyStructuresFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
|
||||||
|
|
||||||
|
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_MARINE)
|
||||||
{
|
{
|
||||||
// Too close to the marine comm chair, don't touch this one
|
// Don't attack if there are turrets or a phase gate in the area.
|
||||||
if (vDist2DSq(ThisNode->Location, AITAC_GetCommChairLocation(EnemyTeam)) < sqrf(UTIL_MetresToGoldSrcUnits(15.0f))) { continue; }
|
EnemyStructuresFilter.DeployableTypes = (STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The enemy alien team has a hive here, don't attack this res node or we'll get smooshed
|
EnemyStructuresFilter.DeployableTypes = (STRUCTURE_ALIEN_OFFENCECHAMBER);
|
||||||
AvHAIHiveDefinition* ParentHive = AITAC_GetHiveFromEdict(ThisNode->ParentHive);
|
|
||||||
|
|
||||||
if (ParentHive && ParentHive->OwningTeam == EnemyTeam) { continue; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enemy has started fortifying the hive we want to build a RT in, leave that tower alone
|
||||||
|
if (AITAC_DeployableExistsAtLocation(ThisNode->Location, &EnemyStructuresFilter)) { continue; }
|
||||||
}
|
}
|
||||||
|
|
||||||
float ThisDist = vDist2DSq(ThisNode->Location, AITAC_GetTeamStartingLocation(EnemyTeam));
|
float ThisDist = vDist2DSq(ThisNode->Location, AITAC_GetTeamStartingLocation(EnemyTeam));
|
||||||
|
@ -3430,6 +3572,7 @@ void AIPlayerSetAlienCapperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have nothing to do as a capper, then revert to assault
|
||||||
AIPlayerSetAlienAssaultPrimaryTask(pBot, Task);
|
AIPlayerSetAlienAssaultPrimaryTask(pBot, Task);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3462,6 +3605,10 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|
||||||
{
|
{
|
||||||
EnemyStuffFilter.DeployableTypes = (STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_COMMCHAIR);
|
EnemyStuffFilter.DeployableTypes = (STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_COMMCHAIR);
|
||||||
EnemyStuffFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
EnemyStuffFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||||
|
if (IsPlayerSkulk(pBot->Edict) || IsPlayerLerk(pBot->Edict))
|
||||||
|
{
|
||||||
|
EnemyStuffFilter.ExcludeStatusFlags |= STRUCTURE_STATUS_RECYCLING;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3598,7 +3745,7 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We're a skulk
|
// We're a skulk or lerk
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (HiveToGuard)
|
if (HiveToGuard)
|
||||||
|
@ -3831,6 +3978,228 @@ void AIPlayerSetAlienHarasserPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
|
||||||
|
|
||||||
void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
{
|
{
|
||||||
|
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||||
|
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
|
||||||
|
|
||||||
|
if (IsPlayerGorge(pBot->Edict))
|
||||||
|
{
|
||||||
|
edict_t* TeamMateToHeal = nullptr;
|
||||||
|
|
||||||
|
vector<AvHPlayer*> AllNearbyTeammates = AITAC_GetAllPlayersOfTeamInArea(BotTeam, pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f), false, pBot->Edict, AVH_USER3_ALIEN_PLAYER2);
|
||||||
|
|
||||||
|
float MinDist = 0.0f;
|
||||||
|
|
||||||
|
for (auto it = AllNearbyTeammates.begin(); it != AllNearbyTeammates.end(); it++)
|
||||||
|
{
|
||||||
|
edict_t* ThisPlayer = (*it)->edict();
|
||||||
|
|
||||||
|
if (!FNullEnt(ThisPlayer) && IsPlayerActiveInGame(ThisPlayer) && GetPlayerOverallHealthPercent(ThisPlayer) < 0.99f)
|
||||||
|
{
|
||||||
|
float ThisDist = vDist2DSq(pBot->Edict->v.origin, ThisPlayer->v.origin);
|
||||||
|
if (FNullEnt(TeamMateToHeal) || ThisDist < MinDist)
|
||||||
|
{
|
||||||
|
TeamMateToHeal = ThisPlayer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FNullEnt(TeamMateToHeal))
|
||||||
|
{
|
||||||
|
Task->TaskType = TASK_HEAL;
|
||||||
|
Task->TaskTarget = TeamMateToHeal;
|
||||||
|
Task->bTaskIsUrgent = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeployableSearchFilter DamagedStructuresFilter;
|
||||||
|
DamagedStructuresFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
|
||||||
|
DamagedStructuresFilter.DeployableTeam = BotTeam;
|
||||||
|
DamagedStructuresFilter.ReachabilityTeam = BotTeam;
|
||||||
|
DamagedStructuresFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
|
||||||
|
DamagedStructuresFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||||
|
DamagedStructuresFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
|
||||||
|
|
||||||
|
vector<AvHAIBuildableStructure*> AllNearbyStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &DamagedStructuresFilter);
|
||||||
|
|
||||||
|
edict_t* StructureToHeal = nullptr;
|
||||||
|
|
||||||
|
MinDist = 0.0f;
|
||||||
|
|
||||||
|
for (auto it = AllNearbyStructures.begin(); it != AllNearbyStructures.end(); it++)
|
||||||
|
{
|
||||||
|
AvHAIBuildableStructure* ThisStructure = (*it);
|
||||||
|
|
||||||
|
if (ThisStructure && ThisStructure->healthPercent < 0.99f)
|
||||||
|
{
|
||||||
|
float ThisDist = vDist2DSq(pBot->Edict->v.origin, ThisStructure->Location);
|
||||||
|
if (FNullEnt(StructureToHeal) || ThisDist < MinDist)
|
||||||
|
{
|
||||||
|
StructureToHeal = ThisStructure->edict;
|
||||||
|
MinDist = ThisDist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FNullEnt(StructureToHeal))
|
||||||
|
{
|
||||||
|
Task->TaskType = TASK_HEAL;
|
||||||
|
Task->TaskTarget = StructureToHeal;
|
||||||
|
Task->bTaskIsUrgent = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AITASK_ClearBotTask(pBot, Task);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<AvHAIHiveDefinition*> AllHives = AITAC_GetAllTeamHives(BotTeam, false);
|
||||||
|
|
||||||
|
AvHAIHiveDefinition* HiveToDefend = nullptr;
|
||||||
|
float MinDist = 0.0f;
|
||||||
|
|
||||||
|
for (auto it = AllHives.begin(); it != AllHives.end(); it++)
|
||||||
|
{
|
||||||
|
AvHAIHiveDefinition* ThisHive = (*it);
|
||||||
|
|
||||||
|
if (ThisHive && ThisHive->bIsUnderAttack)
|
||||||
|
{
|
||||||
|
int AttackerStrength = 0;
|
||||||
|
int DefenderStrength = 0;
|
||||||
|
|
||||||
|
vector<AvHPlayer*> AttackingPlayers = AITAC_GetAllPlayersOfTeamInArea(EnemyTeam, ThisHive->FloorLocation, UTIL_MetresToGoldSrcUnits(15.0f), false, nullptr, AVH_USER3_NONE);
|
||||||
|
|
||||||
|
for (auto AttackerIt = AttackingPlayers.begin(); AttackerIt != AttackingPlayers.end(); AttackerIt++)
|
||||||
|
{
|
||||||
|
AvHPlayer* ThisPlayer = (*AttackerIt);
|
||||||
|
edict_t* ThisPlayerEdict = ThisPlayer->edict();
|
||||||
|
|
||||||
|
int ThisAttackerStrength = 1;
|
||||||
|
|
||||||
|
if (PlayerHasWeapon(ThisPlayer, WEAPON_MARINE_HMG) || PlayerHasHeavyArmour(ThisPlayerEdict))
|
||||||
|
{
|
||||||
|
ThisAttackerStrength = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsPlayerFade(ThisPlayerEdict))
|
||||||
|
{
|
||||||
|
ThisAttackerStrength = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsPlayerOnos(ThisPlayerEdict))
|
||||||
|
{
|
||||||
|
ThisAttackerStrength = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
AttackerStrength += ThisAttackerStrength;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<AvHPlayer*> DefendingPlayers = AITAC_GetAllPlayersOfTeamInArea(EnemyTeam, ThisHive->FloorLocation, UTIL_MetresToGoldSrcUnits(15.0f), false, pBot->Edict, AVH_USER3_ALIEN_PLAYER2);
|
||||||
|
|
||||||
|
for (auto DefenderIt = DefendingPlayers.begin(); DefenderIt != DefendingPlayers.end(); DefenderIt++)
|
||||||
|
{
|
||||||
|
AvHPlayer* ThisPlayer = (*DefenderIt);
|
||||||
|
edict_t* ThisPlayerEdict = ThisPlayer->edict();
|
||||||
|
|
||||||
|
int ThisDefenderStrength = 1;
|
||||||
|
|
||||||
|
if (IsPlayerFade(ThisPlayerEdict))
|
||||||
|
{
|
||||||
|
ThisDefenderStrength = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsPlayerOnos(ThisPlayerEdict))
|
||||||
|
{
|
||||||
|
ThisDefenderStrength = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefenderStrength += ThisDefenderStrength;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<AvHAIPlayer*> AllOtherBots = AIMGR_GetAIPlayersOnTeam(BotTeam);
|
||||||
|
|
||||||
|
for (auto BotIt = AllOtherBots.begin(); BotIt != AllOtherBots.end(); BotIt++)
|
||||||
|
{
|
||||||
|
AvHAIPlayer* ThisBot = (*BotIt);
|
||||||
|
|
||||||
|
if (ThisBot != pBot && IsPlayerActiveInGame(ThisBot->Edict) && !IsPlayerGorge(ThisBot->Edict) && vDist2DSq(ThisBot->Edict->v.origin, ThisHive->FloorLocation) > sqrf(UTIL_MetresToGoldSrcUnits(15.0f)))
|
||||||
|
{
|
||||||
|
if (ThisBot->SecondaryBotTask.TaskType == TASK_DEFEND && ThisBot->SecondaryBotTask.TaskTarget == ThisHive->HiveEntity->edict())
|
||||||
|
{
|
||||||
|
int ThisDefenderStrength = 1;
|
||||||
|
|
||||||
|
if (IsPlayerFade(ThisBot->Edict))
|
||||||
|
{
|
||||||
|
ThisDefenderStrength = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsPlayerOnos(ThisBot->Edict))
|
||||||
|
{
|
||||||
|
ThisDefenderStrength = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefenderStrength += ThisDefenderStrength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AttackerStrength >= DefenderStrength)
|
||||||
|
{
|
||||||
|
float ThisDist = vDist2DSq(ThisHive->FloorLocation, pBot->Edict->v.origin);
|
||||||
|
|
||||||
|
if (!HiveToDefend || ThisDist < MinDist)
|
||||||
|
{
|
||||||
|
HiveToDefend = ThisHive;
|
||||||
|
MinDist = ThisDist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HiveToDefend)
|
||||||
|
{
|
||||||
|
AITASK_SetDefendTask(pBot, Task, HiveToDefend->HiveEntity->edict(), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeployableSearchFilter AttackedStructuresFilter;
|
||||||
|
AttackedStructuresFilter.DeployableTypes = (IsPlayerLerk(pBot->Edict)) ? SEARCH_ALL_STRUCTURES : STRUCTURE_ALIEN_RESTOWER;
|
||||||
|
AttackedStructuresFilter.DeployableTeam = BotTeam;
|
||||||
|
AttackedStructuresFilter.ReachabilityTeam = BotTeam;
|
||||||
|
AttackedStructuresFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
|
||||||
|
AttackedStructuresFilter.IncludeStatusFlags = STRUCTURE_STATUS_UNDERATTACK;
|
||||||
|
AttackedStructuresFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(30.0f);
|
||||||
|
|
||||||
|
vector<AvHAIBuildableStructure*> AllAttackedStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &AttackedStructuresFilter);
|
||||||
|
|
||||||
|
AvHAIBuildableStructure* StructureToDefend = nullptr;
|
||||||
|
MinDist = 0.0f;
|
||||||
|
|
||||||
|
for (auto it = AllAttackedStructures.begin(); it != AllAttackedStructures.end(); it++)
|
||||||
|
{
|
||||||
|
AvHAIBuildableStructure* ThisStructure = (*it);
|
||||||
|
|
||||||
|
float ThisDist = vDist2D(pBot->Edict->v.origin, ThisStructure->edict->v.origin);
|
||||||
|
|
||||||
|
int NumExistingDefenders = AITAC_GetNumPlayersOfTeamInArea(BotTeam, ThisStructure->Location, ThisDist - 10.0f, false, pBot->Edict, AVH_USER3_ALIEN_PLAYER2);
|
||||||
|
|
||||||
|
if (NumExistingDefenders < 2)
|
||||||
|
{
|
||||||
|
if (!StructureToDefend || ThisDist < MinDist)
|
||||||
|
{
|
||||||
|
StructureToDefend = ThisStructure;
|
||||||
|
MinDist = ThisDist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StructureToDefend)
|
||||||
|
{
|
||||||
|
AITASK_SetDefendTask(pBot, Task, StructureToDefend->edict, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AITASK_ClearBotTask(pBot, Task);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3844,6 +4213,8 @@ bool AlienCombatThink(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
if (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_IGNORE) { return false; }
|
if (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_IGNORE) { return false; }
|
||||||
|
|
||||||
|
pBot->LastCombatTime = gpGlobals->time;
|
||||||
|
|
||||||
switch (pBot->Player->GetUser3())
|
switch (pBot->Player->GetUser3())
|
||||||
{
|
{
|
||||||
case AVH_USER3_ALIEN_PLAYER1:
|
case AVH_USER3_ALIEN_PLAYER1:
|
||||||
|
@ -4166,7 +4537,6 @@ bool LerkCombatThink(AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
BotShootLocation(pBot, WEAPON_LERK_SPORES, SporeLocation);
|
BotShootLocation(pBot, WEAPON_LERK_SPORES, SporeLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -37,6 +37,7 @@ void BotShootLocation(AvHAIPlayer* pBot, AvHAIWeapon AttackWeapon, const Vector
|
||||||
void BombardierAttackTarget(AvHAIPlayer* pBot, edict_t* Target);
|
void BombardierAttackTarget(AvHAIPlayer* pBot, edict_t* Target);
|
||||||
|
|
||||||
void BotEvolveLifeform(AvHAIPlayer* pBot, Vector DesiredEvolveLocation, AvHMessageID TargetLifeform);
|
void BotEvolveLifeform(AvHAIPlayer* pBot, Vector DesiredEvolveLocation, AvHMessageID TargetLifeform);
|
||||||
|
void BotEvolveUpgrade(AvHAIPlayer* pBot, Vector DesiredEvolveLocation, AvHMessageID TargetUpgrade);
|
||||||
|
|
||||||
enemy_status* GetTrackedEnemyRefForTarget(AvHAIPlayer* pBot, edict_t* Target);
|
enemy_status* GetTrackedEnemyRefForTarget(AvHAIPlayer* pBot, edict_t* Target);
|
||||||
|
|
||||||
|
@ -106,6 +107,8 @@ bool ShouldAIPlayerTakeCommand(AvHAIPlayer* pBot);
|
||||||
|
|
||||||
int BotGetNextEnemyTarget(AvHAIPlayer* pBot);
|
int BotGetNextEnemyTarget(AvHAIPlayer* pBot);
|
||||||
|
|
||||||
|
AvHMessageID AlienGetDesiredUpgrade(AvHAIPlayer* pBot, HiveTechStatus DesiredTech);
|
||||||
|
|
||||||
AvHAICombatStrategy GetBotCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_status* CurrentEnemy);
|
AvHAICombatStrategy GetBotCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_status* CurrentEnemy);
|
||||||
AvHAICombatStrategy GetAlienCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_status* CurrentEnemy);
|
AvHAICombatStrategy GetAlienCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_status* CurrentEnemy);
|
||||||
AvHAICombatStrategy GetSkulkCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_status* CurrentEnemy);
|
AvHAICombatStrategy GetSkulkCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_status* CurrentEnemy);
|
||||||
|
|
|
@ -593,7 +593,7 @@ void AIMGR_UpdateAIPlayers()
|
||||||
|
|
||||||
UpdateBotChat(bot);
|
UpdateBotChat(bot);
|
||||||
|
|
||||||
AIPlayerThink(bot);
|
CustomThink(bot);
|
||||||
|
|
||||||
BotUpdateDesiredViewRotation(bot);
|
BotUpdateDesiredViewRotation(bot);
|
||||||
}
|
}
|
||||||
|
|
|
@ -641,6 +641,13 @@ bool PlayerHasWeapon(const AvHPlayer* Player, const AvHAIWeapon DesiredCombatWea
|
||||||
// Marines don't have a fixed inventory, so we can just do a simple check for them. Same goes to confirm the alien has the weapon in their inventory
|
// Marines don't have a fixed inventory, so we can just do a simple check for them. Same goes to confirm the alien has the weapon in their inventory
|
||||||
if (IsPlayerMarine(Player) || !HasWeaponInInventory)
|
if (IsPlayerMarine(Player) || !HasWeaponInInventory)
|
||||||
{
|
{
|
||||||
|
if (DesiredCombatWeapon == WEAPON_MARINE_GRENADE && HasWeaponInInventory)
|
||||||
|
{
|
||||||
|
AvHBasePlayerWeapon* Weapon = dynamic_cast<AvHBasePlayerWeapon*>(Player->m_rgpPlayerItems[5]);
|
||||||
|
|
||||||
|
return Weapon->m_iClip > 0;
|
||||||
|
}
|
||||||
|
|
||||||
return HasWeaponInInventory;
|
return HasWeaponInInventory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4200,3 +4200,30 @@ edict_t* AITAC_AlienFindNearestHealingSource(AvHTeamNumber Team, Vector SearchLo
|
||||||
return (!FNullEnt(FriendlyGorge) ? FriendlyGorge : Result);
|
return (!FNullEnt(FriendlyGorge) ? FriendlyGorge : Result);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AITAC_IsAlienUpgradeAvailableForTeam(AvHTeamNumber Team, HiveTechStatus DesiredTech)
|
||||||
|
{
|
||||||
|
AvHAIDeployableStructureType SearchType;
|
||||||
|
|
||||||
|
switch (DesiredTech)
|
||||||
|
{
|
||||||
|
case HIVE_TECH_DEFENCE:
|
||||||
|
SearchType = STRUCTURE_ALIEN_DEFENCECHAMBER;
|
||||||
|
break;
|
||||||
|
case HIVE_TECH_MOVEMENT:
|
||||||
|
SearchType = STRUCTURE_ALIEN_MOVEMENTCHAMBER;
|
||||||
|
break;
|
||||||
|
case HIVE_TECH_SENSORY:
|
||||||
|
SearchType = STRUCTURE_ALIEN_SENSORYCHAMBER;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeployableSearchFilter ChamberFilter;
|
||||||
|
ChamberFilter.DeployableTeam = Team;
|
||||||
|
ChamberFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||||
|
ChamberFilter.DeployableTypes = SearchType;
|
||||||
|
|
||||||
|
return (AITAC_DeployableExistsAtLocation(ZERO_VECTOR, &ChamberFilter));
|
||||||
|
}
|
|
@ -175,4 +175,6 @@ void AITAC_OnTeamStartsModified();
|
||||||
|
|
||||||
edict_t* AITAC_AlienFindNearestHealingSource(AvHTeamNumber Team, Vector SearchLocation, edict_t* SearchingPlayer, bool bIncludeGorges);
|
edict_t* AITAC_AlienFindNearestHealingSource(AvHTeamNumber Team, Vector SearchLocation, edict_t* SearchingPlayer, bool bIncludeGorges);
|
||||||
|
|
||||||
|
bool AITAC_IsAlienUpgradeAvailableForTeam(AvHTeamNumber Team, HiveTechStatus DesiredTech);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -634,13 +634,24 @@ bool AITASK_IsAlienCapResNodeTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask*
|
||||||
}
|
}
|
||||||
|
|
||||||
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||||
|
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
|
||||||
|
|
||||||
|
if (ResNodeIndex->bIsBaseNode)
|
||||||
|
{
|
||||||
|
if (FNullEnt(ResNodeIndex->ParentHive)) { return false; } // This is the marine base res node, leave it alone
|
||||||
|
|
||||||
|
AvHAIHiveDefinition* ParentHive = AITAC_GetHiveFromEdict(ResNodeIndex->ParentHive);
|
||||||
|
|
||||||
|
// An enemy is now building the hive that this res node belongs to, abort
|
||||||
|
if (ParentHive && ParentHive->OwningTeam == EnemyTeam) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
// Don't waste resources switching down to gorge if we're a lerk, fade or onos
|
// Don't waste resources switching down to gorge if we're a lerk, fade or onos
|
||||||
// but we can still clear the area of enemy structures
|
// but we can still clear the area of enemy structures
|
||||||
if (!IsPlayerSkulk(pBot->Edict) && !IsPlayerGorge(pBot->Edict))
|
if (!IsPlayerSkulk(pBot->Edict) && !IsPlayerGorge(pBot->Edict))
|
||||||
{
|
{
|
||||||
DeployableSearchFilter EnemyStructuresFilter;
|
DeployableSearchFilter EnemyStructuresFilter;
|
||||||
EnemyStructuresFilter.DeployableTeam = AIMGR_GetEnemyTeam(BotTeam);
|
EnemyStructuresFilter.DeployableTeam = EnemyTeam;
|
||||||
EnemyStructuresFilter.ReachabilityTeam = BotTeam;
|
EnemyStructuresFilter.ReachabilityTeam = BotTeam;
|
||||||
EnemyStructuresFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
|
EnemyStructuresFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
|
||||||
EnemyStructuresFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
|
EnemyStructuresFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
|
||||||
|
@ -648,6 +659,27 @@ bool AITASK_IsAlienCapResNodeTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask*
|
||||||
return AITAC_DeployableExistsAtLocation(ResNodeIndex->Location, &EnemyStructuresFilter);
|
return AITAC_DeployableExistsAtLocation(ResNodeIndex->Location, &EnemyStructuresFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!FNullEnt(ResNodeIndex->ParentHive))
|
||||||
|
{
|
||||||
|
DeployableSearchFilter EnemyStructuresFilter;
|
||||||
|
EnemyStructuresFilter.DeployableTeam = EnemyTeam;
|
||||||
|
EnemyStructuresFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||||
|
EnemyStructuresFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||||
|
EnemyStructuresFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
|
||||||
|
|
||||||
|
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_MARINE)
|
||||||
|
{
|
||||||
|
EnemyStructuresFilter.DeployableTypes = (STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EnemyStructuresFilter.DeployableTypes = (STRUCTURE_ALIEN_OFFENCECHAMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enemy has started fortifying the hive we want to build a RT in, abort
|
||||||
|
if (AITAC_DeployableExistsAtLocation(ResNodeIndex->Location, &EnemyStructuresFilter)) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
// We can attack structures basically if we aren't stuck with Gorge's spit attack
|
// We can attack structures basically if we aren't stuck with Gorge's spit attack
|
||||||
bool bCanAttackStructures = (!IsPlayerGorge(pBot->Edict) || PlayerHasWeapon(pBot->Player, WEAPON_GORGE_BILEBOMB));
|
bool bCanAttackStructures = (!IsPlayerGorge(pBot->Edict) || PlayerHasWeapon(pBot->Player, WEAPON_GORGE_BILEBOMB));
|
||||||
|
|
||||||
|
@ -962,7 +994,7 @@ bool AITASK_IsAlienHealTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
// If our target is a player, give up if they are too far away. I'm not going to waste time chasing you around the map!
|
// If our target is a player, give up if they are too far away. I'm not going to waste time chasing you around the map!
|
||||||
float MaxHealRelevant = sqrf(UTIL_MetresToGoldSrcUnits(5.0f));
|
float MaxHealRelevant = sqrf(UTIL_MetresToGoldSrcUnits(5.0f));
|
||||||
|
|
||||||
return (vDist2DSq(pBot->CurrentFloorPosition, Task->TaskTarget->v.origin) <= MaxHealRelevant);
|
return (IsPlayerActiveInGame(Task->TaskTarget) && vDist2DSq(pBot->CurrentFloorPosition, Task->TaskTarget->v.origin) <= MaxHealRelevant);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AITASK_IsUseTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
bool AITASK_IsUseTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
|
|
|
@ -182,7 +182,7 @@ typedef enum
|
||||||
ALIEN_EVOLUTION_EIGHT = 108, // Adrenaline
|
ALIEN_EVOLUTION_EIGHT = 108, // Adrenaline
|
||||||
ALIEN_EVOLUTION_NINE = 109, // Silence
|
ALIEN_EVOLUTION_NINE = 109, // Silence
|
||||||
ALIEN_EVOLUTION_TEN = 110, // Cloaking
|
ALIEN_EVOLUTION_TEN = 110, // Cloaking
|
||||||
ALIEN_EVOLUTION_ELEVEN = 111, // Pheromones
|
ALIEN_EVOLUTION_ELEVEN = 111, // Focus
|
||||||
ALIEN_EVOLUTION_TWELVE = 112, // Scent of fear
|
ALIEN_EVOLUTION_TWELVE = 112, // Scent of fear
|
||||||
|
|
||||||
// Alien lifeforms
|
// Alien lifeforms
|
||||||
|
|
Loading…
Reference in a new issue