1 /*
2 * Copyright (C) 2011-2016 OpenDungeons Team
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 3 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, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "utils/ConfigManager.h"
19
20 #include "entities/CreatureDefinition.h"
21 #include "entities/Tile.h"
22 #include "entities/Weapon.h"
23 #include "game/Skill.h"
24 #include "gamemap/TileSet.h"
25 #include "spawnconditions/SpawnCondition.h"
26 #include "utils/Helper.h"
27 #include "utils/LogManager.h"
28
29 #include <boost/dynamic_bitset.hpp>
30 #include <OgreRoot.h>
31
32 const std::vector<std::string> EMPTY_SPAWNPOOL;
33 const std::string EMPTY_STRING;
34 const Ogre::ColourValue DEFAULT_SEAT_COLOURVALUE;
35 const std::string ConfigManager::DEFAULT_TILESET_NAME = "Default";
36
37 const std::string ConfigManager::DEFAULT_KEEPER_VOICE = "Default";
38
39 const std::string ConfigManager::DefaultWorkerCreatureDefinition = "DefaultWorker";
40
41 template<> ConfigManager* Ogre::Singleton<ConfigManager>::msSingleton = nullptr;
42
ConfigManager(const std::string & configPath,const std::string & userConfigPath,const std::string & soundPath)43 ConfigManager::ConfigManager(const std::string& configPath, const std::string& userConfigPath,
44 const std::string& soundPath) :
45 mNetworkPort(0),
46 mClientConnectionTimeout(5000),
47 mBaseSpawnPoint(10),
48 mCreatureDeathCounter(10),
49 mMaxCreaturesPerSeatAbsolute(30),
50 mMaxCreaturesPerSeatDefault(10),
51 mCreatureBaseMood(1000),
52 mCreatureMoodHappy(1200),
53 mCreatureMoodUpset(0),
54 mCreatureMoodAngry(-1000),
55 mCreatureMoodFurious(-2000),
56 mSlapDamagePercent(15),
57 mSlapEffectDuration(15),
58 mTimePayDay(300),
59 mNbTurnsFuriousMax(120),
60 mMaxManaPerSeat(250000.0),
61 mClaimingWallPenalty(0.8),
62 mDigCoefGold(5.0),
63 mDigCoefGem(1.0),
64 mDigCoefClaimedWall(0.5),
65 mNbTurnsKoCreatureAttacked(10),
66 mCreatureDefinitionDefaultWorker(nullptr),
67 mNbWorkersDigSameFaceTile(2),
68 mNbWorkersClaimSameTile(1)
69 {
70 // TODO: it might be better to go through the creature definitions and try to pickup the first worker we can find
71 mCreatureDefinitionDefaultWorker = new CreatureDefinition(DefaultWorkerCreatureDefinition,
72 CreatureDefinition::CreatureJob::Worker, "Kobold.mesh");
73 if(!loadGlobalConfig(configPath))
74 {
75 OD_LOG_ERR("Couldn't read loadCreatureDefinitions");
76 exit(1);
77 }
78 std::string fileName = configPath + mFilenameCreatureDefinition;
79 if(!loadCreatureDefinitions(fileName))
80 {
81 OD_LOG_ERR("Couldn't read loadCreatureDefinitions");
82 exit(1);
83 }
84 fileName = configPath + mFilenameEquipmentDefinition;
85 if(!loadEquipements(fileName))
86 {
87 OD_LOG_ERR("Couldn't read loadEquipements");
88 exit(1);
89 }
90 fileName = configPath + mFilenameSpawnConditions;
91 if(!loadSpawnConditions(fileName))
92 {
93 OD_LOG_ERR("Couldn't read loadSpawnConditions");
94 exit(1);
95 }
96 fileName = configPath + mFilenameFactions;
97 if(!loadFactions(fileName))
98 {
99 OD_LOG_ERR("Couldn't read loadFactions");
100 exit(1);
101 }
102 fileName = configPath + mFilenameRooms;
103 if(!loadRooms(fileName))
104 {
105 OD_LOG_ERR("Couldn't read loadRooms");
106 exit(1);
107 }
108 fileName = configPath + mFilenameTraps;
109 if(!loadTraps(fileName))
110 {
111 OD_LOG_ERR("Couldn't read loadTraps");
112 exit(1);
113 }
114 fileName = configPath + mFilenameSpells;
115 if(!loadSpellConfig(fileName))
116 {
117 OD_LOG_ERR("Couldn't read loadSpellConfig");
118 exit(1);
119 }
120 fileName = configPath + mFilenameSkills;
121 if(!loadSkills(fileName))
122 {
123 OD_LOG_ERR("Couldn't read loadSkills");
124 exit(1);
125 }
126 fileName = configPath + mFilenameTilesets;
127 if(!loadTilesets(fileName))
128 {
129 OD_LOG_ERR("Couldn't read loadTilesets");
130 exit(1);
131 }
132
133 // Reserve space in any case.
134 mUserConfig.resize(Config::Ctg::TOTAL);
135
136 if (!userConfigPath.empty())
137 loadUserConfig(userConfigPath);
138
139 loadKeeperVoices(soundPath);
140 }
141
~ConfigManager()142 ConfigManager::~ConfigManager()
143 {
144 for(auto pair : mCreatureDefs)
145 {
146 delete pair.second;
147 }
148
149 if(mCreatureDefinitionDefaultWorker != nullptr)
150 delete mCreatureDefinitionDefaultWorker;
151
152 for(const Weapon* def : mWeapons)
153 {
154 delete def;
155 }
156 mWeapons.clear();
157
158 for(std::pair<const CreatureDefinition*, std::vector<const SpawnCondition*>> p : mCreatureSpawnConditions)
159 {
160 for(const SpawnCondition* spawnCondition : p.second)
161 {
162 delete spawnCondition;
163 }
164 }
165 mCreatureSpawnConditions.clear();
166
167 for(std::pair<const std::string, const TileSet*> p : mTileSets)
168 {
169 delete p.second;
170 }
171 mTileSets.clear();
172 }
173
loadGlobalConfig(const std::string & configPath)174 bool ConfigManager::loadGlobalConfig(const std::string& configPath)
175 {
176 std::stringstream configFile;
177 std::string fileName = configPath + "global.cfg";
178 if(!Helper::readFileWithoutComments(fileName, configFile))
179 {
180 OD_LOG_ERR("Couldn't read " + fileName);
181 return false;
182 }
183
184 std::string nextParam;
185 uint32_t paramsOk = 0;
186 while(configFile.good())
187 {
188 if(!(configFile >> nextParam))
189 break;
190
191 if(nextParam == "[SeatColors]")
192 {
193 if(!loadGlobalConfigSeatColors(configFile))
194 break;
195
196 paramsOk |= 1;
197 continue;
198 }
199
200 if(nextParam == "[ConfigFiles]")
201 {
202 if(!loadGlobalConfigDefinitionFiles(configFile))
203 break;
204
205 paramsOk |= 2;
206 continue;
207 }
208
209 if(nextParam == "[GameConfig]")
210 {
211 if(!loadGlobalGameConfig(configFile))
212 break;
213
214 paramsOk |= 4;
215 continue;
216 }
217 }
218
219 if(paramsOk != 0x07)
220 {
221 OD_LOG_ERR("Not enough parameters for config file paramsOk=" + Helper::toString(paramsOk));
222 return false;
223 }
224
225 return true;
226 }
227
loadGlobalConfigDefinitionFiles(std::stringstream & configFile)228 bool ConfigManager::loadGlobalConfigDefinitionFiles(std::stringstream& configFile)
229 {
230 std::string nextParam;
231 uint32_t filesOk = 0;
232 while(configFile.good())
233 {
234 if(!(configFile >> nextParam))
235 break;
236
237 if(nextParam == "[/ConfigFiles]")
238 break;
239
240 if(nextParam != "[ConfigFile]")
241 {
242 OD_LOG_ERR("Wrong parameter read nextParam=" + nextParam);
243 return false;
244 }
245
246 uint32_t paramsOk = 0;
247 std::string type;
248 std::string fileName;
249 while(configFile.good())
250 {
251 if(!(configFile >> nextParam))
252 break;
253
254 if(nextParam == "[/ConfigFile]")
255 {
256 break;
257 }
258
259 if(nextParam == "Type")
260 {
261 configFile >> type;
262 paramsOk |= 0x01;
263 continue;
264 }
265
266 if(nextParam == "Filename")
267 {
268 configFile >> fileName;
269 paramsOk |= 0x02;
270 continue;
271 }
272 }
273
274 if(paramsOk != 0x03)
275 {
276 OD_LOG_ERR("Missing parameters paramsOk=" + Helper::toString(paramsOk));
277 return false;
278 }
279
280 if(type == "Creatures")
281 {
282 mFilenameCreatureDefinition = fileName;
283 filesOk |= 1;
284 }
285 else if(type == "Equipments")
286 {
287 mFilenameEquipmentDefinition = fileName;
288 filesOk |= 2;
289 }
290 else if(type == "SpawnConditions")
291 {
292 mFilenameSpawnConditions = fileName;
293 filesOk |= 4;
294 }
295 else if(type == "Factions")
296 {
297 mFilenameFactions = fileName;
298 filesOk |= 8;
299 }
300 else if(type == "Rooms")
301 {
302 mFilenameRooms = fileName;
303 filesOk |= 0x10;
304 }
305 else if(type == "Traps")
306 {
307 mFilenameTraps = fileName;
308 filesOk |= 0x20;
309 }
310 else if(type == "Spells")
311 {
312 mFilenameSpells = fileName;
313 filesOk |= 0x40;
314 }
315 else if(type == "Skills")
316 {
317 mFilenameSkills = fileName;
318 filesOk |= 0x080;
319 }
320 else if(type == "Tilesets")
321 {
322 mFilenameTilesets = fileName;
323 filesOk |= 0x100;
324 }
325 }
326
327 if(filesOk != 0x1FF)
328 {
329 OD_LOG_ERR("Missing parameter file filesOk=" + Helper::toString(filesOk));
330 return false;
331 }
332
333 return true;
334 }
335
loadGlobalConfigSeatColors(std::stringstream & configFile)336 bool ConfigManager::loadGlobalConfigSeatColors(std::stringstream& configFile)
337 {
338 std::string nextParam;
339 while(configFile.good())
340 {
341 if(!(configFile >> nextParam))
342 break;
343
344 if(nextParam == "[/SeatColors]")
345 break;
346
347 if(nextParam != "[SeatColor]")
348 {
349 OD_LOG_ERR("Wrong parameter read nextParam=" + nextParam);
350 return false;
351 }
352
353 uint32_t paramsOk = 0;
354 std::string id;
355 Ogre::ColourValue colourValue;
356 while(configFile.good())
357 {
358 if(!(configFile >> nextParam))
359 break;
360
361 if(nextParam == "[/SeatColor]")
362 {
363 break;
364 }
365
366 if(nextParam == "ID")
367 {
368 configFile >> id;
369 paramsOk |= 0x01;
370 continue;
371 }
372
373 if(nextParam == "ColorR")
374 {
375 configFile >> nextParam;
376 double v = Helper::toDouble(nextParam);
377 if(v < 0.0 || v > 1.0)
378 {
379 OD_LOG_ERR("Wrong parameter read nextParam=" + nextParam);
380 return false;
381 }
382 colourValue.r = v;
383 paramsOk |= 0x02;
384 continue;
385 }
386
387 if(nextParam == "ColorG")
388 {
389 configFile >> nextParam;
390 double v = Helper::toDouble(nextParam);
391 if(v < 0.0 || v > 1.0)
392 {
393 OD_LOG_ERR("Wrong parameter read nextParam=" + nextParam);
394 return false;
395 }
396 colourValue.g = v;
397 paramsOk |= 0x04;
398 continue;
399 }
400
401 if(nextParam == "ColorB")
402 {
403 configFile >> nextParam;
404 double v = Helper::toDouble(nextParam);
405 if(v < 0.0 || v > 1.0)
406 {
407 OD_LOG_ERR("Wrong parameter read nextParam=" + nextParam);
408 return false;
409 }
410 colourValue.b = v;
411 paramsOk |= 0x08;
412 continue;
413 }
414 }
415
416 if(paramsOk != 0x0F)
417 {
418 OD_LOG_ERR("Missing parameters paramsOk=" + Helper::toString(paramsOk));
419 return false;
420 }
421
422 mSeatColors[id] = colourValue;
423 }
424
425 return true;
426 }
427
loadGlobalGameConfig(std::stringstream & configFile)428 bool ConfigManager::loadGlobalGameConfig(std::stringstream& configFile)
429 {
430 std::string nextParam;
431 uint32_t paramsOk = 0;
432 while(configFile.good())
433 {
434 if(!(configFile >> nextParam))
435 break;
436
437 if(nextParam == "[/GameConfig]")
438 break;
439
440 if(nextParam == "NetworkPort")
441 {
442 configFile >> nextParam;
443 mNetworkPort = Helper::toUInt32(nextParam);
444 paramsOk |= 1;
445 }
446
447 if(nextParam == "ClientConnectionTimeout")
448 {
449 configFile >> nextParam;
450 mClientConnectionTimeout = Helper::toUInt32(nextParam);
451 // Not mandatory
452 }
453
454 if(nextParam == "CreatureDeathCounter")
455 {
456 configFile >> nextParam;
457 mCreatureDeathCounter = Helper::toUInt32(nextParam);
458 // Not mandatory
459 }
460
461 if(nextParam == "MaxCreaturesPerSeatAbsolute")
462 {
463 configFile >> nextParam;
464 mMaxCreaturesPerSeatAbsolute = Helper::toUInt32(nextParam);
465 // Not mandatory
466 }
467
468 if(nextParam == "MaxCreaturesPerSeatDefault")
469 {
470 configFile >> nextParam;
471 mMaxCreaturesPerSeatDefault = Helper::toUInt32(nextParam);
472 // Not mandatory
473 }
474
475 if(nextParam == "SlapDamagePercent")
476 {
477 configFile >> nextParam;
478 mSlapDamagePercent = Helper::toDouble(nextParam);
479 // Not mandatory
480 }
481
482 if(nextParam == "SlapEffectDuration")
483 {
484 configFile >> nextParam;
485 mSlapEffectDuration = Helper::toDouble(nextParam);
486 // Not mandatory
487 }
488
489 if(nextParam == "TimePayDay")
490 {
491 configFile >> nextParam;
492 mTimePayDay = Helper::toInt(nextParam);
493 // Not mandatory
494 }
495
496 if(nextParam == "NbTurnsFuriousMax")
497 {
498 configFile >> nextParam;
499 mNbTurnsFuriousMax = Helper::toInt(nextParam);
500 // Not mandatory
501 }
502
503 if(nextParam == "MaxManaPerSeat")
504 {
505 configFile >> nextParam;
506 mMaxManaPerSeat = Helper::toDouble(nextParam);
507 // Not mandatory
508 }
509
510 if(nextParam == "ClaimingWallPenalty")
511 {
512 configFile >> nextParam;
513 mClaimingWallPenalty = Helper::toDouble(nextParam);
514 // Not mandatory
515 }
516
517 if(nextParam == "DigCoefGold")
518 {
519 configFile >> nextParam;
520 mDigCoefGold = Helper::toDouble(nextParam);
521 // Not mandatory
522 }
523
524 if(nextParam == "DigCoefGem")
525 {
526 configFile >> nextParam;
527 mDigCoefGem = Helper::toDouble(nextParam);
528 // Not mandatory
529 }
530
531 if(nextParam == "DigCoefClaimedWall")
532 {
533 configFile >> nextParam;
534 mDigCoefClaimedWall = Helper::toDouble(nextParam);
535 // Not mandatory
536 }
537
538 if(nextParam == "CreatureBaseMood")
539 {
540 configFile >> nextParam;
541 mCreatureBaseMood = Helper::toInt(nextParam);
542 // Not mandatory
543 }
544
545 if(nextParam == "CreatureMoodHappy")
546 {
547 configFile >> nextParam;
548 mCreatureMoodHappy = Helper::toInt(nextParam);
549 // Not mandatory
550 }
551
552 if(nextParam == "CreatureMoodUpset")
553 {
554 configFile >> nextParam;
555 mCreatureMoodUpset = Helper::toInt(nextParam);
556 // Not mandatory
557 }
558
559 if(nextParam == "CreatureMoodAngry")
560 {
561 configFile >> nextParam;
562 mCreatureMoodAngry = Helper::toInt(nextParam);
563 // Not mandatory
564 }
565
566 if(nextParam == "CreatureMoodFurious")
567 {
568 configFile >> nextParam;
569 mCreatureMoodFurious = Helper::toInt(nextParam);
570 // Not mandatory
571 }
572
573 if(nextParam == "NbWorkersDigSameFaceTile")
574 {
575 configFile >> nextParam;
576 mNbWorkersDigSameFaceTile = Helper::toUInt32(nextParam);
577 // Not mandatory
578 }
579
580 if(nextParam == "NbWorkersClaimSameTile")
581 {
582 configFile >> nextParam;
583 mNbWorkersClaimSameTile = Helper::toUInt32(nextParam);
584 // Not mandatory
585 }
586
587 if(nextParam == "NbTurnsKoCreatureAttacked")
588 {
589 configFile >> nextParam;
590 mNbTurnsKoCreatureAttacked = Helper::toInt(nextParam);
591 // Not mandatory
592 }
593
594 if(nextParam == "MainMenuMusic")
595 {
596 std::string line;
597 std::getline(configFile, line);
598 std::vector<std::string> elements = Helper::split(line, '\t', true);
599 if (elements.empty())
600 {
601 OD_LOG_WRN("Invalid MainMenuMusic : " + line);
602 continue;
603 }
604 mMainMenuMusic = elements[0];
605 // Not mandatory
606 }
607
608 if(nextParam == "MasterServerUrl")
609 {
610 configFile >> mMasterServerUrl;
611 // Not mandatory
612 }
613 }
614
615 if(paramsOk != 0x01)
616 {
617 OD_LOG_ERR("Missing parameters paramsOk=" + Helper::toString(paramsOk));
618 return false;
619 }
620
621 return true;
622 }
623
loadCreatureDefinitions(const std::string & fileName)624 bool ConfigManager::loadCreatureDefinitions(const std::string& fileName)
625 {
626 OD_LOG_INF("Load creature definition file: " + fileName);
627 std::stringstream defFile;
628 if(!Helper::readFileWithoutComments(fileName, defFile))
629 {
630 OD_LOG_ERR("Couldn't read " + fileName);
631 return false;
632 }
633
634 std::string nextParam;
635 // Read in the creature class descriptions
636 defFile >> nextParam;
637 if (nextParam != "[CreatureDefinitions]")
638 {
639 OD_LOG_ERR("Invalid Creature classes start format. Line was " + nextParam);
640 return false;
641 }
642
643 while(defFile.good())
644 {
645 if(!(defFile >> nextParam))
646 break;
647
648 if (nextParam == "[/CreatureDefinitions]")
649 break;
650
651 if (nextParam == "[/Creature]")
652 continue;
653
654 // Seek the [Creature] tag
655 if (nextParam != "[Creature]")
656 {
657 OD_LOG_ERR("Invalid Creature classes start format. Line was " + nextParam);
658 return false;
659 }
660
661 // Load the creature definition until a [/Creature] tag is found
662 CreatureDefinition* creatureDef = CreatureDefinition::load(defFile, mCreatureDefs);
663 if (creatureDef == nullptr)
664 {
665 OD_LOG_ERR("Invalid Creature classes start format");
666 return false;
667 }
668 mCreatureDefs.emplace(creatureDef->getClassName(), creatureDef);
669 }
670
671 return true;
672 }
673
loadEquipements(const std::string & fileName)674 bool ConfigManager::loadEquipements(const std::string& fileName)
675 {
676 OD_LOG_INF("Load weapon definition file: " + fileName);
677 std::stringstream defFile;
678 if(!Helper::readFileWithoutComments(fileName, defFile))
679 {
680 OD_LOG_ERR("Couldn't read " + fileName);
681 return false;
682 }
683
684 std::string nextParam;
685 // Read in the creature class descriptions
686 defFile >> nextParam;
687 if (nextParam != "[EquipmentDefinitions]")
688 {
689 OD_LOG_ERR("Invalid weapon start format. Line was " + nextParam);
690 return false;
691 }
692
693 while(defFile.good())
694 {
695 if(!(defFile >> nextParam))
696 break;
697
698 if (nextParam == "[/EquipmentDefinitions]")
699 break;
700
701 if (nextParam == "[/Equipment]")
702 continue;
703
704 if (nextParam != "[Equipment]")
705 {
706 OD_LOG_ERR("Invalid Weapon definition format. Line was " + nextParam);
707 return false;
708 }
709
710 // Load the definition
711 Weapon* weapon = Weapon::load(defFile);
712 if (weapon == nullptr)
713 {
714 OD_LOG_ERR("Invalid Weapon definition format");
715 return false;
716 }
717 mWeapons.push_back(weapon);
718 }
719
720 return true;
721 }
722
loadSpawnConditions(const std::string & fileName)723 bool ConfigManager::loadSpawnConditions(const std::string& fileName)
724 {
725 OD_LOG_INF("Load creature spawn conditions file: " + fileName);
726 std::stringstream defFile;
727 if(!Helper::readFileWithoutComments(fileName, defFile))
728 {
729 OD_LOG_ERR("Couldn't read " + fileName);
730 return false;
731 }
732
733 std::string nextParam;
734 // Read in the creature class descriptions
735 defFile >> nextParam;
736 if (nextParam != "[SpawnConditions]")
737 {
738 OD_LOG_ERR("Invalid creature spawn condition start format. Line was " + nextParam);
739 return false;
740 }
741
742 while(defFile.good())
743 {
744 if(!(defFile >> nextParam))
745 break;
746
747 if (nextParam == "[/SpawnConditions]")
748 break;
749
750 if (nextParam == "[/SpawnCondition]")
751 continue;
752
753 if (nextParam == "BaseSpawnPoint")
754 {
755 defFile >> nextParam;
756 mBaseSpawnPoint = Helper::toUInt32(nextParam);
757 continue;
758 }
759
760 if (nextParam != "[SpawnCondition]")
761 {
762 OD_LOG_ERR("Invalid creature spawn condition format. Line was " + nextParam);
763 return false;
764 }
765
766 if(!(defFile >> nextParam))
767 break;
768 if (nextParam != "CreatureClass")
769 {
770 OD_LOG_ERR("Invalid creature spawn condition format. Line was " + nextParam);
771 return false;
772 }
773 defFile >> nextParam;
774 const CreatureDefinition* creatureDefinition = getCreatureDefinition(nextParam);
775 if(creatureDefinition == nullptr)
776 {
777 OD_LOG_ERR("nextParam=" + nextParam);
778 return false;
779 }
780
781 while(defFile.good())
782 {
783 if(!(defFile >> nextParam))
784 break;
785
786 if (nextParam == "[/SpawnCondition]")
787 break;
788
789 if (nextParam != "[Condition]")
790 {
791 OD_LOG_ERR("Invalid creature spawn condition format. nextParam=" + nextParam);
792 return false;
793 }
794
795 // Load the definition
796 SpawnCondition* def = SpawnCondition::load(defFile);
797 if (def == nullptr)
798 {
799 OD_LOG_ERR("Invalid creature spawn condition format");
800 return false;
801 }
802 mCreatureSpawnConditions[creatureDefinition].push_back(def);
803 }
804 }
805
806 return true;
807 }
808
loadFactions(const std::string & fileName)809 bool ConfigManager::loadFactions(const std::string& fileName)
810 {
811 OD_LOG_INF("Load factions file: " + fileName);
812 std::stringstream defFile;
813 if(!Helper::readFileWithoutComments(fileName, defFile))
814 {
815 OD_LOG_ERR("Couldn't read " + fileName);
816 return false;
817 }
818
819 std::string nextParam;
820 // Read in the creature class descriptions
821 defFile >> nextParam;
822 if (nextParam != "[Factions]")
823 {
824 OD_LOG_ERR("Invalid factions start format. Line was " + nextParam);
825 return false;
826 }
827
828 while(defFile.good())
829 {
830 if(!(defFile >> nextParam))
831 break;
832
833 if (nextParam == "[/Factions]")
834 break;
835
836 if (nextParam != "[Faction]")
837 {
838 OD_LOG_ERR("Invalid faction. Line was " + nextParam);
839 return false;
840 }
841
842 std::string factionName;
843 std::string workerClass;
844 while(defFile.good())
845 {
846 if(!(defFile >> nextParam))
847 break;
848
849 if (nextParam == "[/Faction]")
850 break;
851
852 if (nextParam == "[/Factions]")
853 break;
854
855 if (nextParam == "Name")
856 {
857 defFile >> factionName;
858 continue;
859 }
860 if(factionName.empty())
861 {
862 OD_LOG_ERR("Empty or missing faction name is not allowed");
863 return false;
864 }
865
866 if (nextParam == "WorkerClass")
867 {
868 defFile >> workerClass;
869 continue;
870 }
871 if(workerClass.empty())
872 {
873 OD_LOG_ERR("Empty or missing WorkerClass name is not allowed");
874 return false;
875 }
876
877 if (nextParam != "[SpawnPool]")
878 {
879 OD_LOG_ERR("Invalid faction. Line was " + nextParam);
880 return false;
881 }
882
883 mFactions.push_back(factionName);
884 mFactionDefaultWorkerClass[factionName] = workerClass;
885
886 // The first faction in the config file is also used for the rogue seat
887 if(mDefaultWorkerRogue.empty())
888 mDefaultWorkerRogue = workerClass;
889
890 while(defFile.good())
891 {
892 if(!(defFile >> nextParam))
893 break;
894
895 if (nextParam == "[/SpawnPool]")
896 break;
897
898 if (nextParam == "[/Faction]")
899 break;
900
901 if (nextParam == "[/Factions]")
902 break;
903
904 // We check if the creature definition exists
905 const CreatureDefinition* creatureDefinition = getCreatureDefinition(nextParam);
906 if(creatureDefinition == nullptr)
907 {
908 OD_LOG_ERR("factionName=" + factionName + ", class=" + nextParam);
909 continue;
910 }
911
912 mFactionSpawnPool[factionName].push_back(nextParam);
913 }
914 }
915 }
916
917 return true;
918 }
919
loadRooms(const std::string & fileName)920 bool ConfigManager::loadRooms(const std::string& fileName)
921 {
922 OD_LOG_INF("Load Rooms file: " + fileName);
923 std::stringstream defFile;
924 if(!Helper::readFileWithoutComments(fileName, defFile))
925 {
926 OD_LOG_ERR("Couldn't read " + fileName);
927 return false;
928 }
929
930 std::string nextParam;
931 // Read in the creature class descriptions
932 defFile >> nextParam;
933 if (nextParam != "[Rooms]")
934 {
935 OD_LOG_ERR("Invalid factions start format. Line was " + nextParam);
936 return false;
937 }
938
939 while(defFile.good())
940 {
941 if(!(defFile >> nextParam))
942 break;
943
944 if (nextParam == "[/Rooms]")
945 break;
946
947 defFile >> mRoomsConfig[nextParam];
948 }
949
950 return true;
951 }
952
loadTraps(const std::string & fileName)953 bool ConfigManager::loadTraps(const std::string& fileName)
954 {
955 OD_LOG_INF("Load traps file: " + fileName);
956 std::stringstream defFile;
957 if(!Helper::readFileWithoutComments(fileName, defFile))
958 {
959 OD_LOG_ERR("Couldn't read " + fileName);
960 return false;
961 }
962
963 std::string nextParam;
964 // Read in the creature class descriptions
965 defFile >> nextParam;
966 if (nextParam != "[Traps]")
967 {
968 OD_LOG_ERR("Invalid Traps start format. Line was " + nextParam);
969 return false;
970 }
971
972 while(defFile.good())
973 {
974 if(!(defFile >> nextParam))
975 break;
976
977 if (nextParam == "[/Traps]")
978 break;
979
980 defFile >> mTrapsConfig[nextParam];
981 }
982
983 return true;
984 }
985
loadSpellConfig(const std::string & fileName)986 bool ConfigManager::loadSpellConfig(const std::string& fileName)
987 {
988 OD_LOG_INF("Load Spell config file: " + fileName);
989 std::stringstream defFile;
990 if(!Helper::readFileWithoutComments(fileName, defFile))
991 {
992 OD_LOG_ERR("Couldn't read " + fileName);
993 return false;
994 }
995
996 std::string nextParam;
997 // Read in the creature class descriptions
998 defFile >> nextParam;
999 if (nextParam != "[Spells]")
1000 {
1001 OD_LOG_ERR("Invalid Spells start format. Line was " + nextParam);
1002 return false;
1003 }
1004
1005 while(defFile.good())
1006 {
1007 if(!(defFile >> nextParam))
1008 break;
1009
1010 if (nextParam == "[/Spells]")
1011 break;
1012
1013 defFile >> mSpellConfig[nextParam];
1014 }
1015
1016 return true;
1017 }
1018
loadSkills(const std::string & fileName)1019 bool ConfigManager::loadSkills(const std::string& fileName)
1020 {
1021 OD_LOG_INF("Load Skills file: " + fileName);
1022 std::stringstream defFile;
1023 if(!Helper::readFileWithoutComments(fileName, defFile))
1024 {
1025 OD_LOG_ERR("Couldn't read " + fileName);
1026 return false;
1027 }
1028
1029 std::string nextParam;
1030 // Read in the creature class descriptions
1031 defFile >> nextParam;
1032 if (nextParam != "[Skills]")
1033 {
1034 OD_LOG_ERR("Invalid Skills start format. Line was " + nextParam);
1035 return false;
1036 }
1037
1038 while(defFile.good())
1039 {
1040 if(!(defFile >> nextParam))
1041 break;
1042
1043 if (nextParam == "[/Skills]")
1044 break;
1045
1046 defFile >> mSkillPoints[nextParam];
1047 }
1048 return true;
1049 }
1050
loadTilesets(const std::string & fileName)1051 bool ConfigManager::loadTilesets(const std::string& fileName)
1052 {
1053 OD_LOG_INF("Load Tilesets file: " + fileName);
1054 std::stringstream defFile;
1055 if(!Helper::readFileWithoutComments(fileName, defFile))
1056 {
1057 OD_LOG_ERR("Couldn't read " + fileName);
1058 return false;
1059 }
1060
1061 std::string nextParam;
1062 defFile >> nextParam;
1063 if (nextParam != "[Tilesets]")
1064 {
1065 OD_LOG_ERR("Invalid Tilesets start format. Line was " + nextParam);
1066 return false;
1067 }
1068
1069 while(true)
1070 {
1071 defFile >> nextParam;
1072 if (nextParam == "[/Tilesets]")
1073 break;
1074
1075 if (nextParam == "[/Tileset]")
1076 continue;
1077
1078 if (nextParam != "[Tileset]")
1079 {
1080 OD_LOG_ERR("Expecting TileSet tag but got=" + nextParam);
1081 return false;
1082 }
1083
1084 defFile >> nextParam;
1085 if (nextParam != "Name")
1086 {
1087 OD_LOG_ERR("Expecting Name tag but got=" + nextParam);
1088 return false;
1089 }
1090
1091 std::string tileSetName;
1092 defFile >> tileSetName;
1093
1094 TileSet* tileSet = new TileSet();
1095 mTileSets[tileSetName] = tileSet;
1096
1097 defFile >> nextParam;
1098 if(nextParam != "[TileLink]")
1099 {
1100 OD_LOG_ERR("Expecting TileLink tag but got=" + nextParam);
1101 return false;
1102 }
1103
1104 while(true)
1105 {
1106 defFile >> nextParam;
1107 if(nextParam == "[/TileLink]")
1108 break;
1109
1110 TileVisual tileVisual1 = Tile::tileVisualFromString(nextParam);
1111 if(tileVisual1 == TileVisual::nullTileVisual)
1112 {
1113 OD_LOG_ERR("Wrong TileVisual1 in tileset=" + nextParam);
1114 return false;
1115 }
1116
1117 defFile >> nextParam;
1118 TileVisual tileVisual2 = Tile::tileVisualFromString(nextParam);
1119 if(tileVisual2 == TileVisual::nullTileVisual)
1120 {
1121 OD_LOG_ERR("Wrong TileVisual2 in tileset=" + nextParam);
1122 return false;
1123 }
1124
1125 tileSet->addTileLink(tileVisual1, tileVisual2);
1126 }
1127
1128 if(!loadTilesetValues(defFile, TileVisual::goldGround, tileSet->configureTileValues(TileVisual::goldGround)))
1129 return false;
1130 if(!loadTilesetValues(defFile, TileVisual::goldFull, tileSet->configureTileValues(TileVisual::goldFull)))
1131 return false;
1132 if(!loadTilesetValues(defFile, TileVisual::dirtGround, tileSet->configureTileValues(TileVisual::dirtGround)))
1133 return false;
1134 if(!loadTilesetValues(defFile, TileVisual::dirtFull, tileSet->configureTileValues(TileVisual::dirtFull)))
1135 return false;
1136 if(!loadTilesetValues(defFile, TileVisual::rockGround, tileSet->configureTileValues(TileVisual::rockGround)))
1137 return false;
1138 if(!loadTilesetValues(defFile, TileVisual::rockFull, tileSet->configureTileValues(TileVisual::rockFull)))
1139 return false;
1140 if(!loadTilesetValues(defFile, TileVisual::waterGround, tileSet->configureTileValues(TileVisual::waterGround)))
1141 return false;
1142 if(!loadTilesetValues(defFile, TileVisual::lavaGround, tileSet->configureTileValues(TileVisual::lavaGround)))
1143 return false;
1144 if(!loadTilesetValues(defFile, TileVisual::claimedGround, tileSet->configureTileValues(TileVisual::claimedGround)))
1145 return false;
1146 if(!loadTilesetValues(defFile, TileVisual::claimedFull, tileSet->configureTileValues(TileVisual::claimedFull)))
1147 return false;
1148 if(!loadTilesetValues(defFile, TileVisual::gemGround, tileSet->configureTileValues(TileVisual::gemGround)))
1149 return false;
1150 if(!loadTilesetValues(defFile, TileVisual::gemFull, tileSet->configureTileValues(TileVisual::gemFull)))
1151 return false;
1152 }
1153
1154 // At least the default tileset should be defined
1155 if(mTileSets.count(DEFAULT_TILESET_NAME) <= 0)
1156 {
1157 OD_LOG_ERR("No tileset defined with name=" + DEFAULT_TILESET_NAME);
1158 return false;
1159 }
1160 return true;
1161 }
1162
loadTilesetValues(std::istream & defFile,TileVisual tileVisual,std::vector<TileSetValue> & tileValues)1163 bool ConfigManager::loadTilesetValues(std::istream& defFile, TileVisual tileVisual, std::vector<TileSetValue>& tileValues)
1164 {
1165 std::string nextParam;
1166 std::string beginTag = "[" + Tile::tileVisualToString(tileVisual) + "]";
1167 std::string endTag = "[/" + Tile::tileVisualToString(tileVisual) + "]";
1168 defFile >> nextParam;
1169 if (nextParam != beginTag)
1170 {
1171 OD_LOG_ERR("Expecting " + beginTag + " tag but got=" + nextParam);
1172 return false;
1173 }
1174 while(true)
1175 {
1176 std::string indexStr;
1177 defFile >> indexStr;
1178 if(indexStr == endTag)
1179 return true;
1180
1181 boost::dynamic_bitset<> x(indexStr);
1182 uint32_t index = static_cast<int>(x.to_ulong());
1183
1184 std::string meshName;
1185 defFile >> meshName;
1186
1187 std::string materialName;
1188 defFile >> materialName;
1189 if(materialName.compare("''") == 0)
1190 materialName.clear();
1191
1192 double rotX;
1193 defFile >> rotX;
1194
1195 double rotY;
1196 defFile >> rotY;
1197
1198 double rotZ;
1199 defFile >> rotZ;
1200
1201 if(index >= tileValues.size())
1202 {
1203 OD_LOG_ERR("Tileset index too high in tileset=" + endTag + ", index=" + indexStr);
1204 return false;
1205 }
1206
1207 tileValues[index] = TileSetValue(meshName, materialName, rotX, rotY, rotZ);
1208 }
1209 }
1210
loadUserConfig(const std::string & fileName)1211 void ConfigManager::loadUserConfig(const std::string& fileName)
1212 {
1213 if (fileName.empty())
1214 return;
1215
1216 mFilenameUserCfg = fileName;
1217
1218 OD_LOG_INF("Load user config file: " + fileName);
1219 std::stringstream defFile;
1220 if(!Helper::readFileWithoutComments(fileName, defFile))
1221 {
1222 OD_LOG_INF("Couldn't read " + fileName);
1223 return;
1224 }
1225
1226 mUserConfig.clear();
1227 mUserConfig.resize(Config::Ctg::TOTAL);
1228
1229 std::string nextParam;
1230 defFile >> nextParam;
1231 if (nextParam != "[Configuration]")
1232 {
1233 OD_LOG_WRN("Invalid User configuration start format. Line was " + nextParam);
1234 return;
1235 }
1236
1237 std::string value;
1238 Config::Ctg category = Config::Ctg::NONE;
1239 while(defFile.good())
1240 {
1241 if (!(defFile >> nextParam))
1242 {
1243 break;
1244 }
1245 else if (nextParam == "[/Configuration]")
1246 {
1247 break;
1248 }
1249 else if (nextParam == "[Audio]")
1250 {
1251 category = Config::Ctg::AUDIO;
1252 continue;
1253 }
1254 else if (nextParam == "[Video]")
1255 {
1256 category = Config::Ctg::VIDEO;
1257 continue;
1258 }
1259 else if (nextParam == "[Input]")
1260 {
1261 category = Config::Ctg::INPUT;
1262 continue;
1263 }
1264 else if (nextParam == "[Game]")
1265 {
1266 category = Config::Ctg::GAME;
1267 continue;
1268 }
1269 else if (nextParam == "[/Audio]" || nextParam == "[/Video]" || nextParam == "[/Input]"
1270 || nextParam == "[/Game]")
1271 {
1272 category = Config::Ctg::NONE;
1273 continue;
1274 }
1275 else if (!nextParam.empty())
1276 {
1277 std::string line;
1278 std::getline(defFile, line);
1279 // Make sure to cut the line only when encountering a tab.
1280 line = nextParam + line;
1281 std::vector<std::string> elements = Helper::split(line, '\t');
1282 if (elements.size() != 2)
1283 {
1284 OD_LOG_WRN("Invalid parameter line: " + line);
1285 continue;
1286 }
1287
1288 if (category == Config::Ctg::NONE)
1289 {
1290 OD_LOG_WRN("Parameter set in unknown category. Will be ignored: "
1291 + elements[0] + ": " + elements[1]);
1292 continue;
1293 }
1294
1295 mUserConfig[ category ][ elements[0] ] = elements[1];
1296 }
1297 else
1298 {
1299 continue;
1300 }
1301 }
1302 }
1303
saveUserConfig()1304 bool ConfigManager::saveUserConfig()
1305 {
1306 if (mFilenameUserCfg.empty())
1307 {
1308 OD_LOG_ERR("Can't save config. The user config file isn't set.");
1309 return false;
1310 }
1311
1312 std::ofstream userFile(mFilenameUserCfg.c_str(), std::ifstream::out);
1313 if (!userFile.is_open())
1314 {
1315 OD_LOG_ERR("Couldn't open user config for writing: " + mFilenameUserCfg);
1316 return false;
1317 }
1318
1319 // Split config in categories.
1320 std::map<std::string, std::string>& mAudioUserConfig = mUserConfig.at(Config::Ctg::AUDIO);
1321 std::map<std::string, std::string>& mVideoUserConfig = mUserConfig.at(Config::Ctg::VIDEO);
1322 std::map<std::string, std::string>& mInputUserConfig = mUserConfig.at(Config::Ctg::INPUT);
1323 std::map<std::string, std::string>& mGameUserConfig = mUserConfig.at(Config::Ctg::GAME);
1324
1325 userFile << "[Configuration]" << std::endl;
1326
1327 userFile << "[Audio]" << std::endl;
1328 for(std::pair<std::string, std::string> audio : mAudioUserConfig)
1329 userFile << audio.first << "\t" << audio.second << std::endl;
1330 userFile << "[/Audio]" << std::endl;
1331
1332 userFile << "[Video]" << std::endl;
1333 for(std::pair<std::string, std::string> video : mVideoUserConfig)
1334 userFile << video.first << "\t" << video.second << std::endl;
1335 userFile << "[/Video]" << std::endl;
1336
1337 userFile << "[Input]" << std::endl;
1338 for(std::pair<std::string, std::string> input : mInputUserConfig)
1339 userFile << input.first << "\t" << input.second << std::endl;
1340 userFile << "[/Input]" << std::endl;
1341
1342 userFile << "[Game]" << std::endl;
1343 for(std::pair<std::string, std::string> input : mGameUserConfig)
1344 userFile << input.first << "\t" << input.second << std::endl;
1345 userFile << "[/Game]" << std::endl;
1346
1347 userFile << "[/Configuration]" << std::endl;
1348 userFile.close();
1349 return true;
1350 }
1351
getUserValue(Config::Ctg category,const std::string & param,const std::string & defaultValue,bool triggerError) const1352 const std::string ConfigManager::getUserValue(Config::Ctg category,
1353 const std::string& param,
1354 const std::string& defaultValue,
1355 bool triggerError) const
1356 {
1357 if (category >= mUserConfig.size())
1358 {
1359 OD_LOG_ERR("User configuration categories uninitialized!");
1360 return defaultValue;
1361 }
1362 auto& userCfg = mUserConfig[category];
1363
1364 auto it = userCfg.find(param);
1365 if(it == userCfg.end())
1366 {
1367 if (triggerError)
1368 OD_LOG_ERR("Unknown parameter param=" + param);
1369 return defaultValue;
1370 }
1371
1372 return it->second;
1373 }
1374
getRoomConfigString(const std::string & param) const1375 const std::string& ConfigManager::getRoomConfigString(const std::string& param) const
1376 {
1377 auto it = mRoomsConfig.find(param);
1378 if(it == mRoomsConfig.end())
1379 {
1380 OD_LOG_ERR("Unknown parameter param=" + param);
1381 return EMPTY_STRING;
1382 }
1383
1384 return it->second;
1385 }
1386
getRoomConfigUInt32(const std::string & param) const1387 uint32_t ConfigManager::getRoomConfigUInt32(const std::string& param) const
1388 {
1389 auto it = mRoomsConfig.find(param);
1390 if(it == mRoomsConfig.end())
1391 {
1392 OD_LOG_ERR("Unknown parameter param=" + param);
1393 return 0;
1394 }
1395
1396 return Helper::toUInt32(it->second);
1397 }
1398
getRoomConfigInt32(const std::string & param) const1399 int32_t ConfigManager::getRoomConfigInt32(const std::string& param) const
1400 {
1401 auto it = mRoomsConfig.find(param);
1402 if(it == mRoomsConfig.end())
1403 {
1404 OD_LOG_ERR("Unknown parameter param=" + param);
1405 return 0;
1406 }
1407
1408 return Helper::toInt(it->second);
1409 }
1410
getRoomConfigDouble(const std::string & param) const1411 double ConfigManager::getRoomConfigDouble(const std::string& param) const
1412 {
1413 auto it = mRoomsConfig.find(param);
1414 if(it == mRoomsConfig.end())
1415 {
1416 OD_LOG_ERR("Unknown parameter param=" + param);
1417 return 0.0;
1418 }
1419
1420 return Helper::toDouble(it->second);
1421 }
1422
getTrapConfigString(const std::string & param) const1423 const std::string& ConfigManager::getTrapConfigString(const std::string& param) const
1424 {
1425 auto it = mTrapsConfig.find(param);
1426 if(it == mTrapsConfig.end())
1427 {
1428 OD_LOG_ERR("Unknown parameter param=" + param);
1429 return EMPTY_STRING;
1430 }
1431
1432 return it->second;
1433 }
1434
getTrapConfigUInt32(const std::string & param) const1435 uint32_t ConfigManager::getTrapConfigUInt32(const std::string& param) const
1436 {
1437 auto it = mTrapsConfig.find(param);
1438 if(it == mTrapsConfig.end())
1439 {
1440 OD_LOG_ERR("Unknown parameter param=" + param);
1441 return 0;
1442 }
1443
1444 return Helper::toUInt32(it->second);
1445 }
1446
getTrapConfigInt32(const std::string & param) const1447 int32_t ConfigManager::getTrapConfigInt32(const std::string& param) const
1448 {
1449 auto it = mTrapsConfig.find(param);
1450 if(it == mTrapsConfig.end())
1451 {
1452 OD_LOG_ERR("Unknown parameter param=" + param);
1453 return 0;
1454 }
1455
1456 return Helper::toInt(it->second);
1457 }
1458
getTrapConfigDouble(const std::string & param) const1459 double ConfigManager::getTrapConfigDouble(const std::string& param) const
1460 {
1461 auto it = mTrapsConfig.find(param);
1462 if(it == mTrapsConfig.end())
1463 {
1464 OD_LOG_ERR("Unknown parameter param=" + param);
1465 return 0.0;
1466 }
1467
1468 return Helper::toDouble(it->second);
1469 }
1470
getSpellConfigString(const std::string & param) const1471 const std::string& ConfigManager::getSpellConfigString(const std::string& param) const
1472 {
1473 auto it = mSpellConfig.find(param);
1474 if(it == mSpellConfig.end())
1475 {
1476 OD_LOG_ERR("Unknown parameter param=" + param);
1477 return EMPTY_STRING;
1478 }
1479
1480 return it->second;
1481 }
1482
getSpellConfigUInt32(const std::string & param) const1483 uint32_t ConfigManager::getSpellConfigUInt32(const std::string& param) const
1484 {
1485 auto it = mSpellConfig.find(param);
1486 if(it == mSpellConfig.end())
1487 {
1488 OD_LOG_ERR("Unknown parameter param=" + param);
1489 return 0;
1490 }
1491
1492 return Helper::toUInt32(it->second);
1493 }
1494
getSpellConfigInt32(const std::string & param) const1495 int32_t ConfigManager::getSpellConfigInt32(const std::string& param) const
1496 {
1497 auto it = mSpellConfig.find(param);
1498 if(it == mSpellConfig.end())
1499 {
1500 OD_LOG_ERR("Unknown parameter param=" + param);
1501 return 0;
1502 }
1503
1504 return Helper::toInt(it->second);
1505 }
1506
getSpellConfigDouble(const std::string & param) const1507 double ConfigManager::getSpellConfigDouble(const std::string& param) const
1508 {
1509 auto it = mSpellConfig.find(param);
1510 if(it == mSpellConfig.end())
1511 {
1512 OD_LOG_ERR("Unknown parameter param=" + param);
1513 return 0.0;
1514 }
1515
1516 return Helper::toDouble(it->second);
1517 }
1518
getSkillPoints(const std::string & res) const1519 int32_t ConfigManager::getSkillPoints(const std::string& res) const
1520 {
1521 auto it = mSkillPoints.find(res);
1522 if(it == mSkillPoints.end())
1523 {
1524 OD_LOG_ERR("Unknown parameter res=" + res);
1525 return 0;
1526 }
1527
1528 return it->second;
1529 }
1530
getCreatureDefinition(const std::string & name) const1531 const CreatureDefinition* ConfigManager::getCreatureDefinition(const std::string& name) const
1532 {
1533 auto it = mCreatureDefs.find(name);
1534 if(it != mCreatureDefs.end())
1535 {
1536 return it->second;
1537 }
1538 return nullptr;
1539 }
1540
getWeapon(const std::string & name) const1541 const Weapon* ConfigManager::getWeapon(const std::string& name) const
1542 {
1543 for(const Weapon* def : mWeapons)
1544 {
1545 if(name.compare(def->getName()) == 0)
1546 return def;
1547 }
1548
1549 return nullptr;
1550 }
1551
getColorFromId(const std::string & id) const1552 const Ogre::ColourValue& ConfigManager::getColorFromId(const std::string& id) const
1553 {
1554 auto it = mSeatColors.find(id);
1555 if(it == mSeatColors.end())
1556 return DEFAULT_SEAT_COLOURVALUE;
1557
1558 return it->second;
1559
1560 }
1561
getCreatureSpawnConditions(const CreatureDefinition * def) const1562 const std::vector<const SpawnCondition*>& ConfigManager::getCreatureSpawnConditions(const CreatureDefinition* def) const
1563 {
1564 auto it = mCreatureSpawnConditions.find(def);
1565 if(it == mCreatureSpawnConditions.end())
1566 return SpawnCondition::EMPTY_SPAWNCONDITIONS;
1567
1568 return it->second;
1569 }
1570
getFactionSpawnPool(const std::string & faction) const1571 const std::vector<std::string>& ConfigManager::getFactionSpawnPool(const std::string& faction) const
1572 {
1573 auto it = mFactionSpawnPool.find(faction);
1574 if(it == mFactionSpawnPool.end())
1575 return EMPTY_SPAWNPOOL;
1576
1577 return it->second;
1578 }
1579
getFactionWorkerClass(const std::string & faction) const1580 const std::string& ConfigManager::getFactionWorkerClass(const std::string& faction) const
1581 {
1582 auto it = mFactionDefaultWorkerClass.find(faction);
1583 if(it == mFactionDefaultWorkerClass.end())
1584 return EMPTY_STRING;
1585
1586 return it->second;
1587 }
1588
getTileSet(const std::string & tileSetName) const1589 const TileSet* ConfigManager::getTileSet(const std::string& tileSetName) const
1590 {
1591 if(tileSetName.empty())
1592 return mTileSets.at(DEFAULT_TILESET_NAME);
1593
1594 auto it = mTileSets.find(tileSetName);
1595 if(it == mTileSets.end())
1596 {
1597 OD_LOG_ERR("Cannot find requested tileset name=" + tileSetName);
1598 // We return the default tileset
1599 return mTileSets.at(DEFAULT_TILESET_NAME);
1600 }
1601
1602 return it->second;
1603 }
1604
initVideoConfig(Ogre::Root & ogreRoot)1605 bool ConfigManager::initVideoConfig(Ogre::Root& ogreRoot)
1606 {
1607 // Also creates the config entry if it doesn't exist in config yet.
1608 std::string rendererName = getVideoValue(Config::RENDERER, std::string(), false);
1609 // Try the default OpenGL renderer first, if empty.
1610 if (rendererName.empty())
1611 rendererName = "OpenGL Rendering Subsystem";
1612
1613 Ogre::RenderSystem* renderSystem = ogreRoot.getRenderSystemByName(rendererName);
1614 bool sameRenderer = true;
1615 if (renderSystem == nullptr)
1616 {
1617 const Ogre::RenderSystemList& renderers = ogreRoot.getAvailableRenderers();
1618 if(renderers.empty())
1619 {
1620 OD_LOG_ERR("No valid renderer found. Exiting...");
1621 return false;
1622 }
1623 renderSystem = *renderers.begin();
1624 OD_LOG_INF("No OpenGL renderer found. Using the first available: " + renderSystem->getName());
1625 sameRenderer = false;
1626 }
1627
1628 ogreRoot.setRenderSystem(renderSystem);
1629 Ogre::ConfigOptionMap& options = renderSystem->getConfigOptions();
1630
1631 // If the renderer was changed, we need to reset the video options.
1632 if (sameRenderer == false)
1633 {
1634
1635 mUserConfig[Config::Ctg::VIDEO].clear();
1636
1637 for (std::pair<Ogre::String, Ogre::ConfigOption> option : options)
1638 {
1639 std::string optionName = option.first;
1640 Ogre::ConfigOption& values = option.second;
1641 // We don't store options that are immutable or empty
1642 if (values.immutable || values.possibleValues.empty())
1643 continue;
1644
1645 setVideoValue(optionName, values.currentValue);
1646 }
1647 }
1648 else {
1649 std::vector<std::string> optionsToRemove;
1650
1651 // The renderer system was initialized. Let's load its new option values.
1652 std::map<std::string, std::string>& mVideoUserConfig = mUserConfig[Config::Ctg::VIDEO];
1653 for (std::pair<std::string, std::string> setting : mVideoUserConfig)
1654 {
1655 // Check the option exists.
1656 if (options.find(setting.first) == options.end())
1657 {
1658 optionsToRemove.push_back(setting.first);
1659 continue;
1660 }
1661
1662 // Check the desired option value exists.
1663 Ogre::ConfigOption& values = options.find(setting.first)->second;
1664 bool valueIsPossible = false;
1665 for (std::string value : values.possibleValues)
1666 {
1667 if (setting.second == value)
1668 {
1669 valueIsPossible = true;
1670 break;
1671 }
1672 }
1673 if (!valueIsPossible)
1674 {
1675 optionsToRemove.push_back(setting.first);
1676 continue;
1677 }
1678
1679 renderSystem->setConfigOption(setting.first, setting.second);
1680 }
1681
1682 // Removes now invalid options from the video options.
1683 for (std::string option : optionsToRemove)
1684 mVideoUserConfig.erase(option);
1685 }
1686
1687 return true;
1688 }
1689
loadKeeperVoices(const std::string & soundPath)1690 void ConfigManager::loadKeeperVoices(const std::string& soundPath)
1691 {
1692 std::vector<std::string> directories;
1693 std::string parentPath = soundPath + "Relative";
1694 if(!Helper::fillDirList(parentPath, directories, false))
1695 {
1696 OD_LOG_ERR("Error while loading sounds in directory=" + parentPath);
1697 return;
1698 }
1699
1700 for(const std::string& directory : directories)
1701 {
1702 // We add the keeper voice
1703 OD_LOG_INF("Keeper voice found=" + directory);
1704 mKeeperVoices.push_back(directory);
1705 }
1706
1707 if(mKeeperVoices.empty())
1708 {
1709 OD_LOG_ERR("No keeper voice found. Relative sounds will not work");
1710 return;
1711 }
1712
1713 if(std::find(mKeeperVoices.begin(), mKeeperVoices.end(), ConfigManager::DEFAULT_KEEPER_VOICE) == mKeeperVoices.end())
1714 {
1715 OD_LOG_ERR("No default keeper voice found");
1716 }
1717 }
1718