diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 3d683aff1..4f0aa20db 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -78,6 +78,7 @@ #include "menu/menu.h" #include "intermission/intermission.h" #include "g_levellocals.h" +#include "events.h" // MACROS ------------------------------------------------------------------ @@ -331,6 +332,8 @@ static void MarkRoot() DThinker::MarkRoots(); FCanvasTextureInfo::Mark(); Mark(DACSThinker::ActiveThinker); + Mark(E_FirstEventHandler); + Mark(E_LastEventHandler); for (auto &s : level.sectorPortals) { Mark(s.mSkybox); diff --git a/src/events.cpp b/src/events.cpp index 4522f1989..afa98c99d 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -37,32 +37,42 @@ bool E_RegisterHandler(DStaticEventHandler* handler) // 2. MyHandler3->2: // E_FirstEventHandler = MyHandler2, E_LastEventHandler = MyHandler3 + // (Yes, all those write barriers here are really needed!) if (before != nullptr) { // if before is not null, link it before the existing handler. // note that before can be first handler, check for this. handler->next = before; + GC::WriteBarrier(handler, before); handler->prev = before->prev; + GC::WriteBarrier(handler, before->prev); before->prev = handler; + GC::WriteBarrier(before, handler); if (before == E_FirstEventHandler) + { E_FirstEventHandler = handler; + GC::WriteBarrier(handler); + } } else { // so if before is null, it means add last. // it can also mean that we have no handlers at all yet. handler->prev = E_LastEventHandler; + GC::WriteBarrier(handler, E_LastEventHandler); handler->next = nullptr; - if (E_FirstEventHandler == nullptr) - E_FirstEventHandler = handler; + if (E_FirstEventHandler == nullptr) E_FirstEventHandler = handler; E_LastEventHandler = handler; + GC::WriteBarrier(handler); if (handler->prev != nullptr) + { handler->prev->next = handler; + GC::WriteBarrier(handler->prev, handler); + } } if (handler->IsStatic()) { - handler->ObjectFlags |= OF_Fixed; handler->ObjectFlags |= OF_Transient; } @@ -80,16 +90,28 @@ bool E_UnregisterHandler(DStaticEventHandler* handler) // link out of normal list if (handler->prev) + { handler->prev->next = handler->next; + GC::WriteBarrier(handler->prev, handler->next); + } if (handler->next) + { handler->next->prev = handler->prev; + GC::WriteBarrier(handler->next, handler->prev); + } if (handler == E_FirstEventHandler) + { E_FirstEventHandler = handler->next; + GC::WriteBarrier(handler->next); + } if (handler == E_LastEventHandler) + { E_LastEventHandler = handler->prev; + GC::WriteBarrier(handler->prev); + } if (handler->IsStatic()) { - handler->ObjectFlags &= ~(OF_Fixed|OF_Transient); + handler->ObjectFlags &= ~OF_Transient; handler->Destroy(); } return true; diff --git a/src/events.h b/src/events.h index 71c8a27f6..46ed88b95 100755 --- a/src/events.h +++ b/src/events.h @@ -77,6 +77,7 @@ void E_SerializeEvents(FSerializer& arc); class DStaticEventHandler : public DObject // make it a part of normal GC process { DECLARE_CLASS(DStaticEventHandler, DObject) + HAS_OBJECT_POINTERS public: DStaticEventHandler() { @@ -99,6 +100,7 @@ public: void Serialize(FSerializer& arc) override { Super::Serialize(arc); + /* if (arc.isReading()) { Printf("DStaticEventHandler::Serialize: reading object %s\n", GetClass()->TypeName.GetChars()); @@ -107,6 +109,7 @@ public: { Printf("DStaticEventHandler::Serialize: store object %s\n", GetClass()->TypeName.GetChars()); } + */ arc("Order", Order); arc("IsUiProcessor", IsUiProcessor); @@ -155,6 +158,7 @@ public: bool IsStatic() override { return false; } }; extern DStaticEventHandler* E_FirstEventHandler; +extern DStaticEventHandler* E_LastEventHandler; // we cannot call this DEvent because in ZScript, 'event' is a keyword class DBaseEvent : public DObject diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index e4920ef55..71c0ff645 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -496,7 +496,7 @@ DEFINE_ACTION_FUNCTION(DMenu, SetMenu) { PARAM_PROLOGUE; PARAM_NAME(menu); - PARAM_INT(mparam); + PARAM_INT_DEF(mparam); M_SetMenu(menu, mparam); return 0; } diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index b3b0e1fe7..a1a0fda76 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -267,7 +267,7 @@ DEFINE_ACTION_FUNCTION(DMenu, StartMessage) { PARAM_PROLOGUE; PARAM_STRING(msg); - PARAM_INT(mode); + PARAM_INT_DEF(mode); PARAM_NAME_DEF(action); M_StartMessage(msg, mode, action); return 0; diff --git a/src/p_sight.cpp b/src/p_sight.cpp index 74b9fe165..68bf2ed3d 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -107,6 +107,7 @@ class SightCheck bool P_SightCheckLine (line_t *ld); int P_SightBlockLinesIterator (int x, int y); bool P_SightTraverseIntercepts (); + bool LineBlocksSight(line_t *ld); public: bool P_SightPathTraverse (); @@ -211,7 +212,14 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) double trX = Trace.x + Trace.dx * in->frac; double trY = Trace.y + Trace.dy * in->frac; - P_SightOpening (open, li, trX, trY); + + P_SightOpening(open, li, trX, trY); + if (LineBlocksSight(in->d.line)) + { + // This may not skip P_SightOpening, but only reduce the open range to 0. + open.range = 0; + open.bottom = open.top; + } FLinePortal *lport = li->getPortal(); @@ -362,6 +370,42 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) } +// performs trivial visibility checks. +bool SightCheck::LineBlocksSight(line_t *ld) +{ + // try to early out the check + if (!ld->backsector || !(ld->flags & ML_TWOSIDED) || (ld->flags & ML_BLOCKSIGHT)) + return true; // stop checking + + // [RH] don't see past block everything lines + if (ld->flags & ML_BLOCKEVERYTHING) + { + if (!(Flags & SF_SEEPASTBLOCKEVERYTHING)) + { + return true; + } + // Pretend the other side is invisible if this is not an impact line + // that runs a script on the current map. Used to prevent monsters + // from trying to attack through a block everything line unless + // there's a chance their attack will make it nonblocking. + if (!(Flags & SF_SEEPASTSHOOTABLELINES)) + { + if (!(ld->activation & SPAC_Impact)) + { + return true; + } + if (ld->special != ACS_Execute && ld->special != ACS_ExecuteAlways) + { + return true; + } + if (ld->args[1] != 0 && ld->args[1] != level.levelnum) + { + return true; + } + } + } + return false; +} /* ================== @@ -392,36 +436,9 @@ bool SightCheck::P_SightCheckLine (line_t *ld) return true; // line isn't crossed } - // try to early out the check - if (!ld->backsector || !(ld->flags & ML_TWOSIDED) || (ld->flags & ML_BLOCKSIGHT)) - return false; // stop checking - - // [RH] don't see past block everything lines - if (ld->flags & ML_BLOCKEVERYTHING) + if (!portalfound) // when portals come into play, the quick-outs here may not be performed { - if (!(Flags & SF_SEEPASTBLOCKEVERYTHING)) - { - return false; - } - // Pretend the other side is invisible if this is not an impact line - // that runs a script on the current map. Used to prevent monsters - // from trying to attack through a block everything line unless - // there's a chance their attack will make it nonblocking. - if (!(Flags & SF_SEEPASTSHOOTABLELINES)) - { - if (!(ld->activation & SPAC_Impact)) - { - return false; - } - if (ld->special != ACS_Execute && ld->special != ACS_ExecuteAlways) - { - return false; - } - if (ld->args[1] != 0 && ld->args[1] != level.levelnum) - { - return false; - } - } + if (LineBlocksSight(ld)) return false; } sightcounts[3]++; diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 3a169c585..ab83adc62 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -788,7 +788,7 @@ class Actor : Thinker native native void A_SpawnDebris(class spawntype, bool transfer_translation = false, double mult_h = 1, double mult_v = 1); native void A_SpawnParticle(color color1, int flags = 0, int lifetime = 35, double size = 1, double angle = 0, double xoff = 0, double yoff = 0, double zoff = 0, double velx = 0, double vely = 0, double velz = 0, double accelx = 0, double accely = 0, double accelz = 0, double startalphaf = 1, double fadestepf = -1, double sizestep = 0); native void A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false); - native void A_DropInventory(class itemtype, int amount); + native void A_DropInventory(class itemtype, int amount = -1); native void A_SetBlend(color color1, double alpha, int tics, color color2 = 0); deprecated native void A_ChangeFlag(string flagname, bool value); native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE);