2008-11-15 09:57:18 +00:00
|
|
|
|
|
|
|
#include "a_sharedglobal.h"
|
|
|
|
#include "p_local.h"
|
2009-05-11 22:16:41 +00:00
|
|
|
#include "g_level.h"
|
2009-12-31 09:02:38 +00:00
|
|
|
#include "r_sky.h"
|
|
|
|
#include "p_lnspec.h"
|
2008-11-15 09:57:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
IMPLEMENT_CLASS(AFastProjectile)
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// AFastProjectile :: Tick
|
|
|
|
//
|
|
|
|
// Thinker for the ultra-fast projectiles used by Heretic and Hexen
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void AFastProjectile::Tick ()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
fixed_t xfrac;
|
|
|
|
fixed_t yfrac;
|
|
|
|
fixed_t zfrac;
|
|
|
|
int changexy;
|
|
|
|
|
2016-01-19 12:26:05 +00:00
|
|
|
PrevX = X();
|
|
|
|
PrevY = Y();
|
|
|
|
PrevZ = Z();
|
|
|
|
fixed_t oldz = Z();
|
2009-12-30 12:20:47 +00:00
|
|
|
PrevAngle = angle;
|
2008-11-15 09:57:18 +00:00
|
|
|
|
2009-05-11 22:16:41 +00:00
|
|
|
if (!(flags5 & MF5_NOTIMEFREEZE))
|
|
|
|
{
|
|
|
|
//Added by MC: Freeze mode.
|
|
|
|
if (bglobal.freeze || level.flags2 & LEVEL2_FROZEN)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-15 09:57:18 +00:00
|
|
|
// [RH] Ripping is a little different than it was in Hexen
|
|
|
|
FCheckPosition tm(!!(flags2 & MF2_RIP));
|
|
|
|
|
2009-01-01 15:09:49 +00:00
|
|
|
int shift = 3;
|
|
|
|
int count = 8;
|
|
|
|
if (radius > 0)
|
|
|
|
{
|
2009-06-30 20:57:51 +00:00
|
|
|
while ( ((abs(velx) >> shift) > radius) || ((abs(vely) >> shift) > radius))
|
2009-01-01 15:09:49 +00:00
|
|
|
{
|
|
|
|
// we need to take smaller steps.
|
|
|
|
shift++;
|
|
|
|
count<<=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-15 09:57:18 +00:00
|
|
|
// Handle movement
|
2016-01-19 12:26:05 +00:00
|
|
|
if (velx || vely || (Z() != floorz) || velz)
|
2008-11-15 09:57:18 +00:00
|
|
|
{
|
2009-06-30 20:57:51 +00:00
|
|
|
xfrac = velx >> shift;
|
|
|
|
yfrac = vely >> shift;
|
|
|
|
zfrac = velz >> shift;
|
2008-11-15 09:57:18 +00:00
|
|
|
changexy = xfrac || yfrac;
|
2009-01-01 15:09:49 +00:00
|
|
|
int ripcount = count >> 3;
|
|
|
|
for (i = 0; i < count; i++)
|
2008-11-15 09:57:18 +00:00
|
|
|
{
|
|
|
|
if (changexy)
|
|
|
|
{
|
2009-01-01 15:09:49 +00:00
|
|
|
if (--ripcount <= 0)
|
|
|
|
{
|
2016-01-30 21:06:04 +00:00
|
|
|
tm.LastRipped.Clear(); // [RH] Do rip damage each step, like Hexen
|
2009-01-01 15:09:49 +00:00
|
|
|
}
|
2009-01-25 21:59:38 +00:00
|
|
|
|
2016-01-19 12:26:05 +00:00
|
|
|
if (!P_TryMove (this, X() + xfrac,Y() + yfrac, true, NULL, tm))
|
2008-11-15 09:57:18 +00:00
|
|
|
{ // Blocked move
|
2009-12-31 09:02:38 +00:00
|
|
|
if (!(flags3 & MF3_SKYEXPLODE))
|
|
|
|
{
|
|
|
|
if (tm.ceilingline &&
|
|
|
|
tm.ceilingline->backsector &&
|
|
|
|
tm.ceilingline->backsector->GetTexture(sector_t::ceiling) == skyflatnum &&
|
2016-01-19 12:26:05 +00:00
|
|
|
Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint (this))
|
2009-12-31 09:02:38 +00:00
|
|
|
{
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-15 09:57:18 +00:00
|
|
|
P_ExplodeMissile (this, BlockingLine, BlockingMobj);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2016-01-19 12:26:05 +00:00
|
|
|
AddZ(zfrac);
|
2011-09-21 19:39:12 +00:00
|
|
|
UpdateWaterLevel (oldz);
|
2016-01-19 12:26:05 +00:00
|
|
|
oldz = Z();
|
|
|
|
if (Z() <= floorz)
|
2008-11-15 09:57:18 +00:00
|
|
|
{ // Hit the floor
|
2009-12-31 09:02:38 +00:00
|
|
|
|
|
|
|
if (floorpic == skyflatnum && !(flags3 & MF3_SKYEXPLODE))
|
|
|
|
{
|
|
|
|
// [RH] Just remove the missile without exploding it
|
|
|
|
// if this is a sky floor.
|
|
|
|
Destroy ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-19 12:26:05 +00:00
|
|
|
SetZ(floorz);
|
2008-11-15 09:57:18 +00:00
|
|
|
P_HitFloor (this);
|
|
|
|
P_ExplodeMissile (this, NULL, NULL);
|
|
|
|
return;
|
|
|
|
}
|
2016-01-19 12:26:05 +00:00
|
|
|
if (Top() > ceilingz)
|
2008-11-15 09:57:18 +00:00
|
|
|
{ // Hit the ceiling
|
2009-12-31 09:02:38 +00:00
|
|
|
|
|
|
|
if (ceilingpic == skyflatnum && !(flags3 & MF3_SKYEXPLODE))
|
|
|
|
{
|
|
|
|
Destroy ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-19 12:26:05 +00:00
|
|
|
SetZ(ceilingz - height);
|
2008-11-15 09:57:18 +00:00
|
|
|
P_ExplodeMissile (this, NULL, NULL);
|
|
|
|
return;
|
|
|
|
}
|
2009-01-25 21:59:38 +00:00
|
|
|
if (changexy && ripcount <= 0)
|
|
|
|
{
|
|
|
|
ripcount = count >> 3;
|
|
|
|
Effect();
|
|
|
|
}
|
2008-11-15 09:57:18 +00:00
|
|
|
}
|
|
|
|
}
|
2016-01-27 19:08:23 +00:00
|
|
|
if ((flags7 & MF7_HANDLENODELAY) && !(flags2 & MF2_DORMANT))
|
|
|
|
{
|
|
|
|
flags7 &= ~MF7_HANDLENODELAY;
|
|
|
|
if (state->GetNoDelay())
|
|
|
|
{
|
|
|
|
// For immediately spawned objects with the NoDelay flag set for their
|
|
|
|
// Spawn state, explicitly call the current state's function.
|
|
|
|
if (state->CallAction(this, this) && (ObjectFlags & OF_EuthanizeMe))
|
|
|
|
return; // freed itself
|
|
|
|
}
|
|
|
|
}
|
2008-11-15 09:57:18 +00:00
|
|
|
// Advance the state
|
|
|
|
if (tics != -1)
|
|
|
|
{
|
2009-10-19 17:17:06 +00:00
|
|
|
if (tics > 0) tics--;
|
2008-11-15 09:57:18 +00:00
|
|
|
while (!tics)
|
|
|
|
{
|
|
|
|
if (!SetState (state->GetNextState ()))
|
|
|
|
{ // mobj was removed
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AFastProjectile::Effect()
|
|
|
|
{
|
2009-10-03 17:07:11 +00:00
|
|
|
//if (pr_smoke() < 128) // [RH] I think it looks better if it's consistent
|
|
|
|
{
|
2010-03-25 20:38:00 +00:00
|
|
|
FName name = GetClass()->MissileName;
|
2009-10-03 17:07:11 +00:00
|
|
|
if (name != NAME_None)
|
|
|
|
{
|
2016-01-19 12:26:05 +00:00
|
|
|
fixed_t hitz = Z()-8*FRACUNIT;
|
2010-08-26 18:03:15 +00:00
|
|
|
|
2009-10-03 17:07:11 +00:00
|
|
|
if (hitz < floorz)
|
|
|
|
{
|
|
|
|
hitz = floorz;
|
|
|
|
}
|
2010-08-26 18:03:15 +00:00
|
|
|
// Do not clip this offset to the floor.
|
2010-09-16 03:14:32 +00:00
|
|
|
hitz += GetClass()->MissileHeight;
|
2009-10-03 17:07:11 +00:00
|
|
|
|
2010-04-03 04:07:17 +00:00
|
|
|
PClassActor *trail = PClass::FindActor(name);
|
2009-12-25 00:24:54 +00:00
|
|
|
if (trail != NULL)
|
|
|
|
{
|
2016-01-19 12:26:05 +00:00
|
|
|
AActor *act = Spawn (trail, X(), Y(), hitz, ALLOW_REPLACE);
|
2009-12-25 00:24:54 +00:00
|
|
|
if (act != NULL)
|
|
|
|
{
|
|
|
|
act->angle = this->angle;
|
|
|
|
}
|
|
|
|
}
|
2009-10-03 17:07:11 +00:00
|
|
|
}
|
|
|
|
}
|
2008-11-15 09:57:18 +00:00
|
|
|
}
|
|
|
|
|