qzdoom/wadsrc/static/zscript/shared/fastprojectile.txt
Christoph Oelckers 7011010ff2 - fixed the drain callback.
- changed the effect spawn prevention of the Hexen flame strike weapon and reverted the attempt to fix this in FastProjectile.

This cannot be fixed in the base class, which was doing everything right. It's the flame missile that was doing undefined things by stopping its movement without clearing its missile flag. This cannot work because missiles are given some minimal forced velocity to ensure collision detection and any attempt to address this without clearing the missile flag is doomed to fail.
2017-03-29 22:50:13 +02:00

184 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)
{
// 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;
}
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;
}
}
}
}
}