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