diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 7b5b2d357..cb3a6736f 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -393,7 +393,6 @@ Note: All fields default to false unless mentioned otherwise. Bit 5 (Value 32): midtex3d Bit 6 (Value 64): checkswitchrange Bit 7 (Value 128): firstsideonly - When used in special 208 this arg should be cleared afterward. Special 121 is not being used by UDMF maps in ZDoom and should be completely @@ -508,6 +507,9 @@ Replaced tabs with spaces. 1.31 22.12.2019 Coloriation options added +1.32 28.06.2021 +Blocklandmonsters MBF21 flag + =============================================================================== EOF =============================================================================== diff --git a/src/common/engine/namedef.h b/src/common/engine/namedef.h index af285ce7e..f12806b47 100644 --- a/src/common/engine/namedef.h +++ b/src/common/engine/namedef.h @@ -495,6 +495,7 @@ xx(Blockeverything) xx(Zoneboundary) xx(Jumpover) xx(Blockfloaters) +xx(Blocklandmonsters) xx(Clipmidtex) xx(Wrapmidtex) xx(Midtex3d) diff --git a/src/doomdata.h b/src/doomdata.h index d52d82389..00487ec2f 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -128,7 +128,7 @@ struct maplinedef2_t // LineDef attributes. // -enum ELineFlags : unsigned +enum ELineFlags : uint32_t { ML_BLOCKING =0x00000001, // solid, is an obstacle ML_BLOCKMONSTERS =0x00000002, // blocks monsters only @@ -176,6 +176,8 @@ enum ELineFlags : unsigned ML_REVEALED = 0x20000000, // set if revealed in automap ML_DRAWFULLHEIGHT = 0x40000000, // Draw the full height of the upper/lower sections ML_PORTALCONNECT = 0x80000000, // for internal use only: This line connects to a sector with a linked portal (used to speed up sight checks.) + // Flag words may not exceed 32 bit due to VM limitations. + ML2_BLOCKLANDMONSTERS = 0x1, // MBF21 }; diff --git a/src/gamedata/p_xlat.cpp b/src/gamedata/p_xlat.cpp index 682d40104..13de25649 100644 --- a/src/gamedata/p_xlat.cpp +++ b/src/gamedata/p_xlat.cpp @@ -68,6 +68,7 @@ void FLevelLocals::TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineinde uint32_t flags1 = flags; uint32_t newflags = 0; + uint32_t newflags2 = 0; for(int i=0;i<16;i++) { @@ -80,7 +81,8 @@ void FLevelLocals::TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineinde { if ((flags1 & (1<LineFlagTranslations[i].ismask) { - switch (translator->LineFlagTranslations[i].newvalue) + unsigned val = translator->LineFlagTranslations[i].newvalue; + switch ((int)val) { case -1: passthrough = true; @@ -92,12 +94,14 @@ void FLevelLocals::TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineinde ld->alpha = 0.25; break; default: - newflags |= translator->LineFlagTranslations[i].newvalue; + if ((val & 0x80000000) && val != 0x80000000) newflags2 |= val; + else newflags |= val; break; } } } flags = newflags; + ld->flags2 = newflags2; if (lineindexforid >= 0) { diff --git a/src/gamedata/r_defs.h b/src/gamedata/r_defs.h index 16b7b4184..fa4a30227 100644 --- a/src/gamedata/r_defs.h +++ b/src/gamedata/r_defs.h @@ -1438,7 +1438,7 @@ struct line_t { vertex_t *v1, *v2; // vertices, from v1 to v2 DVector2 delta; // precalculated v2 - v1 for side checking - uint32_t flags; + uint32_t flags, flags2; uint32_t activation; // activation type int special; int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width) diff --git a/src/maploader/udmf.cpp b/src/maploader/udmf.cpp index 5eebbf61e..256a119e6 100644 --- a/src/maploader/udmf.cpp +++ b/src/maploader/udmf.cpp @@ -928,6 +928,12 @@ public: Flag(ld->flags, ML_BLOCK_FLOATERS, key); continue; + case NAME_Blocklandmonsters: + // This is from MBF21 so it may later be needed for a lower level namespace. + CHECK_N(St | Zd | Zdt | Va) + Flag(ld->flags2, ML2_BLOCKLANDMONSTERS, key); + continue; + case NAME_Translucent: CHECK_N(St | Zd | Zdt | Va) strifetrans = CheckBool(key); diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 6edb99fcf..9d0189f41 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -75,6 +75,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, line_t &line, line_t * if (arc.BeginObject(key)) { arc("flags", line.flags, def->flags) + ("flags2", line.flags2, def->flags2) ("activation", line.activation, def->activation) ("special", line.special, def->special) ("alpha", line.alpha, def->alpha) diff --git a/src/playsim/actorinlines.h b/src/playsim/actorinlines.h index a287354c4..78015bb2d 100644 --- a/src/playsim/actorinlines.h +++ b/src/playsim/actorinlines.h @@ -178,3 +178,33 @@ inline bool AActor::isFrozen() const return false; } +// Consolidated from all (incomplete) variants that check if a line should block. +inline bool P_IsBlockedByLine(AActor* actor, line_t* line) +{ + // Keep this stuff readable - so no chained and nested 'if's! + + // Unconditional blockers. + if (line->flags & (ML_BLOCKING | ML_BLOCKEVERYTHING)) return true; + + // MBF considers that friendly monsters are not blocked by monster-blocking lines. + // This is added here as a compatibility option. Note that monsters that are dehacked + // into being friendly with the MBF flag automatically gain MF3_NOBLOCKMONST, so this + // just optionally generalizes the behavior to other friendly monsters. + + if (!((actor->flags3 & MF3_NOBLOCKMONST) + || ((actor->Level->i_compatflags & COMPATF_NOBLOCKFRIENDS) && (actor->flags & MF_FRIENDLY)))) + { + // the regular 'blockmonsters' flag. + if (line->flags & ML_BLOCKMONSTERS) return true; + // MBF21's flag for walking monsters + if ((line->flags2 & ML2_BLOCKLANDMONSTERS) && !(actor->flags & MF_FLOAT)) return true; + } + + // Blocking players + if (((actor->player != nullptr) || (actor->flags8 & MF8_BLOCKASPLAYER)) && (line->flags & ML_BLOCK_PLAYERS)) return true; + + // Blocking floaters. + if ((actor->flags & MF_FLOAT) && (line->flags & ML_BLOCK_FLOATERS)) return true; + + return false; +} \ No newline at end of file diff --git a/src/playsim/p_map.cpp b/src/playsim/p_map.cpp index 813d841f8..64172fa20 100644 --- a/src/playsim/p_map.cpp +++ b/src/playsim/p_map.cpp @@ -849,12 +849,6 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec // MBF bouncers are treated as missiles here. bool Projectile = (tm.thing->flags & MF_MISSILE || tm.thing->BounceFlags & BOUNCE_MBF); - // MBF considers that friendly monsters are not blocked by monster-blocking lines. - // This is added here as a compatibility option. Note that monsters that are dehacked - // into being friendly with the MBF flag automatically gain MF3_NOBLOCKMONST, so this - // just optionally generalizes the behavior to other friendly monsters. - bool NotBlocked = ((tm.thing->flags3 & MF3_NOBLOCKMONST) - || ((tm.thing->Level->i_compatflags & COMPATF_NOBLOCKFRIENDS) && (tm.thing->flags & MF_FRIENDLY))); uint32_t ProjectileBlocking = ML_BLOCKEVERYTHING | ML_BLOCKPROJECTILE; if ( tm.thing->flags8 & MF8_BLOCKASPLAYER ) ProjectileBlocking |= ML_BLOCK_PLAYERS | ML_BLOCKING; @@ -865,11 +859,8 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec { rail = true; } - else if ((ld->flags & (ML_BLOCKING | ML_BLOCKEVERYTHING)) || // explicitly blocking everything - (!(NotBlocked) && (ld->flags & ML_BLOCKMONSTERS)) || // block monsters only - (((tm.thing->player != NULL) || (tm.thing->flags8 & MF8_BLOCKASPLAYER)) && (ld->flags & ML_BLOCK_PLAYERS)) || // block players - ((Projectile) && (ld->flags & ML_BLOCKPROJECTILE)) || // block projectiles - ((tm.thing->flags & MF_FLOAT) && (ld->flags & ML_BLOCK_FLOATERS))) // block floaters + else if (P_IsBlockedByLine(tm.thing, ld) || + ((Projectile) && (ld->flags & ML_BLOCKPROJECTILE))) { if (cres.portalflags & FFCF_NOFLOOR) { @@ -3002,19 +2993,7 @@ void FSlide::SlideTraverse(const DVector2 &start, const DVector2 &end) } goto isblocking; } - if (li->flags & (ML_BLOCKING | ML_BLOCKEVERYTHING)) - { - goto isblocking; - } - if (li->flags & ML_BLOCK_PLAYERS && ((slidemo->player != NULL) || (slidemo->flags8 & MF8_BLOCKASPLAYER))) - { - goto isblocking; - } - if (li->flags & ML_BLOCKMONSTERS && !((slidemo->flags3 & MF3_NOBLOCKMONST) - || ((slidemo->Level->i_compatflags & COMPATF_NOBLOCKFRIENDS) && (slidemo->flags & MF_FRIENDLY)))) - { - goto isblocking; - } + if (P_IsBlockedByLine(slidemo, li)) goto isblocking; // set openrange, opentop, openbottom P_LineOpening(open, slidemo, li, it.InterceptPoint(in)); diff --git a/src/playsim/po_man.cpp b/src/playsim/po_man.cpp index 8bbf80142..8d100bb71 100644 --- a/src/playsim/po_man.cpp +++ b/src/playsim/po_man.cpp @@ -1080,11 +1080,7 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd) open.top = LINEOPEN_MAX; open.bottom = LINEOPEN_MIN; // [TN] Check wether this actor gets blocked by the line. - if (ld->backsector != nullptr && - !(ld->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING)) - && !(ld->flags & ML_BLOCK_PLAYERS && (mobj->player || (mobj->flags8 & MF8_BLOCKASPLAYER))) - && !(ld->flags & ML_BLOCKMONSTERS && mobj->flags3 & MF3_ISMONSTER) - && !((mobj->flags & MF_FLOAT) && (ld->flags & ML_BLOCK_FLOATERS)) + if (ld->backsector != nullptr && !P_IsBlockedByLine(mobj, ld) && (!(ld->flags & ML_3DMIDTEX) || (!P_LineOpening_3dMidtex(mobj, ld, open) && (mobj->Top() < open.top) diff --git a/src/scripting/vmthunks.cpp b/src/scripting/vmthunks.cpp index 8068b1cc0..b37114191 100644 --- a/src/scripting/vmthunks.cpp +++ b/src/scripting/vmthunks.cpp @@ -2768,6 +2768,7 @@ DEFINE_FIELD_X(Line, line_t, v1) DEFINE_FIELD_X(Line, line_t, v2) DEFINE_FIELD_X(Line, line_t, delta) DEFINE_FIELD_X(Line, line_t, flags) +DEFINE_FIELD_X(Line, line_t, flags2) DEFINE_FIELD_X(Line, line_t, activation) DEFINE_FIELD_X(Line, line_t, special) DEFINE_FIELD_X(Line, line_t, args) diff --git a/src/version.h b/src/version.h index f5367c1de..c316cd3c6 100644 --- a/src/version.h +++ b/src/version.h @@ -88,7 +88,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4558 +#define SAVEVER 4559 // This is so that derivates can use the same savegame versions without worrying about engine compatibility #define GAMESIG "GZDOOM" diff --git a/wadsrc/static/xlat/defines.i b/wadsrc/static/xlat/defines.i index 0b0999478..025980382 100644 --- a/wadsrc/static/xlat/defines.i +++ b/wadsrc/static/xlat/defines.i @@ -236,6 +236,7 @@ enum ML_FIRSTSIDEONLY = 0x00800000, ML_BLOCKPROJECTILE = 0x01000000, ML_BLOCKUSE = 0x02000000, + ML_BLOCKLANDMONSTERS = 0x80000001, // goes into the second flag word. // ML_PASSTHROUGH = -1, diff --git a/wadsrc/static/xlat/doom.txt b/wadsrc/static/xlat/doom.txt index c3c037d77..7915f0833 100644 --- a/wadsrc/static/xlat/doom.txt +++ b/wadsrc/static/xlat/doom.txt @@ -40,3 +40,5 @@ lineflag 8 = ML_MAPPED; lineflag 9 = ML_PASSTHROUGH; lineflag 10 = ML_3DMIDTEX; lineflag 11 & (ML_BLOCKING|ML_BLOCKMONSTERS|ML_TWOSIDED|ML_DONTPEGTOP|ML_DONTPEGBOTTOM|ML_SECRET|ML_SOUNDBLOCK|ML_DONTDRAW|ML_MAPPED); +lineflag 12 = ML_BLOCKLANDMONSTERS; +lineflag 13 = ML_BLOCK_PLAYERS; diff --git a/wadsrc/static/zscript/mapdata.zs b/wadsrc/static/zscript/mapdata.zs index 08ecddf1f..f0cfce1c0 100644 --- a/wadsrc/static/zscript/mapdata.zs +++ b/wadsrc/static/zscript/mapdata.zs @@ -162,10 +162,15 @@ struct Line native play ML_3DMIDTEX_IMPASS = 0x10000000, // [TP] if 3D midtex, behaves like a height-restricted ML_BLOCKING }; + enum ELineFlags2 + { + ML2_BLOCKLANDMONSTERS = 1, + } native readonly vertex v1, v2; // vertices, from v1 to v2 native readonly Vector2 delta; // precalculated v2 - v1 for side checking native uint flags; + native uint flags2; native uint activation; // activation type native int special; native int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width)