diff --git a/src/events.cpp b/src/events.cpp index 74afb1b67..b82d660fd 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -536,6 +536,14 @@ bool E_CheckReplacement( PClassActor *replacee, PClassActor **replacement ) return final; } +bool E_CheckReplacee(PClassActor **replacee, PClassActor *replacement) +{ + bool final = false; + for (DStaticEventHandler *handler = E_FirstEventHandler; handler; handler = handler->next) + handler->CheckReplacee(replacee, replacement, &final); + return final; +} + void E_NewGame(EventHandlerType handlerType) { bool isStatic = handlerType == EventHandlerType::Global; @@ -627,6 +635,10 @@ DEFINE_FIELD_X(ReplaceEvent, FReplaceEvent, Replacee) DEFINE_FIELD_X(ReplaceEvent, FReplaceEvent, Replacement) DEFINE_FIELD_X(ReplaceEvent, FReplaceEvent, IsFinal) +DEFINE_FIELD_X(ReplacedEvent, FReplacedEvent, Replacee) +DEFINE_FIELD_X(ReplacedEvent, FReplacedEvent, Replacement) +DEFINE_FIELD_X(ReplacedEvent, FReplacedEvent, IsFinal) + DEFINE_ACTION_FUNCTION(DStaticEventHandler, SetOrder) { PARAM_SELF_PROLOGUE(DStaticEventHandler); @@ -1193,6 +1205,21 @@ void DStaticEventHandler::CheckReplacement( PClassActor *replacee, PClassActor * } } +void DStaticEventHandler::CheckReplacee(PClassActor **replacee, PClassActor *replacement, bool *final) +{ + IFVIRTUAL(DStaticEventHandler, CheckReplacee) + { + // don't create excessive DObjects if not going to be processed anyway + if (isEmpty(func)) return; + FReplacedEvent e = { *replacee, replacement, *final }; + VMValue params[2] = { (DStaticEventHandler*)this, &e }; + VMCall(func, params, 2, nullptr, 0); + if (e.Replacee != replacement) // prevent infinite recursion + *replacee = e.Replacee; + *final = e.IsFinal; + } +} + void DStaticEventHandler::NewGame() { IFVIRTUAL(DStaticEventHandler, NewGame) diff --git a/src/events.h b/src/events.h index 91cf37888..dbd408a42 100755 --- a/src/events.h +++ b/src/events.h @@ -81,6 +81,8 @@ void E_Console(int player, FString name, int arg1, int arg2, int arg3, bool manu // called when looking up the replacement for an actor class bool E_CheckReplacement(PClassActor* replacee, PClassActor** replacement); +// called when looking up the replaced for an actor class +bool E_CheckReplacee(PClassActor** replacee, PClassActor* replacement); // called on new game void E_NewGame(EventHandlerType handlerType); @@ -187,6 +189,7 @@ public: // void CheckReplacement(PClassActor* replacee, PClassActor** replacement, bool* final); + void CheckReplacee(PClassActor** replacee, PClassActor* replacement, bool* final); // void NewGame(); @@ -301,4 +304,11 @@ struct FReplaceEvent bool IsFinal; }; +struct FReplacedEvent +{ + PClassActor* Replacee; + PClassActor* Replacement; + bool IsFinal; +}; + #endif diff --git a/src/g_shared/a_dynlight.cpp b/src/g_shared/a_dynlight.cpp index f3462a69b..d1b91af9d 100644 --- a/src/g_shared/a_dynlight.cpp +++ b/src/g_shared/a_dynlight.cpp @@ -834,15 +834,18 @@ void FLevelLocals::RecreateAllAttachedLights() while ((a=it.Next())) { - if (a->IsKindOf(NAME_DynamicLight)) - { - ::AttachLight(a); - ::ActivateLight(a); - } - else + if (!a->IsKindOf(NAME_DynamicLight)) { a->SetDynamicLights(); } + else if (a->AttachedLights.Size() == 0) + { + ::AttachLight(a); + if (!(a->flags2 & MF2_DORMANT)) + { + ::ActivateLight(a); + } + } } } diff --git a/src/info.cpp b/src/info.cpp index 57f551c59..257f6ecce 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -593,6 +593,16 @@ PClassActor *PClassActor::GetReplacee(bool lookskill) } } PClassActor *savedrep = ActorInfo()->Replacee; + // [MC] Same code as CheckReplacement but turned around so modders can indicate + // what monsters spawn from which entity. I.e. instead of a randomspawner + // showing up, one can assign an Arachnotron as the one being replaced + // so functions like CheckReplacee and A_BossDeath can actually work, given + // modders set it up that way. + if (E_CheckReplacee(&savedrep, this)) + { + // [MK] the replacement is final, so don't continue with the chain + return savedrep ? savedrep : this; + } if (savedrep == nullptr && (!lookskill || skillrepname == NAME_None)) { return this; diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index 4dd256710..19f29c202 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -300,6 +300,13 @@ struct ReplaceEvent native version("2.4") native bool IsFinal; } +struct ReplacedEvent native version("3.7") +{ + native Class Replacee; + native readonly Class Replacement; + native bool IsFinal; +} + class StaticEventHandler : Object native play version("2.4") { // static event handlers CAN register other static event handlers. @@ -312,7 +319,7 @@ class StaticEventHandler : Object native play version("2.4") virtual void OnUnregister() {} // actual handlers are here -virtual void WorldLoaded(WorldEvent e) {} + virtual void WorldLoaded(WorldEvent e) {} virtual void WorldUnloaded(WorldEvent e) {} virtual void WorldThingSpawned(WorldEvent e) {} virtual void WorldThingDied(WorldEvent e) {} @@ -348,6 +355,7 @@ virtual void WorldLoaded(WorldEvent e) {} // virtual void CheckReplacement(ReplaceEvent e) {} + virtual void CheckReplacee(ReplacedEvent e) {} // virtual void NewGame() {} diff --git a/wadsrc/static/zscript/level_compatibility.txt b/wadsrc/static/zscript/level_compatibility.txt index 25eacb9da..be32e4e7f 100644 --- a/wadsrc/static/zscript/level_compatibility.txt +++ b/wadsrc/static/zscript/level_compatibility.txt @@ -358,6 +358,10 @@ class LevelCompatibility native play SetWallTexture(865, Line.back, Side.bottom, "STEP5"); SetWallTexture(1062, Line.front, Side.top, "GSTVINE1"); SetWallTexture(1071, Line.front, Side.top, "MARBLE1"); + // Door requiring yellow keycard can only be opened once, + // change other side to one-shot Door_Open + SetLineSpecial(165, Door_Open, 0, 16); + SetLineFlags(165, 0, Line.ML_REPEAT_SPECIAL); break; } @@ -367,6 +371,11 @@ class LevelCompatibility native play SetWallTexture(590, Line.back, Side.top, "GRAYBIG"); SetWallTexture(590, Line.front, Side.bottom, "BROWN1"); SetWallTexture(1027, Line.back, Side.top, "SP_HOT1"); + // Replace tag for eastern secret at level start to not + // cause any action to the two-Baron trap + AddSectorTag(127, 100); + SetLineSpecial(382, Door_Open, 100, 16); + SetLineSpecial(388, Door_Open, 100, 16); break; } @@ -393,6 +402,13 @@ class LevelCompatibility native play break; } + case 'BBDC4253AE277DA5FCE2F19561627496': // Doom E3M2 + { + // Switch at index finger repeatable in case of being stuck + SetLineFlags(368, Line.ML_REPEAT_SPECIAL); + break; + } + case '2B65CB046EA40D2E44576949381769CA': // Commercial Doom e3m4 { // This line is erroneously specified as Door_Raise that monsters @@ -428,14 +444,29 @@ class LevelCompatibility native play case 'FE97DCB9E6235FB3C52AE7C143160D73': // Doom E3M9 { - // Missing texture + // Missing textures SetWallTexture(102, Line.back, Side.bottom, "STONE3"); + SetWallTexture(445, Line.back, Side.bottom, "GRAY4"); + // First door cannot be opened from inside and can stop you + // from finishing the level if somehow locked in. + SetLineSpecial(24, Door_Open, 0, 16); + SetLineActivation(24, SPAC_Use); + SetLineFlags(24, Line.ML_REPEAT_SPECIAL); + // Door that requires blue skull can only be opened once, + // make it repeatable in case of being locked + SetLineFlags(194, Line.ML_REPEAT_SPECIAL); break; } case 'DA0C8281AC70EEC31127C228BCD7FE2C': // doom.wad e4m1 { - // missing texture + // missing textures + TextureID support3 = TexMan.CheckForTexture("SUPPORT3", TexMan.Type_Wall); + for(int i=0; i<4; i++) + { + SetWallTextureID(252+i, Line.back, Side.top, SUPPORT3); + } + SetWallTexture(322, Line.back, Side.bottom, "GSTONE1"); SetWallTexture(470, Line.front, Side.top, "GSTONE1"); break; } @@ -471,6 +502,13 @@ class LevelCompatibility native play SetSectorSpecial(151, 0); SetSectorSpecial(152, 0); SetSectorSpecial(155, 0); + // Stuck Imp + SetThingXY(69, -656, -1696); + // One line special at the northern lifts is incorrect, change + // to a repeatable line you can walk over to lower lift + SetLineSpecial(46, Plat_DownWaitUpStayLip, 1, 32, 105, 0); + SetLineActivation(46, SPAC_AnyCross); + SetLineFlags(46, Line.ML_REPEAT_SPECIAL); break; } diff --git a/wadsrc/static/zscript/menu/loadsavemenu.txt b/wadsrc/static/zscript/menu/loadsavemenu.txt index eb27b6f6e..09cf2a33b 100644 --- a/wadsrc/static/zscript/menu/loadsavemenu.txt +++ b/wadsrc/static/zscript/menu/loadsavemenu.txt @@ -37,13 +37,13 @@ struct SaveGameNode native { native String SaveTitle; - native String Filename; + native readonly String Filename; native bool bOldVersion; native bool bMissingWads; native bool bNoDelete; } -struct SavegameManager native +struct SavegameManager native ui { native int WindowSize; native SaveGameNode quickSaveSlot;