mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-25 21:41:03 +00:00
- 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:
parent
047070d180
commit
a9ca53bc00
2 changed files with 123 additions and 8 deletions
129
src/p_map.cpp
129
src/p_map.cpp
|
@ -995,6 +995,108 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
|
|||
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
|
||||
// being considered for collision with the player.
|
||||
validcount++;
|
||||
spechit.Clear();
|
||||
portalhit.Clear();
|
||||
|
||||
thing->BlockingMobj = NULL;
|
||||
thing->height = realheight;
|
||||
if (actorsonly || (thing->flags & MF_NOCLIP))
|
||||
return (thing->BlockingMobj = thingblocker) == NULL;
|
||||
|
||||
spechit.Clear();
|
||||
portalhit.Clear();
|
||||
|
||||
FMultiBlockLinesIterator it(pcheck, x, y, thing->Z(), thing->height, thing->radius);
|
||||
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))
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -2199,14 +2317,11 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
|
|||
fixedvec3 oldthingpos = thing->Pos();
|
||||
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, thingpos.x, thingpos.y);
|
||||
P_TranslatePortalZ(ld, out, 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->flags6 &= ~MF6_INTRYMOVE;
|
||||
|
|
|
@ -152,7 +152,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
|
|||
sector_t *front, *back;
|
||||
fixed_t fc, ff, bc, bf;
|
||||
|
||||
if (linedef->sidedef[1] == NULL)
|
||||
if (linedef->backsector == NULL)
|
||||
{
|
||||
// single sided line
|
||||
open.range = 0;
|
||||
|
|
Loading…
Reference in a new issue