- removed the one-sided line portals on polyobjects only limitation. Using Eternity's polyportal testmap shows that it expects one-sided crossable portals on non-polyobject walls.

- converted the P_TranslatePortal* functions to use floating point trigonometry. The combination of R_PointToAngle and finesine even created discrepancies with perfectly parallel portals which is just not acceptable.
- added a function to FPathTraverse to relocate the trace and restart from the new position.
- made P_UseLines portal aware. Traversal through line portals is complete (all types, even teleporters), whether sector portals need better treatment remains to be seen - at the moment it only checks the range at the player's vertical center.
This commit is contained in:
Christoph Oelckers 2016-03-01 01:36:36 +01:00
parent 6bcaa51968
commit 2584108200
9 changed files with 133 additions and 64 deletions

View file

@ -743,6 +743,7 @@ public:
inline bool IsNoClip2() const;
void CheckPortalTransition(bool islinked);
fixedvec3 GetPortalTransition(fixed_t byoffset);
// What species am I?
virtual FName GetSpecies();

View file

@ -820,8 +820,8 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
if (!ld->backsector)
{ // One sided line
// Needed for polyobject portals. Having two-sided lines just for portals on otherwise solid polyobjects is a messy subject.
if ((cres.line->sidedef[0]->Flags & WALLF_POLYOBJ) && cres.line->isLinePortal())
// Needed for polyobject portals.
if (cres.line->isLinePortal())
{
spechit_t spec;
spec.line = ld;
@ -4731,10 +4731,11 @@ bool P_TalkFacing(AActor *player)
//
//==========================================================================
bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline)
bool P_UseTraverse(AActor *usething, fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy, bool &foundline)
{
FPathTraverse it(usething->X(), usething->Y(), endx, endy, PT_ADDLINES | PT_ADDTHINGS);
FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES | PT_ADDTHINGS);
intercept_t *in;
fixedvec3 xpos = { startx, starty, usething->Z() };
while ((in = it.Next()))
{
@ -4754,6 +4755,21 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline
}
continue;
}
if (in->d.line->isLinePortal())
{
if (P_PointOnLineSide(xpos.x, xpos.y, in->d.line) == 0)
{
FLinePortal *port = in->d.line->getPortal();
if (port->mType != PORTT_LINKED) // other types will cause problems with
{
return true;
}
// Also translate the player origin, so that we can use that for checks further below and in P_CheckSwitchRange
it.PortalRealign(in, PT_ADDLINES | PT_ADDTHINGS, &xpos);
}
continue;
}
FLineOpening open;
if (in->d.line->special == 0 || !(in->d.line->activation & (SPAC_Use | SPAC_UseThrough | SPAC_UseBack)))
@ -4782,7 +4798,7 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline
return true;
}
sec = P_PointOnLineSide(usething->X(), usething->Y(), in->d.line) == 0 ?
sec = P_PointOnLineSide(xpos.x, xpos.y, in->d.line) == 0 ?
in->d.line->frontsector : in->d.line->backsector;
if (sec != NULL && sec->SecActTarget &&
@ -4801,7 +4817,7 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline
continue; // not a special line, but keep checking
}
if (P_PointOnLineSide(usething->X(), usething->Y(), in->d.line) == 1)
if (P_PointOnLineSide(xpos.x, xpos.y, in->d.line) == 1)
{
if (!(in->d.line->activation & SPAC_UseBack))
{
@ -4811,7 +4827,7 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline
}
else
{
P_ActivateLine(in->d.line, usething, 1, SPAC_UseBack);
P_ActivateLine(in->d.line, usething, 1, SPAC_UseBack, &xpos);
return true;
}
}
@ -4822,7 +4838,7 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline
goto blocked; // Line cannot be used from front side so treat it as a non-trigger line
}
P_ActivateLine(in->d.line, usething, 0, SPAC_Use);
P_ActivateLine(in->d.line, usething, 0, SPAC_Use, &xpos);
//WAS can't use more than one special line in a row
//jff 3/21/98 NOW multiple use allowed with enabling line flag
@ -4859,9 +4875,9 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline
//
//==========================================================================
bool P_NoWayTraverse(AActor *usething, fixed_t endx, fixed_t endy)
bool P_NoWayTraverse(AActor *usething, fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy)
{
FPathTraverse it(usething->X(), usething->Y(), endx, endy, PT_ADDLINES);
FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES);
intercept_t *in;
while ((in = it.Next()))
@ -4872,6 +4888,7 @@ bool P_NoWayTraverse(AActor *usething, fixed_t endx, fixed_t endy)
// [GrafZahl] de-obfuscated. Was I the only one who was unable to make sense out of
// this convoluted mess?
if (ld->special) continue;
if (ld->isLinePortal()) return false;
if (ld->flags&(ML_BLOCKING | ML_BLOCKEVERYTHING | ML_BLOCK_PLAYERS)) return true;
P_LineOpening(open, NULL, ld, it.Trace().x + FixedMul(it.Trace().dx, in->frac),
it.Trace().y + FixedMul(it.Trace().dy, in->frac));
@ -4890,12 +4907,16 @@ bool P_NoWayTraverse(AActor *usething, fixed_t endx, fixed_t endy)
//
//==========================================================================
CVAR(Int, userange, 0, 0);
void P_UseLines(player_t *player)
{
bool foundline = false;
// If the player is transitioning a portal, use the group that is at its vertical center.
fixedvec2 start = player->mo->GetPortalTransition(player->mo->height / 2);
// [NS] Now queries the Player's UseRange.
fixedvec2 end = player->mo->Vec2Angle(player->mo->UseRange, player->mo->angle, true);
fixedvec2 end = start + Vec2Angle(userange > 0? fixed_t(userange<<FRACBITS) : player->mo->UseRange, player->mo->angle);
// old code:
//
@ -4903,13 +4924,13 @@ void P_UseLines(player_t *player)
//
// This added test makes the "oof" sound work on 2s lines -- killough:
if (!P_UseTraverse(player->mo, end.x, end.y, foundline))
if (!P_UseTraverse(player->mo, start.x, start.y, end.x, end.y, foundline))
{ // [RH] Give sector a chance to eat the use
sector_t *sec = player->mo->Sector;
int spac = SECSPAC_Use;
if (foundline) spac |= SECSPAC_UseWall;
if ((!sec->SecActTarget || !sec->SecActTarget->TriggerAction(player->mo, spac)) &&
P_NoWayTraverse(player->mo, end.x, end.y))
P_NoWayTraverse(player->mo, start.x, start.y, end.x, end.y))
{
S_Sound(player->mo, CHAN_VOICE, "*usefail", 1, ATTN_IDLE);
}

View file

@ -1203,7 +1203,7 @@ void FPathTraverse::AddLineIntercepts(int bx, int by)
P_MakeDivline (ld, &dl);
frac = P_InterceptVector (&trace, &dl);
if (frac < 0 || frac > FRACUNIT) continue; // behind source or beyond end point
if (frac < startfrac || frac > FRACUNIT) continue; // behind source or beyond end point
intercept_t newintercept;
@ -1284,7 +1284,7 @@ void FPathTraverse::AddThingIntercepts (int bx, int by, FBlockThingsIterator &it
{
// It's a hit
fixed_t frac = P_InterceptVector (&trace, &line);
if (frac < 0)
if (frac < startfrac)
{ // behind source
continue;
}
@ -1352,7 +1352,7 @@ void FPathTraverse::AddThingIntercepts (int bx, int by, FBlockThingsIterator &it
frac = P_InterceptVector (&trace, &dl);
if (frac >= 0)
if (frac >= startfrac)
{
intercept_t newintercept;
newintercept.frac = frac;
@ -1400,7 +1400,7 @@ intercept_t *FPathTraverse::Next()
//
//===========================================================================
void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags)
void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, fixed_t startfrac)
{
fixed_t xt1, xt2;
fixed_t yt1, yt2;
@ -1424,6 +1424,7 @@ void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int fl
validcount++;
intercept_index = intercepts.Size();
this->startfrac = startfrac;
if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0)
x1 += FRACUNIT; // don't side exactly on a line
@ -1444,8 +1445,8 @@ void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int fl
trace.dy = y2 - y1;
}
_x1 = (long long)x1 - bmaporgx;
_y1 = (long long)y1 - bmaporgy;
_x1 = (long long)x1 + FixedMul(trace.dx, startfrac) - bmaporgx;
_y1 = (long long)y1 + FixedMul(trace.dy, startfrac) - bmaporgy;
x1 -= bmaporgx;
y1 -= bmaporgy;
xt1 = int(_x1 >> MAPBLOCKSHIFT);
@ -1608,6 +1609,39 @@ void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int fl
}
}
//===========================================================================
//
//
//
//===========================================================================
bool FPathTraverse::PortalRealign(intercept_t *in, int flags, fixedvec3 *optpos)
{
if (!in->isaline || !in->d.line->isLinePortal()) return false;
fixed_t hitx = trace.x;
fixed_t hity = trace.y;
fixed_t endx = trace.x + trace.dx;
fixed_t endy = trace.y + trace.dy;
line_t *out = in->d.line->getPortalDestination();
P_TranslatePortalXY(in->d.line, out, hitx, hity);
P_TranslatePortalXY(in->d.line, out, endx, endy);
if (optpos != NULL)
{
P_TranslatePortalXY(in->d.line, out, optpos->x, optpos->y);
P_TranslatePortalZ(in->d.line, out, optpos->z);
}
intercepts.Resize(intercept_index);
init(hitx, hity, endx, endy, flags, in->frac);
return true;
}
//===========================================================================
//
//
//
//===========================================================================
FPathTraverse::~FPathTraverse()
{
intercepts.Resize(intercept_index);

View file

@ -339,6 +339,7 @@ protected:
static TArray<intercept_t> intercepts;
divline_t trace;
fixed_t startfrac;
unsigned int intercept_index;
unsigned int intercept_count;
unsigned int count;
@ -354,7 +355,8 @@ public:
{
init(x1, y1, x2, y2, flags);
}
void init(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags);
void init(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, fixed_t startfrac = 0);
bool PortalRealign(intercept_t *in, int flags, fixedvec3 *optpos = NULL);
virtual ~FPathTraverse();
const divline_t &Trace() const { return trace; }
};
@ -394,5 +396,4 @@ fixed_t P_InterceptVector (const divline_t *v2, const divline_t *v1);
#define PT_COMPATIBLE 4
#define PT_DELTA 8 // x2,y2 is passed as a delta, not as an endpoint
#endif

