# Conflicts:
#	src/g_doomedmap.cpp
#	src/info.h
#	src/p_saveg.cpp
#	src/p_setup.cpp
#	src/p_spec.cpp
#	src/r_defs.h
#	wadsrc/static/mapinfo/eternity.txt
#	wadsrc/static/xlat/eternity.txt
This commit is contained in:
Christoph Oelckers 2016-02-06 00:41:00 +01:00
commit f8e5a0ebf0
36 changed files with 399 additions and 187 deletions

View file

@ -139,7 +139,6 @@ DEFINE_SPECIAL(Sector_ChangeSound, 140, 2, 2, 2)
DEFINE_SPECIAL(Teleport_NoStop, 154, 2, 3, 3) DEFINE_SPECIAL(Teleport_NoStop, 154, 2, 3, 3)
// portal specials // portal specials
DEFINE_SPECIAL(Line_SetVisualPortal, 155, -1, -1, 3)
DEFINE_SPECIAL(Line_SetPortal, 156, -1, -1, 3) DEFINE_SPECIAL(Line_SetPortal, 156, -1, -1, 3)
// GZDoom/Vavoom specials // GZDoom/Vavoom specials
// Although ZDoom doesn't support them it's better to have them defined so that // Although ZDoom doesn't support them it's better to have them defined so that

View file

@ -35,6 +35,8 @@
#ifndef AUTOSEGS_H #ifndef AUTOSEGS_H
#define AUTOSEGS_H #define AUTOSEGS_H
#include "doomtype.h"
#define REGMARKER(x) (x) #define REGMARKER(x) (x)
typedef void * const REGINFO; typedef void * const REGINFO;
typedef void * NCREGINFO; typedef void * NCREGINFO;
@ -73,11 +75,11 @@ class FAutoSegIterator
} }
Probe = Head; Probe = Head;
} }
NCREGINFO operator*() const NCREGINFO operator*() const NO_SANITIZE
{ {
return *Probe; return *Probe;
} }
FAutoSegIterator &operator++() FAutoSegIterator &operator++() NO_SANITIZE
{ {
do do
{ {

View file

@ -2723,9 +2723,9 @@ static bool LoadDehSupp ()
else else
{ {
TArray<DWORD> &args = sym->Variants[0].ArgFlags; TArray<DWORD> &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); Actions.Push(sym);

View file

@ -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 *class1 = *(const PClass **)a;
const PClass *class2 = *(const PClass **)b; const PClass *class2 = *(const PClass **)b;

View file

@ -113,6 +113,16 @@ typedef TMap<int, PClassActor *> FClassMap;
#define NOVTABLE #define NOVTABLE
#endif #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" #include "basictypes.h"
// Bounding box coordinate storage. // Bounding box coordinate storage.

View file

@ -286,9 +286,11 @@ template<> inline FArchive &operator<< <FFont> (FArchive &arc, FFont* &font)
struct FStrifeDialogueNode; struct FStrifeDialogueNode;
struct FSwitchDef; struct FSwitchDef;
struct FDoorAnimation; struct FDoorAnimation;
struct FLinePortal;
template<> FArchive &operator<< (FArchive &arc, FStrifeDialogueNode *&node); template<> FArchive &operator<< (FArchive &arc, FStrifeDialogueNode *&node);
template<> FArchive &operator<< (FArchive &arc, FSwitchDef* &sw); template<> FArchive &operator<< (FArchive &arc, FSwitchDef* &sw);
template<> FArchive &operator<< (FArchive &arc, FDoorAnimation* &da); template<> FArchive &operator<< (FArchive &arc, FDoorAnimation* &da);
FArchive &operator<< (FArchive &arc, FLinePortal &da);

View file

@ -69,7 +69,7 @@ const char *SpecialMapthingNames[] = {
"$CopyCeilingPlane", "$CopyCeilingPlane",
"$VertexFloorZ", "$VertexFloorZ",
"$VertexCeilingZ", "$VertexCeilingZ",
"$EDFThing", "$EDThing",
}; };
//========================================================================== //==========================================================================

View file

@ -310,7 +310,7 @@ enum ESpecialMapthings
SMT_CopyCeilingPlane, SMT_CopyCeilingPlane,
SMT_VertexFloorZ, SMT_VertexFloorZ,
SMT_VertexCeilingZ, SMT_VertexCeilingZ,
SMT_EDFThing, SMT_EDThing,
}; };

View file

@ -182,7 +182,7 @@ void FName::NameManager::InitBuckets ()
// Register built-in names. 'None' must be name 0. // Register built-in names. 'None' must be name 0.
for (size_t i = 0; i < countof(PredefinedNames); ++i) 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); FindName (PredefinedNames[i], false);
} }
} }

