gamerulespanel.cpp
1 //------------------------------------------------------------------------------
2 // gamerulespanel.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 USA
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2014 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "gamerulespanel.h"
24 #include "ui_gamerulespanel.h"
25 
26 #include "ini/ini.h"
27 #include "plugins/engineplugin.h"
28 #include "serverapi/gamecreateparams.h"
30 
31 #include <climits>
32 #include <QVariant>
33 
34 DClass<GameRulesPanel> : public Ui::GameRulesPanel
35 {
36 public:
37  class GameLimitWidget
38  {
39  public:
40  QWidget *label;
41  QSpinBox *spinBox;
42  GameCVar limit;
43  };
44 
45  bool anythingAvailable;
46  const EnginePlugin *engine;
47  GameCreateParams::HostMode hostMode;
48  GameMode gameMode;
49  QList<GameCVar> gameModifiers;
50  QList<GameLimitWidget *> limitWidgets;
51  QMap<QString, QMap<QString, int> > memorizedLimits;
52 };
53 
54 DPointered(GameRulesPanel)
55 
56 GameRulesPanel::GameRulesPanel(QWidget *parent)
57  : QWidget(parent)
58 {
59  d->setupUi(this);
60  d->anythingAvailable = true;
61  d->engine = nullptr;
62  d->hostMode = GameCreateParams::Host;
63 }
64 
65 GameRulesPanel::~GameRulesPanel()
66 {
67  qDeleteAll(d->limitWidgets);
68 }
69 
70 void GameRulesPanel::applyModeToUi()
71 {
72  bool engineAllowsSlotsLimits = false;
73  bool engineHasModifiers = false;
74  bool engineHasMapList = false;
75 
76  if (d->engine != nullptr)
77  {
78  setupModifiers(d->engine);
79  d->mapListPanel->setupForEngine(d->engine);
80  setupLimitWidgets(d->engine, d->gameMode);
81 
82  auto ecfg = d->engine->data();
83 
84  d->labelMaxClients->setVisible(ecfg->allowsClientSlots);
85  d->spinMaxClients->setVisible(ecfg->allowsClientSlots);
86  d->labelMaxPlayers->setVisible(ecfg->allowsPlayerSlots);
87  d->spinMaxPlayers->setVisible(ecfg->allowsPlayerSlots);
88 
89  // Remove hidden widgets to prevent creating extra spacing
90  // in the form layout.
91  d->hostingLimitsLayout->removeWidget(d->labelMaxClients);
92  d->hostingLimitsLayout->removeWidget(d->spinMaxClients);
93  d->hostingLimitsLayout->removeWidget(d->labelMaxPlayers);
94  d->hostingLimitsLayout->removeWidget(d->spinMaxPlayers);
95 
96  if (ecfg->allowsClientSlots)
97  d->hostingLimitsLayout->addRow(d->labelMaxClients, d->spinMaxClients);
98  if (ecfg->allowsPlayerSlots)
99  d->hostingLimitsLayout->addRow(d->labelMaxPlayers, d->spinMaxPlayers);
100 
101  engineAllowsSlotsLimits = ecfg->allowsClientSlots || ecfg->allowsPlayerSlots;
102  engineHasMapList = ecfg->hasMapList;
103  engineHasModifiers = !d->engine->gameModifiers().isEmpty();
104  }
105 
106  d->gameLimitsBox->setVisible(!d->limitWidgets.isEmpty());
107 
108  bool slotLimitsBoxAvailable = d->hostMode == GameCreateParams::Host && engineAllowsSlotsLimits;
109  d->hostLimitsBox->setVisible(slotLimitsBoxAvailable);
110  d->mapListBox->setVisible(engineHasMapList);
111 
112  d->anythingAvailable = !d->limitWidgets.isEmpty()
113  || engineHasModifiers
114  || engineHasMapList
115  || slotLimitsBoxAvailable;
116 }
117 
118 void GameRulesPanel::fillInParams(GameCreateParams &params)
119 {
120  params.setMaxClients(d->spinMaxClients->value());
121  params.setMaxPlayers(d->spinMaxPlayers->value());
122 
123  fillInLimits(params);
124  fillInModifiers(params);
125 
126  d->mapListPanel->fillInParams(params);
127 }
128 
129 void GameRulesPanel::fillInLimits(GameCreateParams &params)
130 {
131  for (PrivData<GameRulesPanel>::GameLimitWidget *p : d->limitWidgets)
132  {
133  p->limit.setValue(p->spinBox->value());
134  params.cvars() << p->limit;
135  }
136 }
137 
138 void GameRulesPanel::fillInModifiers(GameCreateParams &params)
139 {
140  int modIndex = d->cboModifier->currentIndex();
141  if (modIndex > 0) // Index zero is always "< NONE >"
142  {
143  --modIndex;
144  d->gameModifiers[modIndex].setValue(1);
145  params.cvars() << d->gameModifiers[modIndex];
146  }
147 }
148 
149 bool GameRulesPanel::isAnythingAvailable() const
150 {
151  return d->anythingAvailable;
152 }
153 
154 MapListPanel *GameRulesPanel::mapListPanel()
155 {
156  return d->mapListPanel;
157 }
158 
159 void GameRulesPanel::memorizeLimits()
160 {
161  if (d->engine != nullptr)
162  {
163  if (!d->memorizedLimits.contains(d->engine->nameCanonical()))
164  d->memorizedLimits[d->engine->nameCanonical()] = QMap<QString, int>();
165  QMap<QString, int> &limits = d->memorizedLimits[d->engine->nameCanonical()];
166  for (const PrivData<GameRulesPanel>::GameLimitWidget *limitWidget : d->limitWidgets)
167  {
168  limits[limitWidget->limit.command()] = limitWidget->spinBox->value();
169  }
170  }
171 }
172 
173 void GameRulesPanel::loadMemorizedLimits(const EnginePlugin *engine)
174 {
175  if (d->memorizedLimits.contains(engine->nameCanonical()))
176  {
177  QMap<QString, int> &limits = d->memorizedLimits[engine->nameCanonical()];
178  for (const PrivData<GameRulesPanel>::GameLimitWidget *limitWidget : d->limitWidgets)
179  {
180  if (limits.contains(limitWidget->limit.command()))
181  limitWidget->spinBox->setValue(limits[limitWidget->limit.command()]);
182  }
183  }
184 }
185 
186 void GameRulesPanel::loadConfig(Ini &config)
187 {
188  IniSection section = config.section("Rules");
189 
190  d->cboModifier->setCurrentIndex(section["modifier"]);
191  d->spinMaxClients->setValue(section["maxClients"]);
192  d->spinMaxPlayers->setValue(section["maxPlayers"]);
193  for (PrivData<GameRulesPanel>::GameLimitWidget *widget : d->limitWidgets)
194  {
195  widget->spinBox->setValue(section[widget->limit.command()]);
196  }
197 
198  d->mapListPanel->loadConfig(config);
199 }
200 
201 void GameRulesPanel::saveConfig(Ini &config)
202 {
203  IniSection section = config.section("Rules");
204 
205  section["modifier"] = d->cboModifier->currentIndex();
206  section["maxClients"] = d->spinMaxClients->value();
207  section["maxPlayers"] = d->spinMaxPlayers->value();
208  for (PrivData<GameRulesPanel>::GameLimitWidget *widget : d->limitWidgets)
209  {
210  section[widget->limit.command()] = widget->spinBox->value();
211  }
212 
213  d->mapListPanel->saveConfig(config);
214 }
215 
216 void GameRulesPanel::setCreateServerDialog(CreateServerDialog *dialog)
217 {
218  d->mapListPanel->setCreateServerDialog(dialog);
219 }
220 
221 void GameRulesPanel::setupForEngine(const EnginePlugin *engine, const GameMode &gameMode)
222 {
223  d->engine = engine;
224  d->gameMode = gameMode;
225  applyModeToUi();
226 }
227 
228 void GameRulesPanel::setupForHostMode(GameCreateParams::HostMode hostMode)
229 {
230  d->hostMode = hostMode;
231  applyModeToUi();
232 }
233 
234 void GameRulesPanel::setupModifiers(const EnginePlugin *engine)
235 {
236  QString selectedModifier = d->cboModifier->currentText();
237  d->cboModifier->clear();
238  d->gameModifiers.clear();
239 
240  QList<GameCVar> modifiers = engine->gameModifiers();
241 
242  if (!modifiers.isEmpty())
243  {
244  d->modifierBox->show();
245 
246  d->cboModifier->addItem(tr("< NONE >"));
247 
248  for (const GameCVar &cvar : modifiers)
249  {
250  d->cboModifier->addItem(cvar.name());
251  d->gameModifiers << cvar;
252  }
253  if (!selectedModifier.isEmpty())
254  {
255  int modifierIndex = d->cboModifier->findText(selectedModifier);
256  if (modifierIndex >= 0)
257  d->cboModifier->setCurrentIndex(modifierIndex);
258  }
259  }
260  else
261  {
262  d->modifierBox->hide();
263  }
264 }
265 
266 void GameRulesPanel::removeLimitWidgets()
267 {
268  for (PrivData<GameRulesPanel>::GameLimitWidget *widget : d->limitWidgets)
269  {
270  delete widget->label;
271  delete widget->spinBox;
272  delete widget;
273  }
274 
275  d->limitWidgets.clear();
276 }
277 
278 void GameRulesPanel::setupLimitWidgets(const EnginePlugin *engine, const GameMode &gameMode)
279 {
280  memorizeLimits();
281  removeLimitWidgets();
282  QList<GameCVar> limits = engine->limits(gameMode);
283 
284  for (const GameCVar &limit : limits)
285  {
286  QLabel *label = new QLabel(this);
287  label->setText(limit.name());
288  auto spinBox = new QSpinBox(this);
289  spinBox->setMaximum(INT_MAX);
290  spinBox->setMinimum(INT_MIN);
291  spinBox->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);
292  spinBox->setValue(limit.value().toInt());
293 
294  d->limitsLayout->addRow(label, spinBox);
295 
297  glw->label = label;
298  glw->spinBox = spinBox;
299  glw->limit = limit;
300  d->limitWidgets << glw;
301  }
302 
303  loadMemorizedLimits(engine);
304 }