mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-12-03 17:32:54 +00:00
- scriptified Hexen's Frost shards.
- scriptified all SpecialMissileHit methods.
This commit is contained in:
parent
5ce5466e18
commit
7b5a589635
10 changed files with 242 additions and 302 deletions
|
@ -667,7 +667,7 @@ public:
|
|||
// Called by PIT_CheckThing() and needed for some Hexen things.
|
||||
// Returns -1 for normal behavior, 0 to return false, and 1 to return true.
|
||||
// I'm not sure I like it this way, but it will do for now.
|
||||
virtual int SpecialMissileHit (AActor *victim);
|
||||
int SpecialMissileHit (AActor *victim);
|
||||
|
||||
// Returns true if it's okay to switch target to "other" after being attacked by it.
|
||||
virtual bool OkayToSwitchTarget (AActor *other);
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
// Include all the Hexen stuff here to reduce compile time
|
||||
#include "a_heresiarch.cpp"
|
||||
#include "a_magecone.cpp"
|
||||
#include "a_magelightning.cpp"
|
||||
#include "a_magestaff.cpp"
|
||||
#include "a_serpent.cpp"
|
||||
|
|
|
@ -1,185 +0,0 @@
|
|||
/*
|
||||
#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 "a_action.h"
|
||||
#include "p_pspr.h"
|
||||
#include "gstrings.h"
|
||||
#include "a_hexenglobal.h"
|
||||
#include "vm.h"
|
||||
*/
|
||||
|
||||
const int SHARDSPAWN_LEFT = 1;
|
||||
const int SHARDSPAWN_RIGHT = 2;
|
||||
const int SHARDSPAWN_UP = 4;
|
||||
const int SHARDSPAWN_DOWN = 8;
|
||||
|
||||
static FRandom pr_cone ("FireConePL1");
|
||||
|
||||
void A_FireConePL1 (AActor *actor);
|
||||
void A_ShedShard (AActor *);
|
||||
|
||||
// Frost Missile ------------------------------------------------------------
|
||||
|
||||
class AFrostMissile : public AActor
|
||||
{
|
||||
DECLARE_CLASS (AFrostMissile, AActor)
|
||||
public:
|
||||
int DoSpecialDamage (AActor *victim, int damage, FName damagetype);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(AFrostMissile, false, false)
|
||||
|
||||
int AFrostMissile::DoSpecialDamage (AActor *victim, int damage, FName damagetype)
|
||||
{
|
||||
if (special2 > 0)
|
||||
{
|
||||
damage <<= special2;
|
||||
}
|
||||
return damage;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_FireConePL1
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE(AActor);
|
||||
|
||||
DAngle angle;
|
||||
int damage;
|
||||
DAngle slope;
|
||||
int i;
|
||||
AActor *mo;
|
||||
bool conedone=false;
|
||||
player_t *player;
|
||||
FTranslatedLineTarget t;
|
||||
|
||||
if (NULL == (player = self->player))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
AWeapon *weapon = self->player->ReadyWeapon;
|
||||
if (weapon != NULL)
|
||||
{
|
||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
||||
return 0;
|
||||
}
|
||||
S_Sound (self, CHAN_WEAPON, "MageShardsFire", 1, ATTN_NORM);
|
||||
|
||||
damage = 90+(pr_cone()&15);
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
angle = self->Angles.Yaw + i*(45./16);
|
||||
slope = P_AimLineAttack (self, angle, MELEERANGE, &t, 0., ALF_CHECK3D);
|
||||
if (t.linetarget)
|
||||
{
|
||||
P_DamageMobj (t.linetarget, self, self, damage, NAME_Ice, DMG_USEANGLE, t.angleFromSource.Degrees);
|
||||
conedone = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// didn't find any creatures, so fire projectiles
|
||||
if (!conedone)
|
||||
{
|
||||
mo = P_SpawnPlayerMissile (self, RUNTIME_CLASS(AFrostMissile));
|
||||
if (mo)
|
||||
{
|
||||
mo->special1 = SHARDSPAWN_LEFT|SHARDSPAWN_DOWN|SHARDSPAWN_UP
|
||||
|SHARDSPAWN_RIGHT;
|
||||
mo->special2 = 3; // Set sperm count (levels of reproductivity)
|
||||
mo->target = self;
|
||||
mo->args[0] = 3; // Mark Initial shard as super damage
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_ShedShard
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_ShedShard)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
AActor *mo;
|
||||
int spawndir = self->special1;
|
||||
int spermcount = self->special2;
|
||||
|
||||
if (spermcount <= 0)
|
||||
{
|
||||
return 0; // No sperm left
|
||||
}
|
||||
self->special2 = 0;
|
||||
spermcount--;
|
||||
|
||||
// every so many calls, spawn a new missile in its set directions
|
||||
if (spawndir & SHARDSPAWN_LEFT)
|
||||
{
|
||||
mo = P_SpawnMissileAngleZSpeed(self, self->Z(), RUNTIME_CLASS(AFrostMissile),
|
||||
self->Angles.Yaw + 5, 0, (20. + 2 * spermcount), self->target);
|
||||
if (mo)
|
||||
{
|
||||
mo->special1 = SHARDSPAWN_LEFT;
|
||||
mo->special2 = spermcount;
|
||||
mo->Vel.Z = self->Vel.Z;
|
||||
mo->args[0] = (spermcount==3)?2:0;
|
||||
}
|
||||
}
|
||||
if (spawndir & SHARDSPAWN_RIGHT)
|
||||
{
|
||||
mo = P_SpawnMissileAngleZSpeed(self, self->Z(), RUNTIME_CLASS(AFrostMissile),
|
||||
self->Angles.Yaw - 5, 0, (20. + 2 * spermcount), self->target);
|
||||
if (mo)
|
||||
{
|
||||
mo->special1 = SHARDSPAWN_RIGHT;
|
||||
mo->special2 = spermcount;
|
||||
mo->Vel.Z = self->Vel.Z;
|
||||
mo->args[0] = (spermcount==3)?2:0;
|
||||
}
|
||||
}
|
||||
if (spawndir & SHARDSPAWN_UP)
|
||||
{
|
||||
mo = P_SpawnMissileAngleZSpeed(self, self->Z() + 8., RUNTIME_CLASS(AFrostMissile),
|
||||
self->Angles.Yaw, 0, (15. + 2 * spermcount), self->target);
|
||||
if (mo)
|
||||
{
|
||||
mo->Vel.Z = self->Vel.Z;
|
||||
if (spermcount & 1) // Every other reproduction
|
||||
mo->special1 = SHARDSPAWN_UP | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
|
||||
else
|
||||
mo->special1 = SHARDSPAWN_UP;
|
||||
mo->special2 = spermcount;
|
||||
mo->args[0] = (spermcount==3)?2:0;
|
||||
}
|
||||
}
|
||||
if (spawndir & SHARDSPAWN_DOWN)
|
||||
{
|
||||
mo = P_SpawnMissileAngleZSpeed(self, self->Z() - 4., RUNTIME_CLASS(AFrostMissile),
|
||||
self->Angles.Yaw, 0, (15. + 2 * spermcount), self->target);
|
||||
if (mo)
|
||||
{
|
||||
mo->Vel.Z = self->Vel.Z;
|
||||
if (spermcount & 1) // Every other reproduction
|
||||
mo->special1 = SHARDSPAWN_DOWN | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
|
||||
else
|
||||
mo->special1 = SHARDSPAWN_DOWN;
|
||||
mo->special2 = spermcount;
|
||||
mo->target = self->target;
|
||||
mo->args[0] = (spermcount==3)?2:0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -25,99 +25,6 @@ static FRandom pr_hit ("LightningHit");
|
|||
DECLARE_ACTION(A_LightningClip)
|
||||
DECLARE_ACTION(A_LightningZap)
|
||||
|
||||
// Lightning ----------------------------------------------------------------
|
||||
|
||||
class ALightning : public AActor
|
||||
{
|
||||
DECLARE_CLASS (ALightning, AActor)
|
||||
public:
|
||||
int SpecialMissileHit (AActor *victim);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ALightning, false, false)
|
||||
|
||||
int ALightning::SpecialMissileHit (AActor *thing)
|
||||
{
|
||||
if (thing->flags&MF_SHOOTABLE && thing != target)
|
||||
{
|
||||
if (thing->Mass != INT_MAX)
|
||||
{
|
||||
thing->Vel.X += Vel.X / 16;
|
||||
thing->Vel.Y += Vel.Y / 16;
|
||||
}
|
||||
if ((!thing->player && !(thing->flags2&MF2_BOSS))
|
||||
|| !(level.time&1))
|
||||
{
|
||||
P_DamageMobj(thing, this, target, 3, NAME_Electric);
|
||||
if (!(S_IsActorPlayingSomething (this, CHAN_WEAPON, -1)))
|
||||
{
|
||||
S_Sound (this, CHAN_WEAPON, this->AttackSound, 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
|
||||
{
|
||||
DECLARE_CLASS (ALightningZap, AActor)
|
||||
public:
|
||||
int SpecialMissileHit (AActor *thing);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(ALightningZap, false, false)
|
||||
|
||||
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
|
||||
|
|
|
@ -72,24 +72,11 @@ class AMageStaffFX2 : public AActor
|
|||
{
|
||||
DECLARE_CLASS(AMageStaffFX2, AActor)
|
||||
public:
|
||||
int SpecialMissileHit (AActor *victim);
|
||||
bool SpecialBlastHandling (AActor *source, double strength);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(AMageStaffFX2, false, false)
|
||||
|
||||
int AMageStaffFX2::SpecialMissileHit (AActor *victim)
|
||||
{
|
||||
if (victim != target &&
|
||||
!victim->player &&
|
||||
!(victim->flags2 & MF2_BOSS))
|
||||
{
|
||||
P_DamageMobj (victim, this, target, 10, NAME_Fire);
|
||||
return 1; // Keep going
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool AMageStaffFX2::SpecialBlastHandling (AActor *source, double strength)
|
||||
{
|
||||
// Reflect to originator
|
||||
|
|
|
@ -3357,6 +3357,7 @@ bool AActor::SpecialBlastHandling (AActor *source, double strength)
|
|||
}
|
||||
|
||||
// This only gets called from the script side so we do not need a native wrapper like for the other virtual methods.
|
||||
// This will be removed, once all actors overriding this method are exported.
|
||||
DEFINE_ACTION_FUNCTION(AActor, SpecialBlastHandling)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
@ -3365,10 +3366,20 @@ DEFINE_ACTION_FUNCTION(AActor, SpecialBlastHandling)
|
|||
ACTION_RETURN_BOOL(self->SpecialBlastHandling(source, strength));
|
||||
}
|
||||
|
||||
|
||||
// This virtual method only exists on the script side.
|
||||
int AActor::SpecialMissileHit (AActor *victim)
|
||||
{
|
||||
return -1;
|
||||
IFVIRTUAL(AActor, SpecialMissileHit)
|
||||
{
|
||||
VMValue params[2] = { (DObject*)this, victim };
|
||||
VMReturn ret;
|
||||
int retval;
|
||||
VMFrameStack stack;
|
||||
ret.IntAt(&retval);
|
||||
stack.Call(func, params, 2, &ret, 1, nullptr);
|
||||
return retval;
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
|
||||
bool AActor::AdjustReflectionAngle (AActor *thing, DAngle &angle)
|
||||
|
|
|
@ -6,6 +6,7 @@ class Actor : Thinker native
|
|||
const FLOATRANDZ = ONCEILINGZ-1;
|
||||
const TELEFRAG_DAMAGE = 1000000;
|
||||
const MinVel = 1./65536;
|
||||
const LARGE_MASS = 10000000; // not INT_MAX on purpose
|
||||
|
||||
|
||||
// flags are not defined here, the native fields for those get synthesized from the internal tables.
|
||||
|
@ -268,6 +269,11 @@ class Actor : Thinker native
|
|||
virtual native bool UseInventory(Inventory item);
|
||||
virtual native bool SpecialBlastHandling (Actor source, double strength);
|
||||
|
||||
virtual int SpecialMissileHit (Actor victim) // for this no native version exists
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
native static double GetDefaultSpeed(class<Actor> type);
|
||||
native static class<Actor> GetSpawnableType(int spawnnum);
|
||||
|
|
|
@ -17,8 +17,6 @@ class MWeapFrost : MageWeapon
|
|||
Tag "$TAG_MWEAPFROST";
|
||||
}
|
||||
|
||||
action native void A_FireConePL1();
|
||||
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
|
@ -45,12 +43,68 @@ class MWeapFrost : MageWeapon
|
|||
CONE A 10 A_ReFire;
|
||||
Goto Ready;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_FireConePL1
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
action void A_FireConePL1()
|
||||
{
|
||||
bool conedone=false;
|
||||
FTranslatedLineTarget t;
|
||||
|
||||
if (player == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Weapon weapon = player.ReadyWeapon;
|
||||
if (weapon != null)
|
||||
{
|
||||
if (!weapon.DepleteAmmo (weapon.bAltFire))
|
||||
return;
|
||||
}
|
||||
A_PlaySound ("MageShardsFire", CHAN_WEAPON);
|
||||
|
||||
int damage = 90+(random[MageCone]() & 15);
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
double ang = angle + i*(45./16);
|
||||
double slope = AimLineAttack (ang, MELEERANGE, t, 0., ALF_CHECK3D);
|
||||
if (t.linetarget)
|
||||
{
|
||||
t.linetarget.DamageMobj (self, self, damage, 'Ice', DMG_USEANGLE, t.angleFromSource);
|
||||
conedone = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// didn't find any creatures, so fire projectiles
|
||||
if (!conedone)
|
||||
{
|
||||
Actor mo = SpawnPlayerMissile ("FrostMissile");
|
||||
if (mo)
|
||||
{
|
||||
mo.special1 = FrostMissile.SHARDSPAWN_LEFT|FrostMissile.SHARDSPAWN_DOWN|FrostMissile.SHARDSPAWN_UP|FrostMissile.SHARDSPAWN_RIGHT;
|
||||
mo.special2 = 3; // Set sperm count (levels of reproductivity)
|
||||
mo.target = self;
|
||||
mo.args[0] = 3; // Mark Initial shard as super damage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Frost Missile ------------------------------------------------------------
|
||||
|
||||
class FrostMissile : Actor native
|
||||
class FrostMissile : Actor
|
||||
{
|
||||
const SHARDSPAWN_LEFT = 1;
|
||||
const SHARDSPAWN_RIGHT = 2;
|
||||
const SHARDSPAWN_UP = 4;
|
||||
const SHARDSPAWN_DOWN = 8;
|
||||
|
||||
Default
|
||||
{
|
||||
Speed 25;
|
||||
|
@ -63,8 +117,6 @@ class FrostMissile : Actor native
|
|||
Obituary "$OB_MPMWEAPFROST";
|
||||
}
|
||||
|
||||
native void A_ShedShard();
|
||||
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
|
@ -77,6 +129,88 @@ class FrostMissile : Actor native
|
|||
SHEX ABCDE 5 Bright;
|
||||
Stop;
|
||||
}
|
||||
|
||||
override int DoSpecialDamage (Actor victim, int damage, Name damagetype)
|
||||
{
|
||||
if (special2 > 0)
|
||||
{
|
||||
damage <<= special2;
|
||||
}
|
||||
return damage;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_ShedShard
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_ShedShard()
|
||||
{
|
||||
int spawndir = special1;
|
||||
int spermcount = special2;
|
||||
Actor mo;
|
||||
|
||||
if (spermcount <= 0)
|
||||
{
|
||||
return; // No sperm left
|
||||
}
|
||||
special2 = 0;
|
||||
spermcount--;
|
||||
|
||||
// every so many calls, spawn a new missile in its set directions
|
||||
if (spawndir & SHARDSPAWN_LEFT)
|
||||
{
|
||||
mo = SpawnMissileAngleZSpeed(pos.z, "FrostMissile", angle + 5, 0, (20. + 2 * spermcount), target);
|
||||
if (mo)
|
||||
{
|
||||
mo.special1 = SHARDSPAWN_LEFT;
|
||||
mo.special2 = spermcount;
|
||||
mo.Vel.Z = Vel.Z;
|
||||
mo.args[0] = (spermcount==3)?2:0;
|
||||
}
|
||||
}
|
||||
if (spawndir & SHARDSPAWN_RIGHT)
|
||||
{
|
||||
mo = SpawnMissileAngleZSpeed(pos.z, "FrostMissile", angle - 5, 0, (20. + 2 * spermcount), target);
|
||||
if (mo)
|
||||
{
|
||||
mo.special1 = SHARDSPAWN_RIGHT;
|
||||
mo.special2 = spermcount;
|
||||
mo.Vel.Z = Vel.Z;
|
||||
mo.args[0] = (spermcount==3)?2:0;
|
||||
}
|
||||
}
|
||||
if (spawndir & SHARDSPAWN_UP)
|
||||
{
|
||||
mo = SpawnMissileAngleZSpeed(pos.z + 8., "FrostMissile", angle, 0, (15. + 2 * spermcount), target);
|
||||
if (mo)
|
||||
{
|
||||
mo.Vel.Z = Vel.Z;
|
||||
if (spermcount & 1) // Every other reproduction
|
||||
mo.special1 = SHARDSPAWN_UP | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
|
||||
else
|
||||
mo.special1 = SHARDSPAWN_UP;
|
||||
mo.special2 = spermcount;
|
||||
mo.args[0] = (spermcount==3)?2:0;
|
||||
}
|
||||
}
|
||||
if (spawndir & SHARDSPAWN_DOWN)
|
||||
{
|
||||
mo = SpawnMissileAngleZSpeed(pos.z - 4., "FrostMissile", angle, 0, (15. + 2 * spermcount), target);
|
||||
if (mo)
|
||||
{
|
||||
mo.Vel.Z = Vel.Z;
|
||||
if (spermcount & 1) // Every other reproduction
|
||||
mo.special1 = SHARDSPAWN_DOWN | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
|
||||
else
|
||||
mo.special1 = SHARDSPAWN_DOWN;
|
||||
mo.special2 = spermcount;
|
||||
mo.target = target;
|
||||
mo.args[0] = (spermcount==3)?2:0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ice Shard ----------------------------------------------------------------
|
||||
|
|
|
@ -54,7 +54,7 @@ class MWeapLightning : MageWeapon
|
|||
|
||||
// Ceiling Lightning --------------------------------------------------------
|
||||
|
||||
class Lightning : Actor native
|
||||
class Lightning : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
|
@ -63,6 +63,45 @@ class Lightning : Actor native
|
|||
ActiveSound "MageLightningContinuous";
|
||||
Obituary "$OB_MPMWEAPLIGHTNING";
|
||||
}
|
||||
|
||||
override int SpecialMissileHit (Actor thing)
|
||||
{
|
||||
if (thing.bShootable && thing != target)
|
||||
{
|
||||
if (thing.Mass < LARGE_MASS)
|
||||
{
|
||||
thing.Vel.X += Vel.X / 16;
|
||||
thing.Vel.Y += Vel.Y / 16;
|
||||
}
|
||||
if ((!thing.player && !thing.bBoss) || !(level.time&1))
|
||||
{
|
||||
thing.DamageMobj(self, target, 3, 'Electric');
|
||||
A_PlaySound(self.AttackSound, CHAN_WEAPON, 1, true);
|
||||
if (thing.bIsMonster && random[LightningHit]() < 64)
|
||||
{
|
||||
thing.Howl ();
|
||||
}
|
||||
}
|
||||
health--;
|
||||
if (health <= 0 || thing.health <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (bFloorHugger)
|
||||
{
|
||||
if (lastenemy && ! lastenemy.tracer)
|
||||
{
|
||||
lastenemy.tracer = thing;
|
||||
}
|
||||
}
|
||||
else if (!tracer)
|
||||
{
|
||||
tracer = thing;
|
||||
}
|
||||
}
|
||||
return 1; // lightning zaps through all sprites
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class LightningCeiling : Lightning
|
||||
|
@ -141,7 +180,7 @@ class LightningFloor : LightningCeiling
|
|||
|
||||
// Lightning Zap ------------------------------------------------------------
|
||||
|
||||
class LightningZap : Actor native
|
||||
class LightningZap : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
|
@ -166,4 +205,34 @@ class LightningZap : Actor native
|
|||
MLFX NOPQRSTU 2 Bright;
|
||||
Stop;
|
||||
}
|
||||
|
||||
override int SpecialMissileHit (Actor thing)
|
||||
{
|
||||
Actor lmo;
|
||||
|
||||
if (thing.bShootable && thing != target)
|
||||
{
|
||||
lmo = lastenemy;
|
||||
if (lmo)
|
||||
{
|
||||
if (lmo.bFloorHugger)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -157,4 +157,16 @@ class MageStaffFX2 : Actor native
|
|||
MSP2 I 4 Bright;
|
||||
Stop;
|
||||
}
|
||||
|
||||
override int SpecialMissileHit (Actor victim)
|
||||
{
|
||||
if (victim != target && !victim.player && !victim.bBoss)
|
||||
{
|
||||
victim.DamageMobj (self, target, 10, 'Fire');
|
||||
return 1; // Keep going
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue