- scriptified D'Sparil.

- added retrieval of defaults from an actor pointer.
This commit is contained in:
Christoph Oelckers 2016-11-24 01:23:35 +01:00
parent cd919e72e1
commit 3e890d182b
14 changed files with 349 additions and 406 deletions

View file

@ -857,7 +857,6 @@ set( NOT_COMPILED_SOURCE_FILES
${OTHER_SYSTEM_SOURCES}
sc_man_scanner.h
sc_man_scanner.re
g_heretic/a_dsparil.cpp
g_heretic/a_hereticartifacts.cpp
g_heretic/a_hereticweaps.cpp
g_hexen/a_blastradius.cpp

View file

@ -1,327 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "p_local.h"
#include "p_enemy.h"
#include "a_action.h"
#include "s_sound.h"
#include "m_random.h"
#include "a_sharedglobal.h"
#include "gstrings.h"
#include "a_specialspot.h"
#include "vm.h"
#include "g_level.h"
*/
static FRandom pr_s2fx1 ("S2FX1");
static FRandom pr_scrc1atk ("Srcr1Attack");
static FRandom pr_dst ("D'SparilTele");
static FRandom pr_s2d ("Srcr2Decide");
static FRandom pr_s2a ("Srcr2Attack");
static FRandom pr_bluespark ("BlueSpark");
//----------------------------------------------------------------------------
//
// PROC A_Sor1Pain
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Sor1Pain)
{
PARAM_SELF_PROLOGUE(AActor);
self->special1 = 20; // Number of steps to walk fast
CALL_ACTION(A_Pain, self);
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_Sor1Chase
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Sor1Chase)
{
PARAM_SELF_PROLOGUE(AActor);
if (self->special1)
{
self->special1--;
self->tics -= 3;
}
A_Chase(stack, self);
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_Srcr1Attack
//
// Sorcerer demon attack.
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Srcr1Attack)
{
PARAM_SELF_PROLOGUE(AActor);
AActor *mo;
DAngle angle;
if (!self->target)
{
return 0;
}
S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NORM);
if (self->CheckMeleeRange ())
{
int damage = pr_scrc1atk.HitDice (8);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
return 0;
}
PClassActor *fx = PClass::FindActor("SorcererFX1");
if (self->health > (self->SpawnHealth()/3)*2)
{ // Spit one fireball
P_SpawnMissileZ (self, self->Z() + 48, self->target, fx );
}
else
{ // Spit three fireballs
mo = P_SpawnMissileZ (self, self->Z() + 48, self->target, fx);
if (mo != NULL)
{
angle = mo->Angles.Yaw;
P_SpawnMissileAngleZ(self, self->Z() + 48, fx, angle - 3, mo->Vel.Z);
P_SpawnMissileAngleZ(self, self->Z() + 48, fx, angle + 3, mo->Vel.Z);
}
if (self->health < self->SpawnHealth()/3)
{ // Maybe attack again
if (self->special1)
{ // Just attacked, so don't attack again
self->special1 = 0;
}
else
{ // Set state to attack again
self->special1 = 1;
self->SetState (self->FindState("Missile2"));
}
}
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_SorcererRise
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_SorcererRise)
{
PARAM_SELF_PROLOGUE(AActor);
AActor *mo;
self->flags &= ~MF_SOLID;
mo = Spawn("Sorcerer2", self->Pos(), ALLOW_REPLACE);
mo->Translation = self->Translation;
mo->SetState (mo->FindState("Rise"));
mo->Angles.Yaw = self->Angles.Yaw;
mo->CopyFriendliness (self, true);
return 0;
}
//----------------------------------------------------------------------------
//
// PROC P_DSparilTeleport
//
//----------------------------------------------------------------------------
void P_DSparilTeleport (AActor *actor)
{
DVector3 prev;
AActor *mo;
AActor *spot;
DSpotState *state = DSpotState::GetSpotState();
if (state == NULL) return;
spot = state->GetSpotWithMinMaxDistance(PClass::FindActor("BossSpot"), actor->X(), actor->Y(), 128, 0);
if (spot == NULL) return;
prev = actor->Pos();
if (P_TeleportMove (actor, spot->Pos(), false))
{
mo = Spawn("Sorcerer2Telefade", prev, ALLOW_REPLACE);
if (mo) mo->Translation = actor->Translation;
S_Sound (mo, CHAN_BODY, "misc/teleport", 1, ATTN_NORM);
actor->SetState (actor->FindState("Teleport"));
S_Sound (actor, CHAN_BODY, "misc/teleport", 1, ATTN_NORM);
actor->SetZ(actor->floorz);
actor->Angles.Yaw = spot->Angles.Yaw;
actor->Vel.Zero();
}
}
//----------------------------------------------------------------------------
//
// PROC A_Srcr2Decide
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Decide)
{
PARAM_SELF_PROLOGUE(AActor);
static const int chance[] =
{
192, 120, 120, 120, 64, 64, 32, 16, 0
};
unsigned int chanceindex = self->health / ((self->SpawnHealth()/8 == 0) ? 1 : self->SpawnHealth()/8);
if (chanceindex >= countof(chance))
{
chanceindex = countof(chance) - 1;
}
if (pr_s2d() < chance[chanceindex])
{
P_DSparilTeleport (self);
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_Srcr2Attack
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Attack)
{
PARAM_SELF_PROLOGUE(AActor);
int chance;
if (!self->target)
{
return 0;
}
S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NONE);
if (self->CheckMeleeRange())
{
int damage = pr_s2a.HitDice (20);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
return 0;
}
chance = self->health < self->SpawnHealth()/2 ? 96 : 48;
if (pr_s2a() < chance)
{ // Wizard spawners
PClassActor *fx = PClass::FindActor("Sorcerer2FX2");
if (fx)
{
P_SpawnMissileAngle(self, fx, self->Angles.Yaw - 45, 0.5);
P_SpawnMissileAngle(self, fx, self->Angles.Yaw + 45, 0.5);
}
}
else
{ // Blue bolt
P_SpawnMissile (self, self->target, PClass::FindActor("Sorcerer2FX1"));
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_BlueSpark
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_BlueSpark)
{
PARAM_SELF_PROLOGUE(AActor);
int i;
AActor *mo;
for (i = 0; i < 2; i++)
{
mo = Spawn("Sorcerer2FXSpark", self->Pos(), ALLOW_REPLACE);
mo->Vel.X = pr_bluespark.Random2() / 128.;
mo->Vel.Y = pr_bluespark.Random2() / 128.;
mo->Vel.Z = 1. + pr_bluespark() / 256.;
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_GenWizard
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_GenWizard)
{
PARAM_SELF_PROLOGUE(AActor);
AActor *mo;
mo = Spawn("Wizard", self->Pos(), ALLOW_REPLACE);
if (mo != NULL)
{
mo->AddZ(-mo->GetDefault()->Height / 2, false);
if (!P_TestMobjLocation (mo))
{ // Didn't fit
mo->ClearCounters();
mo->Destroy ();
}
else
{ // [RH] Make the new wizards inherit D'Sparil's target
mo->CopyFriendliness (self->target, true);
self->Vel.Zero();
self->SetState (self->FindState(NAME_Death));
self->flags &= ~MF_MISSILE;
mo->master = self->target;
P_SpawnTeleportFog(self, self->Pos(), false, true);
}
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_Sor2DthInit
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Sor2DthInit)
{
PARAM_SELF_PROLOGUE(AActor);
self->special1 = 7; // Animation loop counter
P_Massacre (); // Kill monsters early
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_Sor2DthLoop
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Sor2DthLoop)
{
PARAM_SELF_PROLOGUE(AActor);
if (--self->special1)
{ // Need to loop
self->SetState (self->FindState("DeathLoop"));
}
return 0;
}

View file

@ -19,6 +19,5 @@
#include "serializer.h"
// Include all the other Heretic stuff here to reduce compile time
#include "a_dsparil.cpp"
#include "a_hereticartifacts.cpp"
#include "a_hereticweaps.cpp"

View file

@ -27,7 +27,6 @@ static FRandom pr_bfx1 ("BlasterFX1");
static FRandom pr_ripd ("RipperD");
static FRandom pr_fb1 ("FireBlasterPL1");
static FRandom pr_bfx1t ("BlasterFX1Tick");
static FRandom pr_hrfx2 ("HornRodFX2");
static FRandom pr_rp ("RainPillar");
static FRandom pr_fsr1 ("FireSkullRodPL1");
static FRandom pr_storm ("SkullRodStorm");
@ -819,27 +818,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnRippers)
// --- Skull rod ------------------------------------------------------------
// Horn Rod FX 2 ------------------------------------------------------------
class AHornRodFX2 : public AActor
{
DECLARE_CLASS (AHornRodFX2, AActor)
public:
int DoSpecialDamage (AActor *target, int damage, FName damagetype);
};
IMPLEMENT_CLASS(AHornRodFX2, false, false, false, false)
int AHornRodFX2::DoSpecialDamage (AActor *target, int damage, FName damagetype)
{
if (target->IsKindOf (PClass::FindClass("Sorcerer2")) && pr_hrfx2() < 96)
{ // D'Sparil teleports away
P_DSparilTeleport (target);
return -1;
}
return damage;
}
// Rain pillar 1 ------------------------------------------------------------
class ARainPillar : public AActor
@ -940,7 +918,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL2)
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AHornRodFX2), self->Angles.Yaw, &t, &MissileActor);
P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("HornRodFX2"), self->Angles.Yaw, &t, &MissileActor);
// Use MissileActor instead of the return value from
// P_SpawnPlayerMissile because we need to give info to the mobj
// even if it exploded immediately.
@ -1170,25 +1148,6 @@ void APhoenixRodPowered::EndPowerup ()
P_SetPsprite(Owner->player, PSP_WEAPON, SisterWeapon->GetReadyState());
}
class APhoenixFX1 : public AActor
{
DECLARE_CLASS (APhoenixFX1, AActor)
public:
int DoSpecialDamage (AActor *target, int damage, FName damagetype);
};
IMPLEMENT_CLASS(APhoenixFX1, false, false, false, false)
int APhoenixFX1::DoSpecialDamage (AActor *target, int damage, FName damagetype)
{
if (target->IsKindOf (PClass::FindClass("Sorcerer2")) && pr_hrfx2() < 96)
{ // D'Sparil teleports away
P_DSparilTeleport (target);
return -1;
}
return damage;
}
// Phoenix FX 2 -------------------------------------------------------------
class APhoenixFX2 : public AActor
@ -1232,7 +1191,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL1)
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
P_SpawnPlayerMissile (self, RUNTIME_CLASS(APhoenixFX1));
P_SpawnPlayerMissile (self, PClass::FindActor("PhoenixFX1"));
self->Thrust(self->Angles.Yaw + 180, 4);
return 0;
}

