2015-06-07 17:54:36 +00:00
|
|
|
#ifndef _PORTALS_H_
|
|
|
|
#define _PORTALS_H_
|
|
|
|
|
|
|
|
#include "basictypes.h"
|
|
|
|
#include "v_video.h"
|
|
|
|
#include "r_defs.h"
|
|
|
|
#include "actor.h"
|
|
|
|
#include "p_local.h"
|
|
|
|
#include "m_bbox.h"
|
2016-02-14 23:53:59 +00:00
|
|
|
#include "a_sharedglobal.h"
|
2015-06-07 17:54:36 +00:00
|
|
|
|
2016-02-16 11:51:10 +00:00
|
|
|
struct FPortalGroupArray;
|
2016-02-15 12:40:31 +00:00
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// This table holds the offsets for the different parts of a map
|
|
|
|
// that are connected by portals.
|
|
|
|
// The idea here is basically the same as implemented in Eternity Engine:
|
|
|
|
//
|
|
|
|
// - each portal creates two sector groups in the map
|
|
|
|
// which are offset by the displacement of the portal anchors
|
|
|
|
//
|
|
|
|
// - for two or multiple groups the displacement is calculated by
|
|
|
|
// adding the displacements between intermediate groups which
|
|
|
|
// have to be traversed to connect the two
|
|
|
|
//
|
|
|
|
// - any sector not connected to any portal is assigned to group 0
|
|
|
|
// Group 0 has no displacement to any other group in the level.
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2016-02-14 15:26:27 +00:00
|
|
|
struct FDisplacement
|
|
|
|
{
|
2016-02-16 15:40:53 +00:00
|
|
|
fixedvec2 pos;
|
2016-02-14 15:26:27 +00:00
|
|
|
bool isSet;
|
|
|
|
BYTE indirect; // just for illustration.
|
2016-02-16 15:40:53 +00:00
|
|
|
|
|
|
|
operator fixedvec2()
|
|
|
|
{
|
|
|
|
return pos;
|
|
|
|
}
|
2016-02-14 15:26:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct FDisplacementTable
|
|
|
|
{
|
|
|
|
TArray<FDisplacement> data;
|
|
|
|
int size;
|
|
|
|
|
|
|
|
void Create(int numgroups)
|
|
|
|
{
|
|
|
|
data.Resize(numgroups*numgroups);
|
|
|
|
memset(&data[0], 0, numgroups*numgroups*sizeof(data[0]));
|
|
|
|
size = numgroups;
|
|
|
|
}
|
|
|
|
|
|
|
|
FDisplacement &operator()(int x, int y)
|
|
|
|
{
|
|
|
|
return data[x + size*y];
|
|
|
|
}
|
|
|
|
};
|
2016-02-05 22:15:56 +00:00
|
|
|
|
2016-02-14 23:53:59 +00:00
|
|
|
extern FDisplacementTable Displacements;
|
|
|
|
|
2016-02-15 12:40:31 +00:00
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// Flags and types for linedef portals
|
|
|
|
//
|
|
|
|
//============================================================================
|
2016-02-14 23:53:59 +00:00
|
|
|
|
2016-02-05 22:15:56 +00:00
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2016-02-14 23:53:59 +00:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
PCOLL_NOTLINKED = 1,
|
|
|
|
PCOLL_LINKED = 2
|
|
|
|
};
|
|
|
|
|
2016-02-15 12:40:31 +00:00
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// All information about a line-to-line portal (all types)
|
|
|
|
// There is no structure for sector plane portals because for historic
|
|
|
|
// reasons those use actors to connect.
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2016-02-05 22:15:56 +00:00
|
|
|
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;
|
|
|
|
|
2016-02-05 15:58:57 +00:00
|
|
|
void P_SpawnLinePortal(line_t* line);
|
2016-02-05 22:15:56 +00:00
|
|
|
void P_FinalizePortals();
|
2016-02-06 20:16:57 +00:00
|
|
|
bool P_ChangePortal(line_t *ln, int thisid, int destid);
|
2016-02-14 12:12:03 +00:00
|
|
|
void P_CreateLinkedPortals();
|
2016-02-16 11:51:10 +00:00
|
|
|
bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortalGroupArray &out);
|
2016-02-14 23:53:59 +00:00
|
|
|
void P_CollectLinkedPortals();
|
|
|
|
inline int P_NumPortalGroups()
|
|
|
|
{
|
|
|
|
return Displacements.size;
|
|
|
|
}
|
2016-02-05 15:58:57 +00:00
|
|
|
|
2015-06-07 17:54:36 +00:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
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);
|
|
|
|
void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z);
|
|
|
|
void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy);
|
|
|
|
|
2016-02-15 12:40:31 +00:00
|
|
|
//============================================================================
|
|
|
|
//
|
2015-06-07 17:54:36 +00:00
|
|
|
// basically, this is a teleporting tracer function,
|
|
|
|
// which can be used by itself (to calculate portal-aware offsets, say, for projectiles)
|
|
|
|
// or to teleport normal tracers (like hitscan, railgun, autoaim tracers)
|
2016-02-15 12:40:31 +00:00
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2015-06-07 17:54:36 +00:00
|
|
|
class PortalTracer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
PortalTracer(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy);
|
|
|
|
|
|
|
|
// trace to next portal
|
|
|
|
bool TraceStep();
|
|
|
|
// trace to last available portal on the path
|
|
|
|
void TraceAll() { while (TraceStep()) continue; }
|
|
|
|
|
|
|
|
int depth;
|
|
|
|
fixed_t startx;
|
|
|
|
fixed_t starty;
|
|
|
|
fixed_t intx;
|
|
|
|
fixed_t inty;
|
|
|
|
fixed_t intxIn;
|
|
|
|
fixed_t intyIn;
|
|
|
|
fixed_t endx;
|
|
|
|
fixed_t endy;
|
|
|
|
angle_t angle;
|
|
|
|
fixed_t z;
|
|
|
|
fixed_t frac;
|
|
|
|
line_t* in;
|
|
|
|
line_t* out;
|
|
|
|
fixed_t vx;
|
|
|
|
fixed_t vy;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* new code */
|
|
|
|
fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y);
|
|
|
|
|
2016-02-15 12:40:31 +00:00
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// some wrappers around the portal data.
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2016-02-05 22:15:56 +00:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2016-02-14 23:53:59 +00:00
|
|
|
inline bool sector_t::PortalBlocksView(int plane)
|
|
|
|
{
|
|
|
|
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
|
|
|
|
return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool sector_t::PortalBlocksMovement(int plane)
|
|
|
|
{
|
|
|
|
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
|
|
|
|
return !!(planes[plane].Flags & (PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool sector_t::PortalBlocksSound(int plane)
|
|
|
|
{
|
|
|
|
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
|
|
|
|
return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
|
|
|
|
}
|
|
|
|
|
2016-02-16 15:40:53 +00:00
|
|
|
// These may only be called if the portal has been validated
|
|
|
|
inline FDisplacement §or_t::FloorDisplacement()
|
|
|
|
{
|
|
|
|
return Displacements(PortalGroup, SkyBoxes[sector_t::floor]->Sector->PortalGroup);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline FDisplacement §or_t::CeilingDisplacement()
|
|
|
|
{
|
|
|
|
return Displacements(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup);
|
|
|
|
}
|
|
|
|
|
2015-06-07 17:54:36 +00:00
|
|
|
#endif
|