From e15b8c360ac5171fe73b8b73fbe00eedba8970ff Mon Sep 17 00:00:00 2001 From: Majin Sniper Date: Mon, 23 Feb 2009 19:19:55 +0100 Subject: Allow to sell non-stackable items like stackables Make it possible to sell non-stackable items all at once by introducing "Duplicate Items" and a Shop that can handle them. Also fix a trivial bug to correctly preview you money while selling. --- src/gui/shop.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 8 deletions(-) (limited to 'src/gui/shop.cpp') diff --git a/src/gui/shop.cpp b/src/gui/shop.cpp index a5f59bac..e13e218c 100644 --- a/src/gui/shop.cpp +++ b/src/gui/shop.cpp @@ -23,6 +23,11 @@ #include "../utils/dtor.h" +ShopItems::ShopItems(bool mergeDuplicates) : + mMergeDuplicates(mergeDuplicates) +{ +} + ShopItems::~ShopItems() { clear(); @@ -38,16 +43,29 @@ std::string ShopItems::getElementAt(int i) return mShopItems.at(i)->getDisplayName(); } -void ShopItems::addItem(int inventoryIndex, short id, int amount, int price) +void ShopItems::addItem(int inventoryIndex, int id, int quantity, + int price) { - ShopItem *item = new ShopItem(id, amount, price); - item->setInvIndex(inventoryIndex); - mShopItems.push_back(item); + ShopItem* item = 0; + if (mMergeDuplicates) + { + item = findItem(id); + } + + if (item) + { + item->addDuplicate (inventoryIndex, quantity); + } + else + { + item = new ShopItem(inventoryIndex, id, quantity, price); + mShopItems.push_back(item); + } } -void ShopItems::addItem(short id, int price) +void ShopItems::addItem(int id, int price) { - mShopItems.push_back(new ShopItem(id, 0, price)); + addItem(-1, id, 0, price); } ShopItem* ShopItems::at(int i) const @@ -55,13 +73,30 @@ ShopItem* ShopItems::at(int i) const return mShopItems.at(i); } +void ShopItems::erase(int i) +{ + mShopItems.erase(mShopItems.begin() + i); +} + void ShopItems::clear() { delete_all(mShopItems); mShopItems.clear(); } -std::vector* ShopItems::getShop() +ShopItem* ShopItems::findItem(int id) { - return &mShopItems; + ShopItem *item; + + std::vector::iterator it; + for(it = mShopItems.begin(); it != mShopItems.end(); it++) + { + item = *(it); + if (item->getId() == id) + { + return item; + } + } + + return 0; } -- cgit v1.2.3-70-g09d2 From f65c1e48107fa2cc615c86d8f6829b50c05baa3f Mon Sep 17 00:00:00 2001 From: Majin Sniper Date: Mon, 23 Feb 2009 19:19:55 +0100 Subject: Allow to sell non-stackable items like stackables Make it possible to sell non-stackable items all at once by introducing "Duplicate Items" and a Shop that can handle them. Also fix a trivial bug to correctly preview you money while selling. --- src/gui/sell.cpp | 33 ++++++++++++++------- src/gui/shop.cpp | 51 +++++++++++++++++++++++++++----- src/gui/shop.h | 59 ++++++++++++++++++++++++++++++++----- src/shopitem.cpp | 58 ++++++++++++++++++++++++++++++++++-- src/shopitem.h | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 259 insertions(+), 32 deletions(-) (limited to 'src/gui/shop.cpp') diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp index fd271c63..f974f247 100644 --- a/src/gui/sell.cpp +++ b/src/gui/sell.cpp @@ -50,7 +50,8 @@ SellDialog::SellDialog(Network *network): setMinHeight(230); setDefaultSize(0, 0, 260, 230); - mShopItems = new ShopItems(); + // Create a ShopItems instance, that is aware of duplicate entries. + mShopItems = new ShopItems(true); mShopItemList = new ShopListBox(mShopItems, mShopItems); mScrollArea = new ScrollArea(mShopItemList); @@ -115,10 +116,11 @@ void SellDialog::reset() void SellDialog::addItem(const Item *item, int price) { if (!item) + { return; + } - mShopItems->addItem( - item->getInvIndex(), item->getId(), + mShopItems->addItem(item->getInvIndex(), item->getId(), item->getQuantity(), price); mShopItemList->adjustSize(); @@ -164,23 +166,34 @@ void SellDialog::action(const gcn::ActionEvent &event) { // Attempt sell MessageOut outMsg(mNetwork); - outMsg.writeInt16(CMSG_NPC_SELL_REQUEST); - outMsg.writeInt16(8); - outMsg.writeInt16(mShopItems->at(selectedItem)->getInvIndex()); - outMsg.writeInt16(mAmountItems); + ShopItem* item = mShopItems->at(selectedItem); + int sellCount; + mPlayerMoney += + mAmountItems * mShopItems->at(selectedItem)->getPrice(); mMaxItems -= mAmountItems; - mShopItems->getShop()->at(selectedItem)->setQuantity(mMaxItems); + while (mAmountItems > 0) { + outMsg.writeInt16(CMSG_NPC_SELL_REQUEST); + outMsg.writeInt16(8); + outMsg.writeInt16(item->getCurrentInvIndex()); + // This order is important, item->getCurrentInvIndex() would return + // the inventory index of the next Duplicate otherwise. + sellCount = item->sellCurrentDuplicate(mAmountItems); + mAmountItems -= sellCount; + outMsg.writeInt16(sellCount); + } + mPlayerMoney += mAmountItems * mShopItems->at(selectedItem)->getPrice(); mAmountItems = 1; + mSlider->setValue(0); if (!mMaxItems) { // All were sold mShopItemList->setSelected(-1); - mShopItems->getShop()->erase( - mShopItems->getShop()->begin() + selectedItem); + delete mShopItems->at(selectedItem); + mShopItems->erase(selectedItem); gcn::Rectangle scroll; scroll.y = mShopItemList->getRowHeight() * (selectedItem + 1); diff --git a/src/gui/shop.cpp b/src/gui/shop.cpp index a56116d3..da68cf28 100644 --- a/src/gui/shop.cpp +++ b/src/gui/shop.cpp @@ -24,6 +24,11 @@ #include "../utils/dtor.h" +ShopItems::ShopItems(bool mergeDuplicates) : + mMergeDuplicates(mergeDuplicates) +{ +} + ShopItems::~ShopItems() { clear(); @@ -39,16 +44,29 @@ std::string ShopItems::getElementAt(int i) return mShopItems.at(i)->getDisplayName(); } -void ShopItems::addItem(int inventoryIndex, short id, int amount, int price) +void ShopItems::addItem(int inventoryIndex, int id, int quantity, + int price) { - ShopItem *item = new ShopItem(id, amount, price); - item->setInvIndex(inventoryIndex); - mShopItems.push_back(item); + ShopItem* item = 0; + if (mMergeDuplicates) + { + item = findItem(id); + } + + if (item) + { + item->addDuplicate (inventoryIndex, quantity); + } + else + { + item = new ShopItem(inventoryIndex, id, quantity, price); + mShopItems.push_back(item); + } } -void ShopItems::addItem(short id, int price) +void ShopItems::addItem(int id, int price) { - mShopItems.push_back(new ShopItem(id, 0, price)); + addItem(-1, id, 0, price); } ShopItem* ShopItems::at(int i) const @@ -56,13 +74,30 @@ ShopItem* ShopItems::at(int i) const return mShopItems.at(i); } +void ShopItems::erase(int i) +{ + mShopItems.erase(mShopItems.begin() + i); +} + void ShopItems::clear() { delete_all(mShopItems); mShopItems.clear(); } -std::vector* ShopItems::getShop() +ShopItem* ShopItems::findItem(int id) { - return &mShopItems; + ShopItem *item; + + std::vector::iterator it; + for(it = mShopItems.begin(); it != mShopItems.end(); it++) + { + item = *(it); + if (item->getId() == id) + { + return item; + } + } + + return 0; } diff --git a/src/gui/shop.h b/src/gui/shop.h index 166eb00b..26a9429d 100644 --- a/src/gui/shop.h +++ b/src/gui/shop.h @@ -32,31 +32,62 @@ class ShopItem; +/** + * This class handles the list of items available in a shop. + * + * The addItem routine can automatically check, if an item already exists and + * only adds duplicates to the old item, if one is found. The original + * distribution of the duplicates can be retrieved from the item. + * + * This functionality can be enabled in the constructor. + */ class ShopItems : public gcn::ListModel { public: + /** + * Constructor. Creates a new ShopItems instance. + * + * @param mergeDuplicates lets the Shop look for duplicate entries and + * merges them to one item. + */ + ShopItems(bool mergeDuplicates = false); + /** * Destructor. */ ~ShopItems(); /** - * Adds an item to the list (used by sell dialog). + * Adds an item to the list (used by sell dialog). Looks for + * duplicate entries, if mergeDuplicates was turned on. + * + * @param inventoryIndex the inventory index of the item + * @param id the id of the item + * @param quantity number of available copies of the item + * @param price price of the item */ - void addItem(int inventoryIndex, short id, int amount, int price); + void addItem(int inventoryIndex, int id, int amount, int price); /** - * Adds an item to the list (used by buy dialog). + * Adds an item to the list (used by buy dialog). Looks for + * duplicate entries, if mergeDuplicates was turned on. + * + * @param id the id of the item + * @param price price of the item */ - void addItem(short id, int price); + void addItem(int id, int price); /** * Returns the number of items in the shop. + * + * @return the number of items in the shop */ int getNumberOfElements(); /** * Returns the name of item number i in the shop. + * + * @param i the index to retrieve */ std::string getElementAt(int i); @@ -65,18 +96,32 @@ class ShopItems : public gcn::ListModel */ ShopItem* at(int i) const; + /** + * Removes an element from the shop. + * + * @param i index to remove + */ + void erase(int i); + /** * Clear the vector. */ void clear(); + private: /** - * Direct access to the vector. + * Searches the current items in the shop for the specified + * id and returns the item if found, or 0 else. + * + * @return the item found or 0 */ - std::vector* getShop(); + ShopItem* findItem(int id); - private: + /** the shop storage */ std::vector mShopItems; + + /** Look for duplicate entries on addition */ + bool mMergeDuplicates; }; #endif diff --git a/src/shopitem.cpp b/src/shopitem.cpp index c8015e45..5573eb37 100644 --- a/src/shopitem.cpp +++ b/src/shopitem.cpp @@ -24,10 +24,62 @@ #include "utils/stringutils.h" -ShopItem::ShopItem(int id, int quantity, int price): - Item(id, quantity), - mPrice(price) +ShopItem::ShopItem (int inventoryIndex, int id, + int quantity, int price) : + Item (id, 0), mPrice(price) { mDisplayName = getInfo().getName() + " (" + toString(mPrice) + " GP)"; + setInvIndex(inventoryIndex); + addDuplicate(inventoryIndex, quantity); +} + +ShopItem::ShopItem (int id, int price) : Item (id, 0), mPrice(price) +{ + mDisplayName = getInfo().getName() + " (" + toString(mPrice) + " GP)"; + setInvIndex(-1); + addDuplicate(-1, 0); +} + +ShopItem::~ShopItem() +{ + /** Clear all remaining duplicates on Object destruction. */ + while (!mDuplicates.empty()) + { + delete mDuplicates.top(); + mDuplicates.pop(); + } +} + +void ShopItem::addDuplicate(int inventoryIndex, + int quantity) +{ + DuplicateItem* di = new DuplicateItem; + di->inventoryIndex = inventoryIndex; + di->quantity = quantity; + mDuplicates.push(di); + mQuantity += quantity; +} + + +void ShopItem::addDuplicate() +{ + DuplicateItem* di = new DuplicateItem; + di->inventoryIndex = -1; + di->quantity = 0; + mDuplicates.push(di); +} + +int ShopItem::sellCurrentDuplicate(int quantity) +{ + DuplicateItem* dupl = mDuplicates.top(); + int sellCount = quantity <= dupl->quantity ? quantity : dupl->quantity; + dupl->quantity -= sellCount; + mQuantity -= sellCount; + if (dupl->quantity == 0) + { + delete dupl; + mDuplicates.pop(); + } + return sellCount; } diff --git a/src/shopitem.h b/src/shopitem.h index 8b1ba4b2..d6226732 100644 --- a/src/shopitem.h +++ b/src/shopitem.h @@ -23,27 +23,100 @@ #ifndef _SHOPITEM_H #define _SHOPITEM_H +#include + #include "item.h" /** - * Represents an item in a shop inventory. + * Represents an item in a shop inventory. It can store quantity and inventory + * indices of duplicate entries in the shop as well. */ class ShopItem : public Item { public: /** - * Constructor. + * Constructor. Creates a new ShopItem. + * + * @param inventoryIndex the inventory index of the item + * @param id the id of the item + * @param quantity number of available copies of the item + * @param price price of the item + */ + ShopItem(int inventoryIndex, int id, int quantity, int price); + + /** + * Constructor. Creates a new ShopItem. Inventory index will be set to + * -1 and quantity to 0. + * + * @param id the id of the item + * @param price price of the item + */ + ShopItem(int id, int price); + + /** + * Destructor. + */ + ~ShopItem(); + + /** + * Add a duplicate. Id and price will be taken from this item. + * + * @param inventoryIndex the inventory index of the item + * @param quantity number of available copies of the item + */ + void addDuplicate (int inventoryIndex, int quantity); + + /** + * Add a duplicate. Id and price will be taken from this item. + * Needed for compatibility with ShopDuplicateItems (see) class + * documentation). */ - ShopItem(int id, int quantity, int price); + void addDuplicate (); + + /** + * Gets the quantity of the currently topmost duplicate. + * + * @return the quantity of the currently topmost duplicate + */ + int getCurrentQuantity() { + return mDuplicates.empty() ? 0 : mDuplicates.top()->quantity; + } + + /** + * Gets the inventory index of the currently topmost duplicate. + * + * @return the inventory index of the currently topmost duplicate + */ + int getCurrentInvIndex() { + return mDuplicates.empty() ? mInvIndex : + mDuplicates.top()->inventoryIndex; + } + + /** + * Reduces the quantity of the topmost duplicate by the specified + * amount. Also reduces the total quantity of this DuplicateItem. + * Empty duplicates are automatically removed. + * + * If the amount is bigger than the quantity of the current topmost, + * only sell as much as possible. Returns the amount actually sold (do + * not ignore the return value!) + * + * @return the amount, that actually was sold. + */ + int sellCurrentDuplicate(int quantity); /** * Gets the price of the item. + * + * @return the price of the item */ int getPrice() const { return mPrice; } /** - * Gets the display name for in the shop list. + * Gets the display name for the item in the shop list. + * + * @return the display name for the item in the shop list */ const std::string& getDisplayName() const { return mDisplayName; } @@ -52,6 +125,15 @@ class ShopItem : public Item int mPrice; int mIndex; std::string mDisplayName; + + /** + * Struct to keep track of duplicates. + */ + typedef struct { + int inventoryIndex; + int quantity; + } DuplicateItem; + std::stack mDuplicates; /** <-- Stores duplicates */ }; #endif -- cgit v1.2.3-70-g09d2 From 0ffbbaa33f633bccf3b2a49713eb1cb117ff8a5a Mon Sep 17 00:00:00 2001 From: Ira Rice Date: Thu, 26 Feb 2009 08:24:01 -0700 Subject: Fixed an error in shoplistboxes as identified by Octalot. Signed-off-by: Ira Rice --- src/gui/buy.cpp | 2 +- src/gui/buy.h | 2 +- src/gui/listbox.cpp | 3 ++- src/gui/listbox.h | 10 +++++----- src/gui/sell.cpp | 2 +- src/gui/shop.cpp | 3 +-- src/gui/shoplistbox.cpp | 9 --------- src/gui/shoplistbox.h | 2 -- src/shopitem.cpp | 6 ++---- src/shopitem.h | 2 +- 10 files changed, 14 insertions(+), 27 deletions(-) (limited to 'src/gui/shop.cpp') diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp index a2485ca1..5a57dcc6 100644 --- a/src/gui/buy.cpp +++ b/src/gui/buy.cpp @@ -118,7 +118,7 @@ void BuyDialog::reset() setMoney(0); } -void BuyDialog::addItem(short id, int price) +void BuyDialog::addItem(int id, int price) { mShopItems->addItem(id, price); mShopItemList->adjustSize(); diff --git a/src/gui/buy.h b/src/gui/buy.h index b05608c0..9029fe9d 100644 --- a/src/gui/buy.h +++ b/src/gui/buy.h @@ -69,7 +69,7 @@ class BuyDialog : public Window, public gcn::ActionListener, /** * Adds an item to the shop inventory. */ - void addItem(short id, int price); + void addItem(int id, int price); /** * Called when receiving actions from the widgets. diff --git a/src/gui/listbox.cpp b/src/gui/listbox.cpp index 8ae68e09..45d14884 100644 --- a/src/gui/listbox.cpp +++ b/src/gui/listbox.cpp @@ -56,7 +56,7 @@ void ListBox::draw(gcn::Graphics *graphics) const int fontHeight = getFont()->getHeight(); - // Draw rectangle below the selected list element + // Draw filled rectangle around the selected list element if (mSelected >= 0) graphics->fillRectangle(gcn::Rectangle(0, fontHeight * mSelected, getWidth(), fontHeight)); @@ -97,6 +97,7 @@ void ListBox::setSelected(int selected) mSelected = selected; } } + gcn::ListBox::setSelected(mSelected); } // -- KeyListener notifications diff --git a/src/gui/listbox.h b/src/gui/listbox.h index a6392a94..09f00cdf 100644 --- a/src/gui/listbox.h +++ b/src/gui/listbox.h @@ -47,17 +47,17 @@ class ListBox : public gcn::ListBox */ void draw(gcn::Graphics *graphics); - void mouseDragged(gcn::MouseEvent &event); - // Inherited from KeyListener - virtual void keyPressed(gcn::KeyEvent& keyEvent); + void keyPressed(gcn::KeyEvent& keyEvent); // Inherited from MouseListener - virtual void mouseWheelMovedUp(gcn::MouseEvent& mouseEvent); + void mouseWheelMovedUp(gcn::MouseEvent& mouseEvent); - virtual void mouseWheelMovedDown(gcn::MouseEvent& mouseEvent); + void mouseWheelMovedDown(gcn::MouseEvent& mouseEvent); + + void mouseDragged(gcn::MouseEvent &event); /** * Sets the selected item. The selected item is represented by diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp index f974f247..154d1a57 100644 --- a/src/gui/sell.cpp +++ b/src/gui/sell.cpp @@ -121,7 +121,7 @@ void SellDialog::addItem(const Item *item, int price) } mShopItems->addItem(item->getInvIndex(), item->getId(), - item->getQuantity(), price); + item->getQuantity(), price); mShopItemList->adjustSize(); } diff --git a/src/gui/shop.cpp b/src/gui/shop.cpp index da68cf28..bd676bc0 100644 --- a/src/gui/shop.cpp +++ b/src/gui/shop.cpp @@ -44,8 +44,7 @@ std::string ShopItems::getElementAt(int i) return mShopItems.at(i)->getDisplayName(); } -void ShopItems::addItem(int inventoryIndex, int id, int quantity, - int price) +void ShopItems::addItem(int inventoryIndex, int id, int quantity, int price) { ShopItem* item = 0; if (mMergeDuplicates) diff --git a/src/gui/shoplistbox.cpp b/src/gui/shoplistbox.cpp index 6d3d9464..6e70e022 100644 --- a/src/gui/shoplistbox.cpp +++ b/src/gui/shoplistbox.cpp @@ -108,15 +108,6 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics) } } -void ShopListBox::mousePressed(gcn::MouseEvent &event) -{ - if (event.getButton() == gcn::MouseEvent::LEFT) - { - setSelected(event.getY() / mRowHeight); - distributeActionEvent(); - } -} - void ShopListBox::adjustSize() { if (mListModel) diff --git a/src/gui/shoplistbox.h b/src/gui/shoplistbox.h index 8542a7b8..bed9902b 100644 --- a/src/gui/shoplistbox.h +++ b/src/gui/shoplistbox.h @@ -57,8 +57,6 @@ class ShopListBox : public ListBox */ unsigned int getRowHeight() const { return mRowHeight; } - void mousePressed(gcn::MouseEvent &event); - /** * gives information about the current player's money */ diff --git a/src/shopitem.cpp b/src/shopitem.cpp index 5573eb37..00875a2d 100644 --- a/src/shopitem.cpp +++ b/src/shopitem.cpp @@ -24,8 +24,7 @@ #include "utils/stringutils.h" -ShopItem::ShopItem (int inventoryIndex, int id, - int quantity, int price) : +ShopItem::ShopItem (int inventoryIndex, int id, int quantity, int price) : Item (id, 0), mPrice(price) { mDisplayName = getInfo().getName() + " (" + toString(mPrice) + " GP)"; @@ -50,8 +49,7 @@ ShopItem::~ShopItem() } } -void ShopItem::addDuplicate(int inventoryIndex, - int quantity) +void ShopItem::addDuplicate(int inventoryIndex, int quantity) { DuplicateItem* di = new DuplicateItem; di->inventoryIndex = inventoryIndex; diff --git a/src/shopitem.h b/src/shopitem.h index d6226732..18608a94 100644 --- a/src/shopitem.h +++ b/src/shopitem.h @@ -89,7 +89,7 @@ class ShopItem : public Item */ int getCurrentInvIndex() { return mDuplicates.empty() ? mInvIndex : - mDuplicates.top()->inventoryIndex; + mDuplicates.top()->inventoryIndex; } /** -- cgit v1.2.3-70-g09d2