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