- 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:
Christoph Oelckers 2016-02-05 23:15:56 +01:00
parent 9eaefc3685
commit 94b7ef72ca
13 changed files with 243 additions and 59 deletions

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

@ -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);
@ -474,6 +475,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;
for (j = 0; j < 2; j++) for (j = 0; j < 2; j++)
{ {
if (li->sidedef[j] == NULL) if (li->sidedef[j] == NULL)
@ -508,6 +515,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

@ -2156,6 +2156,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.
@ -2236,6 +2237,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];
@ -3365,6 +3368,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

@ -1504,6 +1504,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,10 +6,128 @@
#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)
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 // [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, 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 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; 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) void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y)
{ {
if (!src || !dst) 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) 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;
} }
} }

View file

@ -8,7 +8,50 @@
#include "p_local.h" #include "p_local.h"
#include "m_bbox.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_SpawnLinePortal(line_t* line);
void P_FinalizePortals();
/* code ported from prototype */ /* code ported from prototype */
@ -53,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;

View file

@ -988,26 +988,14 @@ 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
unsigned portalindex;
line_t *_portal_dst;
bool _portal;
// returns true if the portal is crossable by actors // returns true if the portal is crossable by actors
bool isLinePortal() const bool isLinePortal() const;
{
return false; // right now there are no crossable portals
}
// returns true if the portal needs to be handled by the renderer // returns true if the portal needs to be handled by the renderer
bool isVisualPortal() const bool isVisualPortal() const;
{ line_t *getPortalDestination() const;
return _portal; int getPortalAlignment() const;
}
line_t *getPortalDestination() const
{
return _portal_dst;
}
}; };
// phares 3/14/98 // phares 3/14/98

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

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