View file

@ -3286,6 +3286,42 @@ void AActor::SetRoll(angle_t r, bool interpolate)
}
fixedvec3 AActor::GetPortalTransition(fixed_t byoffset)
{
bool moved = false;
sector_t *sec = Sector;
fixed_t testz = Z() + byoffset;
fixedvec3 pos = Pos();
while (!sec->PortalBlocksMovement(sector_t::ceiling))
{
AActor *port = sec->SkyBoxes[sector_t::ceiling];
if (testz > port->threshold)
{
pos = PosRelative(port->Sector);
sec = P_PointInSector(pos.x, pos.y);
moved = true;
}
else break;
}
if (!moved)
{
while (!sec->PortalBlocksMovement(sector_t::floor))
{
AActor *port = sec->SkyBoxes[sector_t::floor];
if (testz <= port->threshold)
{
pos = PosRelative(port->Sector);
sec = P_PointInSector(pos.x, pos.y);
}
else break;
}
}
return pos;
}
void AActor::CheckPortalTransition(bool islinked)
{
bool moved = false;

View file

@ -201,14 +201,14 @@ bool CheckIfExitIsGood (AActor *self, level_info_t *info)
//
//============================================================================
bool P_ActivateLine (line_t *line, AActor *mo, int side, int activationType)
bool P_ActivateLine (line_t *line, AActor *mo, int side, int activationType, fixedvec3 *optpos)
{
int lineActivation;
INTBOOL repeat;
INTBOOL buttonSuccess;
BYTE special;
if (!P_TestActivateLine (line, mo, side, activationType))
if (!P_TestActivateLine (line, mo, side, activationType, optpos))
{
return false;
}
@ -262,7 +262,7 @@ bool P_ActivateLine (line_t *line, AActor *mo, int side, int activationType)
//
//============================================================================
bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType)
bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType, fixedvec3 *optpos)
{
int lineActivation = line->activation;
@ -291,7 +291,7 @@ bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType)
}
if (activationType == SPAC_Use || activationType == SPAC_UseBack)
{
if (!P_CheckSwitchRange(mo, line, side))
if (!P_CheckSwitchRange(mo, line, side, optpos))
{
return false;
}

View file

@ -165,8 +165,8 @@ void P_SpawnSpecials (void);
void P_UpdateSpecials (void);
// when needed
bool P_ActivateLine (line_t *ld, AActor *mo, int side, int activationType);
bool P_TestActivateLine (line_t *ld, AActor *mo, int side, int activationType);
bool P_ActivateLine (line_t *ld, AActor *mo, int side, int activationType, fixedvec3 *optpos = NULL);
bool P_TestActivateLine (line_t *ld, AActor *mo, int side, int activationType, fixedvec3 *optpos = NULL);
bool P_PredictLine (line_t *ld, AActor *mo, int side, int activationType);
void P_PlayerInSpecialSector (player_t *player, sector_t * sector=NULL);
@ -404,7 +404,7 @@ void EV_StartLightFading (int tag, int value, int tics);
#define BUTTONTIME TICRATE // 1 second, in ticks.
bool P_ChangeSwitchTexture (side_t *side, int useAgain, BYTE special, bool *quest=NULL);
bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno);
bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno, fixedvec3 *optpos = NULL);
//
// P_PLATS