View file

@ -8299,9 +8299,6 @@ scriptwait:
line->args[4] = STACK(1); line->args[4] = STACK(1);
DPrintf("Set special on line %d (id %d) to %d(%d,%d,%d,%d,%d)\n", 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)); 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; sp -= 7;
} }

View file

@ -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 // Finish setting sector properties that depend on walls
for (i = 0; i < numsectors; ++i, ++bsec) for (i = 0; i < numsectors; ++i, ++bsec)
{ {

View file

@ -3781,7 +3781,7 @@ int P_ExecuteSpecial(int num,
int arg4, int arg4,
int arg5) 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); return LineSpecials[num](line, activator, backSide, arg1, arg2, arg3, arg4, arg5);
} }

View file

@ -53,6 +53,7 @@
#include "p_lnspec.h" #include "p_lnspec.h"
#include "p_acs.h" #include "p_acs.h"
#include "p_terrain.h" #include "p_terrain.h"
#include "portal.h"
static void CopyPlayer (player_t *dst, player_t *src, const char *name); static void CopyPlayer (player_t *dst, player_t *src, const char *name);
static void ReadOnePlayer (FArchive &arc, bool skipload); static void ReadOnePlayer (FArchive &arc, bool skipload);
@ -477,6 +478,12 @@ void P_SerializeWorld (FArchive &arc)
} }
arc << li->args[1] << li->args[2] << li->args[3] << li->args[4]; arc << li->args[1] << li->args[2] << li->args[3] << li->args[4];
if (SaveVersion >= 4532)
{
arc << li->portalindex;
}
else li->portalindex = UINT_MAX;
if (SaveVersion >= 4531) if (SaveVersion >= 4531)
{ {
arc << li->skybox; arc << li->skybox;
@ -516,6 +523,15 @@ void P_SerializeWorld (FArchive &arc)
{ {
arc << zn->Environment; arc << zn->Environment;
} }
if (SaveVersion >= 4532)
{
arc << linePortals;
}
else
{
linePortals.Clear();
}
} }
void extsector_t::Serialize(FArchive &arc) void extsector_t::Serialize(FArchive &arc)

View file

