gzdoom/src/g_hexen/a_blastradius.cpp

167 lines
4 KiB
C++
Raw Normal View History

/*
#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->momx = FixedMul (strength, finecosine[angle]);
victim->momy = 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->momx = FixedMul (BLAST_SPEED, finecosine[angle]);
victim->momy = 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->momx = victim->momx;
mo->momy = victim->momy;
}
if (victim->flags & MF_MISSILE)
{
// [RH] Floor and ceiling huggers should not be blasted vertically.
if (!(victim->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)))
{
victim->momz = 8*FRACUNIT;
mo->momz = victim->momz;
}
}
else
{
victim->momz = (1000 / victim->Mass) << FRACBITS;
}
if (victim->player)
{
// Players handled automatically
}
else
{
victim->flags2 |= MF2_BLASTED;
}
}
}