From 82c94627030b3973584b27afefab9327e55dcc0b Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Mon, 20 Jun 2022 20:59:36 +0300 Subject: [PATCH] Better retreat from danger --- dlls/basemonster.h | 1 + dlls/monsters.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++++++ dlls/schedule.cpp | 21 +++++++++----- 3 files changed, 85 insertions(+), 7 deletions(-) diff --git a/dlls/basemonster.h b/dlls/basemonster.h index 2b0464259..803190937 100644 --- a/dlls/basemonster.h +++ b/dlls/basemonster.h @@ -238,6 +238,7 @@ class CBaseMonster : public CBaseToggle bool FindLateralCover(const Vector& vecThreat, const Vector& vecViewOffset); virtual bool FindCover(Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist); + bool FindRetreat(Vector vecThreat, float flMinDist, float flMaxDist); virtual bool FValidateCover(const Vector& vecCoverLocation) { return true; } virtual float CoverRadius() { return 784; } // Default cover radius diff --git a/dlls/monsters.cpp b/dlls/monsters.cpp index af4809880..0f8ca79b7 100644 --- a/dlls/monsters.cpp +++ b/dlls/monsters.cpp @@ -2317,6 +2317,76 @@ bool CBaseMonster::FindCover(Vector vecThreat, Vector vecViewOffset, float flMin return false; } +bool CBaseMonster::FindRetreat(Vector vecThreat, float flMinDist, float flMaxDist) +{ + int i; + int iMyHullIndex; + int iMyNode; + int iThreatNode; + float flDist; + + if (0 == flMaxDist) + { + // user didn't supply a MaxDist, so work up a crazy one. + flMaxDist = 784; + } + + if (flMinDist > 0.5 * flMaxDist) + { +#if _DEBUG + ALERT(at_console, "FindRetreat MinDist (%.0f) too close to MaxDist (%.0f)\n", flMinDist, flMaxDist); +#endif + flMinDist = 0.5 * flMaxDist; + } + + if (0 == WorldGraph.m_fGraphPresent || 0 == WorldGraph.m_fGraphPointersSet) + { + ALERT(at_aiconsole, "Graph not ready for findretreat!\n"); + return false; + } + + iMyNode = WorldGraph.FindNearestNode(pev->origin, this); + iThreatNode = WorldGraph.FindNearestNode(vecThreat, this); + iMyHullIndex = WorldGraph.HullIndex(this); + + if (iMyNode == NO_NODE) + { + ALERT(at_aiconsole, "FindRetreat() - %s has no nearest node!\n", STRING(pev->classname)); + return false; + } + if (iThreatNode == NO_NODE) + { + // ALERT ( at_aiconsole, "FindRetreat() - Threat has no nearest node!\n" ); + iThreatNode = iMyNode; + // return false; + } + + // we'll do a rough sample to find nodes that are relatively nearby + for (i = 0; i < WorldGraph.m_cNodes; i++) + { + int nodeNumber = (i + WorldGraph.m_iLastCoverSearch) % WorldGraph.m_cNodes; + + CNode& node = WorldGraph.Node(nodeNumber); + + // could use an optimization here!! + flDist = (pev->origin - node.m_vecOrigin).Length(); + + if (flDist >= flMinDist && flDist < flMaxDist) + { + // node is also closer to me than the threat, or the same distance from myself and the threat the node is good. + if ((iMyNode == iThreatNode) || WorldGraph.PathLength(iMyNode, nodeNumber, iMyHullIndex, m_afCapability) <= WorldGraph.PathLength(iThreatNode, nodeNumber, iMyHullIndex, m_afCapability)) + { + if (FValidateCover(node.m_vecOrigin) && MoveToLocation(ACT_RUN, 0, node.m_vecOrigin)) + { + WorldGraph.m_iLastCoverSearch = nodeNumber + 1; // next monster that searches for cover node will start where we left off here. + return true; + } + } + } + } + return false; +} + //========================================================= // BuildNearestRoute - tries to build a route as close to the target diff --git a/dlls/schedule.cpp b/dlls/schedule.cpp index 64bb854f5..5346cff00 100644 --- a/dlls/schedule.cpp +++ b/dlls/schedule.cpp @@ -797,15 +797,22 @@ void CBaseMonster::StartTask(Task_t* pTask) } */ - if (pBestSound && FindCover(pBestSound->m_vecOrigin, g_vecZero, pBestSound->m_iVolume, CoverRadius())) + if (pBestSound) { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); + if (FindCover(pBestSound->m_vecOrigin, g_vecZero, pBestSound->m_iVolume, CoverRadius())) + { + // then try for plain ole cover + m_flMoveWaitFinished = gpGlobals->time + pTask->flData; + TaskComplete(); + } + else if (FindRetreat(pBestSound->m_vecOrigin, pBestSound->m_iVolume, CoverRadius())) + { + m_flMoveWaitFinished = gpGlobals->time + pTask->flData; + TaskComplete(); + } } - else - { - // no coverwhatsoever. or no sound in list + // no coverwhatsoever. or no sound in list + if (!TaskIsComplete()) { TaskFail(); } break;