2006-02-24 04:48:15 +00:00
|
|
|
#include "templates.h"
|
|
|
|
#include "actor.h"
|
|
|
|
#include "info.h"
|
|
|
|
#include "m_random.h"
|
|
|
|
#include "s_sound.h"
|
|
|
|
#include "p_local.h"
|
|
|
|
#include "p_enemy.h"
|
|
|
|
#include "gstrings.h"
|
|
|
|
|
|
|
|
static FRandom pr_imp ("ImpExplode");
|
|
|
|
static FRandom pr_impmeatk ("ImpMeAttack");
|
|
|
|
static FRandom pr_impmsatk ("ImpMsAttack");
|
|
|
|
static FRandom pr_impmsatk2 ("ImpMsAttack2");
|
|
|
|
|
|
|
|
void A_ImpExplode (AActor *);
|
|
|
|
void A_ImpMeAttack (AActor *);
|
|
|
|
void A_ImpMsAttack (AActor *);
|
|
|
|
void A_ImpMsAttack2 (AActor *);
|
|
|
|
void A_ImpDeath (AActor *);
|
|
|
|
void A_ImpXDeath1 (AActor *);
|
|
|
|
void A_ImpXDeath2 (AActor *);
|
|
|
|
|
|
|
|
// Heretic imp (as opposed to the Doom variety) -----------------------------
|
|
|
|
|
|
|
|
class AHereticImp : public AActor
|
|
|
|
{
|
|
|
|
DECLARE_ACTOR (AHereticImp, AActor)
|
|
|
|
};
|
|
|
|
|
|
|
|
FState AHereticImp::States[] =
|
|
|
|
{
|
|
|
|
#define S_IMP_LOOK 0
|
|
|
|
S_NORMAL (IMPX, 'A', 10, A_Look , &States[S_IMP_LOOK+1]),
|
|
|
|
S_NORMAL (IMPX, 'B', 10, A_Look , &States[S_IMP_LOOK+2]),
|
|
|
|
S_NORMAL (IMPX, 'C', 10, A_Look , &States[S_IMP_LOOK+3]),
|
|
|
|
S_NORMAL (IMPX, 'B', 10, A_Look , &States[S_IMP_LOOK+0]),
|
|
|
|
|
|
|
|
#define S_IMP_FLY (S_IMP_LOOK+4)
|
|
|
|
S_NORMAL (IMPX, 'A', 3, A_Chase , &States[S_IMP_FLY+1]),
|
|
|
|
S_NORMAL (IMPX, 'A', 3, A_Chase , &States[S_IMP_FLY+2]),
|
|
|
|
S_NORMAL (IMPX, 'B', 3, A_Chase , &States[S_IMP_FLY+3]),
|
|
|
|
S_NORMAL (IMPX, 'B', 3, A_Chase , &States[S_IMP_FLY+4]),
|
|
|
|
S_NORMAL (IMPX, 'C', 3, A_Chase , &States[S_IMP_FLY+5]),
|
|
|
|
S_NORMAL (IMPX, 'C', 3, A_Chase , &States[S_IMP_FLY+6]),
|
|
|
|
S_NORMAL (IMPX, 'B', 3, A_Chase , &States[S_IMP_FLY+7]),
|
|
|
|
S_NORMAL (IMPX, 'B', 3, A_Chase , &States[S_IMP_FLY+0]),
|
|
|
|
|
|
|
|
#define S_IMP_MEATK (S_IMP_FLY+8)
|
|
|
|
S_NORMAL (IMPX, 'D', 6, A_FaceTarget , &States[S_IMP_MEATK+1]),
|
|
|
|
S_NORMAL (IMPX, 'E', 6, A_FaceTarget , &States[S_IMP_MEATK+2]),
|
|
|
|
S_NORMAL (IMPX, 'F', 6, A_ImpMeAttack , &States[S_IMP_FLY+0]),
|
|
|
|
|
|
|
|
#define S_IMP_MSATK1 (S_IMP_MEATK+3)
|
|
|
|
S_NORMAL (IMPX, 'A', 10, A_FaceTarget , &States[S_IMP_MSATK1+1]),
|
|
|
|
S_NORMAL (IMPX, 'B', 6, A_ImpMsAttack , &States[S_IMP_MSATK1+2]),
|
|
|
|
S_NORMAL (IMPX, 'C', 6, NULL , &States[S_IMP_MSATK1+3]),
|
|
|
|
S_NORMAL (IMPX, 'B', 6, NULL , &States[S_IMP_MSATK1+4]),
|
|
|
|
S_NORMAL (IMPX, 'A', 6, NULL , &States[S_IMP_MSATK1+5]),
|
|
|
|
S_NORMAL (IMPX, 'B', 6, NULL , &States[S_IMP_MSATK1+2]),
|
|
|
|
|
|
|
|
#define S_IMP_PAIN (S_IMP_MSATK1+6)
|
|
|
|
S_NORMAL (IMPX, 'G', 3, NULL , &States[S_IMP_PAIN+1]),
|
|
|
|
S_NORMAL (IMPX, 'G', 3, A_Pain , &States[S_IMP_FLY+0]),
|
|
|
|
|
|
|
|
#define S_IMP_DIE (S_IMP_PAIN+2)
|
|
|
|
S_NORMAL (IMPX, 'G', 4, A_ImpDeath , &States[S_IMP_DIE+1]),
|
|
|
|
S_NORMAL (IMPX, 'H', 5, NULL , &States[S_IMP_DIE+1]),
|
|
|
|
|
|
|
|
#define S_IMP_XDIE (S_IMP_DIE+2)
|
|
|
|
S_NORMAL (IMPX, 'S', 5, A_ImpXDeath1 , &States[S_IMP_XDIE+1]),
|
|
|
|
S_NORMAL (IMPX, 'T', 5, NULL , &States[S_IMP_XDIE+2]),
|
|
|
|
S_NORMAL (IMPX, 'U', 5, NULL , &States[S_IMP_XDIE+3]),
|
|
|
|
S_NORMAL (IMPX, 'V', 5, A_ImpXDeath2 , &States[S_IMP_XDIE+4]),
|
|
|
|
S_NORMAL (IMPX, 'W', 5, NULL , &States[S_IMP_XDIE+4]),
|
|
|
|
|
|
|
|
#define S_IMP_CRASH (S_IMP_XDIE+5)
|
|
|
|
S_NORMAL (IMPX, 'I', 7, A_ImpExplode , &States[S_IMP_CRASH+1]),
|
|
|
|
S_NORMAL (IMPX, 'J', 7, A_Scream , &States[S_IMP_CRASH+2]),
|
|
|
|
S_NORMAL (IMPX, 'K', 7, NULL , &States[S_IMP_CRASH+3]),
|
|
|
|
S_NORMAL (IMPX, 'L', -1, NULL , NULL),
|
|
|
|
|
|
|
|
#define S_IMP_XCRASH (S_IMP_CRASH+4)
|
|
|
|
S_NORMAL (IMPX, 'X', 7, NULL , &States[S_IMP_XCRASH+1]),
|
|
|
|
S_NORMAL (IMPX, 'Y', 7, NULL , &States[S_IMP_XCRASH+2]),
|
|
|
|
S_NORMAL (IMPX, 'Z', -1, NULL , NULL)
|
|
|
|
};
|
|
|
|
|
|
|
|
IMPLEMENT_ACTOR (AHereticImp, Heretic, 66, 5)
|
|
|
|
PROP_SpawnHealth (40)
|
|
|
|
PROP_RadiusFixed (16)
|
|
|
|
PROP_HeightFixed (36)
|
|
|
|
PROP_Mass (50)
|
|
|
|
PROP_SpeedFixed (10)
|
|
|
|
PROP_PainChance (200)
|
|
|
|
PROP_Flags (MF_SOLID|MF_SHOOTABLE|MF_FLOAT|MF_NOGRAVITY|MF_COUNTKILL)
|
2006-06-29 14:21:56 +00:00
|
|
|
PROP_Flags2 (MF2_MCROSS|MF2_SPAWNFLOAT|MF2_PASSMOBJ|MF2_PUSHWALL)
|
2006-02-24 04:48:15 +00:00
|
|
|
PROP_Flags3 (MF3_DONTOVERLAP)
|
|
|
|
PROP_Flags4 (MF4_MISSILEMORE)
|
|
|
|
|
|
|
|
PROP_SpawnState (S_IMP_LOOK)
|
|
|
|
PROP_SeeState (S_IMP_FLY)
|
|
|
|
PROP_PainState (S_IMP_PAIN)
|
|
|
|
PROP_MeleeState (S_IMP_MEATK)
|
|
|
|
PROP_MissileState (S_IMP_MSATK1)
|
|
|
|
PROP_CrashState (S_IMP_CRASH)
|
|
|
|
PROP_DeathState (S_IMP_DIE)
|
|
|
|
PROP_XDeathState (S_IMP_XDIE)
|
|
|
|
|
|
|
|
PROP_SeeSound ("himp/sight")
|
|
|
|
PROP_AttackSound ("himp/attack")
|
|
|
|
PROP_PainSound ("himp/pain")
|
|
|
|
PROP_DeathSound ("himp/death")
|
|
|
|
PROP_ActiveSound ("himp/active")
|
2006-06-17 20:29:41 +00:00
|
|
|
PROP_Obituary("$OB_HERETICIMP")
|
|
|
|
PROP_HitObituary("$OB_HERETICIMPHIT")
|
2006-02-24 04:48:15 +00:00
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
// Heretic imp leader -------------------------------------------------------
|
|
|
|
|
|
|
|
class AHereticImpLeader : public AHereticImp
|
|
|
|
{
|
|
|
|
DECLARE_ACTOR (AHereticImpLeader, AHereticImp)
|
|
|
|
};
|
|
|
|
|
|
|
|
FState AHereticImpLeader::States[] =
|
|
|
|
{
|
|
|
|
#define S_IMP_MSATK2 0
|
|
|
|
S_NORMAL (IMPX, 'D', 6, A_FaceTarget , &States[S_IMP_MSATK2+1]),
|
|
|
|
S_NORMAL (IMPX, 'E', 6, A_FaceTarget , &States[S_IMP_MSATK2+2]),
|
|
|
|
S_NORMAL (IMPX, 'F', 6, A_ImpMsAttack2 , &AHereticImp::States[S_IMP_FLY]),
|
|
|
|
};
|
|
|
|
|
|
|
|
IMPLEMENT_ACTOR (AHereticImpLeader, Heretic, 5, 7)
|
|
|
|
PROP_SpawnHealth (80)
|
|
|
|
|
|
|
|
PROP_MeleeState (~0)
|
|
|
|
PROP_MissileState (S_IMP_MSATK2)
|
|
|
|
PROP_Flags4Clear(MF4_MISSILEMORE) // The imp leader does have a 'normal' missile range!
|
|
|
|
|
|
|
|
PROP_AttackSound ("himp/leaderattack")
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
// Heretic imp chunk 1 ------------------------------------------------------
|
|
|
|
|
|
|
|
class AHereticImpChunk1 : public AActor
|
|
|
|
{
|
|
|
|
DECLARE_ACTOR (AHereticImpChunk1, AActor)
|
|
|
|
};
|
|
|
|
|
|
|
|
FState AHereticImpChunk1::States[] =
|
|
|
|
{
|
|
|
|
S_NORMAL (IMPX, 'M', 5, NULL , &States[1]),
|
|
|
|
S_NORMAL (IMPX, 'N', 700, NULL , &States[2]),
|
|
|
|
S_NORMAL (IMPX, 'O', 700, NULL , NULL)
|
|
|
|
};
|
|
|
|
|
|
|
|
IMPLEMENT_ACTOR (AHereticImpChunk1, Heretic, -1, 0)
|
|
|
|
PROP_Mass (5)
|
|
|
|
PROP_Radius (4)
|
|
|
|
|
|
|
|
PROP_SpawnState (0)
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
// Heretic imp chunk 2 ------------------------------------------------------
|
|
|
|
|
|
|
|
class AHereticImpChunk2 : public AActor
|
|
|
|
{
|
|
|
|
DECLARE_ACTOR (AHereticImpChunk2, AActor)
|
|
|
|
};
|
|
|
|
|
|
|
|
FState AHereticImpChunk2::States[] =
|
|
|
|
{
|
|
|
|
S_NORMAL (IMPX, 'P', 5, NULL , &States[1]),
|
|
|
|
S_NORMAL (IMPX, 'Q', 700, NULL , &States[2]),
|
|
|
|
S_NORMAL (IMPX, 'R', 700, NULL , NULL)
|
|
|
|
};
|
|
|
|
|
|
|
|
IMPLEMENT_ACTOR (AHereticImpChunk2, Heretic, -1, 0)
|
|
|
|
PROP_Mass (5)
|
|
|
|
PROP_Radius (4)
|
|
|
|
|
|
|
|
PROP_SpawnState (0)
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
// Heretic imp ball ---------------------------------------------------------
|
|
|
|
|
|
|
|
class AHereticImpBall : public AActor
|
|
|
|
{
|
|
|
|
DECLARE_ACTOR (AHereticImpBall, AActor)
|
|
|
|
};
|
|
|
|
|
|
|
|
FState AHereticImpBall::States[] =
|
|
|
|
{
|
|
|
|
#define S_IMPFX 0
|
|
|
|
S_BRIGHT (FX10, 'A', 6, NULL , &States[S_IMPFX+1]),
|
|
|
|
S_BRIGHT (FX10, 'B', 6, NULL , &States[S_IMPFX+2]),
|
|
|
|
S_BRIGHT (FX10, 'C', 6, NULL , &States[S_IMPFX+0]),
|
|
|
|
|
|
|
|
#define S_IMPFXI (S_IMPFX+3)
|
|
|
|
S_BRIGHT (FX10, 'D', 5, NULL , &States[S_IMPFXI+1]),
|
|
|
|
S_BRIGHT (FX10, 'E', 5, NULL , &States[S_IMPFXI+2]),
|
|
|
|
S_BRIGHT (FX10, 'F', 5, NULL , &States[S_IMPFXI+3]),
|
|
|
|
S_BRIGHT (FX10, 'G', 5, NULL , NULL)
|
|
|
|
};
|
|
|
|
|
|
|
|
IMPLEMENT_ACTOR (AHereticImpBall, Heretic, -1, 10)
|
|
|
|
PROP_RadiusFixed (8)
|
|
|
|
PROP_HeightFixed (8)
|
|
|
|
PROP_SpeedFixed (10)
|
|
|
|
PROP_Damage (1)
|
|
|
|
PROP_Flags (MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY)
|
|
|
|
PROP_Flags2 (MF2_WINDTHRUST|MF2_NOTELEPORT)
|
|
|
|
PROP_RenderStyle (STYLE_Add)
|
|
|
|
|
|
|
|
PROP_SpawnState (S_IMPFX)
|
|
|
|
PROP_DeathState (S_IMPFXI)
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
AT_SPEED_SET (HereticImpBall, speed)
|
|
|
|
{
|
|
|
|
SimpleSpeedSetter (AHereticImpBall, 10*FRACUNIT, 20*FRACUNIT, speed);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// PROC A_ImpExplode
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void A_ImpExplode (AActor *self)
|
|
|
|
{
|
|
|
|
AActor *chunk;
|
|
|
|
|
|
|
|
self->flags &= ~MF_NOGRAVITY;
|
|
|
|
|
2006-07-16 09:10:45 +00:00
|
|
|
chunk = Spawn<AHereticImpChunk1> (self->x, self->y, self->z, ALLOW_REPLACE);
|
2006-02-24 04:48:15 +00:00
|
|
|
chunk->momx = pr_imp.Random2 () << 10;
|
|
|
|
chunk->momy = pr_imp.Random2 () << 10;
|
|
|
|
chunk->momz = 9*FRACUNIT;
|
|
|
|
|
2006-07-16 09:10:45 +00:00
|
|
|
chunk = Spawn<AHereticImpChunk2> (self->x, self->y, self->z, ALLOW_REPLACE);
|
2006-02-24 04:48:15 +00:00
|
|
|
chunk->momx = pr_imp.Random2 () << 10;
|
|
|
|
chunk->momy = pr_imp.Random2 () << 10;
|
|
|
|
chunk->momz = 9*FRACUNIT;
|
|
|
|
if (self->special1 == 666)
|
|
|
|
{ // Extreme death crash
|
|
|
|
self->SetState (&AHereticImp::States[S_IMP_XCRASH]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// PROC A_ImpMeAttack
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void A_ImpMeAttack (AActor *self)
|
|
|
|
{
|
|
|
|
if (!self->target)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
S_SoundID (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
|
|
|
|
if (self->CheckMeleeRange ())
|
|
|
|
{
|
|
|
|
int damage = 5+(pr_impmeatk()&7);
|
2006-10-31 14:53:21 +00:00
|
|
|
P_DamageMobj (self->target, self, self, damage, NAME_Melee);
|
2006-02-24 04:48:15 +00:00
|
|
|
P_TraceBleed (damage, self->target, self);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// PROC A_ImpMsAttack
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void A_ImpMsAttack (AActor *self)
|
|
|
|
{
|
|
|
|
AActor *dest;
|
|
|
|
angle_t an;
|
|
|
|
int dist;
|
|
|
|
|
|
|
|
if (!self->target || pr_impmsatk() > 64)
|
|
|
|
{
|
|
|
|
self->SetState (self->SeeState);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
dest = self->target;
|
|
|
|
self->flags |= MF_SKULLFLY;
|
|
|
|
S_SoundID (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
|
|
|
|
A_FaceTarget (self);
|
|
|
|
an = self->angle >> ANGLETOFINESHIFT;
|
|
|
|
self->momx = FixedMul (12*FRACUNIT, finecosine[an]);
|
|
|
|
self->momy = FixedMul (12*FRACUNIT, finesine[an]);
|
|
|
|
dist = P_AproxDistance (dest->x - self->x, dest->y - self->y);
|
|
|
|
dist = dist/(12*FRACUNIT);
|
|
|
|
if (dist < 1)
|
|
|
|
{
|
|
|
|
dist = 1;
|
|
|
|
}
|
|
|
|
self->momz = (dest->z + (dest->height>>1) - self->z)/dist;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// PROC A_ImpMsAttack2
|
|
|
|
//
|
|
|
|
// Fireball attack of the imp leader.
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void A_ImpMsAttack2 (AActor *self)
|
|
|
|
{
|
|
|
|
if (!self->target)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
S_SoundID (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
|
|
|
|
if (self->CheckMeleeRange ())
|
|
|
|
{
|
|
|
|
int damage = 5+(pr_impmsatk2()&7);
|
2006-10-31 14:53:21 +00:00
|
|
|
P_DamageMobj (self->target, self, self, damage, NAME_Melee);
|
2006-02-24 04:48:15 +00:00
|
|
|
P_TraceBleed (damage, self->target, self);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
P_SpawnMissile (self, self->target, RUNTIME_CLASS(AHereticImpBall));
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// PROC A_ImpDeath
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void A_ImpDeath (AActor *self)
|
|
|
|
{
|
|
|
|
self->flags &= ~MF_SOLID;
|
|
|
|
self->flags2 |= MF2_FLOORCLIP;
|
|
|
|
if (self->z <= self->floorz)
|
|
|
|
{
|
|
|
|
//self->SetState (&AHereticImp::States[S_IMP_CRASH]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// PROC A_ImpXDeath1
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void A_ImpXDeath1 (AActor *self)
|
|
|
|
{
|
|
|
|
self->flags &= ~MF_SOLID;
|
|
|
|
self->flags |= MF_NOGRAVITY;
|
|
|
|
self->flags2 |= MF2_FLOORCLIP;
|
|
|
|
self->special1 = 666; // Flag the crash routine
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// PROC A_ImpXDeath2
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void A_ImpXDeath2 (AActor *self)
|
|
|
|
{
|
|
|
|
self->flags &= ~MF_NOGRAVITY;
|
|
|
|
if (self->z <= self->floorz)
|
|
|
|
{
|
|
|
|
self->SetState (&AHereticImp::States[S_IMP_CRASH]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|