summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gui/button.cpp55
-rw-r--r--src/gui/inventorywindow.cpp135
-rw-r--r--src/gui/inventorywindow.h31
-rw-r--r--src/gui/item_amount.cpp29
-rw-r--r--src/gui/item_amount.h1
-rw-r--r--src/gui/itemcontainer.cpp338
-rw-r--r--src/gui/itemcontainer.h71
-rw-r--r--src/gui/popupmenu.cpp10
-rw-r--r--src/gui/trade.cpp5
-rw-r--r--src/inventory.cpp14
-rw-r--r--src/inventory.h8
-rw-r--r--src/localplayer.cpp32
-rw-r--r--src/localplayer.h11
-rw-r--r--src/net/gameserver/player.cpp17
-rw-r--r--src/net/gameserver/player.h2
-rw-r--r--src/net/protocol.h3
16 files changed, 564 insertions, 198 deletions
diff --git a/src/gui/button.cpp b/src/gui/button.cpp
index 83d4657c..eec2e4b2 100644
--- a/src/gui/button.cpp
+++ b/src/gui/button.cpp
@@ -34,9 +34,32 @@
#include "../utils/dtor.h"
-ImageRect Button::button[4];
int Button::mInstances = 0;
+enum{
+ BUTTON_STANDARD, // 0
+ BUTTON_HIGHLIGHTED, // 1
+ BUTTON_PRESSED, // 2
+ BUTTON_DISABLED, // 3
+ BUTTON_COUNT // 4 - Must be last.
+};
+
+struct ButtonData
+{
+ char *const file;
+ int gridX;
+ int gridY;
+};
+
+static ButtonData const data[BUTTON_COUNT] = {
+ {"graphics/gui/button.png", 0, 0},
+ {"graphics/gui/buttonhi.png", 9, 4},
+ {"graphics/gui/buttonpress.png", 16, 19},
+ {"graphics/gui/button_disabled.png", 25, 24}
+};
+
+ImageRect Button::button[BUTTON_COUNT];
+
Button::Button(const std::string& caption, const std::string &actionEventId,
gcn::ActionListener *listener):
gcn::Button(caption),
@@ -48,24 +71,20 @@ Button::Button(const std::string& caption, const std::string &actionEventId,
{
// Load the skin
ResourceManager *resman = ResourceManager::getInstance();
- Image *btn[4];
- btn[0] = resman->getImage("graphics/gui/button.png");
- btn[1] = resman->getImage("graphics/gui/buttonhi.png");
- btn[2] = resman->getImage("graphics/gui/buttonpress.png");
- btn[3] = resman->getImage("graphics/gui/button_disabled.png");
- int bgridx[4] = {0, 9, 16, 25};
- int bgridy[4] = {0, 4, 19, 24};
+ Image *btn[BUTTON_COUNT];
+
int a, x, y, mode;
- for (mode = 0; mode < 4; mode++)
+ for (mode = 0; mode < BUTTON_COUNT; mode++)
{
+ btn[mode] = resman->getImage(data[mode].file);
a = 0;
for (y = 0; y < 3; y++) {
for (x = 0; x < 3; x++) {
button[mode].grid[a] = btn[mode]->getSubImage(
- bgridx[x], bgridy[y],
- bgridx[x + 1] - bgridx[x] + 1,
- bgridy[y + 1] - bgridy[y] + 1);
+ data[x].gridX, data[y].gridY,
+ data[x + 1].gridX - data[x].gridX + 1,
+ data[y + 1].gridY - data[y].gridY + 1);
a++;
}
}
@@ -86,7 +105,7 @@ Button::~Button()
if (mInstances == 0)
{
- for (int mode = 0; mode < 4; mode++)
+ for (int mode = 0; mode < BUTTON_COUNT; mode++)
{
for_each(button[mode].grid, button[mode].grid + 9, dtor<Image*>());
}
@@ -99,16 +118,16 @@ Button::draw(gcn::Graphics *graphics)
int mode;
if (!isEnabled()) {
- mode = 3;
+ mode = BUTTON_DISABLED;
}
else if (isPressed() || mIsLogged) {
- mode = 2;
+ mode = BUTTON_PRESSED;
}
- else if (mHasMouse) {
- mode = 1;
+ else if (mHasMouse || isFocused()) {
+ mode = BUTTON_HIGHLIGHTED;
}
else {
- mode = 0;
+ mode = BUTTON_STANDARD;
}
static_cast<Graphics*>(graphics)->
diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp
index 7b199be4..32c18da6 100644
--- a/src/gui/inventorywindow.cpp
+++ b/src/gui/inventorywindow.cpp
@@ -28,6 +28,7 @@
#include <guichan/mouseinput.hpp>
#include <guichan/widgets/label.hpp>
+#include <guichan/widgets/checkbox.hpp>
#include "button.h"
#include "gui.h"
@@ -38,6 +39,7 @@
#include "../item.h"
#include "../localplayer.h"
+#include "../log.h"
#include "../resources/iteminfo.h"
@@ -51,40 +53,60 @@ InventoryWindow::InventoryWindow():
setMinWidth(240);
setMinHeight(172);
// If you adjust these defaults, don't forget to adjust the trade window's.
- setDefaultSize(115, 25, 322, 172);
+ setDefaultSize(115, 25, 368, 326);
+ addKeyListener(this);
mUseButton = new Button(_("Use"), "use", this);
mDropButton = new Button(_("Drop"), "drop", this);
- mItems = new ItemContainer(player_node->mInventory.get());
+ mSplitBox = new gcn::CheckBox(_("Split"));
+
+ mItems = new ItemContainer(player_node->mInventory.get(), 10, 5);
mItems->addSelectionListener(this);
mInvenScroll = new ScrollArea(mItems);
mInvenScroll->setPosition(8, 8);
- mInvenScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
mItemNameLabel = new gcn::Label(strprintf(_("Name: %s"), ""));
- mItemDescriptionLabel = new gcn::Label(strprintf(_("Description: %s"), ""));
+ mItemDescriptionLabel = new gcn::Label(
+ strprintf(_("Description: %s"), ""));
mItemEffectLabel = new gcn::Label(strprintf(_("Effect: %s"), ""));
- mWeightLabel = new gcn::Label(strprintf(_("Total Weight: %d - Maximum Weight: %d"), 0, 0));
+ mWeightLabel = new gcn::Label(
+ strprintf(_("Total Weight: %d - Maximum Weight: %d"), 0, 0));
mWeightLabel->setPosition(8, 8);
mInvenScroll->setPosition(8,
mWeightLabel->getY() + mWeightLabel->getHeight() + 5);
add(mUseButton);
add(mDropButton);
+ add(mSplitBox);
add(mInvenScroll);
add(mItemNameLabel);
add(mItemDescriptionLabel);
add(mItemEffectLabel);
add(mWeightLabel);
- mUseButton->setSize(48, mUseButton->getHeight());
+ mUseButton->setWidth(48);
+ mDropButton->setWidth(48);
loadWindowState("Inventory");
updateContentSize();
}
+InventoryWindow::~InventoryWindow()
+{
+ delete mUseButton;
+ delete mDropButton;
+ delete mSplitBox;
+ delete mItems;
+ delete mInvenScroll;
+
+ delete mItemNameLabel;
+ delete mItemDescriptionLabel;
+ delete mItemEffectLabel;
+ delete mWeightLabel;
+}
+
void InventoryWindow::logic()
{
Window::logic();
@@ -94,7 +116,8 @@ void InventoryWindow::logic()
updateButtons();
// Update weight information
- mWeightLabel->setCaption(strprintf(_("Total Weight: %d - Maximum Weight: %d"),
+ mWeightLabel->setCaption(
+ strprintf(_("Total Weight: %d - Maximum Weight: %d"),
player_node->getTotalWeight(), player_node->getMaxWeight()));
mWeightLabel->adjustSize();
}
@@ -102,23 +125,29 @@ void InventoryWindow::logic()
void InventoryWindow::action(const gcn::ActionEvent &event)
{
Item *item = mItems->getItem();
-
if (!item) {
return;
}
- if (event.getId() == "use") {
+ if (event.getId() == "use")
+ {
if (item->isEquipment()) {
player_node->equipItem(item);
}
else {
- player_node->useItem(item);
+ player_node->useItem(item->getInvIndex());
}
}
else if (event.getId() == "drop")
{
- // Choose amount of items to drop
- new ItemAmountWindow(AMOUNT_ITEM_DROP, this, item);
+ if (item->getQuantity() > 1) {
+ // Choose amount of items to drop
+ new ItemAmountWindow(AMOUNT_ITEM_DROP, this, item);
+ }
+ else {
+ player_node->dropItem(item, 1);
+ }
+ mItems->selectNone();
}
}
@@ -127,16 +156,24 @@ void InventoryWindow::selectionChanged(const SelectionEvent &event)
Item *item = mItems->getItem();
ItemInfo const *info = item ? &item->getInfo() : NULL;
- mItemNameLabel->setCaption
- (strprintf(_("Name: %s"), info ? info->getName().c_str() : ""));
- mItemEffectLabel->setCaption
- (strprintf(_("Effect: %s"), info ? info->getEffect().c_str() : ""));
- mItemDescriptionLabel->setCaption
- (strprintf(_("Description: %s"), info ? info->getDescription().c_str() : ""));
+ mItemNameLabel->setCaption(strprintf(_("Name: %s"),
+ info ? info->getName().c_str() : ""));
+ mItemEffectLabel->setCaption(strprintf(_("Effect: %s"),
+ info ? info->getEffect().c_str() : ""));
+ mItemDescriptionLabel->setCaption(strprintf(_("Description: %s"),
+ info ? info->getDescription().c_str() : ""));
mItemNameLabel->adjustSize();
mItemEffectLabel->adjustSize();
mItemDescriptionLabel->adjustSize();
+
+ if (mSplitBox->isMarked())
+ {
+ if (item && !item->isEquipment() && item->getQuantity() > 1) {
+ mSplitBox->setMarked(false);
+ new ItemAmountWindow(AMOUNT_ITEM_SPLIT, this, item);
+ }
+ }
}
void InventoryWindow::mouseClicked(gcn::MouseEvent &event)
@@ -147,54 +184,47 @@ void InventoryWindow::mouseClicked(gcn::MouseEvent &event)
{
Item *item = mItems->getItem();
- if (!item) return;
+ if (!item) {
+ return;
+ }
/* Convert relative to the window coordinates to absolute screen
* coordinates.
*/
- int mx = event.getX() + getX();
- int my = event.getY() + getY();
+ const int mx = event.getX() + getX();
+ const int my = event.getY() + getY();
viewport->showPopup(mx, my, item);
}
}
void InventoryWindow::updateContentSize()
{
- gcn::Rectangle area = getChildrenArea();
- int width = area.width;
- int height = area.height;
- int columns = width / 24;
-
- if (columns < 1)
- {
- columns = 1;
- }
+ const gcn::Rectangle area = getChildrenArea();
// Resize widgets
- mUseButton->setPosition(8, height - 24);
- mDropButton->setPosition(48 + 16, height - 24);
- mInvenScroll->setSize(width - 16, height - 110);
+ mUseButton->setPosition(8, area.height - 24);
+ mDropButton->setPosition(64, area.height - 24); // 8 + 48 + 8 = 64.
+ mSplitBox->setPosition(128, area.height - 20);
+ mInvenScroll->setSize(area.width - 16, area.height - 110);
mItemNameLabel->setPosition(8,
- mInvenScroll->getY() + mInvenScroll->getHeight() + 4);
+ mInvenScroll->getY() + mInvenScroll->getHeight() + 4);
mItemEffectLabel->setPosition(8,
- mItemNameLabel->getY() + mItemNameLabel->getHeight() + 4);
+ mItemNameLabel->getY() + mItemNameLabel->getHeight() + 4);
mItemDescriptionLabel->setPosition(8,
- mItemEffectLabel->getY() + mItemEffectLabel->getHeight() + 4);
+ mItemEffectLabel->getY() + mItemEffectLabel->getHeight() + 4);
}
void InventoryWindow::updateButtons()
{
- Item *item;
+ Item *item = mItems->getItem();
- if ((item = mItems->getItem()) && item->isEquipment())
- {
+ if (item && item->isEquipment()) {
mUseButton->setCaption(_("Equip"));
}
else {
- mUseButton ->setCaption(_("Use"));
+ mUseButton->setCaption(_("Use"));
}
-
mUseButton->setEnabled(!!item);
mDropButton->setEnabled(!!item);
}
@@ -204,3 +234,26 @@ Item* InventoryWindow::getItem()
return mItems->getItem();
}
+void
+InventoryWindow::keyPressed(gcn::KeyEvent &event)
+{
+ switch (event.getKey().getValue())
+ {
+ case gcn::Key::LEFT_SHIFT:
+ case gcn::Key::RIGHT_SHIFT:
+ mSplitBox->setMarked(true);
+ break;
+ }
+}
+
+void
+InventoryWindow::keyReleased(gcn::KeyEvent &event)
+{
+ switch (event.getKey().getValue())
+ {
+ case gcn::Key::LEFT_SHIFT:
+ case gcn::Key::RIGHT_SHIFT:
+ mSplitBox->setMarked(false);
+ break;
+ }
+}
diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h
index b153bb39..450d6565 100644
--- a/src/gui/inventorywindow.h
+++ b/src/gui/inventorywindow.h
@@ -25,6 +25,9 @@
#define _TMW_INVENTORYWINDOW_H
#include <guichan/actionlistener.hpp>
+#include <guichan/keylistener.hpp>
+
+#include <guichan/widgets/checkbox.hpp>
#include "window.h"
#include "selectionlistener.h"
@@ -39,7 +42,10 @@ class ItemContainer;
*
* \ingroup Interface
*/
-class InventoryWindow : public Window, gcn::ActionListener, SelectionListener
+class InventoryWindow : public Window,
+ public gcn::ActionListener,
+ public gcn::KeyListener,
+ public SelectionListener
{
public:
/**
@@ -48,6 +54,11 @@ class InventoryWindow : public Window, gcn::ActionListener, SelectionListener
InventoryWindow();
/**
+ * Destructor.
+ */
+ ~InventoryWindow();
+
+ /**
* Logic (updates buttons and weight information).
*/
void logic();
@@ -57,8 +68,21 @@ class InventoryWindow : public Window, gcn::ActionListener, SelectionListener
*/
void action(const gcn::ActionEvent &event);
+ /**
+ * Handles the mouse clicks.
+ */
void mouseClicked(gcn::MouseEvent &event);
+ /**
+ * Handles the key presses.
+ */
+ void keyPressed(gcn::KeyEvent &event);
+
+ /**
+ * Handles the key releases.
+ */
+ void keyReleased(gcn::KeyEvent &event);
+
Item* getItem();
/**
@@ -75,8 +99,9 @@ class InventoryWindow : public Window, gcn::ActionListener, SelectionListener
ItemContainer *mItems;
- gcn::Button *mUseButton, *mDropButton;
- gcn::ScrollArea *mInvenScroll;
+ gcn::Button *mUseButton, *mDropButton; /**< Use, Drop Item Buttons. */
+ gcn::CheckBox *mSplitBox; /**< Split item checkbox. */
+ gcn::ScrollArea *mInvenScroll; /**< Inventory Scroll Area. */
gcn::Label *mItemNameLabel;
gcn::Label *mItemDescriptionLabel;
gcn::Label *mItemEffectLabel;
diff --git a/src/gui/item_amount.cpp b/src/gui/item_amount.cpp
index 2e3ac4ad..22c219f2 100644
--- a/src/gui/item_amount.cpp
+++ b/src/gui/item_amount.cpp
@@ -83,6 +83,10 @@ ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item):
setCaption(_("Select amount of items to drop."));
okButton->setActionEventId("Drop");
break;
+ case AMOUNT_ITEM_SPLIT:
+ setCaption(_("Select amount of items to split."));
+ okButton->setActionEventId("Split");
+ break;
default:
break;
}
@@ -105,16 +109,6 @@ void ItemAmountWindow::action(const gcn::ActionEvent &event)
{
scheduleDelete();
}
- else if (event.getId() == "Drop")
- {
- player_node->dropItem(mItem, mItemAmountTextBox->getInt());
- scheduleDelete();
- }
- else if (event.getId() == "AddTrade")
- {
- tradeWindow->tradeItem(mItem, mItemAmountTextBox->getInt());
- scheduleDelete();
- }
else if (event.getId() == "Plus")
{
amount++;
@@ -127,6 +121,21 @@ void ItemAmountWindow::action(const gcn::ActionEvent &event)
{
amount = static_cast<int>(mItemAmountSlide->getValue());
}
+ else if (event.getId() == "Drop")
+ {
+ player_node->dropItem(mItem, mItemAmountTextBox->getInt());
+ scheduleDelete();
+ }
+ else if (event.getId() == "AddTrade")
+ {
+ tradeWindow->tradeItem(mItem, mItemAmountTextBox->getInt());
+ scheduleDelete();
+ }
+ else if (event.getId() == "Split")
+ {
+ player_node->splitItem(mItem, mItemAmountTextBox->getInt());
+ scheduleDelete();
+ }
mItemAmountTextBox->setInt(amount);
mItemAmountSlide->setValue(amount);
}
diff --git a/src/gui/item_amount.h b/src/gui/item_amount.h
index 01319012..227f6a87 100644
--- a/src/gui/item_amount.h
+++ b/src/gui/item_amount.h
@@ -37,6 +37,7 @@ class Item;
#define AMOUNT_TRADE_ADD 1
#define AMOUNT_ITEM_DROP 2
+#define AMOUNT_ITEM_SPLIT 3
/**
* Window used for selecting the amount of items to drop.
diff --git a/src/gui/itemcontainer.cpp b/src/gui/itemcontainer.cpp
index 444be2a2..2f65d157 100644
--- a/src/gui/itemcontainer.cpp
+++ b/src/gui/itemcontainer.cpp
@@ -30,7 +30,7 @@
#include "../graphics.h"
#include "../inventory.h"
#include "../item.h"
-#include "../log.h"
+#include "../localplayer.h"
#include "../resources/image.h"
#include "../resources/iteminfo.h"
@@ -38,18 +38,30 @@
#include "../utils/tostring.h"
-ItemContainer::ItemContainer(Inventory *inventory):
+static const int BOX_WIDTH = 36;
+static const int BOX_HEIGHT = 44;
+
+ItemContainer::ItemContainer(Inventory *inventory,
+ int gridColumns = 1, int gridRows = 1):
mInventory(inventory),
- mSelectedItem(NULL)
+ mGridColumns(gridColumns),
+ mGridRows(gridRows),
+ mSelectedItem(NULL),
+ mHighlightedItem(NULL),
+ mDragged(false),
+ mSwapItems(false)
{
+ setFocusable(true);
+
ResourceManager *resman = ResourceManager::getInstance();
mSelImg = resman->getImage("graphics/gui/selection.png");
- if (!mSelImg) logger->error("Unable to load selection.png");
-
- mMaxItems = mInventory->getLastUsedSlot() + 1;
+ addKeyListener(this);
addMouseListener(this);
+
+ setSize((BOX_WIDTH - 1) * mGridColumns + 1,
+ (BOX_HEIGHT - 1) * mGridRows + 1);
}
ItemContainer::~ItemContainer()
@@ -58,140 +70,284 @@ ItemContainer::~ItemContainer()
}
void
-ItemContainer::logic()
+ItemContainer::draw(gcn::Graphics *graphics)
{
- gcn::Widget::logic();
-
- int i = mInventory->getLastUsedSlot() + 1;
+ Graphics *g = static_cast<Graphics*>(graphics);
- if (i != mMaxItems)
+ for (int i = 0; i < mGridColumns; i++)
{
- mMaxItems = i;
- setWidth(getWidth());
+ for (int j = 0; j < mGridRows; j++)
+ {
+ // Items positions made to overlap on another.
+ int itemX = i * (BOX_WIDTH - 1);
+ int itemY = j * (BOX_HEIGHT - 1);
+
+ // Set color to black.
+ g->setColor(gcn::Color(0, 0, 0));
+ // Draw box border.
+ g->drawRectangle(
+ gcn::Rectangle(itemX, itemY, BOX_WIDTH, BOX_HEIGHT));
+
+ Item *item = mInventory->getItem((j * mGridColumns) + i);
+
+ if (!item)
+ return;
+ Image *image = item->getInfo().getImage();
+ if (image)
+ {
+ if (item == mSelectedItem)
+ {
+ if (mDragged) {
+ // Reposition the coords to that of the cursor.
+ itemX = mDragPosX - (BOX_WIDTH / 2);
+ itemY = mDragPosY - (BOX_HEIGHT / 2);
+ }
+ else {
+ // Draw selected image.
+ g->drawImage(mSelImg, itemX, itemY);
+ }
+ }
+ g->drawImage(image, itemX, itemY);
+ }
+ if (item->getQuantity() > 1) {
+ // Draw item caption
+ g->drawText(
+ toString(item->getQuantity()),
+ itemX + BOX_WIDTH / 2,
+ itemY + BOX_HEIGHT - 14,
+ gcn::Graphics::CENTER);
+ }
+
+ }
+ }
+
+ if (isFocused() && mHighlightedItem) {
+ // Items positions made to overlap on another.
+ const int i = mHighlightedItem->getInvIndex();
+ const int itemX = (i % mGridColumns) * (BOX_WIDTH - 1);
+ const int itemY = (i / mGridColumns) * (BOX_HEIGHT - 1);
+ // Set color to orange.
+ g->setColor(gcn::Color(255, 128, 0));
+ // Draw box border.
+ g->drawRectangle(gcn::Rectangle(itemX, itemY, BOX_WIDTH, BOX_HEIGHT));
}
}
void
-ItemContainer::draw(gcn::Graphics *graphics)
+ItemContainer::selectNone()
{
- int gridWidth = 36; //(item icon width + 4)
- int gridHeight = 42; //(item icon height + 10)
- int columns = getWidth() / gridWidth;
+ setSelectedItem(NULL);
+}
- // Have at least 1 column
- if (columns < 1)
- {
- columns = 1;
+void
+ItemContainer::setSelectedItem(Item *item)
+{
+ if (mSelectedItem != item) {
+ mSelectedItem = item;
+ fireSelectionChangedEvent();
}
+}
- // Reset selected item when quantity not above 0 (should probably be made
- // sure somewhere else)
- if (mSelectedItem && mSelectedItem->getQuantity() <= 0)
+void
+ItemContainer::fireSelectionChangedEvent()
+{
+ SelectionEvent event(this);
+ SelectionListeners::iterator i_end = mListeners.end();
+ SelectionListeners::iterator i;
+
+ for (i = mListeners.begin(); i != i_end; ++i) {
+ (*i)->selectionChanged(event);
+ }
+}
+
+void
+ItemContainer::keyPressed(gcn::KeyEvent &event)
+{
+ switch (event.getKey().getValue())
{
- selectNone();
+ case gcn::Key::LEFT:
+ moveHighlight(ItemContainer::MOVE_SELECTED_LEFT);
+ break;
+ case gcn::Key::RIGHT:
+ moveHighlight(ItemContainer::MOVE_SELECTED_RIGHT);
+ break;
+ case gcn::Key::UP:
+ moveHighlight(ItemContainer::MOVE_SELECTED_UP);
+ break;
+ case gcn::Key::DOWN:
+ moveHighlight(ItemContainer::MOVE_SELECTED_DOWN);
+ break;
+ case gcn::Key::SPACE:
+ keyAction();
+ break;
+ case gcn::Key::LEFT_ALT:
+ case gcn::Key::RIGHT_ALT:
+ mSwapItems = true;
}
+}
- for (int i = 0; i < INVENTORY_SIZE; i++)
+void
+ItemContainer::keyReleased(gcn::KeyEvent &event)
+{
+ switch (event.getKey().getValue())
{
- Item *item = mInventory->getItem(i);
+ case gcn::Key::LEFT_ALT:
+ case gcn::Key::RIGHT_ALT:
+ mSwapItems = false;
+ }
+}
- if (item->getQuantity() <= 0) {
- continue;
+void
+ItemContainer::mousePressed(gcn::MouseEvent &event)
+{
+
+ const int button = event.getButton();
+ if (button == gcn::MouseEvent::LEFT || button == gcn::MouseEvent::RIGHT)
+ {
+ const int index = getSlotIndex(event.getX(), event.getY());
+ if (index == Inventory::NO_SLOT_INDEX) {
+ return;
}
- int itemX = (i % columns) * gridWidth;
- int itemY = (i / columns) * gridHeight;
+ Item *item = mInventory->getItem(index);
- // Draw selection image below selected item
- if (mSelectedItem == item)
- {
- static_cast<Graphics*>(graphics)->drawImage(mSelImg, itemX, itemY);
+ if (mSelectedItem && mSelectedItem == item) {
+ setSelectedItem(NULL);
}
-
- // Draw item icon
- if (Image *image = item->getInfo().getImage())
- {
- static_cast<Graphics*>(graphics)->drawImage(image, itemX, itemY);
+ else if (item->getId()) {
+ setSelectedItem(item);
+ }
+ else {
+ setSelectedItem(NULL);
}
-
- // Draw item caption
- graphics->drawText(
- toString(item->getQuantity()),
- itemX + gridWidth / 2,
- itemY + gridHeight - 11,
- gcn::Graphics::CENTER);
}
}
void
-ItemContainer::setWidth(int width)
+ItemContainer::mouseDragged(gcn::MouseEvent &event)
{
- gcn::Widget::setWidth(width);
-
- int gridWidth = 36; //item icon width + 4
- int gridHeight = 46; //item icon height + 14
- int columns = getWidth() / gridWidth;
-
- if (columns < 1)
+ if (mSelectedItem)
{
- columns = 1;
+ if (!mDragged) {
+ mDragged = true;
+ }
+ mDragPosX = event.getX();
+ mDragPosY = event.getY();
}
-
- setHeight((mMaxItems + columns - 1) / columns * gridHeight);
-}
-
-Item*
-ItemContainer::getItem()
-{
- return mSelectedItem;
}
void
-ItemContainer::selectNone()
+ItemContainer::mouseReleased(gcn::MouseEvent &event)
{
- setSelectedItem(NULL);
+ if (mDragged)
+ {
+ mDragged = false;
+
+ const int index = getSlotIndex(event.getX(), event.getY());
+ if (index == Inventory::NO_SLOT_INDEX) {
+ return;
+ }
+
+ if (mSelectedItem) {
+ player_node->moveInvItem(mSelectedItem, index);
+ setSelectedItem(NULL);
+ }
+ }
}
-void
-ItemContainer::setSelectedItem(Item *item)
+int
+ItemContainer::getSlotIndex(const int posX, const int posY) const
{
- if (mSelectedItem != item)
+ if(gcn::Rectangle(0, 0, (getWidth() - 1), (getHeight() - 1))
+ .isPointInRect(posX, posY))
{
- mSelectedItem = item;
- fireSelectionChangedEvent();
+ // Takes into account, boxes are overlapping each other.
+ return (posY / (BOX_HEIGHT - 1)) * mGridColumns +
+ (posX / (BOX_WIDTH - 1));
}
+ return Inventory::NO_SLOT_INDEX;
}
void
-ItemContainer::fireSelectionChangedEvent()
+ItemContainer::keyAction()
{
- SelectionEvent event(this);
- SelectionListeners::iterator i_end = mListeners.end();
- SelectionListeners::iterator i;
+ // If there is no highlight then return.
+ if (!mHighlightedItem)
+ return;
- for (i = mListeners.begin(); i != i_end; ++i)
+ // If the highlight is on the selected item, then deselect it.
+ if (mHighlightedItem == mSelectedItem)
{
- (*i)->selectionChanged(event);
+ setSelectedItem(NULL);
+ }
+ // Check and swap items if necessary.
+ else if (mSwapItems &&
+ mSelectedItem &&
+ mHighlightedItem->getId())
+ {
+ player_node->moveInvItem(
+ mSelectedItem, mHighlightedItem->getInvIndex());
+ setSelectedItem(mHighlightedItem);
+ }
+ // If the highlight is on an item the select it.
+ else if (mHighlightedItem->getId())
+ {
+ setSelectedItem(mHighlightedItem);
+ }
+ // If the highlight is on a blank space then move it.
+ else if (mSelectedItem)
+ {
+ player_node->moveInvItem(
+ mSelectedItem, mHighlightedItem->getInvIndex());
+ setSelectedItem(NULL);
}
}
void
-ItemContainer::mousePressed(gcn::MouseEvent &event)
+ItemContainer::moveHighlight(int direction)
{
- int button = event.getButton();
-
- if (button == gcn::MouseEvent::LEFT || button == gcn::MouseEvent::RIGHT)
+ if (!mHighlightedItem)
{
- int gridWidth = 36; //(item icon width + 4)
- int gridHeight = 42; //(item icon height + 10)
- int columns = getWidth() / gridWidth;
- int mx = event.getX();
- int my = event.getY();
- int index = mx / gridWidth + ((my / gridHeight) * columns);
-
- if (index > INVENTORY_SIZE)
- index = INVENTORY_SIZE - 1;
+ if (mSelectedItem) {
+ mHighlightedItem = mSelectedItem;
+ }
+ else {
+ mHighlightedItem = mInventory->getItem(0);
+ }
+ return;
+ }
- setSelectedItem(mInventory->getItem(index));
+ switch (direction)
+ {
+ case MOVE_SELECTED_LEFT:
+ if (mHighlightedItem->getInvIndex() % mGridColumns == 0)
+ {
+ mHighlightedItem += mGridColumns;
+ }
+ mHighlightedItem--;
+ break;
+ case MOVE_SELECTED_RIGHT:
+ if ((mHighlightedItem->getInvIndex() % mGridColumns) ==
+ (mGridColumns - 1))
+ {
+ mHighlightedItem -= mGridColumns;
+ }
+ mHighlightedItem++;
+ break;
+ case MOVE_SELECTED_UP:
+ if (mHighlightedItem->getInvIndex() / mGridColumns == 0)
+ {
+ mHighlightedItem += (mGridColumns * mGridRows);
+ }
+ mHighlightedItem -= mGridColumns;
+ break;
+ case MOVE_SELECTED_DOWN:
+ if ((mHighlightedItem->getInvIndex() / mGridColumns) ==
+ (mGridRows - 1))
+ {
+ mHighlightedItem -= (mGridColumns * mGridRows);
+ }
+ mHighlightedItem += mGridColumns;
+ break;
}
}
diff --git a/src/gui/itemcontainer.h b/src/gui/itemcontainer.h
index 8c548fcd..38dc9f6e 100644
--- a/src/gui/itemcontainer.h
+++ b/src/gui/itemcontainer.h
@@ -24,7 +24,9 @@
#ifndef _TMW_ITEMCONTAINER_H__
#define _TMW_ITEMCONTAINER_H__
+#include <guichan/keylistener.hpp>
#include <guichan/mouselistener.hpp>
+
#include <guichan/widget.hpp>
#include <list>
@@ -39,13 +41,18 @@ class SelectionListener;
*
* \ingroup GUI
*/
-class ItemContainer : public gcn::Widget, public gcn::MouseListener
+class ItemContainer : public gcn::Widget,
+ public gcn::KeyListener,
+ public gcn::MouseListener
{
public:
/**
* Constructor. Initializes the graphic.
+ * @param inventory
+ * @param gridColumns Amount of columns in grid.
+ * @param gridRows Amount of rows in grid.
*/
- ItemContainer(Inventory *inventory);
+ ItemContainer(Inventory *inventory, int gridColumns, int gridRows);
/**
* Destructor.
@@ -53,20 +60,19 @@ class ItemContainer : public gcn::Widget, public gcn::MouseListener
virtual ~ItemContainer();
/**
- * Handles the logic of the ItemContainer
+ * Draws the items.
*/
- void logic();
+ void draw(gcn::Graphics *graphics);
/**
- * Draws the items.
+ * Handles the key presses.
*/
- void draw(gcn::Graphics *graphics);
+ void keyPressed(gcn::KeyEvent &event);
/**
- * Sets the width of the container. This is used to determine the new
- * height of the container.
+ * Handles the key releases.
*/
- void setWidth(int width);
+ void keyReleased(gcn::KeyEvent &event);
/**
* Handles mouse click.
@@ -74,9 +80,20 @@ class ItemContainer : public gcn::Widget, public gcn::MouseListener
void mousePressed(gcn::MouseEvent &event);
/**
+ * Handles mouse dragged.
+ */
+ void mouseDragged(gcn::MouseEvent &event);
+
+ /**
+ * Handles mouse released.
+ */
+ void mouseReleased(gcn::MouseEvent &event);
+
+ /**
* Returns the selected item.
*/
- Item* getItem();
+ Item* getItem() const
+ { return mSelectedItem; }
/**
* Sets selected item to NULL.
@@ -101,8 +118,26 @@ class ItemContainer : public gcn::Widget, public gcn::MouseListener
mListeners.remove(listener);
}
+ enum {
+ MOVE_SELECTED_LEFT, // 0
+ MOVE_SELECTED_RIGHT, // 1
+ MOVE_SELECTED_UP, // 2
+ MOVE_SELECTED_DOWN // 3
+ };
private:
/**
+ * Execute all the functionality associated with the action key.
+ */
+ void keyAction();
+
+ /**
+ * Moves the highlight in the direction specified.
+ *
+ * @param direction The move direction of the highlighter.
+ */
+ void moveHighlight(int direction);
+
+ /**
* Sets the currently selected item.
*/
void setSelectedItem(Item *item);
@@ -112,11 +147,21 @@ class ItemContainer : public gcn::Widget, public gcn::MouseListener
*/
void fireSelectionChangedEvent();
+ /**
+ * Gets the slot index based on the cursor position.
+ *
+ * @param posX The X Coordinate position.
+ * @param posY The Y Coordinate position.
+ * @return The slot index on success, -1 on failure.
+ */
+ int getSlotIndex(const int posX, const int posY) const;
+
Inventory *mInventory;
+ int mGridColumns, mGridRows;
Image *mSelImg;
- Item *mSelectedItem;
-
- int mMaxItems;
+ Item *mSelectedItem, *mHighlightedItem;
+ bool mDragged, mSwapItems;
+ int mDragPosX, mDragPosY;
std::list<SelectionListener*> mListeners;
};
diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp
index 65162d35..48bbd3d0 100644
--- a/src/gui/popupmenu.cpp
+++ b/src/gui/popupmenu.cpp
@@ -174,10 +174,13 @@ void PopupMenu::handleLink(const std::string& link)
}
else
{
- player_node->useItem(mItem);
+ player_node->useItem(mItem->getInvIndex());
}
}
-
+ else if (link == "split")
+ {
+ new ItemAmountWindow(AMOUNT_ITEM_SPLIT, inventoryWindow, mItem);
+ }
else if (link == "drop")
{
new ItemAmountWindow(AMOUNT_ITEM_DROP, inventoryWindow, mItem);
@@ -220,9 +223,10 @@ void PopupMenu::showPopup(int x, int y, Item *item)
}
else
mBrowserBox->addRow(_("@@use|Use@@"));
-
mBrowserBox->addRow(_("@@drop|Drop@@"));
mBrowserBox->addRow(_("@@description|Description@@"));
+ if (!item->isEquipment())
+ { mBrowserBox->addRow(_("@@split|Split@@")); }
mBrowserBox->addRow("##3---");
mBrowserBox->addRow(_("@@cancel|Cancel@@"));
diff --git a/src/gui/trade.cpp b/src/gui/trade.cpp
index 724f6d5b..78204120 100644
--- a/src/gui/trade.cpp
+++ b/src/gui/trade.cpp
@@ -57,14 +57,15 @@ TradeWindow::TradeWindow():
mCancelButton = new Button("Cancel", "cancel", this);
mTradeButton = new Button("Trade", "trade", this);
- mMyItemContainer = new ItemContainer(mMyInventory.get());
+ mMyItemContainer = new ItemContainer(mMyInventory.get(), 5, 3);
mMyItemContainer->addSelectionListener(this);
mMyItemContainer->setPosition(2, 2);
mMyScroll = new ScrollArea(mMyItemContainer);
mMyScroll->setPosition(8, 8);
- mPartnerItemContainer = new ItemContainer(mPartnerInventory.get());
+ mPartnerItemContainer = new ItemContainer(
+ mPartnerInventory.get(), 5, 3);
mPartnerItemContainer->addSelectionListener(this);
mPartnerItemContainer->setPosition(2, 58);
diff --git a/src/inventory.cpp b/src/inventory.cpp
index 11c52421..d9bd79f8 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -30,7 +30,7 @@
struct SlotUsed : public std::unary_function<Item, bool>
{
bool operator()(const Item &item) const {
- return (item.getId() != -1 && item.getQuantity() > 0);
+ return (item.getId() && item.getQuantity());
}
};
@@ -72,8 +72,7 @@ void Inventory::addItem(int index, int id, int quantity)
void Inventory::clear()
{
for (int i = 0; i < INVENTORY_SIZE; i++) {
- mItems[i].setId(-1);
- mItems[i].setQuantity(0);
+ removeItemIndex(i);
}
}
@@ -81,12 +80,17 @@ 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);
+ removeItemIndex(i);
}
}
}
+void Inventory::removeItemIndex(int index)
+{
+ mItems[index].setId(0);
+ mItems[index].setQuantity(0);
+}
+
bool Inventory::contains(Item *item)
{
for (int i = 0; i < INVENTORY_SIZE; i++) {
diff --git a/src/inventory.h b/src/inventory.h
index ce537f34..f0d3e4d7 100644
--- a/src/inventory.h
+++ b/src/inventory.h
@@ -26,7 +26,7 @@
class Item;
-#define INVENTORY_SIZE 100
+#define INVENTORY_SIZE 50
class Inventory
{
@@ -62,6 +62,11 @@ class Inventory
void removeItem(int id);
/**
+ * Remove a item from the inventory, specified by the index.
+ */
+ void removeItemIndex(int index);
+
+ /**
* Checks if the given item is in the inventory
*/
bool contains(Item *item);
@@ -86,6 +91,7 @@ class Inventory
*/
int getLastUsedSlot();
+ static const int NO_SLOT_INDEX = -1; /**< Slot has no index. */
protected:
Item *mItems; /**< The holder of items */
};
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 478603b8..035c31f6 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -101,6 +101,17 @@ Item* LocalPlayer::getInvItem(int index)
return mInventory->getItem(index);
}
+void
+LocalPlayer::moveInvItem(Item *item, int newIndex)
+{
+ // special case, the old and new cannot copy over each other.
+ if (item->getInvIndex() == newIndex)
+ return;
+
+ Net::GameServer::Player::moveItem(
+ item->getInvIndex(), newIndex, item->getQuantity());
+}
+
void LocalPlayer::equipItem(Item *item)
{
Net::GameServer::Player::equip(item->getInvIndex());
@@ -114,15 +125,9 @@ void LocalPlayer::unequipItem(int slot)
mEquipment->setEquipment(slot, 0);
}
-void LocalPlayer::useItem(Item *item)
+void LocalPlayer::useItem(int slot)
{
- // XXX Convert for new server
- /*
- MessageOut outMsg(CMSG_PLAYER_INVENTORY_USE);
- outMsg.writeShort(item->getInvIndex());
- outMsg.writeLong(item->getId());
- // Note: id is dest of item, usually player_node->account_ID ??
- */
+ Net::GameServer::Player::useItem(slot);
}
void LocalPlayer::dropItem(Item *item, int quantity)
@@ -130,6 +135,17 @@ void LocalPlayer::dropItem(Item *item, int quantity)
Net::GameServer::Player::drop(item->getInvIndex(), quantity);
}
+void LocalPlayer::splitItem(Item *item, int quantity)
+{
+ int newIndex = mInventory->getFreeSlot();
+ if (newIndex > Inventory::NO_SLOT_INDEX)
+ {
+ Net::GameServer::Player::moveItem(
+ item->getInvIndex(), newIndex, quantity);
+ }
+
+}
+
void LocalPlayer::pickUp(FloorItem *item)
{
int dx = item->getX() - mX / 32;
diff --git a/src/localplayer.h b/src/localplayer.h
index edadd7a0..d2aef38b 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -137,6 +137,11 @@ class LocalPlayer : public Player
Item* getInvItem(int index);
/**
+ * Move the Inventory item from the old slot to the new slot.
+ */
+ void moveInvItem(Item *item, int newIndex);
+
+ /**
* Equips an item.
*/
void equipItem(Item *item);
@@ -146,8 +151,12 @@ class LocalPlayer : public Player
*/
void unequipItem(int slot);
- void useItem(Item *item);
+ void useItem(int slot);
+
void dropItem(Item *item, int quantity);
+
+ void splitItem(Item *item, int quantity);
+
void pickUp(FloorItem *item);
/**
diff --git a/src/net/gameserver/player.cpp b/src/net/gameserver/player.cpp
index e93fff46..29d711d7 100644
--- a/src/net/gameserver/player.cpp
+++ b/src/net/gameserver/player.cpp
@@ -52,6 +52,15 @@ void Net::GameServer::Player::pickUp(int x, int y)
Net::GameServer::connection->send(msg);
}
+void Net::GameServer::Player::moveItem(int oldSlot, int newSlot, int amount)
+{
+ MessageOut msg(PGMSG_MOVE_ITEM);
+ msg.writeByte(oldSlot);
+ msg.writeByte(newSlot);
+ msg.writeByte(amount);
+ Net::GameServer::connection->send(msg);
+}
+
void Net::GameServer::Player::drop(int slot, int amount)
{
MessageOut msg(PGMSG_DROP);
@@ -74,6 +83,13 @@ void Net::GameServer::Player::unequip(int slot)
Net::GameServer::connection->send(msg);
}
+void Net::GameServer::Player::useItem(int slot)
+{
+ MessageOut msg(PGMSG_USE_ITEM);
+ msg.writeByte(slot);
+ Net::GameServer::connection->send(msg);
+}
+
void Net::GameServer::Player::attack(int direction)
{
MessageOut msg(PGMSG_ATTACK);
@@ -123,4 +139,3 @@ void Net::GameServer::Player::tradeItem(int slot, int amount)
msg.writeByte(amount);
Net::GameServer::connection->send(msg);
}
-
diff --git a/src/net/gameserver/player.h b/src/net/gameserver/player.h
index 4c27d4d0..d21e656e 100644
--- a/src/net/gameserver/player.h
+++ b/src/net/gameserver/player.h
@@ -37,9 +37,11 @@ namespace Net
void say(const std::string &text);
void walk(int x, int y);
void pickUp(int x, int y);
+ void moveItem(int oldSlot, int newSlot, int amount);
void drop(int slot, int amount);
void equip(int slot);
void unequip(int slot);
+ void useItem(int slot);
void attack(int direction);
void changeAction(Being::Action action);
void talkToNPC(int id, bool restart);
diff --git a/src/net/protocol.h b/src/net/protocol.h
index 6bbe7919..1dde518e 100644
--- a/src/net/protocol.h
+++ b/src/net/protocol.h
@@ -79,6 +79,7 @@ enum {
PGMSG_DROP = 0x0111, // B slot, B amount
PGMSG_EQUIP = 0x0112, // B slot
PGMSG_UNEQUIP = 0x0113, // B slot
+ PGMSG_MOVE_ITEM = 0x0114, // B slot1, B slot2, B amount
GPMSG_INVENTORY = 0x0120, // { B slot, W item id [, B amount] }*
GPMSG_INVENTORY_FULL = 0x0121, // { B slot, W item id [, B amount] }*
GPMSG_PLAYER_ATTRIBUTE_UPDATE = 0x0130, // { W attribute, W value }*
@@ -116,7 +117,7 @@ enum {
GPMSG_TRADE_ACCEPT = 0x02C7, // -
PGMSG_TRADE_ADD_ITEM = 0x02C8, // B slot, B amount
GPMSG_TRADE_ADD_ITEM = 0x02C9, // W item id, B amount
- PGMSG_USE_ITEM = 0x0300, // L item id
+ PGMSG_USE_ITEM = 0x0300, // B slot
GPMSG_USE_RESPONSE = 0x0301, // B error
GPMSG_BEINGS_DAMAGE = 0x0310, // { W being id, W amount }*