1 /***************************************************************************
2  *      Mechanized Assault and Exploration Reloaded Projectfile            *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18  ***************************************************************************/
19 
20 #include <algorithm>
21 #include <cctype>
22 #include <cassert>
23 
24 #include "ui/graphical/menu/windows/windowgamesettings/gamesettings.h"
25 #include "utility/tounderlyingtype.h"
26 #include "utility/string/iequals.h"
27 #include "main.h"
28 #include "netmessage.h"
29 
30 const std::chrono::seconds cGameSettings::defaultTurnLimitOption0 (60);
31 const std::chrono::seconds cGameSettings::defaultTurnLimitOption1 (120);
32 const std::chrono::seconds cGameSettings::defaultTurnLimitOption2 (180);
33 const std::chrono::seconds cGameSettings::defaultTurnLimitOption3 (240);
34 const std::chrono::seconds cGameSettings::defaultTurnLimitOption4 (300);
35 const std::chrono::seconds cGameSettings::defaultTurnLimitOption5 (350);
36 
37 const std::chrono::seconds cGameSettings::defaultEndTurnDeadlineOption0 (15);
38 const std::chrono::seconds cGameSettings::defaultEndTurnDeadlineOption1 (30);
39 const std::chrono::seconds cGameSettings::defaultEndTurnDeadlineOption2 (45);
40 const std::chrono::seconds cGameSettings::defaultEndTurnDeadlineOption3 (60);
41 const std::chrono::seconds cGameSettings::defaultEndTurnDeadlineOption4 (75);
42 const std::chrono::seconds cGameSettings::defaultEndTurnDeadlineOption5 (90);
43 
44 //------------------------------------------------------------------------------
gameSettingsResourceAmountToString(eGameSettingsResourceAmount amount,bool translated)45 std::string gameSettingsResourceAmountToString (eGameSettingsResourceAmount amount, bool translated)
46 {
47 	if (translated)
48 	{
49 		switch (amount)
50 		{
51 			case eGameSettingsResourceAmount::Limited:
52 				return lngPack.i18n ("Text~Option~Limited");
53 			case eGameSettingsResourceAmount::Normal:
54 				return lngPack.i18n ("Text~Option~Normal");
55 			case eGameSettingsResourceAmount::High:
56 				return lngPack.i18n ("Text~Option~High");
57 			case eGameSettingsResourceAmount::TooMuch:
58 				return lngPack.i18n ("Text~Option~TooMuch");
59 		}
60 	}
61 	else
62 	{
63 		switch (amount)
64 		{
65 			case eGameSettingsResourceAmount::Limited:
66 				return "limited";
67 			case eGameSettingsResourceAmount::Normal:
68 				return "normal";
69 			case eGameSettingsResourceAmount::High:
70 				return "high";
71 			case eGameSettingsResourceAmount::TooMuch:
72 				return "toomuch";
73 		}
74 	}
75 	assert (false);
76 	return "";
77 }
78 
79 //------------------------------------------------------------------------------
gameSettingsResourceAmountFromString(const std::string & string)80 eGameSettingsResourceAmount gameSettingsResourceAmountFromString (const std::string& string)
81 {
82 	if (iequals (string, "limited")) return eGameSettingsResourceAmount::Limited;
83 	else if (iequals (string, "normal")) return eGameSettingsResourceAmount::Normal;
84 	else if (iequals (string, "high")) return eGameSettingsResourceAmount::High;
85 	else if (iequals (string, "toomuch")) return eGameSettingsResourceAmount::TooMuch;
86 	else throw std::runtime_error ("Invalid resource amount string '" + string + "'");
87 }
88 
89 //------------------------------------------------------------------------------
gameSettingsResourceDensityToString(eGameSettingsResourceDensity density,bool translated)90 std::string gameSettingsResourceDensityToString (eGameSettingsResourceDensity density, bool translated)
91 {
92 	if (translated)
93 	{
94 		switch (density)
95 		{
96 			case eGameSettingsResourceDensity::Sparse:
97 				return lngPack.i18n ("Text~Option~Sparse");
98 			case eGameSettingsResourceDensity::Normal:
99 				return lngPack.i18n ("Text~Option~Normal");
100 			case eGameSettingsResourceDensity::Dense:
101 				return lngPack.i18n ("Text~Option~Dense");
102 			case eGameSettingsResourceDensity::TooMuch:
103 				return lngPack.i18n ("Text~Option~TooMuch");
104 		}
105 	}
106 	else
107 	{
108 		switch (density)
109 		{
110 			case eGameSettingsResourceDensity::Sparse:
111 				return "sparse";
112 			case eGameSettingsResourceDensity::Normal:
113 				return "normal";
114 			case eGameSettingsResourceDensity::Dense:
115 				return "dense";
116 			case eGameSettingsResourceDensity::TooMuch:
117 				return "toomuch";
118 		}
119 	}
120 	assert (false);
121 	return "";
122 }
123 
124 //------------------------------------------------------------------------------
gameSettingsResourceDensityFromString(const std::string & string)125 eGameSettingsResourceDensity gameSettingsResourceDensityFromString (const std::string& string)
126 {
127 	if (iequals (string, "sparse")) return eGameSettingsResourceDensity::Sparse;
128 	else if (iequals (string, "normal")) return eGameSettingsResourceDensity::Normal;
129 	else if (iequals (string, "dense")) return eGameSettingsResourceDensity::Dense;
130 	else if (iequals (string, "toomuch")) return eGameSettingsResourceDensity::TooMuch;
131 	else throw std::runtime_error ("Invalid resource density string '" + string + "'");
132 }
133 
134 //------------------------------------------------------------------------------
gameSettingsBridgeheadTypeToString(eGameSettingsBridgeheadType type,bool translated)135 std::string gameSettingsBridgeheadTypeToString (eGameSettingsBridgeheadType type, bool translated)
136 {
137 	if (translated)
138 	{
139 		switch (type)
140 		{
141 			case eGameSettingsBridgeheadType::Definite:
142 				return lngPack.i18n ("Text~Option~Definite");
143 			case eGameSettingsBridgeheadType::Mobile:
144 				return lngPack.i18n ("Text~Option~Mobile");
145 		}
146 	}
147 	else
148 	{
149 		switch (type)
150 		{
151 			case eGameSettingsBridgeheadType::Definite:
152 				return "definite";
153 			case eGameSettingsBridgeheadType::Mobile:
154 				return "mobile";
155 		}
156 	}
157 	assert (false);
158 	return "";
159 }
160 
161 //------------------------------------------------------------------------------
gameSettingsBridgeheadTypeFromString(const std::string & string)162 eGameSettingsBridgeheadType gameSettingsBridgeheadTypeFromString (const std::string& string)
163 {
164 	if (iequals (string, "definite")) return eGameSettingsBridgeheadType::Definite;
165 	else if (iequals (string, "mobile")) return eGameSettingsBridgeheadType::Mobile;
166 	else throw std::runtime_error ("Invalid bridgehead type string '" + string + "'");
167 }
168 
169 //------------------------------------------------------------------------------
gameSettingsGameTypeToString(eGameSettingsGameType type,bool translated)170 std::string gameSettingsGameTypeToString (eGameSettingsGameType type, bool translated)
171 {
172 	if (translated)
173 	{
174 		switch (type)
175 		{
176 			case eGameSettingsGameType::Simultaneous:
177 				return lngPack.i18n ("Text~Option~Type_Simu");
178 			case eGameSettingsGameType::Turns:
179 				return lngPack.i18n ("Text~Option~Type_Turns");
180 			case eGameSettingsGameType::HotSeat:
181 				return "Hot Seat"; // TODO: translation?!
182 		}
183 	}
184 	else
185 	{
186 		switch (type)
187 		{
188 			case eGameSettingsGameType::Simultaneous:
189 				return "simultaneous";
190 			case eGameSettingsGameType::Turns:
191 				return "turns";
192 			case eGameSettingsGameType::HotSeat:
193 				return "hotseat";
194 		}
195 	}
196 	assert (false);
197 	return "";
198 }
199 
200 //------------------------------------------------------------------------------
gameSettingsGameTypeString(const std::string & string)201 eGameSettingsGameType gameSettingsGameTypeString (const std::string& string)
202 {
203 	if (iequals (string, "simultaneous")) return eGameSettingsGameType::Simultaneous;
204 	else if (iequals (string, "turns")) return eGameSettingsGameType::Turns;
205 	else if (iequals (string, "hotseat")) return eGameSettingsGameType::HotSeat;
206 	else throw std::runtime_error ("Invalid game type string '" + string + "'");
207 }
208 
209 //------------------------------------------------------------------------------
gameSettingsVictoryConditionToString(eGameSettingsVictoryCondition condition,bool translated)210 std::string gameSettingsVictoryConditionToString (eGameSettingsVictoryCondition condition, bool translated)
211 {
212 	if (translated)
213 	{
214 		switch (condition)
215 		{
216 			case eGameSettingsVictoryCondition::Turns:
217 				return lngPack.i18n ("Text~Comp~Turns");
218 			case eGameSettingsVictoryCondition::Points:
219 				return lngPack.i18n ("Text~Comp~Points");
220 			case eGameSettingsVictoryCondition::Death:
221 				return lngPack.i18n ("Text~Comp~NoLimit");
222 		}
223 	}
224 	else
225 	{
226 		switch (condition)
227 		{
228 			case eGameSettingsVictoryCondition::Turns:
229 				return "turns";
230 			case eGameSettingsVictoryCondition::Points:
231 				return "points";
232 			case eGameSettingsVictoryCondition::Death:
233 				return "death";
234 		}
235 	}
236 	assert (false);
237 	return "";
238 }
239 
240 //------------------------------------------------------------------------------
gameSettingsVictoryConditionFromString(const std::string & string)241 eGameSettingsVictoryCondition gameSettingsVictoryConditionFromString (const std::string& string)
242 {
243 	if (iequals (string, "turns")) return eGameSettingsVictoryCondition::Turns;
244 	else if (iequals (string, "points")) return eGameSettingsVictoryCondition::Points;
245 	else if (iequals (string, "death")) return eGameSettingsVictoryCondition::Death;
246 	else throw std::runtime_error ("Invalid victory condition string '" + string + "'");
247 }
248 
249 //------------------------------------------------------------------------------
cGameSettings()250 cGameSettings::cGameSettings() :
251 	metalAmount (eGameSettingsResourceAmount::Normal),
252 	oilAmount (eGameSettingsResourceAmount::Normal),
253 	goldAmount (eGameSettingsResourceAmount::Normal),
254 	resourceDensity (eGameSettingsResourceDensity::Normal),
255 	bridgeheadType (eGameSettingsBridgeheadType::Definite),
256 	gameType (eGameSettingsGameType::Simultaneous),
257 	clansEnabled (true),
258 	startCredits (defaultCreditsNormal),
259 	victoryConditionType (eGameSettingsVictoryCondition::Death),
260 	victoryTurns (defaultVictoryTurnsOption2),
261 	victoryPoints (defaultVictoryPointsOption2),
262 	turnEndDeadline (defaultEndTurnDeadlineOption5),
263 	turnEndDeadlineActive (true),
264 	turnLimit (defaultTurnLimitOption5),
265 	turnLimitActive (false)
266 {}
267 
268 //------------------------------------------------------------------------------
cGameSettings(const cGameSettings & other)269 cGameSettings::cGameSettings (const cGameSettings& other) :
270 	metalAmount (other.metalAmount),
271 	oilAmount (other.oilAmount),
272 	goldAmount (other.goldAmount),
273 	resourceDensity (other.resourceDensity),
274 	bridgeheadType (other.bridgeheadType),
275 	gameType (other.gameType),
276 	clansEnabled (other.clansEnabled),
277 	startCredits (other.startCredits),
278 	victoryConditionType (other.victoryConditionType),
279 	victoryTurns (other.victoryTurns),
280 	victoryPoints (other.victoryPoints),
281 	turnEndDeadline (other.turnEndDeadline),
282 	turnEndDeadlineActive (other.turnEndDeadlineActive),
283 	turnLimit (other.turnLimit),
284 	turnLimitActive (other.turnLimitActive)
285 {}
286 
287 //------------------------------------------------------------------------------
operator =(const cGameSettings & other)288 cGameSettings& cGameSettings::operator= (const cGameSettings& other)
289 {
290 	metalAmount = other.metalAmount;
291 	oilAmount = other.oilAmount;
292 	goldAmount = other.goldAmount;
293 	resourceDensity = other.resourceDensity;
294 	bridgeheadType = other.bridgeheadType;
295 	gameType = other.gameType;
296 	clansEnabled = other.clansEnabled;
297 	startCredits = other.startCredits;
298 	victoryConditionType = other.victoryConditionType;
299 	victoryTurns = other.victoryTurns;
300 	victoryPoints = other.victoryPoints;
301 	turnEndDeadline = other.turnEndDeadline;
302 	turnEndDeadlineActive = other.turnEndDeadlineActive;
303 	turnLimit = other.turnLimit;
304 	turnLimitActive = other.turnLimitActive;
305 
306 	return *this;
307 }
308 
309 //------------------------------------------------------------------------------
getMetalAmount() const310 eGameSettingsResourceAmount cGameSettings::getMetalAmount() const
311 {
312 	return metalAmount;
313 }
314 
315 //------------------------------------------------------------------------------
setMetalAmount(eGameSettingsResourceAmount value)316 void cGameSettings::setMetalAmount (eGameSettingsResourceAmount value)
317 {
318 	std::swap (metalAmount, value);
319 	if (metalAmount != value) metalAmountChanged();
320 }
321 
322 //------------------------------------------------------------------------------
getOilAmount() const323 eGameSettingsResourceAmount cGameSettings::getOilAmount() const
324 {
325 	return oilAmount;
326 }
327 
328 //------------------------------------------------------------------------------
setOilAmount(eGameSettingsResourceAmount value)329 void cGameSettings::setOilAmount (eGameSettingsResourceAmount value)
330 {
331 	std::swap (oilAmount, value);
332 	if (oilAmount != value) oilAmountChanged();
333 }
334 
335 //------------------------------------------------------------------------------
getGoldAmount() const336 eGameSettingsResourceAmount cGameSettings::getGoldAmount() const
337 {
338 	return goldAmount;
339 }
340 
341 //------------------------------------------------------------------------------
setGoldAmount(eGameSettingsResourceAmount value)342 void cGameSettings::setGoldAmount (eGameSettingsResourceAmount value)
343 {
344 	std::swap (goldAmount, value);
345 	if (goldAmount != value) goldAmountChanged();
346 }
347 
348 //------------------------------------------------------------------------------
getResourceDensity() const349 eGameSettingsResourceDensity cGameSettings::getResourceDensity() const
350 {
351 	return resourceDensity;
352 }
353 
354 //------------------------------------------------------------------------------
setResourceDensity(eGameSettingsResourceDensity value)355 void cGameSettings::setResourceDensity (eGameSettingsResourceDensity value)
356 {
357 	std::swap (resourceDensity, value);
358 	if (resourceDensity != value) resourceDensityChanged();
359 }
360 
361 //------------------------------------------------------------------------------
getBridgeheadType() const362 eGameSettingsBridgeheadType cGameSettings::getBridgeheadType() const
363 {
364 	return bridgeheadType;
365 }
366 
367 //------------------------------------------------------------------------------
setBridgeheadType(eGameSettingsBridgeheadType value)368 void cGameSettings::setBridgeheadType (eGameSettingsBridgeheadType value)
369 {
370 	std::swap (bridgeheadType, value);
371 	if (bridgeheadType != value) bridgeheadTypeChanged();
372 }
373 
374 //------------------------------------------------------------------------------
getGameType() const375 eGameSettingsGameType cGameSettings::getGameType() const
376 {
377 	return gameType;
378 }
379 
380 //------------------------------------------------------------------------------
setGameType(eGameSettingsGameType value)381 void cGameSettings::setGameType (eGameSettingsGameType value)
382 {
383 	std::swap (gameType, value);
384 	if (gameType != value) gameTypeChanged();
385 }
386 
387 //------------------------------------------------------------------------------
getClansEnabled() const388 bool cGameSettings::getClansEnabled() const
389 {
390 	return clansEnabled;
391 }
392 
393 //------------------------------------------------------------------------------
setClansEnabled(bool value)394 void cGameSettings::setClansEnabled (bool value)
395 {
396 	std::swap (clansEnabled, value);
397 	if (clansEnabled != value) clansEnabledChanged();
398 }
399 
400 //------------------------------------------------------------------------------
getStartCredits() const401 unsigned int cGameSettings::getStartCredits() const
402 {
403 	return startCredits;
404 }
405 
406 //------------------------------------------------------------------------------
setStartCredits(unsigned int value)407 void cGameSettings::setStartCredits (unsigned int value)
408 {
409 	std::swap (startCredits, value);
410 	if (startCredits != value) startCreditsChanged();
411 }
412 
413 //------------------------------------------------------------------------------
getVictoryCondition() const414 eGameSettingsVictoryCondition cGameSettings::getVictoryCondition() const
415 {
416 	return victoryConditionType;
417 }
418 
419 //------------------------------------------------------------------------------
setVictoryCondition(eGameSettingsVictoryCondition value)420 void cGameSettings::setVictoryCondition (eGameSettingsVictoryCondition value)
421 {
422 	std::swap (victoryConditionType, value);
423 	if (victoryConditionType != value) victoryConditionTypeChanged();
424 }
425 
426 //------------------------------------------------------------------------------
getVictoryTurns() const427 unsigned int cGameSettings::getVictoryTurns() const
428 {
429 	return victoryTurns;
430 }
431 
432 //------------------------------------------------------------------------------
setVictoryTurns(unsigned int value)433 void cGameSettings::setVictoryTurns (unsigned int value)
434 {
435 	std::swap (victoryTurns, value);
436 	if (victoryTurns != value) victoryTurnsChanged();
437 }
438 
439 //------------------------------------------------------------------------------
getVictoryPoints() const440 unsigned int cGameSettings::getVictoryPoints() const
441 {
442 	return victoryPoints;
443 }
444 
445 //------------------------------------------------------------------------------
setVictoryPoints(unsigned int value)446 void cGameSettings::setVictoryPoints (unsigned int value)
447 {
448 	std::swap (victoryPoints, value);
449 	if (victoryPoints != value) victoryPointsChanged();
450 }
451 
452 //------------------------------------------------------------------------------
getTurnEndDeadline() const453 const std::chrono::seconds& cGameSettings::getTurnEndDeadline() const
454 {
455 	return turnEndDeadline;
456 }
457 
458 //------------------------------------------------------------------------------
setTurnEndDeadline(const std::chrono::seconds & value)459 void cGameSettings::setTurnEndDeadline (const std::chrono::seconds& value)
460 {
461 	const auto oldValue = turnEndDeadline;
462 	turnEndDeadline = value;
463 	if (oldValue != turnEndDeadline) turnEndDeadlineChanged();
464 }
465 
466 //------------------------------------------------------------------------------
isTurnEndDeadlineActive() const467 bool cGameSettings::isTurnEndDeadlineActive() const
468 {
469 	return turnEndDeadlineActive;
470 }
471 
472 //------------------------------------------------------------------------------
setTurnEndDeadlineActive(bool value)473 void cGameSettings::setTurnEndDeadlineActive (bool value)
474 {
475 	std::swap (turnEndDeadlineActive, value);
476 	if (turnEndDeadlineActive != value) turnEndDeadlineActiveChanged();
477 }
478 
479 //------------------------------------------------------------------------------
getTurnLimit() const480 const std::chrono::seconds& cGameSettings::getTurnLimit() const
481 {
482 	return turnLimit;
483 }
484 
485 //------------------------------------------------------------------------------
setTurnLimit(const std::chrono::seconds & value)486 void cGameSettings::setTurnLimit (const std::chrono::seconds& value)
487 {
488 	const auto oldValue = turnLimit;
489 	turnLimit = value;
490 	if (oldValue != turnLimit) turnLimitChanged();
491 }
492 
493 //------------------------------------------------------------------------------
isTurnLimitActive() const494 bool cGameSettings::isTurnLimitActive() const
495 {
496 	return turnLimitActive;
497 }
498 
499 //------------------------------------------------------------------------------
setTurnLimitActive(bool value)500 void cGameSettings::setTurnLimitActive (bool value)
501 {
502 	std::swap (turnLimitActive, value);
503 	if (turnLimitActive != value) turnLimitActiveChanged();
504 }
505 
506 //------------------------------------------------------------------------------
pushInto(cNetMessage & message) const507 void cGameSettings::pushInto (cNetMessage& message) const
508 {
509 	message.pushInt32 (toUnderlyingType (metalAmount));
510 	message.pushInt32 (toUnderlyingType (oilAmount));
511 	message.pushInt32 (toUnderlyingType (goldAmount));
512 
513 	message.pushInt32 (toUnderlyingType (resourceDensity));
514 
515 	message.pushInt32 (toUnderlyingType (bridgeheadType));
516 
517 	message.pushInt32 (toUnderlyingType (gameType));
518 
519 	message.pushBool (clansEnabled);
520 
521 	message.pushInt32 (startCredits);
522 
523 	message.pushInt32 (toUnderlyingType (victoryConditionType));
524 	message.pushInt32 (victoryTurns);
525 	message.pushInt32 (victoryPoints);
526 
527 	message.pushInt32 (turnEndDeadline.count());
528 	message.pushBool (turnEndDeadlineActive);
529 
530 	message.pushInt32 (turnLimit.count());
531 	message.pushBool (turnLimitActive);
532 }
533 
534 //------------------------------------------------------------------------------
popFrom(cNetMessage & message)535 void cGameSettings::popFrom (cNetMessage& message)
536 {
537 	setTurnLimitActive (message.popBool());
538 	setTurnLimit (std::chrono::seconds (message.popInt32()));
539 
540 	setTurnEndDeadlineActive (message.popBool());
541 	setTurnEndDeadline (std::chrono::seconds (message.popInt32()));
542 
543 	setVictoryPoints (message.popInt32());
544 	setVictoryTurns (message.popInt32());
545 	setVictoryCondition (static_cast<eGameSettingsVictoryCondition> (message.popInt32()));
546 
547 	setStartCredits (message.popInt32());
548 
549 	setClansEnabled (message.popBool());
550 
551 	setGameType (static_cast<eGameSettingsGameType> (message.popInt32()));
552 
553 	setBridgeheadType (static_cast<eGameSettingsBridgeheadType> (message.popInt32()));
554 
555 	setResourceDensity (static_cast<eGameSettingsResourceDensity> (message.popInt32()));
556 
557 	setGoldAmount (static_cast<eGameSettingsResourceAmount> (message.popInt32()));
558 	setOilAmount (static_cast<eGameSettingsResourceAmount> (message.popInt32()));
559 	setMetalAmount (static_cast<eGameSettingsResourceAmount> (message.popInt32()));
560 }
561