2006-02-24 04:48:15 +00:00
|
|
|
#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"
|
2008-08-10 20:48:55 +00:00
|
|
|
#include "thingdef/thingdef.h"
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
#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");
|
|
|
|
|
2008-08-10 22:48:37 +00:00
|
|
|
DECLARE_ACTION(A_LightningClip)
|
|
|
|
DECLARE_ACTION(A_LightningZap)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
// Lightning ----------------------------------------------------------------
|
|
|
|
|
2008-08-08 15:18:23 +00:00
|
|
|
class ALightning : public AActor
|
|
|
|
{
|
|
|
|
DECLARE_CLASS (ALightning, AActor)
|
|
|
|
public:
|
|
|
|
int SpecialMissileHit (AActor *victim);
|
|
|
|
};
|
|
|
|
|
2008-08-07 15:46:52 +00:00
|
|
|
IMPLEMENT_CLASS(ALightning)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
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))
|
|
|
|
{
|
2008-08-08 15:18:23 +00:00
|
|
|
P_DamageMobj(thing, this, target, 3, NAME_Electric);
|
2006-08-31 00:16:12 +00:00
|
|
|
if (!(S_IsActorPlayingSomething (this, CHAN_WEAPON, -1)))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|
{
|
2008-08-07 15:46:52 +00:00
|
|
|
DECLARE_CLASS (ALightningZap, AActor)
|
2006-02-24 04:48:15 +00:00
|
|
|
public:
|
|
|
|
int SpecialMissileHit (AActor *thing);
|
|
|
|
};
|
|
|
|
|
2008-08-07 15:46:52 +00:00
|
|
|
IMPLEMENT_CLASS (ALightningZap)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_LightningReady)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 22:48:37 +00:00
|
|
|
CALL_ACTION(A_WeaponReady, self);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (pr_lightningready() < 160)
|
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
S_Sound (self, CHAN_WEAPON, "MageLightningReady", 1, ATTN_NORM);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_LightningClip
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_LightningClip)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
AActor *cMo;
|
|
|
|
AActor *target = NULL;
|
|
|
|
int zigZag;
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
if (self->flags3 & MF3_FLOORHUGGER)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
if (self->lastenemy == NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
self->z = self->floorz;
|
|
|
|
target = self->lastenemy->tracer;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
else if (self->flags3 & MF3_CEILINGHUGGER)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
self->z = self->ceilingz-self->height;
|
|
|
|
target = self->tracer;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
if (self->flags3 & MF3_FLOORHUGGER)
|
2006-02-24 04:48:15 +00:00
|
|
|
{ // floor lightning zig-zags, and forces the ceiling lightning to mimic
|
2008-08-10 20:48:55 +00:00
|
|
|
cMo = self->lastenemy;
|
2006-02-24 04:48:15 +00:00
|
|
|
zigZag = pr_lightningclip();
|
2008-08-10 20:48:55 +00:00
|
|
|
if((zigZag > 128 && self->special1 < 2) || self->special1 < -2)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
P_ThrustMobj(self, self->angle+ANG90, ZAGSPEED);
|
2006-02-24 04:48:15 +00:00
|
|
|
if(cMo)
|
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
P_ThrustMobj(cMo, self->angle+ANG90, ZAGSPEED);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
self->special1++;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
P_ThrustMobj(self, self->angle-ANG90, ZAGSPEED);
|
2006-02-24 04:48:15 +00:00
|
|
|
if(cMo)
|
|
|
|
{
|
|
|
|
P_ThrustMobj(cMo, cMo->angle-ANG90, ZAGSPEED);
|
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
self->special1--;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if(target)
|
|
|
|
{
|
|
|
|
if(target->health <= 0)
|
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
P_ExplodeMissile(self, NULL, NULL);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
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);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_LightningZap
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_LightningZap)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
AActor *mo;
|
|
|
|
fixed_t deltaZ;
|
|
|
|
|
2008-08-10 22:48:37 +00:00
|
|
|
CALL_ACTION(A_LightningClip, self);
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
self->health -= 8;
|
|
|
|
if (self->health <= 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
self->SetState (self->FindState(NAME_Death));
|
2006-02-24 04:48:15 +00:00
|
|
|
return;
|
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
if (self->flags3 & MF3_FLOORHUGGER)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
deltaZ = 10*FRACUNIT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
deltaZ = -10*FRACUNIT;
|
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
mo = Spawn<ALightningZap> (self->x+((pr_zap()-128)*self->radius/256),
|
|
|
|
self->y+((pr_zap()-128)*self->radius/256),
|
|
|
|
self->z+deltaZ, ALLOW_REPLACE);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (mo)
|
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
mo->lastenemy = self;
|
|
|
|
mo->momx = self->momx;
|
|
|
|
mo->momy = self->momy;
|
|
|
|
mo->target = self->target;
|
|
|
|
if (self->flags3 & MF3_FLOORHUGGER)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
mo->momz = 20*FRACUNIT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mo->momz = -20*FRACUNIT;
|
|
|
|
}
|
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
if ((self->flags3 & MF3_FLOORHUGGER) && pr_zapf() < 160)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
S_Sound (self, CHAN_BODY, "MageLightningContinuous", 1, ATTN_NORM);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_MLightningAttack2
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
static void MLightningAttack2 (AActor *self)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
AActor *fmo, *cmo;
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
fmo = P_SpawnPlayerMissile (self, PClass::FindClass ("LightningFloor"));
|
|
|
|
cmo = P_SpawnPlayerMissile (self, PClass::FindClass ("LightningCeiling"));
|
2006-02-24 04:48:15 +00:00
|
|
|
if (fmo)
|
|
|
|
{
|
|
|
|
fmo->special1 = 0;
|
|
|
|
fmo->lastenemy = cmo;
|
2008-08-10 22:48:37 +00:00
|
|
|
CALL_ACTION(A_LightningZap, fmo);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
if (cmo)
|
|
|
|
{
|
|
|
|
cmo->tracer = NULL;
|
|
|
|
cmo->lastenemy = fmo;
|
2008-08-10 22:48:37 +00:00
|
|
|
CALL_ACTION(A_LightningZap, cmo);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
S_Sound (self, CHAN_BODY, "MageLightningFire", 1, ATTN_NORM);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_MLightningAttack
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_MLightningAttack)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
MLightningAttack2(self);
|
|
|
|
if (self->player != NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
AWeapon *weapon = self->player->ReadyWeapon;
|
2006-02-24 04:48:15 +00:00
|
|
|
if (weapon != NULL)
|
|
|
|
{
|
|
|
|
weapon->DepleteAmmo (weapon->bAltFire);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_ZapMimic
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_ZapMimic)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
AActor *mo;
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
mo = self->lastenemy;
|
2006-02-24 04:48:15 +00:00
|
|
|
if (mo)
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
if (mo->state >= mo->FindState(NAME_Death))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
P_ExplodeMissile (self, NULL, NULL);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
self->momx = mo->momx;
|
|
|
|
self->momy = mo->momy;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_LastZap
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_LastZap)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
AActor *mo;
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
mo = Spawn<ALightningZap> (self->x, self->y, self->z, ALLOW_REPLACE);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (mo)
|
|
|
|
{
|
2008-08-07 15:46:52 +00:00
|
|
|
mo->SetState (mo->FindState ("Death"));
|
2006-02-24 04:48:15 +00:00
|
|
|
mo->momz = 40*FRACUNIT;
|
- Added the ACS commands
ReplaceTextures (str old_texture, str new_texture, optional bool not_lower,
optional bool not_mid, optional bool not_upper, optional bool not_floor,
optional bool not_ceiling); and
SectorDamage (int tag, int amount, str type, bool players_only, bool in_air,
str protection_item, bool subclasses_okay);
- Added the vid_nowidescreen cvar to disable widescreen aspect ratio
correction. When this is enabled, the only display ratio available is 4:3
(and 5:4 if vid_tft is set).
- Added support for setting an actor's damage property to an expression
through decorate. Just enclose it within parentheses, and the expression
will be evaluated exactly as-is without the normal Doom damage calculation.
So if you want something that does exactly 6 damage, use a "Damage (6)"
property. To deal normal Doom missile damage, you can use
"Damage (random(1,8)*6)" instead of "Damage 6".
- Moved InvFirst and InvSel into APlayerPawn so that they can be consistantly
maintained by ObtainInventory.
SVN r288 (trunk)
2006-08-12 02:30:57 +00:00
|
|
|
mo->Damage = 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_LightningRemove
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_LightningRemove)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
AActor *mo;
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
mo = self->lastenemy;
|
2006-02-24 04:48:15 +00:00
|
|
|
if (mo)
|
|
|
|
{
|
|
|
|
mo->lastenemy = NULL;
|
2006-10-22 10:32:41 +00:00
|
|
|
P_ExplodeMissile (mo, NULL, NULL);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|