@ -1769,7 +1769,7 @@ void P_LoadThings (MapData * map)
#ifndef NO_EDATA #ifndef NO_EDATA
if (mti[i].info != NULL && mti[i].info->Special == SMT_EDFThing) if (mti[i].info != NULL && mti[i].info->Special == SMT_EDThing)
{ {
ProcessEDMapthing(&mti[i], flags); ProcessEDMapthing(&mti[i], flags);
} }
@ -1976,7 +1976,6 @@ void P_SetLineID (int i, line_t *ld)
break; break;
case Line_SetPortal: case Line_SetPortal:
case Line_SetVisualPortal:
setid = ld->args[1]; // 0 = target id, 1 = this id, 2 = plane anchor setid = ld->args[1]; // 0 = target id, 1 = this id, 2 = plane anchor
break; break;
} }
@ -2079,9 +2078,6 @@ void P_FinishLoadingLineDef(line_t *ld, int alpha)
ld->special = 0; ld->special = 0;
break; break;
} }
// [ZZ] check initial portal link
P_CheckPortal(ld);
} }
// killough 4/4/98: delay using sidedefs until they are loaded // killough 4/4/98: delay using sidedefs until they are loaded
void P_FinishLoadingLineDefs () void P_FinishLoadingLineDefs ()
@ -2174,6 +2170,7 @@ void P_LoadLineDefs (MapData * map)
for (i = 0; i < numlines; i++, mld++, ld++) for (i = 0; i < numlines; i++, mld++, ld++)
{ {
ld->Alpha = FRACUNIT; // [RH] Opaque by default ld->Alpha = FRACUNIT; // [RH] Opaque by default
ld->portalindex = UINT_MAX;
// [RH] Translate old linedef special and flags to be // [RH] Translate old linedef special and flags to be
// compatible with the new format. // compatible with the new format.
@ -2266,6 +2263,8 @@ void P_LoadLineDefs2 (MapData * map)
{ {
int j; int j;
ld->portalindex = UINT_MAX;
for (j = 0; j < 5; j++) for (j = 0; j < 5; j++)
ld->args[j] = mld->args[j]; ld->args[j] = mld->args[j];
@ -3395,6 +3394,7 @@ void P_FreeLevelData ()
level.killed_monsters = level.found_items = level.found_secrets = level.killed_monsters = level.found_items = level.found_secrets =
wminfo.maxfrags = 0; wminfo.maxfrags = 0;
linePortals.Clear();
FBehavior::StaticUnloadModules (); FBehavior::StaticUnloadModules ();
if (vertexes != NULL) if (vertexes != NULL)
{ {

View file

@ -64,6 +64,7 @@
#include "a_keys.h" #include "a_keys.h"
#include "c_dispatch.h" #include "c_dispatch.h"
#include "r_sky.h" #include "r_sky.h"
#include "portal.h"
#ifndef NO_EDATA #ifndef NO_EDATA
#include "edata.h" #include "edata.h"
#endif #endif
@ -1465,6 +1466,10 @@ void P_SpawnSpecials (void)
} }
break; break;
case Line_SetPortal:
P_SpawnLinePortal(&lines[i]);
break;
// [RH] ZDoom Static_Init settings // [RH] ZDoom Static_Init settings
case Static_Init: case Static_Init:
switch (lines[i].args[1]) switch (lines[i].args[1])
@ -1536,6 +1541,7 @@ void P_SpawnSpecials (void)
} }
// [RH] Start running any open scripts on this map // [RH] Start running any open scripts on this map
FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false); FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false);
P_FinalizePortals();
} }
// killough 2/28/98: // killough 2/28/98:

View file

