X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Finventory.cpp;h=e89993e63d773f43cd610ee54cb9a1ab26be12db;hb=48a718e715710c9cb7edd6ad8e1cd7a0ed416908;hp=03df98de6fd2390db6bd5178ce06fbf9e194ebe5;hpb=cced6aaf8db60e4a28e290f4ca235661037193aa;p=dragonfireclient.git diff --git a/src/inventory.cpp b/src/inventory.cpp index 03df98de6..e89993e63 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -1,297 +1,497 @@ /* -Minetest-c55 -Copyright (C) 2010 celeron55, Perttu Ahola +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Lesser General Public License for more details. -You should have received a copy of the GNU General Public License along +You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -/* -(c) 2010 Perttu Ahola -*/ - #include "inventory.h" #include "serialization.h" -#include "utility.h" #include "debug.h" #include -#include "main.h" -#include "serverobject.h" -#include "content_mapnode.h" -#include "content_inventory.h" +#include "log.h" +#include "itemdef.h" +#include "strfnd.h" +#include "content_mapnode.h" // For loading legacy MaterialItems +#include "nameidmapping.h" // For loading legacy MaterialItems +#include "util/serialize.h" +#include "util/string.h" /* - InventoryItem + ItemStack */ -InventoryItem::InventoryItem(u16 count) +static content_t content_translate_from_19_to_internal(content_t c_from) { - m_count = count; + for(u32 i=0; i= 0x7f || s[i] == ' ' || s[i] == '\"') + return serializeJsonString(s); + } + return s; } -InventoryItem* InventoryItem::deSerialize(std::istream &is) +// Parses a string serialized by serializeJsonStringIfNeeded. +static std::string deSerializeJsonStringIfNeeded(std::istream &is) { - DSTACK(__FUNCTION_NAME); + std::ostringstream tmp_os; + bool expect_initial_quote = true; + bool is_json = false; + bool was_backslash = false; + for(;;) + { + char c = is.get(); + if(is.eof()) + break; + if(expect_initial_quote && c == '"') + { + tmp_os << c; + is_json = true; + } + else if(is_json) + { + tmp_os << c; + if(was_backslash) + was_backslash = false; + else if(c == '\\') + was_backslash = true; + else if(c == '"') + break; // Found end of string + } + else + { + if(c == ' ') + { + // Found end of word + is.unget(); + break; + } + else + { + tmp_os << c; + } + } + expect_initial_quote = false; + } + if(is_json) + { + std::istringstream tmp_is(tmp_os.str(), std::ios::binary); + return deSerializeJsonString(tmp_is); + } + else + return tmp_os.str(); +} + + +ItemStack::ItemStack(std::string name_, u16 count_, + u16 wear_, std::string metadata_, + IItemDefManager *itemdef) +{ + name = itemdef->getAlias(name_); + count = count_; + wear = wear_; + metadata = metadata_; + + if(name.empty() || count == 0) + clear(); + else if(itemdef->get(name).type == ITEM_TOOL) + count = 1; +} + +void ItemStack::serialize(std::ostream &os) const +{ + DSTACK(FUNCTION_NAME); + + if(empty()) + return; + + // Check how many parts of the itemstring are needed + int parts = 1; + if(count != 1) + parts = 2; + if(wear != 0) + parts = 3; + if(metadata != "") + parts = 4; + + os<= 2) + os<<" "<= 3) + os<<" "<= 4) + os<<" "<>material; - u16 count; - is>>count; - if(material > 255) + u16 materialcount; + is>>materialcount; + // Convert old materials + if(material <= 0xff) + material = content_translate_from_19_to_internal(material); + if(material > 0xfff) throw SerializationError("Too large material number"); - return new MaterialItem(material, count); + // Convert old id to name + NameIdMapping legacy_nimap; + content_mapnode_get_name_id_mapping(&legacy_nimap); + legacy_nimap.getName(material, name); + if(name == "") + name = "unknown_block"; + if (itemdef) + name = itemdef->getAlias(name); + count = materialcount; } - else if(name == "MBOItem") + else if(name == "MaterialItem2") + { + // Obsoleted on 2011-11-16 + + u16 material; + is>>material; + u16 materialcount; + is>>materialcount; + if(material > 0xfff) + throw SerializationError("Too large material number"); + // Convert old id to name + NameIdMapping legacy_nimap; + content_mapnode_get_name_id_mapping(&legacy_nimap); + legacy_nimap.getName(material, name); + if(name == "") + name = "unknown_block"; + if (itemdef) + name = itemdef->getAlias(name); + count = materialcount; + } + else if(name == "node" || name == "NodeItem" || name == "MaterialItem3" + || name == "craft" || name == "CraftItem") { - std::string inventorystring; - std::getline(is, inventorystring, '|'); - return new MapBlockObjectItem(inventorystring); + // Obsoleted on 2012-01-07 + + std::string all; + std::getline(is, all, '\n'); + // First attempt to read inside "" + Strfnd fnd(all); + fnd.next("\""); + // If didn't skip to end, we have ""s + if(!fnd.atend()){ + name = fnd.next("\""); + } else { // No luck, just read a word then + fnd.start(all); + name = fnd.next(" "); + } + fnd.skip_over(" "); + if (itemdef) + name = itemdef->getAlias(name); + count = stoi(trim(fnd.next(""))); + if(count == 0) + count = 1; } - else if(name == "CraftItem") + else if(name == "MBOItem") { - std::string subname; - std::getline(is, subname, ' '); - u16 count; - is>>count; - return new CraftItem(subname, count); + // Obsoleted on 2011-10-14 + throw SerializationError("MBOItem not supported anymore"); } - else if(name == "ToolItem") + else if(name == "tool" || name == "ToolItem") { - std::string toolname; - std::getline(is, toolname, ' '); - u16 wear; - is>>wear; - return new ToolItem(toolname, wear); + // Obsoleted on 2012-01-07 + + std::string all; + std::getline(is, all, '\n'); + // First attempt to read inside "" + Strfnd fnd(all); + fnd.next("\""); + // If didn't skip to end, we have ""s + if(!fnd.atend()){ + name = fnd.next("\""); + } else { // No luck, just read a word then + fnd.start(all); + name = fnd.next(" "); + } + count = 1; + // Then read wear + fnd.skip_over(" "); + if (itemdef) + name = itemdef->getAlias(name); + wear = stoi(trim(fnd.next(""))); } else { - dstream<<"Unknown InventoryItem name=\""<getAlias(name); + + // Read the count + std::string count_str; + std::getline(is, count_str, ' '); + if(count_str.empty()) + { + count = 1; + break; + } + else + count = stoi(count_str); + + // Read the wear + std::string wear_str; + std::getline(is, wear_str, ' '); + if(wear_str.empty()) + break; + else + wear = stoi(wear_str); + + // Read metadata + metadata = deSerializeJsonStringIfNeeded(is); + + // In case fields are added after metadata, skip space here: + //std::getline(is, tmp, ' '); + //if(!tmp.empty()) + // throw SerializationError("Unexpected text after metadata"); + + } while(false); } -} -ServerActiveObject* InventoryItem::createSAO(ServerEnvironment *env, u16 id, v3f pos) -{ - /* - Create an ItemSAO - */ - // Get item string - std::ostringstream os(std::ios_base::binary); - serialize(os); - // Create object - ServerActiveObject *obj = new ItemSAO(env, 0, pos, os.str()); - return obj; + if (name.empty() || count == 0) + clear(); + else if (itemdef && itemdef->get(name).type == ITEM_TOOL) + count = 1; } -/* - MaterialItem -*/ - -bool MaterialItem::isCookable() +void ItemStack::deSerialize(const std::string &str, IItemDefManager *itemdef) { - return item_material_is_cookable(m_content); + std::istringstream is(str, std::ios::binary); + deSerialize(is, itemdef); } -InventoryItem *MaterialItem::createCookResult() +std::string ItemStack::getItemString() const { - return item_material_create_cook_result(m_content); -} - -/* - CraftItem -*/ - -#ifndef SERVER -video::ITexture * CraftItem::getImage() -{ - if(g_texturesource == NULL) - return NULL; - - std::string name = item_craft_get_image_name(m_subname); - - // Get such a texture - return g_texturesource->getTextureRaw(name); + std::ostringstream os(std::ios::binary); + serialize(os); + return os.str(); } -#endif -ServerActiveObject* CraftItem::createSAO(ServerEnvironment *env, u16 id, v3f pos) -{ - // Special cases - ServerActiveObject *obj = item_craft_create_object(m_subname, env, id, pos); - if(obj) - return obj; - // Default - return InventoryItem::createSAO(env, id, pos); -} -u16 CraftItem::getDropCount() +ItemStack ItemStack::addItem(const ItemStack &newitem_, + IItemDefManager *itemdef) { - // Special cases - s16 dc = item_craft_get_drop_count(m_subname); - if(dc != -1) - return dc; - // Default - return InventoryItem::getDropCount(); -} + ItemStack newitem = newitem_; -bool CraftItem::isCookable() -{ - return item_craft_is_cookable(m_subname); -} + // If the item is empty or the position invalid, bail out + if(newitem.empty()) + { + // nothing can be added trivially + } + // If this is an empty item, it's an easy job. + else if(empty()) + { + *this = newitem; + newitem.clear(); + } + // If item name differs, bail out + else if(name != newitem.name) + { + // cannot be added + } + // If the item fits fully, add counter and delete it + else if(newitem.count <= freeSpace(itemdef)) + { + add(newitem.count); + newitem.clear(); + } + // Else the item does not fit fully. Add all that fits and return + // the rest. + else + { + u16 freespace = freeSpace(itemdef); + add(freespace); + newitem.remove(freespace); + } -InventoryItem *CraftItem::createCookResult() -{ - return item_craft_create_cook_result(m_subname); + return newitem; } -/* - MapBlockObjectItem DEPRECATED - TODO: Remove -*/ -#ifndef SERVER -video::ITexture * MapBlockObjectItem::getImage() -{ - if(m_inventorystring.substr(0,3) == "Rat") - return g_texturesource->getTextureRaw("rat.png"); - - if(m_inventorystring.substr(0,4) == "Sign") - return g_texturesource->getTextureRaw("sign.png"); - - return NULL; -} -#endif -std::string MapBlockObjectItem::getText() +bool ItemStack::itemFits(const ItemStack &newitem_, + ItemStack *restitem, + IItemDefManager *itemdef) const { - if(m_inventorystring.substr(0,3) == "Rat") - return ""; - - if(m_inventorystring.substr(0,4) == "Sign") - return ""; + ItemStack newitem = newitem_; - return "obj"; -} - -MapBlockObject * MapBlockObjectItem::createObject - (v3f pos, f32 player_yaw, f32 player_pitch) -{ - std::istringstream is(m_inventorystring); - std::string name; - std::getline(is, name, ' '); - - if(name == "None") + // If the item is empty or the position invalid, bail out + if(newitem.empty()) { - return NULL; + // nothing can be added trivially } - else if(name == "Sign") + // If this is an empty item, it's an easy job. + else if(empty()) { - std::string text; - std::getline(is, text, '|'); - SignObject *obj = new SignObject(NULL, -1, pos); - obj->setText(text); - obj->setYaw(-player_yaw); - return obj; + newitem.clear(); } - else if(name == "Rat") + // If item name differs, bail out + else if(name != newitem.name) { - RatObject *obj = new RatObject(NULL, -1, pos); - return obj; + // cannot be added } - else if(name == "ItemObj") + // If the item fits fully, delete it + else if(newitem.count <= freeSpace(itemdef)) { - /* - Now we are an inventory item containing the serialization - string of an object that contains the serialization - string of an inventory item. Fuck this. - */ - //assert(0); - dstream<<__FUNCTION_NAME<<": WARNING: Ignoring ItemObj " - <<"because an item-object should never be inside " - <<"an object-item."<= count) + { + // Take all + clear(); + } + else + { + // Take part + remove(takecount); + result.count = takecount; + } + return result; +} + +ItemStack ItemStack::peekItem(u32 peekcount) const +{ + if(peekcount == 0 || count == 0) + return ItemStack(); + + ItemStack result = *this; + if(peekcount < count) + result.count = peekcount; + return result; } /* Inventory */ -InventoryList::InventoryList(std::string name, u32 size) +InventoryList::InventoryList(std::string name, u32 size, IItemDefManager *itemdef) { m_name = name; m_size = size; + m_width = 0; + m_itemdef = itemdef; clearItems(); //m_dirty = false; } InventoryList::~InventoryList() { - for(u32 i=0; iserialize(os); + os<<"Empty"; } else { - os<<"Empty"; + os<<"Item "; + item.serialize(os); } os<<"\n"; } @@ -305,6 +505,7 @@ void InventoryList::deSerialize(std::istream &is) clearItems(); u32 item_i = 0; + m_width = 0; for(;;) { @@ -326,92 +527,115 @@ void InventoryList::deSerialize(std::istream &is) { break; } + else if(name == "Width") + { + iss >> m_width; + if (iss.fail()) + throw SerializationError("incorrect width property"); + } else if(name == "Item") { if(item_i > getSize() - 1) throw SerializationError("too many items"); - InventoryItem *item = InventoryItem::deSerialize(iss); + ItemStack item; + item.deSerialize(iss, m_itemdef); m_items[item_i++] = item; } else if(name == "Empty") { if(item_i > getSize() - 1) throw SerializationError("too many items"); - m_items[item_i++] = NULL; - } - else - { - throw SerializationError("Unknown inventory identifier"); + m_items[item_i++].clear(); } } } InventoryList::InventoryList(const InventoryList &other) { - /* - Do this so that the items get cloned. Otherwise the pointers - in the array will just get copied. - */ *this = other; } InventoryList & InventoryList::operator = (const InventoryList &other) { - m_name = other.m_name; + m_items = other.m_items; m_size = other.m_size; - clearItems(); - for(u32 i=0; iclone(); - } - } + m_width = other.m_width; + m_name = other.m_name; + m_itemdef = other.m_itemdef; //setDirty(true); return *this; } -std::string InventoryList::getName() +bool InventoryList::operator == (const InventoryList &other) const +{ + if(m_size != other.m_size) + return false; + if(m_width != other.m_width) + return false; + if(m_name != other.m_name) + return false; + for(u32 i=0; i m_items.size() - 1) - return NULL; + assert(i < m_size); // Pre-condition return m_items[i]; } -InventoryItem * InventoryList::changeItem(u32 i, InventoryItem *newitem) +ItemStack& InventoryList::getItem(u32 i) { - assert(i < m_items.size()); + assert(i < m_size); // Pre-condition + return m_items[i]; +} - InventoryItem *olditem = m_items[i]; +ItemStack InventoryList::changeItem(u32 i, const ItemStack &newitem) +{ + if(i >= m_items.size()) + return newitem; + + ItemStack olditem = m_items[i]; m_items[i] = newitem; //setDirty(true); return olditem; @@ -419,29 +643,29 @@ InventoryItem * InventoryList::changeItem(u32 i, InventoryItem *newitem) void InventoryList::deleteItem(u32 i) { - assert(i < m_items.size()); - InventoryItem *item = changeItem(i, NULL); - if(item) - delete item; + assert(i < m_items.size()); // Pre-condition + m_items[i].clear(); } -InventoryItem * InventoryList::addItem(InventoryItem *newitem) +ItemStack InventoryList::addItem(const ItemStack &newitem_) { - if(newitem == NULL) - return NULL; - + ItemStack newitem = newitem_; + + if(newitem.empty()) + return newitem; + /* First try to find if it could be added to some existing items */ for(u32 i=0; iaddableTo(to_item) == false) - return newitem; - - // If the item fits fully in the slot, add counter and delete it - if(newitem->getCount() <= to_item->freeSpace()) - { - to_item->add(newitem->getCount()); - delete newitem; - return NULL; - } - // Else the item does not fit fully. Add all that fits and return - // the rest. - else - { - u16 freespace = to_item->freeSpace(); - to_item->add(freespace); - newitem->remove(freespace); + if(i >= m_items.size()) return newitem; - } + + ItemStack leftover = m_items[i].addItem(newitem, m_itemdef); + //if(leftover != newitem) + // setDirty(true); + return leftover; } -bool InventoryList::itemFits(u32 i, InventoryItem *newitem) +bool InventoryList::itemFits(const u32 i, const ItemStack &newitem, + ItemStack *restitem) const { - // If it is an empty position, it's an easy job. - InventoryItem *to_item = m_items[i]; - if(to_item == NULL) + if(i >= m_items.size()) { - return true; - } - - // If not addable, return the item - if(newitem->addableTo(to_item) == false) + if(restitem) + *restitem = newitem; return false; - - // If the item fits fully in the slot, add counter and delete it - if(newitem->getCount() <= to_item->freeSpace()) - { - return true; } - return false; + return m_items[i].itemFits(newitem, restitem, m_itemdef); } -InventoryItem * InventoryList::takeItem(u32 i, u32 count) +bool InventoryList::roomForItem(const ItemStack &item_) const { - if(count == 0) - return NULL; - - //setDirty(true); - - InventoryItem *item = m_items[i]; - // If it is an empty position, return NULL - if(item == NULL) - return NULL; - - if(count >= item->getCount()) + ItemStack item = item_; + ItemStack leftover; + for(u32 i=0; i::const_reverse_iterator + i = m_items.rbegin(); + i != m_items.rend(); ++i) { - InventoryItem *item2 = item->clone(); - item->remove(count); - item2->setCount(count); - return item2; + if(count == 0) + break; + if(i->name == item.name) + { + if(i->count >= count) + return true; + else + count -= i->count; + } } - return false; } -void InventoryList::decrementMaterials(u16 count) +ItemStack InventoryList::removeItem(const ItemStack &item) { - for(u32 i=0; i::reverse_iterator + i = m_items.rbegin(); + i != m_items.rend(); ++i) { - InventoryItem *item = takeItem(i, count); - if(item) - delete item; + if(i->name == item.name) + { + u32 still_to_remove = item.count - removed.count; + removed.addItem(i->takeItem(still_to_remove), m_itemdef); + if(removed.count == item.count) + break; + } } + return removed; } -void InventoryList::print(std::ostream &o) +ItemStack InventoryList::takeItem(u32 i, u32 takecount) { - o<<"InventoryList:"<= m_items.size()) + return ItemStack(); + + ItemStack taken = m_items[i].takeItem(takecount); + //if(!taken.empty()) + // setDirty(true); + return taken; +} + +ItemStack InventoryList::peekItem(u32 i, u32 peekcount) const +{ + if(i >= m_items.size()) + return ItemStack(); + + return m_items[i].peekItem(peekcount); +} + +void InventoryList::moveItemSomewhere(u32 i, InventoryList *dest, u32 count) +{ + // Take item from source list + ItemStack item1; + if (count == 0) + item1 = changeItem(i, ItemStack()); + else + item1 = takeItem(i, count); + + if (item1.empty()) + return; + + // Try to add the item to destination list + u32 dest_size = dest->getSize(); + // First try all the non-empty slots + for (u32 dest_i = 0; dest_i < dest_size; dest_i++) { + if (!m_items[dest_i].empty()) { + item1 = dest->addItem(dest_i, item1); + if (item1.empty()) return; + } + } + + // Then try all the empty ones + for (u32 dest_i = 0; dest_i < dest_size; dest_i++) { + if (m_items[dest_i].empty()) { + item1 = dest->addItem(dest_i, item1); + if (item1.empty()) return; + } + } + + // If we reach this, the item was not fully added + // Add the remaining part back to the source item + addItem(i, item1); +} + +u32 InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i, + u32 count, bool swap_if_needed, bool *did_swap) +{ + if(this == dest && i == dest_i) + return count; + + // Take item from source list + ItemStack item1; + if(count == 0) + item1 = changeItem(i, ItemStack()); + else + item1 = takeItem(i, count); + + if(item1.empty()) + return 0; + + // Try to add the item to destination list + u32 oldcount = item1.count; + item1 = dest->addItem(dest_i, item1); + + // If something is returned, the item was not fully added + if(!item1.empty()) { - InventoryItem *item = m_items[i]; - if(item != NULL) - { - o<serialize(o); - o<<"\n"; + // If olditem is returned, nothing was added. + bool nothing_added = (item1.count == oldcount); + + // If something else is returned, part of the item was left unadded. + // Add the other part back to the source item + addItem(i, item1); + + // If olditem is returned, nothing was added. + // Swap the items + if (nothing_added && swap_if_needed) { + // Tell that we swapped + if (did_swap != NULL) { + *did_swap = true; + } + // Take item from source list + item1 = changeItem(i, ItemStack()); + // Adding was not possible, swap the items. + ItemStack item2 = dest->changeItem(dest_i, item1); + // Put item from destination list to the source list + changeItem(i, item2); } } + return (oldcount - item1.count); } /* @@ -585,6 +876,7 @@ Inventory::~Inventory() void Inventory::clear() { + m_dirty = true; for(u32 i=0; igetSize(); j++) + { + list->deleteItem(j); + } + } +} + +Inventory::Inventory(IItemDefManager *itemdef) { + m_dirty = false; + m_itemdef = itemdef; } Inventory::Inventory(const Inventory &other) { *this = other; + m_dirty = false; } Inventory & Inventory::operator = (const Inventory &other) { - clear(); - for(u32 i=0; i>listsize; - InventoryList *list = new InventoryList(listname, listsize); + InventoryList *list = new InventoryList(listname, listsize, m_itemdef); list->deSerialize(is); m_lists.push_back(list); } else { - throw SerializationError("Unknown inventory identifier"); + throw SerializationError("invalid inventory specifier: " + name); } } } InventoryList * Inventory::addList(const std::string &name, u32 size) { + m_dirty = true; s32 i = getListIndex(name); if(i != -1) { if(m_lists[i]->getSize() != size) { delete m_lists[i]; - m_lists[i] = new InventoryList(name, size); + m_lists[i] = new InventoryList(name, size, m_itemdef); } return m_lists[i]; } else { - m_lists.push_back(new InventoryList(name, size)); - return m_lists.getLast(); + //don't create list with invalid name + if (name.find(" ") != std::string::npos) return NULL; + + InventoryList *list = new InventoryList(name, size, m_itemdef); + m_lists.push_back(list); + return list; } } @@ -693,257 +1025,44 @@ InventoryList * Inventory::getList(const std::string &name) return m_lists[i]; } -s32 Inventory::getListIndex(const std::string &name) +std::vector Inventory::getLists() { + std::vector lists; for(u32 i=0; igetName() == name) - return i; + InventoryList *list = m_lists[i]; + lists.push_back(list); } - return -1; + return lists; } -/* - InventoryAction -*/ - -InventoryAction * InventoryAction::deSerialize(std::istream &is) +bool Inventory::deleteList(const std::string &name) { - std::string type; - std::getline(is, type, ' '); - - InventoryAction *a = NULL; - - if(type == "Move") - { - a = new IMoveAction(is); - } - - return a; + s32 i = getListIndex(name); + if(i == -1) + return false; + m_dirty = true; + delete m_lists[i]; + m_lists.erase(m_lists.begin() + i); + return true; } -void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr) +const InventoryList * Inventory::getList(const std::string &name) const { -#if 1 - - /*dstream<<"from_inv="<getList(from_list); - InventoryList *list_to = inv_to->getList(to_list); - - /*dstream<<"list_from="<getItem(from_i)="<getItem(from_i) - <getItem(to_i)="<getItem(to_i) - <getItem(from_i) == NULL) - { - dstream<<__FUNCTION_NAME<<": Operation not allowed " - <<"(the source item doesn't exist)" - <changeItem(from_i, NULL); - else - item1 = list_from->takeItem(from_i, count); - - // Try to add the item to destination list - InventoryItem *olditem = item1; - item1 = list_to->addItem(to_i, item1); - - // If something is returned, the item was not fully added - if(item1 != NULL) - { - // If olditem is returned, nothing was added. - bool nothing_added = (item1 == olditem); - - // If something else is returned, part of the item was left unadded. - // Add the other part back to the source item - list_from->addItem(from_i, item1); - - // If olditem is returned, nothing was added. - // Swap the items - if(nothing_added) - { - // Take item from source list - item1 = list_from->changeItem(from_i, NULL); - // Adding was not possible, swap the items. - InventoryItem *item2 = list_to->changeItem(to_i, item1); - // Put item from destination list to the source list - list_from->changeItem(from_i, item2); - } - } - - mgr->inventoryModified(c, from_inv); - if(from_inv != to_inv) - mgr->inventoryModified(c, to_inv); -#endif + s32 i = getListIndex(name); + if(i == -1) + return NULL; + return m_lists[i]; } -/* - Craft checking system -*/ - -bool ItemSpec::checkItem(InventoryItem *item) +const s32 Inventory::getListIndex(const std::string &name) const { - if(type == ITEM_NONE) - { - // Has to be no item - if(item != NULL) - return false; - return true; - } - - // There should be an item - if(item == NULL) - return false; - - std::string itemname = item->getName(); - - if(type == ITEM_MATERIAL) - { - if(itemname != "MaterialItem") - return false; - MaterialItem *mitem = (MaterialItem*)item; - if(mitem->getMaterial() != num) - return false; - } - else if(type == ITEM_CRAFT) - { - if(itemname != "CraftItem") - return false; - CraftItem *mitem = (CraftItem*)item; - if(mitem->getSubName() != name) - return false; - } - else if(type == ITEM_TOOL) - { - // Not supported yet - assert(0); - } - else if(type == ITEM_MBO) - { - // Not supported yet - assert(0); - } - else + for(u32 i=0; igetName() == name) + return i; } - return true; + return -1; } -bool checkItemCombination(InventoryItem **items, ItemSpec *specs) -{ - u16 items_min_x = 100; - u16 items_max_x = 100; - u16 items_min_y = 100; - u16 items_max_y = 100; - for(u16 y=0; y<3; y++) - for(u16 x=0; x<3; x++) - { - if(items[y*3 + x] == NULL) - continue; - if(items_min_x == 100 || x < items_min_x) - items_min_x = x; - if(items_min_y == 100 || y < items_min_y) - items_min_y = y; - if(items_max_x == 100 || x > items_max_x) - items_max_x = x; - if(items_max_y == 100 || y > items_max_y) - items_max_y = y; - } - // No items at all, just return false - if(items_min_x == 100) - return false; - - u16 items_w = items_max_x - items_min_x + 1; - u16 items_h = items_max_y - items_min_y + 1; - - u16 specs_min_x = 100; - u16 specs_max_x = 100; - u16 specs_min_y = 100; - u16 specs_max_y = 100; - for(u16 y=0; y<3; y++) - for(u16 x=0; x<3; x++) - { - if(specs[y*3 + x].type == ITEM_NONE) - continue; - if(specs_min_x == 100 || x < specs_min_x) - specs_min_x = x; - if(specs_min_y == 100 || y < specs_min_y) - specs_min_y = y; - if(specs_max_x == 100 || x > specs_max_x) - specs_max_x = x; - if(specs_max_y == 100 || y > specs_max_y) - specs_max_y = y; - } - // No specs at all, just return false - if(specs_min_x == 100) - return false; - - u16 specs_w = specs_max_x - specs_min_x + 1; - u16 specs_h = specs_max_y - specs_min_y + 1; - - // Different sizes - if(items_w != specs_w || items_h != specs_h) - return false; - - for(u16 y=0; y