qzdoom/src/g_hexen/a_centaur.cpp

340 lines
12 KiB
C++
Raw Normal View History

#include "actor.h"
#include "info.h"
#include "p_local.h"
#include "s_sound.h"
#include "p_enemy.h"
#include "a_action.h"
#include "m_random.h"
#include "a_hexenglobal.h"
static FRandom pr_centaurdefend ("CentaurDefend");
static FRandom pr_reflect ("CentaurDeflect");
static FRandom pr_centaurattack ("CentaurAttack");
static FRandom pr_centaurdrop ("CentaurDrop");
void A_CentaurDefend (AActor *);
void A_CentaurAttack (AActor *);
void A_CentaurAttack2 (AActor *);
void A_CentaurDropStuff (AActor *);
// Centaur ------------------------------------------------------------------
FState ACentaur::States[] =
{
#define S_CENTAUR_LOOK1 0
S_NORMAL (CENT, 'A', 10, A_Look , &States[S_CENTAUR_LOOK1+1]),
S_NORMAL (CENT, 'B', 10, A_Look , &States[S_CENTAUR_LOOK1]),
#define S_CENTAUR_WALK1 (S_CENTAUR_LOOK1+2)
S_NORMAL (CENT, 'A', 4, A_Chase , &States[S_CENTAUR_WALK1+1]),
S_NORMAL (CENT, 'B', 4, A_Chase , &States[S_CENTAUR_WALK1+2]),
S_NORMAL (CENT, 'C', 4, A_Chase , &States[S_CENTAUR_WALK1+3]),
S_NORMAL (CENT, 'D', 4, A_Chase , &States[S_CENTAUR_WALK1]),
#define S_CENTAUR_PAIN1 (S_CENTAUR_WALK1+4)
S_NORMAL (CENT, 'G', 6, A_Pain , &States[S_CENTAUR_PAIN1+1]),
S_NORMAL (CENT, 'G', 6, A_SetReflectiveInvulnerable, &States[S_CENTAUR_PAIN1+2]),
S_NORMAL (CENT, 'E', 15, A_CentaurDefend , &States[S_CENTAUR_PAIN1+3]),
S_NORMAL (CENT, 'E', 15, A_CentaurDefend , &States[S_CENTAUR_PAIN1+4]),
S_NORMAL (CENT, 'E', 15, A_CentaurDefend , &States[S_CENTAUR_PAIN1+5]),
S_NORMAL (CENT, 'E', 1, A_UnSetReflectiveInvulnerable, &States[S_CENTAUR_WALK1]),
#define S_CENTAUR_ATK1 (S_CENTAUR_PAIN1+6)
S_NORMAL (CENT, 'H', 5, A_FaceTarget , &States[S_CENTAUR_ATK1+1]),
S_NORMAL (CENT, 'I', 4, A_FaceTarget , &States[S_CENTAUR_ATK1+2]),
S_NORMAL (CENT, 'J', 7, A_CentaurAttack , &States[S_CENTAUR_WALK1]),
#define S_CENTAUR_MISSILE1 (S_CENTAUR_ATK1+3)
S_NORMAL (CENT, 'E', 10, A_FaceTarget , &States[S_CENTAUR_MISSILE1+1]),
S_BRIGHT (CENT, 'F', 8, A_CentaurAttack2 , &States[S_CENTAUR_MISSILE1+2]),
S_NORMAL (CENT, 'E', 10, A_FaceTarget , &States[S_CENTAUR_MISSILE1+3]),
S_BRIGHT (CENT, 'F', 8, A_CentaurAttack2 , &States[S_CENTAUR_WALK1]),
#define S_CENTAUR_DEATH1 (S_CENTAUR_MISSILE1+4)
S_NORMAL (CENT, 'K', 4, NULL , &States[S_CENTAUR_DEATH1+1]),
S_NORMAL (CENT, 'L', 4, A_Scream , &States[S_CENTAUR_DEATH1+2]),
S_NORMAL (CENT, 'M', 4, NULL , &States[S_CENTAUR_DEATH1+3]),
S_NORMAL (CENT, 'N', 4, NULL , &States[S_CENTAUR_DEATH1+4]),
S_NORMAL (CENT, 'O', 4, A_NoBlocking , &States[S_CENTAUR_DEATH1+5]),
S_NORMAL (CENT, 'P', 4, NULL , &States[S_CENTAUR_DEATH1+6]),
S_NORMAL (CENT, 'Q', 4, NULL , &States[S_CENTAUR_DEATH1+7]),
S_NORMAL (CENT, 'R', 4, A_QueueCorpse , &States[S_CENTAUR_DEATH1+8]),
S_NORMAL (CENT, 'S', 4, NULL , &States[S_CENTAUR_DEATH1+9]),
S_NORMAL (CENT, 'T', -1, NULL , NULL),
#define S_CENTAUR_DEATH_X1 (S_CENTAUR_DEATH1+10)
S_NORMAL (CTXD, 'A', 4, NULL , &States[S_CENTAUR_DEATH_X1+1]),
S_NORMAL (CTXD, 'B', 4, A_NoBlocking , &States[S_CENTAUR_DEATH_X1+2]),
S_NORMAL (CTXD, 'C', 4, A_CentaurDropStuff , &States[S_CENTAUR_DEATH_X1+3]),
S_NORMAL (CTXD, 'D', 3, A_Scream , &States[S_CENTAUR_DEATH_X1+4]),
S_NORMAL (CTXD, 'E', 4, A_QueueCorpse , &States[S_CENTAUR_DEATH_X1+5]),
S_NORMAL (CTXD, 'F', 3, NULL , &States[S_CENTAUR_DEATH_X1+6]),
S_NORMAL (CTXD, 'G', 4, NULL , &States[S_CENTAUR_DEATH_X1+7]),
S_NORMAL (CTXD, 'H', 3, NULL , &States[S_CENTAUR_DEATH_X1+8]),
S_NORMAL (CTXD, 'I', 4, NULL , &States[S_CENTAUR_DEATH_X1+9]),
S_NORMAL (CTXD, 'J', 3, NULL , &States[S_CENTAUR_DEATH_X1+10]),
S_NORMAL (CTXD, 'K', -1, NULL , NULL),
#define S_CENTAUR_ICE1 (S_CENTAUR_DEATH_X1+11)
S_NORMAL (CENT, 'U', 5, A_FreezeDeath , &States[S_CENTAUR_ICE1+1]),
S_NORMAL (CENT, 'U', 1, A_FreezeDeathChunks , &States[S_CENTAUR_ICE1+1]),
};
IMPLEMENT_ACTOR (ACentaur, Hexen, 107, 1)
PROP_SpawnHealth (200)
PROP_PainChance (135)
PROP_SpeedFixed (13)
PROP_HeightFixed (64)
PROP_Mass (120)
PROP_Flags (MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL)
PROP_Flags2 (MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL|MF2_MCROSS)
PROP_Flags4 (MF4_SHIELDREFLECT)
PROP_SpawnState (S_CENTAUR_LOOK1)
PROP_SeeState (S_CENTAUR_WALK1)
PROP_PainState (S_CENTAUR_PAIN1)
PROP_MeleeState (S_CENTAUR_ATK1)
PROP_DeathState (S_CENTAUR_DEATH1)
PROP_XDeathState (S_CENTAUR_DEATH_X1)
PROP_IDeathState (S_CENTAUR_ICE1)
PROP_SeeSound ("CentaurSight")
PROP_AttackSound ("CentaurAttack")
PROP_PainSound ("CentaurPain")
PROP_DeathSound ("CentaurDeath")
PROP_ActiveSound ("CentaurActive")
END_DEFAULTS
void ACentaur::Howl ()
{
int howl = S_FindSound ("PuppyBeat");
if (!S_GetSoundPlayingInfo (this, howl))
{
S_SoundID (this, CHAN_BODY, howl, 1, ATTN_NORM);
}
}
// Centaur Leader -----------------------------------------------------------
class ACentaurLeader : public ACentaur
{
DECLARE_STATELESS_ACTOR (ACentaurLeader, ACentaur)
};
IMPLEMENT_STATELESS_ACTOR (ACentaurLeader, Hexen, 115, 2)
PROP_SpawnHealth (250)
PROP_PainChance (96)
PROP_SpeedFixed (10)
PROP_MissileState (S_CENTAUR_MISSILE1)
END_DEFAULTS
// Mashed centaur -----------------------------------------------------------
//
// The mashed centaur is only placed through ACS. Nowhere in the game source
// is it ever referenced.
class ACentaurMash : public ACentaur
{
DECLARE_STATELESS_ACTOR (ACentaurMash, ACentaur)
};
IMPLEMENT_STATELESS_ACTOR (ACentaurMash, Hexen, -1, 103)
PROP_FlagsSet (MF_NOBLOOD)
PROP_Flags2Set (MF2_BLASTED)
PROP_Flags2Clear (MF2_TELESTOMP)
PROP_RenderStyle (STYLE_Translucent)
PROP_Alpha (HX_ALTSHADOW)
PROP_DeathState (~0)
PROP_XDeathState (~0)
PROP_IDeathState (~0)
END_DEFAULTS
// Centaur projectile -------------------------------------------------------
class ACentaurFX : public AActor
{
DECLARE_ACTOR (ACentaurFX, AActor)
};
FState ACentaurFX::States[] =
{
#define S_CENTAUR_FX1 0
S_BRIGHT (CTFX, 'A', -1, NULL , NULL),
#define S_CENTAUR_FX_X1 (S_CENTAUR_FX1+1)
S_BRIGHT (CTFX, 'B', 4, NULL , &States[S_CENTAUR_FX_X1+1]),
S_BRIGHT (CTFX, 'C', 3, NULL , &States[S_CENTAUR_FX_X1+2]),
S_BRIGHT (CTFX, 'D', 4, NULL , &States[S_CENTAUR_FX_X1+3]),
S_BRIGHT (CTFX, 'E', 3, NULL , &States[S_CENTAUR_FX_X1+4]),
S_BRIGHT (CTFX, 'F', 2, NULL , NULL),
};
IMPLEMENT_ACTOR (ACentaurFX, Hexen, -1, 0)
PROP_SpeedFixed (20)
PROP_Damage (4)
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
PROP_Flags2 (MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS)
PROP_RenderStyle (STYLE_Add)
PROP_SpawnState (S_CENTAUR_FX1)
PROP_DeathState (S_CENTAUR_FX_X1)
PROP_DeathSound ("CentaurMissileExplode")
END_DEFAULTS
// Centaur shield (debris) --------------------------------------------------
class ACentaurShield : public AActor
{
DECLARE_ACTOR (ACentaurShield, AActor)
};
FState ACentaurShield::States[] =
{
#define S_CENTAUR_SHIELD1 0
S_NORMAL (CTDP, 'A', 3, NULL , &States[S_CENTAUR_SHIELD1+1]),
S_NORMAL (CTDP, 'B', 3, NULL , &States[S_CENTAUR_SHIELD1+2]),
S_NORMAL (CTDP, 'C', 3, NULL , &States[S_CENTAUR_SHIELD1+3]),
S_NORMAL (CTDP, 'D', 3, NULL , &States[S_CENTAUR_SHIELD1+4]),
S_NORMAL (CTDP, 'E', 3, NULL , &States[S_CENTAUR_SHIELD1+5]),
S_NORMAL (CTDP, 'F', 3, NULL , &States[S_CENTAUR_SHIELD1+2]),
#define S_CENTAUR_SHIELD_X1 (S_CENTAUR_SHIELD1+6)
S_NORMAL (CTDP, 'G', 4, NULL , &States[S_CENTAUR_SHIELD_X1+1]),
S_NORMAL (CTDP, 'H', 4, A_QueueCorpse , &States[S_CENTAUR_SHIELD_X1+2]),
S_NORMAL (CTDP, 'I', 4, NULL , &States[S_CENTAUR_SHIELD_X1+3]),
S_NORMAL (CTDP, 'J', -1, NULL , NULL),
};
IMPLEMENT_ACTOR (ACentaurShield, Hexen, -1, 0)
PROP_Flags (MF_DROPOFF|MF_CORPSE)
PROP_Flags2 (MF2_NOTELEPORT)
PROP_SpawnState (S_CENTAUR_SHIELD1)
PROP_CrashState (S_CENTAUR_SHIELD_X1)
END_DEFAULTS
// Centaur sword (debris) ---------------------------------------------------
class ACentaurSword : public AActor
{
DECLARE_ACTOR (ACentaurSword, AActor)
};
FState ACentaurSword::States[] =
{
#define S_CENTAUR_SWORD1 0
S_NORMAL (CTDP, 'K', 3, NULL , &States[S_CENTAUR_SWORD1+1]),
S_NORMAL (CTDP, 'L', 3, NULL , &States[S_CENTAUR_SWORD1+2]),
S_NORMAL (CTDP, 'M', 3, NULL , &States[S_CENTAUR_SWORD1+3]),
S_NORMAL (CTDP, 'N', 3, NULL , &States[S_CENTAUR_SWORD1+4]),
S_NORMAL (CTDP, 'O', 3, NULL , &States[S_CENTAUR_SWORD1+5]),
S_NORMAL (CTDP, 'P', 3, NULL , &States[S_CENTAUR_SWORD1+6]),
S_NORMAL (CTDP, 'Q', 3, NULL , &States[S_CENTAUR_SWORD1+2]),
#define S_CENTAUR_SWORD_X1 (S_CENTAUR_SWORD1+7)
S_NORMAL (CTDP, 'R', 4, NULL , &States[S_CENTAUR_SWORD_X1+1]),
S_NORMAL (CTDP, 'S', 4, A_QueueCorpse , &States[S_CENTAUR_SWORD_X1+2]),
S_NORMAL (CTDP, 'T', -1, NULL , NULL),
};
IMPLEMENT_ACTOR (ACentaurSword, Hexen, -1, 0)
PROP_Flags (MF_DROPOFF|MF_CORPSE)
PROP_Flags2 (MF2_NOTELEPORT)
PROP_SpawnState (S_CENTAUR_SWORD1)
PROP_CrashState (S_CENTAUR_SWORD_X1)
END_DEFAULTS
//============================================================================
//
// A_CentaurAttack
//
//============================================================================
void A_CentaurAttack (AActor *actor)
{
if (!actor->target)
{
return;
}
if (actor->CheckMeleeRange ())
{
int damage = pr_centaurattack()%7+3;
P_DamageMobj (actor->target, actor, actor, damage, MOD_HIT);
P_TraceBleed (damage, actor->target, actor);
}
}
//============================================================================
//
// A_CentaurAttack2
//
//============================================================================
void A_CentaurAttack2 (AActor *actor)
{
if (!actor->target)
{
return;
}
P_SpawnMissileZ (actor, actor->z + 45*FRACUNIT,
actor->target, RUNTIME_CLASS(ACentaurFX));
S_Sound (actor, CHAN_WEAPON, "CentaurLeaderAttack", 1, ATTN_NORM);
}
//============================================================================
//
// A_CentaurDropStuff
//
// Spawn shield/sword sprites when the centaur pulps
//============================================================================
void A_CentaurDropStuff (AActor *actor)
{
const TypeInfo *const DropTypes[] =
{
RUNTIME_CLASS(ACentaurSword),
RUNTIME_CLASS(ACentaurShield)
};
for (int i = sizeof(DropTypes)/sizeof(DropTypes[0])-1; i >= 0; --i)
{
AActor *mo;
mo = Spawn (DropTypes[i], actor->x, actor->y, actor->z+45*FRACUNIT);
if (mo)
{
angle_t angle = actor->angle + (i ? ANGLE_90 : ANGLE_270);
mo->momz = FRACUNIT*8+(pr_centaurdrop()<<10);
mo->momx = FixedMul(((pr_centaurdrop()-128)<<11)+FRACUNIT,
finecosine[angle>>ANGLETOFINESHIFT]);
mo->momy = FixedMul(((pr_centaurdrop()-128)<<11)+FRACUNIT,
finesine[angle>>ANGLETOFINESHIFT]);
mo->target = actor;
}
}
}
//============================================================================
//
// A_CentaurDefend
//
//============================================================================
void A_CentaurDefend (AActor *actor)
{
A_FaceTarget (actor);
if (actor->CheckMeleeRange() && pr_centaurdefend() < 32)
{
// This should unset REFLECTIVE as well
// (unless you want the Centaur to reflect projectiles forever!)
A_UnSetReflectiveInvulnerable (actor);
actor->SetState (actor->MeleeState);
}
}