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