View file

@ -112,7 +112,7 @@ static bool P_StartButton (side_t *side, int Where, FSwitchDef *Switch, fixed_t
//
//==========================================================================
bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno)
bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno, fixedvec3 *optpos)
{
// Activated from an empty side -> always succeed
side_t *side = line->sidedef[sideno];
@ -140,7 +140,7 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno)
P_MakeDivline (line, &dll);
fixedvec3 pos = user->PosRelative(line);
fixedvec3 pos = optpos? *optpos : user->PosRelative(line);
dlu.x = pos.x;
dlu.y = pos.y;
dlu.dx = finecosine[user->angle >> ANGLETOFINESHIFT];

View file

@ -277,7 +277,7 @@ void P_SpawnLinePortal(line_t* line)
for (int i = 0; i < numlines; i++)
{
if (tagManager.GetFirstLineID(&lines[i]) == mytag && lines[i].args[0] == 1)
if (tagManager.GetFirstLineID(&lines[i]) == mytag && lines[i].args[0] == 1 && lines[i].special == Line_SetPortal)
{
line->portalindex = linePortals.Reserve(1);
FLinePortal *port = &linePortals.Last();
@ -323,12 +323,6 @@ void P_UpdatePortal(FLinePortal *port)
// Portal has no destination: switch it off
port->mFlags = 0;
}
else if ((port->mOrigin->backsector == NULL && !(port->mOrigin->sidedef[0]->Flags & WALLF_POLYOBJ)) ||
(port->mDestination->backsector == NULL && !(port->mOrigin->sidedef[0]->Flags & WALLF_POLYOBJ)))
{
// disable teleporting capability if a portal is or links to a one-sided wall (unless part of a polyobject.)
port->mFlags = PORTF_VISIBLE;
}
else if (port->mDestination->getPortalDestination() != port->mOrigin)
{
//portal doesn't link back. This will be a simple teleporter portal.
@ -562,24 +556,17 @@ void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y)
// Get the angle between the two linedefs, for rotating
// orientation and velocity. Rotate 180 degrees, and flip
// the position across the exit linedef, if reversed.
angle_t angle =
R_PointToAngle2(0, 0, dst->dx, dst->dy) -
R_PointToAngle2(0, 0, src->dx, src->dy);
angle += ANGLE_180;
// Sine, cosine of angle adjustment
fixed_t s = finesine[angle>>ANGLETOFINESHIFT];
fixed_t c = finecosine[angle>>ANGLETOFINESHIFT];
fixed_t tx, ty;
double angle = atan2(dst->dy, dst->dx) - atan2(src->dy, src->dx) + M_PI;
fixed_t s = FLOAT2FIXED(sin(angle));
fixed_t c = FLOAT2FIXED(cos(angle));
nposx = x - src->v1->x;
nposy = y - src->v1->y;
// Rotate position along normal to match exit linedef
tx = FixedMul(nposx, c) - FixedMul(nposy, s);
ty = FixedMul(nposy, c) + FixedMul(nposx, s);
fixed_t tx = FixedMul(nposx, c) - FixedMul(nposy, s);
fixed_t ty = FixedMul(nposy, c) + FixedMul(nposx, s);
tx += dst->v2->x;
ty += dst->v2->y;
@ -596,15 +583,9 @@ 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)
{
angle_t angle =
R_PointToAngle2(0, 0, dst->dx, dst->dy) -
R_PointToAngle2(0, 0, src->dx, src->dy);
angle += ANGLE_180;
// Sine, cosine of angle adjustment
fixed_t s = finesine[angle>>ANGLETOFINESHIFT];
fixed_t c = finecosine[angle>>ANGLETOFINESHIFT];
double angle = atan2(dst->dy, dst->dx) - atan2(src->dy, src->dx) + M_PI;
fixed_t s = FLOAT2FIXED(sin(angle));
fixed_t c = FLOAT2FIXED(cos(angle));
fixed_t orig_velx = vx;
fixed_t orig_vely = vy;
@ -626,12 +607,7 @@ void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle)
// Get the angle between the two linedefs, for rotating
// orientation and velocity. Rotate 180 degrees, and flip
// the position across the exit linedef, if reversed.
angle_t xangle =
R_PointToAngle2(0, 0, dst->dx, dst->dy) -
R_PointToAngle2(0, 0, src->dx, src->dy);
xangle += ANGLE_180;
angle += xangle;
angle += RAD2ANGLE(atan2(dst->dy, dst->dx) - atan2(src->dy, src->dx)) + ANGLE_180;
}
//============================================================================