extend class Actor { //============================================================================ // // AActor :: AddInventory // //============================================================================ virtual void AddInventory (Inventory item) { // Check if it's already attached to an actor if (item.Owner != NULL) { // Is it attached to us? if (item.Owner == self) return; // No, then remove it from the other actor first item.Owner.RemoveInventory (item); } item.Owner = self; item.Inv = Inv; Inv = item; // Each item receives an unique ID when added to an actor's inventory. // This is used by the DEM_INVUSE command to identify the item. Simply // using the item's position in the list won't work, because ticcmds get // run sometime in the future, so by the time it runs, the inventory // might not be in the same state as it was when DEM_INVUSE was sent. Inv.InventoryID = InventoryID++; } //============================================================================ // // AActor :: GiveInventory // //============================================================================ bool GiveInventory(Class type, int amount, bool givecheat = false) { bool result = true; let player = self.player; // This can be called from places which do not check the given item's type. if (type == null || !(type is 'Inventory')) return false; Weapon savedPendingWeap = player != NULL ? player.PendingWeapon : NULL; bool hadweap = player != NULL ? player.ReadyWeapon != NULL : true; Inventory item; if (!givecheat) { item = Inventory(Spawn (type)); } else { item = Inventory(Spawn (type, Pos, NO_REPLACE)); if (item == NULL) return false; } // This shouldn't count for the item statistics. item.ClearCounters(); if (!givecheat || amount > 0) { item.SetGiveAmount(self, amount, givecheat); } if (!item.CallTryPickup (self)) { item.Destroy (); result = false; } // If the item was a weapon, don't bring it up automatically // unless the player was not already using a weapon. // Don't bring it up automatically if this is called by the give cheat. if (!givecheat && player != NULL && savedPendingWeap != NULL && hadweap) { player.PendingWeapon = savedPendingWeap; } return result; } //============================================================================ // // AActor :: RemoveInventory // //============================================================================ virtual void RemoveInventory(Inventory item) { Inventory invp; if (item != NULL && item.Owner != NULL) // can happen if the owner was destroyed by some action from an item's use state. { if (Inv == item) Inv = item.Inv; else { for (invp = Inv; invp != null; invp = invp.Inv) { if (invp.Inv == item) { invp.Inv = item.Inv; item.DetachFromOwner(); break; } } } item.Owner = NULL; item.Inv = NULL; } } //============================================================================ // // AActor :: TakeInventory // //============================================================================ bool TakeInventory(class itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false) { amount = abs(amount); let item = FindInventory(itemclass); if (item == NULL) return false; if (!fromdecorate) { item.Amount -= amount; if (item.Amount <= 0) { item.DepleteOrDestroy(); } // It won't be used in non-decorate context, so return false here return false; } bool result = false; if (item.Amount > 0) { result = true; } // Do not take ammo if the "no take infinite/take as ammo depletion" flag is set // and infinite ammo is on if (notakeinfinite && (sv_infiniteammo || (player && FindInventory('PowerInfiniteAmmo', true))) && (item is 'Ammo')) { // Nothing to do here, except maybe res = false;? Would it make sense? result = false; } else if (!amount || amount >= item.Amount) { item.DepleteOrDestroy(); } else item.Amount -= amount; return result; } //============================================================================ // // 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; } //=========================================================================== // // AActor :: DropInventory // // Removes a single copy of an item and throws it out in front of the actor. // //=========================================================================== Inventory DropInventory (Inventory item, int amt = 1) { Inventory drop = item.CreateTossable(amt); if (drop == null) return NULL; drop.SetOrigin(Pos + (0, 0, 10.), false); drop.Angle = Angle; drop.VelFromAngle(5.); drop.Vel.Z = 1.; drop.Vel += Vel; drop.bNoGravity = false; // Don't float drop.ClearCounters(); // do not count for statistics again drop.OnDrop(self); return drop; } //============================================================================ // // AActor :: GiveAmmo // // Returns true if the ammo was added, false if not. // //============================================================================ bool GiveAmmo (Class type, int amount) { if (type != NULL && type is 'Ammo') { let item = Inventory(Spawn (type)); if (item) { item.Amount = amount; item.bDropped = true; if (!item.CallTryPickup (self)) { item.Destroy (); return false; } return true; } } return false; } //=========================================================================== // // 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); } }