mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-24 21:11:39 +00:00
7011010ff2
- 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.
184 lines
3.7 KiB
Text
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|