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 "fragglescript/t_script.h"
|
||||
|
||||
|
||||
#include "texturemanager.h"
|
||||
|
||||
void STAT_StartNewGame(const char *lev);
|
||||
|
|
@ -2466,3 +2467,106 @@ DEFINE_ACTION_FUNCTION(FLevelLocals, GetEpisodeName)
|
|||
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();
|
||||
|
||||
bool AStar(AActor *chaser, AActor *target, AActor *startnode = nullptr, AActor *goalnode = nullptr);
|
||||
|
||||
TArray<AActor *> PathNodes;
|
||||
TArray<vertex_t> vertexes;
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -503,6 +503,7 @@ enum
|
|||
SECMF_OVERLAPPING = 512, // floor and ceiling overlap and require special renderer action.
|
||||
SECMF_NOSKYWALLS = 1024, // Do not draw "sky walls"
|
||||
SECMF_LIFT = 2048, // For MBF monster AI
|
||||
SECMF_NOPATHING = 4096, // monsters cannot path find in these areas, saves on time and resources
|
||||
};
|
||||
|
||||
enum
|
||||
|
|
|
|||
|
|
@ -202,6 +202,7 @@ xx(Cast) // 'damage type' for the cast call
|
|||
xx(MapSpot)
|
||||
xx(PatrolPoint)
|
||||
xx(PatrolSpecial)
|
||||
xx(PathNode)
|
||||
xx(Communicator)
|
||||
xx(PowerScanner)
|
||||
|
||||
|
|
|
|||
|
|
@ -611,6 +611,8 @@ void P_SetupLevel(FLevelLocals *Level, int position, bool newGame)
|
|||
while ((ac = it.Next()))
|
||||
{
|
||||
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_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_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 ---
|
||||
|
|
@ -1101,6 +1103,8 @@ public:
|
|||
void AttachLight(unsigned int count, const FLightDefaults *lightdef);
|
||||
void SetDynamicLights();
|
||||
|
||||
void ClearPath();
|
||||
|
||||
// info for drawing
|
||||
// NOTE: The first member variable *must* be snext.
|
||||
AActor *snext, **sprev; // links in sector (if needed)
|
||||
|
|
@ -1157,6 +1161,7 @@ public:
|
|||
TObjPtr<DBoneComponents*> boneComponentData;
|
||||
|
||||
// interaction info
|
||||
TArray<TObjPtr<AActor*> > Path;
|
||||
FBlockNode *BlockNode; // links in blocks (if needed)
|
||||
struct sector_t *Sector;
|
||||
subsector_t * subsector;
|
||||
|
|
|
|||
|
|
@ -2199,6 +2199,26 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearLastHeard)
|
|||
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
|
||||
|
|
@ -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
|
||||
// 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;
|
||||
|
||||
|
|
@ -2443,7 +2463,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
|||
}
|
||||
if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
|
||||
{ // 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.
|
||||
actor->lastenemy = actor->target;
|
||||
|
|
@ -2451,17 +2471,17 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
|||
// hurt our old one temporarily.
|
||||
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
|
||||
actor->flags7 &= ~MF7_INCHASE;
|
||||
return;
|
||||
}
|
||||
if (actor->target == NULL)
|
||||
if (actor->target == nullptr)
|
||||
{
|
||||
if (flags & CHF_DONTIDLE || actor->flags & MF_FRIENDLY)
|
||||
{
|
||||
//A_Look(actor);
|
||||
if (actor->target == NULL)
|
||||
if (actor->target == nullptr)
|
||||
{
|
||||
if (!dontmove) A_Wander(actor);
|
||||
actor->flags7 &= ~MF7_INCHASE;
|
||||
|
|
@ -2470,6 +2490,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
|||
}
|
||||
else
|
||||
{
|
||||
actor->ClearPath();
|
||||
actor->SetIdle();
|
||||
actor->flags7 &= ~MF7_INCHASE;
|
||||
return;
|
||||
|
|
@ -2493,9 +2514,31 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
|||
actor->flags7 &= ~MF7_INCHASE;
|
||||
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
|
||||
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;
|
||||
actor->target = actor->goal;
|
||||
|
|
@ -2513,7 +2556,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
|||
// as the goal.
|
||||
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]);
|
||||
}
|
||||
|
||||
|
|
@ -2536,6 +2579,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
|||
if (newgoal != NULL && delay != 0)
|
||||
{
|
||||
actor->flags4 |= MF4_INCOMBAT;
|
||||
actor->ClearPath(); // [MC] Just to be safe.
|
||||
actor->SetIdle();
|
||||
}
|
||||
actor->flags7 &= ~MF7_INCHASE;
|
||||
|
|
|
|||
|
|
@ -353,6 +353,8 @@ static FFlagDef ActorFlagDefs[]=
|
|||
DEFINE_FLAG(MF9, SHADOWBLOCK, AActor, flags9),
|
||||
DEFINE_FLAG(MF9, SHADOWAIMVERT, AActor, flags9),
|
||||
DEFINE_FLAG(MF9, DECOUPLEDANIMATIONS, AActor, flags9),
|
||||
DEFINE_FLAG(MF9, PATHING, AActor, flags9),
|
||||
DEFINE_FLAG(MF9, KEEPPATH, AActor, flags9),
|
||||
|
||||
// Effect flags
|
||||
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
|
||||
|
|
|
|||
|
|
@ -2125,6 +2125,7 @@ DEFINE_FIELD(AActor, LightLevel)
|
|||
DEFINE_FIELD(AActor, ShadowAimFactor)
|
||||
DEFINE_FIELD(AActor, ShadowPenaltyFactor)
|
||||
DEFINE_FIELD(AActor, AutomapOffsets)
|
||||
DEFINE_FIELD(AActor, Path)
|
||||
|
||||
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, thing);
|
||||
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, pos);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue