mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-16 17:21:24 +00:00
3d8d176087
into the FastProjectile base class and removed the native MageWandMissile class, using the generic functionality instead. - Fixed: GetReplacement and GetReplacee always checked the skill definitions, even if they weren't supposed to be used. It was also missing a range check for 'gameskill'. SVN r1894 (trunk)
357 lines
7.7 KiB
C++
357 lines
7.7 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 "a_action.h"
|
|
#include "p_pspr.h"
|
|
#include "gstrings.h"
|
|
#include "a_hexenglobal.h"
|
|
#include "thingdef/thingdef.h"
|
|
#include "g_level.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->velx += velx>>4;
|
|
thing->vely += vely>>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, this->AttackSound, 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)
|
|
{
|
|
DoReadyWeapon(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->velx = 0;
|
|
self->vely = 0;
|
|
P_ThrustMobj (self, self->angle, self->Speed>>1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//============================================================================
|
|
//
|
|
// A_LightningZap
|
|
//
|
|
//============================================================================
|
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_LightningZap)
|
|
{
|
|
|
|
const PClass *lightning=PClass::FindClass((ENamedName) self->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_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(lightning, 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->velx = self->velx;
|
|
mo->vely = self->vely;
|
|
mo->target = self->target;
|
|
if (self->flags3 & MF3_FLOORHUGGER)
|
|
{
|
|
mo->velz = 20*FRACUNIT;
|
|
}
|
|
else
|
|
{
|
|
mo->velz = -20*FRACUNIT;
|
|
}
|
|
}
|
|
if ((self->flags3 & MF3_FLOORHUGGER) && pr_zapf() < 160)
|
|
{
|
|
S_Sound (self, CHAN_BODY, self->ActiveSound, 1, ATTN_NORM);
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_MLightningAttack
|
|
//
|
|
//============================================================================
|
|
|
|
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MLightningAttack)
|
|
{
|
|
ACTION_PARAM_START(2);
|
|
ACTION_PARAM_CLASS(floor, 0);
|
|
ACTION_PARAM_CLASS(ceiling, 1);
|
|
|
|
AActor *fmo, *cmo;
|
|
|
|
fmo = P_SpawnPlayerMissile (self, floor);
|
|
cmo = P_SpawnPlayerMissile (self, ceiling);
|
|
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->velx = mo->velx;
|
|
self->vely = mo->vely;
|
|
}
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_LastZap
|
|
//
|
|
//============================================================================
|
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_LastZap)
|
|
{
|
|
const PClass *lightning=PClass::FindClass((ENamedName) self->GetClass()->Meta.GetMetaInt (ACMETA_MissileName, NAME_LightningZap));
|
|
|
|
AActor *mo;
|
|
|
|
mo = Spawn(lightning, self->x, self->y, self->z, ALLOW_REPLACE);
|
|
if (mo)
|
|
{
|
|
mo->SetState (mo->FindState (NAME_Death));
|
|
mo->velz = 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);
|
|
}
|
|
}
|