1 #ifndef GAME_MWWORLD_INVENTORYSTORE_H 2 #define GAME_MWWORLD_INVENTORYSTORE_H 3 4 #include "containerstore.hpp" 5 6 #include "../mwmechanics/magiceffects.hpp" 7 8 namespace ESM 9 { 10 struct MagicEffect; 11 } 12 13 namespace MWMechanics 14 { 15 class NpcStats; 16 } 17 18 namespace MWWorld 19 { 20 class InventoryStoreListener 21 { 22 public: 23 /** 24 * Fired when items are equipped or unequipped 25 */ equipmentChanged()26 virtual void equipmentChanged () {} 27 28 /** 29 * @param effect 30 * @param isNew Is this effect new (e.g. the item for it was just now manually equipped) 31 * or was it loaded from a savegame / initial game state? \n 32 * If it isn't new, non-looping VFX should not be played. 33 * @param playSound Play effect sound? 34 */ permanentEffectAdded(const ESM::MagicEffect * magicEffect,bool isNew)35 virtual void permanentEffectAdded (const ESM::MagicEffect *magicEffect, bool isNew) {} 36 37 virtual ~InventoryStoreListener() = default; 38 }; 39 40 ///< \brief Variant of the ContainerStore for NPCs 41 class InventoryStore : public ContainerStore 42 { 43 public: 44 45 static constexpr int Slot_Helmet = 0; 46 static constexpr int Slot_Cuirass = 1; 47 static constexpr int Slot_Greaves = 2; 48 static constexpr int Slot_LeftPauldron = 3; 49 static constexpr int Slot_RightPauldron = 4; 50 static constexpr int Slot_LeftGauntlet = 5; 51 static constexpr int Slot_RightGauntlet = 6; 52 static constexpr int Slot_Boots = 7; 53 static constexpr int Slot_Shirt = 8; 54 static constexpr int Slot_Pants = 9; 55 static constexpr int Slot_Skirt = 10; 56 static constexpr int Slot_Robe = 11; 57 static constexpr int Slot_LeftRing = 12; 58 static constexpr int Slot_RightRing = 13; 59 static constexpr int Slot_Amulet = 14; 60 static constexpr int Slot_Belt = 15; 61 static constexpr int Slot_CarriedRight = 16; 62 static constexpr int Slot_CarriedLeft = 17; 63 static constexpr int Slot_Ammunition = 18; 64 65 static constexpr int Slots = 19; 66 67 static constexpr int Slot_NoSlot = -1; 68 69 private: 70 71 MWMechanics::MagicEffects mMagicEffects; 72 73 InventoryStoreListener* mInventoryListener; 74 75 // Enables updates of magic effects and actor model whenever items are equipped or unequipped. 76 // This is disabled during autoequip to avoid excessive updates 77 bool mUpdatesEnabled; 78 79 bool mFirstAutoEquip; 80 81 // Vanilla allows permanent effects with a random magnitude, so it needs to be stored here. 82 // We also need this to only play sounds and particle effects when the item is equipped, rather than on every update. 83 struct EffectParams 84 { 85 // Modifier to scale between min and max magnitude 86 float mRandom; 87 // Multiplier for when an effect was fully or partially resisted 88 float mMultiplier; 89 }; 90 91 typedef std::map<std::string, std::vector<EffectParams> > TEffectMagnitudes; 92 TEffectMagnitudes mPermanentMagicEffectMagnitudes; 93 94 typedef std::vector<ContainerStoreIterator> TSlots; 95 96 TSlots mSlots; 97 98 void autoEquipWeapon(const MWWorld::Ptr& actor, TSlots& slots_); 99 void autoEquipArmor(const MWWorld::Ptr& actor, TSlots& slots_); 100 void autoEquipShield(const MWWorld::Ptr& actor, TSlots& slots_); 101 102 // selected magic item (for using enchantments of type "Cast once" or "Cast when used") 103 ContainerStoreIterator mSelectedEnchantItem; 104 105 void copySlots (const InventoryStore& store); 106 107 void initSlots (TSlots& slots_); 108 109 void updateMagicEffects(const Ptr& actor); 110 111 void fireEquipmentChangedEvent(const Ptr& actor); 112 113 void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const override; 114 void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory) override; 115 116 ContainerStoreIterator findSlot (int slot) const; 117 118 public: 119 120 InventoryStore(); 121 122 InventoryStore (const InventoryStore& store); 123 124 InventoryStore& operator= (const InventoryStore& store); 125 clone()126 std::unique_ptr<ContainerStore> clone() override { return std::make_unique<InventoryStore>(*this); } 127 128 ContainerStoreIterator add (const Ptr& itemPtr, int count, const Ptr& actorPtr, bool allowAutoEquip = true, bool resolve = true) override; 129 ///< Add the item pointed to by \a ptr to this container. (Stacks automatically if needed) 130 /// Auto-equip items if specific conditions are fulfilled and allowAutoEquip is true (see the implementation). 131 /// 132 /// \note The item pointed to is not required to exist beyond this function call. 133 /// 134 /// \attention Do not add items to an existing stack by increasing the count instead of 135 /// calling this function! 136 /// 137 /// @return if stacking happened, return iterator to the item that was stacked against, otherwise iterator to the newly inserted item. 138 139 void equip (int slot, const ContainerStoreIterator& iterator, const Ptr& actor); 140 ///< \warning \a iterator can not be an end()-iterator, use unequip function instead 141 142 bool isEquipped(const MWWorld::ConstPtr& item); 143 ///< Utility function, returns true if the given item is equipped in any slot 144 145 void setSelectedEnchantItem(const ContainerStoreIterator& iterator); 146 ///< set the selected magic item (for using enchantments of type "Cast once" or "Cast when used") 147 /// \note to unset the selected item, call this method with end() iterator 148 149 ContainerStoreIterator getSelectedEnchantItem(); 150 ///< @return selected magic item (for using enchantments of type "Cast once" or "Cast when used") 151 /// \note if no item selected, return end() iterator 152 153 ContainerStoreIterator getSlot (int slot); 154 ConstContainerStoreIterator getSlot(int slot) const; 155 156 ContainerStoreIterator getPreferredShield(const MWWorld::Ptr& actor); 157 158 void unequipAll(const MWWorld::Ptr& actor); 159 ///< Unequip all currently equipped items. 160 161 void autoEquip (const MWWorld::Ptr& actor); 162 ///< Auto equip items according to stats and item value. 163 164 const MWMechanics::MagicEffects& getMagicEffects() const; 165 ///< Return magic effects from worn items. 166 167 bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2) const override; 168 ///< @return true if the two specified objects can stack with each other 169 170 using ContainerStore::remove; 171 int remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement = 0, bool resolve = true) override; 172 ///< Remove \a count item(s) designated by \a item from this inventory. 173 /// 174 /// @return the number of items actually removed 175 176 ContainerStoreIterator unequipSlot(int slot, const Ptr& actor, bool applyUpdates = true); 177 ///< Unequip \a slot. 178 /// 179 /// @return an iterator to the item that was previously in the slot 180 181 ContainerStoreIterator unequipItem(const Ptr& item, const Ptr& actor); 182 ///< Unequip an item identified by its Ptr. An exception is thrown 183 /// if the item is not currently equipped. 184 /// 185 /// @return an iterator to the item that was previously in the slot 186 /// (it can be re-stacked so its count may be different than when it 187 /// was equipped). 188 189 ContainerStoreIterator unequipItemQuantity(const Ptr& item, const Ptr& actor, int count); 190 ///< Unequip a specific quantity of an item identified by its Ptr. 191 /// An exception is thrown if the item is not currently equipped, 192 /// if count <= 0, or if count > the item stack size. 193 /// 194 /// @return an iterator to the unequipped items that were previously 195 /// in the slot (they can be re-stacked so its count may be different 196 /// than the requested count). 197 198 void setInvListener (InventoryStoreListener* listener, const Ptr& actor); 199 ///< Set a listener for various events, see \a InventoryStoreListener 200 201 InventoryStoreListener* getInvListener(); 202 203 void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor); 204 205 void purgeEffect (short effectId, bool wholeSpell = false); 206 ///< Remove a magic effect 207 208 void purgeEffect (short effectId, const std::string& sourceId, bool wholeSpell = false, int effectIndex=-1); 209 ///< Remove a magic effect 210 211 void clear() override; 212 ///< Empty container. 213 214 void writeState (ESM::InventoryState& state) const override; 215 216 void readState (const ESM::InventoryState& state) override; 217 }; 218 } 219 220 #endif 221