KDEGames

kgamedifficulty.cpp
1 /*
2  SPDX-FileCopyrightText: 2007, 2008 Nicolas Roffet <[email protected]>
3  SPDX-FileCopyrightText: 2007 Pino Toscano <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #include "kgamedifficulty.h"
9 
10 // KF
11 #include <KActionCollection>
12 #include <KComboBox>
13 #include <KLocalizedString>
14 #include <KMessageBox>
15 #include <KSelectAction>
16 #include <KXmlGuiWindow>
17 // Qt
18 #include <QIcon>
19 #include <QStatusBar>
20 
21 
22 class KGameDifficultyPrivate : public QObject
23 {
24  Q_OBJECT
25 
26  public:
27  ~KGameDifficultyPrivate() override;
28 
29  void init(KXmlGuiWindow* window, const QObject* recvr, const char* slotStandard, const char* slotCustom);
30 
31  void rebuildActions();
32 
33  /**
34  * @return standard string for standard level
35  */
37 
38  void setLevel(KGameDifficulty::standardLevel level);
39  void setLevelCustom(int key);
40 
41 
42  /**
43  * @brief Current custom difficulty level
44  */
45  int m_levelCustom;
46 
49  QMap<int, QString> m_customLevels;
50 
51  KSelectAction* m_menu;
52  KGameDifficulty::onChange m_restartOnChange;
53  bool m_running;
54  int m_oldSelection;
55  KComboBox* m_comboBox;
56 
57 
58  public Q_SLOTS:
59  /**
60  * @brief Player wants to change the difficulty level to a standard level
61  *
62  * The difference with the method "setSelection" is that the player may have to confirm that he agrees to end the current game (if needed).
63  * @param newSelection Selected item.
64  */
65  void changeSelection(int newSelection);
66 
67  Q_SIGNALS:
68  /**
69  * @brief Current difficulty level changed to a standard level
70  *
71  * The game catches this signal and restarts a game with the new standard difficulty level.
72  * @param level New standard level.
73  */
74  void standardLevelChanged(KGameDifficulty::standardLevel level);
75 
76  /**
77  * @brief Current difficulty level changed to a custom level
78  *
79  * The game catches this signal and restarts a game with the new standard difficulty level.
80  * @param key Custom level identifier.
81  */
82  void customLevelChanged(int key);
83 
84 
85  private:
86  void setSelection(int newSelection);
87 };
88 
89 
90 KGameDifficultyPrivate::~KGameDifficultyPrivate()
91 {
92  delete KGameDifficulty::self();
93 }
94 
95 
96 void KGameDifficultyPrivate::init(KXmlGuiWindow* window, const QObject* recvr, const char* slotStandard, const char* slotCustom = nullptr)
97 {
98  Q_ASSERT(recvr!=nullptr);
99 
100  m_oldSelection = -1; // No valid selection
101  m_level = KGameDifficulty::NoLevel;
102  m_running = false;
103 
104  QObject::connect(this, SIGNAL(standardLevelChanged(KGameDifficulty::standardLevel)), recvr, slotStandard);
105  if (slotCustom!=nullptr)
106  QObject::connect(this, SIGNAL(customLevelChanged(int)), recvr, slotCustom);
107 
108  m_menu = new KSelectAction(QIcon::fromTheme( QStringLiteral( "games-difficult") ), i18nc("Game difficulty level", "Difficulty" ), window);
109  m_menu->setToolTip(i18n("Set the difficulty level"));
110  m_menu->setWhatsThis(i18n("Set the difficulty level of the game."));
112  this, &KGameDifficultyPrivate::changeSelection);
113  m_menu->setObjectName( QStringLiteral("options_game_difficulty" ));
114  window->actionCollection()->addAction(m_menu->objectName(), m_menu);
115 
116  setParent(window);
117 
118  m_comboBox = new KComboBox(window);
119  m_comboBox->setToolTip(i18n("Difficulty"));
120  connect(m_comboBox, QOverload<int>::of(&QComboBox::activated),
121  this, &KGameDifficultyPrivate::changeSelection);
122  window->statusBar()->addPermanentWidget(m_comboBox);
123 
125 }
126 
127 
128 void KGameDifficultyPrivate::changeSelection(int newSelection)
129 {
130  if (newSelection!=m_oldSelection) {
131  bool mayChange = true;
132 
133  if (mayChange && (m_restartOnChange==KGameDifficulty::RestartOnChange) && m_running)
134  mayChange = ( KMessageBox::warningContinueCancel(nullptr, i18n("Changing the difficulty level will end the current game!"), QString(), KGuiItem(i18n("Change the difficulty level"))) == KMessageBox::Continue );
135 
136  if (mayChange) {
137  setSelection(newSelection);
138  } else {
139  // restore current level selection
140  setSelection(m_oldSelection);
141  }
142  }
143 }
144 
145 QPair<QByteArray, QString> KGameDifficultyPrivate::standardLevelString(KGameDifficulty::standardLevel level)
146 {
147  //The first entry in the pair is to be used as a key so don't change it. It doesn't have to match the string to be translated
148  switch (level) {
150  return qMakePair(QByteArray("Ridiculously Easy"), i18nc("Game difficulty level 1 out of 8", "Ridiculously Easy"));
152  return qMakePair(QByteArray("Very Easy"), i18nc("Game difficulty level 2 out of 8", "Very Easy"));
154  return qMakePair(QByteArray("Easy"), i18nc("Game difficulty level 3 out of 8", "Easy"));
156  return qMakePair(QByteArray("Medium"), i18nc("Game difficulty level 4 out of 8", "Medium"));
158  return qMakePair(QByteArray("Hard"), i18nc("Game difficulty level 5 out of 8", "Hard"));
160  return qMakePair(QByteArray("Very Hard"), i18nc("Game difficulty level 6 out of 8", "Very Hard"));
162  return qMakePair(QByteArray("Extremely Hard"), i18nc("Game difficulty level 7 out of 8", "Extremely Hard"));
164  return qMakePair(QByteArray("Impossible"), i18nc("Game difficulty level 8 out of 8", "Impossible"));
168  // Do nothing
169  break;
170  }
171  return qMakePair(QByteArray(), QString());
172 }
173 
174 void KGameDifficultyPrivate::rebuildActions()
175 {
176  m_menu->clear();
177  m_comboBox->clear();
178  std::sort(m_standardLevels.begin(), m_standardLevels.end());
179 
180  for (KGameDifficulty::standardLevel level : qAsConst(m_standardLevels)) {
181  if (level!=KGameDifficulty::Configurable) {
182  m_menu->addAction(standardLevelString(level).second);
183  m_comboBox->addItem(QIcon::fromTheme( QStringLiteral( "games-difficult" )), standardLevelString(level).second);
184  }
185  }
186 
187  if (!m_customLevels.isEmpty()) {
188  for (const QString &s : qAsConst(m_customLevels)) {
189  m_menu->addAction(s);
190  m_comboBox->addItem(QIcon::fromTheme( QStringLiteral( "games-difficult" )), s);
191  }
192  }
193 
194  if (m_standardLevels.contains(KGameDifficulty::Configurable)) {
195  QAction* separator = new QAction(m_menu);
196  separator->setSeparator(true);
197  m_menu->addAction(separator);
198 
199  QString s = i18nc("Name of the game difficulty level that is customized by the user by setting up different game parameters", "Custom");
200  m_menu->addAction(s);
201  m_comboBox->addItem(QIcon::fromTheme( QStringLiteral( "games-difficult" )), s);
202  }
203 
204  // reselect the previous selected item.
205  if (m_level==KGameDifficulty::Custom)
206  KGameDifficulty::setLevelCustom(m_levelCustom);
207  else if (m_standardLevels.contains(m_level))
208  KGameDifficulty::setLevel(m_level);
209 }
210 
211 void KGameDifficultyPrivate::setSelection(int newSelection)
212 {
213  int countWithoutConfigurable = m_standardLevels.count();
214  if (m_standardLevels.contains(KGameDifficulty::Configurable))
215  countWithoutConfigurable--;
216 
217  if ((m_standardLevels.contains(KGameDifficulty::Configurable)) && (newSelection>m_menu->actions().count()-3))
219  else if(newSelection<countWithoutConfigurable)
220  KGameDifficulty::setLevel(m_standardLevels[newSelection]);
221  else
222  KGameDifficulty::setLevelCustom((m_customLevels.keys()).value(newSelection - countWithoutConfigurable));
223 
224  m_oldSelection = newSelection;
225 }
226 
227 
228 void KGameDifficultyPrivate::setLevel(KGameDifficulty::standardLevel level)
229 {
230  if ((!m_standardLevels.contains(level)) && (level!=KGameDifficulty::Custom))
231  level = KGameDifficulty::NoLevel;
232 
233  if (level==KGameDifficulty::Configurable) {
234  m_menu->setCurrentItem(m_menu->actions().count()-1);
235  m_comboBox->setCurrentIndex(m_comboBox->count()-1);
236  } else if (level!=KGameDifficulty::Custom) {
237  int i = m_standardLevels.indexOf(level);
238  m_menu->setCurrentItem(i);
239  m_comboBox->setCurrentIndex(i);
240  }
241 
242  if (level != m_level) {
243  m_level = level;
244  Q_EMIT standardLevelChanged(level);
245  }
246 
247  m_oldSelection = m_menu->currentItem();
248 }
249 
250 
251 void KGameDifficultyPrivate::setLevelCustom(int key)
252 {
253  m_level = KGameDifficulty::Custom;
254 
255  int a = m_standardLevels.count();
256  if (m_standardLevels.contains(KGameDifficulty::Configurable))
257  a -= 1;
258 
259  int i = (m_customLevels.keys()).indexOf(key) + a;
260  m_menu->setCurrentItem(i);
261  m_comboBox->setCurrentIndex(i);
262 
263  if (key != m_levelCustom) {
264  m_levelCustom = key;
265  Q_EMIT customLevelChanged(key);
266  }
267 
268  m_oldSelection = m_menu->currentItem();
269 }
270 
271 
272 
273 //---//
274 
275 
276 
277 KGameDifficulty* KGameDifficulty::instance = nullptr;
278 
279 
281 {
282  // We do not need to delete d, because d deletes us.
283 }
284 
285 
286 void KGameDifficulty::init(KXmlGuiWindow* window, const QObject* recvr, const char* slotStandard, const char* slotCustom)
287 {
288  self()->d->init(window, recvr, slotStandard, slotCustom);
289 }
290 
291 
293 {
294  Q_ASSERT(self()->d);
295 
296  self()->d->m_restartOnChange = restart;
297  if (restart==RestartOnChange)
298  self()->d->m_comboBox->setWhatsThis(i18n("Select the <b>difficulty</b> of the game.<br />If you change the difficulty level while a game is running, you will have to cancel it and start a new one."));
299  else
300  self()->d->m_comboBox->setWhatsThis(i18n("Select the <b>difficulty</b> of the game.<br />You can change the difficulty level during a running game."));
301 
302 }
303 
304 
306 {
307  Q_ASSERT(self()->d);
308 
309  if ((level!=Custom) && (level!=NoLevel)) {
310  self()->d->m_standardLevels.append(level);
311  self()->d->rebuildActions();
312  }
313 }
314 
315 
317 {
318  Q_ASSERT(self()->d);
319 
320  self()->d->m_standardLevels.removeAll(level);
321  self()->d->rebuildActions();
322 }
323 
324 
325 void KGameDifficulty::addCustomLevel(int key, const QString& appellation)
326 {
327  Q_ASSERT(self()->d);
328 
329  self()->d->m_customLevels.insert(key, appellation);
330  self()->d->rebuildActions();
331 }
332 
333 
335 {
336  Q_ASSERT(self()->d);
337 
338  self()->d->m_customLevels.remove(key);
339  self()->d->rebuildActions();
340 }
341 
342 
343 void KGameDifficulty::setEnabled(bool enabled)
344 {
345  Q_ASSERT(self()->d->m_menu);
346 
347  // TODO: Doing this never disable the combobox in the toolbar (just in the menu). It seems to be a bug in the class KSelectAction of kdelibs/kdeui/actions. To check and solve...
348  self()->d->m_menu->setEnabled(enabled);
349  self()->d->m_comboBox->setEnabled(enabled);
350 }
351 
352 
354 {
355  Q_ASSERT(self()->d);
356 
357  self()->d->setLevel(level);
358 }
359 
360 
362 {
363  Q_ASSERT(self()->d);
364 
365  self()->d->setLevelCustom(key);
366 }
367 
368 
370 {
371  Q_ASSERT(self()->d);
372 
373  return self()->d->m_levelCustom;
374 }
375 
376 
378 {
379  Q_ASSERT(self()->d);
380 
381  return self()->d->m_level;
382 }
383 
384 
386 {
387  Q_ASSERT(self()->d);
388 
389  return self()->d->standardLevelString(self()->d->m_level).second;
390 }
391 
392 
394 {
395  Q_ASSERT(self()->d);
396 
397  return self()->d->standardLevelString(self()->d->m_level);
398 }
399 
400 
402 {
403  Q_ASSERT(self()->d);
404 
405  QMap<QByteArray, QString> levelStrings;
406 
407  levelStrings.insert(self()->d->standardLevelString(RidiculouslyEasy).first, self()->d->standardLevelString(RidiculouslyEasy).second);
408  levelStrings.insert(self()->d->standardLevelString(VeryEasy).first, self()->d->standardLevelString(VeryEasy).second);
409  levelStrings.insert(self()->d->standardLevelString(Easy).first, self()->d->standardLevelString(Easy).second);
410  levelStrings.insert(self()->d->standardLevelString(Medium).first, self()->d->standardLevelString(Medium).second);
411  levelStrings.insert(self()->d->standardLevelString(Hard).first, self()->d->standardLevelString(Hard).second);
412  levelStrings.insert(self()->d->standardLevelString(VeryHard).first, self()->d->standardLevelString(VeryHard).second);
413  levelStrings.insert(self()->d->standardLevelString(ExtremelyHard).first, self()->d->standardLevelString(ExtremelyHard).second);
414  levelStrings.insert(self()->d->standardLevelString(Impossible).first, self()->d->standardLevelString(Impossible).second);
415 
416  return levelStrings;
417 }
418 
420 {
421  Q_ASSERT(self()->d);
422 
423  QMap<int, QByteArray> weights;
424  weights.insert(RidiculouslyEasy, self()->d->standardLevelString(RidiculouslyEasy).first);
425  weights.insert(VeryEasy, self()->d->standardLevelString(VeryEasy).first);
426  weights.insert(Easy, self()->d->standardLevelString(Easy).first);
427  weights.insert(Medium, self()->d->standardLevelString(Medium).first);
428  weights.insert(Hard, self()->d->standardLevelString(Hard).first);
429  weights.insert(VeryHard, self()->d->standardLevelString(VeryHard).first);
430  weights.insert(ExtremelyHard, self()->d->standardLevelString(ExtremelyHard).first);
431  weights.insert(Impossible, self()->d->standardLevelString(Impossible).first);
432 
433  return weights;
434 }
435 
436 void KGameDifficulty::setRunning(bool running)
437 {
438  Q_ASSERT(self()->d);
439 
440  self()->d->m_running = running;
441 }
442 
443 
444 KGameDifficulty::KGameDifficulty() : d(new KGameDifficultyPrivate())
445 {
446 }
447 
448 
449 KGameDifficulty* KGameDifficulty::self()
450 {
451  if (instance==nullptr)
452  instance = new KGameDifficulty();
453  return instance;
454 }
455 
456 #include "kgamedifficulty.moc"
static void addCustomLevel(int key, const QString &appellation)
Add a custom difficulty level.
static void init(KXmlGuiWindow *window, const QObject *recvr, const char *slotStandard, const char *slotCustom=nullptr)
Initialize the difficulty class.
virtual KActionCollection * actionCollection() const
void setSeparator(bool b)
static QPair< QByteArray, QString > localizedLevelString()
Level "Very hard".
QStatusBar * statusBar() const const
Q_INVOKABLE QAction * addAction(const QString &name, QAction *action)
static int levelCustom()
Get the current custom difficulty level.
static QMap< QByteArray, QString > localizedLevelStrings()
Q_SIGNALSQ_SIGNALS
KGameDifficuty manages the game difficulty levels in a standard way.
static void removeStandardLevel(standardLevel level)
Remove a standard difficulty level.
Level "Very easy".
static standardLevel level()
Get the current standard difficulty level.
Level "Ridiculously easy".
Level "Extremely hard".
ButtonCode warningContinueCancel(QWidget *parent, const QString &text, const QString &caption=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
Q_OBJECTQ_OBJECT
Level "Impossible".
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void activated(int index)
static void setLevelCustom(int key)
Set the new current difficulty level as a custom one.
virtual ~KGameDifficulty()
Destructor.
onChange
Behavior on change.
void setParent(QObject *parent)
QCA_EXPORT void init()
static void setLevel(standardLevel level)
Set the new current difficulty level as a standard one.
QString i18n(const char *text, const TYPE &arg...)
if(recurs()&&!first)
void addPermanentWidget(QWidget *widget, int stretch)
static void removeCustomLevel(int key)
Remove a custom difficulty level.
static void setRunning(bool running)
Set the game state: Running or not.
static QString levelString()
standardLevel
Standard difficulty levels.
Any custom appellations for levels.
QIcon fromTheme(const QString &name)
void indexTriggered(int index)
QMap::iterator insert(const Key &key, const T &value)
static void setRestartOnChange(onChange restart)
Set if a new game has to be started by change.
Q_SLOTSQ_SLOTS
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
static void addStandardLevel(standardLevel level)
Add a standard difficulty level.
The current game has to be canceled and a new game will be started on change.
Q_EMITQ_EMIT
static QMap< int, QByteArray > levelWeights()
static void setEnabled(bool enabled)
Set if the difficulty level may be changed.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Dec 7 2021 22:34:14 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.