gzdoom-gles/wadsrc/static/zscript/shared/fastprojectile.txt
Christoph Oelckers 3a3cd87ce0 - perform the stepping adjustment for FastProjectiles in 3D.
Not checking the z-Axis means that they might pass through 3D floors without noticing at steep angles and very high speeds.
2018-02-28 18:26:25 +01:00

185 lines
3.7 KiB
Text

// Fast projectiles --------------------------------------------------------
class FastProjectile : Actor
{
Default
{
Projectile;
MissileHeight 0;
}
virtual void Effect()
{
class<Actor> trail = MissileName;
if (trail != null)
{
double hitz = pos.z - 8;
if (hitz < floorz)
{
hitz = floorz;
}
// Do not clip this offset to the floor.
hitz += MissileHeight;
Actor act = Spawn (trail, (pos.xy, hitz), ALLOW_REPLACE);
if (act != null)
{
if (bGetOwner && target != null)
act.target = target;
else
act.target = self;
act.angle = angle;
act.pitch = pitch;
}
}
}
//----------------------------------------------------------------------------
//
// AFastProjectile :: Tick
//
// Thinker for the ultra-fast projectiles used by Heretic and Hexen
//
//----------------------------------------------------------------------------
override void Tick ()
{
ClearInterpolation();
double oldz = pos.Z;
if (!bNoTimeFreeze)
{
//Added by MC: Freeze mode.
if (globalfreeze || level.Frozen)
{
return;
}
}
// [RH] Ripping is a little different than it was in Hexen
FCheckPosition tm;
tm.DoRipping = bRipper;
int count = 8;
if (radius > 0)
{
while ( abs(Vel.X) >= radius * count || abs(Vel.Y) >= radius * count || abs(Vel.Z) >= height * count)
{
// we need to take smaller steps.
count += count;
}
}
// Handle movement
if (Vel != (0, 0, 0) || (pos.Z != floorz))
{
// force some lateral movement so that collision detection works as intended.
if (bMissile && Vel.X == 0 && Vel.Y == 0 && !IsZeroDamage())
{
Vel.X = MinVel;
}
Vector3 frac = Vel / count;
int changexy = frac.X != 0 || frac.Y != 0;
int ripcount = count / 8;
for (int i = 0; i < count; i++)
{
if (changexy)
{
if (--ripcount <= 0)
{
tm.ClearLastRipped(); // [RH] Do rip damage each step, like Hexen
}
if (!TryMove (Pos.XY + frac.XY, true, NULL, tm))
{ // Blocked move
if (!bSkyExplode)
{
let l = tm.ceilingline;
if (l &&
l.backsector &&
l.backsector.GetTexture(sector.ceiling) == skyflatnum)
{
let posr = PosRelative(l.backsector);
if (pos.Z >= l.backsector.ceilingplane.ZatPoint(posr.XY))
{
// Hack to prevent missiles exploding against the sky.
// Does not handle sky floors.
Destroy ();
return;
}
}
// [RH] Don't explode on horizon lines.
if (BlockingLine != NULL && BlockingLine.special == Line_Horizon)
{
Destroy ();
return;
}
}
ExplodeMissile (BlockingLine, BlockingMobj);
return;
}
}
AddZ(frac.Z);
UpdateWaterLevel ();
oldz = pos.Z;
if (oldz <= floorz)
{ // Hit the floor
if (floorpic == skyflatnum && !bSkyExplode)
{
// [RH] Just remove the missile without exploding it
// if this is a sky floor.
Destroy ();
return;
}
SetZ(floorz);
HitFloor ();
ExplodeMissile (NULL, NULL);
return;
}
if (pos.Z + height > ceilingz)
{ // Hit the ceiling
if (ceilingpic == skyflatnum && !bSkyExplode)
{
Destroy ();
return;
}
SetZ(ceilingz - Height);
ExplodeMissile (NULL, NULL);
return;
}
CheckPortalTransition();
if (changexy && ripcount <= 0)
{
ripcount = count >> 3;
// call the 'Effect' method.
Effect();
}
}
}
if (!CheckNoDelay())
return; // freed itself
// Advance the state
if (tics != -1)
{
if (tics > 0) tics--;
while (!tics)
{
if (!SetState (CurState.NextState))
{ // mobj was removed
return;
}
}
}
}
}