summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMajin Sniper <majinsniper@gmx.de>2009-02-23 19:19:55 +0100
committerJared Adams <jaxad0127@gmail.com>2009-02-23 17:19:56 -0700
commite15b8c360ac5171fe73b8b73fbe00eedba8970ff (patch)
treeec7d2129c8dc35c3cdf7669a08beb71c30a7760c
parentc54b987a4e4d28d35e8bafb03e1dba33b5fda4ab (diff)
downloadmana-e15b8c360ac5171fe73b8b73fbe00eedba8970ff.tar.gz
mana-e15b8c360ac5171fe73b8b73fbe00eedba8970ff.tar.bz2
mana-e15b8c360ac5171fe73b8b73fbe00eedba8970ff.tar.xz
mana-e15b8c360ac5171fe73b8b73fbe00eedba8970ff.zip
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.
-rw-r--r--src/gui/sell.cpp35
-rw-r--r--src/gui/shop.cpp51
-rw-r--r--src/gui/shop.h59
-rw-r--r--src/shopitem.cpp58
-rw-r--r--src/shopitem.h90
5 files changed, 260 insertions, 33 deletions
diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp
index 20a2a786..14620aa6 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);
@@ -252,7 +265,7 @@ void SellDialog::updateButtonsAndLabels()
mQuantityLabel->setCaption(strprintf("%d / %d", mAmountItems, mMaxItems));
mMoneyLabel->setCaption(strprintf(_("Price: %s / Total: %s"),
Units::formatCurrency(income).c_str(),
- Units::formatCurrency(mPlayerMoney - income).c_str()));
+ Units::formatCurrency(mPlayerMoney + income).c_str()));
}
void SellDialog::logic()
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<ShopItem*>* ShopItems::getShop()
+ShopItem* ShopItems::findItem(int id)
{
- return &mShopItems;
+ ShopItem *item;
+
+ std::vector<ShopItem*>::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 e0db4c59..faffe7e3 100644
--- a/src/gui/shop.h
+++ b/src/gui/shop.h
@@ -31,31 +31,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,17 +96,31 @@ 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<ShopItem*>* getShop();
+ ShopItem* findItem(int id);
- private:
+ /** the shop storage */
std::vector<ShopItem*> mShopItems;
+
+ /** Look for duplicate entries on addition */
+ bool mMergeDuplicates;
};
#endif
diff --git a/src/shopitem.cpp b/src/shopitem.cpp
index 6547aaf1..d6bb1d49 100644
--- a/src/shopitem.cpp
+++ b/src/shopitem.cpp
@@ -23,10 +23,62 @@
#include "units.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() +
" (" + Units::formatCurrency(mPrice).c_str() + ")";
+ setInvIndex(inventoryIndex);
+ addDuplicate(inventoryIndex, quantity);
+}
+
+ShopItem::ShopItem (int id, int price) : Item (id, 0), mPrice(price)
+{
+ mDisplayName = getInfo().getName() +
+ " (" + Units::formatCurrency(mPrice).c_str() + ")";
+ 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 3353ebe7..69bed334 100644
--- a/src/shopitem.h
+++ b/src/shopitem.h
@@ -22,27 +22,100 @@
#ifndef _SHOPITEM_H
#define _SHOPITEM_H
+#include <stack>
+
#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; }
@@ -51,6 +124,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<DuplicateItem*> mDuplicates; /** <-- Stores duplicates */
};
#endif