From d15e7bfdadee466ab8ee424a638ee340552763c4 Mon Sep 17 00:00:00 2001 From: RGreenlees Date: Tue, 17 Oct 2023 12:07:27 +0100 Subject: [PATCH] Added weldable obstacles back into navigation Bots now understand how to get around weldable barriers --- main/source/mod/AIPlayers/AvHAINavigation.cpp | 136 +++++++++++++----- main/source/mod/AIPlayers/AvHAINavigation.h | 1 + main/source/mod/AIPlayers/AvHAITactical.cpp | 20 +++ main/source/mod/AIPlayers/AvHAITask.cpp | 3 +- 4 files changed, 123 insertions(+), 37 deletions(-) diff --git a/main/source/mod/AIPlayers/AvHAINavigation.cpp b/main/source/mod/AIPlayers/AvHAINavigation.cpp index 1782e5b6..16d59886 100644 --- a/main/source/mod/AIPlayers/AvHAINavigation.cpp +++ b/main/source/mod/AIPlayers/AvHAINavigation.cpp @@ -32,9 +32,7 @@ #include "DetourAlloc.h" vector NavDoors; - -nav_weldable NavWeldableObstacles[32]; -int NumWeldableObstacles; +vector NavWeldableObstacles; nav_mesh NavMeshes[MAX_NAV_MESHES]; // Array of nav meshes. Currently only 3 are used (building, onos, and regular) nav_profile BaseNavProfiles[MAX_NAV_PROFILES]; // Array of nav profiles @@ -541,11 +539,9 @@ void UnloadNavigationData() UnloadNavMeshes(); UTIL_ClearDoorData(); + UTIL_ClearWeldablesData(); memset(BaseNavProfiles, 0, sizeof(nav_profile)); - memset(NavWeldableObstacles, 0, sizeof(NavWeldableObstacles)); - - NumWeldableObstacles = 0; AIMGR_ClearBotData(); @@ -905,6 +901,7 @@ void UTIL_PopulateBaseNavProfiles() BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF); BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.setExcludeFlags(0); BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB); + BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD); BaseNavProfiles[SKULK_BASE_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH; BaseNavProfiles[SKULK_BASE_NAV_PROFILE].bFlyingProfile = false; @@ -2068,9 +2065,21 @@ void CheckAndHandleDoorObstruction(AvHAIPlayer* pBot) if (FNullEnt(BlockingDoorEdict)) { return; } - CBaseToggle* BlockingDoor = GetClassPtr((CBaseToggle*)VARS(BlockingDoorEdict)); + CBaseToggle* BlockingDoor = dynamic_cast(CBaseEntity::Instance(BlockingDoorEdict)); - if (!BlockingDoor) { return; } + if (!BlockingDoor) + { + AvHWeldable* WeldableRef = dynamic_cast(CBaseEntity::Instance(BlockingDoorEdict)); + + if (!WeldableRef) + { + return; + } + + AITASK_SetWeldTask(pBot, &pBot->BotNavInfo.MovementTask, BlockingDoorEdict, true); + + return; + } Vector NearestPoint = UTIL_GetClosestPointOnEntityToLocation(pBot->Edict->v.origin, BlockingDoorEdict); @@ -2185,7 +2194,8 @@ edict_t* UTIL_GetDoorBlockingPathPoint(AvHAIPlayer* pBot, bot_path_node* PathNod { if (strcmp(STRING(doorHit.pHit->v.classname), "func_door") == 0 || strcmp(STRING(doorHit.pHit->v.classname), "func_seethroughdoor") == 0 - || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0) + || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0 + || strcmp(STRING(doorHit.pHit->v.classname), "avhweldable") == 0) { return doorHit.pHit; } @@ -2207,7 +2217,8 @@ edict_t* UTIL_GetDoorBlockingPathPoint(AvHAIPlayer* pBot, bot_path_node* PathNod { if (strcmp(STRING(doorHit.pHit->v.classname), "func_door") == 0 || strcmp(STRING(doorHit.pHit->v.classname), "func_seethroughdoor") == 0 - || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0) + || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0 + || strcmp(STRING(doorHit.pHit->v.classname), "avhweldable") == 0) { return doorHit.pHit; } @@ -2231,7 +2242,8 @@ edict_t* UTIL_GetDoorBlockingPathPoint(AvHAIPlayer* pBot, bot_path_node* PathNod { if (strcmp(STRING(doorHit.pHit->v.classname), "func_door") == 0 || strcmp(STRING(doorHit.pHit->v.classname), "func_seethroughdoor") == 0 - || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0) + || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0 + || strcmp(STRING(doorHit.pHit->v.classname), "avhweldable") == 0) { return doorHit.pHit; } @@ -2250,7 +2262,8 @@ edict_t* UTIL_GetDoorBlockingPathPoint(AvHAIPlayer* pBot, bot_path_node* PathNod { if (strcmp(STRING(doorHit.pHit->v.classname), "func_door") == 0 || strcmp(STRING(doorHit.pHit->v.classname), "func_seethroughdoor") == 0 - || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0) + || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0 + || strcmp(STRING(doorHit.pHit->v.classname), "avhweldable") == 0) { return doorHit.pHit; } @@ -2272,7 +2285,8 @@ edict_t* UTIL_GetDoorBlockingPathPoint(AvHAIPlayer* pBot, bot_path_node* PathNod { if (strcmp(STRING(doorHit.pHit->v.classname), "func_door") == 0 || strcmp(STRING(doorHit.pHit->v.classname), "func_seethroughdoor") == 0 - || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0) + || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0 + || strcmp(STRING(doorHit.pHit->v.classname), "avhweldable") == 0) { return doorHit.pHit; } @@ -2526,7 +2540,8 @@ edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector T { if (strcmp(STRING(doorHit.pHit->v.classname), "func_door") == 0 || strcmp(STRING(doorHit.pHit->v.classname), "func_seethroughdoor") == 0 - || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0) + || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0 + || strcmp(STRING(doorHit.pHit->v.classname), "avhweldable") == 0 ) { return doorHit.pHit; } @@ -2548,7 +2563,8 @@ edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector T { if (strcmp(STRING(doorHit.pHit->v.classname), "func_door") == 0 || strcmp(STRING(doorHit.pHit->v.classname), "func_seethroughdoor") == 0 - || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0) + || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0 + || strcmp(STRING(doorHit.pHit->v.classname), "avhweldable") == 0) { return doorHit.pHit; } @@ -2572,7 +2588,8 @@ edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector T { if (strcmp(STRING(doorHit.pHit->v.classname), "func_door") == 0 || strcmp(STRING(doorHit.pHit->v.classname), "func_seethroughdoor") == 0 - || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0) + || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0 + || strcmp(STRING(doorHit.pHit->v.classname), "avhweldable") == 0) { return doorHit.pHit; } @@ -2592,7 +2609,8 @@ edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector T { if (strcmp(STRING(doorHit.pHit->v.classname), "func_door") == 0 || strcmp(STRING(doorHit.pHit->v.classname), "func_seethroughdoor") == 0 - || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0) + || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0 + || strcmp(STRING(doorHit.pHit->v.classname), "avhweldable") == 0) { return doorHit.pHit; } @@ -2612,7 +2630,8 @@ edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector T { if (strcmp(STRING(doorHit.pHit->v.classname), "func_door") == 0 || strcmp(STRING(doorHit.pHit->v.classname), "func_seethroughdoor") == 0 - || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0) + || strcmp(STRING(doorHit.pHit->v.classname), "func_door_rotating") == 0 + || strcmp(STRING(doorHit.pHit->v.classname), "avhweldable") == 0) { return doorHit.pHit; } @@ -4766,13 +4785,15 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move bool bHasMovementTask = (BotNavInfo->MovementTask.TaskType != TASK_NONE); Vector MoveTaskDestination = g_vecZero; + Vector MoveTaskOrigin = g_vecZero; if (bHasMovementTask) { - MoveTaskDestination = (!vIsZero(BotNavInfo->MovementTask.TaskLocation)) ? BotNavInfo->MovementTask.TaskLocation : BotNavInfo->MovementTask.TaskTarget->v.origin; + MoveTaskDestination = BotNavInfo->MovementTask.TaskLocation; + MoveTaskOrigin = (!FNullEnt(BotNavInfo->MovementTask.TaskTarget)) ? BotNavInfo->MovementTask.TaskTarget->v.origin : g_vecZero; } - bool bUltimateDestinationChanged = !vEquals(Destination, BotNavInfo->TargetDestination, GetPlayerRadius(pBot->Player)) && !vEquals(Destination, MoveTaskDestination); + bool bUltimateDestinationChanged = !vEquals(Destination, BotNavInfo->TargetDestination, GetPlayerRadius(pBot->Player)) && !vEquals(Destination, MoveTaskDestination) && !vEquals(Destination, MoveTaskOrigin); bool bHasReachedDestination = BotIsAtLocation(pBot, BotNavInfo->TargetDestination); @@ -4781,13 +4802,17 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move // First abort our current move so we don't try to recalculate half-way up a wall or ladder if (bIsFlyingProfile || AbortCurrentMove(pBot, Destination)) { - ClearBotPath(pBot); + // Don't clear the path if we're in the middle of a movement task + if (!vEquals(Destination, MoveTaskDestination) && !vEquals(Destination, MoveTaskOrigin)) + { + ClearBotPath(pBot); + } return true; } } else { - if (bHasMovementTask && !vEquals(Destination, MoveTaskDestination)) + if (bHasMovementTask && !vEquals(Destination, MoveTaskDestination) && !vEquals(Destination, MoveTaskOrigin)) { if (AITASK_IsTaskStillValid(pBot, &BotNavInfo->MovementTask)) { @@ -4817,6 +4842,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move pBot->BotNavInfo.LastPathCalcTime = gpGlobals->time; BotNavInfo->bPendingRecalculation = false; + BotNavInfo->bNavProfileChanged = false; if (vIsZero(BotNavInfo->TargetDestination)) { @@ -6468,15 +6494,15 @@ void UTIL_LinkTriggerToDoor(const edict_t* DoorEdict, nav_door* DoorRef) void UTIL_PopulateWeldableObstacles() { - memset(NavWeldableObstacles, 0, sizeof(NavWeldableObstacles)); - NumWeldableObstacles = 0; + UTIL_ClearWeldablesData(); CBaseEntity* currWeldable = NULL; while (((currWeldable = UTIL_FindEntityByClassname(currWeldable, "avhweldable")) != NULL)) { if (currWeldable->pev->solid == SOLID_BSP) { - NavWeldableObstacles[NumWeldableObstacles].WeldableEdict = currWeldable->edict(); + nav_weldable NewWeldable; + NewWeldable.WeldableEdict = currWeldable->edict(); float SizeX = currWeldable->pev->size.x; float SizeY = currWeldable->pev->size.y; @@ -6511,11 +6537,11 @@ void UTIL_PopulateWeldableObstacles() Vector CurrentPoint = StartPoint; - NavWeldableObstacles[NumWeldableObstacles].NumObstacles = NumObstacles; + NewWeldable.NumObstacles = NumObstacles; for (int ii = 0; ii < NumObstacles; ii++) { - UTIL_AddTemporaryObstacles(CurrentPoint, CylinderRadius, SizeZ, DT_TILECACHE_NULL_AREA, NavWeldableObstacles[NumWeldableObstacles].ObstacleRefs[ii]); + UTIL_AddTemporaryObstacles(CurrentPoint, CylinderRadius, SizeZ, DT_TILECACHE_WELD_AREA, NewWeldable.ObstacleRefs[ii]); if (bUseXAxis) { @@ -6527,7 +6553,7 @@ void UTIL_PopulateWeldableObstacles() } } - NumWeldableObstacles++; + NavWeldableObstacles.push_back(NewWeldable); } } } @@ -6593,20 +6619,24 @@ void UTIL_UpdateDoors(bool bInitial) void UTIL_UpdateWeldableObstacles() { - for (int i = 0; i < NumWeldableObstacles; i++) + for (auto it = NavWeldableObstacles.begin(); it != NavWeldableObstacles.end();) { - if (NavWeldableObstacles[i].NumObstacles == 0) { continue; } - - edict_t* WeldableEdict = NavWeldableObstacles[i].WeldableEdict; + edict_t* WeldableEdict = it->WeldableEdict; if (FNullEnt(WeldableEdict) || WeldableEdict->v.deadflag != DEAD_NO || WeldableEdict->v.solid != SOLID_BSP) { - for (int ii = 0; ii < NavWeldableObstacles[i].NumObstacles; ii++) + for (int ii = 0; ii < it->NumObstacles; ii++) { - UTIL_RemoveTemporaryObstacles(NavWeldableObstacles[i].ObstacleRefs[ii]); + UTIL_RemoveTemporaryObstacles(it->ObstacleRefs[ii]); } - NavWeldableObstacles[i].NumObstacles = 0; + it->NumObstacles = 0; + + it = NavWeldableObstacles.erase(it); + } + else + { + it++; } } } @@ -6666,7 +6696,7 @@ void UTIL_ApplyTempObstaclesToDoor(nav_door* DoorRef, const int Area) for (int ii = 0; ii < NumObstacles; ii++) { - UTIL_AddTemporaryObstacles(CurrentPoint, CylinderRadius, SizeZ * 2.0f, Area, DoorRef->ObstacleRefs[ii]); + UTIL_AddTemporaryObstacles(CurrentPoint, CylinderRadius, SizeZ, Area, DoorRef->ObstacleRefs[ii]); if (bUseXAxis) { @@ -6738,12 +6768,46 @@ void UTIL_UpdateDoorTriggers(nav_door* Door) void UTIL_ClearDoorData() { + for (auto it = NavDoors.begin(); it != NavDoors.end(); it++) + { + if (it->NumObstacles > 0) + { + for (int ii = 0; ii < it->NumObstacles; ii++) + { + UTIL_RemoveTemporaryObstacles(it->ObstacleRefs[ii]); + } + + it->NumObstacles = 0; + + } + } + NavDoors.clear(); } +void UTIL_ClearWeldablesData() +{ + for (auto it = NavWeldableObstacles.begin(); it != NavWeldableObstacles.end(); it++) + { + if (it->NumObstacles > 0) + { + for (int ii = 0; ii < it->NumObstacles; ii++) + { + UTIL_RemoveTemporaryObstacles(it->ObstacleRefs[ii]); + } + + it->NumObstacles = 0; + + } + } + + NavWeldableObstacles.clear(); +} + // TODO: Need to add orientated box obstacle for door void UTIL_PopulateDoors() { + UTIL_ClearDoorData(); CBaseEntity* currDoor = NULL; diff --git a/main/source/mod/AIPlayers/AvHAINavigation.h b/main/source/mod/AIPlayers/AvHAINavigation.h index 1f099848..5f9aa130 100644 --- a/main/source/mod/AIPlayers/AvHAINavigation.h +++ b/main/source/mod/AIPlayers/AvHAINavigation.h @@ -425,6 +425,7 @@ void ClearBotPath(AvHAIPlayer* pBot); void ClearBotStuckMovement(AvHAIPlayer* pBot); void UTIL_ClearDoorData(); +void UTIL_ClearWeldablesData(); // Based on the direction the bot wants to move and it's current facing angle, sets the forward and side move, and the directional buttons to make the bot actually move void BotMovementInputs(AvHAIPlayer* pBot); diff --git a/main/source/mod/AIPlayers/AvHAITactical.cpp b/main/source/mod/AIPlayers/AvHAITactical.cpp index f6850176..4e957128 100644 --- a/main/source/mod/AIPlayers/AvHAITactical.cpp +++ b/main/source/mod/AIPlayers/AvHAITactical.cpp @@ -595,6 +595,7 @@ void AITAC_UpdateMapAIData() } UTIL_UpdateDoors(false); + UTIL_UpdateWeldableObstacles(); AITAC_RefreshHiveData(); } @@ -968,15 +969,32 @@ void AITAC_UpdateBuildableStructure(CBaseEntity* Structure) if (vIsZero(BuildingMap[EntIndex].Location) || !vEquals(BaseBuildable->pev->origin, BuildingMap[EntIndex].Location, 5.0f)) { bool bIsOnNavMesh = UTIL_PointIsOnNavmesh(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], UTIL_GetEntityGroundLocation(BuildingEdict), Vector(max_player_use_reach, max_player_use_reach, max_player_use_reach)); + if (bIsOnNavMesh) { bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(BuildingEdict), max_player_use_reach); bool bIsReachableSkulk = UTIL_PointIsReachable(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(BuildingEdict), max_player_use_reach); bool bIsReachableOnos = UTIL_PointIsReachable(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(BuildingEdict), max_player_use_reach); + // Check if basic marines can reach. If they can then no need to separately check welder marines as they automatically can. If not, separately check for welders. if (bIsReachableMarine) { BuildingMap[EntIndex].ReachabilityFlags |= AI_REACHABILITY_MARINE; + BuildingMap[EntIndex].ReachabilityFlags |= AI_REACHABILITY_WELDER; + } + else + { + nav_profile WelderProfile; + memcpy(&WelderProfile, &BaseNavProfiles[MARINE_BASE_NAV_PROFILE], sizeof(nav_profile)); + + WelderProfile.Filters.removeExcludeFlags(SAMPLE_POLYFLAGS_WELD); + + bool bIsReachableWelder = UTIL_PointIsReachable(WelderProfile, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(BuildingEdict), max_player_use_reach); + + if (bIsReachableWelder) + { + BuildingMap[EntIndex].ReachabilityFlags |= AI_REACHABILITY_WELDER; + } } if (bIsReachableSkulk) @@ -989,6 +1007,8 @@ void AITAC_UpdateBuildableStructure(CBaseEntity* Structure) BuildingMap[EntIndex].ReachabilityFlags |= AI_REACHABILITY_ONOS; } + + } else { diff --git a/main/source/mod/AIPlayers/AvHAITask.cpp b/main/source/mod/AIPlayers/AvHAITask.cpp index 82e31677..85aa230f 100644 --- a/main/source/mod/AIPlayers/AvHAITask.cpp +++ b/main/source/mod/AIPlayers/AvHAITask.cpp @@ -2202,7 +2202,7 @@ void BotProgressWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) if (IsPlayerInUseRange(pBot->Edict, Task->TaskTarget)) { - BotLookAt(pBot, UTIL_GetCentreOfEntity(Task->TaskTarget)); + BotLookAt(pBot, UTIL_GetClosestPointOnEntityToLocation(pBot->CurrentEyePosition, Task->TaskTarget)); pBot->DesiredCombatWeapon = WEAPON_MARINE_WELDER; if (GetBotCurrentWeapon(pBot) != WEAPON_MARINE_WELDER) @@ -2714,6 +2714,7 @@ void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Targe Task->TaskTarget = Target; Task->TaskType = TASK_WELD; Task->bTaskIsUrgent = bIsUrgent; + Task->TaskLocation = ZERO_VECTOR; Task->TaskLength = 0.0f; if (IsEdictPlayer(Target) || IsEdictStructure(Target)) { return; }