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