From 69001ad4f7f59489dba6b0c6c82f70a9e38e24b2 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Mon, 19 Feb 2024 10:43:35 -0600 Subject: [PATCH] Added ExcludeNode virtual for actors to reject certain nodes of choice. - Changed MeleeRange to FriendlySeeBlocks so it's supported by Doom Builder. --- src/g_level.cpp | 17 ++++++++-------- src/playsim/actor.h | 1 + src/playsim/p_enemy.cpp | 14 +++++++++++++ wadsrc/static/zscript/actors/actor.zs | 20 +++++++++++++++++++ .../zscript/actors/shared/sharedmisc.zs | 10 +++++++++- 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index fb53cadef..3ab4f9ce1 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -2472,7 +2472,7 @@ DEFINE_ACTION_FUNCTION(FLevelLocals, GetEpisodeName) // Pathfinding //---------------------------------------------------------------------------- -// Code by RicardoLuis0 +// Code by RicardoLuis0, modified by Major Cooke static TArray>& GetPathNodeNeighbors(AActor * self) { static PClass * nodeCls = PClass::FindClass(NAME_PathNode); @@ -2508,7 +2508,7 @@ static void ReconstructPath(TMap &cameFrom, AActor* current, T static AActor* FindClosestNode(AActor* from) { - static PClass * nodeCls = PClass::FindClass(NAME_PathNode); + static const PClass * nodeCls = PClass::FindClass(NAME_PathNode); AActor * closest = nullptr; double closestDist = DBL_MAX; @@ -2519,9 +2519,10 @@ static AActor* FindClosestNode(AActor* from) if(node && !(node->flags & MF_AMBUSH) && nodeCls->IsAncestorOf(node->GetClass())) { double dst = node->Distance3DSquared(from); - bool mrange = (dst < closestDist && (node->meleerange <= 0.0 || dst < (node->meleerange * node->meleerange))); + const bool mrange = (dst < closestDist && + (node->friendlyseeblocks <= 0 || dst < double(node->friendlyseeblocks * node->friendlyseeblocks))); - if(mrange && P_CheckSight(node, from)) + if (mrange && !from->CallExcludeNode(node) && P_CheckSight(node, from)) { closestDist = dst; closest = node; @@ -2539,9 +2540,8 @@ static V GetOr(TMap map, const K &key, V alt) return k ? *k : alt; } -static bool FindPathAStar(AActor* startnode, AActor* goalnode, TArray> &path) +static bool FindPathAStar(AActor *chaser, AActor* startnode, AActor* goalnode, TArray> &path) { - TArray openSet; TMap cameFrom; TMap gScore; @@ -2570,12 +2570,11 @@ static bool FindPathAStar(AActor* startnode, AActor* goalnode, TArrayDistance3DSquared(neighbor); double neighbor_gScore = GetOr(gScore, neighbor, DBL_MAX); - if(tentative_gScore < neighbor_gScore) + if (tentative_gScore < neighbor_gScore && !chaser->CallExcludeNode(neighbor)) { openSet.SortedDelete(neighbor, lt_fScore); cameFrom.Insert(neighbor, current); @@ -2615,7 +2614,7 @@ bool FLevelLocals::FindPath(AActor* chaser, AActor* target, AActor* startNode, A return true; } - if (FindPathAStar(startNode, goalNode, chaser->Path)) + if (FindPathAStar(chaser, startNode, goalNode, chaser->Path)) { if (chaser->goal && nodeCls->IsAncestorOf(chaser->goal->GetClass())) { diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 93cd34339..d985b0824 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -1106,6 +1106,7 @@ public: void ClearPath(); bool CanPathfind(); + bool CallExcludeNode(AActor *node); void CallReachedNode(AActor *node); // info for drawing diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index 946f4ad60..5cbaba7dd 100644 --- a/src/playsim/p_enemy.cpp +++ b/src/playsim/p_enemy.cpp @@ -2259,6 +2259,20 @@ void AActor::CallReachedNode(AActor *node) } } +// Called while scoring the path. +bool AActor::CallExcludeNode(AActor* node) +{ + IFVIRTUAL(AActor, ExcludeNode) + { + VMValue params[2] = { (DObject*)this, node }; + int retval = 0; + VMReturn ret(&retval); + VMCall(func, params, 2, &ret, 1); + return !!retval; + } + return false; +} + //========================================================================== // // A_Wander diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 049661624..565ddd643 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -837,6 +837,26 @@ class Actor : Thinker native ClearPath(); } + + // Return true to mark the node as ineligible for constructing a path along. + virtual bool ExcludeNode(PathNode node) + { + if (!node) return true; + + // Scale is the size requirements. + // STANDSTILL flag is used to require the actor to be bigger instead of smaller. + double r = node.Scale.X; + double h = node.Scale.Y; + + // Perfect fit. + if (radius == r && height == h) + return false; + + if ((0.0 < r && r < radius) || (0.0 < h && h < height)) + return !node.bSTANDSTILL; + + return false; + } native bool TryMove(vector2 newpos, int dropoff, bool missilecheck = false, FCheckPosition tm = null); native bool CheckMove(vector2 newpos, int flags = 0, FCheckPosition tm = null); diff --git a/wadsrc/static/zscript/actors/shared/sharedmisc.zs b/wadsrc/static/zscript/actors/shared/sharedmisc.zs index 48bb71ed4..aa78a99bc 100644 --- a/wadsrc/static/zscript/actors/shared/sharedmisc.zs +++ b/wadsrc/static/zscript/actors/shared/sharedmisc.zs @@ -257,6 +257,9 @@ AMBUSH Useful for tele/portals since the engine makes them "touch" upon transitioning. These nodes are fast forwarded over in Actor's ReachedNode() function. + +STANDSTILL + Traveller must be bigger instead of smaller. */ class PathNode : Actor { @@ -273,7 +276,12 @@ class PathNode : Actor Radius 16; Height 56; RenderStyle "None"; - MeleeRange 0; // Sight checks limited to this. 0 = infinite. Set within map editor. + + // The following properties can be set directly in Ultimate Doom Builder's Custom tab. + + FriendlySeeBlocks 0; // Sight checks limited to this. <= 0 is infinite. + XScale 0; // filter height - actors must be this small for this node. Only effective if > 0. + YScale 0; // filter radius - ^ but for radius } // Args are TIDs. Can be one way to force single directions.