Remove DSTACK support (#6346)
[oweals/minetest.git] / src / inventory.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser 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 #include "inventory.h"
21 #include "serialization.h"
22 #include "debug.h"
23 #include <sstream>
24 #include "log.h"
25 #include "itemdef.h"
26 #include "util/strfnd.h"
27 #include "content_mapnode.h" // For loading legacy MaterialItems
28 #include "nameidmapping.h" // For loading legacy MaterialItems
29 #include "util/serialize.h"
30 #include "util/string.h"
31
32 /*
33         ItemStack
34 */
35
36 static content_t content_translate_from_19_to_internal(content_t c_from)
37 {
38         for (const auto &tt : trans_table_19) {
39                 if(tt[1] == c_from) {
40                         return tt[0];
41                 }
42         }
43         return c_from;
44 }
45
46 ItemStack::ItemStack(const std::string &name_, u16 count_,
47                 u16 wear_, IItemDefManager *itemdef) :
48         name(itemdef->getAlias(name_)),
49         count(count_),
50         wear(wear_)
51 {
52         if (name.empty() || count == 0)
53                 clear();
54         else if (itemdef->get(name).type == ITEM_TOOL)
55                 count = 1;
56 }
57
58 void ItemStack::serialize(std::ostream &os) const
59 {
60         if (empty())
61                 return;
62
63         // Check how many parts of the itemstring are needed
64         int parts = 1;
65         if(count != 1)
66                 parts = 2;
67         if(wear != 0)
68                 parts = 3;
69         if (!metadata.empty())
70                 parts = 4;
71
72         os<<serializeJsonStringIfNeeded(name);
73         if(parts >= 2)
74                 os<<" "<<count;
75         if(parts >= 3)
76                 os<<" "<<wear;
77         if (parts >= 4) {
78                 os << " ";
79                 metadata.serialize(os);
80         }
81 }
82
83 void ItemStack::deSerialize(std::istream &is, IItemDefManager *itemdef)
84 {
85         clear();
86
87         // Read name
88         name = deSerializeJsonStringIfNeeded(is);
89
90         // Skip space
91         std::string tmp;
92         std::getline(is, tmp, ' ');
93         if(!tmp.empty())
94                 throw SerializationError("Unexpected text after item name");
95
96         if(name == "MaterialItem")
97         {
98                 // Obsoleted on 2011-07-30
99
100                 u16 material;
101                 is>>material;
102                 u16 materialcount;
103                 is>>materialcount;
104                 // Convert old materials
105                 if(material <= 0xff)
106                         material = content_translate_from_19_to_internal(material);
107                 if(material > 0xfff)
108                         throw SerializationError("Too large material number");
109                 // Convert old id to name
110                 NameIdMapping legacy_nimap;
111                 content_mapnode_get_name_id_mapping(&legacy_nimap);
112                 legacy_nimap.getName(material, name);
113                 if(name.empty())
114                         name = "unknown_block";
115                 if (itemdef)
116                         name = itemdef->getAlias(name);
117                 count = materialcount;
118         }
119         else if(name == "MaterialItem2")
120         {
121                 // Obsoleted on 2011-11-16
122
123                 u16 material;
124                 is>>material;
125                 u16 materialcount;
126                 is>>materialcount;
127                 if(material > 0xfff)
128                         throw SerializationError("Too large material number");
129                 // Convert old id to name
130                 NameIdMapping legacy_nimap;
131                 content_mapnode_get_name_id_mapping(&legacy_nimap);
132                 legacy_nimap.getName(material, name);
133                 if(name.empty())
134                         name = "unknown_block";
135                 if (itemdef)
136                         name = itemdef->getAlias(name);
137                 count = materialcount;
138         }
139         else if(name == "node" || name == "NodeItem" || name == "MaterialItem3"
140                         || name == "craft" || name == "CraftItem")
141         {
142                 // Obsoleted on 2012-01-07
143
144                 std::string all;
145                 std::getline(is, all, '\n');
146                 // First attempt to read inside ""
147                 Strfnd fnd(all);
148                 fnd.next("\"");
149                 // If didn't skip to end, we have ""s
150                 if(!fnd.at_end()){
151                         name = fnd.next("\"");
152                 } else { // No luck, just read a word then
153                         fnd.start(all);
154                         name = fnd.next(" ");
155                 }
156                 fnd.skip_over(" ");
157                 if (itemdef)
158                         name = itemdef->getAlias(name);
159                 count = stoi(trim(fnd.next("")));
160                 if(count == 0)
161                         count = 1;
162         }
163         else if(name == "MBOItem")
164         {
165                 // Obsoleted on 2011-10-14
166                 throw SerializationError("MBOItem not supported anymore");
167         }
168         else if(name == "tool" || name == "ToolItem")
169         {
170                 // Obsoleted on 2012-01-07
171
172                 std::string all;
173                 std::getline(is, all, '\n');
174                 // First attempt to read inside ""
175                 Strfnd fnd(all);
176                 fnd.next("\"");
177                 // If didn't skip to end, we have ""s
178                 if(!fnd.at_end()){
179                         name = fnd.next("\"");
180                 } else { // No luck, just read a word then
181                         fnd.start(all);
182                         name = fnd.next(" ");
183                 }
184                 count = 1;
185                 // Then read wear
186                 fnd.skip_over(" ");
187                 if (itemdef)
188                         name = itemdef->getAlias(name);
189                 wear = stoi(trim(fnd.next("")));
190         }
191         else
192         {
193                 do  // This loop is just to allow "break;"
194                 {
195                         // The real thing
196
197                         // Apply item aliases
198                         if (itemdef)
199                                 name = itemdef->getAlias(name);
200
201                         // Read the count
202                         std::string count_str;
203                         std::getline(is, count_str, ' ');
204                         if (count_str.empty()) {
205                                 count = 1;
206                                 break;
207                         }
208
209                         count = stoi(count_str);
210
211                         // Read the wear
212                         std::string wear_str;
213                         std::getline(is, wear_str, ' ');
214                         if(wear_str.empty())
215                                 break;
216
217                         wear = stoi(wear_str);
218
219                         // Read metadata
220                         metadata.deSerialize(is);
221
222                         // In case fields are added after metadata, skip space here:
223                         //std::getline(is, tmp, ' ');
224                         //if(!tmp.empty())
225                         //      throw SerializationError("Unexpected text after metadata");
226
227                 } while(false);
228         }
229
230         if (name.empty() || count == 0)
231                 clear();
232         else if (itemdef && itemdef->get(name).type == ITEM_TOOL)
233                 count = 1;
234 }
235
236 void ItemStack::deSerialize(const std::string &str, IItemDefManager *itemdef)
237 {
238         std::istringstream is(str, std::ios::binary);
239         deSerialize(is, itemdef);
240 }
241
242 std::string ItemStack::getItemString() const
243 {
244         std::ostringstream os(std::ios::binary);
245         serialize(os);
246         return os.str();
247 }
248
249
250 ItemStack ItemStack::addItem(ItemStack newitem, IItemDefManager *itemdef)
251 {
252         // If the item is empty or the position invalid, bail out
253         if(newitem.empty())
254         {
255                 // nothing can be added trivially
256         }
257         // If this is an empty item, it's an easy job.
258         else if(empty())
259         {
260                 const u16 stackMax = newitem.getStackMax(itemdef);
261
262                 *this = newitem;
263
264                 // If the item fits fully, delete it
265                 if (count <= stackMax) {
266                         newitem.clear();
267                 } else { // Else the item does not fit fully. Return the rest.
268                         count = stackMax;
269                         newitem.remove(count);
270                 }
271         }
272         // If item name or metadata differs, bail out
273         else if (name != newitem.name
274                 || metadata != newitem.metadata)
275         {
276                 // cannot be added
277         }
278         // If the item fits fully, add counter and delete it
279         else if(newitem.count <= freeSpace(itemdef))
280         {
281                 add(newitem.count);
282                 newitem.clear();
283         }
284         // Else the item does not fit fully. Add all that fits and return
285         // the rest.
286         else
287         {
288                 u16 freespace = freeSpace(itemdef);
289                 add(freespace);
290                 newitem.remove(freespace);
291         }
292
293         return newitem;
294 }
295
296 bool ItemStack::itemFits(ItemStack newitem,
297                 ItemStack *restitem,
298                 IItemDefManager *itemdef) const
299 {
300
301         // If the item is empty or the position invalid, bail out
302         if(newitem.empty())
303         {
304                 // nothing can be added trivially
305         }
306         // If this is an empty item, it's an easy job.
307         else if(empty())
308         {
309                 const u16 stackMax = newitem.getStackMax(itemdef);
310
311                 // If the item fits fully, delete it
312                 if (newitem.count <= stackMax) {
313                         newitem.clear();
314                 } else { // Else the item does not fit fully. Return the rest.
315                         newitem.remove(stackMax);
316                 }
317         }
318         // If item name or metadata differs, bail out
319         else if (name != newitem.name
320                 || metadata != newitem.metadata)
321         {
322                 // cannot be added
323         }
324         // If the item fits fully, delete it
325         else if(newitem.count <= freeSpace(itemdef))
326         {
327                 newitem.clear();
328         }
329         // Else the item does not fit fully. Return the rest.
330         else
331         {
332                 u16 freespace = freeSpace(itemdef);
333                 newitem.remove(freespace);
334         }
335
336         if(restitem)
337                 *restitem = newitem;
338         return newitem.empty();
339 }
340
341 ItemStack ItemStack::takeItem(u32 takecount)
342 {
343         if(takecount == 0 || count == 0)
344                 return ItemStack();
345
346         ItemStack result = *this;
347         if(takecount >= count)
348         {
349                 // Take all
350                 clear();
351         }
352         else
353         {
354                 // Take part
355                 remove(takecount);
356                 result.count = takecount;
357         }
358         return result;
359 }
360
361 ItemStack ItemStack::peekItem(u32 peekcount) const
362 {
363         if(peekcount == 0 || count == 0)
364                 return ItemStack();
365
366         ItemStack result = *this;
367         if(peekcount < count)
368                 result.count = peekcount;
369         return result;
370 }
371
372 /*
373         Inventory
374 */
375
376 InventoryList::InventoryList(const std::string &name, u32 size, IItemDefManager *itemdef):
377         m_name(name),
378         m_size(size),
379         m_itemdef(itemdef)
380 {
381         clearItems();
382 }
383
384 void InventoryList::clearItems()
385 {
386         m_items.clear();
387
388         for (u32 i=0; i < m_size; i++) {
389                 m_items.emplace_back();
390         }
391
392         //setDirty(true);
393 }
394
395 void InventoryList::setSize(u32 newsize)
396 {
397         if(newsize != m_items.size())
398                 m_items.resize(newsize);
399         m_size = newsize;
400 }
401
402 void InventoryList::setWidth(u32 newwidth)
403 {
404         m_width = newwidth;
405 }
406
407 void InventoryList::setName(const std::string &name)
408 {
409         m_name = name;
410 }
411
412 void InventoryList::serialize(std::ostream &os) const
413 {
414         //os.imbue(std::locale("C"));
415
416         os<<"Width "<<m_width<<"\n";
417
418         for (const auto &item : m_items) {
419                 if (item.empty()) {
420                         os<<"Empty";
421                 } else {
422                         os<<"Item ";
423                         item.serialize(os);
424                 }
425                 os<<"\n";
426         }
427
428         os<<"EndInventoryList\n";
429 }
430
431 void InventoryList::deSerialize(std::istream &is)
432 {
433         //is.imbue(std::locale("C"));
434
435         clearItems();
436         u32 item_i = 0;
437         m_width = 0;
438
439         for(;;)
440         {
441                 std::string line;
442                 std::getline(is, line, '\n');
443
444                 std::istringstream iss(line);
445                 //iss.imbue(std::locale("C"));
446
447                 std::string name;
448                 std::getline(iss, name, ' ');
449
450                 if (name == "EndInventoryList") {
451                         break;
452                 }
453
454                 // This is a temporary backwards compatibility fix
455                 if (name == "end") {
456                         break;
457                 }
458
459                 if (name == "Width") {
460                         iss >> m_width;
461                         if (iss.fail())
462                                 throw SerializationError("incorrect width property");
463                 }
464                 else if(name == "Item")
465                 {
466                         if(item_i > getSize() - 1)
467                                 throw SerializationError("too many items");
468                         ItemStack item;
469                         item.deSerialize(iss, m_itemdef);
470                         m_items[item_i++] = item;
471                 }
472                 else if(name == "Empty")
473                 {
474                         if(item_i > getSize() - 1)
475                                 throw SerializationError("too many items");
476                         m_items[item_i++].clear();
477                 }
478         }
479 }
480
481 InventoryList::InventoryList(const InventoryList &other)
482 {
483         *this = other;
484 }
485
486 InventoryList & InventoryList::operator = (const InventoryList &other)
487 {
488         m_items = other.m_items;
489         m_size = other.m_size;
490         m_width = other.m_width;
491         m_name = other.m_name;
492         m_itemdef = other.m_itemdef;
493         //setDirty(true);
494
495         return *this;
496 }
497
498 bool InventoryList::operator == (const InventoryList &other) const
499 {
500         if(m_size != other.m_size)
501                 return false;
502         if(m_width != other.m_width)
503                 return false;
504         if(m_name != other.m_name)
505                 return false;
506         for(u32 i=0; i<m_items.size(); i++)
507         {
508                 ItemStack s1 = m_items[i];
509                 ItemStack s2 = other.m_items[i];
510                 if(s1.name != s2.name || s1.wear!= s2.wear || s1.count != s2.count ||
511                                 s1.metadata != s2.metadata)
512                         return false;
513         }
514
515         return true;
516 }
517
518 const std::string &InventoryList::getName() const
519 {
520         return m_name;
521 }
522
523 u32 InventoryList::getSize() const
524 {
525         return m_items.size();
526 }
527
528 u32 InventoryList::getWidth() const
529 {
530         return m_width;
531 }
532
533 u32 InventoryList::getUsedSlots() const
534 {
535         u32 num = 0;
536         for (const auto &m_item : m_items) {
537                 if (!m_item.empty())
538                         num++;
539         }
540         return num;
541 }
542
543 u32 InventoryList::getFreeSlots() const
544 {
545         return getSize() - getUsedSlots();
546 }
547
548 const ItemStack& InventoryList::getItem(u32 i) const
549 {
550         assert(i < m_size); // Pre-condition
551         return m_items[i];
552 }
553
554 ItemStack& InventoryList::getItem(u32 i)
555 {
556         assert(i < m_size); // Pre-condition
557         return m_items[i];
558 }
559
560 ItemStack InventoryList::changeItem(u32 i, const ItemStack &newitem)
561 {
562         if(i >= m_items.size())
563                 return newitem;
564
565         ItemStack olditem = m_items[i];
566         m_items[i] = newitem;
567         //setDirty(true);
568         return olditem;
569 }
570
571 void InventoryList::deleteItem(u32 i)
572 {
573         assert(i < m_items.size()); // Pre-condition
574         m_items[i].clear();
575 }
576
577 ItemStack InventoryList::addItem(const ItemStack &newitem_)
578 {
579         ItemStack newitem = newitem_;
580
581         if(newitem.empty())
582                 return newitem;
583
584         /*
585                 First try to find if it could be added to some existing items
586         */
587         for(u32 i=0; i<m_items.size(); i++)
588         {
589                 // Ignore empty slots
590                 if(m_items[i].empty())
591                         continue;
592                 // Try adding
593                 newitem = addItem(i, newitem);
594                 if(newitem.empty())
595                         return newitem; // All was eaten
596         }
597
598         /*
599                 Then try to add it to empty slots
600         */
601         for(u32 i=0; i<m_items.size(); i++)
602         {
603                 // Ignore unempty slots
604                 if(!m_items[i].empty())
605                         continue;
606                 // Try adding
607                 newitem = addItem(i, newitem);
608                 if(newitem.empty())
609                         return newitem; // All was eaten
610         }
611
612         // Return leftover
613         return newitem;
614 }
615
616 ItemStack InventoryList::addItem(u32 i, const ItemStack &newitem)
617 {
618         if(i >= m_items.size())
619                 return newitem;
620
621         ItemStack leftover = m_items[i].addItem(newitem, m_itemdef);
622         //if(leftover != newitem)
623         //      setDirty(true);
624         return leftover;
625 }
626
627 bool InventoryList::itemFits(const u32 i, const ItemStack &newitem,
628                 ItemStack *restitem) const
629 {
630         if(i >= m_items.size())
631         {
632                 if(restitem)
633                         *restitem = newitem;
634                 return false;
635         }
636
637         return m_items[i].itemFits(newitem, restitem, m_itemdef);
638 }
639
640 bool InventoryList::roomForItem(const ItemStack &item_) const
641 {
642         ItemStack item = item_;
643         ItemStack leftover;
644         for(u32 i=0; i<m_items.size(); i++)
645         {
646                 if(itemFits(i, item, &leftover))
647                         return true;
648                 item = leftover;
649         }
650         return false;
651 }
652
653 bool InventoryList::containsItem(const ItemStack &item, bool match_meta) const
654 {
655         u32 count = item.count;
656         if (count == 0)
657                 return true;
658
659         for (auto i = m_items.rbegin(); i != m_items.rend(); ++i) {
660                 if (count == 0)
661                         break;
662                 if (i->name == item.name && (!match_meta || (i->metadata == item.metadata))) {
663                         if (i->count >= count)
664                                 return true;
665
666                         count -= i->count;
667                 }
668         }
669         return false;
670 }
671
672 ItemStack InventoryList::removeItem(const ItemStack &item)
673 {
674         ItemStack removed;
675         for (auto i = m_items.rbegin(); i != m_items.rend(); ++i) {
676                 if (i->name == item.name) {
677                         u32 still_to_remove = item.count - removed.count;
678                         removed.addItem(i->takeItem(still_to_remove), m_itemdef);
679                         if (removed.count == item.count)
680                                 break;
681                 }
682         }
683         return removed;
684 }
685
686 ItemStack InventoryList::takeItem(u32 i, u32 takecount)
687 {
688         if(i >= m_items.size())
689                 return ItemStack();
690
691         ItemStack taken = m_items[i].takeItem(takecount);
692         //if(!taken.empty())
693         //      setDirty(true);
694         return taken;
695 }
696
697 void InventoryList::moveItemSomewhere(u32 i, InventoryList *dest, u32 count)
698 {
699         // Take item from source list
700         ItemStack item1;
701         if (count == 0)
702                 item1 = changeItem(i, ItemStack());
703         else
704                 item1 = takeItem(i, count);
705
706         if (item1.empty())
707                 return;
708
709         // Try to add the item to destination list
710         u32 dest_size = dest->getSize();
711         // First try all the non-empty slots
712         for (u32 dest_i = 0; dest_i < dest_size; dest_i++) {
713                 if (!m_items[dest_i].empty()) {
714                         item1 = dest->addItem(dest_i, item1);
715                         if (item1.empty()) return;
716                 }
717         }
718
719         // Then try all the empty ones
720         for (u32 dest_i = 0; dest_i < dest_size; dest_i++) {
721                 if (m_items[dest_i].empty()) {
722                         item1 = dest->addItem(dest_i, item1);
723                         if (item1.empty()) return;
724                 }
725         }
726
727         // If we reach this, the item was not fully added
728         // Add the remaining part back to the source item
729         addItem(i, item1);
730 }
731
732 u32 InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i,
733                 u32 count, bool swap_if_needed, bool *did_swap)
734 {
735         if(this == dest && i == dest_i)
736                 return count;
737
738         // Take item from source list
739         ItemStack item1;
740         if(count == 0)
741                 item1 = changeItem(i, ItemStack());
742         else
743                 item1 = takeItem(i, count);
744
745         if(item1.empty())
746                 return 0;
747
748         // Try to add the item to destination list
749         u32 oldcount = item1.count;
750         item1 = dest->addItem(dest_i, item1);
751
752         // If something is returned, the item was not fully added
753         if(!item1.empty())
754         {
755                 // If olditem is returned, nothing was added.
756                 bool nothing_added = (item1.count == oldcount);
757
758                 // If something else is returned, part of the item was left unadded.
759                 // Add the other part back to the source item
760                 addItem(i, item1);
761
762                 // If olditem is returned, nothing was added.
763                 // Swap the items
764                 if (nothing_added && swap_if_needed) {
765                         // Tell that we swapped
766                         if (did_swap != NULL) {
767                                 *did_swap = true;
768                         }
769                         // Take item from source list
770                         item1 = changeItem(i, ItemStack());
771                         // Adding was not possible, swap the items.
772                         ItemStack item2 = dest->changeItem(dest_i, item1);
773                         // Put item from destination list to the source list
774                         changeItem(i, item2);
775                 }
776         }
777         return (oldcount - item1.count);
778 }
779
780 /*
781         Inventory
782 */
783
784 Inventory::~Inventory()
785 {
786         clear();
787 }
788
789 void Inventory::clear()
790 {
791         m_dirty = true;
792         for (auto &m_list : m_lists) {
793                 delete m_list;
794         }
795         m_lists.clear();
796 }
797
798 void Inventory::clearContents()
799 {
800         m_dirty = true;
801         for (InventoryList *list : m_lists) {
802                 for (u32 j=0; j<list->getSize(); j++) {
803                         list->deleteItem(j);
804                 }
805         }
806 }
807
808 Inventory::Inventory(IItemDefManager *itemdef)
809 {
810         m_dirty = false;
811         m_itemdef = itemdef;
812 }
813
814 Inventory::Inventory(const Inventory &other)
815 {
816         *this = other;
817         m_dirty = false;
818 }
819
820 Inventory & Inventory::operator = (const Inventory &other)
821 {
822         // Gracefully handle self assignment
823         if(this != &other)
824         {
825                 m_dirty = true;
826                 clear();
827                 m_itemdef = other.m_itemdef;
828                 for (InventoryList *list : other.m_lists) {
829                         m_lists.push_back(new InventoryList(*list));
830                 }
831         }
832         return *this;
833 }
834
835 bool Inventory::operator == (const Inventory &other) const
836 {
837         if(m_lists.size() != other.m_lists.size())
838                 return false;
839
840         for(u32 i=0; i<m_lists.size(); i++)
841         {
842                 if(*m_lists[i] != *other.m_lists[i])
843                         return false;
844         }
845         return true;
846 }
847
848 void Inventory::serialize(std::ostream &os) const
849 {
850         for (InventoryList *list : m_lists) {
851                 os<<"List "<<list->getName()<<" "<<list->getSize()<<"\n";
852                 list->serialize(os);
853         }
854
855         os<<"EndInventory\n";
856 }
857
858 void Inventory::deSerialize(std::istream &is)
859 {
860         clear();
861
862         for(;;)
863         {
864                 std::string line;
865                 std::getline(is, line, '\n');
866
867                 std::istringstream iss(line);
868
869                 std::string name;
870                 std::getline(iss, name, ' ');
871
872                 if (name == "EndInventory") {
873                         break;
874                 }
875
876                 // This is a temporary backwards compatibility fix
877                 if (name == "end") {
878                         break;
879                 }
880
881                 if (name == "List") {
882                         std::string listname;
883                         u32 listsize;
884
885                         std::getline(iss, listname, ' ');
886                         iss>>listsize;
887
888                         InventoryList *list = new InventoryList(listname, listsize, m_itemdef);
889                         list->deSerialize(is);
890
891                         m_lists.push_back(list);
892                 }
893                 else
894                 {
895                         throw SerializationError("invalid inventory specifier: " + name);
896                 }
897         }
898 }
899
900 InventoryList * Inventory::addList(const std::string &name, u32 size)
901 {
902         m_dirty = true;
903         s32 i = getListIndex(name);
904         if(i != -1)
905         {
906                 if(m_lists[i]->getSize() != size)
907                 {
908                         delete m_lists[i];
909                         m_lists[i] = new InventoryList(name, size, m_itemdef);
910                 }
911                 return m_lists[i];
912         }
913
914
915         //don't create list with invalid name
916         if (name.find(' ') != std::string::npos) return NULL;
917
918         InventoryList *list = new InventoryList(name, size, m_itemdef);
919         m_lists.push_back(list);
920         return list;
921 }
922
923 InventoryList * Inventory::getList(const std::string &name)
924 {
925         s32 i = getListIndex(name);
926         if(i == -1)
927                 return NULL;
928         return m_lists[i];
929 }
930
931 std::vector<const InventoryList*> Inventory::getLists()
932 {
933         std::vector<const InventoryList*> lists;
934         for (auto list : m_lists) {
935                 lists.push_back(list);
936         }
937         return lists;
938 }
939
940 bool Inventory::deleteList(const std::string &name)
941 {
942         s32 i = getListIndex(name);
943         if(i == -1)
944                 return false;
945         m_dirty = true;
946         delete m_lists[i];
947         m_lists.erase(m_lists.begin() + i);
948         return true;
949 }
950
951 const InventoryList * Inventory::getList(const std::string &name) const
952 {
953         s32 i = getListIndex(name);
954         if(i == -1)
955                 return NULL;
956         return m_lists[i];
957 }
958
959 const s32 Inventory::getListIndex(const std::string &name) const
960 {
961         for(u32 i=0; i<m_lists.size(); i++)
962         {
963                 if(m_lists[i]->getName() == name)
964                         return i;
965         }
966         return -1;
967 }
968
969 //END