gzdoom/src/g_shared/a_fastprojectile.cpp

183 lines
3.6 KiB
C++
Raw Normal View History

2016-03-01 15:47:10 +00:00
#include "a_sharedglobal.h"
#include "p_local.h"
#include "g_level.h"
#include "r_sky.h"
#include "p_lnspec.h"
#include "b_bot.h"
#include "p_checkposition.h"
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;
ClearInterpolation();
fixed_t oldz = _f_Z();
2016-03-01 15:47:10 +00:00
if (!(flags5 & MF5_NOTIMEFREEZE))
{
//Added by MC: Freeze mode.
if (bglobal.freeze || level.flags2 & LEVEL2_FROZEN)
{
return;
}
}
// [RH] Ripping is a little different than it was in Hexen
FCheckPosition tm(!!(flags2 & MF2_RIP));
int shift = 3;
int count = 8;
if (_f_radius() > 0)
2016-03-01 15:47:10 +00:00
{
while ( ((abs(_f_velx()) >> shift) > _f_radius()) || ((abs(_f_vely()) >> shift) > _f_radius()))
2016-03-01 15:47:10 +00:00
{
// we need to take smaller steps.
shift++;
count<<=1;
}
}
// Handle movement
2016-03-20 18:52:35 +00:00
if (!Vel.isZero() || (Z() != floorz))
2016-03-01 15:47:10 +00:00
{
xfrac = _f_velx() >> shift;
yfrac = _f_vely() >> shift;
zfrac = _f_velz() >> shift;
2016-03-01 15:47:10 +00:00
changexy = xfrac || yfrac;
int ripcount = count >> 3;
for (i = 0; i < count; i++)
{
if (changexy)
{
if (--ripcount <= 0)
{
tm.LastRipped.Clear(); // [RH] Do rip damage each step, like Hexen
}
if (!P_TryMove (this, _f_X() + xfrac,_f_Y() + yfrac, true, NULL, tm))
2016-03-01 15:47:10 +00:00
{ // Blocked move
if (!(flags3 & MF3_SKYEXPLODE))
{
if (tm.ceilingline &&
tm.ceilingline->backsector &&
tm.ceilingline->backsector->GetTexture(sector_t::ceiling) == skyflatnum &&
_f_Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint(PosRelative(tm.ceilingline)))
2016-03-01 15:47:10 +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;
}
}
P_ExplodeMissile (this, BlockingLine, BlockingMobj);
return;
}
}
_f_AddZ(zfrac);
2016-03-01 15:47:10 +00:00
UpdateWaterLevel (oldz);
oldz = _f_Z();
2016-03-20 18:52:35 +00:00
if (Z() <= floorz)
2016-03-01 15:47:10 +00:00
{ // Hit the floor
if (floorpic == skyflatnum && !(flags3 & MF3_SKYEXPLODE))
{
// [RH] Just remove the missile without exploding it
// if this is a sky floor.
Destroy ();
return;
}
2016-03-20 18:52:35 +00:00
SetZ(floorz);
2016-03-01 15:47:10 +00:00
P_HitFloor (this);
P_ExplodeMissile (this, NULL, NULL);
return;
}
if (Top() > ceilingz)
2016-03-01 15:47:10 +00:00
{ // Hit the ceiling
if (ceilingpic == skyflatnum && !(flags3 & MF3_SKYEXPLODE))
{
Destroy ();
return;
}
SetZ(ceilingz - _Height());
2016-03-01 15:47:10 +00:00
P_ExplodeMissile (this, NULL, NULL);
return;
}
if (changexy && ripcount <= 0)
{
ripcount = count >> 3;
Effect();
}
}
}
if (!CheckNoDelay())
return; // freed itself
// Advance the state
if (tics != -1)
{
if (tics > 0) tics--;
while (!tics)
{
if (!SetState (state->GetNextState ()))
{ // mobj was removed
return;
}
}
}
}
void AFastProjectile::Effect()
{
2016-03-20 18:52:35 +00:00
FName name = GetClass()->MissileName;
if (name != NAME_None)
2016-03-01 15:47:10 +00:00
{
2016-03-20 18:52:35 +00:00
double hitz = Z()-8;
2016-03-01 15:47:10 +00:00
2016-03-20 18:52:35 +00:00
if (hitz < floorz)
{
hitz = floorz;
}
// Do not clip this offset to the floor.
hitz += GetClass()->MissileHeight;
2016-03-01 15:47:10 +00:00
2016-03-20 18:52:35 +00:00
PClassActor *trail = PClass::FindActor(name);
if (trail != NULL)
{
AActor *act = Spawn (trail, PosAtZ(hitz), ALLOW_REPLACE);
if (act != NULL)
2016-03-01 15:47:10 +00:00
{
2016-03-20 18:52:35 +00:00
act->Angles.Yaw = Angles.Yaw;
2016-03-01 15:47:10 +00:00
}
}
}
}