2006-02-24 04:48:15 +00:00
|
|
|
#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 *);
|
|
|
|
|
|
|
|
// Lightning ----------------------------------------------------------------
|
|
|
|
|
2008-08-08 15:18:23 +00:00
|
|
|
class ALightning : public AActor
|
|
|
|
{
|
|
|
|
DECLARE_CLASS (ALightning, AActor)
|
|
|
|
public:
|
|
|
|
int SpecialMissileHit (AActor *victim);
|
|
|
|
};
|
|
|
|
|
2008-08-07 15:46:52 +00:00
|
|
|
IMPLEMENT_CLASS(ALightning)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
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))
|
|
|
|
{
|
2008-08-08 15:18:23 +00:00
|
|
|
P_DamageMobj(thing, this, target, 3, NAME_Electric);
|
2006-08-31 00:16:12 +00:00
|
|
|
if (!(S_IsActorPlayingSomething (this, CHAN_WEAPON, -1)))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lightning Zap ------------------------------------------------------------
|
|
|
|
|
|
|
|
class ALightningZap : public AActor
|
|
|
|
{
|
2008-08-07 15:46:52 +00:00
|
|
|
DECLARE_CLASS (ALightningZap, AActor)
|
2006-02-24 04:48:15 +00:00
|
|
|
public:
|
|
|
|
int SpecialMissileHit (AActor *thing);
|
|
|
|
};
|
|
|
|
|
2008-08-07 15:46:52 +00:00
|
|
|
IMPLEMENT_CLASS (ALightningZap)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2006-10-22 10:32:41 +00:00
|
|
|
P_ExplodeMissile(actor, NULL, NULL);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
actor->SetState (actor->FindState(NAME_Death));
|
2006-02-24 04:48:15 +00:00
|
|
|
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),
|
2006-07-16 09:10:45 +00:00
|
|
|
actor->z+deltaZ, ALLOW_REPLACE);
|
2006-02-24 04:48:15 +00:00
|
|
|
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;
|
|
|
|
|
2008-08-07 15:46:52 +00:00
|
|
|
fmo = P_SpawnPlayerMissile (actor, PClass::FindClass ("LightningFloor"));
|
|
|
|
cmo = P_SpawnPlayerMissile (actor, PClass::FindClass ("LightningCeiling"));
|
2006-02-24 04:48:15 +00:00
|
|
|
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)
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
if (mo->state >= mo->FindState(NAME_Death))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-22 10:32:41 +00:00
|
|
|
P_ExplodeMissile (actor, NULL, NULL);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
actor->momx = mo->momx;
|
|
|
|
actor->momy = mo->momy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_LastZap
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
void A_LastZap (AActor *actor)
|
|
|
|
{
|
|
|
|
AActor *mo;
|
|
|
|
|
2006-07-16 09:10:45 +00:00
|
|
|
mo = Spawn<ALightningZap> (actor->x, actor->y, actor->z, ALLOW_REPLACE);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (mo)
|
|
|
|
{
|
2008-08-07 15:46:52 +00:00
|
|
|
mo->SetState (mo->FindState ("Death"));
|
2006-02-24 04:48:15 +00:00
|
|
|
mo->momz = 40*FRACUNIT;
|
- 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
|
|
|
mo->Damage = 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_LightningRemove
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
void A_LightningRemove (AActor *actor)
|
|
|
|
{
|
|
|
|
AActor *mo;
|
|
|
|
|
|
|
|
mo = actor->lastenemy;
|
|
|
|
if (mo)
|
|
|
|
{
|
|
|
|
mo->lastenemy = NULL;
|
2006-10-22 10:32:41 +00:00
|
|
|
P_ExplodeMissile (mo, NULL, NULL);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|