More bug fixes

* Fixed bots getting stuck on top of railings sometimes. Also hopefully fixed issues with bots aborting wall climbs for no reason.
* Fixed issue with duplicate base structures being dropped
* Fixed an issue where marines would become listless if the aliens had 3 hives up and they didn't have phase tech researched. They should continue to attack regardless
* Fixed issue where gorges would go nuts when trying to build defensive structures in an empty hive
* Aliens should be much more focused on evolving into fade/onos, including ignoring a hive under attack to first evolve so they can defend more effectively
This commit is contained in:
RGreenlees 2024-04-25 19:28:50 +01:00 committed by pierow
parent f6796ad025
commit e8a85852e8
11 changed files with 489 additions and 168 deletions

View file

@ -988,6 +988,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
StructureFilter.ReachabilityFlags = AI_REACHABILITY_MARINE;
StructureFilter.ReachabilityTeam = TeamNumber;
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
StructureFilter.PurposeFlags = STRUCTURE_PURPOSE_BASE;
edict_t* BaseBuilder = AITAC_GetNearestHiddenPlayerInLocation(TeamNumber, CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
@ -1002,6 +1003,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
}
StructureFilter.DeployableTypes = (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY);
StructureFilter.PurposeFlags = STRUCTURE_PURPOSE_BASE;
AvHAIBuildableStructure BaseArmoury = AITAC_FindClosestDeployableToLocation(CommChair->v.origin, &StructureFilter);
@ -1015,7 +1017,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase)
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation);
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
@ -1035,7 +1037,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase)
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation);
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
@ -1050,7 +1052,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase)
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation);
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
@ -1079,7 +1081,8 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (AITAC_PhaseGatesAvailable(TeamNumber))
{
StructureFilter.DeployableTypes = STRUCTURE_MARINE_PHASEGATE;
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f);
StructureFilter.PurposeFlags = STRUCTURE_PURPOSE_BASE;
bool bPhaseNearBase = AITAC_DeployableExistsAtLocation(CommChair->v.origin, &StructureFilter);
@ -1094,7 +1097,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase)
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation);
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
@ -1106,7 +1109,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
{
bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f));
bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation);
bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kPhaseGateCost) + 10) { return true; }
}
}
@ -1133,8 +1136,84 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (AICOMM_ShouldCommanderPrioritiseNodes(pBot) && pBot->Player->GetResources() < 30) { return false; }
StructureFilter.DeployableTypes = (STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY);
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f);
StructureFilter.PurposeFlags = STRUCTURE_PURPOSE_BASE;
AvHAIBuildableStructure TF = AITAC_FindClosestDeployableToLocation(CommChair->v.origin, &StructureFilter);
if (!TF.IsValid())
{
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation(STRUCTURE_MARINE_TURRETFACTORY, CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
if (!vIsZero(BuildLocation))
{
bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f));
if (!bEnemyInBase)
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
if (!vIsZero(BuildLocation))
{
bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f));
bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kTurretFactoryCost) + 5) { return true; }
}
}
if (TF.IsValid() && (TF.StructureStatusFlags & STRUCTURE_STATUS_COMPLETED))
{
StructureFilter.DeployableTypes = (STRUCTURE_MARINE_TURRET);
StructureFilter.MaxSearchRadius = BALANCE_VAR(kTurretFactoryBuildDistance);
StructureFilter.PurposeFlags = STRUCTURE_PURPOSE_BASE;
int NumTurrets = AITAC_GetNumDeployablesNearLocation(TF.Location, &StructureFilter);
if (NumTurrets < 5)
{
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), TF.Location, (BALANCE_VAR(kTurretFactoryBuildDistance) * 0.8f));
if (!vIsZero(BuildLocation))
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), TF.Location, (BALANCE_VAR(kTurretFactoryBuildDistance) * 0.8f));
if (!vIsZero(BuildLocation))
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kSentryCost) + 5) { return true; }
}
}
else
{
if (!(TF.StructureStatusFlags & STRUCTURE_STATUS_ELECTRIFIED) && pBot->Player->GetResources() > 50)
{
bool bSuccess = AICOMM_ResearchTech(pBot, &TF, RESEARCH_ELECTRICAL);
if (bSuccess) { return true; }
}
}
}
StructureFilter.DeployableTypes = STRUCTURE_MARINE_ARMSLAB;
StructureFilter.MaxSearchRadius = 0.0f;
StructureFilter.PurposeFlags = STRUCTURE_PURPOSE_BASE;
bool bHasArmsLab = AITAC_DeployableExistsAtLocation(CommChair->v.origin, &StructureFilter);
@ -1148,7 +1227,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase)
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMSLAB, BuildLocation);
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMSLAB, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
@ -1160,20 +1239,20 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
{
bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f));
bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMSLAB, BuildLocation);
bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMSLAB, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kArmsLabCost) + 10) { return true; }
}
}
StructureFilter.DeployableTypes = STRUCTURE_MARINE_OBSERVATORY;
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f);
StructureFilter.PurposeFlags = STRUCTURE_PURPOSE_BASE;
bool bHasObservatory = AITAC_DeployableExistsAtLocation(CommChair->v.origin, &StructureFilter);
if (!bHasObservatory && !FNullEnt(BaseBuilder))
{
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation(STRUCTURE_MARINE_OBSERVATORY, CommChair->v.origin, UTIL_MetresToGoldSrcUnits(15.0f));
if (!vIsZero(BuildLocation))
@ -1182,7 +1261,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase)
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_OBSERVATORY, BuildLocation);
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_OBSERVATORY, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
@ -1194,7 +1273,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
{
bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f));
bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_OBSERVATORY, BuildLocation);
bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_OBSERVATORY, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kObservatoryCost) + 10) { return true; }
@ -1214,7 +1293,9 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kTurretFactoryCost) + 5) { return true; }
}
StructureFilter.MaxSearchRadius = 0.0f;
StructureFilter.DeployableTypes = STRUCTURE_MARINE_ADVARMOURY;
StructureFilter.PurposeFlags = STRUCTURE_PURPOSE_BASE;
bool bHasAdvArmoury = AITAC_DeployableExistsAtLocation(CommChair->v.origin, &StructureFilter);
bool bIsResearchingArmoury = false;
@ -1225,7 +1306,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
StructureFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
StructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING | STRUCTURE_STATUS_RESEARCHING;
AvHAIBuildableStructure NearestArmoury = AITAC_FindClosestDeployableToLocation(CommChair->v.origin, &StructureFilter);
if (NearestArmoury.IsValid())
@ -1246,6 +1327,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f);
StructureFilter.IncludeStatusFlags = STRUCTURE_STATUS_NONE;
StructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
StructureFilter.PurposeFlags = STRUCTURE_PURPOSE_BASE;
bool bHasPrototypeLab = AITAC_DeployableExistsAtLocation(CommChair->v.origin, &StructureFilter);
@ -1259,7 +1341,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase)
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PROTOTYPELAB, BuildLocation);
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PROTOTYPELAB, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
@ -1273,7 +1355,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase)
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PROTOTYPELAB, BuildLocation);
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PROTOTYPELAB, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
@ -1287,7 +1369,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase)
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PROTOTYPELAB, BuildLocation);
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PROTOTYPELAB, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess || pBot->Player->GetResources() < BALANCE_VAR(kPrototypeLabCost) + 20) { return true; }
}
@ -1302,6 +1384,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
StructureFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
StructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING | STRUCTURE_STATUS_ELECTRIFIED;
StructureFilter.MaxSearchRadius = 0.0f;
StructureFilter.PurposeFlags = STRUCTURE_PURPOSE_ANY;
AvHAIBuildableStructure ResTower = AITAC_FindFurthestDeployableFromLocation(CommChair->v.origin, &StructureFilter);
@ -2238,7 +2321,7 @@ bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair)
if (!vIsZero(BuildLocation))
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation);
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
@ -2272,7 +2355,7 @@ bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair)
if (!vIsZero(BuildLocation))
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation);
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
@ -2284,7 +2367,7 @@ bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair)
if (vIsZero(BuildLocation)) { return false; }
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation);
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE);
}
bool AICOMM_CheckForNextRecycleAction(AvHAIPlayer* pBot)

