2008-09-15 14:11:05 +00:00
|
|
|
/*
|
2006-02-24 04:48:15 +00:00
|
|
|
#include "actor.h"
|
|
|
|
#include "info.h"
|
|
|
|
#include "m_random.h"
|
|
|
|
#include "s_sound.h"
|
|
|
|
#include "p_local.h"
|
|
|
|
#include "p_enemy.h"
|
|
|
|
#include "a_action.h"
|
|
|
|
#include "gstrings.h"
|
2008-08-10 20:48:55 +00:00
|
|
|
#include "thingdef/thingdef.h"
|
2008-09-14 23:54:38 +00:00
|
|
|
#include "g_level.h"
|
2008-09-15 14:11:05 +00:00
|
|
|
*/
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
static FRandom pr_foo ("WhirlwindDamage");
|
|
|
|
static FRandom pr_atk ("LichAttack");
|
|
|
|
static FRandom pr_seek ("WhirlwindSeek");
|
|
|
|
|
|
|
|
class AWhirlwind : public AActor
|
|
|
|
{
|
2008-07-21 17:03:30 +00:00
|
|
|
DECLARE_CLASS (AWhirlwind, AActor)
|
2006-02-24 04:48:15 +00:00
|
|
|
public:
|
|
|
|
int DoSpecialDamage (AActor *target, int damage);
|
|
|
|
};
|
|
|
|
|
2008-07-21 17:03:30 +00:00
|
|
|
IMPLEMENT_CLASS(AWhirlwind)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
int AWhirlwind::DoSpecialDamage (AActor *target, int damage)
|
|
|
|
{
|
|
|
|
int randVal;
|
|
|
|
|
|
|
|
target->angle += pr_foo.Random2() << 20;
|
2009-06-30 20:57:51 +00:00
|
|
|
target->velx += pr_foo.Random2() << 10;
|
|
|
|
target->vely += pr_foo.Random2() << 10;
|
2006-02-24 04:48:15 +00:00
|
|
|
if ((level.time & 16) && !(target->flags2 & MF2_BOSS))
|
|
|
|
{
|
|
|
|
randVal = pr_foo();
|
|
|
|
if (randVal > 160)
|
|
|
|
{
|
|
|
|
randVal = 160;
|
|
|
|
}
|
2009-06-30 20:57:51 +00:00
|
|
|
target->velz += randVal << 11;
|
|
|
|
if (target->velz > 12*FRACUNIT)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2009-06-30 20:57:51 +00:00
|
|
|
target->velz = 12*FRACUNIT;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!(level.time & 7))
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
P_DamageMobj (target, NULL, this->target, 3, NAME_Melee);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// PROC A_LichAttack
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_LichAttack)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2010-02-12 06:04:57 +00:00
|
|
|
PARAM_ACTION_PROLOGUE;
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
int i;
|
|
|
|
AActor *fire;
|
|
|
|
AActor *baseFire;
|
|
|
|
AActor *mo;
|
|
|
|
AActor *target;
|
|
|
|
int randAttack;
|
|
|
|
static const int atkResolve1[] = { 50, 150 };
|
|
|
|
static const int atkResolve2[] = { 150, 200 };
|
|
|
|
int dist;
|
|
|
|
|
|
|
|
// Ice ball (close 20% : far 60%)
|
|
|
|
// Fire column (close 40% : far 20%)
|
|
|
|
// Whirlwind (close 40% : far 20%)
|
|
|
|
// Distance threshold = 8 cells
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
target = self->target;
|
2006-02-24 04:48:15 +00:00
|
|
|
if (target == NULL)
|
|
|
|
{
|
2010-02-12 06:04:57 +00:00
|
|
|
return 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
A_FaceTarget (self);
|
|
|
|
if (self->CheckMeleeRange ())
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
int damage = pr_atk.HitDice (6);
|
2008-08-10 20:48:55 +00:00
|
|
|
P_DamageMobj (target, self, self, damage, NAME_Melee);
|
|
|
|
P_TraceBleed (damage, target, self);
|
2010-02-12 06:04:57 +00:00
|
|
|
return 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
dist = P_AproxDistance (self->x-target->x, self->y-target->y)
|
2006-02-24 04:48:15 +00:00
|
|
|
> 8*64*FRACUNIT;
|
|
|
|
randAttack = pr_atk ();
|
|
|
|
if (randAttack < atkResolve1[dist])
|
|
|
|
{ // Ice ball
|
2008-08-10 20:48:55 +00:00
|
|
|
P_SpawnMissile (self, target, PClass::FindClass("HeadFX1"));
|
|
|
|
S_Sound (self, CHAN_BODY, "ironlich/attack2", 1, ATTN_NORM);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else if (randAttack < atkResolve2[dist])
|
|
|
|
{ // Fire column
|
2008-08-10 20:48:55 +00:00
|
|
|
baseFire = P_SpawnMissile (self, target, PClass::FindClass("HeadFX3"));
|
2006-02-24 04:48:15 +00:00
|
|
|
if (baseFire != NULL)
|
|
|
|
{
|
2008-07-21 17:03:30 +00:00
|
|
|
baseFire->SetState (baseFire->FindState("NoGrow"));
|
2006-02-24 04:48:15 +00:00
|
|
|
for (i = 0; i < 5; i++)
|
|
|
|
{
|
2008-07-21 17:03:30 +00:00
|
|
|
fire = Spawn("HeadFX3", baseFire->x, baseFire->y,
|
2006-07-16 09:10:45 +00:00
|
|
|
baseFire->z, ALLOW_REPLACE);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (i == 0)
|
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
S_Sound (self, CHAN_BODY, "ironlich/attack1", 1, ATTN_NORM);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
fire->target = baseFire->target;
|
|
|
|
fire->angle = baseFire->angle;
|
2009-06-30 20:57:51 +00:00
|
|
|
fire->velx = baseFire->velx;
|
|
|
|
fire->vely = baseFire->vely;
|
|
|
|
fire->velz = baseFire->velz;
|
- 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
|
|
|
fire->Damage = 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
fire->health = (i+1) * 2;
|
|
|
|
P_CheckMissileSpawn (fire);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // Whirlwind
|
2008-08-10 20:48:55 +00:00
|
|
|
mo = P_SpawnMissile (self, target, RUNTIME_CLASS(AWhirlwind));
|
2006-02-24 04:48:15 +00:00
|
|
|
if (mo != NULL)
|
|
|
|
{
|
|
|
|
mo->z -= 32*FRACUNIT;
|
|
|
|
mo->tracer = target;
|
|
|
|
mo->special1 = 60;
|
|
|
|
mo->special2 = 50; // Timer for active sound
|
|
|
|
mo->health = 20*TICRATE; // Duration
|
2008-08-10 20:48:55 +00:00
|
|
|
S_Sound (self, CHAN_BODY, "ironlich/attack3", 1, ATTN_NORM);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
2010-02-12 06:04:57 +00:00
|
|
|
return 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// PROC A_WhirlwindSeek
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_WhirlwindSeek)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2010-02-12 06:04:57 +00:00
|
|
|
PARAM_ACTION_PROLOGUE;
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
self->health -= 3;
|
|
|
|
if (self->health < 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2009-06-30 20:57:51 +00:00
|
|
|
self->velx = self->vely = self->velz = 0;
|
2008-08-10 20:48:55 +00:00
|
|
|
self->SetState (self->FindState(NAME_Death));
|
|
|
|
self->flags &= ~MF_MISSILE;
|
2010-02-12 06:04:57 +00:00
|
|
|
return 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
if ((self->special2 -= 3) < 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
self->special2 = 58 + (pr_seek() & 31);
|
|
|
|
S_Sound (self, CHAN_BODY, "ironlich/attack3", 1, ATTN_NORM);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
if (self->tracer && self->tracer->flags&MF_SHADOW)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2010-02-12 06:04:57 +00:00
|
|
|
return 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
P_SeekerMissile (self, ANGLE_1*10, ANGLE_1*30);
|
2010-02-12 06:04:57 +00:00
|
|
|
return 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// PROC A_LichIceImpact
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_LichIceImpact)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2010-02-12 06:04:57 +00:00
|
|
|
PARAM_ACTION_PROLOGUE;
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
int i;
|
|
|
|
angle_t angle;
|
|
|
|
AActor *shard;
|
|
|
|
|
|
|
|
for (i = 0; i < 8; i++)
|
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
shard = Spawn("HeadFX2", self->x, self->y, self->z, ALLOW_REPLACE);
|
2006-02-24 04:48:15 +00:00
|
|
|
angle = i*ANG45;
|
2008-08-10 20:48:55 +00:00
|
|
|
shard->target = self->target;
|
2006-02-24 04:48:15 +00:00
|
|
|
shard->angle = angle;
|
|
|
|
angle >>= ANGLETOFINESHIFT;
|
2009-06-30 20:57:51 +00:00
|
|
|
shard->velx = FixedMul (shard->Speed, finecosine[angle]);
|
|
|
|
shard->vely = FixedMul (shard->Speed, finesine[angle]);
|
|
|
|
shard->velz = -FRACUNIT*6/10;
|
2006-02-24 04:48:15 +00:00
|
|
|
P_CheckMissileSpawn (shard);
|
|
|
|
}
|
2010-02-12 06:04:57 +00:00
|
|
|
return 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// PROC A_LichFireGrow
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_LichFireGrow)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2010-02-12 06:04:57 +00:00
|
|
|
PARAM_ACTION_PROLOGUE;
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
self->health--;
|
|
|
|
self->z += 9*FRACUNIT;
|
|
|
|
if (self->health == 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
self->Damage = self->GetDefault()->Damage;
|
|
|
|
self->SetState (self->FindState("NoGrow"));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2010-02-12 06:04:57 +00:00
|
|
|
return 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|