From ebd2c27e0ab2cd54af4f7937f09d35c879f8cf79 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 28 Nov 2016 00:49:10 +0100 Subject: [PATCH] - scriptified Hexen's Bloodscourge and Serpent. - merged the FrontBlock searcher for the Bloodscourge into RoughMonsterSearch. This also fixes the bug that the searcher was not initialized properly for the MageBoss. --- src/CMakeLists.txt | 2 - src/g_hexen/a_hexenmisc.cpp | 2 - src/g_hexen/a_magestaff.cpp | 260 ---------------- src/g_hexen/a_serpent.cpp | 311 -------------------- src/p_enemy.cpp | 6 + src/p_local.h | 2 +- src/p_maputl.cpp | 54 +++- src/p_mobj.cpp | 7 + src/p_terrain.cpp | 15 + src/scripting/thingdef_data.cpp | 1 + src/scripting/vm/vm.h | 1 + wadsrc/static/zscript/actor.txt | 4 +- wadsrc/static/zscript/base.txt | 21 +- wadsrc/static/zscript/hexen/baseweapons.txt | 2 +- wadsrc/static/zscript/hexen/mageboss.txt | 37 ++- wadsrc/static/zscript/hexen/magestaff.txt | 132 ++++++++- wadsrc/static/zscript/hexen/serpent.txt | 270 ++++++++++++++++- 17 files changed, 507 insertions(+), 620 deletions(-) delete mode 100644 src/g_hexen/a_magestaff.cpp delete mode 100644 src/g_hexen/a_serpent.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1abd8e71b..40d227fa4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -860,8 +860,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.h sc_man_scanner.re g_hexen/a_heresiarch.cpp - g_hexen/a_magestaff.cpp - g_hexen/a_serpent.cpp g_hexen/a_spike.cpp g_hexen/a_teleportother.cpp g_strife/a_acolyte.cpp diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index 45a407faa..4cfd359f8 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -25,7 +25,5 @@ // Include all the Hexen stuff here to reduce compile time #include "a_heresiarch.cpp" -#include "a_magestaff.cpp" -#include "a_serpent.cpp" #include "a_spike.cpp" #include "a_teleportother.cpp" diff --git a/src/g_hexen/a_magestaff.cpp b/src/g_hexen/a_magestaff.cpp deleted file mode 100644 index 035744aba..000000000 --- a/src/g_hexen/a_magestaff.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "p_local.h" -#include "m_random.h" -#include "s_sound.h" -#include "a_hexenglobal.h" -#include "gstrings.h" -#include "a_weaponpiece.h" -#include "vm.h" -#include "doomstat.h" -*/ - -class AMageWeapon : public AWeapon -{ - DECLARE_CLASS (AMageWeapon, AWeapon); -public: -}; - -IMPLEMENT_CLASS(AMageWeapon, false, false) - -static FRandom pr_mstafftrack ("MStaffTrack"); -static FRandom pr_bloodscourgedrop ("BloodScourgeDrop"); - -void A_MStaffTrack (AActor *); -void A_DropBloodscourgePieces (AActor *); -void A_MStaffAttack (AActor *actor); -void A_MStaffPalette (AActor *actor); - -static AActor *FrontBlockCheck (AActor *mo, int index, void *); -static divline_t BlockCheckLine; - -//========================================================================== -// The Mages's Staff (Bloodscourge) ----------------------------------------- - -class AMWeapBloodscourge : public AMageWeapon -{ - DECLARE_CLASS (AMWeapBloodscourge, AMageWeapon) -public: - - void Serialize(FSerializer &arc) - { - Super::Serialize (arc); - arc("mstaffcount", MStaffCount); - } - PalEntry GetBlend () - { - if (paletteflash & PF_HEXENWEAPONS) - { - if (MStaffCount == 3) - return PalEntry(128, 100, 73, 0); - else if (MStaffCount == 2) - return PalEntry(128, 125, 92, 0); - else if (MStaffCount == 1) - return PalEntry(128, 150, 110, 0); - else - return PalEntry(0, 0, 0, 0); - } - else - { - return PalEntry (MStaffCount * 128 / 3, 151, 110, 0); - } - } - BYTE MStaffCount; -}; - -IMPLEMENT_CLASS(AMWeapBloodscourge, false, false) - -// Mage Staff FX2 (Bloodscourge) -------------------------------------------- - -class AMageStaffFX2 : public AActor -{ - DECLARE_CLASS(AMageStaffFX2, AActor) -public: - bool SpecialBlastHandling (AActor *source, double strength); -}; - -IMPLEMENT_CLASS(AMageStaffFX2, false, false) - -bool AMageStaffFX2::SpecialBlastHandling (AActor *source, double strength) -{ - // Reflect to originator - tracer = target; - target = source; - return true; -} - -//============================================================================ - -//============================================================================ -// -// MStaffSpawn -// -//============================================================================ - -void MStaffSpawn (AActor *pmo, DAngle angle, AActor *alttarget) -{ - AActor *mo; - FTranslatedLineTarget t; - - mo = P_SpawnPlayerMissile (pmo, 0, 0, 8, RUNTIME_CLASS(AMageStaffFX2), angle, &t); - if (mo) - { - mo->target = pmo; - if (t.linetarget && !t.unlinked) - mo->tracer = t.linetarget; - else - mo->tracer = alttarget; - } -} - -//============================================================================ -// -// A_MStaffAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_MStaffAttack) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle angle; - player_t *player; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - - AMWeapBloodscourge *weapon = static_cast (self->player->ReadyWeapon); - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - angle = self->Angles.Yaw; - - // [RH] Let's try and actually track what the player aimed at - P_AimLineAttack (self, angle, PLAYERMISSILERANGE, &t, 32.); - if (t.linetarget == NULL) - { - BlockCheckLine.x = self->X(); - BlockCheckLine.y = self->Y(); - BlockCheckLine.dx = -angle.Sin(); - BlockCheckLine.dy = -angle.Cos(); - t.linetarget = P_BlockmapSearch (self, 10, FrontBlockCheck); - } - MStaffSpawn (self, angle, t.linetarget); - MStaffSpawn (self, angle-5, t.linetarget); - MStaffSpawn (self, angle+5, t.linetarget); - S_Sound (self, CHAN_WEAPON, "MageStaffFire", 1, ATTN_NORM); - weapon->MStaffCount = 3; - return 0; -} - -//============================================================================ -// -// A_MStaffPalette -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_MStaffPalette) -{ - PARAM_ACTION_PROLOGUE(AActor); - - if (self->player != NULL) - { - AMWeapBloodscourge *weapon = static_cast (self->player->ReadyWeapon); - if (weapon != NULL && weapon->MStaffCount != 0) - { - weapon->MStaffCount--; - } - } - return 0; -} - -//============================================================================ -// -// A_MStaffTrack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_MStaffTrack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if ((self->tracer == 0) && (pr_mstafftrack()<50)) - { - self->tracer = P_RoughMonsterSearch (self, 10, true); - } - P_SeekerMissile(self, 2, 10); - return 0; -} - -//============================================================================ -// -// FrontBlockCheck -// -// [RH] Like RoughBlockCheck, but it won't return anything behind a line. -// -//============================================================================ - -static AActor *FrontBlockCheck (AActor *mo, int index, void *) -{ - FBlockNode *link; - - for (link = blocklinks[index]; link != NULL; link = link->NextActor) - { - if (link->Me != mo) - { - if (P_PointOnDivlineSide(link->Me->X(), link->Me->Y(), &BlockCheckLine) == 0 && - mo->IsOkayToAttack (link->Me)) - { - return link->Me; - } - } - } - return NULL; -} - -//============================================================================ -// -// MStaffSpawn2 - for use by mage class boss -// -//============================================================================ - -void MStaffSpawn2 (AActor *actor, DAngle angle) -{ - AActor *mo; - - mo = P_SpawnMissileAngleZ (actor, actor->Z()+40, RUNTIME_CLASS(AMageStaffFX2), angle, 0.); - if (mo) - { - mo->target = actor; - mo->tracer = P_BlockmapSearch (mo, 10, FrontBlockCheck); - } -} - -//============================================================================ -// -// A_MStaffAttack2 - for use by mage class boss -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_MageAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->target == NULL) - { - return 0; - } - DAngle angle = self->Angles.Yaw; - MStaffSpawn2(self, angle); - MStaffSpawn2(self, angle - 5); - MStaffSpawn2(self, angle + 5); - S_Sound(self, CHAN_WEAPON, "MageStaffFire", 1, ATTN_NORM); - return 0; -} diff --git a/src/g_hexen/a_serpent.cpp b/src/g_hexen/a_serpent.cpp deleted file mode 100644 index 6f435747e..000000000 --- a/src/g_hexen/a_serpent.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/* -#include "actor.h" -#include "info.h" -#include "p_local.h" -#include "s_sound.h" -#include "p_enemy.h" -#include "a_action.h" -#include "m_random.h" -#include "p_terrain.h" -#include "vm.h" -*/ - -static FRandom pr_serpentchase ("SerpentChase"); -static FRandom pr_serpenthump ("SerpentHump"); -static FRandom pr_serpentattack ("SerpentAttack"); -static FRandom pr_serpentmeattack ("SerpentMeAttack"); -static FRandom pr_serpentgibs ("SerpentGibs"); -static FRandom pr_delaygib ("DelayGib"); - -//============================================================================ -// -// A_SerpentUnHide -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentUnHide) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->renderflags &= ~RF_INVISIBLE; - self->Floorclip = 24; - return 0; -} - -//============================================================================ -// -// A_SerpentHide -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentHide) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->renderflags |= RF_INVISIBLE; - self->Floorclip = 0; - return 0; -} - -//============================================================================ -// -// A_SerpentRaiseHump -// -// Raises the hump above the surface by raising the floorclip level -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentRaiseHump) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->Floorclip -= 4; - return 0; -} - -//============================================================================ -// -// A_SerpentLowerHump -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentLowerHump) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->Floorclip += 4; - return 0; -} - -//============================================================================ -// -// A_SerpentHumpDecide -// -// Decided whether to hump up, or if the mobj is a serpent leader, -// to missile attack -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentHumpDecide) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->MissileState != NULL) - { - if (pr_serpenthump() > 30) - { - return 0; - } - else if (pr_serpenthump() < 40) - { // Missile attack - self->SetState (self->MeleeState); - return 0; - } - } - else if (pr_serpenthump() > 3) - { - return 0; - } - if (!self->CheckMeleeRange ()) - { // The hump shouldn't occur when within melee range - if (self->MissileState != NULL && pr_serpenthump() < 128) - { - self->SetState (self->MeleeState); - } - else - { - self->SetState (self->FindState ("Hump")); - S_Sound (self, CHAN_BODY, "SerpentActive", 1, ATTN_NORM); - } - } - return 0; -} - -//============================================================================ -// -// A_SerpentCheckForAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentCheckForAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (!self->target) - { - return 0; - } - if (self->MissileState != NULL) - { - if (!self->CheckMeleeRange ()) - { - self->SetState (self->FindState ("Attack")); - return 0; - } - } - if (P_CheckMeleeRange2 (self)) - { - self->SetState (self->FindState ("Walk")); - } - else if (self->CheckMeleeRange ()) - { - if (pr_serpentattack() < 32) - { - self->SetState (self->FindState ("Walk")); - } - else - { - self->SetState (self->FindState ("Attack")); - } - } - return 0; -} - -//============================================================================ -// -// A_SerpentChooseAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentChooseAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (!self->target || self->CheckMeleeRange()) - { - return 0; - } - if (self->MissileState != NULL) - { - self->SetState (self->MissileState); - } - return 0; -} - -//============================================================================ -// -// A_SerpentMeleeAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentMeleeAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (!self->target) - { - return 0; - } - if (self->CheckMeleeRange ()) - { - int damage = pr_serpentmeattack.HitDice (5); - int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - S_Sound (self, CHAN_BODY, "SerpentMeleeHit", 1, ATTN_NORM); - } - if (pr_serpentmeattack() < 96) - { - CALL_ACTION(A_SerpentCheckForAttack, self); - } - return 0; -} - -//============================================================================ -// -// A_SerpentSpawnGibs -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentSpawnGibs) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *mo; - static const char *GibTypes[] = - { - "SerpentGib3", - "SerpentGib2", - "SerpentGib1" - }; - - for (int i = countof(GibTypes)-1; i >= 0; --i) - { - double x = (pr_serpentgibs() - 128) / 16.; - double y = (pr_serpentgibs() - 128) / 16.; - - mo = Spawn (GibTypes[i], self->Vec2OffsetZ(x, y, self->floorz + 1), ALLOW_REPLACE); - if (mo) - { - mo->Vel.X = (pr_serpentgibs() - 128) / 1024.f; - mo->Vel.Y = (pr_serpentgibs() - 128) / 1024.f; - mo->Floorclip = 6; - } - } - return 0; -} - -//============================================================================ -// -// A_FloatGib -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FloatGib) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->Floorclip -= 1; - return 0; -} - -//============================================================================ -// -// A_SinkGib -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SinkGib) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->Floorclip += 1;; - return 0; -} - -//============================================================================ -// -// A_DelayGib -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_DelayGib) -{ - PARAM_SELF_PROLOGUE(AActor); - - self->tics -= pr_delaygib()>>2; - return 0; -} - -//============================================================================ -// -// A_SerpentHeadCheck -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SerpentHeadCheck) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (self->Z() <= self->floorz) - { - if (Terrains[P_GetThingFloorType(self)].IsLiquid) - { - P_HitFloor (self); - self->SetState (NULL); - } - else - { - self->SetState (self->FindState(NAME_Death)); - } - } - return 0; -} - diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index a4be4dd1b..4f4920c6f 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -365,6 +365,12 @@ bool P_CheckMeleeRange2 (AActor *actor) return true; } +DEFINE_ACTION_FUNCTION(AActor, CheckMeleeRange2) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_INT(P_CheckMeleeRange2(self)); +} + //============================================================================= // diff --git a/src/p_local.h b/src/p_local.h index d759828dc..12b4a40a3 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -238,7 +238,7 @@ enum PCM AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params = NULL); -AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false); +AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false, bool frontonly = false); // // P_MAP diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 5bb3bea0f..2d2472cbd 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -45,7 +45,6 @@ #include "templates.h" #include "po_man.h" -static AActor *RoughBlockCheck (AActor *mo, int index, void *); sector_t *P_PointInSectorBuggy(double x, double y); int P_VanillaPointOnDivlineSide(double x, double y, const divline_t* line); @@ -1685,19 +1684,6 @@ FPathTraverse::~FPathTraverse() // distance is in MAPBLOCKUNITS //=========================================================================== -AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable) -{ - return P_BlockmapSearch (mo, distance, RoughBlockCheck, (void *)onlyseekable); -} - -DEFINE_ACTION_FUNCTION(AActor, RoughMonsterSearch) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(distance); - PARAM_BOOL_DEF(onlyseekable); - ACTION_RETURN_OBJECT(P_RoughMonsterSearch(self, distance, onlyseekable)); -} - AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params) { int blockX; @@ -1787,6 +1773,13 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in return NULL; } +struct BlockCheckInfo +{ + bool onlyseekable; + bool frontonly; + divline_t frontline; +}; + //=========================================================================== // // RoughBlockCheck @@ -1795,14 +1788,19 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in static AActor *RoughBlockCheck (AActor *mo, int index, void *param) { - bool onlyseekable = param != NULL; + BlockCheckInfo *info = (BlockCheckInfo *)param; + FBlockNode *link; for (link = blocklinks[index]; link != NULL; link = link->NextActor) { if (link->Me != mo) { - if (onlyseekable && !mo->CanSeek(link->Me)) + if (info->onlyseekable && !mo->CanSeek(link->Me)) + { + continue; + } + if (info->frontonly && P_PointOnDivlineSide(link->Me->X(), link->Me->Y(), &info->frontline) != 0) { continue; } @@ -1815,6 +1813,30 @@ static AActor *RoughBlockCheck (AActor *mo, int index, void *param) return NULL; } +AActor *P_RoughMonsterSearch(AActor *mo, int distance, bool onlyseekable, bool frontonly) +{ + BlockCheckInfo info; + info.onlyseekable = onlyseekable; + if ((info.frontonly = frontonly)) + { + info.frontline.x = mo->X(); + info.frontline.y = mo->Y(); + info.frontline.dx = -mo->Angles.Yaw.Sin(); + info.frontline.dy = -mo->Angles.Yaw.Cos(); + } + + return P_BlockmapSearch(mo, distance, RoughBlockCheck, (void *)&info); +} + +DEFINE_ACTION_FUNCTION(AActor, RoughMonsterSearch) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(distance); + PARAM_BOOL_DEF(onlyseekable); + PARAM_BOOL_DEF(frontonly); + ACTION_RETURN_OBJECT(P_RoughMonsterSearch(self, distance, onlyseekable, frontonly)); +} + //========================================================================== // // [RH] LinkToWorldForMapThing diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 22b52d18b..6268c9395 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5908,6 +5908,13 @@ int P_GetThingFloorType (AActor *thing) } } +DEFINE_ACTION_FUNCTION(AActor, GetFloorTerrain) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_POINTER(&Terrains[P_GetThingFloorType(self)]); +} + + //--------------------------------------------------------------------------- // // FUNC P_HitWater diff --git a/src/p_terrain.cpp b/src/p_terrain.cpp index 2504bad94..3adc94876 100644 --- a/src/p_terrain.cpp +++ b/src/p_terrain.cpp @@ -724,3 +724,18 @@ FName P_GetTerrainName(int terrainnum) } } +DEFINE_FIELD_NAMED(FTerrainDef, Name, TerrainName) +DEFINE_FIELD(FTerrainDef, Splash) +DEFINE_FIELD(FTerrainDef, DamageAmount) +DEFINE_FIELD(FTerrainDef, DamageMOD) +DEFINE_FIELD(FTerrainDef, DamageTimeMask) +DEFINE_FIELD(FTerrainDef, FootClip) +DEFINE_FIELD(FTerrainDef, StepVolume) +DEFINE_FIELD(FTerrainDef, WalkStepTics) +DEFINE_FIELD(FTerrainDef, RunStepTics) +DEFINE_FIELD(FTerrainDef, LeftStepSound) +DEFINE_FIELD(FTerrainDef, RightStepSound) +DEFINE_FIELD(FTerrainDef, IsLiquid) +DEFINE_FIELD(FTerrainDef, AllowProtection) +DEFINE_FIELD(FTerrainDef, Friction) +DEFINE_FIELD(FTerrainDef, MoveFactor) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 6f0cad099..d17e10420 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -45,6 +45,7 @@ #include "autosegs.h" #include "p_maputl.h" #include "gi.h" +#include "p_terrain.h" static TArray properties; static TArray AFTable; diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index c7082ff76..fdee430e1 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -1095,6 +1095,7 @@ void CallAction(VMFrameStack *stack, VMFunction *vmfunc, AActor *self); #define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_STATE); return 1; } return 0; } while(0) +#define ACTION_RETURN_POINTER(v) do { void *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_GENERIC); return 1; } return 0; } while(0) #define ACTION_RETURN_OBJECT(v) do { auto state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_OBJECT); return 1; } return 0; } while(0) #define ACTION_RETURN_FLOAT(v) do { double u = v; if (numret > 0) { assert(ret != nullptr); ret->SetFloat(u); return 1; } return 0; } while(0) #define ACTION_RETURN_VEC2(v) do { DVector2 u = v; if (numret > 0) { assert(ret != nullptr); ret[0].SetVector2(u); return 1; } return 0; } while(0) diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 94adbf227..09b983843 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -288,6 +288,7 @@ class Actor : Thinker native native void SetFriendPlayer(PlayerInfo player); native void NoiseAlert(Actor emitter, bool splash = false, double maxdist = 0); native void ClearBounce(); + native TerrainDef GetFloorTerrain(); native void ExplodeMissile(line lin = null, Actor target = null); native void RestoreDamage(); @@ -310,7 +311,7 @@ class Actor : Thinker native native Actor SpawnMissileAngleZSpeed (double z, class type, double angle, double vz, double speed, Actor owner = null, bool checkspawn = true); native Actor, Actor SpawnPlayerMissile(class 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 Actor RoughMonsterSearch(int distance, bool onlyseekable = false); + native Actor RoughMonsterSearch(int distance, bool onlyseekable = false, bool frontonly = false); native int ApplyDamageFactor(Name damagetype, int damage); native int GetModifiedDamage(Name damagetype, int damage, bool passive); @@ -329,6 +330,7 @@ class Actor : Thinker native native void SetIdle(bool nofunction = false); native bool CheckMeleeRange(); + native bool CheckMeleeRange2(); native int DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags = 0, double angle = 0); native double AimLineAttack(double angle, double distance, out FTranslatedLineTarget pLineTarget = null, double vrange = 0., int flags = 0, Actor target = null, Actor friender = null); native Actor, int LineAttack(double angle, double distance, double pitch, int damage, Name damageType, class pufftype, int flags = 0, out FTranslatedLineTarget victim = null); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index c0894eda8..08d655caf 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -247,4 +247,23 @@ struct Wads } native static int CheckNumForName(string name, int ns, int wadnum = -1, bool exact = false); -} \ No newline at end of file +} + +struct TerrainDef native +{ + native Name TerrainName; + native int Splash; + native int DamageAmount; + native Name DamageMOD; + native int DamageTimeMask; + native double FootClip; + native float StepVolume; + native int WalkStepTics; + native int RunStepTics; + native Sound LeftStepSound; + native Sound RightStepSound; + native bool IsLiquid; + native bool AllowProtection; + native double Friction; + native double MoveFactor; +}; diff --git a/wadsrc/static/zscript/hexen/baseweapons.txt b/wadsrc/static/zscript/hexen/baseweapons.txt index b7e2bd398..a1e1af9bd 100644 --- a/wadsrc/static/zscript/hexen/baseweapons.txt +++ b/wadsrc/static/zscript/hexen/baseweapons.txt @@ -19,7 +19,7 @@ class ClericWeapon : Weapon } } -class MageWeapon : Weapon native +class MageWeapon : Weapon { Default { diff --git a/wadsrc/static/zscript/hexen/mageboss.txt b/wadsrc/static/zscript/hexen/mageboss.txt index f9637f8d1..0c081d786 100644 --- a/wadsrc/static/zscript/hexen/mageboss.txt +++ b/wadsrc/static/zscript/hexen/mageboss.txt @@ -18,8 +18,6 @@ class MageBoss : Actor Obituary "$OB_MBOSS"; } - native void A_MageAttack(); - States { Spawn: @@ -83,4 +81,39 @@ class MageBoss : Actor FDTH V 4 Bright; Stop; } + + //============================================================================ + // + // MStaffSpawn2 - for use by mage class boss + // + //============================================================================ + + void MStaffSpawn2 (double angle) + { + Actor mo = SpawnMissileAngleZ (pos.z + 40, "MageStaffFX2", angle, 0.); + if (mo) + { + mo.target = self; + mo.tracer = RoughMonsterSearch(10, true, true); + } + } + + //============================================================================ + // + // A_MStaffAttack2 - for use by mage class boss + // + //============================================================================ + + void A_MageAttack() + { + if (target == NULL) + { + return; + } + MStaffSpawn2(angle); + MStaffSpawn2(angle - 5); + MStaffSpawn2(angle + 5); + A_PlaySound("MageStaffFire", CHAN_WEAPON); + } + } diff --git a/wadsrc/static/zscript/hexen/magestaff.txt b/wadsrc/static/zscript/hexen/magestaff.txt index d485a72fa..e45095240 100644 --- a/wadsrc/static/zscript/hexen/magestaff.txt +++ b/wadsrc/static/zscript/hexen/magestaff.txt @@ -76,8 +76,10 @@ class BloodscourgeDrop : Actor // The Mages's Staff (Bloodscourge) ----------------------------------------- -class MWeapBloodscourge : MageWeapon native +class MWeapBloodscourge : MageWeapon { + int MStaffCount; + Default { Health 3; @@ -97,9 +99,6 @@ class MWeapBloodscourge : MageWeapon native Tag "$TAG_MWEAPBLOODSCOURGE"; } - action native void A_MStaffAttack(); - action native void A_MStaffPalette(); - States { Spawn: @@ -123,11 +122,104 @@ class MWeapBloodscourge : MageWeapon native MSTF J 5 Offset (0, 36); Goto Ready; } + + //============================================================================ + // + // + // + //============================================================================ + + override Color GetBlend () + { + if (paletteflash & PF_HEXENWEAPONS) + { + if (MStaffCount == 3) + return Color(128, 100, 73, 0); + else if (MStaffCount == 2) + return Color(128, 125, 92, 0); + else if (MStaffCount == 1) + return Color(128, 150, 110, 0); + else + return Color(0, 0, 0, 0); + } + else + { + return Color (MStaffCount * 128 / 3, 151, 110, 0); + } + } + + //============================================================================ + // + // MStaffSpawn + // + //============================================================================ + + private action void MStaffSpawn (double angle, Actor alttarget) + { + FTranslatedLineTarget t; + + Actor mo = SpawnPlayerMissile ("MageStaffFX2", angle, pLineTarget:t); + if (mo) + { + mo.target = self; + if (t.linetarget && !t.unlinked) + mo.tracer = t.linetarget; + else + mo.tracer = alttarget; + } + } + + //============================================================================ + // + // A_MStaffAttack + // + //============================================================================ + + action void A_MStaffAttack() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != NULL) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + + // [RH] Let's try and actually track what the player aimed at + AimLineAttack (angle, PLAYERMISSILERANGE, t, 32.); + if (t.linetarget == NULL) + { + t.linetarget = RoughMonsterSearch(10, true, true); + } + MStaffSpawn (angle, t.linetarget); + MStaffSpawn (angle-5, t.linetarget); + MStaffSpawn (angle+5, t.linetarget); + A_PlaySound ("MageStaffFire", CHAN_WEAPON); + invoker.MStaffCount = 3; + } + + //============================================================================ + // + // A_MStaffPalette + // + //============================================================================ + + action void A_MStaffPalette() + { + if (invoker.MStaffCount > 0) invoker.MStaffCount--; + } } + // Mage Staff FX2 (Bloodscourge) -------------------------------------------- -class MageStaffFX2 : Actor native +class MageStaffFX2 : Actor { Default { @@ -143,7 +235,6 @@ class MageStaffFX2 : Actor native Obituary "$OB_MPMWEAPBLOODSCOURGE"; } - native void A_MStaffTrack(); States { @@ -158,6 +249,12 @@ class MageStaffFX2 : Actor native Stop; } + //============================================================================ + // + // + // + //============================================================================ + override int SpecialMissileHit (Actor victim) { if (victim != target && !victim.player && !victim.bBoss) @@ -168,5 +265,26 @@ class MageStaffFX2 : Actor native return -1; } - + override bool SpecialBlastHandling (Actor source, double strength) + { + // Reflect to originator + tracer = target; + target = source; + return true; + } + + //============================================================================ + // + // A_MStaffTrack + // + //============================================================================ + + void A_MStaffTrack() + { + if (tracer == null && random[MStaffTrack]() < 50) + { + tracer = RoughMonsterSearch (10, true); + } + A_SeekerMissile(2, 10); + } } diff --git a/wadsrc/static/zscript/hexen/serpent.txt b/wadsrc/static/zscript/hexen/serpent.txt index 70fb2195a..6eaafcfd1 100644 --- a/wadsrc/static/zscript/hexen/serpent.txt +++ b/wadsrc/static/zscript/hexen/serpent.txt @@ -24,16 +24,6 @@ class Serpent : Actor HitObituary "$OB_SERPENTHIT"; } - native void A_SerpentHumpDecide(); - native void A_SerpentHide(); - native void A_SerpentCheckForAttack(); - native void A_SerpentSpawnGibs(); - native void A_SerpentUnHide(); - native void A_SerpentRaiseHump(); - native void A_SerpentLowerHump(); - native void A_SerpentChooseAttack(); - native void A_SerpentMeleeAttack(); - States { Spawn: @@ -99,6 +89,203 @@ class Serpent : Actor SSPT N 5 A_SerpentMeleeAttack; Goto Dive; } + + //============================================================================ + // + // A_SerpentUnHide + // + //============================================================================ + + void A_SerpentUnHide() + { + bInvisible = false; + Floorclip = 24; + } + + //============================================================================ + // + // A_SerpentHide + // + //============================================================================ + + void A_SerpentHide() + { + bInvisible = true; + Floorclip = 0; + } + + //============================================================================ + // + // A_SerpentRaiseHump + // + // Raises the hump above the surface by raising the floorclip level + //============================================================================ + + void A_SerpentRaiseHump() + { + Floorclip -= 4; + } + + //============================================================================ + // + // A_SerpentLowerHump + // + //============================================================================ + + void A_SerpentLowerHump() + { + Floorclip += 4; + } + + //============================================================================ + // + // A_SerpentHumpDecide + // + // Decided whether to hump up, or if the mobj is a serpent leader, + // to missile attack + //============================================================================ + + void A_SerpentHumpDecide() + { + if (MissileState != NULL) + { + if (random[SerpentHump]() > 30) + { + return; + } + else if (random[SerpentHump]() < 40) + { // Missile attack + SetState (MeleeState); + return; + } + } + else if (random[SerpentHump]() > 3) + { + return; + } + if (!CheckMeleeRange ()) + { // The hump shouldn't occur when within melee range + if (MissileState != NULL && random[SerpentHump]() < 128) + { + SetState (MeleeState); + } + else + { + SetStateLabel("Hump"); + A_PlaySound ("SerpentActive", CHAN_BODY); + } + } + } + + //============================================================================ + // + // A_SerpentCheckForAttack + // + //============================================================================ + + void A_SerpentCheckForAttack() + { + if (!target) + { + return; + } + if (MissileState != NULL) + { + if (!CheckMeleeRange ()) + { + SetStateLabel ("Attack"); + return; + } + } + if (CheckMeleeRange2 ()) + { + SetStateLabel ("Walk"); + } + else if (CheckMeleeRange ()) + { + if (random[SerpentAttack]() < 32) + { + SetStateLabel ("Walk"); + } + else + { + SetStateLabel ("Attack"); + } + } + } + + //============================================================================ + // + // A_SerpentChooseAttack + // + //============================================================================ + + void A_SerpentChooseAttack() + { + if (!target || CheckMeleeRange()) + { + return; + } + if (MissileState != NULL) + { + SetState (MissileState); + } + } + + //============================================================================ + // + // A_SerpentMeleeAttack + // + //============================================================================ + + void A_SerpentMeleeAttack() + { + if (!target) + { + return; + } + if (CheckMeleeRange ()) + { + int damage = random[SerpentAttack](1, 8) * 5; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + A_PlaySound ("SerpentMeleeHit", CHAN_BODY); + } + if (random[SerpentAttack]() < 96) + { + A_SerpentCheckForAttack(); + } + } + + //============================================================================ + // + // A_SerpentSpawnGibs + // + //============================================================================ + + void A_SerpentSpawnGibs() + { + static const class GibTypes[] = + { + "SerpentGib3", + "SerpentGib2", + "SerpentGib1" + }; + + for (int i = 2; i >= 0; --i) + { + double x = (random[SerpentGibs]() - 128) / 16.; + double y = (random[SerpentGibs]() - 128) / 16.; + + Actor mo = Spawn (GibTypes[i], Vec2OffsetZ(x, y, floorz + 1), ALLOW_REPLACE); + if (mo) + { + mo.Vel.X = (random[SerpentGibs]() - 128) / 1024.f; + mo.Vel.Y = (random[SerpentGibs]() - 128) / 1024.f; + mo.Floorclip = 6; + } + } + } } // Serpent Leader ----------------------------------------------------------- @@ -159,8 +346,6 @@ class SerpentHead : Actor +NOBLOCKMAP } - native void A_SerpentHeadCheck(); - States { Spawn: @@ -170,6 +355,28 @@ class SerpentHead : Actor SSXD S -1; Loop; } + + //============================================================================ + // + // A_SerpentHeadCheck + // + //============================================================================ + + void A_SerpentHeadCheck() + { + if (pos.z <= floorz) + { + if (GetFloorTerrain().IsLiquid) + { + HitFloor (); + Destroy(); + } + else + { + SetStateLabel ("NAME_Death"); + } + } + } } // Serpent Gib 1 ------------------------------------------------------------ @@ -183,10 +390,6 @@ class SerpentGib1 : Actor +NOBLOCKMAP +NOGRAVITY } - native void A_FloatGib(); - native void A_DelayGib(); - native void A_SinkGib(); - States { Spawn: @@ -199,6 +402,41 @@ class SerpentGib1 : Actor SSXD QQQ 8 A_SinkGib; Stop; } + + //============================================================================ + // + // A_FloatGib + // + //============================================================================ + + void A_FloatGib() + { + Floorclip -= 1; + } + + //============================================================================ + // + // A_SinkGib + // + //============================================================================ + + void A_SinkGib() + { + Floorclip += 1; + } + + //============================================================================ + // + // A_DelayGib + // + //============================================================================ + + void A_DelayGib() + { + tics -= random[DelayGib]() >> 2; + } + + } // Serpent Gib 2 ------------------------------------------------------------