From 2c25cc1d9b380c5d03787165cfa62aace90b349d Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Sat, 28 Sep 2024 15:55:10 -0400 Subject: [PATCH 01/40] - well ... this was a lil redundant --- src/playsim/p_enemy.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index cf15cbf38..45df68ac1 100644 --- a/src/playsim/p_enemy.cpp +++ b/src/playsim/p_enemy.cpp @@ -1835,14 +1835,6 @@ int P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params) if (!P_IsVisible (actor, player->mo, allaround, params)) continue; // out of sight - // [SP] Deathmatch fixes - if we have MF_FRIENDLY we're definitely in deathmatch - // We're going to ignore our master, but go after his enemies. - if ( actor->flags & MF_FRIENDLY ) - { - if ( actor->IsFriend(player->mo) ) - continue; - } - // [RC] Well, let's let special monsters with this flag active be able to see // the player then, eh? if(!(actor->flags6 & MF6_SEEINVISIBLE)) From 85ae8f81941c668d0374be1af5f7c774d381e6f2 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Sun, 29 Sep 2024 10:05:16 -0400 Subject: [PATCH 02/40] - flat sprites are already square, no need to adjust them --- src/rendering/hwrenderer/scene/hw_sprites.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index aebe8a9b0..70da581cb 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -1036,7 +1036,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t r.Scale(sprscale.X, isSpriteShadow ? sprscale.Y * 0.15 * thing->isoscaleY : sprscale.Y * thing->isoscaleY); - if ((thing->renderflags & (RF_ROLLSPRITE|RF_FLATSPRITE)) || (thing->renderflags2 & RF2_SQUAREPIXELS)) + if ((thing->renderflags & RF_ROLLSPRITE) || (thing->renderflags2 & RF2_SQUAREPIXELS)) { double ps = di->Level->pixelstretch; double mult = 1.0 / sqrt(ps); // shrink slightly From ca9ab7bd5b5e89ed2efff148a25382c3789e9d31 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Sun, 29 Sep 2024 16:04:00 -0400 Subject: [PATCH 03/40] - rename 'restart' ccmd to 'debug_restart' since it is in a broken state right now --- src/d_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index c14149196..fb25fa00f 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -3936,7 +3936,7 @@ void D_Cleanup() // //========================================================================== -UNSAFE_CCMD(restart) +UNSAFE_CCMD(debug_restart) { // remove command line args that would get in the way during restart Args->RemoveArgs("-iwad"); From 89ce70fd0ba83a7aca214acb7c9c160505a8934c Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Fri, 20 Sep 2024 10:33:40 -0400 Subject: [PATCH 04/40] - implement `SPAC_Walking`, mostly useful for teleports or for line crossings that should not happen when the player is falling or flying - update UDMF spec entry --- specs/udmf_zdoom.txt | 1 + src/doomdata.h | 1 + src/maploader/udmf.cpp | 4 ++++ src/namedef_custom.h | 1 + src/playsim/p_spec.cpp | 7 +++++++ 5 files changed, 14 insertions(+) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 73e94ea8a..35b23418d 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -114,6 +114,7 @@ Note: All fields default to false unless mentioned otherwise. // texture to behave like an impassable line (projectiles // pass through it). checkswitchrange = ; // Switches can only be activated when vertically reachable. + walking = ; // Crossing activation checks if creature is on the ground, and fails if they are not. blockprojectiles = ; // Line blocks all projectiles blockuse = ; // Line blocks all use actions blocksight = ; // Line blocks monster line of sight diff --git a/src/doomdata.h b/src/doomdata.h index 12a286921..49ba77421 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -199,6 +199,7 @@ enum SPAC SPAC_UseBack = 1<<10, // Can be used from the backside SPAC_Damage = 1<<11, // [ZZ] when linedef receives damage SPAC_Death = 1<<12, // [ZZ] when linedef receives damage and has 0 health + SPAC_Walking = 1<<13, // Can only be used when standing on a floor (not falling or floating) - only for line cross, not use SPAC_PlayerActivate = (SPAC_Cross|SPAC_Use|SPAC_Impact|SPAC_Push|SPAC_AnyCross|SPAC_UseThrough|SPAC_UseBack), }; diff --git a/src/maploader/udmf.cpp b/src/maploader/udmf.cpp index 725b95b91..ad33538ab 100644 --- a/src/maploader/udmf.cpp +++ b/src/maploader/udmf.cpp @@ -1002,6 +1002,10 @@ public: // This switch contains all keys of the UDMF base spec which only apply to Hexen format specials if (!isTranslated) switch (key.GetIndex()) { + case NAME_Walking: + Flag(ld->activation, SPAC_Walking, key); + continue; + case NAME_Playercross: Flag(ld->activation, SPAC_Cross, key); continue; diff --git a/src/namedef_custom.h b/src/namedef_custom.h index 59752245b..082a254c9 100644 --- a/src/namedef_custom.h +++ b/src/namedef_custom.h @@ -670,6 +670,7 @@ xx(Missilecross) xx(Anycross) xx(Monsteruse) xx(Monsterpush) +xx(Walking) xx(ZDoom) xx(ZDoomTranslated) diff --git a/src/playsim/p_spec.cpp b/src/playsim/p_spec.cpp index ba2036971..3b63839fe 100644 --- a/src/playsim/p_spec.cpp +++ b/src/playsim/p_spec.cpp @@ -254,6 +254,13 @@ bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType, return false; } + if ((activationType & (SPAC_Cross|SPAC_PCross)) && (lineActivation & SPAC_Walking)) + { + // not on floor + if ((mo->Pos().Z > mo->floorz) && !(mo->flags2 & MF2_ONMOBJ)) + return false; + } + if (lineActivation & SPAC_UseThrough) { lineActivation |= SPAC_Use; From 994078feaef07b57bdcc431b0dcb64dc4be3919e Mon Sep 17 00:00:00 2001 From: jekyllgrim Date: Fri, 30 Aug 2024 13:06:26 +0300 Subject: [PATCH 05/40] Added FloatBobFactor This adds a new actor property: `FloatBobFactor` (default 1.0). This will be a multiplier for level.time in `AActor::GetBobOffset`, which finally allows to control not only the range of float bobbing (which is FloatBobStrength) but also the frequency of bobbing. --- src/namedef_custom.h | 1 + src/playsim/actor.h | 1 + src/playsim/actorinlines.h | 2 +- src/playsim/p_mobj.cpp | 1 + src/scripting/thingdef_properties.cpp | 10 ++++++++++ src/scripting/vmthunks_actors.cpp | 1 + wadsrc/static/zscript/actors/actor.zs | 2 ++ 7 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/namedef_custom.h b/src/namedef_custom.h index 082a254c9..3144d46f9 100644 --- a/src/namedef_custom.h +++ b/src/namedef_custom.h @@ -625,6 +625,7 @@ xx(ScaleY) xx(FriendlySeeBlocks) xx(Floatbobphase) xx(Floatbobstrength) +xx(FloatBobFactor) xx(Target) xx(Master) xx(Tracer) diff --git a/src/playsim/actor.h b/src/playsim/actor.h index bbf2eaf98..40be0c599 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -1304,6 +1304,7 @@ public: uint8_t FloatBobPhase; uint8_t FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc) double FloatBobStrength; + double FloatBobFactor; PalEntry BloodColor; FTranslationID BloodTranslation; diff --git a/src/playsim/actorinlines.h b/src/playsim/actorinlines.h index 939807c98..bbc173801 100644 --- a/src/playsim/actorinlines.h +++ b/src/playsim/actorinlines.h @@ -69,7 +69,7 @@ inline double AActor::GetBobOffset(double ticfrac) const { return 0; } - return BobSin(FloatBobPhase + Level->maptime + ticfrac) * FloatBobStrength; + return BobSin(FloatBobPhase + Level->maptime * FloatBobFactor + ticfrac) * FloatBobStrength; } inline double AActor::GetCameraHeight() const diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index e8a6c247a..7df73be6d 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -289,6 +289,7 @@ void AActor::Serialize(FSerializer &arc) A("inventoryid", InventoryID) A("floatbobphase", FloatBobPhase) A("floatbobstrength", FloatBobStrength) + A("floatbobfactor", FloatBobFactor) A("translation", Translation) A("bloodcolor", BloodColor) A("bloodtranslation", BloodTranslation) diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index bedd66cd3..f6cd07335 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -642,6 +642,16 @@ DEFINE_PROPERTY(floatbobstrength, F, Actor) defaults->FloatBobStrength = id; } +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(floatbobfactor, F, Actor) +{ + PROP_DOUBLE_PARM(id, 0); + if (id <= 0) I_Error ("FloatBobFactor must be above 0.0"); + defaults->FloatBobFactor = id; +} + //========================================================================== // //========================================================================== diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index acf253807..53fc0a062 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -2035,6 +2035,7 @@ DEFINE_FIELD(AActor, DamageType) DEFINE_FIELD(AActor, DamageTypeReceived) DEFINE_FIELD(AActor, FloatBobPhase) DEFINE_FIELD(AActor, FloatBobStrength) +DEFINE_FIELD(AActor, FloatBobFactor) DEFINE_FIELD(AActor, RipperLevel) DEFINE_FIELD(AActor, RipLevelMin) DEFINE_FIELD(AActor, RipLevelMax) diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 31dc08052..7a9a53929 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -178,6 +178,7 @@ class Actor : Thinker native native name DamageTypeReceived; native uint8 FloatBobPhase; native double FloatBobStrength; + native double FloatBobFactor; native int RipperLevel; native int RipLevelMin; native int RipLevelMax; @@ -413,6 +414,7 @@ class Actor : Thinker native FloatSpeed 4; FloatBobPhase -1; // randomly initialize by default FloatBobStrength 1.0; + FloatBobFactor 1.0; Gravity 1; Friction 1; DamageFactor 1.0; // damage multiplier as target of damage. From 96ec9b9dbdff5c31205f3e2da33b0d65ebe15013 Mon Sep 17 00:00:00 2001 From: HHonzik <87828740+HHonzik@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:40:48 +0200 Subject: [PATCH 06/40] Add another soundfonts search directory for *nix This adds another soundfont search directory for the convenience of the user. --- src/gameconfigfile.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp index a0f27899e..82179217c 100644 --- a/src/gameconfigfile.cpp +++ b/src/gameconfigfile.cpp @@ -180,6 +180,7 @@ FGameConfigFile::FGameConfigFile () SetValueForKey("Path", "/usr/share/doom/fm_banks", true); SetValueForKey("Path", "/usr/share/games/doom/soundfonts", true); SetValueForKey("Path", "/usr/share/games/doom/fm_banks", true); + SetValueForKey("Path", "/usr/share/soundfonts", true); #endif } From 1e96ed31aa91acc2c036ac2429da81fcd2740a5d Mon Sep 17 00:00:00 2001 From: Boondorl Date: Sun, 29 Sep 2024 17:31:06 -0400 Subject: [PATCH 07/40] Exported DPrintf Allows for custom debug message handling using the built-in --- src/common/scripting/interface/vmnatives.cpp | 11 +++++++++++ wadsrc/static/zscript/engine/base.zs | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/common/scripting/interface/vmnatives.cpp b/src/common/scripting/interface/vmnatives.cpp index 8a5674afd..2b57ceb25 100644 --- a/src/common/scripting/interface/vmnatives.cpp +++ b/src/common/scripting/interface/vmnatives.cpp @@ -1162,6 +1162,17 @@ DEFINE_ACTION_FUNCTION(_Console, PrintfEx) return 0; } +DEFINE_ACTION_FUNCTION(_Console, DebugPrintf) +{ + PARAM_PROLOGUE; + PARAM_INT(debugLevel); + PARAM_VA_POINTER(va_reginfo); + + FString s = FStringFormat(VM_ARGS_NAMES, 1); + DPrintf(debugLevel, "%s\n", s.GetChars()); + return 0; +} + static void StopAllSounds() { soundEngine->StopAllChannels(); diff --git a/wadsrc/static/zscript/engine/base.zs b/wadsrc/static/zscript/engine/base.zs index f55919116..c4322918f 100644 --- a/wadsrc/static/zscript/engine/base.zs +++ b/wadsrc/static/zscript/engine/base.zs @@ -143,6 +143,15 @@ enum EPrintLevel PRINT_NOLOG = 2048, // Flag - do not print to log file }; +enum EDebugLevel +{ + DMSG_OFF, // no developer messages. + DMSG_ERROR, // general notification messages + DMSG_WARNING, // warnings + DMSG_NOTIFY, // general notification messages + DMSG_SPAMMY, // for those who want to see everything, regardless of its usefulness. +}; + enum EConsoleState { c_up = 0, @@ -665,6 +674,7 @@ struct Console native native static void HideConsole(); native static vararg void Printf(string fmt, ...); native static vararg void PrintfEx(int printlevel, string fmt, ...); + native static vararg void DebugPrintf(int debuglevel, string fmt, ...); } struct CVar native From a4c98d8dd939d9e98cebfc7aef560a0e1ec1ae10 Mon Sep 17 00:00:00 2001 From: RaveYard <29225776+MrRaveYard@users.noreply.github.com> Date: Sun, 4 Aug 2024 16:06:55 +0200 Subject: [PATCH 08/40] Add RADF_CIRCULARTHRUST and matching XF_/RTF_ flags --- src/playsim/actor.h | 11 ++++++- src/playsim/p_local.h | 3 +- src/playsim/p_map.cpp | 40 ++++++++++++++++++------- wadsrc/static/zscript/actors/attacks.zs | 1 + wadsrc/static/zscript/constants.zs | 5 +++- 5 files changed, 47 insertions(+), 13 deletions(-) diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 40be0c599..906fe2c1b 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -1524,9 +1524,13 @@ public: { return Z() + Height; } + double CenterOffset() const + { + return Height / 2; + } double Center() const { - return Z() + Height/2; + return Z() + CenterOffset(); } void SetZ(double newz, bool moving = true) { @@ -1603,6 +1607,11 @@ public: Vel.Y += speed * angle.Sin(); } + void Thrust(const DVector3& vel) + { + Vel += vel; + } + void Vel3DFromAngle(DAngle angle, DAngle pitch, double speed) { double cospitch = pitch.Cos(); diff --git a/src/playsim/p_local.h b/src/playsim/p_local.h index cde45f403..6d02d2a56 100644 --- a/src/playsim/p_local.h +++ b/src/playsim/p_local.h @@ -408,7 +408,8 @@ enum RADF_OLDRADIUSDAMAGE = 32, RADF_THRUSTLESS = 64, RADF_NOALLIES = 128, - RADF_CIRCULAR = 256 + RADF_CIRCULAR = 256, + RADF_CIRCULARTHRUST = 512, }; int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, double distance, double fulldmgdistance, bool oldradiusdmg, bool circular); int P_RadiusAttack (AActor *spot, AActor *source, int damage, double distance, diff --git a/src/playsim/p_map.cpp b/src/playsim/p_map.cpp index af8df92a7..589204993 100644 --- a/src/playsim/p_map.cpp +++ b/src/playsim/p_map.cpp @@ -6236,24 +6236,44 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, double if (!(thing->flags7 & MF7_DONTTHRUST)) { thrust = points * 0.5 / (double)thing->Mass; + if (bombsource == thing) { thrust *= selfthrustscale; } - vz = (thing->Center() - bombspot->Z()) * thrust; - if (bombsource != thing) + + if (flags & RADF_CIRCULARTHRUST) { - vz *= 0.5; + auto dir = bombspot->Vec3To(thing); + dir.Z += thing->CenterOffset() - bombspot->CenterOffset(); + + if (!dir.isZero()) + { + dir.MakeUnit(); + thing->Thrust(dir * thrust); + } } else { - vz *= 0.8; - } - thing->Thrust(bombspot->AngleTo(thing), thrust); - if (!(flags & RADF_NODAMAGE) || (flags & RADF_THRUSTZ)) - { - if (!(thing->Level->i_compatflags2 & COMPATF2_EXPLODE1) || (flags & RADF_THRUSTZ)) - thing->Vel.Z += vz; // this really doesn't work well + thing->Thrust(bombspot->AngleTo(thing), thrust); + + if (!(flags & RADF_NODAMAGE) || (flags & RADF_THRUSTZ)) + { + if (!(thing->Level->i_compatflags2 & COMPATF2_EXPLODE1) || (flags & RADF_THRUSTZ)) + { + vz = (thing->Center() - bombspot->Z()) * thrust; + if (bombsource != thing) + { + vz *= 0.5; + } + else + { + vz *= 0.8; + } + + thing->Vel.Z += vz; // this really doesn't work well + } + } } } } diff --git a/wadsrc/static/zscript/actors/attacks.zs b/wadsrc/static/zscript/actors/attacks.zs index db9da6f35..1965be0b1 100644 --- a/wadsrc/static/zscript/actors/attacks.zs +++ b/wadsrc/static/zscript/actors/attacks.zs @@ -609,6 +609,7 @@ extend class Actor if (flags & XF_THRUSTLESS) pflags |= RADF_THRUSTLESS; if (flags & XF_NOALLIES) pflags |= RADF_NOALLIES; if (flags & XF_CIRCULAR) pflags |= RADF_CIRCULAR; + if (flags & XF_CIRCULARTHRUST) pflags |= RADF_CIRCULARTHRUST; int count = RadiusAttack (target, damage, distance, damagetype, pflags, fulldamagedistance); if (!(flags & XF_NOSPLASH)) CheckSplash(distance); diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index f22204cbf..641d90a12 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -267,6 +267,7 @@ enum EExplodeFlags XF_THRUSTLESS = 64, XF_NOALLIES = 128, XF_CIRCULAR = 256, + XF_CIRCULARTHRUST = 512, }; // Flags for A_RadiusThrust @@ -276,6 +277,7 @@ enum ERadiusThrustFlags RTF_NOIMPACTDAMAGE = 2, RTF_NOTMISSILE = 4, RTF_THRUSTZ = 16, + RTF_CIRCULARTHRUST = 512, }; // Flags for A_RadiusDamageSelf @@ -1254,7 +1256,8 @@ enum RadiusDamageFlags RADF_OLDRADIUSDAMAGE = 32, RADF_THRUSTLESS = 64, RADF_NOALLIES = 128, - RADF_CIRCULAR = 256 + RADF_CIRCULAR = 256, + RADF_CIRCULARTHRUST = 512, }; enum IntermissionSequenceType From 5cc718ec7728acb3093f91992023935ba4c73594 Mon Sep 17 00:00:00 2001 From: Hexadec <164735227+Hex4dec@users.noreply.github.com> Date: Mon, 30 Sep 2024 01:06:49 +0300 Subject: [PATCH 09/40] Search more paths in SHARE_DIR (#2610) * Search more paths in SHARE_DIR Makes it more compatible with more exotic systems such as Guix or NixOS. (one day we'll have a gzdoom without patches) * Make more places search in SHARE_DIR. --------- Co-authored-by: Rachael Alexanderson <18584402+madame-rachelle@users.noreply.github.com> --- src/gameconfigfile.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp index 82179217c..b61279ebc 100644 --- a/src/gameconfigfile.cpp +++ b/src/gameconfigfile.cpp @@ -125,6 +125,9 @@ FGameConfigFile::FGameConfigFile () SetValueForKey ("Path", "/usr/local/share/games/doom", true); SetValueForKey ("Path", "/usr/share/doom", true); SetValueForKey ("Path", "/usr/share/games/doom", true); + SetValueForKey ("Path", SHARE_DIR "/doom", true); + SetValueForKey ("Path", SHARE_DIR "/games/doom", true); + #endif } @@ -143,6 +146,8 @@ FGameConfigFile::FGameConfigFile () SetValueForKey ("Path", "$HOME/" GAME_DIR, true); SetValueForKey ("Path", "$HOME/.local/share/games/doom", true); SetValueForKey ("Path", SHARE_DIR, true); + SetValueForKey ("Path", SHARE_DIR "/doom", true); + SetValueForKey ("Path", SHARE_DIR "/games/doom", true); SetValueForKey ("Path", "/usr/local/share/doom", true); SetValueForKey ("Path", "/usr/local/share/games/doom", true); SetValueForKey ("Path", "/usr/share/doom", true); @@ -180,6 +185,10 @@ FGameConfigFile::FGameConfigFile () SetValueForKey("Path", "/usr/share/doom/fm_banks", true); SetValueForKey("Path", "/usr/share/games/doom/soundfonts", true); SetValueForKey("Path", "/usr/share/games/doom/fm_banks", true); + SetValueForKey("Path", SHARE_DIR "/doom/soundfonts", true); + SetValueForKey("Path", SHARE_DIR "/doom/fm_banks", true); + SetValueForKey("Path", SHARE_DIR "/games/doom/soundfonts", true); + SetValueForKey("Path", SHARE_DIR "/games/doom/fm_banks", true); SetValueForKey("Path", "/usr/share/soundfonts", true); #endif } From bbeaea1ea75ef466b2f0e08b433af43bb8d89f45 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson <18584402+madame-rachelle@users.noreply.github.com> Date: Sun, 29 Sep 2024 18:09:07 -0400 Subject: [PATCH 10/40] - implement anamorphesis proof-of-concept (#2431) Co-authored-by: Rachael Alexanderson --- src/rendering/hwrenderer/scene/hw_sprites.cpp | 53 +++++++++++++++++++ wadsrc/static/menudef.txt | 1 + 2 files changed, 54 insertions(+) diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 70da581cb..61c120f31 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -81,6 +81,8 @@ EXTERN_CVAR(Float, r_actorspriteshadowfadeheight) CVAR(Bool, gl_usecolorblending, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, gl_sprite_blend, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); CVAR(Int, gl_spriteclip, 1, CVAR_ARCHIVE) +CVAR(Bool, r_debug_nolimitanamorphoses, false, 0) +CVAR(Float, r_spriteclipanamorphicminbias, 0.6, CVAR_ARCHIVE) CVAR(Float, gl_sclipthreshold, 10.0, CVAR_ARCHIVE) CVAR(Float, gl_sclipfactor, 1.8f, CVAR_ARCHIVE) CVAR(Int, gl_particles_style, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // 0 = square, 1 = round, 2 = smooth @@ -1117,6 +1119,56 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t if(thing->renderflags2 & RF2_ISOMETRICSPRITES) depth = depth * vp.PitchCos - vp.PitchSin * z2; // Helps with stacking actors with small xy offsets if (isSpriteShadow) depth += 1.f/65536.f; // always sort shadows behind the sprite. + if (gl_spriteclip == -1 && (thing->renderflags & RF_SPRITETYPEMASK) == RF_FACESPRITE) // perform anamorphosis + { + float minbias = r_spriteclipanamorphicminbias; + minbias = clamp(minbias, 0.3f, 1.0f); + + float btm = thing->Sector->floorplane.ZatPoint(thing) - thing->Floorclip; + float top = thing->Sector->ceilingplane.ZatPoint(thingpos); + + float vbtm = thing->Sector->floorplane.ZatPoint(vp.Pos); + float vtop = thing->Sector->ceilingplane.ZatPoint(vp.Pos); + + float vpx = vp.Pos.X; + float vpy = vp.Pos.Y; + float vpz = vp.Pos.Z; + + float tpx = thingpos.X; + float tpy = thingpos.Y; + float tpz = thingpos.Z; + + if (!(r_debug_nolimitanamorphoses)) + { + // this should help prevent clipping through walls ... + float objradiusbias = 1.f - thing->radius / sqrt((vpx - tpx) * (vpx - tpx) + (vpy - tpy) * (vpy - tpy)); + minbias = max(minbias, objradiusbias); + } + + float bintersect, tintersect; + if (z2 < vpz && vbtm < vpz) + bintersect = min((btm - vpz) / (z2 - vpz), (vbtm - vpz) / (z2 - vpz)); + else + bintersect = 1.0; + + if (z1 > vpz && vtop > vpz) + tintersect = min((top - vpz) / (z1 - vpz), (vtop - vpz) / (z1 - vpz)); + else + tintersect = 1.0; + + if (thing->waterlevel >= 1 && thing->waterlevel <= 2) + bintersect = tintersect = 1.0f; + + float spbias = clamp(min(bintersect, tintersect), minbias, 1.0f); + float vpbias = 1.0 - spbias; + x1 = x1 * spbias + vpx * vpbias; + y1 = y1 * spbias + vpy * vpbias; + z1 = z1 * spbias + vpz * vpbias; + x2 = x2 * spbias + vpx * vpbias; + y2 = y2 * spbias + vpy * vpbias; + z2 = z2 * spbias + vpz * vpbias; + } + // light calculation bool enhancedvision = false; @@ -1335,6 +1387,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t { lightlist = nullptr; } + PutSprite(di, hw_styleflags != STYLEHW_Solid); rendered_sprites++; } diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 0d099afb6..4ac0a00ff 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -2392,6 +2392,7 @@ OptionValue "SpriteclipModes" 1, "$OPTVAL_SMART" 2, "$OPTVAL_ALWAYS" 3, "$OPTVAL_SMARTER" + -1, "$OPTVAL_ANAMORPHIC" } OptionValue "EnhancedStealth" From 391f4965128f2f5e2c07d764d42f363c67d9ed1c Mon Sep 17 00:00:00 2001 From: inkoalawetrust <56005600+inkoalawetrust@users.noreply.github.com> Date: Fri, 29 Mar 2024 20:55:50 +0200 Subject: [PATCH 11/40] Added SECMF_HURTMONSTERS, SECMF_HARMINAIR and NOSECTORDAMAGE. - Added SECMF_HURTMONSTERS, which allows monsters in the flagged sector to be hurt with the same behavior as players (i.e damage leaking). - Added SECMF_HARMINAIR, which allows players (And monsters with SECMF_HURTMONSTERS) to be hurt when they're inside the sector in general, instead of only when they're walking on it. Replicates the behavior of the DAMAGE_IN_AIR flag that SectorDamage() uses. - Added NOSECTORDAMAGE, which makes actors with the flag immune to any harmful floors. --- specs/udmf_zdoom.txt | 2 + src/gamedata/r_defs.h | 2 + src/maploader/udmf.cpp | 8 ++++ src/namedef_custom.h | 2 + src/playsim/actor.h | 3 +- src/playsim/p_3dfloors.cpp | 18 ++++----- src/playsim/p_3dfloors.h | 3 +- src/playsim/p_mobj.cpp | 8 ++++ src/playsim/p_spec.cpp | 65 +++++++++++++++----------------- src/playsim/p_spec.h | 4 +- src/playsim/p_user.cpp | 9 ----- src/scripting/thingdef_data.cpp | 1 + wadsrc/static/zscript/mapdata.zs | 8 ++++ 13 files changed, 76 insertions(+), 57 deletions(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 35b23418d..78ccd05b4 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -307,6 +307,8 @@ Note: All fields default to false unless mentioned otherwise. leakiness = ; // Probability of leaking through radiation suit (0 = never, 256 = always), default = 0. damageterraineffect = ; // Will spawn a terrain splash when damage is inflicted. Default = false. damagehazard = ; // Changes damage model to Strife's delayed damage for the given sector. Default = false. + hurtmonsters = ; // Non-players like monsters and decorations are hurt by this sector in the same manner as player. Doesn't work with damagehazard. + harminair = ; // Actors in this sector are harmed by the damage effects of the floor even if they aren't touching it. floorterrain = ; // Sets the terrain for the sector's floor. Default = 'use the flat texture's terrain definition.' ceilingterrain = ; // Sets the terrain for the sector's ceiling. Default = 'use the flat texture's terrain definition.' floor_reflect = ; // reflectiveness of floor (OpenGL only, not functional on sloped sectors) diff --git a/src/gamedata/r_defs.h b/src/gamedata/r_defs.h index 943893c66..d6453b6f8 100644 --- a/src/gamedata/r_defs.h +++ b/src/gamedata/r_defs.h @@ -504,6 +504,8 @@ 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_HURTMONSTERS = 4096, // Monsters in this sector are hurt like players. + SECMF_HARMINAIR = 8192, // Actors in this sector are also hurt mid-air. }; enum diff --git a/src/maploader/udmf.cpp b/src/maploader/udmf.cpp index ad33538ab..38ec2a0f9 100644 --- a/src/maploader/udmf.cpp +++ b/src/maploader/udmf.cpp @@ -1978,6 +1978,14 @@ public: Flag(sec->Flags, SECF_HAZARD, key); break; + case NAME_hurtmonsters: + Flag(sec->MoreFlags, SECMF_HURTMONSTERS, key); + break; + + case NAME_harminair: + Flag(sec->MoreFlags, SECMF_HARMINAIR, key); + break; + case NAME_floorterrain: sec->terrainnum[sector_t::floor] = P_FindTerrain(CheckString(key)); break; diff --git a/src/namedef_custom.h b/src/namedef_custom.h index 3144d46f9..4545e8746 100644 --- a/src/namedef_custom.h +++ b/src/namedef_custom.h @@ -810,6 +810,8 @@ xx(damageinterval) xx(leakiness) xx(damageterraineffect) xx(damagehazard) +xx(hurtmonsters) +xx(harminair) xx(floorterrain) xx(ceilingterrain) xx(floor_reflect) diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 906fe2c1b..a96e7f316 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -442,7 +442,8 @@ enum ActorFlag9 MF9_DOSHADOWBLOCK = 0x00000002, // [inkoalawetrust] Should the monster look for SHADOWBLOCK actors ? MF9_SHADOWBLOCK = 0x00000004, // [inkoalawetrust] Actors in the line of fire with this flag trigger the MF_SHADOW aiming penalty. MF9_SHADOWAIMVERT = 0x00000008, // [inkoalawetrust] Monster aim is also offset vertically when aiming at shadow actors. - MF9_DECOUPLEDANIMATIONS = 0x00000010, // [RL0] Decouple model animations from states + MF9_DECOUPLEDANIMATIONS = 0x00000010, // [RL0] Decouple model animations from states + MF9_NOSECTORDAMAGE = 0x00000020, // [inkoalawetrust] Actor ignores any sector-based damage (i.e damaging floors, NOT crushers) }; // --- mobj.renderflags --- diff --git a/src/playsim/p_3dfloors.cpp b/src/playsim/p_3dfloors.cpp index dd5a2bb0a..505bfa794 100644 --- a/src/playsim/p_3dfloors.cpp +++ b/src/playsim/p_3dfloors.cpp @@ -198,15 +198,15 @@ void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flags, int //========================================================================== // -// P_PlayerOnSpecial3DFloor -// Checks to see if a player is standing on or is inside a 3D floor (water) +// P_ActorOnSpecial3DFloor +// Checks to see if an actor is standing on or is inside a 3D floor (water) // and applies any specials.. // //========================================================================== -void P_PlayerOnSpecial3DFloor(player_t* player) +void P_ActorOnSpecial3DFloor(AActor* victim) { - for(auto rover : player->mo->Sector->e->XFloor.ffloors) + for(auto rover : victim->Sector->e->XFloor.ffloors) { if (!(rover->flags & FF_EXISTS)) continue; if (rover->flags & FF_FIX) continue; @@ -215,22 +215,22 @@ void P_PlayerOnSpecial3DFloor(player_t* player) if(rover->flags & FF_SOLID) { // Player must be on top of the floor to be affected... - if(player->mo->Z() != rover->top.plane->ZatPoint(player->mo)) continue; + if(victim->Z() != rover->top.plane->ZatPoint(victim)) continue; } else { //Water and DEATH FOG!!! heh if ((rover->flags & FF_NODAMAGE) || - player->mo->Z() > rover->top.plane->ZatPoint(player->mo) || - player->mo->Top() < rover->bottom.plane->ZatPoint(player->mo)) + victim->Z() > rover->top.plane->ZatPoint(victim) || + victim->Top() < rover->bottom.plane->ZatPoint(victim)) continue; } // Apply sector specials - P_PlayerInSpecialSector(player, rover->model); + P_ActorInSpecialSector(victim, rover->model); // Apply flat specials (using the ceiling!) - P_PlayerOnSpecialFlat(player, rover->model->GetTerrain(rover->top.isceiling)); + P_ActorOnSpecialFlat(victim, rover->model->GetTerrain(rover->top.isceiling)); break; } diff --git a/src/playsim/p_3dfloors.h b/src/playsim/p_3dfloors.h index 05d222137..2dba7f713 100644 --- a/src/playsim/p_3dfloors.h +++ b/src/playsim/p_3dfloors.h @@ -113,8 +113,7 @@ struct lightlist_t -class player_t; -void P_PlayerOnSpecial3DFloor(player_t* player); +void P_ActorOnSpecial3DFloor(AActor* victim); bool P_CheckFor3DFloorHit(AActor * mo, double z, bool trigger); bool P_CheckFor3DCeilingHit(AActor * mo, double z, bool trigger); diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index 7df73be6d..c9bf3dd37 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -4431,6 +4431,14 @@ void AActor::Tick () // must have been removed if (ObjectFlags & OF_EuthanizeMe) return; } + //[inkoalawetrust] Genericized level damage handling that makes sector, 3D floor, and TERRAIN flat damage affect monsters and other NPCs too. + if (!(flags9 & MF9_NOSECTORDAMAGE) && (player || (player == nullptr && Sector->MoreFlags & SECMF_HURTMONSTERS))) + { + P_ActorOnSpecial3DFloor(this); + P_ActorInSpecialSector(this,Sector); + if (!isAbove(Sector->floorplane.ZatPoint(this)) || waterlevel) // Actor must be touching the floor for TERRAIN flats. + P_ActorOnSpecialFlat(this, P_GetThingFloorType(this)); + } if (tics != -1) { diff --git a/src/playsim/p_spec.cpp b/src/playsim/p_spec.cpp index 3b63839fe..d72b14e96 100644 --- a/src/playsim/p_spec.cpp +++ b/src/playsim/p_spec.cpp @@ -100,7 +100,7 @@ #include "c_console.h" #include "p_spec_thinkers.h" -static FRandom pr_playerinspecialsector ("PlayerInSpecialSector"); +static FRandom pr_actorinspecialsector ("ActorInSpecialSector"); EXTERN_CVAR(Bool, cl_predict_specials) EXTERN_CVAR(Bool, forcewater) @@ -419,21 +419,20 @@ bool P_PredictLine(line_t *line, AActor *mo, int side, int activationType) } // -// P_PlayerInSpecialSector +// P_ActorInSpecialSector // Called every tic frame -// that the player origin is in a special sector +// that the actor origin is in a special sector // -void P_PlayerInSpecialSector (player_t *player, sector_t * sector) +void P_ActorInSpecialSector (AActor *victim, sector_t * sector) { if (sector == NULL) + sector = victim->Sector; + + // Falling, not all the way down yet? + if (!(sector->MoreFlags & SECMF_HARMINAIR) && !victim->isAtZ(sector->LowestFloorAt(victim)) && !victim->waterlevel) { - // Falling, not all the way down yet? - sector = player->mo->Sector; - if (!player->mo->isAtZ(sector->LowestFloorAt(player->mo)) - && !player->mo->waterlevel) - { - return; - } + DPrintf(2,"P_ActorInSpecialSector(): %p is not touching the floor and HARMINAIR isn't on, so they won't be harmed by the sector.\n",victim); + return; } // Has hit ground. @@ -445,7 +444,7 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) if (sector->damageinterval <= 0) sector->damageinterval = 32; // repair invalid damageinterval values - if (sector->Flags & (SECF_EXIT1 | SECF_EXIT2)) + if (victim->player && sector->Flags & (SECF_EXIT1 | SECF_EXIT2)) { for (int i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) @@ -464,7 +463,7 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) // different damage types yet, so that's not happening for now. // [MK] account for subclasses that may have "Full" protection (i.e.: prevent leaky damage) int ironfeet = 0; - for (auto i = player->mo->Inventory; i != NULL; i = i->Inventory) + for (auto i = victim->Inventory; i != NULL; i = i->Inventory) { if (i->IsKindOf(NAME_PowerIronFeet)) { @@ -476,28 +475,28 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) } } - if (sector->Flags & SECF_ENDGODMODE) player->cheats &= ~CF_GODMODE; - if ((ironfeet == 0 || (ironfeet < 2 && pr_playerinspecialsector() < sector->leakydamage))) + if (victim->player && sector->Flags & SECF_ENDGODMODE) victim->player->cheats &= ~CF_GODMODE; + if ((ironfeet == 0 || (ironfeet < 2 && pr_actorinspecialsector() < sector->leakydamage))) { - if (sector->Flags & SECF_HAZARD) + if (victim->player && sector->Flags & SECF_HAZARD) { - player->hazardcount += sector->damageamount; - player->hazardtype = sector->damagetype; - player->hazardinterval = sector->damageinterval; + victim->player->hazardcount += sector->damageamount; + victim->player->hazardtype = sector->damagetype; + victim->player->hazardinterval = sector->damageinterval; } else if (Level->time % sector->damageinterval == 0) { - if (!(player->cheats & (CF_GODMODE | CF_GODMODE2))) + if (!(victim->player && victim->player->cheats & (CF_GODMODE | CF_GODMODE2))) { - P_DamageMobj(player->mo, NULL, NULL, sector->damageamount, sector->damagetype); + P_DamageMobj(victim, NULL, NULL, sector->damageamount, sector->damagetype); } - if ((sector->Flags & SECF_ENDLEVEL) && player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT))) + if (victim->player && (sector->Flags & SECF_ENDLEVEL) && victim->player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT))) { Level->ExitLevel(0, false); } if (sector->Flags & SECF_DMGTERRAINFX) { - P_HitWater(player->mo, player->mo->Sector, player->mo->Pos(), false, true, true); + P_HitWater(victim, victim->Sector, victim->Pos(), false, true, true); } } } @@ -506,14 +505,14 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) { if (Level->time % sector->damageinterval == 0) { - P_GiveBody(player->mo, -sector->damageamount, 100); + P_GiveBody(victim, -sector->damageamount, 100); } } - if (sector->isSecret()) + if (victim->player && sector->isSecret()) { sector->ClearSecret(); - P_GiveSecret(Level, player->mo, true, true, sector->Index()); + P_GiveSecret(Level, victim, true, true, sector->Index()); } } @@ -652,13 +651,13 @@ DEFINE_ACTION_FUNCTION(FLevelLocals, GiveSecret) //============================================================================ // -// P_PlayerOnSpecialFlat +// P_ActorOnSpecialFlat // //============================================================================ -void P_PlayerOnSpecialFlat (player_t *player, int floorType) +void P_ActorOnSpecialFlat (AActor *victim, int floorType) { - auto Level = player->mo->Level; + auto Level = victim->Level; if (Terrains[floorType].DamageAmount && !(Level->time % (Terrains[floorType].DamageTimeMask+1))) @@ -668,7 +667,7 @@ void P_PlayerOnSpecialFlat (player_t *player, int floorType) if (Terrains[floorType].AllowProtection) { auto pitype = PClass::FindActor(NAME_PowerIronFeet); - for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory) + for (ironfeet = victim->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory) { if (ironfeet->IsKindOf (pitype)) break; @@ -678,20 +677,18 @@ void P_PlayerOnSpecialFlat (player_t *player, int floorType) int damage = 0; if (ironfeet == NULL) { - damage = P_DamageMobj (player->mo, NULL, NULL, Terrains[floorType].DamageAmount, + damage = P_DamageMobj (victim, NULL, NULL, Terrains[floorType].DamageAmount, Terrains[floorType].DamageMOD); } if (damage > 0 && Terrains[floorType].Splash != -1) { - S_Sound (player->mo, CHAN_AUTO, 0, + S_Sound (victim, CHAN_AUTO, 0, Splashes[Terrains[floorType].Splash].NormalSplashSound, 1, ATTN_IDLE); } } } - - // // P_UpdateSpecials // Animate planes, scroll walls, etc. diff --git a/src/playsim/p_spec.h b/src/playsim/p_spec.h index cc7d990a9..ebb5d93f9 100644 --- a/src/playsim/p_spec.h +++ b/src/playsim/p_spec.h @@ -90,8 +90,8 @@ bool P_ActivateLine (line_t *ld, AActor *mo, int side, int activationType, DVect bool P_TestActivateLine (line_t *ld, AActor *mo, int side, int activationType, DVector3 *optpos = NULL); bool P_PredictLine (line_t *ld, AActor *mo, int side, int activationType); -void P_PlayerInSpecialSector (player_t *player, sector_t * sector=NULL); -void P_PlayerOnSpecialFlat (player_t *player, int floorType); +void P_ActorInSpecialSector (AActor *victim, sector_t * sector=NULL); +void P_ActorOnSpecialFlat (AActor *victim, int floorType); void P_SectorDamage(FLevelLocals *Level, int tag, int amount, FName type, PClassActor *protectClass, int flags); void P_SetSectorFriction (FLevelLocals *level, int tag, int amount, bool alterFlag); double FrictionToMoveFactor(double friction); diff --git a/src/playsim/p_user.cpp b/src/playsim/p_user.cpp index fefb0f943..43cc67bd8 100644 --- a/src/playsim/p_user.cpp +++ b/src/playsim/p_user.cpp @@ -1181,15 +1181,6 @@ DEFINE_ACTION_FUNCTION(APlayerPawn, CheckMusicChange) void P_CheckEnvironment(player_t *player) { - P_PlayerOnSpecial3DFloor(player); - P_PlayerInSpecialSector(player); - - if (!player->mo->isAbove(player->mo->Sector->floorplane.ZatPoint(player->mo)) || - player->mo->waterlevel) - { - // Player must be touching the floor - P_PlayerOnSpecialFlat(player, P_GetThingFloorType(player->mo)); - } if (player->mo->Vel.Z <= -player->mo->FloatVar(NAME_FallingScreamMinSpeed) && player->mo->Vel.Z >= -player->mo->FloatVar(NAME_FallingScreamMaxSpeed) && player->mo->alternative == nullptr && player->mo->waterlevel == 0) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 5bbb35fae..bc62f2250 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -353,6 +353,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF9, SHADOWBLOCK, AActor, flags9), DEFINE_FLAG(MF9, SHADOWAIMVERT, AActor, flags9), DEFINE_FLAG(MF9, DECOUPLEDANIMATIONS, AActor, flags9), + DEFINE_FLAG(MF9, NOSECTORDAMAGE, AActor, flags9), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), diff --git a/wadsrc/static/zscript/mapdata.zs b/wadsrc/static/zscript/mapdata.zs index db217e7cc..080e05f32 100644 --- a/wadsrc/static/zscript/mapdata.zs +++ b/wadsrc/static/zscript/mapdata.zs @@ -435,6 +435,11 @@ 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_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_HURTMONSTERS = 4096, // Monsters in this sector are hurt like players. + SECMF_HARMINAIR = 8192, // Actors in this sector are also hurt mid-air. } native uint16 MoreFlags; @@ -452,6 +457,9 @@ struct Sector native play SECF_ENDLEVEL = 512, // ends level when health goes below 10 SECF_HAZARD = 1024, // Change to Strife's delayed damage handling. SECF_NOATTACK = 2048, // monsters cannot start attacks in this sector. + SECF_EXIT1 = 4096, + SECF_EXIT2 = 8192, + SECF_KILLMONSTERS = 16384,// Monsters in this sector are instantly killed. SECF_WASSECRET = 1 << 30, // a secret that was discovered SECF_SECRET = 1 << 31, // a secret sector From 9b8c79d1823e96102cb3be146259642a592daa90 Mon Sep 17 00:00:00 2001 From: inkoalawetrust <56005600+inkoalawetrust@users.noreply.github.com> Date: Fri, 29 Mar 2024 21:10:36 +0200 Subject: [PATCH 12/40] Added check for hurt floors in P_IsUnderDamage(). --- src/playsim/p_enemy.cpp | 6 ++++++ src/playsim/p_spec.cpp | 3 --- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index 45df68ac1..1d49f4b3a 100644 --- a/src/playsim/p_enemy.cpp +++ b/src/playsim/p_enemy.cpp @@ -465,6 +465,12 @@ static int P_IsUnderDamage(AActor* actor) dir |= cl->getDirection(); } // Q: consider crushing 3D floors too? + // [inkoalawetrust] Check for sectors that can harm the actor. + if (!(actor->flags9 & MF9_NOSECTORDAMAGE) && seclist->m_sector->damageamount > 0) + { + if (seclist->m_sector->MoreFlags & SECMF_HARMINAIR || actor->isAtZ(seclist->m_sector->LowestFloorAt(actor)) || actor->waterlevel) + return (actor->player || (actor->player == nullptr && seclist->m_sector->MoreFlags & SECMF_HURTMONSTERS)) ? -1 : 0; + } } return dir; } diff --git a/src/playsim/p_spec.cpp b/src/playsim/p_spec.cpp index d72b14e96..3ee5fe871 100644 --- a/src/playsim/p_spec.cpp +++ b/src/playsim/p_spec.cpp @@ -430,10 +430,7 @@ void P_ActorInSpecialSector (AActor *victim, sector_t * sector) // Falling, not all the way down yet? if (!(sector->MoreFlags & SECMF_HARMINAIR) && !victim->isAtZ(sector->LowestFloorAt(victim)) && !victim->waterlevel) - { - DPrintf(2,"P_ActorInSpecialSector(): %p is not touching the floor and HARMINAIR isn't on, so they won't be harmed by the sector.\n",victim); return; - } // Has hit ground. From 4c27b55eb940a94e7de3c624c3bcc68e0b3dda30 Mon Sep 17 00:00:00 2001 From: Jon Heard Date: Sun, 28 Apr 2024 19:39:45 -0400 Subject: [PATCH 13/40] SetSkin and GetSkinCount added to PlayerInfo class --- src/playsim/p_user.cpp | 23 +++++++++++++++++++ wadsrc/static/zscript/actors/player/player.zs | 2 ++ 2 files changed, 25 insertions(+) diff --git a/src/playsim/p_user.cpp b/src/playsim/p_user.cpp index 43cc67bd8..a98a7c523 100644 --- a/src/playsim/p_user.cpp +++ b/src/playsim/p_user.cpp @@ -520,6 +520,23 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, SetFOV) return 0; } +DEFINE_ACTION_FUNCTION(_PlayerInfo, SetSkin) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_INT(skinIndex); + if (skinIndex >= 0 && skinIndex < Skins.size()) + { + // commented code - cvar_set calls this automatically, along with saving the skin selection. + //self->userinfo.SkinNumChanged(skinIndex); + cvar_set("skin", Skins[skinIndex].Name.GetChars()); + ACTION_RETURN_INT(self->userinfo.GetSkin()); + } + else + { + ACTION_RETURN_INT(-1); + } +} + //=========================================================================== // // EnumColorsets @@ -773,6 +790,12 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, GetSkin) ACTION_RETURN_INT(self->userinfo.GetSkin()); } +DEFINE_ACTION_FUNCTION(_PlayerInfo, GetSkinCount) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + ACTION_RETURN_INT(Skins.size()); +} + DEFINE_ACTION_FUNCTION(_PlayerInfo, GetGender) { PARAM_SELF_STRUCT_PROLOGUE(player_t); diff --git a/wadsrc/static/zscript/actors/player/player.zs b/wadsrc/static/zscript/actors/player/player.zs index 69e534b70..c2da5f46c 100644 --- a/wadsrc/static/zscript/actors/player/player.zs +++ b/wadsrc/static/zscript/actors/player/player.zs @@ -2867,6 +2867,7 @@ struct PlayerInfo native play // self is what internally is known as player_t native clearscope int GetColorSet() const; native clearscope int GetPlayerClassNum() const; native clearscope int GetSkin() const; + native clearscope int GetSkinCount() const; native clearscope bool GetNeverSwitch() const; native clearscope int GetGender() const; native clearscope int GetTeam() const; @@ -2878,6 +2879,7 @@ struct PlayerInfo native play // self is what internally is known as player_t native bool GetFViewBob() const; native double GetStillBob() const; native void SetFOV(float fov); + native int SetSkin(int skinIndex); native clearscope bool GetClassicFlight() const; native void SendPitchLimits(); native clearscope bool HasWeaponsInSlot(int slot) const; From 41c69736b1544158816c9254a5837afd79b06209 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Mon, 30 Sep 2024 01:51:55 -0400 Subject: [PATCH 14/40] - fix some issues with ClearInventory() that sometimes caused script errors --- wadsrc/static/zscript/actors/inventory/inventory.zs | 1 + wadsrc/static/zscript/actors/inventory_util.zs | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/wadsrc/static/zscript/actors/inventory/inventory.zs b/wadsrc/static/zscript/actors/inventory/inventory.zs index 52009f2e1..f41880a3c 100644 --- a/wadsrc/static/zscript/actors/inventory/inventory.zs +++ b/wadsrc/static/zscript/actors/inventory/inventory.zs @@ -940,6 +940,7 @@ class Inventory : Actor } else { + Owner = null; Destroy(); } } diff --git a/wadsrc/static/zscript/actors/inventory_util.zs b/wadsrc/static/zscript/actors/inventory_util.zs index 011ca134f..e47172a49 100644 --- a/wadsrc/static/zscript/actors/inventory_util.zs +++ b/wadsrc/static/zscript/actors/inventory_util.zs @@ -333,8 +333,13 @@ extend class Actor // destroy something we already processed, we've already destroyed it, // so it won't have anything to destroy. - let last = self; + if (player != null) + { + player.ReadyWeapon = null; + player.PendingWeapon = WP_NOCHANGE; + } + let last = self; while (last.inv != NULL) { let inv = last.inv; @@ -348,11 +353,6 @@ extend class Actor last = inv; } } - if (player != null) - { - player.ReadyWeapon = null; - player.PendingWeapon = WP_NOCHANGE; - } } From 0b3ee04025d62de65c3a8337f5ee595e7fa9881c Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Mon, 30 Sep 2024 02:09:52 -0400 Subject: [PATCH 15/40] - bail out if `shape` is null in `F2DDrawer::AddShape` --- src/common/2d/v_2ddrawer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/common/2d/v_2ddrawer.cpp b/src/common/2d/v_2ddrawer.cpp index 717d607c6..10f4869b9 100644 --- a/src/common/2d/v_2ddrawer.cpp +++ b/src/common/2d/v_2ddrawer.cpp @@ -592,6 +592,10 @@ void DShape2D::OnDestroy() { void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms) { + // bail if shape is null (shouldn't happen but it might) + if (!shape) + ThrowAbortException(X_OTHER, "shape is null"); + // [MK] bail out if vertex/coord array sizes are mismatched if ( shape->mVertices.Size() != shape->mCoords.Size() ) ThrowAbortException(X_OTHER, "Mismatch in vertex/coord count: %u != %u", shape->mVertices.Size(), shape->mCoords.Size()); From 8e1b25803e6c65630b06be8d39188f9eafeb2564 Mon Sep 17 00:00:00 2001 From: Boondorl Date: Sun, 29 Sep 2024 19:55:13 -0400 Subject: [PATCH 16/40] Fix for NoLocalRender not snapshotting between hub levels --- src/playsim/p_mobj.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index c9bf3dd37..e39db44cb 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -217,6 +217,7 @@ void AActor::Serialize(FSerializer &arc) A("angles", Angles) A("frame", frame) A("scale", Scale) + A("nolocalrender", NoLocalRender) // Note: This will probably be removed later since a better solution is needed A("renderstyle", RenderStyle) A("renderflags", renderflags) A("renderflags2", renderflags2) From 18c068fd1f803e97d96224994145f950bd78b82e Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Mon, 30 Sep 2024 03:27:39 -0400 Subject: [PATCH 17/40] Revert "- fix some issues with ClearInventory() that sometimes caused script errors" This reverts commit 41c69736b1544158816c9254a5837afd79b06209. This introduced more bugs and so the fix was not valid. --- wadsrc/static/zscript/actors/inventory/inventory.zs | 1 - wadsrc/static/zscript/actors/inventory_util.zs | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/wadsrc/static/zscript/actors/inventory/inventory.zs b/wadsrc/static/zscript/actors/inventory/inventory.zs index f41880a3c..52009f2e1 100644 --- a/wadsrc/static/zscript/actors/inventory/inventory.zs +++ b/wadsrc/static/zscript/actors/inventory/inventory.zs @@ -940,7 +940,6 @@ class Inventory : Actor } else { - Owner = null; Destroy(); } } diff --git a/wadsrc/static/zscript/actors/inventory_util.zs b/wadsrc/static/zscript/actors/inventory_util.zs index e47172a49..011ca134f 100644 --- a/wadsrc/static/zscript/actors/inventory_util.zs +++ b/wadsrc/static/zscript/actors/inventory_util.zs @@ -333,13 +333,8 @@ extend class Actor // destroy something we already processed, we've already destroyed it, // so it won't have anything to destroy. - if (player != null) - { - player.ReadyWeapon = null; - player.PendingWeapon = WP_NOCHANGE; - } - let last = self; + while (last.inv != NULL) { let inv = last.inv; @@ -353,6 +348,11 @@ extend class Actor last = inv; } } + if (player != null) + { + player.ReadyWeapon = null; + player.PendingWeapon = WP_NOCHANGE; + } } From 568a39d20335cc4c6b1260f8a5102e1fec028166 Mon Sep 17 00:00:00 2001 From: "Dileep V. Reddy" Date: Mon, 30 Sep 2024 07:58:43 -0600 Subject: [PATCH 18/40] Removing pre-clipping of Frustum if pitch > 46 degrees and viewpoint is not allowed out of bounds. This is like old behavior. --- src/rendering/hwrenderer/scene/hw_drawinfo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index b7c02a841..3453b6e50 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -366,6 +366,7 @@ angle_t HWDrawInfo::FrustumAngle() { // If pitch is larger than this you can look all around at an FOV of 90 degrees if (fabs(Viewpoint.HWAngles.Pitch.Degrees()) > 89.0) return 0xffffffff; + else if (fabs(Viewpoint.HWAngles.Pitch.Degrees()) > 46.0 && !Viewpoint.IsAllowedOoB()) return 0xffffffff; // Just like 4.12.2 and older did int aspMult = AspectMultiplier(r_viewwindow.WidescreenRatio); // 48 == square window double absPitch = fabs(Viewpoint.HWAngles.Pitch.Degrees()); // Smaller aspect ratios still clip too much. Need a better solution From 2c9b8f4eec82e32b0b7771048b3027e213fe5c5e Mon Sep 17 00:00:00 2001 From: inkoalawetrust <56005600+inkoalawetrust@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:17:48 +0300 Subject: [PATCH 19/40] Fixed problem in CheckForShadows(). Fixed a regression in CheckForShadows() that made it always return a +SHADOW or +SHADOWBLOCK actor even when there were none. Causing monsters to always have messy aim if +DOSHADOWBLOCK is on. --- src/playsim/shadowinlines.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/playsim/shadowinlines.h b/src/playsim/shadowinlines.h index 574abd251..b36b051ac 100644 --- a/src/playsim/shadowinlines.h +++ b/src/playsim/shadowinlines.h @@ -88,6 +88,7 @@ inline AActor* CheckForShadows(AActor* self, AActor* other, DVector3 pos, double if ((other && (other->flags & MF_SHADOW)) || (self->flags9 & MF9_DOSHADOWBLOCK)) { AActor* shadowBlock = P_CheckForShadowBlock(self, other, pos, penaltyFactor); + if (other && !(other->flags & MF_SHADOW)) other = nullptr; //Other doesn't have MF_SHADOW, so don't count them as a valid return. return shadowBlock ? shadowBlock : other; } return nullptr; From e88d912892646e8048131fd2d3555a6b87d1f5b9 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 15 Aug 2024 23:32:54 +0600 Subject: [PATCH 20/40] ID24 interlevel lumps implementation --- src/common/audio/music/music.cpp | 18 + src/common/audio/music/s_music.h | 3 + src/common/engine/serializer.cpp | 27 +- src/common/engine/serializer.h | 2 + src/gamedata/g_mapinfo.cpp | 49 ++ src/gamedata/g_mapinfo.h | 7 +- src/gamedata/umapinfo.cpp | 12 + src/wi_stuff.cpp | 548 ++++++++++++++++-- .../zscript/ui/statscreen/statscreen.zs | 4 +- 9 files changed, 605 insertions(+), 65 deletions(-) diff --git a/src/common/audio/music/music.cpp b/src/common/audio/music/music.cpp index 13837e93e..01b3a5da3 100644 --- a/src/common/audio/music/music.cpp +++ b/src/common/audio/music/music.cpp @@ -130,6 +130,24 @@ static FileReader OpenMusic(const char* musicname) return reader; } +bool MusicExists(const char* music_name) +{ + if (music_name == nullptr) + return false; + + if (FileExists(music_name)) + return true; + else + { + int lumpnum; + lumpnum = mus_cb.FindMusic(music_name); + if (lumpnum == -1) lumpnum = fileSystem.CheckNumForName(music_name, FileSys::ns_music); + if (lumpnum != -1 && fileSystem.FileLength(lumpnum) != 0) + return true; + } + return false; +} + void S_SetMusicCallbacks(MusicCallbacks* cb) { mus_cb = *cb; diff --git a/src/common/audio/music/s_music.h b/src/common/audio/music/s_music.h index cddfd36d6..629f6f95d 100644 --- a/src/common/audio/music/s_music.h +++ b/src/common/audio/music/s_music.h @@ -45,6 +45,9 @@ bool S_StartMusic (const char *music_name); // Start music using , and set whether looping bool S_ChangeMusic (const char *music_name, int order=0, bool looping=true, bool force=false); +// Check if exists +bool MusicExists(const char* music_name); + void S_RestartMusic (); void S_MIDIDeviceChanged(int newdev); diff --git a/src/common/engine/serializer.cpp b/src/common/engine/serializer.cpp index dcf930842..97ded1adf 100644 --- a/src/common/engine/serializer.cpp +++ b/src/common/engine/serializer.cpp @@ -197,7 +197,10 @@ void FSerializer::Close() } if (mErrors > 0) { - I_Error("%d errors parsing JSON", mErrors); + if (mLumpName.IsNotEmpty()) + I_Error("%d errors parsing JSON lump %s", mErrors, mLumpName.GetChars()); + else + I_Error("%d errors parsing JSON", mErrors); } } @@ -331,6 +334,28 @@ bool FSerializer::HasObject(const char* name) // //========================================================================== +bool FSerializer::IsKeyNull(const char* name) +{ + if (isReading()) + { + auto val = r->FindKey(name); + if (val != nullptr) + { + if (val->IsNull()) + { + return true; + } + } + } + return false; +} + +//========================================================================== +// +// +// +//========================================================================== + void FSerializer::EndObject() { if (isWriting()) diff --git a/src/common/engine/serializer.h b/src/common/engine/serializer.h index 99ffb72dc..40b6ab706 100644 --- a/src/common/engine/serializer.h +++ b/src/common/engine/serializer.h @@ -94,6 +94,7 @@ public: void EndObject(); bool HasKey(const char* name); bool HasObject(const char* name); + bool IsKeyNull(const char* name); bool BeginArray(const char *name); void EndArray(); unsigned GetSize(const char *group); @@ -225,6 +226,7 @@ public: int mErrors = 0; int mObjectErrors = 0; + FString mLumpName; }; FSerializer& Serialize(FSerializer& arc, const char* key, char& value, char* defval); diff --git a/src/gamedata/g_mapinfo.cpp b/src/gamedata/g_mapinfo.cpp index 3d9bc8bd9..6cd4fdcdf 100644 --- a/src/gamedata/g_mapinfo.cpp +++ b/src/gamedata/g_mapinfo.cpp @@ -164,6 +164,20 @@ bool CheckWarpTransMap (FString &mapname, bool substitute) // //========================================================================== +bool SecretLevelVisited() +{ + for (unsigned int i = 0; i < wadlevelinfos.Size(); i++) + if ((wadlevelinfos[i].flags3 & LEVEL3_SECRET) && (wadlevelinfos[i].flags & LEVEL_VISITED)) + return true; + + return false; +} + +//========================================================================== +// +// +//========================================================================== + static int FindWadClusterInfo (int cluster) { for (unsigned int i = 0; i < wadclusterinfos.Size(); i++) @@ -280,6 +294,8 @@ void level_info_t::Reset() RedirectCVARMapName = ""; EnterPic = ""; ExitPic = ""; + EnterAnim = ""; + ExitAnim = ""; Intermission = NAME_None; deathsequence = NAME_None; slideshow = NAME_None; @@ -1256,6 +1272,20 @@ DEFINE_MAP_OPTION(enterpic, true) info->EnterPic = parse.sc.String; } +DEFINE_MAP_OPTION(exitanim, true) +{ + parse.ParseAssign(); + parse.sc.MustGetString(); + info->ExitAnim = parse.sc.String; +} + +DEFINE_MAP_OPTION(enteranim, true) +{ + parse.ParseAssign(); + parse.sc.MustGetString(); + info->EnterAnim = parse.sc.String; +} + DEFINE_MAP_OPTION(specialaction, true) { parse.ParseAssign(); @@ -2601,6 +2631,7 @@ void G_ParseMapInfo (FString basemapinfo) { int lump, lastlump = 0; level_info_t gamedefaults; + TArray secretMaps; int flags1 = 0, flags2 = 0; if (gameinfo.gametype == GAME_Doom) @@ -2717,5 +2748,23 @@ void G_ParseMapInfo (FString basemapinfo) { I_FatalError ("You cannot use clearskills in a MAPINFO if you do not define any new skills after it."); } + + // Find any and all secret maps. + for (unsigned int i = 0; i < wadlevelinfos.Size(); i++) + { + if (wadlevelinfos[i].NextSecretMap.IsNotEmpty() && wadlevelinfos[i].NextSecretMap != wadlevelinfos[i].NextMap) + { + secretMaps.Push(wadlevelinfos[i].NextSecretMap); + } + } + // ...and then mark them all as secret maps. + for (unsigned int i = 0; i < secretMaps.Size(); i++) + { + auto* li = FindLevelInfo(secretMaps[i].GetChars(), false); + if (li) + { + li->flags3 |= LEVEL3_SECRET; + } + } } diff --git a/src/gamedata/g_mapinfo.h b/src/gamedata/g_mapinfo.h index 8f311f6a2..b07e6e442 100644 --- a/src/gamedata/g_mapinfo.h +++ b/src/gamedata/g_mapinfo.h @@ -269,8 +269,9 @@ enum ELevelFlags : unsigned int LEVEL3_NOSHADOWMAP = 0x00010000, // disables shadowmaps for a given level. 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_LIGHTCREATED = 0x00080000, // a light had been created in the last frame LEVEL3_NOFOGOFWAR = 0x00100000, // disables effect of r_radarclipper CVAR on this map + LEVEL3_SECRET = 0x00200000, // level is a secret level }; @@ -389,6 +390,8 @@ struct level_info_t FString EnterPic; FString ExitPic; + FString EnterAnim; + FString ExitAnim; FString InterMusic; int intermusicorder; TMap > MapInterMusic; @@ -488,6 +491,8 @@ level_info_t *FindLevelInfo (const char *mapname, bool allowdefault=true); level_info_t *FindLevelByNum (int num); level_info_t *CheckLevelRedirect (level_info_t *info); +bool SecretLevelVisited(); + FString CalcMapName (int episode, int level); void G_ClearMapinfo(); diff --git a/src/gamedata/umapinfo.cpp b/src/gamedata/umapinfo.cpp index 08e16d9f8..50757e734 100644 --- a/src/gamedata/umapinfo.cpp +++ b/src/gamedata/umapinfo.cpp @@ -52,6 +52,8 @@ struct UMapEntry char endpic[9] = ""; char exitpic[9] = ""; char enterpic[9] = ""; + char exitanim[9] = ""; + char enteranim[9] = ""; char interbackdrop[9] = "FLOOR4_8"; char intermusic[9] = ""; int partime = 0; @@ -186,6 +188,14 @@ static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape) { ParseLumpName(scanner, mape->enterpic); } + else if (!pname.CompareNoCase("exitanim")) + { + ParseLumpName(scanner, mape->exitanim); + } + else if (!pname.CompareNoCase("enteranim")) + { + ParseLumpName(scanner, mape->enteranim); + } else if (!pname.CompareNoCase("nointermission")) { scanner.MustGetBoolToken(); @@ -443,6 +453,8 @@ void CommitUMapinfo(level_info_t *defaultinfo) if (map.partime > 0) levelinfo->partime = map.partime; if (map.enterpic[0]) levelinfo->EnterPic = map.enterpic; if (map.exitpic[0]) levelinfo->ExitPic = map.exitpic; + if (map.enteranim[0]) levelinfo->EnterAnim = map.enteranim; + if (map.exitanim[0]) levelinfo->ExitAnim = map.exitanim; /* UMAPINFO's intermusic is for the text screen, not the summary. if (map.intermusic[0]) { diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index dddc37c31..8a5c7945c 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -57,6 +57,9 @@ #include "texturemanager.h" #include "v_draw.h" +#include "serializer.h" +#include "s_music.h" + CVAR(Bool, wi_percents, true, CVAR_ARCHIVE) CVAR(Bool, wi_showtotaltime, true, CVAR_ARCHIVE) CVAR(Bool, wi_noautostartmap, false, CVAR_USERINFO | CVAR_ARCHIVE) @@ -109,6 +112,8 @@ class DInterBackground : public DObject { ANIM_ALWAYS, // determined by patch entry ANIM_PIC, // continuous + ANIM_FRAME, // determined by frame properties + ANIM_NONE, // frozen (used for infinite duration frames) // condition bitflags ANIM_IFVISITED = 8, @@ -137,13 +142,41 @@ class DInterBackground : public DObject FString Level; }; + struct frame_t + { + FTextureID image; + uint32_t type; + // In tics! + int duration; + int max_duration; + }; + + enum ECondition + { + COND_NONE = 0, // None. + COND_GREATER = 1, // Parameter is greater than current map number. + COND_EQUAL = 2, // Parameter is equal to current map number. + COND_VISITED = 3, // Map number corresponding to parameter is visited. + COND_NOTSECRET = 4, // Current map is not a secret one. + COND_SECRETVISTED = 5, // Any secret map was visited. + COND_TALLY = 6, // Tally screen. + COND_ENTERING = 7, // "Entering" screen. + }; + + struct condition_t + { + ECondition condition; + int param; + }; + struct in_anim_t { int type; // Made an int so I can use '|' int period; // period in tics between animations yahpt_t loc; // location of animation int data; // ALWAYS: n/a, RANDOM: period deviation (<256) - TArray frames; // actual graphics for frames of animations + TArray frames; // actual graphics for frames of animations + TArray conditions; // conditions to display the animation // following must be initialized to zero before use! int nexttic; // next value of bcnt (used in conjunction with period) @@ -162,9 +195,15 @@ class DInterBackground : public DObject } }; + struct in_layer_t + { + TArray anims; + TArray conditions; // conditions to display the animations. + }; + private: TArray lnodes; - TArray anims; + TArray layers; int bcnt = 0; // used for timing of background animation TArray yah; // You Are Here graphic FTextureID splat{}; // splat @@ -174,12 +213,14 @@ private: int bgwidth = -1; int bgheight = -1; bool tilebackground = false; + FString muslump; public: DInterBackground(wbstartstruct_t *wbst); bool LoadBackground(bool isenterpic); + bool IsUsingMusic(); void updateAnimatedBack(); void drawBackground(int state, bool drawsplat, bool snl_pointeron); @@ -242,6 +283,70 @@ private: } } } + + //==================================================================== + // + // Draws the splats and the 'You are here' arrows + // + //==================================================================== + bool ConditionsMet(int state, TArray& conditions) + { + for (auto& condition : conditions) + { + switch (condition.condition) + { + case ECondition::COND_NONE: + break; + case ECondition::COND_EQUAL: + { + auto* li = FindLevelInfo(state != StatCount ? wbs->next.GetChars() : wbs->current.GetChars()); + if (!li) + return false; + if (li->levelnum != condition.param) + return false; + break; + } + case ECondition::COND_GREATER: + { + auto* li = FindLevelInfo(state != StatCount ? wbs->next.GetChars() : wbs->current.GetChars()); + if (!li) + return false; + if (li->levelnum <= condition.param) + return false; + break; + } + case ECondition::COND_VISITED: + { + auto* li = FindLevelByNum(condition.param); + if (li == NULL || !(li->flags & LEVEL_VISITED)) + return false; + break; + } + case ECondition::COND_NOTSECRET: + { + auto* li = FindLevelInfo(state != StatCount ? wbs->next.GetChars() : wbs->current.GetChars()); + if (!li) + return false; + if (li->flags3 & LEVEL3_SECRET) + return false; + break; + } + case ECondition::COND_SECRETVISTED: + if (!SecretLevelVisited()) + return false; + break; + case ECondition::COND_TALLY: + if (state != StatCount) + return false; + break; + case ECondition::COND_ENTERING: + if (state == StatCount) + return false; + break; + } + } + return true; + } }; DInterBackground:: DInterBackground(wbstartstruct_t *wbst) @@ -270,11 +375,13 @@ bool DInterBackground::LoadBackground(bool isenterpic) { const char* lumpname = nullptr; const char* exitpic = nullptr; + const char* exitanim = nullptr; char buffer[10]; in_anim_t an; lnode_t pt; FTextureID texture; bool noautostartmap = false; + bool id24anim = false; bcnt = 0; @@ -284,8 +391,17 @@ bool DInterBackground::LoadBackground(bool isenterpic) level_info_t* li = FindLevelInfo(wbs->current.GetChars()); if (li != nullptr) { - exitpic = li->ExitPic.GetChars(); - if (li->ExitPic.IsNotEmpty()) tilebackground = false; + if (li->ExitAnim.IsNotEmpty()) + { + id24anim = true; + exitpic = li->ExitAnim.GetChars(); + tilebackground = false; + } + else + { + exitpic = li->ExitPic.GetChars(); + if (li->ExitPic.IsNotEmpty()) tilebackground = false; + } } lumpname = exitpic; @@ -294,8 +410,17 @@ bool DInterBackground::LoadBackground(bool isenterpic) level_info_t* li = FindLevelInfo(wbs->next.GetChars()); if (li != NULL) { - lumpname = li->EnterPic.GetChars(); - if (li->EnterPic.IsNotEmpty()) tilebackground = false; + if (li->EnterAnim.IsNotEmpty()) + { + id24anim = true; + lumpname = li->EnterAnim.GetChars(); + tilebackground = false; + } + else + { + lumpname = li->EnterPic.GetChars(); + if (li->EnterPic.IsNotEmpty()) tilebackground = false; + } } } @@ -382,12 +507,251 @@ bool DInterBackground::LoadBackground(bool isenterpic) } lnodes.Clear(); - anims.Clear(); + layers.Clear(); yah.Clear(); splat.SetInvalid(); + if (!id24anim) + layers.Resize(1); + if (id24anim) + { + try + { + int lumpnum = fileSystem.CheckNumForFullName(lumpname, true); + if (lumpnum == -1) + { + I_Error("Intermission animation lump %s not found!", lumpname); + } + auto data = fileSystem.ReadFile(lumpnum); + FSerializer jsonReader; + jsonReader.mLumpName = fileSystem.GetFileFullPath(lumpnum); + lumpname = jsonReader.mLumpName.GetChars(); + if (jsonReader.OpenReader(data.string(), data.size())) + { + FString type = jsonReader.GetString("type"); + if (type.Compare("interlevel")) + { + I_Error("Interlevel lump %s is not interlevel!", lumpname); + } + if (jsonReader.BeginObject("data")) + { + FString music = jsonReader.GetString("music"); + if (music.IsEmpty()) + { + I_Error("No music lump specified for intermission animation %s!", lumpname); + } + muslump = music; + if (!MusicExists(muslump.GetChars())) + { + I_Error("Music lump %s not found!", muslump.GetChars()); + } + + // Check for background lump. + FString backgroundimage = jsonReader.GetString("backgroundimage"); + texture = TexMan.CheckForTexture(backgroundimage.GetChars(), ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny); + if (!texture.isValid()) + { + if (backgroundimage.IsEmpty()) + { + I_Error("No background image specified for intermission animation %s!", lumpname); + } + else + { + I_Error("Texture %s not found!", backgroundimage.GetChars()); + } + } + + if (!jsonReader.IsKeyNull("layers") && jsonReader.BeginArray("layers")) + { + int size = jsonReader.ArraySize(); + + if (size == 0) + I_Error("Zero-length 'layers' array in %s", lumpname); + + for (int i = 0; i < size; i++) + { + if (jsonReader.BeginObject(nullptr)) + { + layers.Reserve(1); + auto& layer = layers.back(); + if (!jsonReader.IsKeyNull("conditions") && jsonReader.BeginArray("conditions")) + { + int condition_size = jsonReader.ArraySize(); + if (condition_size == 0) + { + I_Error("Condition array empty and not null for layer %d in lump %s", layers.Size(), lumpname); + } + for (int j = 0; j < condition_size; j++) + { + if (jsonReader.BeginObject(nullptr)) + { + ECondition cond = COND_NONE; + int param = 0; + ::Serialize(jsonReader, "condition", (int&)cond, nullptr); + ::Serialize(jsonReader, "param", param, nullptr); + layer.conditions.Push(condition_t{ cond, param }); + jsonReader.EndObject(); + } + } + jsonReader.EndArray(); + } + + // Read anims. + if (jsonReader.BeginArray("anims")) + { + int anim_size = jsonReader.ArraySize(); + if (anim_size == 0) + { + I_Error("No animations defined for layer %d in lump %s", layers.Size(), lumpname); + } + + for (int j = 0; j < anim_size; j++) + { + if (jsonReader.BeginObject(nullptr)) + { + layer.anims.Reserve(1); + auto& anim = layer.anims.back(); + + anim.Reset(); + anim.type = ANIM_FRAME; + anim.ctr = 0; + anim.data = 0; + + ::Serialize(jsonReader, "x", anim.loc.x, nullptr); + ::Serialize(jsonReader, "y", anim.loc.y, nullptr); + + if (!jsonReader.IsKeyNull("conditions") && jsonReader.BeginArray("conditions")) + { + int condition_size = jsonReader.ArraySize(); + if (condition_size == 0) + { + I_Error("Condition array empty and not null for anim %d, layer %d in lump %s", layer.anims.Size(), layers.Size(), lumpname); + } + for (int k = 0; k < condition_size; k++) + { + if (jsonReader.BeginObject(nullptr)) + { + ECondition cond = COND_NONE; + int param = 0; + ::Serialize(jsonReader, "condition", (int&)cond, nullptr); + ::Serialize(jsonReader, "param", param, nullptr); + anim.conditions.Push(condition_t{ cond, param }); + jsonReader.EndObject(); + } + } + jsonReader.EndArray(); + } + + if (jsonReader.BeginArray("frames")) + { + int frames = jsonReader.ArraySize(); + + if (frames == 0) + { + I_Error("No frames defined for anim %d, layer %d in lump %s", layer.anims.Size(), layers.Size(), lumpname); + } + for (int k = 0; k < frames; k++) + { + if (jsonReader.BeginObject(nullptr)) + { + double duration = 0.0; + double maxduration = 0.0; + anim.frames.Reserve(1); + auto& frame = anim.frames.back(); + + ::Serialize(jsonReader, "duration", duration, nullptr); + ::Serialize(jsonReader, "maxduration", maxduration, nullptr); + ::Serialize(jsonReader, "type", frame.type, nullptr); + + FString image = jsonReader.GetString("image"); + if (image.IsEmpty()) + { + I_Error("No image defined for frame %d, anim %d, layer %d in lump %s", anim.frames.Size(), layer.anims.Size(), layers.Size(), lumpname); + } + + frame.image = TexMan.CheckForTexture(image.GetChars(), ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny); + if (!frame.image.isValid()) + { + I_Error("Texture '%s' not found!", image.GetChars()); + } + + frame.duration = round(duration * (double)TICRATE); + frame.max_duration = round(maxduration * (double)TICRATE); + + if (frame.duration <= 0 && duration > 0.0) + { + frame.duration = 1; + } + + if (frame.max_duration <= 0 && maxduration > 0.0) + { + frame.max_duration = 1; + } + + if (anim.frames.Size() == 1) + { + if (frame.type & 0x1000) + { + frame.type &= ~0x1000; + anim.nexttic = 1 + (M_Random() % frame.duration); + } + else + { + + switch (frame.type) + { + case 0x1: + anim.type = ANIM_NONE; + break; + case 0x4: + anim.nexttic = 1 + M_Random(frame.max_duration - frame.duration + 1) + frame.duration; + break; + case 0x2: + anim.nexttic = 1 + frame.duration; + break; + } + } + } + + jsonReader.EndObject(); + } + } + jsonReader.EndArray(); + } + + jsonReader.EndObject(); + } + } + + jsonReader.EndArray(); + } + + jsonReader.EndObject(); + } + } + jsonReader.EndArray(); + } + + jsonReader.EndObject(); + } + jsonReader.Close(); + } + } + // This is deliberate. Errors coming from here shouldn't cause a console abort. + catch (CRecoverableError& error) + { + Printf(TEXTCOLOR_RED "Failed to parse intermission anim definition %s: %s.\nFalling back to non-anim definitions.\n", lumpname, error.GetMessage()); + + if (isenterpic) + li->EnterAnim = ""; + else + li->ExitAnim = ""; + + return LoadBackground(isenterpic); + } + } // a name with a starting '$' indicates an intermission script - if (*lumpname != '$') + else if (*lumpname != '$') { texture = TexMan.CheckForTexture(lumpname, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny); } @@ -520,18 +884,20 @@ bool DInterBackground::LoadBackground(bool isenterpic) if (!sc.CheckString("{")) { sc.MustGetString(); - an.frames.Push(TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny)); + auto textureId = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny); + an.frames.Push(frame_t{ textureId, 0, 0, 0 }); } else { while (!sc.CheckString("}")) { sc.MustGetString(); - an.frames.Push(TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny)); + auto textureId = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny); + an.frames.Push(frame_t{ textureId, 0, 0, 0 }); } } an.ctr = -1; - anims.Push(an); + layers[0].anims.Push(an); break; case 13: // Pic @@ -542,8 +908,8 @@ bool DInterBackground::LoadBackground(bool isenterpic) an.loc.y = sc.Number; sc.MustGetString(); an.frames.Reserve(1); // allocate exactly one element - an.frames[0] = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny); - anims.Push(an); + an.frames[0].image = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny); + layers[0].anims.Push(an); break; default: @@ -554,6 +920,7 @@ bool DInterBackground::LoadBackground(bool isenterpic) } else { + Printf("Intermission script %s not found!\n", lumpname + 1); texture = TexMan.GetTextureID("INTERPIC", ETextureType::MiscPatch); } @@ -585,27 +952,59 @@ void DInterBackground::updateAnimatedBack() unsigned int i; bcnt++; - for (i = 0; itype & ANIM_TYPE) + S_ChangeMusic(muslump.GetChars()); + } + + for (auto& layer : layers) + { + auto& anims = layer.anims; + for (i = 0; i < anims.Size(); i++) { - case ANIM_ALWAYS: - if (bcnt >= a->nexttic) + in_anim_t* a = &anims[i]; + switch (a->type & ANIM_TYPE) { - if (++a->ctr >= (int)a->frames.Size()) + case ANIM_NONE: + break; + + case ANIM_FRAME: + if (bcnt >= a->nexttic) { - if (a->data == 0) a->ctr = 0; - else a->ctr--; + if (++a->ctr >= (int)a->frames.Size()) + a->ctr = 0; + + switch (a->frames[a->ctr].type & 0x7) { + case 0x1: + a->type &= ANIM_CONDITION; + a->type = ANIM_NONE; + break; + case 0x4: + a->nexttic = bcnt + M_Random(a->frames[a->ctr].max_duration - a->frames[a->ctr].duration + 1) + a->frames[a->ctr].duration; + break; + case 0x2: + a->nexttic = bcnt + a->frames[a->ctr].duration; + break; + } } - a->nexttic = bcnt + a->period; + break; + case ANIM_ALWAYS: + if (bcnt >= a->nexttic) + { + if (++a->ctr >= (int)a->frames.Size()) + { + if (a->data == 0) a->ctr = 0; + else a->ctr--; + } + a->nexttic = bcnt + a->period; + } + break; + + case ANIM_PIC: + a->ctr = 0; + break; + } - break; - - case ANIM_PIC: - a->ctr = 0; - break; - } } } @@ -656,51 +1055,59 @@ void DInterBackground::drawBackground(int state, bool drawsplat, bool snl_pointe ClearRect(twod, 0, 0, twod->GetWidth(), twod->GetHeight(), 0, 0); } - for (i = 0; itype & ANIM_CONDITION) + if (!ConditionsMet(state, layer.conditions)) + continue; + + for (i = 0; i < anims.Size(); i++) { - case ANIM_IFVISITED: - li = FindLevelInfo(a->LevelName.GetChars()); - if (li == NULL || !(li->flags & LEVEL_VISITED)) continue; - break; + in_anim_t* a = &anims[i]; + level_info_t* li; - case ANIM_IFNOTVISITED: - li = FindLevelInfo(a->LevelName.GetChars()); - if (li == NULL || (li->flags & LEVEL_VISITED)) continue; - break; + switch (a->type & ANIM_CONDITION) + { + case ANIM_IFVISITED: + li = FindLevelInfo(a->LevelName.GetChars()); + if (li == NULL || !(li->flags & LEVEL_VISITED)) continue; + break; - // StatCount means 'leaving' - everything else means 'entering'! - case ANIM_IFENTERING: - if (state == StatCount || a->LevelName.CompareNoCase(wbs->next, 8)) continue; - break; + case ANIM_IFNOTVISITED: + li = FindLevelInfo(a->LevelName.GetChars()); + if (li == NULL || (li->flags & LEVEL_VISITED)) continue; + break; - case ANIM_IFNOTENTERING: - if (state != StatCount && !a->LevelName.CompareNoCase(wbs->next, 8)) continue; - break; + // StatCount means 'leaving' - everything else means 'entering'! + case ANIM_IFENTERING: + if (state == StatCount || a->LevelName.CompareNoCase(wbs->next, 8)) continue; + break; - case ANIM_IFLEAVING: - if (state != StatCount || a->LevelName.CompareNoCase(wbs->current, 8)) continue; - break; + case ANIM_IFNOTENTERING: + if (state != StatCount && !a->LevelName.CompareNoCase(wbs->next, 8)) continue; + break; - case ANIM_IFNOTLEAVING: - if (state == StatCount && !a->LevelName.CompareNoCase(wbs->current, 8)) continue; - break; + case ANIM_IFLEAVING: + if (state != StatCount || a->LevelName.CompareNoCase(wbs->current, 8)) continue; + break; - case ANIM_IFTRAVELLING: - if (a->LevelName2.CompareNoCase(wbs->current, 8) || a->LevelName.CompareNoCase(wbs->next, 8)) continue; - break; + case ANIM_IFNOTLEAVING: + if (state == StatCount && !a->LevelName.CompareNoCase(wbs->current, 8)) continue; + break; - case ANIM_IFNOTTRAVELLING: - if (!a->LevelName2.CompareNoCase(wbs->current, 8) && !a->LevelName.CompareNoCase(wbs->next, 8)) continue; - break; + case ANIM_IFTRAVELLING: + if (a->LevelName2.CompareNoCase(wbs->current, 8) || a->LevelName.CompareNoCase(wbs->next, 8)) continue; + break; + + case ANIM_IFNOTTRAVELLING: + if (!a->LevelName2.CompareNoCase(wbs->current, 8) && !a->LevelName.CompareNoCase(wbs->next, 8)) continue; + break; + } + if (a->ctr >= 0 && ConditionsMet(state, a->conditions)) + DrawTexture(twod, a->frames[a->ctr].image, false, a->loc.x, a->loc.y, + DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, DTA_FullscreenScale, FSMode_ScaleToFit43, TAG_DONE); } - if (a->ctr >= 0) - DrawTexture(twod, a->frames[a->ctr], false, a->loc.x, a->loc.y, - DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, DTA_FullscreenScale, FSMode_ScaleToFit43, TAG_DONE); } if (drawsplat) @@ -731,6 +1138,23 @@ DEFINE_ACTION_FUNCTION(DInterBackground, drawBackground) return 0; } +//==================================================================== +// +// +// +//==================================================================== + +bool DInterBackground::IsUsingMusic() +{ + return muslump.IsNotEmpty(); +} + +DEFINE_ACTION_FUNCTION(DInterBackground, IsUsingMusic) +{ + PARAM_SELF_PROLOGUE(DInterBackground); + ACTION_RETURN_BOOL(self->IsUsingMusic()); +} + IMPLEMENT_CLASS(DInterBackground, true, false) //==================================================================== diff --git a/wadsrc/static/zscript/ui/statscreen/statscreen.zs b/wadsrc/static/zscript/ui/statscreen/statscreen.zs index 4b50f0cf7..3ae9cf447 100644 --- a/wadsrc/static/zscript/ui/statscreen/statscreen.zs +++ b/wadsrc/static/zscript/ui/statscreen/statscreen.zs @@ -6,6 +6,7 @@ class InterBackground native ui version("2.5") native virtual bool LoadBackground(bool isenterpic); native virtual void updateAnimatedBack(); native virtual void drawBackground(int CurState, bool drawsplat, bool snl_pointeron); + native virtual bool IsUsingMusic(); } // This is obsolete. Hopefully this was never used... @@ -825,7 +826,8 @@ class StatusScreen : ScreenJob abstract version("2.5") virtual void StartMusic() { - Level.SetInterMusic(wbs.next); + if (!bg.IsUsingMusic()) + Level.SetInterMusic(wbs.next); } //==================================================================== From 59b567689a8cc971c43e513fc5ae5a692516b441 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 1 Oct 2024 16:38:14 +0200 Subject: [PATCH 21/40] make the broken ID24 levelnums work somehow so that Legacy of Rust's intermissions play. --- src/gamedata/g_mapinfo.cpp | 4 ++++ src/gamedata/g_mapinfo.h | 1 + src/gamedata/umapinfo.cpp | 14 ++++++++++---- src/wi_stuff.cpp | 4 ++-- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/gamedata/g_mapinfo.cpp b/src/gamedata/g_mapinfo.cpp index 6cd4fdcdf..eb65e6943 100644 --- a/src/gamedata/g_mapinfo.cpp +++ b/src/gamedata/g_mapinfo.cpp @@ -2401,9 +2401,13 @@ static void SetLevelNum (level_info_t *info, int num) for (unsigned int i = 0; i < wadlevelinfos.Size(); ++i) { if (wadlevelinfos[i].levelnum == num) + { wadlevelinfos[i].levelnum = 0; + wadlevelinfos[i].broken_id24_levelnum = 0; + } } info->levelnum = num; + info->broken_id24_levelnum = num; // at least make it work - somehow. } //========================================================================== diff --git a/src/gamedata/g_mapinfo.h b/src/gamedata/g_mapinfo.h index b07e6e442..8b2706ed0 100644 --- a/src/gamedata/g_mapinfo.h +++ b/src/gamedata/g_mapinfo.h @@ -324,6 +324,7 @@ struct FExitText struct level_info_t { int levelnum; + int broken_id24_levelnum; FString MapName; FString NextMap; diff --git a/src/gamedata/umapinfo.cpp b/src/gamedata/umapinfo.cpp index 50757e734..d6a2c47ee 100644 --- a/src/gamedata/umapinfo.cpp +++ b/src/gamedata/umapinfo.cpp @@ -58,6 +58,7 @@ struct UMapEntry char intermusic[9] = ""; int partime = 0; int nointermission = 0; + int id24_levelnum = 0; // note that this one's semantics are massively screwed up. Only to be used for ID24-style intermissions. }; static TArray Maps; @@ -124,7 +125,7 @@ static int ParseLumpName(FScanner &scanner, char *buffer) // // ----------------------------------------------- -static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape) +static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape, int *id24_levelnum) { // find the next line with content. // this line is no property. @@ -254,6 +255,7 @@ static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape) epi.mEpisodeMap = mape->MapName; epi.mPicName = split[0]; epi.mNoSkill = false; + mape->id24_levelnum = *id24_levelnum = 1; unsigned i; for (i = 0; i < AllEpisodes.Size(); i++) @@ -324,15 +326,16 @@ static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape) // // ----------------------------------------------- -static int ParseMapEntry(FScanner &scanner, UMapEntry *val) +static int ParseMapEntry(FScanner &scanner, UMapEntry *val, int *id24_levelnum) { scanner.MustGetToken(TK_Identifier); val->MapName = scanner.String; + val->id24_levelnum = ++(*id24_levelnum); scanner.MustGetToken('{'); while(!scanner.CheckToken('}')) { - ParseStandardProperty(scanner, val); + ParseStandardProperty(scanner, val, id24_levelnum); } return 1; } @@ -348,12 +351,13 @@ int ParseUMapInfo(int lumpnum) FScanner scanner(lumpnum); unsigned int i; + int id24_levelnum = 1; while (scanner.GetToken()) { scanner.TokenMustBe(TK_Map); UMapEntry parsed; - ParseMapEntry(scanner, &parsed); + ParseMapEntry(scanner, &parsed, &id24_levelnum); // Endpic overrides level exits. if (parsed.endpic[0]) @@ -455,6 +459,8 @@ void CommitUMapinfo(level_info_t *defaultinfo) if (map.exitpic[0]) levelinfo->ExitPic = map.exitpic; if (map.enteranim[0]) levelinfo->EnterAnim = map.enteranim; if (map.exitanim[0]) levelinfo->ExitAnim = map.exitanim; + levelinfo->broken_id24_levelnum = map.id24_levelnum; + Printf("%s: id24 levelnum = %d\n", map.MapName, map.id24_levelnum); /* UMAPINFO's intermusic is for the text screen, not the summary. if (map.intermusic[0]) { diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 8a5c7945c..3af0a7829 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -302,7 +302,7 @@ private: auto* li = FindLevelInfo(state != StatCount ? wbs->next.GetChars() : wbs->current.GetChars()); if (!li) return false; - if (li->levelnum != condition.param) + if (li->broken_id24_levelnum != condition.param) return false; break; } @@ -311,7 +311,7 @@ private: auto* li = FindLevelInfo(state != StatCount ? wbs->next.GetChars() : wbs->current.GetChars()); if (!li) return false; - if (li->levelnum <= condition.param) + if (li->broken_id24_levelnum <= condition.param) return false; break; } From f13bc09840c1c215587fba2fd40e22f16a9c076b Mon Sep 17 00:00:00 2001 From: jekyllgrim Date: Mon, 3 Jun 2024 01:47:41 +0300 Subject: [PATCH 22/40] Add bIsPuff flag --- src/playsim/actor.h | 1 + src/playsim/p_mobj.cpp | 3 +++ src/scripting/thingdef_data.cpp | 1 + 3 files changed, 5 insertions(+) diff --git a/src/playsim/actor.h b/src/playsim/actor.h index a96e7f316..ebdfeebaa 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -444,6 +444,7 @@ enum ActorFlag9 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_NOSECTORDAMAGE = 0x00000020, // [inkoalawetrust] Actor ignores any sector-based damage (i.e damaging floors, NOT crushers) + MF9_ISPUFF = 0x00000020, // [AA] Set on actors by P_SpawnPuff }; // --- mobj.renderflags --- diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index e39db44cb..e004c4a46 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -6289,6 +6289,9 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, const DVector3 &pos1 // Angle is the opposite of the hit direction (i.e. the puff faces the source.) puff->Angles.Yaw = hitdir + DAngle::fromDeg(180); + // [AA] Mark the spawned actor as a puff with a flag. + puff->flags9 |= MF9_ISPUFF; + // If a puff has a crash state and an actor was not hit, // it will enter the crash state. This is used by the StrifeSpark // and BlasterPuff. diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index bc62f2250..b8cfd8d74 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -354,6 +354,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF9, SHADOWAIMVERT, AActor, flags9), DEFINE_FLAG(MF9, DECOUPLEDANIMATIONS, AActor, flags9), DEFINE_FLAG(MF9, NOSECTORDAMAGE, AActor, flags9), + DEFINE_FLAG(MF9, ISPUFF, AActor, flags9), //[AA] was spawned by SpawnPuff // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), From 83165dccbf345172464c677391b2dc530f277e1e Mon Sep 17 00:00:00 2001 From: jekyllgrim Date: Mon, 3 Jun 2024 12:25:12 +0300 Subject: [PATCH 23/40] Add damagesource --- src/playsim/actor.h | 1 + src/playsim/p_mobj.cpp | 4 ++++ src/scripting/vmthunks_actors.cpp | 1 + wadsrc/static/zscript/actors/actor.zs | 1 + 4 files changed, 7 insertions(+) diff --git a/src/playsim/actor.h b/src/playsim/actor.h index ebdfeebaa..34e5d7110 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -1233,6 +1233,7 @@ public: TObjPtr alternative; // (Un)Morphed actors stored here. Those with the MF_UNMORPHED flag are the originals. TObjPtr tracer; // Thing being chased/attacked for tracers TObjPtr master; // Thing which spawned this one (prevents mutual attacks) + TObjPtr damagesource; // [AA] Thing that fired a hitscan using this actor as a puff int tid; // thing identifier int special; // special diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index e004c4a46..df6661871 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -168,6 +168,7 @@ IMPLEMENT_POINTERS_START(AActor) IMPLEMENT_POINTER(target) IMPLEMENT_POINTER(lastenemy) IMPLEMENT_POINTER(tracer) + IMPLEMENT_POINTER(damagesource) IMPLEMENT_POINTER(goal) IMPLEMENT_POINTER(LastLookActor) IMPLEMENT_POINTER(Inventory) @@ -6286,6 +6287,9 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, const DVector3 &pos1 if ( puff && (puff->flags5 & MF5_PUFFGETSOWNER)) puff->target = source; + // [AA] Track the source of the attack unconditionally in a separate field. + puff->damagesource = source; + // Angle is the opposite of the hit direction (i.e. the puff faces the source.) puff->Angles.Yaw = hitdir + DAngle::fromDeg(180); diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index 53fc0a062..527bd9178 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -2005,6 +2005,7 @@ DEFINE_FIELD(AActor, strafecount) DEFINE_FIELD(AActor, target) DEFINE_FIELD(AActor, master) DEFINE_FIELD(AActor, tracer) +DEFINE_FIELD(AActor, damagesource) DEFINE_FIELD(AActor, LastHeard) DEFINE_FIELD(AActor, lastenemy) DEFINE_FIELD(AActor, LastLookActor) diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 7a9a53929..eebfbe329 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -148,6 +148,7 @@ class Actor : Thinker native native Actor Target; native Actor Master; native Actor Tracer; + native Actor DamageSource; native Actor LastHeard; native Actor LastEnemy; native Actor LastLookActor; From f8b68a692768a3eb91b9a4c49fef473aa6255d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Mon, 3 Jun 2024 10:37:25 -0300 Subject: [PATCH 24/40] Serialize damagesource, fix bad character in actor.zs --- src/playsim/p_mobj.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index df6661871..e863445f2 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -401,7 +401,8 @@ void AActor::Serialize(FSerializer &arc) ("unmorphtime", UnmorphTime) ("morphflags", MorphFlags) ("premorphproperties", PremorphProperties) - ("morphexitflash", MorphExitFlash); + ("morphexitflash", MorphExitFlash) + ("damagesource", damagesource); SerializeTerrain(arc, "floorterrain", floorterrain, &def->floorterrain); From 1392db2f5bd9e821aefcb174a7438592c8633d43 Mon Sep 17 00:00:00 2001 From: jekyllgrim Date: Mon, 30 Sep 2024 16:00:44 +0300 Subject: [PATCH 25/40] Made DamageSource and bIsPuff readonly --- src/scripting/thingdef_data.cpp | 2 +- wadsrc/static/zscript/actors/actor.zs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index b8cfd8d74..cc97b1a2d 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -354,7 +354,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF9, SHADOWAIMVERT, AActor, flags9), DEFINE_FLAG(MF9, DECOUPLEDANIMATIONS, AActor, flags9), DEFINE_FLAG(MF9, NOSECTORDAMAGE, AActor, flags9), - DEFINE_FLAG(MF9, ISPUFF, AActor, flags9), //[AA] was spawned by SpawnPuff + DEFINE_PROTECTED_FLAG(MF9, ISPUFF, AActor, flags9), //[AA] was spawned by SpawnPuff // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index eebfbe329..cae1d161b 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -148,7 +148,7 @@ class Actor : Thinker native native Actor Target; native Actor Master; native Actor Tracer; - native Actor DamageSource; + native readonly Actor DamageSource; native Actor LastHeard; native Actor LastEnemy; native Actor LastLookActor; From 70ec8ce71198f71a3cb27f44b5653d5b3a1bcc2a Mon Sep 17 00:00:00 2001 From: jekyllgrim Date: Tue, 1 Oct 2024 12:30:22 +0300 Subject: [PATCH 26/40] Fixed MF9_ISPUFF overlapping with MF9_NOSECTORDAMAGE --- src/playsim/actor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 34e5d7110..c83a7f229 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -444,7 +444,7 @@ enum ActorFlag9 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_NOSECTORDAMAGE = 0x00000020, // [inkoalawetrust] Actor ignores any sector-based damage (i.e damaging floors, NOT crushers) - MF9_ISPUFF = 0x00000020, // [AA] Set on actors by P_SpawnPuff + MF9_ISPUFF = 0x00000040, // [AA] Set on actors by P_SpawnPuff }; // --- mobj.renderflags --- From 9f7a8188c573ae415c017db9b564c152fa6442e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Tue, 1 Oct 2024 11:59:05 -0300 Subject: [PATCH 27/40] Fix broken if statement in ParseFireTexture --- src/gamedata/textures/animations.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gamedata/textures/animations.cpp b/src/gamedata/textures/animations.cpp index 7b7a1049b..b0dce0a55 100644 --- a/src/gamedata/textures/animations.cpp +++ b/src/gamedata/textures/animations.cpp @@ -832,8 +832,10 @@ void FTextureAnimator::ParseFireTexture(FScanner& sc) sc.MustGetValue(false); a = sc.Number; palette.Push(PalEntry(a, r, g, b)); - if (a != 255 && a != 0); + if (a != 255 && a != 0) + { gametex->SetTranslucent(true); + } if (palette.Size() > 256) { From 896c73b1e5aa968e679ba102a4b40b1abcbef7e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Tue, 1 Oct 2024 12:05:49 -0300 Subject: [PATCH 28/40] Fix compilation --- src/gamedata/umapinfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gamedata/umapinfo.cpp b/src/gamedata/umapinfo.cpp index d6a2c47ee..5582c29d4 100644 --- a/src/gamedata/umapinfo.cpp +++ b/src/gamedata/umapinfo.cpp @@ -460,7 +460,7 @@ void CommitUMapinfo(level_info_t *defaultinfo) if (map.enteranim[0]) levelinfo->EnterAnim = map.enteranim; if (map.exitanim[0]) levelinfo->ExitAnim = map.exitanim; levelinfo->broken_id24_levelnum = map.id24_levelnum; - Printf("%s: id24 levelnum = %d\n", map.MapName, map.id24_levelnum); + Printf("%s: id24 levelnum = %d\n", map.MapName.GetChars(), map.id24_levelnum); /* UMAPINFO's intermusic is for the text screen, not the summary. if (map.intermusic[0]) { From d455f57346a681938ce59240eb3fc2f38c57118e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 1 Oct 2024 17:28:42 +0200 Subject: [PATCH 29/40] remove test code. --- src/gamedata/umapinfo.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gamedata/umapinfo.cpp b/src/gamedata/umapinfo.cpp index 5582c29d4..e5de4fbec 100644 --- a/src/gamedata/umapinfo.cpp +++ b/src/gamedata/umapinfo.cpp @@ -460,7 +460,6 @@ void CommitUMapinfo(level_info_t *defaultinfo) if (map.enteranim[0]) levelinfo->EnterAnim = map.enteranim; if (map.exitanim[0]) levelinfo->ExitAnim = map.exitanim; levelinfo->broken_id24_levelnum = map.id24_levelnum; - Printf("%s: id24 levelnum = %d\n", map.MapName.GetChars(), map.id24_levelnum); /* UMAPINFO's intermusic is for the text screen, not the summary. if (map.intermusic[0]) { From 2decf10863d6a44b69b747a431babb20885df0c1 Mon Sep 17 00:00:00 2001 From: Professor Hastig Date: Tue, 1 Oct 2024 14:35:27 +0200 Subject: [PATCH 30/40] add missing 'author' and 'label' UMAPINFO fields. --- src/gamedata/g_mapinfo.cpp | 8 ++++++++ src/gamedata/g_mapinfo.h | 1 + src/gamedata/umapinfo.cpp | 20 ++++++++++++++++++++ src/scripting/vmthunks.cpp | 8 +++++++- wadsrc/static/zscript/doombase.zs | 1 + 5 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/gamedata/g_mapinfo.cpp b/src/gamedata/g_mapinfo.cpp index eb65e6943..22981062b 100644 --- a/src/gamedata/g_mapinfo.cpp +++ b/src/gamedata/g_mapinfo.cpp @@ -268,6 +268,7 @@ void level_info_t::Reset() Music = ""; LevelName = ""; AuthorName = ""; + MapLabel = ""; FadeTable = "COLORMAP"; CustomColorMap = "COLORMAP"; WallHorizLight = -8; @@ -1028,6 +1029,13 @@ DEFINE_MAP_OPTION(author, true) info->AuthorName = parse.sc.String; } +DEFINE_MAP_OPTION(label, true) +{ + parse.ParseAssign(); + parse.sc.MustGetString(); + info->MapLabel = parse.sc.String; +} + DEFINE_MAP_OPTION(secretnext, true) { parse.ParseAssign(); diff --git a/src/gamedata/g_mapinfo.h b/src/gamedata/g_mapinfo.h index 8b2706ed0..5d3309f4a 100644 --- a/src/gamedata/g_mapinfo.h +++ b/src/gamedata/g_mapinfo.h @@ -350,6 +350,7 @@ struct level_info_t FString LightningSound = "world/thunder"; FString Music; FString LevelName; + FString MapLabel; FString AuthorName; int8_t WallVertLight, WallHorizLight; int musicorder; diff --git a/src/gamedata/umapinfo.cpp b/src/gamedata/umapinfo.cpp index e5de4fbec..9ba72e61b 100644 --- a/src/gamedata/umapinfo.cpp +++ b/src/gamedata/umapinfo.cpp @@ -41,6 +41,8 @@ struct UMapEntry FString LevelName; FString InterText; FString InterTextSecret; + FString author; + FString label; TArray BossActions; bool BossCleared = false; @@ -139,6 +141,16 @@ static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape, int *id24_l scanner.MustGetToken(TK_StringConst); mape->LevelName = scanner.String; } + else if (!pname.CompareNoCase("author")) + { + scanner.MustGetToken(TK_StringConst); + mape->author = scanner.String; + } + else if (!pname.CompareNoCase("label")) + { + scanner.MustGetToken(TK_StringConst); + mape->label = scanner.String; + } else if (!pname.CompareNoCase("next")) { ParseLumpName(scanner, mape->nextmap); @@ -417,6 +429,14 @@ void CommitUMapinfo(level_info_t *defaultinfo) levelinfo->LevelName = map.LevelName; levelinfo->PName = ""; // clear the map name patch to force the string version to be shown - unless explicitly overridden right next. } + if (map.author.IsNotEmpty()) + { + levelinfo->AuthorName = map.author; + } + if (map.label.IsNotEmpty()) + { + levelinfo->MapLabel = map.label; + } if (map.levelpic[0]) levelinfo->PName = map.levelpic; if (map.nextmap[0]) levelinfo->NextMap = map.nextmap; else if (map.endpic[0]) diff --git a/src/scripting/vmthunks.cpp b/src/scripting/vmthunks.cpp index 4cc048843..3153a4eab 100644 --- a/src/scripting/vmthunks.cpp +++ b/src/scripting/vmthunks.cpp @@ -2263,7 +2263,12 @@ void FormatMapName(FLevelLocals *self, int cr, FString *result) bool ishub = (cluster != nullptr && (cluster->flags & CLUSTER_HUB)); *result = ""; - if (am_showmaplabel == 1 || (am_showmaplabel == 2 && !ishub)) + // If a label is specified, use it uncontitionally here. + if (self->info->MapLabel.IsNotEmpty()) + { + *result << self->info->MapLabel << ": "; + } + else if (am_showmaplabel == 1 || (am_showmaplabel == 2 && !ishub)) { *result << self->MapName << ": "; } @@ -2767,6 +2772,7 @@ DEFINE_FIELD_X(LevelInfo, level_info_t, Music) DEFINE_FIELD_X(LevelInfo, level_info_t, LightningSound) DEFINE_FIELD_X(LevelInfo, level_info_t, LevelName) DEFINE_FIELD_X(LevelInfo, level_info_t, AuthorName) +DEFINE_FIELD_X(LevelInfo, level_info_t, MapLabel) DEFINE_FIELD_X(LevelInfo, level_info_t, musicorder) DEFINE_FIELD_X(LevelInfo, level_info_t, skyspeed1) DEFINE_FIELD_X(LevelInfo, level_info_t, skyspeed2) diff --git a/wadsrc/static/zscript/doombase.zs b/wadsrc/static/zscript/doombase.zs index 54c44f821..1ef97188c 100644 --- a/wadsrc/static/zscript/doombase.zs +++ b/wadsrc/static/zscript/doombase.zs @@ -345,6 +345,7 @@ struct LevelInfo native native readonly String LightningSound; native readonly String Music; native readonly String LevelName; + native readonly String MapLabel; native readonly String AuthorName; native readonly int musicorder; native readonly float skyspeed1; From ad4eef3b6c7806680032b95d95f199b5febb7e64 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Tue, 1 Oct 2024 17:38:29 -0400 Subject: [PATCH 31/40] - SPAC_Walking should check for SPAC_MCross not SPAC_PCross --- src/playsim/p_spec.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playsim/p_spec.cpp b/src/playsim/p_spec.cpp index 3ee5fe871..9c3fde6f4 100644 --- a/src/playsim/p_spec.cpp +++ b/src/playsim/p_spec.cpp @@ -254,7 +254,7 @@ bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType, return false; } - if ((activationType & (SPAC_Cross|SPAC_PCross)) && (lineActivation & SPAC_Walking)) + if ((activationType & (SPAC_Cross|SPAC_MCross)) && (lineActivation & SPAC_Walking)) { // not on floor if ((mo->Pos().Z > mo->floorz) && !(mo->flags2 & MF2_ONMOBJ)) From 8354c4a5c360460cbcc53e141da32ec2684601e4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 3 Oct 2024 12:24:16 +0200 Subject: [PATCH 32/40] Replaced MISSILE(EVEN)MORE with a real property and added related Dehacked options from Crispy Doom. This also adds proper deprecation messages to the deprecated flags which were missing due to a bad definition macro. --- src/gamedata/d_dehacked.cpp | 30 ++++++- src/playsim/actor.h | 5 +- src/playsim/p_enemy.cpp | 3 +- src/playsim/p_mobj.cpp | 1 + src/scripting/decorate/thingdef_parse.cpp | 2 +- src/scripting/thingdef.h | 8 +- src/scripting/thingdef_data.cpp | 36 +++++---- src/scripting/thingdef_properties.cpp | 81 +++++++++++++------ src/scripting/vmthunks_actors.cpp | 1 + src/scripting/zscript/zcc_compile_doom.cpp | 7 +- wadsrc/static/zscript/actors/actor.zs | 2 + .../static/zscript/actors/doom/cyberdemon.zs | 2 +- wadsrc/static/zscript/actors/doom/lostsoul.zs | 3 +- wadsrc/static/zscript/actors/doom/revenant.zs | 2 +- .../zscript/actors/doom/spidermaster.zs | 2 +- .../zscript/actors/heretic/hereticimp.zs | 4 +- .../static/zscript/actors/strife/acolyte.zs | 14 ++-- .../static/zscript/actors/strife/crusader.zs | 2 +- .../static/zscript/actors/strife/sentinel.zs | 2 +- 19 files changed, 138 insertions(+), 69 deletions(-) diff --git a/src/gamedata/d_dehacked.cpp b/src/gamedata/d_dehacked.cpp index 77e9d1320..e10f78dfb 100644 --- a/src/gamedata/d_dehacked.cpp +++ b/src/gamedata/d_dehacked.cpp @@ -1153,7 +1153,7 @@ static const struct DehFlags2 deh_mobjflags_mbf21[] = { {"NORADIUSDMG", [](AActor* defaults) { defaults->flags3 |= MF3_NORADIUSDMG; }}, // doesn't take splash damage {"FORCERADIUSDMG", [](AActor* defaults) { defaults->flags4 |= MF4_FORCERADIUSDMG; }}, // causes splash damage even if target immune {"HIGHERMPROB", [](AActor* defaults) { defaults->MinMissileChance = 160; }}, // higher missile attack probability - {"RANGEHALF", [](AActor* defaults) { defaults->flags4 |= MF4_MISSILEMORE; }}, // use half distance for missile attack probability + {"RANGEHALF", [](AActor* defaults) { defaults->missilechancemult = 0.5; }}, // use half distance for missile attack probability {"NOTHRESHOLD", [](AActor* defaults) { defaults->flags4 |= MF4_QUICKTORETALIATE; }}, // no targeting threshold {"LONGMELEE", [](AActor* defaults) { defaults->meleethreshold = 196; }}, // long melee range {"BOSS", [](AActor* defaults) { defaults->flags2 |= MF2_BOSS; defaults->flags3 |= MF3_NORADIUSDMG; }}, // full volume see / death sound + splash immunity @@ -1174,9 +1174,10 @@ static void ClearBits2Stuff(AActor* defaults) defaults->maxtargetrange = 0; defaults->MinMissileChance = 200; defaults->meleethreshold = 0; + defaults->missilechancemult = 1; defaults->flags2 &= ~(MF2_BOSS | MF2_RIP); defaults->flags3 &= ~(MF3_NOTARGET | MF3_NORADIUSDMG | MF3_FULLVOLDEATH); - defaults->flags4 &= ~(MF4_MISSILEMORE | MF4_QUICKTORETALIATE | MF4_FORCERADIUSDMG); + defaults->flags4 &= ~(MF4_QUICKTORETALIATE | MF4_FORCERADIUSDMG); defaults->flags8 &= ~(MF8_E1M8BOSS | MF8_E2M8BOSS | MF8_E3M8BOSS | MF8_E4M8BOSS | MF8_E4M6BOSS | MF8_MAP07BOSS1 | MF8_MAP07BOSS2 | MF8_FULLVOLSEE); } @@ -1437,6 +1438,27 @@ static int PatchThing (int thingy, int flags) } DPrintf(DMSG_SPAMMY, "MBF21 Bits: %d (0x%08x)\n", info->flags.GetValue(), info->flags.GetValue()); } + // New fields from Crispy Doom + else if (!stricmp(Line1, "Melee threshold")) + { + info->meleethreshold = DEHToDouble(val); + } + else if (!stricmp(Line1, "Max target range")) + { + // [crispy] Maximum distance range to start shooting (zero for unlimited) + info->maxtargetrange = DEHToDouble(val); + } + else if (!stricmp(Line1, "Min missile chance")) + { + // [crispy] Minimum chance for firing a missile + info->MinMissileChance = DEHToDouble(val); + } + else if (!stricmp(Line1, "Missile chance multiplier")) + { + // [crispy] Multiplies the chance of firing a missile (65536 = normal chance) + info->missilechancemult = DEHToDouble(val); + } + else if (linelen > 6) { if (stricmp (Line1 + linelen - 6, " frame") == 0) @@ -3861,7 +3883,7 @@ struct FlagHandler #define F4(flag) { [](AActor* a) { a->flags4 |= flag; }, [](AActor* a) { a->flags4 &= ~flag; }, [](AActor* a)->bool { return a->flags4 & flag; } } #define F6(flag) { [](AActor* a) { a->flags6 |= flag; }, [](AActor* a) { a->flags6 &= ~flag; }, [](AActor* a)->bool { return a->flags6 & flag; } } #define F8(flag) { [](AActor* a) { a->flags8 |= flag; }, [](AActor* a) { a->flags8 &= ~flag; }, [](AActor* a)->bool { return a->flags8 & flag; } } -#define DEPF(flag) { [](AActor* a) { HandleDeprecatedFlags(a, nullptr, true, flag); }, [](AActor* a) { HandleDeprecatedFlags(a, nullptr, false, flag); }, [](AActor* a)->bool { return CheckDeprecatedFlags(a, nullptr, flag); } } +#define DEPF(flag) { [](AActor* a) { HandleDeprecatedFlags(a, true, flag); }, [](AActor* a) { HandleDeprecatedFlags(a, false, flag); }, [](AActor* a)->bool { return !!CheckDeprecatedFlags(a, flag); } } void SetNoSector(AActor* a) { @@ -4112,7 +4134,7 @@ static FlagHandler flag2handlers[32] = { F3(MF3_NORADIUSDMG), F4(MF4_FORCERADIUSDMG), DEPF(DEPF_HIGHERMPROB), - F4(MF4_MISSILEMORE), + DEPF(DEPF_MISSILEMORE), F4(MF4_QUICKTORETALIATE), DEPF(DEPF_LONGMELEERANGE), { SetBoss, ClearBoss, [](AActor* a)->bool { return a->flags2 & MF2_BOSS; } }, diff --git a/src/playsim/actor.h b/src/playsim/actor.h index c83a7f229..daa60f45f 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -262,8 +262,8 @@ enum ActorFlag4 MF4_STRIFEDAMAGE = 0x00000100, // Strife projectiles only do up to 4x damage, not 8x MF4_CANUSEWALLS = 0x00000200, // Can activate 'use' specials - MF4_MISSILEMORE = 0x00000400, // increases the chance of a missile attack - MF4_MISSILEEVENMORE = 0x00000800, // significantly increases the chance of a missile attack + // = 0x00000400, + // = 0x00000800, MF4_FORCERADIUSDMG = 0x00001000, // if put on an object it will override MF3_NORADIUSDMG MF4_DONTFALL = 0x00002000, // Doesn't have NOGRAVITY disabled when dying. MF4_SEESDAGGERS = 0x00004000, // This actor can see you striking with a dagger @@ -1255,6 +1255,7 @@ public: // but instead tries to come closer for a melee attack. // This is not the same as meleerange double maxtargetrange; // any target farther away cannot be attacked + double missilechancemult; // distance multiplier for CheckMeleeRange, formerly done with MISSILE(EVEN)MORE flags. double bouncefactor; // Strife's grenades use 50%, Hexen's Flechettes 70. double wallbouncefactor; // The bounce factor for walls can be different. double Gravity; // [GRB] Gravity factor diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index 1d49f4b3a..55f501488 100644 --- a/src/playsim/p_enemy.cpp +++ b/src/playsim/p_enemy.cpp @@ -373,8 +373,7 @@ static int P_CheckMissileRange (AActor *actor) if (actor->MeleeState != nullptr && dist < actor->meleethreshold) return false; // From the Revenant: close enough for fist attack - if (actor->flags4 & MF4_MISSILEMORE) dist *= 0.5; - if (actor->flags4 & MF4_MISSILEEVENMORE) dist *= 0.125; + dist *= actor->missilechancemult; int mmc = int(actor->MinMissileChance * G_SkillProperty(SKILLP_Aggressiveness)); return pr_checkmissilerange() >= min(int(dist), mmc); diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index e863445f2..0cbcb813b 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -320,6 +320,7 @@ void AActor::Serialize(FSerializer &arc) A("wallbouncefactor", wallbouncefactor) A("bouncecount", bouncecount) A("maxtargetrange", maxtargetrange) + A("missilechancemult", missilechancemult) A("meleethreshold", meleethreshold) A("meleerange", meleerange) A("damagetype", DamageType) diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index a1cc7702e..19c8f38ab 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -475,7 +475,7 @@ void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char * AActor *defaults = (AActor*)bag.Info->Defaults; if (fd->structoffset == -1) // this is a deprecated flag that has been changed into a real property { - HandleDeprecatedFlags(defaults, bag.Info, mod=='+', fd->flagbit); + HandleDeprecatedFlags(defaults, mod=='+', fd->flagbit); } else { diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 34cd34666..f12cca99d 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -66,12 +66,13 @@ struct FFlagDef int structoffset; int fieldsize; int varflags; + VersionInfo deprecationVersion; }; void FinalizeClass(PClass *cls, FStateDefinitions &statedef); FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2, bool strict = false); -void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int index); -bool CheckDeprecatedFlags(AActor *actor, PClassActor *info, int index); +void HandleDeprecatedFlags(AActor *defaults, int set, int index); +int CheckDeprecatedFlags(AActor *actor, int index); const char *GetFlagName(unsigned int flagnum, int flagoffset); void ModActorFlag(AActor *actor, FFlagDef *fd, bool set); bool ModActorFlag(AActor *actor, const FString &flagname, bool set, bool printerror = true); @@ -229,6 +230,9 @@ enum DEPF_DOOMBOUNCE = 11, DEPF_INTERHUBSTRIP = 12, DEPF_HIGHERMPROB = 13, + // all that follow need ZScript emulation! + DEPF_MISSILEMORE = 14, + DEPF_MISSILEEVENMORE = 15 }; // Types of old style decorations diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index cc97b1a2d..8f19bab54 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -75,8 +75,8 @@ extern float BackbuttonAlpha; #define DEFINE_FLAG(prefix, name, type, variable) { (unsigned int)prefix##_##name, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native } #define DEFINE_PROTECTED_FLAG(prefix, name, type, variable) { (unsigned int)prefix##_##name, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native|VARF_ReadOnly|VARF_InternalAccess } #define DEFINE_FLAG2(symbol, name, type, variable) { (unsigned int)symbol, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native } -#define DEFINE_FLAG2_DEPRECATED(symbol, name, type, variable) { (unsigned int)symbol, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native|VARF_Deprecated } -#define DEFINE_DEPRECATED_FLAG(name) { DEPF_##name, #name, -1, 0, true } +#define DEFINE_FLAG2_DEPRECATED(symbol, name, type, variable, version) { (unsigned int)symbol, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native|VARF_Deprecated } +#define DEFINE_DEPRECATED_FLAG(name, version) { DEPF_##name, #name, -1, 0, VARF_Deprecated, version } #define DEFINE_DUMMY_FLAG(name, deprec) { DEPF_UNUSED, #name, -1, 0, deprec? VARF_Deprecated:0 } // internal flags. These do not get exposed to actor definitions but scripts need to be able to access them as variables. @@ -210,8 +210,6 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF4, ACTLIKEBRIDGE, AActor, flags4), DEFINE_FLAG(MF4, STRIFEDAMAGE, AActor, flags4), DEFINE_FLAG(MF4, CANUSEWALLS, AActor, flags4), - DEFINE_FLAG(MF4, MISSILEMORE, AActor, flags4), - DEFINE_FLAG(MF4, MISSILEEVENMORE, AActor, flags4), DEFINE_FLAG(MF4, FORCERADIUSDMG, AActor, flags4), DEFINE_FLAG(MF4, DONTFALL, AActor, flags4), DEFINE_FLAG(MF4, SEESDAGGERS, AActor, flags4), @@ -410,6 +408,11 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG2(BOUNCE_NotOnSky, DONTBOUNCEONSKY, AActor, BounceFlags), DEFINE_FLAG2(OF_Transient, NOSAVEGAME, AActor, ObjectFlags), + + // Deprecated flags which need a ZScript workaround. + DEFINE_DEPRECATED_FLAG(MISSILEMORE, MakeVersion(4, 13, 0)), + DEFINE_DEPRECATED_FLAG(MISSILEEVENMORE, MakeVersion(4, 13, 0)), + }; // These won't be accessible through bitfield variables @@ -417,24 +420,25 @@ static FFlagDef MoreFlagDefs[] = { // Deprecated flags. Handling must be performed in HandleDeprecatedFlags - DEFINE_DEPRECATED_FLAG(FIREDAMAGE), - DEFINE_DEPRECATED_FLAG(ICEDAMAGE), - DEFINE_DEPRECATED_FLAG(LOWGRAVITY), - DEFINE_DEPRECATED_FLAG(SHORTMISSILERANGE), - DEFINE_DEPRECATED_FLAG(LONGMELEERANGE), - DEFINE_DEPRECATED_FLAG(QUARTERGRAVITY), - DEFINE_DEPRECATED_FLAG(FIRERESIST), - DEFINE_DEPRECATED_FLAG(HERETICBOUNCE), - DEFINE_DEPRECATED_FLAG(HEXENBOUNCE), - DEFINE_DEPRECATED_FLAG(DOOMBOUNCE), - DEFINE_DEPRECATED_FLAG(HIGHERMPROB), + // Note: Although deprecated since DECORATE times, they were never actually flagged as deprecated before 4.13.0 and no message was output... + DEFINE_DEPRECATED_FLAG(FIREDAMAGE, MakeVersion(4, 13, 0)), + DEFINE_DEPRECATED_FLAG(ICEDAMAGE, MakeVersion(4, 13, 0)), + DEFINE_DEPRECATED_FLAG(LOWGRAVITY, MakeVersion(4, 13, 0)), + DEFINE_DEPRECATED_FLAG(SHORTMISSILERANGE, MakeVersion(4, 13, 0)), + DEFINE_DEPRECATED_FLAG(LONGMELEERANGE, MakeVersion(4, 13, 0)), + DEFINE_DEPRECATED_FLAG(QUARTERGRAVITY, MakeVersion(4, 13, 0)), + DEFINE_DEPRECATED_FLAG(FIRERESIST, MakeVersion(4, 13, 0)), + DEFINE_DEPRECATED_FLAG(HERETICBOUNCE, MakeVersion(4, 13, 0)), + DEFINE_DEPRECATED_FLAG(HEXENBOUNCE, MakeVersion(4, 13, 0)), + DEFINE_DEPRECATED_FLAG(DOOMBOUNCE, MakeVersion(4, 13, 0)), + DEFINE_DEPRECATED_FLAG(HIGHERMPROB, MakeVersion(4, 13, 0)), // Deprecated flags with no more existing functionality. DEFINE_DUMMY_FLAG(FASTER, true), // obsolete, replaced by 'Fast' state flag DEFINE_DUMMY_FLAG(FASTMELEE, true), // obsolete, replaced by 'Fast' state flag // Deprecated name as an alias - DEFINE_FLAG2_DEPRECATED(MF4_DONTHARMCLASS, DONTHURTSPECIES, AActor, flags4), + DEFINE_FLAG2_DEPRECATED(MF4_DONTHARMCLASS, DONTHURTSPECIES, AActor, flags4, 0), // Various Skulltag flags that are quite irrelevant to ZDoom // [BC] New DECORATE flag defines here. diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index f6cd07335..4969765a7 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -176,7 +176,7 @@ bool ModActorFlag(AActor *actor, const FString &flagname, bool set, bool printer if (fd->structoffset == -1) { - HandleDeprecatedFlags(actor, cls, set, fd->flagbit); + HandleDeprecatedFlags(actor, set, fd->flagbit); } else { @@ -214,7 +214,7 @@ INTBOOL CheckActorFlag(AActor *owner, FFlagDef *fd) { if (fd->structoffset == -1) { - return CheckDeprecatedFlags(owner, owner->GetClass(), fd->flagbit); + return CheckDeprecatedFlags(owner, fd->flagbit); } else #ifdef __BIG_ENDIAN__ @@ -270,65 +270,92 @@ INTBOOL CheckActorFlag(AActor *owner, const char *flagname, bool printerror) // Handles the deprecated flags and sets the respective properties // to appropriate values. This is solely intended for backwards // compatibility so mixing this with code that is aware of the real -// properties is not recommended +// properties is not recommended and may not do what is expected // //=========================================================================== -void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int index) +void HandleDeprecatedFlags(AActor *actor, int set, int index) { switch (index) { case DEPF_FIREDAMAGE: - defaults->DamageType = set? NAME_Fire : NAME_None; + actor->DamageType = set? NAME_Fire : NAME_None; break; case DEPF_ICEDAMAGE: - defaults->DamageType = set? NAME_Ice : NAME_None; + actor->DamageType = set? NAME_Ice : NAME_None; break; case DEPF_LOWGRAVITY: - defaults->Gravity = set ? 1. / 8 : 1.; + actor->Gravity = set ? 1. / 8 : 1.; break; case DEPF_SHORTMISSILERANGE: - defaults->maxtargetrange = set? 896. : 0.; + actor->maxtargetrange = set? 896. : 0.; break; case DEPF_LONGMELEERANGE: - defaults->meleethreshold = set? 196. : 0.; + actor->meleethreshold = set? 196. : 0.; break; case DEPF_QUARTERGRAVITY: - defaults->Gravity = set ? 1. / 4 : 1.; + actor->Gravity = set ? 1. / 4 : 1.; break; case DEPF_FIRERESIST: - info->SetDamageFactor(NAME_Fire, set ? 0.5 : 1.); + actor->GetClass()->SetDamageFactor(NAME_Fire, set ? 0.5 : 1.); break; // the bounce flags will set the compatibility bounce modes to remain compatible case DEPF_HERETICBOUNCE: - defaults->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound); - if (set) defaults->BounceFlags |= BOUNCE_HereticCompat; + actor->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound); + if (set) actor->BounceFlags |= BOUNCE_HereticCompat; break; case DEPF_HEXENBOUNCE: - defaults->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound); - if (set) defaults->BounceFlags |= BOUNCE_HexenCompat; + actor->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound); + if (set) actor->BounceFlags |= BOUNCE_HexenCompat; break; case DEPF_DOOMBOUNCE: - defaults->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound); - if (set) defaults->BounceFlags |= BOUNCE_DoomCompat; + actor->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound); + if (set) actor->BounceFlags |= BOUNCE_DoomCompat; break; case DEPF_PICKUPFLASH: if (set) { - defaults->PointerVar(NAME_PickupFlash) = FindClassTentative("PickupFlash", RUNTIME_CLASS(AActor)); + actor->PointerVar(NAME_PickupFlash) = FindClassTentative("PickupFlash", RUNTIME_CLASS(AActor)); } else { - defaults->PointerVar(NAME_PickupFlash) = nullptr; + actor->PointerVar(NAME_PickupFlash) = nullptr; } break; case DEPF_INTERHUBSTRIP: // Old system was 0 or 1, so if the flag is cleared, assume 1. - defaults->IntVar(NAME_InterHubAmount) = set ? 0 : 1; + actor->IntVar(NAME_InterHubAmount) = set ? 0 : 1; break; case DEPF_HIGHERMPROB: - defaults->MinMissileChance = set ? 160 : 200; + actor->MinMissileChance = set ? 160 : 200; break; + case DEPF_MISSILEMORE: + if (set) + { + if (actor->missilechancemult == 0.125) actor->missilechancemult = 0.0625; + else actor->missilechancemult = 0.5; + } + else + { + if (actor->missilechancemult == 0.0625) actor->missilechancemult = 0.125; + else actor->missilechancemult = 1; + } + break; + + case DEPF_MISSILEEVENMORE: + if (set) + { + if (actor->missilechancemult == 0.5) actor->missilechancemult = 0.0625; + else actor->missilechancemult = 0.125; + } + else + { + if (actor->missilechancemult == 0.0625) actor->missilechancemult = 0.5; + else actor->missilechancemult = 1; + } + break; + + default: break; // silence GCC } @@ -344,7 +371,7 @@ void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int in // //=========================================================================== -bool CheckDeprecatedFlags(AActor *actor, PClassActor *info, int index) +int CheckDeprecatedFlags(AActor *actor, int index) { // A deprecated flag is false if // a) it hasn't been added here @@ -368,7 +395,7 @@ bool CheckDeprecatedFlags(AActor *actor, PClassActor *info, int index) case DEPF_QUARTERGRAVITY: return actor->Gravity == 1./4; case DEPF_FIRERESIST: - for (auto &df : info->ActorInfo()->DamageFactors) + for (auto &df : actor->GetClass()->ActorInfo()->DamageFactors) { if (df.first == NAME_Fire) return df.second == 0.5; } @@ -387,10 +414,16 @@ bool CheckDeprecatedFlags(AActor *actor, PClassActor *info, int index) return actor->PointerVar(NAME_PickupFlash) == PClass::FindClass(NAME_PickupFlash); case DEPF_INTERHUBSTRIP: - return !(actor->IntVar(NAME_InterHubAmount)); + return actor->IntVar(NAME_InterHubAmount) == 0; case DEPF_HIGHERMPROB: return actor->MinMissileChance <= 160; + + case DEPF_MISSILEMORE: + return actor->missilechancemult == 0.5 || actor->missilechancemult == 0.0625; + + case DEPF_MISSILEEVENMORE: + return actor->missilechancemult == 0.125 || actor->missilechancemult == 0.0625; } return false; // Any entirely unknown flag is not set diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index 527bd9178..18cd8aa32 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -2044,6 +2044,7 @@ DEFINE_FIELD(AActor, Species) DEFINE_FIELD(AActor, alternative) DEFINE_FIELD(AActor, goal) DEFINE_FIELD(AActor, MinMissileChance) +DEFINE_FIELD(AActor, missilechancemult) DEFINE_FIELD(AActor, LastLookPlayerNumber) DEFINE_FIELD(AActor, SpawnFlags) DEFINE_FIELD(AActor, meleethreshold) diff --git a/src/scripting/zscript/zcc_compile_doom.cpp b/src/scripting/zscript/zcc_compile_doom.cpp index 4becfc4fe..3563967e5 100644 --- a/src/scripting/zscript/zcc_compile_doom.cpp +++ b/src/scripting/zscript/zcc_compile_doom.cpp @@ -795,13 +795,14 @@ void ZCCDoomCompiler::ProcessDefaultFlag(PClassActor *cls, ZCC_FlagStmt *flg) auto fd = FindFlag(cls, n1, n2, true); if (fd != nullptr) { - if (fd->varflags & VARF_Deprecated) + if ((fd->varflags & VARF_Deprecated) && fd->deprecationVersion <= this->mVersion) { - Warn(flg, "Deprecated flag '%s%s%s' used", n1, n2 ? "." : "", n2 ? n2 : ""); + Warn(flg, "Deprecated flag '%s%s%s' used, deprecated since %d.%d.%d", n1, n2 ? "." : "", n2 ? n2 : "", + fd->deprecationVersion.major, fd->deprecationVersion.minor, fd->deprecationVersion.revision); } if (fd->structoffset == -1) { - HandleDeprecatedFlags((AActor*)cls->Defaults, cls, flg->set, fd->flagbit); + HandleDeprecatedFlags((AActor*)cls->Defaults, flg->set, fd->flagbit); } else { diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index cae1d161b..a29b912c5 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -187,6 +187,7 @@ class Actor : Thinker native native Actor Alternative; native Actor goal; native uint8 MinMissileChance; + native double MissileChanceMult; native int8 LastLookPlayerNumber; native uint SpawnFlags; native double meleethreshold; @@ -339,6 +340,7 @@ class Actor : Thinker native property WeaveIndexXY: WeaveIndexXY; property WeaveIndexZ: WeaveIndexZ; property MinMissileChance: MinMissileChance; + property MissileChanceMult: MissileChanceMult; property MaxStepHeight: MaxStepHeight; property MaxDropoffHeight: MaxDropoffHeight; property MaxSlopeSteepness: MaxSlopeSteepness; diff --git a/wadsrc/static/zscript/actors/doom/cyberdemon.zs b/wadsrc/static/zscript/actors/doom/cyberdemon.zs index d795fc31a..b18861bf9 100644 --- a/wadsrc/static/zscript/actors/doom/cyberdemon.zs +++ b/wadsrc/static/zscript/actors/doom/cyberdemon.zs @@ -16,8 +16,8 @@ class Cyberdemon : Actor PainChance 20; Monster; MinMissileChance 160; + MissileChanceMult 0.5; +BOSS - +MISSILEMORE +FLOORCLIP +NORADIUSDMG +DONTMORPH diff --git a/wadsrc/static/zscript/actors/doom/lostsoul.zs b/wadsrc/static/zscript/actors/doom/lostsoul.zs index 7feb8553b..0712a6d49 100644 --- a/wadsrc/static/zscript/actors/doom/lostsoul.zs +++ b/wadsrc/static/zscript/actors/doom/lostsoul.zs @@ -14,8 +14,9 @@ class LostSoul : Actor Speed 8; Damage 3; PainChance 256; + MissileChanceMult 0.5; Monster; - +FLOAT +NOGRAVITY +MISSILEMORE +DONTFALL +NOICEDEATH +ZDOOMTRANS +RETARGETAFTERSLAM + +FLOAT +NOGRAVITY +DONTFALL +NOICEDEATH +ZDOOMTRANS +RETARGETAFTERSLAM AttackSound "skull/melee"; PainSound "skull/pain"; DeathSound "skull/death"; diff --git a/wadsrc/static/zscript/actors/doom/revenant.zs b/wadsrc/static/zscript/actors/doom/revenant.zs index 36599e3a9..90492727a 100644 --- a/wadsrc/static/zscript/actors/doom/revenant.zs +++ b/wadsrc/static/zscript/actors/doom/revenant.zs @@ -15,7 +15,7 @@ class Revenant : Actor PainChance 100; Monster; MeleeThreshold 196; - +MISSILEMORE + MissileChanceMult 0.5; +FLOORCLIP SeeSound "skeleton/sight"; PainSound "skeleton/pain"; diff --git a/wadsrc/static/zscript/actors/doom/spidermaster.zs b/wadsrc/static/zscript/actors/doom/spidermaster.zs index 3ad0b8846..62701e395 100644 --- a/wadsrc/static/zscript/actors/doom/spidermaster.zs +++ b/wadsrc/static/zscript/actors/doom/spidermaster.zs @@ -13,9 +13,9 @@ class SpiderMastermind : Actor Mass 1000; Speed 12; PainChance 40; + MissileChanceMult 0.5; Monster; +BOSS - +MISSILEMORE +FLOORCLIP +NORADIUSDMG +DONTMORPH diff --git a/wadsrc/static/zscript/actors/heretic/hereticimp.zs b/wadsrc/static/zscript/actors/heretic/hereticimp.zs index 3a938b4ed..5ea8b063e 100644 --- a/wadsrc/static/zscript/actors/heretic/hereticimp.zs +++ b/wadsrc/static/zscript/actors/heretic/hereticimp.zs @@ -13,12 +13,12 @@ class HereticImp : Actor Mass 50; Speed 10; Painchance 200; + MissileChanceMult 0.5; Monster; +FLOAT +NOGRAVITY +SPAWNFLOAT +DONTOVERLAP - +MISSILEMORE SeeSound "himp/sight"; AttackSound "himp/attack"; PainSound "himp/pain"; @@ -159,7 +159,7 @@ class HereticImpLeader : HereticImp { Species "HereticImpLeader"; Health 80; - -MISSILEMORE + MissileChanceMult 1; AttackSound "himp/leaderattack"; } States diff --git a/wadsrc/static/zscript/actors/strife/acolyte.zs b/wadsrc/static/zscript/actors/strife/acolyte.zs index 5aeb0e63a..c86a6e5d3 100644 --- a/wadsrc/static/zscript/actors/strife/acolyte.zs +++ b/wadsrc/static/zscript/actors/strife/acolyte.zs @@ -155,7 +155,7 @@ class AcolyteTan : Acolyte { Default { - +MISSILEMORE +MISSILEEVENMORE + MissileChanceMult 0.0625; DropItem "ClipOfBullets"; } } @@ -166,7 +166,7 @@ class AcolyteRed : Acolyte { Default { - +MISSILEMORE +MISSILEEVENMORE + MissileChanceMult 0.0625; Translation 0; } } @@ -177,7 +177,7 @@ class AcolyteRust : Acolyte { Default { - +MISSILEMORE +MISSILEEVENMORE + MissileChanceMult 0.0625; Translation 1; } } @@ -188,7 +188,7 @@ class AcolyteGray : Acolyte { Default { - +MISSILEMORE +MISSILEEVENMORE + MissileChanceMult 0.0625; Translation 2; } } @@ -199,7 +199,7 @@ class AcolyteDGreen : Acolyte { Default { - +MISSILEMORE +MISSILEEVENMORE + MissileChanceMult 0.0625; Translation 3; } } @@ -210,7 +210,7 @@ class AcolyteGold : Acolyte { Default { - +MISSILEMORE +MISSILEEVENMORE + MissileChanceMult 0.0625; Translation 4; } } @@ -243,7 +243,7 @@ class AcolyteShadow : Acolyte { Default { - +MISSILEMORE + MissileChanceMult 0.5; DropItem "ClipOfBullets"; } States diff --git a/wadsrc/static/zscript/actors/strife/crusader.zs b/wadsrc/static/zscript/actors/strife/crusader.zs index f08d0f847..daee0d2e9 100644 --- a/wadsrc/static/zscript/actors/strife/crusader.zs +++ b/wadsrc/static/zscript/actors/strife/crusader.zs @@ -11,10 +11,10 @@ class Crusader : Actor Mass 400; Health 400; Painchance 128; + MissileChanceMult 0.5; Monster; +FLOORCLIP +DONTMORPH - +MISSILEMORE +INCOMBAT +NOICEDEATH +NOBLOOD diff --git a/wadsrc/static/zscript/actors/strife/sentinel.zs b/wadsrc/static/zscript/actors/strife/sentinel.zs index 0acc8580f..0987cc018 100644 --- a/wadsrc/static/zscript/actors/strife/sentinel.zs +++ b/wadsrc/static/zscript/actors/strife/sentinel.zs @@ -11,6 +11,7 @@ class Sentinel : Actor Radius 23; Height 53; Mass 300; + MissileChanceMult 0.5; Monster; +SPAWNCEILING +NOGRAVITY @@ -18,7 +19,6 @@ class Sentinel : Actor +NOBLOOD +NOBLOCKMONST +INCOMBAT - +MISSILEMORE +LOOKALLAROUND +NEVERRESPAWN MinMissileChance 150; From 3798fd815f7f1c227ec6b9ca522e08fe4f4d0b32 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 3 Oct 2024 12:32:09 +0200 Subject: [PATCH 33/40] the MISSILE(EVEN)MORE flags still need to be accessible by ZScript for backwards compatibility. Since these do not exist anymore an internal interface to Handle/CheckDeprecatedFlags was added. --- src/common/engine/namedef.h | 2 + src/common/scripting/backend/codegen.cpp | 261 ++++++++++++++--------- src/scripting/thingdef_data.cpp | 12 ++ src/scripting/thingdef_properties.cpp | 16 ++ wadsrc/static/zscript/engine/base.zs | 2 + 5 files changed, 190 insertions(+), 103 deletions(-) diff --git a/src/common/engine/namedef.h b/src/common/engine/namedef.h index 7f98beba0..13827382c 100644 --- a/src/common/engine/namedef.h +++ b/src/common/engine/namedef.h @@ -278,6 +278,8 @@ xx(BuiltinNameToClass) xx(BuiltinClassCast) xx(BuiltinFunctionPtrCast) xx(BuiltinFindTranslation) +xx(HandleDeprecatedFlags) +xx(CheckDeprecatedFlags) xx(ScreenJobRunner) xx(Action) diff --git a/src/common/scripting/backend/codegen.cpp b/src/common/scripting/backend/codegen.cpp index 5b1a975a6..b14fb267c 100644 --- a/src/common/scripting/backend/codegen.cpp +++ b/src/common/scripting/backend/codegen.cpp @@ -2828,83 +2828,104 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) // Special case: Assignment to a bitfield. IsBitWrite = Base->GetBitValue(); + if (IsBitWrite >= 0x10000) + { + // internal flags - need more here + IsBitWrite &= 0xffff; + } return this; } ExpEmit FxAssign::Emit(VMFunctionBuilder *build) { - static const uint8_t loadops[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP }; - assert(Base->ValueType->GetRegType() == Right->ValueType->GetRegType()); - - ExpEmit pointer = Base->Emit(build); - Address = pointer; - - ExpEmit result; - bool intconst = false; - int intconstval = 0; - - if (Right->isConstant() && Right->ValueType->GetRegType() == REGT_INT) + if (IsBitWrite < 64) { - intconst = true; - intconstval = static_cast(Right)->GetValue().GetInt(); - result.Konst = true; - result.RegType = REGT_INT; - } - else - { - result = Right->Emit(build); - } - assert(result.RegType <= REGT_TYPE); + static const uint8_t loadops[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP }; + assert(Base->ValueType->GetRegType() == Right->ValueType->GetRegType()); - if (pointer.Target) - { - if (result.Konst) + ExpEmit pointer = Base->Emit(build); + Address = pointer; + + ExpEmit result; + bool intconst = false; + int intconstval = 0; + + if (Right->isConstant() && Right->ValueType->GetRegType() == REGT_INT) { - if (intconst) build->EmitLoadInt(pointer.RegNum, intconstval); - else build->Emit(loadops[result.RegType], pointer.RegNum, result.RegNum); + intconst = true; + intconstval = static_cast(Right)->GetValue().GetInt(); + result.Konst = true; + result.RegType = REGT_INT; } else { - build->Emit(Right->ValueType->GetMoveOp(), pointer.RegNum, result.RegNum); + result = Right->Emit(build); } - } - else - { - if (result.Konst) + assert(result.RegType <= REGT_TYPE); + + if (pointer.Target) + { + if (result.Konst) + { + if (intconst) build->EmitLoadInt(pointer.RegNum, intconstval); + else build->Emit(loadops[result.RegType], pointer.RegNum, result.RegNum); + } + else + { + build->Emit(Right->ValueType->GetMoveOp(), pointer.RegNum, result.RegNum); + } + } + else + { + if (result.Konst) + { + ExpEmit temp(build, result.RegType); + if (intconst) build->EmitLoadInt(temp.RegNum, intconstval); + else build->Emit(loadops[result.RegType], temp.RegNum, result.RegNum); + result.Free(build); + result = temp; + } + + if (IsBitWrite == -1) + { + build->Emit(Base->ValueType->GetStoreOp(), pointer.RegNum, result.RegNum, build->GetConstantInt(0)); + } + else + { + build->Emit(OP_SBIT, pointer.RegNum, result.RegNum, 1 << IsBitWrite); + } + } + + if (AddressRequested) { - ExpEmit temp(build, result.RegType); - if (intconst) build->EmitLoadInt(temp.RegNum, intconstval); - else build->Emit(loadops[result.RegType], temp.RegNum, result.RegNum); result.Free(build); - result = temp; + return pointer; } - if (IsBitWrite == -1) - { - build->Emit(Base->ValueType->GetStoreOp(), pointer.RegNum, result.RegNum, build->GetConstantInt(0)); + pointer.Free(build); + + if (intconst) + { //fix int constant return for assignment + return Right->Emit(build); } else { - build->Emit(OP_SBIT, pointer.RegNum, result.RegNum, 1 << IsBitWrite); + return result; } - - } - - if (AddressRequested) - { - result.Free(build); - return pointer; - } - - pointer.Free(build); - - if(intconst) - { //fix int constant return for assignment - return Right->Emit(build); } else { - return result; + VMFunction* callfunc; + auto sym = FindBuiltinFunction(NAME_HandleDeprecatedFlags); + + assert(sym); + callfunc = sym->Variants[0].Implementation; + + FunctionCallEmitter emitters(callfunc); + emitters.AddParameter(build, Base); + emitters.AddParameter(build, Right); + emitters.AddParameterIntConst(IsBitWrite - 64); + return emitters.EmitCall(build); } } @@ -2934,23 +2955,40 @@ FxExpression *FxAssignSelf::Resolve(FCompileContext &ctx) ExpEmit FxAssignSelf::Emit(VMFunctionBuilder *build) { - ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it - if (!pointer.Target) + if (Assignment->IsBitWrite < 64) { - ExpEmit out(build, ValueType->GetRegType(), ValueType->GetRegCount()); - if (Assignment->IsBitWrite != -1) + ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it + if (!pointer.Target) { - build->Emit(OP_LBIT, out.RegNum, pointer.RegNum, 1 << Assignment->IsBitWrite); + ExpEmit out(build, ValueType->GetRegType(), ValueType->GetRegCount()); + if (Assignment->IsBitWrite == -1) + { + build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0)); + } + else + { + build->Emit(OP_LBIT, out.RegNum, pointer.RegNum, 1 << Assignment->IsBitWrite); + } + return out; } else { - build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0)); + return pointer; } - return out; } else { - return pointer; + VMFunction* callfunc; + auto sym = FindBuiltinFunction(NAME_CheckDeprecatedFlags); + + assert(sym); + callfunc = sym->Variants[0].Implementation; + + FunctionCallEmitter emitters(callfunc); + emitters.AddParameter(build, Assignment->Base); + emitters.AddParameterIntConst(Assignment->IsBitWrite - 64); + emitters.AddReturn(REGT_INT); + return emitters.EmitCall(build); } } @@ -7728,56 +7766,73 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) ExpEmit FxStructMember::Emit(VMFunctionBuilder *build) { - ExpEmit obj = classx->Emit(build); - assert(obj.RegType == REGT_POINTER); - - if (obj.Konst) + if (membervar->BitValue < 64 || AddressRequested) { - // If the situation where we are dereferencing a constant - // pointer is common, then it would probably be worthwhile - // to add new opcodes for those. But as of right now, I - // don't expect it to be a particularly common case. - ExpEmit newobj(build, REGT_POINTER); - build->Emit(OP_LKP, newobj.RegNum, obj.RegNum); - obj = newobj; - } + ExpEmit obj = classx->Emit(build); + assert(obj.RegType == REGT_POINTER); - if (membervar->Flags & VARF_Meta) - { - obj.Free(build); - ExpEmit meta(build, REGT_POINTER); - build->Emit(OP_META, meta.RegNum, obj.RegNum); - obj = meta; - } - - if (AddressRequested) - { - if (membervar->Offset == 0) + if (obj.Konst) { - return obj; + // If the situation where we are dereferencing a constant + // pointer is common, then it would probably be worthwhile + // to add new opcodes for those. But as of right now, I + // don't expect it to be a particularly common case. + ExpEmit newobj(build, REGT_POINTER); + build->Emit(OP_LKP, newobj.RegNum, obj.RegNum); + obj = newobj; + } + + if (membervar->Flags & VARF_Meta) + { + obj.Free(build); + ExpEmit meta(build, REGT_POINTER); + build->Emit(OP_META, meta.RegNum, obj.RegNum); + obj = meta; + } + + if (AddressRequested) + { + if (membervar->Offset == 0) + { + return obj; + } + obj.Free(build); + ExpEmit out(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, build->GetConstantInt((int)membervar->Offset)); + return out; + } + + int offsetreg = build->GetConstantInt((int)membervar->Offset); + ExpEmit loc(build, membervar->Type->GetRegType(), membervar->Type->GetRegCount()); + + if (membervar->BitValue == -1) + { + build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg); + } + else + { + ExpEmit out(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, offsetreg); + build->Emit(OP_LBIT, loc.RegNum, out.RegNum, 1 << membervar->BitValue); + out.Free(build); } obj.Free(build); - ExpEmit out(build, REGT_POINTER); - build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, build->GetConstantInt((int)membervar->Offset)); - return out; - } - - int offsetreg = build->GetConstantInt((int)membervar->Offset); - ExpEmit loc(build, membervar->Type->GetRegType(), membervar->Type->GetRegCount()); - - if (membervar->BitValue == -1) - { - build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg); + return loc; } else { - ExpEmit out(build, REGT_POINTER); - build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, offsetreg); - build->Emit(OP_LBIT, loc.RegNum, out.RegNum, 1 << membervar->BitValue); - out.Free(build); + VMFunction* callfunc; + auto sym = FindBuiltinFunction(NAME_CheckDeprecatedFlags); + + assert(sym); + callfunc = sym->Variants[0].Implementation; + + FunctionCallEmitter emitters(callfunc); + emitters.AddParameter(build, classx); + emitters.AddParameterIntConst(membervar->BitValue - 64); + emitters.AddReturn(REGT_INT); + return emitters.EmitCall(build); } - obj.Free(build); - return loc; } diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 8f19bab54..129c06b78 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -920,6 +920,18 @@ void SynthesizeFlagFields() { cls->VMType->AddNativeField(FStringf("b%s", fl.Defs[i].name), (fl.Defs[i].fieldsize == 4 ? TypeSInt32 : TypeSInt16), fl.Defs[i].structoffset, fl.Defs[i].varflags, fl.Defs[i].flagbit); } + else if (fl.Defs[i].flagbit == DEPF_MISSILEMORE || fl.Defs[i].flagbit == DEPF_MISSILEEVENMORE) // these need script side emulation because they have been around for many years. + { + auto field = cls->VMType->AddNativeField(FStringf("b%s", fl.Defs[i].name), TypeSInt32, 0, VARF_Native); + if (field) + { + // these are deprecated so flag accordingly with a proper message. + field->DeprecationMessage = "Use missilechancemult property instead"; + field->mVersion = MakeVersion(4, 13, 0); + field->Flags |= VARF_Deprecated; + field->BitValue = fl.Defs[i].flagbit + 64; + } + } } } } diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 4969765a7..2154f4db5 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -361,6 +361,15 @@ void HandleDeprecatedFlags(AActor *actor, int set, int index) } } +// the interface here works on object, but currently all deprecated flags affect subclasses of Actor only +DEFINE_ACTION_FUNCTION_NATIVE(DObject, HandleDeprecatedFlags, HandleDeprecatedFlags) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(set); + PARAM_INT(index); + HandleDeprecatedFlags(self, set, index); + return 0; +} //=========================================================================== // // CheckDeprecatedFlags @@ -429,6 +438,13 @@ int CheckDeprecatedFlags(AActor *actor, int index) return false; // Any entirely unknown flag is not set } +DEFINE_ACTION_FUNCTION_NATIVE(DObject, CheckDeprecatedFlags, CheckDeprecatedFlags) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(index); + ACTION_RETURN_INT(CheckDeprecatedFlags(self, index)); +} + //========================================================================== // // diff --git a/wadsrc/static/zscript/engine/base.zs b/wadsrc/static/zscript/engine/base.zs index c4322918f..18fe1b363 100644 --- a/wadsrc/static/zscript/engine/base.zs +++ b/wadsrc/static/zscript/engine/base.zs @@ -760,6 +760,8 @@ class Object native private native static Class BuiltinNameToClass(Name nm, Class filter); private native static Object BuiltinClassCast(Object inptr, Class test); private native static Function BuiltinFunctionPtrCast(Function inptr, voidptr newtype); + private native static void HandleDeprecatedFlags(Object obj, bool set, int index); + private native static bool CheckDeprecatedFlags(Object obj, int index); native static uint MSTime(); native static double MSTimeF(); From b667b930a3247b3f5240148dfab15a37ef8902da Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 3 Oct 2024 22:30:09 +0200 Subject: [PATCH 34/40] fixed logic bug with HitFriend and Refire functions. The old code was essentially ineffective and useless, this is how MBF had it and how it was supposed to be. --- wadsrc/static/zscript/actors/doom/possessed.zs | 6 +++++- wadsrc/static/zscript/actors/doom/spidermaster.zs | 6 +++++- wadsrc/static/zscript/actors/strife/sentinel.zs | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/wadsrc/static/zscript/actors/doom/possessed.zs b/wadsrc/static/zscript/actors/doom/possessed.zs index 4fa9e0f7e..26966e1f0 100644 --- a/wadsrc/static/zscript/actors/doom/possessed.zs +++ b/wadsrc/static/zscript/actors/doom/possessed.zs @@ -342,12 +342,16 @@ extend class Actor void A_CPosRefire() { + if (HitFriend()) + { + SetState(SeeState); + return; + } // keep firing unless target got out of sight A_FaceTarget(); if (Random[CPosRefire](0, 255) >= 40) { if (!target - || HitFriend() || target.health <= 0 || !CheckSight(target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES)) { diff --git a/wadsrc/static/zscript/actors/doom/spidermaster.zs b/wadsrc/static/zscript/actors/doom/spidermaster.zs index 62701e395..c2685f480 100644 --- a/wadsrc/static/zscript/actors/doom/spidermaster.zs +++ b/wadsrc/static/zscript/actors/doom/spidermaster.zs @@ -73,12 +73,16 @@ extend class Actor { void A_SpidRefire() { + if (HitFriend()) + { + SetState(SeeState); + return; + } // keep firing unless target got out of sight A_FaceTarget(); if (Random[CPosRefire](0, 255) >= 10) { if (!target - || HitFriend() || target.health <= 0 || !CheckSight(target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES)) { diff --git a/wadsrc/static/zscript/actors/strife/sentinel.zs b/wadsrc/static/zscript/actors/strife/sentinel.zs index 0987cc018..84b9c3f0c 100644 --- a/wadsrc/static/zscript/actors/strife/sentinel.zs +++ b/wadsrc/static/zscript/actors/strife/sentinel.zs @@ -164,13 +164,17 @@ extend class Actor void A_SentinelRefire() { A_FaceTarget (); + if (HitFriend()) + { + SetState(SeeState); + return; + } if (random[SentinelRefire]() >= 30) { if (target == NULL || target.health <= 0 || !CheckSight (target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES) || - HitFriend() || (MissileState == NULL && !CheckMeleeRange()) || random[SentinelRefire]() < 40) { From 6aa71184f790be7b9bf02ed5f3a2da2fc4dd5d0e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 3 Oct 2024 23:01:09 +0200 Subject: [PATCH 35/40] fixed: MBF21's flag functions did not call the special wrappers for MF_FRIENDLY. --- src/gamedata/d_dehacked.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gamedata/d_dehacked.cpp b/src/gamedata/d_dehacked.cpp index e10f78dfb..69874529b 100644 --- a/src/gamedata/d_dehacked.cpp +++ b/src/gamedata/d_dehacked.cpp @@ -3961,6 +3961,7 @@ void SetFriendly(AActor* a) { if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters--; a->flags |= MF_FRIENDLY; + a->flags3 |= MF3_NOBLOCKMONST; if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters++; } @@ -3968,6 +3969,7 @@ void ClearFriendly(AActor* a) { if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters--; a->flags &= ~MF_FRIENDLY; + a->flags3 &= ~MF3_NOBLOCKMONST; if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters++; } @@ -4123,7 +4125,7 @@ static FlagHandler flag1handlers[32] = { { SetTranslation2, ClearTranslation2, CheckTranslation2 }, F6(MF6_TOUCHY), { SetBounces, ClearBounces, [](AActor* a)->bool { return a->BounceFlags & BOUNCE_DEH; } }, - F(MF_FRIENDLY), + { SetFriendly, ClearFriendly, [](AActor* a)->bool { return a->flags & MF_FRIENDLY; } }, { SetTranslucent, ClearTranslucent, CheckTranslucent }, }; From 5b1f0fdc86a8b91e41938c8c8ece680b053bfa36 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 4 Oct 2024 18:31:04 +0200 Subject: [PATCH 36/40] bFriendly should not be set from scripts because this omits needed bookkeeping. --- wadsrc/static/zscript/actors/attacks.zs | 2 +- wadsrc/static/zscript/actors/doom/painelemental.zs | 2 +- wadsrc/static/zscript/actors/strife/acolyte.zs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/wadsrc/static/zscript/actors/attacks.zs b/wadsrc/static/zscript/actors/attacks.zs index 1965be0b1..c1cb445e1 100644 --- a/wadsrc/static/zscript/actors/attacks.zs +++ b/wadsrc/static/zscript/actors/attacks.zs @@ -250,7 +250,7 @@ extend class Actor else if (originator.player) { // A player always spawns a monster friendly to him - mo.bFriendly = true; + mo.A_SetFriendly(true); mo.SetFriendPlayer(originator.player); Actor attacker=originator.player.attacker; diff --git a/wadsrc/static/zscript/actors/doom/painelemental.zs b/wadsrc/static/zscript/actors/doom/painelemental.zs index 244261303..75f90a02a 100644 --- a/wadsrc/static/zscript/actors/doom/painelemental.zs +++ b/wadsrc/static/zscript/actors/doom/painelemental.zs @@ -218,7 +218,7 @@ extend class Actor { if (target && IsFriend(target)) { // And I thought you were my friend! - bFriendly = false; + A_SetFriendly(false); } A_NoBlocking(); A_PainShootSkull(spawntype, angle + 90); diff --git a/wadsrc/static/zscript/actors/strife/acolyte.zs b/wadsrc/static/zscript/actors/strife/acolyte.zs index c86a6e5d3..b982d8429 100644 --- a/wadsrc/static/zscript/actors/strife/acolyte.zs +++ b/wadsrc/static/zscript/actors/strife/acolyte.zs @@ -118,7 +118,7 @@ class Acolyte : StrifeHumanoid void A_BeShadowyFoe() { A_SetRenderStyle(HR_SHADOW, STYLE_Translucent); - bFriendly = false; + A_SetFriendly(false); } //============================================================================ From ccbebfcf34b761b94cb504a50b6dd39b922c33eb Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 4 Oct 2024 18:33:53 +0200 Subject: [PATCH 37/40] fix kill count management in CopyFriendliness when used on corpses. --- src/playsim/p_mobj.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index 0cbcb813b..8d34e6c73 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -803,7 +803,7 @@ DEFINE_ACTION_FUNCTION(AActor, GiveInventoryType) void AActor::CopyFriendliness (AActor *other, bool changeTarget, bool resetHealth) { - Level->total_monsters -= CountsAsKill(); + if (health > 0) Level->total_monsters -= CountsAsKill(); TIDtoHate = other->TIDtoHate; LastLookActor = other->LastLookActor; LastLookPlayerNumber = other->LastLookPlayerNumber; @@ -818,7 +818,7 @@ void AActor::CopyFriendliness (AActor *other, bool changeTarget, bool resetHealt LastHeard = target = other->target; } if (resetHealth) health = SpawnHealth(); - Level->total_monsters += CountsAsKill(); + if (health > 0) Level->total_monsters += CountsAsKill(); } DEFINE_ACTION_FUNCTION(AActor, CopyFriendliness) From 2b2e85005c8299ac8736f07056b645375bd83f9a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 4 Oct 2024 18:34:32 +0200 Subject: [PATCH 38/40] fix MBF21 ClearCountItem --- src/gamedata/d_dehacked.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gamedata/d_dehacked.cpp b/src/gamedata/d_dehacked.cpp index 69874529b..8ddcc7935 100644 --- a/src/gamedata/d_dehacked.cpp +++ b/src/gamedata/d_dehacked.cpp @@ -3952,7 +3952,7 @@ void ClearCountitem(AActor* a) { if (a->flags & MF_COUNTITEM) { - a->flags |= MF_COUNTITEM; + a->flags &= ~MF_COUNTITEM; a->Level->total_items--; } } From f0676cdf019f65f17ea917acb3f65be08718a00f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 5 Oct 2024 10:22:05 +0200 Subject: [PATCH 39/40] fixed a few memory leaks --- libraries/ZWidget/src/widgets/lineedit/lineedit.cpp | 2 ++ src/common/scripting/core/types.cpp | 3 ++- src/common/startscreen/startscreen.cpp | 7 +++++++ src/common/startscreen/startscreen.h | 2 +- src/common/widgets/widgetresourcedata.cpp | 1 + src/d_main.cpp | 2 ++ 6 files changed, 15 insertions(+), 2 deletions(-) diff --git a/libraries/ZWidget/src/widgets/lineedit/lineedit.cpp b/libraries/ZWidget/src/widgets/lineedit/lineedit.cpp index 5c90e68e1..9065ccde4 100644 --- a/libraries/ZWidget/src/widgets/lineedit/lineedit.cpp +++ b/libraries/ZWidget/src/widgets/lineedit/lineedit.cpp @@ -18,6 +18,8 @@ LineEdit::LineEdit(Widget* parent) : Widget(parent) LineEdit::~LineEdit() { + delete timer; + delete scroll_timer; } bool LineEdit::IsReadOnly() const diff --git a/src/common/scripting/core/types.cpp b/src/common/scripting/core/types.cpp index 8e13dcc52..b70783f3e 100644 --- a/src/common/scripting/core/types.cpp +++ b/src/common/scripting/core/types.cpp @@ -330,7 +330,8 @@ void PType::StaticInit() TypeVoidPtr = NewPointer(TypeVoid, false); TypeRawFunction = new PPointer; - TypeRawFunction->mDescriptiveName = "Raw Function Pointer"; + TypeRawFunction->mDescriptiveName = "Raw Function Pointer"; + TypeTable.AddType(TypeRawFunction, NAME_None); TypeVMFunction = NewPointer(NewStruct("VMFunction", nullptr, true)); TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. TypeStringStruct = NewStruct("Stringstruct", nullptr, true); diff --git a/src/common/startscreen/startscreen.cpp b/src/common/startscreen/startscreen.cpp index b71949f46..56a179526 100644 --- a/src/common/startscreen/startscreen.cpp +++ b/src/common/startscreen/startscreen.cpp @@ -372,6 +372,13 @@ FStartScreen* GetGameStartScreen(int max_progress) return nullptr; } +FStartScreen::~FStartScreen() +{ + if (StartupTexture) delete StartupTexture; + if (HeaderTexture) delete HeaderTexture; + if (NetTexture) delete NetTexture; +} + //========================================================================== // // ST_Util_ClearBlock diff --git a/src/common/startscreen/startscreen.h b/src/common/startscreen/startscreen.h index afac6c759..c90d092f9 100644 --- a/src/common/startscreen/startscreen.h +++ b/src/common/startscreen/startscreen.h @@ -70,7 +70,7 @@ protected: FGameTexture* NetTexture = nullptr; public: FStartScreen(int maxp) { MaxPos = maxp; } - virtual ~FStartScreen() = default; + virtual ~FStartScreen(); void Render(bool force = false); bool Progress(int); void NetProgress(int count); diff --git a/src/common/widgets/widgetresourcedata.cpp b/src/common/widgets/widgetresourcedata.cpp index 85ee3e249..13f151932 100644 --- a/src/common/widgets/widgetresourcedata.cpp +++ b/src/common/widgets/widgetresourcedata.cpp @@ -21,6 +21,7 @@ void InitWidgetResources(const char* filename) void CloseWidgetResources() { if (WidgetResources) delete WidgetResources; + WidgetResources = nullptr; } static std::vector LoadFile(const char* name) diff --git a/src/d_main.cpp b/src/d_main.cpp index fb25fa00f..c00f2231c 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -161,6 +161,7 @@ bool M_SetSpecialMenu(FName& menu, int param); // game specific checks const FIWADInfo *D_FindIWAD(TArray &wadfiles, const char *iwad, const char *basewad); void InitWidgetResources(const char* basewad); +void CloseWidgetResources(); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -3844,6 +3845,7 @@ int GameMain() M_SaveDefaultsFinal(); DeleteStartupScreen(); C_UninitCVars(); // must come last so that nothing will access the CVARs anymore after deletion. + CloseWidgetResources(); delete Args; Args = nullptr; return ret; From 6b5be653dce78e1ab5bf7a7bb37c3fefc14c05a6 Mon Sep 17 00:00:00 2001 From: Blue Shadow Date: Sat, 5 Oct 2024 10:40:07 +0300 Subject: [PATCH 40/40] - set a default value of 1.0 for `MissileChanceMult` property --- wadsrc/static/zscript/actors/actor.zs | 1 + 1 file changed, 1 insertion(+) diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index a29b912c5..5c4dc376e 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -407,6 +407,7 @@ class Actor : Thinker native RenderStyle 'Normal'; Alpha 1; MinMissileChance 200; + MissileChanceMult 1.0; MeleeRange 64 - MELEEDELTA; MaxDropoffHeight 24; MaxStepHeight 24;