diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1c8ae0abb..60ee44f18 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1150,7 +1150,6 @@ set (PCH_SOURCES g_inventory/a_ammo.cpp g_inventory/a_armor.cpp g_inventory/a_artifacts.cpp - g_inventory/a_health.cpp g_inventory/a_keys.cpp g_inventory/a_pickups.cpp g_inventory/a_weaponpiece.cpp diff --git a/src/g_inventory/a_artifacts.cpp b/src/g_inventory/a_artifacts.cpp index e767d4356..832d8e62c 100644 --- a/src/g_inventory/a_artifacts.cpp +++ b/src/g_inventory/a_artifacts.cpp @@ -1307,121 +1307,6 @@ void APowerSpeed::DoEffect () } } -// Targeter powerup --------------------------------------------------------- - -IMPLEMENT_CLASS(APowerTargeter, false, false) - -void APowerTargeter::Travelled () -{ - CallInitEffect (); -} - -void APowerTargeter::InitEffect () -{ - // Why is this called when the inventory isn't even attached yet - // in APowerup::CreateCopy? - if (!Owner->FindInventory(GetClass(), true)) - return; - - player_t *player; - - Super::InitEffect(); - - if ((player = Owner->player) == nullptr) - return; - - FState *state = FindState("Targeter"); - - if (state != nullptr) - { - P_SetPsprite(player, PSP_TARGETCENTER, state + 0); - P_SetPsprite(player, PSP_TARGETLEFT, state + 1); - P_SetPsprite(player, PSP_TARGETRIGHT, state + 2); - } - - player->GetPSprite(PSP_TARGETCENTER)->x = (160-3); - player->GetPSprite(PSP_TARGETCENTER)->y = - player->GetPSprite(PSP_TARGETLEFT)->y = - player->GetPSprite(PSP_TARGETRIGHT)->y = (100-3); - PositionAccuracy (); -} - -void APowerTargeter::AttachToOwner(AActor *other) -{ - Super::AttachToOwner(other); - - // Let's actually properly call this for the targeters. - CallInitEffect(); -} - -bool APowerTargeter::HandlePickup(AInventory *item) -{ - if (Super::HandlePickup(item)) - { - CallInitEffect(); // reset the HUD sprites - return true; - } - return false; -} - -void APowerTargeter::DoEffect () -{ - Super::DoEffect (); - - if (Owner != nullptr && Owner->player != nullptr) - { - player_t *player = Owner->player; - - PositionAccuracy (); - if (EffectTics < 5*TICRATE) - { - FState *state = FindState("Targeter"); - - if (state != nullptr) - { - if (EffectTics & 32) - { - P_SetPsprite(player, PSP_TARGETRIGHT, nullptr); - P_SetPsprite(player, PSP_TARGETLEFT, state + 1); - } - else if (EffectTics & 16) - { - P_SetPsprite(player, PSP_TARGETRIGHT, state + 2); - P_SetPsprite(player, PSP_TARGETLEFT, nullptr); - } - } - } - } -} - -void APowerTargeter::EndEffect () -{ - Super::EndEffect(); - if (Owner != nullptr && Owner->player != nullptr) - { - // Calling GetPSprite here could crash if we're creating a new game. - // This is because P_SetupLevel nulls the player's mo before destroying - // every DThinker which in turn ends up calling this. - // However P_SetupLevel is only called after G_NewInit which calls - // every player's dtor which destroys all their psprites. - DPSprite *pspr; - if ((pspr = Owner->player->FindPSprite(PSP_TARGETCENTER)) != nullptr) pspr->SetState(nullptr); - if ((pspr = Owner->player->FindPSprite(PSP_TARGETLEFT)) != nullptr) pspr->SetState(nullptr); - if ((pspr = Owner->player->FindPSprite(PSP_TARGETRIGHT)) != nullptr) pspr->SetState(nullptr); - } -} - -void APowerTargeter::PositionAccuracy () -{ - player_t *player = Owner->player; - - if (player != nullptr) - { - player->GetPSprite(PSP_TARGETLEFT)->x = (160-3) - ((100 - player->mo->accuracy)); - player->GetPSprite(PSP_TARGETRIGHT)->x = (160-3)+ ((100 - player->mo->accuracy)); - } -} - // Morph powerup ------------------------------------------------------ IMPLEMENT_CLASS(APowerMorph, false, true) diff --git a/src/g_inventory/a_artifacts.h b/src/g_inventory/a_artifacts.h index 6cd10f637..6045b5c42 100644 --- a/src/g_inventory/a_artifacts.h +++ b/src/g_inventory/a_artifacts.h @@ -161,19 +161,6 @@ public: #define PSF_NOTRAIL 1 -class APowerTargeter : public APowerup -{ - DECLARE_CLASS (APowerTargeter, APowerup) -protected: - virtual void InitEffect () override; - virtual void DoEffect () override; - virtual void EndEffect () override; - void PositionAccuracy (); - virtual void Travelled () override; - virtual void AttachToOwner(AActor *other) override; - virtual bool HandlePickup(AInventory *item) override; -}; - class APowerMorph : public APowerup { DECLARE_CLASS( APowerMorph, APowerup ) diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 38568bb5e..6f51bb6b5 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -368,19 +368,6 @@ void AInventory::CallDoEffect() } -//=========================================================================== -// -// AInventory :: Travelled -// -// Called when an item in somebody's inventory is carried over to another -// map, in case it needs to do special reinitialization. -// -//=========================================================================== - -void AInventory::Travelled () -{ -} - //=========================================================================== // // AInventory :: OwnerDied @@ -1403,7 +1390,7 @@ bool AInventory::TryPickup (AActor *&toucher) copy->ItemFlags &= ~IF_CREATECOPYMOVED; } // Continue onwards with the rest - copy->AttachToOwner (newtoucher); + copy->CallAttachToOwner (newtoucher); if (ItemFlags & IF_AUTOACTIVATE) { if (copy->CallUse (true)) diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 894849ef2..9cd49bbaf 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -140,7 +140,6 @@ public: double GetSpeedFactor(); bool GetNoTeleportFreeze(); // Stuff for later when more features are exported. - virtual void Travelled(); virtual void OwnerDied(); diff --git a/src/g_level.cpp b/src/g_level.cpp index b8d73727c..0c7326c78 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -84,6 +84,7 @@ #include "r_utility.h" #include "p_spec.h" #include "serializer.h" +#include "virtual.h" #include "gi.h" @@ -1313,7 +1314,13 @@ void G_FinishTravel () { inv->ChangeStatNum (STAT_INVENTORY); inv->LinkToWorld (nullptr); - inv->Travelled (); + + IFVIRTUALPTR(inv, AInventory, Travelled) + { + VMValue params[1] = { inv }; + VMFrameStack stack; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } } if (ib_compatflags & BCOMPATF_RESETPLAYERSPEED) { diff --git a/src/namedef.h b/src/namedef.h index 329b2cea3..9e89a1acf 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -171,6 +171,7 @@ xx(PuzzleItemNumber) xx(HealthPickup) xx(autousemode) xx(Ammo) +xx(PowerTargeter) xx(AcolyteBlue) xx(SpectralLightningV1) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 66ae0207a..850c8ef0d 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -233,7 +233,7 @@ DPSprite *player_t::GetPSprite(PSPLayers layer) { if (mo != nullptr) { - newcaller = mo->FindInventory(RUNTIME_CLASS(APowerTargeter), true); + newcaller = mo->FindInventory(PClass::FindActor(NAME_PowerTargeter), true); } } else if (layer == PSP_STRIFEHANDS) diff --git a/wadsrc/static/zscript/inventory/inventory.txt b/wadsrc/static/zscript/inventory/inventory.txt index b2fc6a236..051f62bb3 100644 --- a/wadsrc/static/zscript/inventory/inventory.txt +++ b/wadsrc/static/zscript/inventory/inventory.txt @@ -38,6 +38,18 @@ class Inventory : Actor native virtual native void AttachToOwner(Actor user); virtual native void DetachFromOwner(); + //=========================================================================== + // + // AInventory :: Travelled + // + // Called when an item in somebody's inventory is carried over to another + // map, in case it needs to do special reinitialization. + // + //=========================================================================== + + virtual void Travelled() + {} + virtual double GetSpeedFactor() { return 1; } virtual bool GetNoTeleportFreeze() { return false; } virtual void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive) {} diff --git a/wadsrc/static/zscript/inventory/powerups.txt b/wadsrc/static/zscript/inventory/powerups.txt index 2842989f0..305b0d638 100644 --- a/wadsrc/static/zscript/inventory/powerups.txt +++ b/wadsrc/static/zscript/inventory/powerups.txt @@ -179,7 +179,7 @@ class PowerMinotaur : Powerup } } -class PowerTargeter : Powerup native +class PowerTargeter : Powerup { Default { @@ -196,6 +196,119 @@ class PowerTargeter : Powerup native TRGT C -1; Stop; } + + override void Travelled () + { + InitEffect (); + } + + override void InitEffect () + { + // Why is this called when the inventory isn't even attached yet + // in APowerup.CreateCopy? + if (!Owner.FindInventory(GetClass(), true)) + return; + + let player = Owner.player; + + Super.InitEffect(); + + if (player == null) + return; + + let stat = FindState("Targeter"); + + if (stat != null) + { + player.SetPsprite(PSprite.TARGETCENTER, stat); + player.SetPsprite(PSprite.TARGETLEFT, stat + 1); + player.SetPsprite(PSprite.TARGETRIGHT, stat + 2); + } + + player.GetPSprite(PSprite.TARGETCENTER).x = (160-3); + player.GetPSprite(PSprite.TARGETCENTER).y = + player.GetPSprite(PSprite.TARGETLEFT).y = + player.GetPSprite(PSprite.TARGETRIGHT).y = (100-3); + PositionAccuracy (); + } + + override void AttachToOwner(Actor other) + { + Super.AttachToOwner(other); + + // Let's actually properly call this for the targeters. + InitEffect(); + } + + override bool HandlePickup(Inventory item) + { + if (Super.HandlePickup(item)) + { + InitEffect(); // reset the HUD sprites + return true; + } + return false; + } + + override void DoEffect () + { + Super.DoEffect (); + + if (Owner != null && Owner.player != null) + { + let player = Owner.player; + + PositionAccuracy (); + if (EffectTics < 5*TICRATE) + { + let stat = FindState("Targeter"); + + if (stat != null) + { + if (EffectTics & 32) + { + player.SetPsprite(PSprite.TARGETRIGHT, null); + player.SetPsprite(PSprite.TARGETLEFT, stat + 1); + } + else if (EffectTics & 16) + { + player.SetPsprite(PSprite.TARGETRIGHT, stat + 2); + player.SetPsprite(PSprite.TARGETLEFT, null); + } + } + } + } + } + + override void EndEffect () + { + Super.EndEffect(); + if (Owner != null && Owner.player != null) + { + // Calling GetPSprite here could crash if we're creating a new game. + // This is because P_SetupLevel nulls the player's mo before destroying + // every DThinker which in turn ends up calling this. + // However P_SetupLevel is only called after G_NewInit which calls + // every player's dtor which destroys all their psprites. + let player = Owner.player; + PSprite pspr; + if ((pspr = player.FindPSprite(PSprite.TARGETCENTER)) != null) pspr.SetState(null); + if ((pspr = player.FindPSprite(PSprite.TARGETLEFT)) != null) pspr.SetState(null); + if ((pspr = player.FindPSprite(PSprite.TARGETRIGHT)) != null) pspr.SetState(null); + } + } + + private void PositionAccuracy () + { + let player = Owner.player; + + if (player != null) + { + player.GetPSprite(PSprite.TARGETLEFT).x = (160-3) - ((100 - player.mo.accuracy)); + player.GetPSprite(PSprite.TARGETRIGHT).x = (160-3)+ ((100 - player.mo.accuracy)); + } + } + } //=========================================================================== diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 2d8564164..e2f01d866 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -128,6 +128,16 @@ class PlayerChunk : PlayerPawn native class PSprite : Object native { + enum PSPLayers + { + STRIFEHANDS = -1, + WEAPON = 1, + FLASH = 1000, + TARGETCENTER = 0x7fffffff - 2, + TARGETLEFT, + TARGETRIGHT, + }; + native readonly State CurState; native readonly Actor Caller; native readonly PSprite Next;