3f3c5435b4cc5e10da98c1c6b93026209dc6e519
[oweals/minetest.git] / src / inventory.h
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
14
15 You should have received a copy of the GNU 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 #ifndef INVENTORY_HEADER
21 #define INVENTORY_HEADER
22
23 #include <iostream>
24 #include <sstream>
25 #include <string>
26 #include "common_irrlicht.h"
27 #include "debug.h"
28 #include "mapnode.h" // For content_t
29
30 #define QUANTITY_ITEM_MAX_COUNT 99
31
32 class ServerActiveObject;
33 class ServerEnvironment;
34 struct PointedThing;
35 class ITextureSource;
36 class IGameDef;
37
38 class InventoryItem
39 {
40 public:
41         InventoryItem(IGameDef *gamedef, u16 count);
42         virtual ~InventoryItem();
43         
44         static InventoryItem* deSerialize(std::istream &is, IGameDef *gamedef);
45         static InventoryItem* deSerialize(const std::string &str,
46                         IGameDef *gamedef);
47         
48         virtual const char* getName() const = 0;
49         // Shall write the name and the parameters
50         virtual void serialize(std::ostream &os) const = 0;
51         // Shall make an exact clone of the item
52         virtual InventoryItem* clone() = 0;
53         // Return the name of the image for this item
54         virtual std::string getImageBasename() const { return ""; }
55 #ifndef SERVER
56         // Shall return an image of the item (or NULL)
57         virtual video::ITexture * getImage() const
58                 { return NULL; }
59         // Shall return an image of the item without embellishments (or NULL)
60         virtual video::ITexture * getImageRaw() const
61                 { return getImage(); }
62 #endif
63         // Shall return a text to show in the GUI
64         virtual std::string getText() { return ""; }
65         // Returns the string used for inventory
66         virtual std::string getItemString();
67         
68         // Shall return false if item is not known and cannot be used
69         virtual bool isKnown() const { return true; }
70
71         /*
72                 Quantity methods
73         */
74
75         // Return true if the item can be add()ed to the other
76         virtual bool addableTo(const InventoryItem *other) const
77         { return false; }
78         // Return true if the other item contains this item
79         virtual bool isSubsetOf(const InventoryItem *other) const
80         { return false; }
81         // Remove the other item from this one if possible and return true
82         // Return false if not possible
83         virtual bool removeOther(const InventoryItem *other)
84         { return false; }
85         
86         u16 getCount() const
87         { return m_count; }
88         void setCount(u16 count)
89         { m_count = count; }
90
91         u16 freeSpace() const
92         {
93                 u16 max = getStackMax();
94                 if(m_count > max)
95                         return 0;
96                 return max - m_count;
97         }
98
99         void add(u16 count)
100         {
101                 m_count += count;
102         }
103         void remove(u16 count)
104         {
105                 assert(m_count >= count);
106                 m_count -= count;
107         }
108
109         /*
110                 Other properties
111         */
112
113         // Maximum size of a stack
114         virtual u16 getStackMax() const {return 1;}
115         // Whether it can be used
116         virtual bool isUsable() const {return false;}
117         // Whether it can be cooked
118         virtual bool isCookable() const {return false;}
119         // Result of cooking (can randomize)
120         virtual InventoryItem *createCookResult() const {return NULL;}
121         // Time of cooking
122         virtual float getCookTime() const {return 3.0;}
123         // Whether it can be burned (<0 = cannot be burned)
124         virtual float getBurnTime() const {return -1;}
125         // Gets amount of items that dropping one ItemSAO will decrement
126         // -1 means as many as possible
127         virtual s16 getDropCount() const { return -1; }
128         // Whether this item can point to liquids
129         virtual bool areLiquidsPointable() const { return false; }
130
131         // Creates an object from the item and places it in the world.
132         // If return value is true, item should be removed.
133         virtual bool dropOrPlace(ServerEnvironment *env,
134                         ServerActiveObject *dropper,
135                         v3f pos, bool place, s16 count);
136
137         // Eat, press, activate, whatever.
138         // Called when item is left-clicked while in hand.
139         // If returns true, item shall be deleted.
140         virtual bool use(ServerEnvironment *env,
141                         ServerActiveObject *user,
142                         const PointedThing& pointed){return false;}
143
144 protected:
145         IGameDef *m_gamedef;
146         u16 m_count;
147 };
148
149 class MaterialItem : public InventoryItem
150 {
151 public:
152         MaterialItem(IGameDef *gamedef, std::string nodename, u16 count);
153         // Legacy constructor
154         MaterialItem(IGameDef *gamedef, content_t content, u16 count);
155         /*
156                 Implementation interface
157         */
158         virtual const char* getName() const
159         {
160                 return "MaterialItem";
161         }
162         virtual void serialize(std::ostream &os) const
163         {
164                 os<<"node";
165                 os<<" \"";
166                 os<<m_nodename;
167                 os<<"\" ";
168                 os<<m_count;
169         }
170         virtual InventoryItem* clone()
171         {
172                 return new MaterialItem(m_gamedef, m_nodename, m_count);
173         }
174 #ifndef SERVER
175         video::ITexture * getImage() const;
176 #endif
177         std::string getText()
178         {
179                 std::ostringstream os;
180                 os<<m_count;
181                 return os.str();
182         }
183
184         virtual bool addableTo(const InventoryItem *other) const
185         {
186                 if(std::string(other->getName()) != "MaterialItem")
187                         return false;
188                 MaterialItem *m = (MaterialItem*)other;
189                 if(m->m_nodename != m_nodename)
190                         return false;
191                 return true;
192         }
193         virtual bool isSubsetOf(const InventoryItem *other) const
194         {
195                 if(std::string(other->getName()) != "MaterialItem")
196                         return false;
197                 MaterialItem *m = (MaterialItem*)other;
198                 if(m->m_nodename != m_nodename)
199                         return false;
200                 return m_count <= m->m_count;
201         }
202         virtual bool removeOther(const InventoryItem *other)
203         {
204                 if(!other->isSubsetOf(this))
205                         return false;
206                 MaterialItem *m = (MaterialItem*)other;
207                 m_count += m->m_count;
208                 return true;
209         }
210
211         u16 getStackMax() const
212         {
213                 return QUANTITY_ITEM_MAX_COUNT;
214         }
215
216         /*
217                 Other properties
218         */
219         bool isCookable() const;
220         InventoryItem *createCookResult() const;
221         float getCookTime() const;
222         float getBurnTime() const;
223         /*
224                 Special properties (not part of virtual interface)
225         */
226         std::string getNodeName() const
227         { return m_nodename; }
228         content_t getMaterial() const;
229 private:
230         std::string m_nodename;
231 };
232
233 /*
234         An item that is used as a mid-product when crafting.
235         Subnames:
236         - Stick
237 */
238 class CraftItem : public InventoryItem
239 {
240 public:
241         CraftItem(IGameDef *gamedef, std::string subname, u16 count):
242                 InventoryItem(gamedef, count)
243         {
244                 m_subname = subname;
245         }
246         /*
247                 Implementation interface
248         */
249         virtual const char* getName() const
250         {
251                 return "CraftItem";
252         }
253         virtual void serialize(std::ostream &os) const
254         {
255                 os<<"craft";
256                 os<<" \"";
257                 os<<m_subname;
258                 os<<"\" ";
259                 os<<m_count;
260         }
261         virtual InventoryItem* clone()
262         {
263                 return new CraftItem(m_gamedef, m_subname, m_count);
264         }
265 #ifndef SERVER
266         video::ITexture * getImage() const;
267 #endif
268         std::string getText()
269         {
270                 std::ostringstream os;
271                 os<<m_count;
272                 return os.str();
273         }
274
275         virtual bool isKnown() const;
276
277         virtual bool addableTo(const InventoryItem *other) const
278         {
279                 if(std::string(other->getName()) != "CraftItem")
280                         return false;
281                 CraftItem *m = (CraftItem*)other;
282                 if(m->m_subname != m_subname)
283                         return false;
284                 return true;
285         }
286         virtual bool isSubsetOf(const InventoryItem *other) const
287         {
288                 if(std::string(other->getName()) != "CraftItem")
289                         return false;
290                 CraftItem *m = (CraftItem*)other;
291                 if(m->m_subname != m_subname)
292                         return false;
293                 return m_count <= m->m_count;
294         }
295         virtual bool removeOther(const InventoryItem *other)
296         {
297                 if(!other->isSubsetOf(this))
298                         return false;
299                 CraftItem *m = (CraftItem*)other;
300                 m_count += m->m_count;
301                 return true;
302         }
303
304         /*
305                 Other properties
306         */
307
308         u16 getStackMax() const;
309         bool isUsable() const;
310         bool isCookable() const;
311         InventoryItem *createCookResult() const;
312         float getCookTime() const;
313         float getBurnTime() const;
314         s16 getDropCount() const;
315         bool areLiquidsPointable() const;
316
317         bool dropOrPlace(ServerEnvironment *env,
318                         ServerActiveObject *dropper,
319                         v3f pos, bool place, s16 count);
320         bool use(ServerEnvironment *env,
321                         ServerActiveObject *user,
322                         const PointedThing& pointed);
323
324         /*
325                 Special methods
326         */
327         std::string getSubName()
328         {
329                 return m_subname;
330         }
331 private:
332         std::string m_subname;
333 };
334
335 class ToolItem : public InventoryItem
336 {
337 public:
338         ToolItem(IGameDef *gamedef, std::string toolname, u16 wear):
339                 InventoryItem(gamedef, 1)
340         {
341                 m_toolname = toolname;
342                 m_wear = wear;
343         }
344         /*
345                 Implementation interface
346         */
347         virtual const char* getName() const
348         {
349                 return "ToolItem";
350         }
351         virtual void serialize(std::ostream &os) const
352         {
353                 os<<"tool";
354                 os<<" \"";
355                 os<<m_toolname;
356                 os<<"\" ";
357                 os<<m_wear;
358         }
359         virtual InventoryItem* clone()
360         {
361                 return new ToolItem(m_gamedef, m_toolname, m_wear);
362         }
363
364         std::string getImageBasename() const;
365 #ifndef SERVER
366         video::ITexture * getImage() const;
367         video::ITexture * getImageRaw() const;
368 #endif
369
370         std::string getText()
371         {
372                 return "";
373         }
374         
375         virtual bool isKnown() const;
376
377         virtual bool isSubsetOf(const InventoryItem *other) const
378         {
379                 if(std::string(other->getName()) != "ToolItem")
380                         return false;
381                 ToolItem *m = (ToolItem*)other;
382                 if(m->m_toolname != m_toolname)
383                         return false;
384                 return m_wear <= m->m_wear;
385         }
386         virtual bool removeOther(const InventoryItem *other)
387         {
388                 if(!other->isSubsetOf(this))
389                         return false;
390                 ToolItem *m = (ToolItem*)other;
391                 m_wear -= m->m_wear;
392                 return true;
393         }
394
395         /*
396                 Special methods
397         */
398         std::string getToolName()
399         {
400                 return m_toolname;
401         }
402         u16 getWear()
403         {
404                 return m_wear;
405         }
406         // Returns true if weared out
407         bool addWear(u16 add)
408         {
409                 if(m_wear >= 65535 - add)
410                 {
411                         m_wear = 65535;
412                         return true;
413                 }
414                 else
415                 {
416                         m_wear += add;
417                         return false;
418                 }
419         }
420 private:
421         std::string m_toolname;
422         u16 m_wear;
423 };
424
425 class InventoryList
426 {
427 public:
428         InventoryList(std::string name, u32 size);
429         ~InventoryList();
430         void clearItems();
431         void serialize(std::ostream &os) const;
432         void deSerialize(std::istream &is, IGameDef *gamedef);
433
434         InventoryList(const InventoryList &other);
435         InventoryList & operator = (const InventoryList &other);
436
437         const std::string &getName() const;
438         u32 getSize();
439         // Count used slots
440         u32 getUsedSlots();
441         u32 getFreeSlots();
442
443         /*bool getDirty(){ return m_dirty; }
444         void setDirty(bool dirty=true){ m_dirty = dirty; }*/
445         
446         // Get pointer to item
447         const InventoryItem * getItem(u32 i) const;
448         InventoryItem * getItem(u32 i);
449         // Returns old item (or NULL). Parameter can be NULL.
450         InventoryItem * changeItem(u32 i, InventoryItem *newitem);
451         // Delete item
452         void deleteItem(u32 i);
453
454         // Adds an item to a suitable place. Returns leftover item.
455         // If all went into the list, returns NULL.
456         InventoryItem * addItem(InventoryItem *newitem);
457
458         // If possible, adds item to given slot.
459         // If cannot be added at all, returns the item back.
460         // If can be added partly, decremented item is returned back.
461         // If can be added fully, NULL is returned.
462         InventoryItem * addItem(u32 i, InventoryItem *newitem);
463
464         // Checks whether the item could be added to the given slot
465         bool itemFits(const u32 i, const InventoryItem *newitem);
466
467         // Checks whether there is room for a given item
468         bool roomForItem(const InventoryItem *item);
469
470         // Checks whether there is room for a given item aftr it has been cooked
471         bool roomForCookedItem(const InventoryItem *item);
472
473         // Takes some items from a slot.
474         // If there are not enough, takes as many as it can.
475         // Returns NULL if couldn't take any.
476         InventoryItem * takeItem(u32 i, u32 count);
477
478         // Decrements amount of every material item
479         void decrementMaterials(u16 count);
480
481         void print(std::ostream &o);
482         
483 private:
484         core::array<InventoryItem*> m_items;
485         u32 m_size;
486         std::string m_name;
487         //bool m_dirty;
488 };
489
490 class Inventory
491 {
492 public:
493         ~Inventory();
494
495         void clear();
496
497         Inventory();
498         Inventory(const Inventory &other);
499         Inventory & operator = (const Inventory &other);
500         
501         void serialize(std::ostream &os) const;
502         void deSerialize(std::istream &is, IGameDef *gamedef);
503
504         InventoryList * addList(const std::string &name, u32 size);
505         InventoryList * getList(const std::string &name);
506         const InventoryList * getList(const std::string &name) const;
507         bool deleteList(const std::string &name);
508         // A shorthand for adding items.
509         // Returns NULL if the item was fully added, leftover otherwise.
510         InventoryItem * addItem(const std::string &listname, InventoryItem *newitem)
511         {
512                 InventoryList *list = getList(listname);
513                 if(list == NULL)
514                         return newitem;
515                 return list->addItem(newitem);
516         }
517         
518 private:
519         // -1 if not found
520         const s32 getListIndex(const std::string &name) const;
521
522         core::array<InventoryList*> m_lists;
523 };
524
525 class Player;
526
527 struct InventoryContext
528 {
529         Player *current_player;
530         
531         InventoryContext():
532                 current_player(NULL)
533         {}
534 };
535
536 struct InventoryAction;
537
538 class InventoryManager
539 {
540 public:
541         InventoryManager(){}
542         virtual ~InventoryManager(){}
543         
544         /*
545                 Get a pointer to an inventory specified by id.
546                 id can be:
547                 - "current_player"
548                 - "nodemeta:X,Y,Z"
549         */
550         virtual Inventory* getInventory(InventoryContext *c, std::string id)
551                 {return NULL;}
552         // Used on the server by InventoryAction::apply and other stuff
553         virtual void inventoryModified(InventoryContext *c, std::string id)
554                 {}
555         // Used on the client
556         virtual void inventoryAction(InventoryAction *a)
557                 {}
558 };
559
560 #define IACTION_MOVE 0
561 #define IACTION_DROP 1
562
563 struct InventoryAction
564 {
565         static InventoryAction * deSerialize(std::istream &is);
566         
567         virtual u16 getType() const = 0;
568         virtual void serialize(std::ostream &os) const = 0;
569         virtual void apply(InventoryContext *c, InventoryManager *mgr,
570                         ServerEnvironment *env) = 0;
571 };
572
573 struct IMoveAction : public InventoryAction
574 {
575         // count=0 means "everything"
576         u16 count;
577         std::string from_inv;
578         std::string from_list;
579         s16 from_i;
580         std::string to_inv;
581         std::string to_list;
582         s16 to_i;
583         
584         IMoveAction()
585         {
586                 count = 0;
587                 from_i = -1;
588                 to_i = -1;
589         }
590         
591         IMoveAction(std::istream &is);
592
593         u16 getType() const
594         {
595                 return IACTION_MOVE;
596         }
597
598         void serialize(std::ostream &os) const
599         {
600                 os<<"Move ";
601                 os<<count<<" ";
602                 os<<from_inv<<" ";
603                 os<<from_list<<" ";
604                 os<<from_i<<" ";
605                 os<<to_inv<<" ";
606                 os<<to_list<<" ";
607                 os<<to_i;
608         }
609
610         void apply(InventoryContext *c, InventoryManager *mgr,
611                         ServerEnvironment *env);
612 };
613
614 struct IDropAction : public InventoryAction
615 {
616         // count=0 means "everything"
617         u16 count;
618         std::string from_inv;
619         std::string from_list;
620         s16 from_i;
621         
622         IDropAction()
623         {
624                 count = 0;
625                 from_i = -1;
626         }
627         
628         IDropAction(std::istream &is);
629
630         u16 getType() const
631         {
632                 return IACTION_DROP;
633         }
634
635         void serialize(std::ostream &os) const
636         {
637                 os<<"Drop ";
638                 os<<count<<" ";
639                 os<<from_inv<<" ";
640                 os<<from_list<<" ";
641                 os<<from_i;
642         }
643
644         void apply(InventoryContext *c, InventoryManager *mgr,
645                         ServerEnvironment *env);
646 };
647
648 /*
649         Craft checking system
650 */
651
652 enum ItemSpecType
653 {
654         ITEM_NONE,
655         ITEM_MATERIAL,
656         ITEM_CRAFT,
657         ITEM_TOOL,
658         ITEM_MBO
659 };
660
661 struct ItemSpec
662 {
663         enum ItemSpecType type;
664         // Only other one of these is used
665         std::string name;
666         u16 num;
667
668         ItemSpec():
669                 type(ITEM_NONE)
670         {
671         }
672         ItemSpec(enum ItemSpecType a_type, std::string a_name):
673                 type(a_type),
674                 name(a_name),
675                 num(65535)
676         {
677         }
678         ItemSpec(enum ItemSpecType a_type, u16 a_num):
679                 type(a_type),
680                 name(""),
681                 num(a_num)
682         {
683         }
684
685         bool checkItem(const InventoryItem *item) const;
686 };
687
688 /*
689         items: a pointer to an array of 9 pointers to items
690         specs: a pointer to an array of 9 ItemSpecs
691 */
692 bool checkItemCombination(const InventoryItem * const*items, const ItemSpec *specs);
693
694 /*
695         items: a pointer to an array of 9 pointers to items
696         specs: a pointer to an array of 9 pointers to items
697 */
698 bool checkItemCombination(const InventoryItem * const * items,
699                 const InventoryItem * const * specs);
700
701 #endif
702