@ -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 bool FTagManager::LineHasID(int i, int tag) const
{ {
if (LineHasIDs(i)) if (LineHasIDs(i))

View file

@ -57,6 +57,7 @@ public:
bool SectorHasTag(int sector, int tag) const; bool SectorHasTag(int sector, int tag) const;
bool SectorHasTag(const sector_t *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(int line, int id) const;
bool LineHasID(const line_t *line, int id) const; bool LineHasID(const line_t *line, int id) const;

View file

@ -792,6 +792,7 @@ public:
memset(ld, 0, sizeof(*ld)); memset(ld, 0, sizeof(*ld));
ld->Alpha = FRACUNIT; ld->Alpha = FRACUNIT;
ld->portalindex = UINT_MAX;
ld->sidedef[0] = ld->sidedef[1] = NULL; ld->sidedef[0] = ld->sidedef[1] = NULL;
if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX; if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX;
if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX; if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX;

View file

@ -6,97 +6,35 @@
#include "c_cvars.h" #include "c_cvars.h"
#include "m_bbox.h" #include "m_bbox.h"
#include "p_tags.h" #include "p_tags.h"
#include "farchive.h"
// simulation recurions maximum // simulation recurions maximum
CVAR(Int, sv_portal_recursions, 4, CVAR_ARCHIVE|CVAR_SERVERINFO) CVAR(Int, sv_portal_recursions, 4, CVAR_ARCHIVE|CVAR_SERVERINFO)
PortalDrawseg* CurrentPortal = NULL; TArray<FLinePortal> linePortals;
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, FArchive &operator<< (FArchive &arc, FLinePortal &port)
fixed_t o2x, fixed_t o2y, fixed_t p2x, fixed_t p2y,
fixed_t& rx, fixed_t& ry)
{ {
float xx = FIXED2FLOAT(o2x) - FIXED2FLOAT(o1x); arc << port.mOrigin
float xy = FIXED2FLOAT(o2y) - FIXED2FLOAT(o1y); << port.mDestination
<< port.mXDisplacement
float d1x = FIXED2FLOAT(p1x) - FIXED2FLOAT(o1x); << port.mYDisplacement
float d1y = FIXED2FLOAT(p1y) - FIXED2FLOAT(o1y); << port.mType
<< port.mFlags
if (d1x > d1y) << port.mDefFlags
{ << port.mAlign;
d1y = d1y / d1x * 32767.0f; return arc;
d1x = 32767.0;
}
else
{
d1x = d1x / d1y * 32767.0f;
d1y = 32767.0;
}
float d2x = FIXED2FLOAT(p2x) - FIXED2FLOAT(o2x);
float d2y = FIXED2FLOAT(p2y) - FIXED2FLOAT(o2y);
float cross = d1x*d2y - d1y*d2x;
if (fabs(cross) < 1e-8)
return false;
float t1 = (xx * d2y - xy * d2x)/cross;
rx = o1x + FLOAT2FIXED(d1x * t1);
ry = o1y + FLOAT2FIXED(d1y * t1);
return true;
} }
inline int P_PointOnLineSideExplicit (fixed_t x, fixed_t y, fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
void P_SpawnLinePortal(line_t* line)
{ {
return DMulScale32 (y-y1, x2-x1, x1-x, y2-y1) > 0; // portal destination is special argument #0
} line_t* dst = NULL;
bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t viewy, bool partial, bool samebehind) if (line->args[2] >= PORTT_VISUAL && line->args[2] <= PORTT_LINKED)
{
// 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);
// [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)
if ((line->v1->x == portal->v1->x && line->v1->y == portal->v1->y) ||
(line->v1->x == portal->v2->x && line->v1->y == portal->v2->y))
behind1 = samebehind;
if ((line->v2->x == portal->v1->x && line->v2->y == portal->v1->y) ||
(line->v2->x == portal->v2->x && line->v2->y == portal->v2->y))
behind2 = samebehind;
if (behind1 && behind2)
{ {
// 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);
if (infront1 && infront2)
return true;
}
return false;
}
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 ||
line->special == Line_SetVisualPortal)
{
// portal destination is special argument #0
line_t* dst = NULL;
if (line->args[0] > 0) if (line->args[0] > 0)
{ {
int linenum = -1; int linenum = -1;
@ -113,30 +51,161 @@ bool P_CheckPortal(line_t* line)
} }
} }
if (dst) 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)
{ {
line->portal = true; port->mDefFlags = port->mType == PORTT_VISUAL ? PORTF_VISIBLE : port->mType == PORTT_TELEPORT ? PORTF_TYPETELEPORT : PORTF_TYPEINTERACTIVE;
line->portal_mirror = false;
line->portal_passive = (line->special == Line_SetVisualPortal);
line->portal_dst = dst;
} }
else }
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++)
{ {
line->portal = false; if (tagManager.GetFirstLineID(&lines[i]) == mytag && lines[i].args[0] == 1)
line->portal_mirror = false; {
line->portal_passive = false; line->portalindex = linePortals.Reserve(1);
line->portal_dst = NULL; 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;
// 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;
}
} }
} }
else else
{ {
line->portal = false; // undefined type
line->portal_mirror = false; return;
line->portal_passive = false; }
line->portal_dst = NULL; }
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,
fixed_t& rx, fixed_t& ry)
{
double xx = FIXED2DBL(o2x) - FIXED2DBL(o1x);
double xy = FIXED2DBL(o2y) - FIXED2DBL(o1y);
double d1x = FIXED2DBL(p1x) - FIXED2DBL(o1x);
double d1y = FIXED2DBL(p1y) - FIXED2DBL(o1y);
if (d1x > d1y)
{
d1y = d1y / d1x * 32767.0f;
d1x = 32767.0;
}
else
{
d1x = d1x / d1y * 32767.0f;
d1y = 32767.0;
} }
return (line->portal); double d2x = FIXED2DBL(p2x) - FIXED2DBL(o2x);
double d2y = FIXED2DBL(p2y) - FIXED2DBL(o2y);
double cross = d1x*d2y - d1y*d2x;
if (fabs(cross) < 1e-8)
return false;
double t1 = (xx * d2y - xy * d2x)/cross;
rx = o1x + FLOAT2FIXED(d1x * t1);
ry = o1y + FLOAT2FIXED(d1y * t1);
return true;
}
inline int P_PointOnLineSideExplicit (fixed_t x, fixed_t y, fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
{
return DMulScale32 (y-y1, x2-x1, x1-x, y2-y1) > 0;
}
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_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)
if ((line->v1->x == portal->v1->x && line->v1->y == portal->v1->y) ||
(line->v1->x == portal->v2->x && line->v1->y == portal->v2->y))
behind1 = samebehind;
if ((line->v2->x == portal->v1->x && line->v2->y == portal->v1->y) ||
(line->v2->x == portal->v2->x && line->v2->y == portal->v2->y))
behind2 = samebehind;
if (behind1 && behind2)
{
// 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 = 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;
}
return false;
} }
void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y) void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y)
@ -211,17 +280,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) 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] = 1 - adjust by floor difference
// args[2] = 2 - adjust by ceiling 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); z = z - src->frontsector->floorplane.ZatPoint(src->v1->x, src->v1->y) + dst->frontsector->floorplane.ZatPoint(dst->v2->x, dst->v2->y);
} return;
else if (src->args[2] == 2)
{ 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); 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;
} }
} }
@ -244,9 +318,9 @@ fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y)
void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy) void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy)
{ {
float _vx = FIXED2FLOAT(vx); double _vx = FIXED2DBL(vx);
float _vy = FIXED2FLOAT(vy); double _vy = FIXED2DBL(vy);
float len = sqrt(_vx*_vx+_vy*_vy); double len = sqrt(_vx*_vx+_vy*_vy);
vx = FLOAT2FIXED(_vx/len); vx = FLOAT2FIXED(_vx/len);
vy = FLOAT2FIXED(_vy/len); vy = FLOAT2FIXED(_vy/len);
} }
@ -302,12 +376,12 @@ bool PortalTracer::TraceStep()
{ {
li = in->d.line; li = in->d.line;
if (li->portal && !li->portal_passive) if (li->isLinePortal())
{ {
if (P_PointOnLineSide(startx-dirx, starty-diry, li)) if (P_PointOnLineSide(startx-dirx, starty-diry, li))
continue; // we're at the back side of this line 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->in = li;
this->out = out; this->out = out;
@ -361,7 +435,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 return (oDepth != depth); // if a portal has been found, return false
} }

View file

@ -8,29 +8,54 @@
#include "p_local.h" #include "p_local.h"
#include "m_bbox.h" #include "m_bbox.h"
/* portal structure, this is used in r_ code in order to store drawsegs with portals (and mirrors) */
struct PortalDrawseg enum
{ {
line_t* src; // source line (the one drawn) this doesn't change over render loops PORTF_VISIBLE = 1,
line_t* dst; // destination line (the one that the portal is linked with, equals 'src' for mirrors) PORTF_PASSABLE = 2,
PORTF_SOUNDTRAVERSE = 4,
PORTF_INTERACTIVE = 8,
int x1; // drawseg x1 PORTF_TYPETELEPORT = PORTF_VISIBLE | PORTF_PASSABLE | PORTF_SOUNDTRAVERSE,
int x2; // drawseg x2 PORTF_TYPEINTERACTIVE = PORTF_VISIBLE | PORTF_PASSABLE | PORTF_SOUNDTRAVERSE | PORTF_INTERACTIVE,
int len;
TArray<short> ceilingclip;
TArray<short> floorclip;
bool mirror; // true if this is a mirror (src should equal dst)
}; };
extern PortalDrawseg* CurrentPortal; enum
extern int CurrentPortalUniq; {
extern bool CurrentPortalInSkybox; 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<FLinePortal> linePortals;
void P_SpawnLinePortal(line_t* line);
void P_FinalizePortals();
/* code ported from prototype */ /* 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_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_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_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); void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle);
@ -71,4 +96,27 @@ public:
/* new code */ /* new code */
fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y); 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 #endif

View file

@ -99,7 +99,7 @@ static BYTE FakeSide;
int WindowLeft, WindowRight; int WindowLeft, WindowRight;
WORD MirrorFlags; WORD MirrorFlags;
TArray<PortalDrawseg> WallPortals; TArray<PortalDrawseg> WallPortals(1000); // note: this array needs to go away as reallocation can cause crashes.
static subsector_t *InSubsector; static subsector_t *InSubsector;
@ -590,7 +590,7 @@ void R_AddLine (seg_t *line)
rw_havehigh = rw_havelow = false; rw_havehigh = rw_havelow = false;
// Single sided line? // 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; solid = true;
} }

