qzdoom/src/g_hexen/a_magelightning.cpp
Christoph Oelckers f3922ec6a1 - Added a few more macros so that the action function code doesn't have
to reference its arguments directly, except 'self'. This may be helpful if it 
  becomes necessary to restructure this code once DoomScript becomes real.
- Removed the last remaining global variable related to action functions:
  pStateCall. Everything is passed properly as function arguments now.
- fixed: PlayerChunk was missing the NOSKIN flag.


SVN r1169 (trunk)
2008-08-14 08:52:55 +00:00

347 lines
7.4 KiB
C++

#include "actor.h"
#include "gi.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "a_action.h"
#include "p_local.h"
#include "p_enemy.h"
#include "a_action.h"
#include "p_pspr.h"
#include "gstrings.h"
#include "a_hexenglobal.h"
#include "thingdef/thingdef.h"
#define ZAGSPEED FRACUNIT
static FRandom pr_lightningready ("LightningReady");
static FRandom pr_lightningclip ("LightningClip");
static FRandom pr_zap ("LightningZap");
static FRandom pr_zapf ("LightningZapF");
static FRandom pr_hit ("LightningHit");
DECLARE_ACTION(A_LightningClip)
DECLARE_ACTION(A_LightningZap)
// Lightning ----------------------------------------------------------------
class ALightning : public AActor
{
DECLARE_CLASS (ALightning, AActor)
public:
int SpecialMissileHit (AActor *victim);
};
IMPLEMENT_CLASS(ALightning)
int ALightning::SpecialMissileHit (AActor *thing)
{
if (thing->flags&MF_SHOOTABLE && thing != target)
{
if (thing->Mass != INT_MAX)
{
thing->momx += momx>>4;
thing->momy += momy>>4;
}
if ((!thing->player && !(thing->flags2&MF2_BOSS))
|| !(level.time&1))
{
P_DamageMobj(thing, this, target, 3, NAME_Electric);
if (!(S_IsActorPlayingSomething (this, CHAN_WEAPON, -1)))
{
S_Sound (this, CHAN_WEAPON, "MageLightningZap", 1, ATTN_NORM);
}
if (thing->flags3&MF3_ISMONSTER && pr_hit() < 64)
{
thing->Howl ();
}
}
health--;
if (health <= 0 || thing->health <= 0)
{
return 0;
}
if (flags3 & MF3_FLOORHUGGER)
{
if (lastenemy && ! lastenemy->tracer)
{
lastenemy->tracer = thing;
}
}
else if (!tracer)
{
tracer = thing;
}
}
return 1; // lightning zaps through all sprites
}
// Lightning Zap ------------------------------------------------------------
class ALightningZap : public AActor
{
DECLARE_CLASS (ALightningZap, AActor)
public:
int SpecialMissileHit (AActor *thing);
};
IMPLEMENT_CLASS (ALightningZap)
int ALightningZap::SpecialMissileHit (AActor *thing)
{
AActor *lmo;
if (thing->flags&MF_SHOOTABLE && thing != target)
{
lmo = lastenemy;
if (lmo)
{
if (lmo->flags3 & MF3_FLOORHUGGER)
{
if (lmo->lastenemy && !lmo->lastenemy->tracer)
{
lmo->lastenemy->tracer = thing;
}
}
else if (!lmo->tracer)
{
lmo->tracer = thing;
}
if (!(level.time&3))
{
lmo->health--;
}
}
}
return -1;
}
//============================================================================
//
// A_LightningReady
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_LightningReady)
{
CALL_ACTION(A_WeaponReady, self);
if (pr_lightningready() < 160)
{
S_Sound (self, CHAN_WEAPON, "MageLightningReady", 1, ATTN_NORM);
}
}
//============================================================================
//
// A_LightningClip
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_LightningClip)
{
AActor *cMo;
AActor *target = NULL;
int zigZag;
if (self->flags3 & MF3_FLOORHUGGER)
{
if (self->lastenemy == NULL)
{
return;
}
self->z = self->floorz;
target = self->lastenemy->tracer;
}
else if (self->flags3 & MF3_CEILINGHUGGER)
{
self->z = self->ceilingz-self->height;
target = self->tracer;
}
if (self->flags3 & MF3_FLOORHUGGER)
{ // floor lightning zig-zags, and forces the ceiling lightning to mimic
cMo = self->lastenemy;
zigZag = pr_lightningclip();
if((zigZag > 128 && self->special1 < 2) || self->special1 < -2)
{
P_ThrustMobj(self, self->angle+ANG90, ZAGSPEED);
if(cMo)
{
P_ThrustMobj(cMo, self->angle+ANG90, ZAGSPEED);
}
self->special1++;
}
else
{
P_ThrustMobj(self, self->angle-ANG90, ZAGSPEED);
if(cMo)
{
P_ThrustMobj(cMo, cMo->angle-ANG90, ZAGSPEED);
}
self->special1--;
}
}
if(target)
{
if(target->health <= 0)
{
P_ExplodeMissile(self, NULL, NULL);
}
else
{
self->angle = R_PointToAngle2(self->x, self->y, target->x, target->y);
self->momx = 0;
self->momy = 0;
P_ThrustMobj (self, self->angle, self->Speed>>1);
}
}
}
//============================================================================
//
// A_LightningZap
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_LightningZap)
{
AActor *mo;
fixed_t deltaZ;
CALL_ACTION(A_LightningClip, self);
self->health -= 8;
if (self->health <= 0)
{
self->SetState (self->FindState(NAME_Death));
return;
}
if (self->flags3 & MF3_FLOORHUGGER)
{
deltaZ = 10*FRACUNIT;
}
else
{
deltaZ = -10*FRACUNIT;
}
mo = Spawn<ALightningZap> (self->x+((pr_zap()-128)*self->radius/256),
self->y+((pr_zap()-128)*self->radius/256),
self->z+deltaZ, ALLOW_REPLACE);
if (mo)
{
mo->lastenemy = self;
mo->momx = self->momx;
mo->momy = self->momy;
mo->target = self->target;
if (self->flags3 & MF3_FLOORHUGGER)
{
mo->momz = 20*FRACUNIT;
}
else
{
mo->momz = -20*FRACUNIT;
}
}
if ((self->flags3 & MF3_FLOORHUGGER) && pr_zapf() < 160)
{
S_Sound (self, CHAN_BODY, "MageLightningContinuous", 1, ATTN_NORM);
}
}
//============================================================================
//
// A_MLightningAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_MLightningAttack)
{
AActor *fmo, *cmo;
fmo = P_SpawnPlayerMissile (self, PClass::FindClass ("LightningFloor"));
cmo = P_SpawnPlayerMissile (self, PClass::FindClass ("LightningCeiling"));
if (fmo)
{
fmo->special1 = 0;
fmo->lastenemy = cmo;
CALL_ACTION(A_LightningZap, fmo);
}
if (cmo)
{
cmo->tracer = NULL;
cmo->lastenemy = fmo;
CALL_ACTION(A_LightningZap, cmo);
}
S_Sound (self, CHAN_BODY, "MageLightningFire", 1, ATTN_NORM);
if (self->player != NULL)
{
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
weapon->DepleteAmmo (weapon->bAltFire);
}
}
}
//============================================================================
//
// A_ZapMimic
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_ZapMimic)
{
AActor *mo;
mo = self->lastenemy;
if (mo)
{
if (mo->state >= mo->FindState(NAME_Death))
{
P_ExplodeMissile (self, NULL, NULL);
}
else
{
self->momx = mo->momx;
self->momy = mo->momy;
}
}
}
//============================================================================
//
// A_LastZap
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_LastZap)
{
AActor *mo;
mo = Spawn<ALightningZap> (self->x, self->y, self->z, ALLOW_REPLACE);
if (mo)
{
mo->SetState (mo->FindState (NAME_Death));
mo->momz = 40*FRACUNIT;
mo->Damage = 0;
}
}
//============================================================================
//
// A_LightningRemove
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_LightningRemove)
{
AActor *mo;
mo = self->lastenemy;
if (mo)
{
mo->lastenemy = NULL;
P_ExplodeMissile (mo, NULL, NULL);
}
}