View file

@ -344,6 +344,18 @@ ASpecialSpot *DSpotState::GetSpotWithMinMaxDistance(PClassActor *type, double x,
return NULL;
}
DEFINE_ACTION_FUNCTION(DSpotState, GetSpotWithMinMaxDistance)
{
PARAM_SELF_PROLOGUE(DSpotState);
PARAM_CLASS(type, AActor);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(mindist);
PARAM_FLOAT(maxdist);
ACTION_RETURN_OBJECT(self->GetSpotWithMinMaxDistance(type, x, y, mindist, maxdist));
}
//----------------------------------------------------------------------------
//
//

View file

@ -1777,6 +1777,11 @@ bool P_TestMobjLocation(AActor *mobj)
return false;
}
DEFINE_ACTION_FUNCTION(AActor, TestMobjLocation)
{
PARAM_SELF_PROLOGUE(AActor);
ACTION_RETURN_BOOL(P_TestMobjLocation(self));
}
//=============================================================================
//

View file

@ -6781,6 +6781,12 @@ int AActor::SpawnHealth() const
}
}
DEFINE_ACTION_FUNCTION(AActor, SpawnHealth)
{
PARAM_SELF_PROLOGUE(AActor);
ACTION_RETURN_INT(self->SpawnHealth());
}
FState *AActor::GetRaiseState()
{
if (!(flags & MF_CORPSE))

View file

@ -1449,19 +1449,6 @@ DEFINE_ACTION_FUNCTION(AActor, AimTarget)
ACTION_RETURN_OBJECT(P_AimTarget(self));
}
DEFINE_ACTION_FUNCTION(AActor, A_Light)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_INT(light);
if (self->player != NULL)
{
self->player->extralight = clamp<int>(light, -20, 20);
}
return 0;
}
//------------------------------------------------------------------------
//
// PROC P_SetupPsprites

