From a105a08bd6035238790b99892856f61213db9a73 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 30 Dec 2016 20:00:24 +0100 Subject: [PATCH 1/5] - restored the original implementation of DONTOVERLAP, because Heretic depends on it being somewhat broken. A side effect of the incorrect implementation is that Gargoyles hitting other Gargoyles won't call P_DamageMobj. --- src/p_interaction.cpp | 2 +- src/p_map.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 102142d38f..9aa178e64d 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1545,7 +1545,7 @@ dopain: target->SetState (target->SeeState); } } - else if ((damage > 0 || fakedPain) && source != target->target && target->OkayToSwitchTarget (source)) + else if (source != target->target && target->OkayToSwitchTarget (source)) { // Target actor is not intent on another actor, // so make him chase after source diff --git a/src/p_map.cpp b/src/p_map.cpp index 1f53181f16..434db69f1d 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1298,7 +1298,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch if ((tm.thing->Z() >= topz) || (tm.thing->Top() <= thing->Z())) return true; } - // If they are not allowed to overlap, the rest of this function still needs to be executed. + else return unblocking; // This may not really make sense, but Heretic depends on the broken implementation. } } From 5e34bad03b81b6d3200fc321b8b8e45fc56cb35e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 30 Dec 2016 21:32:06 +0100 Subject: [PATCH 2/5] - fixed: AActor::Tick must call CallDoEffect, not DoEffect for its inventory items or scripted overrides won't be called. --- src/p_mobj.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 7e5dbc88e7..8d31035a20 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3801,7 +3801,7 @@ void AActor::Tick () // by the order in the inventory, not the order in the thinker table while (item != NULL && item->Owner == this) { - item->DoEffect(); + item->CallDoEffect(); item = item->Inventory; } From fe0f19e1e0f71feaf0e4710ddb9d2132d9816647 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 30 Dec 2016 23:32:43 +0100 Subject: [PATCH 3/5] - exported Powerup.InitEffect and EndEffect to scripting. --- src/g_inventory/a_artifacts.cpp | 51 ++++++++++++++++++++--- src/g_inventory/a_artifacts.h | 6 ++- src/g_shared/a_morph.cpp | 4 +- wadsrc/static/zscript/shared/powerups.txt | 3 ++ 4 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/g_inventory/a_artifacts.cpp b/src/g_inventory/a_artifacts.cpp index 131c161dcb..aac58997e2 100644 --- a/src/g_inventory/a_artifacts.cpp +++ b/src/g_inventory/a_artifacts.cpp @@ -21,6 +21,7 @@ #include "v_palette.h" #include "serializer.h" #include "r_utility.h" +#include "virtual.h" #include "r_data/colormaps.h" @@ -182,6 +183,25 @@ void APowerup::InitEffect () { } +DEFINE_ACTION_FUNCTION(APowerup, InitEffect) +{ + PARAM_SELF_PROLOGUE(APowerup); + self->InitEffect(); + return 0; +} + +void APowerup::CallInitEffect() +{ + IFVIRTUAL(APowerup, InitEffect) + { + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } + else InitEffect(); +} + + //=========================================================================== // // APowerup :: DoEffect @@ -230,6 +250,25 @@ void APowerup::EndEffect () } } +DEFINE_ACTION_FUNCTION(APowerup, EndEffect) +{ + PARAM_SELF_PROLOGUE(APowerup); + self->EndEffect(); + return 0; +} + +void APowerup::CallEndEffect() +{ + IFVIRTUAL(APowerup, InitEffect) + { + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } + else EndEffect(); +} + + //=========================================================================== // // APowerup :: Destroy @@ -238,7 +277,7 @@ void APowerup::EndEffect () void APowerup::Destroy () { - EndEffect (); + CallEndEffect (); Super::Destroy (); } @@ -325,7 +364,7 @@ AInventory *APowerup::CreateCopy (AActor *other) // properly attached to anything yet. Owner = other; // Actually activate the powerup. - InitEffect (); + CallInitEffect (); // Clear the Owner field, unless it was // changed by the activation, for example, // if this instance is a morph powerup; @@ -599,7 +638,7 @@ void APowerInvisibility::InitEffect () flags5 &= ~(Owner->flags5 & INVISIBILITY_FLAGS5); Owner->flags5 |= flags5 & INVISIBILITY_FLAGS5; - DoEffect(); + CallDoEffect(); } } @@ -1261,7 +1300,7 @@ IMPLEMENT_CLASS(APowerTargeter, false, false) void APowerTargeter::Travelled () { - InitEffect (); + CallInitEffect (); } void APowerTargeter::InitEffect () @@ -1299,14 +1338,14 @@ void APowerTargeter::AttachToOwner(AActor *other) Super::AttachToOwner(other); // Let's actually properly call this for the targeters. - InitEffect(); + CallInitEffect(); } bool APowerTargeter::HandlePickup(AInventory *item) { if (Super::HandlePickup(item)) { - InitEffect(); // reset the HUD sprites + CallInitEffect(); // reset the HUD sprites return true; } return false; diff --git a/src/g_inventory/a_artifacts.h b/src/g_inventory/a_artifacts.h index bb821b5d63..36f4d3443f 100644 --- a/src/g_inventory/a_artifacts.h +++ b/src/g_inventory/a_artifacts.h @@ -26,11 +26,15 @@ public: FNameNoInit Mode; double Strength; -protected: +public: virtual void InitEffect (); virtual void DoEffect () override; virtual void EndEffect (); +protected: + void CallInitEffect(); + void CallEndEffect(); + friend void EndAllPowerupEffects(AInventory *item); friend void InitAllPowerupEffects(AInventory *item); }; diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 136c096a31..7550ff0da7 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -585,7 +585,7 @@ void EndAllPowerupEffects(AInventory *item) { if (item->IsKindOf(RUNTIME_CLASS(APowerup))) { - static_cast(item)->EndEffect(); + static_cast(item)->CallEndEffect(); } item = item->Inventory; } @@ -605,7 +605,7 @@ void InitAllPowerupEffects(AInventory *item) { if (item->IsKindOf(RUNTIME_CLASS(APowerup))) { - static_cast(item)->InitEffect(); + static_cast(item)->CallInitEffect(); } item = item->Inventory; } diff --git a/wadsrc/static/zscript/shared/powerups.txt b/wadsrc/static/zscript/shared/powerups.txt index d28799ff23..43af361f38 100644 --- a/wadsrc/static/zscript/shared/powerups.txt +++ b/wadsrc/static/zscript/shared/powerups.txt @@ -25,6 +25,9 @@ class Powerup : Inventory native // Note, that while this is an inventory flag, it only has meaning on an active powerup. override bool GetNoTeleportFreeze() { return bNoTeleportFreeze; } + + native virtual void InitEffect(); + native virtual void EndEffect(); } From 3b524cbed4aed133fe05ae57881767cc9e3da2c3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 31 Dec 2016 00:20:02 +0100 Subject: [PATCH 4/5] - scriptified PowerInfiniteAmmo to test the exported functions. --- src/g_inventory/a_artifacts.cpp | 41 +---------------------- src/g_inventory/a_artifacts.h | 8 ----- wadsrc/static/zscript/constants.txt | 29 ++++++++++++++++ wadsrc/static/zscript/shared/powerups.txt | 31 ++++++++++++++++- 4 files changed, 60 insertions(+), 49 deletions(-) diff --git a/src/g_inventory/a_artifacts.cpp b/src/g_inventory/a_artifacts.cpp index aac58997e2..17c2269b2c 100644 --- a/src/g_inventory/a_artifacts.cpp +++ b/src/g_inventory/a_artifacts.cpp @@ -259,7 +259,7 @@ DEFINE_ACTION_FUNCTION(APowerup, EndEffect) void APowerup::CallEndEffect() { - IFVIRTUAL(APowerup, InitEffect) + IFVIRTUAL(APowerup, EndEffect) { VMValue params[1] = { (DObject*)this }; VMFrameStack stack; @@ -1993,42 +1993,3 @@ void APowerMorph::EndEffect( ) MorphedPlayer = NULL; } -// Infinite Ammo Powerup ----------------------------------------------------- - -IMPLEMENT_CLASS(APowerInfiniteAmmo, false, false) - -//=========================================================================== -// -// APowerInfiniteAmmo :: InitEffect -// -//=========================================================================== - -void APowerInfiniteAmmo::InitEffect( ) -{ - Super::InitEffect(); - - if (Owner== NULL || Owner->player == NULL) - return; - - // Give the player infinite ammo - Owner->player->cheats |= CF_INFINITEAMMO; -} - -//=========================================================================== -// -// APowerInfiniteAmmo :: EndEffect -// -//=========================================================================== - -void APowerInfiniteAmmo::EndEffect( ) -{ - Super::EndEffect(); - - // Nothing to do if there's no owner. - if (Owner != NULL && Owner->player != NULL) - { - // Take away the limitless ammo - Owner->player->cheats &= ~CF_INFINITEAMMO; - } -} - diff --git a/src/g_inventory/a_artifacts.h b/src/g_inventory/a_artifacts.h index 36f4d3443f..82f93649c4 100644 --- a/src/g_inventory/a_artifacts.h +++ b/src/g_inventory/a_artifacts.h @@ -257,14 +257,6 @@ protected: virtual void EndEffect() override; }; -class APowerInfiniteAmmo : public APowerup -{ - DECLARE_CLASS( APowerInfiniteAmmo, APowerup ) -protected: - virtual void InitEffect() override; - virtual void EndEffect() override; -}; - class APowerMorph : public APowerup { DECLARE_CLASS( APowerMorph, APowerup ) diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 1d2064aa1a..20df35dd7f 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -1055,3 +1055,32 @@ enum EPuffFlags PF_HITTHINGBLEED = 8, PF_NORANDOMZ = 16 }; + +enum EPlayerCheats +{ + CF_NOCLIP = 1 << 0, // No clipping, walk through barriers. + CF_GODMODE = 1 << 1, // No damage, no health loss. + CF_NOVELOCITY = 1 << 2, // Not really a cheat, just a debug aid. + CF_NOTARGET = 1 << 3, // [RH] Monsters don't target + CF_FLY = 1 << 4, // [RH] Flying player + CF_CHASECAM = 1 << 5, // [RH] Put camera behind player + CF_FROZEN = 1 << 6, // [RH] Don't let the player move + CF_REVERTPLEASE = 1 << 7, // [RH] Stick camera in player's head if (s)he moves + CF_STEPLEFT = 1 << 9, // [RH] Play left footstep sound next time + CF_FRIGHTENING = 1 << 10, // [RH] Scare monsters away + CF_INSTANTWEAPSWITCH= 1 << 11, // [RH] Switch weapons instantly + CF_TOTALLYFROZEN = 1 << 12, // [RH] All players can do is press +use + CF_PREDICTING = 1 << 13, // [RH] Player movement is being predicted + CF_INTERPVIEW = 1 << 14, // [RH] view was changed outside of input, so interpolate one frame + CF_DRAIN = 1 << 16, // Player owns a drain powerup + CF_HIGHJUMP = 1 << 18, // more Skulltag flags. Implementation not guaranteed though. ;) + CF_REFLECTION = 1 << 19, + CF_PROSPERITY = 1 << 20, + CF_DOUBLEFIRINGSPEED= 1 << 21, // Player owns a double firing speed artifact + CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths. + CF_INFINITEAMMO = 1 << 23, // Player owns an infinite ammo artifact + CF_BUDDHA2 = 1 << 24, // [MC] Absolute buddha. No voodoo can kill it either. + CF_GODMODE2 = 1 << 25, // [MC] Absolute godmode. No voodoo can kill it either. + CF_BUDDHA = 1 << 27, // [SP] Buddha mode - take damage, but don't die + CF_NOCLIP2 = 1 << 30, // [RH] More Quake-like noclip +}; diff --git a/wadsrc/static/zscript/shared/powerups.txt b/wadsrc/static/zscript/shared/powerups.txt index 43af361f38..255372f912 100644 --- a/wadsrc/static/zscript/shared/powerups.txt +++ b/wadsrc/static/zscript/shared/powerups.txt @@ -281,11 +281,40 @@ class PowerMorph : Powerup native } } -class PowerInfiniteAmmo : Powerup native +//=========================================================================== +// +// PowerInfiniteAmmo +// +//=========================================================================== + +class PowerInfiniteAmmo : Powerup { Default { Powerup.Duration -30; } + + override void InitEffect() + { + Super.InitEffect(); + + if (Owner!= null && Owner.player != null) + { + // Give the player infinite ammo + Owner.player.cheats |= CF_INFINITEAMMO; + } + } + + override void EndEffect() + { + Super.EndEffect(); + + // Nothing to do if there's no owner. + if (Owner!= null && Owner.player != null) + { + // Take away the limitless ammo + Owner.player.cheats &= ~CF_INFINITEAMMO; + } + } } From 267b1842b4cf4b52e7e7a76bc5a585cf959d78b4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 31 Dec 2016 01:08:09 +0100 Subject: [PATCH 5/5] - scriptified a few more of the simpler powerups. --- src/am_map.cpp | 2 +- src/g_inventory/a_artifacts.cpp | 142 ------------------- src/g_inventory/a_artifacts.h | 36 ----- src/namedef.h | 1 + wadsrc/static/zscript/shared/powerups.txt | 160 +++++++++++++++++++--- 5 files changed, 142 insertions(+), 199 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 8fb46ed6b9..8c250ee685 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -3050,7 +3050,7 @@ void AM_Drawer () return; bool allmap = (level.flags2 & LEVEL2_ALLMAP) != 0; - bool allthings = allmap && players[consoleplayer].mo->FindInventory(RUNTIME_CLASS(APowerScanner), true) != NULL; + bool allthings = allmap && players[consoleplayer].mo->FindInventory(PClass::FindActor(NAME_PowerScanner), true) != nullptr; if (am_portaloverlay) { diff --git a/src/g_inventory/a_artifacts.cpp b/src/g_inventory/a_artifacts.cpp index 17c2269b2c..00efa0579d 100644 --- a/src/g_inventory/a_artifacts.cpp +++ b/src/g_inventory/a_artifacts.cpp @@ -1481,10 +1481,6 @@ void APowerBuddha::EndEffect () Owner->player->cheats &= ~CF_BUDDHA; } -// Scanner powerup ---------------------------------------------------------- - -IMPLEMENT_CLASS(APowerScanner, false, false) - // Time freezer powerup ----------------------------------------------------- IMPLEMENT_CLASS( APowerTimeFreezer, false, false) @@ -1747,144 +1743,6 @@ void APowerProtection::ModifyDamage(int damage, FName damageType, int &newdamage } } -// Drain rune ------------------------------------------------------- - -IMPLEMENT_CLASS(APowerDrain, false, false) - -//=========================================================================== -// -// ARuneDrain :: InitEffect -// -//=========================================================================== - -void APowerDrain::InitEffect( ) -{ - Super::InitEffect(); - - if (Owner== NULL || Owner->player == NULL) - return; - - // Give the player the power to drain life from opponents when he damages them. - Owner->player->cheats |= CF_DRAIN; -} - -//=========================================================================== -// -// ARuneDrain :: EndEffect -// -//=========================================================================== - -void APowerDrain::EndEffect( ) -{ - Super::EndEffect(); - - // Nothing to do if there's no owner. - if (Owner != NULL && Owner->player != NULL) - { - // Take away the drain power. - Owner->player->cheats &= ~CF_DRAIN; - } -} - - -// Regeneration rune ------------------------------------------------------- - -IMPLEMENT_CLASS(APowerRegeneration, false, false) - -//=========================================================================== -// -// APowerRegeneration :: DoEffect -// -//=========================================================================== - -void APowerRegeneration::DoEffect() -{ - Super::DoEffect(); - if (Owner != NULL && Owner->health > 0 && (level.time & 31) == 0) - { - if (P_GiveBody(Owner, int(Strength))) - { - S_Sound(Owner, CHAN_ITEM, "*regenerate", 1, ATTN_NORM ); - } - } -} - -// High jump rune ------------------------------------------------------- - -IMPLEMENT_CLASS(APowerHighJump, false, false) - -//=========================================================================== -// -// ARuneHighJump :: InitEffect -// -//=========================================================================== - -void APowerHighJump::InitEffect( ) -{ - Super::InitEffect(); - - if (Owner== NULL || Owner->player == NULL) - return; - - // Give the player the power to jump much higher. - Owner->player->cheats |= CF_HIGHJUMP; -} - -//=========================================================================== -// -// ARuneHighJump :: EndEffect -// -//=========================================================================== - -void APowerHighJump::EndEffect( ) -{ - Super::EndEffect(); - // Nothing to do if there's no owner. - if (Owner != NULL && Owner->player != NULL) - { - // Take away the high jump power. - Owner->player->cheats &= ~CF_HIGHJUMP; - } -} - -// Double firing speed rune --------------------------------------------- - -IMPLEMENT_CLASS(APowerDoubleFiringSpeed, false, false) - -//=========================================================================== -// -// APowerDoubleFiringSpeed :: InitEffect -// -//=========================================================================== - -void APowerDoubleFiringSpeed::InitEffect( ) -{ - Super::InitEffect(); - - if (Owner== NULL || Owner->player == NULL) - return; - - // Give the player the power to shoot twice as fast. - Owner->player->cheats |= CF_DOUBLEFIRINGSPEED; -} - -//=========================================================================== -// -// APowerDoubleFiringSpeed :: EndEffect -// -//=========================================================================== - -void APowerDoubleFiringSpeed::EndEffect( ) -{ - Super::EndEffect(); - // Nothing to do if there's no owner. - if (Owner != NULL && Owner->player != NULL) - { - // Take away the shooting twice as fast power. - Owner->player->cheats &= ~CF_DOUBLEFIRINGSPEED; - } -} - // Morph powerup ------------------------------------------------------ IMPLEMENT_CLASS(APowerMorph, false, true) diff --git a/src/g_inventory/a_artifacts.h b/src/g_inventory/a_artifacts.h index 82f93649c4..f68516de7b 100644 --- a/src/g_inventory/a_artifacts.h +++ b/src/g_inventory/a_artifacts.h @@ -165,11 +165,6 @@ class APowerMinotaur : public APowerup DECLARE_CLASS (APowerMinotaur, APowerup) }; -class APowerScanner : public APowerup -{ - DECLARE_CLASS (APowerScanner, APowerup) -}; - class APowerTargeter : public APowerup { DECLARE_CLASS (APowerTargeter, APowerup) @@ -226,37 +221,6 @@ protected: virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive) override; }; -class APowerDrain : public APowerup -{ - DECLARE_CLASS( APowerDrain, APowerup ) -protected: - virtual void InitEffect() override; - virtual void EndEffect() override; -}; - -class APowerRegeneration : public APowerup -{ - DECLARE_CLASS( APowerRegeneration, APowerup ) -protected: - virtual void DoEffect() override; -}; - -class APowerHighJump : public APowerup -{ - DECLARE_CLASS( APowerHighJump, APowerup ) -protected: - virtual void InitEffect() override; - virtual void EndEffect() override; -}; - -class APowerDoubleFiringSpeed : public APowerup -{ - DECLARE_CLASS( APowerDoubleFiringSpeed, APowerup ) -protected: - virtual void InitEffect() override; - virtual void EndEffect() override; -}; - class APowerMorph : public APowerup { DECLARE_CLASS( APowerMorph, APowerup ) diff --git a/src/namedef.h b/src/namedef.h index d50f8131dc..45e1e67f28 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -354,6 +354,7 @@ xx(MapSpot) xx(PatrolPoint) xx(PatrolSpecial) xx(Communicator) +xx(PowerScanner) // Textmap properties //xx(X) diff --git a/wadsrc/static/zscript/shared/powerups.txt b/wadsrc/static/zscript/shared/powerups.txt index 255372f912..8689511666 100644 --- a/wadsrc/static/zscript/shared/powerups.txt +++ b/wadsrc/static/zscript/shared/powerups.txt @@ -213,7 +213,13 @@ class PowerBuddha : Powerup native } } -class PowerScanner : Powerup native +//=========================================================================== +// +// Scanner (this is active just by being present) +// +//=========================================================================== + +class PowerScanner : Powerup { Default { @@ -246,44 +252,138 @@ class PowerProtection : Powerup native } } -class PowerDrain : Powerup native +//=========================================================================== +// +// Drain +// +//=========================================================================== + +class PowerDrain : Powerup { Default { Powerup.Duration -60; } + + override void InitEffect() + { + Super.InitEffect(); + + if (Owner!= null && Owner.player != null) + { + // Give the player the power to drain life from opponents when he damages them. + Owner.player.cheats |= CF_DRAIN; + } + } + + override void EndEffect() + { + Super.EndEffect(); + + // Nothing to do if there's no owner. + if (Owner!= null && Owner.player != null) + { + // Take away the drain power. + Owner.player.cheats &= ~CF_DRAIN; + } + } + } -class PowerRegeneration : Powerup native +//=========================================================================== +// +// Regeneration +// +//=========================================================================== + +class PowerRegeneration : Powerup { Default { Powerup.Duration -120; Powerup.Strength 5; } -} - -class PowerHighJump : Powerup native {} - -class PowerDoubleFiringSpeed : Powerup native {} - -class PowerMorph : Powerup native -{ - native Class PlayerClass; - native Class MorphFlash, UnMorphFlash; - native int MorphStyle; - native PlayerInfo MorphedPlayer; - native bool bInUndoMorph; - - Default + + override void DoEffect() { - Powerup.Duration -40; + Super.DoEffect(); + if (Owner != null && Owner.health > 0 && (level.time & 31) == 0) + { + if (Owner.GiveBody(int(Strength))) + { + Owner.A_PlaySound("*regenerate", CHAN_ITEM); + } + } } } //=========================================================================== // -// PowerInfiniteAmmo +// HighJump +// +//=========================================================================== + +class PowerHighJump : Powerup +{ + override void InitEffect() + { + Super.InitEffect(); + + if (Owner!= null && Owner.player != null) + { + // Give the player the power to jump much higher. + Owner.player.cheats |= CF_HIGHJUMP; + } + } + + override void EndEffect() + { + Super.EndEffect(); + + // Nothing to do if there's no owner. + if (Owner!= null && Owner.player != null) + { + // Take away the high jump power. + Owner.player.cheats &= ~CF_HIGHJUMP; + } + } +} + +//=========================================================================== +// +// DoubleFiringSpeed +// +//=========================================================================== + +class PowerDoubleFiringSpeed : Powerup +{ + override void InitEffect() + { + Super.InitEffect(); + + if (Owner!= null && Owner.player != null) + { + // Give the player the power to shoot twice as fast. + Owner.player.cheats |= CF_DOUBLEFIRINGSPEED; + } + } + + override void EndEffect() + { + Super.EndEffect(); + + // Nothing to do if there's no owner. + if (Owner!= null && Owner.player != null) + { + // Take away the shooting twice as fast power. + Owner.player.cheats &= ~CF_DOUBLEFIRINGSPEED; + } + } +} + +//=========================================================================== +// +// InfiniteAmmo // //=========================================================================== @@ -318,3 +418,23 @@ class PowerInfiniteAmmo : Powerup } } +//=========================================================================== +// +// PowerMorph +// +//=========================================================================== + +class PowerMorph : Powerup native +{ + native Class PlayerClass; + native Class MorphFlash, UnMorphFlash; + native int MorphStyle; + native PlayerInfo MorphedPlayer; + native bool bInUndoMorph; + + Default + { + Powerup.Duration -40; + } +} +