- 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.
This commit is contained in:
Christoph Oelckers 2016-02-27 18:06:24 +01:00
parent fcb38a9419
commit 047070d180
6 changed files with 60 additions and 22 deletions

View file

@ -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;
}
}

View file

@ -4046,6 +4046,7 @@ void P_SetupLevel (const char *lumpname, int position)
times[16].Clock();
if (reloop) P_LoopSidedefs (false);
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);

View file

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

View file

@ -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();
}
//============================================================================

View file

@ -81,7 +81,7 @@ static TArray<InterpolationViewer> PastViewers;
static FRandom pr_torchflicker ("TorchFlicker");
static FRandom pr_hom;
static bool NoInterpolateView;
static TArray<fixedvec3> InterpolationPath;
static TArray<fixedvec3a> 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<double>(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<double>(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);
}

View file

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