- fixed some line clipping issues with portals

* Blocking lines above or below the current sector should only block if they actually intersect with the currently checking actor.
 * Sectors above a ceiling portal should not change current floor information and vice versa.
This commit is contained in:
Christoph Oelckers 2016-02-23 16:59:16 +01:00
parent 1f09341d2b
commit 58839200e5

View file

@ -748,6 +748,30 @@ int P_GetMoveFactor(const AActor *mo, int *frictionp)
} }
//==========================================================================
//
// Checks if the line intersects with the actor
// returns
// - 1 when above/below
// - 0 when intersecting
// - -1 when outside the portal
//
//==========================================================================
static int LineIsAbove(line_t *line, AActor *actor)
{
AActor *point = line->frontsector->SkyBoxes[sector_t::floor];
if (point == NULL) return -1;
return point->threshold >= actor->Top();
}
static int LineIsBelow(line_t *line, AActor *actor)
{
AActor *point = line->frontsector->SkyBoxes[sector_t::ceiling];
if (point == NULL) return -1;
return point->threshold <= actor->Z();
}
// //
// MOVEMENT ITERATOR FUNCTIONS // MOVEMENT ITERATOR FUNCTIONS
// //
@ -788,6 +812,13 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
if (!ld->backsector) if (!ld->backsector)
{ // One sided line { // One sided line
if (((cres.portalflags & FFCF_NOFLOOR) && LineIsAbove(cres.line, tm.thing) != 0) ||
((cres.portalflags & FFCF_NOCEILING) && LineIsBelow(cres.line, tm.thing) != 0))
{
// this blocking line is in a different vertical layer and does not intersect with the actor that is being checked.
// Since a one-sided line does not have an opening there's nothing left to do about it.
return true;
}
if (tm.thing->flags2 & MF2_BLASTED) if (tm.thing->flags2 & MF2_BLASTED)
{ {
P_DamageMobj(tm.thing, NULL, NULL, tm.thing->Mass >> 5, NAME_Melee); P_DamageMobj(tm.thing, NULL, NULL, tm.thing->Mass >> 5, NAME_Melee);
@ -818,17 +849,52 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
((Projectile) && (ld->flags & ML_BLOCKPROJECTILE)) || // block projectiles ((Projectile) && (ld->flags & ML_BLOCKPROJECTILE)) || // block projectiles
((tm.thing->flags & MF_FLOAT) && (ld->flags & ML_BLOCK_FLOATERS))) // block floaters ((tm.thing->flags & MF_FLOAT) && (ld->flags & ML_BLOCK_FLOATERS))) // block floaters
{ {
if (tm.thing->flags2 & MF2_BLASTED) if (cres.portalflags & FFCF_NOFLOOR)
{ {
P_DamageMobj(tm.thing, NULL, NULL, tm.thing->Mass >> 5, NAME_Melee); int state = LineIsAbove(cres.line, tm.thing);
if (state == -1) return true;
if (state == 1)
{
// the line should not block but we should set the ceilingz to the portal boundary so that we can't float up into that line.
fixed_t portalz = cres.line->frontsector->SkyBoxes[sector_t::floor]->threshold;
if (portalz < tm.ceilingz)
{
tm.ceilingz = portalz;
tm.ceilingsector = cres.line->frontsector;
}
return true;
}
}
else if (cres.portalflags & FFCF_NOCEILING)
{
// same, but for downward portals
int state = LineIsBelow(cres.line, tm.thing);
if (state == -1) return true;
if (state == 1)
{
fixed_t portalz = cres.line->frontsector->SkyBoxes[sector_t::ceiling]->threshold;
if (portalz > tm.floorz)
{
tm.floorz = portalz;
tm.floorsector = cres.line->frontsector;
tm.floorterrain = 0;
}
return true;
}
}
else
{
if (tm.thing->flags2 & MF2_BLASTED)
{
P_DamageMobj(tm.thing, NULL, NULL, tm.thing->Mass >> 5, NAME_Melee);
}
tm.thing->BlockingLine = ld;
// Calculate line side based on the actor's original position, not the new one.
CheckForPushSpecial(ld, P_PointOnLineSide(cres.position.x, cres.position.y, ld), tm.thing);
return false;
} }
tm.thing->BlockingLine = ld;
// Calculate line side based on the actor's original position, not the new one.
CheckForPushSpecial(ld, P_PointOnLineSide(cres.position.x, cres.position.y, ld), tm.thing);
return false;
} }
} }
fixedvec2 ref = FindRefPoint(ld, cres.position); fixedvec2 ref = FindRefPoint(ld, cres.position);
FLineOpening open; FLineOpening open;
@ -867,33 +933,39 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
} }
// adjust floor / ceiling heights // adjust floor / ceiling heights
if (open.top < tm.ceilingz) if (!(cres.portalflags & FFCF_NOCEILING))
{ {
tm.ceilingz = open.top; if (open.top < tm.ceilingz)
tm.ceilingsector = open.topsec; {
tm.ceilingpic = open.ceilingpic; tm.ceilingz = open.top;
tm.ceilingline = ld; tm.ceilingsector = open.topsec;
tm.thing->BlockingLine = ld; tm.ceilingpic = open.ceilingpic;
tm.ceilingline = ld;
tm.thing->BlockingLine = ld;
}
} }
if (open.bottom > tm.floorz) if (!(cres.portalflags & FFCF_NOFLOOR))
{ {
tm.floorz = open.bottom; if (open.bottom > tm.floorz)
tm.floorsector = open.bottomsec; {
tm.floorpic = open.floorpic; tm.floorz = open.bottom;
tm.floorterrain = open.floorterrain; tm.floorsector = open.bottomsec;
tm.touchmidtex = open.touchmidtex; tm.floorpic = open.floorpic;
tm.abovemidtex = open.abovemidtex; tm.floorterrain = open.floorterrain;
tm.thing->BlockingLine = ld; tm.touchmidtex = open.touchmidtex;
} tm.abovemidtex = open.abovemidtex;
else if (open.bottom == tm.floorz) tm.thing->BlockingLine = ld;
{ }
tm.touchmidtex |= open.touchmidtex; else if (open.bottom == tm.floorz)
tm.abovemidtex |= open.abovemidtex; {
} tm.touchmidtex |= open.touchmidtex;
tm.abovemidtex |= open.abovemidtex;
}
if (open.lowfloor < tm.dropoffz) if (open.lowfloor < tm.dropoffz)
tm.dropoffz = open.lowfloor; tm.dropoffz = open.lowfloor;
}
// if contacted a special line, add it to the list // if contacted a special line, add it to the list
spechit_t spec; spechit_t spec;
@ -903,7 +975,7 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
spec.refpos = cres.position; spec.refpos = cres.position;
spechit.Push(spec); spechit.Push(spec);
} }
if (ld->portalindex >= 0) if (ld->portalindex >= 0 && ld->portalindex != UINT_MAX)
{ {
spec.line = ld; spec.line = ld;
spec.refpos = cres.position; spec.refpos = cres.position;