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