2024-03-21 18:17:18 +00:00
# include "AvHAICommander.h"
# include "AvHAITactical.h"
# include "AvHAIMath.h"
# include "AvHAIPlayerUtil.h"
# include "AvHAIWeaponHelper.h"
# include "AvHAINavigation.h"
# include "AvHAITask.h"
# include "AvHAIHelper.h"
# include "AvHAIPlayerManager.h"
2024-05-23 08:42:33 +00:00
# include "AvHAIConfig.h"
2024-03-21 18:17:18 +00:00
# include "AvHSharedUtil.h"
# include "AvHServerUtil.h"
2024-06-05 19:32:15 +00:00
AvHAIBuildableStructure * AICOMM_DeployStructure ( AvHAIPlayer * pBot , const AvHAIDeployableStructureType StructureToDeploy , const Vector Location , StructurePurpose Purpose , bool bPlacedByHuman )
2024-03-21 18:17:18 +00:00
{
2024-06-05 19:32:15 +00:00
if ( vIsZero ( Location ) ) { return nullptr ; }
2024-03-21 18:17:18 +00:00
nav_profile WelderProfile = GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) ;
WelderProfile . Filters . addIncludeFlags ( SAMPLE_POLYFLAGS_WELD ) ;
// Don't allow the commander to place a structure somewhere unreachable to marines
if ( ! UTIL_PointIsReachable ( WelderProfile , AITAC_GetTeamStartingLocation ( pBot - > Player - > GetTeam ( ) ) , Location , max_player_use_reach ) )
{
return false ;
}
AvHMessageID StructureID = UTIL_StructureTypeToImpulseCommand ( StructureToDeploy ) ;
Vector BuildLocation = Location ;
BuildLocation . z + = 4.0f ;
// This would be rejected if a human was trying to build here, so don't let the bot do it
if ( ! AvHSHUGetIsSiteValidForBuild ( StructureID , & BuildLocation ) )
{
2024-06-05 19:32:15 +00:00
return nullptr ;
2024-03-21 18:17:18 +00:00
}
string theErrorMessage ;
int theCost = 0 ;
bool thePurchaseAllowed = pBot - > Player - > GetPurchaseAllowed ( StructureID , theCost , & theErrorMessage ) ;
2024-06-05 19:32:15 +00:00
if ( ! thePurchaseAllowed ) { return nullptr ; }
2024-03-21 18:17:18 +00:00
CBaseEntity * NewStructureEntity = AvHSUBuildTechForPlayer ( StructureID , BuildLocation , pBot - > Player ) ;
2024-06-05 19:32:15 +00:00
if ( ! NewStructureEntity ) { return nullptr ; }
2024-03-21 18:17:18 +00:00
AvHAIBuildableStructure * NewStructure = AITAC_UpdateBuildableStructure ( NewStructureEntity ) ;
if ( NewStructure )
{
NewStructure - > Purpose = Purpose ;
2024-06-05 19:32:15 +00:00
NewStructure - > bPlacedByHuman = bPlacedByHuman ;
2024-03-21 18:17:18 +00:00
}
pBot - > Player - > PayPurchaseCost ( theCost ) ;
pBot - > next_commander_action_time = gpGlobals - > time + 1.0f ;
2024-06-05 19:32:15 +00:00
return NewStructure ;
2024-03-21 18:17:18 +00:00
}
bool AICOMM_DeployItem ( AvHAIPlayer * pBot , const AvHAIDeployableItemType ItemToDeploy , const Vector Location )
{
AvHMessageID StructureID = UTIL_ItemTypeToImpulseCommand ( ItemToDeploy ) ;
Vector BuildLocation = Location ;
string theErrorMessage ;
int theCost = 0 ;
bool thePurchaseAllowed = pBot - > Player - > GetPurchaseAllowed ( StructureID , theCost , & theErrorMessage ) ;
if ( ! thePurchaseAllowed ) { return false ; }
if ( ! AvHSHUGetIsSiteValidForBuild ( StructureID , & BuildLocation ) ) { return false ; }
CBaseEntity * NewItem = AvHSUBuildTechForPlayer ( StructureID , BuildLocation , pBot - > Player ) ;
if ( ! NewItem ) { return false ; }
AITAC_UpdateMarineItem ( NewItem , ItemToDeploy ) ;
pBot - > Player - > PayPurchaseCost ( theCost ) ;
pBot - > next_commander_action_time = gpGlobals - > time + 0.2f ;
return true ;
}
bool AICOMM_ResearchTech ( AvHAIPlayer * pBot , AvHAIBuildableStructure * StructureToResearch , AvHMessageID Research )
{
if ( ! StructureToResearch | | FNullEnt ( StructureToResearch - > edict ) | | ! StructureToResearch - > EntityRef ) { return false ; }
// Don't do anything if the structure is being recycled, or we DON'T want to recycle but the structure is already busy
if ( StructureToResearch - > EntityRef - > GetIsRecycling ( ) | | ( Research ! = BUILD_RECYCLE & & StructureToResearch - > EntityRef - > GetIsResearching ( ) ) ) { return false ; }
int StructureIndex = ENTINDEX ( StructureToResearch - > edict ) ;
if ( StructureIndex < 0 ) { return false ; }
if ( ! StructureToResearch - > EntityRef - > GetIsTechnologyAvailable ( Research ) ) { return false ; }
AvHTeam * CommanderTeamRef = AIMGR_GetTeamRef ( pBot - > Player - > GetTeam ( ) ) ;
if ( ! CommanderTeamRef ) { return false ; }
AvHResearchManager & theResearchManager = CommanderTeamRef - > GetResearchManager ( ) ;
bool theIsResearchable = false ;
int theResearchCost = 0.0f ;
float theResearchTime = 0.0f ;
theResearchManager . GetResearchInfo ( Research , theIsResearchable , theResearchCost , theResearchTime ) ;
if ( pBot - > Player - > GetResources ( ) < theResearchCost ) { return false ; }
pBot - > Player - > SetSelection ( StructureIndex , true ) ;
pBot - > Button | = IN_ATTACK2 ;
pBot - > Impulse = Research ;
pBot - > next_commander_action_time = gpGlobals - > time + 1.0f ;
return true ;
}
bool AICOMM_UpgradeStructure ( AvHAIPlayer * pBot , AvHAIBuildableStructure * StructureToUpgrade )
{
AvHMessageID UpgradeImpulse = MESSAGE_NULL ;
switch ( StructureToUpgrade - > StructureType )
{
case STRUCTURE_MARINE_ARMOURY :
UpgradeImpulse = ARMORY_UPGRADE ;
break ;
case STRUCTURE_MARINE_TURRETFACTORY :
UpgradeImpulse = TURRET_FACTORY_UPGRADE ;
break ;
default :
return false ;
}
return AICOMM_ResearchTech ( pBot , StructureToUpgrade , UpgradeImpulse ) ;
}
bool AICOMM_RecycleStructure ( AvHAIPlayer * pBot , AvHAIBuildableStructure * StructureToRecycle )
{
2024-04-12 15:40:50 +00:00
if ( ! StructureToRecycle | | StructureToRecycle - > StructureType = = STRUCTURE_MARINE_DEPLOYEDMINE | | UTIL_StructureIsRecycling ( StructureToRecycle - > edict ) ) { return false ; }
2024-03-21 18:17:18 +00:00
return AICOMM_ResearchTech ( pBot , StructureToRecycle , BUILD_RECYCLE ) ;
}
bool AICOMM_IssueMovementOrder ( AvHAIPlayer * pBot , edict_t * Recipient , const Vector MoveLocation )
{
if ( FNullEnt ( Recipient ) | | ! IsPlayerActiveInGame ( Recipient ) | | vIsZero ( MoveLocation ) ) { return false ; }
int ReceiverIndex = ENTINDEX ( Recipient ) ;
if ( ReceiverIndex < = 0 ) { return false ; }
AvHOrder NewOrder ;
NewOrder . SetOrderType ( ORDERTYPEL_MOVE ) ;
NewOrder . SetReceiver ( ReceiverIndex ) ;
NewOrder . SetLocation ( MoveLocation ) ;
NewOrder . SetOrderID ( ) ;
pBot - > Player - > SetSelection ( ReceiverIndex , true ) ;
pBot - > Player - > GiveOrderToSelection ( NewOrder ) ;
return true ;
}
bool AICOMM_IssueBuildOrder ( AvHAIPlayer * pBot , edict_t * Recipient , edict_t * TargetStructure )
{
if ( FNullEnt ( Recipient ) | | ! IsPlayerActiveInGame ( Recipient ) | | FNullEnt ( TargetStructure ) | | UTIL_StructureIsFullyBuilt ( TargetStructure ) ) { return false ; }
int ReceiverIndex = ENTINDEX ( Recipient ) ;
int TargetIndex = ENTINDEX ( TargetStructure ) ;
if ( ReceiverIndex < = 0 | | TargetIndex < = 0 ) { return false ; }
AvHBaseBuildable * BuildingRef = dynamic_cast < AvHBaseBuildable * > ( CBaseEntity : : Instance ( TargetStructure ) ) ;
if ( ! BuildingRef ) { return false ; }
AvHOrder NewOrder ;
NewOrder . SetOrderType ( ORDERTYPET_BUILD ) ;
NewOrder . SetReceiver ( ReceiverIndex ) ;
NewOrder . SetTargetIndex ( TargetIndex ) ;
NewOrder . SetUser3TargetType ( ( AvHUser3 ) TargetStructure - > v . iuser3 ) ;
NewOrder . SetOrderTargetType ( ORDERTARGETTYPE_LOCATION ) ;
NewOrder . SetLocation ( TargetStructure - > v . origin ) ;
NewOrder . SetOrderID ( ) ;
pBot - > Player - > SetSelection ( ReceiverIndex , true ) ;
pBot - > Player - > GiveOrderToSelection ( NewOrder ) ;
return true ;
}
void AICOMM_AssignNewPlayerOrder ( AvHAIPlayer * pBot , edict_t * Assignee , edict_t * TargetEntity , AvHAIOrderPurpose OrderPurpose )
{
if ( FNullEnt ( Assignee ) | | FNullEnt ( TargetEntity ) | | OrderPurpose = = ORDERPURPOSE_NONE ) { return ; }
// Clear any existing order we have for this player
for ( auto it = pBot - > ActiveOrders . begin ( ) ; it ! = pBot - > ActiveOrders . end ( ) ; )
{
if ( it - > Assignee = = Assignee )
{
it = pBot - > ActiveOrders . erase ( it ) ;
}
else
{
it + + ;
}
}
ai_commander_order NewOrder ;
NewOrder . Assignee = Assignee ;
NewOrder . OrderTarget = TargetEntity ;
2024-06-19 19:50:30 +00:00
NewOrder . OrderLocation = TargetEntity - > v . origin ;
2024-03-21 18:17:18 +00:00
NewOrder . OrderPurpose = OrderPurpose ;
NewOrder . LastReminderTime = 0.0f ;
NewOrder . LastPlayerDistance = 0.0f ;
pBot - > ActiveOrders . push_back ( NewOrder ) ;
if ( AICOMM_DoesPlayerOrderNeedReminder ( pBot , & NewOrder ) )
{
AICOMM_IssueOrderForAssignedJob ( pBot , & NewOrder ) ;
}
}
2024-06-12 19:21:55 +00:00
void AICOMM_AssignNewPlayerOrder ( AvHAIPlayer * pBot , edict_t * Assignee , Vector OrderLocation , AvHAIOrderPurpose OrderPurpose )
{
if ( FNullEnt ( Assignee ) | | vIsZero ( OrderLocation ) | | OrderPurpose = = ORDERPURPOSE_NONE ) { return ; }
// Clear any existing order we have for this player
for ( auto it = pBot - > ActiveOrders . begin ( ) ; it ! = pBot - > ActiveOrders . end ( ) ; )
{
if ( it - > Assignee = = Assignee )
{
it = pBot - > ActiveOrders . erase ( it ) ;
}
else
{
it + + ;
}
}
ai_commander_order NewOrder ;
NewOrder . Assignee = Assignee ;
NewOrder . OrderLocation = OrderLocation ;
NewOrder . OrderPurpose = OrderPurpose ;
NewOrder . LastReminderTime = 0.0f ;
NewOrder . LastPlayerDistance = 0.0f ;
pBot - > ActiveOrders . push_back ( NewOrder ) ;
if ( AICOMM_DoesPlayerOrderNeedReminder ( pBot , & NewOrder ) )
{
AICOMM_IssueOrderForAssignedJob ( pBot , & NewOrder ) ;
}
}
2024-03-21 18:17:18 +00:00
void AICOMM_IssueOrderForAssignedJob ( AvHAIPlayer * pBot , ai_commander_order * Order )
{
2024-06-12 19:21:55 +00:00
if ( Order - > OrderPurpose = = ORDERPURPOSE_BUILD_GUARDPOST | | Order - > OrderPurpose = = ORDERPURPOSE_BUILD_SIEGE | | Order - > OrderPurpose = = ORDERPURPOSE_BUILD_OUTPOST | | Order - > OrderPurpose = = ORDERPURPOSE_BUILD_MAINBASE )
{
Vector MoveLoc = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , Order - > OrderLocation , UTIL_MetresToGoldSrcUnits ( 1.0f ) ) ;
AICOMM_IssueMovementOrder ( pBot , Order - > Assignee , MoveLoc ) ;
Order - > LastReminderTime = gpGlobals - > time ;
Order - > LastPlayerDistance = vDist2DSq ( Order - > Assignee - > v . origin , MoveLoc ) ;
Order - > OrderLocation = MoveLoc ;
return ;
}
2024-03-21 18:17:18 +00:00
if ( Order - > OrderPurpose = = ORDERPURPOSE_SIEGE_HIVE | | Order - > OrderPurpose = = ORDERPURPOSE_SECURE_HIVE )
{
bool bIsSiegeHiveOrder = ( Order - > OrderPurpose = = ORDERPURPOSE_SIEGE_HIVE ) ;
const AvHAIHiveDefinition * Hive = AITAC_GetHiveFromEdict ( Order - > OrderTarget ) ;
if ( Hive )
{
Vector OrderLocation = Hive - > FloorLocation ;
DeployableSearchFilter StructureFilter ;
StructureFilter . DeployableTeam = pBot - > Player - > GetTeam ( ) ;
StructureFilter . DeployableTypes = STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY ;
StructureFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
StructureFilter . MaxSearchRadius = ( bIsSiegeHiveOrder ) ? UTIL_MetresToGoldSrcUnits ( 25.0f ) : UTIL_MetresToGoldSrcUnits ( 10.0f ) ;
AvHAIBuildableStructure NearestToHive = AITAC_FindClosestDeployableToLocation ( Hive - > Location , & StructureFilter ) ;
if ( NearestToHive . IsValid ( ) )
{
if ( ! ( NearestToHive . StructureStatusFlags & STRUCTURE_STATUS_COMPLETED ) )
{
AICOMM_IssueBuildOrder ( pBot , Order - > Assignee , NearestToHive . edict ) ;
Order - > LastReminderTime = gpGlobals - > time ;
Order - > LastPlayerDistance = vDist2DSq ( Order - > Assignee - > v . origin , NearestToHive . Location ) ;
Order - > OrderLocation = NearestToHive . Location ;
return ;
}
else
{
Vector MoveLoc = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , NearestToHive . Location , UTIL_MetresToGoldSrcUnits ( 3.0f ) ) ;
AICOMM_IssueMovementOrder ( pBot , Order - > Assignee , MoveLoc ) ;
Order - > LastReminderTime = gpGlobals - > time ;
Order - > LastPlayerDistance = vDist2DSq ( Order - > Assignee - > v . origin , MoveLoc ) ;
Order - > OrderLocation = MoveLoc ;
return ;
}
}
else
{
2024-03-23 23:10:52 +00:00
Vector MoveLoc = ( bIsSiegeHiveOrder ) ? UTIL_GetRandomPointOnNavmeshInDonutIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , Hive - > FloorLocation , UTIL_MetresToGoldSrcUnits ( 10.0f ) , UTIL_MetresToGoldSrcUnits ( 20.0f ) ) : Hive - > FloorLocation ;
2024-03-21 18:17:18 +00:00
AICOMM_IssueMovementOrder ( pBot , Order - > Assignee , MoveLoc ) ;
Order - > LastReminderTime = gpGlobals - > time ;
Order - > LastPlayerDistance = vDist2DSq ( Order - > Assignee - > v . origin , MoveLoc ) ;
Order - > OrderLocation = MoveLoc ;
return ;
}
}
Order - > LastReminderTime = gpGlobals - > time ;
return ;
}
if ( Order - > OrderPurpose = = ORDERPURPOSE_SECURE_RESNODE )
{
const AvHAIResourceNode * ResNode = AITAC_GetResourceNodeFromEdict ( Order - > OrderTarget ) ;
if ( ResNode )
{
if ( ResNode - > OwningTeam = = pBot - > Player - > GetTeam ( ) & & ResNode - > ActiveTowerEntity & & ! UTIL_StructureIsFullyBuilt ( ResNode - > ActiveTowerEntity ) )
{
AICOMM_IssueBuildOrder ( pBot , Order - > Assignee , ResNode - > ActiveTowerEntity ) ;
Order - > LastReminderTime = gpGlobals - > time ;
Order - > LastPlayerDistance = vDist2DSq ( Order - > Assignee - > v . origin , ResNode - > Location ) ;
Order - > OrderLocation = ResNode - > Location ;
return ;
}
Vector MoveLoc = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , ResNode - > Location , UTIL_MetresToGoldSrcUnits ( 3.0f ) ) ;
AICOMM_IssueMovementOrder ( pBot , Order - > Assignee , MoveLoc ) ;
Order - > LastReminderTime = gpGlobals - > time ;
Order - > LastPlayerDistance = vDist2DSq ( Order - > Assignee - > v . origin , MoveLoc ) ;
Order - > OrderLocation = MoveLoc ;
return ;
}
return ;
}
}
2024-06-12 19:21:55 +00:00
int AICOMM_GetNumPlayersAssignedToOrderLocation ( AvHAIPlayer * pBot , Vector OrderLocation , AvHAIOrderPurpose OrderPurpose )
{
int Result = 0 ;
for ( auto it = pBot - > ActiveOrders . begin ( ) ; it ! = pBot - > ActiveOrders . end ( ) ; it + + )
{
if ( ( OrderPurpose = = ORDERPURPOSE_NONE | | it - > OrderPurpose = = OrderPurpose ) & & vDist2DSq ( it - > OrderLocation , OrderLocation ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 5.0f ) ) )
{
Result + + ;
}
}
return Result ;
}
int AICOMM_GetNumPlayersAssignedToOrderType ( AvHAIPlayer * pBot , AvHAIOrderPurpose OrderPurpose )
{
int Result = 0 ;
for ( auto it = pBot - > ActiveOrders . begin ( ) ; it ! = pBot - > ActiveOrders . end ( ) ; it + + )
{
if ( it - > OrderPurpose = = OrderPurpose )
{
Result + + ;
}
}
return Result ;
}
2024-03-21 18:17:18 +00:00
int AICOMM_GetNumPlayersAssignedToOrder ( AvHAIPlayer * pBot , edict_t * TargetEntity , AvHAIOrderPurpose OrderPurpose )
{
int Result = 0 ;
for ( auto it = pBot - > ActiveOrders . begin ( ) ; it ! = pBot - > ActiveOrders . end ( ) ; it + + )
{
if ( it - > OrderTarget = = TargetEntity & & it - > OrderPurpose = = OrderPurpose )
{
Result + + ;
}
}
return Result ;
}
2024-06-12 19:21:55 +00:00
AvHAIMarineBase * AICOMM_GetNearestBaseToLocation ( AvHAIPlayer * pBot , Vector SearchLocation )
{
AvHAIMarineBase * Result = nullptr ;
float MinDist = 0.0f ;
for ( auto it = pBot - > Bases . begin ( ) ; it ! = pBot - > Bases . end ( ) ; it + + )
{
AvHAIMarineBase * ThisBase = & ( * it ) ;
float ThisDist = vDist2DSq ( ThisBase - > BaseLocation , SearchLocation ) ;
if ( ! Result | | ThisDist < MinDist )
{
Result = ThisBase ;
MinDist = ThisDist ;
}
}
return Result ;
}
2024-03-21 18:17:18 +00:00
bool AICOMM_IsOrderStillValid ( AvHAIPlayer * pBot , ai_commander_order * Order )
{
2024-06-12 19:21:55 +00:00
if ( FNullEnt ( Order - > Assignee ) | | ( FNullEnt ( Order - > OrderTarget ) & & vIsZero ( Order - > OrderLocation ) ) | | ! IsPlayerActiveInGame ( Order - > Assignee ) | | Order - > OrderPurpose = = ORDERPURPOSE_NONE ) { return false ; }
2024-03-21 18:17:18 +00:00
switch ( Order - > OrderPurpose )
{
case ORDERPURPOSE_SECURE_HIVE :
{
const AvHAIHiveDefinition * Hive = AITAC_GetHiveFromEdict ( Order - > OrderTarget ) ;
if ( ! Hive | | Hive - > Status ! = HIVE_STATUS_UNBUILT ) { return false ; }
return ! AICOMM_IsHiveFullySecured ( pBot , Hive , false ) ;
}
break ;
case ORDERPURPOSE_SIEGE_HIVE :
{
const AvHAIHiveDefinition * Hive = AITAC_GetHiveFromEdict ( Order - > OrderTarget ) ;
// Hive has been destroyed, no longer needs sieging
return ( Hive & & Hive - > Status ! = HIVE_STATUS_UNBUILT ) ;
}
break ;
case ORDERPURPOSE_SECURE_RESNODE :
{
if ( ! AICOMM_ShouldCommanderPrioritiseNodes ( pBot ) ) { return false ; }
const AvHAIResourceNode * ResNode = AITAC_GetResourceNodeFromEdict ( Order - > OrderTarget ) ;
if ( ! ResNode ) { return false ; }
return ( ResNode - > OwningTeam ! = pBot - > Player - > GetTeam ( ) | | ! ResNode - > ActiveTowerEntity | | ! UTIL_StructureIsFullyBuilt ( ResNode - > ActiveTowerEntity ) ) ;
}
break ;
2024-06-12 19:21:55 +00:00
case ORDERPURPOSE_BUILD_SIEGE :
case ORDERPURPOSE_BUILD_OUTPOST :
case ORDERPURPOSE_BUILD_GUARDPOST :
case ORDERPURPOSE_BUILD_MAINBASE :
{
AvHAIMarineBase * NearestBase = AICOMM_GetNearestBaseToLocation ( pBot , Order - > OrderLocation ) ;
if ( ! NearestBase | | NearestBase - > bRecycleBase | | ! NearestBase - > bIsActive | | ! NearestBase - > bCanBeBuiltOut ) { return false ; }
// If this is a main base, it's established (has 2 or more infantry portals) and our active comm chair is based there, then we don't need anyone ordered to this location any more
if ( NearestBase - > BaseType = = MARINE_BASE_MAINBASE & & NearestBase - > bBaseInitialised & & vDist2DSq ( NearestBase - > BaseLocation , AITAC_GetCommChairLocation ( pBot - > Player - > GetTeam ( ) ) ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ) { return false ; }
if ( vDist2DSq ( NearestBase - > BaseLocation , Order - > OrderLocation ) > sqrf ( UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ) { return false ; }
return true ;
}
break ;
2024-03-21 18:17:18 +00:00
default :
return false ;
}
return false ;
}
bool AICOMM_DoesPlayerOrderNeedReminder ( AvHAIPlayer * pBot , ai_commander_order * Order )
{
2024-05-13 08:36:17 +00:00
// For now, disable reminders as it is annoying for humans and pointless for bots who should obey it always anyway
2024-05-17 20:46:35 +00:00
return ( Order - > LastReminderTime < 0.1f ) ;
2024-05-13 08:36:17 +00:00
2024-03-21 18:17:18 +00:00
float NewDist = vDist2DSq ( Order - > Assignee - > v . origin , Order - > OrderLocation ) ;
float OldDist = Order - > LastPlayerDistance ;
Order - > LastPlayerDistance = NewDist ;
if ( gpGlobals - > time - Order - > LastReminderTime < MIN_COMMANDER_REMIND_TIME ) { return false ; }
if ( Order - > OrderPurpose = = ORDERPURPOSE_SECURE_RESNODE )
{
if ( vDist2DSq ( Order - > Assignee - > v . origin , Order - > OrderTarget - > v . origin ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ) { return false ; }
}
if ( Order - > OrderPurpose = = ORDERPURPOSE_SIEGE_HIVE )
{
if ( vDist2DSq ( Order - > Assignee - > v . origin , Order - > OrderTarget - > v . origin ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 25.0f ) ) ) { return false ; }
}
if ( Order - > OrderPurpose = = ORDERPURPOSE_SECURE_HIVE )
{
if ( vDist2DSq ( Order - > Assignee - > v . origin , Order - > OrderTarget - > v . origin ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 15.0f ) ) ) { return false ; }
}
return NewDist > = OldDist ;
}
bool AICOMM_ShouldCommanderPrioritiseNodes ( AvHAIPlayer * pBot )
{
AvHTeamNumber BotTeam = pBot - > Player - > GetTeam ( ) ;
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam ( BotTeam ) ;
int NumOwnedNodes = 0 ;
int NumEligibleNodes = 0 ;
int NumFreeNodes = 0 ;
// First get ours and the enemy's ownership of all eligible nodes (we can reach them, and they're in the enemy base)
vector < AvHAIResourceNode * > AllNodes = AITAC_GetAllReachableResourceNodes ( BotTeam ) ;
for ( auto it = AllNodes . begin ( ) ; it ! = AllNodes . end ( ) ; it + + )
{
AvHAIResourceNode * ThisNode = ( * it ) ;
// We don't care about the node at marine spawn or enemy hives, ignore then in our calculations
if ( ThisNode - > OwningTeam = = EnemyTeam & & ThisNode - > bIsBaseNode ) { continue ; }
if ( ThisNode - > OwningTeam = = TEAM_IND )
{
NumFreeNodes + + ;
}
NumEligibleNodes + + ;
if ( ThisNode - > OwningTeam = = BotTeam ) { NumOwnedNodes + + ; }
}
int NumDesiredNodes = imini ( 4 , ( int ) ceilf ( ( float ) NumEligibleNodes * 0.5f ) ) ;
int NumNodesLeft = NumEligibleNodes - NumOwnedNodes ;
if ( NumNodesLeft = = 0 ) { return false ; }
return NumOwnedNodes < NumDesiredNodes | | NumFreeNodes > 1 ;
}
void AICOMM_UpdatePlayerOrders ( AvHAIPlayer * pBot )
{
// Clear out any orders which aren't relevant any more
for ( auto it = pBot - > ActiveOrders . begin ( ) ; it ! = pBot - > ActiveOrders . end ( ) ; )
{
if ( ! AICOMM_IsOrderStillValid ( pBot , & ( * it ) ) )
{
it = pBot - > ActiveOrders . erase ( it ) ;
}
else
{
// If the person we're ordering around isn't doing as they're told, then issue them a reminder
if ( AICOMM_DoesPlayerOrderNeedReminder ( pBot , & ( * it ) ) )
{
AICOMM_IssueOrderForAssignedJob ( pBot , & ( * it ) ) ;
}
it + + ;
}
}
2024-06-12 19:21:55 +00:00
AvHTeamNumber BotTeam = pBot - > Player - > GetTeam ( ) ;
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam ( BotTeam ) ;
2024-03-21 18:17:18 +00:00
int NumPlayersOnTeam = AITAC_GetNumActivePlayersOnTeam ( pBot - > Player - > GetTeam ( ) ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
for ( auto it = pBot - > Bases . begin ( ) ; it ! = pBot - > Bases . end ( ) ; it + + )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
AvHAIMarineBase * ThisBase = & ( * it ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( ThisBase - > BaseType = = MARINE_BASE_MAINBASE & & ! ThisBase - > bIsBaseEstablished )
{
bool bCommChairInBase = vDist2DSq ( ThisBase - > BaseLocation , AITAC_GetCommChairLocation ( BotTeam ) ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( bCommChairInBase & & ThisBase - > bIsBaseEstablished ) { continue ; }
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
// Either the base isn't established (has comm chair and infantry portals), or the active comm chair isn't in the base (we're relocating)
int NumDesiredBuilders = ThisBase - > bIsBaseEstablished ? 1 : 2 ;
2024-05-22 15:21:40 +00:00
2024-06-14 16:12:07 +00:00
NumDesiredBuilders = imini ( NumDesiredBuilders , NumPlayersOnTeam ) ;
2024-06-12 19:21:55 +00:00
int NumBuilders = ThisBase - > NumBuilders + AICOMM_GetNumPlayersAssignedToOrderLocation ( pBot , ThisBase - > BaseLocation , ORDERPURPOSE_BUILD_MAINBASE ) ;
if ( NumBuilders < NumDesiredBuilders )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
edict_t * NewBuilder = AICOMM_GetPlayerWithoutSpecificOrderNearestLocation ( pBot , ThisBase - > BaseLocation , ORDERPURPOSE_BUILD_MAINBASE ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( ! FNullEnt ( NewBuilder ) )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
AICOMM_AssignNewPlayerOrder ( pBot , NewBuilder , ThisBase - > BaseLocation , ORDERPURPOSE_BUILD_MAINBASE ) ;
2024-05-22 15:21:40 +00:00
return ;
}
}
2024-06-12 19:21:55 +00:00
else
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
continue ;
2024-03-21 18:17:18 +00:00
}
}
}
2024-06-12 19:21:55 +00:00
int MinResGatherers = imini ( 3 , ( int ) ceilf ( NumPlayersOnTeam * 0.35f ) ) ;
if ( AICOMM_ShouldCommanderPrioritiseNodes ( pBot ) & & AICOMM_GetNumPlayersAssignedToOrderType ( pBot , ORDERPURPOSE_SECURE_RESNODE ) < MinResGatherers )
2024-03-21 18:17:18 +00:00
{
DeployableSearchFilter ResNodeFilter ;
ResNodeFilter . ReachabilityTeam = pBot - > Player - > GetTeam ( ) ;
ResNodeFilter . ReachabilityFlags = AI_REACHABILITY_MARINE ;
vector < AvHAIResourceNode * > EligibleResNodes = AITAC_GetAllMatchingResourceNodes ( ZERO_VECTOR , & ResNodeFilter ) ;
AvHAIResourceNode * NearestNode = nullptr ;
float MinDist = 0.0f ;
2024-06-12 19:21:55 +00:00
Vector TeamStartingLocation = AITAC_GetCommChairLocation ( BotTeam ) ;
int NumResNodesOrdered = 0 ;
2024-03-21 18:17:18 +00:00
for ( auto it = EligibleResNodes . begin ( ) ; it ! = EligibleResNodes . end ( ) ; it + + )
{
AvHAIResourceNode * ThisNode = ( * it ) ;
if ( ! ThisNode | | ThisNode - > OwningTeam = = BotTeam ) { continue ; }
int NumAssignedPlayers = AICOMM_GetNumPlayersAssignedToOrder ( pBot , ThisNode - > ResourceEntity - > edict ( ) , ORDERPURPOSE_SECURE_RESNODE ) ;
2024-06-12 19:21:55 +00:00
if ( NumAssignedPlayers > 0 ) { continue ; }
2024-03-21 18:17:18 +00:00
float ThisDist = vDist2DSq ( TeamStartingLocation , ThisNode - > Location ) ;
if ( ThisNode - > OwningTeam = = EnemyTeam )
{
ThisDist * = 2.0f ;
}
if ( ! NearestNode | | ThisDist < MinDist )
{
NearestNode = ThisNode ;
MinDist = ThisDist ;
}
}
if ( NearestNode )
{
edict_t * NewAssignee = AICOMM_GetPlayerWithNoOrderNearestLocation ( pBot , NearestNode - > Location ) ;
if ( ! FNullEnt ( NewAssignee ) )
{
AICOMM_AssignNewPlayerOrder ( pBot , NewAssignee , NearestNode - > ResourceEntity - > edict ( ) , ORDERPURPOSE_SECURE_RESNODE ) ;
2024-06-12 19:21:55 +00:00
return ;
2024-03-21 18:17:18 +00:00
}
}
}
2024-06-12 19:21:55 +00:00
AvHAIMarineBase * SiegeBase = nullptr ;
AvHAIMarineBase * Outpost = nullptr ;
AvHAIMarineBase * Guardpost = nullptr ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
for ( auto it = pBot - > Bases . begin ( ) ; it ! = pBot - > Bases . end ( ) ; it + + )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
AvHAIMarineBase * ThisBase = & ( * it ) ;
if ( ThisBase - > bRecycleBase | | ! ThisBase - > bIsActive | | ! ThisBase - > bCanBeBuiltOut ) { continue ; }
if ( ThisBase - > BaseType = = MARINE_BASE_MAINBASE ) { continue ; }
int NumDesiredBuilders = 0 ;
AvHAIOrderPurpose NewOrderPurpose = ORDERPURPOSE_NONE ;
switch ( ThisBase - > BaseType )
{
case MARINE_BASE_SIEGE :
NumDesiredBuilders = imini ( 3 , ( int ) ceilf ( ( float ) NumPlayersOnTeam * 0.5f ) ) ;
NewOrderPurpose = ORDERPURPOSE_BUILD_SIEGE ;
break ;
case MARINE_BASE_OUTPOST :
NumDesiredBuilders = imini ( 2 , ( int ) ceilf ( ( float ) NumPlayersOnTeam * 0.25f ) ) ;
NewOrderPurpose = ORDERPURPOSE_BUILD_OUTPOST ;
break ;
case MARINE_BASE_GUARDPOST :
NumDesiredBuilders = 1 ;
NewOrderPurpose = ORDERPURPOSE_BUILD_GUARDPOST ;
break ;
default :
continue ;
}
int NumPlayersThere = ThisBase - > NumBuilders ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
int Deficit = NumDesiredBuilders - NumPlayersThere ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( Deficit > 0 )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
int NumOrders = AICOMM_GetNumPlayersAssignedToOrderLocation ( pBot , ThisBase - > BaseLocation , NewOrderPurpose ) ;
Deficit - = NumOrders ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( Deficit > 0 )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
if ( ThisBase - > BaseType = = MARINE_BASE_SIEGE )
{
SiegeBase = ThisBase ;
}
else if ( ThisBase - > BaseType = = MARINE_BASE_OUTPOST )
{
Outpost = ThisBase ;
}
else if ( ThisBase - > BaseType = = MARINE_BASE_GUARDPOST )
{
Guardpost = ThisBase ;
}
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
}
}
if ( SiegeBase )
{
edict_t * NearestEligiblePlayer = AICOMM_GetPlayerWithNoOrderNearestLocation ( pBot , SiegeBase - > BaseLocation ) ;
if ( ! FNullEnt ( NearestEligiblePlayer ) )
{
AICOMM_AssignNewPlayerOrder ( pBot , NearestEligiblePlayer , SiegeBase - > BaseLocation , ORDERPURPOSE_BUILD_SIEGE ) ;
return ;
2024-03-21 18:17:18 +00:00
}
}
2024-06-12 19:21:55 +00:00
if ( Outpost )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
edict_t * NearestEligiblePlayer = AICOMM_GetPlayerWithNoOrderNearestLocation ( pBot , Outpost - > BaseLocation ) ;
if ( ! FNullEnt ( NearestEligiblePlayer ) )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
AICOMM_AssignNewPlayerOrder ( pBot , NearestEligiblePlayer , Outpost - > BaseLocation , ORDERPURPOSE_BUILD_OUTPOST ) ;
return ;
}
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( Guardpost )
{
edict_t * NearestEligiblePlayer = AICOMM_GetPlayerWithNoOrderNearestLocation ( pBot , Guardpost - > BaseLocation ) ;
if ( ! FNullEnt ( NearestEligiblePlayer ) )
{
AICOMM_AssignNewPlayerOrder ( pBot , NearestEligiblePlayer , Guardpost - > BaseLocation , ORDERPURPOSE_BUILD_GUARDPOST ) ;
return ;
2024-03-21 18:17:18 +00:00
}
}
2024-06-12 19:21:55 +00:00
}
edict_t * AICOMM_GetPlayerWithoutSpecificOrderNearestLocation ( AvHAIPlayer * pBot , Vector SearchLocation , AvHAIOrderPurpose OrderPurpose )
{
edict_t * Result = nullptr ;
float MinDist = 0.0f ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
vector < AvHPlayer * > PlayerList = AIMGR_GetAllPlayersOnTeam ( pBot - > Player - > GetTeam ( ) ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
// First, remove all players who are dead or otherwise not active with boots on the ground (e.g. commander, or being digested)
for ( auto it = PlayerList . begin ( ) ; it ! = PlayerList . end ( ) ; )
{
AvHPlayer * PlayerRef = ( * it ) ;
AvHAIPlayer * AIPlayerRef = AIMGR_GetBotRefFromPlayer ( PlayerRef ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
// Don't give orders to incapacitated players, or if the bot is currently playing a defensive role. Stops the commander sending everyone out
// and leaving nobody at base
if ( ! IsPlayerActiveInGame ( PlayerRef - > edict ( ) ) | | ( AIPlayerRef & & AIPlayerRef - > BotRole = = BOT_ROLE_SWEEPER ) )
{
it = PlayerList . erase ( it ) ;
}
else
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
it + + ;
}
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
// Next, erase all players with orders so we only have a list of players without orders assigned to them
for ( auto it = pBot - > ActiveOrders . begin ( ) ; it ! = pBot - > ActiveOrders . end ( ) ; it + + )
{
if ( it - > OrderPurpose ! = OrderPurpose ) { continue ; }
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
AvHPlayer * ThisPlayer = dynamic_cast < AvHPlayer * > ( CBaseEntity : : Instance ( it - > Assignee ) ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ! ThisPlayer ) { continue ; }
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
std : : vector < AvHPlayer * > : : iterator FoundPlayer = std : : find ( PlayerList . begin ( ) , PlayerList . end ( ) , ThisPlayer ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( FoundPlayer ! = PlayerList . end ( ) )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
PlayerList . erase ( FoundPlayer ) ;
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
}
// Now rank them by distance and return the result
for ( auto it = PlayerList . begin ( ) ; it ! = PlayerList . end ( ) ; it + + )
{
edict_t * PlayerEdict = ( * it ) - > edict ( ) ;
float ThisDist = vDist2DSq ( PlayerEdict - > v . origin , SearchLocation ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ! Result | | ThisDist < MinDist )
{
Result = PlayerEdict ;
MinDist = ThisDist ;
}
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
return Result ;
2024-03-21 18:17:18 +00:00
}
edict_t * AICOMM_GetPlayerWithNoOrderNearestLocation ( AvHAIPlayer * pBot , Vector SearchLocation )
{
edict_t * Result = nullptr ;
float MinDist = 0.0f ;
vector < AvHPlayer * > PlayerList = AIMGR_GetAllPlayersOnTeam ( pBot - > Player - > GetTeam ( ) ) ;
// First, remove all players who are dead or otherwise not active with boots on the ground (e.g. commander, or being digested)
for ( auto it = PlayerList . begin ( ) ; it ! = PlayerList . end ( ) ; )
{
AvHPlayer * PlayerRef = ( * it ) ;
AvHAIPlayer * AIPlayerRef = AIMGR_GetBotRefFromPlayer ( PlayerRef ) ;
// Don't give orders to incapacitated players, or if the bot is currently playing a defensive role. Stops the commander sending everyone out
// and leaving nobody at base
if ( ! IsPlayerActiveInGame ( PlayerRef - > edict ( ) ) | | ( AIPlayerRef & & AIPlayerRef - > BotRole = = BOT_ROLE_SWEEPER ) )
{
it = PlayerList . erase ( it ) ;
}
else
{
it + + ;
}
}
// Next, erase all players with orders so we only have a list of players without orders assigned to them
for ( auto it = pBot - > ActiveOrders . begin ( ) ; it ! = pBot - > ActiveOrders . end ( ) ; it + + )
{
AvHPlayer * ThisPlayer = dynamic_cast < AvHPlayer * > ( CBaseEntity : : Instance ( it - > Assignee ) ) ;
if ( ! ThisPlayer ) { continue ; }
std : : vector < AvHPlayer * > : : iterator FoundPlayer = std : : find ( PlayerList . begin ( ) , PlayerList . end ( ) , ThisPlayer ) ;
if ( FoundPlayer ! = PlayerList . end ( ) )
{
PlayerList . erase ( FoundPlayer ) ;
}
}
// Now rank them by distance and return the result
for ( auto it = PlayerList . begin ( ) ; it ! = PlayerList . end ( ) ; it + + )
{
edict_t * PlayerEdict = ( * it ) - > edict ( ) ;
float ThisDist = vDist2DSq ( PlayerEdict - > v . origin , SearchLocation ) ;
if ( ! Result | | ThisDist < MinDist )
{
Result = PlayerEdict ;
MinDist = ThisDist ;
}
}
return Result ;
}
bool AICOMM_IssueSecureHiveOrder ( AvHAIPlayer * pBot , edict_t * Recipient , const AvHAIHiveDefinition * HiveToSecure )
{
if ( ! HiveToSecure | | FNullEnt ( Recipient ) | | ! IsPlayerActiveInGame ( Recipient ) ) { return false ; }
int ReceiverIndex = ENTINDEX ( Recipient ) ;
if ( ReceiverIndex < = 0 ) { return false ; }
AvHTeamNumber CommanderTeam = pBot - > Player - > GetTeam ( ) ;
bool bPhaseGatesAvailable = AITAC_PhaseGatesAvailable ( CommanderTeam ) ;
if ( bPhaseGatesAvailable )
{
DeployableSearchFilter PGFilter ;
PGFilter . DeployableTeam = CommanderTeam ;
PGFilter . DeployableTypes = STRUCTURE_MARINE_PHASEGATE ;
PGFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
PGFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
PGFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 15.0f ) ;
bool bPhaseExists = AITAC_DeployableExistsAtLocation ( HiveToSecure - > FloorLocation , & PGFilter ) ;
if ( ! bPhaseExists )
{
Vector OrderLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , HiveToSecure - > FloorLocation , UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ;
return AICOMM_IssueMovementOrder ( pBot , Recipient , OrderLocation ) ;
}
}
DeployableSearchFilter TFFilter ;
TFFilter . DeployableTeam = CommanderTeam ;
TFFilter . DeployableTypes = STRUCTURE_MARINE_TURRETFACTORY ;
TFFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
TFFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
TFFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 15.0f ) ;
AvHAIBuildableStructure TF = AITAC_FindClosestDeployableToLocation ( HiveToSecure - > FloorLocation , & TFFilter ) ;
if ( ! TF . IsValid ( ) )
{
Vector OrderLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , HiveToSecure - > FloorLocation , UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ;
return AICOMM_IssueMovementOrder ( pBot , Recipient , OrderLocation ) ;
}
DeployableSearchFilter TurretFilter ;
TurretFilter . DeployableTeam = CommanderTeam ;
TurretFilter . DeployableTypes = STRUCTURE_MARINE_TURRET ;
TurretFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
TurretFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
TurretFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 5.0f ) ;
int NumTurrets = AITAC_GetNumDeployablesNearLocation ( TF . Location , & TurretFilter ) ;
if ( NumTurrets < 5 )
{
Vector OrderLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , HiveToSecure - > FloorLocation , UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ;
return AICOMM_IssueMovementOrder ( pBot , Recipient , OrderLocation ) ;
}
AvHAIResourceNode * HiveNode = HiveToSecure - > HiveResNodeRef ;
if ( HiveNode & & ( FNullEnt ( HiveNode - > ActiveTowerEntity ) | | HiveNode - > ActiveTowerEntity - > v . team ! = CommanderTeam | | ! UTIL_StructureIsFullyBuilt ( HiveNode - > ActiveTowerEntity ) ) )
{
Vector OrderLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , HiveNode - > Location , UTIL_MetresToGoldSrcUnits ( 2.0f ) ) ;
return AICOMM_IssueMovementOrder ( pBot , Recipient , OrderLocation ) ;
}
Vector OrderLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , HiveToSecure - > FloorLocation , UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ;
return AICOMM_IssueMovementOrder ( pBot , Recipient , OrderLocation ) ;
}
bool AICOMM_IssueSiegeHiveOrder ( AvHAIPlayer * pBot , edict_t * Recipient , const AvHAIHiveDefinition * HiveToSiege , const Vector SiegePosition )
{
if ( ! HiveToSiege | | FNullEnt ( Recipient ) | | ! IsPlayerActiveInGame ( Recipient ) ) { return false ; }
return AICOMM_IssueMovementOrder ( pBot , Recipient , SiegePosition ) ;
}
bool AICOMM_IssueSecureResNodeOrder ( AvHAIPlayer * pBot , edict_t * Recipient , const AvHAIResourceNode * ResNode )
{
if ( ! ResNode | | FNullEnt ( Recipient ) | | ! IsPlayerActiveInGame ( Recipient ) ) { return false ; }
Vector MoveLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , ResNode - > Location , UTIL_MetresToGoldSrcUnits ( 3.0f ) ) ;
if ( MoveLocation = = ZERO_VECTOR )
{
MoveLocation = ResNode - > Location ;
}
return AICOMM_IssueMovementOrder ( pBot , Recipient , MoveLocation ) ;
}
ai_commander_request * AICOMM_GetExistingRequestForPlayer ( AvHAIPlayer * pBot , edict_t * Requestor )
{
for ( auto it = pBot - > ActiveRequests . begin ( ) ; it ! = pBot - > ActiveRequests . end ( ) ; it + + )
{
if ( it - > Requestor = = Requestor )
{
return & ( * it ) ;
}
}
return nullptr ;
}
void AICOMM_CheckNewRequests ( AvHAIPlayer * pBot )
{
// Clear all expired requests
for ( auto it = pBot - > ActiveRequests . begin ( ) ; it ! = pBot - > ActiveRequests . end ( ) ; )
{
if ( gpGlobals - > time - it - > RequestTime > BALANCE_VAR ( kAlertExpireTime ) )
{
it = pBot - > ActiveRequests . erase ( it ) ;
}
else
{
it + + ;
}
}
AvHTeam * TeamRef = pBot - > Player - > GetTeamPointer ( ) ;
AlertListType HealthRequests = TeamRef - > GetAlerts ( COMMANDER_NEXTHEALTH ) ;
AlertListType AmmoRequests = TeamRef - > GetAlerts ( COMMANDER_NEXTAMMO ) ;
AlertListType OrderRequests = TeamRef - > GetAlerts ( COMMANDER_NEXTIDLE ) ;
// Cycle through all active health requests and see if any are new or overriding existing ones
for ( auto it = HealthRequests . begin ( ) ; it ! = HealthRequests . end ( ) ; it + + )
{
edict_t * Requestor = INDEXENT ( it - > GetEntityIndex ( ) ) ;
ai_commander_request * ExistingRequest = AICOMM_GetExistingRequestForPlayer ( pBot , Requestor ) ;
// This is a new request from the player, update our list accordingly
if ( ! ExistingRequest | | ExistingRequest - > RequestTime < it - > GetTime ( ) )
{
ai_commander_request NewRequest ;
ai_commander_request * RequestRef = ( ExistingRequest ) ? ExistingRequest : & NewRequest ;
RequestRef - > bNewRequest = true ;
RequestRef - > bResponded = false ;
RequestRef - > RequestTime = it - > GetTime ( ) ;
RequestRef - > RequestType = COMMANDER_NEXTHEALTH ;
RequestRef - > Requestor = Requestor ;
if ( ! ExistingRequest )
{
pBot - > ActiveRequests . push_back ( NewRequest ) ;
}
}
}
// Do same for ammo requests
for ( auto it = AmmoRequests . begin ( ) ; it ! = AmmoRequests . end ( ) ; it + + )
{
edict_t * Requestor = INDEXENT ( it - > GetEntityIndex ( ) ) ;
ai_commander_request * ExistingRequest = AICOMM_GetExistingRequestForPlayer ( pBot , Requestor ) ;
if ( ! ExistingRequest | | ExistingRequest - > RequestTime < it - > GetTime ( ) )
{
ai_commander_request NewRequest ;
ai_commander_request * RequestRef = ( ExistingRequest ) ? ExistingRequest : & NewRequest ;
RequestRef - > bNewRequest = true ;
RequestRef - > bResponded = false ;
RequestRef - > RequestTime = it - > GetTime ( ) ;
RequestRef - > RequestType = COMMANDER_NEXTAMMO ;
RequestRef - > Requestor = Requestor ;
if ( ! ExistingRequest )
{
pBot - > ActiveRequests . push_back ( NewRequest ) ;
}
}
}
// And for order requests
for ( auto it = OrderRequests . begin ( ) ; it ! = OrderRequests . end ( ) ; it + + )
{
edict_t * Requestor = INDEXENT ( it - > GetEntityIndex ( ) ) ;
ai_commander_request * ExistingRequest = AICOMM_GetExistingRequestForPlayer ( pBot , Requestor ) ;
if ( ! ExistingRequest | | ExistingRequest - > RequestTime < it - > GetTime ( ) )
{
ai_commander_request NewRequest ;
ai_commander_request * RequestRef = ( ExistingRequest ) ? ExistingRequest : & NewRequest ;
RequestRef - > bNewRequest = true ;
RequestRef - > bResponded = false ;
RequestRef - > RequestTime = it - > GetTime ( ) ;
RequestRef - > RequestType = COMMANDER_NEXTIDLE ;
RequestRef - > Requestor = Requestor ;
if ( ! ExistingRequest )
{
pBot - > ActiveRequests . push_back ( NewRequest ) ;
}
}
}
}
bool AICOMM_IsRequestValid ( ai_commander_request * Request )
{
if ( Request - > bResponded ) { return false ; }
// We tried and failed to respond 5 times, give up so we don't block the queue of people needing help
if ( Request - > ResponseAttempts > 5 ) { return false ; }
edict_t * Requestor = Request - > Requestor ;
if ( FNullEnt ( Requestor ) | | ! IsPlayerActiveInGame ( Requestor ) ) { return false ; }
AvHPlayer * PlayerRef = dynamic_cast < AvHPlayer * > ( CBaseEntity : : Instance ( Requestor ) ) ;
if ( ! PlayerRef ) { return false ; }
AvHTeamNumber RequestorTeam = PlayerRef - > GetTeam ( ) ;
switch ( Request - > RequestType )
{
case COMMANDER_NEXTHEALTH :
return Requestor - > v . health < Requestor - > v . max_health ;
case BUILD_SHOTGUN :
return ! PlayerHasWeapon ( PlayerRef , WEAPON_MARINE_SHOTGUN )
& & ! AITAC_ItemExistsInLocation ( Requestor - > v . origin , DEPLOYABLE_ITEM_SHOTGUN , RequestorTeam , AI_REACHABILITY_MARINE , 0.0f , UTIL_MetresToGoldSrcUnits ( 5.0f ) , false ) ;
case BUILD_WELDER :
return ! PlayerHasWeapon ( PlayerRef , WEAPON_MARINE_WELDER )
& & ! AITAC_ItemExistsInLocation ( Requestor - > v . origin , DEPLOYABLE_ITEM_WELDER , RequestorTeam , AI_REACHABILITY_MARINE , 0.0f , UTIL_MetresToGoldSrcUnits ( 5.0f ) , false ) ;
case BUILD_HMG :
return ! PlayerHasWeapon ( PlayerRef , WEAPON_MARINE_HMG )
& & ! AITAC_ItemExistsInLocation ( Requestor - > v . origin , DEPLOYABLE_ITEM_HMG , RequestorTeam , AI_REACHABILITY_MARINE , 0.0f , UTIL_MetresToGoldSrcUnits ( 5.0f ) , false ) ;
2024-04-02 11:14:10 +00:00
case BUILD_HEAVY :
return ! PlayerHasEquipment ( Requestor )
& & ! AITAC_ItemExistsInLocation ( Requestor - > v . origin , DEPLOYABLE_ITEM_HEAVYARMOUR , RequestorTeam , AI_REACHABILITY_MARINE , 0.0f , UTIL_MetresToGoldSrcUnits ( 5.0f ) , false ) ;
case BUILD_JETPACK :
return ! PlayerHasEquipment ( Requestor )
& & ! AITAC_ItemExistsInLocation ( Requestor - > v . origin , DEPLOYABLE_ITEM_JETPACK , RequestorTeam , AI_REACHABILITY_MARINE , 0.0f , UTIL_MetresToGoldSrcUnits ( 5.0f ) , false ) ;
2024-03-21 18:17:18 +00:00
case BUILD_GRENADE_GUN :
return ! PlayerHasWeapon ( PlayerRef , WEAPON_MARINE_GL )
& & ! AITAC_ItemExistsInLocation ( Requestor - > v . origin , DEPLOYABLE_ITEM_GRENADELAUNCHER , RequestorTeam , AI_REACHABILITY_MARINE , 0.0f , UTIL_MetresToGoldSrcUnits ( 5.0f ) , false ) ;
case BUILD_MINES :
return ! PlayerHasWeapon ( PlayerRef , WEAPON_MARINE_MINES )
& & ! AITAC_ItemExistsInLocation ( Requestor - > v . origin , DEPLOYABLE_ITEM_MINES , RequestorTeam , AI_REACHABILITY_MARINE , 0.0f , UTIL_MetresToGoldSrcUnits ( 5.0f ) , false ) ;
case BUILD_CAT :
return ! IsPlayerBuffed ( Requestor )
& & ! AITAC_ItemExistsInLocation ( Requestor - > v . origin , DEPLOYABLE_ITEM_CATALYSTS , RequestorTeam , AI_REACHABILITY_MARINE , 0.0f , UTIL_MetresToGoldSrcUnits ( 5.0f ) , false ) ;
case BUILD_PHASEGATE :
2024-04-12 15:40:50 +00:00
return ! AITAC_IsStructureOfTypeNearLocation ( RequestorTeam , STRUCTURE_MARINE_PHASEGATE , Requestor - > v . origin , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
2024-03-21 18:17:18 +00:00
case BUILD_TURRET_FACTORY :
2024-04-12 15:40:50 +00:00
return ! AITAC_IsStructureOfTypeNearLocation ( RequestorTeam , ( STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY ) , Requestor - > v . origin , UTIL_MetresToGoldSrcUnits ( 15.0f ) ) ;
2024-03-21 18:17:18 +00:00
case BUILD_ARMORY :
2024-04-12 15:40:50 +00:00
return ! AITAC_IsStructureOfTypeNearLocation ( RequestorTeam , ( STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY ) , Requestor - > v . origin , UTIL_MetresToGoldSrcUnits ( 15.0f ) ) ;
2024-04-05 20:34:50 +00:00
case BUILD_COMMANDSTATION :
return ! AITAC_IsStructureOfTypeNearLocation ( RequestorTeam , STRUCTURE_MARINE_COMMCHAIR , Requestor - > v . origin , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
case BUILD_SCAN :
return ! AITAC_ItemExistsInLocation ( Requestor - > v . origin , DEPLOYABLE_ITEM_SCAN , RequestorTeam , AI_REACHABILITY_NONE , 0.0f , UTIL_MetresToGoldSrcUnits ( 5.0f ) , false ) ;
2024-05-25 15:35:50 +00:00
case BUILD_ARMSLAB :
return ! AITAC_IsStructureOfTypeNearLocation ( RequestorTeam , STRUCTURE_MARINE_ARMSLAB , Requestor - > v . origin , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
case BUILD_PROTOTYPE_LAB :
return ! AITAC_IsStructureOfTypeNearLocation ( RequestorTeam , STRUCTURE_MARINE_PROTOTYPELAB , Requestor - > v . origin , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
2024-03-21 18:17:18 +00:00
default :
return true ;
}
return true ;
}
2024-06-12 19:21:55 +00:00
Vector AICOMM_GetNextScanLocation ( AvHAIPlayer * pBot )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
AvHTeamNumber BotTeam = pBot - > Player - > GetTeam ( ) ;
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam ( BotTeam ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
AvHClassType EnemyType = AIMGR_GetTeamType ( EnemyTeam ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
DeployableSearchFilter ObsFilter ;
ObsFilter . DeployableTeam = BotTeam ;
ObsFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
ObsFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ! AITAC_DeployableExistsAtLocation ( ZERO_VECTOR , & ObsFilter ) ) { return ZERO_VECTOR ; }
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
AvHAIBuildableStructure SiegeTurret ;
2024-03-21 18:17:18 +00:00
2024-06-14 16:12:07 +00:00
for ( auto it = pBot - > Bases . begin ( ) ; it ! = pBot - > Bases . end ( ) ; it + + )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
AvHAIMarineBase * ThisBase = & ( * it ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ThisBase - > BaseType ! = MARINE_BASE_SIEGE | | ThisBase - > bRecycleBase ) { continue ; }
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
bool bHasAdvTF = false ;
bool bHasST = false ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
for ( auto structIt = ThisBase - > PlacedStructures . begin ( ) ; structIt ! = ThisBase - > PlacedStructures . end ( ) ; structIt + + )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
AvHAIBuildableStructure StructureRef = AITAC_GetDeployableStructureByEntIndex ( BotTeam , * structIt ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( StructureRef . IsValid ( ) & & StructureRef . IsCompleted ( ) )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
if ( StructureRef . StructureType = = STRUCTURE_MARINE_ADVTURRETFACTORY )
{
bHasAdvTF = true ;
}
else if ( StructureRef . StructureType = = STRUCTURE_MARINE_SIEGETURRET )
{
SiegeTurret = StructureRef ;
bHasST = true ;
}
2024-03-21 18:17:18 +00:00
}
}
2024-06-12 19:21:55 +00:00
if ( bHasAdvTF & & bHasST )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
if ( EnemyType = = AVH_CLASS_TYPE_ALIEN )
2024-03-21 18:17:18 +00:00
{
2024-06-14 16:12:07 +00:00
const AvHAIHiveDefinition * SiegedHive = AITAC_GetActiveHiveNearestLocation ( EnemyTeam , ThisBase - > BaseLocation ) ;
2024-03-21 18:17:18 +00:00
2024-06-14 16:12:07 +00:00
if ( SiegedHive & & vDist2DSq ( SiegedHive - > Location , ThisBase - > BaseLocation ) < sqrf ( BALANCE_VAR ( kSiegeTurretRange ) ) )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
bool bAlreadyScanning = AITAC_ItemExistsInLocation ( SiegedHive - > Location , DEPLOYABLE_ITEM_SCAN , TEAM_IND , AI_REACHABILITY_NONE , 0.0f , UTIL_MetresToGoldSrcUnits ( 10.0f ) , false ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ! bAlreadyScanning )
{
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , SiegedHive - > FloorLocation , UTIL_MetresToGoldSrcUnits ( 3.0f ) ) ;
return ( ! vIsZero ( BuildLocation ) ) ? BuildLocation : SiegedHive - > FloorLocation ;
}
2024-03-21 18:17:18 +00:00
}
}
2024-06-12 19:21:55 +00:00
DeployableSearchFilter EnemyStuffFilter ;
EnemyStuffFilter . DeployableTeam = EnemyTeam ;
EnemyStuffFilter . MaxSearchRadius = BALANCE_VAR ( kSiegeTurretRange ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
AvHAIBuildableStructure NearestEnemyThing = AITAC_FindClosestDeployableToLocation ( SiegeTurret . Location , & EnemyStuffFilter ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( NearestEnemyThing . IsValid ( ) )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
bool bAlreadyScanning = AITAC_ItemExistsInLocation ( NearestEnemyThing . Location , DEPLOYABLE_ITEM_SCAN , TEAM_IND , AI_REACHABILITY_NONE , 0.0f , UTIL_MetresToGoldSrcUnits ( 10.0f ) , false ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ! bAlreadyScanning )
{
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , NearestEnemyThing . Location , UTIL_MetresToGoldSrcUnits ( 3.0f ) ) ;
return ( ! vIsZero ( BuildLocation ) ) ? BuildLocation : NearestEnemyThing . Location ;
}
2024-03-21 18:17:18 +00:00
}
}
}
2024-06-12 19:21:55 +00:00
return ZERO_VECTOR ;
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
bool AICOMM_CheckForNextBuildAction ( AvHAIPlayer * pBot )
{
AvHTeamNumber BotTeam = pBot - > Player - > GetTeam ( ) ;
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam ( BotTeam ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
Vector NextScanLocation = AICOMM_GetNextScanLocation ( pBot ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( NextScanLocation ) )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_DeployItem ( pBot , DEPLOYABLE_ITEM_SCAN , NextScanLocation ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
edict_t * CommChair = AITAC_GetCommChair ( BotTeam ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( FNullEnt ( CommChair ) ) { return false ; }
2024-04-25 18:28:50 +00:00
2024-06-12 19:21:55 +00:00
AvHAIMarineBase * MainBase = nullptr ;
AvHAIMarineBase * SiegeBase = nullptr ;
AvHAIMarineBase * OutpostBase = nullptr ;
AvHAIMarineBase * GuardpostBase = nullptr ;
2024-04-25 18:28:50 +00:00
2024-06-12 19:21:55 +00:00
for ( auto it = pBot - > Bases . begin ( ) ; it ! = pBot - > Bases . end ( ) ; it + + )
2024-04-25 18:28:50 +00:00
{
2024-06-12 19:21:55 +00:00
AvHAIMarineBase * ThisBase = & ( * it ) ;
2024-04-25 18:28:50 +00:00
2024-06-12 19:21:55 +00:00
if ( ! ThisBase - > bCanBeBuiltOut | | ThisBase - > bRecycleBase | | ! ThisBase - > bIsActive | | ThisBase - > NumBuilders = = 0 ) { continue ; }
2024-04-25 18:28:50 +00:00
2024-06-12 19:21:55 +00:00
if ( ThisBase - > BaseType = = MARINE_BASE_MAINBASE )
2024-04-25 18:28:50 +00:00
{
2024-06-12 19:21:55 +00:00
MainBase = ThisBase ;
continue ;
2024-04-25 18:28:50 +00:00
}
2024-06-12 19:21:55 +00:00
if ( ThisBase - > BaseType = = MARINE_BASE_SIEGE )
2024-04-25 18:28:50 +00:00
{
2024-06-12 19:21:55 +00:00
if ( ThisBase - > NumEnemies > ThisBase - > NumBuilders ) { continue ; }
2024-04-25 18:28:50 +00:00
2024-06-12 19:21:55 +00:00
if ( ! ThisBase - > bBaseInitialised )
2024-04-25 18:28:50 +00:00
{
2024-06-12 19:21:55 +00:00
if ( ! AITAC_GetNearestHiddenPlayerInLocation ( BotTeam , ThisBase - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ) { continue ; }
2024-04-25 18:28:50 +00:00
}
2024-06-12 19:21:55 +00:00
// Always favour bases which are started but not established yet
if ( ! SiegeBase | | ( SiegeBase - > bIsBaseEstablished & & ! ThisBase - > bIsBaseEstablished ) )
2024-04-25 18:28:50 +00:00
{
2024-06-12 19:21:55 +00:00
SiegeBase = ThisBase ;
2024-04-25 18:28:50 +00:00
}
}
2024-06-12 19:21:55 +00:00
else if ( ThisBase - > BaseType = = MARINE_BASE_OUTPOST )
2024-04-25 18:28:50 +00:00
{
2024-06-12 19:21:55 +00:00
// Don't build this base out yet if there are enemies in it: helps avoid wasting resources
if ( ThisBase - > NumEnemies > 0 ) { continue ; }
2024-04-25 18:28:50 +00:00
2024-06-12 19:21:55 +00:00
// Always favour bases which are started but not established yet
if ( ! OutpostBase | | ( OutpostBase - > bIsBaseEstablished & & ! ThisBase - > bIsBaseEstablished ) )
{
OutpostBase = ThisBase ;
2024-04-25 18:28:50 +00:00
}
}
2024-06-12 19:21:55 +00:00
else if ( ThisBase - > BaseType = = MARINE_BASE_GUARDPOST )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
// Don't build this base out yet if there are enemies in it: helps avoid wasting resources
if ( ThisBase - > NumEnemies > 0 ) { continue ; }
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
// Always favour bases which are started but not established yet
if ( ! GuardpostBase | | ( GuardpostBase - > bIsBaseEstablished & & ! ThisBase - > bIsBaseEstablished ) )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
GuardpostBase = ThisBase ;
2024-03-21 18:17:18 +00:00
}
}
}
2024-06-19 19:50:30 +00:00
// This is important, make sure we always prioritise critical base infrastructure over everything else
// If we don't have enough resources to drop the critical infrastructure then block the whole commander thought process
// This ensures we aren't placing sentries in Eclipse Command when we don't even have an infantry portal at base
2024-06-14 16:12:07 +00:00
if ( MainBase )
2024-03-21 18:17:18 +00:00
{
2024-06-14 16:12:07 +00:00
bool bMustPrioritise = ! MainBase - > bIsBaseEstablished ;
2024-03-21 18:17:18 +00:00
2024-06-14 16:12:07 +00:00
if ( ! bMustPrioritise )
{
vector < AvHAIBuildableStructure > BaseStructures = AICOMM_GetBaseStructures ( MainBase ) ;
bool bHasArmoury = false ;
2024-06-19 19:50:30 +00:00
bool bHasTF = false ;
bool bHasPG = false ;
2024-06-14 16:12:07 +00:00
int NumSentries = 0 ;
int DesiredInfPortals = ( int ) ceilf ( ( float ) AIMGR_GetNumPlayersOnTeam ( BotTeam ) / 4.0f ) ;
int NumInfantryPortals = 0 ;
for ( auto it = BaseStructures . begin ( ) ; it ! = BaseStructures . end ( ) ; it + + )
{
if ( it - > StructureType = = STRUCTURE_MARINE_INFANTRYPORTAL ) { NumInfantryPortals + + ; }
2024-06-19 19:50:30 +00:00
else if ( it - > StructureType = = STRUCTURE_MARINE_PHASEGATE ) { bHasPG = true ; }
2024-06-14 16:12:07 +00:00
else if ( it - > StructureType & ( STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY ) ) { bHasArmoury = true ; }
else if ( it - > StructureType & ( STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY ) ) { bHasTF = true ; }
else if ( it - > StructureType = = STRUCTURE_MARINE_TURRET ) { NumSentries + + ; }
}
2024-03-21 18:17:18 +00:00
2024-06-19 19:50:30 +00:00
bMustPrioritise = ! bHasArmoury | | ! bHasTF | | NumInfantryPortals < DesiredInfPortals | | NumSentries < 3 | | ( ! bHasPG & & AITAC_ResearchIsComplete ( BotTeam , TECH_RESEARCH_PHASETECH ) ) ;
2024-06-14 16:12:07 +00:00
}
if ( bMustPrioritise )
{
bool bSuccess = AICOMM_BuildOutBase ( pBot , MainBase ) ;
if ( bSuccess ) { return true ; }
// We can't build anything in our base right now, but don't build anything elsewhere unless we have at least 30 resources so we can put down infrastructure when needed
if ( pBot - > Player - > GetResources ( ) < BALANCE_VAR ( kInfantryPortalCost ) * 1.5f ) { return true ; }
}
2024-06-12 19:21:55 +00:00
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
const AvHAIResourceNode * CappableNode = AICOMM_GetNearestResourceNodeCapOpportunity ( BotTeam , CommChair - > v . origin ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( CappableNode )
{
AvHAIBuildableStructure * DeployedStructure = AICOMM_DeployStructure ( pBot , STRUCTURE_MARINE_RESTOWER , CappableNode - > Location ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( DeployedStructure | | pBot - > Player - > GetResources ( ) < = BALANCE_VAR ( kResourceTowerCost ) + 10 ) { return true ; }
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
if ( SiegeBase )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_BuildOutBase ( pBot , SiegeBase ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
if ( OutpostBase )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_BuildOutBase ( pBot , OutpostBase ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
if ( GuardpostBase )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_BuildOutBase ( pBot , GuardpostBase ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( MainBase )
{
bool bSuccess = AICOMM_BuildOutBase ( pBot , MainBase ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
2024-03-21 18:17:18 +00:00
}
int Resources = pBot - > Player - > GetResources ( ) ;
if ( Resources > 100 )
{
2024-06-12 19:21:55 +00:00
DeployableSearchFilter StructureFilter ;
2024-03-21 18:17:18 +00:00
StructureFilter . DeployableTypes = STRUCTURE_MARINE_RESTOWER ;
StructureFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
2024-06-12 19:21:55 +00:00
StructureFilter . ExcludeStatusFlags = ( STRUCTURE_STATUS_RECYCLING | STRUCTURE_STATUS_ELECTRIFIED ) ;
2024-03-21 18:17:18 +00:00
AvHAIBuildableStructure ResTower = AITAC_FindFurthestDeployableFromLocation ( CommChair - > v . origin , & StructureFilter ) ;
if ( ResTower . IsValid ( ) & & AITAC_ElectricalResearchIsAvailable ( ResTower . edict ) )
{
if ( AICOMM_ResearchTech ( pBot , & ResTower , RESEARCH_ELECTRICAL ) )
{
return true ;
}
}
}
return false ;
2024-06-12 19:21:55 +00:00
2024-03-21 18:17:18 +00:00
}
bool AICOMM_CheckForNextSupplyAction ( AvHAIPlayer * pBot )
{
AvHTeamNumber CommanderTeam = pBot - > Player - > GetTeam ( ) ;
// First thing: if our base is damaged and there's nobody able to weld, drop a welder so we don't let the base die
bool bBaseIsDamaged = false ;
DeployableSearchFilter DamagedBaseStructures ;
DamagedBaseStructures . DeployableTypes = ( STRUCTURE_MARINE_COMMCHAIR | STRUCTURE_MARINE_INFANTRYPORTAL ) ;
DamagedBaseStructures . DeployableTeam = CommanderTeam ;
DamagedBaseStructures . ReachabilityTeam = CommanderTeam ;
DamagedBaseStructures . ReachabilityFlags = pBot - > BotNavInfo . NavProfile . ReachabilityFlag ;
DamagedBaseStructures . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
DamagedBaseStructures . IncludeStatusFlags = STRUCTURE_STATUS_DAMAGED ;
DamagedBaseStructures . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
DamagedBaseStructures . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 15.0f ) ;
bBaseIsDamaged = AITAC_DeployableExistsAtLocation ( AITAC_GetCommChairLocation ( CommanderTeam ) , & DamagedBaseStructures ) ;
if ( bBaseIsDamaged )
{
2024-05-30 12:44:46 +00:00
AvHAIDroppedItem NearestWelder = AITAC_FindClosestItemToLocation ( AITAC_GetCommChairLocation ( CommanderTeam ) , DEPLOYABLE_ITEM_WELDER , CommanderTeam , AI_REACHABILITY_MARINE , 0.0f , UTIL_MetresToGoldSrcUnits ( 15.0f ) , false ) ;
2024-03-21 18:17:18 +00:00
bool bPlayerHasWelder = false ;
2024-05-30 12:44:46 +00:00
if ( ! NearestWelder . IsValid ( ) )
2024-03-21 18:17:18 +00:00
{
vector < AvHPlayer * > PlayersAtBase = AITAC_GetAllPlayersOfTeamInArea ( CommanderTeam , AITAC_GetCommChairLocation ( CommanderTeam ) , UTIL_MetresToGoldSrcUnits ( 15.0f ) , false , pBot - > Edict , AVH_USER3_COMMANDER_PLAYER ) ;
for ( auto it = PlayersAtBase . begin ( ) ; it ! = PlayersAtBase . end ( ) ; it + + )
{
AvHPlayer * ThisPlayer = ( * it ) ;
if ( PlayerHasWeapon ( ThisPlayer , WEAPON_MARINE_WELDER ) )
{
bPlayerHasWelder = true ;
}
}
}
2024-05-30 12:44:46 +00:00
if ( ! NearestWelder . IsValid ( ) & & ! bPlayerHasWelder )
2024-03-21 18:17:18 +00:00
{
DeployableSearchFilter ArmouryFilter ;
ArmouryFilter . DeployableTypes = ( STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY ) ;
ArmouryFilter . DeployableTeam = CommanderTeam ;
ArmouryFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
ArmouryFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
AvHAIBuildableStructure NearestArmoury = AITAC_FindClosestDeployableToLocation ( AITAC_GetTeamStartingLocation ( CommanderTeam ) , & ArmouryFilter ) ;
if ( NearestArmoury . IsValid ( ) )
{
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , NearestArmoury . Location , UTIL_MetresToGoldSrcUnits ( 3.0f ) ) ;
bool bSuccess = AICOMM_DeployItem ( pBot , DEPLOYABLE_ITEM_WELDER , DeployLocation ) ;
return bSuccess ;
}
}
}
2024-06-12 19:21:55 +00:00
bool bShouldPrioritiseNodes = AICOMM_ShouldCommanderPrioritiseNodes ( pBot ) ;
if ( bShouldPrioritiseNodes & & pBot - > Player - > GetResources ( ) < 25 ) { return false ; }
2024-03-21 18:17:18 +00:00
// Now work out how many welders we want on the team generally
int NumDesiredWelders = 1 ;
2024-06-12 19:21:55 +00:00
if ( ! bShouldPrioritiseNodes & & pBot - > Player - > GetResources ( ) > = 20 )
2024-03-21 18:17:18 +00:00
{
2024-07-01 14:45:38 +00:00
NumDesiredWelders = ( int ) ceilf ( ( float ) ( AIMGR_GetNumPlayersOnTeam ( CommanderTeam ) - 1 ) * 0.3f ) ;
2024-03-21 18:17:18 +00:00
}
int NumTeamWelders = AITAC_GetNumWeaponsInPlay ( CommanderTeam , WEAPON_MARINE_WELDER ) ;
// Add additional welders to the team if we have hives or resource nodes which can only be reached with a welder
vector < AvHAIResourceNode * > AllNodes = AITAC_GetAllResourceNodes ( ) ;
for ( auto it = AllNodes . begin ( ) ; it ! = AllNodes . end ( ) ; it + + )
{
AvHAIResourceNode * ThisNode = ( * it ) ;
unsigned int TeamReachabilityFlags = ( CommanderTeam = = AIMGR_GetTeamANumber ( ) ) ? ThisNode - > TeamAReachabilityFlags : ThisNode - > TeamBReachabilityFlags ;
if ( ( TeamReachabilityFlags & AI_REACHABILITY_WELDER ) & & ! ( TeamReachabilityFlags & AI_REACHABILITY_MARINE ) )
{
NumDesiredWelders + + ;
break ;
}
}
vector < AvHAIHiveDefinition * > AllHives = AITAC_GetAllHives ( ) ;
for ( auto it = AllHives . begin ( ) ; it ! = AllHives . end ( ) ; it + + )
{
AvHAIHiveDefinition * ThisHive = ( * it ) ;
unsigned int TeamReachabilityFlags = ( CommanderTeam = = AIMGR_GetTeamANumber ( ) ) ? ThisHive - > TeamAReachabilityFlags : ThisHive - > TeamBReachabilityFlags ;
if ( ( TeamReachabilityFlags & AI_REACHABILITY_WELDER ) & & ! ( TeamReachabilityFlags & AI_REACHABILITY_MARINE ) )
{
NumDesiredWelders + + ;
break ;
}
}
2024-07-01 14:45:38 +00:00
NumDesiredWelders = imini ( NumDesiredWelders , ( int ) ( ceilf ( ( float ) ( AIMGR_GetNumPlayersOnTeam ( CommanderTeam ) - 1 ) * 0.5f ) ) ) ;
2024-03-21 18:17:18 +00:00
if ( NumTeamWelders < NumDesiredWelders )
{
DeployableSearchFilter ArmouryFilter ;
ArmouryFilter . DeployableTypes = ( STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY ) ;
ArmouryFilter . DeployableTeam = CommanderTeam ;
ArmouryFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
ArmouryFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
AvHAIBuildableStructure NearestArmoury = AITAC_FindClosestDeployableToLocation ( AITAC_GetTeamStartingLocation ( CommanderTeam ) , & ArmouryFilter ) ;
if ( NearestArmoury . IsValid ( ) )
{
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , NearestArmoury . Location , UTIL_MetresToGoldSrcUnits ( 3.0f ) ) ;
bool bSuccess = AICOMM_DeployItem ( pBot , DEPLOYABLE_ITEM_WELDER , DeployLocation ) ;
return bSuccess ;
}
}
// Don't drop stuff if we badly need resource nodes
2024-07-01 14:45:38 +00:00
if ( AICOMM_ShouldCommanderPrioritiseNodes ( pBot ) & & pBot - > Player - > GetResources ( ) < 30 ) { return false ; }
// Get basic research first
if ( ! AITAC_ResearchIsComplete ( CommanderTeam , TECH_RESEARCH_ARMOR_ONE ) | | ! AITAC_ResearchIsComplete ( CommanderTeam , TECH_RESEARCH_WEAPONS_ONE ) ) { return false ; }
// Likewise, don't spend res if we can get phase tech going!
if ( ! AITAC_ResearchIsComplete ( CommanderTeam , TECH_RESEARCH_PHASETECH ) & & AITAC_MarineResearchIsAvailable ( CommanderTeam , RESEARCH_PHASETECH ) ) { return false ; }
2024-03-21 18:17:18 +00:00
2024-07-01 14:45:38 +00:00
int NumDesiredShotguns = ( int ) ceilf ( ( AIMGR_GetNumPlayersOnTeam ( CommanderTeam ) - 1 ) * 0.33f ) ;
2024-03-21 18:17:18 +00:00
int NumShottysInPlay = AITAC_GetNumWeaponsInPlay ( CommanderTeam , WEAPON_MARINE_SHOTGUN ) ;
if ( NumShottysInPlay < NumDesiredShotguns )
{
DeployableSearchFilter ArmouryFilter ;
ArmouryFilter . DeployableTypes = ( STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY ) ;
ArmouryFilter . DeployableTeam = CommanderTeam ;
ArmouryFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
ArmouryFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
AvHAIBuildableStructure NearestArmoury = AITAC_FindClosestDeployableToLocation ( AITAC_GetTeamStartingLocation ( CommanderTeam ) , & ArmouryFilter ) ;
if ( NearestArmoury . IsValid ( ) )
{
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , NearestArmoury . Location , UTIL_MetresToGoldSrcUnits ( 3.0f ) ) ;
bool bSuccess = AICOMM_DeployItem ( pBot , DEPLOYABLE_ITEM_SHOTGUN , DeployLocation ) ;
return bSuccess ;
}
}
int NumMinesInPlay = AITAC_GetNumWeaponsInPlay ( CommanderTeam , WEAPON_MARINE_MINES ) ;
bool bNeedsMines = false ;
int DesiredMines = 0 ;
DeployableSearchFilter MineFilter ;
MineFilter . DeployableTypes = STRUCTURE_MARINE_DEPLOYEDMINE ;
int NumDeployedMines = AITAC_GetNumDeployablesNearLocation ( ZERO_VECTOR , & MineFilter ) ;
if ( NumMinesInPlay < 2 & & NumDeployedMines < 32 )
{
int UnminedStructures = 0 ;
DeployableSearchFilter MineStructures ;
MineStructures . DeployableTeam = CommanderTeam ;
MineStructures . DeployableTypes = ( STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_INFANTRYPORTAL ) ;
MineStructures . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
MineStructures . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
MineStructures . ReachabilityTeam = CommanderTeam ;
MineStructures . ReachabilityFlags = AI_REACHABILITY_MARINE ;
vector < AvHAIBuildableStructure > MineableStructures = AITAC_FindAllDeployables ( ZERO_VECTOR , & MineStructures ) ;
MineStructures . DeployableTypes = STRUCTURE_MARINE_DEPLOYEDMINE ;
MineStructures . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 3.0f ) ;
for ( auto it = MineableStructures . begin ( ) ; it ! = MineableStructures . end ( ) ; it + + )
{
AvHAIBuildableStructure ThisStructure = ( * it ) ;
int NumMines = AITAC_GetNumDeployablesNearLocation ( ThisStructure . Location , & MineStructures ) ;
if ( NumMines < 2 )
{
UnminedStructures + + ;
}
}
DesiredMines = ( int ) ceilf ( ( float ) UnminedStructures / 2.0f ) ;
DesiredMines = clampi ( DesiredMines , 0 , 2 ) ;
}
if ( NumMinesInPlay < DesiredMines )
{
DeployableSearchFilter ArmouryFilter ;
ArmouryFilter . DeployableTypes = ( STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY ) ;
ArmouryFilter . DeployableTeam = CommanderTeam ;
ArmouryFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
ArmouryFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
AvHAIBuildableStructure NearestArmoury = AITAC_FindClosestDeployableToLocation ( AITAC_GetTeamStartingLocation ( CommanderTeam ) , & ArmouryFilter ) ;
if ( NearestArmoury . IsValid ( ) )
{
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , NearestArmoury . Location , UTIL_MetresToGoldSrcUnits ( 3.0f ) ) ;
bool bSuccess = AICOMM_DeployItem ( pBot , DEPLOYABLE_ITEM_MINES , DeployLocation ) ;
return bSuccess ;
}
}
if ( ! AITAC_ResearchIsComplete ( CommanderTeam , TECH_RESEARCH_HEAVYARMOR ) ) { return false ; }
DeployableSearchFilter StructureFilter ;
StructureFilter . DeployableTypes = STRUCTURE_MARINE_ADVARMOURY ;
StructureFilter . DeployableTeam = CommanderTeam ;
StructureFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
StructureFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
AvHAIBuildableStructure NearestAdvArmoury = AITAC_FindClosestDeployableToLocation ( AITAC_GetTeamStartingLocation ( CommanderTeam ) , & StructureFilter ) ;
StructureFilter . DeployableTypes = STRUCTURE_MARINE_PROTOTYPELAB ;
AvHAIBuildableStructure NearestPrototypeLab = AITAC_FindClosestDeployableToLocation ( AITAC_GetTeamStartingLocation ( CommanderTeam ) , & StructureFilter ) ;
if ( ! NearestAdvArmoury . IsValid ( ) | | ! NearestPrototypeLab . IsValid ( ) ) { return false ; }
2024-05-30 12:44:46 +00:00
AvHAIDroppedItem ExistingHA = AITAC_FindClosestItemToLocation ( NearestPrototypeLab . Location , DEPLOYABLE_ITEM_HEAVYARMOUR , CommanderTeam , AI_REACHABILITY_MARINE , 0.0f , UTIL_MetresToGoldSrcUnits ( 5.0f ) , false ) ;
AvHAIDroppedItem ExistingHMG = AITAC_FindClosestItemToLocation ( NearestAdvArmoury . Location , DEPLOYABLE_ITEM_HMG , CommanderTeam , AI_REACHABILITY_MARINE , 0.0f , UTIL_MetresToGoldSrcUnits ( 5.0f ) , false ) ;
AvHAIDroppedItem ExistingWelder = AITAC_FindClosestItemToLocation ( NearestAdvArmoury . Location , DEPLOYABLE_ITEM_WELDER , CommanderTeam , AI_REACHABILITY_MARINE , 0.0f , UTIL_MetresToGoldSrcUnits ( 5.0f ) , false ) ;
2024-03-21 18:17:18 +00:00
2024-05-30 12:44:46 +00:00
if ( ExistingHA . IsValid ( ) & & ExistingHMG . IsValid ( ) & & ExistingWelder . IsValid ( ) ) { return false ; }
2024-03-21 18:17:18 +00:00
vector < edict_t * > NearbyPlayers = AITAC_GetAllPlayersOfClassInArea ( CommanderTeam , NearestAdvArmoury . Location , UTIL_MetresToGoldSrcUnits ( 10.0f ) , false , pBot - > Edict , AVH_USER3_MARINE_PLAYER ) ;
bool bDropWeapon = false ;
bool bDropWelder = false ;
for ( auto it = NearbyPlayers . begin ( ) ; it ! = NearbyPlayers . end ( ) ; it + + )
{
edict_t * PlayerEdict = ( * it ) ;
AvHPlayer * PlayerRef = dynamic_cast < AvHPlayer * > ( CBaseEntity : : Instance ( PlayerEdict ) ) ;
if ( ! PlayerEdict ) { continue ; }
if ( PlayerHasHeavyArmour ( PlayerEdict ) | | PlayerHasJetpack ( PlayerEdict ) )
{
if ( PlayerHasWeapon ( PlayerRef , WEAPON_MARINE_MG ) | | UTIL_GetPlayerPrimaryWeapon ( PlayerRef ) = = WEAPON_INVALID )
{
bDropWeapon = true ;
}
else
{
if ( ! PlayerHasWeapon ( PlayerRef , WEAPON_MARINE_WELDER ) )
{
bDropWelder = true ;
}
}
}
}
2024-05-30 12:44:46 +00:00
if ( ! ExistingHA . IsValid ( ) & & ! bDropWelder & & ! bDropWeapon )
2024-03-21 18:17:18 +00:00
{
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , NearestPrototypeLab . Location , UTIL_MetresToGoldSrcUnits ( 3.0f ) ) ;
if ( vIsZero ( DeployLocation ) )
{
DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , NearestPrototypeLab . Location , UTIL_MetresToGoldSrcUnits ( 3.0f ) ) ;
}
bool bSuccess = AICOMM_DeployItem ( pBot , DEPLOYABLE_ITEM_HEAVYARMOUR , DeployLocation ) ;
return bSuccess ;
}
2024-05-30 12:44:46 +00:00
if ( bDropWeapon & & ! ExistingHMG . IsValid ( ) )
2024-03-21 18:17:18 +00:00
{
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , NearestAdvArmoury . Location , UTIL_MetresToGoldSrcUnits ( 3.0f ) ) ;
if ( vIsZero ( DeployLocation ) )
{
DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , NearestAdvArmoury . Location , UTIL_MetresToGoldSrcUnits ( 3.0f ) ) ;
}
bool bSuccess = AICOMM_DeployItem ( pBot , DEPLOYABLE_ITEM_HMG , DeployLocation ) ;
return bSuccess ;
}
2024-05-30 12:44:46 +00:00
if ( bDropWelder & & ! ExistingWelder . IsValid ( ) )
2024-03-21 18:17:18 +00:00
{
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , NearestAdvArmoury . Location , UTIL_MetresToGoldSrcUnits ( 3.0f ) ) ;
if ( vIsZero ( DeployLocation ) )
{
DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , NearestAdvArmoury . Location , UTIL_MetresToGoldSrcUnits ( 3.0f ) ) ;
}
bool bSuccess = AICOMM_DeployItem ( pBot , DEPLOYABLE_ITEM_WELDER , DeployLocation ) ;
return bSuccess ;
}
return false ;
}
bool AICOMM_CheckForNextResearchAction ( AvHAIPlayer * pBot )
{
AvHTeamNumber CommanderTeam = pBot - > Player - > GetTeam ( ) ;
vector < AvHAIHiveDefinition * > Hives = AITAC_GetAllHives ( ) ;
for ( auto it = Hives . begin ( ) ; it ! = Hives . end ( ) ; it + + )
{
AvHAIHiveDefinition * Hive = ( * it ) ;
if ( Hive - > Status ! = HIVE_STATUS_UNBUILT ) { continue ; }
DeployableSearchFilter TFFilter ;
TFFilter . DeployableTeam = pBot - > Player - > GetTeam ( ) ;
TFFilter . DeployableTypes = STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY ;
TFFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
TFFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING | STRUCTURE_STATUS_ELECTRIFIED ;
TFFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 15.0f ) ;
AvHAIBuildableStructure NearestTF = AITAC_FindClosestDeployableToLocation ( Hive - > FloorLocation , & TFFilter ) ;
if ( NearestTF . IsValid ( ) )
{
TFFilter . DeployableTypes = STRUCTURE_MARINE_TURRET ;
TFFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 5.0f ) ;
int NumTurrets = AITAC_GetNumDeployablesNearLocation ( NearestTF . Location , & TFFilter ) ;
if ( NumTurrets > 0 )
{
if ( AICOMM_ResearchTech ( pBot , & NearestTF , RESEARCH_ELECTRICAL ) )
{
return true ;
}
}
}
if ( pBot - > Player - > GetResources ( ) > 60 )
{
if ( Hive - > HiveResNodeRef & & Hive - > HiveResNodeRef - > OwningTeam = = pBot - > Player - > GetTeam ( ) )
{
edict_t * Tower = Hive - > HiveResNodeRef - > ActiveTowerEntity ;
if ( ! FNullEnt ( Tower ) & & UTIL_StructureIsFullyBuilt ( Tower ) & & ! UTIL_IsStructureElectrified ( Tower ) )
{
AvHAIBuildableStructure ResTower = AITAC_GetDeployableFromEdict ( Tower ) ;
if ( ResTower . IsValid ( ) & & AICOMM_ResearchTech ( pBot , & ResTower , RESEARCH_ELECTRICAL ) )
{
return true ;
}
}
}
}
}
DeployableSearchFilter StructureFilter ;
StructureFilter . DeployableTeam = CommanderTeam ;
StructureFilter . ReachabilityTeam = CommanderTeam ;
StructureFilter . ReachabilityFlags = AI_REACHABILITY_MARINE ;
StructureFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
if ( AITAC_MarineResearchIsAvailable ( CommanderTeam , RESEARCH_GRENADES ) )
{
StructureFilter . DeployableTypes = STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY ;
StructureFilter . ExcludeStatusFlags | = STRUCTURE_STATUS_RESEARCHING ;
AvHAIBuildableStructure Armoury = AITAC_FindClosestDeployableToLocation ( AITAC_GetTeamStartingLocation ( CommanderTeam ) , & StructureFilter ) ;
if ( Armoury . IsValid ( ) )
{
2024-06-19 19:50:30 +00:00
bool bSuccess = AICOMM_ResearchTech ( pBot , & Armoury , RESEARCH_GRENADES ) ;
if ( bSuccess ) { return true ; }
return pBot - > Player - > GetResources ( ) < ( BALANCE_VAR ( kGrenadesResearchCost ) * 1.5f ) ;
2024-03-21 18:17:18 +00:00
}
}
StructureFilter . DeployableTypes = STRUCTURE_MARINE_ARMSLAB ;
StructureFilter . ExcludeStatusFlags | = STRUCTURE_STATUS_RESEARCHING ;
AvHAIBuildableStructure ArmsLab = AITAC_FindClosestDeployableToLocation ( AITAC_GetTeamStartingLocation ( CommanderTeam ) , & StructureFilter ) ;
if ( AITAC_MarineResearchIsAvailable ( CommanderTeam , RESEARCH_ARMOR_ONE ) )
{
if ( ArmsLab . IsValid ( ) )
{
2024-06-19 19:50:30 +00:00
bool bSuccess = AICOMM_ResearchTech ( pBot , & ArmsLab , RESEARCH_ARMOR_ONE ) ;
if ( bSuccess ) { return true ; }
return pBot - > Player - > GetResources ( ) < ( BALANCE_VAR ( kArmorOneResearchCost ) * 1.5f ) ;
2024-03-21 18:17:18 +00:00
}
}
if ( AITAC_MarineResearchIsAvailable ( CommanderTeam , RESEARCH_WEAPONS_ONE ) )
{
if ( ArmsLab . IsValid ( ) )
{
2024-06-19 19:50:30 +00:00
bool bSuccess = AICOMM_ResearchTech ( pBot , & ArmsLab , RESEARCH_WEAPONS_ONE ) ;
if ( bSuccess ) { return true ; }
return pBot - > Player - > GetResources ( ) < ( BALANCE_VAR ( kWeaponsOneResearchCost ) * 1.5f ) ;
2024-03-21 18:17:18 +00:00
}
}
StructureFilter . DeployableTypes = STRUCTURE_MARINE_OBSERVATORY ;
StructureFilter . ExcludeStatusFlags | = STRUCTURE_STATUS_RESEARCHING ;
AvHAIBuildableStructure Observatory = AITAC_FindClosestDeployableToLocation ( AITAC_GetTeamStartingLocation ( CommanderTeam ) , & StructureFilter ) ;
if ( AITAC_MarineResearchIsAvailable ( CommanderTeam , RESEARCH_PHASETECH ) )
{
if ( Observatory . IsValid ( ) )
{
2024-06-19 19:50:30 +00:00
bool bSuccess = AICOMM_ResearchTech ( pBot , & Observatory , RESEARCH_PHASETECH ) ;
if ( bSuccess ) { return true ; }
return pBot - > Player - > GetResources ( ) < ( BALANCE_VAR ( kPhaseTechResearchCost ) * 1.5f ) ;
2024-03-21 18:17:18 +00:00
}
}
if ( AITAC_MarineResearchIsAvailable ( CommanderTeam , RESEARCH_MOTIONTRACK ) )
{
if ( Observatory . IsValid ( ) )
{
return AICOMM_ResearchTech ( pBot , & Observatory , RESEARCH_MOTIONTRACK ) ;
}
}
if ( AITAC_MarineResearchIsAvailable ( CommanderTeam , RESEARCH_ARMOR_TWO ) )
{
if ( ArmsLab . IsValid ( ) )
{
return AICOMM_ResearchTech ( pBot , & ArmsLab , RESEARCH_ARMOR_TWO ) ;
}
}
if ( AITAC_MarineResearchIsAvailable ( CommanderTeam , RESEARCH_WEAPONS_TWO ) )
{
if ( ArmsLab . IsValid ( ) )
{
return AICOMM_ResearchTech ( pBot , & ArmsLab , RESEARCH_WEAPONS_TWO ) ;
}
}
if ( AITAC_MarineResearchIsAvailable ( CommanderTeam , RESEARCH_CATALYSTS ) )
{
if ( ArmsLab . IsValid ( ) )
{
return AICOMM_ResearchTech ( pBot , & ArmsLab , RESEARCH_CATALYSTS ) ;
}
}
StructureFilter . DeployableTypes = STRUCTURE_MARINE_PROTOTYPELAB ;
StructureFilter . ExcludeStatusFlags | = STRUCTURE_STATUS_RESEARCHING ;
AvHAIBuildableStructure ProtoLab = AITAC_FindClosestDeployableToLocation ( AITAC_GetTeamStartingLocation ( CommanderTeam ) , & StructureFilter ) ;
if ( AITAC_MarineResearchIsAvailable ( CommanderTeam , RESEARCH_HEAVYARMOR ) )
{
if ( ProtoLab . IsValid ( ) )
{
return AICOMM_ResearchTech ( pBot , & ProtoLab , RESEARCH_HEAVYARMOR ) ;
}
}
if ( AITAC_MarineResearchIsAvailable ( CommanderTeam , RESEARCH_JETPACKS ) )
{
if ( ProtoLab . IsValid ( ) )
{
return AICOMM_ResearchTech ( pBot , & ProtoLab , RESEARCH_JETPACKS ) ;
}
}
if ( AITAC_MarineResearchIsAvailable ( CommanderTeam , RESEARCH_ARMOR_THREE ) )
{
if ( ArmsLab . IsValid ( ) )
{
return AICOMM_ResearchTech ( pBot , & ArmsLab , RESEARCH_ARMOR_THREE ) ;
}
}
if ( AITAC_MarineResearchIsAvailable ( CommanderTeam , RESEARCH_WEAPONS_THREE ) )
{
if ( ArmsLab . IsValid ( ) )
{
return AICOMM_ResearchTech ( pBot , & ArmsLab , RESEARCH_WEAPONS_THREE ) ;
}
}
return false ;
}
const AvHAIHiveDefinition * AICOMM_GetHiveSiegeOpportunityNearestLocation ( AvHAIPlayer * CommanderBot , const Vector SearchLocation )
{
AvHTeamNumber CommanderTeam = CommanderBot - > Player - > GetTeam ( ) ;
bool bPhaseGatesAvailable = AITAC_PhaseGatesAvailable ( CommanderTeam ) ;
// Only siege if we have phase gates available
if ( ! bPhaseGatesAvailable ) { return nullptr ; }
const AvHAIHiveDefinition * Result = nullptr ;
float MinDist = 0.0f ;
const vector < AvHAIHiveDefinition * > Hives = AITAC_GetAllHives ( ) ;
for ( auto it = Hives . begin ( ) ; it ! = Hives . end ( ) ; it + + )
{
const AvHAIHiveDefinition * Hive = ( * it ) ;
if ( Hive - > Status = = HIVE_STATUS_UNBUILT ) { continue ; }
DeployableSearchFilter StructureFilter ;
StructureFilter . DeployableTypes = STRUCTURE_MARINE_PHASEGATE ;
StructureFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 20.0f ) ;
StructureFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
StructureFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
AvHAIBuildableStructure BuiltPhaseGate = AITAC_FindClosestDeployableToLocation ( Hive - > Location , & StructureFilter ) ;
// If we have a phase gate already in place, then keep building as long as someone is there. If we don't have a phase gate, only build if there is a marine who isn't sighted by the enemy (to allow element of surprise)
if ( BuiltPhaseGate . IsValid ( ) )
{
int NumBuilders = AITAC_GetNumPlayersOfTeamInArea ( CommanderTeam , BuiltPhaseGate . Location , UTIL_MetresToGoldSrcUnits ( 5.0f ) , false , CommanderBot - > Edict , AVH_USER3_COMMANDER_PLAYER ) ;
if ( NumBuilders = = 0 ) { continue ; }
}
else
{
if ( AITAC_GetMarineEligibleToBuildSiege ( CommanderTeam , Hive ) = = nullptr ) { continue ; }
}
float ThisDist = vDist2DSq ( Hive - > FloorLocation , SearchLocation ) ;
if ( ! Result | | ThisDist < MinDist )
{
Result = Hive ;
MinDist = ThisDist ;
}
}
return Result ;
}
const AvHAIResourceNode * AICOMM_GetNearestResourceNodeCapOpportunity ( const AvHTeamNumber Team , const Vector SearchLocation )
{
vector < AvHAIResourceNode * > AllNodes = AITAC_GetAllResourceNodes ( ) ;
AvHAIResourceNode * Result = nullptr ;
float MinDist = 0.0f ;
for ( auto it = AllNodes . begin ( ) ; it ! = AllNodes . end ( ) ; it + + )
{
AvHAIResourceNode * ResNode = ( * it ) ;
if ( ResNode - > bIsOccupied ) { continue ; }
if ( ! AITAC_AnyPlayerOnTeamWithLOS ( Team , ( ResNode - > Location + Vector ( 0.0f , 0.0f , 32.0f ) ) , UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ) { continue ; }
if ( AITAC_AnyPlayerOnTeamWithLOS ( AIMGR_GetEnemyTeam ( Team ) , ( ResNode - > Location + Vector ( 0.0f , 0.0f , 32.0f ) ) , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ) { continue ; }
float ThisDist = vDist2DSq ( ResNode - > Location , SearchLocation ) ;
if ( ! Result | | ThisDist < MinDist )
{
Result = ResNode ;
MinDist = ThisDist ;
}
}
return Result ;
}
bool AICOMM_CheckForNextRecycleAction ( AvHAIPlayer * pBot )
{
2024-06-12 19:21:55 +00:00
for ( auto it = pBot - > Bases . begin ( ) ; it ! = pBot - > Bases . end ( ) ; it + + )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
AvHAIMarineBase * ThisBase = & ( * it ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ThisBase - > bRecycleBase )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
for ( auto structIt = ThisBase - > PlacedStructures . begin ( ) ; structIt ! = ThisBase - > PlacedStructures . end ( ) ; structIt + + )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
AvHAIBuildableStructure ThisStructure = AITAC_GetDeployableStructureByEntIndex ( pBot - > Player - > GetTeam ( ) , ( * structIt ) ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ThisStructure . IsValid ( ) & & ! ( ThisStructure . StructureStatusFlags & STRUCTURE_STATUS_RECYCLING ) )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_RecycleStructure ( pBot , & ThisStructure ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
2024-03-21 18:17:18 +00:00
}
}
}
2024-06-14 16:12:07 +00:00
else if ( ThisBase - > BaseType ! = MARINE_BASE_MAINBASE )
{
for ( auto structIt = ThisBase - > PlacedStructures . begin ( ) ; structIt ! = ThisBase - > PlacedStructures . end ( ) ; structIt + + )
{
AvHAIBuildableStructure ThisStructure = AITAC_GetDeployableStructureByEntIndex ( pBot - > Player - > GetTeam ( ) , ( * structIt ) ) ;
if ( ThisStructure . IsValid ( ) & & ! ( ThisStructure . StructureStatusFlags & STRUCTURE_STATUS_RECYCLING ) )
{
// Don't allow any infantry portals to be scattered elsewhere outside the base
if ( ThisStructure . StructureType = = STRUCTURE_MARINE_INFANTRYPORTAL )
{
bool bSuccess = AICOMM_RecycleStructure ( pBot , & ThisStructure ) ;
if ( bSuccess ) { return true ; }
}
}
}
}
2024-03-21 18:17:18 +00:00
}
return false ;
}
bool AICOMM_CheckForNextSupportAction ( AvHAIPlayer * pBot )
{
AvHTeamNumber CommanderTeam = pBot - > Player - > GetTeam ( ) ;
AICOMM_CheckNewRequests ( pBot ) ;
ai_commander_request * NextRequest = nullptr ;
float OldestTime = 0.0f ;
// Find the oldest request we haven't fulfilled yet
for ( auto it = pBot - > ActiveRequests . begin ( ) ; it ! = pBot - > ActiveRequests . end ( ) ; it + + )
{
// Ignore if we've already responded, or the request is too new (leave a nice 1 second response time to requests)
if ( it - > bResponded | | ( gpGlobals - > time - it - > RequestTime ) < 1.0f ) { continue ; }
// Ignore the request if it's not valid (e.g. request for health while not injured)
if ( ! AICOMM_IsRequestValid ( & ( * it ) ) )
{
it - > bResponded = true ;
continue ;
}
float ThisTime = gpGlobals - > time - it - > RequestTime ;
if ( ThisTime > OldestTime )
{
NextRequest = & ( * it ) ;
OldestTime = ThisTime ;
}
}
// We didn't find any unresponded requests outstanding
if ( ! NextRequest ) { return false ; }
edict_t * Requestor = NextRequest - > Requestor ;
if ( FNullEnt ( Requestor ) | | ! IsEdictPlayer ( Requestor ) | | ! IsPlayerActiveInGame ( Requestor ) )
{
NextRequest - > bResponded = true ;
return false ;
}
int NumDesiredHealthPacks = 0 ;
int NumDesiredAmmoPacks = 0 ;
float RequestorHealthDeficit = Requestor - > v . max_health - Requestor - > v . health ;
float HealthPerPack = BALANCE_VAR ( kPointsPerHealth ) ;
if ( RequestorHealthDeficit > 10.0f )
{
NumDesiredHealthPacks = ( int ) ceilf ( RequestorHealthDeficit / HealthPerPack ) ;
int NumHealthPacksPresent = AITAC_GetNumItemsInLocation ( Requestor - > v . origin , DEPLOYABLE_ITEM_HEALTHPACK , ( AvHTeamNumber ) Requestor - > v . team , AI_REACHABILITY_MARINE , 0.0f , UTIL_MetresToGoldSrcUnits ( 5.0f ) , false ) ;
NumDesiredHealthPacks - = NumHealthPacksPresent ;
}
if ( NumDesiredHealthPacks > 0 )
{
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , Requestor - > v . origin , UTIL_MetresToGoldSrcUnits ( 2.0f ) ) ;
bool bSuccess = AICOMM_DeployItem ( pBot , DEPLOYABLE_ITEM_HEALTHPACK , DeployLocation ) ;
if ( bSuccess )
{
if ( NextRequest - > RequestType = = COMMANDER_NEXTHEALTH & & NumDesiredHealthPacks < = 1 )
{
NextRequest - > bResponded = true ;
}
}
else
{
NextRequest - > ResponseAttempts + + ;
}
return true ;
}
else
{
if ( NextRequest - > RequestType = = COMMANDER_NEXTHEALTH )
{
NextRequest - > bResponded = true ;
return false ;
}
}
if ( NextRequest - > RequestType = = COMMANDER_NEXTAMMO )
{
AvHPlayer * thePlayer = dynamic_cast < AvHPlayer * > ( CBaseEntity : : Instance ( Requestor ) ) ;
bool bFillPrimaryWeapon = true ;
AvHAIWeapon WeaponType = UTIL_GetPlayerPrimaryWeapon ( thePlayer ) ;
// Requesting player doesn't have a primary weapon, check if they have a pistol
if ( WeaponType = = WEAPON_INVALID )
{
bFillPrimaryWeapon = false ;
WeaponType = UTIL_GetPlayerSecondaryWeapon ( thePlayer ) ;
}
// They've only got a knife, don't bother dropping ammo
if ( WeaponType = = WEAPON_INVALID )
{
NextRequest - > bResponded = true ;
return false ;
}
int AmmoDeficit = ( bFillPrimaryWeapon ) ? ( UTIL_GetPlayerPrimaryMaxAmmoReserve ( thePlayer ) - UTIL_GetPlayerPrimaryAmmoReserve ( thePlayer ) ) : ( UTIL_GetPlayerSecondaryMaxAmmoReserve ( thePlayer ) - UTIL_GetPlayerSecondaryAmmoReserve ( thePlayer ) ) ;
int WeaponClipSize = ( bFillPrimaryWeapon ) ? UTIL_GetPlayerPrimaryWeaponMaxClipSize ( thePlayer ) : UTIL_GetPlayerSecondaryWeaponMaxClipSize ( thePlayer ) ;
// Player already has full ammo, they're yanking our chain
if ( AmmoDeficit = = 0 )
{
NextRequest - > bResponded = true ;
return false ;
}
int DesiredNumAmmoPacks = ( int ) ( ceilf ( ( float ) AmmoDeficit / ( float ) WeaponClipSize ) ) ;
// Don't drop more than 5 at any one time
DesiredNumAmmoPacks = clampi ( DesiredNumAmmoPacks , 0 , 5 ) ;
int NumAmmoPacksPresent = AITAC_GetNumItemsInLocation ( Requestor - > v . origin , DEPLOYABLE_ITEM_AMMO , ( AvHTeamNumber ) Requestor - > v . team , AI_REACHABILITY_MARINE , 0.0f , UTIL_MetresToGoldSrcUnits ( 5.0f ) , false ) ;
DesiredNumAmmoPacks - = NumAmmoPacksPresent ;
// Do we need to drop any ammo, or has the player got enough surrounding them already?
if ( DesiredNumAmmoPacks > 0 )
{
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , Requestor - > v . origin , UTIL_MetresToGoldSrcUnits ( 2.0f ) ) ;
bool bSuccess = AICOMM_DeployItem ( pBot , DEPLOYABLE_ITEM_AMMO , DeployLocation ) ;
if ( bSuccess )
{
// We've dropped enough that the player has enough to fill their boots. Mission accomplished
if ( DesiredNumAmmoPacks < = 1 )
{
NextRequest - > bResponded = true ;
}
}
else
{
NextRequest - > ResponseAttempts + + ;
}
return true ;
}
else
{
// Player already has enough ammo packs deployed by them to satisfy. Don't drop any more
NextRequest - > bResponded = true ;
}
return false ;
}
if ( NextRequest - > RequestType = = COMMANDER_NEXTIDLE )
{
// TODO: Have the commander prioritise this player when looking for people to give orders to
NextRequest - > bResponded = true ;
}
if ( NextRequest - > RequestType = = BUILD_CAT )
{
if ( ! AITAC_ResearchIsComplete ( CommanderTeam , TECH_RESEARCH_CATALYSTS ) )
{
char msg [ 128 ] ;
sprintf ( msg , " We haven't researched catalysts yet, %s. Ask again later. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
if ( ! AITAC_IsCompletedStructureOfTypeNearLocation ( CommanderTeam , ( STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY ) , ZERO_VECTOR , 0.0f ) )
{
char msg [ 128 ] ;
sprintf ( msg , " Don't have an armory anymore, %s. We need to build one. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , Requestor - > v . origin , UTIL_MetresToGoldSrcUnits ( 2.0f ) ) ;
bool bSuccess = AICOMM_DeployItem ( pBot , DEPLOYABLE_ITEM_CATALYSTS , DeployLocation ) ;
if ( bSuccess )
{
NextRequest - > bResponded = true ;
}
else
{
NextRequest - > ResponseAttempts + + ;
}
return true ;
}
if ( NextRequest - > RequestType = = BUILD_WELDER | | NextRequest - > RequestType = = BUILD_SHOTGUN | | NextRequest - > RequestType = = BUILD_MINES )
{
AvHAIDeployableItemType ItemToDrop = DEPLOYABLE_ITEM_NONE ;
float Cost = 0.0f ;
switch ( NextRequest - > RequestType )
{
case BUILD_WELDER :
ItemToDrop = DEPLOYABLE_ITEM_WELDER ;
Cost = BALANCE_VAR ( kWelderCost ) ;
break ;
case BUILD_SHOTGUN :
ItemToDrop = DEPLOYABLE_ITEM_SHOTGUN ;
Cost = BALANCE_VAR ( kShotgunCost ) ;
break ;
case BUILD_MINES :
ItemToDrop = DEPLOYABLE_ITEM_MINES ;
Cost = BALANCE_VAR ( kMineCost ) ;
break ;
default :
ItemToDrop = DEPLOYABLE_ITEM_WELDER ;
Cost = BALANCE_VAR ( kWelderCost ) ;
break ;
}
DeployableSearchFilter ArmouryFilter ;
ArmouryFilter . DeployableTeam = CommanderTeam ;
ArmouryFilter . DeployableTypes = ( STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY ) ;
ArmouryFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
ArmouryFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
ArmouryFilter . MaxSearchRadius = BALANCE_VAR ( kArmoryBuildDistance ) ;
AvHAIBuildableStructure NearestArmoury = AITAC_FindClosestDeployableToLocation ( Requestor - > v . origin , & ArmouryFilter ) ;
if ( ! NearestArmoury . IsValid ( ) )
{
if ( ! NextRequest - > bAcknowledged )
{
char msg [ 128 ] ;
sprintf ( msg , " Get to an working armory %s, and ask again. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bAcknowledged = true ;
}
return false ;
}
if ( pBot - > Player - > GetResources ( ) < Cost )
{
if ( ! NextRequest - > bAcknowledged )
{
char msg [ 128 ] ;
sprintf ( msg , " Wait for resources %s, I'll drop it soon. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bAcknowledged = true ;
}
return false ;
}
Vector IdealDeployLocation = Requestor - > v . origin + ( UTIL_GetForwardVector2D ( Requestor - > v . angles ) * 75.0f ) ;
Vector ProjectedDeployLocation = AdjustPointForPathfinding ( IdealDeployLocation ) ;
if ( vDist2DSq ( ProjectedDeployLocation , NearestArmoury . Location ) < BALANCE_VAR ( kArmoryBuildDistance ) )
{
bool bSuccess = AICOMM_DeployItem ( pBot , ItemToDrop , ProjectedDeployLocation ) ;
if ( bSuccess )
{
NextRequest - > bResponded = bSuccess ;
return true ;
}
}
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , NearestArmoury . Location , UTIL_MetresToGoldSrcUnits ( 4.0f ) ) ;
if ( vIsZero ( DeployLocation ) )
{
DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , NearestArmoury . Location , UTIL_MetresToGoldSrcUnits ( 4.0f ) ) ;
}
if ( vIsZero ( DeployLocation ) )
{
char msg [ 128 ] ;
sprintf ( msg , " I can't find a drop location, %s. Try asking again elsewhere. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
bool bSuccess = AICOMM_DeployItem ( pBot , ItemToDrop , DeployLocation ) ;
NextRequest - > ResponseAttempts + + ;
NextRequest - > bResponded = bSuccess ;
return true ;
}
2024-04-02 11:14:10 +00:00
if ( NextRequest - > RequestType = = BUILD_HEAVY | | NextRequest - > RequestType = = BUILD_JETPACK )
{
AvHAIDeployableItemType ItemToDrop = ( NextRequest - > RequestType = = BUILD_HEAVY ) ? DEPLOYABLE_ITEM_HEAVYARMOUR : DEPLOYABLE_ITEM_JETPACK ;
float Cost = ( NextRequest - > RequestType = = BUILD_HEAVY ) ? BALANCE_VAR ( kHeavyArmorCost ) : BALANCE_VAR ( kJetpackCost ) ;
AvHTechID TechNeeded = ( NextRequest - > RequestType = = BUILD_HEAVY ) ? TECH_RESEARCH_HEAVYARMOR : TECH_RESEARCH_JETPACKS ;
if ( ! AITAC_ResearchIsComplete ( CommanderTeam , TechNeeded ) )
{
char msg [ 128 ] ;
sprintf ( msg , " We haven't researched it yet, %s. Ask again later. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
DeployableSearchFilter PrototypeLabFilter ;
PrototypeLabFilter . DeployableTeam = CommanderTeam ;
PrototypeLabFilter . DeployableTypes = STRUCTURE_MARINE_PROTOTYPELAB ;
PrototypeLabFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
PrototypeLabFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
AvHAIBuildableStructure NearestPL = AITAC_FindClosestDeployableToLocation ( Requestor - > v . origin , & PrototypeLabFilter ) ;
if ( ! NearestPL . IsValid ( ) )
{
char msg [ 128 ] ;
sprintf ( msg , " We don't have a prototype lab %s, ask again later. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
if ( vDist2DSq ( Requestor - > v . origin , NearestPL . Location ) > sqrf ( BALANCE_VAR ( kArmoryBuildDistance ) ) )
{
if ( ! NextRequest - > bAcknowledged )
{
char msg [ 128 ] ;
sprintf ( msg , " Get near the prototype lab %s, and I will drop it for you. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bAcknowledged = true ;
}
return false ;
}
Vector IdealDeployLocation = Requestor - > v . origin + ( UTIL_GetForwardVector2D ( Requestor - > v . angles ) * 75.0f ) ;
Vector ProjectedDeployLocation = AdjustPointForPathfinding ( IdealDeployLocation ) ;
if ( vDist2DSq ( ProjectedDeployLocation , NearestPL . Location ) < BALANCE_VAR ( kArmoryBuildDistance ) )
{
bool bSuccess = AICOMM_DeployItem ( pBot , ItemToDrop , ProjectedDeployLocation ) ;
if ( bSuccess )
{
NextRequest - > bResponded = bSuccess ;
return true ;
}
}
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , NearestPL . Location , UTIL_MetresToGoldSrcUnits ( 4.0f ) ) ;
if ( vIsZero ( DeployLocation ) )
{
DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , NearestPL . Location , UTIL_MetresToGoldSrcUnits ( 4.0f ) ) ;
}
if ( vIsZero ( DeployLocation ) )
{
char msg [ 128 ] ;
sprintf ( msg , " I can't find a drop location, %s. Try asking again elsewhere. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
bool bSuccess = AICOMM_DeployItem ( pBot , ItemToDrop , DeployLocation ) ;
NextRequest - > ResponseAttempts + + ;
NextRequest - > bResponded = bSuccess ;
return true ;
}
2024-03-21 18:17:18 +00:00
if ( NextRequest - > RequestType = = BUILD_HMG | | NextRequest - > RequestType = = BUILD_GRENADE_GUN )
{
AvHAIDeployableItemType ItemToDrop = ( NextRequest - > RequestType = = BUILD_HMG ) ? DEPLOYABLE_ITEM_HMG : DEPLOYABLE_ITEM_GRENADELAUNCHER ;
float Cost = ( NextRequest - > RequestType = = BUILD_HMG ) ? BALANCE_VAR ( kHMGCost ) : BALANCE_VAR ( kGrenadeLauncherCost ) ;
DeployableSearchFilter ArmouryFilter ;
ArmouryFilter . DeployableTeam = CommanderTeam ;
ArmouryFilter . DeployableTypes = STRUCTURE_MARINE_ADVARMOURY ;
ArmouryFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
ArmouryFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
AvHAIBuildableStructure NearestArmoury = AITAC_FindClosestDeployableToLocation ( Requestor - > v . origin , & ArmouryFilter ) ;
if ( ! NearestArmoury . IsValid ( ) )
{
char msg [ 128 ] ;
sprintf ( msg , " We don't have an adv armory yet %s, ask again later. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
if ( vDist2DSq ( Requestor - > v . origin , NearestArmoury . Location ) > sqrf ( BALANCE_VAR ( kArmoryBuildDistance ) ) )
{
if ( ! NextRequest - > bAcknowledged )
{
char msg [ 128 ] ;
sprintf ( msg , " Get near the adv armory %s, and I will drop it for you. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bAcknowledged = true ;
}
return false ;
}
if ( pBot - > Player - > GetResources ( ) < Cost )
{
if ( ! NextRequest - > bAcknowledged )
{
char msg [ 128 ] ;
sprintf ( msg , " Wait for resources %s, will drop asap. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bAcknowledged = true ;
}
return false ;
}
Vector IdealDeployLocation = Requestor - > v . origin + ( UTIL_GetForwardVector2D ( Requestor - > v . angles ) * 75.0f ) ;
Vector ProjectedDeployLocation = AdjustPointForPathfinding ( IdealDeployLocation ) ;
if ( vDist2DSq ( ProjectedDeployLocation , NearestArmoury . Location ) < BALANCE_VAR ( kArmoryBuildDistance ) )
{
bool bSuccess = AICOMM_DeployItem ( pBot , ItemToDrop , ProjectedDeployLocation ) ;
if ( bSuccess )
{
NextRequest - > bResponded = bSuccess ;
return true ;
}
}
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , NearestArmoury . Location , UTIL_MetresToGoldSrcUnits ( 4.0f ) ) ;
if ( vIsZero ( DeployLocation ) )
{
DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , NearestArmoury . Location , UTIL_MetresToGoldSrcUnits ( 4.0f ) ) ;
}
if ( vIsZero ( DeployLocation ) )
{
char msg [ 128 ] ;
sprintf ( msg , " I can't find a drop location, %s. Try asking again elsewhere. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
bool bSuccess = AICOMM_DeployItem ( pBot , ItemToDrop , DeployLocation ) ;
NextRequest - > ResponseAttempts + + ;
NextRequest - > bResponded = bSuccess ;
return true ;
}
2024-04-05 20:34:50 +00:00
if ( NextRequest - > RequestType = = BUILD_SCAN )
{
DeployableSearchFilter ObsFilter ;
ObsFilter . DeployableTeam = CommanderTeam ;
ObsFilter . DeployableTypes = STRUCTURE_MARINE_OBSERVATORY ;
ObsFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
ObsFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
AvHAIBuildableStructure NearestObservatory = AITAC_FindClosestDeployableToLocation ( Requestor - > v . origin , & ObsFilter ) ;
if ( ! NearestObservatory . IsValid ( ) )
{
char msg [ 128 ] ;
sprintf ( msg , " We don't have an observatory yet %s, ask again later. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
Vector IdealDeployLocation = Requestor - > v . origin + ( UTIL_GetForwardVector2D ( Requestor - > v . angles ) * 75.0f ) ;
Vector ProjectedDeployLocation = AdjustPointForPathfinding ( IdealDeployLocation , GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) ) ;
if ( ! vIsZero ( ProjectedDeployLocation ) )
{
2024-04-06 16:04:30 +00:00
bool bSuccess = AICOMM_DeployItem ( pBot , DEPLOYABLE_ITEM_SCAN , ProjectedDeployLocation ) ;
2024-04-05 20:34:50 +00:00
if ( bSuccess )
{
NextRequest - > bResponded = true ;
return true ;
}
}
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , Requestor - > v . origin , UTIL_MetresToGoldSrcUnits ( 1.0f ) ) ;
if ( ! vIsZero ( DeployLocation ) )
{
2024-04-06 16:04:30 +00:00
bool bSuccess = AICOMM_DeployItem ( pBot , DEPLOYABLE_ITEM_SCAN , DeployLocation ) ;
2024-04-05 20:34:50 +00:00
if ( bSuccess )
{
NextRequest - > bResponded = true ;
return true ;
}
}
DeployLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , Requestor - > v . origin , UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ;
if ( ! vIsZero ( DeployLocation ) )
{
bool bSuccess = AICOMM_DeployItem ( pBot , DEPLOYABLE_ITEM_SCAN , DeployLocation ) ;
if ( bSuccess )
{
NextRequest - > bResponded = true ;
return true ;
}
else
{
char msg [ 128 ] ;
sprintf ( msg , " I can't find a good scan spot, %s. Try again elsewhere. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
}
else
{
char msg [ 128 ] ;
sprintf ( msg , " I can't find a good scan spot, %s. Try again elsewhere. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
return false ;
}
2024-04-12 15:40:50 +00:00
if ( NextRequest - > RequestType = = BUILD_PHASEGATE & & ! AITAC_ResearchIsComplete ( CommanderTeam , TECH_RESEARCH_PHASETECH ) )
{
char msg [ 128 ] ;
sprintf ( msg , " We haven't got phase tech yet, %s. Ask again later. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
2024-03-21 18:17:18 +00:00
2024-05-25 15:35:50 +00:00
if ( NextRequest - > RequestType = = BUILD_OBSERVATORY | | NextRequest - > RequestType = = BUILD_ARMSLAB )
2024-04-12 15:40:50 +00:00
{
DeployableSearchFilter ArmouryFilter ;
ArmouryFilter . DeployableTeam = CommanderTeam ;
ArmouryFilter . DeployableTypes = ( STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY ) ;
ArmouryFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
ArmouryFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
2024-03-21 18:17:18 +00:00
2024-04-12 15:40:50 +00:00
bool bHasArmoury = AITAC_DeployableExistsAtLocation ( ZERO_VECTOR , & ArmouryFilter ) ;
2024-03-21 18:17:18 +00:00
2024-04-12 15:40:50 +00:00
if ( ! bHasArmoury )
2024-03-21 18:17:18 +00:00
{
char msg [ 128 ] ;
2024-04-12 15:40:50 +00:00
sprintf ( msg , " We haven't got an armory yet, %s. Ask again later. " , STRING ( Requestor - > v . netname ) ) ;
2024-03-21 18:17:18 +00:00
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
}
2024-05-25 15:35:50 +00:00
if ( NextRequest - > RequestType = = BUILD_PROTOTYPE_LAB )
{
DeployableSearchFilter RequiredFilter ;
RequiredFilter . DeployableTeam = CommanderTeam ;
RequiredFilter . DeployableTypes = STRUCTURE_MARINE_ADVARMOURY ;
RequiredFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
RequiredFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
bool bHasArmoury = AITAC_DeployableExistsAtLocation ( ZERO_VECTOR , & RequiredFilter ) ;
if ( ! bHasArmoury )
{
char msg [ 128 ] ;
sprintf ( msg , " We haven't got an advanced armory yet, %s. Ask again later. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
RequiredFilter . DeployableTypes = STRUCTURE_MARINE_ARMSLAB ;
bool bHasArmsLab = AITAC_DeployableExistsAtLocation ( ZERO_VECTOR , & RequiredFilter ) ;
if ( ! bHasArmsLab )
{
char msg [ 128 ] ;
sprintf ( msg , " We haven't got an arms lab yet, %s. Ask again later. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
}
2024-04-02 11:14:10 +00:00
2024-04-12 15:40:50 +00:00
float RequiredRes = 0.0f ;
AvHAIDeployableStructureType StructureToDeploy = STRUCTURE_NONE ;
2024-04-02 11:14:10 +00:00
2024-04-12 15:40:50 +00:00
switch ( NextRequest - > RequestType )
{
case BUILD_ARMORY :
RequiredRes = BALANCE_VAR ( kArmoryCost ) ;
StructureToDeploy = STRUCTURE_MARINE_ARMOURY ;
break ;
case BUILD_COMMANDSTATION :
RequiredRes = BALANCE_VAR ( kCommandStationCost ) ;
StructureToDeploy = STRUCTURE_MARINE_COMMCHAIR ;
break ;
case BUILD_OBSERVATORY :
RequiredRes = BALANCE_VAR ( kObservatoryCost ) ;
StructureToDeploy = STRUCTURE_MARINE_OBSERVATORY ;
break ;
case BUILD_TURRET_FACTORY :
RequiredRes = BALANCE_VAR ( kTurretFactoryCost ) ;
StructureToDeploy = STRUCTURE_MARINE_TURRETFACTORY ;
2024-04-14 19:50:26 +00:00
break ;
2024-04-12 15:40:50 +00:00
case BUILD_TURRET :
RequiredRes = BALANCE_VAR ( kSentryCost ) ;
StructureToDeploy = STRUCTURE_MARINE_TURRET ;
2024-04-14 19:50:26 +00:00
break ;
2024-04-12 15:40:50 +00:00
case BUILD_PHASEGATE :
RequiredRes = BALANCE_VAR ( kPhaseGateCost ) ;
StructureToDeploy = STRUCTURE_MARINE_PHASEGATE ;
2024-04-14 19:50:26 +00:00
break ;
2024-05-25 15:35:50 +00:00
case BUILD_INFANTRYPORTAL :
RequiredRes = BALANCE_VAR ( kInfantryPortalCost ) ;
StructureToDeploy = STRUCTURE_MARINE_INFANTRYPORTAL ;
break ;
case BUILD_PROTOTYPE_LAB :
RequiredRes = BALANCE_VAR ( kPrototypeLabCost ) ;
StructureToDeploy = STRUCTURE_MARINE_PROTOTYPELAB ;
break ;
case BUILD_ARMSLAB :
RequiredRes = BALANCE_VAR ( kArmsLabCost ) ;
StructureToDeploy = STRUCTURE_MARINE_ARMSLAB ;
break ;
2024-04-12 15:40:50 +00:00
default :
break ;
}
2024-04-02 11:14:10 +00:00
2024-04-12 15:40:50 +00:00
// Invalid commander request
if ( StructureToDeploy = = STRUCTURE_NONE )
{
NextRequest - > bResponded = true ;
return false ;
}
2024-04-02 11:14:10 +00:00
2024-04-12 15:40:50 +00:00
if ( pBot - > Player - > GetResources ( ) < RequiredRes )
{
if ( ! NextRequest - > bAcknowledged )
2024-04-02 11:14:10 +00:00
{
char msg [ 128 ] ;
2024-04-12 15:40:50 +00:00
sprintf ( msg , " Just waiting on resources, %s. Will drop asap. " , STRING ( Requestor - > v . netname ) ) ;
2024-04-02 11:14:10 +00:00
BotSay ( pBot , true , 0.5f , msg ) ;
2024-04-12 15:40:50 +00:00
NextRequest - > bAcknowledged = true ;
2024-04-02 11:14:10 +00:00
return false ;
}
return false ;
}
2024-05-25 15:35:50 +00:00
float ProjectDistance = ( NextRequest - > RequestType = = BUILD_INFANTRYPORTAL | | NextRequest - > RequestType = = BUILD_SIEGE ) ? 32.0f : 75.0f ;
Vector IdealDeployLocation = Requestor - > v . origin + ( UTIL_GetForwardVector2D ( Requestor - > v . angles ) * ProjectDistance ) ;
2024-04-12 15:40:50 +00:00
Vector ProjectedDeployLocation = AdjustPointForPathfinding ( IdealDeployLocation , GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) ) ;
2024-03-21 18:17:18 +00:00
2024-06-25 16:36:13 +00:00
AvHAIMarineBase * BaseToDeployIn = nullptr ;
float MinDist = 0.0f ;
for ( auto it = pBot - > Bases . begin ( ) ; it ! = pBot - > Bases . end ( ) ; it + + )
{
float DistFromBase = vDist2DSq ( Requestor - > v . origin , it - > BaseLocation ) ;
if ( it - > BaseType = = MARINE_BASE_MAINBASE & & DistFromBase < sqrf ( UTIL_MetresToGoldSrcUnits ( 20.0f ) ) )
{
BaseToDeployIn = & ( * it ) ;
break ;
}
float DesiredDist = ( it - > BaseType = = MARINE_BASE_GUARDPOST ) ? BALANCE_VAR ( kTurretFactoryBuildDistance ) : UTIL_MetresToGoldSrcUnits ( 15.0f ) ;
if ( DistFromBase < sqrf ( DesiredDist ) )
{
if ( ! BaseToDeployIn | | DistFromBase < MinDist )
{
BaseToDeployIn = & ( * it ) ;
MinDist = DistFromBase ;
}
}
}
// We've requested a building away from any existing bases the commander is building
if ( ! BaseToDeployIn & & ( NextRequest - > RequestType = = BUILD_PHASEGATE | | NextRequest - > RequestType = = BUILD_TURRET_FACTORY ) )
{
const AvHAIHiveDefinition * NearestHive = AITAC_GetHiveNearestLocation ( Requestor - > v . origin ) ;
float DesiredDistance = ( NearestHive - > Status ! = HIVE_STATUS_UNBUILT ) ? sqrf ( BALANCE_VAR ( kSiegeTurretRange ) ) : sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
float DistFromHive = vDist2DSq ( NearestHive - > Location , Requestor - > v . origin ) ;
if ( NearestHive & & DistFromHive < DesiredDistance )
{
AvHAIMarineBase * ExistingBase = nullptr ;
for ( auto it = pBot - > Bases . begin ( ) ; it ! = pBot - > Bases . end ( ) ; it + + )
{
if ( ! it - > bIsActive | | ! it - > bRecycleBase ) { continue ; }
if ( NearestHive - > Status ! = HIVE_STATUS_UNBUILT )
{
if ( it - > BaseType = = MARINE_BASE_SIEGE & & vEquals2D ( it - > SiegeTarget , NearestHive - > Location ) )
{
if ( ! it - > bBaseInitialised )
{
BaseToDeployIn = & ( * it ) ;
BaseToDeployIn - > BaseLocation = Requestor - > v . origin ;
break ;
}
}
}
else
{
if ( it - > BaseType = = MARINE_BASE_OUTPOST & & vDist2DSq ( it - > BaseLocation , NearestHive - > FloorLocation ) < UTIL_MetresToGoldSrcUnits ( 15.0f ) )
{
if ( ! it - > bBaseInitialised )
{
BaseToDeployIn = & ( * it ) ;
break ;
}
}
}
}
if ( ! BaseToDeployIn & & NearestHive )
{
MarineBaseType NewBaseType = ( NearestHive - > Status ! = HIVE_STATUS_UNBUILT ) ? MARINE_BASE_SIEGE : MARINE_BASE_OUTPOST ;
BaseToDeployIn = AICOMM_AddNewBase ( pBot , Requestor - > v . origin , NewBaseType ) ;
}
}
else
{
BaseToDeployIn = AICOMM_AddNewBase ( pBot , Requestor - > v . origin , MARINE_BASE_GUARDPOST ) ;
}
}
2024-04-12 15:40:50 +00:00
if ( ! vIsZero ( ProjectedDeployLocation ) )
{
2024-05-25 15:35:50 +00:00
if ( NextRequest - > RequestType = = BUILD_INFANTRYPORTAL )
{
DeployableSearchFilter CCFilter ;
CCFilter . DeployableTeam = CommanderTeam ;
CCFilter . DeployableTypes = STRUCTURE_MARINE_COMMCHAIR ;
CCFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
CCFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
CCFilter . MaxSearchRadius = BALANCE_VAR ( kCommandStationBuildDistance ) ;
bool bHasChair = AITAC_DeployableExistsAtLocation ( ProjectedDeployLocation , & CCFilter ) ;
if ( ! bHasChair )
{
char msg [ 128 ] ;
sprintf ( msg , " There isn't a comm chair there, %s. Ask again next to the CC " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
}
2024-06-24 13:23:45 +00:00
if ( NextRequest - > RequestType = = BUILD_SIEGE | | NextRequest - > RequestType = = BUILD_TURRET )
2024-05-25 15:35:50 +00:00
{
DeployableSearchFilter TFFilter ;
TFFilter . DeployableTeam = CommanderTeam ;
2024-06-24 13:23:45 +00:00
TFFilter . DeployableTypes = ( NextRequest - > RequestType = = BUILD_SIEGE ) ? STRUCTURE_MARINE_ADVTURRETFACTORY : STRUCTURE_MARINE_TURRETFACTORY ;
2024-05-25 15:35:50 +00:00
TFFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
TFFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
TFFilter . MaxSearchRadius = BALANCE_VAR ( kTurretFactoryBuildDistance ) ;
2024-06-24 13:23:45 +00:00
bool bHasTF = AITAC_DeployableExistsAtLocation ( ProjectedDeployLocation , & TFFilter ) ;
2024-05-25 15:35:50 +00:00
2024-06-24 13:23:45 +00:00
if ( ! bHasTF )
2024-05-25 15:35:50 +00:00
{
char msg [ 128 ] ;
2024-06-24 13:23:45 +00:00
if ( NextRequest - > RequestType = = BUILD_SIEGE )
{
sprintf ( msg , " There isn't an advanced turret factory in range, %s. Ask again near one " , STRING ( Requestor - > v . netname ) ) ;
}
else
{
sprintf ( msg , " There isn't a completed turret factory in range, %s. Ask again near one " , STRING ( Requestor - > v . netname ) ) ;
}
2024-05-25 15:35:50 +00:00
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
}
2024-06-25 16:36:13 +00:00
bool bSuccess = false ;
2024-03-21 18:17:18 +00:00
2024-06-25 16:36:13 +00:00
if ( BaseToDeployIn )
{
bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , ProjectedDeployLocation , BaseToDeployIn ) ;
}
else
{
AvHAIBuildableStructure * DeployedStructure = AICOMM_DeployStructure ( pBot , StructureToDeploy , ProjectedDeployLocation , STRUCTURE_PURPOSE_GENERAL , true ) ;
bSuccess = DeployedStructure ! = nullptr ;
}
if ( bSuccess )
2024-03-21 18:17:18 +00:00
{
NextRequest - > bResponded = true ;
2024-04-12 15:40:50 +00:00
return true ;
2024-03-21 18:17:18 +00:00
}
}
2024-04-12 15:40:50 +00:00
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , Requestor - > v . origin , UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ;
2024-03-21 18:17:18 +00:00
2024-04-12 15:40:50 +00:00
if ( ! vIsZero ( DeployLocation ) )
{
2024-06-25 16:36:13 +00:00
bool bSuccess = false ;
2024-03-21 18:17:18 +00:00
2024-06-25 16:36:13 +00:00
if ( BaseToDeployIn )
{
bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , DeployLocation , BaseToDeployIn ) ;
}
else
{
AvHAIBuildableStructure * DeployedStructure = AICOMM_DeployStructure ( pBot , StructureToDeploy , DeployLocation , STRUCTURE_PURPOSE_GENERAL , true ) ;
bSuccess = DeployedStructure ! = nullptr ;
}
if ( bSuccess )
2024-03-21 18:17:18 +00:00
{
2024-04-12 15:40:50 +00:00
NextRequest - > bResponded = true ;
return true ;
2024-03-21 18:17:18 +00:00
}
2024-04-12 15:40:50 +00:00
}
2024-03-21 18:17:18 +00:00
2024-04-12 15:40:50 +00:00
DeployLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , Requestor - > v . origin , UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ;
2024-03-21 18:17:18 +00:00
2024-04-12 15:40:50 +00:00
if ( ! vIsZero ( DeployLocation ) )
{
2024-06-25 16:36:13 +00:00
bool bSuccess = false ;
if ( BaseToDeployIn )
{
bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , DeployLocation , BaseToDeployIn ) ;
}
else
{
AvHAIBuildableStructure * DeployedStructure = AICOMM_DeployStructure ( pBot , StructureToDeploy , DeployLocation , STRUCTURE_PURPOSE_GENERAL , true ) ;
2024-03-21 18:17:18 +00:00
2024-06-25 16:36:13 +00:00
bSuccess = DeployedStructure ! = nullptr ;
}
if ( bSuccess )
2024-03-21 18:17:18 +00:00
{
2024-04-12 15:40:50 +00:00
NextRequest - > bResponded = true ;
return true ;
2024-03-21 18:17:18 +00:00
}
else
{
char msg [ 128 ] ;
sprintf ( msg , " I can't find a good deploy spot, %s. Try again elsewhere. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
return false ;
}
2024-04-12 15:40:50 +00:00
}
else
{
char msg [ 128 ] ;
sprintf ( msg , " I can't find a good deploy spot, %s. Try again elsewhere. " , STRING ( Requestor - > v . netname ) ) ;
BotSay ( pBot , true , 0.5f , msg ) ;
NextRequest - > bResponded = true ;
2024-03-21 18:17:18 +00:00
return false ;
}
return false ;
}
2024-06-12 19:21:55 +00:00
void AICOMM_PopulateBaseList ( AvHAIPlayer * pBot )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
pBot - > Bases . clear ( ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
AvHTeamNumber BotTeam = pBot - > Player - > GetTeam ( ) ;
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam ( BotTeam ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
// First, figure out where our main base is. Might not be the chair we're in!
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
edict_t * ActiveCommChair = AITAC_GetCommChair ( BotTeam ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
// Shouldn't happen, but might as well double-check
if ( FNullEnt ( ActiveCommChair ) ) { return ; }
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
edict_t * WinningCommChair = nullptr ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
Vector BaseLocation = ActiveCommChair - > v . origin ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
DeployableSearchFilter CommChairsFilter ;
CommChairsFilter . DeployableTeam = BotTeam ;
CommChairsFilter . DeployableTypes = STRUCTURE_MARINE_COMMCHAIR ;
CommChairsFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
vector < AvHAIBuildableStructure > AllCommChairs = AITAC_FindAllDeployables ( ZERO_VECTOR , & CommChairsFilter ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
int MaxInfPortals = 0 ;
// Basically, find all comm chairs in the map, and whichever one has the most infantry portals around it, that's the base
for ( auto it = AllCommChairs . begin ( ) ; it ! = AllCommChairs . end ( ) ; it + + )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
DeployableSearchFilter InfPortalFilter ;
InfPortalFilter . DeployableTeam = BotTeam ;
InfPortalFilter . DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL ;
InfPortalFilter . MaxSearchRadius = BALANCE_VAR ( kCommandStationBuildDistance ) ;
int ThisNumInfPortals = AITAC_GetNumDeployablesNearLocation ( it - > Location , & InfPortalFilter ) ;
if ( ThisNumInfPortals > MaxInfPortals )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
WinningCommChair = it - > edict ;
MaxInfPortals = ThisNumInfPortals ;
2024-03-21 18:17:18 +00:00
}
}
2024-06-12 19:21:55 +00:00
// None of the comm chairs have any infantry portals, therefore the chair we're in is (for now) where our base will be
if ( FNullEnt ( WinningCommChair ) )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
WinningCommChair = ActiveCommChair ;
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
// Add an entry for the base now
AvHAIMarineBase * MainBase = AICOMM_AddNewBase ( pBot , WinningCommChair - > v . origin , MARINE_BASE_MAINBASE ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ! MainBase ) { return ; }
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
// Get all structures and start adding them to our base
DeployableSearchFilter AllStructuresFilter ;
AllStructuresFilter . DeployableTeam = BotTeam ;
AllStructuresFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
AllStructuresFilter . DeployableTypes = ( SEARCH_ALL_STRUCTURES & ~ ( STRUCTURE_MARINE_RESTOWER ) ) ; // Don't include resource towers in this list
vector < AvHAIBuildableStructure > AllTeamStructures = AITAC_FindAllDeployables ( ZERO_VECTOR , & AllStructuresFilter ) ;
for ( auto it = AllTeamStructures . begin ( ) ; it ! = AllTeamStructures . end ( ) ; )
{
AvHAIBuildableStructure ThisStructure = ( * it ) ;
// Obviously make sure the comm chair is part of the base
if ( ThisStructure . edict = = WinningCommChair )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
MainBase - > PlacedStructures . push_back ( ThisStructure . EntIndex ) ;
it = AllTeamStructures . erase ( it ) ;
continue ;
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
// All structures within a 15m radius of the comm chair can be considered part of the main base
if ( vDist2DSq ( ThisStructure . Location , MainBase - > BaseLocation ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 15.0f ) ) )
{
MainBase - > PlacedStructures . push_back ( ThisStructure . EntIndex ) ;
it = AllTeamStructures . erase ( it ) ;
continue ;
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
it + + ;
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
// Get all remaining phase gates not in the main base
vector < AvHAIBuildableStructure > AllPhaseGates ;
for ( auto it = AllTeamStructures . begin ( ) ; it ! = AllTeamStructures . end ( ) ; )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
AvHAIBuildableStructure ThisStructure = ( * it ) ;
if ( ThisStructure . StructureType = = STRUCTURE_MARINE_PHASEGATE )
{
AllPhaseGates . push_back ( ThisStructure ) ;
it = AllTeamStructures . erase ( it ) ;
}
else
{
it + + ;
}
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
for ( auto it = AllPhaseGates . begin ( ) ; it ! = AllPhaseGates . end ( ) ; it + + )
{
AvHAIBuildableStructure ThisPG = ( * it ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
AvHAIMarineBase * NewOutpost = AICOMM_AddNewBase ( pBot , ThisPG . Location , MARINE_BASE_OUTPOST ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ! NewOutpost ) { continue ; }
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
NewOutpost - > PlacedStructures . push_back ( ThisPG . EntIndex ) ;
bool bHasSiegeTurrets = false ;
for ( auto allStructIt = AllTeamStructures . begin ( ) ; allStructIt ! = AllTeamStructures . end ( ) ; )
{
AvHAIBuildableStructure ThisStructure = ( * allStructIt ) ;
// All structures within a 10m radius of the phase gate can be considered part of the outpost or siege base
if ( vDist2DSq ( ThisStructure . Location , NewOutpost - > BaseLocation ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) )
{
NewOutpost - > PlacedStructures . push_back ( ThisStructure . EntIndex ) ;
if ( ThisStructure . StructureType = = STRUCTURE_MARINE_SIEGETURRET )
{
bHasSiegeTurrets = true ;
}
// Remove these structures from the list
allStructIt = AllTeamStructures . erase ( allStructIt ) ;
continue ;
}
allStructIt + + ;
}
// Determine if the new outpost should be a siege base or not. Bot will assume it's a siege base if:
// It has siege turrets (obviously)
// It is in siege range of a hive which is either owned by an enemy alien team, or has been colonised by an enemy marine team
if ( bHasSiegeTurrets )
{
NewOutpost - > BaseType = MARINE_BASE_SIEGE ;
}
else
{
const AvHAIHiveDefinition * NearestHive = AITAC_GetHiveNearestLocation ( ThisPG . Location ) ;
if ( NearestHive & & vDist2DSq ( NearestHive - > Location , ThisPG . Location ) < = sqrf ( UTIL_MetresToGoldSrcUnits ( 25.0f ) ) )
{
if ( AIMGR_GetTeamType ( EnemyTeam ) = = AVH_CLASS_TYPE_ALIEN )
{
if ( NearestHive - > Status ! = HIVE_STATUS_UNBUILT )
{
NewOutpost - > BaseType = MARINE_BASE_SIEGE ;
}
}
else
{
DeployableSearchFilter EnemyStuffFilter ;
EnemyStuffFilter . DeployableTeam = EnemyTeam ;
EnemyStuffFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
EnemyStuffFilter . DeployableTypes = ( STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY ) ;
EnemyStuffFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 10.0f ) ;
if ( AITAC_GetNumDeployablesNearLocation ( NearestHive - > FloorLocation , & EnemyStuffFilter ) > 0 )
{
NewOutpost - > BaseType = MARINE_BASE_SIEGE ;
}
}
}
}
}
// All that is left now in AllTeamStructures are any structures not yet considered part of the main base, an outpost or siege base
// Get all turret factories left
vector < AvHAIBuildableStructure > AllRemainingTFs ;
for ( auto it = AllTeamStructures . begin ( ) ; it ! = AllTeamStructures . end ( ) ; )
{
AvHAIBuildableStructure ThisStructure = ( * it ) ;
if ( ThisStructure . StructureType & ( STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY ) )
{
AllRemainingTFs . push_back ( ThisStructure ) ;
it = AllTeamStructures . erase ( it ) ;
}
else
{
it + + ;
}
}
//Loop through all the turret factories. These will either be guard posts, or siege bases without a phase gate
for ( auto it = AllRemainingTFs . begin ( ) ; it ! = AllRemainingTFs . end ( ) ; it + + )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
AvHAIBuildableStructure ThisTF = ( * it ) ;
2024-06-14 16:12:07 +00:00
MarineBaseType NewBaseType = MARINE_BASE_GUARDPOST ;
if ( vDist2DSq ( ThisTF . Location , AITAC_GetTeamOriginalStartLocation ( BotTeam ) ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) )
{
NewBaseType = MARINE_BASE_OUTPOST ;
}
AvHAIMarineBase * NewOutpost = AICOMM_AddNewBase ( pBot , ThisTF . Location , NewBaseType ) ;
2024-06-12 19:21:55 +00:00
if ( ! NewOutpost ) { continue ; }
NewOutpost - > PlacedStructures . push_back ( ThisTF . EntIndex ) ;
bool bHasSiegeTurrets = false ;
for ( auto allStructIt = AllTeamStructures . begin ( ) ; allStructIt ! = AllTeamStructures . end ( ) ; )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
AvHAIBuildableStructure ThisStructure = ( * allStructIt ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
// All structures within a 10m radius of the phase gate can be considered part of the outpost or siege base
if ( vDist2DSq ( ThisStructure . Location , NewOutpost - > BaseLocation ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
NewOutpost - > PlacedStructures . push_back ( ThisStructure . EntIndex ) ;
2024-05-28 21:58:37 +00:00
2024-06-12 19:21:55 +00:00
if ( ThisStructure . StructureType = = STRUCTURE_MARINE_SIEGETURRET )
2024-05-28 21:58:37 +00:00
{
2024-06-12 19:21:55 +00:00
bHasSiegeTurrets = true ;
2024-05-28 21:58:37 +00:00
}
2024-06-12 19:21:55 +00:00
// Remove these structures from the list
allStructIt = AllTeamStructures . erase ( allStructIt ) ;
continue ;
}
allStructIt + + ;
}
if ( ThisTF . StructureType = = STRUCTURE_MARINE_ADVTURRETFACTORY )
{
if ( bHasSiegeTurrets )
{
NewOutpost - > BaseType = MARINE_BASE_SIEGE ;
}
else
{
const AvHAIHiveDefinition * NearestHive = AITAC_GetHiveNearestLocation ( ThisTF . Location ) ;
2024-05-22 15:21:40 +00:00
2024-06-14 16:12:07 +00:00
float DistToHive = vDist2DSq ( NearestHive - > Location , ThisTF . Location ) ;
if ( NearestHive & & DistToHive < = sqrf ( UTIL_MetresToGoldSrcUnits ( 25.0f ) ) )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
if ( AIMGR_GetTeamType ( EnemyTeam ) = = AVH_CLASS_TYPE_ALIEN )
{
2024-06-14 16:12:07 +00:00
// Player was sieging a hive
2024-06-12 19:21:55 +00:00
if ( NearestHive - > Status ! = HIVE_STATUS_UNBUILT )
{
NewOutpost - > BaseType = MARINE_BASE_SIEGE ;
}
2024-06-14 16:12:07 +00:00
else
{
// This is an outpost in an empty hive
if ( DistToHive < = sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) )
{
NewOutpost - > BaseType = MARINE_BASE_OUTPOST ;
}
}
2024-06-12 19:21:55 +00:00
}
else
2024-05-23 19:17:46 +00:00
{
2024-06-12 19:21:55 +00:00
DeployableSearchFilter EnemyStuffFilter ;
EnemyStuffFilter . DeployableTeam = EnemyTeam ;
EnemyStuffFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
EnemyStuffFilter . DeployableTypes = ( STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY ) ;
EnemyStuffFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 10.0f ) ;
2024-06-14 16:12:07 +00:00
// Player was sieging a bunch of stuff
2024-06-12 19:21:55 +00:00
if ( AITAC_GetNumDeployablesNearLocation ( NearestHive - > FloorLocation , & EnemyStuffFilter ) > 0 )
{
NewOutpost - > BaseType = MARINE_BASE_SIEGE ;
}
2024-05-23 19:17:46 +00:00
}
2024-05-22 15:21:40 +00:00
}
}
}
2024-06-12 19:21:55 +00:00
}
}
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
void AICOMM_CommanderThink ( AvHAIPlayer * pBot )
{
if ( IsPlayerCommander ( pBot - > Edict ) )
{
if ( AICOMM_ShouldBeacon ( pBot ) )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
return ;
}
}
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
// Thanks to EterniumDev (Alien) for the suggestion to have the commander jump out and build if nobody is around to help
if ( AICOMM_ShouldCommanderLeaveChair ( pBot ) )
{
if ( IsPlayerCommander ( pBot - > Edict ) )
{
BotStopCommanderMode ( pBot ) ;
2024-05-22 15:21:40 +00:00
return ;
}
2024-06-12 19:21:55 +00:00
DeployableSearchFilter StructureFilter ;
StructureFilter . DeployableTypes = SEARCH_ALL_STRUCTURES ;
StructureFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 20.0f ) ;
StructureFilter . DeployableTeam = pBot - > Player - > GetTeam ( ) ;
StructureFilter . ReachabilityFlags = AI_REACHABILITY_MARINE ;
StructureFilter . ReachabilityTeam = pBot - > Player - > GetTeam ( ) ;
StructureFilter . ExcludeStatusFlags = STRUCTURE_STATUS_COMPLETED | STRUCTURE_STATUS_RECYCLING ;
AvHAIBuildableStructure NearestUnbuiltStructure = AITAC_FindClosestDeployableToLocation ( AITAC_GetCommChairLocation ( pBot - > Player - > GetTeam ( ) ) , & StructureFilter ) ;
if ( NearestUnbuiltStructure . IsValid ( ) )
{
AITASK_SetBuildTask ( pBot , & pBot - > PrimaryBotTask , NearestUnbuiltStructure . edict , false ) ;
}
BotProgressTask ( pBot , & pBot - > PrimaryBotTask ) ;
return ;
}
if ( ! IsPlayerCommander ( pBot - > Edict ) )
{
BotProgressTakeCommandTask ( pBot ) ;
return ;
}
if ( gpGlobals - > time < pBot - > next_commander_action_time ) { return ; }
if ( pBot - > Bases . size ( ) = = 0 )
{
AICOMM_PopulateBaseList ( pBot ) ;
2024-05-22 15:21:40 +00:00
}
2024-06-12 19:21:55 +00:00
AICOMM_ManageActiveBases ( pBot ) ;
AICOMM_DeployBases ( pBot ) ;
AICOMM_UpdatePlayerOrders ( pBot ) ;
if ( AICOMM_CheckForNextSupportAction ( pBot ) ) { return ; }
2024-05-22 15:21:40 +00:00
if ( AICOMM_CheckForNextRecycleAction ( pBot ) ) { return ; }
2024-03-21 18:17:18 +00:00
if ( AICOMM_CheckForNextBuildAction ( pBot ) ) { return ; }
if ( AICOMM_CheckForNextResearchAction ( pBot ) ) { return ; }
if ( AICOMM_CheckForNextSupplyAction ( pBot ) ) { return ; }
}
2024-06-12 19:21:55 +00:00
bool AICOMM_IsMarineBaseValid ( AvHAIMarineBase * Base )
2024-05-23 19:17:46 +00:00
{
2024-06-12 19:21:55 +00:00
if ( Base - > PlacedStructures . size ( ) > 0 ) { return true ; }
2024-05-23 19:17:46 +00:00
2024-06-12 19:21:55 +00:00
if ( ! Base - > bBaseInitialised & & ! Base - > bIsActive ) { return false ; }
2024-05-23 19:17:46 +00:00
2024-06-12 19:21:55 +00:00
if ( ( Base - > bRecycleBase | | Base - > bBaseInitialised ) & & Base - > PlacedStructures . size ( ) = = 0 ) { return false ; }
2024-05-23 19:17:46 +00:00
2024-06-12 19:21:55 +00:00
return true ;
2024-05-23 19:17:46 +00:00
}
2024-06-12 19:21:55 +00:00
void AICOMM_UpdateBaseStatus ( AvHAIPlayer * pBot , AvHAIMarineBase * Base )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
if ( ! pBot | | ! Base ) { return ; }
AvHTeamNumber BotTeam = pBot - > Player - > GetTeam ( ) ;
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam ( BotTeam ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
// TODO: Add check if base is doomed
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
float BuildRadius = UTIL_MetresToGoldSrcUnits ( 10.0f ) ;
float EnemyRadius = UTIL_MetresToGoldSrcUnits ( 10.0f ) ;
switch ( Base - > BaseType )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
case MARINE_BASE_SIEGE :
AICOMM_UpdateSiegeBaseStatus ( pBot , Base ) ;
BuildRadius = UTIL_MetresToGoldSrcUnits ( 10.0f ) ;
EnemyRadius = UTIL_MetresToGoldSrcUnits ( 5.0f ) ;
break ;
case MARINE_BASE_GUARDPOST :
AICOMM_UpdateGuardpostStatus ( pBot , Base ) ;
BuildRadius = UTIL_MetresToGoldSrcUnits ( 5.0f ) ;
EnemyRadius = UTIL_MetresToGoldSrcUnits ( 5.0f ) ;
break ;
case MARINE_BASE_OUTPOST :
AICOMM_UpdateOutpostStatus ( pBot , Base ) ;
BuildRadius = UTIL_MetresToGoldSrcUnits ( 10.0f ) ;
EnemyRadius = UTIL_MetresToGoldSrcUnits ( 10.0f ) ;
break ;
case MARINE_BASE_MAINBASE :
AICOMM_UpdateMainBaseStatus ( pBot , Base ) ;
BuildRadius = UTIL_MetresToGoldSrcUnits ( 15.0f ) ;
break ;
default :
break ;
}
if ( ! Base - > bRecycleBase & & Base - > bIsActive )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
Base - > bCanBeBuiltOut = AITAC_CanBuildOutBase ( Base ) ;
if ( Base - > bCanBeBuiltOut )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
Base - > NumBuilders = AITAC_GetNumPlayersOfTeamInArea ( BotTeam , Base - > BaseLocation , BuildRadius , false , pBot - > Edict , AVH_USER3_COMMANDER_PLAYER ) ;
Base - > NumEnemies = AITAC_GetNumPlayersOnTeamWithLOS ( EnemyTeam , Base - > BaseLocation + Vector ( 0.0f , 0.0f , 16.0f ) , EnemyRadius , nullptr ) ;
2024-03-21 18:17:18 +00:00
}
}
}
2024-06-12 19:21:55 +00:00
vector < AvHAIBuildableStructure > AICOMM_GetBaseStructures ( AvHAIMarineBase * Base )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
vector < AvHAIBuildableStructure > Result ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
for ( auto it = Base - > PlacedStructures . begin ( ) ; it ! = Base - > PlacedStructures . end ( ) ; it + + )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
AvHAIBuildableStructure ThisStructure = AITAC_GetDeployableStructureByEntIndex ( Base - > BaseTeam , ( * it ) ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
Result . push_back ( ThisStructure ) ;
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
return Result ;
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
void AICOMM_UpdateMainBaseStatus ( AvHAIPlayer * pBot , AvHAIMarineBase * Base )
{
// If this main base location is far from the active comm chair we're in, then we must be relocating
// In that case, if we've not yet established the base and the enemy have already started building fortifications there, then abandon the base.
if ( ! Base - > bIsBaseEstablished & & vDist2DSq ( Base - > BaseLocation , AITAC_GetCommChairLocation ( pBot - > Player - > GetTeam ( ) ) ) > sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) )
{
DeployableSearchFilter EnemyStuffFilter ;
EnemyStuffFilter . DeployableTeam = AIMGR_GetEnemyTeam ( pBot - > Player - > GetTeam ( ) ) ;
EnemyStuffFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
EnemyStuffFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
EnemyStuffFilter . DeployableTypes = ( STRUCTURE_MARINE_COMMCHAIR | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_PHASEGATE | STRUCTURE_ALIEN_OFFENCECHAMBER ) ;
EnemyStuffFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 10.0f ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( AITAC_DeployableExistsAtLocation ( Base - > BaseLocation , & EnemyStuffFilter ) )
{
Base - > bRecycleBase = true ;
Base - > bIsActive = false ;
return ;
}
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
// Either the enemy haven't started fortifying this area, or this base is where our active comm chair is. Either way, we need to crack on
Base - > bRecycleBase = false ;
Base - > bIsActive = true ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
// Check how far we are into building this outpost. If we have a TF and at least 3 sentries then we can consider it "established"
// even if it isn't finished yet
vector < AvHAIBuildableStructure > BaseStructures = AICOMM_GetBaseStructures ( Base ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
bool bHasCommChair = true ;
int NumInfPortals = 0 ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
for ( auto structIt = BaseStructures . begin ( ) ; structIt ! = BaseStructures . end ( ) ; structIt + + )
{
AvHAIBuildableStructure ThisStructure = ( * structIt ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ThisStructure . StructureType = = STRUCTURE_MARINE_COMMCHAIR ) { bHasCommChair = true ; }
if ( ThisStructure . StructureType = = STRUCTURE_MARINE_INFANTRYPORTAL & & ( ThisStructure . StructureStatusFlags & STRUCTURE_STATUS_COMPLETED ) ) { NumInfPortals + + ; }
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
Base - > bIsBaseEstablished = bHasCommChair & & NumInfPortals > 0 ;
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
void AICOMM_UpdateGuardpostStatus ( AvHAIPlayer * pBot , AvHAIMarineBase * Base )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
// If we've not started building this base and the enemy are already securing this area then don't start building it out
if ( ! Base - > bBaseInitialised )
{
DeployableSearchFilter EnemyStuffFilter ;
EnemyStuffFilter . DeployableTeam = AIMGR_GetEnemyTeam ( pBot - > Player - > GetTeam ( ) ) ;
EnemyStuffFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
EnemyStuffFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
EnemyStuffFilter . DeployableTypes = ( STRUCTURE_MARINE_COMMCHAIR | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_PHASEGATE | STRUCTURE_ALIEN_OFFENCECHAMBER ) ;
EnemyStuffFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 10.0f ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( AITAC_DeployableExistsAtLocation ( Base - > BaseLocation , & EnemyStuffFilter ) )
{
Base - > bRecycleBase = false ;
Base - > bIsActive = false ;
return ;
}
}
2024-06-25 16:36:13 +00:00
Base - > bRecycleBase = false ;
Base - > bIsActive = true ;
2024-06-12 19:21:55 +00:00
// Check how far we are into building this outpost. If we have a TF and at least 3 sentries then we can consider it "established"
// even if it isn't finished yet
vector < AvHAIBuildableStructure > BaseStructures = AICOMM_GetBaseStructures ( Base ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
bool bHasTF = true ;
int NumSentries = 0 ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
for ( auto structIt = BaseStructures . begin ( ) ; structIt ! = BaseStructures . end ( ) ; structIt + + )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
AvHAIBuildableStructure ThisStructure = ( * structIt ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ThisStructure . StructureType & ( STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY ) ) { bHasTF = true ; }
if ( ThisStructure . StructureType = = STRUCTURE_MARINE_TURRET ) { NumSentries + + ; }
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
Base - > bIsBaseEstablished = bHasTF & & NumSentries > 2 ;
}
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
void AICOMM_UpdateOutpostStatus ( AvHAIPlayer * pBot , AvHAIMarineBase * Base )
{
AvHTeamNumber BotTeam = pBot - > Player - > GetTeam ( ) ;
const AvHAIHiveDefinition * NearestHive = AITAC_GetHiveNearestLocation ( Base - > BaseLocation ) ;
// Recycle this base if it's meant to be securing a hive and that hive is not inactive any more
// We will replace with a siege base outside the hive
if ( NearestHive & & vDist2DSq ( NearestHive - > FloorLocation , Base - > BaseLocation ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) )
{
if ( NearestHive - > Status ! = HIVE_STATUS_UNBUILT )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
Base - > bIsActive = false ;
Base - > bRecycleBase = true ;
return ;
2024-05-22 15:21:40 +00:00
}
2024-06-12 19:21:55 +00:00
}
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
// If we've not started building this base and the enemy are already securing this area then don't start building it out
if ( ! Base - > bBaseInitialised )
{
DeployableSearchFilter EnemyStuffFilter ;
EnemyStuffFilter . DeployableTeam = AIMGR_GetEnemyTeam ( pBot - > Player - > GetTeam ( ) ) ;
EnemyStuffFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
EnemyStuffFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
EnemyStuffFilter . DeployableTypes = ( STRUCTURE_MARINE_COMMCHAIR | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_PHASEGATE | STRUCTURE_ALIEN_OFFENCECHAMBER ) ;
EnemyStuffFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 10.0f ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( AITAC_DeployableExistsAtLocation ( Base - > BaseLocation , & EnemyStuffFilter ) )
{
Base - > bRecycleBase = false ;
Base - > bIsActive = false ;
return ;
}
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
// Check how far we are into building this outpost. If we have a PG (assuming phase tech researched), a TF and at least 3 sentries then we can consider it "established"
// even if it isn't finished yet
vector < AvHAIBuildableStructure > BaseStructures = AICOMM_GetBaseStructures ( Base ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
bool bHasPG = true ;
bool bHasTF = true ;
int NumSentries = 0 ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
for ( auto structIt = BaseStructures . begin ( ) ; structIt ! = BaseStructures . end ( ) ; structIt + + )
{
AvHAIBuildableStructure ThisStructure = ( * structIt ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ThisStructure . StructureType = = STRUCTURE_MARINE_PHASEGATE ) { bHasPG = true ; }
if ( ThisStructure . StructureType & ( STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY ) ) { bHasTF = true ; }
if ( ThisStructure . StructureType = = STRUCTURE_MARINE_TURRET ) { NumSentries + + ; }
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
Base - > bIsBaseEstablished = ( bHasPG | | ! AITAC_ResearchIsComplete ( BotTeam , TECH_RESEARCH_PHASETECH ) ) & & bHasTF & & NumSentries > 2 ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
Base - > bIsActive = true ;
Base - > bRecycleBase = false ;
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
void AICOMM_UpdateSiegeBaseStatus ( AvHAIPlayer * pBot , AvHAIMarineBase * Base )
{
AvHTeamNumber BotTeam = pBot - > Player - > GetTeam ( ) ;
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam ( BotTeam ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
DeployableSearchFilter EnemyStuffFilter ;
EnemyStuffFilter . DeployableTeam = EnemyTeam ;
EnemyStuffFilter . MaxSearchRadius = BALANCE_VAR ( kSiegeTurretRange ) ;
2024-03-21 18:17:18 +00:00
2024-06-14 16:12:07 +00:00
bool bStillStuffToSiege = AITAC_DeployableExistsAtLocation ( Base - > BaseLocation , & EnemyStuffFilter ) ;
2024-06-12 19:21:55 +00:00
const AvHAIHiveDefinition * NearestHive = AITAC_GetHiveNearestLocation ( Base - > BaseLocation ) ;
2024-06-24 13:23:45 +00:00
const AvHAIHiveDefinition * SiegeHive = nullptr ;
if ( vDist2DSq ( Base - > BaseLocation , NearestHive - > Location ) < sqrf ( BALANCE_VAR ( kSiegeTurretRange ) ) )
{
SiegeHive = NearestHive ;
}
2024-06-12 19:21:55 +00:00
2024-06-24 13:23:45 +00:00
if ( bStillStuffToSiege | | ( SiegeHive & & SiegeHive - > Status ! = HIVE_STATUS_UNBUILT ) )
2024-06-12 19:21:55 +00:00
{
2024-06-24 13:23:45 +00:00
if ( SiegeHive & & SiegeHive - > Status ! = HIVE_STATUS_UNBUILT )
{
Base - > SiegeTarget = SiegeHive - > Location ;
}
else
{
// Basically, find the centroid (average location) of all siege structures, that will be our target
vector < AvHAIBuildableStructure > NearbyEnemyStuff = AITAC_FindAllDeployables ( Base - > BaseLocation , & EnemyStuffFilter ) ;
Vector Centroid = ZERO_VECTOR ;
for ( auto it = NearbyEnemyStuff . begin ( ) ; it ! = NearbyEnemyStuff . end ( ) ; it + + )
{
Centroid = Centroid + it - > Location ;
}
Centroid = Centroid / NearbyEnemyStuff . size ( ) ;
Base - > SiegeTarget = Centroid ;
}
2024-06-12 19:21:55 +00:00
Base - > bRecycleBase = false ;
Base - > bIsActive = true ;
2024-06-19 19:50:30 +00:00
return ;
2024-06-12 19:21:55 +00:00
}
else
{
2024-06-24 13:23:45 +00:00
if ( ! SiegeHive )
2024-03-21 18:17:18 +00:00
{
2024-06-19 19:50:30 +00:00
Base - > bRecycleBase = false ;
2024-06-12 19:21:55 +00:00
Base - > bIsActive = false ;
2024-06-19 19:50:30 +00:00
return ;
2024-03-21 18:17:18 +00:00
}
else
{
2024-06-19 19:50:30 +00:00
for ( auto it = pBot - > Bases . begin ( ) ; it ! = pBot - > Bases . end ( ) ; it + + )
2024-06-12 19:21:55 +00:00
{
2024-06-24 13:23:45 +00:00
if ( it - > BaseType = = MARINE_BASE_OUTPOST & & vDist2DSq ( SiegeHive - > FloorLocation , it - > BaseLocation ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) )
2024-06-12 19:21:55 +00:00
{
2024-06-19 19:50:30 +00:00
if ( it - > bIsBaseEstablished )
{
Base - > bRecycleBase = true ;
Base - > bIsActive = false ;
return ;
}
2024-06-12 19:21:55 +00:00
}
}
2024-06-19 19:50:30 +00:00
Base - > bRecycleBase = false ;
Base - > bIsActive = false ;
return ;
2024-06-12 19:21:55 +00:00
}
}
2024-06-24 13:23:45 +00:00
Base - > SiegeTarget = ZERO_VECTOR ;
Base - > bRecycleBase = true ;
Base - > bIsActive = false ;
2024-06-12 19:21:55 +00:00
}
void AICOMM_DeployBases ( AvHAIPlayer * pBot )
{
AvHTeamNumber BotTeam = pBot - > Player - > GetTeam ( ) ;
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam ( BotTeam ) ;
Vector CurrentChairLocation = AITAC_GetCommChairLocation ( BotTeam ) ;
if ( AICOMM_ShouldCommanderRelocate ( pBot ) )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
AvHAIMarineBase * CurrentMainBase = nullptr ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
for ( auto it = pBot - > Bases . begin ( ) ; it ! = pBot - > Bases . end ( ) ; it + + )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
if ( it - > BaseType = = MARINE_BASE_MAINBASE )
{
if ( ! CurrentMainBase | | it - > bIsBaseEstablished )
{
CurrentMainBase = & ( * it ) ;
}
}
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
if ( ! CurrentMainBase )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
AICOMM_AddNewBase ( pBot , CurrentChairLocation , MARINE_BASE_MAINBASE ) ;
return ;
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
bool bMainBaseAtCommChair = vDist2DSq ( CurrentMainBase - > BaseLocation , CurrentChairLocation ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ! bMainBaseAtCommChair & & ! CurrentMainBase - > bIsBaseEstablished & & AIMGR_GetMatchLength ( ) > 90.0f )
{
AvHAIMarineBase * ChairBase = AICOMM_GetNearestBaseToLocation ( pBot , CurrentChairLocation ) ;
if ( ChairBase ! = CurrentMainBase )
{
CurrentMainBase - > BaseType = MARINE_BASE_OUTPOST ;
ChairBase - > BaseType = MARINE_BASE_MAINBASE ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
char NewMsg [ 128 ] ;
if ( AICOMM_GetRelocationMessage ( CurrentChairLocation , NewMsg ) )
{
BotSay ( pBot , true , 1.0f , NewMsg ) ;
}
2024-06-14 16:12:07 +00:00
return ;
}
else
{
CurrentMainBase - > BaseType = MARINE_BASE_OUTPOST ;
AICOMM_AddNewBase ( pBot , CurrentChairLocation , MARINE_BASE_MAINBASE ) ;
char NewMsg [ 128 ] ;
if ( AICOMM_GetRelocationMessage ( CurrentChairLocation , NewMsg ) )
{
BotSay ( pBot , true , 1.0f , NewMsg ) ;
}
return ;
2024-06-12 19:21:55 +00:00
}
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
else
{
Vector NewBaseLocation = AITAC_FindNewTeamRelocationPoint ( BotTeam ) ;
2024-06-14 16:12:07 +00:00
if ( ! vIsZero ( NewBaseLocation ) & & vDist2DSq ( NewBaseLocation , CurrentMainBase - > BaseLocation ) > sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) )
2024-06-12 19:21:55 +00:00
{
// Turn our starting base into an outpost, and lay down a new main base elsewhere
CurrentMainBase - > BaseType = MARINE_BASE_OUTPOST ;
AICOMM_AddNewBase ( pBot , NewBaseLocation , MARINE_BASE_MAINBASE ) ;
char NewMsg [ 128 ] ;
if ( AICOMM_GetRelocationMessage ( NewBaseLocation , NewMsg ) )
{
BotSay ( pBot , true , 1.0f , NewMsg ) ;
}
2024-06-14 16:12:07 +00:00
return ;
2024-06-12 19:21:55 +00:00
}
else
{
if ( ! bMainBaseAtCommChair )
{
AvHAIMarineBase * ChairBase = AICOMM_GetNearestBaseToLocation ( pBot , CurrentChairLocation ) ;
if ( ChairBase ! = CurrentMainBase )
{
CurrentMainBase - > BaseType = MARINE_BASE_OUTPOST ;
ChairBase - > BaseType = MARINE_BASE_MAINBASE ;
char NewMsg [ 128 ] ;
if ( AICOMM_GetRelocationMessage ( CurrentChairLocation , NewMsg ) )
{
BotSay ( pBot , true , 1.0f , NewMsg ) ;
}
2024-06-14 16:12:07 +00:00
return ;
2024-06-12 19:21:55 +00:00
}
}
}
}
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
vector < AvHAIHiveDefinition * > AllHives = AITAC_GetAllHives ( ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
bool bNeedsResources = AICOMM_ShouldCommanderPrioritiseNodes ( pBot ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
for ( auto it = AllHives . begin ( ) ; it ! = AllHives . end ( ) ; it + + )
{
const AvHAIHiveDefinition * ThisHive = ( * it ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ThisHive - > Status = = HIVE_STATUS_UNBUILT )
{
bool bHasOutpost = false ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
for ( auto baseIt = pBot - > Bases . begin ( ) ; baseIt ! = pBot - > Bases . end ( ) ; baseIt + + )
{
AvHAIMarineBase * ThisBase = & ( * baseIt ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ( ThisBase - > BaseType = = MARINE_BASE_OUTPOST | | ThisBase - > BaseType = = MARINE_BASE_MAINBASE ) & & ! ThisBase - > bRecycleBase )
{
if ( vDist2DSq ( ThisHive - > FloorLocation , ThisBase - > BaseLocation ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) )
{
bHasOutpost = true ;
break ;
}
}
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ! bHasOutpost )
{
DeployableSearchFilter EnemyStuffFilter ;
EnemyStuffFilter . DeployableTeam = AIMGR_GetEnemyTeam ( pBot - > Player - > GetTeam ( ) ) ;
EnemyStuffFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
EnemyStuffFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
EnemyStuffFilter . DeployableTypes = ( STRUCTURE_MARINE_COMMCHAIR | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_PHASEGATE | STRUCTURE_ALIEN_OFFENCECHAMBER ) ;
EnemyStuffFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 10.0f ) ;
if ( ! AITAC_DeployableExistsAtLocation ( ThisHive - > FloorLocation , & EnemyStuffFilter ) )
{
2024-06-25 16:36:13 +00:00
Vector ProjectedPoint = UTIL_ProjectPointToNavmesh ( ThisHive - > FloorLocation , Vector ( 500.0f , 500.0f , 500.0f ) , GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) ) ;
if ( ! vIsZero ( ProjectedPoint ) )
{
AICOMM_AddNewBase ( pBot , ProjectedPoint , MARINE_BASE_OUTPOST ) ;
}
2024-06-12 19:21:55 +00:00
}
}
}
else
{
// Only siege if we can use phase gates
// TODO: Define scenario where we can siege without using phase gates. Probably when we don't have any outposts or guardposts to build
if ( ! AITAC_ResearchIsComplete ( BotTeam , TECH_RESEARCH_PHASETECH ) ) { continue ; }
// Also don't try sieging if we don't have enough nodes
if ( bNeedsResources & & pBot - > Player - > GetResources ( ) < 50 ) { continue ; }
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
bool bHasSiege = false ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
for ( auto baseIt = pBot - > Bases . begin ( ) ; baseIt ! = pBot - > Bases . end ( ) ; baseIt + + )
{
AvHAIMarineBase * ThisBase = & ( * baseIt ) ;
2024-03-21 18:17:18 +00:00
2024-07-03 15:01:17 +00:00
if ( ThisBase - > BaseType = = MARINE_BASE_SIEGE )
2024-06-12 19:21:55 +00:00
{
if ( vDist2DSq ( ThisHive - > Location , ThisBase - > BaseLocation ) < sqrf ( BALANCE_VAR ( kSiegeTurretRange ) ) )
{
bHasSiege = true ;
break ;
}
}
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ! bHasSiege )
{
2024-06-24 13:23:45 +00:00
vector < AvHPlayer * > PotentialBuilders = AITAC_GetAllPlayersOfTeamInArea ( BotTeam , ThisHive - > Location , BALANCE_VAR ( kSiegeTurretRange ) , false , nullptr , AVH_USER3_COMMANDER_PLAYER ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
for ( auto playerIt = PotentialBuilders . begin ( ) ; playerIt ! = PotentialBuilders . end ( ) ; playerIt + + )
{
AvHPlayer * ThisPlayer = ( * playerIt ) ;
2024-06-24 13:23:45 +00:00
if ( vDist2DSq ( ThisPlayer - > pev - > origin , ThisHive - > Location ) > sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) )
2024-06-12 19:21:55 +00:00
{
2024-06-24 13:23:45 +00:00
// If this player isn't right inside the hive and hasn't been spotted by an enemy, then they're eligible to start building a siege base
2024-06-12 19:21:55 +00:00
if ( ! ( ThisPlayer - > pev - > iuser4 & MASK_VIS_SIGHTED ) )
{
DeployableSearchFilter EnemyStuffFilter ;
EnemyStuffFilter . DeployableTeam = AIMGR_GetEnemyTeam ( pBot - > Player - > GetTeam ( ) ) ;
EnemyStuffFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
EnemyStuffFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
EnemyStuffFilter . DeployableTypes = ( STRUCTURE_MARINE_COMMCHAIR | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_PHASEGATE | STRUCTURE_ALIEN_OFFENCECHAMBER ) ;
EnemyStuffFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 5.0f ) ;
2024-06-24 13:23:45 +00:00
if ( ! AITAC_DeployableExistsAtLocation ( ThisPlayer - > pev - > origin , & EnemyStuffFilter ) )
2024-06-12 19:21:55 +00:00
{
2024-06-25 16:36:13 +00:00
// Make sure that our siege guy is somewhere we can build
Vector ProjectedPoint = UTIL_ProjectPointToNavmesh ( ThisPlayer - > pev - > origin , Vector ( 100.0f , 100.0f , 100.0f ) , GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) ) ;
2024-06-28 11:06:36 +00:00
if ( ! vIsZero ( ProjectedPoint ) & & vDist2DSq ( ProjectedPoint , ThisHive - > Location ) < sqrf ( BALANCE_VAR ( kSiegeTurretRange ) ) )
2024-06-25 16:36:13 +00:00
{
AICOMM_AddNewBase ( pBot , ProjectedPoint , MARINE_BASE_SIEGE ) ;
}
2024-06-12 19:21:55 +00:00
}
}
}
}
}
}
}
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
void AICOMM_ManageActiveBases ( AvHAIPlayer * pBot )
{
AvHTeamNumber BotTeam = pBot - > Player - > GetTeam ( ) ;
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam ( BotTeam ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
for ( auto it = pBot - > Bases . begin ( ) ; it ! = pBot - > Bases . end ( ) ; )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
AvHAIMarineBase * ThisBase = & ( * it ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ! ThisBase - > bBaseInitialised )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
ThisBase - > bBaseInitialised = it - > PlacedStructures . size ( ) > 0 ;
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
for ( auto structIt = it - > PlacedStructures . begin ( ) ; structIt ! = it - > PlacedStructures . end ( ) ; )
2024-03-21 18:17:18 +00:00
{
2024-06-12 19:21:55 +00:00
AvHAIBuildableStructure StructureRef = AITAC_GetDeployableStructureByEntIndex ( BotTeam , ( * structIt ) ) ;
if ( ! StructureRef . IsValid ( ) | | ( StructureRef . StructureStatusFlags & STRUCTURE_STATUS_RECYCLING ) )
{
structIt = it - > PlacedStructures . erase ( structIt ) ;
}
else
{
structIt + + ;
}
}
if ( ! AICOMM_IsMarineBaseValid ( & ( * it ) ) )
{
it = pBot - > Bases . erase ( it ) ;
}
else
{
AICOMM_UpdateBaseStatus ( pBot , ThisBase ) ;
it + + ;
2024-03-21 18:17:18 +00:00
}
}
2024-06-12 19:21:55 +00:00
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
bool AICOMM_GetRelocationMessage ( Vector RelocationPoint , char * MessageBuffer )
{
2024-06-14 16:12:07 +00:00
const AvHAIHiveDefinition * NearestHive = AITAC_GetHiveNearestLocation ( RelocationPoint ) ;
string LocationName ;
2024-03-21 18:17:18 +00:00
2024-06-14 16:12:07 +00:00
if ( NearestHive & & vDist2DSq ( RelocationPoint , NearestHive - > FloorLocation ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) )
{
LocationName = string ( NearestHive - > HiveName ) ;
}
else
2024-03-21 18:17:18 +00:00
{
2024-06-14 16:12:07 +00:00
LocationName = AITAC_GetLocationName ( RelocationPoint ) ;
}
if ( LocationName . empty ( ) )
{
sprintf ( MessageBuffer , " Get ready to relocate " ) ;
2024-06-12 19:21:55 +00:00
return true ;
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
int MsgIndex = irandrange ( 0 , 2 ) ;
switch ( MsgIndex )
{
case 0 :
2024-06-14 16:12:07 +00:00
sprintf ( MessageBuffer , " We're relocating to %s, lads " , LocationName . c_str ( ) ) ;
2024-06-12 19:21:55 +00:00
return true ;
case 1 :
2024-06-14 16:12:07 +00:00
sprintf ( MessageBuffer , " Relocate to %s, go go go " , LocationName . c_str ( ) ) ;
2024-06-12 19:21:55 +00:00
return true ;
case 2 :
2024-06-14 16:12:07 +00:00
sprintf ( MessageBuffer , " I'm relocating to %s " , LocationName . c_str ( ) ) ;
2024-06-12 19:21:55 +00:00
return true ;
default :
sprintf ( MessageBuffer , " We're relocating, get ready " ) ;
return true ;
}
return false ;
}
bool AICOMM_ShouldCommanderLeaveChair ( AvHAIPlayer * pBot )
{
if ( pBot - > BotRole ! = BOT_ROLE_COMMAND ) { return true ; }
if ( AIMGR_GetCommanderMode ( ) = = COMMANDERMODE_DISABLED ) { return true ; }
if ( AIMGR_GetCommanderMode ( ) = = COMMANDERMODE_IFNOHUMAN )
{
if ( AIMGR_GetNumHumanPlayersOnTeam ( pBot - > Player - > GetTeam ( ) ) > 0 ) { return true ; }
}
if ( IsPlayerCommander ( pBot - > Edict ) & & AIMGR_GetCommanderAllowedTime ( pBot - > Player - > GetTeam ( ) ) > gpGlobals - > time ) { return true ; }
int NumAliveMarinesInBase = AITAC_GetNumPlayersOfTeamInArea ( pBot - > Player - > GetTeam ( ) , AITAC_GetCommChairLocation ( pBot - > Player - > GetTeam ( ) ) , UTIL_MetresToGoldSrcUnits ( 30.0f ) , true , pBot - > Edict , AVH_USER3_NONE ) ;
if ( NumAliveMarinesInBase > 0 ) { return false ; }
DeployableSearchFilter StructureFilter ;
StructureFilter . DeployableTypes = SEARCH_ALL_STRUCTURES ;
StructureFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 20.0f ) ;
StructureFilter . DeployableTeam = pBot - > Player - > GetTeam ( ) ;
StructureFilter . ReachabilityFlags = AI_REACHABILITY_MARINE ;
StructureFilter . ReachabilityTeam = pBot - > Player - > GetTeam ( ) ;
StructureFilter . ExcludeStatusFlags = STRUCTURE_STATUS_COMPLETED | STRUCTURE_STATUS_RECYCLING ;
int NumUnbuiltStructuresInBase = AITAC_GetNumDeployablesNearLocation ( AITAC_GetCommChairLocation ( pBot - > Player - > GetTeam ( ) ) , & StructureFilter ) ;
if ( NumUnbuiltStructuresInBase = = 0 ) { return false ; }
StructureFilter . DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL ;
StructureFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 5.0f ) ;
StructureFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
StructureFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
int NumInfantryPortals = AITAC_GetNumDeployablesNearLocation ( AITAC_GetCommChairLocation ( pBot - > Player - > GetTeam ( ) ) , & StructureFilter ) ;
if ( NumInfantryPortals = = 0 ) { return true ; }
if ( AITAC_GetNumDeadPlayersOnTeam ( pBot - > Player - > GetTeam ( ) ) = = 0 ) { return true ; }
return false ;
}
const AvHAIHiveDefinition * AICOMM_GetEmptyHiveOpportunityNearestLocation ( AvHAIPlayer * CommanderBot , const Vector SearchLocation )
{
AvHTeamNumber CommanderTeam = CommanderBot - > Player - > GetTeam ( ) ;
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam ( CommanderTeam ) ;
const AvHAIHiveDefinition * Result = nullptr ;
float MinDist = 0.0f ;
const vector < AvHAIHiveDefinition * > Hives = AITAC_GetAllHives ( ) ;
Vector TeamStartLocation = AITAC_GetTeamStartingLocation ( CommanderTeam ) ;
Vector RelocationPoint = CommanderBot - > RelocationSpot ;
for ( auto it = Hives . begin ( ) ; it ! = Hives . end ( ) ; it + + )
{
const AvHAIHiveDefinition * Hive = ( * it ) ;
if ( Hive - > Status ! = HIVE_STATUS_UNBUILT ) { continue ; }
if ( AICOMM_IsHiveFullySecured ( CommanderBot , Hive , false ) ) { continue ; }
// If the hive is close enough that we could siege it from our base, then don't bother securing it
if ( vDist2DSq ( TeamStartLocation , Hive - > FloorLocation ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 15.0f ) ) ) { continue ; }
// If the hive is close enough that we could siege it from our base, then don't bother securing it
if ( ! vIsZero ( CommanderBot - > RelocationSpot ) )
{
// Likewise, don't secure if we're planning to move there. We will build the base instead
if ( vDist2DSq ( CommanderBot - > RelocationSpot , Hive - > FloorLocation ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ) { continue ; }
}
Vector SecureLocation = Hive - > FloorLocation ;
DeployableSearchFilter StructureFilter ;
StructureFilter . DeployableTeam = CommanderTeam ;
StructureFilter . ReachabilityTeam = CommanderTeam ;
StructureFilter . ReachabilityFlags = AI_REACHABILITY_MARINE ;
StructureFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
StructureFilter . DeployableTypes = STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY ;
StructureFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 15.0f ) ;
AvHAIBuildableStructure ExistingStructure = AITAC_FindClosestDeployableToLocation ( Hive - > FloorLocation , & StructureFilter ) ;
if ( ExistingStructure . IsValid ( ) & & ( ExistingStructure . Purpose = = STRUCTURE_PURPOSE_FORTIFY | | ExistingStructure . Purpose = = STRUCTURE_PURPOSE_BASE ) )
{
SecureLocation = ExistingStructure . Location ;
}
float MarineDist = ( ExistingStructure . IsValid ( ) ) ? UTIL_MetresToGoldSrcUnits ( 5.0f ) : UTIL_MetresToGoldSrcUnits ( 10.0f ) ;
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 ) ;
if ( ! Result | | ThisDist < MinDist )
{
Result = Hive ;
MinDist = ThisDist ;
}
}
return Result ;
}
bool AICOMM_IsHiveFullySecured ( AvHAIPlayer * CommanderBot , const AvHAIHiveDefinition * Hive , bool bIncludeElectrical )
{
AvHTeamNumber CommanderTeam = CommanderBot - > Player - > GetTeam ( ) ;
bool bPhaseGatesAvailable = AITAC_PhaseGatesAvailable ( CommanderTeam ) ;
bool bHasPhaseGate = false ;
bool bHasTurretFactory = false ;
bool bTurretFactoryElectrified = false ;
int NumTurrets = 0 ;
DeployableSearchFilter SearchFilter ;
SearchFilter . DeployableTypes = ( STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY ) ;
SearchFilter . DeployableTeam = CommanderTeam ;
SearchFilter . ReachabilityTeam = CommanderTeam ;
SearchFilter . ReachabilityFlags = AI_REACHABILITY_MARINE ;
SearchFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
SearchFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
SearchFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 15.0f ) ;
vector < AvHAIBuildableStructure > HiveStructures = AITAC_FindAllDeployables ( Hive - > FloorLocation , & SearchFilter ) ;
for ( auto it = HiveStructures . begin ( ) ; it ! = HiveStructures . end ( ) ; it + + )
{
AvHAIBuildableStructure Structure = ( * it ) ;
if ( Structure . StructureType = = STRUCTURE_MARINE_PHASEGATE )
{
bHasPhaseGate = true ;
}
if ( Structure . StructureType = = STRUCTURE_MARINE_TURRETFACTORY | | Structure . StructureType = = STRUCTURE_MARINE_ADVTURRETFACTORY )
{
bHasTurretFactory = true ;
bTurretFactoryElectrified = ( Structure . StructureStatusFlags & STRUCTURE_STATUS_ELECTRIFIED ) ;
SearchFilter . DeployableTypes = STRUCTURE_MARINE_TURRET ;
SearchFilter . MaxSearchRadius = BALANCE_VAR ( kTurretFactoryBuildDistance ) ;
NumTurrets = AITAC_GetNumDeployablesNearLocation ( Structure . Location , & SearchFilter ) ;
}
}
const AvHAIResourceNode * ResNode = Hive - > HiveResNodeRef ;
bool bSecuredResNode = ( ! ResNode | | ( ResNode - > bIsOccupied & & ResNode - > OwningTeam = = CommanderTeam & & UTIL_StructureIsFullyBuilt ( ResNode - > ActiveTowerEntity ) ) ) ;
return ( ( ! bPhaseGatesAvailable | | bHasPhaseGate ) & & bHasTurretFactory & & ( ! bIncludeElectrical | | bTurretFactoryElectrified ) & & NumTurrets > = 5 & & bSecuredResNode ) ;
}
2024-06-14 16:12:07 +00:00
bool AICOMM_IsMainBaseInTrouble ( AvHAIPlayer * pBot , AvHAIMarineBase * Base )
2024-06-12 19:21:55 +00:00
{
AvHTeamNumber BotTeam = pBot - > Player - > GetTeam ( ) ;
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam ( BotTeam ) ;
Vector BaseLocation = AITAC_GetTeamStartingLocation ( BotTeam ) ;
2024-06-14 16:12:07 +00:00
vector < AvHAIBuildableStructure > BaseStructures = AICOMM_GetBaseStructures ( Base ) ;
2024-06-12 19:21:55 +00:00
bool bHasInfantryPortals = false ;
2024-06-14 16:12:07 +00:00
bool bCriticalStructureUnderAttack = false ;
bool bAnyStructureUnderAttack = false ;
2024-06-12 19:21:55 +00:00
for ( auto it = BaseStructures . begin ( ) ; it ! = BaseStructures . end ( ) ; it + + )
{
AvHAIBuildableStructure ThisStructure = ( * it ) ;
if ( ThisStructure . StructureStatusFlags & STRUCTURE_STATUS_UNDERATTACK )
{
2024-06-14 16:12:07 +00:00
bAnyStructureUnderAttack = true ;
if ( ThisStructure . StructureType = = STRUCTURE_MARINE_COMMCHAIR | | ThisStructure . StructureType = = STRUCTURE_MARINE_INFANTRYPORTAL )
{
bCriticalStructureUnderAttack = true ;
}
2024-06-12 19:21:55 +00:00
}
2024-06-14 16:12:07 +00:00
}
if ( ! bAnyStructureUnderAttack ) { return false ; }
2024-06-12 19:21:55 +00:00
2024-06-14 16:12:07 +00:00
float EnemyStrength = 0.0f ;
float DefenderStrength = 0.0f ;
vector < AvHPlayer * > DefendingPlayers = AITAC_GetAllPlayersOfTeamInArea ( BotTeam , Base - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 20.0f ) , true , nullptr , AVH_USER3_COMMANDER_PLAYER ) ;
for ( auto it = DefendingPlayers . begin ( ) ; it ! = DefendingPlayers . end ( ) ; it + + )
{
AvHPlayer * ThisPlayer = ( * it ) ;
edict_t * PlayerEdict = ThisPlayer - > edict ( ) ;
float ThisPlayerValue = 1.0f ;
if ( PlayerHasHeavyArmour ( PlayerEdict ) )
2024-06-12 19:21:55 +00:00
{
2024-06-14 16:12:07 +00:00
ThisPlayerValue + = 0.5f ;
2024-06-12 19:21:55 +00:00
}
2024-06-14 16:12:07 +00:00
if ( PlayerHasSpecialWeapon ( ThisPlayer ) )
{
ThisPlayerValue + = 1.0f ;
}
2024-06-12 19:21:55 +00:00
2024-06-14 16:12:07 +00:00
DefenderStrength + = ThisPlayerValue ;
}
2024-06-12 19:21:55 +00:00
if ( AIMGR_GetTeamType ( EnemyTeam ) = = AVH_CLASS_TYPE_MARINE )
{
2024-06-14 16:12:07 +00:00
vector < AvHPlayer * > AttackingPlayers = AITAC_GetAllPlayersOfTeamInArea ( EnemyTeam , Base - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 10.0f ) , false , nullptr , AVH_USER3_COMMANDER_PLAYER ) ;
for ( auto it = AttackingPlayers . begin ( ) ; it ! = AttackingPlayers . end ( ) ; it + + )
{
AvHPlayer * ThisPlayer = ( * it ) ;
edict_t * PlayerEdict = ThisPlayer - > edict ( ) ;
float ThisPlayerValue = 1.0f ;
if ( PlayerHasHeavyArmour ( PlayerEdict ) )
{
ThisPlayerValue + = 0.5f ;
}
if ( PlayerHasSpecialWeapon ( ThisPlayer ) )
{
ThisPlayerValue + = 1.0f ;
}
DefenderStrength + = ThisPlayerValue ;
}
2024-06-12 19:21:55 +00:00
}
else
{
int NumSkulks = AITAC_GetNumPlayersOfTeamAndClassInArea ( EnemyTeam , BaseLocation , UTIL_MetresToGoldSrcUnits ( 10.0f ) , false , nullptr , AVH_USER3_ALIEN_PLAYER1 ) ;
int NumFades = AITAC_GetNumPlayersOfTeamAndClassInArea ( EnemyTeam , BaseLocation , UTIL_MetresToGoldSrcUnits ( 10.0f ) , false , nullptr , AVH_USER3_ALIEN_PLAYER4 ) ;
int NumOnos = AITAC_GetNumPlayersOfTeamAndClassInArea ( EnemyTeam , BaseLocation , UTIL_MetresToGoldSrcUnits ( 10.0f ) , false , nullptr , AVH_USER3_ALIEN_PLAYER5 ) ;
2024-06-14 16:12:07 +00:00
EnemyStrength = ( NumSkulks * 0.8f ) + ( NumFades * 2 ) + ( NumOnos * 2.5f ) ;
2024-06-12 19:21:55 +00:00
}
2024-06-14 16:12:07 +00:00
if ( EnemyStrength > = 3.0f & & EnemyStrength > = DefenderStrength * 3.0f )
2024-06-12 19:21:55 +00:00
{
2024-06-14 16:12:07 +00:00
return true ;
}
return false ;
}
bool AICOMM_ShouldBeacon ( AvHAIPlayer * pBot )
{
if ( pBot - > Player - > GetResources ( ) < BALANCE_VAR ( kDistressBeaconCost ) ) { return false ; }
AvHTeamNumber BotTeam = pBot - > Player - > GetTeam ( ) ;
DeployableSearchFilter ObservatoryFilter ;
ObservatoryFilter . DeployableTypes = STRUCTURE_MARINE_OBSERVATORY ;
ObservatoryFilter . DeployableTeam = BotTeam ;
ObservatoryFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
ObservatoryFilter . ExcludeStatusFlags = ( STRUCTURE_STATUS_RECYCLING | STRUCTURE_STATUS_RESEARCHING ) ;
AvHAIBuildableStructure Observatory = AITAC_FindClosestDeployableToLocation ( ZERO_VECTOR , & ObservatoryFilter ) ;
if ( ! Observatory . IsValid ( ) ) { return false ; }
for ( auto it = pBot - > Bases . begin ( ) ; it ! = pBot - > Bases . end ( ) ; it + + )
{
if ( it - > BaseType = = MARINE_BASE_MAINBASE )
{
return AICOMM_IsMainBaseInTrouble ( pBot , & ( * it ) ) ;
}
2024-03-21 18:17:18 +00:00
}
return false ;
}
void AICOMM_ReceiveChatRequest ( AvHAIPlayer * Commander , edict_t * Requestor , const char * Request )
{
AvHMessageID NewRequestType = MESSAGE_NULL ;
if ( ! stricmp ( Request , " shotgun " ) | | ! stricmp ( Request , " sg " ) | | ! stricmp ( Request , " shotty " ) )
{
NewRequestType = BUILD_SHOTGUN ;
}
else if ( ! stricmp ( Request , " welder " ) )
{
NewRequestType = BUILD_WELDER ;
}
else if ( ! stricmp ( Request , " HMG " ) )
{
NewRequestType = BUILD_HMG ;
}
else if ( ! stricmp ( Request , " gl " ) )
{
NewRequestType = BUILD_GRENADE_GUN ;
}
else if ( ! stricmp ( Request , " mines " ) )
{
NewRequestType = BUILD_MINES ;
}
2024-04-02 11:14:10 +00:00
else if ( ! stricmp ( Request , " ha " ) | | ! stricmp ( Request , " heavy " ) | | ! stricmp ( Request , " heavyarmor " ) | | ! stricmp ( Request , " heavy armor " ) )
{
2024-06-12 19:21:55 +00:00
NewRequestType = BUILD_HEAVY ;
}
else if ( ! stricmp ( Request , " jp " ) | | ! stricmp ( Request , " jetpack " ) | | ! stricmp ( Request , " jet pack " ) )
{
NewRequestType = BUILD_JETPACK ;
}
else if ( ! stricmp ( Request , " cat " ) | | ! stricmp ( Request , " cats " ) | | ! stricmp ( Request , " catalysts " ) )
{
NewRequestType = BUILD_CAT ;
}
else if ( ! stricmp ( Request , " pg " ) | | ! stricmp ( Request , " phase " ) | | ! stricmp ( Request , " phasegate " ) )
{
NewRequestType = BUILD_PHASEGATE ;
}
else if ( ! stricmp ( Request , " TF " ) | | ! stricmp ( Request , " turretfactory " ) )
{
NewRequestType = BUILD_TURRET_FACTORY ;
}
else if ( ! stricmp ( Request , " turret " ) )
{
NewRequestType = BUILD_TURRET ;
}
else if ( ! stricmp ( Request , " armory " ) | | ! stricmp ( Request , " armoury " ) )
{
NewRequestType = BUILD_ARMORY ;
}
else if ( ! stricmp ( Request , " scan " ) )
{
NewRequestType = BUILD_SCAN ;
}
else if ( ! stricmp ( Request , " cc " ) | | ! stricmp ( Request , " chair " ) | | ! stricmp ( Request , " command chair " ) )
{
NewRequestType = BUILD_COMMANDSTATION ;
}
else if ( ! stricmp ( Request , " obs " ) | | ! stricmp ( Request , " observatory " ) )
{
NewRequestType = BUILD_OBSERVATORY ;
}
else if ( ! stricmp ( Request , " pl " ) | | ! stricmp ( Request , " protolab " ) | | ! stricmp ( Request , " proto lab " ) | | ! stricmp ( Request , " prototype lab " ) )
{
NewRequestType = BUILD_PROTOTYPE_LAB ;
}
else if ( ! stricmp ( Request , " ip " ) | | ! stricmp ( Request , " portal " ) | | ! stricmp ( Request , " inf portal " ) | | ! stricmp ( Request , " infantry portal " ) )
{
NewRequestType = BUILD_INFANTRYPORTAL ;
}
else if ( ! stricmp ( Request , " al " ) | | ! stricmp ( Request , " armslab " ) | | ! stricmp ( Request , " arms lab " ) )
{
NewRequestType = BUILD_ARMSLAB ;
}
else if ( ! stricmp ( Request , " sc " ) | | ! stricmp ( Request , " st " ) | | ! stricmp ( Request , " siegeturret " ) | | ! stricmp ( Request , " siege turret " ) | | ! stricmp ( Request , " siegecannon " ) | | ! stricmp ( Request , " siege cannon " ) )
{
NewRequestType = BUILD_SIEGE ;
}
if ( NewRequestType = = MESSAGE_NULL ) { return ; }
ai_commander_request * ExistingRequest = AICOMM_GetExistingRequestForPlayer ( Commander , Requestor ) ;
ai_commander_request NewRequest ;
ai_commander_request * RequestRef = ( ExistingRequest ) ? ExistingRequest : & NewRequest ;
RequestRef - > bNewRequest = true ;
RequestRef - > bResponded = false ;
RequestRef - > RequestTime = gpGlobals - > time ;
RequestRef - > RequestType = NewRequestType ;
RequestRef - > Requestor = Requestor ;
RequestRef - > RequestLocation = UTIL_GetFloorUnderEntity ( Requestor ) + ( UTIL_GetForwardVector2D ( Requestor - > v . angles ) * 75.0f ) ;
if ( ! ExistingRequest )
{
Commander - > ActiveRequests . push_back ( NewRequest ) ;
2024-04-02 11:14:10 +00:00
}
2024-06-12 19:21:55 +00:00
}
bool AICOMM_ShouldCommanderRelocate ( AvHAIPlayer * pBot )
{
if ( ! CONFIG_IsRelocationAllowed ( ) ) { return false ; }
AvHTeamNumber Team = pBot - > Player - > GetTeam ( ) ;
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam ( Team ) ;
edict_t * CurrentCommChair = AITAC_GetCommChair ( Team ) ;
if ( FNullEnt ( CurrentCommChair ) ) { return false ; }
AvHAIMarineBase * CurrentMainBase = nullptr ;
for ( auto it = pBot - > Bases . begin ( ) ; it ! = pBot - > Bases . end ( ) ; it + + )
2024-04-02 11:14:10 +00:00
{
2024-06-12 19:21:55 +00:00
if ( it - > BaseType = = MARINE_BASE_MAINBASE )
{
CurrentMainBase = & ( * it ) ;
break ;
}
2024-04-02 11:14:10 +00:00
}
2024-06-12 19:21:55 +00:00
if ( ! CurrentMainBase ) { return true ; }
if ( ! CurrentMainBase - > bIsActive | | CurrentMainBase - > bRecycleBase ) { return true ; }
2024-07-01 14:45:38 +00:00
// If our main base is within 10m of the chair we're sitting in, then we clearly haven't relocated yet
2024-06-14 16:12:07 +00:00
bool bMainBaseIsAtChair = vDist2DSq ( CurrentCommChair - > v . origin , CurrentMainBase - > BaseLocation ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
// We're not able to relocate after 90 seconds, best find somewhere else or we're in trouble
if ( AIMGR_GetMatchLength ( ) > 90.0f & & ! CurrentMainBase - > bIsBaseEstablished & & ! bMainBaseIsAtChair )
{
return ( CurrentMainBase - > NumBuilders = = 0 ) ;
}
2024-06-19 19:50:30 +00:00
if ( AITAC_IsRelocationAtStartEnabled ( ) & & AIMGR_GetMatchLength ( ) < 90.0f )
2024-06-14 16:12:07 +00:00
{
// We've not tried relocating yet
if ( bMainBaseIsAtChair ) { return true ; }
const AvHAIHiveDefinition * RelocationHive = AITAC_GetHiveNearestLocation ( CurrentMainBase - > BaseLocation ) ;
// The hive we were planning to relocate to has somehow started being built within 90 seconds of start. Not sure how, but we better not move there now
if ( RelocationHive & & vDist2DSq ( RelocationHive - > FloorLocation , CurrentMainBase - > BaseLocation ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 15.0f ) ) )
{
if ( RelocationHive - > Status ! = HIVE_STATUS_UNBUILT ) { return true ; }
}
// The enemy beat us to it and has started setting up shop in that location
DeployableSearchFilter EnemyStuffFilter ;
EnemyStuffFilter . DeployableTeam = EnemyTeam ;
EnemyStuffFilter . DeployableTypes = ( STRUCTURE_MARINE_COMMCHAIR | STRUCTURE_MARINE_INFANTRYPORTAL | STRUCTURE_MARINE_TURRETFACTORY ) ;
EnemyStuffFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
EnemyStuffFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
EnemyStuffFilter . MaxSearchRadius = UTIL_MetresToGoldSrcUnits ( 10.0f ) ;
// Those marine bastards stole our spot!
if ( AITAC_DeployableExistsAtLocation ( CurrentMainBase - > BaseLocation , & EnemyStuffFilter ) ) { return true ; }
EnemyStuffFilter . DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER ;
// Those alien bastards stole our spot!
if ( AITAC_GetNumDeployablesNearLocation ( CurrentMainBase - > BaseLocation , & EnemyStuffFilter ) > 1 ) { return true ; }
}
// If we have an established main base, then only relocate if it's fucked. This means:
// Base is not at the original start, or we can't beacon to save the base
// Critical structures are under attack (comm chair or infantry portals)
// The number of enemies is overwhelming and we're doomed
2024-06-12 19:21:55 +00:00
if ( CurrentMainBase - > bIsBaseEstablished )
2024-03-21 18:17:18 +00:00
{
2024-06-14 16:12:07 +00:00
if ( CurrentMainBase - > NumBuilders > 0 ) { return false ; }
DeployableSearchFilter ObsFilter ;
ObsFilter . DeployableTeam = Team ;
ObsFilter . DeployableTypes = STRUCTURE_MARINE_OBSERVATORY ;
ObsFilter . IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED ;
ObsFilter . ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING ;
bool bCanBeacon = AITAC_DeployableExistsAtLocation ( ZERO_VECTOR , & ObsFilter ) ;
2024-06-12 19:21:55 +00:00
bool bCriticalStructureAttacked = false ;
2024-06-14 16:12:07 +00:00
bool bBaseIsAtStart = vDist2DSq ( CurrentMainBase - > BaseLocation , AITAC_GetTeamOriginalStartLocation ( Team ) ) < sqrf ( UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
2024-06-12 19:21:55 +00:00
vector < AvHAIBuildableStructure > BaseStructures = AICOMM_GetBaseStructures ( CurrentMainBase ) ;
for ( auto structIt = BaseStructures . begin ( ) ; structIt ! = BaseStructures . end ( ) ; structIt + + )
{
AvHAIBuildableStructure * ThisStructure = & ( * structIt ) ;
if ( ( ThisStructure - > StructureStatusFlags & STRUCTURE_STATUS_RECYCLING ) | | ! ( ThisStructure - > StructureStatusFlags & STRUCTURE_STATUS_COMPLETED ) ) { continue ; }
if ( ThisStructure - > StructureStatusFlags & STRUCTURE_STATUS_UNDERATTACK )
{
if ( ThisStructure - > StructureType = = STRUCTURE_MARINE_COMMCHAIR | | ThisStructure - > StructureType = = STRUCTURE_MARINE_INFANTRYPORTAL )
{
bCriticalStructureAttacked = true ;
}
}
}
2024-06-14 16:12:07 +00:00
if ( ! bCriticalStructureAttacked ) { return false ; }
2024-06-12 19:21:55 +00:00
2024-06-14 16:12:07 +00:00
if ( bBaseIsAtStart & & bCanBeacon ) { return false ; }
2024-06-12 19:21:55 +00:00
2024-06-14 16:12:07 +00:00
return AICOMM_IsMainBaseInTrouble ( pBot , CurrentMainBase ) ;
2024-03-21 18:17:18 +00:00
}
2024-06-12 19:21:55 +00:00
return false ;
}
bool AICOMM_BuildOutBase ( AvHAIPlayer * pBot , AvHAIMarineBase * BaseToBuildOut )
{
if ( ! pBot | | ! BaseToBuildOut ) { return false ; }
switch ( BaseToBuildOut - > BaseType )
2024-05-25 15:35:50 +00:00
{
2024-06-12 19:21:55 +00:00
case MARINE_BASE_SIEGE :
return AICOMM_BuildOutSiege ( pBot , BaseToBuildOut ) ;
case MARINE_BASE_OUTPOST :
return AICOMM_BuildOutOutpost ( pBot , BaseToBuildOut ) ;
case MARINE_BASE_MAINBASE :
return AICOMM_BuildOutMainBase ( pBot , BaseToBuildOut ) ;
2024-06-25 16:36:13 +00:00
case MARINE_BASE_GUARDPOST :
return AICOMM_BuildOutGuardPost ( pBot , BaseToBuildOut ) ;
2024-06-12 19:21:55 +00:00
default :
return false ;
2024-05-25 15:35:50 +00:00
}
2024-06-12 19:21:55 +00:00
return false ;
}
bool AICOMM_BuildOutMainBase ( AvHAIPlayer * pBot , AvHAIMarineBase * BaseToBuildOut )
{
if ( ! BaseToBuildOut ) { return false ; }
AvHTeamNumber BotTeam = pBot - > Player - > GetTeam ( ) ;
AvHAIBuildableStructure CommChair ;
AvHAIBuildableStructure ArmsLab ;
AvHAIBuildableStructure ProtoLab ;
AvHAIBuildableStructure PhaseGate ;
AvHAIBuildableStructure Armoury ;
AvHAIBuildableStructure TurretFactory ;
AvHAIBuildableStructure Observatory ;
int NumInfPortals = 0 ;
int NumTurrets = 0 ;
int NumIncomplete = 0 ;
2024-06-28 11:06:36 +00:00
vector < Vector > TurretLocations ;
2024-06-12 19:21:55 +00:00
int DesiredInfPortals = ( int ) ceilf ( ( float ) AIMGR_GetNumPlayersOnTeam ( BotTeam ) / 4.0f ) ;
for ( auto it = BaseToBuildOut - > PlacedStructures . begin ( ) ; it ! = BaseToBuildOut - > PlacedStructures . end ( ) ; it + + )
2024-05-25 15:35:50 +00:00
{
2024-06-12 19:21:55 +00:00
AvHAIBuildableStructure StructureRef = AITAC_GetDeployableStructureByEntIndex ( BaseToBuildOut - > BaseTeam , * it ) ;
if ( ! StructureRef . IsCompleted ( ) ) { NumIncomplete + + ; }
switch ( StructureRef . StructureType )
{
case STRUCTURE_MARINE_COMMCHAIR :
CommChair = StructureRef ;
break ;
case STRUCTURE_MARINE_INFANTRYPORTAL :
NumInfPortals + + ;
break ;
case STRUCTURE_MARINE_ARMSLAB :
{
// We do this in case we have more than one arms lab. This ensures we always pick
// the complete one (if it exists) and don't accidentally pick up an unfinished one
if ( ! ArmsLab . IsValid ( ) | | ! ArmsLab . IsCompleted ( ) )
{
ArmsLab = StructureRef ;
}
}
break ;
case STRUCTURE_MARINE_PROTOTYPELAB :
{
if ( ! ProtoLab . IsValid ( ) | | ! ProtoLab . IsCompleted ( ) )
{
ProtoLab = StructureRef ;
}
}
break ;
case STRUCTURE_MARINE_PHASEGATE :
{
if ( ! PhaseGate . IsValid ( ) | | ! PhaseGate . IsCompleted ( ) )
{
PhaseGate = StructureRef ;
}
}
break ;
case STRUCTURE_MARINE_TURRETFACTORY :
{
if ( ! TurretFactory . IsValid ( ) | | ! TurretFactory . IsCompleted ( ) )
{
TurretFactory = StructureRef ;
}
}
break ;
case STRUCTURE_MARINE_ADVTURRETFACTORY :
TurretFactory = StructureRef ;
break ;
case STRUCTURE_MARINE_ARMOURY :
{
if ( ! Armoury . IsValid ( ) | | ! Armoury . IsCompleted ( ) )
{
Armoury = StructureRef ;
}
}
break ;
case STRUCTURE_MARINE_ADVARMOURY :
Armoury = StructureRef ;
break ;
case STRUCTURE_MARINE_OBSERVATORY :
{
if ( ! Observatory . IsValid ( ) | | ! Observatory . IsCompleted ( ) )
{
Observatory = StructureRef ;
}
}
break ;
case STRUCTURE_MARINE_TURRET :
NumTurrets + + ;
2024-06-28 11:06:36 +00:00
TurretLocations . push_back ( StructureRef . Location ) ;
2024-06-12 19:21:55 +00:00
break ;
default :
break ;
}
2024-05-25 15:35:50 +00:00
}
2024-06-12 19:21:55 +00:00
if ( NumIncomplete > 0 )
2024-05-25 15:35:50 +00:00
{
2024-06-12 19:21:55 +00:00
int NumBuilders = AITAC_GetNumPlayersOfTeamInArea ( pBot - > Player - > GetTeam ( ) , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 10.0f ) , false , nullptr , AVH_USER3_COMMANDER_PLAYER ) ;
// Don't spam too many structures
if ( NumIncomplete > NumBuilders ) { return false ; }
2024-05-25 15:35:50 +00:00
}
2024-06-12 19:21:55 +00:00
if ( ! CommChair . IsValid ( ) )
2024-05-25 15:35:50 +00:00
{
2024-06-12 19:21:55 +00:00
if ( pBot - > Player - > GetResources ( ) < BALANCE_VAR ( kCommandStationCost ) ) { return true ; }
2024-03-21 18:17:18 +00:00
2024-07-01 14:45:38 +00:00
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation ( STRUCTURE_MARINE_COMMCHAIR , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 20.0f ) ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_COMMCHAIR , BuildLocation , BaseToBuildOut ) ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
}
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
int NumAttempts = 0 ;
2024-03-21 18:17:18 +00:00
2024-06-12 19:21:55 +00:00
while ( NumAttempts < 5 )
{
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_COMMCHAIR , BuildLocation , BaseToBuildOut ) ;
2024-05-23 08:42:33 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
}
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( ONOS_BASE_NAV_PROFILE ) , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_COMMCHAIR , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
NumAttempts + + ;
}
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
return pBot - > Player - > GetResources ( ) < = ( BALANCE_VAR ( kCommandStationCost ) * 1.5f ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
}
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( ! CommChair . IsCompleted ( ) ) { return false ; }
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( NumInfPortals < DesiredInfPortals )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
if ( pBot - > Player - > GetResources ( ) < BALANCE_VAR ( kInfantryPortalCost ) ) { return true ; }
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation ( STRUCTURE_MARINE_INFANTRYPORTAL , CommChair . Location , BALANCE_VAR ( kCommandStationBuildDistance ) ) ;
if ( ! vIsZero ( BuildLocation ) )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_INFANTRYPORTAL , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
2024-05-22 15:21:40 +00:00
}
2024-06-12 19:21:55 +00:00
int NumAttempts = 0 ;
while ( NumAttempts < 5 )
{
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , CommChair . Location , BALANCE_VAR ( kCommandStationBuildDistance ) * 0.8f ) ;
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_INFANTRYPORTAL , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( ONOS_BASE_NAV_PROFILE ) , CommChair . Location , BALANCE_VAR ( kCommandStationBuildDistance ) * 0.8f ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_INFANTRYPORTAL , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
NumAttempts + + ;
}
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
return pBot - > Player - > GetResources ( ) < = ( BALANCE_VAR ( kInfantryPortalCost ) * 1.5f ) ;
}
if ( ! Armoury . IsValid ( ) )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
if ( pBot - > Player - > GetResources ( ) < BALANCE_VAR ( kArmoryCost ) ) { return true ; }
2024-07-01 14:45:38 +00:00
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation ( STRUCTURE_MARINE_ARMOURY , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 20.0f ) ) ;
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_ARMOURY , BuildLocation , BaseToBuildOut ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
}
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
int NumAttempts = 0 ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
while ( NumAttempts < 5 )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , CommChair . Location , UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_ARMOURY , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
2024-05-22 15:21:40 +00:00
}
2024-06-12 19:21:55 +00:00
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( ONOS_BASE_NAV_PROFILE ) , CommChair . Location , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
if ( ! vIsZero ( BuildLocation ) )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_ARMOURY , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
2024-05-22 15:21:40 +00:00
}
2024-06-12 19:21:55 +00:00
NumAttempts + + ;
2024-05-22 15:21:40 +00:00
}
2024-06-12 19:21:55 +00:00
return pBot - > Player - > GetResources ( ) < = ( BALANCE_VAR ( kInfantryPortalCost ) * 1.5f ) ;
}
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( ! TurretFactory . IsValid ( ) )
{
if ( pBot - > Player - > GetResources ( ) < BALANCE_VAR ( kTurretFactoryCost ) ) { return true ; }
2024-05-22 15:21:40 +00:00
2024-07-01 14:45:38 +00:00
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation ( STRUCTURE_MARINE_TURRETFACTORY , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 20.0f ) ) ;
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_TURRETFACTORY , BuildLocation , BaseToBuildOut ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
2024-05-22 15:21:40 +00:00
}
2024-06-28 11:06:36 +00:00
if ( NumTurrets > 0 )
{
Vector Centroid = ZERO_VECTOR ;
for ( auto tLocs = TurretLocations . begin ( ) ; tLocs ! = TurretLocations . end ( ) ; tLocs + + )
{
Centroid = Centroid + * tLocs ;
}
Centroid = Centroid / TurretLocations . size ( ) ;
if ( ! vIsZero ( Centroid ) )
{
Vector CentroidBuildLocation = UTIL_ProjectPointToNavmesh ( Centroid , GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) ) ;
if ( ! vIsZero ( CentroidBuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_TURRETFACTORY , CentroidBuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
}
}
2024-06-12 19:21:55 +00:00
int NumAttempts = 0 ;
while ( NumAttempts < 5 )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , CommChair . Location , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_TURRETFACTORY , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( ONOS_BASE_NAV_PROFILE ) , CommChair . Location , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_TURRETFACTORY , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
NumAttempts + + ;
2024-05-22 15:21:40 +00:00
}
2024-06-12 19:21:55 +00:00
return pBot - > Player - > GetResources ( ) < = ( BALANCE_VAR ( kTurretFactoryCost ) * 1.5f ) ;
2024-05-22 15:21:40 +00:00
}
2024-06-12 19:21:55 +00:00
if ( ! TurretFactory . IsCompleted ( ) ) { return false ; }
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( NumTurrets < 5 )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
if ( pBot - > Player - > GetResources ( ) < BALANCE_VAR ( kSentryCost ) ) { return true ; }
2024-05-22 15:21:40 +00:00
2024-06-24 13:23:45 +00:00
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation ( STRUCTURE_MARINE_TURRET , TurretFactory . Location , BALANCE_VAR ( kTurretFactoryBuildDistance ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_TURRET , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
2024-06-12 19:21:55 +00:00
int NumAttempts = 0 ;
while ( NumAttempts < 5 )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , TurretFactory . Location , BALANCE_VAR ( kTurretFactoryBuildDistance ) * 0.8f ) ;
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_TURRET , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( ONOS_BASE_NAV_PROFILE ) , TurretFactory . Location , BALANCE_VAR ( kTurretFactoryBuildDistance ) * 0.8f ) ;
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_TURRET , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
NumAttempts + + ;
2024-05-22 15:21:40 +00:00
}
2024-06-12 19:21:55 +00:00
return pBot - > Player - > GetResources ( ) < = ( BALANCE_VAR ( kSentryCost ) * 1.5f ) ;
}
if ( ! Armoury . IsCompleted ( ) ) { return false ; }
if ( AICOMM_ShouldCommanderPrioritiseNodes ( pBot ) & & pBot - > Player - > GetResources ( ) < 30 ) { return false ; }
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( ! ArmsLab . IsValid ( ) )
{
if ( pBot - > Player - > GetResources ( ) < BALANCE_VAR ( kArmsLabCost ) ) { return true ; }
2024-07-01 14:45:38 +00:00
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation ( STRUCTURE_MARINE_ARMSLAB , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 20.0f ) ) ;
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_ARMSLAB , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
2024-05-22 15:21:40 +00:00
}
2024-06-12 19:21:55 +00:00
int NumAttempts = 0 ;
while ( NumAttempts < 5 )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , CommChair . Location , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_ARMSLAB , BuildLocation , BaseToBuildOut ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
}
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( ONOS_BASE_NAV_PROFILE ) , CommChair . Location , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_ARMSLAB , BuildLocation , BaseToBuildOut ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
}
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
NumAttempts + + ;
}
return pBot - > Player - > GetResources ( ) < = ( BALANCE_VAR ( kArmsLabCost ) * 1.5f ) ;
2024-05-22 15:21:40 +00:00
}
2024-06-12 19:21:55 +00:00
if ( ! Observatory . IsValid ( ) )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
if ( pBot - > Player - > GetResources ( ) < BALANCE_VAR ( kObservatoryCost ) ) { return true ; }
2024-05-22 15:21:40 +00:00
2024-07-01 14:45:38 +00:00
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation ( STRUCTURE_MARINE_OBSERVATORY , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 20.0f ) ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_OBSERVATORY , BuildLocation , BaseToBuildOut ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
2024-05-22 15:21:40 +00:00
}
2024-06-12 19:21:55 +00:00
int NumAttempts = 0 ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
while ( NumAttempts < 5 )
{
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , CommChair . Location , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_OBSERVATORY , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( ONOS_BASE_NAV_PROFILE ) , CommChair . Location , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_OBSERVATORY , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
NumAttempts + + ;
}
return pBot - > Player - > GetResources ( ) < = ( BALANCE_VAR ( kObservatoryCost ) * 1.5f ) ;
}
2024-06-19 19:50:30 +00:00
if ( ! AITAC_ResearchIsComplete ( BotTeam , TECH_RESEARCH_PHASETECH ) ) { return false ; }
if ( ! PhaseGate . IsValid ( ) )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
if ( pBot - > Player - > GetResources ( ) < BALANCE_VAR ( kPhaseGateCost ) ) { return true ; }
2024-05-23 08:42:33 +00:00
2024-07-01 14:45:38 +00:00
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation ( STRUCTURE_MARINE_PHASEGATE , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 20.0f ) ) ;
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
2024-05-23 08:42:33 +00:00
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_PHASEGATE , BuildLocation , BaseToBuildOut ) ;
2024-05-28 21:58:37 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
2024-05-23 08:42:33 +00:00
}
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
int NumAttempts = 0 ;
while ( NumAttempts < 5 )
{
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , CommChair . Location , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_PHASEGATE , BuildLocation , BaseToBuildOut ) ;
2024-05-28 21:58:37 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
}
2024-05-28 21:58:37 +00:00
2024-06-12 19:21:55 +00:00
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( ONOS_BASE_NAV_PROFILE ) , CommChair . Location , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_PHASEGATE , BuildLocation , BaseToBuildOut ) ;
2024-05-28 21:58:37 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
}
2024-05-28 21:58:37 +00:00
2024-06-12 19:21:55 +00:00
NumAttempts + + ;
2024-05-22 15:21:40 +00:00
}
2024-06-12 19:21:55 +00:00
return pBot - > Player - > GetResources ( ) < = ( BALANCE_VAR ( kPhaseGateCost ) * 1.5f ) ;
2024-05-22 15:21:40 +00:00
}
2024-06-12 19:21:55 +00:00
if ( Armoury . StructureType ! = STRUCTURE_MARINE_ADVARMOURY )
{
if ( pBot - > Player - > GetResources ( ) < BALANCE_VAR ( kArmoryUpgradeCost ) ) { return true ; }
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_UpgradeStructure ( pBot , & Armoury ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
return pBot - > Player - > GetResources ( ) < = ( BALANCE_VAR ( kArmoryUpgradeCost ) * 1.5f ) ;
2024-05-22 15:21:40 +00:00
}
2024-06-12 19:21:55 +00:00
if ( ! ProtoLab . IsValid ( ) )
{
if ( pBot - > Player - > GetResources ( ) < BALANCE_VAR ( kPrototypeLabCost ) ) { return true ; }
2024-05-22 15:21:40 +00:00
2024-07-01 14:45:38 +00:00
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation ( STRUCTURE_MARINE_PROTOTYPELAB , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 20.0f ) ) ;
2024-05-22 15:21:40 +00:00
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
2024-05-22 15:21:40 +00:00
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_PROTOTYPELAB , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
2024-05-22 15:21:40 +00:00
}
2024-06-12 19:21:55 +00:00
int NumAttempts = 0 ;
2024-06-05 19:32:15 +00:00
2024-06-12 19:21:55 +00:00
while ( NumAttempts < 5 )
{
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , Armoury . Location , UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ;
2024-06-05 19:32:15 +00:00
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_PROTOTYPELAB , BuildLocation , BaseToBuildOut ) ;
2024-06-05 19:32:15 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( ONOS_BASE_NAV_PROFILE ) , CommChair . Location , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , STRUCTURE_MARINE_PROTOTYPELAB , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
NumAttempts + + ;
}
return pBot - > Player - > GetResources ( ) < = ( BALANCE_VAR ( kPrototypeLabCost ) * 1.5f ) ;
}
2024-06-05 19:32:15 +00:00
return false ;
}
bool AICOMM_BuildOutOutpost ( AvHAIPlayer * pBot , AvHAIMarineBase * BaseToBuildOut )
{
AvHAIDeployableStructureType StructureToDeploy = STRUCTURE_NONE ;
AvHAIBuildableStructure PhaseGate ;
AvHAIBuildableStructure Armoury ;
AvHAIBuildableStructure TurretFactory ;
AvHAIBuildableStructure Observatory ;
int NumTurrets = 0 ;
int NumIncomplete = 0 ;
2024-06-28 11:06:36 +00:00
vector < Vector > TurretLocations ;
2024-06-05 19:32:15 +00:00
for ( auto it = BaseToBuildOut - > PlacedStructures . begin ( ) ; it ! = BaseToBuildOut - > PlacedStructures . end ( ) ; it + + )
{
AvHAIBuildableStructure StructureRef = AITAC_GetDeployableStructureByEntIndex ( BaseToBuildOut - > BaseTeam , * it ) ;
if ( ! StructureRef . IsCompleted ( ) ) { NumIncomplete + + ; }
switch ( StructureRef . StructureType )
{
case STRUCTURE_MARINE_PHASEGATE :
PhaseGate = StructureRef ;
break ;
case STRUCTURE_MARINE_TURRETFACTORY :
case STRUCTURE_MARINE_ADVTURRETFACTORY :
TurretFactory = StructureRef ;
break ;
case STRUCTURE_MARINE_ARMOURY :
case STRUCTURE_MARINE_ADVARMOURY :
Armoury = StructureRef ;
break ;
case STRUCTURE_MARINE_OBSERVATORY :
Observatory = StructureRef ;
break ;
case STRUCTURE_MARINE_TURRET :
NumTurrets + + ;
2024-06-28 11:06:36 +00:00
TurretLocations . push_back ( StructureRef . Location ) ;
2024-06-05 19:32:15 +00:00
break ;
default :
break ;
}
}
if ( NumIncomplete > 0 )
{
int NumBuilders = AITAC_GetNumPlayersOfTeamInArea ( pBot - > Player - > GetTeam ( ) , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 10.0f ) , false , nullptr , AVH_USER3_COMMANDER_PLAYER ) ;
// Don't spam too many structures
if ( NumIncomplete > = NumBuilders ) { return false ; }
}
if ( PhaseGate . IsValid ( ) & & ! PhaseGate . IsCompleted ( ) ) { return false ; }
if ( TurretFactory . IsValid ( ) & & ! TurretFactory . IsCompleted ( ) ) { return false ; }
if ( ! PhaseGate . IsValid ( ) & & AITAC_ResearchIsComplete ( pBot - > Player - > GetTeam ( ) , TECH_RESEARCH_PHASETECH ) )
{
StructureToDeploy = STRUCTURE_MARINE_PHASEGATE ;
}
else if ( ! TurretFactory . IsValid ( ) )
{
StructureToDeploy = STRUCTURE_MARINE_TURRETFACTORY ;
}
else if ( TurretFactory . IsCompleted ( ) & & NumTurrets < 5 )
{
StructureToDeploy = STRUCTURE_MARINE_TURRET ;
}
else if ( ! Armoury . IsValid ( ) )
{
StructureToDeploy = STRUCTURE_MARINE_ARMOURY ;
}
else if ( ! Observatory . IsValid ( ) )
{
StructureToDeploy = STRUCTURE_MARINE_OBSERVATORY ;
}
if ( StructureToDeploy = = STRUCTURE_NONE ) { return false ; }
2024-06-12 19:21:55 +00:00
int ResourcesRequired = UTIL_GetCostOfStructureType ( StructureToDeploy ) ;
if ( pBot - > Player - > GetResources ( ) < ResourcesRequired ) { return true ; }
2024-06-05 19:32:15 +00:00
if ( StructureToDeploy = = STRUCTURE_MARINE_TURRET )
{
int NumAttempts = 0 ;
while ( NumAttempts < 5 )
{
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , TurretFactory . Location , ( BALANCE_VAR ( kTurretFactoryBuildDistance ) * 0.8f ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
2024-06-05 19:32:15 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
2024-06-05 19:32:15 +00:00
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , TurretFactory . Location , ( BALANCE_VAR ( kTurretFactoryBuildDistance ) * 0.8f ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
2024-06-05 19:32:15 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
2024-06-05 19:32:15 +00:00
}
NumAttempts + + ;
}
2024-06-12 19:21:55 +00:00
return pBot - > Player - > GetResources ( ) < = 15 ;
}
2024-06-29 19:31:51 +00:00
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation ( StructureToDeploy , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 15.0f ) ) ;
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
2024-06-05 19:32:15 +00:00
}
2024-06-28 11:06:36 +00:00
if ( StructureToDeploy = = STRUCTURE_MARINE_TURRETFACTORY )
{
if ( NumTurrets > 0 )
{
Vector Centroid = ZERO_VECTOR ;
for ( auto tLocs = TurretLocations . begin ( ) ; tLocs ! = TurretLocations . end ( ) ; tLocs + + )
{
Centroid = Centroid + * tLocs ;
}
Centroid = Centroid / TurretLocations . size ( ) ;
if ( ! vIsZero ( Centroid ) )
{
Vector CentroidBuildLocation = UTIL_ProjectPointToNavmesh ( Centroid , GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) ) ;
if ( ! vIsZero ( CentroidBuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , CentroidBuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
}
}
}
2024-06-05 19:32:15 +00:00
int NumAttempts = 0 ;
while ( NumAttempts < 5 )
{
2024-06-12 19:21:55 +00:00
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 8.0f ) ) ;
2024-06-05 19:32:15 +00:00
if ( ! vIsZero ( BuildLocation ) )
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
2024-06-05 19:32:15 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( ONOS_BASE_NAV_PROFILE ) , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 8.0f ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
2024-06-05 19:32:15 +00:00
}
NumAttempts + + ;
}
2024-06-12 19:21:55 +00:00
return pBot - > Player - > GetResources ( ) < = 15 ;
2024-06-05 19:32:15 +00:00
}
bool AICOMM_BuildOutSiege ( AvHAIPlayer * pBot , AvHAIMarineBase * BaseToBuildOut )
{
AvHAIDeployableStructureType StructureToDeploy = STRUCTURE_NONE ;
AvHAIBuildableStructure PhaseGate ;
AvHAIBuildableStructure Armoury ;
AvHAIBuildableStructure TurretFactory ;
AvHAIBuildableStructure Observatory ;
int NumTurrets = 0 ;
int NumIncomplete = 0 ;
2024-06-28 11:06:36 +00:00
vector < Vector > TurretLocations ;
2024-06-05 19:32:15 +00:00
for ( auto it = BaseToBuildOut - > PlacedStructures . begin ( ) ; it ! = BaseToBuildOut - > PlacedStructures . end ( ) ; it + + )
{
AvHAIBuildableStructure StructureRef = AITAC_GetDeployableStructureByEntIndex ( BaseToBuildOut - > BaseTeam , * it ) ;
if ( ! StructureRef . IsCompleted ( ) )
{
NumIncomplete + + ;
}
switch ( StructureRef . StructureType )
{
case STRUCTURE_MARINE_PHASEGATE :
PhaseGate = StructureRef ;
break ;
case STRUCTURE_MARINE_TURRETFACTORY :
case STRUCTURE_MARINE_ADVTURRETFACTORY :
TurretFactory = StructureRef ;
break ;
case STRUCTURE_MARINE_ARMOURY :
case STRUCTURE_MARINE_ADVARMOURY :
Armoury = StructureRef ;
break ;
case STRUCTURE_MARINE_OBSERVATORY :
Observatory = StructureRef ;
break ;
case STRUCTURE_MARINE_SIEGETURRET :
NumTurrets + + ;
2024-06-28 11:06:36 +00:00
TurretLocations . push_back ( StructureRef . Location ) ;
2024-06-05 19:32:15 +00:00
break ;
default :
break ;
}
}
if ( NumIncomplete > 0 )
{
// Don't spam too many structures
2024-06-12 19:21:55 +00:00
if ( NumIncomplete > = BaseToBuildOut - > NumBuilders ) { return false ; }
2024-06-05 19:32:15 +00:00
}
// Don't place any more structures until we have the phase gate up
if ( PhaseGate . IsValid ( ) & & ! PhaseGate . IsCompleted ( ) ) { return false ; }
if ( ! PhaseGate . IsValid ( ) & & AITAC_ResearchIsComplete ( BaseToBuildOut - > BaseTeam , TECH_RESEARCH_PHASETECH ) )
{
StructureToDeploy = STRUCTURE_MARINE_PHASEGATE ;
}
else if ( ! TurretFactory . IsValid ( ) )
{
StructureToDeploy = STRUCTURE_MARINE_TURRETFACTORY ;
}
else if ( TurretFactory . IsCompleted ( ) & & TurretFactory . IsIdle ( ) & & TurretFactory . StructureType ! = STRUCTURE_MARINE_ADVTURRETFACTORY )
{
return AICOMM_UpgradeStructure ( pBot , & TurretFactory ) ;
}
else if ( TurretFactory . StructureType = = STRUCTURE_MARINE_ADVTURRETFACTORY & & NumTurrets < 3 )
{
StructureToDeploy = STRUCTURE_MARINE_SIEGETURRET ;
}
else if ( ! Armoury . IsValid ( ) )
{
StructureToDeploy = STRUCTURE_MARINE_ARMOURY ;
}
else if ( ! Observatory . IsValid ( ) )
{
StructureToDeploy = STRUCTURE_MARINE_OBSERVATORY ;
}
if ( StructureToDeploy = = STRUCTURE_NONE ) { return false ; }
2024-06-12 19:21:55 +00:00
int ResourcesRequired = UTIL_GetCostOfStructureType ( StructureToDeploy ) ;
if ( pBot - > Player - > GetResources ( ) < ResourcesRequired ) { return true ; }
2024-06-24 13:23:45 +00:00
if ( StructureToDeploy = = STRUCTURE_MARINE_TURRETFACTORY )
{
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation ( StructureToDeploy , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ;
if ( ! vIsZero ( BuildLocation ) & & ( vIsZero ( BaseToBuildOut - > SiegeTarget ) | | vDist2DSq ( BuildLocation , BaseToBuildOut - > SiegeTarget ) < sqrf ( BALANCE_VAR ( kSiegeTurretRange ) ) ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
int NumAttempts = 0 ;
2024-06-28 11:06:36 +00:00
if ( NumTurrets > 0 )
{
Vector Centroid = ZERO_VECTOR ;
for ( auto tLocs = TurretLocations . begin ( ) ; tLocs ! = TurretLocations . end ( ) ; tLocs + + )
{
Centroid = Centroid + * tLocs ;
}
Centroid = Centroid / TurretLocations . size ( ) ;
if ( ! vIsZero ( Centroid ) )
{
Vector BuildLocation = UTIL_ProjectPointToNavmesh ( Centroid , GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
}
}
2024-06-24 13:23:45 +00:00
while ( NumAttempts < 5 )
{
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 2.0f + NumAttempts ) ) ;
if ( ! vIsZero ( BuildLocation ) & & ( vIsZero ( BaseToBuildOut - > SiegeTarget ) | | vDist2DSq ( BuildLocation , BaseToBuildOut - > SiegeTarget ) < sqrf ( BALANCE_VAR ( kSiegeTurretRange ) ) ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 2.0f + NumAttempts ) ) ;
if ( ! vIsZero ( BuildLocation ) & & ( vIsZero ( BaseToBuildOut - > SiegeTarget ) | | vDist2DSq ( BuildLocation , BaseToBuildOut - > SiegeTarget ) < sqrf ( BALANCE_VAR ( kSiegeTurretRange ) ) ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
NumAttempts + + ;
}
return ( pBot - > Player - > GetResources ( ) < = BALANCE_VAR ( kTurretFactoryCost ) * 2 ) ;
}
2024-06-05 19:32:15 +00:00
if ( StructureToDeploy = = STRUCTURE_MARINE_SIEGETURRET )
{
2024-06-24 13:23:45 +00:00
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation ( StructureToDeploy , TurretFactory . Location , BALANCE_VAR ( kTurretFactoryBuildDistance ) ) ;
2024-06-12 19:21:55 +00:00
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
2024-06-05 19:32:15 +00:00
int NumAttempts = 0 ;
while ( NumAttempts < 5 )
{
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , TurretFactory . Location , ( BALANCE_VAR ( kTurretFactoryBuildDistance ) * 0.4f ) ) ;
2024-06-24 13:23:45 +00:00
if ( ! vIsZero ( BuildLocation ) & & ( vIsZero ( BaseToBuildOut - > SiegeTarget ) | | vDist2DSq ( BuildLocation , BaseToBuildOut - > SiegeTarget ) < sqrf ( BALANCE_VAR ( kSiegeTurretRange ) ) ) )
2024-06-05 19:32:15 +00:00
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
2024-06-05 19:32:15 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
2024-06-05 19:32:15 +00:00
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , TurretFactory . Location , ( BALANCE_VAR ( kTurretFactoryBuildDistance ) * 0.6f ) ) ;
2024-06-24 13:23:45 +00:00
if ( ! vIsZero ( BuildLocation ) & & ( vIsZero ( BaseToBuildOut - > SiegeTarget ) | | vDist2DSq ( BuildLocation , BaseToBuildOut - > SiegeTarget ) < sqrf ( BALANCE_VAR ( kSiegeTurretRange ) ) ) )
2024-06-05 19:32:15 +00:00
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
2024-06-05 19:32:15 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
2024-06-05 19:32:15 +00:00
}
NumAttempts + + ;
}
2024-06-12 19:21:55 +00:00
return ( pBot - > Player - > GetResources ( ) < = BALANCE_VAR ( kSiegeCost ) + 5 ) ;
}
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation ( StructureToDeploy , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 10.0f ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
2024-06-05 19:32:15 +00:00
}
int NumAttempts = 0 ;
while ( NumAttempts < 5 )
{
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 3.0f ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
2024-06-05 19:32:15 +00:00
2024-06-12 19:21:55 +00:00
if ( bSuccess ) { return true ; }
2024-06-05 19:32:15 +00:00
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
2024-06-12 19:21:55 +00:00
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
NumAttempts + + ;
}
return ( pBot - > Player - > GetResources ( ) < = 15 ) ;
}
bool AICOMM_BuildOutGuardPost ( AvHAIPlayer * pBot , AvHAIMarineBase * BaseToBuildOut )
{
AvHAIBuildableStructure TurretFactory ;
AvHAIBuildableStructure Observatory ;
int NumTurrets = 0 ;
int NumIncomplete = 0 ;
2024-06-28 11:06:36 +00:00
vector < Vector > TurretLocations ;
2024-06-12 19:21:55 +00:00
for ( auto it = BaseToBuildOut - > PlacedStructures . begin ( ) ; it ! = BaseToBuildOut - > PlacedStructures . end ( ) ; it + + )
{
AvHAIBuildableStructure StructureRef = AITAC_GetDeployableStructureByEntIndex ( BaseToBuildOut - > BaseTeam , * it ) ;
if ( ! StructureRef . IsCompleted ( ) )
{
NumIncomplete + + ;
}
2024-06-05 19:32:15 +00:00
2024-06-12 19:21:55 +00:00
if ( StructureRef . StructureType & ( STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY ) )
{
if ( ! TurretFactory . IsValid ( ) | | ! TurretFactory . IsCompleted ( ) )
2024-06-05 19:32:15 +00:00
{
2024-06-12 19:21:55 +00:00
TurretFactory = StructureRef ;
}
}
else if ( StructureRef . StructureType = = STRUCTURE_MARINE_TURRET )
{
NumTurrets + + ;
2024-06-28 11:06:36 +00:00
TurretLocations . push_back ( StructureRef . Location ) ;
2024-06-12 19:21:55 +00:00
}
else if ( StructureRef . StructureType = = STRUCTURE_MARINE_OBSERVATORY )
{
Observatory = StructureRef ;
}
}
if ( NumIncomplete > 0 )
{
int NumBuilders = AITAC_GetNumPlayersOfTeamInArea ( pBot - > Player - > GetTeam ( ) , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 10.0f ) , false , nullptr , AVH_USER3_COMMANDER_PLAYER ) ;
// Don't spam too many structures
if ( NumIncomplete > = NumBuilders ) { return false ; }
}
AvHAIDeployableStructureType StructureToDeploy = STRUCTURE_NONE ;
if ( ! TurretFactory . IsValid ( ) )
{
StructureToDeploy = STRUCTURE_MARINE_TURRETFACTORY ;
}
else
{
if ( ! TurretFactory . IsCompleted ( ) ) { return false ; }
if ( NumTurrets < 5 )
{
StructureToDeploy = STRUCTURE_MARINE_TURRET ;
}
else if ( ! Observatory . IsValid ( ) )
{
StructureToDeploy = STRUCTURE_MARINE_OBSERVATORY ;
}
}
if ( StructureToDeploy = = STRUCTURE_NONE ) { return false ; }
int ResourcesRequired = UTIL_GetCostOfStructureType ( StructureToDeploy ) ;
if ( pBot - > Player - > GetResources ( ) < ResourcesRequired ) { return true ; }
if ( StructureToDeploy = = STRUCTURE_MARINE_TURRET )
{
int NumAttempts = 0 ;
while ( NumAttempts < 5 )
{
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , TurretFactory . Location , ( BALANCE_VAR ( kTurretFactoryBuildDistance ) * 0.8f ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius ( GetBaseNavProfile ( MARINE_BASE_NAV_PROFILE ) , TurretFactory . Location , ( BALANCE_VAR ( kTurretFactoryBuildDistance ) * 0.8f ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
2024-06-05 19:32:15 +00:00
}
2024-06-12 19:21:55 +00:00
NumAttempts + + ;
}
return pBot - > Player - > GetResources ( ) < = 15 ;
}
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation ( StructureToDeploy , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
2024-06-28 11:06:36 +00:00
if ( StructureToDeploy = = STRUCTURE_MARINE_TURRETFACTORY )
{
if ( NumTurrets > 0 )
{
Vector Centroid = ZERO_VECTOR ;
for ( auto tLocs = TurretLocations . begin ( ) ; tLocs ! = TurretLocations . end ( ) ; tLocs + + )
{
Centroid = Centroid + * tLocs ;
}
Centroid = Centroid / TurretLocations . size ( ) ;
if ( ! vIsZero ( Centroid ) )
{
Vector CentroidBuildLocation = UTIL_ProjectPointToNavmesh ( Centroid , GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) ) ;
if ( ! vIsZero ( CentroidBuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , CentroidBuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
}
}
}
}
2024-06-12 19:21:55 +00:00
int NumAttempts = 0 ;
while ( NumAttempts < 5 )
{
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability ( GetBaseNavProfile ( STRUCTURE_BASE_NAV_PROFILE ) , BaseToBuildOut - > BaseLocation , UTIL_MetresToGoldSrcUnits ( 5.0f ) ) ;
if ( ! vIsZero ( BuildLocation ) )
{
bool bSuccess = AICOMM_AddStructureToBase ( pBot , StructureToDeploy , BuildLocation , BaseToBuildOut ) ;
if ( bSuccess ) { return true ; }
2024-06-05 19:32:15 +00:00
}
NumAttempts + + ;
}
2024-06-12 19:21:55 +00:00
return pBot - > Player - > GetResources ( ) < = 15 ;
2024-06-05 19:32:15 +00:00
}
2024-06-12 19:21:55 +00:00
AvHAIMarineBase * AICOMM_AddNewBase ( AvHAIPlayer * pBot , Vector NewBaseLocation , MarineBaseType NewBaseType )
2024-06-05 19:32:15 +00:00
{
AvHAIMarineBase NewBase ;
NewBase . BaseLocation = NewBaseLocation ;
NewBase . BaseType = NewBaseType ;
NewBase . BaseTeam = pBot - > Player - > GetTeam ( ) ;
pBot - > Bases . push_back ( NewBase ) ;
2024-06-12 19:21:55 +00:00
return & pBot - > Bases . back ( ) ;
}
bool AICOMM_AddStructureToBase ( AvHAIPlayer * pBot , AvHAIDeployableStructureType StructureToDeploy , Vector BuildLocation , AvHAIMarineBase * BaseToAdd )
{
2024-06-28 11:06:36 +00:00
if ( ! BaseToAdd | | vIsZero ( BuildLocation ) ) { return false ; }
2024-06-12 19:21:55 +00:00
AvHAIBuildableStructure * DeployedStructure = AICOMM_DeployStructure ( pBot , StructureToDeploy , BuildLocation ) ;
if ( DeployedStructure )
{
BaseToAdd - > PlacedStructures . push_back ( DeployedStructure - > EntIndex ) ;
BaseToAdd - > bBaseInitialised = true ;
2024-06-28 11:06:36 +00:00
if ( BaseToAdd - > BaseType = = MARINE_BASE_MAINBASE )
{
DeployedStructure - > Purpose = STRUCTURE_PURPOSE_BASE ;
}
else if ( BaseToAdd - > BaseType = = MARINE_BASE_SIEGE )
{
DeployedStructure - > Purpose = STRUCTURE_PURPOSE_SIEGE ;
}
else
{
DeployedStructure - > Purpose = STRUCTURE_PURPOSE_FORTIFY ;
}
2024-06-12 19:21:55 +00:00
return true ;
}
return false ;
2024-03-21 18:17:18 +00:00
}