diff options
38 files changed, 392 insertions, 286 deletions
@@ -727,6 +727,21 @@ data/graphics/maps/new_15-1.tmx: Updated desert maps with new tiles by Len. +2007-11-16 Bjørn Lindeijer <bjorn@lindeijer.nl> + + * src/floor_item.cpp, src/localplayer.cpp, src/item.cpp, + src/inventory.h, src/gui/sell.cpp, src/gui/equipmentwindow.cpp, + src/gui/shop.cpp, src/gui/shoplistbox.cpp, src/gui/shop.h, + src/gui/itemshortcutcontainer.cpp, src/gui/buy.cpp, + src/gui/itemcontainer.cpp, src/inventory.cpp, src/item.h, + src/equipment.h, src/shopitem.cpp, src/CMakeLists.txt, + src/floor_item.h, src/net/inventoryhandler.cpp, src/equipment.cpp, + src/localplayer.h, src/Makefile.am, src/resources/iteminfo.h, + src/resources/itemdb.cpp, src/resources/iteminfo.cpp, src/shopitem.h: + Moved item icon from ItemInfo class to the Item class, so that it can + be loaded on demand. Results in faster startup time and reduced memory + usage. + 2007-11-16 Guillaume Melquiond <guillaume.melquiond@gmail.com> * src/resources/resourcemanager.h, src/resources/resource.h, @@ -1,3 +1,4 @@ +- Item icons are now loaded on demand and unloaded when no longer used - Fixed display of critical hits 0.0.24.1 (7 April 2008) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3d19fdc9..0c2ef4cd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -326,6 +326,8 @@ SET(SRCS player.h properties.h serverinfo.h + shopitem.cpp + shopitem.h simpleanimation.cpp simpleanimation.h sound.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 98c0e53e..3156a800 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -284,6 +284,8 @@ tmw_SOURCES = gui/widgets/resizegrip.cpp \ player_relations.h \ properties.h \ serverinfo.h \ + shopitem.cpp \ + shopitem.h \ simpleanimation.cpp \ simpleanimation.h \ sound.cpp \ diff --git a/src/equipment.cpp b/src/equipment.cpp index 6cd4d967..d1f9a6cf 100644 --- a/src/equipment.cpp +++ b/src/equipment.cpp @@ -26,18 +26,19 @@ #include <algorithm> #include "item.h" +#include "item.h" Equipment::Equipment(): mArrows(0) { - std::fill_n(mEquipment, EQUIPMENT_SIZE, (Item*)0); + std::fill_n(mEquipment, EQUIPMENT_SIZE, (Item*) 0); } void Equipment::removeEquipment(Item *item) { - Item **i = std::find(mEquipment, mEquipment+EQUIPMENT_SIZE, item); - if (i != mEquipment+EQUIPMENT_SIZE) { + Item **i = std::find(mEquipment, mEquipment + EQUIPMENT_SIZE, item); + if (i != mEquipment + EQUIPMENT_SIZE) { *i = 0; } } diff --git a/src/equipment.h b/src/equipment.h index db9cf27d..80a2ae49 100644 --- a/src/equipment.h +++ b/src/equipment.h @@ -39,8 +39,8 @@ class Equipment /** * Get equipment at the given slot. */ - Item* - getEquipment(int index) { return mEquipment[index]; } + Item* getEquipment(int index) const + { return mEquipment[index]; } /** * Set equipment at the given slot. @@ -71,7 +71,7 @@ class Equipment void setArrows(Item *arrows) { mArrows = arrows; } - protected: + private: Item *mEquipment[EQUIPMENT_SIZE]; Item *mArrows; }; diff --git a/src/floor_item.cpp b/src/floor_item.cpp index 5d83e1dd..9727093f 100644 --- a/src/floor_item.cpp +++ b/src/floor_item.cpp @@ -25,23 +25,18 @@ #include "map.h" -#include "resources/itemdb.h" -#include "resources/iteminfo.h" - - FloorItem::FloorItem(unsigned int id, unsigned int itemId, unsigned short x, unsigned short y, Map *map): mId(id), - mItemId(itemId), mX(x), mY(y), mMap(map) { - // Retrieve item image from item info - mImage = ItemDB::get(itemId).getImage(); + // Create a corresponding item instance + mItem = new Item(itemId); // Add ourselves to the map mSpriteIterator = mMap->addSprite(this); @@ -51,4 +46,6 @@ FloorItem::~FloorItem() { // Remove ourselves from the map mMap->removeSprite(mSpriteIterator); + + delete mItem; } diff --git a/src/floor_item.h b/src/floor_item.h index 36f81585..a87e3f79 100644 --- a/src/floor_item.h +++ b/src/floor_item.h @@ -25,6 +25,7 @@ #define _TMW_FLOORITEM_H_ #include "graphics.h" +#include "item.h" #include "map.h" #include "sprite.h" #include "resources/image.h" @@ -59,7 +60,7 @@ class FloorItem : public Sprite * Returns the item id. */ unsigned int - getItemId() const { return mItemId; } + getItemId() const { return mItem->getId(); } /** * Returns the x coordinate. @@ -89,16 +90,15 @@ class FloorItem : public Sprite void draw(Graphics *graphics, int offsetX, int offsetY) const { - graphics->drawImage(mImage, + graphics->drawImage(mItem->getImage(), mX * 32 + offsetX, mY * 32 + offsetY); } private: unsigned int mId; - unsigned int mItemId; unsigned short mX, mY; - Image *mImage; + Item *mItem; Sprites::iterator mSpriteIterator; Map *mMap; }; diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp index 17e5dba7..259fcfd9 100644 --- a/src/gui/buy.cpp +++ b/src/gui/buy.cpp @@ -33,8 +33,6 @@ #include "../npc.h" -#include "../resources/itemdb.h" - #include "../net/messageout.h" #include "../net/protocol.h" @@ -170,7 +168,7 @@ void BuyDialog::action(const gcn::ActionEvent &event) outMsg.writeInt16(CMSG_NPC_BUY_REQUEST); outMsg.writeInt16(8); outMsg.writeInt16(mAmountItems); - outMsg.writeInt16(mShopItems->at(selectedItem).id); + outMsg.writeInt16(mShopItems->at(selectedItem)->getId()); // Reset selection mAmountItems = 1; @@ -179,7 +177,8 @@ void BuyDialog::action(const gcn::ActionEvent &event) // Update money and adjust the max number of items that can be bought mMaxItems -= mAmountItems; - setMoney(mMoney - mAmountItems * mShopItems->at(selectedItem).price); + setMoney(mMoney - + mAmountItems * mShopItems->at(selectedItem)->getPrice()); } } @@ -246,20 +245,22 @@ BuyDialog::updateButtonsAndLabels() if (selectedItem > -1) { - const ItemInfo &info = ItemDB::get(mShopItems->at(selectedItem).id); + const ItemInfo &info = mShopItems->at(selectedItem)->getInfo(); mItemDescLabel->setCaption("Description: " + info.getDescription()); mItemEffectLabel->setCaption("Effect: " + info.getEffect()); + int itemPrice = mShopItems->at(selectedItem)->getPrice(); + // Calculate how many the player can afford - mMaxItems = mMoney / mShopItems->at(selectedItem).price; + mMaxItems = mMoney / itemPrice; if (mAmountItems > mMaxItems) { mAmountItems = mMaxItems; } // Calculate price of pending purchase - price = mAmountItems * mShopItems->at(selectedItem).price; + price = mAmountItems * itemPrice; } else { diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp index 4df18b19..93b9ea37 100644 --- a/src/gui/equipmentwindow.cpp +++ b/src/gui/equipmentwindow.cpp @@ -61,22 +61,20 @@ void EquipmentWindow::draw(gcn::Graphics *graphics) graphics->drawRectangle(gcn::Rectangle(10 + 36 * (i % 4), 36 * (i / 4) + 25, 32, 32)); - if (!(item = mEquipment->getEquipment(i))) { + if (!(item = mEquipment->getEquipment(i))) continue; - } - image = item->getInfo().getImage(); + image = item->getImage(); static_cast<Graphics*>(graphics)->drawImage( image, 36 * (i % 4) + 10, 36 * (i / 4) + 25); } graphics->drawRectangle(gcn::Rectangle(160, 25, 32, 32)); - if (!(item = mEquipment->getArrows())) { + if (!(item = mEquipment->getArrows())) return; - } - image = item->getInfo().getImage(); + image = item->getImage(); static_cast<Graphics*>(graphics)->drawImage(image, 160, 25); graphics->drawText(toString(item->getQuantity()), 170, 62, diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp index 4172a532..fcc602f9 100644 --- a/src/gui/inventorywindow.cpp +++ b/src/gui/inventorywindow.cpp @@ -57,7 +57,7 @@ InventoryWindow::InventoryWindow(): mUseButton = new Button("Use", "use", this); mDropButton = new Button("Drop", "drop", this); - mItems = new ItemContainer(player_node->mInventory); + mItems = new ItemContainer(player_node->getInventory()); mItems->addSelectionListener(this); mInvenScroll = new ScrollArea(mItems); @@ -100,11 +100,10 @@ void InventoryWindow::logic() void InventoryWindow::action(const gcn::ActionEvent &event) { - Item *item = mItems->getItem(); + Item *item = mItems->getSelectedItem(); - if (!item) { + if (!item) return; - } if (event.getId() == "use") { if (item->isEquipment()) { @@ -133,7 +132,7 @@ void InventoryWindow::action(const gcn::ActionEvent &event) void InventoryWindow::valueChanged(const gcn::SelectionEvent &event) { - Item *item = mItems->getItem(); + const Item *item = mItems->getSelectedItem(); // Update name, effect and description if (!item) @@ -161,7 +160,7 @@ void InventoryWindow::mouseClicked(gcn::MouseEvent &event) if (event.getButton() == gcn::MouseEvent::RIGHT) { - Item *item = mItems->getItem(); + Item *item = mItems->getSelectedItem(); if (!item) return; @@ -208,11 +207,11 @@ void InventoryWindow::widgetResized(const gcn::Event &event) void InventoryWindow::updateButtons() { - Item *item; + const Item *selectedItem = mItems->getSelectedItem(); - if ((item = mItems->getItem()) && item->isEquipment()) + if (selectedItem && selectedItem->isEquipment()) { - if (item->isEquipped()) { + if (selectedItem->isEquipped()) { mUseButton->setCaption("Unequip"); } else { @@ -220,14 +219,14 @@ void InventoryWindow::updateButtons() } } else { - mUseButton ->setCaption("Use"); + mUseButton->setCaption("Use"); } - mUseButton->setEnabled(!!item); - mDropButton->setEnabled(!!item); + mUseButton->setEnabled(selectedItem != 0); + mDropButton->setEnabled(selectedItem != 0); } -Item* InventoryWindow::getItem() +Item* InventoryWindow::getSelectedItem() const { - return mItems->getItem(); + return mItems->getSelectedItem(); } diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h index 3222009f..d45602d2 100644 --- a/src/gui/inventorywindow.h +++ b/src/gui/inventorywindow.h @@ -58,7 +58,10 @@ class InventoryWindow : public Window, gcn::ActionListener, */ void action(const gcn::ActionEvent &event); - Item* getItem(); + /** + * Returns the selected item. + */ + Item* getSelectedItem() const; /** * Updates labels to currently selected item. diff --git a/src/gui/itemcontainer.cpp b/src/gui/itemcontainer.cpp index eb8b91a7..cf5dcb92 100644 --- a/src/gui/itemcontainer.cpp +++ b/src/gui/itemcontainer.cpp @@ -101,9 +101,8 @@ ItemContainer::draw(gcn::Graphics *graphics) { Item *item = mInventory->getItem(i); - if (item->getQuantity() <= 0) { + if (!item || item->getQuantity() <= 0) continue; - } int itemX = ((i - 2) % columns) * gridWidth; int itemY = ((i - 2) / columns) * gridHeight; @@ -116,8 +115,8 @@ ItemContainer::draw(gcn::Graphics *graphics) } // Draw item icon - Image* image; - if ((image = item->getInfo().getImage()) != NULL) + Image* image = item->getImage(); + if (image) { static_cast<Graphics*>(graphics)->drawImage( image, itemX, itemY); @@ -151,7 +150,7 @@ void ItemContainer::recalculateHeight() } Item* -ItemContainer::getItem() +ItemContainer::getSelectedItem() const { return mSelectedItem; } @@ -206,7 +205,7 @@ ItemContainer::mousePressed(gcn::MouseEvent &event) } Item *item = mInventory->getItem(index); setSelectedItem(item); - if (!item->isEquipment()) + if (item && !item->isEquipment()) { itemShortcut->setItemSelected(item->getId()); } diff --git a/src/gui/itemcontainer.h b/src/gui/itemcontainer.h index 9320cdcf..db8c6f3d 100644 --- a/src/gui/itemcontainer.h +++ b/src/gui/itemcontainer.h @@ -80,7 +80,7 @@ class ItemContainer : public gcn::Widget, public gcn::MouseListener, /** * Returns the selected item. */ - Item* getItem(); + Item* getSelectedItem() const; /** * Sets selected item to NULL. diff --git a/src/gui/itemshortcutcontainer.cpp b/src/gui/itemshortcutcontainer.cpp index b15c8983..0ce4f6b7 100644 --- a/src/gui/itemshortcutcontainer.cpp +++ b/src/gui/itemshortcutcontainer.cpp @@ -25,6 +25,7 @@ #include "../localplayer.h" #include "../graphics.h" +#include "../inventory.h" #include "../item.h" #include "../itemshortcut.h" #include "../keyboardconfig.h" @@ -93,10 +94,11 @@ ItemShortcutContainer::draw(gcn::Graphics *graphics) if (itemShortcut->getItem(i) < 0) continue; - Item *item = player_node->searchForItem(itemShortcut->getItem(i)); + Item *item = + player_node->getInventory()->findItem(itemShortcut->getItem(i)); if (item) { // Draw item icon. - Image* image = item->getInfo().getImage(); + Image* image = item->getImage(); if (image) { g->drawImage(image, itemX, itemY); g->drawText( @@ -110,7 +112,7 @@ ItemShortcutContainer::draw(gcn::Graphics *graphics) if (mItemMoved) { // Draw the item image being dragged by the cursor. - Image* image = mItemMoved->getInfo().getImage(); + Image* image = mItemMoved->getImage(); if (image) { const int tPosX = mCursorPosX - (image->getWidth() / 2); @@ -151,9 +153,10 @@ ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event) if (index == -1) { return; } - if (itemShortcut->getItem(index) < 0) + const int itemId = itemShortcut->getItem(index); + if (itemId < 0) return; - Item *item = player_node->searchForItem(itemShortcut->getItem(index)); + Item *item = player_node->getInventory()->findItem(itemId); if (item) { mItemMoved = item; diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp index 0a590ec6..82d340fb 100644 --- a/src/gui/sell.cpp +++ b/src/gui/sell.cpp @@ -37,7 +37,6 @@ #include "../npc.h" #include "../resources/iteminfo.h" -#include "../resources/itemdb.h" #include "../net/messageout.h" #include "../net/protocol.h" @@ -117,22 +116,15 @@ void SellDialog::reset() updateButtonsAndLabels(); } -void SellDialog::addItem(Item *item, int price) +void SellDialog::addItem(const Item *item, int price) { if (!item) return; - ITEM_SHOP item_shop; + mShopItems->addItem( + item->getInvIndex(), item->getId(), + item->getQuantity(), price); - item_shop.name = item->getInfo().getName() - + " (" + toString(price) + " GP)"; - item_shop.price = price; - item_shop.index = item->getInvIndex(); - item_shop.id = item->getId(); - item_shop.quantity = item->getQuantity(); - item_shop.image = item->getInfo().getImage(); - - mShopItems->push_back(item_shop); mShopItemList->adjustSize(); } @@ -178,12 +170,13 @@ void SellDialog::action(const gcn::ActionEvent &event) MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_NPC_SELL_REQUEST); outMsg.writeInt16(8); - outMsg.writeInt16(mShopItems->at(selectedItem).index); + outMsg.writeInt16(mShopItems->at(selectedItem)->getInvIndex()); outMsg.writeInt16(mAmountItems); mMaxItems -= mAmountItems; - mShopItems->getShop()->at(selectedItem).quantity = mMaxItems; - mPlayerMoney += (mAmountItems * mShopItems->at(selectedItem).price); + mShopItems->getShop()->at(selectedItem)->setQuantity(mMaxItems); + mPlayerMoney += + mAmountItems * mShopItems->at(selectedItem)->getPrice(); mAmountItems = 1; if (!mMaxItems) @@ -277,15 +270,15 @@ SellDialog::updateButtonsAndLabels() if (selectedItem > -1) { - mMaxItems = mShopItems->at(selectedItem).quantity; + mMaxItems = mShopItems->at(selectedItem)->getQuantity(); if (mAmountItems > mMaxItems) { mAmountItems = mMaxItems; } - income = mAmountItems * mShopItems->at(selectedItem).price; + income = mAmountItems * mShopItems->at(selectedItem)->getPrice(); - const ItemInfo &info = ItemDB::get(mShopItems->at(selectedItem).id); + const ItemInfo &info = mShopItems->at(selectedItem)->getInfo(); mItemDescLabel->setCaption("Description: " + info.getDescription()); mItemEffectLabel->setCaption("Effect: " + info.getEffect()); } diff --git a/src/gui/sell.h b/src/gui/sell.h index c56337ef..0c1a2007 100644 --- a/src/gui/sell.h +++ b/src/gui/sell.h @@ -64,7 +64,7 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener /** * Adds an item to the inventory. */ - void addItem(Item *item, int price); + void addItem(const Item *item, int price); /** * Called when receiving actions from the widgets. diff --git a/src/gui/shop.cpp b/src/gui/shop.cpp index 3d972bc2..ff6e3d68 100644 --- a/src/gui/shop.cpp +++ b/src/gui/shop.cpp @@ -22,8 +22,8 @@ */ #include "shop.h" -#include "../utils/tostring.h" -#include "../resources/itemdb.h" + +#include "../utils/dtor.h" ShopItems::~ShopItems() { @@ -32,43 +32,38 @@ ShopItems::~ShopItems() int ShopItems::getNumberOfElements() { - return mItemsShop.size(); + return mShopItems.size(); } std::string ShopItems::getElementAt(int i) { - return mItemsShop.at(i).name; + return mShopItems.at(i)->getDisplayName(); } -void ShopItems::addItem(short id, int price) +void ShopItems::addItem(int inventoryIndex, short id, int amount, int price) { - ITEM_SHOP item_shop; - - item_shop.name = ItemDB::get(id).getName() - + " (" + toString(price) + " GP)"; - item_shop.price = price; - item_shop.id = id; - item_shop.image = ItemDB::get(id).getImage(); - - mItemsShop.push_back(item_shop); + ShopItem *item = new ShopItem(id, amount, price); + item->setInvIndex(inventoryIndex); + mShopItems.push_back(item); } -ITEM_SHOP ShopItems::at(int i) +void ShopItems::addItem(short id, int price) { - return mItemsShop.at(i); + mShopItems.push_back(new ShopItem(id, 0, price)); } -void ShopItems::push_back(ITEM_SHOP item_shop) +ShopItem* ShopItems::at(int i) const { - mItemsShop.push_back(item_shop); + return mShopItems.at(i); } void ShopItems::clear() { - mItemsShop.clear(); + std::for_each(mShopItems.begin(), mShopItems.end(), make_dtor(mShopItems)); + mShopItems.clear(); } -std::vector<ITEM_SHOP>* ShopItems::getShop() +std::vector<ShopItem*>* ShopItems::getShop() { - return &mItemsShop; + return &mShopItems; } diff --git a/src/gui/shop.h b/src/gui/shop.h index de452b5c..22e715c9 100644 --- a/src/gui/shop.h +++ b/src/gui/shop.h @@ -28,34 +28,28 @@ #include <vector> #include <guichan/listmodel.hpp> + #include "../resources/image.h" -struct ITEM_SHOP { - short id; - std::string name; - Image *image; - int price; - int index; - int quantity; -}; +#include "../shopitem.h" class ShopItems : public gcn::ListModel { public: /** - * Destructor + * Destructor. */ ~ShopItems(); /** - * Adds an item and its associated picture + * Adds an item to the list (used by sell dialog). */ - void addItem(short id, int price); + void addItem(int inventoryIndex, short id, int amount, int price); /** - * Convenience function for adding items + * Adds an item to the list (used by buy dialog). */ - void push_back(ITEM_SHOP item_shop); + void addItem(short id, int price); /** * Returns the number of items in the shop. @@ -70,7 +64,7 @@ class ShopItems : public gcn::ListModel /** * Returns the item number i in the shop. */ - ITEM_SHOP at(int i); + ShopItem* at(int i) const; /** * Clear the vector. @@ -78,13 +72,12 @@ class ShopItems : public gcn::ListModel void clear(); /** - * Direct access to the vector + * Direct access to the vector. */ - std::vector<ITEM_SHOP>* getShop(); + std::vector<ShopItem*>* getShop(); private: - std::vector<ITEM_SHOP> mItemsShop; - + std::vector<ShopItem*> mShopItems; }; #endif diff --git a/src/gui/shoplistbox.cpp b/src/gui/shoplistbox.cpp index f3f98062..7a8b52ed 100644 --- a/src/gui/shoplistbox.cpp +++ b/src/gui/shoplistbox.cpp @@ -77,7 +77,7 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics) backgroundColor = gcn::Color(110, 160, 255); } else if (mShopItems && - mPlayerMoney < mShopItems->at(i).price && mPriceCheck) + mPlayerMoney < mShopItems->at(i)->getPrice() && mPriceCheck) { backgroundColor = gcn::Color(0x919191); } @@ -87,7 +87,7 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics) if (mShopItems) { - Image *icon = mShopItems->at(i).image; + Image *icon = mShopItems->at(i)->getImage(); if (icon) { graphics->drawImage(icon, 1, y); diff --git a/src/gui/trade.cpp b/src/gui/trade.cpp index db33fb12..54544250 100644 --- a/src/gui/trade.cpp +++ b/src/gui/trade.cpp @@ -227,17 +227,17 @@ void TradeWindow::tradeItem(Item *item, int quantity) void TradeWindow::valueChanged(const gcn::SelectionEvent &event) { - Item *item; + const Item *item; /* If an item is selected in one container, make sure no item is selected * in the other container. */ if (event.getSource() == mMyItemContainer && - (item = mMyItemContainer->getItem())) + (item = mMyItemContainer->getSelectedItem())) { mPartnerItemContainer->selectNone(); } - else if ((item = mPartnerItemContainer->getItem())) + else if ((item = mPartnerItemContainer->getSelectedItem())) { mMyItemContainer->selectNone(); } @@ -262,19 +262,15 @@ void TradeWindow::valueChanged(const gcn::SelectionEvent &event) void TradeWindow::action(const gcn::ActionEvent &event) { - Item *item = inventoryWindow->getItem(); + Item *item = inventoryWindow->getSelectedItem(); if (event.getId() == "add") { if (!item) - { return; - } if (mMyInventory->getFreeSlot() < 1) - { return; - } if (mMyInventory->contains(item)) { chatWindow->chatLog("Failed adding item. You can not " diff --git a/src/inventory.cpp b/src/inventory.cpp index be002dfe..470b6c85 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -29,84 +29,104 @@ #include "item.h" #include "log.h" -struct SlotUsed : public std::unary_function<Item, bool> +struct SlotUsed : public std::unary_function<Item*, bool> { - bool operator()(const Item &item) const { - return (item.getId() != -1 && item.getQuantity() > 0); + bool operator()(const Item *item) const { + return item && item->getId() != -1 && item->getQuantity() > 0; } }; Inventory::Inventory() { - mItems = new Item[INVENTORY_SIZE]; - for (int i = 0; i < INVENTORY_SIZE; i++) { - mItems[i].setInvIndex(i); - } + mItems = new Item*[INVENTORY_SIZE]; + std::fill_n(mItems, INVENTORY_SIZE, (Item*) 0); } Inventory::~Inventory() { + for (int i = 0; i < INVENTORY_SIZE; i++) + delete mItems[i]; + delete [] mItems; } -Item* Inventory::getItem(int index) +Item* Inventory::getItem(int index) const { if (index < 0 || index >= INVENTORY_SIZE) - { return 0; - } - return &mItems[index]; + return mItems[index]; +} + +Item* Inventory::findItem(int itemId) const +{ + for (int i = 0; i < INVENTORY_SIZE; i++) + { + if (mItems[i] && mItems[i]->getId() == itemId) + return mItems[i]; + } + return NULL; } void Inventory::addItem(int id, int quantity, bool equipment) { - addItem(getFreeSlot(), id, quantity, equipment); + setItem(getFreeSlot(), id, quantity, equipment); } -void Inventory::addItem(int index, int id, int quantity, bool equipment) +void Inventory::setItem(int index, int id, int quantity, bool equipment) { if (index < 0 || index >= INVENTORY_SIZE) { logger->log("Warning: invalid inventory index: %d", index); return; } - mItems[index].setId(id); - + /* TODO: Check where to reenable this code. // Dont stack equipment other than arrows. if (equipment && !(id == 1199 || id == 529)) mItems[index].setQuantity(quantity); else mItems[index].increaseQuantity(quantity); - - mItems[index].setEquipment(equipment); + */ + + if (!mItems[index] && id > 0) { + Item *item = new Item(id, quantity, equipment); + item->setInvIndex(index); + mItems[index] = item; + } else if (id > 0) { + mItems[index]->setId(id); + mItems[index]->setQuantity(quantity); + mItems[index]->setEquipment(equipment); + } else if (mItems[index]) { + removeItemAt(index); + } } - void Inventory::clear() { for (int i = 0; i < INVENTORY_SIZE; i++) { - mItems[i].setId(-1); - mItems[i].setQuantity(0); - mItems[i].setEquipped(false); + removeItemAt(i); } } void Inventory::removeItem(int id) { for (int i = 0; i < INVENTORY_SIZE; i++) { - if (mItems[i].getId() == id) { - mItems[i].setId(-1); - mItems[i].setQuantity(0); - mItems[i].setEquipped(false); + if (mItems[i] && mItems[i]->getId() == id) { + removeItemAt(i); } } } -bool Inventory::contains(Item *item) +void Inventory::removeItemAt(int index) +{ + delete mItems[index]; + mItems[index] = 0; +} + +bool Inventory::contains(Item *item) const { for (int i = 0; i < INVENTORY_SIZE; i++) { - if (mItems[i].getId() == item->getId()) { + if (mItems[i] && mItems[i]->getId() == item->getId()) { return true; } } @@ -116,7 +136,7 @@ bool Inventory::contains(Item *item) int Inventory::getFreeSlot() { - Item *i = std::find_if(mItems + 2, mItems + INVENTORY_SIZE, + Item **i = std::find_if(mItems + 2, mItems + INVENTORY_SIZE, std::not1(SlotUsed())); return (i == mItems + INVENTORY_SIZE) ? -1 : (i - mItems); } diff --git a/src/inventory.h b/src/inventory.h index d5c3cf35..0d2bbc5a 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -44,7 +44,15 @@ class Inventory /** * Returns the item at the specified index. */ - Item* getItem(int index); + Item* getItem(int index) const; + + /** + * Searches for the specified item by it's id. + * + * @param itemId The id of the item to be searched. + * @return Item found on success, NULL on failure. + */ + Item* findItem(int itemId) const; /** * Adds a new item in a free slot. @@ -52,9 +60,9 @@ class Inventory void addItem(int id, int quantity, bool equipment); /** - * Adds a new item at a given position. + * Sets the item at the given position. */ - void addItem(int index, int id, int quantity, bool equipment); + void setItem(int index, int id, int quantity, bool equipment); /** * Remove a item from the inventory. @@ -62,9 +70,14 @@ class Inventory void removeItem(int id); /** + * Remove the item at the specified index from the inventory. + */ + void removeItemAt(int index); + + /** * Checks if the given item is in the inventory */ - bool contains(Item *item); + bool contains(Item *item) const; /** * Returns id of next free slot or -1 if all occupied. @@ -87,7 +100,7 @@ class Inventory int getLastUsedSlot(); protected: - Item *mItems; /**< The holder of items */ + Item **mItems; /**< The holder of items */ }; #endif diff --git a/src/item.cpp b/src/item.cpp index 3cea30e5..e84a06df 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -21,3 +21,38 @@ * $Id$ */ +#include "item.h" + +#include "resources/image.h" +#include "resources/resourcemanager.h" + +Item::Item(int id, int quantity, bool equipment, bool equipped): + mImage(0), + mQuantity(quantity), + mEquipment(equipment), + mEquipped(equipped) +{ + setId(id); +} + +Item::~Item() +{ + if (mImage) + mImage->decRef(); +} + +void Item::setId(int id) +{ + mId = id; + + // Load the associated image + if (mImage) + mImage->decRef(); + + ResourceManager *resman = ResourceManager::getInstance(); + std::string imagePath = "graphics/items/" + getInfo().getImageName(); + mImage = resman->getImage(imagePath); + + if (!mImage) + mImage = resman->getImage("graphics/gui/unknown-item.png"); +} @@ -26,6 +26,8 @@ #include "resources/itemdb.h" +class Image; + /** * Represents one or more instances of a certain item type. */ @@ -36,24 +38,18 @@ class Item * Constructor. */ Item(int id = -1, int quantity = 0, - bool equipment = false, bool equipped = false): - mId(id), - mQuantity(quantity), - mEquipment(equipment), - mEquipped(equipped) - { - } + bool equipment = false, bool equipped = false); /** * Destructor. */ - ~Item() {} + ~Item(); /** * Sets the item id, identifying the item type. */ void - setId(int id) { mId = id; } + setId(int id); /** * Returns the item id. @@ -62,6 +58,11 @@ class Item getId() const { return mId; } /** + * Returns the item image. + */ + Image* getImage() { return mImage; } + + /** * Sets the number of items. */ void @@ -123,6 +124,7 @@ class Item protected: int mId; /**< Item type id. */ + Image *mImage; /**< Item image. */ int mQuantity; /**< Number of items. */ bool mEquipment; /**< Item is equipment. */ bool mEquipped; /**< Item is equipped. */ diff --git a/src/itemshortcut.cpp b/src/itemshortcut.cpp index 1201b23b..a32e50e0 100644 --- a/src/itemshortcut.cpp +++ b/src/itemshortcut.cpp @@ -23,9 +23,10 @@ #include "itemshortcut.h" +#include "configuration.h" +#include "inventory.h" #include "item.h" #include "localplayer.h" -#include "configuration.h" #include "utils/tostring.h" @@ -78,9 +79,8 @@ void ItemShortcut::useItem(int index) { if (mItems[index]) { - Item *item = player_node->searchForItem(mItems[index]); - if (item && item->getQuantity()) { + Item *item = player_node->getInventory()->findItem(mItems[index]); + if (item && item->getQuantity()) player_node->useItem(item); - } } } diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 20f6b6a7..3929da8b 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -45,12 +45,12 @@ LocalPlayer::LocalPlayer(Uint32 id, Uint16 job, Map *map): Player(id, job, map), mXpForNextLevel(0), mAttackRange(0), - mInventory(new Inventory), mXp(0), mNetwork(0), mTarget(NULL), mPickUpTarget(NULL), mTrading(false), mGoingToTarget(false), mLastAction(-1), - mWalkingDir(0), mDestX(0), mDestY(0) + mWalkingDir(0), mDestX(0), mDestY(0), + mInventory(new Inventory) { } @@ -125,37 +125,6 @@ void LocalPlayer::nextStep() Player::nextStep(); } -void LocalPlayer::clearInventory() -{ - mInventory->clear(); -} - -void LocalPlayer::addInvItem(int id, int quantity, bool equipment) -{ - mInventory->addItem(id, quantity, equipment); -} - -void LocalPlayer::addInvItem(int index, int id, int quantity, bool equipment) -{ - mInventory->addItem(index, id, quantity, equipment); -} - -Item* LocalPlayer::getInvItem(int index) -{ - return mInventory->getItem(index); -} - -Item* LocalPlayer::searchForItem(int itemId) -{ - for (int i = 0; i < INVENTORY_SIZE; i++) - { - if (itemId == mInventory->getItem(i)->getId()) { - return mInventory->getItem(i); - } - } - return NULL; -} - void LocalPlayer::equipItem(Item *item) { MessageOut outMsg(mNetwork); @@ -173,7 +142,7 @@ void LocalPlayer::unequipItem(Item *item) outMsg.writeInt16(CMSG_PLAYER_UNEQUIP); outMsg.writeInt16(item->getInvIndex()); - // Tidy equipment directly to avoid weapon still shown bug, by instance + // Tidy equipment directly to avoid weapon still shown bug, for instance mEquipment->removeEquipment(item); } diff --git a/src/localplayer.h b/src/localplayer.h index bdf43fff..5ce94081 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -70,18 +70,10 @@ class LocalPlayer : public Player virtual void drawName(Graphics *graphics, Sint32 offsetX, Sint32 offsetY) {}; - void clearInventory(); - void addInvItem(int id, int quantity, bool equipment); - void addInvItem(int index, int id, int quantity, bool equipment); - Item* getInvItem(int index); - /** - * Searches for the specified item by it's identification. - * - * @param itemId The id of the item to be searched. - * @return Item found on success, NULL on failure. + * Returns the player's inventory. */ - Item* searchForItem(int itemId); + Inventory* getInventory() const { return mInventory; } /** * Equips an item. @@ -213,8 +205,6 @@ class LocalPlayer : public Player float mLastAttackTime; /**< Used to synchronize the charge dialog */ - Inventory *mInventory; - protected: void walk(unsigned char dir); @@ -230,6 +220,8 @@ class LocalPlayer : public Player int mWalkingDir; /**< The direction the player is walking in. */ int mDestX; /**< X coordinate of destination. */ int mDestY; /**< Y coordinate of destination. */ + + Inventory *mInventory; }; extern LocalPlayer *player_node; diff --git a/src/net/buysellhandler.cpp b/src/net/buysellhandler.cpp index d7f063a7..26261664 100644 --- a/src/net/buysellhandler.cpp +++ b/src/net/buysellhandler.cpp @@ -29,6 +29,7 @@ #include "protocol.h" #include "../beingmanager.h" +#include "../inventory.h" #include "../item.h" #include "../localplayer.h" #include "../npc.h" @@ -99,7 +100,7 @@ void BuySellHandler::handleMessage(MessageIn *msg) Sint32 value = msg->readInt32(); msg->readInt32(); // OCvalue - Item *item = player_node->getInvItem(index); + Item *item = player_node->getInventory()->getItem(index); if (item && !(item->isEquipped())) { sellDialog->addItem(item, value); } diff --git a/src/net/equipmenthandler.cpp b/src/net/equipmenthandler.cpp index 69f24d80..85790b42 100644 --- a/src/net/equipmenthandler.cpp +++ b/src/net/equipmenthandler.cpp @@ -28,6 +28,7 @@ #include "../beingmanager.h" #include "../equipment.h" +#include "../inventory.h" #include "../item.h" #include "../localplayer.h" #include "../log.h" @@ -54,6 +55,7 @@ void EquipmentHandler::handleMessage(MessageIn *msg) Sint8 type; int mask, position; Item *item; + Inventory *inventory = player_node->getInventory(); switch (msg->getId()) { @@ -73,7 +75,7 @@ void EquipmentHandler::handleMessage(MessageIn *msg) msg->readInt8(); // refine msg->skip(8); // card - player_node->addInvItem(index, itemId, 1, true); + inventory->setItem(index, itemId, 1, true); if (equipPoint) { @@ -84,7 +86,7 @@ void EquipmentHandler::handleMessage(MessageIn *msg) mask <<= 1; position++; } - item = player_node->getInvItem(index); + item = inventory->getItem(index); player_node->mEquipment->setEquipment(position, item); } } @@ -120,7 +122,7 @@ void EquipmentHandler::handleMessage(MessageIn *msg) item->setEquipped(false); } - item = player_node->getInvItem(index); + item = inventory->getItem(index); player_node->mEquipment->setEquipment(position, item); break; @@ -146,8 +148,7 @@ void EquipmentHandler::handleMessage(MessageIn *msg) position++; } - item = player_node->getInvItem(index); - + item = inventory->getItem(index); if (!item) break; @@ -181,18 +182,18 @@ void EquipmentHandler::handleMessage(MessageIn *msg) break; case SMSG_PLAYER_ARROW_EQUIP: - itemId = msg->readInt16(); + index = msg->readInt16(); - if (itemId <= 1) + if (index <= 1) break; - item = player_node->getInvItem(itemId); + item = inventory->getItem(index); if (!item) break; item->setEquipped(true); player_node->mEquipment->setArrows(item); - logger->log("Arrows equipped: %i", itemId); + logger->log("Arrows equipped: %i", index); break; } } diff --git a/src/net/inventoryhandler.cpp b/src/net/inventoryhandler.cpp index a2190c1e..48cf18ff 100644 --- a/src/net/inventoryhandler.cpp +++ b/src/net/inventoryhandler.cpp @@ -32,9 +32,13 @@ #include "../item.h" #include "../itemshortcut.h" #include "../localplayer.h" +#include "../log.h" +#include "../inventory.h" #include "../gui/chat.h" +#include "../utils/tostring.h" + InventoryHandler::InventoryHandler() { static const Uint16 _messages[] = { @@ -52,13 +56,14 @@ void InventoryHandler::handleMessage(MessageIn *msg) { Sint32 number; Sint16 index, amount, itemId, equipType; + Inventory *inventory = player_node->getInventory(); switch (msg->getId()) { case SMSG_PLAYER_INVENTORY: // Only called on map load / warp. First reset all items // to not load them twice on map change. - player_node->clearInventory(); + inventory->clear(); msg->readInt16(); // length number = (msg->getLength() - 4) / 18; @@ -72,12 +77,13 @@ void InventoryHandler::handleMessage(MessageIn *msg) msg->skip(2); // unknown msg->skip(8); // card (4 shorts) - player_node->addInvItem(index, itemId, amount, false); + inventory->setItem(index, itemId, amount, false); // Trick because arrows are not considered equipment if (itemId == 1199 || itemId == 529) { - player_node->getInvItem(index)->setEquipment(true); + if (Item *item = inventory->getItem(index)) + item->setEquipment(true); } } break; @@ -93,20 +99,32 @@ void InventoryHandler::handleMessage(MessageIn *msg) equipType = msg->readInt16(); msg->readInt8(); // type - if (msg->readInt8()> 0) { + if (msg->readInt8() > 0) { chatWindow->chatLog("Unable to pick up item", BY_SERVER); } else { const ItemInfo &itemInfo = ItemDB::get(itemId); - chatWindow->chatLog("You picked up a " + + const std::string amountStr = + (amount > 1) ? toString(amount) : "a"; + chatWindow->chatLog("You picked up " + amountStr + " " + itemInfo.getName(), BY_SERVER); - player_node->addInvItem(index, itemId, amount, equipType != 0); + + if (Item *item = inventory->getItem(index)) { + item->setId(itemId); + item->increaseQuantity(amount); + } else { + inventory->setItem(index, itemId, amount, equipType != 0); + } } break; case SMSG_PLAYER_INVENTORY_REMOVE: index = msg->readInt16(); amount = msg->readInt16(); - player_node->getInvItem(index)->increaseQuantity(-amount); + if (Item *item = inventory->getItem(index)) { + item->increaseQuantity(-amount); + if (item->getQuantity() == 0) + inventory->removeItemAt(index); + } break; case SMSG_PLAYER_INVENTORY_USE: @@ -116,7 +134,8 @@ void InventoryHandler::handleMessage(MessageIn *msg) amount = msg->readInt16(); msg->readInt8(); // type - player_node->getInvItem(index)->setQuantity(amount); + if (Item *item = inventory->getItem(index)) + item->setQuantity(amount); break; case SMSG_ITEM_USE_RESPONSE: @@ -126,7 +145,8 @@ void InventoryHandler::handleMessage(MessageIn *msg) if (msg->readInt8() == 0) { chatWindow->chatLog("Failed to use item", BY_SERVER); } else { - player_node->getInvItem(index)->setQuantity(amount); + if (Item *item = inventory->getItem(index)) + item->setQuantity(amount); } break; } diff --git a/src/net/tradehandler.cpp b/src/net/tradehandler.cpp index 9b3c590e..85ab65c1 100644 --- a/src/net/tradehandler.cpp +++ b/src/net/tradehandler.cpp @@ -26,6 +26,7 @@ #include "messagein.h" #include "protocol.h" +#include "../inventory.h" #include "../item.h" #include "../localplayer.h" #include "../player_relations.h" @@ -157,7 +158,8 @@ void TradeHandler::handleMessage(MessageIn *msg) case SMSG_TRADE_ITEM_ADD_RESPONSE: // Trade: New Item add response (was 0x00ea, now 01b1) { - Item *item = player_node->getInvItem(msg->readInt16()); + const int index = msg->readInt16(); + Item *item = player_node->getInventory()->getItem(index); Sint16 quantity = msg->readInt16(); switch (msg->readInt8()) diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp index e8ad393b..71bd898a 100644 --- a/src/resources/itemdb.cpp +++ b/src/resources/itemdb.cpp @@ -55,7 +55,7 @@ void ItemDB::load() mUnknown = new ItemInfo(); mUnknown->setName("Unknown item"); - mUnknown->setImage(""); + mUnknown->setImageName(""); mUnknown->setSprite("error.xml", 0); mUnknown->setSprite("error.xml", 1); @@ -97,7 +97,7 @@ void ItemDB::load() if (id) { ItemInfo *itemInfo = new ItemInfo(); - itemInfo->setImage(image); + itemInfo->setImageName(image); itemInfo->setName((name == "") ? "Unnamed" : name); itemInfo->setDescription(description); itemInfo->setEffect(effect); diff --git a/src/resources/iteminfo.cpp b/src/resources/iteminfo.cpp index 82c46e3c..f1ebd0a9 100644 --- a/src/resources/iteminfo.cpp +++ b/src/resources/iteminfo.cpp @@ -23,36 +23,8 @@ #include "iteminfo.h" -#include "resourcemanager.h" -#include "image.h" #include "itemdb.h" -ItemInfo::~ItemInfo() -{ - if (mImage) - { - mImage->decRef(); - } -} - -void -ItemInfo::setImage(const std::string &image) -{ - if (mImage) - { - mImage->decRef(); - } - - ResourceManager *resman = ResourceManager::getInstance(); - mImageName = "graphics/items/" + image; - mImage = ResourceManager::getInstance()->getImage(mImageName); - - if (!mImage) - { - mImage = resman->getImage("graphics/gui/unknown-item.png"); - } -} - const std::string& ItemInfo::getSprite(int gender) const { diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h index 2726a012..680c8d61 100644 --- a/src/resources/iteminfo.h +++ b/src/resources/iteminfo.h @@ -30,8 +30,6 @@ #include "spritedef.h" -class Image; - enum EquipmentSoundEvent { EQUIP_EVENT_STRIKE, @@ -49,7 +47,6 @@ class ItemInfo * Constructor. */ ItemInfo(): - mImage(NULL), mType(0), mWeight(0), mView(0), @@ -57,21 +54,17 @@ class ItemInfo { } - /** - * Destructor. - */ - ~ItemInfo(); - void setName(const std::string &name) { mName = name; } const std::string& getName() const { return mName; } - void setImage(const std::string &image); + void setImageName(const std::string &imageName) + { mImageName = imageName; } - Image* getImage() const - { return mImage; } + const std::string& getImageName() const + { return mImageName; } void setDescription(const std::string &description) { mDescription = description; } @@ -116,13 +109,6 @@ class ItemInfo protected: std::string mImageName; /**< The filename of the icon image. */ - - /* TODO (BL): I do not think the item info should keep a reference to - * the item icon. It would probably be better if this was kept in the - * Item class, so that the images can be lazily instantiated and also - * unloaded when no longer used. - */ - Image *mImage; /**< The loaded icon image. */ std::string mName; std::string mDescription; /**< Short description. */ std::string mEffect; /**< Description of effects. */ diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp index 9c109257..ef8671a8 100644 --- a/src/resources/resourcemanager.cpp +++ b/src/resources/resourcemanager.cpp @@ -98,11 +98,15 @@ ResourceManager::~ResourceManager() void ResourceManager::cleanUp(Resource *res) { - logger->log("ResourceManager::~ResourceManager() cleaning up %d " + if (res->mRefCount > 0) + { + logger->log("ResourceManager::~ResourceManager() cleaning up %d " "reference%s to %s", res->mRefCount, (res->mRefCount == 1) ? "" : "s", res->mIdPath.c_str()); + } + delete res; } diff --git a/src/shopitem.cpp b/src/shopitem.cpp new file mode 100644 index 00000000..ed5d30a9 --- /dev/null +++ b/src/shopitem.cpp @@ -0,0 +1,33 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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. + * + * The Mana World 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "shopitem.h" + +#include "utils/tostring.h" + +ShopItem::ShopItem(int id, int quantity, int price): + Item(id, quantity), + mPrice(price) +{ + mDisplayName = getInfo().getName() + " (" + toString(mPrice) + " GP)"; +} diff --git a/src/shopitem.h b/src/shopitem.h new file mode 100644 index 00000000..ffafbebe --- /dev/null +++ b/src/shopitem.h @@ -0,0 +1,58 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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. + * + * The Mana World 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _SHOPITEM_H_ +#define _SHOPITEM_H_ + +#include "item.h" + +/** + * Represents an item in a shop inventory. + */ +class ShopItem : public Item +{ + public: + /** + * Constructor. + */ + ShopItem(int id, int quantity, int price); + + /** + * Gets the price of the item. + */ + int getPrice() const + { return mPrice; } + + /** + * Gets the display name for in the shop list. + */ + const std::string& getDisplayName() const + { return mDisplayName; } + + protected: + int mPrice; + int mIndex; + std::string mDisplayName; +}; + +#endif |