Some work-in-progress in hp and mobs and a frightening amount of random fixes.
[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 if(m_toolname == "WSword")
373                         basename = "tool_woodsword.png";
374                 else if(m_toolname == "STSword")
375                         basename = "tool_stonesword.png";
376                 else if(m_toolname == "SteelSword")
377                         basename = "tool_steelsword.png";
378                 else
379                         basename = "cloud.png";
380                 
381                 /*
382                         Calculate a progress value with sane amount of
383                         maximum states
384                 */
385                 u32 maxprogress = 30;
386                 u32 toolprogress = (65535-m_wear)/(65535/maxprogress);
387                 
388                 float value_f = (float)toolprogress / (float)maxprogress;
389                 std::ostringstream os;
390                 os<<basename<<"^[progressbar"<<value_f;
391
392                 return g_texturesource->getTextureRaw(os.str());
393
394                 /*TextureSpec spec;
395                 spec.addTid(g_irrlicht->getTextureId(basename));
396                 spec.addTid(g_irrlicht->getTextureId(os.str()));
397                 return g_irrlicht->getTexture(spec);*/
398         }
399 #endif
400         std::string getText()
401         {
402                 return "";
403                 
404                 /*std::ostringstream os;
405                 u16 f = 4;
406                 u16 d = 65535/f;
407                 u16 i;
408                 for(i=0; i<(65535-m_wear)/d; i++)
409                         os<<'X';
410                 for(; i<f; i++)
411                         os<<'-';
412                 return os.str();*/
413                 
414                 /*std::ostringstream os;
415                 os<<m_toolname;
416                 os<<" ";
417                 os<<(m_wear/655);
418                 return os.str();*/
419         }
420         /*
421                 Special methods
422         */
423         std::string getToolName()
424         {
425                 return m_toolname;
426         }
427         u16 getWear()
428         {
429                 return m_wear;
430         }
431         // Returns true if weared out
432         bool addWear(u16 add)
433         {
434                 if(m_wear >= 65535 - add)
435                 {
436                         m_wear = 65535;
437                         return true;
438                 }
439                 else
440                 {
441                         m_wear += add;
442                         return false;
443                 }
444         }
445 private:
446         std::string m_toolname;
447         u16 m_wear;
448 };
449
450 class InventoryList
451 {
452 public:
453         InventoryList(std::string name, u32 size);
454         ~InventoryList();
455         void clearItems();
456         void serialize(std::ostream &os);
457         void deSerialize(std::istream &is);
458
459         InventoryList(const InventoryList &other);
460         InventoryList & operator = (const InventoryList &other);
461
462         std::string getName();
463         u32 getSize();
464         // Count used slots
465         u32 getUsedSlots();
466         u32 getFreeSlots();
467
468         /*bool getDirty(){ return m_dirty; }
469         void setDirty(bool dirty=true){ m_dirty = dirty; }*/
470         
471         // Get pointer to item
472         InventoryItem * getItem(u32 i);
473         // Returns old item (or NULL). Parameter can be NULL.
474         InventoryItem * changeItem(u32 i, InventoryItem *newitem);
475         // Delete item
476         void deleteItem(u32 i);
477
478         // Adds an item to a suitable place. Returns leftover item.
479         // If all went into the list, returns NULL.
480         InventoryItem * addItem(InventoryItem *newitem);
481
482         // If possible, adds item to given slot.
483         // If cannot be added at all, returns the item back.
484         // If can be added partly, decremented item is returned back.
485         // If can be added fully, NULL is returned.
486         InventoryItem * addItem(u32 i, InventoryItem *newitem);
487
488         // Checks whether the item could be added to the given slot
489         bool itemFits(u32 i, InventoryItem *newitem);
490
491         // Takes some items from a slot.
492         // If there are not enough, takes as many as it can.
493         // Returns NULL if couldn't take any.
494         InventoryItem * takeItem(u32 i, u32 count);
495
496         // Decrements amount of every material item
497         void decrementMaterials(u16 count);
498
499         void print(std::ostream &o);
500         
501 private:
502         core::array<InventoryItem*> m_items;
503         u32 m_size;
504         std::string m_name;
505         //bool m_dirty;
506 };
507
508 class Inventory
509 {
510 public:
511         ~Inventory();
512
513         void clear();
514
515         Inventory();
516         Inventory(const Inventory &other);
517         Inventory & operator = (const Inventory &other);
518         
519         void serialize(std::ostream &os);
520         void deSerialize(std::istream &is);
521
522         InventoryList * addList(const std::string &name, u32 size);
523         InventoryList * getList(const std::string &name);
524         bool deleteList(const std::string &name);
525         // A shorthand for adding items.
526         // Returns NULL if the item was fully added, leftover otherwise.
527         InventoryItem * addItem(const std::string &listname, InventoryItem *newitem)
528         {
529                 InventoryList *list = getList(listname);
530                 if(list == NULL)
531                         return newitem;
532                 return list->addItem(newitem);
533         }
534         
535 private:
536         // -1 if not found
537         s32 getListIndex(const std::string &name);
538
539         core::array<InventoryList*> m_lists;
540 };
541
542 class Player;
543
544 struct InventoryContext
545 {
546         Player *current_player;
547         
548         InventoryContext():
549                 current_player(NULL)
550         {}
551 };
552
553 class InventoryAction;
554
555 class InventoryManager
556 {
557 public:
558         InventoryManager(){}
559         virtual ~InventoryManager(){}
560         
561         /*
562                 Get a pointer to an inventory specified by id.
563                 id can be:
564                 - "current_player"
565                 - "nodemeta:X,Y,Z"
566         */
567         virtual Inventory* getInventory(InventoryContext *c, std::string id)
568                 {return NULL;}
569         // Used on the server by InventoryAction::apply and other stuff
570         virtual void inventoryModified(InventoryContext *c, std::string id)
571                 {}
572         // Used on the client
573         virtual void inventoryAction(InventoryAction *a)
574                 {}
575 };
576
577 #define IACTION_MOVE 0
578
579 struct InventoryAction
580 {
581         static InventoryAction * deSerialize(std::istream &is);
582         
583         virtual u16 getType() const = 0;
584         virtual void serialize(std::ostream &os) = 0;
585         virtual void apply(InventoryContext *c, InventoryManager *mgr) = 0;
586 };
587
588 struct IMoveAction : public InventoryAction
589 {
590         // count=0 means "everything"
591         u16 count;
592         std::string from_inv;
593         std::string from_list;
594         s16 from_i;
595         std::string to_inv;
596         std::string to_list;
597         s16 to_i;
598         
599         IMoveAction()
600         {
601                 count = 0;
602                 from_i = -1;
603                 to_i = -1;
604         }
605         IMoveAction(std::istream &is)
606         {
607                 std::string ts;
608
609                 std::getline(is, ts, ' ');
610                 count = stoi(ts);
611
612                 std::getline(is, from_inv, ' ');
613
614                 std::getline(is, from_list, ' ');
615
616                 std::getline(is, ts, ' ');
617                 from_i = stoi(ts);
618
619                 std::getline(is, to_inv, ' ');
620
621                 std::getline(is, to_list, ' ');
622
623                 std::getline(is, ts, ' ');
624                 to_i = stoi(ts);
625         }
626
627         u16 getType() const
628         {
629                 return IACTION_MOVE;
630         }
631
632         void serialize(std::ostream &os)
633         {
634                 os<<"Move ";
635                 os<<count<<" ";
636                 os<<from_inv<<" ";
637                 os<<from_list<<" ";
638                 os<<from_i<<" ";
639                 os<<to_inv<<" ";
640                 os<<to_list<<" ";
641                 os<<to_i;
642         }
643
644         void apply(InventoryContext *c, InventoryManager *mgr);
645 };
646
647 /*
648         Craft checking system
649 */
650
651 enum ItemSpecType
652 {
653         ITEM_NONE,
654         ITEM_MATERIAL,
655         ITEM_CRAFT,
656         ITEM_TOOL,
657         ITEM_MBO
658 };
659
660 struct ItemSpec
661 {
662         enum ItemSpecType type;
663         // Only other one of these is used
664         std::string name;
665         u16 num;
666
667         ItemSpec():
668                 type(ITEM_NONE)
669         {
670         }
671         ItemSpec(enum ItemSpecType a_type, std::string a_name):
672                 type(a_type),
673                 name(a_name),
674                 num(65535)
675         {
676         }
677         ItemSpec(enum ItemSpecType a_type, u16 a_num):
678                 type(a_type),
679                 name(""),
680                 num(a_num)
681         {
682         }
683
684         bool checkItem(InventoryItem *item);
685 };
686
687 /*
688         items: a pointer to an array of 9 pointers to items
689         specs: a pointer to an array of 9 ItemSpecs
690 */
691 bool checkItemCombination(InventoryItem **items, ItemSpec *specs);
692
693 #endif
694