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