View file

@ -96,6 +96,18 @@ void P_SpawnTeleportFog(AActor *mobj, const DVector3 &pos, bool beforeTele, bool
mo->target = mobj;
}
DEFINE_ACTION_FUNCTION(AActor, SpawnTeleportFog)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(z);
PARAM_BOOL(before);
PARAM_BOOL(settarget);
P_SpawnTeleportFog(self, DVector3(x, y, z), before, settarget);
return 0;
}
//
// TELEPORTATION
//

View file

@ -5593,6 +5593,22 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classct
PSymbol *sym;
PSymbolTable *symtbl;
bool isclass = objtype->IsKindOf(RUNTIME_CLASS(PClass));
if (Identifier == NAME_Default)
{
if (!objtype->IsKindOf(RUNTIME_CLASS(PClassActor)))
{
ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type.");
delete this;
return nullptr;
}
FxExpression * x = new FxClassDefaults(object, ScriptPosition);
object = nullptr;
delete this;
return x->Resolve(ctx);
}
if ((sym = objtype->Symbols.FindSymbolInTable(Identifier, symtbl)) != nullptr)
{
if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst)))

View file

@ -249,6 +249,7 @@ class Actor : Thinker native
native bool GiveBody (int num, int max=0);
native void RestoreDamage();
native int SpawnHealth();
native void SetDamage(int dmg);
native double Distance2D(Actor other);
native void SetOrigin(vector3 newpos, bool moving);
@ -259,17 +260,19 @@ class Actor : Thinker native
native Actor AimTarget();
native bool CheckMissileSpawn(double maxdist);
native bool CheckPosition(Vector2 pos, bool actorsonly = false);
native bool TestMobjLocation();
native static Actor Spawn(class<Actor> type, vector3 pos = (0,0,0), int replace = NO_REPLACE);
native Actor SpawnMissile(Actor dest, class<Actor> type, Actor owner = null);
native Actor SpawnMissileZ (double z, Actor dest, class<Actor> type);
native Actor SpawnMissileAngleZSpeed (double z, class<Actor> type, double angle, double vz, double speed, Actor owner = null, bool checkspawn = true);
native Actor, Actor SpawnPlayerMissile(class<Actor> type, double angle = 0, double x = 0, double y = 0, double z = 0, out FTranslatedLineTarget pLineTarget = null, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0);
native void SpawnTeleportFog(Vector3 pos, bool beforeTele, bool setTarget);
native void A_Light(int extralight);
void A_Light0() { A_Light(0); }
void A_Light1() { A_Light(1); }
void A_Light2() { A_Light(2); }
void A_LightInverse() { A_Light(0x80000000); }
void A_Light(int extralight) { if (player) player.extralight = clamp(extralight, -20, 20); }
void A_Light0() { if (player) player.extralight = 0; }
void A_Light1() { if (player) player.extralight = 1; }
void A_Light2() { if (player) player.extralight = 2; }
void A_LightInverse() { if (player) player.extralight = 0x80000000; }
native Actor OldSpawnMissile(Actor dest, class<Actor> type, Actor owner = null);
native Actor SpawnPuff(class<Actor> pufftype, vector3 pos, double hitdir, double particledir, int updown, int flags = 0, Actor vict = null);

