57af376501b4d5fec503518bf815cf0afaa7cc19
[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         /*
243                 Implementation interface
244         */
245         virtual const char* getName() const
246         {
247                 return "CraftItem";
248         }
249         virtual void serialize(std::ostream &os) const
250         {
251                 os<<"craft";
252                 os<<" \"";
253                 os<<m_subname;
254                 os<<"\" ";
255                 os<<m_count;
256         }
257         virtual InventoryItem* clone()
258         {
259                 return new CraftItem(m_gamedef, m_subname, m_count);
260         }
261 #ifndef SERVER
262         video::ITexture * getImage() const;
263 #endif
264         std::string getText()
265         {
266                 std::ostringstream os;
267                 os<<m_count;
268                 return os.str();
269         }
270
271         virtual bool isKnown() const;
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<<"tool";
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 isKnown() const;
372
373         virtual bool isSubsetOf(const InventoryItem *other) const
374         {
375                 if(std::string(other->getName()) != "ToolItem")
376                         return false;
377                 ToolItem *m = (ToolItem*)other;
378                 if(m->m_toolname != m_toolname)
379                         return false;
380                 return m_wear <= m->m_wear;
381         }
382         virtual bool removeOther(const InventoryItem *other)
383         {
384                 if(!other->isSubsetOf(this))
385                         return false;
386                 ToolItem *m = (ToolItem*)other;
387                 m_wear -= m->m_wear;
388                 return true;
389         }
390
391         /*
392                 Special methods
393         */
394         std::string getToolName()
395         {
396                 return m_toolname;
397         }
398         u16 getWear()
399         {
400                 return m_wear;
401         }
402         // Returns true if weared out
403         bool addWear(u16 add)
404         {
405                 if(m_wear >= 65535 - add)
406                 {
407                         m_wear = 65535;
408                         return true;
409                 }
410                 else
411                 {
412                         m_wear += add;
413                         return false;
414                 }
415         }
416 private:
417         std::string m_toolname;
418         u16 m_wear;
419 };
420
421 class InventoryList
422 {
423 public:
424         InventoryList(std::string name, u32 size);
425         ~InventoryList();
426         void clearItems();
427         void serialize(std::ostream &os) const;
428         void deSerialize(std::istream &is, IGameDef *gamedef);
429
430         InventoryList(const InventoryList &other);
431         InventoryList & operator = (const InventoryList &other);
432
433         const std::string &getName() const;
434         u32 getSize();
435         // Count used slots
436         u32 getUsedSlots();
437         u32 getFreeSlots();
438
439         /*bool getDirty(){ return m_dirty; }
440         void setDirty(bool dirty=true){ m_dirty = dirty; }*/
441         
442         // Get pointer to item
443         const InventoryItem * getItem(u32 i) const;
444         InventoryItem * getItem(u32 i);
445         // Returns old item (or NULL). Parameter can be NULL.
446         InventoryItem * changeItem(u32 i, InventoryItem *newitem);
447         // Delete item
448         void deleteItem(u32 i);
449
450         // Adds an item to a suitable place. Returns leftover item.
451         // If all went into the list, returns NULL.
452         InventoryItem * addItem(InventoryItem *newitem);
453
454         // If possible, adds item to given slot.
455         // If cannot be added at all, returns the item back.
456         // If can be added partly, decremented item is returned back.
457         // If can be added fully, NULL is returned.
458         InventoryItem * addItem(u32 i, InventoryItem *newitem);
459
460         // Checks whether the item could be added to the given slot
461         bool itemFits(const u32 i, const InventoryItem *newitem);
462
463         // Checks whether there is room for a given item
464         bool roomForItem(const InventoryItem *item);
465
466         // Checks whether there is room for a given item aftr it has been cooked
467         bool roomForCookedItem(const InventoryItem *item);
468
469         // Takes some items from a slot.
470         // If there are not enough, takes as many as it can.
471         // Returns NULL if couldn't take any.
472         InventoryItem * takeItem(u32 i, u32 count);
473
474         // Decrements amount of every material item
475         void decrementMaterials(u16 count);
476
477         void print(std::ostream &o);
478         
479 private:
480         core::array<InventoryItem*> m_items;
481         u32 m_size;
482         std::string m_name;
483         //bool m_dirty;
484 };
485
486 class Inventory
487 {
488 public:
489         ~Inventory();
490
491         void clear();
492
493         Inventory();
494         Inventory(const Inventory &other);
495         Inventory & operator = (const Inventory &other);
496         
497         void serialize(std::ostream &os) const;
498         void deSerialize(std::istream &is, IGameDef *gamedef);
499
500         InventoryList * addList(const std::string &name, u32 size);
501         InventoryList * getList(const std::string &name);
502         const InventoryList * getList(const std::string &name) const;
503         bool deleteList(const std::string &name);
504         // A shorthand for adding items.
505         // Returns NULL if the item was fully added, leftover otherwise.
506         InventoryItem * addItem(const std::string &listname, InventoryItem *newitem)
507         {
508                 InventoryList *list = getList(listname);
509                 if(list == NULL)
510                         return newitem;
511                 return list->addItem(newitem);
512         }
513         
514 private:
515         // -1 if not found
516         const s32 getListIndex(const std::string &name) const;
517
518         core::array<InventoryList*> m_lists;
519 };
520
521 class Player;
522
523 struct InventoryContext
524 {
525         Player *current_player;
526         
527         InventoryContext():
528                 current_player(NULL)
529         {}
530 };
531
532 struct InventoryAction;
533
534 class InventoryManager
535 {
536 public:
537         InventoryManager(){}
538         virtual ~InventoryManager(){}
539         
540         /*
541                 Get a pointer to an inventory specified by id.
542                 id can be:
543                 - "current_player"
544                 - "nodemeta:X,Y,Z"
545         */
546         virtual Inventory* getInventory(InventoryContext *c, std::string id)
547                 {return NULL;}
548         // Used on the server by InventoryAction::apply and other stuff
549         virtual void inventoryModified(InventoryContext *c, std::string id)
550                 {}
551         // Used on the client
552         virtual void inventoryAction(InventoryAction *a)
553                 {}
554 };
555
556 #define IACTION_MOVE 0
557 #define IACTION_DROP 1
558
559 struct InventoryAction
560 {
561         static InventoryAction * deSerialize(std::istream &is);
562         
563         virtual u16 getType() const = 0;
564         virtual void serialize(std::ostream &os) const = 0;
565         virtual void apply(InventoryContext *c, InventoryManager *mgr,
566                         ServerEnvironment *env) = 0;
567 };
568
569 struct IMoveAction : public InventoryAction
570 {
571         // count=0 means "everything"
572         u16 count;
573         std::string from_inv;
574         std::string from_list;
575         s16 from_i;
576         std::string to_inv;
577         std::string to_list;
578         s16 to_i;
579         
580         IMoveAction()
581         {
582                 count = 0;
583                 from_i = -1;
584                 to_i = -1;
585         }
586         
587         IMoveAction(std::istream &is);
588
589         u16 getType() const
590         {
591                 return IACTION_MOVE;
592         }
593
594         void serialize(std::ostream &os) const
595         {
596                 os<<"Move ";
597                 os<<count<<" ";
598                 os<<from_inv<<" ";
599                 os<<from_list<<" ";
600                 os<<from_i<<" ";
601                 os<<to_inv<<" ";
602                 os<<to_list<<" ";
603                 os<<to_i;
604         }
605
606         void apply(InventoryContext *c, InventoryManager *mgr,
607                         ServerEnvironment *env);
608 };
609
610 struct IDropAction : public InventoryAction
611 {
612         // count=0 means "everything"
613         u16 count;
614         std::string from_inv;
615         std::string from_list;
616         s16 from_i;
617         
618         IDropAction()
619         {
620                 count = 0;
621                 from_i = -1;
622         }
623         
624         IDropAction(std::istream &is);
625
626         u16 getType() const
627         {
628                 return IACTION_DROP;
629         }
630
631         void serialize(std::ostream &os) const
632         {
633                 os<<"Drop ";
634                 os<<count<<" ";
635                 os<<from_inv<<" ";
636                 os<<from_list<<" ";
637                 os<<from_i;
638         }
639
640         void apply(InventoryContext *c, InventoryManager *mgr,
641                         ServerEnvironment *env);
642 };
643
644 /*
645         Craft checking system
646 */
647
648 enum ItemSpecType
649 {
650         ITEM_NONE,
651         ITEM_MATERIAL,
652         ITEM_CRAFT,
653         ITEM_TOOL,
654         ITEM_MBO
655 };
656
657 struct ItemSpec
658 {
659         enum ItemSpecType type;
660         // Only other one of these is used
661         std::string name;
662         u16 num;
663
664         ItemSpec():
665                 type(ITEM_NONE)
666         {
667         }
668         ItemSpec(enum ItemSpecType a_type, std::string a_name):
669                 type(a_type),
670                 name(a_name),
671                 num(65535)
672         {
673         }
674         ItemSpec(enum ItemSpecType a_type, u16 a_num):
675                 type(a_type),
676                 name(""),
677                 num(a_num)
678         {
679         }
680
681         bool checkItem(const InventoryItem *item) const;
682 };
683
684 /*
685         items: a pointer to an array of 9 pointers to items
686         specs: a pointer to an array of 9 ItemSpecs
687 */
688 bool checkItemCombination(const InventoryItem * const*items, const ItemSpec *specs);
689
690 /*
691         items: a pointer to an array of 9 pointers to items
692         specs: a pointer to an array of 9 pointers to items
693 */
694 bool checkItemCombination(const InventoryItem * const * items,
695                 const InventoryItem * const * specs);
696
697 #endif
698