View file

@ -107,8 +107,6 @@ extern size_t FirstInterestingDrawseg;
extern int WindowLeft, WindowRight; extern int WindowLeft, WindowRight;
extern WORD MirrorFlags; extern WORD MirrorFlags;
extern TArray<PortalDrawseg> WallPortals;
typedef void (*drawfunc_t) (int start, int stop); typedef void (*drawfunc_t) (int start, int stop);
EXTERN_CVAR (Bool, r_drawflat) // [RH] Don't texture segs? EXTERN_CVAR (Bool, r_drawflat) // [RH] Don't texture segs?

View file

@ -379,6 +379,7 @@ enum
PLANEF_NOPASS = 16, PLANEF_NOPASS = 16,
PLANEF_BLOCKSOUND = 32, PLANEF_BLOCKSOUND = 32,
PLANEF_DISABLED = 64, PLANEF_DISABLED = 64,
PLANEF_OBSTRUCTED = 128, // if the portal plane is beyond the sector's floor or ceiling.
}; };
// Internal sector flags // Internal sector flags
@ -1084,16 +1085,15 @@ struct line_t
sector_t *frontsector, *backsector; sector_t *frontsector, *backsector;
int validcount; // if == validcount, already checked int validcount; // if == validcount, already checked
int locknumber; // [Dusk] lock number for special int locknumber; // [Dusk] lock number for special
line_t *portal_dst; unsigned portalindex;
bool portal;
bool portal_mirror;
bool portal_passive;
TObjPtr<ASkyViewpoint> skybox; TObjPtr<ASkyViewpoint> skybox;
bool isLinePortal() const // returns true if the portal is crossable by actors
{ bool isLinePortal() const;
return portal; // returns true if the portal needs to be handled by the renderer
} bool isVisualPortal() const;
line_t *getPortalDestination() const;
int getPortalAlignment() const;
}; };
// phares 3/14/98 // phares 3/14/98