View file

@ -14,7 +14,7 @@
static const float MIN_COMMANDER_REMIND_TIME = 20.0f; // How frequently the commander can nag a player to do something, if they don't think they're doing it
bool AICOMM_DeployStructure(AvHAIPlayer* pBot, const AvHAIDeployableStructureType StructureToDeploy, const Vector Location, StructurePurpose Purpose = STRUCTURE_PURPOSE_NONE);
bool AICOMM_DeployStructure(AvHAIPlayer* pBot, const AvHAIDeployableStructureType StructureToDeploy, const Vector Location, StructurePurpose Purpose = STRUCTURE_PURPOSE_GENERAL);
bool AICOMM_DeployItem(AvHAIPlayer* pBot, const AvHAIDeployableItemType ItemToDeploy, const Vector Location);
bool AICOMM_UpgradeStructure(AvHAIPlayer* pBot, AvHAIBuildableStructure* StructureToUpgrade);
bool AICOMM_ResearchTech(AvHAIPlayer* pBot, AvHAIBuildableStructure* StructureToResearch, AvHMessageID Research);

View file

@ -169,8 +169,11 @@ typedef enum
typedef enum _STRUCTUREPURPOSE
{
STRUCTURE_PURPOSE_NONE = 0,
STRUCTURE_PURPOSE_SIEGE,
STRUCTURE_PURPOSE_FORTIFY
STRUCTURE_PURPOSE_GENERAL = 1u,
STRUCTURE_PURPOSE_SIEGE = 1u << 1,
STRUCTURE_PURPOSE_FORTIFY = 1u << 2,
STRUCTURE_PURPOSE_BASE = 1u << 3,
STRUCTURE_PURPOSE_ANY = -1
} StructurePurpose;
@ -308,6 +311,7 @@ typedef struct _DEPLOYABLE_SEARCH_FILTER
bool bConsiderPhaseDistance = false;
AvHTeamNumber DeployableTeam = TEAM_IND;
AvHTeamNumber ReachabilityTeam = TEAM_IND;
unsigned int PurposeFlags = STRUCTURE_PURPOSE_ANY;
} DeployableSearchFilter;
// Pending message a bot wants to say. Allows for a delay in sending a message to simulate typing, or prevent too many messages on the same frame
@ -350,7 +354,7 @@ typedef struct _AVH_AI_BUILDABLE_STRUCTURE
vector<AvHAIOffMeshConnection> OffMeshConnections; // References to any off-mesh connections this structure is associated with
Vector LastSuccessfulCommanderLocation = g_vecZero; // Tracks the last commander view location where it successfully placed or selected the building
Vector LastSuccessfulCommanderAngle = g_vecZero; // Tracks the last commander input angle ("click" location) used to successfully place or select building
StructurePurpose Purpose = STRUCTURE_PURPOSE_NONE;
StructurePurpose Purpose = STRUCTURE_PURPOSE_GENERAL;
bool bReachabilityMarkedDirty = false; // If true, reachability flags will be recalculated for this structure
bool IsValid() { return !FNullEnt(edict) && !edict->free && !(edict->v.flags & EF_NODRAW) && edict->v.deadflag == DEAD_NO; }
@ -489,7 +493,7 @@ typedef struct _ENEMY_STATUS
float LastDetectedTime = 0.0f; // When the bot last saw the enemy or they pinged on motion tracking
float InitialAwarenessTime = 0.0f; // When the bot first became aware of the enemy
float LastVisibleTime = 0.0f; // Last time the bot actually saw the enemy
float EnemyThreatLevel = 0.0f;
float EnemyThreatLevel = 0.0f; // Generally, >=3.0 means actively fighting them, >=2.0 means visible and close, >=1.0 means not visible but close and <1.0 means they can be heard but not close
bool bHasLOS = false; // Does the bot has LOS of the enemy?
bool bEnemyHasLOS = false;

