Mana
Loading...
Searching...
No Matches
charselectdialog.cpp
Go to the documentation of this file.
1/*
2 * The Mana Client
3 * Copyright (C) 2004-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
23
24#include "client.h"
25#include "localplayer.h"
26#include "log.h"
27#include "textpopup.h"
28#include "units.h"
29
33#include "gui/confirmdialog.h"
34#include "gui/sdlinput.h"
36
37#include "gui/widgets/button.h"
39#include "gui/widgets/label.h"
40#include "gui/widgets/layout.h"
42#include "gui/widgets/spacer.h"
43
44#include "net/charhandler.h"
45#include "net/logindata.h"
46#include "net/loginhandler.h"
47#include "net/net.h"
48
49#include "utils/gettext.h"
50#include "utils/stringutils.h"
51
52#include <guichan/font.hpp>
53
54#include <string>
55#include <cassert>
56
57// Character slots per row in the dialog
58static const int SLOTS_PER_ROW = 5;
59
64{
65 public:
67 ConfirmDialog(_("Confirm Character Delete"),
68 _("Are you sure you want to delete this character?"), m),
69 mMaster(m),
70 mIndex(index)
71 {
72 }
73
74 void action(const gcn::ActionEvent &event) override
75 {
76 if (event.getId() == "yes")
78
80 }
81
82 private:
84 int mIndex;
85};
86
87class CharacterDisplay : public Container, public gcn::MouseListener
88{
89 public:
90 CharacterDisplay(CharSelectDialog *charSelectDialog);
91
92 void setCharacter(Net::Character *character);
93
95 { return mCharacter; }
96
97 void requestFocus() override;
98
99 void mouseMoved(gcn::MouseEvent &event) override;
100 void mouseExited(gcn::MouseEvent &event) override;
101
102 void setActive(bool active);
103
104 private:
105 void update();
106
108
113
119};
120
122 Window(_("Account and Character Management")),
123 mLoginData(loginData),
124 mCharHandler(Net::getCharHandler())
125{
126 setCloseButton(false);
127
129 mSwitchLoginButton = new Button(_("Logout"), "switch", this);
130 mChangePasswordButton = new Button(_("Change Password"), "change_password",
131 this);
132
133 int optionalActions = Net::getLoginHandler()->supportedOptionalActions();
134
136 place = getPlacer(0, 0);
137
138 place(0, 0, mAccountNameLabel, 2);
140 place(0, 2, new Spacer);
142
143 if (optionalActions & Net::LoginHandler::ChangeEmail)
144 {
145 mChangeEmailButton = new Button(_("Change Email"),
146 "change_email", this);
148 }
149
150 place(0, 5, new Spacer);
151
152 if (optionalActions & Net::LoginHandler::Unregister)
153 {
154 mUnregisterButton = new Button(_("Unregister"),
155 "unregister", this);
157 }
158
159 place = getPlacer(1, 0);
160
161 for (int i = 0; i < (int)mLoginData->characterSlots; i++)
162 {
163 mCharacterEntries.push_back(new CharacterDisplay(this));
164 place(i % SLOTS_PER_ROW, i / SLOTS_PER_ROW, mCharacterEntries[i]);
165 }
166
167 reflowLayout();
168
169 addKeyListener(this);
170
171 center();
172 setVisible(true);
173
175 mCharacterEntries[0]->requestFocus();
176}
177
179
180void CharSelectDialog::action(const gcn::ActionEvent &event)
181{
182 // Check if a button of a character was pressed
183 const gcn::Widget *sourceParent = event.getSource()->getParent();
184 int selected = -1;
185 for (int i = 0; i < (int)mCharacterEntries.size(); ++i)
186 {
187 if (mCharacterEntries[i] == sourceParent)
188 {
189 selected = i;
190 break;
191 }
192 }
193
194 const std::string &eventId = event.getId();
195
196 if (selected != -1)
197 {
198 if (eventId == "use")
199 {
200 attemptCharacterSelect(selected);
201 }
202 else if (eventId == "new"
203 && !mCharacterEntries[selected]->getCharacter())
204 {
205 // Start new character dialog
206 auto *charCreateDialog =
207 new CharCreateDialog(this, selected);
208 mCharHandler->setCharCreateDialog(charCreateDialog);
209 }
210 else if (eventId == "delete"
211 && mCharacterEntries[selected]->getCharacter())
212 {
213 new CharDeleteConfirm(this, selected);
214 }
215 }
216 else if (eventId == "switch")
217 {
219 }
220 else if (eventId == "change_password")
221 {
223 }
224 else if (eventId == "change_email")
225 {
227 }
228 else if (eventId == "unregister")
229 {
231 }
232}
233
234void CharSelectDialog::keyPressed(gcn::KeyEvent &keyEvent)
235{
236 gcn::Key key = keyEvent.getKey();
237
238 if (key.getValue() == Key::ESCAPE)
239 {
240 action(gcn::ActionEvent(mSwitchLoginButton,
241 mSwitchLoginButton->getActionEventId()));
242 }
243}
244
249{
250 if (mLocked)
251 return;
252
253 mCharHandler->deleteCharacter(mCharacterEntries[index]->getCharacter());
254 lock();
255}
256
261{
262 if (mLocked)
263 return;
264
265 setVisible(false);
266 mCharHandler->chooseCharacter(mCharacterEntries[index]->getCharacter());
267 lock();
268}
269
271{
272 // Reset previous characters
273 for (auto *characterEntry : mCharacterEntries)
274 characterEntry->setCharacter(nullptr);
275
276 for (auto character : characters)
277 {
278 // Slots Number start at 1 for Manaserv, so we offset them by one.
279 int characterSlot = character->slot;
280 if (Net::getNetworkType() == ServerType::ManaServ && characterSlot > 0)
281 --characterSlot;
282
283 if (characterSlot >= (int)mCharacterEntries.size())
284 {
285 Log::warn("Slot out of range: %d", character->slot);
286 continue;
287 }
288
289 mCharacterEntries[characterSlot]->setCharacter(character);
290 }
291}
292
294{
295 assert(!mLocked);
296 setLocked(true);
297}
298
300{
301 setLocked(false);
302}
303
305{
306 mLocked = locked;
307
308 mSwitchLoginButton->setEnabled(!locked);
309 mChangePasswordButton->setEnabled(!locked);
311 mUnregisterButton->setEnabled(!locked);
313 mChangeEmailButton->setEnabled(!locked);
314
315 for (auto &characterEntry : mCharacterEntries)
316 characterEntry->setActive(!mLocked);
317}
318
319bool CharSelectDialog::selectByName(const std::string &name,
320 SelectAction action)
321{
322 if (mLocked)
323 return false;
324
325 for (int i = 0; i < (int)mCharacterEntries.size(); ++i)
326 {
327 if (Net::Character *character = mCharacterEntries[i]->getCharacter())
328 {
329 if (character->dummy->getName() == name)
330 {
331 mCharacterEntries[i]->requestFocus();
332 if (action == Choose)
334 return true;
335 }
336 }
337 }
338
339 return false;
340}
341
342
344
346 mPlayerBox(new PlayerBox)
347{
348 mPlayerBox->addMouseListener(this);
349
350 mName = new Label(std::string());
351 mName->setAlignment(Graphics::CENTER);
352 mButton = new Button("", "go", charSelectDialog);
353 mDelete = new Button(_("Delete"), "delete", charSelectDialog);
354
355 place(0, 0, mPlayerBox, 3, 5);
356 place(0, 5, mName, 3);
357 place(0, 6, mButton, 3);
358 place(0, 7, mDelete, 3);
359
360 update();
361
362 setSize(80, 112 + mName->getHeight()
363 + mButton->getHeight()
364 + mDelete->getHeight());
365
366 // Create the tooltip popup. It is shared by all instances and will get
367 // deleted by the WindowContainer.
368 if (!mTextPopup)
369 mTextPopup = new TextPopup;
370}
371
373{
374 if (mCharacter == character)
375 return;
376
377 mCharacter = character;
378 mPlayerBox->setPlayer(character ? character->dummy : nullptr);
379 update();
380}
381
383{
384 mButton->requestFocus();
385}
386
388{
389 mButton->setEnabled(active);
390 mDelete->setEnabled(active);
391}
392
394{
395 if (mCharacter)
396 {
397 const LocalPlayer *character = mCharacter->dummy;
398 mButton->setCaption(_("Choose"));
399 mButton->setActionEventId("use");
400 mName->setCaption(strprintf("%s", character->getName().c_str()));
401 mDelete->setVisible(true);
402 }
403 else
404 {
405 mButton->setCaption(_("Create"));
406 mButton->setActionEventId("new");
407 mName->setCaption(_("(empty)"));
408 mDelete->setVisible(false);
409 }
410
411 // Recompute layout
412 distributeResizedEvent();
413}
414
415void CharacterDisplay::mouseMoved(gcn::MouseEvent &event)
416{
417 int x = event.getX();
418 int y = event.getY();
419
420 if (event.getSource() == mPlayerBox && mCharacter)
421 {
422 int absX, absY;
423 mPlayerBox->getAbsolutePosition(absX, absY);
424
425 const auto level = strprintf(_("Level %d"), mCharacter->data.mAttributes[LEVEL]);
427
428 mTextPopup->show(x + absX, y + absY, level, money);
429 }
430 else
431 {
432 mTextPopup->setVisible(false);
433 }
434}
435
436void CharacterDisplay::mouseExited(gcn::MouseEvent &event)
437{
438 mTextPopup->setVisible(false);
439}
const std::string & getName() const
Returns the name of the being.
Definition being.h:190
Button widget.
Definition button.h:38
void setCaption(const std::string &caption)
Definition button.cpp:226
Character creation dialog.
Listener for confirming character deletion.
CharSelectDialog * mMaster
void action(const gcn::ActionEvent &event) override
CharDeleteConfirm(CharSelectDialog *m, int index)
Character selection dialog.
std::vector< CharacterDisplay * > mCharacterEntries
The player boxes.
void keyPressed(gcn::KeyEvent &keyEvent) override
void attemptCharacterSelect(int index)
Communicate character selection to the server.
void setLocked(bool locked)
gcn::Button * mChangeEmailButton
gcn::Button * mUnregisterButton
Net::CharHandler * mCharHandler
void attemptCharacterDelete(int index)
Communicate character deletion to the server.
CharSelectDialog(LoginData *loginData)
~CharSelectDialog() override
LoginData * mLoginData
friend class CharDeleteConfirm
void setCharacters(const Net::Characters &characters)
gcn::Button * mChangePasswordButton
void action(const gcn::ActionEvent &event) override
gcn::Label * mAccountNameLabel
bool selectByName(const std::string &name, SelectAction action=Focus)
Attempt to select the character with the given name.
gcn::Button * mSwitchLoginButton
void requestFocus() override
void setCharacter(Net::Character *character)
Net::Character * getCharacter() const
static TextPopup * mTextPopup
The character info popup.
void mouseMoved(gcn::MouseEvent &event) override
void mouseExited(gcn::MouseEvent &event) override
CharacterDisplay(CharSelectDialog *charSelectDialog)
void setActive(bool active)
Net::Character * mCharacter
static void setState(State state)
Definition client.h:169
An option dialog.
void action(const gcn::ActionEvent &event) override
Called when receiving actions from the widgets.
This class is a helper for adding widgets to nested tables in a window.
Definition layout.h:34
A widget container.
Definition container.h:41
LayoutCell & place(int x, int y, gcn::Widget *wg, int w=1, int h=1)
Adds a widget to the container and sets it at given cell.
Definition container.cpp:46
Label widget.
Definition label.h:34
The local player character.
Definition localplayer.h:75
unsigned short characterSlots
The number of character slots.
Definition logindata.h:47
std::string username
Definition logindata.h:33
virtual void chooseCharacter(Net::Character *character)=0
virtual void setCharSelectDialog(CharSelectDialog *window)=0
virtual void setCharCreateDialog(CharCreateDialog *window)=0
virtual void deleteCharacter(Net::Character *character)=0
virtual int supportedOptionalActions() const =0
A box showing a player character.
Definition playerbox.h:34
void setPlayer(const Being *being)
Sets a new player character to be displayed by this box.
Definition playerbox.h:47
A space.
Definition spacer.h:33
A popup that displays information about an item.
Definition textpopup.h:36
void show(int x, int y, const std::string &str1, const std::string &str2=std::string())
Sets the text to be displayed.
Definition textpopup.cpp:54
static std::string formatCurrency(int value)
Formats the given number in the correct currency format.
Definition units.cpp:216
A window.
Definition window.h:59
void center()
Positions the window in the center of it's parent.
Definition window.cpp:768
virtual void setVisible(bool visible)
Overloads window setVisible by Guichan to allow sticky window handling.
Definition window.cpp:282
ContainerPlacer getPlacer(int x, int y)
Returns a proxy for adding widgets in an inner table of the layout.
Definition window.cpp:743
void reflowLayout(int w=0, int h=0)
Computes the position of the widgets according to the current layout.
Definition window.cpp:748
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
LoginData loginData
Definition client.cpp:95
@ STATE_CHANGEEMAIL
Definition client.h:83
@ STATE_UNREGISTER
Definition client.h:86
@ STATE_SWITCH_LOGIN
Definition client.h:90
@ STATE_CHANGEPASSWORD
Definition client.h:80
#define _(s)
Definition gettext.h:38
@ ESCAPE
Definition sdlinput.h:96
void warn(const char *log_text,...) LOG_PRINTF_ATTR
The network communication layer.
LoginHandler * getLoginHandler()
Definition net.cpp:95
ServerType getNetworkType()
Definition net.cpp:200
std::list< Character * > Characters
Definition charhandler.h:49
CharHandler * getCharHandler()
Definition net.cpp:65
@ LEVEL
Definition playerinfo.h:30
@ MONEY
Definition playerinfo.h:34
std::string strprintf(char const *format,...)
A safe version of sprintf that returns a std::string of the result.
A structure to hold information about a character.
Definition charhandler.h:38
LocalPlayer * dummy
A dummy representing this character.
Definition charhandler.h:45
PlayerInfoBackend data
Definition charhandler.h:46
std::map< int, int > mAttributes
Definition playerinfo.h:56