View file

@ -49,6 +49,8 @@ class SpotState : Object native
{
native static SpotState GetSpotState();
native SpecialSpot GetNextInList(class<Actor> type, int skipcounter);
native SpecialSpot GetSpotWithMinMaxDistance(Class<Actor> type, double x, double y, double mindist, double maxdist);
}
struct LevelLocals native

View file

@ -38,10 +38,6 @@ class Sorcerer1 : Actor
HitObituary "$OB_DSPARIL1HIT";
}
native void A_Sor1Pain ();
native void A_Sor1Chase ();
native void A_Srcr1Attack ();
native void A_SorcererRise ();
States
{
@ -79,6 +75,104 @@ class Sorcerer1 : Actor
SRCR L 12;
SRCR P -1 A_SorcererRise;
}
//----------------------------------------------------------------------------
//
// PROC A_Sor1Pain
//
//----------------------------------------------------------------------------
void A_Sor1Pain ()
{
special1 = 20; // Number of steps to walk fast
A_Pain();
}
//----------------------------------------------------------------------------
//
// PROC A_Sor1Chase
//
//----------------------------------------------------------------------------
void A_Sor1Chase ()
{
if (special1)
{
special1--;
tics -= 3;
}
A_Chase();
}
//----------------------------------------------------------------------------
//
// PROC A_Srcr1Attack
//
// Sorcerer demon attack.
//
//----------------------------------------------------------------------------
void A_Srcr1Attack ()
{
if (!target)
{
return;
}
A_PlaySound (AttackSound, CHAN_BODY);
if (CheckMeleeRange ())
{
int damage = random[Srcr1Attack](1,8) * 8;
int newdam = target.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self);
return;
}
if (health > (SpawnHealth()/3)*2)
{ // Spit one fireball
SpawnMissileZ (pos.z + 48, target, "SorcererFX1");
}
else
{ // Spit three fireballs
Actor mo = SpawnMissileZ (pos.z + 48, target, "SorcererFX1");
if (mo != null)
{
double ang = mo.angle;
SpawnMissileAngleZ(pos.z + 48, "SorcererFX1", ang - 3, mo.Vel.Z);
SpawnMissileAngleZ(pos.z + 48, "SorcererFX1", ang + 3, mo.Vel.Z);
}
if (health < SpawnHealth()/3)
{ // Maybe attack again
if (special1)
{ // Just attacked, so don't attack again
special1 = 0;
}
else
{ // Set state to attack again
special1 = 1;
SetStateLabel("Missile2");
}
}
}
}
//----------------------------------------------------------------------------
//
// PROC A_SorcererRise
//
//----------------------------------------------------------------------------
void A_SorcererRise ()
{
bSolid = false;
Actor mo = Spawn("Sorcerer2", Pos, ALLOW_REPLACE);
mo.Translation = Translation;
mo.SetStateLabel("Rise");
mo.angle = angle;
mo.CopyFriendliness (self, true);
}
}
@ -142,10 +236,6 @@ class Sorcerer2 : Actor
HitObituary "$OB_DSPARIL2HIT";
}
native void A_Srcr2Decide ();
native void A_Srcr2Attack ();
native void A_Sor2DthInit ();
native void A_Sor2DthLoop ();
States
{
@ -189,6 +279,118 @@ class Sorcerer2 : Actor
SDTH O -1 A_BossDeath;
Stop;
}
//----------------------------------------------------------------------------
//
// PROC P_DSparilTeleport
//
//----------------------------------------------------------------------------
void DSparilTeleport ()
{
SpotState state = SpotState.GetSpotState();
if (state == null) return;
Actor spot = state.GetSpotWithMinMaxDistance("BossSpot", pos.x, pos.y, 128, 0);
if (spot == null) return;
Vector3 prev = Pos;
if (TeleportMove (spot.Pos, false))
{
Actor mo = Spawn("Sorcerer2Telefade", prev, ALLOW_REPLACE);
if (mo)
{
mo.Translation = Translation;
mo.A_PlaySound("misc/teleport", CHAN_BODY);
}
SetStateLabel ("Teleport");
A_PlaySound ("misc/teleport", CHAN_BODY);
SetZ(floorz);
angle = spot.angle;
vel = (0,0,0);
}
}
//----------------------------------------------------------------------------
//
// PROC A_Srcr2Decide
//
//----------------------------------------------------------------------------
void A_Srcr2Decide ()
{
static const int chance[] =
{
192, 120, 120, 120, 64, 64, 32, 16, 0
};
int health8 = max(1, SpawnHealth() / 8);
int chanceindex = min(8, health / health8);
if (random[Srcr2Decide]() < chance[chanceindex])
{
DSparilTeleport ();
}
}
//----------------------------------------------------------------------------
//
// PROC A_Srcr2Attack
//
//----------------------------------------------------------------------------
void A_Srcr2Attack ()
{
if (!target)
{
return;
}
A_PlaySound (AttackSound, CHAN_BODY);
if (CheckMeleeRange())
{
int damage = random[Srcr2Atk](1, 8) * 20;
int newdam = target.DamageMobj (self, self, damage, 'Melee');
target.TraceBleed (newdam > 0 ? newdam : damage, self);
return;
}
int chance = health < SpawnHealth()/2 ? 96 : 48;
if (random[Srcr2Atk]() < chance)
{ // Wizard spawners
SpawnMissileAngle("Sorcerer2FX2", Angle - 45, 0.5);
SpawnMissileAngle("Sorcerer2FX2", Angle + 45, 0.5);
}
else
{ // Blue bolt
SpawnMissile (target, "Sorcerer2FX1");
}
}
//----------------------------------------------------------------------------
//
// PROC A_Sor2DthInit
//
//----------------------------------------------------------------------------
void A_Sor2DthInit ()
{
special1 = 7; // Animation loop counter
Thing_Destroy(0); // Kill monsters early
}
//----------------------------------------------------------------------------
//
// PROC A_Sor2DthLoop
//
//----------------------------------------------------------------------------
void A_Sor2DthLoop ()
{
if (--special1)
{ // Need to loop
SetStateLabel("DeathLoop");
}
}
}
@ -210,8 +412,6 @@ class Sorcerer2FX1 : Actor
RenderStyle "Add";
}
native void A_BlueSpark ();
States
{
Spawn:
@ -222,6 +422,23 @@ class Sorcerer2FX1 : Actor
FX16 HIJKL 5 BRIGHT;
Stop;
}
//----------------------------------------------------------------------------
//
// PROC A_BlueSpark
//
//----------------------------------------------------------------------------
void A_BlueSpark ()
{
for (int i = 0; i < 2; i++)
{
Actor mo = Spawn("Sorcerer2FXSpark", pos, ALLOW_REPLACE);
mo.Vel.X = Random2[BlueSpark]() / 128.;
mo.Vel.Y = Random2[BlueSpark]() / 128.;
mo.Vel.Z = 1. + Random[BlueSpark]() / 256.;
}
}
}
// Sorcerer 2 FX Spark ------------------------------------------------------
@ -263,8 +480,6 @@ class Sorcerer2FX2 : Actor
RenderStyle "Add";
}
native void A_GenWizard ();
States
{
Spawn:
@ -277,7 +492,38 @@ class Sorcerer2FX2 : Actor
Stop;
}
//----------------------------------------------------------------------------
//
// PROC A_GenWizard
//
//----------------------------------------------------------------------------
void A_GenWizard ()
{
Actor mo = Spawn("Wizard", pos, ALLOW_REPLACE);
if (mo != null)
{
mo.AddZ(-mo.Default.Height / 2, false);
if (!mo.TestMobjLocation ())
{ // Didn't fit
mo.ClearCounters();
mo.Destroy ();
}
else
{ // [RH] Make the new wizards inherit D'Sparil's target
mo.CopyFriendliness (self.target, true);
Vel = (0,0,0);
SetStateLabel('Death');
bMissile = false;
mo.master = target;
SpawnTeleportFog(pos, false, true);
}
}
}
}
// Sorcerer 2 Telefade ------------------------------------------------------
class Sorcerer2Telefade : Actor