View file

@ -554,7 +554,7 @@ void UTIL_DrawHUDText(edict_t* pEntity, char channel, float x, float y, unsigned
WRITE_BYTE(1); // effect ALPHA
WRITE_SHORT(0); // fade-in time in seconds * 256
WRITE_SHORT(0); // fade-out time in seconds * 256
WRITE_SHORT(5); // hold time in seconds * 256
WRITE_SHORT(20); // hold time in seconds * 256
WRITE_STRING(string);//string); // send the string
MESSAGE_END(); // end
@ -646,4 +646,78 @@ void UTIL_LocalizeText(const char* InputText, string& OutputText)
LocalizedLocationsMap[InputText] = OutputText;
}
char* UTIL_TaskTypeToChar(const BotTaskType TaskType)
{
switch (TaskType)
{
case TASK_ATTACK:
return "Attack";
case TASK_BUILD:
return "Build";
case TASK_CAP_RESNODE:
return "Cap Res Node";
case TASK_COMMAND:
return "Take Command";
case TASK_DEFEND:
return "Defend Structure";
case TASK_EVOLVE:
return "Evolve";
case TASK_GET_AMMO:
return "Get Ammo Pack";
case TASK_GET_EQUIPMENT:
return "Get Equipment";
case TASK_GET_HEALTH:
return "Get Health Pack";
case TASK_GET_WEAPON:
return "Get Weapon";
case TASK_GUARD:
return "Guard";
case TASK_HEAL:
return "Heal Target";
case TASK_MOVE:
return "Move to Location";
case TASK_PLACE_MINE:
return "Place Mine";
case TASK_REINFORCE_STRUCTURE:
return "Reinforce Structure";
case TASK_RESUPPLY:
return "Resupply";
case TASK_SECURE_HIVE:
return "Secure Hive";
case TASK_TOUCH:
return "Touch Trigger";
case TASK_WELD:
return "Weld Target";
default:
return "None";
}
return "None";
}
char* UTIL_BotRoleToChar(const AvHAIBotRole Role)
{
switch (Role)
{
case BOT_ROLE_ASSAULT:
return "Assault";
case BOT_ROLE_BOMBARDIER:
return "Bombardier";
case BOT_ROLE_BUILDER:
return "Builder";
case BOT_ROLE_COMMAND:
return "Commander";
case BOT_ROLE_FIND_RESOURCES:
return "Res Capper";
case BOT_ROLE_HARASS:
return "Harrasser";
case BOT_ROLE_SWEEPER:
return "Sweeper";
default:
return "None";
}
return "None";
}

View file

