diff --git a/src/actor.h b/src/actor.h index 5218b7fc3e..58a8c2792c 100644 --- a/src/actor.h +++ b/src/actor.h @@ -746,15 +746,8 @@ public: // APlayerPawn for some specific handling for players. None of this // should ever be overridden by custom classes. - // Take the amount value of an item from the inventory list. - // If nothing is left, the item may be destroyed. - // Returns true if the initial item count is positive. - virtual bool TakeInventory (PClassActor *itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false); - - bool SetInventory(PClassActor *itemclass, int amount, bool beyondMax); - // Uses an item and removes it from the inventory. - virtual bool UseInventory (AInventory *item); + bool UseInventory (AInventory *item); // Tosses an item out of the inventory. AInventory *DropInventory (AInventory *item, int amt = -1); diff --git a/src/d_player.h b/src/d_player.h index e6137b53f5..2a5e3ef609 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -89,7 +89,6 @@ public: virtual void PostBeginPlay() override; virtual void Tick() override; - virtual bool UseInventory (AInventory *item) override; virtual void BeginPlay () override; virtual bool UpdateWaterLevel (bool splash) override; diff --git a/src/g_statusbar/sbar.h b/src/g_statusbar/sbar.h index 52ba6dfd41..264749d23b 100644 --- a/src/g_statusbar/sbar.h +++ b/src/g_statusbar/sbar.h @@ -424,7 +424,6 @@ public: void CallDraw(EHudState state, double ticFrac); void DrawBottomStuff (EHudState state); void DrawTopStuff (EHudState state); - void FlashItem (const PClass *itemtype); void AttachToPlayer(player_t *player); DVector2 GetHUDScale() const; virtual void FlashCrosshair (); diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index 9990cdb116..34171a3c4c 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -1190,15 +1190,6 @@ void DBaseStatusBar::DrawWaiting () const } } -void DBaseStatusBar::FlashItem (const PClass *itemtype) -{ - IFVIRTUAL(DBaseStatusBar, FlashItem) - { - VMValue params[] = { (DObject*)this, (PClass*)itemtype }; - VMCall(func, params, countof(params), nullptr, 0); - } -} - void DBaseStatusBar::NewGame () { IFVIRTUAL(DBaseStatusBar, NewGame) @@ -1232,7 +1223,7 @@ void DBaseStatusBar::ScreenSizeChanged () for (size_t i = 0; i < countof(Messages); ++i) { - DHUDMessageBase *message = Messages[i]; + DHUDMessageBase *message = Messages[i]; while (message != NULL) { message->CallScreenSizeChanged (); diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index f9c0f6783a..674141eae0 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -549,25 +549,11 @@ FString cht_Morph(player_t *player, PClassActor *morphclass, bool quickundo) void cht_SetInv(player_t *player, const char *string, int amount, bool beyond) { - if (!stricmp(string, "health")) + IFVIRTUALPTR(player->mo, APlayerPawn, CheatSetInv) { - if (amount <= 0) - { - cht_Suicide(player); - return; - } - if (!beyond) amount = MIN(amount, player->mo->GetMaxHealth(true)); - player->health = player->mo->health = amount; - } - else - { - auto item = PClass::FindActor(string); - if (item != nullptr && item->IsDescendantOf(RUNTIME_CLASS(AInventory))) - { - player->mo->SetInventory(item, amount, beyond); - return; - } - Printf("Unknown item \"%s\"\n", string); + FString message = string; + VMValue params[] = { player->mo, &message, amount, beyond }; + VMCall(func, params, 4, nullptr, 0); } } diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index e863a442c5..b43fdd33cf 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -1588,238 +1588,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_CustomRailgun) return 0; } -//=========================================================================== -// -// DoGiveInventory -// -//=========================================================================== - -static bool DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS) -{ - int paramnum = 0; - PARAM_CLASS (mi, AInventory); - PARAM_INT (amount) - - if (!orresult) - { - PARAM_INT(setreceiver) - receiver = COPY_AAPTR(receiver, setreceiver); - } - if (receiver == NULL) - { // If there's nothing to receive it, it's obviously a fail, right? - return false; - } - // Owned inventory items cannot own anything because their Inventory pointer is repurposed for the owner's linked list. - if (receiver->IsKindOf(RUNTIME_CLASS(AInventory)) && static_cast(receiver)->Owner != nullptr) - { - return false; - } - - if (amount <= 0) - { - amount = 1; - } - if (mi) - { - AInventory *item = static_cast(Spawn(mi)); - if (item == NULL) - { - return false; - } - if (item->IsKindOf(NAME_Health)) - { - item->Amount *= amount; - } - else - { - item->Amount = amount; - } - item->flags |= MF_DROPPED; - item->ClearCounters(); - if (!item->CallTryPickup(receiver)) - { - item->Destroy(); - return false; - } - else - { - return true; - } - } - return false; -} - -DEFINE_ACTION_FUNCTION(AActor, A_GiveInventory) -{ - PARAM_SELF_PROLOGUE(AActor); - ACTION_RETURN_BOOL(DoGiveInventory(self, false, VM_ARGS_NAMES)); -} - -DEFINE_ACTION_FUNCTION(AActor, A_GiveToTarget) -{ - PARAM_SELF_PROLOGUE(AActor); - ACTION_RETURN_BOOL(DoGiveInventory(self->target, false, VM_ARGS_NAMES)); -} - -DEFINE_ACTION_FUNCTION(AActor, A_GiveToChildren) -{ - PARAM_SELF_PROLOGUE(AActor); - - TThinkerIterator it; - AActor *mo; - int count = 0; - - while ((mo = it.Next())) - { - if (mo->master == self) - { - count += DoGiveInventory(mo, true, VM_ARGS_NAMES); - } - } - ACTION_RETURN_INT(count); -} - -DEFINE_ACTION_FUNCTION(AActor, A_GiveToSiblings) -{ - PARAM_SELF_PROLOGUE(AActor); - - TThinkerIterator it; - AActor *mo; - int count = 0; - - if (self->master != NULL) - { - while ((mo = it.Next())) - { - if (mo->master == self->master && mo != self) - { - count += DoGiveInventory(mo, true, VM_ARGS_NAMES); - } - } - } - ACTION_RETURN_INT(count); -} - -//=========================================================================== -// -// A_SetInventory -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_SetInventory) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_CLASS(itemtype, AInventory); - PARAM_INT(amount); - PARAM_INT(ptr); - PARAM_BOOL(beyondMax); - - bool res = false; - - if (itemtype == nullptr) - { - ACTION_RETURN_BOOL(false); - } - - AActor *mobj = COPY_AAPTR(self, ptr); - - if (mobj == nullptr) - { - ACTION_RETURN_BOOL(false); - } - - // Do not run this function on voodoo dolls because the way they transfer the inventory to the player will not work with the code below. - if (mobj->player != nullptr) - { - mobj = mobj->player->mo; - } - ACTION_RETURN_BOOL(mobj->SetInventory(itemtype, amount, beyondMax)); -} - -//=========================================================================== -// -// A_TakeInventory -// -//=========================================================================== - -enum -{ - TIF_NOTAKEINFINITE = 1, -}; - -bool DoTakeInventory(AActor *receiver, bool orresult, VM_ARGS) -{ - int paramnum = 0; - PARAM_CLASS (itemtype, AInventory); - PARAM_INT (amount); - PARAM_INT (flags); - - if (itemtype == NULL) - { - return false; - } - if (!orresult) - { - PARAM_INT(setreceiver); - receiver = COPY_AAPTR(receiver, setreceiver); - } - if (receiver == NULL) - { - return false; - } - - return receiver->TakeInventory(itemtype, amount, true, (flags & TIF_NOTAKEINFINITE) != 0); -} - -DEFINE_ACTION_FUNCTION(AActor, A_TakeInventory) -{ - PARAM_SELF_PROLOGUE(AActor); - ACTION_RETURN_BOOL(DoTakeInventory(self, false, VM_ARGS_NAMES)); -} - -DEFINE_ACTION_FUNCTION(AActor, A_TakeFromTarget) -{ - PARAM_SELF_PROLOGUE(AActor); - ACTION_RETURN_BOOL(DoTakeInventory(self->target, false, VM_ARGS_NAMES)); -} - -DEFINE_ACTION_FUNCTION(AActor, A_TakeFromChildren) -{ - PARAM_SELF_PROLOGUE(AActor); - TThinkerIterator it; - AActor *mo; - int count = 0; - - while ((mo = it.Next())) - { - if (mo->master == self) - { - count += DoTakeInventory(mo, true, VM_ARGS_NAMES); - } - } - ACTION_RETURN_INT(count); -} - -DEFINE_ACTION_FUNCTION(AActor, A_TakeFromSiblings) -{ - PARAM_SELF_PROLOGUE(AActor); - TThinkerIterator it; - AActor *mo; - int count = 0; - - if (self->master != NULL) - { - while ((mo = it.Next())) - { - if (mo->master == self->master && mo != self) - { - count += DoTakeInventory(mo, true, VM_ARGS_NAMES); - } - } - } - ACTION_RETURN_INT(count); -} - //=========================================================================== // // A_Recoil diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index d0e67ca7af..1d8c48055b 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -641,7 +641,11 @@ static void TakeStrifeItem (player_t *player, PClassActor *itemtype, int amount) if (itemtype->TypeName == NAME_Sigil) return; - player->mo->TakeInventory(itemtype, amount); + IFVM(Actor, TakeInventory) + { + VMValue params[] = { player->mo, itemtype, amount, false, false }; + VMCall(func, params, 5, nullptr, 0); + } } CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 3dc5d88680..00b63790dc 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -753,91 +753,6 @@ DEFINE_ACTION_FUNCTION(AActor, SetState) ACTION_RETURN_BOOL(self->SetState(state, nofunction)); }; -//============================================================================ -// -// AActor :: TakeInventory -// -//============================================================================ - -bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate, bool notakeinfinite) -{ - IFVM(Actor, TakeInventory) - { - VMValue params[] = { this, itemclass, amount, fromdecorate, notakeinfinite }; - int retval = 0; - VMReturn ret(&retval); - VMCall(func, params, 5, &ret, 1); - return !!retval; - } -} - - -bool AActor::SetInventory(PClassActor *itemtype, int amount, bool beyondMax) -{ - AInventory *item = FindInventory(itemtype); - - if (item != nullptr) - { - // A_SetInventory sets the absolute amount. - // Subtract or set the appropriate amount as necessary. - - if (amount == item->Amount) - { - // Nothing was changed. - return false; - } - else if (amount <= 0) - { - //Remove it all. - return TakeInventory(itemtype, item->Amount, true, false); - } - else if (amount < item->Amount) - { - int amt = abs(item->Amount - amount); - return TakeInventory(itemtype, amt, true, false); - } - else - { - item->Amount = (beyondMax ? amount : clamp(amount, 0, item->MaxAmount)); - return true; - } - } - else - { - if (amount <= 0) - { - return true; - } - item = static_cast(Spawn(itemtype)); - if (item == nullptr) - { - return false; - } - else - { - item->Amount = amount; - item->flags |= MF_DROPPED; - item->ItemFlags |= IF_IGNORESKILL; - item->ClearCounters(); - if (!item->CallTryPickup(this)) - { - item->Destroy(); - return false; - } - return true; - } - } - return false; -} - -DEFINE_ACTION_FUNCTION(AActor, SetInventory) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_CLASS_NOT_NULL(item, AInventory); - PARAM_INT(amount); - PARAM_BOOL(beyondMax); - ACTION_RETURN_BOOL(self->SetInventory(item, amount, beyondMax)); -} //============================================================================ // @@ -919,41 +834,14 @@ DEFINE_ACTION_FUNCTION(AActor, FirstInv) bool AActor::UseInventory (AInventory *item) { - // No using items if you're dead. - if (health <= 0) + IFVIRTUAL(AActor, UseInventory) { - return false; - } - // Don't use it if you don't actually have any of it. - if (item->Amount <= 0 || (item->ObjectFlags & OF_EuthanizeMe)) - { - return false; - } - - IFVIRTUALPTR(item, AInventory, Use) - { - VMValue params[2] = { item, false }; - int retval; + VMValue params[] = { this, item }; + int retval = 0; VMReturn ret(&retval); VMCall(func, params, 2, &ret, 1); - if (!retval) return false; + return !!retval; } - - if (dmflags2 & DF2_INFINITE_INVENTORY) - return true; - - if (--item->Amount <= 0) - { - item->DepleteOrDestroy (); - } - return true; -} - -DEFINE_ACTION_FUNCTION(AActor, UseInventory) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT_NOT_NULL(item, AInventory); - ACTION_RETURN_BOOL(self->UseInventory(item)); } //=========================================================================== diff --git a/src/p_user.cpp b/src/p_user.cpp index d440b5f2ed..179819fd78 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -938,40 +938,6 @@ void APlayerPawn::PostBeginPlay() } } -//=========================================================================== -// -// APlayerPawn :: UseInventory -// -//=========================================================================== - -bool APlayerPawn::UseInventory (AInventory *item) -{ - const PClass *itemtype = item->GetClass(); - - if (player->cheats & CF_TOTALLYFROZEN) - { // You can't use items if you're totally frozen - return false; - } - if ((level.flags2 & LEVEL2_FROZEN) && (player == NULL || player->timefreezer == 0)) - { - // Time frozen - return false; - } - - if (!Super::UseInventory (item)) - { - // Heretic and Hexen advance the inventory cursor if the use failed. - // Should this behavior be retained? - return false; - } - if (player == &players[consoleplayer]) - { - S_Sound (this, CHAN_ITEM, item->UseSound, 1, ATTN_NORM); - StatusBar->FlashItem (itemtype); - } - return true; -} - //=========================================================================== // // APlayerPawn :: PickNewWeapon diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index e1f5605ae1..5c7e122119 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -743,11 +743,9 @@ class Actor : Thinker native native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); native void ClearInventory(); protected native void DestroyAllInventory(); // This is not supposed to be called by user code! - native bool SetInventory(class itemclass, int amount, bool beyondMax = false); native clearscope Inventory FindInventory(class itemtype, bool subclass = false) const; native Inventory GiveInventoryType(class itemtype); native Inventory DropInventory (Inventory item, int amt = -1); - native bool UseInventory(Inventory item); native void ObtainInventory(Actor other); native bool GiveAmmo (Class type, int amount); native bool UsePuzzleItem(int PuzzleItemType); @@ -1013,9 +1011,6 @@ class Actor : Thinker native native action state A_Jump(int chance, statelabel label, ...); native Actor A_SpawnProjectile(class missiletype, double spawnheight = 32, double spawnofs_xy = 0, double angle = 0, int flags = 0, double pitch = 0, int ptr = AAPTR_TARGET); native void A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = 0, color color2 = 0, int flags = 0, int aim = 0, double maxdiff = 0, class pufftype = "BulletPuff", double spread_xy = 0, double spread_z = 0, double range = 0, int duration = 0, double sparsity = 1.0, double driftspeed = 1.0, class spawnclass = null, double spawnofs_z = 0, int spiraloffset = 270, int limit = 0, double veleffect = 3); - native bool A_SetInventory(class itemtype, int amount, int ptr = AAPTR_DEFAULT, bool beyondMax = false); - native bool A_GiveInventory(class itemtype, int amount = 0, int giveto = AAPTR_DEFAULT); - native bool A_TakeInventory(class itemtype, int amount = 0, int flags = 0, int giveto = AAPTR_DEFAULT); native void A_Print(string whattoprint, double time = 0, name fontname = "none"); native void A_PrintBold(string whattoprint, double time = 0, name fontname = "none"); native void A_Log(string whattoprint, bool local = false); @@ -1049,8 +1044,6 @@ class Actor : Thinker native native void A_LookEx(int flags = 0, double minseedist = 0, double maxseedist = 0, double maxheardist = 0, double fov = 0, statelabel label = null); native void A_Recoil(double xyvel); - native bool A_GiveToTarget(class itemtype, int amount = 0, int forward_ptr = AAPTR_DEFAULT); - native bool A_TakeFromTarget(class itemtype, int amount = 0, int flags = 0, int forward_ptr = AAPTR_DEFAULT); native int A_RadiusGive(class itemtype, double distance, int flags, int amount = 0, class filter = null, name species = "None", double mindist = 0, int limit = 0); native void A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true); native void A_CustomComboAttack(class missiletype, double spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true); @@ -1097,10 +1090,6 @@ class Actor : Thinker native native void A_RemoveChildren(bool removeall = false, int flags = 0, class filter = null, name species = "None"); native void A_RemoveSiblings(bool removeall = false, int flags = 0, class filter = null, name species = "None"); native void A_Remove(int removee, int flags = 0, class filter = null, name species = "None"); - native int A_GiveToChildren(class itemtype, int amount = 0); - native int A_GiveToSiblings(class itemtype, int amount = 0); - native int A_TakeFromChildren(class itemtype, int amount = 0); - native int A_TakeFromSiblings(class itemtype, int amount = 0); native void A_SetTeleFog(class oldpos, class newpos); native void A_SwapTeleFog(); native void A_SetHealth(int health, int ptr = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/actor_inventory.txt b/wadsrc/static/zscript/actor_inventory.txt index 910c575892..f8c4865782 100644 --- a/wadsrc/static/zscript/actor_inventory.txt +++ b/wadsrc/static/zscript/actor_inventory.txt @@ -159,4 +159,311 @@ extend class Actor } -} \ No newline at end of file + //============================================================================ + // + // AActor :: SetInventory + // + //============================================================================ + + bool SetInventory(class itemclass, int amount, bool beyondMax = false) + { + let item = FindInventory(itemclass); + + if (item != null) + { + // A_SetInventory sets the absolute amount. + // Subtract or set the appropriate amount as necessary. + + if (amount == item.Amount) + { + // Nothing was changed. + return false; + } + else if (amount <= 0) + { + //Remove it all. + return TakeInventory(itemclass, item.Amount, true, false); + } + else if (amount < item.Amount) + { + int amt = abs(item.Amount - amount); + return TakeInventory(itemclass, amt, true, false); + } + else + { + item.Amount = (beyondMax ? amount : clamp(amount, 0, item.MaxAmount)); + return true; + } + } + else + { + if (amount <= 0) + { + return true; + } + item = Inventory(Spawn(itemclass)); + if (item == null) + { + return false; + } + else + { + item.Amount = amount; + item.bDropped = true; + item.bIgnoreSkill = true; + item.ClearCounters(); + if (!item.CallTryPickup(self)) + { + item.Destroy(); + return false; + } + return true; + } + } + return false; + } + + + //============================================================================ + // + // AActor :: UseInventory + // + // Attempts to use an item. If the use succeeds, one copy of the item is + // removed from the inventory. If all copies are removed, then the item is + // destroyed. + // + //============================================================================ + + virtual bool UseInventory (Inventory item) + { + // No using items if you're dead or you don't have them. + if (health <= 0 || item.Amount <= 0 || item.bDestroyed) + { + return false; + } + + if (!item.Use(false)) + { + return false; + } + + if (sv_infiniteinventory) + { + return true; + } + + if (--item.Amount <= 0) + { + item.DepleteOrDestroy (); + } + return true; + } + + + //=========================================================================== + // + // DoGiveInventory + // + //=========================================================================== + + static bool DoGiveInventory(Actor receiver, bool orresult, class mi, int amount, int setreceiver) + { + int paramnum = 0; + + if (!orresult) + { + receiver = receiver.GetPointer(setreceiver); + } + if (receiver == NULL) + { // If there's nothing to receive it, it's obviously a fail, right? + return false; + } + // Owned inventory items cannot own anything because their Inventory pointer is repurposed for the owner's linked list. + if (receiver is 'Inventory' && Inventory(receiver).Owner != null) + { + return false; + } + + if (amount <= 0) + { + amount = 1; + } + if (mi) + { + let item = Inventory(Spawn(mi)); + if (item == NULL) + { + return false; + } + if (item is 'Health') + { + item.Amount *= amount; + } + else + { + item.Amount = amount; + } + item.bDropped = true; + item.ClearCounters(); + if (!item.CallTryPickup(receiver)) + { + item.Destroy(); + return false; + } + else + { + return true; + } + } + return false; + } + + bool A_GiveInventory(class itemtype, int amount = 0, int giveto = AAPTR_DEFAULT) + { + return DoGiveInventory(self, false, itemtype, amount, giveto); + } + + bool A_GiveToTarget(class itemtype, int amount = 0, int giveto = AAPTR_DEFAULT) + { + return DoGiveInventory(target, false, itemtype, amount, giveto); + } + + int A_GiveToChildren(class itemtype, int amount = 0) + { + let it = ThinkerIterator.Create('Actor'); + Actor mo; + int count = 0; + + while ((mo = Actor(it.Next()))) + { + if (mo.master == self) + { + count += DoGiveInventory(mo, true, itemtype, amount, AAPTR_DEFAULT); + } + } + return count; + } + + int A_GiveToSiblings(class itemtype, int amount = 0) + { + let it = ThinkerIterator.Create('Actor'); + Actor mo; + int count = 0; + + if (self.master != NULL) + { + while ((mo = Actor(it.Next()))) + { + if (mo.master == self.master && mo != self) + { + count += DoGiveInventory(mo, true, itemtype, amount, AAPTR_DEFAULT); + } + } + } + return count; + } + + //=========================================================================== + // + // A_TakeInventory + // + //=========================================================================== + + bool DoTakeInventory(Actor receiver, bool orresult, class itemtype, int amount, int flags, int setreceiver = AAPTR_DEFAULT) + { + int paramnum = 0; + + if (itemtype == NULL) + { + return false; + } + if (!orresult) + { + receiver = receiver.GetPointer(setreceiver); + } + if (receiver == NULL) + { + return false; + } + + return receiver.TakeInventory(itemtype, amount, true, (flags & TIF_NOTAKEINFINITE) != 0); + } + + bool A_TakeInventory(class itemtype, int amount = 0, int flags = 0, int giveto = AAPTR_DEFAULT) + { + return DoTakeInventory(self, false, itemtype, amount, flags, giveto); + } + + bool A_TakeFromTarget(class itemtype, int amount = 0, int flags = 0, int giveto = AAPTR_DEFAULT) + { + return DoTakeInventory(target, false, itemtype, amount, flags, giveto); + } + + int A_TakeFromChildren(class itemtype, int amount = 0) + { + let it = ThinkerIterator.Create('Actor'); + Actor mo; + int count = 0; + + while ((mo = Actor(it.Next()))) + { + if (mo.master == self) + { + count += DoTakeInventory(mo, true, itemtype, amount, 0, AAPTR_DEFAULT); + } + } + return count; + } + + int A_TakeFromSiblings(class itemtype, int amount = 0) + { + let it = ThinkerIterator.Create('Actor'); + Actor mo; + int count = 0; + + if (self.master != NULL) + { + while ((mo = Actor(it.Next()))) + { + if (mo.master == self.master && mo != self) + { + count += DoTakeInventory(mo, true, itemtype, amount, 0, AAPTR_DEFAULT); + } + } + } + return count; + } + + //=========================================================================== + // + // A_SetInventory + // + //=========================================================================== + + bool A_SetInventory(class itemtype, int amount, int ptr = AAPTR_DEFAULT, bool beyondMax = false) + { + bool res = false; + + if (itemtype == null) + { + return false; + } + + Actor mobj = GetPointer(ptr); + + if (mobj == null) + { + return false; + } + + // Do not run this function on voodoo dolls because the way they transfer the inventory to the player will not work with the code below. + if (mobj.player != null) + { + mobj = mobj.player.mo; + } + return mobj.SetInventory(itemtype, amount, beyondMax); + } + + +} + diff --git a/wadsrc/static/zscript/shared/player_cheat.txt b/wadsrc/static/zscript/shared/player_cheat.txt index 8c10b5898e..8bd9d34c24 100644 --- a/wadsrc/static/zscript/shared/player_cheat.txt +++ b/wadsrc/static/zscript/shared/player_cheat.txt @@ -399,6 +399,31 @@ extend class PlayerPawn } return; } + + virtual void CheatSetInv(String strng, int amount, bool beyond) + { + if (!(strng ~== "health")) + { + if (amount <= 0) + { + CheatSuicide(); + return; + } + if (!beyond) amount = MIN(amount, player.mo.GetMaxHealth(true)); + player.health = player.mo.health = amount; + } + else + { + class item = strng; + if (item != null) + { + player.mo.SetInventory(item, amount, beyond); + return; + } + Console.Printf("Unknown item \"%s\"\n", strng); + } + } + virtual String CheatMorph(class morphClass, bool quickundo) { diff --git a/wadsrc/static/zscript/shared/player_inventory.txt b/wadsrc/static/zscript/shared/player_inventory.txt index 748a293d3f..9ab6f14272 100644 --- a/wadsrc/static/zscript/shared/player_inventory.txt +++ b/wadsrc/static/zscript/shared/player_inventory.txt @@ -75,4 +75,37 @@ extend class PlayerPawn } } + //=========================================================================== + // + // APlayerPawn :: UseInventory + // + //=========================================================================== + + override bool UseInventory (Inventory item) + { + let itemtype = item.GetClass(); + + if (player.cheats & CF_TOTALLYFROZEN) + { // You can't use items if you're totally frozen + return false; + } + if ((level.FROZEN) && (player == NULL || player.timefreezer == 0)) + { + // Time frozen + return false; + } + + if (!Super.UseInventory (item)) + { + // Heretic and Hexen advance the inventory cursor if the use failed. + // Should this behavior be retained? + return false; + } + if (player == players[consoleplayer]) + { + A_PlaySound(item.UseSound, CHAN_ITEM); + StatusBar.FlashItem (itemtype); // Fixme: This shouldn't be called from here, because it is in the UI. + } + return true; + } } \ No newline at end of file diff --git a/wadsrc/static/zscript/statusbar/statusbar.txt b/wadsrc/static/zscript/statusbar/statusbar.txt index 6af5199ecd..2a187d7012 100644 --- a/wadsrc/static/zscript/statusbar/statusbar.txt +++ b/wadsrc/static/zscript/statusbar/statusbar.txt @@ -297,8 +297,8 @@ class BaseStatusBar native ui native PlayerInfo CPlayer; native bool ShowLog; native Vector2 defaultScale; // factor for fully scaled fullscreen display. - native int artiflashTick; - native double itemflashFade; + clearscope native int artiflashTick; + clearscope native double itemflashFade; // These are block properties for the drawers. A child class can set them to have a block of items use the same settings. native double Alpha; @@ -331,7 +331,7 @@ class BaseStatusBar native ui native virtual clearscope void ReceivedWeapon (Weapon weapn); native virtual clearscope void SetMugShotState (String state_name, bool wait_till_done=false, bool reset=false); - virtual void FlashItem (class itemtype) { artiflashTick = 4; itemflashFade = 0.75; } + clearscope virtual void FlashItem (class itemtype) { artiflashTick = 4; itemflashFade = 0.75; } virtual void AttachToPlayer (PlayerInfo player) { CPlayer = player; UpdateScreenGeometry(); } virtual void FlashCrosshair () { CrosshairSize = XHAIRPICKUPSIZE; } virtual void NewGame () { if (CPlayer != null) AttachToPlayer(CPlayer); }