#ifndef GAME_MWWORLD_INVENTORYSTORE_H #define GAME_MWWORLD_INVENTORYSTORE_H #include "containerstore.hpp" #include "../mwmechanics/magiceffects.hpp" namespace ESM { struct MagicEffect; } namespace MWMechanics { class NpcStats; } namespace MWWorld { class InventoryStoreListener { public: /** * Fired when items are equipped or unequipped */ virtual void equipmentChanged () {} /** * @param effect * @param isNew Is this effect new (e.g. the item for it was just now manually equipped) * or was it loaded from a savegame / initial game state? \n * If it isn't new, non-looping VFX should not be played. * @param playSound Play effect sound? */ virtual void permanentEffectAdded (const ESM::MagicEffect *magicEffect, bool isNew) {} }; ///< \brief Variant of the ContainerStore for NPCs class InventoryStore : public ContainerStore { public: static const int Slot_Helmet = 0; static const int Slot_Cuirass = 1; static const int Slot_Greaves = 2; static const int Slot_LeftPauldron = 3; static const int Slot_RightPauldron = 4; static const int Slot_LeftGauntlet = 5; static const int Slot_RightGauntlet = 6; static const int Slot_Boots = 7; static const int Slot_Shirt = 8; static const int Slot_Pants = 9; static const int Slot_Skirt = 10; static const int Slot_Robe = 11; static const int Slot_LeftRing = 12; static const int Slot_RightRing = 13; static const int Slot_Amulet = 14; static const int Slot_Belt = 15; static const int Slot_CarriedRight = 16; static const int Slot_CarriedLeft = 17; static const int Slot_Ammunition = 18; static const int Slots = 19; static const int Slot_NoSlot = -1; private: MWMechanics::MagicEffects mMagicEffects; InventoryStoreListener* mListener; // Enables updates of magic effects and actor model whenever items are equipped or unequipped. // This is disabled during autoequip to avoid excessive updates bool mUpdatesEnabled; bool mFirstAutoEquip; // Vanilla allows permanent effects with a random magnitude, so it needs to be stored here. // We also need this to only play sounds and particle effects when the item is equipped, rather than on every update. struct EffectParams { // Modifier to scale between min and max magnitude float mRandom; // Multiplier for when an effect was fully or partially resisted float mMultiplier; }; typedef std::map > TEffectMagnitudes; TEffectMagnitudes mPermanentMagicEffectMagnitudes; typedef std::vector TSlots; TSlots mSlots; // selected magic item (for using enchantments of type "Cast once" or "Cast when used") ContainerStoreIterator mSelectedEnchantItem; // (item, max charge) typedef std::vector > TRechargingItems; TRechargingItems mRechargingItems; bool mRechargingItemsUpToDate; void copySlots (const InventoryStore& store); void initSlots (TSlots& slots_); void updateMagicEffects(const Ptr& actor); void updateRechargingItems(); void fireEquipmentChangedEvent(const Ptr& actor); virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const; virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory); bool canActorAutoEquip(const MWWorld::Ptr& actor, const MWWorld::Ptr& item); ContainerStoreIterator findSlot (int slot) const; public: InventoryStore(); InventoryStore (const InventoryStore& store); InventoryStore& operator= (const InventoryStore& store); virtual InventoryStore* clone() { return new InventoryStore(*this); } virtual ContainerStoreIterator add (const Ptr& itemPtr, int count, const Ptr& actorPtr, bool setOwner=false); ///< Add the item pointed to by \a ptr to this container. (Stacks automatically if needed) /// Auto-equip items if specific conditions are fulfilled (see the implementation). /// /// \note The item pointed to is not required to exist beyond this function call. /// /// \attention Do not add items to an existing stack by increasing the count instead of /// calling this function! /// /// @param setOwner Set the owner of the added item to \a actorPtr? /// /// @return if stacking happened, return iterator to the item that was stacked against, otherwise iterator to the newly inserted item. void equip (int slot, const ContainerStoreIterator& iterator, const Ptr& actor); ///< \warning \a iterator can not be an end()-iterator, use unequip function instead bool isEquipped(const MWWorld::ConstPtr& item); ///< Utility function, returns true if the given item is equipped in any slot void setSelectedEnchantItem(const ContainerStoreIterator& iterator); ///< set the selected magic item (for using enchantments of type "Cast once" or "Cast when used") /// \note to unset the selected item, call this method with end() iterator ContainerStoreIterator getSelectedEnchantItem(); ///< @return selected magic item (for using enchantments of type "Cast once" or "Cast when used") /// \note if no item selected, return end() iterator ContainerStoreIterator getSlot (int slot); ConstContainerStoreIterator getSlot(int slot) const; void unequipAll(const MWWorld::Ptr& actor); ///< Unequip all currently equipped items. void autoEquip (const MWWorld::Ptr& actor); ///< Auto equip items according to stats and item value. void autoEquipShield(const MWWorld::Ptr& actor); ///< Auto-equip the shield with most health. const MWMechanics::MagicEffects& getMagicEffects() const; ///< Return magic effects from worn items. virtual void flagAsModified(); ///< \attention This function is internal to the world model and should not be called from /// outside. virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2) const; ///< @return true if the two specified objects can stack with each other virtual int remove(const std::string& itemId, int count, const Ptr& actor); virtual int remove(const std::string& itemId, int count, const Ptr& actor, bool equipReplacement); virtual int remove(const Ptr& item, int count, const Ptr& actor); virtual int remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement); ///< Remove \a count item(s) designated by \a item from this inventory. /// /// @return the number of items actually removed ContainerStoreIterator unequipSlot(int slot, const Ptr& actor); ///< Unequip \a slot. /// /// @return an iterator to the item that was previously in the slot ContainerStoreIterator unequipItem(const Ptr& item, const Ptr& actor); ///< Unequip an item identified by its Ptr. An exception is thrown /// if the item is not currently equipped. /// /// @return an iterator to the item that was previously in the slot /// (it can be re-stacked so its count may be different than when it /// was equipped). ContainerStoreIterator unequipItemQuantity(const Ptr& item, const Ptr& actor, int count); ///< Unequip a specific quantity of an item identified by its Ptr. /// An exception is thrown if the item is not currently equipped, /// if count <= 0, or if count > the item stack size. /// /// @return an iterator to the unequipped items that were previously /// in the slot (they can be re-stacked so its count may be different /// than the requested count). void setInvListener (InventoryStoreListener* listener, const Ptr& actor); ///< Set a listener for various events, see \a InventoryStoreListener InventoryStoreListener* getInvListener(); void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor); void rechargeItems (float duration); ///< Restore charge on enchanted items. Note this should only be done for the player. void purgeEffect (short effectId); ///< Remove a magic effect void purgeEffect (short effectId, const std::string& sourceId); ///< Remove a magic effect virtual void clear(); ///< Empty container. virtual void writeState (ESM::InventoryState& state) const; virtual void readState (const ESM::InventoryState& state); }; } #endif