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