From 2516b8f8af7f384a7e22fd50ec82b1fd50e5c6ba Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 4 Feb 2016 20:36:39 -0600 Subject: [PATCH 01/14] Adjusted the assert conditions in DoJump() - With multiple A_Jump calls possible in a single action now, it is now possible for DoJump() to be called with a callingstate that does not match self->state because the state had been changed by a prior A_Jump in the same action function. --- src/thingdef/thingdef_codeptr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index ba5bc7f47..a3e4ac6fa 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -676,7 +676,7 @@ static void DoJump(AActor *self, AActor *stateowner, FState *callingstate, FStat { P_SetPsprite(self->player, ps_flash, jumpto); } - else if (callingstate == self->state) + else if (callingstate == self->state || (self->ObjectFlags & OF_StateChanged)) { // Rather than using self->SetState(jumpto) to set the state, // set the state directly. Since this function is only called by From 6639984772a3409a1a11d2c5e102352ad345ca15 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 5 Feb 2016 14:24:20 +0100 Subject: [PATCH 02/14] - removed Line_SetVisualPortal special. This will be folded into Line_SetPortal later --- src/actionspecials.h | 1 - src/p_setup.cpp | 1 - src/portal.cpp | 5 ++--- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/actionspecials.h b/src/actionspecials.h index a9813c24f..7e783051e 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -139,7 +139,6 @@ DEFINE_SPECIAL(Sector_ChangeSound, 140, 2, 2, 2) DEFINE_SPECIAL(Teleport_NoStop, 154, 2, 3, 3) // portal specials -DEFINE_SPECIAL(Line_SetVisualPortal, 155, -1, -1, 3) DEFINE_SPECIAL(Line_SetPortal, 156, -1, -1, 3) // GZDoom/Vavoom specials // Although ZDoom doesn't support them it's better to have them defined so that diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 82e4a88ba..5988a73cf 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1962,7 +1962,6 @@ void P_SetLineID (int i, line_t *ld) break; case Line_SetPortal: - case Line_SetVisualPortal: setid = ld->args[1]; // 0 = target id, 1 = this id, 2 = plane anchor break; } diff --git a/src/portal.cpp b/src/portal.cpp index 7e8405d57..d45219ea3 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -91,8 +91,7 @@ bool P_CheckPortal(line_t* line) line->portal_passive = true; line->portal_dst = line; } - else if (line->special == Line_SetPortal || - line->special == Line_SetVisualPortal) + else if (line->special == Line_SetPortal) { // portal destination is special argument #0 line_t* dst = NULL; @@ -117,7 +116,7 @@ bool P_CheckPortal(line_t* line) { line->portal = true; line->portal_mirror = false; - line->portal_passive = (line->special == Line_SetVisualPortal); + line->portal_passive = true;// !!(line->args[2] & PORTAL_VISUAL; (line->special == Line_SetVisualPortal); line->portal_dst = dst; } else From 01b075660d18e53382f7f2a95ce3db0e218d9832 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 5 Feb 2016 14:34:01 +0100 Subject: [PATCH 03/14] - removed the option to toggle portals with SetLineSpecial. This is to keep some people from jumping the gun on this and preventing the implementation of a proper toggling mechanism. The feature itself will come back, but differently. - removed portal setup from Build maps they don't define it anyway so it makes no sense to have it there. Once this code gets refactored this will be in a different place that's identical for all map types. --- src/p_acs.cpp | 3 --- src/p_buildmap.cpp | 5 ----- 2 files changed, 8 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index e53b8dec6..7115b611c 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -8299,9 +8299,6 @@ scriptwait: line->args[4] = STACK(1); DPrintf("Set special on line %d (id %d) to %d(%d,%d,%d,%d,%d)\n", linenum, STACK(7), specnum, arg0, STACK(4), STACK(3), STACK(2), STACK(1)); - - // [ZZ] re-link with portals (in case this was something related to portal specials) - P_CheckPortal(line); } sp -= 7; } diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp index e72d87d06..295dff831 100644 --- a/src/p_buildmap.cpp +++ b/src/p_buildmap.cpp @@ -630,11 +630,6 @@ static void LoadWalls (walltype *walls, int numwalls, sectortype *bsec) } } - // [ZZ] set initial line portal link - // (even though this is rather hard to happen... build doesn't have portals in our sense and it's walls don't get translated into anything like this) - for (int i = 0; i < numlines; i++) - P_CheckPortal(&lines[i]); - // Finish setting sector properties that depend on walls for (i = 0; i < numsectors; ++i, ++bsec) { From 00895c245eaa398c1f428db9147f5b1890b40e38 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 5 Feb 2016 15:39:06 +0100 Subject: [PATCH 04/14] - mpved all software renderer specific code for the portals into the render sources. --- src/portal.cpp | 4 ---- src/portal.h | 19 ------------------- src/r_bsp.h | 2 -- src/r_main.cpp | 1 + src/r_segs.cpp | 3 +++ src/r_segs.h | 21 +++++++++++++++++++++ 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/portal.cpp b/src/portal.cpp index d45219ea3..3b17eb74a 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -10,10 +10,6 @@ // simulation recurions maximum CVAR(Int, sv_portal_recursions, 4, CVAR_ARCHIVE|CVAR_SERVERINFO) -PortalDrawseg* CurrentPortal = NULL; -int CurrentPortalUniq = 0; -bool CurrentPortalInSkybox = false; - // [ZZ] lots of floats here to avoid overflowing a lot bool R_IntersectLines(fixed_t o1x, fixed_t o1y, fixed_t p1x, fixed_t p1y, fixed_t o2x, fixed_t o2y, fixed_t p2x, fixed_t p2y, diff --git a/src/portal.h b/src/portal.h index 103e3072b..be4848821 100644 --- a/src/portal.h +++ b/src/portal.h @@ -8,25 +8,6 @@ #include "p_local.h" #include "m_bbox.h" -/* portal structure, this is used in r_ code in order to store drawsegs with portals (and mirrors) */ -struct PortalDrawseg -{ - line_t* src; // source line (the one drawn) this doesn't change over render loops - line_t* dst; // destination line (the one that the portal is linked with, equals 'src' for mirrors) - - int x1; // drawseg x1 - int x2; // drawseg x2 - - int len; - TArray ceilingclip; - TArray floorclip; - - bool mirror; // true if this is a mirror (src should equal dst) -}; - -extern PortalDrawseg* CurrentPortal; -extern int CurrentPortalUniq; -extern bool CurrentPortalInSkybox; /* code ported from prototype */ bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t viewy, bool partial = true, bool samebehind = true); diff --git a/src/r_bsp.h b/src/r_bsp.h index 3b2a399e3..8c19a2670 100644 --- a/src/r_bsp.h +++ b/src/r_bsp.h @@ -107,8 +107,6 @@ extern size_t FirstInterestingDrawseg; extern int WindowLeft, WindowRight; extern WORD MirrorFlags; -extern TArray WallPortals; - typedef void (*drawfunc_t) (int start, int stop); EXTERN_CVAR (Bool, r_drawflat) // [RH] Don't texture segs? diff --git a/src/r_main.cpp b/src/r_main.cpp index 4c2b89c0a..883ab13dc 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -37,6 +37,7 @@ #include "r_local.h" #include "r_plane.h" #include "r_bsp.h" +#include "r_segs.h" #include "r_3dfloors.h" #include "r_sky.h" #include "st_stuff.h" diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 1f09dbf18..79b5251c4 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -67,6 +67,9 @@ CVAR(Bool, r_np2, true, 0) extern fixed_t globaluclip, globaldclip; +PortalDrawseg* CurrentPortal = NULL; +int CurrentPortalUniq = 0; +bool CurrentPortalInSkybox = false; // OPTIMIZE: closed two sided lines as single sided diff --git a/src/r_segs.h b/src/r_segs.h index b8bf96511..e2f8d7611 100644 --- a/src/r_segs.h +++ b/src/r_segs.h @@ -49,4 +49,25 @@ extern fixed_t rw_lightstep; extern fixed_t rw_lightleft; extern fixed_t rw_offset; +/* portal structure, this is used in r_ code in order to store drawsegs with portals (and mirrors) */ +struct PortalDrawseg +{ + line_t* src; // source line (the one drawn) this doesn't change over render loops + line_t* dst; // destination line (the one that the portal is linked with, equals 'src' for mirrors) + + int x1; // drawseg x1 + int x2; // drawseg x2 + + int len; + TArray ceilingclip; + TArray floorclip; + + bool mirror; // true if this is a mirror (src should equal dst) +}; + +extern PortalDrawseg* CurrentPortal; +extern int CurrentPortalUniq; +extern bool CurrentPortalInSkybox; +extern TArray WallPortals; + #endif From a85a8c1465ea905c0fbbf65b2fa1a3acea1f6146 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 5 Feb 2016 16:14:45 +0100 Subject: [PATCH 05/14] - changed mirror handling so that it works without attaching a portal to the mirror line and removed line_t::portal_mirror member. - did some cleanup on the portal interface on linedefs: All checks should go through isLinePortal (gameplay related) and isVisualPortal (renderer related) which then can decide on the actual data what to return. - removed portal_passive because it won't survive the upcoming refactoring. - removed all direct access to portal members of line_t. - always use the precise (and fast) version of P_PointOnLineSide inside the renderer. --- src/portal.cpp | 37 ++++++++++--------------------------- src/r_bsp.cpp | 2 +- src/r_defs.h | 21 ++++++++++++++++----- src/r_segs.cpp | 7 +++---- src/r_things.cpp | 7 ++++--- 5 files changed, 34 insertions(+), 40 deletions(-) diff --git a/src/portal.cpp b/src/portal.cpp index 3b17eb74a..02ff5e7fd 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -80,14 +80,7 @@ bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t vie bool P_CheckPortal(line_t* line) { - if (line->special == Line_Mirror) - { - line->portal = true; - line->portal_mirror = true; - line->portal_passive = true; - line->portal_dst = line; - } - else if (line->special == Line_SetPortal) + if (line->special == Line_SetPortal) { // portal destination is special argument #0 line_t* dst = NULL; @@ -110,28 +103,18 @@ bool P_CheckPortal(line_t* line) if (dst) { - line->portal = true; - line->portal_mirror = false; - line->portal_passive = true;// !!(line->args[2] & PORTAL_VISUAL; (line->special == Line_SetVisualPortal); - line->portal_dst = dst; + line->_portal = true; + //line->portal_passive = true;// !!(line->args[2] & PORTAL_VISUAL; (line->special == Line_SetVisualPortal); + line->_portal_dst = dst; } else { - line->portal = false; - line->portal_mirror = false; - line->portal_passive = false; - line->portal_dst = NULL; + line->_portal = false; + //line->portal_passive = false; + line->_portal_dst = NULL; } } - else - { - line->portal = false; - line->portal_mirror = false; - line->portal_passive = false; - line->portal_dst = NULL; - } - - return (line->portal); + return (line->_portal); } void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y) @@ -297,12 +280,12 @@ bool PortalTracer::TraceStep() { li = in->d.line; - if (li->portal && !li->portal_passive) + if (li->isLinePortal()) { if (P_PointOnLineSide(startx-dirx, starty-diry, li)) continue; // we're at the back side of this line - line_t* out = li->portal_dst; + line_t* out = li->getPortalDestination(); this->in = li; this->out = out; diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index e9802e5b1..a6dd7f61b 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -590,7 +590,7 @@ void R_AddLine (seg_t *line) rw_havehigh = rw_havelow = false; // Single sided line? - if (backsector == NULL || (line->linedef->portal && line->sidedef == line->linedef->sidedef[0])) + if (backsector == NULL || (line->linedef->isVisualPortal() && line->sidedef == line->linedef->sidedef[0])) { solid = true; } diff --git a/src/r_defs.h b/src/r_defs.h index fb40a2bd1..901dadcb0 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -988,14 +988,25 @@ struct line_t sector_t *frontsector, *backsector; int validcount; // if == validcount, already checked int locknumber; // [Dusk] lock number for special - line_t *portal_dst; - bool portal; - bool portal_mirror; - bool portal_passive; + line_t *_portal_dst; + bool _portal; + + // returns true if the portal is crossable by actors bool isLinePortal() const { - return portal; + return false; // right now there are no crossable portals + } + + // returns true if the portal needs to be handled by the renderer + bool isVisualPortal() const + { + return _portal; + } + + line_t *getPortalDestination() const + { + return _portal_dst; } }; diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 79b5251c4..59bf12b39 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -2004,8 +2004,7 @@ void R_NewWall (bool needlights) midtexture = toptexture = bottomtexture = 0; if (sidedef == linedef->sidedef[0] && - linedef->portal && - (!linedef->portal_mirror || r_drawmirrors)) // [ZZ] compatibility with r_drawmirrors cvar that existed way before portals + (linedef->isVisualPortal() || (linedef->special == Line_Mirror && r_drawmirrors))) // [ZZ] compatibility with r_drawmirrors cvar that existed way before portals { markfloor = markceiling = true; // act like an one-sided wall here (todo: check how does this work with transparency) rw_markportal = true; @@ -2632,7 +2631,7 @@ void R_StoreWallRange (int start, int stop) { PortalDrawseg pds; pds.src = curline->linedef; - pds.dst = curline->linedef->portal_dst; + pds.dst = curline->linedef->special == Line_Mirror? curline->linedef : curline->linedef->getPortalDestination(); pds.x1 = ds_p->x1; pds.x2 = ds_p->x2; pds.len = pds.x2 - pds.x1; @@ -2653,7 +2652,7 @@ void R_StoreWallRange (int start, int stop) pds.floorclip[i] = RenderTarget->GetHeight()-1; } - pds.mirror = curline->linedef->portal_mirror; + pds.mirror = curline->linedef->special == Line_Mirror; WallPortals.Push(pds); } diff --git a/src/r_things.cpp b/src/r_things.cpp index 003e3a758..682ad5f35 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -31,6 +31,7 @@ #include #include +#include "p_lnspec.h" #include "templates.h" #include "doomdef.h" #include "m_swap.h" @@ -339,11 +340,11 @@ static inline bool R_ClipSpriteColumnWithPortals (fixed_t x, fixed_t y, vissprit if (!seg->curline) continue; line_t* line = seg->curline->linedef; - // divline? wtf, anyway, divlines aren't supposed to be drawn. But I definitely saw NULL linedefs in drawsegs. + // ignore minisegs from GL nodes. if (!line) continue; // check if this line will clip sprites to itself - if (!line->portal) + if (!line->isVisualPortal() && line->special != Line_Mirror) continue; // don't clip sprites with portal's back side (it's transparent) @@ -739,7 +740,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor // [ZZ] Or less definitely not visible (hue) // [ZZ] 10.01.2016: don't try to clip stuff inside a skybox against the current portal. - if (!CurrentPortalInSkybox && CurrentPortal && !!P_PointOnLineSide(thing->X(), thing->Y(), CurrentPortal->dst)) + if (!CurrentPortalInSkybox && CurrentPortal && !!P_PointOnLineSidePrecise(thing->X(), thing->Y(), CurrentPortal->dst)) return; // [RH] Interpolate the sprite's position to make it look smooth From 9eaefc3685d4f2f344c4ca33e0fdd58d2a38befb Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 5 Feb 2016 16:58:57 +0100 Subject: [PATCH 06/14] - initialize portals with all other static line specials instead of doing it separately in P_FinishLoadingLineDefs when the map isn't fully set up yet. - replace all float use in portal.cpp with doubles. --- src/p_setup.cpp | 3 -- src/p_spec.cpp | 5 +++ src/portal.cpp | 88 +++++++++++++++++++++++-------------------------- src/portal.h | 3 +- 4 files changed, 49 insertions(+), 50 deletions(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 5988a73cf..6229d811c 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -2064,9 +2064,6 @@ void P_FinishLoadingLineDef(line_t *ld, int alpha) ld->special = 0; break; } - - // [ZZ] check initial portal link - P_CheckPortal(ld); } // killough 4/4/98: delay using sidedefs until they are loaded void P_FinishLoadingLineDefs () diff --git a/src/p_spec.cpp b/src/p_spec.cpp index fd505f207..15182661b 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -64,6 +64,7 @@ #include "a_keys.h" #include "c_dispatch.h" #include "r_sky.h" +#include "portal.h" // State. #include "r_state.h" @@ -1428,6 +1429,10 @@ void P_SpawnSpecials (void) } break; + case Line_SetPortal: + P_SpawnLinePortal(&lines[i]); + break; + // [RH] ZDoom Static_Init settings case Static_Init: switch (lines[i].args[1]) diff --git a/src/portal.cpp b/src/portal.cpp index 02ff5e7fd..2d99a3df7 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -11,15 +11,15 @@ CVAR(Int, sv_portal_recursions, 4, CVAR_ARCHIVE|CVAR_SERVERINFO) // [ZZ] lots of floats here to avoid overflowing a lot -bool R_IntersectLines(fixed_t o1x, fixed_t o1y, fixed_t p1x, fixed_t p1y, +bool P_IntersectLines(fixed_t o1x, fixed_t o1y, fixed_t p1x, fixed_t p1y, fixed_t o2x, fixed_t o2y, fixed_t p2x, fixed_t p2y, fixed_t& rx, fixed_t& ry) { - float xx = FIXED2FLOAT(o2x) - FIXED2FLOAT(o1x); - float xy = FIXED2FLOAT(o2y) - FIXED2FLOAT(o1y); + double xx = FIXED2DBL(o2x) - FIXED2DBL(o1x); + double xy = FIXED2DBL(o2y) - FIXED2DBL(o1y); - float d1x = FIXED2FLOAT(p1x) - FIXED2FLOAT(o1x); - float d1y = FIXED2FLOAT(p1y) - FIXED2FLOAT(o1y); + double d1x = FIXED2DBL(p1x) - FIXED2DBL(o1x); + double d1y = FIXED2DBL(p1y) - FIXED2DBL(o1y); if (d1x > d1y) { @@ -32,14 +32,14 @@ bool R_IntersectLines(fixed_t o1x, fixed_t o1y, fixed_t p1x, fixed_t p1y, d1y = 32767.0; } - float d2x = FIXED2FLOAT(p2x) - FIXED2FLOAT(o2x); - float d2y = FIXED2FLOAT(p2y) - FIXED2FLOAT(o2y); + double d2x = FIXED2DBL(p2x) - FIXED2DBL(o2x); + double d2y = FIXED2DBL(p2y) - FIXED2DBL(o2y); - float cross = d1x*d2y - d1y*d2x; + double cross = d1x*d2y - d1y*d2x; if (fabs(cross) < 1e-8) return false; - float t1 = (xx * d2y - xy * d2x)/cross; + double t1 = (xx * d2y - xy * d2x)/cross; rx = o1x + FLOAT2FIXED(d1x * t1); ry = o1y + FLOAT2FIXED(d1y * t1); return true; @@ -53,8 +53,8 @@ inline int P_PointOnLineSideExplicit (fixed_t x, fixed_t y, fixed_t x1, fixed_t bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t viewy, bool partial, bool samebehind) { // check if this line is between portal and the viewer. clip away if it is. - bool behind1 = !!P_PointOnLineSide(line->v1->x, line->v1->y, portal); - bool behind2 = !!P_PointOnLineSide(line->v2->x, line->v2->y, portal); + bool behind1 = !!P_PointOnLineSidePrecise(line->v1->x, line->v1->y, portal); + bool behind2 = !!P_PointOnLineSidePrecise(line->v2->x, line->v2->y, portal); // [ZZ] update 16.12.2014: if a vertex equals to one of portal's vertices, it's treated as being behind the portal. // this is required in order to clip away diagonal lines around the portal (example: 1-sided triangle shape with a mirror on it's side) @@ -69,8 +69,8 @@ bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t vie { // line is behind the portal plane. now check if it's in front of two view plane borders (i.e. if it will get in the way of rendering) fixed_t dummyx, dummyy; - bool infront1 = R_IntersectLines(line->v1->x, line->v1->y, line->v2->x, line->v2->y, viewx, viewy, portal->v1->x, portal->v1->y, dummyx, dummyy); - bool infront2 = R_IntersectLines(line->v1->x, line->v1->y, line->v2->x, line->v2->y, viewx, viewy, portal->v2->x, portal->v2->y, dummyx, dummyy); + bool infront1 = P_IntersectLines(line->v1->x, line->v1->y, line->v2->x, line->v2->y, viewx, viewy, portal->v1->x, portal->v1->y, dummyx, dummyy); + bool infront2 = P_IntersectLines(line->v1->x, line->v1->y, line->v2->x, line->v2->y, viewx, viewy, portal->v2->x, portal->v2->y, dummyx, dummyy); if (infront1 && infront2) return true; } @@ -78,43 +78,39 @@ bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t vie return false; } -bool P_CheckPortal(line_t* line) +void P_SpawnLinePortal(line_t* line) { - if (line->special == Line_SetPortal) + // portal destination is special argument #0 + line_t* dst = NULL; + + if (line->args[0] > 0) { - // portal destination is special argument #0 - line_t* dst = NULL; + int linenum = -1; - if (line->args[0] > 0) + for (int i = 0; i < numlines; i++) { - int linenum = -1; - - for (int i = 0; i < numlines; i++) + if (&lines[i] == line) + continue; + if (tagManager.LineHasID(&lines[i], line->args[0])) { - if (&lines[i] == line) - continue; - if (tagManager.LineHasID(&lines[i], line->args[0])) - { - dst = &lines[i]; - break; - } + dst = &lines[i]; + break; } } - - if (dst) - { - line->_portal = true; - //line->portal_passive = true;// !!(line->args[2] & PORTAL_VISUAL; (line->special == Line_SetVisualPortal); - line->_portal_dst = dst; - } - else - { - line->_portal = false; - //line->portal_passive = false; - line->_portal_dst = NULL; - } } - return (line->_portal); + + if (dst) + { + line->_portal = true; + //line->portal_passive = true;// !!(line->args[2] & PORTAL_VISUAL; (line->special == Line_SetVisualPortal); + line->_portal_dst = dst; + } + else + { + line->_portal = false; + //line->portal_passive = false; + line->_portal_dst = NULL; + } } void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y) @@ -222,9 +218,9 @@ fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y) void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy) { - float _vx = FIXED2FLOAT(vx); - float _vy = FIXED2FLOAT(vy); - float len = sqrt(_vx*_vx+_vy*_vy); + double _vx = FIXED2DBL(vx); + double _vy = FIXED2DBL(vy); + double len = sqrt(_vx*_vx+_vy*_vy); vx = FLOAT2FIXED(_vx/len); vy = FLOAT2FIXED(_vy/len); } @@ -339,7 +335,7 @@ bool PortalTracer::TraceStep() } } - //Printf("returning %d; vx = %.2f; vy = %.2f\n", (oDepth != depth), FIXED2FLOAT(this->vx), FIXED2FLOAT(this->vy)); + //Printf("returning %d; vx = %.2f; vy = %.2f\n", (oDepth != depth), FIXED2DBL(this->vx), FIXED2DBL(this->vy)); return (oDepth != depth); // if a portal has been found, return false } diff --git a/src/portal.h b/src/portal.h index be4848821..3b707f543 100644 --- a/src/portal.h +++ b/src/portal.h @@ -8,10 +8,11 @@ #include "p_local.h" #include "m_bbox.h" +void P_SpawnLinePortal(line_t* line); + /* code ported from prototype */ bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t viewy, bool partial = true, bool samebehind = true); -bool P_CheckPortal(line_t* line); void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y); void P_TranslatePortalVXVY(line_t* src, line_t* dst, fixed_t& vx, fixed_t& vy); void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle); From 42287213519d1fc5a659206959a928c0f83cdda0 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 5 Feb 2016 14:19:14 -0600 Subject: [PATCH 07/14] Enable running when built with Clang's -fsanitize=address --- src/autosegs.h | 6 ++++-- src/dobjtype.cpp | 2 +- src/doomtype.h | 10 ++++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/autosegs.h b/src/autosegs.h index 61872610c..f62632139 100644 --- a/src/autosegs.h +++ b/src/autosegs.h @@ -35,6 +35,8 @@ #ifndef AUTOSEGS_H #define AUTOSEGS_H +#include "doomtype.h" + #define REGMARKER(x) (x) typedef void * const REGINFO; typedef void * NCREGINFO; @@ -73,11 +75,11 @@ class FAutoSegIterator } Probe = Head; } - NCREGINFO operator*() const + NCREGINFO operator*() const NO_SANITIZE { return *Probe; } - FAutoSegIterator &operator++() + FAutoSegIterator &operator++() NO_SANITIZE { do { diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index cc0a077f2..d9af4044a 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1986,7 +1986,7 @@ END_POINTERS // //========================================================================== -static int STACK_ARGS cregcmp (const void *a, const void *b) +static int STACK_ARGS cregcmp (const void *a, const void *b) NO_SANITIZE { const PClass *class1 = *(const PClass **)a; const PClass *class2 = *(const PClass **)b; diff --git a/src/doomtype.h b/src/doomtype.h index 06541f526..0d9a13ff4 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -113,6 +113,16 @@ typedef TMap FClassMap; #define NOVTABLE #endif +#if defined(__clang__) +#if defined(__has_feature) && __has_feature(address_sanitizer)) +#define NO_SANITIZE __attribute__((no_sanitize("address"))) +#else +#define NO_SANITIZE +#endif +#else +#define NO_SANITIZE +#endif + #include "basictypes.h" // Bounding box coordinate storage. From 26eb3356226c18b7004c33009a9bdc2db42e5ff1 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 5 Feb 2016 16:07:18 -0600 Subject: [PATCH 08/14] Quiet a couple GCC warnings --- src/name.cpp | 2 +- src/p_lnspec.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/name.cpp b/src/name.cpp index 5ab361d42..359f3398c 100644 --- a/src/name.cpp +++ b/src/name.cpp @@ -182,7 +182,7 @@ void FName::NameManager::InitBuckets () // Register built-in names. 'None' must be name 0. for (size_t i = 0; i < countof(PredefinedNames); ++i) { - assert((NULL == FindName(PredefinedNames[i], true)) && "Predefined name already inserted"); + assert((0 == FindName(PredefinedNames[i], true)) && "Predefined name already inserted"); FindName (PredefinedNames[i], false); } } diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 1e1f76923..c74378f61 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -3777,7 +3777,7 @@ int P_ExecuteSpecial(int num, int arg4, int arg5) { - if (num >= 0 && num < countof(LineSpecials)) + if (num >= 0 && num < (int)countof(LineSpecials)) { return LineSpecials[num](line, activator, backSide, arg1, arg2, arg3, arg4, arg5); } From 3ad2e4191dd584153905de8c5597e1df2dc5b25c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 5 Feb 2016 16:08:20 -0600 Subject: [PATCH 09/14] Remove fudging from the end of (O)WallMost - This might have been added in an effort to fix problems caused by mixing inclusive and exclusive right edges. It might not be needed anymore. Let's find out... --- src/r_segs.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 59bf12b39..96a0595d7 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -520,7 +520,7 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2) wallupper[i] = mceilingclip[i]; } mceilingclip = wallupper; - } + } if (fake3D & FAKE3D_CLIPBOTTOM) { OWallMost(walllower, sclipBottom - viewz, &WallC); @@ -2763,11 +2763,6 @@ int OWallMost (short *mostbuf, fixed_t z, const FWallCoords *wallc) } #endif #endif - if (mostbuf[ix1] < 0) mostbuf[ix1] = 0; - else if (mostbuf[ix1] > viewheight) mostbuf[ix1] = (short)viewheight; - if (mostbuf[ix2-1] < 0) mostbuf[ix2-1] = 0; - else if (mostbuf[ix2-1] > viewheight) mostbuf[ix2-1] = (short)viewheight; - return bad; } @@ -2921,11 +2916,6 @@ int WallMost (short *mostbuf, const secplane_t &plane, const FWallCoords *wallc) qinterpolatedown16short (&mostbuf[ix1], ix2-ix1, y + centeryfrac,yinc); } - if (mostbuf[ix1] < 0) mostbuf[ix1] = 0; - else if (mostbuf[ix1] > viewheight) mostbuf[ix1] = (short)viewheight; - if (mostbuf[ix2-1] < 0) mostbuf[ix2-1] = 0; - else if (mostbuf[ix2-1] > viewheight) mostbuf[ix2-1] = (short)viewheight; - return bad; } From 94b7ef72ca680fcdfa4773e2410f7e9947cd2a56 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 5 Feb 2016 23:15:56 +0100 Subject: [PATCH 10/14] - more cleanup on portal implementation: - store portal data in a separate structure. - store portal data in savegames because some of this will be changeable later. - run a cleanup pass after all portals have been created to weed out broken ones. - add a definition type that's compatible with Eternity Engine's line portal types. - swapped arg[2] and arg[3] of Line_SetPortal, because the type is more significant than the alignment. --- src/farchive.h | 2 + src/p_saveg.cpp | 16 +++++ src/p_setup.cpp | 4 ++ src/p_spec.cpp | 1 + src/p_tags.cpp | 12 ++++ src/p_tags.h | 1 + src/p_udmf.cpp | 1 + src/portal.cpp | 168 ++++++++++++++++++++++++++++++++++++------------ src/portal.h | 66 +++++++++++++++++++ src/r_bsp.cpp | 2 +- src/r_defs.h | 22 ++----- src/r_utility.h | 5 ++ src/version.h | 2 +- 13 files changed, 243 insertions(+), 59 deletions(-) diff --git a/src/farchive.h b/src/farchive.h index 64c7cc9fe..b6a223bab 100644 --- a/src/farchive.h +++ b/src/farchive.h @@ -286,9 +286,11 @@ template<> inline FArchive &operator<< (FArchive &arc, FFont* &font) struct FStrifeDialogueNode; struct FSwitchDef; struct FDoorAnimation; +struct FLinePortal; template<> FArchive &operator<< (FArchive &arc, FStrifeDialogueNode *&node); template<> FArchive &operator<< (FArchive &arc, FSwitchDef* &sw); template<> FArchive &operator<< (FArchive &arc, FDoorAnimation* &da); +FArchive &operator<< (FArchive &arc, FLinePortal &da); diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 31eb76c7a..f0aedd5c6 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -53,6 +53,7 @@ #include "p_lnspec.h" #include "p_acs.h" #include "p_terrain.h" +#include "portal.h" static void CopyPlayer (player_t *dst, player_t *src, const char *name); static void ReadOnePlayer (FArchive &arc, bool skipload); @@ -474,6 +475,12 @@ void P_SerializeWorld (FArchive &arc) } arc << li->args[1] << li->args[2] << li->args[3] << li->args[4]; + if (SaveVersion >= 4532) + { + arc << li->portalindex; + } + else li->portalindex = UINT_MAX; + for (j = 0; j < 2; j++) { if (li->sidedef[j] == NULL) @@ -508,6 +515,15 @@ void P_SerializeWorld (FArchive &arc) { arc << zn->Environment; } + + if (SaveVersion >= 4532) + { + arc << linePortals; + } + else + { + linePortals.Clear(); + } } void extsector_t::Serialize(FArchive &arc) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 6229d811c..d1519d031 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -2156,6 +2156,7 @@ void P_LoadLineDefs (MapData * map) for (i = 0; i < numlines; i++, mld++, ld++) { ld->Alpha = FRACUNIT; // [RH] Opaque by default + ld->portalindex = UINT_MAX; // [RH] Translate old linedef special and flags to be // compatible with the new format. @@ -2236,6 +2237,8 @@ void P_LoadLineDefs2 (MapData * map) { int j; + ld->portalindex = UINT_MAX; + for (j = 0; j < 5; j++) ld->args[j] = mld->args[j]; @@ -3365,6 +3368,7 @@ void P_FreeLevelData () level.killed_monsters = level.found_items = level.found_secrets = wminfo.maxfrags = 0; + linePortals.Clear(); FBehavior::StaticUnloadModules (); if (vertexes != NULL) { diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 15182661b..833e3b632 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1504,6 +1504,7 @@ void P_SpawnSpecials (void) } // [RH] Start running any open scripts on this map FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false); + P_FinalizePortals(); } // killough 2/28/98: diff --git a/src/p_tags.cpp b/src/p_tags.cpp index 15528378b..30b0db819 100644 --- a/src/p_tags.cpp +++ b/src/p_tags.cpp @@ -247,6 +247,18 @@ bool FTagManager::SectorHasTag(const sector_t *sector, int tag) const // //----------------------------------------------------------------------------- +int FTagManager::GetFirstLineID(const line_t *line) const +{ + int i = lineindex(line); + return LineHasIDs(i) ? allIDs[startForLine[i]].tag : 0; +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + bool FTagManager::LineHasID(int i, int tag) const { if (LineHasIDs(i)) diff --git a/src/p_tags.h b/src/p_tags.h index c3162d9b5..b351b04eb 100644 --- a/src/p_tags.h +++ b/src/p_tags.h @@ -57,6 +57,7 @@ public: bool SectorHasTag(int sector, int tag) const; bool SectorHasTag(const sector_t *sector, int tag) const; + int GetFirstLineID(const line_t *line) const; bool LineHasID(int line, int id) const; bool LineHasID(const line_t *line, int id) const; diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 366a56dcf..118ee2d95 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -792,6 +792,7 @@ public: memset(ld, 0, sizeof(*ld)); ld->Alpha = FRACUNIT; + ld->portalindex = UINT_MAX; ld->sidedef[0] = ld->sidedef[1] = NULL; if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX; if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX; diff --git a/src/portal.cpp b/src/portal.cpp index 2d99a3df7..b49eb0d3a 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -6,10 +6,128 @@ #include "c_cvars.h" #include "m_bbox.h" #include "p_tags.h" +#include "farchive.h" // simulation recurions maximum CVAR(Int, sv_portal_recursions, 4, CVAR_ARCHIVE|CVAR_SERVERINFO) +TArray linePortals; + + +FArchive &operator<< (FArchive &arc, FLinePortal &port) +{ + arc << port.mOrigin + << port.mDestination + << port.mXDisplacement + << port.mYDisplacement + << port.mType + << port.mFlags + << port.mDefFlags + << port.mAlign; + return arc; +} + + +void P_SpawnLinePortal(line_t* line) +{ + // portal destination is special argument #0 + line_t* dst = NULL; + + if (line->args[2] >= PORTT_VISUAL && line->args[2] <= PORTT_LINKED) + { + if (line->args[0] > 0) + { + int linenum = -1; + + for (int i = 0; i < numlines; i++) + { + if (&lines[i] == line) + continue; + if (tagManager.LineHasID(&lines[i], line->args[0])) + { + dst = &lines[i]; + break; + } + } + } + + line->portalindex = linePortals.Reserve(1); + FLinePortal *port = &linePortals.Last(); + + memset(port, 0, sizeof(FLinePortal)); + port->mOrigin = line; + port->mDestination = dst; + port->mType = BYTE(line->args[2]); // range check is done above. + port->mAlign = BYTE(line->args[3] >= PORG_ABSOLUTE && line->args[3] <= PORG_CEILING ? line->args[3] : PORG_ABSOLUTE); + if (port->mDestination != NULL) + { + port->mDefFlags = port->mType == PORTT_VISUAL ? PORTF_VISIBLE : port->mType == PORTT_TELEPORT ? PORTF_TYPETELEPORT : PORTF_TYPEINTERACTIVE; + + + } + } + else if (line->args[2] == PORTT_LINKEDEE && line->args[0] == 0) + { + // EE-style portals require that the first line ID is identical and the first arg of the two linked linedefs are 0 and 1 respectively. + + int mytag = tagManager.GetFirstLineID(line); + + for (int i = 0; i < numlines; i++) + { + if (tagManager.GetFirstLineID(&lines[i]) == mytag && lines[i].args[0] == 1) + { + line->portalindex = linePortals.Reserve(1); + FLinePortal *port = &linePortals.Last(); + + memset(port, 0, sizeof(FLinePortal)); + port->mOrigin = line; + port->mDestination = &lines[i]; + port->mType = PORTT_LINKED; + port->mAlign = PORG_ABSOLUTE; + port->mDefFlags = PORTF_TYPEINTERACTIVE; + } + } + } + else + { + // undefined type + return; + } +} + +void P_UpdatePortal(FLinePortal *port) +{ + if (port->mDestination == NULL) + { + // Portal has no destination: switch it off + port->mFlags = 0; + } + else if (port->mDestination->getPortalDestination() != port->mOrigin) + { + //portal doesn't link back. This will be a simple teleporter portal. + port->mFlags = port->mDefFlags & ~PORTF_INTERACTIVE; + if (port->mType == PORTT_LINKED) + { + // this is illegal. Demote the type to TELEPORT + port->mType = PORTT_TELEPORT; + port->mDefFlags &= ~PORTF_INTERACTIVE; + } + } + else + { + port->mFlags = port->mDefFlags; + } +} + +void P_FinalizePortals() +{ + for (unsigned i = 0; i < linePortals.Size(); i++) + { + FLinePortal * port = &linePortals[i]; + P_UpdatePortal(port); + } +} + // [ZZ] lots of floats here to avoid overflowing a lot bool P_IntersectLines(fixed_t o1x, fixed_t o1y, fixed_t p1x, fixed_t p1y, fixed_t o2x, fixed_t o2y, fixed_t p2x, fixed_t p2y, @@ -78,41 +196,6 @@ bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t vie return false; } -void P_SpawnLinePortal(line_t* line) -{ - // portal destination is special argument #0 - line_t* dst = NULL; - - if (line->args[0] > 0) - { - int linenum = -1; - - for (int i = 0; i < numlines; i++) - { - if (&lines[i] == line) - continue; - if (tagManager.LineHasID(&lines[i], line->args[0])) - { - dst = &lines[i]; - break; - } - } - } - - if (dst) - { - line->_portal = true; - //line->portal_passive = true;// !!(line->args[2] & PORTAL_VISUAL; (line->special == Line_SetVisualPortal); - line->_portal_dst = dst; - } - else - { - line->_portal = false; - //line->portal_passive = false; - line->_portal_dst = NULL; - } -} - void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y) { if (!src || !dst) @@ -185,17 +268,22 @@ void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle) void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z) { - // args[2] = 0 - no teleport + // args[2] = 0 - no adjustment // args[2] = 1 - adjust by floor difference // args[2] = 2 - adjust by ceiling difference - if (src->args[2] == 1) + switch (src->getPortalAlignment()) { + case PORG_FLOOR: z = z - src->frontsector->floorplane.ZatPoint(src->v1->x, src->v1->y) + dst->frontsector->floorplane.ZatPoint(dst->v2->x, dst->v2->y); - } - else if (src->args[2] == 2) - { + return; + + case PORG_CEILING: z = z - src->frontsector->ceilingplane.ZatPoint(src->v1->x, src->v1->y) + dst->frontsector->ceilingplane.ZatPoint(dst->v2->x, dst->v2->y); + return; + + default: + return; } } diff --git a/src/portal.h b/src/portal.h index 3b707f543..6a947fd0e 100644 --- a/src/portal.h +++ b/src/portal.h @@ -8,7 +8,50 @@ #include "p_local.h" #include "m_bbox.h" + +enum +{ + PORTF_VISIBLE = 1, + PORTF_PASSABLE = 2, + PORTF_SOUNDTRAVERSE = 4, + PORTF_INTERACTIVE = 8, + + PORTF_TYPETELEPORT = PORTF_VISIBLE | PORTF_PASSABLE | PORTF_SOUNDTRAVERSE, + PORTF_TYPEINTERACTIVE = PORTF_VISIBLE | PORTF_PASSABLE | PORTF_SOUNDTRAVERSE | PORTF_INTERACTIVE, +}; + +enum +{ + PORTT_VISUAL, + PORTT_TELEPORT, + PORTT_INTERACTIVE, + PORTT_LINKED, + PORTT_LINKEDEE // Eternity compatible definition which uses only one line ID and a different anchor type to link to. +}; + +enum +{ + PORG_ABSOLUTE, // does not align at all. z-ccoordinates must match. + PORG_FLOOR, + PORG_CEILING, +}; + +struct FLinePortal +{ + line_t *mOrigin; + line_t *mDestination; + fixed_t mXDisplacement; + fixed_t mYDisplacement; + BYTE mType; + BYTE mFlags; + BYTE mDefFlags; + BYTE mAlign; +}; + +extern TArray linePortals; + void P_SpawnLinePortal(line_t* line); +void P_FinalizePortals(); /* code ported from prototype */ @@ -53,4 +96,27 @@ public: /* new code */ fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y); + +// returns true if the portal is crossable by actors +inline bool line_t::isLinePortal() const +{ + return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_PASSABLE); +} + +// returns true if the portal needs to be handled by the renderer +inline bool line_t::isVisualPortal() const +{ + return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_VISIBLE); +} + +inline line_t *line_t::getPortalDestination() const +{ + return portalindex >= linePortals.Size() ? (line_t*)NULL : linePortals[portalindex].mDestination; +} + +inline int line_t::getPortalAlignment() const +{ + return portalindex >= linePortals.Size() ? 0 : linePortals[portalindex].mAlign; +} + #endif \ No newline at end of file diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index a6dd7f61b..819bd9532 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -99,7 +99,7 @@ static BYTE FakeSide; int WindowLeft, WindowRight; WORD MirrorFlags; -TArray WallPortals; +TArray WallPortals(1000); // note: this array needs to go away as reallocation can cause crashes. static subsector_t *InSubsector; diff --git a/src/r_defs.h b/src/r_defs.h index 901dadcb0..a000fb8e3 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -988,26 +988,14 @@ struct line_t sector_t *frontsector, *backsector; int validcount; // if == validcount, already checked int locknumber; // [Dusk] lock number for special - - line_t *_portal_dst; - bool _portal; + unsigned portalindex; // returns true if the portal is crossable by actors - bool isLinePortal() const - { - return false; // right now there are no crossable portals - } - + bool isLinePortal() const; // returns true if the portal needs to be handled by the renderer - bool isVisualPortal() const - { - return _portal; - } - - line_t *getPortalDestination() const - { - return _portal_dst; - } + bool isVisualPortal() const; + line_t *getPortalDestination() const; + int getPortalAlignment() const; }; // phares 3/14/98 diff --git a/src/r_utility.h b/src/r_utility.h index 2d9aac086..10dcf5352 100644 --- a/src/r_utility.h +++ b/src/r_utility.h @@ -58,6 +58,11 @@ inline int R_PointOnSide (fixed_t x, fixed_t y, const node_t *node) angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); inline angle_t R_PointToAngle (fixed_t x, fixed_t y) { return R_PointToAngle2 (viewx, viewy, x, y); } +inline angle_t R_PointToAnglePrecise (fixed_t viewx, fixed_t viewy, fixed_t x, fixed_t y) +{ + return xs_RoundToUInt(atan2(double(y-viewy), double(x-viewx)) * (ANGLE_180/M_PI)); +} + subsector_t *R_PointInSubsector (fixed_t x, fixed_t y); fixed_t R_PointToDist2 (fixed_t dx, fixed_t dy); void R_ResetViewInterpolation (); diff --git a/src/version.h b/src/version.h index b4b3ace12..3af1c1b7f 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4531 +#define SAVEVER 4532 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) From cb6504669d1b69172b4fdb69d1a9fe170568288e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 5 Feb 2016 16:34:17 -0600 Subject: [PATCH 11/14] Add return statements for DECORATE. --- src/thingdef/thingdef_exp.h | 13 +++++++++++++ src/thingdef/thingdef_expression.cpp | 15 +++++++++++++++ src/thingdef/thingdef_states.cpp | 6 ++++++ 3 files changed, 34 insertions(+) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index d1f7e75da..691d4b872 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -892,6 +892,19 @@ public: ExpEmit Emit(VMFunctionBuilder *build, bool tailcall); }; +//========================================================================== +// +// FxReturnStatement +// +//========================================================================== + +class FxReturnStatement : public FxTailable +{ +public: + FxReturnStatement(const FScriptPosition &pos); + ExpEmit Emit(VMFunctionBuilder *build, bool tailcall); +}; + //========================================================================== // // diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 2a756a68c..19c02837c 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3484,6 +3484,21 @@ ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build, bool tailcall) // //========================================================================== +FxReturnStatement::FxReturnStatement(const FScriptPosition &pos) +: FxTailable(pos) +{ +} + +ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build, bool tailcall) +{ + build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0); + return ExpEmit(); +} + +//========================================================================== +// +//========================================================================== + FxClassTypeCast::FxClassTypeCast(const PClass *dtype, FxExpression *x) : FxExpression(x->ScriptPosition) { diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index a44fa1ed1..d6f3eb939 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -386,6 +386,12 @@ FxTailable *ParseActions(FScanner &sc, FState state, FString statestring, Baggag } add = new FxIfStatement(cond, true_part, false_part, sc); } + else if (sc.Compare("return")) + { // Handle a return statement + sc.MustGetStringName(";"); + sc.MustGetString(); + add = new FxReturnStatement(sc); + } else { // Handle a regular action function call add = ParseAction(sc, state, statestring, bag); From e88901f4b788b786662efff4d40a0d1717a26445 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 5 Feb 2016 23:51:28 +0100 Subject: [PATCH 12/14] - added the EE-Extradata parser I wrote for GZDoom so I can use the Vaporware demo map for testing portal stuff. --- src/CMakeLists.txt | 1 + src/edata.cpp | 784 +++++++++++++++++++++++++++++ src/edata.h | 12 + src/g_doomedmap.cpp | 1 + src/info.h | 1 + src/p_lnspec.h | 2 + src/p_setup.cpp | 78 ++- src/p_spec.cpp | 8 + src/r_defs.h | 7 + src/sc_man.cpp | 2 +- wadsrc/static/mapinfo/eternity.txt | 8 + wadsrc/static/xlat/eternity.txt | 185 +++---- 12 files changed, 980 insertions(+), 109 deletions(-) create mode 100644 src/edata.cpp create mode 100644 src/edata.h create mode 100644 wadsrc/static/mapinfo/eternity.txt diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3c43f2ba4..765c90e3d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -901,6 +901,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE doomstat.cpp dsectoreffect.cpp dthinker.cpp + edata.cpp f_wipe.cpp farchive.cpp files.cpp diff --git a/src/edata.cpp b/src/edata.cpp new file mode 100644 index 000000000..13e986425 --- /dev/null +++ b/src/edata.cpp @@ -0,0 +1,784 @@ +/* +** edata.cpp +** Parses Eternity Extradata lumps +** +**--------------------------------------------------------------------------- +** Copyright 2015 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** This code was written based on the documentation in the Eternity Wiki +** +*/ + +#include "w_wad.h" +#include "m_argv.h" +#include "zstring.h" +#include "sc_man.h" +#include "g_level.h" +#include "doomdata.h" +#include "r_defs.h" +#include "info.h" +#include "p_lnspec.h" +#include "p_setup.h" +#include "p_tags.h" +#include "p_terrain.h" +#include "v_palette.h" +#include "p_acs.h" +#include "r_data/colormaps.h" + + +struct FEDOptions : public FOptionalMapinfoData +{ + FEDOptions() + { + identifier = "EData"; + } + virtual FOptionalMapinfoData *Clone() const + { + FEDOptions *newopt = new FEDOptions; + newopt->identifier = identifier; + newopt->EDName = EDName; + newopt->acsName = acsName; + return newopt; + } + FString EDName; + FString acsName; +}; + +DEFINE_MAP_OPTION(edata, false) +{ + FEDOptions *opt = info->GetOptData("EData"); + + parse.ParseAssign(); + parse.sc.MustGetString(); + opt->EDName = parse.sc.String; +} + +DEFINE_MAP_OPTION(loadacs, false) +{ + FEDOptions *opt = info->GetOptData("EData"); + + parse.ParseAssign(); + parse.sc.MustGetString(); + opt->acsName = parse.sc.String; +} + +struct EDMapthing +{ + int recordnum; + int tid; + int type; + fixed_t height; + int args[5]; + WORD skillfilter; + DWORD flags; +}; + +struct EDLinedef +{ + int recordnum; + int special; + int tag; + int id; + int args[5]; + fixed_t alpha; + DWORD flags; + DWORD activation; +}; + + + +struct EDSector +{ + int recordnum; + + DWORD flags; + DWORD flagsRemove; + DWORD flagsAdd; + + int damageamount; + int damageinterval; + FNameNoInit damagetype; + BYTE leaky; + BYTE leakyadd; + BYTE leakyremove; + int floorterrain; + int ceilingterrain; + + DWORD color; + + DWORD damageflags; + DWORD damageflagsAdd; + DWORD damageflagsRemove; + + bool flagsSet; + bool damageflagsSet; + bool colorSet; + + // colormaptop//bottom cannot be used because ZDoom has no corresponding properties. + + FTransform planexform[2]; + DWORD portalflags[2]; + fixed_t overlayalpha[2]; +}; + +static FString EDMap; +static TMap EDLines; +static TMap EDSectors; +static TMap EDThings; + + +static void parseLinedef(FScanner &sc) +{ + EDLinedef ld; + bool argsset = false; + + memset(&ld, 0, sizeof(ld)); + ld.alpha = FRACUNIT; + + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + if (sc.Compare("recordnum")) + { + sc.CheckString("="); + sc.MustGetNumber(); + ld.recordnum = sc.Number; + } + else if (sc.Compare("tag")) + { + sc.CheckString("="); + sc.MustGetNumber(); + ld.tag = sc.Number; + } + else if (sc.Compare("id")) + { + sc.CheckString("="); + sc.MustGetNumber(); + ld.id = sc.Number; + } + else if (sc.Compare("special")) + { + sc.CheckString("="); + if (sc.CheckNumber()) + { + // Oh joy, this is going to be fun... + // Here we cannot do anything because we need the tag to make this work. + // For now just store a negative number and resolve this later. + ld.special = -sc.Number; + } + else + { + sc.MustGetString(); + ld.special = P_FindLineSpecial(sc.String); + } + } + else if (sc.Compare("args")) + { + sc.CheckString("="); + sc.MustGetStringName("{"); + int c = 0; + while (true) + { + sc.MustGetNumber(); + ld.args[c++] = sc.Number; + if (sc.CheckString("}")) break; + sc.MustGetStringName(","); + } + argsset = true; + } + else if (sc.Compare("alpha")) + { + sc.CheckString("="); + sc.MustGetFloat(); + ld.alpha = FLOAT2FIXED(sc.Float); + } + else if (sc.Compare("extflags")) + { + // these are needed to build the proper activation mask out of the possible flags which do not match ZDoom 1:1. + DWORD actmethod = 0; + DWORD acttype = 0; + do + { + sc.CheckString("="); + sc.MustGetString(); + for (const char *tok = strtok(sc.String, ",+ \t"); tok != NULL; tok = strtok(NULL, ",+ \t")) + { + if (!stricmp(tok, "USE")) actmethod |= SPAC_Use | SPAC_MUse; + else if (!stricmp(tok, "CROSS")) actmethod |= SPAC_Cross | SPAC_MCross | SPAC_PCross; + else if (!stricmp(tok, "IMPACT")) ld.activation |= SPAC_Impact; + else if (!stricmp(tok, "PUSH")) actmethod |= SPAC_Push; + else if (!stricmp(tok, "PLAYER")) acttype |= SPAC_Use | SPAC_Cross | SPAC_Push; + else if (!stricmp(tok, "MONSTER")) acttype |= SPAC_MUse | SPAC_MCross | SPAC_MPush; + else if (!stricmp(tok, "MISSILE")) acttype |= SPAC_PCross; + else if (!stricmp(tok, "REPEAT")) ld.flags |= ML_REPEAT_SPECIAL; + else if (!stricmp(tok, "1SONLY")) ld.flags |= ML_FIRSTSIDEONLY; + else if (!stricmp(tok, "ADDITIVE")) ld.flags |= ML_ADDTRANS; + else if (!stricmp(tok, "BLOCKALL")) ld.flags |= ML_BLOCKEVERYTHING; + else if (!stricmp(tok, "ZONEBOUNDARY")) ld.flags |= ML_ZONEBOUNDARY; + else if (!stricmp(tok, "CLIPMIDTEX")) ld.flags |= ML_CLIP_MIDTEX; + else sc.ScriptError("Unknown option '%s'", tok); + } + } while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop. + + // and finally we must mask in the activation method + ld.activation |= (actmethod & acttype); + } + else + { + sc.ScriptError("Unknown property '%s'", sc.String); + } + } + if (ld.tag == 0) ld.tag = ld.id; // urgh... + if (ld.special < 0) // translate numeric specials. + { + line_t line; + maplinedef_t mld; + mld.special = -ld.special; + mld.tag = ld.tag; + P_TranslateLineDef(&line, &mld); + ld.special = line.special; + ld.activation = line.activation; + ld.flags = (ld.flags & ~(ML_REPEAT_SPECIAL | ML_FIRSTSIDEONLY)) | (line.flags & (ML_REPEAT_SPECIAL | ML_FIRSTSIDEONLY)); + if (!argsset) memcpy(ld.args, line.args, sizeof(ld.args)); + } + EDLines[ld.recordnum] = ld; +} + +static void parseSector(FScanner &sc) +{ + EDSector sec; + + memset(&sec, 0, sizeof(sec)); + sec.overlayalpha[sector_t::floor] = sec.overlayalpha[sector_t::ceiling] = FRACUNIT; + sec.floorterrain = sec.ceilingterrain = -1; + + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + if (sc.Compare("recordnum")) + { + sc.CheckString("="); + sc.MustGetNumber(); + sec.recordnum = sc.Number; + } + else if (sc.Compare("flags")) + { + DWORD *flagvar = NULL; + if (sc.CheckString(".")) + { + sc.MustGetString(); + if (sc.Compare("add")) + { + flagvar = &sec.flagsAdd; + } + else if (sc.Compare("remove")) + { + flagvar = &sec.flagsRemove; + } + else + { + sc.ScriptError("Invalid property 'flags.%s'", sc.String); + } + } + else + { + sec.flagsSet = true; + flagvar = &sec.flags; + } + sc.CheckString("="); + do + { + sc.MustGetString(); + for (const char *tok = strtok(sc.String, ",+ \t"); tok != NULL; tok = strtok(NULL, ",+ \t")) + { + if (!stricmp(tok, "SECRET")) *flagvar |= SECF_SECRET | SECF_WASSECRET; + else if (!stricmp(tok, "FRICTION")) *flagvar |= SECF_FRICTION; + else if (!stricmp(tok, "PUSH")) *flagvar |= SECF_PUSH; + else if (!stricmp(tok, "KILLSOUND")) *flagvar |= SECF_SILENT; + else if (!stricmp(tok, "KILLMOVESOUND")) *flagvar |= SECF_SILENTMOVE; + else sc.ScriptError("Unknown option '%s'", tok); + } + } while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop. + } + else if (sc.Compare("damage")) + { + sc.CheckString("="); + sc.MustGetNumber(); + sec.damageamount = sc.Number; + } + else if (sc.Compare("damagemask")) + { + sc.CheckString("="); + sc.MustGetNumber(); + sec.damageinterval = sc.Number; + } + else if (sc.Compare("damageflags")) + { + DWORD *flagvar = NULL; + BYTE *leakvar = NULL; + if (sc.CheckString(".")) + { + sc.MustGetString(); + if (sc.Compare("add")) + { + flagvar = &sec.damageflagsAdd; + leakvar = &sec.leakyadd; + } + else if (sc.Compare("remove")) + { + flagvar = &sec.damageflagsRemove; + leakvar = &sec.leakyremove; + } + else + { + sc.ScriptError("Invalid property 'flags.%s'", sc.String); + } + } + else + { + sec.damageflagsSet = true; + flagvar = &sec.damageflags; + leakvar = &sec.leaky; + } + sc.CheckString("="); + do + { + sc.MustGetString(); + for (const char *tok = strtok(sc.String, ",+ \t"); tok != NULL; tok = strtok(NULL, ",+ \t")) + { + if (!stricmp(tok, "LEAKYSUIT")) *leakvar |= 1; + else if (!stricmp(tok, "IGNORESUIT")) *leakvar |= 2; // these 2 bits will be used to set 'leakychance', but this can only be done when the sector gets initialized + else if (!stricmp(tok, "ENDGODMODE")) *flagvar |= SECF_ENDGODMODE; + else if (!stricmp(tok, "ENDLEVEL")) *flagvar |= SECF_ENDLEVEL; + else if (!stricmp(tok, "TERRAINHIT")) *flagvar |= SECF_DMGTERRAINFX; + else sc.ScriptError("Unknown option '%s'", tok); + } + } while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop. + } + else if (sc.Compare("floorterrain")) + { + sc.CheckString("="); + sc.MustGetString(); + sec.floorterrain = P_FindTerrain(sc.String); + } + else if (sc.Compare("floorangle")) + { + sc.CheckString("="); + sc.MustGetFloat(); + sec.planexform[sector_t::floor].angle = angle_t(sc.Float * ANGLE_90 / 90.); + } + else if (sc.Compare("flooroffsetx")) + { + sc.CheckString("="); + sc.MustGetFloat(); + sec.planexform[sector_t::floor].xoffs = FLOAT2FIXED(sc.Float); + } + else if (sc.Compare("flooroffsety")) + { + sc.CheckString("="); + sc.MustGetFloat(); + sec.planexform[sector_t::floor].yoffs = FLOAT2FIXED(sc.Float); + } + else if (sc.Compare("ceilingterrain")) + { + sc.CheckString("="); + sc.MustGetString(); + sec.ceilingterrain = P_FindTerrain(sc.String); + } + else if (sc.Compare("ceilingangle")) + { + sc.CheckString("="); + sc.MustGetFloat(); + sec.planexform[sector_t::ceiling].angle = angle_t(sc.Float * ANGLE_90 / 90.); + } + else if (sc.Compare("ceilingoffsetx")) + { + sc.CheckString("="); + sc.MustGetFloat(); + sec.planexform[sector_t::ceiling].xoffs = FLOAT2FIXED(sc.Float); + } + else if (sc.Compare("ceilingoffsety")) + { + sc.CheckString("="); + sc.MustGetFloat(); + sec.planexform[sector_t::ceiling].yoffs = FLOAT2FIXED(sc.Float); + } + else if (sc.Compare("colormaptop") || sc.Compare("colormapbottom")) + { + sc.CheckString("="); + sc.MustGetString(); + // these properties are not implemented by ZDoom + } + else if (sc.Compare("colormapmid")) + { + sc.CheckString("="); + sc.MustGetString(); + // Eternity is based on SMMU and uses colormaps differently than all other ports. + // The only solution here is to convert the colormap to an RGB value and set it as the sector's color. + DWORD cmap = R_ColormapNumForName(sc.String); + if (cmap != 0) + { + sec.color = R_BlendForColormap(cmap) & 0xff000000; + sec.colorSet = true; + } + } + else if (sc.Compare("overlayalpha")) + { + sc.MustGetStringName("."); + sc.MustGetString(); + if (sc.Compare("floor")) + { + sc.MustGetNumber(); + if (sc.CheckString("%")) sc.Float = sc.Number / 100.f; + else sc.Float = sc.Number / 255.f; + sec.overlayalpha[sector_t::floor] = FLOAT2FIXED(sc.Float); + } + else if (sc.Compare("ceiling")) + { + sc.MustGetFloat(); + if (sc.CheckString("%")) sc.Float = sc.Number / 100.f; + else sc.Float = sc.Number / 255.f; + sec.overlayalpha[sector_t::floor] = FLOAT2FIXED(sc.Float); + } + } + else if (sc.Compare("portalflags")) + { + int dest = 0; + sc.MustGetStringName("."); + sc.MustGetString(); + if (sc.Compare("floor")) dest = sector_t::floor; + else if (sc.Compare("ceiling")) dest = sector_t::ceiling; + else sc.ScriptError("Unknown portal type '%s'", sc.String); + + sc.CheckString("="); + do + { + sc.MustGetString(); + for (const char *tok = strtok(sc.String, ",+ \t"); tok != NULL; tok = strtok(NULL, ",+ \t")) + { + if (!stricmp(tok, "DISABLED")) sec.portalflags[dest] |= PLANEF_DISABLED; + else if (!stricmp(tok, "NORENDER")) sec.portalflags[dest] |= PLANEF_NORENDER; + else if (!stricmp(tok, "NOPASS")) sec.portalflags[dest] |= PLANEF_NOPASS; + else if (!stricmp(tok, "BLOCKSOUND")) sec.portalflags[dest] |= PLANEF_BLOCKSOUND; + else if (!stricmp(tok, "OVERLAY")) sec.portalflags[dest] |= 0; // we do not use this. Alpha is the sole determinant for overlay drawing + else if (!stricmp(tok, "ADDITIVE")) sec.portalflags[dest] |= PLANEF_ADDITIVE; + else if (!stricmp(tok, "USEGLOBALTEX")) {} // not implemented + else sc.ScriptError("Unknown option '%s'", tok); + } + } while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop. + } + else + { + sc.ScriptError("Unknown property '%s'", sc.String); + } + } + EDSectors[sec.recordnum] = sec; +} + +static void parseMapthing(FScanner &sc) +{ + EDMapthing mt; + + memset(&mt, 0, sizeof(mt)); + mt.flags |= MTF_SINGLE | MTF_COOPERATIVE | MTF_DEATHMATCH; // Extradata uses inverse logic, like Doom.exe + + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + if (sc.Compare("recordnum")) + { + sc.CheckString("="); + sc.MustGetNumber(); + mt.recordnum = sc.Number; + } + else if (sc.Compare("tid")) + { + sc.CheckString("="); + sc.MustGetNumber(); + mt.tid = sc.Number; + } + else if (sc.Compare("type")) + { + sc.CheckString("="); + if (sc.CheckNumber()) + { + mt.type = sc.Number; + } + else + { + // Class name. + sc.MustGetString(); + // According to the Eternity Wiki a name may be prefixed with 'thing:'. + const char *pos = strchr(sc.String, ':'); // Eternity never checks if the prefix actually is 'thing'. + if (pos) pos++; + else pos = sc.String; + const PClass *cls = PClass::FindClass(pos); + if (cls != NULL) + { + FDoomEdMap::Iterator it(DoomEdMap); + FDoomEdMap::Pair *pair; + while (it.NextPair(pair)) + { + if (pair->Value.Type == cls) + { + mt.type = pair->Key; + break; + } + } + } + else + { + // Let's hope this isn't an internal Eternity name. + // If so, a name mapping needs to be defined... + sc.ScriptError("Unknown type '%s'", sc.String); + } + + } + } + else if (sc.Compare("args")) + { + sc.CheckString("="); + sc.MustGetStringName("{"); + int c = 0; + while (!sc.CheckString("}")) + { + sc.MustGetNumber(); + mt.args[c++] = sc.Number; + + } + } + else if (sc.Compare("height")) + { + sc.CheckString("="); + sc.MustGetFloat(); // no idea if Eternity allows fractional numbers. Better be safe and do it anyway. + mt.height = FLOAT2FIXED(sc.Float); + } + else if (sc.Compare("options")) + { + sc.CheckString("="); + do + { + sc.MustGetString(); + for (const char *tok = strtok(sc.String, ",+ \t"); tok != NULL; tok = strtok(NULL, ",+ \t")) + { + if (!stricmp(tok, "EASY")) mt.skillfilter |= 3; + else if (!stricmp(tok, "NORMAL")) mt.skillfilter |= 4; + else if (!stricmp(tok, "HARD")) mt.skillfilter |= 24; + else if (!stricmp(tok, "AMBUSH")) mt.flags |= MTF_AMBUSH; + else if (!stricmp(tok, "NOTSINGLE")) mt.flags &= ~MTF_SINGLE; + else if (!stricmp(tok, "NOTDM")) mt.flags &= ~MTF_DEATHMATCH; + else if (!stricmp(tok, "NOTCOOP")) mt.flags &= ~MTF_COOPERATIVE; + else if (!stricmp(tok, "FRIEND")) mt.flags |= MTF_FRIENDLY; + else if (!stricmp(tok, "DORMANT")) mt.flags |= MTF_DORMANT; + else sc.ScriptError("Unknown option '%s'", tok); + } + } while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop. + } + else + { + sc.ScriptError("Unknown property '%s'", sc.String); + } + } + EDThings[mt.recordnum] = mt; +} + +void InitED() +{ + FString filename; + FScanner sc; + + if (EDMap.CompareNoCase(level.MapName) != 0) + { + EDLines.Clear(); + EDSectors.Clear(); + EDThings.Clear(); + EDMap = level.MapName; + + const char *arg = Args->CheckValue("-edf"); + + if (arg != NULL) filename = arg; + else + { + FEDOptions *opt = level.info->GetOptData("EData", false); + if (opt != NULL) + { + filename = opt->EDName; + } + } + + if (filename.IsEmpty()) return; + int lump = Wads.CheckNumForFullName(filename, true, ns_global); + if (lump == -1) return; + sc.OpenLumpNum(lump); + + sc.SetCMode(true); + while (sc.GetString()) + { + if (sc.Compare("linedef")) + { + parseLinedef(sc); + } + else if (sc.Compare("mapthing")) + { + parseMapthing(sc); + } + else if (sc.Compare("sector")) + { + parseSector(sc); + } + else + { + sc.ScriptError("Unknown keyword '%s'", sc.String); + } + } + } +} + +void ProcessEDMapthing(FMapThing *mt, int recordnum) +{ + InitED(); + + EDMapthing *emt = EDThings.CheckKey(recordnum); + if (emt == NULL) + { + Printf("EDF Mapthing record %d not found\n", recordnum); + mt->EdNum = 0; + return; + } + mt->thingid = emt->tid; + mt->EdNum = emt->type; + mt->info = DoomEdMap.CheckKey(mt->EdNum); + mt->z = emt->height; + memcpy(mt->args, emt->args, sizeof(mt->args)); + mt->SkillFilter = emt->skillfilter; + mt->flags = emt->flags; +} + +void ProcessEDLinedef(line_t *ld, int recordnum) +{ + InitED(); + + EDLinedef *eld = EDLines.CheckKey(recordnum); + if (eld == NULL) + { + Printf("EDF Linedef record %d not found\n", recordnum); + ld->special = 0; + return; + } + const DWORD fmask = ML_REPEAT_SPECIAL | ML_FIRSTSIDEONLY | ML_ADDTRANS | ML_BLOCKEVERYTHING | ML_ZONEBOUNDARY | ML_CLIP_MIDTEX; + ld->special = eld->special; + ld->activation = eld->activation; + ld->flags = (ld->flags&~fmask) | eld->flags; + ld->Alpha = eld->alpha; + memcpy(ld->args, eld->args, sizeof(ld->args)); + tagManager.AddLineID(int(ld - lines), eld->tag); +} + +void ProcessEDSector(sector_t *sec, int recordnum) +{ + EDSector *esec = EDSectors.CheckKey(recordnum); + if (esec == NULL) + { + Printf("EDF Sector record %d not found\n", recordnum); + return; + } + + // In ZDoom the regular and the damage flags are part of the same flag word so we need to do some masking. + const DWORD flagmask = SECF_SECRET | SECF_WASSECRET | SECF_FRICTION | SECF_PUSH | SECF_SILENT | SECF_SILENTMOVE; + if (esec->flagsSet) sec->Flags = (sec->Flags & ~flagmask); + sec->Flags = (sec->Flags | esec->flags | esec->flagsAdd) & ~esec->flagsRemove; + + BYTE leak = 0; + if (esec->damageflagsSet) sec->Flags = (sec->Flags & ~SECF_DAMAGEFLAGS); + else leak = sec->leakydamage >= 256 ? 2 : sec->leakydamage >= 5 ? 1 : 0; + sec->Flags = (sec->Flags | esec->damageflags | esec->damageflagsAdd) & ~esec->damageflagsRemove; + leak = (leak | esec->leaky | esec->leakyadd) & ~esec->leakyremove; + + // the damage properties will be unconditionally overridden by Extradata. + sec->leakydamage = leak == 0 ? 0 : leak == 1 ? 5 : 256; + sec->damageamount = esec->damageamount; + sec->damageinterval = esec->damageinterval; + sec->damagetype = esec->damagetype; + + sec->terrainnum[sector_t::floor] = esec->floorterrain; + sec->terrainnum[sector_t::ceiling] = esec->ceilingterrain; + + if (esec->colorSet) sec->SetColor(RPART(esec->color), GPART(esec->color), BPART(esec->color), 0); + + const DWORD pflagmask = PLANEF_DISABLED | PLANEF_NORENDER | PLANEF_NOPASS | PLANEF_BLOCKSOUND | PLANEF_ADDITIVE; + for (int i = 0; i < 2; i++) + { + sec->planes[i].xform.xoffs = esec->planexform[i].xoffs; + sec->planes[i].xform.yoffs = esec->planexform[i].yoffs; + sec->planes[i].xform.angle = esec->planexform[i].angle; + sec->planes[i].alpha = esec->overlayalpha[i]; + sec->planes[i].Flags = (sec->planes[i].Flags & ~pflagmask) | esec->portalflags[i]; + } +} + + +void ProcessEDSectors() +{ + int i; + + InitED(); + if (EDSectors.CountUsed() == 0) return; // don't waste time if there's no records. + + // collect all Extradata sector records up front so we do not need to search the complete line array for each sector separately. + int *sectorrecord = new int[numsectors]; + memset(sectorrecord, -1, numsectors * sizeof(int)); + for (i = 0; i < numlines; i++) + { + if (lines[i].special == Static_Init && lines[i].args[1] == Init_EDSector) + { + sectorrecord[lines[i].frontsector - sectors] = lines[i].args[0]; + lines[i].special = 0; + } + } + for (i = 0; i < numsectors; i++) + { + if (sectorrecord[i] >= 0) + { + ProcessEDSector(§ors[i], sectorrecord[i]); + } + } + delete[] sectorrecord; +} + +void LoadMapinfoACSLump() +{ + FEDOptions *opt = level.info->GetOptData("EData", false); + if (opt != NULL) + { + int lump = Wads.CheckNumForName(opt->acsName); + if (lump >= 0) FBehavior::StaticLoadModule(lump); + } +} diff --git a/src/edata.h b/src/edata.h new file mode 100644 index 000000000..ffbe7d59a --- /dev/null +++ b/src/edata.h @@ -0,0 +1,12 @@ +#ifndef EDATA_H +#define EDATA_H + +struct FMapThing; +struct line_t; + +void ProcessEDMapthing(FMapThing *mt, int recordnum); +void ProcessEDLinedef(line_t *line, int recordnum); +void ProcessEDSectors(); +void LoadMapinfoACSLump(); + +#endif \ No newline at end of file diff --git a/src/g_doomedmap.cpp b/src/g_doomedmap.cpp index cce2889c7..3f42562bb 100644 --- a/src/g_doomedmap.cpp +++ b/src/g_doomedmap.cpp @@ -69,6 +69,7 @@ const char *SpecialMapthingNames[] = { "$CopyCeilingPlane", "$VertexFloorZ", "$VertexCeilingZ", + "$EDThing", }; //========================================================================== diff --git a/src/info.h b/src/info.h index b567bd05a..2d0c627ec 100644 --- a/src/info.h +++ b/src/info.h @@ -310,6 +310,7 @@ enum ESpecialMapthings SMT_CopyCeilingPlane, SMT_VertexFloorZ, SMT_VertexCeilingZ, + SMT_EDThing, }; diff --git a/src/p_lnspec.h b/src/p_lnspec.h index 3b91298d6..6a6818aa3 100644 --- a/src/p_lnspec.h +++ b/src/p_lnspec.h @@ -59,6 +59,8 @@ typedef enum { Init_Damage = 2, Init_SectorLink = 3, NUM_STATIC_INITS, + Init_EDSector = 253, + Init_EDLine = 254, Init_TransferSky = 255 } staticinit_t; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index d1519d031..746e50e40 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -69,6 +69,9 @@ #include "r_renderer.h" #include "r_data/colormaps.h" #include "portal.h" +#ifndef NO_EDATA +#include "edata.h" +#endif #include "fragglescript/t_fs.h" @@ -1757,34 +1760,45 @@ void P_LoadThings (MapData * map) mti[i].alpha = -1; mti[i].health = 1; mti[i].FloatbobPhase = -1; - flags &= ~MTF_SKILLMASK; - mti[i].flags = (short)((flags & 0xf) | 0x7e0); - if (gameinfo.gametype == GAME_Strife) - { - mti[i].flags &= ~MTF_AMBUSH; - if (flags & STF_SHADOW) mti[i].flags |= MTF_SHADOW; - if (flags & STF_ALTSHADOW) mti[i].flags |= MTF_ALTSHADOW; - if (flags & STF_STANDSTILL) mti[i].flags |= MTF_STANDSTILL; - if (flags & STF_AMBUSH) mti[i].flags |= MTF_AMBUSH; - if (flags & STF_FRIENDLY) mti[i].flags |= MTF_FRIENDLY; - } - else - { - if (flags & BTF_BADEDITORCHECK) - { - flags &= 0x1F; - } - if (flags & BTF_NOTDEATHMATCH) mti[i].flags &= ~MTF_DEATHMATCH; - if (flags & BTF_NOTCOOPERATIVE) mti[i].flags &= ~MTF_COOPERATIVE; - if (flags & BTF_FRIENDLY) mti[i].flags |= MTF_FRIENDLY; - } - if (flags & BTF_NOTSINGLE) mti[i].flags &= ~MTF_SINGLE; mti[i].x = LittleShort(mt->x) << FRACBITS; mti[i].y = LittleShort(mt->y) << FRACBITS; mti[i].angle = LittleShort(mt->angle); mti[i].EdNum = LittleShort(mt->type); mti[i].info = DoomEdMap.CheckKey(mti[i].EdNum); + + +#ifndef NO_EDATA + if (mti[i].info != NULL && mti[i].info->Special == SMT_EDThing) + { + ProcessEDMapthing(&mti[i], flags); + } + else +#endif + { + flags &= ~MTF_SKILLMASK; + mti[i].flags = (short)((flags & 0xf) | 0x7e0); + if (gameinfo.gametype == GAME_Strife) + { + mti[i].flags &= ~MTF_AMBUSH; + if (flags & STF_SHADOW) mti[i].flags |= MTF_SHADOW; + if (flags & STF_ALTSHADOW) mti[i].flags |= MTF_ALTSHADOW; + if (flags & STF_STANDSTILL) mti[i].flags |= MTF_STANDSTILL; + if (flags & STF_AMBUSH) mti[i].flags |= MTF_AMBUSH; + if (flags & STF_FRIENDLY) mti[i].flags |= MTF_FRIENDLY; + } + else + { + if (flags & BTF_BADEDITORCHECK) + { + flags &= 0x1F; + } + if (flags & BTF_NOTDEATHMATCH) mti[i].flags &= ~MTF_DEATHMATCH; + if (flags & BTF_NOTCOOPERATIVE) mti[i].flags &= ~MTF_COOPERATIVE; + if (flags & BTF_FRIENDLY) mti[i].flags |= MTF_FRIENDLY; + } + if (flags & BTF_NOTSINGLE) mti[i].flags &= ~MTF_SINGLE; + } } delete [] mtp; } @@ -2160,7 +2174,19 @@ void P_LoadLineDefs (MapData * map) // [RH] Translate old linedef special and flags to be // compatible with the new format. - P_TranslateLineDef (ld, mld, i); + + P_TranslateLineDef (ld, mld, -1); + // do not assign the tag for Extradata lines. + if (ld->special != Static_Init || (ld->args[1] != Init_EDLine && ld->args[1] != Init_EDSector)) + { + tagManager.AddLineID(i, mld->tag); + } +#ifndef NO_EDATA + if (ld->special == Static_Init && ld->args[1] == Init_EDLine) + { + ProcessEDLinedef(ld, mld->tag); + } +#endif ld->v1 = &vertexes[LittleShort(mld->v1)]; ld->v2 = &vertexes[LittleShort(mld->v2)]; @@ -3330,7 +3356,7 @@ void P_LoadBehavior (MapData * map) void P_GetPolySpots (MapData * map, TArray &spots, TArray &anchors) { - if (map->HasBehavior) + //if (map->HasBehavior) { for (unsigned int i = 0; i < MapThingsConverted.Size(); ++i) { @@ -3682,6 +3708,10 @@ void P_SetupLevel (const char *lumpname, int position) } FBehavior::StaticLoadDefaultModules (); +#ifndef NO_EDATA + LoadMapinfoACSLump(); +#endif + P_LoadStrifeConversations (map, lumpname); diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 833e3b632..a8c13c5ac 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -65,6 +65,9 @@ #include "c_dispatch.h" #include "r_sky.h" #include "portal.h" +#ifndef NO_EDATA +#include "edata.h" +#endif // State. #include "r_state.h" @@ -1324,6 +1327,11 @@ void P_SpawnSpecials (void) P_InitSectorSpecial(sector, sector->special, false); } + +#ifndef NO_EDATA + ProcessEDSectors(); +#endif + // Init other misc stuff diff --git a/src/r_defs.h b/src/r_defs.h index a000fb8e3..fc9d522de 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -336,6 +336,13 @@ enum PLANEF_ABSLIGHTING = 1, // floor/ceiling light is absolute, not relative PLANEF_BLOCKED = 2, // can not be moved anymore. PLANEF_ADDITIVE = 4, // rendered additive + + // linked portal stuff + PLANEF_NORENDER = 8, + PLANEF_NOPASS = 16, + PLANEF_BLOCKSOUND = 32, + PLANEF_DISABLED = 64, + PLANEF_OBSTRUCTED = 128, // if the portal plane is beyond the sector's floor or ceiling. }; // Internal sector flags diff --git a/src/sc_man.cpp b/src/sc_man.cpp index 03b52a050..9268404fb 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -856,7 +856,7 @@ int FScanner::MustMatchString (const char * const *strings, size_t stride) i = MatchString (strings, stride); if (i == -1) { - ScriptError (NULL); + ScriptError ("Unknown keyword '%s'", String); } return i; } diff --git a/wadsrc/static/mapinfo/eternity.txt b/wadsrc/static/mapinfo/eternity.txt new file mode 100644 index 000000000..6dc624a29 --- /dev/null +++ b/wadsrc/static/mapinfo/eternity.txt @@ -0,0 +1,8 @@ +// This should be included by any converted Eternity project so set the DoomEdNums that conflict with regular ZDoom get set. + +DoomEdNums +{ + 5003 = none + 5004 = "$EDThing" +} + diff --git a/wadsrc/static/xlat/eternity.txt b/wadsrc/static/xlat/eternity.txt index 7b4367ee3..f76466c29 100644 --- a/wadsrc/static/xlat/eternity.txt +++ b/wadsrc/static/xlat/eternity.txt @@ -8,11 +8,18 @@ define Unsupported (0) +enum +{ + Init_EDSector = 253, + Init_EDLine = 254 +} + // The tag for such a line is actually a key to find, in an ExtraData lump // indicated for the current level by the EMAPINFO lump, what line special // to actually use. This is how parameterized linedefs are used by Eternity -// in the Doom format. "xlating" this would thus be quite complicated... -270 = 0, Unsupported() // "ExtraDataSpecial" +// in the Doom format. + +270 = 0, Static_Init(tag, Init_EDLine) // "ExtraDataSpecial" // These two are standard MBF specials, no need to redefine them, they're in xlat/doom.txt // 271 = 0, Static_Init (tag, Init_TransferSky, 0) @@ -60,53 +67,51 @@ define Unsupported (0) // Parameterized linedefs // They are never used directly in Doom-format maps. Instead, it passes through ExtraData and 270. // Hexen format is incomplete; and Quasar wants to use ZDoom-compatible special values for UDMF. -// So there is no need to bother with them and they are listed only for completeness' sake. -/* - 300: "Door_Raise" - 301: "Door_Open" - 302: "Door_Close" - 303: "Door_CloseWaitOpen" - 304: "Door_WaitRaise" - 305: "Door_WaitClose" - 306: "Floor_RaiseToHighest" - 307: "Floor_LowerToHighest" - 308: "Floor_RaiseToLowest" - 309: "Floor_LowerToLowest" - 310: "Floor_RaiseToNearest" - 311: "Floor_LowerToNearest" - 312: "Floor_RaiseToLowestCeiling" - 313: "Floor_LowerToLowestCeiling" - 314: "Floor_RaiseToCeiling" - 315: "Floor_RaiseByTexture" - 316: "Floor_LowerByTexture" - 317: "Floor_RaiseByValue" - 318: "Floor_LowerByValue" - 319: "Floor_MoveToValue" - 320: "Floor_RaiseInstant" - 321: "Floor_LowerInstant" - 322: "Floor_ToCeilingInstant" - 323: "Ceiling_RaiseToHighest" - 324: "Ceiling_ToHighestInstant" - 325: "Ceiling_RaiseToNearest" - 326: "Ceiling_LowerToNearest" - 327: "Ceiling_RaiseToLowest" - 328: "Ceiling_LowerToLowest" - 329: "Ceiling_RaiseToHighestFloor" - 330: "Ceiling_LowerToHighestFloor" - 331: "Ceiling_ToFloorInstant" - 332: "Ceiling_LowerToFloor" - 333: "Ceiling_RaiseByTexture" - 334: "Ceiling_LowerByTexture" - 335: "Ceiling_RaiseByValue" - 336: "Ceiling_LowerByValue" - 337: "Ceiling_MoveToValue" - 338: "Ceiling_RaiseInstant" - 339: "Ceiling_LowerInstant" - 340: "Stairs_BuildUpDoom" - 341: "Stairs_BuildDownDoom" - 342: "Stairs_BuildUpDoomSync" - 343: "Stairs_BuildDownDoomSync" -*/ +// The translation here is for the odd Extradata that specifies them as numbers. +300 = 0, Door_Raise(0) +301 = 0, Door_Open(0) +302 = 0, Door_Close(0) +303 = 0, Door_CloseWaitOpen(0) +304 = 0, Door_WaitRaise(0) +305 = 0, Door_WaitClose(0) +306 = 0, Floor_RaiseToHighest(0) +307 = 0, Floor_LowerToHighestEE(0) +308 = 0, Floor_RaiseToLowest(0) +309 = 0, Floor_LowerToLowest(0) +310 = 0, Floor_RaiseToNearest(0) +311 = 0, Floor_LowerToNearest(0) +312 = 0, Floor_RaiseToLowestCeiling(0) +313 = 0, Floor_LowerToLowestCeiling(0) +314 = 0, Floor_RaiseToCeiling(0) +315 = 0, Floor_RaiseByTexture(0) +316 = 0, Floor_LowerByTexture(0) +317 = 0, Floor_RaiseByValue(0) +318 = 0, Floor_LowerByValue(0) +319 = 0, Floor_MoveToValue(0) +320 = 0, Floor_RaiseInstant(0) +321 = 0, Floor_LowerInstant(0) +322 = 0, Floor_ToCeilingInstant(0) +323 = 0, Ceiling_RaiseToHighest(0) +324 = 0, Ceiling_ToHighestInstant(0) +325 = 0, Ceiling_RaiseToNearest(0) +326 = 0, Ceiling_LowerToNearest(0) +327 = 0, Ceiling_RaiseToLowest(0) +328 = 0, Ceiling_LowerToLowest(0) +329 = 0, Ceiling_RaiseToHighestFloor(0) +330 = 0, Ceiling_LowerToHighestFloor(0) +331 = 0, Ceiling_ToFloorInstant(0) +332 = 0, Ceiling_LowerToFloor(0) +333 = 0, Ceiling_RaiseByTexture(0) +334 = 0, Ceiling_LowerByTexture(0) +335 = 0, Ceiling_RaiseByValue(0) +336 = 0, Ceiling_LowerByValue(0) +337 = 0, Ceiling_MoveToValue(0) +338 = 0, Ceiling_RaiseInstant(0) +339 = 0, Ceiling_LowerInstant(0) +340 = 0, Stairs_BuildUpDoom(0) +341 = 0, Stairs_BuildDownDoom(0) +342 = 0, Stairs_BuildUpDoomSync(0) +343 = 0, Stairs_BuildDownDoomSync(0) // Two-way portals are not supported yet either 344 = 0, Unsupported() // "Portal_TwowayCeiling" @@ -115,18 +120,16 @@ define Unsupported (0) 347 = 0, Unsupported() // "Portal_TwowayAnchorLineFloor" // More parameterized linedefs -/* - 348: "Polyobj_StartLine" - 349: "Polyobj_ExplicitLine" - 350: "Polyobj_DoorSlide" - 351: "Polyobj_DoorSwing" - 352: "Polyobj_Move" - 353: "Polyobj_OR_Move" - 354: "Polyobj_RotateRight" - 355: "Polyobj_OR_RotateRight" - 356: "Polyobj_RotateLeft" - 357: "Polyobj_OR_RotateLeft" -*/ +348 = 0, Polyobj_StartLine(0) +349 = 0, Polyobj_ExplicitLine(0) +350 = 0, Polyobj_DoorSlide(0) +351 = 0, Polyobj_DoorSwing(0) +352 = 0, Polyobj_Move(0) +353 = 0, Polyobj_OR_Move(0) +354 = 0, Polyobj_RotateRight(0) +355 = 0, Polyobj_OR_RotateRight(0) +356 = 0, Polyobj_RotateLeft(0) +357 = 0, Polyobj_OR_RotateLeft(0) // Eternity's linked portals, vertical link version (floor-to-ceiling) 358 = 0, Unsupported() // "Portal_LinkedCeiling" @@ -135,29 +138,27 @@ define Unsupported (0) 361 = 0, Unsupported() // "Portal_LinkedAnchorLineFloor" // Even more parameterized linedefs -/* - 362: "Pillar_Build" - 363: "Pillar_BuildAndCrush" - 364: "Pillar_Open" - 365: "ACS_Execute" - 366: "ACS_Suspend" - 367: "ACS_Terminate" - 368: "Light_RaiseByValue" - 369: "Light_LowerByValue" - 370: "Light_ChangeToValue" - 371: "Light_Fade" - 372: "Light_Glow" - 373: "Light_Flicker" - 374: "Light_Strobe" - 375: "Radius_Quake" -*/ +362 = 0, Pillar_Build(0) +363 = 0, Pillar_BuildAndCrush(0) +364 = 0, Pillar_Open(0) +365 = 0, ACS_Execute(0) +366 = 0, ACS_Suspend(0) +367 = 0, ACS_Terminate(0) +368 = 0, Light_RaiseByValue(0) +369 = 0, Light_LowerByValue(0) +370 = 0, Light_ChangeToValue(0) +371 = 0, Light_Fade(0) +372 = 0, Light_Glow(0) +373 = 0, Light_Flicker(0) +374 = 0, Light_Strobe(0) +375 = 0, Radius_Quake(0) // Eternity's linked portals, horizontal link version (wall-to-wall) -376 = 0, Unsupported() // "Portal_LinkedLineToLine" -377 = 0, Unsupported() // "Portal_LinkedLineToLineAnchor" +376 = 0, Line_SetPortal(0, tag, 4) // "Portal_LinkedLineToLine" +377 = 0, Line_SetPortal(1, tag, 4) // "Portal_LinkedLineToLineAnchor" // The famous Hexen linedef -// 378 = Line_SetIdentification +378 = 0, Line_SetIdentification(0) // Attached sectors == linked sectors; However, the implementation in Eternity // is based on front sectors of tagged lines, not on sector tags. So instead @@ -186,7 +187,23 @@ define Unsupported (0) 396 = 0, Plane_Copy(tag, tag)// "Slope_FrontFloorAndCeilingToTaggedSlope" // Last parameterized linedefs -// 397 = Floor_Waggle -// 398 = Thing_Spawn -// 399 = Thing_SpawnNoFog -// 400 = Teleport_EndGame +397 = 0, Floor_Waggle(0) +398 = 0, Thing_Spawn(0) +399 = 0, Thing_SpawnNoFog(0) +400 = 0, Teleport_EndGame(0) + +401 = 0, Static_Init(tag, Init_EDSector) + +402 = 0, Thing_Projectile(0) +403 = 0, Thing_ProjectileGravity(0) +404 = 0, Thing_Activate(0) +405 = 0, Thing_Deactivate(0) +410 = 0, Plat_PerpetualRaise(0) +411 = 0, Plat_Stop(0) +412 = 0, Plat_DownWaitUpStay(0) +413 = 0, Plat_DownByValue(0) +414 = 0, Plat_UpWaitDownStay(0) +415 = 0, Plat_UpByValue(0) +416 = 0, Floor_LowerToHighest(0) +420 = 0, ACS_ExecuteWithResult(0) +421 = 0, Thing_ChangeTID(0) From ee3c41bf7bc75b4702ccd17d9d724f1bbba5b928 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 6 Feb 2016 00:19:38 +0100 Subject: [PATCH 13/14] - fixed: The minimum parameter count for an action function is 3, so the DEHSUPP parser needs to take this into account when validating the code pointers. --- src/d_dehacked.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 5f784e6de..b6ae7d0bb 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -2723,9 +2723,9 @@ static bool LoadDehSupp () else { TArray &args = sym->Variants[0].ArgFlags; - if (args.Size() != 0 && !(args[0] & VARF_Optional)) + if (args.Size() > 3 && !(args[3] & VARF_Optional)) { - sc.ScriptError("Incompatible code pointer '%s'", sc.String); + sc.ScriptMessage("Incompatible code pointer '%s' %d, %d", sc.String, args.Size(), args.Size() > 3? args[3] : 0); } } Actions.Push(sym); From ed7b7fc0ba1f05c08e47cfff6eccb28249917f47 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 6 Feb 2016 00:21:44 +0100 Subject: [PATCH 14/14] - fixed: The backlink portal for EE-style definition needs to be done along with the first portal because the code won't find the anchor line itself. --- src/portal.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/portal.cpp b/src/portal.cpp index b49eb0d3a..79d0a5f7d 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -85,6 +85,18 @@ void P_SpawnLinePortal(line_t* line) port->mType = PORTT_LINKED; port->mAlign = PORG_ABSOLUTE; port->mDefFlags = PORTF_TYPEINTERACTIVE; + + // we need to create the backlink here, too. + lines[i].portalindex = linePortals.Reserve(1); + port = &linePortals.Last(); + + memset(port, 0, sizeof(FLinePortal)); + port->mOrigin = &lines[i]; + port->mDestination = line; + port->mType = PORTT_LINKED; + port->mAlign = PORG_ABSOLUTE; + port->mDefFlags = PORTF_TYPEINTERACTIVE; + } } }