@ -59,4 +59,8 @@ void UTIL_DrawHUDText(edict_t* pEntity, char channel, float x, float y, unsigned
void UTIL_ClearLocalizations();
void UTIL_LocalizeText(const char* InputText, string& OutputText);
char* UTIL_TaskTypeToChar(const BotTaskType TaskType);
char* UTIL_BotRoleToChar(const AvHAIBotRole Role);
#endif

View file

@ -2069,7 +2069,17 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle,
Vector FromLocation = pBot->CurrentFloorPosition;
Vector FromFloorLocation = AdjustPointForPathfinding(FromLocation);
// Add a slight bias towards trying to move forward if on a railing or other narrow bit of navigable terrain
// rather than potentially dropping back off it the wrong way
Vector GeneralDir = UTIL_GetVectorNormal2D(ToLocation - pBot->CurrentFloorPosition);
Vector CheckLocation = FromLocation + (GeneralDir * 16.0f);
Vector FromFloorLocation = AdjustPointForPathfinding(CheckLocation);
if (vIsZero(FromFloorLocation))
{
FromFloorLocation = AdjustPointForPathfinding(FromLocation);
}
nav_door* LiftReference = UTIL_GetLiftReferenceByEdict(pBot->Edict->v.groundentity);
bool bMustDisembarkLiftFirst = false;
@ -4852,20 +4862,6 @@ void WallClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndP
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(pBot->desiredMovementDir + (vRight * modifier));
}
// Jump if we're on the floor, to give ourselves a boost and remove that momentary pause while "wall-sticking" mode activates if skulk
if ((pEdict->v.flags & FL_ONGROUND) && !IsPlayerClimbingWall(pBot->Edict))
{
Vector CurrentVelocity = UTIL_GetVectorNormal2D(pBot->Edict->v.velocity);
float VelocityDot = UTIL_GetDotProduct2D(vForward, CurrentVelocity);
if (VelocityDot > 0.7f)
{
// This was causing issues in tight areas, rethink this
//BotJump(pBot);
}
}
// Stop holding crouch if we're a skulk so we can actually climb
if (IsPlayerSkulk(pBot->Edict))
{
@ -4899,20 +4895,12 @@ void WallClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndP
else
{
LookLocation = DirectAheadView - Vector(0.0f, 0.0f, 20.0f);
//LookLocation = pBot->CurrentEyePosition + (ClimbSurfaceNormal * 100.0f);
}
}
else
{
if (ZDiff > 16.0f)
{
ClimbSurfaceNormal = ClimbSurfaceNormal;
LookLocation = pBot->CurrentEyePosition + (ClimbSurfaceNormal * 100.0f);
}
else
{
LookLocation = DirectAheadView + Vector(0.0f, 0.0f, 20.0f);
}
ClimbSurfaceNormal = ClimbSurfaceNormal;
LookLocation = pBot->CurrentEyePosition + (ClimbSurfaceNormal * 100.0f);
}
}
@ -6437,12 +6425,12 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
bool bSucceeded = NAV_GenerateNewBasePath(pBot, Destination, MoveStyle, MaxAcceptableDist);
if (!bSucceeded)
{
if (pBot->BotNavInfo.CurrentPath.size() == 0)
{
pBot->BotNavInfo.StuckInfo.bPathFollowFailed = true;
{
pBot->BotNavInfo.StuckInfo.bPathFollowFailed = true;
if (!UTIL_PointIsOnNavmesh(pBot->CollisionHullBottomLocation, pBot->BotNavInfo.NavProfile) && !vIsZero(BotNavInfo->LastNavMeshPosition))
if (!UTIL_PointIsOnNavmesh(pBot->CollisionHullBottomLocation, pBot->BotNavInfo.NavProfile))
{
if (!vIsZero(BotNavInfo->LastNavMeshPosition))
{
MoveDirectlyTo(pBot, BotNavInfo->LastNavMeshPosition);
@ -6451,7 +6439,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
BotNavInfo->LastNavMeshPosition = g_vecZero;
}
return true;
return false;
}
else
{
@ -6462,19 +6450,20 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
if (vIsZero(BotNavInfo->UnstuckMoveLocation))
{
BotNavInfo->UnstuckMoveLocation = FindClosestPointBackOnPath(pBot);
BotNavInfo->UnstuckMoveLocation = FindClosestPointBackOnPath(pBot, Destination);
}
if (!vIsZero(BotNavInfo->UnstuckMoveLocation))
{
MoveDirectlyTo(pBot, BotNavInfo->UnstuckMoveLocation);
return true;
return false;
}
}
}
else
{
BotFollowPath(pBot);
MoveDirectlyTo(pBot, Destination);
return false;
}
return false;
@ -6486,17 +6475,6 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
if (!bSucceeded)
{
if (!FNullEnt(pBot->Edict->v.groundentity))
{
nav_door* Door = UTIL_GetNavDoorByEdict(pBot->Edict->v.groundentity);
if (Door)
{
}
}
if (!FNullEnt(BotNavInfo->MovementTask.TaskTarget))
{
CBaseEntity* TargetEntity = CBaseEntity::Instance(BotNavInfo->MovementTask.TaskTarget);
@ -6587,26 +6565,33 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
}
Vector FindClosestPointBackOnPath(AvHAIPlayer* pBot)
Vector FindClosestPointBackOnPath(AvHAIPlayer* pBot, Vector Destination)
{
Vector GeneralMoveDir = UTIL_GetVectorNormal2D(Destination - pBot->Edict->v.origin);
Vector CheckDir = pBot->Edict->v.origin + (GeneralMoveDir * 16.0f);
DeployableSearchFilter ResNodeFilter;
ResNodeFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
AvHAIResourceNode* NearestResNode = AITAC_FindNearestResourceNodeToLocation(pBot->Edict->v.origin, &ResNodeFilter);
Vector ValidNavmeshPoint = AITAC_GetTeamStartingLocation(pBot->Player->GetTeam());
if (NearestResNode && vDist2D(pBot->Edict->v.origin, NearestResNode->Location) < vDist2D(pBot->Edict->v.origin, ValidNavmeshPoint))
{
ValidNavmeshPoint = NearestResNode->Location;
}
ValidNavmeshPoint = UTIL_ProjectPointToNavmesh(ValidNavmeshPoint, pBot->BotNavInfo.NavProfile);
Vector ValidNavmeshPoint = AdjustPointForPathfinding(CheckDir);
if (vIsZero(ValidNavmeshPoint))
{
return g_vecZero;
DeployableSearchFilter ResNodeFilter;
ResNodeFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
AvHAIResourceNode* NearestResNode = AITAC_FindNearestResourceNodeToLocation(pBot->Edict->v.origin, &ResNodeFilter);
Vector ValidNavmeshPoint = AITAC_GetTeamStartingLocation(pBot->Player->GetTeam());
if (NearestResNode && vDist2D(pBot->Edict->v.origin, NearestResNode->Location) < vDist2D(pBot->Edict->v.origin, ValidNavmeshPoint))
{
ValidNavmeshPoint = NearestResNode->Location;
}
ValidNavmeshPoint = UTIL_ProjectPointToNavmesh(ValidNavmeshPoint, pBot->BotNavInfo.NavProfile);
if (vIsZero(ValidNavmeshPoint))
{
return g_vecZero;
}
}
vector<bot_path_node> BackwardsPath;
@ -6829,9 +6814,6 @@ LerkFlightBehaviour BotFlightClimbMove(AvHAIPlayer* pBot, Vector FromLocation, V
pBot->Edict->v.velocity.z = fmaxf(pBot->Edict->v.velocity.z, 10.0f);
}
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->Edict->v.origin + UTIL_GetVectorNormal(pBot->Edict->v.velocity) * 100.0f, 255, 0, 0);
return FLIGHT_FLAP;
}

View file

@ -371,7 +371,7 @@ dtStatus FindPathClosestToPoint(const nav_profile& NavProfile, const Vector From
dtStatus DEBUG_TestFindPath(const nav_profile& NavProfile, const Vector FromLocation, const Vector ToLocation, vector<bot_path_node>& path, float MaxAcceptableDistance);
// If the bot is stuck and off the path or nav mesh, this will try to find a point it can directly move towards to get it back on track
Vector FindClosestPointBackOnPath(AvHAIPlayer* pBot);
Vector FindClosestPointBackOnPath(AvHAIPlayer* pBot, Vector Destination);
Vector FindClosestNavigablePointToDestination(const nav_profile& NavProfile, const Vector FromLocation, const Vector ToLocation, float MaxAcceptableDistance);

View file

@ -392,9 +392,9 @@ bool BotReloadWeapons(AvHAIPlayer* pBot)
if (IsPlayerReloading(pBot->Player))
{
pBot->DesiredCombatWeapon = GetPlayerCurrentWeapon(pBot->Player);
return true;
}
AvHAIWeapon PrimaryWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player);
AvHAIWeapon SecondaryWeapon = GetBotMarineSecondaryWeapon(pBot);
AvHAIWeapon CurrentWeapon = GetPlayerCurrentWeapon(pBot->Player);
@ -2172,8 +2172,25 @@ void UpdateAIMarinePlayerNSRole(AvHAIPlayer* pBot)
int NumSweeperBots = AIMGR_GetNumAIPlayersWithRoleOnTeam(BotTeamNumber, BOT_ROLE_SWEEPER, pBot);
int NumDesiredSweeperBots = 1;
if (NumSweeperBots < 2)
{
DeployableSearchFilter DefenceStructuresFilter;
DefenceStructuresFilter.DeployableTeam = BotTeamNumber;
DefenceStructuresFilter.DeployableTypes = (STRUCTURE_MARINE_TURRET | STRUCTURE_MARINE_OBSERVATORY);
DefenceStructuresFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
DefenceStructuresFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
DefenceStructuresFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
if (!AITAC_DeployableExistsAtLocation(AITAC_GetTeamStartingLocation(BotTeamNumber), &DefenceStructuresFilter))
{
NumDesiredSweeperBots = 2;
}
}
// Always have a sweeper
if (NumSweeperBots < 1)
if (NumSweeperBots < NumDesiredSweeperBots)
{
SetNewAIPlayerRole(pBot, BOT_ROLE_SWEEPER);
return;
@ -2208,18 +2225,18 @@ void AIPlayerNSThink(AvHAIPlayer* pBot)
{
AvHTeam* BotTeam = GetGameRules()->GetTeam(pBot->Player->GetTeam());
if (!BotTeam) { return; }
if (!BotTeam) { return; }
pBot->CurrentEnemy = BotGetNextEnemyTarget(pBot);
pBot->CurrentEnemy = BotGetNextEnemyTarget(pBot);
if (BotTeam->GetTeamType() == AVH_CLASS_TYPE_MARINE)
{
AIPlayerNSMarineThink(pBot);
}
else
{
AIPlayerNSAlienThink(pBot);
}
if (BotTeam->GetTeamType() == AVH_CLASS_TYPE_MARINE)
{
AIPlayerNSMarineThink(pBot);
}
else
{
AIPlayerNSAlienThink(pBot);
}
}
int BotGetNextEnemyTarget(AvHAIPlayer* pBot)
@ -2266,18 +2283,18 @@ AvHAICombatStrategy GetAlienCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_sta
switch (PlayerUser3)
{
case AVH_USER3_ALIEN_PLAYER1:
return GetSkulkCombatStrategyForTarget(pBot, CurrentEnemy);
case AVH_USER3_ALIEN_PLAYER2:
return GetGorgeCombatStrategyForTarget(pBot, CurrentEnemy);
case AVH_USER3_ALIEN_PLAYER3:
return GetLerkCombatStrategyForTarget(pBot, CurrentEnemy);
case AVH_USER3_ALIEN_PLAYER4:
return GetFadeCombatStrategyForTarget(pBot, CurrentEnemy);
case AVH_USER3_ALIEN_PLAYER5:
return GetOnosCombatStrategyForTarget(pBot, CurrentEnemy);
default:
return COMBAT_STRATEGY_IGNORE;
case AVH_USER3_ALIEN_PLAYER1:
return GetSkulkCombatStrategyForTarget(pBot, CurrentEnemy);
case AVH_USER3_ALIEN_PLAYER2:
return GetGorgeCombatStrategyForTarget(pBot, CurrentEnemy);
case AVH_USER3_ALIEN_PLAYER3:
return GetLerkCombatStrategyForTarget(pBot, CurrentEnemy);
case AVH_USER3_ALIEN_PLAYER4:
return GetFadeCombatStrategyForTarget(pBot, CurrentEnemy);
case AVH_USER3_ALIEN_PLAYER5:
return GetOnosCombatStrategyForTarget(pBot, CurrentEnemy);
default:
return COMBAT_STRATEGY_IGNORE;
}
}
@ -2305,7 +2322,15 @@ AvHAICombatStrategy GetSkulkCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_sta
return COMBAT_STRATEGY_ATTACK;
}
if (CurrentEnemy->EnemyThreatLevel < 2.0f && (gpGlobals->time - CurrentEnemy->LastVisibleTime > 5.0f))
if (pBot->CurrentTask->TaskType == TASK_EVOLVE)
{
if (CurrentEnemy->EnemyThreatLevel < 3.0f || !CurrentEnemy->bHasLOS)
{
return COMBAT_STRATEGY_IGNORE;
}
}
if (CurrentEnemy->EnemyThreatLevel < 2.0f && gpGlobals->time - CurrentEnemy->LastVisibleTime > 5.0f)
{
return COMBAT_STRATEGY_IGNORE;
}
@ -3698,10 +3723,43 @@ void AIPlayerSetMarineAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
{
DeployableSearchFilter AnyEnemyStuff;
AnyEnemyStuff.DeployableTeam = EnemyTeam;
AnyEnemyStuff.DeployableTypes = SEARCH_ALL_STRUCTURES;
AnyEnemyStuff.DeployableTypes = SEARCH_ANY_RES_TOWER;
AnyEnemyStuff.ReachabilityTeam = BotTeam;
AnyEnemyStuff.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
AvHAIBuildableStructure EnemyRT = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &AnyEnemyStuff);
if (EnemyRT.IsValid())
{
AITASK_SetAttackTask(pBot, Task, EnemyRT.edict, false);
return;
}
if (AIMGR_GetEnemyTeamType(EnemyTeam) == AVH_CLASS_TYPE_ALIEN)
{
const AvHAIHiveDefinition* ActiveHive = AITAC_GetActiveHiveNearestLocation(AIMGR_GetEnemyTeam(BotTeam), pBot->Edict->v.origin);
if (ActiveHive)
{
AITASK_SetAttackTask(pBot, Task, ActiveHive->HiveEdict, false);
return;
}
}
else
{
AnyEnemyStuff.DeployableTypes = STRUCTURE_MARINE_COMMCHAIR;
AvHAIBuildableStructure EnemyCommChair = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &AnyEnemyStuff);
if (EnemyCommChair.IsValid())
{
AITASK_SetAttackTask(pBot, Task, EnemyCommChair.edict, false);
return;
}
}
AnyEnemyStuff.DeployableTypes = SEARCH_ALL_STRUCTURES;
AvHAIBuildableStructure EnemyStructure = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &AnyEnemyStuff);
if (EnemyStructure.IsValid())
@ -3723,10 +3781,6 @@ void AIPlayerSetMarineBombardierPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask*
void AIPlayerSetWantsAndNeedsCOMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
{
if (BotReloadWeapons(pBot)) { return; }
}
if (Task->TaskType == TASK_RESUPPLY) { return; }
@ -3774,10 +3828,6 @@ void AIPlayerSetWantsAndNeedsCOMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Ta
void AIPlayerSetWantsAndNeedsMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
{
if (BotReloadWeapons(pBot)) { return; }
}
if (Task->TaskType == TASK_RESUPPLY || Task->TaskType == TASK_GET_HEALTH || Task->TaskType == TASK_GET_AMMO) { return; }
@ -5479,25 +5529,8 @@ void AIPlayerThink(AvHAIPlayer* pBot)
AIDEBUG_DrawBotPath(pBot);
if (pBot->BotNavInfo.CurrentPath.size() > 0 && pBot->BotNavInfo.CurrentPathPoint < pBot->BotNavInfo.CurrentPath.size())
{
bot_path_node CurrentPathNode = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint];
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, CurrentPathNode.FromLocation, 255, 0, 0);
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, CurrentPathNode.Location, 0, 128, 0);
}
if (pBot->CurrentTask && pBot->CurrentTask->TaskType != TASK_NONE)
{
if (!FNullEnt(pBot->CurrentTask->TaskTarget))
{
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->CurrentTask->TaskTarget->v.origin, 255, 0, 0);
}
if (!vIsZero(pBot->CurrentTask->TaskLocation))
{
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->CurrentTask->TaskLocation, 255, 0, 0);
}
}
DEBUG_PrintTaskInfo(pBot);
//DEBUG_PrintCombatInfo(pBot);
}
#endif
@ -6987,6 +7020,12 @@ void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
return;
}
if (pBot->PrimaryBotTask.TaskType == TASK_EVOLVE)
{
AITASK_ClearBotTask(pBot, &pBot->SecondaryBotTask);
return;
}
vector<AvHAIHiveDefinition*> AllHives = AITAC_GetAllTeamHives(BotTeam, false);
AvHAIHiveDefinition* HiveToDefend = nullptr;
@ -7105,6 +7144,21 @@ void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
}
if (pBot->PrimaryBotTask.TaskType == TASK_CAP_RESNODE)
{
float ResourceCost = BALANCE_VAR(kResourceTowerCost);
if (!IsPlayerGorge(pBot->Edict))
{
ResourceCost += BALANCE_VAR(kGorgeCost);
}
if (pBot->Player->GetResources() >= ResourceCost)
{
AITASK_ClearBotTask(pBot, &pBot->SecondaryBotTask);
return;
}
}
DeployableSearchFilter AttackedStructuresFilter;
AttackedStructuresFilter.DeployableTypes = (IsPlayerLerk(pBot->Edict)) ? SEARCH_ALL_STRUCTURES : STRUCTURE_ALIEN_RESTOWER;
AttackedStructuresFilter.DeployableTeam = BotTeam;
@ -7612,6 +7666,8 @@ bool GorgeCombatThink(AvHAIPlayer* pBot)
float CurrentHealthPercent = GetPlayerOverallHealthPercent(pBot->Edict);
bool bPlayerCloaked = UTIL_IsCloakedPlayerInvisible(CurrentEnemy, pBot->Player);
if (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_RETREAT)
{
BotAttackResult AttackResult = PerformAttackLOSCheck(pBot, WEAPON_GORGE_SPIT, CurrentEnemy);
@ -7631,19 +7687,24 @@ bool GorgeCombatThink(AvHAIPlayer* pBot)
if (!bInHealingRange)
{
pBot->BotNavInfo.bShouldWalk = bPlayerCloaked && TrackedEnemyRef->bEnemyHasLOS;
MoveTo(pBot, UTIL_GetEntityGroundLocation(NearestHealingSource), MOVESTYLE_NORMAL, DesiredDistFromHealingSource);
if (CurrentHealthPercent > 0.5f && AttackResult == ATTACK_SUCCESS)
if (!bPlayerCloaked)
{
BotShootTarget(pBot, WEAPON_GORGE_SPIT, CurrentEnemy);
}
else
{
pBot->DesiredCombatWeapon = WEAPON_GORGE_HEALINGSPRAY;
if (GetPlayerCurrentWeapon(pBot->Player) == WEAPON_GORGE_HEALINGSPRAY)
if (CurrentHealthPercent > 0.5f && AttackResult == ATTACK_SUCCESS)
{
pBot->Button |= IN_ATTACK;
BotShootTarget(pBot, WEAPON_GORGE_SPIT, CurrentEnemy);
}
else
{
pBot->DesiredCombatWeapon = WEAPON_GORGE_HEALINGSPRAY;
if (GetPlayerCurrentWeapon(pBot->Player) == WEAPON_GORGE_HEALINGSPRAY)
{
pBot->Button |= IN_ATTACK;
}
}
}
@ -7664,6 +7725,21 @@ bool GorgeCombatThink(AvHAIPlayer* pBot)
return true;
}
// If we're invisible and healing, do nothing. Don't give our position away
if (bPlayerCloaked)
{
if (TrackedEnemyRef->bHasLOS)
{
BotLookAt(pBot, TrackedEnemyRef->LastDetectedLocation);
}
else
{
BotLookAt(pBot, TrackedEnemyRef->LastLOSPosition);
}
return true;
}
if (bOutOfEnemyLOS)
{
if (bInHealingRange)
@ -8385,6 +8461,66 @@ bool OnosCombatThink(AvHAIPlayer* pBot)
return true;
}
void DEBUG_PrintTaskInfo(AvHAIPlayer* pBot)
{
char buf[511];
char interbuf[164];
sprintf(buf, "Task info for %s:\n\n", STRING(pBot->Edict->v.netname));
sprintf(interbuf, "Role: %s\n\n", UTIL_BotRoleToChar(pBot->BotRole));
strcat(buf, interbuf);
if (IsPlayerMarine(pBot->Edict))
{
const char* CommanderTask = UTIL_TaskTypeToChar(pBot->CommanderTask.TaskType);
sprintf(interbuf, "Commander-Issued: %s\n", CommanderTask);
strcat(buf, interbuf);
}
const char* PrimaryTask = UTIL_TaskTypeToChar(pBot->PrimaryBotTask.TaskType);
sprintf(interbuf, "Primary: %s\n", PrimaryTask);
strcat(buf, interbuf);
const char* SecondaryTask = UTIL_TaskTypeToChar(pBot->SecondaryBotTask.TaskType);
sprintf(interbuf, "Secondary: %s\n", SecondaryTask);
strcat(buf, interbuf);
const char* WantAndNeedTask = UTIL_TaskTypeToChar(pBot->WantsAndNeedsTask.TaskType);
sprintf(interbuf, "Want/Need: %s\n\n", WantAndNeedTask);
strcat(buf, interbuf);
if (pBot->CurrentTask)
{
const char* CurrentTask = UTIL_TaskTypeToChar(pBot->CurrentTask->TaskType);
sprintf(interbuf, "Current: %s\n\n", CurrentTask);
strcat(buf, interbuf);
}
if (pBot->CurrentTask && pBot->CurrentTask->TaskType != TASK_NONE)
{
sprintf(interbuf, "Red = Target, Yellow = Location\n");
strcat(buf, interbuf);
if (!FNullEnt(pBot->CurrentTask->TaskTarget))
{
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->CurrentTask->TaskTarget->v.origin, 255, 0, 0);
}
if (!vIsZero(pBot->CurrentTask->TaskLocation))
{
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->CurrentTask->TaskLocation, 255, 255, 0);
}
}
UTIL_DrawHUDText(INDEXENT(1), 0, 0.1f, 0.1f, 255, 255, 255, buf);
}
void DEBUG_PrintCombatInfo(AvHAIPlayer* pBot)
{
char buf[511];
@ -8396,18 +8532,18 @@ void DEBUG_PrintCombatInfo(AvHAIPlayer* pBot)
if (TrackedEnemy < 0)
{
sprintf(interbuf, "Biggest threat: NONE\n\n");
sprintf(interbuf, "Main Threat: NONE\n\n");
}
else
{
sprintf(interbuf, "Biggest threat: %s\n\n", STRING(pBot->TrackedEnemies[TrackedEnemy].PlayerEdict->v.netname));
sprintf(interbuf, "Main Threat: %s\n\n", STRING(pBot->TrackedEnemies[TrackedEnemy].PlayerEdict->v.netname));
}
strcat(buf, interbuf);
if (TrackedEnemy < 0)
{
UTIL_DrawHUDText(INDEXENT(1), 0, 0.1f, 0.1f, 255, 255, 255, buf);
UTIL_DrawHUDText(INDEXENT(1), 0, 0.6f, 0.1f, 255, 255, 255, buf);
return;
}
@ -8434,24 +8570,40 @@ void DEBUG_PrintCombatInfo(AvHAIPlayer* pBot)
strcat(buf, interbuf);
sprintf(interbuf, "Threat: %.2f\n", TrackedInfo->EnemyThreatLevel);
sprintf(interbuf, "Threat: %.2f\n\n", TrackedInfo->EnemyThreatLevel);
strcat(buf, interbuf);
UTIL_DrawHUDText(INDEXENT(1), 0, 0.1f, 0.1f, 255, 255, 255, buf);
AvHAICombatStrategy CurrentStrategy = GetBotCombatStrategyForTarget(pBot, TrackedInfo);
switch (CurrentStrategy)
{
case COMBAT_STRATEGY_AMBUSH:
sprintf(interbuf, "Strategy: Ambush\n");
break;
case COMBAT_STRATEGY_ATTACK:
sprintf(interbuf, "Strategy: Attack\n");
break;
case COMBAT_STRATEGY_IGNORE:
sprintf(interbuf, "Strategy: Ignore\n");
break;
case COMBAT_STRATEGY_RETREAT:
sprintf(interbuf, "Strategy: Retreat\n");
break;
case COMBAT_STRATEGY_SKIRMISH:
sprintf(interbuf, "Strategy: Skirmish\n");
break;
default:
sprintf(interbuf, "Strategy: None\n");
break;
}
strcat(buf, interbuf);
UTIL_DrawHUDText(INDEXENT(1), 0, 0.6f, 0.1f, 255, 255, 255, buf);
if (!vIsZero(TrackedInfo->LastDetectedLocation))
{
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, TrackedInfo->LastDetectedLocation, 255, 0, 0);
}
if (!vIsZero(TrackedInfo->LastLOSPosition))
{
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, TrackedInfo->LastLOSPosition - Vector(0.0f, 0.0f, 5.0f), 255, 255, 0);
}
if (!vIsZero(TrackedInfo->LastVisibleLocation))
{
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, TrackedInfo->LastVisibleLocation + Vector(0.0f, 0.0f, 5.0f), 0, 0, 255);
}
}

