# 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)
// 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

View file

@ -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
{

View file

@ -2723,9 +2723,9 @@ static bool LoadDehSupp ()
else
{
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);

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

View file

@ -113,6 +113,16 @@ typedef TMap<int, PClassActor *> 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.

View file

@ -286,9 +286,11 @@ template<> inline FArchive &operator<< <FFont> (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);

View file

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

View file

@ -310,7 +310,7 @@ enum ESpecialMapthings
SMT_CopyCeilingPlane,
SMT_VertexFloorZ,
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.
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);
}
}

View file

@ -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;
}

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
for (i = 0; i < numsectors; ++i, ++bsec)
{

View file

@ -3781,7 +3781,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);
}

View file

@ -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);
@ -477,6 +478,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;
if (SaveVersion >= 4531)
{
arc << li->skybox;
@ -516,6 +523,15 @@ void P_SerializeWorld (FArchive &arc)
{
arc << zn->Environment;
}
if (SaveVersion >= 4532)
{
arc << linePortals;
}
else
{
linePortals.Clear();
}
}
void extsector_t::Serialize(FArchive &arc)

View file

@ -1769,7 +1769,7 @@ void P_LoadThings (MapData * map)
#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);
}
@ -1976,7 +1976,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;
}
@ -2079,9 +2078,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 ()
@ -2174,6 +2170,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.
@ -2266,6 +2263,8 @@ void P_LoadLineDefs2 (MapData * map)
{
int j;
ld->portalindex = UINT_MAX;
for (j = 0; j < 5; j++)
ld->args[j] = mld->args[j];
@ -3395,6 +3394,7 @@ void P_FreeLevelData ()
level.killed_monsters = level.found_items = level.found_secrets =
wminfo.maxfrags = 0;
linePortals.Clear();
FBehavior::StaticUnloadModules ();
if (vertexes != NULL)
{

View file

@ -64,6 +64,7 @@
#include "a_keys.h"
#include "c_dispatch.h"
#include "r_sky.h"
#include "portal.h"
#ifndef NO_EDATA
#include "edata.h"
#endif
@ -1465,6 +1466,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])
@ -1536,6 +1541,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:

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
{
if (LineHasIDs(i))

View file

@ -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;

View file

@ -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;

View file

@ -6,97 +6,35 @@
#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)
PortalDrawseg* CurrentPortal = NULL;
int CurrentPortalUniq = 0;
bool CurrentPortalInSkybox = false;
TArray<FLinePortal> linePortals;
// [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,
fixed_t& rx, fixed_t& ry)
FArchive &operator<< (FArchive &arc, FLinePortal &port)
{
float xx = FIXED2FLOAT(o2x) - FIXED2FLOAT(o1x);
float xy = FIXED2FLOAT(o2y) - FIXED2FLOAT(o1y);
float d1x = FIXED2FLOAT(p1x) - FIXED2FLOAT(o1x);
float d1y = FIXED2FLOAT(p1y) - FIXED2FLOAT(o1y);
if (d1x > d1y)
{
d1y = d1y / d1x * 32767.0f;
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;
arc << port.mOrigin
<< port.mDestination
<< port.mXDisplacement
<< port.mYDisplacement
<< port.mType
<< port.mFlags
<< port.mDefFlags
<< port.mAlign;
return arc;
}
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)
{
// 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)
if (line->args[2] >= PORTT_VISUAL && line->args[2] <= PORTT_LINKED)
{
// 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)
{
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;
line->portal_mirror = false;
line->portal_passive = (line->special == Line_SetVisualPortal);
line->portal_dst = dst;
port->mDefFlags = port->mType == PORTT_VISUAL ? PORTF_VISIBLE : port->mType == PORTT_TELEPORT ? PORTF_TYPETELEPORT : PORTF_TYPEINTERACTIVE;
}
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;
line->portal_mirror = false;
line->portal_passive = false;
line->portal_dst = NULL;
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;
// 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
{
line->portal = false;
line->portal_mirror = false;
line->portal_passive = false;
line->portal_dst = NULL;
// 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,
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)
@ -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)
{
// 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;
}
}
@ -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)
{
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);
}
@ -302,12 +376,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;
@ -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
}

View file

@ -8,29 +8,54 @@
#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
enum
{
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)
PORTF_VISIBLE = 1,
PORTF_PASSABLE = 2,
PORTF_SOUNDTRAVERSE = 4,
PORTF_INTERACTIVE = 8,
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)
PORTF_TYPETELEPORT = PORTF_VISIBLE | PORTF_PASSABLE | PORTF_SOUNDTRAVERSE,
PORTF_TYPEINTERACTIVE = PORTF_VISIBLE | PORTF_PASSABLE | PORTF_SOUNDTRAVERSE | PORTF_INTERACTIVE,
};
extern PortalDrawseg* CurrentPortal;
extern int CurrentPortalUniq;
extern bool CurrentPortalInSkybox;
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<FLinePortal> linePortals;
void P_SpawnLinePortal(line_t* line);
void P_FinalizePortals();
/* 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);
@ -71,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

View file

@ -99,7 +99,7 @@ static BYTE FakeSide;
int WindowLeft, WindowRight;
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;
@ -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;
}

View file

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

View file

@ -379,6 +379,7 @@ enum
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
@ -1084,16 +1085,15 @@ 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;
unsigned portalindex;
TObjPtr<ASkyViewpoint> skybox;
bool isLinePortal() const
{
return portal;
}
// returns true if the portal is crossable by actors
bool isLinePortal() const;
// 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

View file

@ -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"

View file

@ -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
@ -517,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);
@ -2001,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;
@ -2629,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;
@ -2650,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);
}
@ -2761,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;
}
@ -2919,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;
}

View file

@ -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<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

View file

@ -31,6 +31,7 @@
#include <stdlib.h>
#include <algorithm>
#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

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);
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 ();

View file

@ -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;
}

View file

@ -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

View file

@ -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);
};
//==========================================================================
//
//

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)
: 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);
}
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);

View file

@ -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)

View file

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

View file

@ -67,9 +67,7 @@ enum
// 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.
// 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)
301 = 0, Door_Open(0)
302 = 0, Door_Close(0)
@ -77,7 +75,7 @@ enum
304 = 0, Door_WaitRaise(0)
305 = 0, Door_WaitClose(0)
306 = 0, Floor_RaiseToHighest(0)
307 = 0, Floor_LowerToHighest(0)
307 = 0, Floor_LowerToHighestEE(0)
308 = 0, Floor_RaiseToLowest(0)
309 = 0, Floor_LowerToLowest(0)
310 = 0, Floor_RaiseToNearest(0)
@ -114,7 +112,6 @@ enum
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"
@ -157,11 +154,11 @@ enum
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