View file

@ -37,6 +37,7 @@
#include "r_local.h" #include "r_local.h"
#include "r_plane.h" #include "r_plane.h"
#include "r_bsp.h" #include "r_bsp.h"
#include "r_segs.h"
#include "r_3dfloors.h" #include "r_3dfloors.h"
#include "r_sky.h" #include "r_sky.h"
#include "st_stuff.h" #include "st_stuff.h"

View file

@ -67,6 +67,9 @@ CVAR(Bool, r_np2, true, 0)
extern fixed_t globaluclip, globaldclip; extern fixed_t globaluclip, globaldclip;
PortalDrawseg* CurrentPortal = NULL;
int CurrentPortalUniq = 0;
bool CurrentPortalInSkybox = false;
// OPTIMIZE: closed two sided lines as single sided // OPTIMIZE: closed two sided lines as single sided
@ -517,7 +520,7 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
wallupper[i] = mceilingclip[i]; wallupper[i] = mceilingclip[i];
} }
mceilingclip = wallupper; mceilingclip = wallupper;
} }
if (fake3D & FAKE3D_CLIPBOTTOM) if (fake3D & FAKE3D_CLIPBOTTOM)
{ {
OWallMost(walllower, sclipBottom - viewz, &WallC); OWallMost(walllower, sclipBottom - viewz, &WallC);
@ -2001,8 +2004,7 @@ void R_NewWall (bool needlights)
midtexture = toptexture = bottomtexture = 0; midtexture = toptexture = bottomtexture = 0;
if (sidedef == linedef->sidedef[0] && if (sidedef == linedef->sidedef[0] &&
linedef->portal && (linedef->isVisualPortal() || (linedef->special == Line_Mirror && r_drawmirrors))) // [ZZ] compatibility with r_drawmirrors cvar that existed way before portals
(!linedef->portal_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) markfloor = markceiling = true; // act like an one-sided wall here (todo: check how does this work with transparency)
rw_markportal = true; rw_markportal = true;
@ -2629,7 +2631,7 @@ void R_StoreWallRange (int start, int stop)
{ {
PortalDrawseg pds; PortalDrawseg pds;
pds.src = curline->linedef; 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.x1 = ds_p->x1;
pds.x2 = ds_p->x2; pds.x2 = ds_p->x2;
pds.len = pds.x2 - pds.x1; pds.len = pds.x2 - pds.x1;
@ -2650,7 +2652,7 @@ void R_StoreWallRange (int start, int stop)
pds.floorclip[i] = RenderTarget->GetHeight()-1; pds.floorclip[i] = RenderTarget->GetHeight()-1;
} }
pds.mirror = curline->linedef->portal_mirror; pds.mirror = curline->linedef->special == Line_Mirror;
WallPortals.Push(pds); WallPortals.Push(pds);
} }
@ -2761,11 +2763,6 @@ int OWallMost (short *mostbuf, fixed_t z, const FWallCoords *wallc)
} }
#endif #endif
#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; return bad;
} }
@ -2919,11 +2916,6 @@ int WallMost (short *mostbuf, const secplane_t &plane, const FWallCoords *wallc)
qinterpolatedown16short (&mostbuf[ix1], ix2-ix1, y + centeryfrac,yinc); 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; return bad;
} }

