From 5ce5466e186e013c482e2f4b8a06d21dc5b92066 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 27 Nov 2016 20:14:43 +0100 Subject: [PATCH] - scriptified hexenspecialdecs. - made '->' a single token. Although ZScript does not use it, the parser tends to get confused and fatally chokes on leftover arrows so this ensures more robust error handling. --- src/CMakeLists.txt | 2 - src/g_hexen/a_flies.cpp | 110 ------ src/g_hexen/a_hexenmisc.cpp | 2 - src/g_hexen/a_hexenspecialdecs.cpp | 365 ------------------ src/g_level.cpp | 1 + src/p_things.cpp | 7 + src/sc_man_scanner.re | 3 +- src/sc_man_tokens.h | 1 + wadsrc/static/zscript/actor.txt | 1 + wadsrc/static/zscript/base.txt | 1 + .../static/zscript/hexen/hexenspecialdecs.txt | 291 +++++++++++++- 11 files changed, 284 insertions(+), 500 deletions(-) delete mode 100644 src/g_hexen/a_flies.cpp delete mode 100644 src/g_hexen/a_hexenspecialdecs.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2164e0a8b..6111d1714 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -859,9 +859,7 @@ set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} sc_man_scanner.h sc_man_scanner.re - g_hexen/a_flies.cpp g_hexen/a_heresiarch.cpp - g_hexen/a_hexenspecialdecs.cpp g_hexen/a_magecone.cpp g_hexen/a_magelightning.cpp g_hexen/a_magestaff.cpp diff --git a/src/g_hexen/a_flies.cpp b/src/g_hexen/a_flies.cpp deleted file mode 100644 index 7281dd8f2..000000000 --- a/src/g_hexen/a_flies.cpp +++ /dev/null @@ -1,110 +0,0 @@ -static FRandom pr_fly("GetOffMeFly"); - -//=========================================================================== -// -// FindCorpse -// -// Finds a corpse to buzz around. We can't use a blockmap check because -// corpses generally aren't linked into the blockmap. -// -//=========================================================================== - -static AActor *FindCorpse(AActor *fly, sector_t *sec, int recurselimit) -{ - AActor *fallback = NULL; - sec->validcount = validcount; - - // Search the current sector - for (AActor *check = sec->thinglist; check != NULL; check = check->snext) - { - if (check == fly) - continue; - if (!(check->flags & MF_CORPSE)) - continue; - if (!P_CheckSight(fly, check)) - continue; - fallback = check; - if (pr_fly(2)) // 50% chance to try to pick a different corpse - continue; - return check; - } - if (--recurselimit <= 0 || (fallback != NULL && pr_fly(2))) - { - return fallback; - } - // Try neighboring sectors - for (int i = 0; i < sec->linecount; ++i) - { - line_t *line = sec->lines[i]; - sector_t *sec2 = (line->frontsector == sec) ? line->backsector : line->frontsector; - if (sec2 != NULL && sec2->validcount != validcount) - { - AActor *neighbor = FindCorpse(fly, sec2, recurselimit); - if (neighbor != NULL) - { - return neighbor; - } - } - } - return fallback; -} - -DEFINE_ACTION_FUNCTION(AActor, A_FlySearch) -{ - // The version from the retail beta is not so great for general use: - // 1. Pick one of the first fifty thinkers at random. - // 2. Starting from that thinker, find one that is an actor, not itself, - // and within sight. Give up after 100 sequential thinkers. - // It's effectively useless if there are more than 150 thinkers on a map. - // - // So search the sectors instead. We can't potentially find something all - // the way on the other side of the map and we can't find invisible corpses, - // but at least we aren't crippled on maps with lots of stuff going on. - PARAM_SELF_PROLOGUE(AActor); - - validcount++; - AActor *other = FindCorpse(self, self->Sector, 5); - if (other != NULL) - { - self->target = other; - self->SetState(self->FindState("Buzz")); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_FlyBuzz) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *targ = self->target; - - if (targ == NULL || !(targ->flags & MF_CORPSE) || pr_fly() < 5) - { - self->SetIdle(); - return 0; - } - - self->Angles.Yaw = self->AngleTo(targ); - self->args[0]++; - if (!P_TryMove(self, self->Pos().XY() + self->Angles.Yaw.ToVector(6), true)) - { - self->SetIdle(true); - return 0; - } - if (self->args[0] & 2) - { - self->Vel.X += (pr_fly() - 128) / 512.; - self->Vel.Y += (pr_fly() - 128) / 512.; - } - int zrand = pr_fly(); - if (targ->Z() + 5. < self->Z() && zrand > 150) - { - zrand = -zrand; - } - self->Vel.Z = zrand / 512.; - if (pr_fly() < 40) - { - S_Sound(self, CHAN_VOICE, self->ActiveSound, 0.5f, ATTN_STATIC); - } - return 0; -} diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index ae4399526..503ac6fbc 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -24,9 +24,7 @@ #include "a_pickups.h" // Include all the Hexen stuff here to reduce compile time -#include "a_flies.cpp" #include "a_heresiarch.cpp" -#include "a_hexenspecialdecs.cpp" #include "a_magecone.cpp" #include "a_magelightning.cpp" #include "a_magestaff.cpp" diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp deleted file mode 100644 index 899d9326d..000000000 --- a/src/g_hexen/a_hexenspecialdecs.cpp +++ /dev/null @@ -1,365 +0,0 @@ -/* -** Decorations that do special things -*/ - -/* -#include "actor.h" -#include "info.h" -#include "a_action.h" -#include "m_random.h" -#include "s_sound.h" -#include "p_local.h" -#include "p_lnspec.h" -#include "a_hexenglobal.h" -#include "vm.h" -#include "g_level.h" -#include "doomstat.h" -*/ - -static FRandom pr_pottery ("PotteryExplode"); -static FRandom pr_bit ("PotteryChooseBit"); -static FRandom pr_drip ("CorpseBloodDrip"); -static FRandom pr_foo ("CorpseExplode"); -static FRandom pr_leaf ("LeafSpawn"); -static FRandom pr_leafthrust ("LeafThrust"); -static FRandom pr_leafcheck ("LeafCheck"); -static FRandom pr_shroom ("PoisonShroom"); -static FRandom pr_soaexplode ("SoAExplode"); - -// Pottery1 ------------------------------------------------------------------ - -void A_PotteryExplode (AActor *); -void A_PotteryChooseBit (AActor *); -void A_PotteryCheck (AActor *); - -//============================================================================ -// -// A_PotteryExplode -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_PotteryExplode) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo = NULL; - int i; - - for(i = (pr_pottery()&3)+3; i; i--) - { - mo = Spawn ("PotteryBit", self->Pos(), ALLOW_REPLACE); - if (mo) - { - mo->SetState (mo->SpawnState + (pr_pottery()%5)); - mo->Vel.X = pr_pottery.Random2() / 64.; - mo->Vel.Y = pr_pottery.Random2() / 64.; - mo->Vel.Z = ((pr_pottery() & 7) + 5) * 0.75; - } - } - S_Sound (mo, CHAN_BODY, "PotteryExplode", 1, ATTN_NORM); - // Spawn an item? - PClassActor *type = P_GetSpawnableType(self->args[0]); - if (type != NULL) - { - if (!((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS)) - || !(GetDefaultByType (type)->flags3 & MF3_ISMONSTER)) - { // Only spawn monsters if not -nomonsters - Spawn (type, self->Pos(), ALLOW_REPLACE); - } - } - return 0; -} - -//============================================================================ -// -// A_PotteryChooseBit -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_PotteryChooseBit) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->SetState (self->FindState(NAME_Death) + 1 + 2*(pr_bit()%5)); - self->tics = 256+(pr_bit()<<1); - return 0; -} - -//============================================================================ -// -// A_PotteryCheck -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_PotteryCheck) -{ - PARAM_SELF_PROLOGUE(AActor); - - int i; - - for(i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i]) - { - AActor *pmo = players[i].mo; - if (P_CheckSight (self, pmo) && (absangle(pmo->AngleTo(self), pmo->Angles.Yaw) <= 45)) - { // Previous state (pottery bit waiting state) - self->SetState (self->state - 1); - return 0; - } - } - } - return 0; -} - -// Lynched corpse (no heart) ------------------------------------------------ - -class AZCorpseLynchedNoHeart : public AActor -{ -DECLARE_CLASS (AZCorpseLynchedNoHeart, AActor) -public: - void PostBeginPlay (); -}; - -IMPLEMENT_CLASS(AZCorpseLynchedNoHeart, false, false) - -void AZCorpseLynchedNoHeart::PostBeginPlay () -{ - Super::PostBeginPlay (); - Spawn ("BloodPool", PosAtZ(floorz), ALLOW_REPLACE); -} - -//============================================================================ -// -// A_CorpseBloodDrip -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CorpseBloodDrip) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (pr_drip() <= 128) - { - Spawn ("CorpseBloodDrip", self->PosPlusZ(self->Height / 2), ALLOW_REPLACE); - } - return 0; -} - -//============================================================================ -// -// A_CorpseExplode -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_CorpseExplode) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - int i; - - for (i = (pr_foo()&3)+3; i; i--) - { - mo = Spawn ("CorpseBit", self->Pos(), ALLOW_REPLACE); - if (mo) - { - mo->SetState (mo->SpawnState + (pr_foo()%3)); - mo->Vel.X = pr_foo.Random2() / 64.; - mo->Vel.Y = pr_foo.Random2() / 64.; - mo->Vel.Z = ((pr_foo() & 7) + 5) * 0.75; - } - } - // Spawn a skull - mo = Spawn ("CorpseBit", self->Pos(), ALLOW_REPLACE); - if (mo) - { - mo->SetState (mo->SpawnState + 3); - mo->Vel.X = pr_foo.Random2() / 64.; - mo->Vel.Y = pr_foo.Random2() / 64.; - mo->Vel.Z = ((pr_foo() & 7) + 5) * 0.75; - } - S_Sound (self, CHAN_BODY, self->DeathSound, 1, ATTN_IDLE); - self->Destroy (); - return 0; -} - -//============================================================================ -// -// A_LeafSpawn -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_LeafSpawn) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - int i; - - for (i = (pr_leaf()&3)+1; i; i--) - { - double xo = pr_leaf.Random2() / 4.; - double yo = pr_leaf.Random2() / 4.; - double zo = pr_leaf() / 4.; - mo = Spawn (pr_leaf()&1 ? PClass::FindActor ("Leaf1") : PClass::FindActor ("Leaf2"), - self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); - - if (mo) - { - mo->Thrust(pr_leaf() / 128. + 3); - mo->target = self; - mo->special1 = 0; - } - } - return 0; -} - -//============================================================================ -// -// A_LeafThrust -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_LeafThrust) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (pr_leafthrust() <= 96) - { - self->Vel.Z += pr_leafthrust() / 128. + 1; - } - return 0; -} - -//============================================================================ -// -// A_LeafCheck -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_LeafCheck) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->special1++; - if (self->special1 >= 20) - { - self->SetState (NULL); - return 0; - } - DAngle ang = self->target ? self->target->Angles.Yaw : self->Angles.Yaw; - if (pr_leafcheck() > 64) - { - if (self->Vel.X == 0 && self->Vel.Y == 0) - { - self->Thrust(ang, pr_leafcheck() / 128. + 1); - } - return 0; - } - self->SetState (self->SpawnState + 7); - self->Vel.Z = pr_leafcheck() / 128. + 1; - self->Thrust(ang, pr_leafcheck() / 128. + 2); - self->flags |= MF_MISSILE; - return 0; -} - -//=========================================================================== -// -// A_SoAExplode - Suit of Armor Explode -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_SoAExplode) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - int i; - - for (i = 0; i < 10; i++) - { - double xo = (pr_soaexplode() - 128) / 16.; - double yo = (pr_soaexplode() - 128) / 16.; - double zo = pr_soaexplode()*self->Height / 256.; - mo = Spawn ("ZArmorChunk", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); - if (mo) - { - mo->SetState (mo->SpawnState + i); - mo->Vel.X = pr_soaexplode.Random2() / 64.; - mo->Vel.Y = pr_soaexplode.Random2() / 64.; - mo->Vel.Z = (pr_soaexplode() & 7) + 5; - } - } - // Spawn an item? - PClassActor *type = P_GetSpawnableType(self->args[0]); - if (type != NULL) - { - if (!((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS)) - || !(GetDefaultByType (type)->flags3 & MF3_ISMONSTER)) - { // Only spawn monsters if not -nomonsters - Spawn (type, self->Pos(), ALLOW_REPLACE); - } - } - S_Sound (self, CHAN_BODY, self->DeathSound, 1, ATTN_NORM); - self->Destroy (); - return 0; -} - -// Bell --------------------------------------------------------------------- - -class AZBell : public AActor -{ - DECLARE_CLASS (AZBell, AActor) -public: - void Activate (AActor *activator); -}; - -IMPLEMENT_CLASS(AZBell, false, false) - -void AZBell::Activate (AActor *activator) -{ - if (health > 0) - { - P_DamageMobj (this, activator, activator, 10, NAME_Melee, DMG_THRUSTLESS); // 'ring' the bell - } -} - -//=========================================================================== -// -// A_BellReset1 -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_BellReset1) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->flags |= MF_NOGRAVITY; - self->Height *= 4; - if (self->special) - { // Initiate death action - P_ExecuteSpecial(self->special, NULL, NULL, false, self->args[0], - self->args[1], self->args[2], self->args[3], self->args[4]); - self->special = 0; - } - return 0; -} - -//=========================================================================== -// -// A_BellReset2 -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_BellReset2) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->flags |= MF_SHOOTABLE; - self->flags &= ~MF_CORPSE; - self->flags6 &= ~MF6_KILLED; - self->health = 5; - return 0; -} - diff --git a/src/g_level.cpp b/src/g_level.cpp index 904b38b8a..ea34dc95c 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1889,6 +1889,7 @@ DEFINE_FIELD_BIT(FLevelLocals, flags2, missilesactivateimpact, LEVEL2_MISSILESAC DEFINE_FIELD_BIT(FLevelLocals, flags2, monsterfallingdamage, LEVEL2_MONSTERFALLINGDAMAGE) DEFINE_FIELD_BIT(FLevelLocals, flags2, checkswitchrange, LEVEL2_CHECKSWITCHRANGE) DEFINE_FIELD_BIT(FLevelLocals, flags2, polygrind, LEVEL2_POLYGRIND) +DEFINE_FIELD_BIT(FLevelLocals, flags2, nomonsters, LEVEL2_NOMONSTERS) //========================================================================== // diff --git a/src/p_things.cpp b/src/p_things.cpp index d94ba6a01..ea01d38ed 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -520,6 +520,13 @@ PClassActor *P_GetSpawnableType(int spawnnum) return NULL; } +DEFINE_ACTION_FUNCTION(AActor, GetSpawnableType) +{ + PARAM_PROLOGUE; + PARAM_INT(num); + ACTION_RETURN_OBJECT(P_GetSpawnableType(num)); +} + struct MapinfoSpawnItem { FName classname; // DECORATE is read after MAPINFO so we do not have the actual classes available here yet. diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index 59113e4a7..a57cc34ad 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -162,13 +162,11 @@ std2: 'private' { RET(TK_Private); } 'dot' { RET(TK_Dot); } 'cross' { RET(TK_Cross); } - 'ignores' { RET(TK_Ignores); } 'localized' { RET(TK_Localized); } 'latent' { RET(TK_Latent); } 'singular' { RET(TK_Singular); } 'config' { RET(TK_Config); } 'coerce' { RET(TK_Coerce); } - 'iterator' { RET(TK_Iterator); } 'optional' { RET(TK_Optional); } 'export' { RET(TK_Export); } 'virtual' { RET(TK_Virtual); } @@ -240,6 +238,7 @@ std2: "<>=" { RET(TK_LtGtEq); } "**" { RET(TK_MulMul); } "::" { RET(TK_ColonColon); } + "->" { RET(TK_Arrow); } ";" { StateOptions = false; RET(';'); } "{" { StateOptions = false; RET('{'); } "}" { RET('}'); } diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index dfa6c044c..c1ba10044 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -33,6 +33,7 @@ xx(TK_Neq, "'!='") xx(TK_ApproxEq, "'~=='") xx(TK_LtGtEq, "'<>='") xx(TK_MulMul, "'**'") +xx(TK_Arrow, "'->'") xx(TK_Action, "'action'") xx(TK_Break, "'break'") xx(TK_Case, "'case'") diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 7b2b99570..17dfea393 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -270,6 +270,7 @@ class Actor : Thinker native native static double GetDefaultSpeed(class type); + native static class GetSpawnableType(int spawnnum); native void RemoveFromHash(); native string GetTag(string defstr = ""); native double GetBobOffset(double frac = 0); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 397ba4c32..c0894eda8 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -92,6 +92,7 @@ struct LevelLocals native native bool monsterfallingdamage; native bool checkswitchrange; native bool polygrind; + native bool nomonsters; // level_info_t *info cannot be done yet. } diff --git a/wadsrc/static/zscript/hexen/hexenspecialdecs.txt b/wadsrc/static/zscript/hexen/hexenspecialdecs.txt index 558ef8395..feebf515f 100644 --- a/wadsrc/static/zscript/hexen/hexenspecialdecs.txt +++ b/wadsrc/static/zscript/hexen/hexenspecialdecs.txt @@ -95,7 +95,6 @@ class Pottery1 : Actor +NOICEDEATH } - native void A_PotteryExplode(); States { @@ -106,6 +105,40 @@ class Pottery1 : Actor POT1 A 0 A_PotteryExplode; Stop; } + + //============================================================================ + // + // A_PotteryExplode + // + //============================================================================ + + void A_PotteryExplode() + { + Actor mo = null; + int i; + + for(i = (random[Pottery]()&3)+3; i; i--) + { + mo = Spawn ("PotteryBit", Pos, ALLOW_REPLACE); + if (mo) + { + mo.SetState (mo.SpawnState + (random[Pottery]()%5)); + mo.Vel.X = random2[Pottery]() / 64.; + mo.Vel.Y = random2[Pottery]() / 64.; + mo.Vel.Z = ((random[Pottery]() & 7) + 5) * 0.75; + } + } + mo.A_PlaySound ("PotteryExplode", CHAN_BODY); + // Spawn an item? + Class type = GetSpawnableType(args[0]); + if (type != null) + { + if (!(level.nomonsters || sv_nomonsters) || !(GetDefaultByType (type).bIsMonster)) + { // Only spawn monsters if not -nomonsters + Spawn (type, Pos, ALLOW_REPLACE); + } + } + } } // Pottery2 ----------------------------------------------------------------- @@ -144,6 +177,8 @@ class Pottery3 : Pottery1 class PotteryBit : Actor { + State LoopState; + Default { Radius 5; @@ -153,9 +188,6 @@ class PotteryBit : Actor +NOICEDEATH } - native void A_PotteryChooseBit(); - native void A_PotteryCheck(); - States { Spawn: @@ -185,6 +217,42 @@ class PotteryBit : Actor PBIT J 1 A_PotteryCheck; Stop; } + + //============================================================================ + // + // A_PotteryChooseBit + // + //============================================================================ + + void A_PotteryChooseBit() + { + static const statelabel bits[] = { "Pottery1", "Pottery2", "Pottery3", "Pottery4", "Pottery5" }; + LoopState = FindState(bits[random[PotteryBit]() % 5]); // Save the state for jumping back to. + SetState (LoopState); + tics = 256 + (random[PotteryBit]() << 1); + } + + //============================================================================ + // + // A_PotteryCheck + // + //============================================================================ + + void A_PotteryCheck() + { + for(int i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + { + Actor pmo = players[i].mo; + if (CheckSight (pmo) && (absangle(pmo.AngleTo(self), pmo.Angle) <= 45)) + { // jump back to previpusly set state. + SetState (LoopState); + return; + } + } + } + } } @@ -203,7 +271,7 @@ class BloodPool : Actor // Lynched corpse (no heart) ------------------------------------------------ -class ZCorpseLynchedNoHeart : Actor native +class ZCorpseLynchedNoHeart : Actor { Default { @@ -212,14 +280,32 @@ class ZCorpseLynchedNoHeart : Actor native +SOLID +SPAWNCEILING +NOGRAVITY } - native void A_CorpseBloodDrip(); - States { Spawn: CPS5 A 140 A_CorpseBloodDrip; Loop; } + + override void PostBeginPlay () + { + Super.PostBeginPlay (); + Spawn ("BloodPool", (pos.xy, floorz), ALLOW_REPLACE); + } + + //============================================================================ + // + // A_CorpseBloodDrip + // + //============================================================================ + + void A_CorpseBloodDrip() + { + if (random[CorpseDrip]() <= 128) + { + Spawn ("CorpseBloodDrip", pos + (0, 0, Height / 2), ALLOW_REPLACE); + } + } } @@ -289,8 +375,6 @@ class ZCorpseSitting : Actor DeathSound "FireDemonDeath"; } - native void A_CorpseExplode(); - States { Spawn: @@ -300,6 +384,40 @@ class ZCorpseSitting : Actor CPS6 A 1 A_CorpseExplode; Stop; } + + //============================================================================ + // + // A_CorpseExplode + // + //============================================================================ + + void A_CorpseExplode() + { + Actor mo; + + for (int i = (random[CorpseExplode]() & 3) + 3; i; i--) + { + mo = Spawn ("CorpseBit", Pos, ALLOW_REPLACE); + if (mo) + { + mo.SetState (mo.SpawnState + (random[CorpseExplode]() % 3)); + mo.Vel.X = random2[CorpseExplode]() / 64.; + mo.Vel.Y = random2[CorpseExplode]() / 64.; + mo.Vel.Z = ((random[CorpseExplode]() & 7) + 5) * 0.75; + } + } + // Spawn a skull + mo = Spawn ("CorpseBit", Pos, ALLOW_REPLACE); + if (mo) + { + mo.SetState (mo.SpawnState + 3); + mo.Vel.X = random2[CorpseExplode]() / 64.; + mo.Vel.Y = random2[CorpseExplode]() / 64.; + mo.Vel.Z = ((random[CorpseExplode]() & 7) + 5) * 0.75; + } + A_PlaySound (DeathSound, CHAN_BODY); + Destroy (); + } } @@ -313,7 +431,6 @@ class LeafSpawner : Actor +INVISIBLE } - native void A_LeafSpawn(); States { @@ -321,6 +438,32 @@ class LeafSpawner : Actor TNT1 A 20 A_LeafSpawn; Loop; } + + //============================================================================ + // + // A_LeafSpawn + // + //============================================================================ + + void A_LeafSpawn() + { + static const class leaves[] = { "Leaf1", "Leaf2" }; + + for (int i = (random[LeafSpawn]() & 3) + 1; i; i--) + { + double xo = random2[LeafSpawn]() / 4.; + double yo = random2[LeafSpawn]() / 4.; + double zo = random[LeafSpawn]() / 4.; + Actor mo = Spawn (leaves[random[LeafSpawn]()&1], Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + + if (mo) + { + mo.Thrust(random[LeafSpawn]() / 128. + 3); + mo.target = self; + mo.special1 = 0; + } + } + } } @@ -338,15 +481,13 @@ class Leaf1 : Actor +NOICEDEATH } - native void A_LeafThrust(); - native void A_LeafCheck(); - States { Spawn: LEF1 ABC 4; LEF1 D 4 A_LeafThrust; LEF1 EFG 4; + Looping: LEF1 H 4 A_LeafThrust; LEF1 I 4; LEF1 AB 4; @@ -359,6 +500,49 @@ class Leaf1 : Actor LEF3 D 10 A_LeafCheck; Wait; } + + //============================================================================ + // + // A_LeafThrust + // + //============================================================================ + + void A_LeafThrust() + { + if (random[LeafThrust]() <= 96) + { + Vel.Z += random[LeafThrust]() / 128. + 1; + } + } + + //============================================================================ + // + // A_LeafCheck + // + //============================================================================ + + void A_LeafCheck() + { + special1++; + if (special1 >= 20) + { + Destroy(); + return; + } + double ang = target ? target.angle : angle; + if (random[LeafCheck]() > 64) + { + if (Vel.X == 0 && Vel.Y == 0) + { + Thrust(random[LeafCheck]() / 128. + 1, ang); + } + return; + } + SetStateLabel ("Looping"); + Vel.Z = random[LeafCheck]() / 128. + 1; + Thrust(random[LeafCheck]() / 128. + 2, ang); + bMissile = true; + } } @@ -556,8 +740,6 @@ class ZSuitOfArmor : Actor DeathSound "SuitofArmorBreak"; } - native void A_SoAExplode(); - States { Spawn: @@ -567,6 +749,41 @@ class ZSuitOfArmor : Actor ZSUI A 1 A_SoAExplode; Stop; } + + //=========================================================================== + // + // A_SoAExplode - Suit of Armor Explode + // + //=========================================================================== + + void A_SoAExplode() + { + for (int i = 0; i < 10; i++) + { + double xo = (random[SoAExplode]() - 128) / 16.; + double yo = (random[SoAExplode]() - 128) / 16.; + double zo = random[SoAExplode]() * Height / 256.; + Actor mo = Spawn ("ZArmorChunk", Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + if (mo) + { + mo.SetState (mo.SpawnState + i); + mo.Vel.X = random2[SoAExplode]() / 64.; + mo.Vel.Y = random2[SoAExplode]() / 64.; + mo.Vel.Z = (random[SoAExplode]() & 7) + 5; + } + } + // Spawn an item? + Class type = GetSpawnableType(args[0]); + if (type != null) + { + if (!(level.nomonsters || sv_nomonsters) || !(GetDefaultByType (type).bIsMonster)) + { // Only spawn monsters if not -nomonsters + Spawn (type, Pos, ALLOW_REPLACE); + } + } + A_PlaySound (DeathSound, CHAN_BODY); + Destroy (); + } } @@ -608,7 +825,7 @@ class ZArmorChunk : Actor // Bell --------------------------------------------------------------------- -class ZBell : Actor native +class ZBell : Actor { Default { @@ -621,9 +838,6 @@ class ZBell : Actor native DeathSound "BellRing"; } - native void A_BellReset1(); - native void A_BellReset2(); - States { Spawn: @@ -665,6 +879,45 @@ class ZBell : Actor native BBLL A 1 A_BellReset2; Goto Spawn; } + + override void Activate (Actor activator) + { + if (health > 0) A_Die(); + { + DamageMobj (activator, activator, 10, 'Melee', DMG_THRUSTLESS); // 'ring' the bell + } + } + + //=========================================================================== + // + // A_BellReset1 + // + //=========================================================================== + + void A_BellReset1() + { + bNoGravity = true; + Height = Default.Height; + if (special) + { // Initiate death action + A_CallSpecial(special, args[0], args[1], args[2], args[3], args[4]); + special = 0; + } + } + + //=========================================================================== + // + // A_BellReset2 + // + //=========================================================================== + + void A_BellReset2() + { + bShootable = true; + bCorpse = false; + bKilled = false; + health = 5; + } }