From 047070d180712e43e7c415d58e37ab9ed8032c78 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 27 Feb 2016 18:06:24 +0100 Subject: [PATCH] - made arbitrary portals passable. This includes: * allow one sided portal linedefs to be crossable when part of a polyobject. Due to the limitations, two-sided linedefs won't work here. For general use this is still not allowed because making them passable would require some crippling fudging. * delay portal finalization until after polyobjects have been spawned. * the camera interpolation also needs to handle angle differences. The code is still not 100% complete - the most important thing that is still missing is proper handling of P_CheckPosition through arbitrary portals. --- src/p_map.cpp | 31 +++++++++++++++++++++++-------- src/p_setup.cpp | 3 ++- src/p_spec.cpp | 2 -- src/portal.cpp | 7 +++++++ src/r_utility.cpp | 29 +++++++++++++++++++---------- src/r_utility.h | 10 +++++++++- 6 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 942b1dfdc..4804780e0 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -808,6 +808,18 @@ 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()) + { + spechit_t spec; + spec.line = ld; + spec.refpos = cres.position; + spec.oldrefpos = tm.thing->PosRelative(ld); + portalhit.Push(spec); + return true; + } + if (((cres.portalflags & FFCF_NOFLOOR) && LineIsAbove(cres.line, tm.thing) != 0) || ((cres.portalflags & FFCF_NOCEILING) && LineIsBelow(cres.line, tm.thing) != 0)) { @@ -2143,7 +2155,7 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, while (true) { fixed_t bestfrac = FIXED_MAX; - spechit_t *besthit = NULL; + spechit_t besthit; // find the portal nearest to the crossing actor for (auto &spec : portalhit) { @@ -2160,7 +2172,7 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, fixed_t frac = P_InterceptVector(&dl1, &dl2); if (frac < bestfrac) { - besthit = &spec; + besthit = spec; bestfrac = frac; } } @@ -2168,7 +2180,7 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, if (bestfrac < FIXED_MAX) { - line_t *ld = besthit->line; + line_t *ld = besthit.line; FLinePortal *port = ld->getPortal(); if (port->mType == PORTT_LINKED) { @@ -2192,8 +2204,6 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, // so that the spechit array gets proper positions assigned that can be evaluated later. P_TranslatePortalXY(ld, out, pos.x, pos.y); P_TranslatePortalXY(ld, out, thingpos.x, thingpos.y); - P_TranslatePortalVXVY(ld, out, thing->velx, thing->vely); - P_TranslatePortalAngle(ld, out, thing->angle); P_TranslatePortalZ(ld, out, pos.z); thing->SetXYZ(thingpos.x, thingpos.y, pos.z); if (!P_CheckPosition(thing, pos.x, pos.y)) @@ -2204,16 +2214,19 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, } thing->UnlinkFromWorld(); thing->SetXYZ(pos); + P_TranslatePortalVXVY(ld, out, thing->velx, thing->vely); + P_TranslatePortalAngle(ld, out, thing->angle); thing->LinkToWorld(); P_FindFloorCeiling(thing); thing->ClearInterpolation(); + portalcrossed = true; } // if this is the current camera we need to store the point where the portal was crossed and the exit // so that the renderer can properly calculate an interpolated position along the movement path. if (thing == players[consoleplayer].camera) { - divline_t dl1 = { besthit->oldrefpos.x,besthit-> oldrefpos.y, besthit->refpos.x - besthit->oldrefpos.x, besthit->refpos.y - besthit->oldrefpos.y }; - fixedvec3 hit = { dl1.x + FixedMul(dl1.dx, bestfrac), dl1.y + FixedMul(dl1.dy, bestfrac), 0 }; + divline_t dl1 = { besthit.oldrefpos.x,besthit. oldrefpos.y, besthit.refpos.x - besthit.oldrefpos.x, besthit.refpos.y - besthit.oldrefpos.y }; + fixedvec3a hit = { dl1.x + FixedMul(dl1.dx, bestfrac), dl1.y + FixedMul(dl1.dy, bestfrac), 0, 0 }; line_t *out = port->mDestination; R_AddInterpolationPoint(hit); @@ -2226,6 +2239,8 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y, { P_TranslatePortalXY(ld, out, hit.x, hit.y); P_TranslatePortalZ(ld, out, hit.z); + players[consoleplayer].viewz += hit.z; // needs to be done here because otherwise the renderer will not catch the change. + P_TranslatePortalAngle(ld, out, hit.angle); } R_AddInterpolationPoint(hit); } @@ -5450,7 +5465,7 @@ void PIT_FloorDrop(AActor *thing, FChangePosition *cpos) } if (thing->player && thing->player->mo == thing) { - thing->player->viewz += thing->Z() - oldz; + //thing->player->viewz += thing->Z() - oldz; } } diff --git a/src/p_setup.cpp b/src/p_setup.cpp index e5da17126..5fdff87e1 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -4045,7 +4045,8 @@ void P_SetupLevel (const char *lumpname, int position) times[16].Clock(); if (reloop) P_LoopSidedefs (false); - PO_Init (); // Initialize the polyobjs + PO_Init (); // Initialize the polyobjs + P_FinalizePortals(); // finalize line portals after polyobjects have been initialized. This info is needed for properly flagging them. times[16].Unclock(); assert(sidetemp != NULL); diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 206a7e172..23bd2f911 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1531,8 +1531,6 @@ void P_SpawnSpecials (void) } // [RH] Start running any open scripts on this map FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false); - P_FinalizePortals(); - P_CreateLinkedPortals(); } // killough 2/28/98: diff --git a/src/portal.cpp b/src/portal.cpp index 2a920f74c..cd501513a 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -323,6 +323,12 @@ 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. @@ -387,6 +393,7 @@ void P_FinalizePortals() } P_CollectLinkedPortals(); BuildBlockmap(); + P_CreateLinkedPortals(); } //============================================================================ diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 0239aaa5d..0c23064af 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -81,7 +81,7 @@ static TArray PastViewers; static FRandom pr_torchflicker ("TorchFlicker"); static FRandom pr_hom; static bool NoInterpolateView; -static TArray InterpolationPath; +static TArray InterpolationPath; // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -586,6 +586,8 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi int oldgroup = R_PointInSubsector(iview->oviewx, iview->oviewy)->sector->PortalGroup; int newgroup = R_PointInSubsector(iview->nviewx, iview->nviewy)->sector->PortalGroup; + fixed_t oviewangle = iview->oviewangle; + fixed_t nviewangle = iview->nviewangle; if ((iview->oviewx != iview->nviewx || iview->oviewy != iview->nviewy) && InterpolationPath.Size() > 0) { viewx = iview->nviewx; @@ -601,27 +603,31 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi fixed_t pathlen = 0; fixed_t zdiff = 0; fixed_t totalzdiff = 0; + angle_t adiff = 0; + angle_t totaladiff = 0; fixed_t oviewz = iview->oviewz; fixed_t nviewz = iview->nviewz; - fixedvec3 oldpos = { iview->oviewx, iview->oviewy, 0 }; - fixedvec3 newpos = { iview->nviewx, iview->nviewy, 0 }; + fixedvec3a oldpos = { iview->oviewx, iview->oviewy, 0, 0 }; + fixedvec3a newpos = { iview->nviewx, iview->nviewy, 0, 0 }; InterpolationPath.Push(newpos); // add this to the array to simplify the loops below for (unsigned i = 0; i < InterpolationPath.Size(); i += 2) { - fixedvec3 &start = i == 0 ? oldpos : InterpolationPath[i - 1]; - fixedvec3 &end = InterpolationPath[i]; + fixedvec3a &start = i == 0 ? oldpos : InterpolationPath[i - 1]; + fixedvec3a &end = InterpolationPath[i]; pathlen += xs_CRoundToInt(TVector2(end.x - start.x, end.y - start.y).Length()); totalzdiff += start.z; + totaladiff += start.angle; } fixed_t interpolatedlen = FixedMul(frac, pathlen); for (unsigned i = 0; i < InterpolationPath.Size(); i += 2) { - fixedvec3 &start = i == 0 ? oldpos : InterpolationPath[i - 1]; - fixedvec3 &end = InterpolationPath[i]; + fixedvec3a &start = i == 0 ? oldpos : InterpolationPath[i - 1]; + fixedvec3a &end = InterpolationPath[i]; fixed_t fraglen = xs_CRoundToInt(TVector2(end.x - start.x, end.y - start.y).Length()); zdiff += start.z; + adiff += start.angle; if (fraglen <= interpolatedlen) { interpolatedlen -= fraglen; @@ -631,9 +637,12 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi fixed_t fragfrac = FixedDiv(interpolatedlen, fraglen); oviewz += zdiff; nviewz -= totalzdiff - zdiff; + oviewangle += adiff; + nviewangle -= totaladiff - adiff; viewx = start.x + FixedMul(fragfrac, end.x - start.x); viewy = start.y + FixedMul(fragfrac, end.y - start.y); viewz = oviewz + FixedMul(frac, nviewz - oviewz); + break; } } InterpolationPath.Pop(); @@ -661,7 +670,7 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi (!netgame || !cl_noprediction) && !LocalKeyboardTurner) { - viewangle = iview->nviewangle + (LocalViewAngle & 0xFFFF0000); + viewangle = nviewangle + (LocalViewAngle & 0xFFFF0000); fixed_t delta = player->centering ? 0 : -(signed)(LocalViewPitch & 0xFFFF0000); @@ -694,7 +703,7 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi else { viewpitch = iview->oviewpitch + FixedMul (frac, iview->nviewpitch - iview->oviewpitch); - viewangle = iview->oviewangle + FixedMul (frac, iview->nviewangle - iview->oviewangle); + viewangle = oviewangle + FixedMul (frac, nviewangle - oviewangle); } // Due to interpolation this is not necessarily the same as the sector the camera is in. @@ -876,7 +885,7 @@ void R_ClearInterpolationPath() // //========================================================================== -void R_AddInterpolationPoint(const fixedvec3 &vec) +void R_AddInterpolationPoint(const fixedvec3a &vec) { InterpolationPath.Push(vec); } diff --git a/src/r_utility.h b/src/r_utility.h index e9efb14e9..f8f91c1bc 100644 --- a/src/r_utility.h +++ b/src/r_utility.h @@ -63,13 +63,21 @@ inline angle_t R_PointToAnglePrecise (fixed_t viewx, fixed_t viewy, fixed_t x, f return xs_RoundToUInt(atan2(double(y-viewy), double(x-viewx)) * (ANGLE_180/M_PI)); } +// Used for interpolation waypoints. +struct fixedvec3a +{ + fixed_t x, y, z; + angle_t angle; +}; + + subsector_t *R_PointInSubsector (fixed_t x, fixed_t y); fixed_t R_PointToDist2 (fixed_t dx, fixed_t dy); void R_ResetViewInterpolation (); void R_RebuildViewInterpolation(player_t *player); bool R_GetViewInterpolationStatus(); void R_ClearInterpolationPath(); -void R_AddInterpolationPoint(const fixedvec3 &vec); +void R_AddInterpolationPoint(const fixedvec3a &vec); void R_SetViewSize (int blocks); void R_SetFOV (float fov); float R_GetFOV ();