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