View file

@ -49,4 +49,25 @@ extern fixed_t rw_lightstep;
extern fixed_t rw_lightleft; extern fixed_t rw_lightleft;
extern fixed_t rw_offset; 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<short> ceilingclip;
TArray<short> floorclip;
bool mirror; // true if this is a mirror (src should equal dst)
};
extern PortalDrawseg* CurrentPortal;
extern int CurrentPortalUniq;
extern bool CurrentPortalInSkybox;
extern TArray<PortalDrawseg> WallPortals;
#endif #endif

View file

@ -31,6 +31,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <algorithm> #include <algorithm>
#include "p_lnspec.h"
#include "templates.h" #include "templates.h"
#include "doomdef.h" #include "doomdef.h"
#include "m_swap.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; if (!seg->curline) continue;
line_t* line = seg->curline->linedef; 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; if (!line) continue;
// check if this line will clip sprites to itself // check if this line will clip sprites to itself
if (!line->portal) if (!line->isVisualPortal() && line->special != Line_Mirror)
continue; continue;
// don't clip sprites with portal's back side (it's transparent) // 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] Or less definitely not visible (hue)
// [ZZ] 10.01.2016: don't try to clip stuff inside a skybox against the current portal. // [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; return;
// [RH] Interpolate the sprite's position to make it look smooth // [RH] Interpolate the sprite's position to make it look smooth

View file

@ -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); 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_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); subsector_t *R_PointInSubsector (fixed_t x, fixed_t y);
fixed_t R_PointToDist2 (fixed_t dx, fixed_t dy); fixed_t R_PointToDist2 (fixed_t dx, fixed_t dy);
void R_ResetViewInterpolation (); void R_ResetViewInterpolation ();

View file

@ -856,7 +856,7 @@ int FScanner::MustMatchString (const char * const *strings, size_t stride)
i = MatchString (strings, stride); i = MatchString (strings, stride);
if (i == -1) if (i == -1)
{ {
ScriptError (NULL); ScriptError ("Unknown keyword '%s'", String);
} }
return i; return i;
} }

View file

@ -676,7 +676,7 @@ static void DoJump(AActor *self, AActor *stateowner, FState *callingstate, FStat
{ {
P_SetPsprite(self->player, ps_flash, jumpto); 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, // Rather than using self->SetState(jumpto) to set the state,
// set the state directly. Since this function is only called by // set the state directly. Since this function is only called by

View file

@ -892,6 +892,19 @@ public:
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall); ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
}; };
//==========================================================================
//
// FxReturnStatement
//
//==========================================================================
class FxReturnStatement : public FxTailable
{
public:
FxReturnStatement(const FScriptPosition &pos);
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
};
//========================================================================== //==========================================================================
// //
// //

View file

