mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-10 23:01:50 +00:00
- 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.
This commit is contained in:
parent
9eaefc3685
commit
94b7ef72ca
13 changed files with 243 additions and 59 deletions
|
@ -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);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
168
src/portal.cpp
168
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<FLinePortal> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
66
src/portal.h
66
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<FLinePortal> 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
|
|
@ -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;
|
||||
|
|
22
src/r_defs.h
22
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
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue