From 2584108200b7a72b78189efb82c7be23320040ee Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 1 Mar 2016 01:36:36 +0100 Subject: [PATCH] - 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. --- src/actor.h | 1 + src/p_map.cpp | 47 ++++++++++++++++++++++++++++++++++------------- src/p_maputl.cpp | 46 ++++++++++++++++++++++++++++++++++++++++------ src/p_maputl.h | 5 +++-- src/p_mobj.cpp | 36 ++++++++++++++++++++++++++++++++++++ src/p_spec.cpp | 8 ++++---- src/p_spec.h | 6 +++--- src/p_switch.cpp | 4 ++-- src/portal.cpp | 44 ++++++++++---------------------------------- 9 files changed, 133 insertions(+), 64 deletions(-) diff --git a/src/actor.h b/src/actor.h index 8f38e6e8c..d30da8922 100644 --- a/src/actor.h +++ b/src/actor.h @@ -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(); diff --git a/src/p_map.cpp b/src/p_map.cpp index 7f66fd2d4..235282434 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -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<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); } diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 9d98f4bf5..64eec19be 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -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); diff --git a/src/p_maputl.h b/src/p_maputl.h index 21d69e1c8..97c534c0e 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -339,6 +339,7 @@ protected: static TArray 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 \ No newline at end of file diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 51a671369..f03362ab5 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -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; diff --git a/src/p_spec.cpp b/src/p_spec.cpp index e229b973f..b9f2fa218 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -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; } diff --git a/src/p_spec.h b/src/p_spec.h index 0548a6b51..560ec9acd 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -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 diff --git a/src/p_switch.cpp b/src/p_switch.cpp index 0c9d37ccc..98630705c 100644 --- a/src/p_switch.cpp +++ b/src/p_switch.cpp @@ -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]; diff --git a/src/portal.cpp b/src/portal.cpp index 8cf4bf546..6f7192a52 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -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; } //============================================================================