@ -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) FxClassTypeCast::FxClassTypeCast(const PClass *dtype, FxExpression *x)
: FxExpression(x->ScriptPosition) : FxExpression(x->ScriptPosition)
{ {

View file

@ -386,6 +386,12 @@ FxTailable *ParseActions(FScanner &sc, FState state, FString statestring, Baggag
} }
add = new FxIfStatement(cond, true_part, false_part, sc); 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 else
{ // Handle a regular action function call { // Handle a regular action function call
add = ParseAction(sc, state, statestring, bag); add = ParseAction(sc, state, statestring, bag);

View file

@ -76,7 +76,7 @@ const char *GetVersionString();
// Use 4500 as the base git save version, since it's higher than the // Use 4500 as the base git save version, since it's higher than the
// SVN revision ever got. // SVN revision ever got.
#define SAVEVER 4531 #define SAVEVER 4532
#define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY2(x) #x
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)

View file

@ -3,6 +3,6 @@
DoomEdNums DoomEdNums
{ {
5003 = none 5003 = none
5004 = "$EDFThing" 5004 = "$EDThing"
} }

View file

@ -67,9 +67,7 @@ enum
// Parameterized linedefs // Parameterized linedefs
// They are never used directly in Doom-format maps. Instead, it passes through ExtraData and 270. // 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. // Hexen format is incomplete; and Quasar wants to use ZDoom-compatible special values for UDMF.
// The translation here is for the odd EDF that specifies them as numbers. // The translation here is for the odd Extradata that specifies them as numbers.
/*
300 = 0, Door_Raise(0) 300 = 0, Door_Raise(0)
301 = 0, Door_Open(0) 301 = 0, Door_Open(0)
302 = 0, Door_Close(0) 302 = 0, Door_Close(0)
@ -77,7 +75,7 @@ enum
304 = 0, Door_WaitRaise(0) 304 = 0, Door_WaitRaise(0)
305 = 0, Door_WaitClose(0) 305 = 0, Door_WaitClose(0)
306 = 0, Floor_RaiseToHighest(0) 306 = 0, Floor_RaiseToHighest(0)
307 = 0, Floor_LowerToHighest(0) 307 = 0, Floor_LowerToHighestEE(0)
308 = 0, Floor_RaiseToLowest(0) 308 = 0, Floor_RaiseToLowest(0)
309 = 0, Floor_LowerToLowest(0) 309 = 0, Floor_LowerToLowest(0)
310 = 0, Floor_RaiseToNearest(0) 310 = 0, Floor_RaiseToNearest(0)
@ -114,7 +112,6 @@ enum
341 = 0, Stairs_BuildDownDoom(0) 341 = 0, Stairs_BuildDownDoom(0)
342 = 0, Stairs_BuildUpDoomSync(0) 342 = 0, Stairs_BuildUpDoomSync(0)
343 = 0, Stairs_BuildDownDoomSync(0) 343 = 0, Stairs_BuildDownDoomSync(0)
*/
// Two-way portals are not supported yet either // Two-way portals are not supported yet either
344 = 0, Unsupported() // "Portal_TwowayCeiling" 344 = 0, Unsupported() // "Portal_TwowayCeiling"
@ -157,11 +154,11 @@ enum
375 = 0, Radius_Quake(0) 375 = 0, Radius_Quake(0)
// Eternity's linked portals, horizontal link version (wall-to-wall) // Eternity's linked portals, horizontal link version (wall-to-wall)
376 = 0, Unsupported() // "Portal_LinkedLineToLine" 376 = 0, Line_SetPortal(0, tag, 4) // "Portal_LinkedLineToLine"
377 = 0, Unsupported() // "Portal_LinkedLineToLineAnchor" 377 = 0, Line_SetPortal(1, tag, 4) // "Portal_LinkedLineToLineAnchor"
// The famous Hexen linedef // The famous Hexen linedef
// 378 = Line_SetIdentification 378 = 0, Line_SetIdentification(0)
// Attached sectors == linked sectors; However, the implementation in Eternity // Attached sectors == linked sectors; However, the implementation in Eternity
// is based on front sectors of tagged lines, not on sector tags. So instead // is based on front sectors of tagged lines, not on sector tags. So instead