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