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