diff --git a/src/g_level.cpp b/src/g_level.cpp index c490cbbcd..f4452bfbd 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -98,7 +98,6 @@ #include "s_music.h" #include "fragglescript/t_script.h" - #include "texturemanager.h" void STAT_StartNewGame(const char *lev); @@ -2473,188 +2472,3 @@ DEFINE_ACTION_FUNCTION(FLevelLocals, GetEpisodeName) ACTION_RETURN_STRING(GStrings.localize(STAT_EpisodeName().GetChars())); } - -//---------------------------------------------------------------------------- -// Pathfinding -//---------------------------------------------------------------------------- - -// Code by RicardoLuis0, modified by Major Cooke -static TArray>& GetPathNodeNeighbors(AActor * self) -{ - static PClass * nodeCls = PClass::FindClass(NAME_PathNode); - -#ifndef NDEBUG - if(!nodeCls->IsAncestorOf(self->GetClass())) - { - ThrowAbortException(X_BAD_SELF, "Invalid class passed to GetNeighbors (must be PathNode)"); - } -#endif - - static PField *var = dyn_cast(nodeCls->FindSymbol("neighbors", true)); - - assert(var); - assert(var->Type->isDynArray()); - assert(static_cast(var->Type)->ElementType == nodeCls->VMType); - - return *reinterpret_cast>*>(reinterpret_cast(self) + var->Offset); -} - -static void ReconstructPath(TMap &cameFrom, AActor* current, TArray> &path) -{ - path.Clear(); - path.Push(current); - AActor ** tmp = cameFrom.CheckKey(current); - - if(tmp) do - { - path.Insert(0, *tmp); - } - while(tmp = cameFrom.CheckKey(*tmp)); -} - -static AActor* FindClosestNode(AActor* from) -{ - static const PClass * nodeCls = PClass::FindClass(NAME_PathNode); - - AActor * closest = nullptr; - double closestDist = DBL_MAX; - - for (int i = 0; i < from->Level->PathNodes.Size(); i++) - { - AActor* node = from->Level->PathNodes[i]; - if(node && !(node->flags & MF_AMBUSH) && nodeCls->IsAncestorOf(node->GetClass())) - { - double dst = node->Distance3DSquared(from); - const bool mrange = (dst < closestDist && - (node->friendlyseeblocks <= 0 || dst < double(node->friendlyseeblocks * node->friendlyseeblocks))); - - if (mrange && !from->CallExcludeNode(node) && P_CheckSight(node, from)) - { - closestDist = dst; - closest = node; - } - } - } - - return closest; -} - -template -static V GetOr(TMap map, const K &key, V alt) -{ - V *k = map.CheckKey(key); - return k ? *k : alt; -} - -static bool FindPathAStar(AActor *chaser, AActor* startnode, AActor* goalnode, TArray> &path) -{ - TArray openSet; - TMap cameFrom; - TMap gScore; - TMap fScore; - - openSet.Push(startnode); - gScore.Insert(startnode, 0); - fScore.Insert(startnode, startnode->Distance3DSquared(goalnode)); - - auto lt_fScore = [&fScore](AActor* lhs, AActor* rhs) - { - return GetOr(fScore, lhs, DBL_MAX) < GetOr(fScore, rhs, DBL_MAX); - }; - - while(openSet.Size() > 0) - { - AActor * current = openSet[0]; - openSet.Delete(0); - if(current == goalnode) - { - ReconstructPath(cameFrom, current, path); - return true; - } - - double current_gScore = GetOr(gScore, current, DBL_MAX); - - for(AActor * neighbor : GetPathNodeNeighbors(current)) - { - double tentative_gScore = current_gScore + current->Distance3DSquared(neighbor); - - double neighbor_gScore = GetOr(gScore, neighbor, DBL_MAX); - - if (tentative_gScore < neighbor_gScore && !chaser->CallExcludeNode(neighbor)) - { - openSet.SortedDelete(neighbor, lt_fScore); - cameFrom.Insert(neighbor, current); - gScore.Insert(neighbor, tentative_gScore); - fScore.Insert(neighbor, tentative_gScore + neighbor->Distance3DSquared(goalnode)); - openSet.SortedInsert(neighbor, lt_fScore); - } - } - } - return false; -} - -bool FLevelLocals::FindPath(AActor* chaser, AActor* target, AActor* startNode, AActor* goalNode) -{ - if (!chaser || !target || PathNodes.Size() < 1) - { - return false; - } - - static PClass* nodeCls = PClass::FindClass(NAME_PathNode); - assert(startNode == nullptr || nodeCls->IsAncestorOf(startNode->GetClass())); - assert(goalNode == nullptr || nodeCls->IsAncestorOf(goalNode->GetClass())); - - if(startNode == nullptr) startNode = FindClosestNode(chaser); - if(goalNode == nullptr) goalNode = FindClosestNode(target); - - // Incomplete graph. - if (!startNode || !goalNode) - { - return false; - } - - if (startNode == goalNode) - { - chaser->ClearPath(); - chaser->Path.Push(MakeObjPtr(startNode)); - return true; - } - - if (FindPathAStar(chaser, startNode, goalNode, chaser->Path)) - { - if (chaser->goal && nodeCls->IsAncestorOf(chaser->goal->GetClass())) - { - chaser->goal = nullptr; - } - return true; - } - - return false; -} - -DEFINE_ACTION_FUNCTION(FLevelLocals, FindPath) -{ - PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); - PARAM_OBJECT(chaser, AActor); - PARAM_OBJECT(target, AActor); - PARAM_OBJECT(startnode, AActor); - PARAM_OBJECT(goalnode, AActor); - return self->FindPath(chaser, target, startnode, goalnode); -} - -DEFINE_ACTION_FUNCTION(FLevelLocals, HandlePathNode) -{ - PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); - PARAM_OBJECT(node, AActor); - PARAM_BOOL(add); - if (node) - { - if (add) - { - if (self->PathNodes.Find(node) >= self->PathNodes.Size()) - self->PathNodes.Push(node); - } - else self->PathNodes.Delete(self->PathNodes.Find(node)); - } - return 0; -} diff --git a/src/g_levellocals.h b/src/g_levellocals.h index de0483879..2a9c41af6 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -444,9 +444,6 @@ public: void SetMusic(); - bool FindPath(AActor *chaser, AActor *target, AActor *startnode = nullptr, AActor *goalnode = nullptr); - - TArray PathNodes; TArray vertexes; TArray sectors; TArray extsectors; // container for non-trivial sector information. sector_t must be trivially copyable for *_fakeflat to work as intended. diff --git a/src/gamedata/g_mapinfo.cpp b/src/gamedata/g_mapinfo.cpp index 76b5e7d00..dde9d1cc4 100644 --- a/src/gamedata/g_mapinfo.cpp +++ b/src/gamedata/g_mapinfo.cpp @@ -1823,7 +1823,6 @@ MapFlagHandlers[] = { "disableskyboxao", MITYPE_CLRFLAG3, LEVEL3_SKYBOXAO, 0 }, { "avoidmelee", MITYPE_SETFLAG3, LEVEL3_AVOIDMELEE, 0 }, { "attenuatelights", MITYPE_SETFLAG3, LEVEL3_ATTENUATE, 0 }, - { "pathing", MITYPE_SETFLAG3, LEVEL3_PATHING, 0 }, { "nousersave", MITYPE_SETVKDFLAG, VKDLEVELFLAG_NOUSERSAVE, 0 }, { "noautomap", MITYPE_SETVKDFLAG, VKDLEVELFLAG_NOAUTOMAP, 0 }, { "noautosaveonenter", MITYPE_SETVKDFLAG, VKDLEVELFLAG_NOAUTOSAVEONENTER, 0 }, diff --git a/src/gamedata/g_mapinfo.h b/src/gamedata/g_mapinfo.h index a2505e057..17fae6255 100644 --- a/src/gamedata/g_mapinfo.h +++ b/src/gamedata/g_mapinfo.h @@ -270,7 +270,6 @@ enum ELevelFlags : unsigned int LEVEL3_AVOIDMELEE = 0x00020000, // global flag needed for proper MBF support. LEVEL3_NOJUMPDOWN = 0x00040000, // only for MBF21. Inverse of MBF's dog_jumping flag. LEVEL3_LIGHTCREATED = 0x00080000, // a light had been created in the last frame - LEVEL3_PATHING = 0x00100000, // enable pathfinding by default // VKDoom custom flags VKDLEVELFLAG_NOUSERSAVE = 0x00000001, diff --git a/src/gamedata/r_defs.h b/src/gamedata/r_defs.h index cc3a82aaa..efdbd4959 100644 --- a/src/gamedata/r_defs.h +++ b/src/gamedata/r_defs.h @@ -503,7 +503,6 @@ 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 diff --git a/src/namedef_custom.h b/src/namedef_custom.h index 720546407..135278197 100644 --- a/src/namedef_custom.h +++ b/src/namedef_custom.h @@ -202,7 +202,6 @@ xx(Cast) // 'damage type' for the cast call xx(MapSpot) xx(PatrolPoint) xx(PatrolSpecial) -xx(PathNode) xx(Communicator) xx(PowerScanner) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index c2e32f4d8..53cbfce62 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -326,7 +326,6 @@ void FLevelLocals::ClearLevelData(bool fullgc) } ClearPortals(); - PathNodes.Clear(); tagManager.Clear(); ClearTIDHashes(); if (SpotState) SpotState->Destroy(); diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 176848704..14e5ee906 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -442,10 +442,7 @@ 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_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. - MF9_NOPATHING = 0x00000080, // [MC] override the mapinfo "pathfinding" + MF9_DECOUPLEDANIMATIONS = 0x00000010, // [RL0] Decouple model animations from states }; // --- mobj.renderflags --- @@ -1104,11 +1101,6 @@ public: void AttachLight(unsigned int count, const FLightDefaults *lightdef); void SetDynamicLights(); - void ClearPath(); - bool CanPathfind(); - bool CallExcludeNode(AActor *node); - void CallReachedNode(AActor *node); - // info for drawing // NOTE: The first member variable *must* be snext. AActor *snext, **sprev; // links in sector (if needed) @@ -1165,7 +1157,6 @@ public: TObjPtr boneComponentData; // interaction info - TArray > Path; FBlockNode *BlockNode; // links in blocks (if needed) struct sector_t *Sector; subsector_t * subsector; @@ -1369,6 +1360,10 @@ public: int SpawnTime; uint32_t SpawnOrder; + // landing speed from a jump with normal gravity (squats the player's view) + // (note: this is put into AActor instead of the PlayerPawn because non-players also use the value) + double LandingSpeed; + double SourceRadius = 5.0; // Light source radius // ThingIDs diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp index 76d6be9fd..410ac6a53 100644 --- a/src/playsim/p_actionfunctions.cpp +++ b/src/playsim/p_actionfunctions.cpp @@ -5165,7 +5165,7 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s if(animStart == FErr_NotFound) { self->modelData->curAnim.flags = ANIMOVERRIDE_NONE; - Printf("Could not find animation %s", animName.GetChars()); + Printf("Could not find animation %s\n", animName.GetChars()); return; } int animEnd = mdl->FindLastFrame(animName); @@ -5180,13 +5180,13 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s if(startFrame >= len) { self->modelData->curAnim.flags = ANIMOVERRIDE_NONE; - Printf("frame %d is past the end of animation %s", startFrame, animName.GetChars()); + Printf("frame %d is past the end of animation %s\n", startFrame, animName.GetChars()); return; } else if(loopFrame >= len) { self->modelData->curAnim.flags = ANIMOVERRIDE_NONE; - Printf("frame %d is past the end of animation %s", startFrame, animName.GetChars()); + Printf("frame %d is past the end of animation %s\n", startFrame, animName.GetChars()); return; } @@ -5330,7 +5330,7 @@ void ChangeModelNative( if (n_modeldef != NAME_None && (modeldef = PClass::FindActor(n_modeldef.GetChars())) == nullptr) { - Printf("Attempt to pass invalid modeldef name %s in %s.", n_modeldef.GetChars(), self->GetCharacterName()); + Printf("Attempt to pass invalid modeldef name %s in %s.\n", n_modeldef.GetChars(), self->GetCharacterName()); return; } diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index 0dc3fd0ef..f63d00588 100644 --- a/src/playsim/p_enemy.cpp +++ b/src/playsim/p_enemy.cpp @@ -318,14 +318,13 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, CheckMeleeRange, P_CheckMeleeRange) // //============================================================================= -static int DoCheckMissileRange (AActor *actor, int &sight) +static int P_CheckMissileRange (AActor *actor) { double dist; if ((actor->Sector->Flags & SECF_NOATTACK)) return false; - sight = P_CheckSight(actor, actor->target, SF_SEEPASTBLOCKEVERYTHING); - if (!sight) + if (!P_CheckSight (actor, actor->target, SF_SEEPASTBLOCKEVERYTHING)) return false; if (actor->flags & MF_JUSTHIT) @@ -381,12 +380,6 @@ static int DoCheckMissileRange (AActor *actor, int &sight) return pr_checkmissilerange() >= min(int(dist), mmc); } -static int P_CheckMissileRange(AActor* actor) -{ - int n = -1; - return DoCheckMissileRange(actor, n); -} - DEFINE_ACTION_FUNCTION_NATIVE(AActor, CheckMissileRange, P_CheckMissileRange) { PARAM_SELF_PROLOGUE(AActor); @@ -951,13 +944,13 @@ void P_DoNewChaseDir (AActor *actor, double deltax, double deltay) // //============================================================================= -void DoNewChaseDir(AActor * actor, bool node) +void P_NewChaseDir(AActor * actor) { DVector2 delta; actor->strafecount = 0; - if ((node || actor->flags5&MF5_CHASEGOAL || actor->goal == actor->target) && actor->goal != nullptr) + if ((actor->flags5&MF5_CHASEGOAL || actor->goal == actor->target) && actor->goal!=NULL) { delta = actor->Vec2To(actor->goal); } @@ -1096,11 +1089,6 @@ void DoNewChaseDir(AActor * actor, bool node) } -void P_NewChaseDir(AActor* actor) -{ - DoNewChaseDir(actor, false); -} - //============================================================================= // // P_RandomChaseDir @@ -2211,81 +2199,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearLastHeard) return 0; } -//========================================================================== -// -// ClearPath -// -//========================================================================== - -void AActor::ClearPath() -{ - Path.Clear(); - if (goal) - { - static PClass* nodeCls = PClass::FindClass(NAME_PathNode); - if (nodeCls->IsAncestorOf(goal->GetClass())) - goal = nullptr; - } -} - -DEFINE_ACTION_FUNCTION(AActor, ClearPath) -{ - PARAM_SELF_PROLOGUE(AActor); - self->ClearPath(); - return 0; -} - -bool AActor::CanPathfind() -{ - if (Level->PathNodes.Size() > 0 && - (!(flags9 & MF9_NOPATHING) && !(Sector->MoreFlags & SECMF_NOPATHING)) && - (flags9 & MF9_PATHING || Level->flags3 & LEVEL3_PATHING)) - { - if ((flags6 & MF6_NOFEAR)) - return true; - - // Can't pathfind while feared. - if (!(flags4 & MF4_FRIGHTENED)) - { - if (!target) - return true; - - if (!target->flags8 & MF8_FRIGHTENING) - return (!target->player || !(target->player->cheats & CF_FRIGHTENING)); - } - } - return false; -} - -DEFINE_ACTION_FUNCTION(AActor, CanPathfind) -{ - PARAM_SELF_PROLOGUE(AActor); - return self->CanPathfind(); -} - -void AActor::CallReachedNode(AActor *node) -{ - IFVIRTUAL(AActor, ReachedNode) - { - VMValue params[2] = { this, node }; - VMCall(func, params, 2, nullptr, 0); - } -} - -// 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 @@ -2420,7 +2333,6 @@ nosee: void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missilestate, bool playactive, bool nightmarefast, bool dontmove, int flags) { - int sight = -1; if (actor->flags5 & MF5_INCONVERSATION) return; @@ -2499,7 +2411,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 == nullptr) + if (actor->flags & MF_FRIENDLY && actor->target == NULL) { player_t *player; @@ -2558,7 +2470,6 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi } else { - actor->ClearPath(); actor->SetIdle(); actor->flags7 &= ~MF7_INCHASE; return; @@ -2582,13 +2493,9 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi actor->flags7 &= ~MF7_INCHASE; return; } - + // [RH] Don't attack if just moving toward goal - static const PClass* nodeCls = PClass::FindClass(NAME_PathNode); - bool pnode = (actor->goal && nodeCls->IsAncestorOf(actor->goal->GetClass())); - - if (!pnode && - (actor->target == actor->goal || (actor->flags5&MF5_CHASEGOAL && actor->goal))) + if (actor->target == actor->goal || (actor->flags5&MF5_CHASEGOAL && actor->goal != NULL)) { AActor * savedtarget = actor->target; actor->target = actor->goal; @@ -2606,7 +2513,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, nullptr, actor, false, spec->args[0], + P_ExecuteSpecial(actor->Level, spec->special, NULL, actor, false, spec->args[0], spec->args[1], spec->args[2], spec->args[3], spec->args[4]); } @@ -2629,7 +2536,6 @@ 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; @@ -2687,9 +2593,17 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi } // check for missile attack - if (missilestate && (actor->isFast() || actor->movecount < 1) && DoCheckMissileRange(actor, sight)) + if (missilestate) { - actor->SetState(missilestate); + if (!actor->isFast() && actor->movecount) + { + goto nomissile; + } + + if (!P_CheckMissileRange (actor)) + goto nomissile; + + actor->SetState (missilestate); actor->flags |= MF_JUSTATTACKED; actor->flags4 |= MF4_INCOMBAT; actor->flags7 &= ~MF7_INCHASE; @@ -2719,43 +2633,10 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi if (gotNew && actor->target != oldtarget) { actor->flags7 &= ~MF7_INCHASE; - actor->ClearPath(); return; // got a new target } } - if (!dontmove && actor->target && actor->CanPathfind()) - { - // Try to get sight checks from missile states if they have any, saving time. - if (!(actor->flags9 & MF9_KEEPPATH)) - { - if (sight < 0) - sight = P_CheckSight(actor, actor->target, SF_SEEPASTBLOCKEVERYTHING); - } - else sight = 0; - - if (sight == 0) - { - if (pnode && !(actor->goal->flags & MF_AMBUSH)) - { - AActor* temp = actor->target; - actor->target = actor->goal; - bool reached = (P_CheckMeleeRange(actor)); - actor->target = temp; - - if (reached) - actor->CallReachedNode(actor->goal); - - } - if (!actor->goal) - { - if (actor->Path.Size() > 0 || actor->Level->FindPath(actor, actor->target)) - actor->goal = actor->Path[0]; - } - } - else actor->ClearPath(); - } - // // chase towards player // @@ -2774,7 +2655,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi // chase towards player if ((--actor->movecount < 0 && !(flags & CHF_NORANDOMTURN)) || (!P_SmartMove(actor) && !(flags & CHF_STOPIFBLOCKED))) { - DoNewChaseDir(actor, pnode); + P_NewChaseDir(actor); } // if the move was illegal, reset it // (copied from A_SerpentChase - it applies to everything with CANTLEAVEFLOORPIC!) @@ -2790,7 +2671,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi } } if (!(flags & CHF_STOPIFBLOCKED)) - DoNewChaseDir(actor, pnode); + P_NewChaseDir(actor); } } else if (dontmove && actor->movecount > 0) actor->movecount--; diff --git a/src/playsim/p_map.cpp b/src/playsim/p_map.cpp index e3c0e16f5..d6a828024 100644 --- a/src/playsim/p_map.cpp +++ b/src/playsim/p_map.cpp @@ -592,7 +592,7 @@ bool P_TeleportMove(AActor* thing, const DVector3 &pos, bool telefrag, bool modi thing->CheckSectorTransition(oldsec); } } - thing->ClearPath(); + return true; } @@ -2536,8 +2536,8 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, // Check for crossed portals - bool portalcrossed, nodecall; - nodecall = portalcrossed = false; + bool portalcrossed; + portalcrossed = false; while (true) { @@ -2582,7 +2582,6 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, thing->Prev += port->mDisplacement; thing->LinkToWorld(&ctx); P_FindFloorCeiling(thing); - thing->ClearPath(); portalcrossed = true; tm.portalstep = false; tm.pos += port->mDisplacement; @@ -2612,8 +2611,7 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, P_TranslatePortalVXVY(ld, thing->Vel.X, thing->Vel.Y); P_TranslatePortalAngle(ld, thing->Angles.Yaw); thing->LinkToWorld(&ctx); - P_FindFloorCeiling(thing); - thing->ClearPath(); + P_FindFloorCeiling(thing); thing->ClearInterpolation(); portalcrossed = true; tm.portalstep = false; @@ -2771,7 +2769,7 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, thing->Sector = thing->Level->PointInSector(thing->Pos()); thing->PrevPortalGroup = thing->Sector->PortalGroup; thing->LinkToWorld(&ctx); - thing->ClearPath(); + P_FindFloorCeiling(thing); } diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index 0b78d0b90..c4e6ab69e 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -391,7 +391,8 @@ void AActor::Serialize(FSerializer &arc) A("lightlevel", LightLevel) A("userlights", UserLights) A("WorldOffset", WorldOffset) - ("modelData", modelData); + ("modelData", modelData) + A("LandingSpeed", LandingSpeed); SerializeTerrain(arc, "floorterrain", floorterrain, &def->floorterrain); SerializeArgs(arc, "args", args, def->args, special); @@ -2584,11 +2585,9 @@ static void P_ZMovement (AActor *mo, double oldfloorz) mo->SetZ(mo->floorz); if (mo->Vel.Z < 0) { - const double minvel = -8; // landing speed from a jump with normal gravity - // Spawn splashes, etc. P_HitFloor (mo); - if (mo->DamageType == NAME_Ice && mo->Vel.Z < minvel) + if (mo->DamageType == NAME_Ice && mo->Vel.Z < mo->LandingSpeed) { mo->tics = 1; mo->Vel.Zero(); @@ -2601,11 +2600,11 @@ static void P_ZMovement (AActor *mo, double oldfloorz) } if (mo->player) { - if (mo->player->jumpTics < 0 || mo->Vel.Z < minvel) + if (mo->player->jumpTics < 0 || mo->Vel.Z < mo->LandingSpeed) { // delay any jumping for a short while mo->player->jumpTics = 7; } - if (mo->Vel.Z < minvel && !(mo->flags & MF_NOGRAVITY)) + if (mo->Vel.Z < mo->LandingSpeed && !(mo->flags & MF_NOGRAVITY)) { // Squat down. // Decrease viewheight for a moment after hitting the ground (hard), diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp index 3a9d3afbb..ec9cd502f 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -1141,7 +1141,7 @@ FSpriteModelFrame * FindModelFrame(const AActor * thing, int sprite, int frame, if(thing->flags9 & MF9_DECOUPLEDANIMATIONS) { - return &BaseSpriteModelFrames[(thing->modelData != nullptr && thing->modelData->modelDef != nullptr) ? thing->modelData->modelDef : thing->GetClass()]; + return BaseSpriteModelFrames.CheckKey((thing->modelData != nullptr && thing->modelData->modelDef != nullptr) ? thing->modelData->modelDef : thing->GetClass()); } else { diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 12fbf1ce1..4da560df3 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -466,18 +466,13 @@ bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp) const bool useOffsets = (actor != nullptr) && !(actor->renderflags & RF_ROLLCENTER); FVector2 offset = FVector2( offx, offy ); - - // Account for +ROLLCENTER flag. Takes the embedded image offsets and adds them in with SpriteOffsets. - if (drawRollSpriteActor && useOffsets) - { - offset.X += center.X - x; - offset.Y += center.Z - z; - } - + float xx = -center.X + x; + float yy = -center.Y + y; + float zz = -center.Z + z; // [Nash] check for special sprite drawing modes if (drawWithXYBillboard || isWallSprite) { - // Compute center of sprite + mat.MakeIdentity(); mat.Translate(center.X, center.Z, center.Y); // move to sprite center @@ -512,16 +507,21 @@ bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp) mat.Rotate(0, 1, 0, 0); if (drawRollSpriteActor) { + + if (useOffsets) mat.Translate(xx, zz, yy); mat.Rotate(yawvecX, 0, yawvecY, rollDegrees); + if (useOffsets) mat.Translate(-xx, -zz, -yy); } } else if (doRoll) { + if (useOffsets) mat.Translate(xx, zz, yy); if (drawWithXYBillboard) { mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees()); } mat.Rotate(cos(angleRad), 0, sin(angleRad), rollDegrees); + if (useOffsets) mat.Translate(-xx, -zz, -yy); } else if (drawWithXYBillboard) { @@ -554,7 +554,9 @@ bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp) float rollDegrees = Angles.Roll.Degrees(); mat.Translate(center.X, center.Z, center.Y); + if (useOffsets) mat.Translate(xx, zz, yy); mat.Rotate(cos(angleRad), 0, sin(angleRad), rollDegrees); + if (useOffsets) mat.Translate(-xx, -zz, -yy); mat.Translate(-center.X, -center.Z, -center.Y); } diff --git a/src/rendering/r_utility.cpp b/src/rendering/r_utility.cpp index 09cab0583..fbb785d0b 100644 --- a/src/rendering/r_utility.cpp +++ b/src/rendering/r_utility.cpp @@ -598,9 +598,9 @@ void R_InterpolateView(FRenderViewpoint& viewPoint, const player_t* const player } else { - viewPoint.Angles.Pitch = iView->Old.Angles.Pitch * inverseTicFrac + iView->New.Angles.Pitch * ticFrac; - viewPoint.Angles.Yaw = prevYaw * inverseTicFrac + curYaw * ticFrac; - viewPoint.Angles.Roll = iView->Old.Angles.Roll * inverseTicFrac + iView->New.Angles.Roll * ticFrac; + viewPoint.Angles.Pitch = iView->Old.Angles.Pitch + deltaangle(iView->Old.Angles.Pitch, iView->New.Angles.Pitch) * ticFrac; + viewPoint.Angles.Yaw = prevYaw + deltaangle(prevYaw, curYaw) * ticFrac; + viewPoint.Angles.Roll = iView->Old.Angles.Roll + deltaangle(iView->Old.Angles.Roll, iView->New.Angles.Roll) * ticFrac; } // Now that the base position and angles are set, add offsets. @@ -624,9 +624,9 @@ void R_InterpolateView(FRenderViewpoint& viewPoint, const player_t* const player { if (player == nullptr || (player->cheats & CF_INTERPVIEWANGLES)) { - viewPoint.Angles.Yaw += iView->Old.ViewAngles.Yaw * inverseTicFrac + iView->New.ViewAngles.Yaw * ticFrac; - viewPoint.Angles.Pitch += iView->Old.ViewAngles.Pitch * inverseTicFrac + iView->New.ViewAngles.Pitch * ticFrac; - viewPoint.Angles.Roll += iView->Old.ViewAngles.Roll * inverseTicFrac + iView->New.ViewAngles.Roll * ticFrac; + viewPoint.Angles.Yaw += iView->Old.ViewAngles.Yaw + deltaangle(iView->Old.ViewAngles.Yaw, iView->New.ViewAngles.Yaw) * ticFrac; + viewPoint.Angles.Pitch += iView->Old.ViewAngles.Pitch + deltaangle(iView->Old.ViewAngles.Pitch, iView->New.ViewAngles.Pitch) * ticFrac; + viewPoint.Angles.Roll += iView->Old.ViewAngles.Roll + deltaangle(iView->Old.ViewAngles.Roll, iView->New.ViewAngles.Roll) * ticFrac; } else { diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 9f835aff8..997ab78b1 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -353,9 +353,6 @@ 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), - DEFINE_FLAG(MF9, NOPATHING, AActor, flags9), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), diff --git a/src/scripting/vmthunks.cpp b/src/scripting/vmthunks.cpp index 5ffa4dba4..94e62782f 100644 --- a/src/scripting/vmthunks.cpp +++ b/src/scripting/vmthunks.cpp @@ -2787,7 +2787,6 @@ DEFINE_FIELD_X(LevelInfo, level_info_t, RedirectMapName) DEFINE_FIELD_X(LevelInfo, level_info_t, teamdamage) DEFINE_GLOBAL_NAMED(currentVMLevel, level) -DEFINE_FIELD(FLevelLocals, PathNodes) DEFINE_FIELD(FLevelLocals, sectors) DEFINE_FIELD(FLevelLocals, lines) DEFINE_FIELD(FLevelLocals, sides) @@ -2855,7 +2854,6 @@ DEFINE_FIELD_BIT(FLevelLocals, flags2, infinite_flight, LEVEL2_INFINITE_FLIGHT) DEFINE_FIELD_BIT(FLevelLocals, flags2, no_dlg_freeze, LEVEL2_CONV_SINGLE_UNFREEZE) DEFINE_FIELD_BIT(FLevelLocals, flags2, keepfullinventory, LEVEL2_KEEPFULLINVENTORY) DEFINE_FIELD_BIT(FLevelLocals, flags3, removeitems, LEVEL3_REMOVEITEMS) -DEFINE_FIELD_BIT(FLevelLocals, flags3, pathing, LEVEL3_PATHING) DEFINE_FIELD_BIT(FLevelLocals, vkdflags, nousersave, VKDLEVELFLAG_NOUSERSAVE) DEFINE_FIELD_BIT(FLevelLocals, vkdflags, noautomap, VKDLEVELFLAG_NOAUTOMAP) diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index 219d63e0d..c10212098 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -2125,7 +2125,7 @@ DEFINE_FIELD(AActor, LightLevel) DEFINE_FIELD(AActor, ShadowAimFactor) DEFINE_FIELD(AActor, ShadowPenaltyFactor) DEFINE_FIELD(AActor, AutomapOffsets) -DEFINE_FIELD(AActor, Path) +DEFINE_FIELD(AActor, LandingSpeed) DEFINE_FIELD_X(FCheckPosition, FCheckPosition, thing); DEFINE_FIELD_X(FCheckPosition, FCheckPosition, pos); diff --git a/wadsrc/static/engine/commonbinds.txt b/wadsrc/static/engine/commonbinds.txt index 0cb5756cc..8493529f2 100644 --- a/wadsrc/static/engine/commonbinds.txt +++ b/wadsrc/static/engine/commonbinds.txt @@ -115,6 +115,6 @@ mapbind joy2 am_clearmarks mapbind pov1right +am_panright mapbind pov1left +am_panleft mapbind pov1up +am_panup -mapbind pov2down +am_pandown +mapbind pov1down +am_pandown mapbind joy5 +am_zoomout mapbind joy6 +am_zoomin diff --git a/wadsrc/static/mapinfo/common.txt b/wadsrc/static/mapinfo/common.txt index 7046f7308..e80a50105 100644 --- a/wadsrc/static/mapinfo/common.txt +++ b/wadsrc/static/mapinfo/common.txt @@ -44,7 +44,6 @@ DoomEdNums 5065 = InvisibleBridge8 9001 = MapSpot 9013 = MapSpotGravity - 9022 = PathNode 9024 = PatrolPoint 9025 = SecurityCamera 9026 = Spark diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 9c694e38f..c1fe424de 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -261,7 +261,7 @@ class Actor : Thinker native private native int InventoryID; // internal counter. native uint freezetics; native Vector2 AutomapOffsets; - native Array Path; + native double LandingSpeed; meta String Obituary; // Player was killed by this actor meta String HitObituary; // Player was killed by this actor in melee @@ -367,6 +367,7 @@ class Actor : Thinker native property ShadowAimFactor: ShadowAimFactor; property ShadowPenaltyFactor: ShadowPenaltyFactor; property AutomapOffsets : AutomapOffsets; + property LandingSpeed: LandingSpeed; // need some definition work first //FRenderStyle RenderStyle; @@ -455,6 +456,7 @@ class Actor : Thinker native RenderHidden 0; RenderRequired 0; FriendlySeeBlocks 10; // 10 (blocks) * 128 (one map unit block) + LandingSpeed -8; // landing speed from a jump with normal gravity (squats the player's view) } // Functions @@ -664,7 +666,7 @@ class Actor : Thinker native // called before and after triggering a teleporter // return false in PreTeleport() to cancel the action early virtual bool PreTeleport( Vector3 destpos, double destangle, int flags ) { return true; } - virtual void PostTeleport( Vector3 destpos, double destangle, int flags ) { } + virtual void PostTeleport( Vector3 destpos, double destangle, int flags ) {} native virtual bool OkayToSwitchTarget(Actor other); native clearscope static class GetReplacement(class cls); @@ -698,7 +700,7 @@ class Actor : Thinker native native void SoundAlert(Actor target, bool splash = false, double maxdist = 0); native void ClearBounce(); 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 UpdateWaterLevel (bool splash = true); native bool IsZeroDamage(); @@ -797,72 +799,6 @@ class Actor : Thinker native movecount = random[TryWalk](0, 15); return true; } - - native void ClearPath(); - native clearscope bool CanPathfind() const; - virtual void ReachedNode(Actor mo) - { - if (!mo) - { - if (!goal) - return; - mo = goal; - } - - let node = PathNode(mo); - if (!node || !target || (!bKEEPPATH && CheckSight(target))) - { - ClearPath(); - return; - } - - int i = Path.Find(node) + 1; - int end = Path.Size(); - - for (i; i < end; i++) - { - PathNode next = Path[i]; - - if (!next || next == node) - continue; - - // Monsters will never 'reach' AMBUSH flagged nodes. Instead, the engine - // indicates they're reached the moment they tele/portal. - - if (node.bAMBUSH && next.bAMBUSH) - continue; - - goal = next; - break; - } - - if (i >= end) - 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; - - if (r <= 0.0 && h <= 0.0) - return false; - - // Perfect fit. - if (radius == r && height == h) - return false; - - if ((r < radius) || (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 aa78a99bc..5e146f6c9 100644 --- a/wadsrc/static/zscript/actors/shared/sharedmisc.zs +++ b/wadsrc/static/zscript/actors/shared/sharedmisc.zs @@ -245,123 +245,3 @@ class SpeakerIcon : Unknown Scale 0.125; } } - -/* -================================================================= -Path Nodes -================================================================= -Special flags are as follows: - -AMBUSH - Node is blind. Things cannot "touch" these nodes with A_Chase. - 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 -{ - Array neighbors; - - Default - { - +NOINTERACTION - +NOBLOCKMAP - +INVISIBLE - +DONTSPLASH - +NOTONAUTOMAP - +NOGRAVITY - Radius 16; - Height 56; - RenderStyle "None"; - - // 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. - 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())) - - } - level.HandlePathNode(self, true); - } - - override void OnDestroy() - { - level.HandlePathNode(self, false); - Super.OnDestroy(); - } - - // 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 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)); - } -} \ No newline at end of file diff --git a/wadsrc/static/zscript/doombase.zs b/wadsrc/static/zscript/doombase.zs index c67b1c3f1..daaf143bf 100644 --- a/wadsrc/static/zscript/doombase.zs +++ b/wadsrc/static/zscript/doombase.zs @@ -409,7 +409,7 @@ struct LevelLocals native const CLUSTER_HUB = 0x00000001; // Cluster uses hub behavior - native readonly Array PathNodes; + native Array<@Sector> Sectors; native Array<@Line> Lines; native Array<@Side> Sides; @@ -477,7 +477,6 @@ struct LevelLocals native native readonly int compatflags; native readonly int compatflags2; native readonly LevelInfo info; - native readonly bool pathing; native bool nousersave; native bool noautomap; @@ -558,9 +557,6 @@ struct LevelLocals native native void SpawnParticle(FSpawnParticleParams p); native VisualThinker SpawnVisualThinker(Class type); - - native bool FindPath(Actor chaser, Actor target, PathNode startnode = null, PathNode goalnode = null); - native void HandlePathNode(PathNode node, bool add); // This is only here because there's no other way to register the node privately. } // a few values of this need to be readable by the play code. diff --git a/wadsrc/static/zscript/mapdata.zs b/wadsrc/static/zscript/mapdata.zs index dd1d406e8..db217e7cc 100644 --- a/wadsrc/static/zscript/mapdata.zs +++ b/wadsrc/static/zscript/mapdata.zs @@ -435,7 +435,6 @@ struct Sector native play SECMF_UNDERWATERMASK = 32+64, SECMF_DRAWN = 128, // sector has been drawn at least once 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;