View file

@ -1037,7 +1037,7 @@ class HornRodFX1 : Actor
// Horn Rod FX 2 ------------------------------------------------------------
class HornRodFX2 : Actor native
class HornRodFX2 : Actor
{
Default
{
@ -1074,6 +1074,18 @@ class HornRodFX2 : Actor native
FX00 G 1 A_SkullRodStorm;
Wait;
}
override int DoSpecialDamage (Actor target, int damage, Name damagetype)
{
Sorcerer2 s2 = Sorcerer2(target);
if (s2 != null && random[HornRodFX2]() < 96)
{ // D'Sparil teleports away
s2.DSparilTeleport ();
return -1;
}
return damage;
}
}
// Rain pillar 1 ------------------------------------------------------------
@ -1195,7 +1207,7 @@ class PhoenixRodPowered : PhoenixRod native
// Phoenix FX 1 -------------------------------------------------------------
class PhoenixFX1 : Actor native
class PhoenixFX1 : Actor
{
Default
{
@ -1225,6 +1237,18 @@ class PhoenixFX1 : Actor native
FX08 DEFGH 4 BRIGHT;
Stop;
}
override int DoSpecialDamage (Actor target, int damage, Name damagetype)
{
Sorcerer2 s2 = Sorcerer2(target);
if (s2 != null && random[HornRodFX2]() < 96)
{ // D'Sparil teleports away
s2.DSparilTeleport ();
return -1;
}
return damage;
}
}
// Phoenix puff -------------------------------------------------------------