mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-12 07:34:50 +00:00
1bd6ac028b
- Added a PickupMessage property to the internal actor parser, replaced most of the virtual PickupMessages with it and placed the code that reads the metadata into AInventory::PickupMessage. Now the PickupMessage method is truly virtual and I can do: Added a Health.LowMessage property to define double message items like Doom's medikit in DECORATE. - Since defining Mana3 as an ammo type and then overriding the TryPickup method means that this item defeats all ammo checks in the game it might as well be defined as a CustomInventory item. At least this fixes the amount given in easy and very hard skills. - Converted all ammo items to DECORATE. - Changed internal property setting of ammo types and sister weapons to use fuglyname as for DECORATE definitions. This allows to export the ammo definitions into DECORATE definitions without doing it for the weapons themselves. - Replaced obituary methods with actor properties. - Fixed: The secret map check didn't work for maps inside Zips. SVN r196 (trunk)
582 lines
18 KiB
C++
582 lines
18 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"
|
|
|
|
#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");
|
|
|
|
void A_LightningReady (AActor *actor);
|
|
void A_MLightningAttack (AActor *actor);
|
|
|
|
void A_LightningClip (AActor *);
|
|
void A_LightningZap (AActor *);
|
|
void A_ZapMimic (AActor *);
|
|
void A_LastZap (AActor *);
|
|
void A_LightningRemove (AActor *);
|
|
void A_FreeTargMobj (AActor *);
|
|
|
|
// The Mage's Lightning Arc of Death ----------------------------------------
|
|
|
|
class AMWeapLightning : public AMageWeapon
|
|
{
|
|
DECLARE_ACTOR (AMWeapLightning, AMageWeapon)
|
|
};
|
|
|
|
FState AMWeapLightning::States[] =
|
|
{
|
|
#define S_MW_LIGHTNING1 0
|
|
S_BRIGHT (WMLG, 'A', 4, NULL , &States[S_MW_LIGHTNING1+1]),
|
|
S_BRIGHT (WMLG, 'B', 4, NULL , &States[S_MW_LIGHTNING1+2]),
|
|
S_BRIGHT (WMLG, 'C', 4, NULL , &States[S_MW_LIGHTNING1+3]),
|
|
S_BRIGHT (WMLG, 'D', 4, NULL , &States[S_MW_LIGHTNING1+4]),
|
|
S_BRIGHT (WMLG, 'E', 4, NULL , &States[S_MW_LIGHTNING1+5]),
|
|
S_BRIGHT (WMLG, 'F', 4, NULL , &States[S_MW_LIGHTNING1+6]),
|
|
S_BRIGHT (WMLG, 'G', 4, NULL , &States[S_MW_LIGHTNING1+7]),
|
|
S_BRIGHT (WMLG, 'H', 4, NULL , &States[S_MW_LIGHTNING1]),
|
|
|
|
#define S_MLIGHTNINGREADY (S_MW_LIGHTNING1+8)
|
|
S_BRIGHT (MLNG, 'A', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+1]),
|
|
S_BRIGHT (MLNG, 'A', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+2]),
|
|
S_BRIGHT (MLNG, 'A', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+3]),
|
|
S_BRIGHT (MLNG, 'A', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+4]),
|
|
S_BRIGHT (MLNG, 'A', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+5]),
|
|
S_BRIGHT (MLNG, 'A', 1, A_LightningReady , &States[S_MLIGHTNINGREADY+6]),
|
|
S_BRIGHT (MLNG, 'B', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+7]),
|
|
S_BRIGHT (MLNG, 'B', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+8]),
|
|
S_BRIGHT (MLNG, 'B', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+9]),
|
|
S_BRIGHT (MLNG, 'B', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+10]),
|
|
S_BRIGHT (MLNG, 'B', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+11]),
|
|
S_BRIGHT (MLNG, 'B', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+12]),
|
|
S_BRIGHT (MLNG, 'C', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+13]),
|
|
S_BRIGHT (MLNG, 'C', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+14]),
|
|
S_BRIGHT (MLNG, 'C', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+15]),
|
|
S_BRIGHT (MLNG, 'C', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+16]),
|
|
S_BRIGHT (MLNG, 'C', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+17]),
|
|
S_BRIGHT (MLNG, 'C', 1, A_LightningReady , &States[S_MLIGHTNINGREADY+18]),
|
|
S_BRIGHT (MLNG, 'B', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+19]),
|
|
S_BRIGHT (MLNG, 'B', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+20]),
|
|
S_BRIGHT (MLNG, 'B', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+21]),
|
|
S_BRIGHT (MLNG, 'B', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+22]),
|
|
S_BRIGHT (MLNG, 'B', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY+23]),
|
|
S_BRIGHT (MLNG, 'B', 1, A_WeaponReady , &States[S_MLIGHTNINGREADY]),
|
|
|
|
#define S_MLIGHTNINGDOWN (S_MLIGHTNINGREADY+24)
|
|
S_BRIGHT (MLNG, 'A', 1, A_Lower , &States[S_MLIGHTNINGDOWN]),
|
|
|
|
#define S_MLIGHTNINGUP (S_MLIGHTNINGDOWN+1)
|
|
S_BRIGHT (MLNG, 'A', 1, A_Raise , &States[S_MLIGHTNINGUP]),
|
|
|
|
#define S_MLIGHTNINGATK (S_MLIGHTNINGUP+1)
|
|
S_BRIGHT (MLNG, 'D', 3, NULL , &States[S_MLIGHTNINGATK+1]),
|
|
S_BRIGHT (MLNG, 'E', 3, NULL , &States[S_MLIGHTNINGATK+2]),
|
|
S_BRIGHT (MLNG, 'F', 4, A_MLightningAttack , &States[S_MLIGHTNINGATK+3]),
|
|
S_BRIGHT (MLNG, 'G', 4, NULL , &States[S_MLIGHTNINGATK+4]),
|
|
S_BRIGHT (MLNG, 'H', 3, NULL , &States[S_MLIGHTNINGATK+5]),
|
|
S_BRIGHT (MLNG, 'I', 3, NULL , &States[S_MLIGHTNINGATK+6]),
|
|
S_BRIGHT2 (MLNG, 'I', 6, NULL , &States[S_MLIGHTNINGATK+7], 0, 199),
|
|
S_BRIGHT2 (MLNG, 'C', 2, NULL , &States[S_MLIGHTNINGATK+8], 0, 55),
|
|
S_BRIGHT2 (MLNG, 'B', 2, NULL , &States[S_MLIGHTNINGATK+9], 0, 50),
|
|
S_BRIGHT2 (MLNG, 'B', 2, NULL , &States[S_MLIGHTNINGATK+10], 0, 45),
|
|
S_BRIGHT2 (MLNG, 'B', 2, NULL , &States[S_MLIGHTNINGREADY], 0, 40),
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AMWeapLightning, Hexen, 8040, 0)
|
|
PROP_Flags (MF_SPECIAL|MF_NOGRAVITY)
|
|
PROP_SpawnState (S_MW_LIGHTNING1)
|
|
|
|
PROP_Weapon_SelectionOrder (1100)
|
|
PROP_Weapon_AmmoUse1 (5)
|
|
PROP_Weapon_AmmoGive1 (25)
|
|
PROP_Weapon_UpState (S_MLIGHTNINGUP)
|
|
PROP_Weapon_DownState (S_MLIGHTNINGDOWN)
|
|
PROP_Weapon_ReadyState (S_MLIGHTNINGREADY)
|
|
PROP_Weapon_AtkState (S_MLIGHTNINGATK)
|
|
PROP_Weapon_HoldAtkState (S_MLIGHTNINGATK)
|
|
PROP_Weapon_Kickback (0)
|
|
PROP_Weapon_YAdjust (20)
|
|
PROP_Weapon_MoveCombatDist (23000000)
|
|
PROP_Weapon_AmmoType1 ("Mana2")
|
|
PROP_Weapon_ProjectileType ("LightningFloor")
|
|
PROP_Inventory_PickupMessage("$TXT_WEAPON_M3")
|
|
END_DEFAULTS
|
|
|
|
// Lightning ----------------------------------------------------------------
|
|
|
|
IMPLEMENT_ABSTRACT_ACTOR (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))
|
|
{
|
|
if (thing->IsKindOf(RUNTIME_CLASS(ACentaur)))
|
|
{ // Lightning does more damage to centaurs
|
|
P_DamageMobj(thing, this, target, 9, MOD_ELECTRIC);
|
|
}
|
|
else
|
|
{
|
|
P_DamageMobj(thing, this, target, 3, MOD_ELECTRIC);
|
|
}
|
|
if (!(S_IsActorPlayingSomething (this, CHAN_WEAPON)))
|
|
{
|
|
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
|
|
}
|
|
|
|
// Ceiling Lightning --------------------------------------------------------
|
|
|
|
class ALightningCeiling : public ALightning
|
|
{
|
|
DECLARE_ACTOR (ALightningCeiling, ALightning)
|
|
};
|
|
|
|
FState ALightningCeiling::States[] =
|
|
{
|
|
#define S_LIGHTNING_CEILING1 0
|
|
S_BRIGHT (MLFX, 'A', 2, A_LightningZap , &States[S_LIGHTNING_CEILING1+1]),
|
|
S_BRIGHT (MLFX, 'B', 2, A_LightningClip , &States[S_LIGHTNING_CEILING1+2]),
|
|
S_BRIGHT (MLFX, 'C', 2, A_LightningClip , &States[S_LIGHTNING_CEILING1+3]),
|
|
S_BRIGHT (MLFX, 'D', 2, A_LightningClip , &States[S_LIGHTNING_CEILING1]),
|
|
|
|
#define S_LIGHTNING_C_X1 (S_LIGHTNING_CEILING1+4)
|
|
S_BRIGHT (MLF2, 'A', 2, A_LightningRemove , &States[S_LIGHTNING_C_X1+1]),
|
|
S_BRIGHT (MLF2, 'B', 3, NULL , &States[S_LIGHTNING_C_X1+2]),
|
|
S_BRIGHT (MLF2, 'C', 3, NULL , &States[S_LIGHTNING_C_X1+3]),
|
|
S_BRIGHT (MLF2, 'D', 3, NULL , &States[S_LIGHTNING_C_X1+4]),
|
|
S_BRIGHT (MLF2, 'E', 3, NULL , &States[S_LIGHTNING_C_X1+5]),
|
|
S_BRIGHT (MLF2, 'K', 3, NULL , &States[S_LIGHTNING_C_X1+6]),
|
|
S_BRIGHT (MLF2, 'L', 3, NULL , &States[S_LIGHTNING_C_X1+7]),
|
|
S_BRIGHT (MLF2, 'M', 3, NULL , &States[S_LIGHTNING_C_X1+8]),
|
|
S_NORMAL (ACLO, 'E', 35, NULL , &States[S_LIGHTNING_C_X1+9]),
|
|
S_BRIGHT (MLF2, 'N', 3, NULL , &States[S_LIGHTNING_C_X1+10]),
|
|
S_BRIGHT (MLF2, 'O', 3, NULL , &States[S_LIGHTNING_C_X1+11]),
|
|
S_BRIGHT (MLF2, 'P', 4, NULL , &States[S_LIGHTNING_C_X1+12]),
|
|
S_BRIGHT (MLF2, 'Q', 3, NULL , &States[S_LIGHTNING_C_X1+13]),
|
|
S_BRIGHT (MLF2, 'P', 3, NULL , &States[S_LIGHTNING_C_X1+14]),
|
|
S_BRIGHT (MLF2, 'Q', 4, NULL , &States[S_LIGHTNING_C_X1+15]),
|
|
S_BRIGHT (MLF2, 'P', 3, NULL , &States[S_LIGHTNING_C_X1+16]),
|
|
S_BRIGHT (MLF2, 'O', 3, NULL , &States[S_LIGHTNING_C_X1+17]),
|
|
S_BRIGHT (MLF2, 'P', 3, NULL , &States[S_LIGHTNING_C_X1+18]),
|
|
S_BRIGHT (MLF2, 'P', 1, A_HideThing , &States[S_LIGHTNING_C_X1+19]),
|
|
S_NORMAL (ACLO, 'E', 1050, A_FreeTargMobj , NULL),
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ALightningCeiling, Hexen, -1, 0)
|
|
PROP_SpawnHealth (144)
|
|
PROP_SpeedFixed (25)
|
|
PROP_RadiusFixed (16)
|
|
PROP_HeightFixed (40)
|
|
PROP_Damage (8)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
|
|
PROP_Flags2 (MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS)
|
|
PROP_Flags3 (MF3_CEILINGHUGGER)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
|
|
PROP_SpawnState (S_LIGHTNING_CEILING1)
|
|
PROP_DeathState (S_LIGHTNING_C_X1)
|
|
END_DEFAULTS
|
|
|
|
// Floor Lightning ----------------------------------------------------------
|
|
|
|
class ALightningFloor : public ALightning
|
|
{
|
|
DECLARE_ACTOR (ALightningFloor, ALightning)
|
|
};
|
|
|
|
FState ALightningFloor::States[] =
|
|
{
|
|
#define S_LIGHTNING_FLOOR1 0
|
|
S_BRIGHT (MLFX, 'E', 2, A_LightningZap , &States[S_LIGHTNING_FLOOR1+1]),
|
|
S_BRIGHT (MLFX, 'F', 2, A_LightningClip , &States[S_LIGHTNING_FLOOR1+2]),
|
|
S_BRIGHT (MLFX, 'G', 2, A_LightningClip , &States[S_LIGHTNING_FLOOR1+3]),
|
|
S_BRIGHT (MLFX, 'H', 2, A_LightningClip , &States[S_LIGHTNING_FLOOR1]),
|
|
|
|
#define S_LIGHTNING_F_X1 (S_LIGHTNING_FLOOR1+4)
|
|
S_BRIGHT (MLF2, 'F', 2, A_LightningRemove , &States[S_LIGHTNING_F_X1+1]),
|
|
S_BRIGHT (MLF2, 'G', 3, NULL , &States[S_LIGHTNING_F_X1+2]),
|
|
S_BRIGHT (MLF2, 'H', 3, NULL , &States[S_LIGHTNING_F_X1+3]),
|
|
S_BRIGHT (MLF2, 'I', 3, NULL , &States[S_LIGHTNING_F_X1+4]),
|
|
S_BRIGHT (MLF2, 'J', 3, NULL , &States[S_LIGHTNING_F_X1+5]),
|
|
S_BRIGHT (MLF2, 'K', 3, NULL , &States[S_LIGHTNING_F_X1+6]),
|
|
S_BRIGHT (MLF2, 'L', 3, NULL , &States[S_LIGHTNING_F_X1+7]),
|
|
S_BRIGHT (MLF2, 'M', 3, NULL , &States[S_LIGHTNING_F_X1+8]),
|
|
S_NORMAL (ACLO, 'E', 20, NULL , &States[S_LIGHTNING_F_X1+9]),
|
|
S_BRIGHT (MLF2, 'N', 3, NULL , &States[S_LIGHTNING_F_X1+10]),
|
|
S_BRIGHT (MLF2, 'O', 3, NULL , &States[S_LIGHTNING_F_X1+11]),
|
|
S_BRIGHT (MLF2, 'P', 4, NULL , &States[S_LIGHTNING_F_X1+12]),
|
|
S_BRIGHT (MLF2, 'Q', 3, NULL , &States[S_LIGHTNING_F_X1+13]),
|
|
S_BRIGHT (MLF2, 'P', 3, NULL , &States[S_LIGHTNING_F_X1+14]),
|
|
S_BRIGHT (MLF2, 'Q', 4, A_LastZap , &States[S_LIGHTNING_F_X1+15]),
|
|
S_BRIGHT (MLF2, 'P', 3, NULL , &States[S_LIGHTNING_F_X1+16]),
|
|
S_BRIGHT (MLF2, 'O', 3, NULL , &States[S_LIGHTNING_F_X1+17]),
|
|
S_BRIGHT (MLF2, 'P', 3, NULL , &States[S_LIGHTNING_F_X1+18]),
|
|
S_BRIGHT (MLF2, 'P', 1, A_HideThing , &ALightningCeiling::States[S_LIGHTNING_C_X1+19]),
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ALightningFloor, Hexen, -1, 0)
|
|
PROP_SpawnHealth (144)
|
|
PROP_SpeedFixed (25)
|
|
PROP_RadiusFixed (16)
|
|
PROP_HeightFixed (40)
|
|
PROP_Damage (8)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
|
|
PROP_Flags2 (MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS)
|
|
PROP_Flags3 (MF3_FLOORHUGGER)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
|
|
PROP_SpawnState (S_LIGHTNING_FLOOR1)
|
|
PROP_DeathState (S_LIGHTNING_F_X1)
|
|
END_DEFAULTS
|
|
|
|
// Lightning Zap ------------------------------------------------------------
|
|
|
|
class ALightningZap : public AActor
|
|
{
|
|
DECLARE_ACTOR (ALightningZap, AActor)
|
|
public:
|
|
int SpecialMissileHit (AActor *thing);
|
|
};
|
|
|
|
FState ALightningZap::States[] =
|
|
{
|
|
#define S_LIGHTNING_ZAP1 0
|
|
S_BRIGHT (MLFX, 'I', 2, A_ZapMimic , &States[S_LIGHTNING_ZAP1+1]),
|
|
S_BRIGHT (MLFX, 'J', 2, A_ZapMimic , &States[S_LIGHTNING_ZAP1+2]),
|
|
S_BRIGHT (MLFX, 'K', 2, A_ZapMimic , &States[S_LIGHTNING_ZAP1+3]),
|
|
S_BRIGHT (MLFX, 'L', 2, A_ZapMimic , &States[S_LIGHTNING_ZAP1+4]),
|
|
S_BRIGHT (MLFX, 'M', 2, A_ZapMimic , &States[S_LIGHTNING_ZAP1]),
|
|
|
|
#define S_LIGHTNING_ZAP_X1 (S_LIGHTNING_ZAP1+5)
|
|
S_BRIGHT (MLFX, 'N', 2, NULL , &States[S_LIGHTNING_ZAP_X1+1]),
|
|
S_BRIGHT (MLFX, 'O', 2, NULL , &States[S_LIGHTNING_ZAP_X1+2]),
|
|
S_BRIGHT (MLFX, 'P', 2, NULL , &States[S_LIGHTNING_ZAP_X1+3]),
|
|
S_BRIGHT (MLFX, 'Q', 2, NULL , &States[S_LIGHTNING_ZAP_X1+4]),
|
|
S_BRIGHT (MLFX, 'R', 2, NULL , &States[S_LIGHTNING_ZAP_X1+5]),
|
|
S_BRIGHT (MLFX, 'S', 2, NULL , &States[S_LIGHTNING_ZAP_X1+6]),
|
|
S_BRIGHT (MLFX, 'T', 2, NULL , &States[S_LIGHTNING_ZAP_X1+7]),
|
|
S_BRIGHT (MLFX, 'U', 2, NULL , NULL),
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (ALightningZap, Hexen, -1, 0)
|
|
PROP_RadiusFixed (15)
|
|
PROP_HeightFixed (35)
|
|
PROP_Damage (2)
|
|
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
|
|
PROP_RenderStyle (STYLE_Add)
|
|
|
|
PROP_SpawnState (S_LIGHTNING_ZAP1)
|
|
PROP_DeathState (S_LIGHTNING_ZAP_X1+7)
|
|
END_DEFAULTS
|
|
|
|
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
|
|
//
|
|
//============================================================================
|
|
|
|
void A_LightningReady (AActor *actor)
|
|
{
|
|
A_WeaponReady (actor);
|
|
if (pr_lightningready() < 160)
|
|
{
|
|
S_Sound (actor, CHAN_WEAPON, "MageLightningReady", 1, ATTN_NORM);
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_LightningClip
|
|
//
|
|
//============================================================================
|
|
|
|
void A_LightningClip (AActor *actor)
|
|
{
|
|
AActor *cMo;
|
|
AActor *target = NULL;
|
|
int zigZag;
|
|
|
|
if (actor->flags3 & MF3_FLOORHUGGER)
|
|
{
|
|
if (actor->lastenemy == NULL)
|
|
{
|
|
return;
|
|
}
|
|
actor->z = actor->floorz;
|
|
target = actor->lastenemy->tracer;
|
|
}
|
|
else if (actor->flags3 & MF3_CEILINGHUGGER)
|
|
{
|
|
actor->z = actor->ceilingz-actor->height;
|
|
target = actor->tracer;
|
|
}
|
|
if (actor->flags3 & MF3_FLOORHUGGER)
|
|
{ // floor lightning zig-zags, and forces the ceiling lightning to mimic
|
|
cMo = actor->lastenemy;
|
|
zigZag = pr_lightningclip();
|
|
if((zigZag > 128 && actor->special1 < 2) || actor->special1 < -2)
|
|
{
|
|
P_ThrustMobj(actor, actor->angle+ANG90, ZAGSPEED);
|
|
if(cMo)
|
|
{
|
|
P_ThrustMobj(cMo, actor->angle+ANG90, ZAGSPEED);
|
|
}
|
|
actor->special1++;
|
|
}
|
|
else
|
|
{
|
|
P_ThrustMobj(actor, actor->angle-ANG90, ZAGSPEED);
|
|
if(cMo)
|
|
{
|
|
P_ThrustMobj(cMo, cMo->angle-ANG90, ZAGSPEED);
|
|
}
|
|
actor->special1--;
|
|
}
|
|
}
|
|
if(target)
|
|
{
|
|
if(target->health <= 0)
|
|
{
|
|
P_ExplodeMissile(actor, NULL);
|
|
}
|
|
else
|
|
{
|
|
actor->angle = R_PointToAngle2(actor->x, actor->y, target->x, target->y);
|
|
actor->momx = 0;
|
|
actor->momy = 0;
|
|
P_ThrustMobj (actor, actor->angle, actor->Speed>>1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//============================================================================
|
|
//
|
|
// A_LightningZap
|
|
//
|
|
//============================================================================
|
|
|
|
void A_LightningZap (AActor *actor)
|
|
{
|
|
AActor *mo;
|
|
fixed_t deltaZ;
|
|
|
|
A_LightningClip(actor);
|
|
|
|
actor->health -= 8;
|
|
if (actor->health <= 0)
|
|
{
|
|
actor->SetState (actor->DeathState);
|
|
return;
|
|
}
|
|
if (actor->flags3 & MF3_FLOORHUGGER)
|
|
{
|
|
deltaZ = 10*FRACUNIT;
|
|
}
|
|
else
|
|
{
|
|
deltaZ = -10*FRACUNIT;
|
|
}
|
|
mo = Spawn<ALightningZap> (actor->x+((pr_zap()-128)*actor->radius/256),
|
|
actor->y+((pr_zap()-128)*actor->radius/256),
|
|
actor->z+deltaZ);
|
|
if (mo)
|
|
{
|
|
mo->lastenemy = actor;
|
|
mo->momx = actor->momx;
|
|
mo->momy = actor->momy;
|
|
mo->target = actor->target;
|
|
if (actor->flags3 & MF3_FLOORHUGGER)
|
|
{
|
|
mo->momz = 20*FRACUNIT;
|
|
}
|
|
else
|
|
{
|
|
mo->momz = -20*FRACUNIT;
|
|
}
|
|
}
|
|
if ((actor->flags3 & MF3_FLOORHUGGER) && pr_zapf() < 160)
|
|
{
|
|
S_Sound (actor, CHAN_BODY, "MageLightningContinuous", 1, ATTN_NORM);
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_MLightningAttack2
|
|
//
|
|
//============================================================================
|
|
|
|
void A_MLightningAttack2 (AActor *actor)
|
|
{
|
|
AActor *fmo, *cmo;
|
|
|
|
fmo = P_SpawnPlayerMissile (actor, RUNTIME_CLASS(ALightningFloor));
|
|
cmo = P_SpawnPlayerMissile (actor, RUNTIME_CLASS(ALightningCeiling));
|
|
if (fmo)
|
|
{
|
|
fmo->special1 = 0;
|
|
fmo->lastenemy = cmo;
|
|
A_LightningZap (fmo);
|
|
}
|
|
if (cmo)
|
|
{
|
|
cmo->tracer = NULL;
|
|
cmo->lastenemy = fmo;
|
|
A_LightningZap (cmo);
|
|
}
|
|
S_Sound (actor, CHAN_BODY, "MageLightningFire", 1, ATTN_NORM);
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_MLightningAttack
|
|
//
|
|
//============================================================================
|
|
|
|
void A_MLightningAttack (AActor *actor)
|
|
{
|
|
A_MLightningAttack2(actor);
|
|
if (actor->player != NULL)
|
|
{
|
|
AWeapon *weapon = actor->player->ReadyWeapon;
|
|
if (weapon != NULL)
|
|
{
|
|
weapon->DepleteAmmo (weapon->bAltFire);
|
|
}
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_ZapMimic
|
|
//
|
|
//============================================================================
|
|
|
|
void A_ZapMimic (AActor *actor)
|
|
{
|
|
AActor *mo;
|
|
|
|
mo = actor->lastenemy;
|
|
if (mo)
|
|
{
|
|
if (mo->state >= mo->DeathState)
|
|
{
|
|
P_ExplodeMissile (actor, NULL);
|
|
}
|
|
else
|
|
{
|
|
actor->momx = mo->momx;
|
|
actor->momy = mo->momy;
|
|
}
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_LastZap
|
|
//
|
|
//============================================================================
|
|
|
|
void A_LastZap (AActor *actor)
|
|
{
|
|
AActor *mo;
|
|
|
|
mo = Spawn<ALightningZap> (actor->x, actor->y, actor->z);
|
|
if (mo)
|
|
{
|
|
mo->SetState (&ALightningZap::States[S_LIGHTNING_ZAP_X1]);
|
|
mo->momz = 40*FRACUNIT;
|
|
mo->damage = 0;
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_LightningRemove
|
|
//
|
|
//============================================================================
|
|
|
|
void A_LightningRemove (AActor *actor)
|
|
{
|
|
AActor *mo;
|
|
|
|
mo = actor->lastenemy;
|
|
if (mo)
|
|
{
|
|
mo->lastenemy = NULL;
|
|
P_ExplodeMissile (mo, NULL);
|
|
}
|
|
}
|