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