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