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