ManaPlus
charselectdialog.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2004-2009 The Mana World Development Team
4  * Copyright (C) 2009-2010 The Mana Developers
5  * Copyright (C) 2011-2019 The ManaPlus Developers
6  * Copyright (C) 2019-2021 Andrei Karas
7  *
8  * This file is part of The ManaPlus Client.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <http://www.gnu.org/licenses/>.
22  */
23 
25 
26 #include "client.h"
27 #include "configuration.h"
28 #include "pincodemanager.h"
29 
31 
34 #include "gui/windows/editdialog.h"
36 #include "gui/windows/okdialog.h"
37 #include "gui/windows/textdialog.h"
38 
39 #include "gui/widgets/button.h"
45 
46 #include "net/character.h"
47 #include "net/charserverhandler.h"
48 #include "net/logindata.h"
49 #ifdef TMWA_SUPPORT
50 #include "net/net.h"
51 #endif // TMWA_SUPPORT
52 #include "net/serverfeatures.h"
53 
54 #include "utils/foreach.h"
55 
56 #include "resources/db/unitsdb.h"
57 
58 #include "debug.h"
59 
60 // Character slots per row in the dialog
61 static const int SLOTS_PER_ROW = 5;
62 
64  // TRANSLATORS: char select dialog name
65  Window(strprintf(_("Account %s (last login time %s)"),
66  data.username.c_str(), data.lastLogin.c_str()),
68  nullptr,
69  "char.xml"),
71  KeyListener(),
72  mLoginData(&data),
73  // TRANSLATORS: char select dialog. button.
74  mSwitchLoginButton(new Button(this, _("Switch"), "switch",
75  BUTTON_SKIN, this)),
76  // TRANSLATORS: char select dialog. button.
77  mChangePasswordButton(new Button(this, _("Password"), "change_password",
78  BUTTON_SKIN, this)),
79  // TRANSLATORS: char select dialog. button.
80  mPlayButton(new Button(this, _("Play"), "use", BUTTON_SKIN, this)),
81  // TRANSLATORS: char select dialog. button.
82  mInfoButton(new Button(this, _("Info"), "info", BUTTON_SKIN, this)),
83  // TRANSLATORS: char select dialog. button.
84  mDeleteButton(new Button(this, _("Delete"), "delete", BUTTON_SKIN, this)),
85  // TRANSLATORS: char select dialog. button.
86  mRenameButton(nullptr),
87  mChangePinButton(nullptr),
88  mCharacterView(nullptr),
89  mCharacterEntries(0),
90  mCharServerHandler(charServerHandler),
91  mDeleteDialog(nullptr),
92  mDeleteIndex(-1),
93  mLocked(false),
94  mSmallScreen(mainGraphics->getWidth() < 470
95  || mainGraphics->getHeight() < 370)
96 {
97  setCloseButton(true);
98  setFocusable(true);
99 
100  ContainerPlacer placer(nullptr, nullptr);
101  placer = getPlacer(0, 0);
102 
103  placer(0, 0, mSwitchLoginButton, 1, 1);
104 
105  int n = 1;
106  placer(n, 0, mChangePasswordButton, 1, 1);
107  n ++;
108  placer(n, 0, mDeleteButton, 1, 1);
109  n ++;
110 #ifdef TMWA_SUPPORT
112 #endif
113  {
114  mRenameButton = new Button(this,
115  // TRANSLATORS: character rename button
116  _("Rename"),
117  "rename",
118  BUTTON_SKIN,
119  this);
120  placer(n, 0, mRenameButton, 1, 1);
121  n ++;
122  }
123 #ifdef TMWA_SUPPORT
125 #endif
126  {
127  mChangePinButton = new Button(this,
128  // TRANSLATORS: change pincode button
129  _("Change pin"),
130  "changepin",
131  BUTTON_SKIN,
132  this);
133  placer(n, 0, mChangePinButton, 1, 1);
134  n ++;
135  }
136  placer(n, 0, mInfoButton, 1, 1);
137  n ++;
138 
139  for (int i = 0; i < CAST_S32(mLoginData->characterSlots); i++)
140  {
141  CharacterDisplay *const character = new CharacterDisplay(this, this);
142  character->setVisible(Visible_false);
143  mCharacterEntries.push_back(character);
144  }
145 
146  placer(0, 2, mPlayButton, 1, 1);
147 
148  if (!mSmallScreen)
149  {
151  this, &mCharacterEntries, mPadding);
152  placer(0, 1, mCharacterView, 10, 1);
153  int sz = 410 + 2 * mPadding;
154  if (config.getIntValue("fontSize") > 18)
155  sz = 500 + 2 * mPadding;
156  const int width = mCharacterView->getWidth() + 2 * mPadding;
157  if (sz < width)
158  sz = width;
159  if (sz > mainGraphics->getWidth())
160  sz = mainGraphics->getWidth();
161  reflowLayout(sz, 0);
162  }
163  else
164  {
165  // TRANSLATORS: char select dialog name
166  setCaption(strprintf(_("Account %s"), mLoginData->username.c_str()));
168  this, &mCharacterEntries, mPadding);
170  - 2 * getPadding());
171  placer(0, 1, mCharacterView, 10, 1);
172  reflowLayout(0, 0);
173  }
174  addKeyListener(this);
175  center();
176 
178  mCharacterView->show(0);
179  updateState();
180 }
181 
183 {
184  mDeleteDialog = nullptr;
185 }
186 
188 {
191  requestFocus();
192 }
193 
195 {
196  // Check if a button of a character was pressed
197  const Widget *const sourceParent = event.getSource()->getParent();
198  int selected = -1;
199  for (unsigned int i = 0, fsz = CAST_U32(
200  mCharacterEntries.size());
201  i < fsz;
202  ++i)
203  {
204  if (mCharacterEntries[i] == sourceParent)
205  {
206  selected = i;
207  mCharacterView->show(i);
208  updateState();
209  break;
210  }
211  }
212  if (selected == -1)
213  selected = mCharacterView->getSelected();
214 
215  const std::string &eventId = event.getId();
216  const bool blocked = pincodeManager.isBlocked();
217 
218  if (selected >= 0)
219  {
220  if (blocked)
221  return;
222  if (eventId == "use")
223  {
224  use(selected);
225  return;
226  }
227  else if (eventId == "delete"
228  && (mCharacterEntries[selected]->getCharacter() != nullptr))
229  {
230  CREATEWIDGET(CharDeleteConfirm, this, selected);
231  return;
232  }
233  else if (eventId == "rename"
234  && (mCharacterEntries[selected]->getCharacter() != nullptr))
235  {
236  const LocalPlayer *const player = mCharacterEntries[
237  selected]->getCharacter()->dummy;
238  EditDialog *const dialog = CREATEWIDGETR(EditDialog,
239  // TRANSLATORS: character rename dialog header.
240  _("Please enter new name"),
241  player->getName(),
242  "OK",
243  300,
244  nullptr,
245  Modal_true);
246  charRenameListener.setId(player->getId());
249  }
250  else if (eventId == "info")
251  {
252  Net::Character *const character = mCharacterEntries[
253  selected]->getCharacter();
254  if (character == nullptr)
255  return;
256 
257  const LocalPlayer *const data = character->dummy;
258  if (data == nullptr)
259  return;
260 
261  const std::string strExp = toString(CAST_U64(
263  const std::string msg = strprintf(
264  // TRANSLATORS: char select dialog. player info message.
265  _("Hp: %u/%u\nMp: %u/%u\nLevel: %u\n"
266  "Experience: %s\nMoney: %s"),
267  CAST_U32(
269  CAST_U32(
271  CAST_U32(
273  CAST_U32(
275  CAST_U32(
277  strExp.c_str(),
279  character->data.mAttributes[Attributes::MONEY])).c_str());
280  CREATEWIDGET(OkDialog, data->getName(), msg,
281  // TRANSLATORS: ok dialog button
282  _("OK"),
284  Modal_true,
286  nullptr,
287  260);
288  }
289  }
290  if (eventId == "switch")
291  {
293  close();
294  }
295  else if (eventId == "change_password")
296  {
297  if (blocked)
298  return;
300  }
301  else if (eventId == "change_email")
302  {
303  if (blocked)
304  return;
306  }
307  else if (eventId == "try delete character")
308  {
309  if (blocked)
310  return;
311  if ((mDeleteDialog != nullptr) && mDeleteIndex != -1)
312  {
314  {
316  mDeleteDialog = nullptr;
317  }
319  {
321  mDeleteDialog = nullptr;
322  }
323  else
324  {
326  // TRANSLATORS: error header
327  _("Error"),
328  // TRANSLATORS: error message
329  _("Incorrect password"),
330  // TRANSLATORS: ok dialog button
331  _("OK"),
333  Modal_true,
335  nullptr,
336  260);
337  }
338  }
339  mDeleteIndex = -1;
340  }
341  else if (eventId == "changepin")
342  {
343  if (blocked)
344  return;
347  }
348 }
349 
350 void CharSelectDialog::use(const int selected)
351 {
352  if ((mCharacterEntries[selected] != nullptr)
353  && (mCharacterEntries[selected]->getCharacter() != nullptr))
354  {
355  attemptCharacterSelect(selected);
356  }
357  else
358  {
359  CharCreateDialog *const charCreateDialog =
360  CREATEWIDGETR(CharCreateDialog, this, selected);
361  mCharServerHandler->setCharCreateDialog(charCreateDialog);
362  }
363 }
364 
366 {
367  const InputActionT actionId = event.getActionId();
368  const bool blocked = pincodeManager.isBlocked();
369  PRAGMA45(GCC diagnostic push)
370  PRAGMA45(GCC diagnostic ignored "-Wswitch-enum")
371  switch (actionId)
372  {
374  event.consume();
377  break;
378 
380  {
381  event.consume();
382  int idx = mCharacterView->getSelected();
383  if (idx >= 0)
384  {
385  if ((idx + 1) % SLOTS_PER_ROW == 0)
386  break;
387  idx ++;
388  mCharacterView->show(idx);
389  updateState();
390  }
391  break;
392  }
393 
395  {
396  event.consume();
397  int idx = mCharacterView->getSelected();
398  if (idx >= 0)
399  {
400  if (idx == 0 || idx % SLOTS_PER_ROW == 0)
401  break;
402  idx --;
403  mCharacterView->show(idx);
404  updateState();
405  }
406  break;
407  }
408 
409  case InputAction::GUI_UP:
410  {
411  event.consume();
412  int idx = mCharacterView->getSelected();
413  if (idx >= 0)
414  {
415  if (idx < SLOTS_PER_ROW)
416  break;
417  idx -= SLOTS_PER_ROW;
418  mCharacterView->show(idx);
419  updateState();
420  }
421  break;
422  }
423 
425  {
426  event.consume();
427  int idx = mCharacterView->getSelected();
428  if (idx >= 0)
429  {
431  break;
432  idx += SLOTS_PER_ROW;
433  mCharacterView->show(idx);
434  updateState();
435  }
436  break;
437  }
438 
440  {
441  if (blocked)
442  return;
443  event.consume();
444  const int idx = mCharacterView->getSelected();
445  if (idx >= 0 && (mCharacterEntries[idx] != nullptr)
446  && (mCharacterEntries[idx]->getCharacter() != nullptr))
447  {
448  CREATEWIDGET(CharDeleteConfirm, this, idx);
449  }
450  break;
451  }
452 
454  {
455  if (blocked)
456  return;
457  event.consume();
459  break;
460  }
461  default:
462  break;
463  }
464  PRAGMA45(GCC diagnostic pop)
465 }
466 
471  const std::string &email)
472 {
473  if (mLocked)
474  return;
475 
476  if (mCharacterEntries[index] != nullptr)
477  {
479  mCharacterEntries[index]->getCharacter(),
480  email);
481  }
482  lock();
483 }
484 
486 {
487  mDeleteIndex = index;
489  {
491  // TRANSLATORS: char deletion question.
492  _("Enter your email for deleting character"),
493  // TRANSLATORS: email label.
494  _("Enter email:"),
495  this,
496  false);
497  }
498  else
499  {
501  // TRANSLATORS: char deletion question.
502  _("Enter password for deleting character"),
503  // TRANSLATORS: email label.
504  _("Enter password:"),
505  this,
506  true);
507  }
508  mDeleteDialog->setActionEventId("try delete character");
510 }
511 
516 {
517  if (mLocked || (mCharacterEntries[index] == nullptr))
518  return;
519 
521  if (mCharServerHandler != nullptr)
522  {
524  mCharacterEntries[index]->getCharacter());
525  }
526  lock();
527 }
528 
530 {
531  // Reset previous characters
532  FOR_EACH (STD_VECTOR<CharacterDisplay*>::const_iterator,
533  iter, mCharacterEntries)
534  {
535  if (*iter != nullptr)
536  (*iter)->setCharacter(nullptr);
537  }
538 
539  FOR_EACH (Net::Characters::const_iterator, i, characters)
540  setCharacter(*i);
541  updateState();
542 }
543 
545 {
546  if (character == nullptr)
547  return;
548  const int characterSlot = character->slot;
549  if (characterSlot >= CAST_S32(mCharacterEntries.size()))
550  {
551  logger->log("Warning: slot out of range: %d", character->slot);
552  return;
553  }
554 
555  if (mCharacterEntries[characterSlot] != nullptr)
556  mCharacterEntries[characterSlot]->setCharacter(character);
557 }
558 
560 {
561  if (!mLocked)
562  setLocked(true);
563 }
564 
566 {
567  setLocked(false);
568 }
569 
570 void CharSelectDialog::setLocked(const bool locked)
571 {
572  mLocked = locked;
573 
574  if (mSwitchLoginButton != nullptr)
575  mSwitchLoginButton->setEnabled(!locked);
576  if (mChangePasswordButton != nullptr)
578  mPlayButton->setEnabled(!locked);
579  if (mDeleteButton != nullptr)
580  mDeleteButton->setEnabled(!locked);
581 
582  for (size_t i = 0, sz = mCharacterEntries.size(); i < sz; ++i)
583  {
584  if (mCharacterEntries[i] != nullptr)
585  mCharacterEntries[i]->setActive(!mLocked);
586  }
587 }
588 
589 bool CharSelectDialog::selectByName(const std::string &name,
590  const SelectAction selAction)
591 {
592  if (mLocked)
593  return false;
594 
595  for (size_t i = 0, sz = mCharacterEntries.size(); i < sz; ++i)
596  {
597  if (mCharacterEntries[i] != nullptr)
598  {
599  const Net::Character *const character
600  = mCharacterEntries[i]->getCharacter();
601  if (character != nullptr)
602  {
603  if (character->dummy != nullptr &&
604  character->dummy->getName() == name)
605  {
607  updateState();
608  if (selAction == Choose)
610  return true;
611  }
612  }
613  }
614  }
615 
616  return false;
617 }
618 
620 {
622  Window::close();
623 }
624 
626 {
627  Window::widgetResized(event);
629 }
630 
632 {
633  const int idx = mCharacterView->getSelected();
634  if (idx == -1)
635  {
636  mPlayButton->setEnabled(false);
637  return;
638  }
639  mPlayButton->setEnabled(true);
640 
641  if (mCharacterEntries[idx] != nullptr &&
642  mCharacterEntries[idx]->getCharacter() != nullptr)
643  {
644  // TRANSLATORS: char select dialog. button.
645  mPlayButton->setCaption(_("Play"));
646 
647  const LocalPlayer *const player = mCharacterEntries[
648  idx]->getCharacter()->dummy;
649  if ((player != nullptr) && (mRenameButton != nullptr))
650  mRenameButton->setEnabled(player->getRename() ? true : false);
651  }
652  else
653  {
654  // TRANSLATORS: char select dialog. button.
655  mPlayButton->setCaption(_("Create"));
656  }
657 }
658 
659 void CharSelectDialog::setName(const BeingId id, const std::string &newName)
660 {
661  for (unsigned int i = 0, fsz = CAST_U32(
662  mCharacterEntries.size());
663  i < fsz;
664  ++i)
665  {
666  CharacterDisplay *const character = mCharacterEntries[i];
667  if (character == nullptr)
668  continue;
669  LocalPlayer *const player = character->getCharacter()->dummy;
670  if ((player != nullptr) && player->getId() == id)
671  {
672  player->setName(newName);
673  character->update();
674  return;
675  }
676  }
677 }
int BeingId
Definition: beingid.h:30
const std::string BUTTON_SKIN
Definition: button.h:89
#define CAST_S32
Definition: cast.h:30
#define CAST_U32
Definition: cast.h:31
#define CAST_U64
Definition: cast.h:33
CharRenameListener charRenameListener
static const int SLOTS_PER_ROW
Net::CharServerHandler * charServerHandler
Definition: net.cpp:85
BeingId getId() const
Definition: actorsprite.h:64
void setName(const std::string &name)
Definition: being.cpp:1136
const std::string & getName() const
Definition: being.h:232
Definition: button.h:102
void setCaption(const std::string &caption)
Definition: button.h:214
void setDialog(EditDialog *const dialog)
void setId(const BeingId id)
std::vector< CharacterDisplay * > mCharacterEntries
CharacterViewBase * mCharacterView
bool selectByName(const std::string &name, const SelectAction action)
CharSelectDialog(LoginData &data)
void setName(const BeingId id, const std::string &newName)
Net::CharServerHandler * mCharServerHandler
void action(const ActionEvent &event)
void setLocked(const bool locked)
TextDialog * mDeleteDialog
LoginData * mLoginData
void setCharacter(Net::Character *const character)
void askPasswordForDeletion(const int index)
void widgetResized(const Event &event)
Button * mSwitchLoginButton
Button * mChangePasswordButton
void keyPressed(KeyEvent &event)
void attemptCharacterDelete(const int index, const std::string &email)
void setCharacters(const Net::Characters &characters)
void attemptCharacterSelect(const int index)
void use(const int selected)
Net::Character * getCharacter() const
virtual void show(const int i)=0
int getSelected() const
virtual void resize()=0
void setState(const StateT state)
Definition: client.h:66
int getIntValue(const std::string &key) const
Definition: event.h:79
int getWidth() const
Definition: graphics.cpp:643
bool getRename() const
Definition: localplayer.h:425
void log(const char *const log_text,...)
Definition: logger.cpp:269
std::string username
Definition: logindata.h:59
uint16_t characterSlots
Definition: logindata.h:77
static std::string savedPassword
Definition: logindialog.h:80
virtual void chooseCharacter(Net::Character *const character) const =0
virtual void setCharCreateDialog(CharCreateDialog *const window) const =0
virtual void clear() const =0
virtual void setCharSelectDialog(CharSelectDialog *const window) const =0
virtual void deleteCharacter(Net::Character *const character, const std::string &email) const =0
virtual bool havePincode() const =0
virtual bool haveEmailOnDelete() const =0
void setState(const PincodeStateT state)
const std::string & getText() const
Definition: textdialog.cpp:124
Definition: widget.h:99
void setVisible(Visible visible)
Definition: widget.cpp:225
void setFocusable(const bool focusable)
Definition: widget.cpp:192
void setWidth(const int width)
Definition: widget.cpp:133
void setEnabled(const bool enabled)
Definition: widget.h:352
void setActionEventId(const std::string &actionEventId)
Definition: widget.h:596
void addKeyListener(KeyListener *const keyListener)
Definition: widget.cpp:272
virtual void requestFocus()
Definition: widget.cpp:204
void addActionListener(ActionListener *const actionListener)
Definition: widget.cpp:252
Widget * getParent() const
Definition: widget.h:202
const std::string & getActionEventId() const
Definition: widget.h:605
int getWidth() const
Definition: widget.h:221
Definition: window.h:102
void center()
Definition: window.cpp:1417
ContainerPlacer getPlacer(const int x, const int y)
Definition: window.cpp:1391
virtual void close()
Definition: window.cpp:902
virtual void setVisible(Visible visible)
Definition: window.cpp:778
void reflowLayout(int w, int h)
Definition: window.cpp:1396
void setCaption(const std::string &caption)
Definition: window.h:531
void postInit()
Definition: window.cpp:249
int getPadding() const
Definition: window.h:504
void widgetResized(const Event &event)
Definition: window.cpp:655
void setCloseButton(const bool flag)
Definition: window.cpp:749
int mPadding
Definition: window.h:618
Configuration config
#define CREATEWIDGET(type,...)
Definition: createwidget.h:29
#define CREATEWIDGETR(type,...)
Definition: createwidget.h:36
#define CREATEWIDGETV(var, type,...)
Definition: createwidget.h:25
#define new
Definition: debug_new.h:147
Client * client
Definition: client.cpp:118
#define FOR_EACH(type, iter, array)
Definition: foreach.h:25
#define _(s)
Definition: gettext.h:35
Graphics * mainGraphics
Definition: graphics.cpp:109
PRAGMA45(GCC diagnostic push) PRAGMA45(GCC diagnostic ignored "-Wredundant-decls") PRAGMA45(GCC diagnostic pop) class TestMain
InputAction ::T InputActionT
Definition: inputaction.h:717
#define nullptr
Definition: localconsts.h:45
Logger * logger
Definition: logger.cpp:89
uint32_t data
const bool Modal_false
Definition: modal.h:30
const bool Modal_true
Definition: modal.h:30
bool msg(InputEvent &event)
Definition: chat.cpp:39
@ PLAYER_MAX_MP
Definition: attributes.h:35
@ PLAYER_BASE_LEVEL
Definition: attributes.h:31
@ PLAYER_MAX_HP
Definition: attributes.h:33
std::string toString(T const &value)
converts any type to a string
Definition: catch.hpp:1774
std::list< Character * > Characters
Definition: character.h:61
ServerTypeT getNetworkType()
Definition: net.cpp:189
@ CHANGEPASSWORD
Definition: state.h:56
@ CHANGEEMAIL
Definition: state.h:59
@ SWITCH_LOGIN
Definition: state.h:63
std::string formatCurrency(const int value)
Definition: unitsdb.cpp:324
Net::ServerFeatures * serverFeatures
Definition: net.cpp:101
PincodeManager pincodeManager
const bool ShowCenter_true
Definition: showcenter.h:30
std::string strprintf(const char *const format,...)
LocalPlayer * dummy
Definition: character.h:56
PlayerInfoBackend data
Definition: character.h:57
uint16_t slot
Definition: character.h:58
AtrIntMap mAttributes
Definition: playerinfo.h:73
const bool Visible_false
Definition: visible.h:30
const bool Visible_true
Definition: visible.h:30