mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-14 08:31:23 +00:00
- completely redid how A_PainShootSkull checks the legality of the LS spawn.
It turned out that the Boom method does not work well with portals and fixing it while keeping it doesn't look feasible - the entire approach was bad from the start. Instead, let's use the same approach as P_XYMovement: Spawn the Lost Soul at the center of the PE, and then use multiple P_TryMoves to get it to its intended location. This will check all blocking lines, just like Boom did, but it will also properly handle z-positioning and portal transitions.
This commit is contained in:
parent
7325e3f0f8
commit
f8c6adb7eb
1 changed files with 64 additions and 62 deletions
|
@ -62,77 +62,78 @@ void A_PainShootSkull (VMFrameStack *stack, AActor *self, DAngle Angle, PClassAc
|
||||||
}
|
}
|
||||||
|
|
||||||
// okay, there's room for another one
|
// okay, there's room for another one
|
||||||
prestep = 4 + (self->radius + GetDefaultByType(spawntype)->radius) * 1.5;
|
double otherradius = GetDefaultByType(spawntype)->radius;
|
||||||
|
prestep = 4 + (self->radius + otherradius) * 1.5;
|
||||||
|
|
||||||
// NOTE: The following code contains some advance work for line-to-line portals which is currenty inactive.
|
DVector2 move = Angle.ToVector(prestep);
|
||||||
|
DVector3 spawnpos = self->PosPlusZ(8.0);
|
||||||
|
DVector3 destpos = spawnpos + move;
|
||||||
|
|
||||||
DVector2 dist = Angle.ToVector(prestep);
|
other = Spawn(spawntype, spawnpos, ALLOW_REPLACE);
|
||||||
DVector3 pos = self->Vec3Offset(dist.X, dist.Y, 8., true);
|
|
||||||
DVector3 src = self->Pos();
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++)
|
// Now check if the spawn is legal. Unlike Boom's hopeless attempt at fixing it, let's do it the same way
|
||||||
|
// P_XYMovement solves the line skipping: Spawn the Lost Soul near the PE's center and then use multiple
|
||||||
|
// smaller steps to get it to its intended position. This will also result in proper clipping, but
|
||||||
|
// it will avoid all the problems of the Boom method, which checked too many lines and despite some
|
||||||
|
// adjustments never worked with portals.
|
||||||
|
|
||||||
|
if (other != nullptr)
|
||||||
{
|
{
|
||||||
// Check whether the Lost Soul is being fired through a 1-sided // phares
|
double maxmove = other->radius - 1;
|
||||||
// wall or an impassible line, or a "monsters can't cross" line.// |
|
|
||||||
// If it is, then we don't allow the spawn. // V
|
|
||||||
|
|
||||||
FBoundingBox box(MIN(src.X, pos.X), MIN(src.Y, pos.Y), MAX(src.X, pos.X), MAX(src.Y, pos.Y));
|
if (maxmove <= 0) maxmove = MAXMOVE;
|
||||||
FBlockLinesIterator it(box);
|
|
||||||
line_t *ld;
|
|
||||||
bool inportal = false;
|
|
||||||
|
|
||||||
while ((ld = it.Next()))
|
const double xspeed = fabs(move.X);
|
||||||
|
const double yspeed = fabs(move.Y);
|
||||||
|
|
||||||
|
int steps = 1;
|
||||||
|
|
||||||
|
if (xspeed > yspeed)
|
||||||
{
|
{
|
||||||
if (ld->isLinePortal() && i == 0)
|
if (xspeed > maxmove)
|
||||||
{
|
{
|
||||||
if (P_PointOnLineSidePrecise(src, ld) == 0 &&
|
steps = int(1 + xspeed / maxmove);
|
||||||
P_PointOnLineSidePrecise(pos, ld) == 1)
|
|
||||||
{
|
|
||||||
// crossed a portal line from front to back, we need to repeat the check on the other side as well.
|
|
||||||
inportal = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!(ld->flags & ML_TWOSIDED) ||
|
else
|
||||||
(ld->flags & (ML_BLOCKING | ML_BLOCKMONSTERS | ML_BLOCKEVERYTHING)))
|
|
||||||
{
|
{
|
||||||
if (box.inRange(ld))
|
if (yspeed > maxmove)
|
||||||
{
|
{
|
||||||
if (P_PointOnLineSidePrecise(src, ld) != P_PointOnLineSidePrecise(pos, ld))
|
steps = int(1 + yspeed / maxmove);
|
||||||
return; // line blocks trajectory // ^
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!inportal) break;
|
|
||||||
|
|
||||||
// recalculate position and redo the check on the other side of the portal
|
DVector2 stepmove = move / steps;
|
||||||
pos = self->Vec3Offset(dist.X, dist.Y, 8.);
|
self->flags &= ~MF_SOLID; // make it solid again
|
||||||
src.X = pos.X - dist.X;
|
other->flags2 |= MF2_NOTELEPORT; // we do not want the LS to teleport
|
||||||
src.Y = pos.Y - dist.Y;
|
for (int i = 0; i < steps; i++)
|
||||||
|
{
|
||||||
}
|
DVector2 ptry = other->Pos().XY() + stepmove;
|
||||||
|
DAngle oldangle = other->Angles.Yaw;
|
||||||
other = Spawn (spawntype, pos, ALLOW_REPLACE);
|
if (!P_TryMove(other, ptry, 0, nullptr))
|
||||||
|
|
||||||
// Check to see if the new Lost Soul's z value is above the
|
|
||||||
// ceiling of its new sector, or below the floor. If so, kill it.
|
|
||||||
|
|
||||||
if (other->Top() > other->Sector->HighestCeilingAt(other) ||
|
|
||||||
other->Z() < other->Sector->LowestFloorAt(other))
|
|
||||||
{
|
{
|
||||||
// kill it immediately
|
// kill it immediately
|
||||||
P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None);// ^
|
other->ClearCounters();
|
||||||
return; // |
|
P_DamageMobj(other, self, self, TELEFRAG_DAMAGE, NAME_None);
|
||||||
} // phares
|
|
||||||
|
|
||||||
// Check for movements.
|
|
||||||
|
|
||||||
if (!P_CheckPosition (other, other->Pos()))
|
|
||||||
{
|
|
||||||
// kill it immediately
|
|
||||||
P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (other->Pos().XY() != ptry)
|
||||||
|
{
|
||||||
|
// If the new position does not match the desired position, the player
|
||||||
|
// must have gone through a portal.
|
||||||
|
// For that we need to adjust the movement vector for the following steps.
|
||||||
|
DAngle anglediff = deltaangle(oldangle, other->Angles.Yaw);
|
||||||
|
|
||||||
|
if (anglediff != 0)
|
||||||
|
{
|
||||||
|
stepmove = stepmove.Rotated(anglediff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
self->flags |= MF_SOLID; // don't let the LS be stuck in the PE while checking the move
|
||||||
|
|
||||||
// [RH] Lost souls hate the same things as their pain elementals
|
// [RH] Lost souls hate the same things as their pain elementals
|
||||||
other->CopyFriendliness (self, !(flags & PAF_NOTARGET));
|
other->CopyFriendliness (self, !(flags & PAF_NOTARGET));
|
||||||
|
|
||||||
|
@ -141,6 +142,7 @@ void A_PainShootSkull (VMFrameStack *stack, AActor *self, DAngle Angle, PClassAc
|
||||||
DECLARE_VMFUNC(AActor, A_SkullAttack);
|
DECLARE_VMFUNC(AActor, A_SkullAttack);
|
||||||
CallAction(stack, A_SkullAttack, other);
|
CallAction(stack, A_SkullAttack, other);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue