Mana
Loading...
Searching...
No Matches
outfitwindow.cpp
Go to the documentation of this file.
1/*
2 * The Mana Client
3 * Copyright (C) 2007-2009 The Mana World Development Team
4 * Copyright (C) 2009-2012 The Mana Developers
5 *
6 * This file is part of The Mana Client.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include "outfitwindow.h"
23
24#include "configuration.h"
25#include "equipment.h"
26#include "graphics.h"
27#include "inventory.h"
28#include "item.h"
29#include "playerinfo.h"
30
31#include "gui/widgets/button.h"
33#include "gui/widgets/label.h"
34#include "gui/widgets/layout.h"
35
36#include "resources/image.h"
37
38#include "utils/gettext.h"
39#include "utils/stringutils.h"
40
42 Window(_("Outfits"))
43{
44 setWindowName("Outfits");
45 setResizable(true);
46 setCloseButton(true);
47 setDefaultSize(250, 250, 118, 180);
48
49 mPreviousButton = new Button(_("<"), "previous", this);
50 mNextButton = new Button(_(">"), "next", this);
51 mCurrentLabel = new Label(strprintf(_("Outfit: %d"), 1));
52 mCurrentLabel->setAlignment(gcn::Graphics::CENTER);
53 mUnequipCheck = new CheckBox(_("Unequip first"));
54
55 mUnequipCheck->setActionEventId("unequip");
56 mUnequipCheck->addActionListener(this);
57
58 place(0, 3, mPreviousButton, 1);
59 place(1, 3, mCurrentLabel, 2);
60 place(3, 3, mNextButton, 1);
61 place(0, 4, mUnequipCheck, 4);
62
63 Layout &layout = getLayout();
65 layout.setColWidth(4, Layout::CENTER);
66
68
69 load();
70
71 mUnequipCheck->setSelected(mOutfits[mCurrentOutfit].unequip);
72}
73
78
80{
81 for (auto &mOutfit : mOutfits)
82 memset(mOutfit.items, -1, sizeof(mOutfit.items));
83
84 for (auto &outfit : config.outfits)
85 {
86 if (outfit.index < 0 || outfit.index >= OUTFITS_COUNT)
87 continue;
88
89 std::string buf;
90 std::stringstream ss(outfit.items);
91
92 for (int i = 0; (ss >> buf) && i < OUTFIT_ITEM_COUNT; i++)
93 mOutfits[outfit.index].items[i] = atoi(buf.c_str());
94
95 mOutfits[outfit.index].unequip = outfit.unequip;
96 }
97}
98
100{
101 config.outfits.clear();
102
103 std::string outfitStr;
104 for (int o = 0; o < OUTFITS_COUNT; o++)
105 {
106 bool emptyOutfit = true;
107
108 for (int item : mOutfits[o].items)
109 {
110 if (!outfitStr.empty())
111 outfitStr += " ";
112
113 outfitStr += item ? toString(item) : toString(-1);
114 emptyOutfit &= item <= 0;
115 }
116
117 if (!emptyOutfit)
118 config.outfits.push_back({ o, outfitStr, mOutfits[o].unequip });
119
120 outfitStr.clear();
121 }
122}
123
124void OutfitWindow::action(const gcn::ActionEvent &event)
125{
126 if (event.getId() == "next")
127 {
128 if (mCurrentOutfit < (OUTFITS_COUNT - 1))
130 else
131 mCurrentOutfit = 0;
132 mCurrentLabel->setCaption(strprintf(_("Outfit: %d"), mCurrentOutfit + 1));
133 mUnequipCheck->setSelected(mOutfits[mCurrentOutfit].unequip);
134 }
135 else if (event.getId() == "previous")
136 {
137 if (mCurrentOutfit > 0)
138 {
140 }
141 else
142 {
144 }
145 mCurrentLabel->setCaption(strprintf(_("Outfit: %d"), mCurrentOutfit + 1));
146 mUnequipCheck->setSelected(mOutfits[mCurrentOutfit].unequip);
147 }
148 else if (event.getId() == "unequip")
149 {
151 }
152}
153
155{
156 if (mOutfits[outfit].unequip)
157 unequipNotInOutfit(outfit);
158
159 for (int i : mOutfits[outfit].items)
160 {
162 if (item && !item->isEquipped() && item->getQuantity())
163 {
164 if (item->isEquippable())
165 item->doEvent(Event::DoEquip);
166 }
167 }
168}
169
171{
172 for (int i = 0; i < OUTFIT_ITEM_COUNT; i++)
173 mOutfits[mCurrentOutfit].items[i] = mOutfits[outfit].items[i];
174}
175
176void OutfitWindow::draw(gcn::Graphics *graphics)
177{
179 auto *g = static_cast<Graphics*>(graphics);
180
181 for (int i = 0; i < OUTFIT_ITEM_COUNT; i++)
182 {
183 const int itemX = 10 + (i % mGridWidth) * mBoxWidth;
184 const int itemY = 25 + (i / mGridWidth) * mBoxHeight;
185
186 graphics->setColor(gcn::Color(0, 0, 0, 64));
187 graphics->drawRectangle(gcn::Rectangle(itemX, itemY,
190 graphics->setColor(gcn::Color(255, 255, 255, 32));
191 graphics->fillRectangle(gcn::Rectangle(itemX, itemY,
194
195 if (mOutfits[mCurrentOutfit].items[i] < 0)
196 {
197 continue;
198 }
199
200 Item *item =
202 if (item)
203 {
204 // Draw item icon.
205 if (Image *image = item->getImage())
206 {
207 g->drawImage(image, itemX, itemY);
208 }
209 }
210 }
211
212 if (mItemMoved)
213 {
214 // Draw the item image being dragged by the cursor.
215 if (Image *image = mItemMoved->getImage())
216 {
217 const int tPosX = mCursorPosX - (image->getWidth() / 2);
218 const int tPosY = mCursorPosY - (image->getHeight() / 2);
219
220 g->drawImage(image, tPosX, tPosY);
221 }
222 }
223}
224
225
226void OutfitWindow::mouseDragged(gcn::MouseEvent &event)
227{
229
230 if (event.getButton() == gcn::MouseEvent::LEFT)
231 {
232 if (!mItemMoved && mItemClicked)
233 {
234 const int index = getIndexFromGrid(event.getX(), event.getY());
235 if (index == -1)
236 return;
237
238 const int itemId = mOutfits[mCurrentOutfit].items[index];
239 if (itemId < 0)
240 return;
241
242 if (Item *item = PlayerInfo::getInventory()->findItem(itemId))
243 {
244 mItemMoved = item;
245 mOutfits[mCurrentOutfit].items[index] = -1;
246 }
247 }
248
249 if (mItemMoved)
250 {
251 mCursorPosX = event.getX();
252 mCursorPosY = event.getY();
253 }
254 }
255}
256
257void OutfitWindow::mousePressed(gcn::MouseEvent &event)
258{
260 const int index = getIndexFromGrid(event.getX(), event.getY());
261 if (index == -1)
262 return;
263
264 // Stores the selected item if there is one.
265 if (isItemSelected())
266 {
268 mItemSelected = -1;
269 }
270 else if (mOutfits[mCurrentOutfit].items[index])
271 {
272 mItemClicked = true;
273 }
274}
275
276void OutfitWindow::mouseReleased(gcn::MouseEvent &event)
277{
279 if (event.getButton() == gcn::MouseEvent::LEFT)
280 {
281 if (isItemSelected())
282 {
283 mItemSelected = -1;
284 }
285 const int index = getIndexFromGrid(event.getX(), event.getY());
286 if (index == -1)
287 {
288 mItemMoved = nullptr;
289 return;
290 }
291 if (mItemMoved)
292 {
294 mItemMoved = nullptr;
295 }
296 if (mItemClicked)
297 mItemClicked = false;
298 }
299}
300
301int OutfitWindow::getIndexFromGrid(int pointX, int pointY) const
302{
303 const gcn::Rectangle tRect = gcn::Rectangle(
304 10, 25, 10 + mGridWidth * mBoxWidth, 25 + mGridHeight * mBoxHeight);
305 if (!tRect.isPointInRect(pointX, pointY))
306 return -1;
307 const int index = (((pointY - 25) / mBoxHeight) * mGridWidth) +
308 (pointX - 10) / mBoxWidth;
309 if (index >= OUTFIT_ITEM_COUNT)
310 return -1;
311 return index;
312}
313
315{
316 Inventory *inventory = PlayerInfo::getInventory();
317 if (!inventory)
318 return;
319
320 for (int i = 0; i < inventory->getSize(); i++)
321 {
322 if (inventory->getItem(i) && inventory->getItem(i)->isEquipped())
323 {
324 bool found = false;
325 for (int item : mOutfits[outfit].items)
326 {
327 if (inventory->getItem(i)->getId() == item)
328 {
329 found = true;
330 break;
331 }
332 }
333 if (!found)
334 {
335 if (Item *item = inventory->getItem(i))
336 item->doEvent(Event::DoUnequip);
337 }
338 }
339 }
340}
Button widget.
Definition button.h:38
Check box widget.
Definition checkbox.h:32
@ DoEquip
Definition event.h:76
@ DoUnequip
Definition event.h:78
A central point of control for graphics.
Definition graphics.h:78
void setColor(const gcn::Color &color) override
Definition graphics.h:255
Defines a class for loading and storing images.
Definition image.h:45
Item * findItem(int itemId) const
Searches for the specified item by it's id.
Definition inventory.cpp:52
Item * getItem(int index) const
Returns the item at the specified index.
Definition inventory.cpp:44
int getSize() const
Returns the size that this instance is configured for.
Definition inventory.h:67
Represents one or more instances of a certain item type.
Definition item.h:35
void doEvent(Event::Type eventType)
Definition item.cpp:54
bool isEquipped() const
Returns whether this item is equipped.
Definition item.h:79
int getQuantity() const
Returns the number of items.
Definition item.h:69
int getId() const
Returns the item id.
Definition item.h:49
Image * getImage() const
Returns the item image.
Definition item.h:54
bool isEquippable() const
Returns whether this item is equippable.
Definition item.cpp:69
Label widget.
Definition label.h:34
void setRowHeight(int n, int h)
Definition layout.h:221
void setColWidth(int n, int w)
Definition layout.h:215
This class is an helper for setting the position of widgets.
Definition layout.h:281
@ AUTO_SET
Uses the share as the new size.
Definition layout.h:304
Label * mCurrentLabel
int getIndexFromGrid(int pointX, int pointY) const
void unequipNotInOutfit(int outfit)
void mouseReleased(gcn::MouseEvent &event) override
bool isItemSelected() const
void mouseDragged(gcn::MouseEvent &event) override
void wearOutfit(int outfit)
void mousePressed(gcn::MouseEvent &event) override
Button * mPreviousButton
CheckBox * mUnequipCheck
~OutfitWindow() override
Outfit mOutfits[OUTFITS_COUNT]
void action(const gcn::ActionEvent &event) override
void copyOutfit(int outfit)
Button * mNextButton
Item * mItemMoved
void draw(gcn::Graphics *graphics) override
A window.
Definition window.h:59
void mouseReleased(gcn::MouseEvent &event) override
When the mouse button has been let go, this ensures that the mouse custom cursor is restored back to ...
Definition window.cpp:337
void draw(gcn::Graphics *graphics) override
Draws the window contents.
Definition window.cpp:103
Layout & getLayout()
Gets the layout handler for this window.
Definition window.cpp:714
void setWindowName(const std::string &name)
Sets the name of the window.
Definition window.h:272
void mouseDragged(gcn::MouseEvent &event) override
Implements window resizing and makes sure the window is not dragged/resized outside of the screen.
Definition window.cpp:397
void setResizable(bool resize)
Sets whether or not the window can be resized.
Definition window.cpp:212
LayoutCell & place(int x, int y, gcn::Widget *, int w=1, int h=1)
Adds a widget to the window and sets it at given cell.
Definition window.cpp:737
void setCloseButton(bool flag)
Sets whether or not the window has a close button.
Definition window.cpp:262
void setDefaultSize()
Set the default win pos and size to the current ones.
Definition window.cpp:545
void loadWindowState()
Reads the position (and the size for resizable windows) in the configuration based on the given strin...
Definition window.cpp:467
void mousePressed(gcn::MouseEvent &event) override
Starts window resizing when appropriate.
Definition window.cpp:304
Config config
Global settings (config.xml)
Definition client.cpp:97
Graphics * graphics
Definition client.cpp:104
#define _(s)
Definition gettext.h:38
const int ITEM_ICON_SIZE
Definition item.h:29
Inventory * getInventory()
Returns the player's inventory.
constexpr int OUTFIT_ITEM_COUNT
constexpr int OUTFITS_COUNT
std::string strprintf(char const *format,...)
A safe version of sprintf that returns a std::string of the result.
std::string toString(const T &arg)
Converts the given value to a string using std::stringstream.
Definition stringutils.h:68
std::vector< Outfit > outfits
int items[OUTFIT_ITEM_COUNT]