From 733ad6eb04bb52b2c8c009622fede5f8f7bccf97 Mon Sep 17 00:00:00 2001 From: RGreenlees Date: Mon, 24 Jun 2024 14:23:45 +0100 Subject: [PATCH] Fixed base bugs * Fixed issue where commander would build siege turrets too far from the siege target * Improved commander response to requests for turrets * Nav reachabilities and paths are now regenerated after all nav mesh modifications are updated --- main/source/mod/AvHAICommander.cpp | 125 ++++++++++++++++++++----- main/source/mod/AvHAIConstants.h | 1 + main/source/mod/AvHAIHelper.cpp | 98 +++++++++++++++++-- main/source/mod/AvHAIHelper.h | 1 + main/source/mod/AvHAINavigation.cpp | 53 +++-------- main/source/mod/AvHAIPlayer.cpp | 37 +++++--- main/source/mod/AvHAIPlayerManager.cpp | 58 ++++++++++++ main/source/mod/AvHAIPlayerManager.h | 2 + main/source/mod/AvHAITactical.cpp | 1 - main/source/mod/AvHAITask.cpp | 44 +++++++-- 10 files changed, 327 insertions(+), 93 deletions(-) diff --git a/main/source/mod/AvHAICommander.cpp b/main/source/mod/AvHAICommander.cpp index 11343afb..39432c86 100644 --- a/main/source/mod/AvHAICommander.cpp +++ b/main/source/mod/AvHAICommander.cpp @@ -3166,21 +3166,29 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot) } } - if (NextRequest->RequestType == BUILD_SIEGE) + if (NextRequest->RequestType == BUILD_SIEGE || NextRequest->RequestType == BUILD_TURRET) { DeployableSearchFilter TFFilter; TFFilter.DeployableTeam = CommanderTeam; - TFFilter.DeployableTypes = STRUCTURE_MARINE_ADVTURRETFACTORY; + TFFilter.DeployableTypes = (NextRequest->RequestType == BUILD_SIEGE) ? STRUCTURE_MARINE_ADVTURRETFACTORY : STRUCTURE_MARINE_TURRETFACTORY; TFFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED; TFFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; TFFilter.MaxSearchRadius = BALANCE_VAR(kTurretFactoryBuildDistance); - bool bHasChair = AITAC_DeployableExistsAtLocation(ProjectedDeployLocation, &TFFilter); + bool bHasTF = AITAC_DeployableExistsAtLocation(ProjectedDeployLocation, &TFFilter); - if (!bHasChair) + if (!bHasTF) { char msg[128]; - sprintf(msg, "There isn't a an advanced armory there, %s. Ask again next to one", STRING(Requestor->v.netname)); + + 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)); + } BotSay(pBot, true, 0.5f, msg); NextRequest->bResponded = true; return false; @@ -3826,16 +3834,42 @@ void AICOMM_UpdateSiegeBaseStatus(AvHAIPlayer* pBot, AvHAIMarineBase* Base) bool bStillStuffToSiege = AITAC_DeployableExistsAtLocation(Base->BaseLocation, &EnemyStuffFilter); const AvHAIHiveDefinition* NearestHive = AITAC_GetHiveNearestLocation(Base->BaseLocation); + const AvHAIHiveDefinition* SiegeHive = nullptr; - if (bStillStuffToSiege || (NearestHive && NearestHive->Status != HIVE_STATUS_UNBUILT && vDist2DSq(Base->BaseLocation, NearestHive->Location) < sqrf(BALANCE_VAR(kSiegeTurretRange)))) + if (vDist2DSq(Base->BaseLocation, NearestHive->Location) < sqrf(BALANCE_VAR(kSiegeTurretRange))) { + SiegeHive = NearestHive; + } + + if (bStillStuffToSiege || (SiegeHive && SiegeHive->Status != HIVE_STATUS_UNBUILT)) + { + 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 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; + } Base->bRecycleBase = false; Base->bIsActive = true; return; } else { - if (!NearestHive || vDist2DSq(Base->BaseLocation, NearestHive->Location) > sqrf(BALANCE_VAR(kSiegeTurretRange))) + if (!SiegeHive) { Base->bRecycleBase = false; Base->bIsActive = false; @@ -3845,7 +3879,7 @@ void AICOMM_UpdateSiegeBaseStatus(AvHAIPlayer* pBot, AvHAIMarineBase* Base) { for (auto it = pBot->Bases.begin(); it != pBot->Bases.end(); it++) { - if (it->BaseType == MARINE_BASE_OUTPOST && vDist2DSq(NearestHive->FloorLocation, it->BaseLocation) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f))) + if (it->BaseType == MARINE_BASE_OUTPOST && vDist2DSq(SiegeHive->FloorLocation, it->BaseLocation) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f))) { if (it->bIsBaseEstablished) { @@ -3862,8 +3896,9 @@ void AICOMM_UpdateSiegeBaseStatus(AvHAIPlayer* pBot, AvHAIMarineBase* Base) } } - Base->bRecycleBase = false; - Base->bIsActive = true; + Base->SiegeTarget = ZERO_VECTOR; + Base->bRecycleBase = true; + Base->bIsActive = false; } void AICOMM_DeployBases(AvHAIPlayer* pBot) @@ -4036,13 +4071,14 @@ void AICOMM_DeployBases(AvHAIPlayer* pBot) if (!bHasSiege) { - vector PotentialBuilders = AITAC_GetAllPlayersOfTeamInArea(BotTeam, ThisHive->FloorLocation, BALANCE_VAR(kSiegeTurretRange), false, nullptr, AVH_USER3_COMMANDER_PLAYER); + vector PotentialBuilders = AITAC_GetAllPlayersOfTeamInArea(BotTeam, ThisHive->Location, BALANCE_VAR(kSiegeTurretRange), false, nullptr, AVH_USER3_COMMANDER_PLAYER); for (auto playerIt = PotentialBuilders.begin(); playerIt != PotentialBuilders.end(); playerIt++) { AvHPlayer* ThisPlayer = (*playerIt); - if (vDist2DSq(ThisPlayer->pev->origin, ThisHive->FloorLocation) > sqrf(UTIL_MetresToGoldSrcUnits(10.0f))) + if (vDist2DSq(ThisPlayer->pev->origin, ThisHive->Location) > sqrf(UTIL_MetresToGoldSrcUnits(10.0f))) { + // 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 if (!(ThisPlayer->pev->iuser4 & MASK_VIS_SIGHTED)) { DeployableSearchFilter EnemyStuffFilter; @@ -4052,7 +4088,7 @@ void AICOMM_DeployBases(AvHAIPlayer* pBot) EnemyStuffFilter.DeployableTypes = (STRUCTURE_MARINE_COMMCHAIR | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_PHASEGATE | STRUCTURE_ALIEN_OFFENCECHAMBER); EnemyStuffFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f); - if (!AITAC_DeployableExistsAtLocation(ThisHive->FloorLocation, &EnemyStuffFilter)) + if (!AITAC_DeployableExistsAtLocation(ThisPlayer->pev->origin, &EnemyStuffFilter)) { AICOMM_AddNewBase(pBot, ThisPlayer->pev->origin, MARINE_BASE_SIEGE); } @@ -5078,6 +5114,15 @@ bool AICOMM_BuildOutMainBase(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut) { if (pBot->Player->GetResources() < BALANCE_VAR(kSentryCost)) { return true; } + 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; } + } + int NumAttempts = 0; while (NumAttempts < 5) @@ -5114,7 +5159,7 @@ bool AICOMM_BuildOutMainBase(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut) { if (pBot->Player->GetResources() < BALANCE_VAR(kArmsLabCost)) { return true; } - Vector BuildLocation = AITAC_GetRandomBuildHintInLocation(STRUCTURE_MARINE_ARMSLAB, CommChair.Location, UTIL_MetresToGoldSrcUnits(15.0f)); + Vector BuildLocation = AITAC_GetRandomBuildHintInLocation(STRUCTURE_MARINE_ARMSLAB, CommChair.Location, UTIL_MetresToGoldSrcUnits(20.0f)); if (!vIsZero(BuildLocation)) { @@ -5155,7 +5200,7 @@ bool AICOMM_BuildOutMainBase(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut) { if (pBot->Player->GetResources() < BALANCE_VAR(kObservatoryCost)) { return true; } - Vector BuildLocation = AITAC_GetRandomBuildHintInLocation(STRUCTURE_MARINE_OBSERVATORY, CommChair.Location, UTIL_MetresToGoldSrcUnits(15.0f)); + Vector BuildLocation = AITAC_GetRandomBuildHintInLocation(STRUCTURE_MARINE_OBSERVATORY, CommChair.Location, UTIL_MetresToGoldSrcUnits(20.0f)); if (!vIsZero(BuildLocation)) { @@ -5198,7 +5243,7 @@ bool AICOMM_BuildOutMainBase(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut) { if (pBot->Player->GetResources() < BALANCE_VAR(kPhaseGateCost)) { return true; } - Vector BuildLocation = AITAC_GetRandomBuildHintInLocation(STRUCTURE_MARINE_PHASEGATE, CommChair.Location, UTIL_MetresToGoldSrcUnits(15.0f)); + Vector BuildLocation = AITAC_GetRandomBuildHintInLocation(STRUCTURE_MARINE_PHASEGATE, CommChair.Location, UTIL_MetresToGoldSrcUnits(20.0f)); if (!vIsZero(BuildLocation)) { @@ -5250,7 +5295,7 @@ bool AICOMM_BuildOutMainBase(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut) { if (pBot->Player->GetResources() < BALANCE_VAR(kPrototypeLabCost)) { return true; } - Vector BuildLocation = AITAC_GetRandomBuildHintInLocation(STRUCTURE_MARINE_PROTOTYPELAB, CommChair.Location, UTIL_MetresToGoldSrcUnits(15.0f)); + Vector BuildLocation = AITAC_GetRandomBuildHintInLocation(STRUCTURE_MARINE_PROTOTYPELAB, CommChair.Location, UTIL_MetresToGoldSrcUnits(20.0f)); if (!vIsZero(BuildLocation)) { @@ -5481,7 +5526,6 @@ bool AICOMM_BuildOutSiege(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut) default: break; } - } if (NumIncomplete > 0) @@ -5524,9 +5568,48 @@ bool AICOMM_BuildOutSiege(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut) if (pBot->Player->GetResources() < ResourcesRequired) { return true; } + 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; + + 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); + } + if (StructureToDeploy == STRUCTURE_MARINE_SIEGETURRET) { - Vector BuildLocation = AITAC_GetRandomBuildHintInLocation(StructureToDeploy, BaseToBuildOut->BaseLocation, UTIL_MetresToGoldSrcUnits(10.0f)); + Vector BuildLocation = AITAC_GetRandomBuildHintInLocation(StructureToDeploy, TurretFactory.Location, BALANCE_VAR(kTurretFactoryBuildDistance)); if (!vIsZero(BuildLocation)) { @@ -5541,7 +5624,7 @@ bool AICOMM_BuildOutSiege(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut) { Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), TurretFactory.Location, (BALANCE_VAR(kTurretFactoryBuildDistance) * 0.4f)); - if (!vIsZero(BuildLocation)) + if (!vIsZero(BuildLocation) && (vIsZero(BaseToBuildOut->SiegeTarget) || vDist2DSq(BuildLocation, BaseToBuildOut->SiegeTarget) < sqrf(BALANCE_VAR(kSiegeTurretRange)))) { bool bSuccess = AICOMM_AddStructureToBase(pBot, StructureToDeploy, BuildLocation, BaseToBuildOut); @@ -5550,7 +5633,7 @@ bool AICOMM_BuildOutSiege(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut) BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), TurretFactory.Location, (BALANCE_VAR(kTurretFactoryBuildDistance) * 0.6f)); - if (!vIsZero(BuildLocation)) + if (!vIsZero(BuildLocation) && (vIsZero(BaseToBuildOut->SiegeTarget) || vDist2DSq(BuildLocation, BaseToBuildOut->SiegeTarget) < sqrf(BALANCE_VAR(kSiegeTurretRange)))) { bool bSuccess = AICOMM_AddStructureToBase(pBot, StructureToDeploy, BuildLocation, BaseToBuildOut); diff --git a/main/source/mod/AvHAIConstants.h b/main/source/mod/AvHAIConstants.h index 63845c5b..c88fc7bd 100644 --- a/main/source/mod/AvHAIConstants.h +++ b/main/source/mod/AvHAIConstants.h @@ -488,6 +488,7 @@ typedef struct _AI_MARINE_BASE AvHTeamNumber BaseTeam = TEAM_IND; MarineBaseType BaseType = MARINE_BASE_OUTPOST; // The purpose of the base. Determines what structures the commander will place Vector BaseLocation = ZERO_VECTOR; // Where the base should be located. The base will be grown around this location + Vector SiegeTarget = ZERO_VECTOR; // For siege bases, this is where the siege base wants to blast stuff vector PlacedStructures; // Which structures are part of this base. int NumBuilders = 0; // How many potential builders are there, able to construct stuff? int NumEnemies = 0; // How many enemies are in and around the base? diff --git a/main/source/mod/AvHAIHelper.cpp b/main/source/mod/AvHAIHelper.cpp index ca2becd7..c0725283 100644 --- a/main/source/mod/AvHAIHelper.cpp +++ b/main/source/mod/AvHAIHelper.cpp @@ -350,9 +350,16 @@ void AIDEBUG_DrawPath(edict_t* OutputPlayer, vector& path, float void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end) { - if (FNullEnt(pEntity) || pEntity->free) { return; } - MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity); + if (FNullEnt(pEntity) || pEntity->free) + { + MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY); + } + else + { + MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity); + } + WRITE_BYTE(TE_BEAMPOINTS); WRITE_COORD(start.x); WRITE_COORD(start.y); @@ -378,12 +385,18 @@ void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end) void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSeconds) { - if (FNullEnt(pEntity) || pEntity->free) { return; } - int timeTenthSeconds = (int)floorf(drawTimeSeconds * 10.0f); timeTenthSeconds = fmaxf(timeTenthSeconds, 1); - MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity); + if (FNullEnt(pEntity) || pEntity->free) + { + MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY); + } + else + { + MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity); + } + WRITE_BYTE(TE_BEAMPOINTS); WRITE_COORD(start.x); WRITE_COORD(start.y); @@ -409,12 +422,18 @@ void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSec void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSeconds, int r, int g, int b) { - if (FNullEnt(pEntity) || pEntity->free) { return; } - int timeTenthSeconds = (int)ceilf(drawTimeSeconds * 10.0f); timeTenthSeconds = fmaxf(timeTenthSeconds, 1); - MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity); + if (FNullEnt(pEntity) || pEntity->free) + { + MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY); + } + else + { + MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity); + } + WRITE_BYTE(TE_BEAMPOINTS); WRITE_COORD(start.x); WRITE_COORD(start.y); @@ -440,9 +459,15 @@ void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSec void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, int r, int g, int b) { - if (FNullEnt(pEntity) || pEntity->free) { return; } + if (FNullEnt(pEntity) || pEntity->free) + { + MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY); + } + else + { + MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity); + } - MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity); WRITE_BYTE(TE_BEAMPOINTS); WRITE_COORD(start.x); WRITE_COORD(start.y); @@ -638,11 +663,64 @@ void UTIL_LocalizeText(const char* InputText, string& OutputText) } +char* UTIL_StructTypeToChar(const AvHAIDeployableStructureType StructureType) +{ + switch (StructureType) + { + case STRUCTURE_MARINE_RESTOWER: + return "RT"; + case STRUCTURE_MARINE_INFANTRYPORTAL: + return "IP"; + case STRUCTURE_MARINE_TURRETFACTORY: + return "TF"; + case STRUCTURE_MARINE_ADVTURRETFACTORY: + return "Adv TF"; + case STRUCTURE_MARINE_ARMOURY: + return "Armoury"; + case STRUCTURE_MARINE_ADVARMOURY: + return "Adv Armoury"; + case STRUCTURE_MARINE_ARMSLAB: + return "Armslab"; + case STRUCTURE_MARINE_PROTOTYPELAB: + return "ProtoLab"; + case STRUCTURE_MARINE_OBSERVATORY: + return "Obs"; + case STRUCTURE_MARINE_PHASEGATE: + return "PG"; + case STRUCTURE_MARINE_TURRET: + return "Sentry"; + case STRUCTURE_MARINE_SIEGETURRET: + return "Siege T"; + case STRUCTURE_MARINE_COMMCHAIR: + return "CC"; + case STRUCTURE_MARINE_DEPLOYEDMINE: + return "Mine"; + + case STRUCTURE_ALIEN_HIVE: + return "Hive"; + case STRUCTURE_ALIEN_RESTOWER: + return "RT"; + case STRUCTURE_ALIEN_DEFENCECHAMBER: + return "DC"; + case STRUCTURE_ALIEN_SENSORYCHAMBER: + return "SC"; + case STRUCTURE_ALIEN_MOVEMENTCHAMBER: + return "MC"; + case STRUCTURE_ALIEN_OFFENCECHAMBER: + return "OC"; + default: + return "None"; + } + + return "None"; +} + char* UTIL_TaskTypeToChar(const BotTaskType TaskType) { switch (TaskType) { case TASK_ATTACK: + return "Attack"; case TASK_BUILD: return "Build"; diff --git a/main/source/mod/AvHAIHelper.h b/main/source/mod/AvHAIHelper.h index b2fea79e..90a769de 100644 --- a/main/source/mod/AvHAIHelper.h +++ b/main/source/mod/AvHAIHelper.h @@ -60,6 +60,7 @@ void UTIL_ClearLocalizations(); void UTIL_LocalizeText(const char* InputText, string& OutputText); char* UTIL_TaskTypeToChar(const BotTaskType TaskType); +char* UTIL_StructTypeToChar(const AvHAIDeployableStructureType StructureType); char* UTIL_BotRoleToChar(const AvHAIBotRole Role); diff --git a/main/source/mod/AvHAINavigation.cpp b/main/source/mod/AvHAINavigation.cpp index 428f9a8a..13772f78 100644 --- a/main/source/mod/AvHAINavigation.cpp +++ b/main/source/mod/AvHAINavigation.cpp @@ -479,7 +479,7 @@ void AIDEBUG_DrawOffMeshConnections(float DrawTime) bool UTIL_UpdateTileCache() { - bTileCacheUpToDate = true; + bool bNewTileCacheUpToDate = true; for (int i = 0; i < MAX_NAV_MESHES; i++) { @@ -487,10 +487,17 @@ bool UTIL_UpdateTileCache() { bool bUpToDate; NavMeshes[i].tileCache->update(0.0f, NavMeshes[i].navMesh, &bUpToDate); - if (!bUpToDate) { bTileCacheUpToDate = false; } + if (i != BUILDING_NAV_MESH && !bUpToDate) { bNewTileCacheUpToDate = false; } } } + if (!bTileCacheUpToDate && bNewTileCacheUpToDate) + { + bNavMeshModified = true; + } + + bTileCacheUpToDate = bNewTileCacheUpToDate; + return bTileCacheUpToDate; } @@ -604,11 +611,6 @@ unsigned int UTIL_AddTemporaryObstacle(unsigned int NavMeshIndex, const Vector L NavMeshes[NavMeshIndex].tileCache->addObstacle(Pos, Radius, Height, area, &ObsRef); ObstacleNum = (unsigned int)ObsRef; - - if (ObstacleNum > 0 && NavMeshIndex != BUILDING_NAV_MESH) - { - bNavMeshModified = true; - } } return ObstacleNum; @@ -670,14 +672,7 @@ void UTIL_RemoveStructureTemporaryObstacles(AvHAIBuildableStructure* Structure) if (ObstacleToRemove) { dtStatus RemovalStatus = NavMeshes[NavMeshIndex].tileCache->removeObstacle((dtObstacleRef)it->ObstacleRef); - - if (dtStatusSucceed(RemovalStatus)) - { - bNavMeshModified = true; - } } - - } it = Structure->Obstacles.erase(it); @@ -700,11 +695,6 @@ void UTIL_AddTemporaryObstacles(const Vector Location, float Radius, float Heigh NavMeshes[i].tileCache->addObstacle(Pos, Radius, Height, area, &ObsRef); ObstacleRefArray[i] = (unsigned int)ObsRef; - - if ((unsigned int)ObsRef > 0) - { - bNavMeshModified = true; - } } } } @@ -724,12 +714,6 @@ unsigned int UTIL_AddTemporaryBoxObstacle(const Vector bMin, const Vector bMax, NavMeshes[i].tileCache->addBoxObstacle(bMinf, bMaxf, area, &ObsRef); ObstacleNum = (unsigned int)ObsRef; - - if (area == DT_TILECACHE_NULL_AREA || area == DT_TILECACHE_WELD_AREA) - { - bNavMeshModified = true; - } - } } @@ -746,11 +730,6 @@ void UTIL_RemoveTemporaryObstacle(unsigned int ObstacleRef) { const dtTileCacheObstacle* ObstacleToRemove = NavMeshes[i].tileCache->getObstacleByRef((dtObstacleRef)ObstacleRef); - if (ObstacleToRemove && (ObstacleToRemove->cylinder.area == DT_TILECACHE_NULL_AREA || ObstacleToRemove->cylinder.area == DT_TILECACHE_WELD_AREA)) - { - bNavMeshModified = true; - } - NavMeshes[i].tileCache->removeObstacle((dtObstacleRef)ObstacleRef); } } @@ -765,11 +744,6 @@ void UTIL_RemoveTemporaryObstacles(unsigned int* ObstacleRefs) { const dtTileCacheObstacle* ObstacleToRemove = NavMeshes[i].tileCache->getObstacleByRef((dtObstacleRef)ObstacleRefs[i]); - if (ObstacleToRemove && (ObstacleToRemove->cylinder.area == DT_TILECACHE_NULL_AREA || ObstacleToRemove->cylinder.area == DT_TILECACHE_WELD_AREA)) - { - bNavMeshModified = true; - } - NavMeshes[i].tileCache->removeObstacle((dtObstacleRef)ObstacleRefs[i]); } @@ -6823,6 +6797,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move if (!vIsZero(BotNavInfo->LastNavMeshPosition)) { MoveDirectlyTo(pBot, BotNavInfo->LastNavMeshPosition); + UTIL_DrawLine(nullptr, pBot->Edict->v.origin, BotNavInfo->LastNavMeshPosition, 255, 0, 0); if (vDist2DSq(pBot->CurrentFloorPosition, BotNavInfo->LastNavMeshPosition) < sqrf(8.0f)) { @@ -6846,6 +6821,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move if (!vIsZero(BotNavInfo->UnstuckMoveLocation)) { MoveDirectlyTo(pBot, BotNavInfo->UnstuckMoveLocation); + UTIL_DrawLine(nullptr, pBot->Edict->v.origin, BotNavInfo->UnstuckMoveLocation, 255, 255, 0); return false; } } @@ -6853,6 +6829,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move else { MoveDirectlyTo(pBot, Destination); + UTIL_DrawLine(nullptr, pBot->Edict->v.origin, BotNavInfo->UnstuckMoveLocation, 0, 128, 0); return false; } @@ -8838,8 +8815,6 @@ void UTIL_ModifyOffMeshConnectionFlag(AvHAIOffMeshConnection* Connection, const NavMeshes[i].tileCache->modifyOffMeshConnection(Connection->ConnectionRefs[i], NewFlag); } } - - bNavMeshModified = true; } void UTIL_UpdateDoors(bool bInitial) @@ -9584,8 +9559,6 @@ void UTIL_AddOffMeshConnection(Vector StartLoc, Vector EndLoc, unsigned char are RemoveConnectionDef->ConnectionRefs[i] = (unsigned int)ref; } - - bNavMeshModified = true; } void UTIL_RemoveOffMeshConnections(AvHAIOffMeshConnection* RemoveConnectionDef) @@ -9596,8 +9569,6 @@ void UTIL_RemoveOffMeshConnections(AvHAIOffMeshConnection* RemoveConnectionDef) RemoveConnectionDef->ConnectionRefs[i] = 0; } - - bNavMeshModified = true; } const nav_profile GetBaseNavProfile(const int index) diff --git a/main/source/mod/AvHAIPlayer.cpp b/main/source/mod/AvHAIPlayer.cpp index 646b7a27..fa741368 100644 --- a/main/source/mod/AvHAIPlayer.cpp +++ b/main/source/mod/AvHAIPlayer.cpp @@ -1887,21 +1887,24 @@ void EndBotFrame(AvHAIPlayer* pBot) void CustomThink(AvHAIPlayer* pBot) { - if (IsPlayerAlien(pBot->Edict)) { return; } + if (!IsPlayerAlien(pBot->Edict)) { return; } - if (!IsPlayerCommander(pBot->Edict)) + int Enemy = BotGetNextEnemyTarget(pBot); + + if (Enemy > -1) { - BotProgressTakeCommandTask(pBot); - return; + AlienCombatThink(pBot); } - - for (auto it = pBot->Bases.begin(); it != pBot->Bases.end(); it++) + else { - if (it->bCanBeBuiltOut) + edict_t* CommChair = AITAC_GetCommChair(AIMGR_GetEnemyTeam(pBot->Player->GetTeam())); + + if (!FNullEnt(CommChair)) { - if (AICOMM_BuildOutBase(pBot, &(*it))) { return; } + MoveTo(pBot, CommChair->v.origin, MOVESTYLE_NORMAL); } } + } void DroneThink(AvHAIPlayer* pBot) @@ -2059,7 +2062,17 @@ void AIPlayerTakeDamage(AvHAIPlayer* pBot, int damageTaken, edict_t* aggressor) } TrackingInfo->AwarenessOfPlayer = 1.0f; - TrackingInfo->bHasLOS = true; + + Vector VisiblePoint = GetVisiblePointOnPlayerFromObserver(pBot->Edict, aggressor); + + if (!vIsZero(VisiblePoint)) + { + TrackingInfo->bHasLOS = true; + TrackingInfo->bEnemyHasLOS = true; + TrackingInfo->LastVisibleTime = gpGlobals->time; + } + + } } @@ -6348,7 +6361,7 @@ void AIPlayerSetAlienCapperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) // If we're already capping a node, are at the node and there is an unfinished tower on there, then finish the job and don't move on yet if (Task->TaskType == TASK_CAP_RESNODE) { - const AvHAIResourceNode* ResNodeIndex = AITAC_GetNearestResourceNodeToLocation(Task->TaskLocation); + const AvHAIResourceNode* ResNodeIndex = AITAC_GetResourceNodeFromEdict(Task->TaskTarget); if (ResNodeIndex && ResNodeIndex->OwningTeam != BotTeam) { @@ -6358,7 +6371,7 @@ void AIPlayerSetAlienCapperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) } else { - if (!FNullEnt(ResNodeIndex->ActiveTowerEntity) && !UTIL_StructureIsFullyBuilt(ResNodeIndex->ActiveTowerEntity)) + if (IsPlayerGorge(pBot->Edict) && !FNullEnt(ResNodeIndex->ActiveTowerEntity) && !UTIL_StructureIsFullyBuilt(ResNodeIndex->ActiveTowerEntity)) { if (vDist2DSq(pBot->Edict->v.origin, ResNodeIndex->Location) < sqrf(UTIL_MetresToGoldSrcUnits(5.0f))) { @@ -6380,7 +6393,7 @@ void AIPlayerSetAlienCapperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) if (IsPlayerLerk(pBot->Edict) || IsPlayerFade(pBot->Edict) || IsPlayerOnos(pBot->Edict)) { - bCanPlaceTower = pBot->Player->GetResources() >= 75 && AITAC_GetTeamResNodeOwnership(BotTeam, true) >= 0.5f; + bCanPlaceTower = pBot->Player->GetResources() >= 75 && AITAC_GetTeamResNodeOwnership(BotTeam, true) < 0.5f; } // If we have enough resources to cap a node, then find an empty one we can slap one down in diff --git a/main/source/mod/AvHAIPlayerManager.cpp b/main/source/mod/AvHAIPlayerManager.cpp index 5744bef4..3557f919 100644 --- a/main/source/mod/AvHAIPlayerManager.cpp +++ b/main/source/mod/AvHAIPlayerManager.cpp @@ -1313,6 +1313,64 @@ void AIMGR_SetDebugAIPlayer(edict_t* SpectatingPlayer, edict_t* AIPlayer) DebugBots[PlayerIndex] = nullptr; } + +void AIDEBUG_DisplayTeamGoals() +{ + AvHTeamNumber TeamANumber = AIMGR_GetTeamANumber(); + AvHTeamNumber TeamBNumber = AIMGR_GetTeamBNumber(); + + vector Team1Players = AIMGR_GetAIPlayersOnTeam(TeamANumber); + vector Team2Players = AIMGR_GetAIPlayersOnTeam(TeamBNumber); + + char buf[511]; + char interbuf[164]; + + sprintf(buf, "Team A (%s)\n\n", (AIMGR_GetTeamType(TeamANumber) == AVH_CLASS_TYPE_MARINE) ? "Marines" : "Aliens"); + + for (auto it = Team1Players.begin(); it != Team1Players.end(); it++) + { + AvHAIPlayer* ThisPlayer = (*it); + + if (!ThisPlayer->CurrentTask || !IsPlayerActiveInGame(ThisPlayer->Edict)) { continue; } + + if (!FNullEnt(ThisPlayer->CurrentTask->TaskTarget)) + { + sprintf(interbuf, "%s: %s (%s)\n", STRING(ThisPlayer->Player->pev->netname), UTIL_TaskTypeToChar(ThisPlayer->CurrentTask->TaskType), UTIL_StructTypeToChar(UTIL_IUSER3ToStructureType(ThisPlayer->CurrentTask->TaskTarget->v.iuser3))); + } + else + { + sprintf(interbuf, "%s: %s\n", STRING(ThisPlayer->Player->pev->netname), UTIL_TaskTypeToChar(ThisPlayer->CurrentTask->TaskType)); + } + + + strcat(buf, interbuf); + } + + UTIL_DrawHUDText(INDEXENT(1), 0, 0.1, 0.1f, 255, 255, 255, buf); + + sprintf(buf, "Team B (%s)\n\n", (AIMGR_GetTeamType(TeamBNumber) == AVH_CLASS_TYPE_MARINE) ? "Marines" : "Aliens"); + + for (auto it = Team2Players.begin(); it != Team2Players.end(); it++) + { + AvHAIPlayer* ThisPlayer = (*it); + + if (!ThisPlayer->CurrentTask || !IsPlayerActiveInGame(ThisPlayer->Edict)) { continue; } + + if (!FNullEnt(ThisPlayer->CurrentTask->TaskTarget)) + { + sprintf(interbuf, "%s: %s (%s)\n", STRING(ThisPlayer->Player->pev->netname), UTIL_TaskTypeToChar(ThisPlayer->CurrentTask->TaskType), UTIL_StructTypeToChar(UTIL_IUSER3ToStructureType(ThisPlayer->CurrentTask->TaskTarget->v.iuser3))); + } + else + { + sprintf(interbuf, "%s: %s\n", STRING(ThisPlayer->Player->pev->netname), UTIL_TaskTypeToChar(ThisPlayer->CurrentTask->TaskType)); + } + + + strcat(buf, interbuf); + } + + UTIL_DrawHUDText(INDEXENT(1), 1, 0.6, 0.1f, 255, 255, 255, buf); +} #endif void AIMGR_ReceiveCommanderRequest(AvHTeamNumber Team, edict_t* Requestor, const char* Request) diff --git a/main/source/mod/AvHAIPlayerManager.h b/main/source/mod/AvHAIPlayerManager.h index 2e6b33bd..de0cec16 100644 --- a/main/source/mod/AvHAIPlayerManager.h +++ b/main/source/mod/AvHAIPlayerManager.h @@ -137,4 +137,6 @@ void AIMGR_ProcessPendingSounds(); void AIMGR_SetFrameDelta(float NewValue); float AIMGR_GetFrameDelta(); +void AIDEBUG_DisplayTeamGoals(); + #endif \ No newline at end of file diff --git a/main/source/mod/AvHAITactical.cpp b/main/source/mod/AvHAITactical.cpp index dd75f254..5290d11b 100644 --- a/main/source/mod/AvHAITactical.cpp +++ b/main/source/mod/AvHAITactical.cpp @@ -3154,7 +3154,6 @@ bool UTIL_ShouldStructureCollide(AvHAIDeployableStructureType StructureType) { case STRUCTURE_MARINE_INFANTRYPORTAL: case STRUCTURE_MARINE_PHASEGATE: - case STRUCTURE_MARINE_TURRET: case STRUCTURE_MARINE_DEPLOYEDMINE: return false; default: diff --git a/main/source/mod/AvHAITask.cpp b/main/source/mod/AvHAITask.cpp index 5284173a..dac31355 100644 --- a/main/source/mod/AvHAITask.cpp +++ b/main/source/mod/AvHAITask.cpp @@ -875,12 +875,32 @@ bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTas if (bActiveHiveWithoutTechExists) { return true; } + int NumMissing = 0; + AvHAIDeployableStructureType MissingStructure = AITAC_GetNextMissingUpgradeChamberForTeam(BotTeam, NumMissing); + + if (MissingStructure != STRUCTURE_NONE) { return true; } + + Vector ReinforceLocation = Task->TaskTarget->v.origin; + float SearchRadius = UTIL_MetresToGoldSrcUnits(5.0f); + + if (IsEdictHive(Task->TaskTarget)) + { + AvHAIHiveDefinition* HiveToReinforce = AITAC_GetHiveFromEdict(Task->TaskTarget); + + if (HiveToReinforce) + { + ReinforceLocation = HiveToReinforce->FloorLocation; + } + + SearchRadius = UTIL_MetresToGoldSrcUnits(10.0f); + } + DeployableSearchFilter StructureFilter; StructureFilter.DeployableTypes = SEARCH_ALL_ALIEN_STRUCTURES; - StructureFilter.MaxSearchRadius = (IsEdictHive(Task->TaskTarget)) ? UTIL_MetresToGoldSrcUnits(10.0f) : UTIL_MetresToGoldSrcUnits(5.0f); - StructureFilter.DeployableTeam = BotTeam; + StructureFilter.MaxSearchRadius = SearchRadius * 1.25f; + StructureFilter.DeployableTeam = BotTeam; - vector AllNearbyStructures = AITAC_FindAllDeployables(Task->TaskTarget->v.origin, &StructureFilter); + vector AllNearbyStructures = AITAC_FindAllDeployables(ReinforceLocation, &StructureFilter); bool bUnfinishedStructureExists = false; int NumOffenceChambers = 0; @@ -916,11 +936,11 @@ bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTas // Task is still valid if we have any missing structures, or we're a gorge at the target site and there is an incomplete structure that we can finish off - if (NumOffenceChambers < 2 + if (NumOffenceChambers < 3 || (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_DEFENSE_CHAMBER) && NumDefenceChambers < 2) || (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_MOVEMENT_CHAMBER) && NumMovementChambers < 1) || (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_SENSORY_CHAMBER) && NumSensoryChambers < 1) - || (IsPlayerGorge(pBot->Edict) && bUnfinishedStructureExists && vDist2DSq(pBot->Edict->v.origin, Task->TaskTarget->v.origin) <= sqrf(UTIL_MetresToGoldSrcUnits(10.0f))) + || (IsPlayerGorge(pBot->Edict) && bUnfinishedStructureExists && vDist2DSq(pBot->Edict->v.origin, ReinforceLocation) <= sqrf(UTIL_MetresToGoldSrcUnits(10.0f))) ) { return true; } // Otherwise, are there any enemy structures lying around we could clear out? @@ -934,9 +954,9 @@ bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTas EnemyStuff.DeployableTeam = AIMGR_GetEnemyTeam(BotTeam); EnemyStuff.ReachabilityTeam = BotTeam; EnemyStuff.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag; - EnemyStuff.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f); + EnemyStuff.MaxSearchRadius = SearchRadius; - return AITAC_DeployableExistsAtLocation(Task->TaskTarget->v.origin, &EnemyStuff); + return AITAC_DeployableExistsAtLocation(ReinforceLocation, &EnemyStuff); } bool AITASK_IsAlienSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) @@ -1388,7 +1408,7 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) DeployableSearchFilter StructureFilter; StructureFilter.DeployableTeam = BotTeam; - StructureFilter.MaxSearchRadius = SearchRadius; + StructureFilter.MaxSearchRadius = SearchRadius * 1.25f; StructureFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER; int NumOCs = AITAC_GetNumDeployablesNearLocation(ReinforceLocation, &StructureFilter); @@ -1443,6 +1463,14 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) } } + if (NextStructure == STRUCTURE_NONE) + { + int NumMissing = 0; + AvHAIDeployableStructureType MissingStructure = AITAC_GetNextMissingUpgradeChamberForTeam(BotTeam, NumMissing); + + NextStructure = MissingStructure; + } + if (NextStructure != STRUCTURE_NONE) { if (vIsZero(Task->TaskLocation))