mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 07:12:02 +00:00
- scriptified D'Sparil.
- added retrieval of defaults from an actor pointer.
This commit is contained in:
parent
cd919e72e1
commit
3e890d182b
14 changed files with 349 additions and 406 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 -------------------------------------------------------------
|
||||
|
|
Loading…
Reference in a new issue