mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-22 12:11:25 +00:00
Begin adding PathNodes.
This commit is contained in:
parent
3033fafaa7
commit
b2cb4b0a6d
14 changed files with 286 additions and 10 deletions
104
src/g_level.cpp
104
src/g_level.cpp
|
@ -98,6 +98,7 @@
|
||||||
#include "s_music.h"
|
#include "s_music.h"
|
||||||
#include "fragglescript/t_script.h"
|
#include "fragglescript/t_script.h"
|
||||||
|
|
||||||
|
|
||||||
#include "texturemanager.h"
|
#include "texturemanager.h"
|
||||||
|
|
||||||
void STAT_StartNewGame(const char *lev);
|
void STAT_StartNewGame(const char *lev);
|
||||||
|
@ -2466,3 +2467,106 @@ DEFINE_ACTION_FUNCTION(FLevelLocals, GetEpisodeName)
|
||||||
ACTION_RETURN_STRING(GStrings.localize(STAT_EpisodeName().GetChars()));
|
ACTION_RETURN_STRING(GStrings.localize(STAT_EpisodeName().GetChars()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// Pathfinding
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Code by RicardoLuis0
|
||||||
|
TArray<AActor*> * GetNeighbors(AActor * self)
|
||||||
|
{
|
||||||
|
PClass * cls = PClass::FindClass("PathNode");
|
||||||
|
if(!cls->IsAncestorOf(self->GetClass()))
|
||||||
|
{
|
||||||
|
ThrowAbortException(X_BAD_SELF, "Invalid class passed to GetNeighbors (must be PathNodeInfo)");
|
||||||
|
}
|
||||||
|
|
||||||
|
PField *var = dyn_cast<PField>(cls->FindSymbol("neighbors", true));
|
||||||
|
|
||||||
|
assert(var);
|
||||||
|
assert(var->Type->isDynArray());
|
||||||
|
assert(static_cast<PDynArray*>(var->Type)->ElementType == cls);
|
||||||
|
|
||||||
|
return reinterpret_cast<TArray<AActor*>*>(reinterpret_cast<uintptr_t>(self) + var->Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AS_BinarySearch(TMap<AActor*, double>* fScore, bool exact = false)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AS_ReconstructPath(TMap<AActor*, AActor*>* cameFrom, AActor* chaser)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FLevelLocals::AStar(AActor* chaser, AActor* target, AActor* startnode, AActor* goalnode)
|
||||||
|
{
|
||||||
|
if (!chaser || !target || PathNodes.Size() < 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If supplying nodes, skip the search.
|
||||||
|
const bool getstart = (!startnode || !startnode->IsKindOf(NAME_PathNode));
|
||||||
|
const bool getgoal = (!goalnode || !goalnode->IsKindOf(NAME_PathNode));
|
||||||
|
|
||||||
|
if (getstart || getgoal)
|
||||||
|
{
|
||||||
|
double dist[2];
|
||||||
|
dist[0] = dist[1] = 100000000.0;
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 0; i < PathNodes.Size(); i++)
|
||||||
|
{
|
||||||
|
AActor *node = PathNodes[i];
|
||||||
|
if (!node) continue;
|
||||||
|
|
||||||
|
double dis;
|
||||||
|
if (getstart)
|
||||||
|
{
|
||||||
|
dis = node->Distance2DSquared(chaser);
|
||||||
|
if (dis < dist[0] && P_CheckSight(node, chaser)) // TO DO: Make 3D aware, so 3D floors can work better.
|
||||||
|
{
|
||||||
|
startnode = node;
|
||||||
|
dist[0] = dis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dis = node->Distance2DSquared(target);
|
||||||
|
if (dis < dist[1] && P_CheckSight(node, target))
|
||||||
|
{
|
||||||
|
goalnode = node;
|
||||||
|
dist[1] = dis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Incomplete graph.
|
||||||
|
if (!startnode || !goalnode)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (startnode == goalnode)
|
||||||
|
{
|
||||||
|
chaser->ClearPath();
|
||||||
|
chaser->Path.Push(MakeObjPtr<AActor*>(startnode));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Begin A* here.
|
||||||
|
TArray<AActor*> openSet;
|
||||||
|
TMap<AActor*, AActor*> cameFrom;
|
||||||
|
TMap<AActor*, double> gScore;
|
||||||
|
TMap<AActor*, double> fScore;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(FLevelLocals, AStar)
|
||||||
|
{
|
||||||
|
PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals);
|
||||||
|
PARAM_OBJECT(chaser, AActor);
|
||||||
|
PARAM_OBJECT(target, AActor);
|
||||||
|
PARAM_OBJECT(startnode, AActor);
|
||||||
|
PARAM_OBJECT(goalnode, AActor);
|
||||||
|
return self->AStar(chaser, target, startnode, goalnode);
|
||||||
|
}
|
||||||
|
|
|
@ -444,6 +444,9 @@ public:
|
||||||
|
|
||||||
void SetMusic();
|
void SetMusic();
|
||||||
|
|
||||||
|
bool AStar(AActor *chaser, AActor *target, AActor *startnode = nullptr, AActor *goalnode = nullptr);
|
||||||
|
|
||||||
|
TArray<AActor *> PathNodes;
|
||||||
TArray<vertex_t> vertexes;
|
TArray<vertex_t> vertexes;
|
||||||
TArray<sector_t> sectors;
|
TArray<sector_t> sectors;
|
||||||
TArray<extsector_t> extsectors; // container for non-trivial sector information. sector_t must be trivially copyable for *_fakeflat to work as intended.
|
TArray<extsector_t> extsectors; // container for non-trivial sector information. sector_t must be trivially copyable for *_fakeflat to work as intended.
|
||||||
|
|
|
@ -503,6 +503,7 @@ enum
|
||||||
SECMF_OVERLAPPING = 512, // floor and ceiling overlap and require special renderer action.
|
SECMF_OVERLAPPING = 512, // floor and ceiling overlap and require special renderer action.
|
||||||
SECMF_NOSKYWALLS = 1024, // Do not draw "sky walls"
|
SECMF_NOSKYWALLS = 1024, // Do not draw "sky walls"
|
||||||
SECMF_LIFT = 2048, // For MBF monster AI
|
SECMF_LIFT = 2048, // For MBF monster AI
|
||||||
|
SECMF_NOPATHING = 4096, // monsters cannot path find in these areas, saves on time and resources
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
|
|
@ -202,6 +202,7 @@ xx(Cast) // 'damage type' for the cast call
|
||||||
xx(MapSpot)
|
xx(MapSpot)
|
||||||
xx(PatrolPoint)
|
xx(PatrolPoint)
|
||||||
xx(PatrolSpecial)
|
xx(PatrolSpecial)
|
||||||
|
xx(PathNode)
|
||||||
xx(Communicator)
|
xx(Communicator)
|
||||||
xx(PowerScanner)
|
xx(PowerScanner)
|
||||||
|
|
||||||
|
|
|
@ -611,6 +611,8 @@ void P_SetupLevel(FLevelLocals *Level, int position, bool newGame)
|
||||||
while ((ac = it.Next()))
|
while ((ac = it.Next()))
|
||||||
{
|
{
|
||||||
ac->SetDynamicLights();
|
ac->SetDynamicLights();
|
||||||
|
if (ac->IsKindOf(NAME_PathNode))
|
||||||
|
Level->PathNodes.Push(ac);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -442,7 +442,9 @@ enum ActorFlag9
|
||||||
MF9_DOSHADOWBLOCK = 0x00000002, // [inkoalawetrust] Should the monster look for SHADOWBLOCK actors ?
|
MF9_DOSHADOWBLOCK = 0x00000002, // [inkoalawetrust] Should the monster look for SHADOWBLOCK actors ?
|
||||||
MF9_SHADOWBLOCK = 0x00000004, // [inkoalawetrust] Actors in the line of fire with this flag trigger the MF_SHADOW aiming penalty.
|
MF9_SHADOWBLOCK = 0x00000004, // [inkoalawetrust] Actors in the line of fire with this flag trigger the MF_SHADOW aiming penalty.
|
||||||
MF9_SHADOWAIMVERT = 0x00000008, // [inkoalawetrust] Monster aim is also offset vertically when aiming at shadow actors.
|
MF9_SHADOWAIMVERT = 0x00000008, // [inkoalawetrust] Monster aim is also offset vertically when aiming at shadow actors.
|
||||||
MF9_DECOUPLEDANIMATIONS = 0x00000010, // [RL0] Decouple model animations from states
|
MF9_DECOUPLEDANIMATIONS = 0x00000010, // [RL0] Decouple model animations from states
|
||||||
|
MF9_PATHING = 0x00000020, // [MC] Enables monsters to do pathfinding, such as A*.
|
||||||
|
MF9_KEEPPATH = 0x00000040, // [MC] Forces monsters to keep to the path when target's in sight.
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- mobj.renderflags ---
|
// --- mobj.renderflags ---
|
||||||
|
@ -1101,6 +1103,8 @@ public:
|
||||||
void AttachLight(unsigned int count, const FLightDefaults *lightdef);
|
void AttachLight(unsigned int count, const FLightDefaults *lightdef);
|
||||||
void SetDynamicLights();
|
void SetDynamicLights();
|
||||||
|
|
||||||
|
void ClearPath();
|
||||||
|
|
||||||
// info for drawing
|
// info for drawing
|
||||||
// NOTE: The first member variable *must* be snext.
|
// NOTE: The first member variable *must* be snext.
|
||||||
AActor *snext, **sprev; // links in sector (if needed)
|
AActor *snext, **sprev; // links in sector (if needed)
|
||||||
|
@ -1157,6 +1161,7 @@ public:
|
||||||
TObjPtr<DBoneComponents*> boneComponentData;
|
TObjPtr<DBoneComponents*> boneComponentData;
|
||||||
|
|
||||||
// interaction info
|
// interaction info
|
||||||
|
TArray<TObjPtr<AActor*> > Path;
|
||||||
FBlockNode *BlockNode; // links in blocks (if needed)
|
FBlockNode *BlockNode; // links in blocks (if needed)
|
||||||
struct sector_t *Sector;
|
struct sector_t *Sector;
|
||||||
subsector_t * subsector;
|
subsector_t * subsector;
|
||||||
|
|
|
@ -2199,6 +2199,26 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearLastHeard)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// ClearPath
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void AActor::ClearPath()
|
||||||
|
{
|
||||||
|
Path.Clear();
|
||||||
|
if (goal && goal->IsKindOf(NAME_PathNode))
|
||||||
|
goal = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(AActor, ClearPath)
|
||||||
|
{
|
||||||
|
PARAM_SELF_PROLOGUE(AActor);
|
||||||
|
self->ClearPath();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// A_Wander
|
// A_Wander
|
||||||
|
@ -2411,7 +2431,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
||||||
|
|
||||||
// [RH] Friendly monsters will consider chasing whoever hurts a player if they
|
// [RH] Friendly monsters will consider chasing whoever hurts a player if they
|
||||||
// don't already have a target.
|
// don't already have a target.
|
||||||
if (actor->flags & MF_FRIENDLY && actor->target == NULL)
|
if (actor->flags & MF_FRIENDLY && actor->target == nullptr)
|
||||||
{
|
{
|
||||||
player_t *player;
|
player_t *player;
|
||||||
|
|
||||||
|
@ -2443,7 +2463,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
||||||
}
|
}
|
||||||
if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
|
if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
|
||||||
{ // look for a new target
|
{ // look for a new target
|
||||||
if (actor->target != NULL && (actor->target->flags2 & MF2_NONSHOOTABLE))
|
if (actor->target != nullptr && (actor->target->flags2 & MF2_NONSHOOTABLE))
|
||||||
{
|
{
|
||||||
// Target is only temporarily unshootable, so remember it.
|
// Target is only temporarily unshootable, so remember it.
|
||||||
actor->lastenemy = actor->target;
|
actor->lastenemy = actor->target;
|
||||||
|
@ -2451,17 +2471,17 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
||||||
// hurt our old one temporarily.
|
// hurt our old one temporarily.
|
||||||
actor->threshold = 0;
|
actor->threshold = 0;
|
||||||
}
|
}
|
||||||
if (P_LookForPlayers (actor, !(flags & CHF_DONTLOOKALLAROUND), NULL) && actor->target != actor->goal)
|
if (P_LookForPlayers (actor, !(flags & CHF_DONTLOOKALLAROUND), nullptr) && actor->target != actor->goal)
|
||||||
{ // got a new target
|
{ // got a new target
|
||||||
actor->flags7 &= ~MF7_INCHASE;
|
actor->flags7 &= ~MF7_INCHASE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (actor->target == NULL)
|
if (actor->target == nullptr)
|
||||||
{
|
{
|
||||||
if (flags & CHF_DONTIDLE || actor->flags & MF_FRIENDLY)
|
if (flags & CHF_DONTIDLE || actor->flags & MF_FRIENDLY)
|
||||||
{
|
{
|
||||||
//A_Look(actor);
|
//A_Look(actor);
|
||||||
if (actor->target == NULL)
|
if (actor->target == nullptr)
|
||||||
{
|
{
|
||||||
if (!dontmove) A_Wander(actor);
|
if (!dontmove) A_Wander(actor);
|
||||||
actor->flags7 &= ~MF7_INCHASE;
|
actor->flags7 &= ~MF7_INCHASE;
|
||||||
|
@ -2470,6 +2490,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
actor->ClearPath();
|
||||||
actor->SetIdle();
|
actor->SetIdle();
|
||||||
actor->flags7 &= ~MF7_INCHASE;
|
actor->flags7 &= ~MF7_INCHASE;
|
||||||
return;
|
return;
|
||||||
|
@ -2493,9 +2514,31 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
||||||
actor->flags7 &= ~MF7_INCHASE;
|
actor->flags7 &= ~MF7_INCHASE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (actor->target && actor->flags9 & MF9_PATHING)
|
||||||
|
{
|
||||||
|
if (actor->goal && actor->goal->IsKindOf(NAME_PathNode))
|
||||||
|
{
|
||||||
|
AActor* temp = actor->target;
|
||||||
|
actor->target = actor->goal;
|
||||||
|
bool result = P_CheckMeleeRange(actor);
|
||||||
|
actor->target = temp;
|
||||||
|
|
||||||
|
if (result) // TO DO
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!actor->goal)
|
||||||
|
{
|
||||||
|
if (actor->Path.Size() < 1 && actor->Level->AStar(actor, actor->target))
|
||||||
|
actor->goal = actor->Path[0];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
// [RH] Don't attack if just moving toward goal
|
// [RH] Don't attack if just moving toward goal
|
||||||
if (actor->target == actor->goal || (actor->flags5&MF5_CHASEGOAL && actor->goal != NULL))
|
else if (actor->target == actor->goal || (actor->flags5&MF5_CHASEGOAL && actor->goal != nullptr))
|
||||||
{
|
{
|
||||||
AActor * savedtarget = actor->target;
|
AActor * savedtarget = actor->target;
|
||||||
actor->target = actor->goal;
|
actor->target = actor->goal;
|
||||||
|
@ -2513,7 +2556,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
||||||
// as the goal.
|
// as the goal.
|
||||||
while ( (spec = specit.Next()) )
|
while ( (spec = specit.Next()) )
|
||||||
{
|
{
|
||||||
P_ExecuteSpecial(actor->Level, spec->special, NULL, actor, false, spec->args[0],
|
P_ExecuteSpecial(actor->Level, spec->special, nullptr, actor, false, spec->args[0],
|
||||||
spec->args[1], spec->args[2], spec->args[3], spec->args[4]);
|
spec->args[1], spec->args[2], spec->args[3], spec->args[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2536,6 +2579,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
||||||
if (newgoal != NULL && delay != 0)
|
if (newgoal != NULL && delay != 0)
|
||||||
{
|
{
|
||||||
actor->flags4 |= MF4_INCOMBAT;
|
actor->flags4 |= MF4_INCOMBAT;
|
||||||
|
actor->ClearPath(); // [MC] Just to be safe.
|
||||||
actor->SetIdle();
|
actor->SetIdle();
|
||||||
}
|
}
|
||||||
actor->flags7 &= ~MF7_INCHASE;
|
actor->flags7 &= ~MF7_INCHASE;
|
||||||
|
|
|
@ -353,6 +353,8 @@ static FFlagDef ActorFlagDefs[]=
|
||||||
DEFINE_FLAG(MF9, SHADOWBLOCK, AActor, flags9),
|
DEFINE_FLAG(MF9, SHADOWBLOCK, AActor, flags9),
|
||||||
DEFINE_FLAG(MF9, SHADOWAIMVERT, AActor, flags9),
|
DEFINE_FLAG(MF9, SHADOWAIMVERT, AActor, flags9),
|
||||||
DEFINE_FLAG(MF9, DECOUPLEDANIMATIONS, AActor, flags9),
|
DEFINE_FLAG(MF9, DECOUPLEDANIMATIONS, AActor, flags9),
|
||||||
|
DEFINE_FLAG(MF9, PATHING, AActor, flags9),
|
||||||
|
DEFINE_FLAG(MF9, KEEPPATH, AActor, flags9),
|
||||||
|
|
||||||
// Effect flags
|
// Effect flags
|
||||||
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
|
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
|
||||||
|
|
|
@ -2125,6 +2125,7 @@ DEFINE_FIELD(AActor, LightLevel)
|
||||||
DEFINE_FIELD(AActor, ShadowAimFactor)
|
DEFINE_FIELD(AActor, ShadowAimFactor)
|
||||||
DEFINE_FIELD(AActor, ShadowPenaltyFactor)
|
DEFINE_FIELD(AActor, ShadowPenaltyFactor)
|
||||||
DEFINE_FIELD(AActor, AutomapOffsets)
|
DEFINE_FIELD(AActor, AutomapOffsets)
|
||||||
|
DEFINE_FIELD(AActor, Path)
|
||||||
|
|
||||||
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, thing);
|
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, thing);
|
||||||
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, pos);
|
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, pos);
|
||||||
|
|
|
@ -285,6 +285,7 @@ DoomEdNums
|
||||||
14163 = MusicChanger, 63
|
14163 = MusicChanger, 63
|
||||||
14164 = MusicChanger, 64
|
14164 = MusicChanger, 64
|
||||||
14165 = MusicChanger
|
14165 = MusicChanger
|
||||||
|
14166 = PathNode
|
||||||
32000 = DoomBuilderCamera
|
32000 = DoomBuilderCamera
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -261,6 +261,7 @@ class Actor : Thinker native
|
||||||
private native int InventoryID; // internal counter.
|
private native int InventoryID; // internal counter.
|
||||||
native uint freezetics;
|
native uint freezetics;
|
||||||
native Vector2 AutomapOffsets;
|
native Vector2 AutomapOffsets;
|
||||||
|
native Array<Actor> Path; // Cannot be cast to PathNode, unfortunately.
|
||||||
|
|
||||||
meta String Obituary; // Player was killed by this actor
|
meta String Obituary; // Player was killed by this actor
|
||||||
meta String HitObituary; // Player was killed by this actor in melee
|
meta String HitObituary; // Player was killed by this actor in melee
|
||||||
|
@ -697,7 +698,7 @@ class Actor : Thinker native
|
||||||
native void SoundAlert(Actor target, bool splash = false, double maxdist = 0);
|
native void SoundAlert(Actor target, bool splash = false, double maxdist = 0);
|
||||||
native void ClearBounce();
|
native void ClearBounce();
|
||||||
native TerrainDef GetFloorTerrain();
|
native TerrainDef GetFloorTerrain();
|
||||||
native bool CheckLocalView(int consoleplayer = -1 /* parameter is not used anymore but needed for backward compatibilityö. */);
|
native bool CheckLocalView(int consoleplayer = -1 /* parameter is not used anymore but needed for backward compatibility. */);
|
||||||
native bool CheckNoDelay();
|
native bool CheckNoDelay();
|
||||||
native bool UpdateWaterLevel (bool splash = true);
|
native bool UpdateWaterLevel (bool splash = true);
|
||||||
native bool IsZeroDamage();
|
native bool IsZeroDamage();
|
||||||
|
@ -705,6 +706,7 @@ class Actor : Thinker native
|
||||||
native void ClearFOVInterpolation();
|
native void ClearFOVInterpolation();
|
||||||
native clearscope Vector3 PosRelative(sector sec) const;
|
native clearscope Vector3 PosRelative(sector sec) const;
|
||||||
native void RailAttack(FRailParams p);
|
native void RailAttack(FRailParams p);
|
||||||
|
native void ClearPath();
|
||||||
|
|
||||||
native void HandleSpawnFlags();
|
native void HandleSpawnFlags();
|
||||||
native void ExplodeMissile(line lin = null, Actor target = null, bool onsky = false);
|
native void ExplodeMissile(line lin = null, Actor target = null, bool onsky = false);
|
||||||
|
|
|
@ -245,3 +245,110 @@ class SpeakerIcon : Unknown
|
||||||
Scale 0.125;
|
Scale 0.125;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===============================================================
|
||||||
|
// Path Nodes
|
||||||
|
//===============================================================
|
||||||
|
|
||||||
|
class PathNode : Actor
|
||||||
|
{
|
||||||
|
// For non-connected paths. Stamina will be used to set this. Necessary for tele/portals.
|
||||||
|
private int group;
|
||||||
|
|
||||||
|
Array<Actor> neighbors;
|
||||||
|
|
||||||
|
Default
|
||||||
|
{
|
||||||
|
//$Arg0 "TID 1"
|
||||||
|
//$Arg1 "TID 2"
|
||||||
|
//$Arg2 "TID 3"
|
||||||
|
//$Arg3 "TID 4"
|
||||||
|
//$Arg4 "TID 5"
|
||||||
|
//$Arg0Type 14
|
||||||
|
//$Arg1Type 14
|
||||||
|
//$Arg2Type 14
|
||||||
|
//$Arg3Type 14
|
||||||
|
//$Arg4Type 14
|
||||||
|
+NOBLOCKMAP
|
||||||
|
+INVISIBLE
|
||||||
|
+DONTSPLASH
|
||||||
|
+NOTONAUTOMAP
|
||||||
|
+NOGRAVITY // TO DO: Look into 3D variant for traversing up and down 3D floors and floating monsters.
|
||||||
|
RenderStyle "None";
|
||||||
|
MeleeRange 2048; // Sight checks limited to this. 0 = infinite.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Args are TIDs. Can be one way to force single directions.
|
||||||
|
override void PostBeginPlay()
|
||||||
|
{
|
||||||
|
Super.PostBeginPlay();
|
||||||
|
for (int i = 0; i < Args.Size(); i++)
|
||||||
|
{
|
||||||
|
if (!Args[i]) continue;
|
||||||
|
|
||||||
|
let it = level.CreateActorIterator(Args[i], "PathNode");
|
||||||
|
PathNode node;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (node && node != self)
|
||||||
|
neighbors.Push(node);
|
||||||
|
} while (node = PathNode(it.Next()))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For ACS access with ScriptCall.
|
||||||
|
// 'con' values are:
|
||||||
|
// 0: No connections
|
||||||
|
// 1: Connect tid1 to tid2 one-way
|
||||||
|
// 2: ^ but two-way.
|
||||||
|
static void SetConnectionGlobal(int tid1, int tid2, int con)
|
||||||
|
{
|
||||||
|
if (tid1 == 0 || tid2 == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PathNode node;
|
||||||
|
Array<PathNode> nodes2; // Cache for actors with tid2
|
||||||
|
{
|
||||||
|
let it = Level.CreateActorIterator(tid2, "PathNode");
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (node)
|
||||||
|
nodes2.Push(node);
|
||||||
|
} while (node = PathNode(it.Next()))
|
||||||
|
}
|
||||||
|
// Nothing to set to.
|
||||||
|
if (nodes2.Size() < 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let it = Level.CreateActorIterator(tid1, "PathNode");
|
||||||
|
node = null;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
foreach (n2 : nodes2)
|
||||||
|
{
|
||||||
|
if (n2)
|
||||||
|
{
|
||||||
|
node.SetConnection(n2, con);
|
||||||
|
n2.SetConnection(node, (con > 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (node = PathNode(it.Next()))
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetConnection(PathNode other, bool on)
|
||||||
|
{
|
||||||
|
if (!other) return;
|
||||||
|
|
||||||
|
if (on)
|
||||||
|
{
|
||||||
|
if (neighbors.Find(other) >= neighbors.Size())
|
||||||
|
neighbors.Push(other);
|
||||||
|
}
|
||||||
|
else neighbors.Delete(neighbors.Find(other));
|
||||||
|
}
|
||||||
|
}
|
|
@ -553,6 +553,8 @@ struct LevelLocals native
|
||||||
|
|
||||||
native void SpawnParticle(FSpawnParticleParams p);
|
native void SpawnParticle(FSpawnParticleParams p);
|
||||||
native VisualThinker SpawnVisualThinker(Class<VisualThinker> type);
|
native VisualThinker SpawnVisualThinker(Class<VisualThinker> type);
|
||||||
|
|
||||||
|
native bool AStar(Actor chaser, Actor target, Actor startnode = null, Actor goalnode = null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// a few values of this need to be readable by the play code.
|
// a few values of this need to be readable by the play code.
|
||||||
|
|
|
@ -435,6 +435,7 @@ struct Sector native play
|
||||||
SECMF_UNDERWATERMASK = 32+64,
|
SECMF_UNDERWATERMASK = 32+64,
|
||||||
SECMF_DRAWN = 128, // sector has been drawn at least once
|
SECMF_DRAWN = 128, // sector has been drawn at least once
|
||||||
SECMF_HIDDEN = 256, // Do not draw on textured automap
|
SECMF_HIDDEN = 256, // Do not draw on textured automap
|
||||||
|
SECMF_NOPATHING = 4096, // monsters cannot path find in these areas, saves on time and resources
|
||||||
}
|
}
|
||||||
native uint16 MoreFlags;
|
native uint16 MoreFlags;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue