From 0ef042562ec7f1e21a46e5bfce3cdc3b575cf39e Mon Sep 17 00:00:00 2001 From: Boondorl Date: Fri, 8 Mar 2024 13:54:02 -0500 Subject: [PATCH 01/21] Fix for Morph virtual Allows class to be used as an argument type in place of class within the third argument for backwards compatibility. --- src/common/objects/dobjtype.cpp | 4 +++- src/namedef_custom.h | 1 + src/scripting/backend/codegen_doom.cpp | 13 +++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/common/objects/dobjtype.cpp b/src/common/objects/dobjtype.cpp index 70e83f8eadf..7b4463011c8 100644 --- a/src/common/objects/dobjtype.cpp +++ b/src/common/objects/dobjtype.cpp @@ -669,6 +669,8 @@ PClass *PClass::FindClassTentative(FName name) // //========================================================================== +bool ShouldAllowGameSpecificVirtual(FName name, unsigned index, PType* arg, PType* varg); + int PClass::FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction *parentfunc, bool exactReturnType, bool ignorePointerReadOnly) { auto proto = variant->Proto; @@ -700,7 +702,7 @@ int PClass::FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction break; } } - else + else if(!ShouldAllowGameSpecificVirtual(name, a, proto->ArgumentTypes[a], vproto->ArgumentTypes[a])) { fail = true; break; diff --git a/src/namedef_custom.h b/src/namedef_custom.h index 1bb07ad603b..d9730abdf28 100644 --- a/src/namedef_custom.h +++ b/src/namedef_custom.h @@ -463,6 +463,7 @@ xx(WBobSpeed) xx(WBobFire) xx(PlayerClass) xx(MonsterClass) +xx(Morph) xx(MorphedMonster) xx(Wi_NoAutostartMap) diff --git a/src/scripting/backend/codegen_doom.cpp b/src/scripting/backend/codegen_doom.cpp index 60e0cc61411..0e52790d723 100644 --- a/src/scripting/backend/codegen_doom.cpp +++ b/src/scripting/backend/codegen_doom.cpp @@ -57,6 +57,19 @@ PFunction* FindBuiltinFunction(FName funcname); // //========================================================================== +bool ShouldAllowGameSpecificVirtual(FName name, unsigned index, PType* arg, PType* varg) +{ + return (name == NAME_Morph && index == 3u && arg->isClassPointer() && varg->isClassPointer() + && PType::toClassPointer(varg)->ClassRestriction->TypeName == NAME_Actor + && PType::toClassPointer(arg)->ClassRestriction->TypeName == NAME_MorphedMonster); +} + +//========================================================================== +// +// +// +//========================================================================== + bool isActor(PContainerType *type) { auto cls = PType::toClass(type); From 730ef1a23aebf25f7784ea33417e60e17d159299 Mon Sep 17 00:00:00 2001 From: Boondorl Date: Sun, 10 Mar 2024 12:40:50 -0400 Subject: [PATCH 02/21] Adjusted view angle interpolation Now uses deltaangle to get the shortest interpolation path for angles. --- src/rendering/r_utility.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/rendering/r_utility.cpp b/src/rendering/r_utility.cpp index 09cab05832f..fbb785d0b52 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 { From 0d9855cfe719d3a776436bf304427654886a3d40 Mon Sep 17 00:00:00 2001 From: nashmuhandes Date: Wed, 13 Mar 2024 05:30:35 +0800 Subject: [PATCH 03/21] Expose `LandingSpeed` to ZScript. This controls the minimum Z velocity from falling down that's needed to "squat" the player's view (defaults to -8). --- src/playsim/actor.h | 3 +++ src/playsim/p_mobj.cpp | 11 +++++------ src/scripting/vmthunks_actors.cpp | 1 + wadsrc/static/zscript/actors/actor.zs | 3 +++ 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/playsim/actor.h b/src/playsim/actor.h index d985b082423..e14e7ea171f 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -1369,6 +1369,9 @@ class AActor final : public DThinker 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; // ThingIDs void SetTID (int newTID); diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index c3f4a82d588..ff98fb4da46 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/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index 219d63e0d0a..e8c7acbb6b0 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -2126,6 +2126,7 @@ 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/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 9c694e38ff6..1c4ea98c806 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -262,6 +262,7 @@ class Actor : Thinker native 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 +368,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 +457,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 From f081ef1850e56de9505cef64d12f320ac446c90a Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Sat, 9 Mar 2024 13:02:35 -0600 Subject: [PATCH 04/21] Enhanced pathing for floaters Their checks are now 2D instead of 3D. --- src/playsim/p_enemy.cpp | 14 ++++++++++++-- wadsrc/static/zscript/actors/actor.zs | 14 ++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index 0dc3fd0ef53..aa2b40b994a 100644 --- a/src/playsim/p_enemy.cpp +++ b/src/playsim/p_enemy.cpp @@ -2733,14 +2733,24 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi sight = P_CheckSight(actor, actor->target, SF_SEEPASTBLOCKEVERYTHING); } else sight = 0; - + + // Out of sight, so keep pathfinding if (sight == 0) { if (pnode && !(actor->goal->flags & MF_AMBUSH)) { AActor* temp = actor->target; actor->target = actor->goal; - bool reached = (P_CheckMeleeRange(actor)); + bool reached = false; + // 2D checks for floaters, 3D otherwise + if (actor->flags & MF_FLOAT) + { + bool vrange = !!(actor->flags5 & MF5_NOVERTICALMELEERANGE); + actor->flags5 |= MF5_NOVERTICALMELEERANGE; + P_CheckMeleeRange(actor); + if (!vrange) actor->flags5 &= ~(MF5_NOVERTICALMELEERANGE); + } + else reached = (P_CheckMeleeRange(actor)); actor->target = temp; if (reached) diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 1c4ea98c806..f3482864fc7 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -829,6 +829,20 @@ class Actor : Thinker native if (!next || next == node) continue; + // 2D checks for floaters, 3D for ground + Actor tar = target; + bool vrange = bNOVERTICALMELEERANGE; + bNOVERTICALMELEERANGE = bFLOAT; + target = next; + + bool inrange = CheckMeleeRange(); + + target = tar; + bNOVERTICALMELEERANGE = vrange; + + if (inrange) + continue; + // Monsters will never 'reach' AMBUSH flagged nodes. Instead, the engine // indicates they're reached the moment they tele/portal. From 4682b7172ea44f1a481cb0e72bde1ebb3ab31a5a Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Wed, 13 Mar 2024 10:49:53 -0500 Subject: [PATCH 05/21] Fixed typo --- src/playsim/p_enemy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index aa2b40b994a..722b5c602eb 100644 --- a/src/playsim/p_enemy.cpp +++ b/src/playsim/p_enemy.cpp @@ -2747,7 +2747,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi { bool vrange = !!(actor->flags5 & MF5_NOVERTICALMELEERANGE); actor->flags5 |= MF5_NOVERTICALMELEERANGE; - P_CheckMeleeRange(actor); + reached = P_CheckMeleeRange(actor); if (!vrange) actor->flags5 &= ~(MF5_NOVERTICALMELEERANGE); } else reached = (P_CheckMeleeRange(actor)); From 6d99395b6883d09009f800939f234c5116aa1a21 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Wed, 13 Mar 2024 13:10:10 -0500 Subject: [PATCH 06/21] - Fixed: Fear checks were incorrect when accounting for player being present or not. --- src/playsim/p_enemy.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index 722b5c602eb..ffc40197f10 100644 --- a/src/playsim/p_enemy.cpp +++ b/src/playsim/p_enemy.cpp @@ -2245,14 +2245,18 @@ bool AActor::CanPathfind() return true; // Can't pathfind while feared. - if (!(flags4 & MF4_FRIGHTENED)) + if (flags4 & MF4_FRIGHTENED) + return false; + + if (target) { - if (!target) - return true; + if (target->flags8 & MF8_FRIGHTENING) + return false; - if (!target->flags8 & MF8_FRIGHTENING) - return (!target->player || !(target->player->cheats & CF_FRIGHTENING)); + if (target->player && target->player->cheats & CF_FRIGHTENING) + return false; } + return true; } return false; } From cafafbe3a0575b5a8cdfdd4e131c176afe9b44d4 Mon Sep 17 00:00:00 2001 From: nashmuhandes Date: Thu, 14 Mar 2024 07:12:03 +0800 Subject: [PATCH 07/21] The default bind was wrong here (supposed to be Pov1, not Pov2. Obviously a typo) --- wadsrc/static/engine/commonbinds.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/engine/commonbinds.txt b/wadsrc/static/engine/commonbinds.txt index 0cb5756cc27..8493529f2d6 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 From 341c1bbede82e65e6cebe654ce9052c18353f79e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Thu, 14 Mar 2024 18:51:42 -0300 Subject: [PATCH 08/21] Fix crash with DecoupledModels flag defined but no actual model --- src/r_data/models.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp index 3cca0791ca9..09010c19548 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -1124,7 +1124,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 { From fe0de5053a42beac7c4433e9543488243b34d8a0 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Wed, 13 Mar 2024 14:47:37 -0500 Subject: [PATCH 09/21] - Fixed: ROLLCENTER was always being applied even when the flag wasn't present. --- src/rendering/hwrenderer/scene/hw_sprites.cpp | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 3fa433133f5..37b4d1a29b1 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -415,18 +415,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 @@ -461,16 +456,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) { @@ -503,7 +503,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); } From c9e678b60e4714f522c4cd546783a46c85758651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Fri, 15 Mar 2024 14:33:17 -0300 Subject: [PATCH 10/21] Fix missing newlines in animation messages --- src/playsim/p_actionfunctions.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp index 76d6be9fd82..410ac6a534d 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; } From 520b960ca5e054fb6bf6921ec14aa467d2706500 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 15 Mar 2024 20:24:39 +0100 Subject: [PATCH 11/21] Reverted the path node system Code reviews were unfavorable so better nix it before it finds wider use. --- src/common/objects/dobjgc.h | 3 - src/common/utility/tarray.h | 29 --- src/g_level.cpp | 186 ------------------ src/g_levellocals.h | 3 - src/gamedata/g_mapinfo.cpp | 1 - src/gamedata/g_mapinfo.h | 1 - src/gamedata/r_defs.h | 1 - src/namedef_custom.h | 1 - src/p_setup.cpp | 1 - src/playsim/actor.h | 11 +- src/playsim/p_enemy.cpp | 173 ++-------------- src/playsim/p_map.cpp | 12 +- src/r_data/models.cpp | 2 +- src/scripting/thingdef_data.cpp | 3 - src/scripting/vmthunks.cpp | 2 - src/scripting/vmthunks_actors.cpp | 1 - wadsrc/static/mapinfo/common.txt | 1 - wadsrc/static/zscript/actors/actor.zs | 85 +------- .../zscript/actors/shared/sharedmisc.zs | 120 ----------- wadsrc/static/zscript/doombase.zs | 6 +- wadsrc/static/zscript/mapdata.zs | 1 - 21 files changed, 30 insertions(+), 613 deletions(-) diff --git a/src/common/objects/dobjgc.h b/src/common/objects/dobjgc.h index 280c86273f5..f5514255dba 100644 --- a/src/common/objects/dobjgc.h +++ b/src/common/objects/dobjgc.h @@ -215,9 +215,6 @@ class TObjPtr mutable DObject *o; }; public: - TObjPtr() = default; - - TObjPtr(T t) : pp(t) {} constexpr TObjPtr& operator=(T q) noexcept { diff --git a/src/common/utility/tarray.h b/src/common/utility/tarray.h index b642f3c87ef..f849e9cca54 100644 --- a/src/common/utility/tarray.h +++ b/src/common/utility/tarray.h @@ -576,35 +576,6 @@ class TArray return f; } - bool SortedDelete(const T& obj) - { - auto f = SortedFind(obj, true); - if (f == Size()) - { - Delete(f); - return true; - } - else - { - return false; - } - } - - template - bool SortedDelete(const T& obj, Func lt) - { - auto f = SortedFind(obj, lt, true); - if (f == Size()) - { - Delete(f); - return true; - } - else - { - return false; - } - } - bool Pop () { if (Count > 0) diff --git a/src/g_level.cpp b/src/g_level.cpp index 85bdf842469..fcf4906a58d 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); @@ -2467,188 +2466,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 589e1490f97..cf63f81b2da 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -444,9 +444,6 @@ struct FLevelLocals 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 71addc09ef8..dfe90b2c952 100644 --- a/src/gamedata/g_mapinfo.cpp +++ b/src/gamedata/g_mapinfo.cpp @@ -1819,7 +1819,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 }, { "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes { "nopassover", MITYPE_COMPATFLAG, COMPATF_NO_PASSMOBJ, 0 }, { "passover", MITYPE_CLRCOMPATFLAG, COMPATF_NO_PASSMOBJ, 0 }, diff --git a/src/gamedata/g_mapinfo.h b/src/gamedata/g_mapinfo.h index a36cc4d5dce..b56d3b6329c 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 }; diff --git a/src/gamedata/r_defs.h b/src/gamedata/r_defs.h index 3a9c20a6463..3333a0c7a83 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 d9730abdf28..a62974bd03e 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 e3a971af610..02f89c860d1 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 e14e7ea171f..59ad5606056 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 @@ class AActor final : public DThinker 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 @@ class AActor final : public DThinker TObjPtr boneComponentData; // interaction info - TArray > Path; FBlockNode *BlockNode; // links in blocks (if needed) struct sector_t *Sector; subsector_t * subsector; diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index ffc40197f10..f63d005885b 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,85 +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) - return false; - - if (target) - { - if (target->flags8 & MF8_FRIGHTENING) - return false; - - if (target->player && target->player->cheats & CF_FRIGHTENING) - return false; - } - return true; - } - 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 @@ -2424,7 +2333,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look2) 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; @@ -2503,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; @@ -2562,7 +2470,6 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi } else { - actor->ClearPath(); actor->SetIdle(); actor->flags7 &= ~MF7_INCHASE; return; @@ -2586,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; @@ -2610,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]); } @@ -2633,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; @@ -2691,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; @@ -2723,53 +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; - - // Out of sight, so keep pathfinding - if (sight == 0) - { - if (pnode && !(actor->goal->flags & MF_AMBUSH)) - { - AActor* temp = actor->target; - actor->target = actor->goal; - bool reached = false; - // 2D checks for floaters, 3D otherwise - if (actor->flags & MF_FLOAT) - { - bool vrange = !!(actor->flags5 & MF5_NOVERTICALMELEERANGE); - actor->flags5 |= MF5_NOVERTICALMELEERANGE; - reached = P_CheckMeleeRange(actor); - if (!vrange) actor->flags5 &= ~(MF5_NOVERTICALMELEERANGE); - } - else 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 // @@ -2788,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!) @@ -2804,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 e3c0e16f5f1..d6a828024ba 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/r_data/models.cpp b/src/r_data/models.cpp index 09010c19548..3cca0791ca9 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -1124,7 +1124,7 @@ FSpriteModelFrame * FindModelFrame(const AActor * thing, int sprite, int frame, if(thing->flags9 & MF9_DECOUPLEDANIMATIONS) { - return BaseSpriteModelFrames.CheckKey((thing->modelData != nullptr && thing->modelData->modelDef != nullptr) ? thing->modelData->modelDef : thing->GetClass()); + return &BaseSpriteModelFrames[(thing->modelData != nullptr && thing->modelData->modelDef != nullptr) ? thing->modelData->modelDef : thing->GetClass()]; } else { diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 9f835aff884..997ab78b1a5 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 766dcddf943..450d4552a78 100644 --- a/src/scripting/vmthunks.cpp +++ b/src/scripting/vmthunks.cpp @@ -2786,7 +2786,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) @@ -2854,7 +2853,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_X(Sector, sector_t, floorplane) DEFINE_FIELD_X(Sector, sector_t, ceilingplane) diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index e8c7acbb6b0..c1021209836 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -2125,7 +2125,6 @@ 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); diff --git a/wadsrc/static/mapinfo/common.txt b/wadsrc/static/mapinfo/common.txt index c41dca18eb3..f079ee6e6e3 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 f3482864fc7..c1fe424de5c 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -261,7 +261,6 @@ 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 @@ -667,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); @@ -701,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(); @@ -800,86 +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; - - // 2D checks for floaters, 3D for ground - Actor tar = target; - bool vrange = bNOVERTICALMELEERANGE; - bNOVERTICALMELEERANGE = bFLOAT; - target = next; - - bool inrange = CheckMeleeRange(); - - target = tar; - bNOVERTICALMELEERANGE = vrange; - - if (inrange) - 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 aa78a99bc84..5e146f6c9ac 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 b2c859016fe..829e7527075 100644 --- a/wadsrc/static/zscript/doombase.zs +++ b/wadsrc/static/zscript/doombase.zs @@ -408,7 +408,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; @@ -476,7 +476,6 @@ struct LevelLocals native native readonly int compatflags; native readonly int compatflags2; native readonly LevelInfo info; - native readonly bool pathing; native String GetUDMFString(int type, int index, Name key); native int GetUDMFInt(int type, int index, Name key); @@ -554,9 +553,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 dd1d406e82c..db217e7cc74 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; From 0092aa07724b5bb03190dde95e3ba7dfa6f846d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Thu, 14 Mar 2024 18:51:42 -0300 Subject: [PATCH 12/21] Fix crash with DecoupledModels flag defined but no actual model --- src/r_data/models.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp index 3cca0791ca9..09010c19548 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -1124,7 +1124,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 { From cc88dfbe5015dcf0156450b0d6d6707bed81f1ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Fri, 15 Mar 2024 17:19:02 -0300 Subject: [PATCH 13/21] Unrevert two changes * Sorted Delete for TArray * Typed constructor for TObjPtr --- src/common/objects/dobjgc.h | 3 +++ src/common/utility/tarray.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/common/objects/dobjgc.h b/src/common/objects/dobjgc.h index f5514255dba..280c86273f5 100644 --- a/src/common/objects/dobjgc.h +++ b/src/common/objects/dobjgc.h @@ -215,6 +215,9 @@ class TObjPtr mutable DObject *o; }; public: + TObjPtr() = default; + + TObjPtr(T t) : pp(t) {} constexpr TObjPtr& operator=(T q) noexcept { diff --git a/src/common/utility/tarray.h b/src/common/utility/tarray.h index f849e9cca54..b642f3c87ef 100644 --- a/src/common/utility/tarray.h +++ b/src/common/utility/tarray.h @@ -576,6 +576,35 @@ class TArray return f; } + bool SortedDelete(const T& obj) + { + auto f = SortedFind(obj, true); + if (f == Size()) + { + Delete(f); + return true; + } + else + { + return false; + } + } + + template + bool SortedDelete(const T& obj, Func lt) + { + auto f = SortedFind(obj, lt, true); + if (f == Size()) + { + Delete(f); + return true; + } + else + { + return false; + } + } + bool Pop () { if (Count > 0) From 1e2a491f9ebe1d9585ffb14a6a36b2435b24b5db Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Sat, 16 Mar 2024 22:58:29 -0400 Subject: [PATCH 14/21] - don't show path if longsavemessages is false. fixes https://github.com/ZDoom/gzdoom/issues/2467 --- src/common/platform/posix/cocoa/i_system.mm | 5 +++-- src/common/platform/posix/sdl/i_system.cpp | 9 +++++++-- src/common/platform/win32/i_system.cpp | 9 +++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/common/platform/posix/cocoa/i_system.mm b/src/common/platform/posix/cocoa/i_system.mm index 3338f54dbae..8d3b5e1526c 100644 --- a/src/common/platform/posix/cocoa/i_system.mm +++ b/src/common/platform/posix/cocoa/i_system.mm @@ -40,7 +40,7 @@ #include "st_console.h" #include "v_text.h" - +EXTERN_CVAR(Bool, longsavemessages) double PerfToSec, PerfToMillisec; void CalculateCPUSpeed() @@ -188,7 +188,8 @@ void I_OpenShellFolder(const char* folder) NSString *currentpath = [filemgr currentDirectoryPath]; [filemgr changeCurrentDirectoryPath:[NSString stringWithUTF8String:folder]]; - Printf("Opening folder: %s\n", folder); + if (longsavemessages) + Printf("Opening folder: %s\n", folder); std::system("open ."); [filemgr changeCurrentDirectoryPath:currentpath]; } diff --git a/src/common/platform/posix/sdl/i_system.cpp b/src/common/platform/posix/sdl/i_system.cpp index c6d3df291ad..37af023817c 100644 --- a/src/common/platform/posix/sdl/i_system.cpp +++ b/src/common/platform/posix/sdl/i_system.cpp @@ -77,6 +77,7 @@ int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad double PerfToSec, PerfToMillisec; CVAR(Bool, con_printansi, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE); CVAR(Bool, con_4bitansi, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE); +EXTERN_CVAR(Bool, longsavemessages) extern FStartupScreen *StartWindow; @@ -372,13 +373,17 @@ void I_OpenShellFolder(const char* infolder) if (!chdir(infolder)) { - Printf("Opening folder: %s\n", infolder); + if (longsavemessages") + Printf("Opening folder: %s\n", infolder); std::system("xdg-open ."); chdir(curdir); } else { - Printf("Unable to open directory '%s\n", infolder); + if (longsavemessages") + Printf("Unable to open directory '%s\n", infolder); + else + Printf("Unable to open requested directory\n"); } free(curdir); } diff --git a/src/common/platform/win32/i_system.cpp b/src/common/platform/win32/i_system.cpp index 58cfa3c34b7..fe5fada533c 100644 --- a/src/common/platform/win32/i_system.cpp +++ b/src/common/platform/win32/i_system.cpp @@ -114,6 +114,7 @@ static HCURSOR CreateBitmapCursor(int xhot, int yhot, HBITMAP and_mask, HBITMAP EXTERN_CVAR (Bool, queryiwad); // Used on welcome/IWAD screen. EXTERN_CVAR (Int, vid_preferbackend) +EXTERN_CVAR(Bool, longsavemessages) extern HANDLE StdOut; extern bool FancyStdOut; @@ -824,13 +825,17 @@ void I_OpenShellFolder(const char* infolder) } else if (SetCurrentDirectoryW(WideString(infolder).c_str())) { - Printf("Opening folder: %s\n", infolder); + if (longsavemessages) + Printf("Opening folder: %s\n", infolder); ShellExecuteW(NULL, L"open", L"explorer.exe", L".", NULL, SW_SHOWNORMAL); SetCurrentDirectoryW(curdir.Data()); } else { - Printf("Unable to open directory '%s\n", infolder); + if (longsavemessages) + Printf("Unable to open directory '%s\n", infolder); + else + Printf("Unable to open requested directory\n"); } } From c73ec9702782ffb139b085dbbed19a5b76b63a22 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Sat, 16 Mar 2024 23:22:42 -0400 Subject: [PATCH 15/21] - accidentally added erroneous quotes to the last commit --- src/common/platform/posix/sdl/i_system.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/platform/posix/sdl/i_system.cpp b/src/common/platform/posix/sdl/i_system.cpp index 37af023817c..7fa41b2bc78 100644 --- a/src/common/platform/posix/sdl/i_system.cpp +++ b/src/common/platform/posix/sdl/i_system.cpp @@ -373,14 +373,14 @@ void I_OpenShellFolder(const char* infolder) if (!chdir(infolder)) { - if (longsavemessages") + if (longsavemessages) Printf("Opening folder: %s\n", infolder); std::system("xdg-open ."); chdir(curdir); } else { - if (longsavemessages") + if (longsavemessages) Printf("Unable to open directory '%s\n", infolder); else Printf("Unable to open requested directory\n"); From 7f8ce13d24a4b86a99499f2714f1a375c6029ae7 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Sun, 17 Mar 2024 00:58:24 -0400 Subject: [PATCH 16/21] - add missing include for macos --- src/common/platform/posix/cocoa/i_system.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/platform/posix/cocoa/i_system.mm b/src/common/platform/posix/cocoa/i_system.mm index 8d3b5e1526c..cef2d177b62 100644 --- a/src/common/platform/posix/cocoa/i_system.mm +++ b/src/common/platform/posix/cocoa/i_system.mm @@ -32,6 +32,7 @@ */ #include "i_common.h" +#include "c_cvars.h" #include #include From caa4728bd447854a5a59f32ce92d651b2402ca63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Tue, 12 Mar 2024 19:17:20 -0300 Subject: [PATCH 17/21] Export A_DoChase to zscript and make A_Chase a direct native function --- src/playsim/p_enemy.cpp | 39 ++++++++++++++++++++++----- wadsrc/static/zscript/actors/actor.zs | 1 + 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index f63d005885b..b2b2db78f15 100644 --- a/src/playsim/p_enemy.cpp +++ b/src/playsim/p_enemy.cpp @@ -2899,13 +2899,8 @@ void A_Chase(AActor *self) A_DoChase(self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, 0); } -DEFINE_ACTION_FUNCTION(AActor, A_Chase) +void A_ChaseNative(AActor * self, int meleelabel, int missilelabel, int flags) { - PARAM_SELF_PROLOGUE(AActor); - PARAM_STATELABEL(meleelabel); - PARAM_STATELABEL(missilelabel); - PARAM_INT(flags); - FName meleename = ENamedName(meleelabel - 0x10000000); FName missilename = ENamedName(missilelabel - 0x10000000); if (meleename != NAME__a_chase_default || missilename != NAME__a_chase_default) @@ -2913,7 +2908,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Chase) FState *melee = StateLabels.GetState(meleelabel, self->GetClass()); FState *missile = StateLabels.GetState(missilelabel, self->GetClass()); if ((flags & CHF_RESURRECT) && P_CheckForResurrection(self, false)) - return 0; + return; A_DoChase(self, !!(flags&CHF_FASTCHASE), melee, missile, !(flags&CHF_NOPLAYACTIVE), !!(flags&CHF_NIGHTMAREFAST), !!(flags&CHF_DONTMOVE), flags & 0x3fffffff); @@ -2922,6 +2917,36 @@ DEFINE_ACTION_FUNCTION(AActor, A_Chase) { A_DoChase(self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, 0); } +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_Chase, A_ChaseNative) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_STATELABEL(meleelabel); + PARAM_STATELABEL(missilelabel); + PARAM_INT(flags); + + A_ChaseNative(self, meleelabel, missilelabel, flags); + + return 0; +} + +void A_DoChaseNative(AActor * self, FState *melee, FState *missile, int flags) +{ + if ((flags & CHF_RESURRECT) && P_CheckForResurrection(self, false)) + return; + A_DoChase(self, !!(flags&CHF_FASTCHASE), melee, missile, !(flags&CHF_NOPLAYACTIVE), !!(flags&CHF_NIGHTMAREFAST), !!(flags&CHF_DONTMOVE), flags & 0x3fffffff); +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_DoChase, A_DoChaseNative) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_STATE(melee); + PARAM_STATE(missile); + PARAM_INT(flags); + + A_DoChaseNative(self, melee, missile, flags); + return 0; } diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index c1fe424de5c..0dc28c396e3 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -1145,6 +1145,7 @@ class Actor : Thinker native void A_Fall() { A_NoBlocking(); } native void A_Look(); native void A_Chase(statelabel melee = '_a_chase_default', statelabel missile = '_a_chase_default', int flags = 0); + native void A_DoChase(State melee, State missile, int flags = 0); native void A_VileChase(); native bool A_CheckForResurrection(State state = null, Sound snd = 0); native void A_BossDeath(); From e62651e3cfd85886bb01a691136b67fa368e6451 Mon Sep 17 00:00:00 2001 From: Ru5tK1ng Date: Sun, 3 Mar 2024 21:33:35 -0600 Subject: [PATCH 18/21] Fixed: A_LookEx did not account for the +LOOKALLAROUND flag. --- src/playsim/p_enemy.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index b2b2db78f15..4823b522d21 100644 --- a/src/playsim/p_enemy.cpp +++ b/src/playsim/p_enemy.cpp @@ -1271,7 +1271,7 @@ int P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams { maxdist = params->maxDist; mindist = params->minDist; - fov = params->Fov; + fov = allaround ? 0 : params->Fov; // [RK] Account for LOOKALLAROUND flag. } else { @@ -2086,7 +2086,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LookEx) { // If we find a valid target here, the wandering logic should *not* // be activated! If would cause the seestate to be set twice. - if (P_LookForPlayers(self, true, ¶ms)) + if (P_LookForPlayers(self, (self->flags4 & MF4_LOOKALLAROUND), ¶ms)) // [RK] Passing true for allround should only occur if the flag is actually set. goto seeyou; } From 631eb5847b617a2a09daf7b6859102bc8a7e6ed6 Mon Sep 17 00:00:00 2001 From: Ru5tK1ng Date: Mon, 4 Mar 2024 22:04:49 -0600 Subject: [PATCH 19/21] Use fromDeg for angle of 0. --- src/playsim/p_enemy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index 4823b522d21..50ed1a74d8d 100644 --- a/src/playsim/p_enemy.cpp +++ b/src/playsim/p_enemy.cpp @@ -1271,7 +1271,7 @@ int P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams { maxdist = params->maxDist; mindist = params->minDist; - fov = allaround ? 0 : params->Fov; // [RK] Account for LOOKALLAROUND flag. + fov = allaround ? DAngle::fromDeg(0.) : params->Fov; // [RK] Account for LOOKALLAROUND flag. } else { From ce479e09ff65216f4b0c65494c3d8b25fdbfb06d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Sun, 17 Mar 2024 17:47:53 -0300 Subject: [PATCH 20/21] Fix A_ChangeModel serialization I overlooked this part on my first A_ChangeModel fix --- src/common/engine/serializer.cpp | 15 +++++++++ src/common/engine/serializer.h | 12 ++++++++ src/common/models/model.cpp | 5 ++- src/common/models/model.h | 5 ++- src/g_game.cpp | 8 ----- src/p_saveg.cpp | 3 +- src/playsim/actor.h | 26 +++++++++++----- src/playsim/p_actionfunctions.cpp | 51 ------------------------------- src/playsim/p_mobj.cpp | 44 ++++++++++++++++++++++++-- src/r_data/models.cpp | 2 +- 10 files changed, 95 insertions(+), 76 deletions(-) diff --git a/src/common/engine/serializer.cpp b/src/common/engine/serializer.cpp index 261aa464cbd..dcf93084287 100644 --- a/src/common/engine/serializer.cpp +++ b/src/common/engine/serializer.cpp @@ -294,6 +294,21 @@ bool FSerializer::BeginObject(const char *name) // //========================================================================== +bool FSerializer::HasKey(const char* name) +{ + if (isReading()) + { + return r->FindKey(name) != nullptr; + } + return false; +} + +//========================================================================== +// +// +// +//========================================================================== + bool FSerializer::HasObject(const char* name) { if (isReading()) diff --git a/src/common/engine/serializer.h b/src/common/engine/serializer.h index 29677237b5e..ae25853d948 100644 --- a/src/common/engine/serializer.h +++ b/src/common/engine/serializer.h @@ -91,6 +91,7 @@ class FSerializer void ReadObjects(bool hubtravel); bool BeginObject(const char *name); void EndObject(); + bool HasKey(const char* name); bool HasObject(const char* name); bool BeginArray(const char *name); void EndArray(); @@ -245,6 +246,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundI FSerializer &Serialize(FSerializer &arc, const char *key, FString &sid, FString *def); FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &sid, NumericValue *def); FSerializer &Serialize(FSerializer &arc, const char *key, struct ModelOverride &mo, struct ModelOverride *def); +FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimModelOverride &mo, struct AnimModelOverride *def); FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimOverride &ao, struct AnimOverride *def); FSerializer& Serialize(FSerializer& arc, const char* key, FTranslationID& value, FTranslationID* defval); @@ -259,6 +261,16 @@ FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **) return arc; } +template +FSerializer &Serialize(FSerializer &arc, const char *key, std::pair &value, std::pair *def) +{ + arc.BeginObject(key); + Serialize(arc, "first", value.first, def ? &def->first : nullptr); + Serialize(arc, "second", value.second, def ? &def->second : nullptr); + arc.EndObject(); + return arc; +} + template FSerializer &Serialize(FSerializer &arc, const char *key, TArray &value, TArray *def) { diff --git a/src/common/models/model.cpp b/src/common/models/model.cpp index a8ee8958f8c..0f160341588 100644 --- a/src/common/models/model.cpp +++ b/src/common/models/model.cpp @@ -43,8 +43,6 @@ #include "texturemanager.h" #include "modelrenderer.h" - -TArray savedModelFiles; TDeletingArray Models; TArray SpriteModelFrames; TMap BaseSpriteModelFrames; @@ -160,7 +158,7 @@ unsigned FindModel(const char * path, const char * modelfile, bool silent) for(unsigned i = 0; i< Models.Size(); i++) { - if (!Models[i]->mFileName.CompareNoCase(fullname)) return i; + if (Models[i]->mFileName.CompareNoCase(fullname) == 0) return i; } auto len = fileSystem.FileLength(lump); @@ -236,6 +234,7 @@ unsigned FindModel(const char * path, const char * modelfile, bool silent) } // The vertex buffer cannot be initialized here because this gets called before OpenGL is initialized model->mFileName = fullname; + model->mFilePath = {path, modelfile}; return Models.Push(model); } diff --git a/src/common/models/model.h b/src/common/models/model.h index f5bbf43db0e..7d5746e3317 100644 --- a/src/common/models/model.h +++ b/src/common/models/model.h @@ -18,7 +18,7 @@ struct FSpriteModelFrame; FTextureID LoadSkin(const char* path, const char* fn); void FlushModels(); -extern TArray savedModelFiles; + extern TDeletingArray Models; extern TArray SpriteModelFrames; extern TMap BaseSpriteModelFrames; @@ -76,6 +76,7 @@ enum EFrameError class FModel { public: + FModel(); virtual ~FModel(); @@ -100,7 +101,9 @@ class FModel void DestroyVertexBuffer(); bool hasSurfaces = false; + FString mFileName; + std::pair mFilePath; FSpriteModelFrame *baseFrame; private: diff --git a/src/g_game.cpp b/src/g_game.cpp index 1b81ae6b064..752b8f930fe 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2148,14 +2148,6 @@ void G_DoLoadGame () BackupSaveName = savename; - //Push any added models from A_ChangeModel - for (auto& smf : savedModelFiles) - { - FString modelFilePath = smf.Left(smf.LastIndexOf("/")+1); - FString modelFileName = smf.Right(smf.Len() - smf.Left(smf.LastIndexOf("/") + 1).Len()); - FindModel(modelFilePath.GetChars(), modelFileName.GetChars()); - } - // At this point, the GC threshold is likely a lot higher than the // amount of memory in use, so bring it down now by starting a // collection. diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 865810cdc75..de4f7c1c1e7 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -1013,8 +1013,7 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload) ("scrolls", Scrolls) ("automap", automap) ("interpolator", interpolator) - ("frozenstate", frozenstate) - ("savedModelFiles", savedModelFiles); + ("frozenstate", frozenstate); // Hub transitions must keep the current total time diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 59ad5606056..c9465dbbf7b 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -719,6 +719,16 @@ struct ModelOverride TArray surfaceSkinIDs; }; +struct AnimModelOverride +{ + int id; + + AnimModelOverride() = default; + + AnimModelOverride(int i) : id(i) {} + operator int() { return id; } +}; + enum EModelDataFlags { MODELDATA_HADMODEL = 1 << 0, @@ -729,14 +739,14 @@ class DActorModelData : public DObject { DECLARE_CLASS(DActorModelData, DObject); public: - PClass * modelDef; - TArray models; - TArray skinIDs; - TArray animationIDs; - TArray modelFrameGenerators; - int flags; - int overrideFlagsSet; - int overrideFlagsClear; + PClass * modelDef; + TArray models; + TArray skinIDs; + TArray animationIDs; + TArray modelFrameGenerators; + int flags; + int overrideFlagsSet; + int overrideFlagsClear; AnimOverride curAnim; AnimOverride prevAnim; // used for interpolation when switching anims diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp index 410ac6a534d..8ab0a021366 100644 --- a/src/playsim/p_actionfunctions.cpp +++ b/src/playsim/p_actionfunctions.cpp @@ -5438,57 +5438,6 @@ void ChangeModelNative( } } - //[SM] - We need to serialize file paths and model names so that they are pushed on loading save files. Likewise, let's not include models that were already parsed when initialized. - if (queryModel >= 0) - { - FString fullName; - fullName.Format("%s%s", modelpath.GetChars(), model.GetChars()); - bool found = false; - - for (auto &m : savedModelFiles) - { - if(m.CompareNoCase(fullName) == 0) - { - found = true; - break; - } - } - if(!found) for (auto &m : Models) - { - if (m->mFileName.CompareNoCase(fullName) == 0) - { - found = true; - break; - } - } - if(!found) savedModelFiles.Push(fullName); - } - //Same for animations - if (queryAnimation >= 0) - { - FString fullName; - fullName.Format("%s%s", animationpath.GetChars(), animation.GetChars()); - bool found = false; - - for (auto &m : savedModelFiles) - { - if(m.CompareNoCase(fullName) == 0) - { - found = true; - break; - } - } - if(!found) for (auto &m : Models) - { - if (m->mFileName.CompareNoCase(fullName) == 0) - { - found = true; - break; - } - } - if(!found) savedModelFiles.Push(fullName); - } - CleanupModelData(mobj); return; diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index ff98fb4da46..eda2a46e1e9 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -101,6 +101,7 @@ #include "fragglescript/t_fs.h" #include "shadowinlines.h" #include "d_net.h" +#include "model.h" // MACROS ------------------------------------------------------------------ @@ -1387,18 +1388,57 @@ bool AActor::Massacre () // //---------------------------------------------------------------------------- +void SerializeModelID(FSerializer &arc, const char *key, int &id) +{ // TODO: make it a proper serializable type (FModelID) instead of an int + if(arc.isWriting()) + { + if(id >= 0) + { + arc(key, Models[id]->mFilePath); + } + } + else + { + if(arc.HasKey(key)) + { + std::pair modelFile; + arc(key, modelFile); + + id = FindModel(modelFile.first.GetChars(), modelFile.second.GetChars(), true); + } + else + { + id = -1; + } + } +} + FSerializer &Serialize(FSerializer &arc, const char *key, ModelOverride &mo, ModelOverride *def) { arc.BeginObject(key); - arc("modelID", mo.modelID); + SerializeModelID(arc, "model", mo.modelID); arc("surfaceSkinIDs", mo.surfaceSkinIDs); arc.EndObject(); return arc; } +FSerializer &Serialize(FSerializer &arc, const char *key, AnimModelOverride &amo, AnimModelOverride *def) +{ + int ok = arc.BeginObject(key); + if(arc.isReading() && !ok) + { + amo.id = -1; + } + else if(ok) + { + SerializeModelID(arc, "model", amo.id); + arc.EndObject(); + } + return arc; +} + FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimOverride &ao, struct AnimOverride *def) { - //TODO arc.BeginObject(key); arc("firstFrame", ao.firstFrame); arc("lastFrame", ao.lastFrame); diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp index 09010c19548..d2436fc6789 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -506,7 +506,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr skinid = smf->skinIDs[i]; } - if (modelid >= 0) + if (modelid >= 0 && modelid < Models.size()) { FModel * mdl = Models[modelid]; auto tex = skinid.isValid() ? TexMan.GetGameTexture(skinid, true) : nullptr; From 458d81cede493a8e3b2f2d7a64223d206e935ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Sun, 17 Mar 2024 17:49:16 -0300 Subject: [PATCH 21/21] Make TArray take functions by forward-reference and call them by invoke (1. avoids copying for lambdas, and 2. allows passing methods) --- src/common/utility/tarray.h | 41 ++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/common/utility/tarray.h b/src/common/utility/tarray.h index b642f3c87ef..bce3ba3ea1c 100644 --- a/src/common/utility/tarray.h +++ b/src/common/utility/tarray.h @@ -55,6 +55,7 @@ #include #include #include +#include #if !defined(_WIN32) #include // for intptr_t @@ -366,11 +367,11 @@ class TArray } template - bool IsSorted(Func lt) + bool IsSorted(Func &<) { for(unsigned i = 1; i < Count; i++) { - if(lt(Array[i], Array[i-1])) return false; + if(std::invoke(lt, Array[i], Array[i-1])) return false; } return true; } @@ -418,7 +419,7 @@ class TArray // // exact = false returns the closest match, to be used for, ex., insertions, exact = true returns Size() when no match, like Find does template - unsigned int SortedFind(const T& item, Func lt, bool exact = true) const + unsigned int SortedFind(const T& item, Func &<, bool exact = true) const { if(Count == 0) return 0; if(Count == 1) return lt(item, Array[0]) ? 0 : 1; @@ -430,11 +431,11 @@ class TArray { int mid = lo + ((hi - lo) / 2); - if(lt(Array[mid], item)) + if(std::invoke(lt, Array[mid], item)) { lo = mid + 1; } - else if(lt(item, Array[mid])) + else if(std::invoke(lt, item, Array[mid])) { if(mid == 0) break; // prevent negative overflow due to unsigned numbers hi = mid - 1; @@ -450,7 +451,7 @@ class TArray } else { - return (lo == Count || lt(item, Array[lo])) ? lo : lo + 1; + return (lo == Count || std::invoke(lt, item, Array[lo])) ? lo : lo + 1; } } @@ -466,12 +467,24 @@ class TArray } template - unsigned int FindEx(Func compare) const + bool Contains(const T& item, Func &&compare) const + { + unsigned int i; + for(i = 0;i < Count;++i) + { + if(std::invoke(compare, Array[i], item)) + return true; + } + return false; + } + + template + unsigned int FindEx(Func &&compare) const { unsigned int i; for (i = 0; i < Count; ++i) { - if (compare(Array[i])) + if (std::invoke(compare, Array[i])) break; } return i; @@ -569,9 +582,9 @@ class TArray } template - unsigned SortedAddUnique(const T& obj, Func lt) + unsigned SortedAddUnique(const T& obj, Func &<) { - auto f = SortedFind(obj, lt, true); + auto f = SortedFind(obj, std::forward(lt), true); if (f == Size()) Push(obj); return f; } @@ -591,9 +604,9 @@ class TArray } template - bool SortedDelete(const T& obj, Func lt) + bool SortedDelete(const T& obj, Func &<) { - auto f = SortedFind(obj, lt, true); + auto f = SortedFind(obj, std::forward(lt), true); if (f == Size()) { Delete(f); @@ -691,9 +704,9 @@ class TArray } template - void SortedInsert (const T &item, Func lt) + void SortedInsert (const T &item, Func &<) { - Insert (SortedFind (item, lt, false), item); + Insert (SortedFind (item, std::forward(lt), false), item); } void ShrinkToFit ()