1 /* 2 Minetest 3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU Lesser General Public License as published by 7 the Free Software Foundation; either version 2.1 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public License along 16 with this program; if not, write to the Free Software Foundation, Inc., 17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20 #pragma once 21 22 #include "itemdef.h" 23 #include "irrlichttypes.h" 24 #include "itemstackmetadata.h" 25 #include <istream> 26 #include <ostream> 27 #include <string> 28 #include <vector> 29 #include <cassert> 30 31 struct ToolCapabilities; 32 33 struct ItemStack 34 { 35 ItemStack() = default; 36 37 ItemStack(const std::string &name_, u16 count_, 38 u16 wear, IItemDefManager *itemdef); 39 40 ~ItemStack() = default; 41 42 // Serialization 43 void serialize(std::ostream &os, bool serialize_meta = true) const; 44 // Deserialization. Pass itemdef unless you don't want aliases resolved. 45 void deSerialize(std::istream &is, IItemDefManager *itemdef = NULL); 46 void deSerialize(const std::string &s, IItemDefManager *itemdef = NULL); 47 48 // Returns the string used for inventory 49 std::string getItemString(bool include_meta = true) const; 50 // Returns the tooltip 51 std::string getDescription(IItemDefManager *itemdef) const; 52 std::string getShortDescription(IItemDefManager *itemdef) const; 53 54 /* 55 Quantity methods 56 */ 57 emptyItemStack58 bool empty() const 59 { 60 return count == 0; 61 } 62 clearItemStack63 void clear() 64 { 65 name = ""; 66 count = 0; 67 wear = 0; 68 metadata.clear(); 69 } 70 addItemStack71 void add(u16 n) 72 { 73 count += n; 74 } 75 removeItemStack76 void remove(u16 n) 77 { 78 assert(count >= n); // Pre-condition 79 count -= n; 80 if(count == 0) 81 clear(); // reset name, wear and metadata too 82 } 83 84 // Maximum size of a stack getStackMaxItemStack85 u16 getStackMax(IItemDefManager *itemdef) const 86 { 87 return itemdef->get(name).stack_max; 88 } 89 90 // Number of items that can be added to this stack freeSpaceItemStack91 u16 freeSpace(IItemDefManager *itemdef) const 92 { 93 u16 max = getStackMax(itemdef); 94 if (count >= max) 95 return 0; 96 return max - count; 97 } 98 99 // Returns false if item is not known and cannot be used isKnownItemStack100 bool isKnown(IItemDefManager *itemdef) const 101 { 102 return itemdef->isKnown(name); 103 } 104 105 // Returns a pointer to the item definition struct, 106 // or a fallback one (name="unknown") if the item is unknown. getDefinitionItemStack107 const ItemDefinition& getDefinition( 108 IItemDefManager *itemdef) const 109 { 110 return itemdef->get(name); 111 } 112 113 // Get tool digging properties, or those of the hand if not a tool getToolCapabilitiesItemStack114 const ToolCapabilities& getToolCapabilities( 115 IItemDefManager *itemdef) const 116 { 117 const ToolCapabilities *item_cap = 118 itemdef->get(name).tool_capabilities; 119 120 if (item_cap == NULL) 121 // Fall back to the hand's tool capabilities 122 item_cap = itemdef->get("").tool_capabilities; 123 124 assert(item_cap != NULL); 125 return metadata.getToolCapabilities(*item_cap); // Check for override 126 } 127 128 // Wear out (only tools) 129 // Returns true if the item is (was) a tool addWearItemStack130 bool addWear(s32 amount, IItemDefManager *itemdef) 131 { 132 if(getDefinition(itemdef).type == ITEM_TOOL) 133 { 134 if(amount > 65535 - wear) 135 clear(); 136 else if(amount < -wear) 137 wear = 0; 138 else 139 wear += amount; 140 return true; 141 } 142 143 return false; 144 } 145 146 // If possible, adds newitem to this item. 147 // If cannot be added at all, returns the item back. 148 // If can be added partly, decremented item is returned back. 149 // If can be added fully, empty item is returned. 150 ItemStack addItem(ItemStack newitem, IItemDefManager *itemdef); 151 152 // Checks whether newitem could be added. 153 // If restitem is non-NULL, it receives the part of newitem that 154 // would be left over after adding. 155 bool itemFits(ItemStack newitem, 156 ItemStack *restitem, // may be NULL 157 IItemDefManager *itemdef) const; 158 159 // Takes some items. 160 // If there are not enough, takes as many as it can. 161 // Returns empty item if couldn't take any. 162 ItemStack takeItem(u32 takecount); 163 164 // Similar to takeItem, but keeps this ItemStack intact. 165 ItemStack peekItem(u32 peekcount) const; 166 167 bool operator ==(const ItemStack &s) const 168 { 169 return (this->name == s.name && 170 this->count == s.count && 171 this->wear == s.wear && 172 this->metadata == s.metadata); 173 } 174 175 bool operator !=(const ItemStack &s) const 176 { 177 return !(*this == s); 178 } 179 180 /* 181 Properties 182 */ 183 std::string name = ""; 184 u16 count = 0; 185 u16 wear = 0; 186 ItemStackMetadata metadata; 187 }; 188 189 class InventoryList 190 { 191 public: 192 InventoryList(const std::string &name, u32 size, IItemDefManager *itemdef); 193 ~InventoryList() = default; 194 void clearItems(); 195 void setSize(u32 newsize); 196 void setWidth(u32 newWidth); 197 void setName(const std::string &name); 198 void serialize(std::ostream &os, bool incremental) const; 199 void deSerialize(std::istream &is); 200 201 InventoryList(const InventoryList &other); 202 InventoryList & operator = (const InventoryList &other); 203 bool operator == (const InventoryList &other) const; 204 bool operator != (const InventoryList &other) const 205 { 206 return !(*this == other); 207 } 208 209 const std::string &getName() const; 210 u32 getSize() const; 211 u32 getWidth() const; 212 // Count used slots 213 u32 getUsedSlots() const; 214 u32 getFreeSlots() const; 215 216 // Get reference to item 217 const ItemStack& getItem(u32 i) const; 218 ItemStack& getItem(u32 i); 219 // Returns old item. Parameter can be an empty item. 220 ItemStack changeItem(u32 i, const ItemStack &newitem); 221 // Delete item 222 void deleteItem(u32 i); 223 224 // Adds an item to a suitable place. Returns leftover item (possibly empty). 225 ItemStack addItem(const ItemStack &newitem); 226 227 // If possible, adds item to given slot. 228 // If cannot be added at all, returns the item back. 229 // If can be added partly, decremented item is returned back. 230 // If can be added fully, empty item is returned. 231 ItemStack addItem(u32 i, const ItemStack &newitem); 232 233 // Checks whether the item could be added to the given slot 234 // If restitem is non-NULL, it receives the part of newitem that 235 // would be left over after adding. 236 bool itemFits(const u32 i, const ItemStack &newitem, 237 ItemStack *restitem = NULL) const; 238 239 // Checks whether there is room for a given item 240 bool roomForItem(const ItemStack &item) const; 241 242 // Checks whether the given count of the given item 243 // exists in this inventory list. 244 // If match_meta is false, only the items' names are compared. 245 bool containsItem(const ItemStack &item, bool match_meta) const; 246 247 // Removes the given count of the given item name from 248 // this inventory list. Walks the list in reverse order. 249 // If not as many items exist as requested, removes as 250 // many as possible. 251 // Returns the items that were actually removed. 252 ItemStack removeItem(const ItemStack &item); 253 254 // Takes some items from a slot. 255 // If there are not enough, takes as many as it can. 256 // Returns empty item if couldn't take any. 257 ItemStack takeItem(u32 i, u32 takecount); 258 259 // Move an item to a different list (or a different stack in the same list) 260 // count is the maximum number of items to move (0 for everything) 261 // returns number of moved items 262 u32 moveItem(u32 i, InventoryList *dest, u32 dest_i, 263 u32 count = 0, bool swap_if_needed = true, bool *did_swap = NULL); 264 265 // like moveItem, but without a fixed destination index 266 // also with optional rollback recording 267 void moveItemSomewhere(u32 i, InventoryList *dest, u32 count); 268 checkModified()269 inline bool checkModified() const { return m_dirty; } 270 inline void setModified(bool dirty = true) { m_dirty = dirty; } 271 272 private: 273 std::vector<ItemStack> m_items; 274 std::string m_name; 275 u32 m_size; 276 u32 m_width = 0; 277 IItemDefManager *m_itemdef; 278 bool m_dirty = true; 279 }; 280 281 class Inventory 282 { 283 public: 284 ~Inventory(); 285 286 void clear(); 287 288 Inventory(IItemDefManager *itemdef); 289 Inventory(const Inventory &other); 290 Inventory & operator = (const Inventory &other); 291 bool operator == (const Inventory &other) const; 292 bool operator != (const Inventory &other) const 293 { 294 return !(*this == other); 295 } 296 297 // Never ever serialize to disk using "incremental"! 298 void serialize(std::ostream &os, bool incremental = false) const; 299 void deSerialize(std::istream &is); 300 301 InventoryList * addList(const std::string &name, u32 size); 302 InventoryList * getList(const std::string &name); 303 const InventoryList * getList(const std::string &name) const; 304 std::vector<const InventoryList*> getLists(); 305 bool deleteList(const std::string &name); 306 // A shorthand for adding items. Returns leftover item (possibly empty). addItem(const std::string & listname,const ItemStack & newitem)307 ItemStack addItem(const std::string &listname, const ItemStack &newitem) 308 { 309 InventoryList *list = getList(listname); 310 if(list == NULL) 311 return newitem; 312 return list->addItem(newitem); 313 } 314 checkModified()315 inline bool checkModified() const 316 { 317 if (m_dirty) 318 return true; 319 320 for (const auto &list : m_lists) 321 if (list->checkModified()) 322 return true; 323 324 return false; 325 } 326 327 inline void setModified(bool dirty = true) 328 { 329 m_dirty = dirty; 330 // Set all as handled 331 if (!dirty) { 332 for (const auto &list : m_lists) 333 list->setModified(dirty); 334 } 335 } 336 private: 337 // -1 if not found 338 const s32 getListIndex(const std::string &name) const; 339 340 std::vector<InventoryList*> m_lists; 341 IItemDefManager *m_itemdef; 342 bool m_dirty = true; 343 }; 344