View file

@ -184,6 +184,7 @@ bool OnosCombatThink(AvHAIPlayer* pBot);
bool BombardierCombatThink(AvHAIPlayer* pBot);
bool RegularMarineCombatThink(AvHAIPlayer* pBot);
void DEBUG_PrintTaskInfo(AvHAIPlayer* pBot);
void DEBUG_PrintCombatInfo(AvHAIPlayer* pBot);
#endif

View file

@ -89,6 +89,7 @@ std::vector<AvHAIBuildableStructure> AITAC_FindAllDeployables(const Vector& Loca
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE)
{
@ -122,6 +123,7 @@ std::vector<AvHAIBuildableStructure> AITAC_FindAllDeployables(const Vector& Loca
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE)
{
@ -173,6 +175,7 @@ std::vector<AvHAIBuildableStructure*> AITAC_FindAllDeployablesByRef(const Vector
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE)
{
@ -206,6 +209,7 @@ std::vector<AvHAIBuildableStructure*> AITAC_FindAllDeployablesByRef(const Vector
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE)
{
@ -253,6 +257,7 @@ bool AITAC_DeployableExistsAtLocation(const Vector& Location, const DeployableSe
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -283,6 +288,7 @@ bool AITAC_DeployableExistsAtLocation(const Vector& Location, const DeployableSe
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -331,6 +337,7 @@ AvHAIBuildableStructure AITAC_FindClosestDeployableToLocation(const Vector& Loca
if (!(it.second.StructureType & Filter->DeployableTypes)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -360,6 +367,7 @@ AvHAIBuildableStructure AITAC_FindClosestDeployableToLocation(const Vector& Loca
if (!(it.second.StructureType & Filter->DeployableTypes)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -405,7 +413,8 @@ AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocationByRef(const Vector
if (!(it.second.StructureType & Filter->DeployableTypes)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -435,6 +444,7 @@ AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocationByRef(const Vector
if (!(it.second.StructureType & Filter->DeployableTypes)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -481,6 +491,7 @@ AvHAIBuildableStructure AITAC_FindFurthestDeployableFromLocation(const Vector& L
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (!(it.second.StructureType & Filter->DeployableTypes)) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -510,6 +521,7 @@ AvHAIBuildableStructure AITAC_FindFurthestDeployableFromLocation(const Vector& L
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (!(it.second.StructureType & Filter->DeployableTypes)) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -556,6 +568,7 @@ AvHAIBuildableStructure* AITAC_FindFurthestDeployableFromLocationByRef(const Vec
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (!(it.second.StructureType & Filter->DeployableTypes)) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -585,6 +598,7 @@ AvHAIBuildableStructure* AITAC_FindFurthestDeployableFromLocationByRef(const Vec
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (!(it.second.StructureType & Filter->DeployableTypes)) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -787,6 +801,7 @@ AvHAIBuildableStructure AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer*
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -820,6 +835,7 @@ AvHAIBuildableStructure AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer*
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -870,6 +886,7 @@ AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachableByRef(AvHAIP
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -903,6 +920,7 @@ AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachableByRef(AvHAIP
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -952,6 +970,7 @@ int AITAC_GetNumDeployablesNearLocation(const Vector& Location, const Deployable
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
@ -982,6 +1001,7 @@ int AITAC_GetNumDeployablesNearLocation(const Vector& Location, const Deployable
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
if (it.second.Purpose != Filter->PurposeFlags && (it.second.Purpose & Filter->PurposeFlags) != it.second.Purpose) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);

View file

@ -864,8 +864,9 @@ bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTas
if (!FNullEnt(Task->TaskSecondaryTarget) && !UTIL_StructureIsFullyBuilt(Task->TaskSecondaryTarget)) { return true; }
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
if (Task->TaskTarget->v.team != BotTeam) { return false; }
if (Task->TaskTarget->v.team == EnemyTeam) { return false; }
// The reinforce structure task is true if we have an undecided hive available that we could build a new chamber with
bool bActiveHiveWithoutTechExists = AITAC_TeamHiveWithTechExists(pBot->Player->GetTeam(), MESSAGE_NULL);