diff options
Diffstat (limited to 'src/resources/inventory')
-rw-r--r-- | src/resources/inventory/inventory.cpp | 462 | ||||
-rw-r--r-- | src/resources/inventory/inventory.h | 203 |
2 files changed, 665 insertions, 0 deletions
diff --git a/src/resources/inventory/inventory.cpp b/src/resources/inventory/inventory.cpp new file mode 100644 index 000000000..ad44245a1 --- /dev/null +++ b/src/resources/inventory/inventory.cpp @@ -0,0 +1,462 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2016 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * 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 + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "resources/inventory/inventory.h" + +#include "logger.h" + +#include "being/playerinfo.h" + +#include "net/inventoryhandler.h" + +#include "resources/iteminfo.h" + +#include "resources/item/item.h" + +#include "listeners/inventorylistener.h" + +#include "utils/delete2.h" +#include "utils/gettext.h" +#include "utils/stringutils.h" + +#include <algorithm> + +#include "debug.h" + +namespace +{ + struct SlotUsed final + { + bool operator()(const Item *const item) const + { + return item && item->mId >= 0 && item->mQuantity > 0; + } + typedef Item *argument_type; + }; +} // namespace + +Inventory::Inventory(const InventoryTypeT type, const int size1) : + mInventoryListeners(), + mVirtualRemove(), + mType(type), + mSize(size1 == -1 ? static_cast<unsigned>( + inventoryHandler->getSize(type)) + : static_cast<unsigned>(size1)), + mItems(new Item*[mSize]), + mUsed(0) +{ + std::fill_n(mItems, mSize, static_cast<Item*>(nullptr)); +} + +Inventory::~Inventory() +{ + for (unsigned i = 0; i < mSize; i++) + delete mItems[i]; + + delete [] mItems; + mItems = nullptr; +} + +Item *Inventory::getItem(const int index) const +{ + if (index < 0 || index >= static_cast<int>(mSize) || !mItems[index] + || mItems[index]->mQuantity <= 0) + { + return nullptr; + } + + return mItems[index]; +} + +Item *Inventory::findItem(const int itemId, + const ItemColor color) const +{ + for (unsigned i = 0; i < mSize; i++) + { + Item *const item = mItems[i]; + if (item && item->mId == itemId) + { + if (color == ItemColor_zero || + item->mColor == color || + (color == ItemColor_one && + item->mColor <= ItemColor_one)) + { + return item; + } + } + } + + return nullptr; +} + +int Inventory::addItem(const int id, + const int type, + const int quantity, + const uint8_t refine, + const ItemColor color, + const Identified identified, + const Damaged damaged, + const Favorite favorite, + const Equipm equipment, + const Equipped equipped) +{ + const int slot = getFreeSlot(); + setItem(slot, id, type, quantity, refine, color, + identified, damaged, favorite, equipment, equipped); + return slot; +} + +void Inventory::setItem(const int index, + const int id, + const int type, + const int quantity, + const uint8_t refine, + const ItemColor color, + const Identified identified, + const Damaged damaged, + const Favorite favorite, + const Equipm equipment, + const Equipped equipped) +{ + if (index < 0 || index >= static_cast<int>(mSize)) + { + logger->log("Warning: invalid inventory index: %d", index); + return; + } + + Item *const item1 = mItems[index]; + if (!item1 && id > 0) + { + Item *const item = new Item(id, type, quantity, refine, color, + identified, damaged, favorite, equipment, equipped); + item->setInvIndex(index); + mItems[index] = item; + mUsed++; + distributeSlotsChangedEvent(); + } + else if (id > 0 && item1) + { + item1->setId(id, color); + item1->setQuantity(quantity); + item1->setRefine(refine); + item1->setEquipment(equipment); + item1->setIdentified(identified); + item1->setDamaged(damaged); + item1->setFavorite(favorite); + } + else if (item1) + { + removeItemAt(index); + } +} + +void Inventory::setCards(const int index, + const int *const cards, + const int size) const +{ + if (index < 0 || index >= static_cast<int>(mSize)) + { + logger->log("Warning: invalid inventory index: %d", index); + return; + } + + Item *const item1 = mItems[index]; + item1->setCards(cards, size); +} + +void Inventory::clear() +{ + for (unsigned i = 0; i < mSize; i++) + removeItemAt(i); +} + +void Inventory::removeItem(const int id) +{ + for (unsigned i = 0; i < mSize; i++) + { + const Item *const item = mItems[i]; + if (item && item->mId == id) + removeItemAt(i); + } +} + +void Inventory::removeItemAt(const int index) +{ + if (!mItems[index]) + return; + delete2(mItems[index]); + mUsed--; + if (mUsed < 0) // Already at 0, no need to distribute event + mUsed = 0; + else + distributeSlotsChangedEvent(); +} + +bool Inventory::contains(const Item *const item) const +{ + if (!item) + return false; + + const int id = item->mId; + for (unsigned i = 0; i < mSize; i++) + { + const Item *const item1 = mItems[i]; + if (item1 && item1->mId == id) + return true; + } + + return false; +} + +int Inventory::getFreeSlot() const +{ + Item **const i = std::find_if(mItems, mItems + mSize, + std::not1(SlotUsed())); + return (i == mItems + mSize) ? -1 + : static_cast<int>(i - mItems); +} + +int Inventory::getLastUsedSlot() const +{ + for (int i = mSize - 1; i >= 0; i--) + { + if (SlotUsed()(mItems[i])) + return i; + } + + return -1; +} + +void Inventory::addInventoyListener(InventoryListener* const listener) +{ + mInventoryListeners.push_back(listener); +} + +void Inventory::removeInventoyListener(InventoryListener* const listener) +{ + mInventoryListeners.remove(listener); +} + +void Inventory::distributeSlotsChangedEvent() +{ + FOR_EACH (InventoryListenerList::const_iterator, i, mInventoryListeners) + (*i)->slotsChanged(this); +} + +const Item *Inventory::findItemBySprite(std::string spritePath, + const GenderT gender, + const BeingTypeId race) const +{ + spritePath = removeSpriteIndex(spritePath); + + const std::string spritePathShort = extractNameFromSprite(spritePath); + int partialIndex = -1; + + for (unsigned i = 0; i < mSize; i++) + { + const Item *const item = mItems[i]; + if (item) + { + std::string path = item->getInfo().getSprite(gender, race); + if (!path.empty()) + { + path = removeSpriteIndex(path); + if (spritePath == path) + return item; + + path = extractNameFromSprite(path); + if (spritePathShort == path) + partialIndex = i; + } + } + } + if (partialIndex != -1) + return mItems[partialIndex]; + + return nullptr; +} + +std::string Inventory::getName() const +{ + switch (mType) + { + case InventoryType::Inventory: +#ifdef EATHENA_SUPPORT + case InventoryType::Vending: +#endif + case InventoryType::TypeEnd: + default: + { + // TRANSLATORS: inventory type name + return N_("Inventory"); + } + case InventoryType::Storage: + { + // TRANSLATORS: inventory type name + return N_("Storage"); + } + case InventoryType::Npc: + { + // TRANSLATORS: inventory type name + return N_("Npc"); + } +#ifdef EATHENA_SUPPORT + case InventoryType::Cart: + { + // TRANSLATORS: inventory type name + return N_("Cart"); + } + case InventoryType::Mail: + { + // TRANSLATORS: inventory type name + return N_("Mail"); + } +#endif + case InventoryType::Trade: + { + // TRANSLATORS: inventory type name + return N_("Trade"); + } + } +} + +void Inventory::resize(const unsigned int newSize) +{ + clear(); + if (mSize == newSize) + return; + + for (unsigned i = 0; i < mSize; i++) + delete mItems[i]; + delete [] mItems; + + mSize = newSize; + mItems = new Item*[static_cast<size_t>(mSize)]; + std::fill_n(mItems, mSize, static_cast<Item*>(nullptr)); +} + +int Inventory::findIndexByTag(const int tag) const +{ + for (unsigned i = 0; i < mSize; i++) + { + const Item *const item = mItems[i]; + if (item && item->mTag == tag) + return i; + } + + return -1; +} + +bool Inventory::addVirtualItem(const Item *const item, + int index) +{ + if (item && !PlayerInfo::isItemProtected(item->getId())) + { + if (index >= 0 && index < static_cast<int>(mSize)) + { + if (mItems[index] != nullptr) + return false; + setItem(index, + item->getId(), + item->getType(), + 1, + 1, + item->getColor(), + item->getIdentified(), + item->getDamaged(), + item->getFavorite(), + Equipm_false, + Equipped_false); + } + else + { + index = addItem(item->getId(), + item->getType(), + 1, + 1, + item->getColor(), + item->getIdentified(), + item->getDamaged(), + item->getFavorite(), + Equipm_false, + Equipped_false); + } + if (index == -1) + return false; + + Item *const item2 = getItem(index); + if (item2) + item2->setTag(item->getInvIndex()); + return true; + } + return false; +} + +void Inventory::virtualRemove(Item *const item, + const int amount) +{ + if (!item || item->mQuantity < amount) + return; + + const int index = item->getInvIndex(); + const IntMapCIter it = mVirtualRemove.find(index); + if (it == mVirtualRemove.end()) + mVirtualRemove[index] = amount; + else + mVirtualRemove[index] += amount; + item->mQuantity -= amount; +} + +void Inventory::restoreVirtuals() +{ + const int sz = static_cast<int>(mSize); + + logger->log("Inventory::restoreVirtuals 1"); + FOR_EACH (IntMapCIter, it, mVirtualRemove) + { + logger->log("Inventory::restoreVirtuals 2"); + const int index = (*it).first; + if (index < 0 || index >= sz) + continue; + Item *const item = mItems[index]; + if (!item) + continue; + item->mQuantity += (*it).second; + } + mVirtualRemove.clear(); +} + +void Inventory::virtualRestore(const Item *const item, + const int amount) +{ + const int index = item->getTag(); + const IntMapCIter it = mVirtualRemove.find(index); + if (it != mVirtualRemove.end()) + { + mVirtualRemove[index] -= amount; + if (mVirtualRemove[index] < 0) + mVirtualRemove.erase(index); + if (index < 0 || index >= static_cast<int>(mSize) || !mItems[index]) + return; + mItems[index]->mQuantity += amount; + } +} diff --git a/src/resources/inventory/inventory.h b/src/resources/inventory/inventory.h new file mode 100644 index 000000000..501141ed8 --- /dev/null +++ b/src/resources/inventory/inventory.h @@ -0,0 +1,203 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2016 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * 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 + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef RESOURCES_INVENTORY_INVENTORY_H +#define RESOURCES_INVENTORY_INVENTORY_H + +#include "enums/inventorytype.h" + +#include "enums/simpletypes/beingtypeid.h" +#include "enums/simpletypes/damaged.h" +#include "enums/simpletypes/equipm.h" +#include "enums/simpletypes/equipped.h" +#include "enums/simpletypes/favorite.h" +#include "enums/simpletypes/identified.h" +#include "enums/simpletypes/itemcolor.h" + +#include "enums/being/gender.h" + +#include "utils/intmap.h" + +#include <list> +#include <string> + +#include "localconsts.h" + +class InventoryListener; +class Item; + +class Inventory final +{ + public: + A_DELETE_COPY(Inventory) + + static const int NO_SLOT_INDEX = -1; /**< Slot has no index. */ + + /** + * Constructor. + * + * @param size the number of items that fit in the inventory + */ + explicit Inventory(const InventoryTypeT type, + const int size = -1); + + /** + * Destructor. + */ + ~Inventory(); + + /** + * Returns the size that this instance is configured for. + */ + unsigned getSize() const A_WARN_UNUSED + { return mSize; } + + /** + * Returns the item at the specified index. + */ + Item *getItem(const int index) const A_WARN_UNUSED; + + /** + * Searches for the specified item by it's id. + * + * @param itemId The id of the item to be searched. + * @param color The color of the item to be searched. + * @return Item found on success, NULL on failure. + */ + Item *findItem(const int itemId, + const ItemColor color) const A_WARN_UNUSED; + + /** + * Adds a new item in a free slot. + */ + int addItem(const int id, + const int type, + const int quantity, + const uint8_t refine, + const ItemColor color, + const Identified identified, + const Damaged damaged, + const Favorite favorite, + const Equipm equipment, + const Equipped equipped); + + /** + * Sets the item at the given position. + */ + void setItem(const int index, + const int id, + const int type, + const int quantity, + const uint8_t refine, + const ItemColor color, + const Identified identified, + const Damaged damaged, + const Favorite favorite, + const Equipm equipment, + const Equipped equipped); + + void setCards(const int index, + const int *const cards, + const int size) const; + + /** + * Remove a item from the inventory. + */ + void removeItem(const int id); + + /** + * Remove the item at the specified index from the inventory. + */ + void removeItemAt(const int index); + + /** + * Checks if the given item is in the inventory. + */ + bool contains(const Item *const item) const A_WARN_UNUSED; + + /** + * Returns id of next free slot or -1 if all occupied. + */ + int getFreeSlot() const A_WARN_UNUSED; + + /** + * Reset all item slots. + */ + void clear(); + + /** + * Get the number of slots filled with an item + */ + int getNumberOfSlotsUsed() const A_WARN_UNUSED + { return mUsed; } + + /** + * Returns the index of the last occupied slot or 0 if none occupied. + */ + int getLastUsedSlot() const A_WARN_UNUSED; + + void addInventoyListener(InventoryListener *const listener); + + void removeInventoyListener(InventoryListener *const listener); + + InventoryTypeT getType() const A_WARN_UNUSED + { return mType; } + + bool isMainInventory() const A_WARN_UNUSED + { return mType == InventoryType::Inventory; } + + const Item *findItemBySprite(std::string spritePath, + const GenderT gender, + const BeingTypeId race) + const A_WARN_UNUSED; + + std::string getName() const A_WARN_UNUSED; + + void resize(const unsigned int newSize); + + int findIndexByTag(const int tag) const; + + bool addVirtualItem(const Item *const item, + int index); + + void virtualRemove(Item *const item, + const int amount); + + void virtualRestore(const Item *const item, + const int amount); + + void restoreVirtuals(); + + protected: + typedef std::list<InventoryListener*> InventoryListenerList; + InventoryListenerList mInventoryListeners; + + void distributeSlotsChangedEvent(); + + IntMap mVirtualRemove; + InventoryTypeT mType; + unsigned mSize; /**< The max number of inventory items */ + Item **mItems; /**< The holder of items */ + int mUsed; /**< THe number of slots in use */ +}; + +#endif // RESOURCES_INVENTORY_INVENTORY_H |