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