Merge remote-tracking branch 'origin/upstream'
[oweals/minetest.git] / src / inventory.h
1 /*
2 Minetest-c55
3 Copyright (C) 2010 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 /*
21 (c) 2010 Perttu Ahola <celeron55@gmail.com>
22 */
23
24 #ifndef INVENTORY_HEADER
25 #define INVENTORY_HEADER
26
27 #include <iostream>
28 #include <sstream>
29 #include <string>
30 #include "common_irrlicht.h"
31 #include "debug.h"
32 #include "mapblockobject.h"
33 #include "main.h" // For g_materials
34 #include "mapnode.h" // For content_t
35
36 #define QUANTITY_ITEM_MAX_COUNT 99
37
38 class ServerActiveObject;
39 class ServerEnvironment;
40
41 class InventoryItem
42 {
43 public:
44         InventoryItem(u16 count);
45         virtual ~InventoryItem();
46         
47         static InventoryItem* deSerialize(std::istream &is);
48         
49         virtual const char* getName() const = 0;
50         // Shall write the name and the parameters
51         virtual void serialize(std::ostream &os) = 0;
52         // Shall make an exact clone of the item
53         virtual InventoryItem* clone() = 0;
54 #ifndef SERVER
55         // Shall return an image to show in the GUI (or NULL)
56         virtual video::ITexture * getImage() { return NULL; }
57 #endif
58         // Shall return a text to show in the GUI
59         virtual std::string getText() { return ""; }
60         // Creates an object from the item, to be placed in the world.
61         virtual ServerActiveObject* createSAO(ServerEnvironment *env, u16 id, v3f pos);
62         // Gets amount of items that dropping one SAO will decrement
63         virtual u16 getDropCount(){ return getCount(); }
64
65         /*
66                 Quantity methods
67         */
68
69         // Shall return true if the item can be add()ed to the other
70         virtual bool addableTo(InventoryItem *other)
71         {
72                 return false;
73         }
74         
75         u16 getCount()
76         {
77                 return m_count;
78         }
79         void setCount(u16 count)
80         {
81                 m_count = count;
82         }
83         // This should return something else for stackable items
84         virtual u16 freeSpace()
85         {
86                 return 0;
87         }
88         void add(u16 count)
89         {
90                 assert(m_count + count <= QUANTITY_ITEM_MAX_COUNT);
91                 m_count += count;
92         }
93         void remove(u16 count)
94         {
95                 assert(m_count >= count);
96                 m_count -= count;
97         }
98
99         /*
100                 Other properties
101         */
102         // Whether it can be cooked
103         virtual bool isCookable(){return false;}
104         // Time of cooking
105         virtual float getCookTime(){return 3.0;}
106         // Result of cooking
107         virtual InventoryItem *createCookResult(){return NULL;}
108
109 protected:
110         u16 m_count;
111 };
112
113 class MaterialItem : public InventoryItem
114 {
115 public:
116         MaterialItem(content_t content, u16 count):
117                 InventoryItem(count)
118         {
119                 m_content = content;
120         }
121         /*
122                 Implementation interface
123         */
124         virtual const char* getName() const
125         {
126                 return "MaterialItem";
127         }
128         virtual void serialize(std::ostream &os)
129         {
130                 //os.imbue(std::locale("C"));
131                 os<<getName();
132                 os<<" ";
133                 os<<(unsigned int)m_content;
134                 os<<" ";
135                 os<<m_count;
136         }
137         virtual InventoryItem* clone()
138         {
139                 return new MaterialItem(m_content, m_count);
140         }
141 #ifndef SERVER
142         video::ITexture * getImage()
143         {
144                 return content_features(m_content).inventory_texture;
145                 return NULL;
146         }
147 #endif
148         std::string getText()
149         {
150                 std::ostringstream os;
151                 os<<m_count;
152                 return os.str();
153         }
154
155         virtual bool addableTo(InventoryItem *other)
156         {
157                 if(std::string(other->getName()) != "MaterialItem")
158                         return false;
159                 MaterialItem *m = (MaterialItem*)other;
160                 if(m->getMaterial() != m_content)
161                         return false;
162                 return true;
163         }
164         u16 freeSpace()
165         {
166                 if(m_count > QUANTITY_ITEM_MAX_COUNT)
167                         return 0;
168                 return QUANTITY_ITEM_MAX_COUNT - m_count;
169         }
170         /*
171                 Other properties
172         */
173         bool isCookable();
174         InventoryItem *createCookResult();
175         /*
176                 Special methods
177         */
178         content_t getMaterial()
179         {
180                 return m_content;
181         }
182 private:
183         content_t m_content;
184 };
185
186 //TODO: Remove
187 class MapBlockObjectItem : public InventoryItem
188 {
189 public:
190         MapBlockObjectItem(std::string inventorystring):
191                 InventoryItem(1)
192         {
193                 m_inventorystring = inventorystring;
194         }
195         
196         /*
197                 Implementation interface
198         */
199         virtual const char* getName() const
200         {
201                 return "MBOItem";
202         }
203         virtual void serialize(std::ostream &os)
204         {
205                 for(;;)
206                 {
207                         size_t t = m_inventorystring.find('|');
208                         if(t == std::string::npos)
209                                 break;
210                         m_inventorystring[t] = '?';
211                 }
212                 os<<getName();
213                 os<<" ";
214                 os<<m_inventorystring;
215                 os<<"|";
216         }
217         virtual InventoryItem* clone()
218         {
219                 return new MapBlockObjectItem(m_inventorystring);
220         }
221
222 #ifndef SERVER
223         video::ITexture * getImage();
224 #endif
225         std::string getText();
226
227         /*
228                 Special methods
229         */
230         std::string getInventoryString()
231         {
232                 return m_inventorystring;
233         }
234
235         MapBlockObject * createObject(v3f pos, f32 player_yaw, f32 player_pitch);
236
237 private:
238         std::string m_inventorystring;
239 };
240
241 /*
242         An item that is used as a mid-product when crafting.
243         Subnames:
244         - Stick
245 */
246 class CraftItem : public InventoryItem
247 {
248 public:
249         CraftItem(std::string subname, u16 count):
250                 InventoryItem(count)
251         {
252                 m_subname = subname;
253         }
254         /*
255                 Implementation interface
256         */
257         virtual const char* getName() const
258         {
259                 return "CraftItem";
260         }
261         virtual void serialize(std::ostream &os)
262         {
263                 os<<getName();
264                 os<<" ";
265                 os<<m_subname;
266                 os<<" ";
267                 os<<m_count;
268         }
269         virtual InventoryItem* clone()
270         {
271                 return new CraftItem(m_subname, m_count);
272         }
273 #ifndef SERVER
274         video::ITexture * getImage();
275 #endif
276         std::string getText()
277         {
278                 std::ostringstream os;
279                 os<<m_count;
280                 return os.str();
281         }
282
283         ServerActiveObject* createSAO(ServerEnvironment *env, u16 id, v3f pos);
284         u16 getDropCount();
285
286         virtual bool addableTo(InventoryItem *other)
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 true;
294         }
295         u16 freeSpace()
296         {
297                 if(m_count > QUANTITY_ITEM_MAX_COUNT)
298                         return 0;
299                 return QUANTITY_ITEM_MAX_COUNT - m_count;
300         }
301         /*
302                 Other properties
303         */
304         bool isCookable();
305         InventoryItem *createCookResult();
306         /*
307                 Special methods
308         */
309         std::string getSubName()
310         {
311                 return m_subname;
312         }
313 private:
314         std::string m_subname;
315 };
316
317 class ToolItem : public InventoryItem
318 {
319 public:
320         ToolItem(std::string toolname, u16 wear):
321                 InventoryItem(1)
322         {
323                 m_toolname = toolname;
324                 m_wear = wear;
325         }
326         /*
327                 Implementation interface
328         */
329         virtual const char* getName() const
330         {
331                 return "ToolItem";
332         }
333         virtual void serialize(std::ostream &os)
334         {
335                 os<<getName();
336                 os<<" ";
337                 os<<m_toolname;
338                 os<<" ";
339                 os<<m_wear;
340         }
341         virtual InventoryItem* clone()
342         {
343                 return new ToolItem(m_toolname, m_wear);
344         }
345 #ifndef SERVER
346         video::ITexture * getImage()
347         {
348                 if(g_texturesource == NULL)
349                         return NULL;
350                 
351                 std::string basename;
352                 if(m_toolname == "WPick")
353                         basename = "tool_woodpick.png";
354                 else if(m_toolname == "STPick")
355                         basename = "tool_stonepick.png";
356                 else if(m_toolname == "SteelPick")
357                         basename = "tool_steelpick.png";
358                 else if(m_toolname == "MesePick")
359                         basename = "tool_mesepick.png";
360                 else if(m_toolname == "WShovel")
361                         basename = "tool_woodshovel.png";
362                 else if(m_toolname == "STShovel")
363                         basename = "tool_stoneshovel.png";
364                 else if(m_toolname == "SteelShovel")
365                         basename = "tool_steelshovel.png";
366                 else if(m_toolname == "WAxe")
367                         basename = "tool_woodaxe.png";
368                 else if(m_toolname == "STAxe")
369                         basename = "tool_stoneaxe.png";
370                 else if(m_toolname == "SteelAxe")
371                         basename = "tool_steelaxe.png";
372                 else if(m_toolname == "WSword")
373                         basename = "tool_woodsword.png";
374                 else if(m_toolname == "STSword")
375                         basename = "tool_stonesword.png";
376                 else if(m_toolname == "SteelSword")
377                         basename = "tool_steelsword.png";
378                 else
379                         basename = "cloud.png";
380                 
381                 /*
382                         Calculate a progress value with sane amount of
383                         maximum states
384                 */
385                 u32 maxprogress = 30;
386                 u32 toolprogress = (65535-m_wear)/(65535/maxprogress);
387                 
388                 float value_f = (float)toolprogress / (float)maxprogress;
389                 std::ostringstream os;
390                 os<<basename<<"^[progressbar"<<value_f;
391
392                 return g_texturesource->getTextureRaw(os.str());
393         }
394 #endif
395         std::string getText()
396         {
397                 return "";
398                 
399                 /*std::ostringstream os;
400                 u16 f = 4;
401                 u16 d = 65535/f;
402                 u16 i;
403                 for(i=0; i<(65535-m_wear)/d; i++)
404                         os<<'X';
405                 for(; i<f; i++)
406                         os<<'-';
407                 return os.str();*/
408                 
409                 /*std::ostringstream os;
410                 os<<m_toolname;
411                 os<<" ";
412                 os<<(m_wear/655);
413                 return os.str();*/
414         }
415         /*
416                 Special methods
417         */
418         std::string getToolName()
419         {
420                 return m_toolname;
421         }
422         u16 getWear()
423         {
424                 return m_wear;
425         }
426         // Returns true if weared out
427         bool addWear(u16 add)
428         {
429                 if(m_wear >= 65535 - add)
430                 {
431                         m_wear = 65535;
432                         return true;
433                 }
434                 else
435                 {
436                         m_wear += add;
437                         return false;
438                 }
439         }
440 private:
441         std::string m_toolname;
442         u16 m_wear;
443 };
444
445 class InventoryList
446 {
447 public:
448         InventoryList(std::string name, u32 size);
449         ~InventoryList();
450         void clearItems();
451         void serialize(std::ostream &os);
452         void deSerialize(std::istream &is);
453
454         InventoryList(const InventoryList &other);
455         InventoryList & operator = (const InventoryList &other);
456
457         std::string getName();
458         u32 getSize();
459         // Count used slots
460         u32 getUsedSlots();
461         u32 getFreeSlots();
462
463         /*bool getDirty(){ return m_dirty; }
464         void setDirty(bool dirty=true){ m_dirty = dirty; }*/
465         
466         // Get pointer to item
467         InventoryItem * getItem(u32 i);
468         // Returns old item (or NULL). Parameter can be NULL.
469         InventoryItem * changeItem(u32 i, InventoryItem *newitem);
470         // Delete item
471         void deleteItem(u32 i);
472
473         // Adds an item to a suitable place. Returns leftover item.
474         // If all went into the list, returns NULL.
475         InventoryItem * addItem(InventoryItem *newitem);
476
477         // If possible, adds item to given slot.
478         // If cannot be added at all, returns the item back.
479         // If can be added partly, decremented item is returned back.
480         // If can be added fully, NULL is returned.
481         InventoryItem * addItem(u32 i, InventoryItem *newitem);
482
483         // Checks whether the item could be added to the given slot
484         bool itemFits(u32 i, InventoryItem *newitem);
485
486         // Takes some items from a slot.
487         // If there are not enough, takes as many as it can.
488         // Returns NULL if couldn't take any.
489         InventoryItem * takeItem(u32 i, u32 count);
490
491         // Decrements amount of every material item
492         void decrementMaterials(u16 count);
493
494         void print(std::ostream &o);
495         
496 private:
497         core::array<InventoryItem*> m_items;
498         u32 m_size;
499         std::string m_name;
500         //bool m_dirty;
501 };
502
503 class Inventory
504 {
505 public:
506         ~Inventory();
507
508         void clear();
509
510         Inventory();
511         Inventory(const Inventory &other);
512         Inventory & operator = (const Inventory &other);
513         
514         void serialize(std::ostream &os);
515         void deSerialize(std::istream &is);
516
517         InventoryList * addList(const std::string &name, u32 size);
518         InventoryList * getList(const std::string &name);
519         bool deleteList(const std::string &name);
520         // A shorthand for adding items.
521         // Returns NULL if the item was fully added, leftover otherwise.
522         InventoryItem * addItem(const std::string &listname, InventoryItem *newitem)
523         {
524                 InventoryList *list = getList(listname);
525                 if(list == NULL)
526                         return newitem;
527                 return list->addItem(newitem);
528         }
529         
530 private:
531         // -1 if not found
532         s32 getListIndex(const std::string &name);
533
534         core::array<InventoryList*> m_lists;
535 };
536
537 class Player;
538
539 struct InventoryContext
540 {
541         Player *current_player;
542         
543         InventoryContext():
544                 current_player(NULL)
545         {}
546 };
547
548 class InventoryAction;
549
550 class InventoryManager
551 {
552 public:
553         InventoryManager(){}
554         virtual ~InventoryManager(){}
555         
556         /*
557                 Get a pointer to an inventory specified by id.
558                 id can be:
559                 - "current_player"
560                 - "nodemeta:X,Y,Z"
561         */
562         virtual Inventory* getInventory(InventoryContext *c, std::string id)
563                 {return NULL;}
564         // Used on the server by InventoryAction::apply and other stuff
565         virtual void inventoryModified(InventoryContext *c, std::string id)
566                 {}
567         // Used on the client
568         virtual void inventoryAction(InventoryAction *a)
569                 {}
570 };
571
572 #define IACTION_MOVE 0
573
574 struct InventoryAction
575 {
576         static InventoryAction * deSerialize(std::istream &is);
577         
578         virtual u16 getType() const = 0;
579         virtual void serialize(std::ostream &os) = 0;
580         virtual void apply(InventoryContext *c, InventoryManager *mgr) = 0;
581 };
582
583 struct IMoveAction : public InventoryAction
584 {
585         // count=0 means "everything"
586         u16 count;
587         std::string from_inv;
588         std::string from_list;
589         s16 from_i;
590         std::string to_inv;
591         std::string to_list;
592         s16 to_i;
593         
594         IMoveAction()
595         {
596                 count = 0;
597                 from_i = -1;
598                 to_i = -1;
599         }
600         IMoveAction(std::istream &is)
601         {
602                 std::string ts;
603
604                 std::getline(is, ts, ' ');
605                 count = stoi(ts);
606
607                 std::getline(is, from_inv, ' ');
608
609                 std::getline(is, from_list, ' ');
610
611                 std::getline(is, ts, ' ');
612                 from_i = stoi(ts);
613
614                 std::getline(is, to_inv, ' ');
615
616                 std::getline(is, to_list, ' ');
617
618                 std::getline(is, ts, ' ');
619                 to_i = stoi(ts);
620         }
621
622         u16 getType() const
623         {
624                 return IACTION_MOVE;
625         }
626
627         void serialize(std::ostream &os)
628         {
629                 os<<"Move ";
630                 os<<count<<" ";
631                 os<<from_inv<<" ";
632                 os<<from_list<<" ";
633                 os<<from_i<<" ";
634                 os<<to_inv<<" ";
635                 os<<to_list<<" ";
636                 os<<to_i;
637         }
638
639         void apply(InventoryContext *c, InventoryManager *mgr);
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(InventoryItem *item);
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(InventoryItem **items, ItemSpec *specs);
687
688 #endif
689