qzdoom-gpl/src/g_hexen/a_blastradius.cpp
Randy Heit e4af82ae96 - Enough with this "momentum" garbage. What Doom calls "momentum" is really
velocity, and now it's known as such. The actor variables momx/momy/momz
  are now known as velx/vely/velz, and the ACS functions GetActorMomX/Y/Z
  are now known as GetActorVelX/Y/Z. For compatibility, momx/momy/momz will
  continue to work as aliases from DECORATE. The ACS functions, however,
  require you to use the new name, since they never saw an official release
  yet.


SVN r1689 (trunk)
2009-06-30 20:57:51 +00:00

166 lines
4 KiB
C++

/*
#include "info.h"
#include "a_pickups.h"
#include "a_artifacts.h"
#include "gstrings.h"
#include "p_local.h"
#include "p_enemy.h"
#include "s_sound.h"
*/
#define BLAST_RADIUS_DIST 255*FRACUNIT
#define BLAST_SPEED 20*FRACUNIT
#define BLAST_FULLSTRENGTH 255
// Disc of Repulsion --------------------------------------------------------
class AArtiBlastRadius : public AInventory
{
DECLARE_CLASS (AArtiBlastRadius, AInventory)
public:
bool Use (bool pickup);
protected:
void BlastActor (AActor *victim, fixed_t strength);
};
IMPLEMENT_CLASS (AArtiBlastRadius)
//==========================================================================
//
// AArtiBlastRadius :: Activate
//
// Blast all actors away
//
//==========================================================================
bool AArtiBlastRadius::Use (bool pickup)
{
AActor *mo;
TThinkerIterator<AActor> iterator;
fixed_t dist;
S_Sound (Owner, CHAN_AUTO, "BlastRadius", 1, ATTN_NORM);
P_NoiseAlert (Owner, Owner);
while ( (mo = iterator.Next ()) )
{
if ((mo == Owner) || (mo->flags2 & MF2_BOSS))
{ // Not a valid monster
continue;
}
if ((mo->flags & MF_ICECORPSE) || (mo->flags3 & MF3_CANBLAST))
{
// Let these special cases go
}
else if ((mo->flags3 & MF3_ISMONSTER) && (mo->health <= 0))
{
continue;
}
else if (!(mo->flags3 & MF3_ISMONSTER) &&
!(mo->player) &&
!(mo->flags & MF_MISSILE) &&
!(mo->flags3 & MF3_CANBLAST))
{ // Must be monster, player, or missile
continue;
}
if (mo->flags2 & MF2_DORMANT)
{
continue; // no dormant creatures
}
if (mo->flags3 & MF3_DONTBLAST)
{ // A few things that would normally be blastable should not be blasted
continue;
}
dist = P_AproxDistance (Owner->x - mo->x, Owner->y - mo->y);
if (dist > BLAST_RADIUS_DIST)
{ // Out of range
continue;
}
BlastActor (mo, BLAST_FULLSTRENGTH);
}
return true;
}
//==========================================================================
//
// AArtiBlastRadius :: BlastActor
//
//==========================================================================
void AArtiBlastRadius::BlastActor (AActor *victim, fixed_t strength)
{
angle_t angle,ang;
AActor *mo;
fixed_t x,y,z;
if (!victim->SpecialBlastHandling (Owner, strength))
{
return;
}
angle = R_PointToAngle2 (Owner->x, Owner->y, victim->x, victim->y);
angle >>= ANGLETOFINESHIFT;
if (strength < BLAST_FULLSTRENGTH)
{
victim->velx = FixedMul (strength, finecosine[angle]);
victim->vely = FixedMul (strength, finesine[angle]);
if (victim->player)
{
// Players handled automatically
}
else
{
victim->flags2 |= MF2_BLASTED;
}
}
else // full strength blast from artifact
{
if (victim->flags & MF_MISSILE)
{
#if 0
if (victim->IsKindOf (RUNTIME_CLASS(AMageStaffFX2)))
{ // Reflect to originator
victim->special1 = (int)victim->target;
victim->target = Owner;
}
#endif
}
victim->velx = FixedMul (BLAST_SPEED, finecosine[angle]);
victim->vely = FixedMul (BLAST_SPEED, finesine[angle]);
// Spawn blast puff
ang = R_PointToAngle2 (victim->x, victim->y, Owner->x, Owner->y);
ang >>= ANGLETOFINESHIFT;
x = victim->x + FixedMul (victim->radius+FRACUNIT, finecosine[ang]);
y = victim->y + FixedMul (victim->radius+FRACUNIT, finesine[ang]);
z = victim->z - victim->floorclip + (victim->height>>1);
mo = Spawn ("BlastEffect", x, y, z, ALLOW_REPLACE);
if (mo)
{
mo->velx = victim->velx;
mo->vely = victim->vely;
}
if (victim->flags & MF_MISSILE)
{
// [RH] Floor and ceiling huggers should not be blasted vertically.
if (!(victim->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)))
{
victim->velz = 8*FRACUNIT;
mo->velz = victim->velz;
}
}
else
{
victim->velz = (1000 / victim->Mass) << FRACBITS;
}
if (victim->player)
{
// Players handled automatically
}
else
{
victim->flags2 |= MF2_BLASTED;
}
}
}