qzdoom-gpl/src/g_hexen/a_blastradius.cpp
Christoph Oelckers f1602882c8 - added a no-parameter Spawn function for inventory items that never show on the map, because the coordinate and replacement parameters will always be 0 for them.
- started converting g_hexen.

Most importantly this removes CHolyWeave as it is just a specialized version of A_Weave with far more convoluted use of parameters.
2016-03-21 14:00:05 +01:00

158 lines
3.9 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"
*/
/* For reference, the default values:
#define BLAST_RADIUS_DIST 255*F.RACUNIT
#define BLAST_SPEED 20*F.RACUNIT
#define BLAST_FULLSTRENGTH 255
*/
// Disc of Repulsion --------------------------------------------------------
//==========================================================================
//
// AArtiBlastRadius :: BlastActor
//
//==========================================================================
void BlastActor (AActor *victim, double strength, double speed, AActor *Owner, PClassActor *blasteffect, bool dontdamage)
{
DAngle angle;
AActor *mo;
DVector3 pos;
if (!victim->SpecialBlastHandling (Owner, strength))
{
return;
}
angle = Owner->AngleTo(victim);
DVector2 move = angle.ToVector(speed);
victim->Vel.X = move.X;
victim->Vel.Y = move.Y;
// Spawn blast puff
angle -= 180.;
pos = victim->Vec3Offset(
(victim->radius + 1) * angle.Cos(),
(victim->radius + 1) * angle.Sin(),
(victim->Height / 2) - victim->Floorclip);
mo = Spawn (blasteffect, pos, ALLOW_REPLACE);
if (mo)
{
mo->Vel.X = victim->Vel.X;
mo->Vel.Y = victim->Vel.Y;
}
if (victim->flags & MF_MISSILE)
{
// [RH] Floor and ceiling huggers should not be blasted vertically.
if (!(victim->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)))
{
mo->Vel.Z = victim->Vel.Z = 8;
}
}
else
{
victim->Vel.Z = 1000. / victim->Mass;
}
if (victim->player)
{
// Players handled automatically
}
else if (!dontdamage)
{
victim->flags2 |= MF2_BLASTED;
}
if (victim->flags6 & MF6_TOUCHY)
{ // Touchy objects die when blasted
victim->flags6 &= ~MF6_ARMED; // Disarm
P_DamageMobj(victim, Owner, Owner, victim->health, NAME_Melee, DMG_FORCED);
}
}
enum
{
BF_USEAMMO = 1,
BF_DONTWARN = 2,
BF_AFFECTBOSSES = 4,
BF_NOIMPACTDAMAGE = 8,
};
//==========================================================================
//
// AArtiBlastRadius :: Activate
//
// Blast all actors away
//
//==========================================================================
DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_Blast)
{
PARAM_ACTION_PROLOGUE;
PARAM_INT_OPT (blastflags) { blastflags = 0; }
PARAM_FLOAT_OPT (strength) { strength = 255; }
PARAM_FLOAT_OPT (radius) { radius = 255; }
PARAM_FLOAT_OPT (speed) { speed = 20; }
PARAM_CLASS_OPT (blasteffect, AActor) { blasteffect = PClass::FindActor("BlastEffect"); }
PARAM_SOUND_OPT (blastsound) { blastsound = "BlastRadius"; }
AActor *mo;
TThinkerIterator<AActor> iterator;
if (self->player && (blastflags & BF_USEAMMO) && ACTION_CALL_FROM_WEAPON())
{
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && !weapon->DepleteAmmo(weapon->bAltFire))
{
return 0;
}
}
S_Sound (self, CHAN_AUTO, blastsound, 1, ATTN_NORM);
if (!(blastflags & BF_DONTWARN))
{
P_NoiseAlert (self, self);
}
while ( (mo = iterator.Next ()) )
{
if ((mo == self) || ((mo->flags2 & MF2_BOSS) && !(blastflags & BF_AFFECTBOSSES))
|| (mo->flags2 & MF2_DORMANT) || (mo->flags3 & MF3_DONTBLAST))
{ // Not a valid monster: originator, boss, dormant, or otherwise protected
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->player) &&
!(mo->flags & MF_MISSILE) &&
!(mo->flags3 & (MF3_ISMONSTER|MF3_CANBLAST)) &&
!(mo->flags6 & (MF6_TOUCHY|MF6_VULNERABLE)))
{ // Must be monster, player, missile, touchy or vulnerable
continue;
}
if (self->Distance2D(mo) > radius)
{ // Out of range
continue;
}
if (mo->Sector->PortalGroup != self->Sector->PortalGroup && !P_CheckSight(self, mo))
{
// in another region and cannot be seen.
continue;
}
BlastActor (mo, strength, speed, self, blasteffect, !!(blastflags & BF_NOIMPACTDAMAGE));
}
return 0;
}