- added a check for the destination of a portal to P_CheckPosition. This needs to run a separate BlockLinesIterator that only sets selected fields.

This commit is contained in:
Christoph Oelckers 2016-02-27 21:17:02 +01:00
parent 047070d180
commit a9ca53bc00
2 changed files with 123 additions and 8 deletions

View file

@ -995,6 +995,108 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
return true; return true;
} }
//==========================================================================
//
//
// PIT_CheckPortal
// This checks the destination side of a non-static line portal
// We cannot run a full P_CheckPosition there because it'd set
// multiple fields to values that can cause problems in other
// parts of the code
//
// What this does is starting a separate BlockLinesIterator
// and only taking the absolutely necessary information
// (i.e. floor and ceiling height plus terrain)
//
//
//==========================================================================
static bool PIT_CheckPortal(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::CheckResult cres, const FBoundingBox &box, FCheckPosition &tm)
{
// if in another vertical section let's just ignore it.
if (cres.portalflags & (FFCF_NOCEILING | FFCF_NOFLOOR)) return false;
if (box.Right() <= cres.line->bbox[BOXLEFT]
|| box.Left() >= cres.line->bbox[BOXRIGHT]
|| box.Top() <= cres.line->bbox[BOXBOTTOM]
|| box.Bottom() >= cres.line->bbox[BOXTOP])
return false;
if (box.BoxOnLineSide(cres.line) != -1)
return false;
line_t *lp = cres.line->getPortalDestination();
fixed_t zofs = 0;
P_TranslatePortalXY(cres.line, lp, cres.position.x, cres.position.y);
P_TranslatePortalZ(cres.line, lp, zofs);
// fudge a bit with the portal line so that this gets included in the checks that normally only get run on two-sided lines
sector_t *sec = lp->backsector;
if (lp->backsector == NULL) lp->backsector = lp->frontsector;
tm.thing->AddZ(zofs);
FBoundingBox pbox(cres.position.x, cres.position.y, tm.thing->radius);
FBlockLinesIterator it(pbox);
bool ret = false;
line_t *ld;
// Check all lines at the destination
while ((ld = it.Next()))
{
if (pbox.Right() <= ld->bbox[BOXLEFT]
|| pbox.Left() >= ld->bbox[BOXRIGHT]
|| pbox.Top() <= ld->bbox[BOXBOTTOM]
|| pbox.Bottom() >= ld->bbox[BOXTOP])
continue;
if (pbox.BoxOnLineSide(ld) != -1)
continue;
if (ld->backsector == NULL)
continue;
fixedvec2 ref = FindRefPoint(ld, cres.position);
FLineOpening open;
P_LineOpening(open, tm.thing, ld, ref.x, ref.y, cres.position.x, cres.position.y, 0);
// adjust floor / ceiling heights
if (open.top - zofs < tm.ceilingz)
{
tm.ceilingz = open.top - zofs;
tm.ceilingpic = open.ceilingpic;
/*
tm.ceilingsector = open.topsec;
tm.ceilingline = ld;
tm.thing->BlockingLine = ld;
*/
ret = true;
}
if (open.bottom - zofs > tm.floorz)
{
tm.floorz = open.bottom - zofs;
tm.floorpic = open.floorpic;
tm.floorterrain = open.floorterrain;
/*
tm.floorsector = open.bottomsec;
tm.touchmidtex = open.touchmidtex;
tm.abovemidtex = open.abovemidtex;
tm.thing->BlockingLine = ld;
*/
ret = true;
}
if (open.lowfloor - zofs < tm.dropoffz)
tm.dropoffz = open.lowfloor - zofs;
}
tm.thing->AddZ(-zofs);
lp->backsector = sec;
return ret;
}
//========================================================================== //==========================================================================
// //
@ -1617,14 +1719,15 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo
// a pickup they cannot get, because their validcount will prevent them from // a pickup they cannot get, because their validcount will prevent them from
// being considered for collision with the player. // being considered for collision with the player.
validcount++; validcount++;
spechit.Clear();
portalhit.Clear();
thing->BlockingMobj = NULL; thing->BlockingMobj = NULL;
thing->height = realheight; thing->height = realheight;
if (actorsonly || (thing->flags & MF_NOCLIP)) if (actorsonly || (thing->flags & MF_NOCLIP))
return (thing->BlockingMobj = thingblocker) == NULL; return (thing->BlockingMobj = thingblocker) == NULL;
spechit.Clear();
portalhit.Clear();
FMultiBlockLinesIterator it(pcheck, x, y, thing->Z(), thing->height, thing->radius); FMultiBlockLinesIterator it(pcheck, x, y, thing->Z(), thing->height, thing->radius);
FMultiBlockLinesIterator::CheckResult lcres; FMultiBlockLinesIterator::CheckResult lcres;
@ -1636,7 +1739,22 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo
while (it.Next(&lcres)) while (it.Next(&lcres))
{ {
good &= PIT_CheckLine(it, lcres, it.Box(), tm); bool thisresult = PIT_CheckLine(it, lcres, it.Box(), tm);
good &= thisresult;
if (thisresult)
{
FLinePortal *port = lcres.line->getPortal();
if (port != NULL && port->mFlags & PORTF_PASSABLE && port->mType != PORTT_LINKED)
{
// Checking the other side of the portal completely is too costly,
// but checking the portal's destination line is necessary to
// retrieve the proper sector heights on the other side.
if (PIT_CheckPortal(it, lcres, it.Box(), tm))
{
tm.thing->BlockingLine = lcres.line;
}
}
}
} }
if (!good) if (!good)
{ {
@ -2199,14 +2317,11 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
fixedvec3 oldthingpos = thing->Pos(); fixedvec3 oldthingpos = thing->Pos();
fixedvec2 thingpos = oldthingpos; fixedvec2 thingpos = oldthingpos;
// This gets a bit tricky because we want to catch all line specials the actor crosses on the other side, too.
// So we have to translate the old Actor xy and temporarily set this as the actor's current position for the P_CheckPosition call,
// 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, pos.x, pos.y);
P_TranslatePortalXY(ld, out, thingpos.x, thingpos.y); P_TranslatePortalXY(ld, out, thingpos.x, thingpos.y);
P_TranslatePortalZ(ld, out, pos.z); P_TranslatePortalZ(ld, out, pos.z);
thing->SetXYZ(thingpos.x, thingpos.y, pos.z); thing->SetXYZ(thingpos.x, thingpos.y, pos.z);
if (!P_CheckPosition(thing, pos.x, pos.y)) if (!P_CheckPosition(thing, pos.x, pos.y, true)) // check if some actor blocks us on the other side. (No line checks, because of the mess that'd create.)
{ {
thing->SetXYZ(oldthingpos); thing->SetXYZ(oldthingpos);
thing->flags6 &= ~MF6_INTRYMOVE; thing->flags6 &= ~MF6_INTRYMOVE;

View file

@ -152,7 +152,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
sector_t *front, *back; sector_t *front, *back;
fixed_t fc, ff, bc, bf; fixed_t fc, ff, bc, bf;
if (linedef->sidedef[1] == NULL) if (linedef->backsector == NULL)
{ {
// single sided line // single sided line
open.range = 0; open.range = 0;