gzdoom/src/g_hexen/a_clericflame.cpp

481 lines
15 KiB
C++
Raw Normal View History

#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"
const fixed_t FLAMESPEED = fixed_t(0.45*FRACUNIT);
const fixed_t CFLAMERANGE = 12*64*FRACUNIT;
const fixed_t FLAMEROTSPEED = 2*FRACUNIT;
static FRandom pr_missile ("CFlameMissile");
void A_CFlameAttack (AActor *);
void A_CFlameRotate (AActor *);
void A_CFlamePuff (AActor *);
void A_CFlameMissile (AActor *);
// The Cleric's Flame Strike ------------------------------------------------
class ACWeapFlame : public AClericWeapon
{
DECLARE_ACTOR (ACWeapFlame, AClericWeapon)
public:
const char *PickupMessage ()
{
return GStrings("TXT_WEAPON_C3");
}
};
FState ACWeapFlame::States[] =
{
#define S_CFLAME1 0
S_BRIGHT (WCFM, 'A', 4, NULL , &States[S_CFLAME1+1]),
S_BRIGHT (WCFM, 'B', 4, NULL , &States[S_CFLAME1+2]),
S_BRIGHT (WCFM, 'C', 4, NULL , &States[S_CFLAME1+3]),
S_BRIGHT (WCFM, 'D', 4, NULL , &States[S_CFLAME1+4]),
S_BRIGHT (WCFM, 'E', 4, NULL , &States[S_CFLAME1+5]),
S_BRIGHT (WCFM, 'F', 4, NULL , &States[S_CFLAME1+6]),
S_BRIGHT (WCFM, 'G', 4, NULL , &States[S_CFLAME1+7]),
S_BRIGHT (WCFM, 'H', 4, NULL , &States[S_CFLAME1]),
#define S_CFLAMEREADY (S_CFLAME1+8)
S_NORMAL (CFLM, 'A', 1, A_WeaponReady , &States[S_CFLAMEREADY+1]),
S_NORMAL (CFLM, 'A', 1, A_WeaponReady , &States[S_CFLAMEREADY+2]),
S_NORMAL (CFLM, 'A', 1, A_WeaponReady , &States[S_CFLAMEREADY+3]),
S_NORMAL (CFLM, 'A', 1, A_WeaponReady , &States[S_CFLAMEREADY+4]),
S_NORMAL (CFLM, 'B', 1, A_WeaponReady , &States[S_CFLAMEREADY+5]),
S_NORMAL (CFLM, 'B', 1, A_WeaponReady , &States[S_CFLAMEREADY+6]),
S_NORMAL (CFLM, 'B', 1, A_WeaponReady , &States[S_CFLAMEREADY+7]),
S_NORMAL (CFLM, 'B', 1, A_WeaponReady , &States[S_CFLAMEREADY+8]),
S_NORMAL (CFLM, 'C', 1, A_WeaponReady , &States[S_CFLAMEREADY+9]),
S_NORMAL (CFLM, 'C', 1, A_WeaponReady , &States[S_CFLAMEREADY+10]),
S_NORMAL (CFLM, 'C', 1, A_WeaponReady , &States[S_CFLAMEREADY+11]),
S_NORMAL (CFLM, 'C', 1, A_WeaponReady , &States[S_CFLAMEREADY]),
#define S_CFLAMEDOWN (S_CFLAMEREADY+12)
S_NORMAL (CFLM, 'A', 1, A_Lower , &States[S_CFLAMEDOWN]),
#define S_CFLAMEUP (S_CFLAMEDOWN+1)
S_NORMAL (CFLM, 'A', 1, A_Raise , &States[S_CFLAMEUP]),
#define S_CFLAMEATK (S_CFLAMEUP+1)
S_NORMAL2 (CFLM, 'A', 2, NULL , &States[S_CFLAMEATK+1], 0, 40),
S_NORMAL2 (CFLM, 'D', 2, NULL , &States[S_CFLAMEATK+2], 0, 50),
S_NORMAL2 (CFLM, 'D', 2, NULL , &States[S_CFLAMEATK+3], 0, 36),
S_BRIGHT (CFLM, 'E', 4, NULL , &States[S_CFLAMEATK+4]),
S_BRIGHT (CFLM, 'F', 4, A_CFlameAttack , &States[S_CFLAMEATK+5]),
S_BRIGHT (CFLM, 'E', 4, NULL , &States[S_CFLAMEATK+6]),
S_NORMAL2 (CFLM, 'G', 2, NULL , &States[S_CFLAMEATK+7], 0, 40),
S_NORMAL (CFLM, 'G', 2, NULL , &States[S_CFLAMEREADY]),
};
IMPLEMENT_ACTOR (ACWeapFlame, Hexen, 8009, 0)
PROP_Flags (MF_SPECIAL|MF_NOGRAVITY)
PROP_SpawnState (S_CFLAME1)
PROP_Weapon_SelectionOrder (1000)
PROP_Weapon_AmmoUse1 (4)
PROP_Weapon_AmmoGive1 (25)
PROP_Weapon_UpState (S_CFLAMEUP)
PROP_Weapon_DownState (S_CFLAMEDOWN)
PROP_Weapon_ReadyState (S_CFLAMEREADY)
PROP_Weapon_AtkState (S_CFLAMEATK)
PROP_Weapon_HoldAtkState (S_CFLAMEATK)
PROP_Weapon_Kickback (150)
PROP_Weapon_YAdjust (10)
PROP_Weapon_MoveCombatDist (27000000)
PROP_Weapon_AmmoType1 ("Mana2")
PROP_Weapon_ProjectileType ("CFlameMissile")
END_DEFAULTS
// Floor Flame --------------------------------------------------------------
class ACFlameFloor : public AActor
{
DECLARE_ACTOR (ACFlameFloor, AActor)
};
FState ACFlameFloor::States[] =
{
S_BRIGHT (CFFX, 'N', 5, NULL , &States[1]),
S_BRIGHT (CFFX, 'O', 4, NULL , &States[2]),
S_BRIGHT (CFFX, 'P', 3, NULL , NULL),
};
IMPLEMENT_ACTOR (ACFlameFloor, Hexen, -1, 0)
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
PROP_RenderStyle (STYLE_Add)
PROP_SpawnState (0)
END_DEFAULTS
// Flame Puff ---------------------------------------------------------------
class AFlamePuff : public AActor
{
DECLARE_ACTOR (AFlamePuff, AActor)
};
FState AFlamePuff::States[] =
{
S_BRIGHT (CFFX, 'A', 3, NULL , &States[1]),
S_BRIGHT (CFFX, 'B', 3, NULL , &States[2]),
S_BRIGHT (CFFX, 'C', 3, NULL , &States[3]),
S_BRIGHT (CFFX, 'D', 4, NULL , &States[4]),
S_BRIGHT (CFFX, 'E', 3, NULL , &States[5]),
S_BRIGHT (CFFX, 'F', 4, NULL , &States[6]),
S_BRIGHT (CFFX, 'G', 3, NULL , &States[7]),
S_BRIGHT (CFFX, 'H', 4, NULL , &States[8]),
S_BRIGHT (CFFX, 'I', 3, NULL , &States[9]),
S_BRIGHT (CFFX, 'J', 4, NULL , &States[10]),
S_BRIGHT (CFFX, 'K', 3, NULL , &States[11]),
S_BRIGHT (CFFX, 'L', 4, NULL , &States[12]),
S_BRIGHT (CFFX, 'M', 3, NULL , NULL),
};
IMPLEMENT_ACTOR (AFlamePuff, Hexen, -1, 0)
PROP_RadiusFixed (1)
PROP_HeightFixed (1)
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
PROP_RenderStyle (STYLE_Add)
PROP_SpawnState (0)
PROP_SeeSound ("ClericFlameExplode")
PROP_AttackSound ("ClericFlameExplode")
END_DEFAULTS
// Flame Puff 2 -------------------------------------------------------------
class AFlamePuff2 : public AActor
{
DECLARE_ACTOR (AFlamePuff2, AActor)
};
FState AFlamePuff2::States[] =
{
S_BRIGHT (CFFX, 'A', 3, NULL , &States[1]),
S_BRIGHT (CFFX, 'B', 3, NULL , &States[2]),
S_BRIGHT (CFFX, 'C', 3, NULL , &States[3]),
S_BRIGHT (CFFX, 'D', 4, NULL , &States[4]),
S_BRIGHT (CFFX, 'E', 3, NULL , &States[5]),
S_BRIGHT (CFFX, 'F', 4, NULL , &States[6]),
S_BRIGHT (CFFX, 'G', 3, NULL , &States[7]),
S_BRIGHT (CFFX, 'H', 4, NULL , &States[8]),
S_BRIGHT (CFFX, 'I', 3, NULL , &States[9]),
S_BRIGHT (CFFX, 'C', 3, NULL , &States[10]),
S_BRIGHT (CFFX, 'D', 4, NULL , &States[11]),
S_BRIGHT (CFFX, 'E', 3, NULL , &States[12]),
S_BRIGHT (CFFX, 'F', 4, NULL , &States[13]),
S_BRIGHT (CFFX, 'G', 3, NULL , &States[14]),
S_BRIGHT (CFFX, 'H', 4, NULL , &States[15]),
S_BRIGHT (CFFX, 'I', 3, NULL , &States[16]),
S_BRIGHT (CFFX, 'J', 4, NULL , &States[17]),
S_BRIGHT (CFFX, 'K', 3, NULL , &States[18]),
S_BRIGHT (CFFX, 'L', 4, NULL , &States[19]),
S_BRIGHT (CFFX, 'M', 3, NULL , NULL),
};
IMPLEMENT_ACTOR (AFlamePuff2, Hexen, -1, 0)
PROP_RadiusFixed (1)
PROP_HeightFixed (1)
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
PROP_RenderStyle (STYLE_Add)
PROP_SpawnState (0)
PROP_SeeSound ("ClericFlameExplode")
PROP_AttackSound ("ClericFlameExplode")
END_DEFAULTS
// Circle Flame -------------------------------------------------------------
class ACircleFlame : public AActor
{
DECLARE_ACTOR (ACircleFlame, AActor)
public:
void GetExplodeParms (int &damage, int &dist, bool &hurtSource);
};
FState ACircleFlame::States[] =
{
#define S_CIRCLE_FLAME1 0
S_BRIGHT (CFCF, 'A', 4, NULL , &States[S_CIRCLE_FLAME1+1]),
S_BRIGHT (CFCF, 'B', 2, A_CFlameRotate , &States[S_CIRCLE_FLAME1+2]),
S_BRIGHT (CFCF, 'C', 2, NULL , &States[S_CIRCLE_FLAME1+3]),
S_BRIGHT (CFCF, 'D', 1, NULL , &States[S_CIRCLE_FLAME1+4]),
S_BRIGHT (CFCF, 'E', 2, NULL , &States[S_CIRCLE_FLAME1+5]),
S_BRIGHT (CFCF, 'F', 2, A_CFlameRotate , &States[S_CIRCLE_FLAME1+6]),
S_BRIGHT (CFCF, 'G', 1, NULL , &States[S_CIRCLE_FLAME1+7]),
S_BRIGHT (CFCF, 'H', 2, NULL , &States[S_CIRCLE_FLAME1+8]),
S_BRIGHT (CFCF, 'I', 2, NULL , &States[S_CIRCLE_FLAME1+9]),
S_BRIGHT (CFCF, 'J', 1, A_CFlameRotate , &States[S_CIRCLE_FLAME1+10]),
S_BRIGHT (CFCF, 'K', 2, NULL , &States[S_CIRCLE_FLAME1+11]),
S_BRIGHT (CFCF, 'L', 3, NULL , &States[S_CIRCLE_FLAME1+12]),
S_BRIGHT (CFCF, 'M', 3, NULL , &States[S_CIRCLE_FLAME1+13]),
S_BRIGHT (CFCF, 'N', 2, A_CFlameRotate , &States[S_CIRCLE_FLAME1+14]),
S_BRIGHT (CFCF, 'O', 3, NULL , &States[S_CIRCLE_FLAME1+15]),
S_BRIGHT (CFCF, 'P', 2, NULL , NULL),
#define S_CIRCLE_FLAME_X1 (S_CIRCLE_FLAME1+16)
S_BRIGHT (CFCF, 'Q', 3, NULL , &States[S_CIRCLE_FLAME_X1+1]),
S_BRIGHT (CFCF, 'R', 3, NULL , &States[S_CIRCLE_FLAME_X1+2]),
S_BRIGHT (CFCF, 'S', 3, A_Explode , &States[S_CIRCLE_FLAME_X1+3]),
S_BRIGHT (CFCF, 'T', 3, NULL , &States[S_CIRCLE_FLAME_X1+4]),
S_BRIGHT (CFCF, 'U', 3, NULL , &States[S_CIRCLE_FLAME_X1+5]),
S_BRIGHT (CFCF, 'V', 3, NULL , &States[S_CIRCLE_FLAME_X1+6]),
S_BRIGHT (CFCF, 'W', 3, NULL , &States[S_CIRCLE_FLAME_X1+7]),
S_BRIGHT (CFCF, 'X', 3, NULL , &States[S_CIRCLE_FLAME_X1+8]),
S_BRIGHT (CFCF, 'Y', 3, NULL , &States[S_CIRCLE_FLAME_X1+9]),
S_BRIGHT (CFCF, 'Z', 3, NULL , NULL),
};
IMPLEMENT_ACTOR (ACircleFlame, Hexen, -1, 0)
PROP_RadiusFixed (6)
PROP_Damage (2)
PROP_DamageType (MOD_FIRE)
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
PROP_Flags2 (MF2_NOTELEPORT)
PROP_RenderStyle (STYLE_Add)
PROP_SpawnState (S_CIRCLE_FLAME1)
PROP_DeathState (S_CIRCLE_FLAME_X1)
PROP_DeathSound ("ClericFlameCircle")
END_DEFAULTS
void ACircleFlame::GetExplodeParms (int &damage, int &dist, bool &hurtSource)
{
damage = 20;
hurtSource = false;
}
// Flame Missile ------------------------------------------------------------
class ACFlameMissile : public AActor
{
DECLARE_ACTOR (ACFlameMissile, AActor)
public:
void BeginPlay ();
void Tick ();
};
FState ACFlameMissile::States[] =
{
#define S_CFLAME_MISSILE1 0
S_BRIGHT (CFFX, 'A', 4, NULL , &States[S_CFLAME_MISSILE1+1]),
S_NORMAL (CFFX, 'A', 1, A_CFlamePuff , &AFlamePuff::States[0]),
#define S_CFLAME_MISSILE_X (S_CFLAME_MISSILE1+2)
S_BRIGHT (CFFX, 'A', 1, A_CFlameMissile , &AFlamePuff::States[0]),
};
IMPLEMENT_ACTOR (ACFlameMissile, Hexen, -1, 0)
PROP_SpeedFixed (200)
PROP_RadiusFixed (14)
PROP_HeightFixed (8)
PROP_Damage (8)
PROP_DamageType (MOD_FIRE)
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
PROP_Flags2 (MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS)
PROP_RenderFlags (RF_INVISIBLE)
PROP_RenderStyle (STYLE_Add)
PROP_SpawnState (S_CFLAME_MISSILE1)
PROP_DeathState (S_CFLAME_MISSILE_X)
END_DEFAULTS
void ACFlameMissile::BeginPlay ()
{
special1 = 2;
}
void ACFlameMissile::Tick ()
{
int i;
fixed_t xfrac;
fixed_t yfrac;
fixed_t zfrac;
fixed_t newz;
bool changexy;
AActor *mo;
PrevX = x;
PrevY = y;
PrevZ = z;
// Handle movement
if (momx || momy || (z != floorz) || momz)
{
xfrac = momx>>3;
yfrac = momy>>3;
zfrac = momz>>3;
changexy = xfrac || yfrac;
for (i = 0; i < 8; i++)
{
if (changexy)
{
if (!P_TryMove (this, x+xfrac, y+yfrac, true))
{ // Blocked move
P_ExplodeMissile (this, BlockingLine);
return;
}
}
z += zfrac;
if (z <= floorz)
{ // Hit the floor
z = floorz;
P_HitFloor (this);
P_ExplodeMissile (this, NULL);
return;
}
if (z+height > ceilingz)
{ // Hit the ceiling
z = ceilingz-height;
P_ExplodeMissile (this, NULL);
return;
}
if (changexy)
{
if (!--special1)
{
special1 = 4;
newz = z-12*FRACUNIT;
if (newz < floorz)
{
newz = floorz;
}
mo = Spawn<ACFlameFloor> (x, y, newz);
if (mo)
{
mo->angle = angle;
}
}
}
}
}
// Advance the state
if (tics != -1)
{
tics--;
while (!tics)
{
if (!SetState (state->GetNextState ()))
{ // mobj was removed
return;
}
}
}
}
//============================================================================
//
// A_CFlameAttack
//
//============================================================================
void A_CFlameAttack (AActor *actor)
{
player_t *player;
if (NULL == (player = actor->player))
{
return;
}
AWeapon *weapon = actor->player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return;
}
P_SpawnPlayerMissile (actor, RUNTIME_CLASS(ACFlameMissile));
S_Sound (actor, CHAN_WEAPON, "ClericFlameFire", 1, ATTN_NORM);
}
//============================================================================
//
// A_CFlamePuff
//
//============================================================================
void A_CFlamePuff (AActor *actor)
{
A_UnHideThing (actor);
actor->momx = 0;
actor->momy = 0;
actor->momz = 0;
S_Sound (actor, CHAN_BODY, "ClericFlameExplode", 1, ATTN_NORM);
}
//============================================================================
//
// A_CFlameMissile
//
//============================================================================
void A_CFlameMissile (AActor *actor)
{
int i;
int an, an90;
fixed_t dist;
AActor *mo;
A_UnHideThing (actor);
S_Sound (actor, CHAN_BODY, "ClericFlameExplode", 1, ATTN_NORM);
if (BlockingMobj && BlockingMobj->flags&MF_SHOOTABLE)
{ // Hit something, so spawn the flame circle around the thing
dist = BlockingMobj->radius+18*FRACUNIT;
for (i = 0; i < 4; i++)
{
an = (i*ANG45)>>ANGLETOFINESHIFT;
an90 = (i*ANG45+ANG90)>>ANGLETOFINESHIFT;
mo = Spawn<ACircleFlame> (BlockingMobj->x+FixedMul(dist, finecosine[an]),
BlockingMobj->y+FixedMul(dist, finesine[an]),
BlockingMobj->z+5*FRACUNIT);
if (mo)
{
mo->angle = an<<ANGLETOFINESHIFT;
mo->target = actor->target;
mo->momx = mo->special1 = FixedMul(FLAMESPEED, finecosine[an]);
mo->momy = mo->special2 = FixedMul(FLAMESPEED, finesine[an]);
mo->tics -= pr_missile()&3;
}
mo = Spawn<ACircleFlame> (BlockingMobj->x-FixedMul(dist, finecosine[an]),
BlockingMobj->y-FixedMul(dist, finesine[an]),
BlockingMobj->z+5*FRACUNIT);
if(mo)
{
mo->angle = ANG180+(an<<ANGLETOFINESHIFT);
mo->target = actor->target;
mo->momx = mo->special1 = FixedMul(-FLAMESPEED, finecosine[an]);
mo->momy = mo->special2 = FixedMul(-FLAMESPEED, finesine[an]);
mo->tics -= pr_missile()&3;
}
}
actor->SetState (&AFlamePuff2::States[0]);
}
}
//============================================================================
//
// A_CFlameRotate
//
//============================================================================
void A_CFlameRotate (AActor *actor)
{
int an;
an = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
actor->momx = actor->special1+FixedMul(FLAMEROTSPEED, finecosine[an]);
actor->momy = actor->special2+FixedMul(FLAMEROTSPEED, finesine[an]);
actor->angle += ANG90/15;
}