Просмотр исходного кода

Integrated defaultMods into mod system

Ivan Savenko 2 лет назад
Родитель
Сommit
383387ef29
67 измененных файлов с 505 добавлено и 362 удалено
  1. 2 2
      AI/Nullkiller/AIGateway.cpp
  2. 2 2
      AI/Nullkiller/AIUtility.cpp
  3. 4 4
      AI/VCAI/VCAI.cpp
  4. 5 0
      client/CGameInfo.cpp
  5. 1 1
      client/CGameInfo.h
  6. 1 0
      client/CServerHandler.cpp
  7. 15 18
      client/Client.cpp
  8. 1 0
      client/ClientCommandManager.cpp
  9. 2 1
      client/adventureMap/CList.cpp
  10. 1 0
      client/lobby/RandomMapTab.cpp
  11. 2 1
      client/lobby/SelectionTab.cpp
  12. 1 0
      client/renderSDL/CBitmapFont.cpp
  13. 2 1
      client/widgets/MiscWidgets.cpp
  14. 3 2
      client/windows/CCastleInterface.cpp
  15. 3 2
      client/windows/CCreatureWindow.cpp
  16. 2 1
      client/windows/CKingdomInterface.cpp
  17. 4 2
      client/windows/GUIClasses.cpp
  18. 2 0
      cmake_modules/VCMI_lib.cmake
  19. 0 102
      config/defaultMods.json
  20. 117 1
      config/gameConfig.json
  21. 2 0
      include/vcmi/Services.h
  22. 1 1
      lib/BattleFieldHandler.cpp
  23. 1 1
      lib/BattleFieldHandler.h
  24. 22 8
      lib/CArtHandler.cpp
  25. 1 1
      lib/CArtHandler.h
  26. 6 3
      lib/CCreatureHandler.cpp
  27. 1 1
      lib/CCreatureHandler.h
  28. 4 3
      lib/CCreatureSet.cpp
  29. 2 1
      lib/CGameInfoCallback.cpp
  30. 5 4
      lib/CGameState.cpp
  31. 2 1
      lib/CGeneralTextHandler.cpp
  32. 7 2
      lib/CHeroHandler.cpp
  33. 2 2
      lib/CHeroHandler.h
  34. 10 72
      lib/CModHandler.cpp
  35. 1 74
      lib/CModHandler.h
  36. 1 1
      lib/CSkillHandler.cpp
  37. 1 1
      lib/CSkillHandler.h
  38. 4 1
      lib/CTownHandler.cpp
  39. 1 1
      lib/CTownHandler.h
  40. 99 0
      lib/GameSettings.cpp
  41. 88 0
      lib/GameSettings.h
  42. 1 1
      lib/IHandlerBase.h
  43. 3 2
      lib/NetPacksLib.cpp
  44. 1 1
      lib/ObstacleHandler.cpp
  45. 1 1
      lib/ObstacleHandler.h
  46. 4 1
      lib/RiverHandler.cpp
  47. 1 1
      lib/RiverHandler.h
  48. 4 1
      lib/RoadHandler.cpp
  49. 1 1
      lib/RoadHandler.h
  50. 1 1
      lib/ScriptHandler.cpp
  51. 1 1
      lib/ScriptHandler.h
  52. 4 1
      lib/TerrainHandler.cpp
  53. 1 1
      lib/TerrainHandler.h
  54. 7 0
      lib/VCMI_Lib.cpp
  55. 4 0
      lib/VCMI_Lib.h
  56. 5 5
      lib/battle/DamageCalculator.cpp
  57. 8 6
      lib/mapObjects/CGHeroInstance.cpp
  58. 2 2
      lib/mapObjects/CGMarket.cpp
  59. 2 1
      lib/mapObjects/CGTownInstance.cpp
  60. 4 1
      lib/mapObjects/CObjectClassesHandler.cpp
  61. 1 1
      lib/mapObjects/CObjectClassesHandler.h
  62. 6 5
      lib/mapObjects/MiscObjects.cpp
  63. 1 1
      lib/rmg/CRmgTemplateStorage.cpp
  64. 1 1
      lib/rmg/CRmgTemplateStorage.h
  65. 1 1
      lib/spells/CSpellHandler.cpp
  66. 1 1
      lib/spells/CSpellHandler.h
  67. 8 6
      server/CGameHandler.cpp

+ 2 - 2
AI/Nullkiller/AIGateway.cpp

@@ -13,7 +13,7 @@
 #include "../../lib/mapObjects/MapObjects.h"
 #include "../../lib/CConfigHandler.h"
 #include "../../lib/CHeroHandler.h"
-#include "../../lib/CModHandler.h"
+#include "../../lib/GameSettings.h"
 #include "../../lib/CGameState.h"
 #include "../../lib/NetPacks.h"
 #include "../../lib/serializer/CTypeList.h"
@@ -1072,7 +1072,7 @@ bool AIGateway::canRecruitAnyHero(const CGTownInstance * t) const
 		return false;
 	if(cb->getHeroesInfo().size() >= ALLOWED_ROAMING_HEROES)
 		return false;
-	if(cb->getHeroesInfo().size() >= VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER)
+	if(cb->getHeroesInfo().size() >= VLC->settings()->getInteger(EGameSettings::INT_MAX_HEROES_ON_MAP_PER_PLAYER))
 		return false;
 	if(!cb->getAvailableHeroes(t).size())
 		return false;

+ 2 - 2
AI/Nullkiller/AIUtility.cpp

@@ -18,7 +18,7 @@
 #include "../../lib/mapObjects/MapObjects.h"
 #include "../../lib/mapping/CMapDefines.h"
 
-#include "../../lib/CModHandler.h"
+#include "../../lib/GameSettings.h"
 
 namespace NKAI
 {
@@ -445,7 +445,7 @@ bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObject
 	case Obj::MAGIC_WELL:
 		return h->mana < h->manaLimit();
 	case Obj::PRISON:
-		return ai->cb->getHeroesInfo().size() < VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER;
+		return ai->cb->getHeroesInfo().size() < VLC->settings()->getInteger(EGameSettings::INT_MAX_HEROES_ON_MAP_PER_PLAYER);
 	case Obj::TAVERN:
 	case Obj::EYE_OF_MAGI:
 	case Obj::BOAT:

+ 4 - 4
AI/VCAI/VCAI.cpp

@@ -18,7 +18,7 @@
 #include "../../lib/mapObjects/MapObjects.h"
 #include "../../lib/CConfigHandler.h"
 #include "../../lib/CHeroHandler.h"
-#include "../../lib/CModHandler.h"
+#include "../../lib/GameSettings.h"
 #include "../../lib/CGameState.h"
 #include "../../lib/NetPacksBase.h"
 #include "../../lib/NetPacks.h"
@@ -1318,7 +1318,7 @@ bool VCAI::canRecruitAnyHero(const CGTownInstance * t) const
 		return false;
 	if(cb->getHeroesInfo().size() >= ALLOWED_ROAMING_HEROES)
 		return false;
-	if(cb->getHeroesInfo().size() >= VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER)
+	if(cb->getHeroesInfo().size() >= VLC->settings()->getInteger(EGameSettings::INT_MAX_HEROES_ON_MAP_PER_PLAYER))
 		return false;
 	if(!cb->getAvailableHeroes(t).size())
 		return false;
@@ -2851,12 +2851,12 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
 	case Obj::MAGIC_WELL:
 		return h->mana < h->manaLimit();
 	case Obj::PRISON:
-		return ai->myCb->getHeroesInfo().size() < VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER;
+		return ai->myCb->getHeroesInfo().size() < VLC->settings()->getInteger(EGameSettings::INT_MAX_HEROES_ON_MAP_PER_PLAYER);
 	case Obj::TAVERN:
 	{
 		//TODO: make AI actually recruit heroes
 		//TODO: only on request
-		if(ai->myCb->getHeroesInfo().size() >= VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER)
+		if(ai->myCb->getHeroesInfo().size() >= VLC->settings()->getInteger(EGameSettings::INT_MAX_HEROES_ON_MAP_PER_PLAYER))
 			return false;
 		else if(ai->ah->freeGold() < GameConstants::HERO_GOLD_COST)
 			return false;

+ 5 - 0
client/CGameInfo.cpp

@@ -94,6 +94,11 @@ const ObstacleService * CGameInfo::obstacles() const
 	return globalServices->obstacles();
 }
 
+const IGameSettings * CGameInfo::settings() const
+{
+	return globalServices->settings();
+}
+
 void CGameInfo::updateEntity(Metatype metatype, int32_t index, const JsonNode & data)
 {
 	logGlobal->error("CGameInfo::updateEntity call is not expected.");

+ 1 - 1
client/CGameInfo.h

@@ -71,13 +71,13 @@ public:
 	const SkillService * skills() const override;
 	const BattleFieldService * battlefields() const override;
 	const ObstacleService * obstacles() const override;
+	const IGameSettings * settings() const override;
 
 	void updateEntity(Metatype metatype, int32_t index, const JsonNode & data) override;
 
 	const spells::effects::Registry * spellEffects() const override;
 	spells::effects::Registry * spellEffects() override;
 
-
 	ConstTransitivePtr<CModHandler> modh; //public?
 	ConstTransitivePtr<BattleFieldHandler> battleFieldHandler;
 	ConstTransitivePtr<CHeroHandler> heroh;

+ 1 - 0
client/CServerHandler.cpp

@@ -45,6 +45,7 @@
 #include "../lib/mapping/CMapInfo.h"
 #include "../lib/mapObjects/MiscObjects.h"
 #include "../lib/rmg/CMapGenOptions.h"
+#include "../lib/filesystem/Filesystem.h"
 #include "../lib/registerTypes/RegisterTypes.h"
 #include "../lib/serializer/Connection.h"
 #include "../lib/serializer/CMemorySerializer.h"

+ 15 - 18
client/Client.cpp

@@ -10,30 +10,27 @@
 #include "StdInc.h"
 #include "Client.h"
 
-#include "../CCallback.h"
-#include "adventureMap/CAdvMapInt.h"
-#include "mapView/mapHandler.h"
 #include "CGameInfo.h"
-#include "../lib/CGameState.h"
 #include "CPlayerInterface.h"
-#include "../lib/StartInfo.h"
-#include "../lib/battle/BattleInfo.h"
-#include "../lib/serializer/CTypeList.h"
-#include "../lib/serializer/Connection.h"
-#include "../lib/NetPacks.h"
+#include "CServerHandler.h"
 #include "ClientNetPackVisitors.h"
-#include "../lib/VCMI_Lib.h"
-#include "../lib/VCMIDirs.h"
-#include "../lib/mapping/CMap.h"
-#include "../lib/mapping/CMapService.h"
-#include "../lib/JsonNode.h"
-#include "../lib/CConfigHandler.h"
+#include "adventureMap/CAdvMapInt.h"
 #include "battle/BattleInterface.h"
+#include "gui/CGuiHandler.h"
+#include "mapView/mapHandler.h"
+
+#include "../CCallback.h"
+#include "../lib/CConfigHandler.h"
+#include "../lib/CGameState.h"
 #include "../lib/CThreadHelper.h"
+#include "../lib/VCMIDirs.h"
+#include "../lib/battle/BattleInfo.h"
+#include "../lib/serializer/BinaryDeserializer.h"
+#include "../lib/mapping/CMapService.h"
+#include "../lib/filesystem/Filesystem.h"
 #include "../lib/registerTypes/RegisterTypes.h"
-#include "gui/CGuiHandler.h"
-#include "CServerHandler.h"
-#include "serializer/BinaryDeserializer.h"
+#include "../lib/serializer/Connection.h"
+
 #include <vcmi/events/EventBus.h>
 
 #if SCRIPTING_ENABLED

+ 1 - 0
client/ClientCommandManager.cpp

@@ -30,6 +30,7 @@
 #include "render/CAnimation.h"
 #include "../CCallback.h"
 #include "../lib/CGeneralTextHandler.h"
+#include "../lib/filesystem/Filesystem.h"
 #include "../lib/CHeroHandler.h"
 #include "../lib/CModHandler.h"
 #include "../lib/VCMIDirs.h"

+ 2 - 1
client/adventureMap/CList.cpp

@@ -23,6 +23,7 @@
 #include "../../lib/CGeneralTextHandler.h"
 #include "../../lib/CHeroHandler.h"
 #include "../../lib/CModHandler.h"
+#include "../../lib/GameSettings.h"
 #include "../../lib/mapObjects/CGHeroInstance.h"
 #include "../../lib/mapObjects/CGTownInstance.h"
 
@@ -283,7 +284,7 @@ std::shared_ptr<CIntObject> CTownList::CTownItem::genSelection()
 
 void CTownList::CTownItem::update()
 {
-	size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->builded >= CGI->modh->settings.MAX_BUILDING_PER_TURN];
+	size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->builded >= CGI->settings()->getInteger(EGameSettings::INT_MAX_BUILDING_PER_TURN)];
 
 	picture->setFrame(iconIndex + 2);
 	redraw();

+ 1 - 0
client/lobby/RandomMapTab.cpp

@@ -29,6 +29,7 @@
 #include "../../lib/rmg/CMapGenOptions.h"
 #include "../../lib/CModHandler.h"
 #include "../../lib/rmg/CRmgTemplateStorage.h"
+#include "../../lib/filesystem/Filesystem.h"
 #include "../../lib/RoadHandler.h"
 
 RandomMapTab::RandomMapTab():

+ 2 - 1
client/lobby/SelectionTab.cpp

@@ -31,6 +31,7 @@
 #include "../../lib/NetPacksLobby.h"
 #include "../../lib/CGeneralTextHandler.h"
 #include "../../lib/CModHandler.h"
+#include "../../lib/GameSettings.h"
 #include "../../lib/filesystem/Filesystem.h"
 #include "../../lib/mapping/CMapInfo.h"
 #include "../../lib/mapping/CMap.h"
@@ -538,7 +539,7 @@ void SelectionTab::parseMaps(const std::unordered_set<ResourceID> & files)
 
 			// ignore unsupported map versions (e.g. WoG maps without WoG)
 			// but accept VCMI maps
-			if((mapInfo->mapHeader->version >= EMapFormat::VCMI) || (mapInfo->mapHeader->version <= CGI->modh->settings.data["textData"]["mapVersion"].Float()))
+			if((mapInfo->mapHeader->version >= EMapFormat::VCMI) || (mapInfo->mapHeader->version <= CGI->settings()->getInteger(EGameSettings::TEXTS_MAP_VERSION)))
 				allItems.push_back(mapInfo);
 		}
 		catch(std::exception & e)

+ 1 - 0
client/renderSDL/CBitmapFont.cpp

@@ -20,6 +20,7 @@
 #include "../../lib/TextOperations.h"
 #include "../../lib/filesystem/Filesystem.h"
 #include "../../lib/vcmi_endian.h"
+#include "../../lib/VCMI_Lib.h"
 
 #include <SDL_surface.h>
 

+ 2 - 1
client/widgets/MiscWidgets.cpp

@@ -28,6 +28,7 @@
 #include "../../lib/CGameState.h"
 #include "../../lib/CGeneralTextHandler.h"
 #include "../../lib/CModHandler.h"
+#include "../../lib/GameSettings.h"
 #include "../../lib/TextOperations.h"
 #include "../../lib/mapObjects/CGHeroInstance.h"
 #include "../../lib/mapObjects/CGTownInstance.h"
@@ -328,7 +329,7 @@ void CTownTooltip::init(const InfoAboutTown & town)
 
 	assert(town.tType);
 
-	size_t iconIndex = town.tType->clientInfo.icons[town.fortLevel > 0][town.built >= CGI->modh->settings.MAX_BUILDING_PER_TURN];
+	size_t iconIndex = town.tType->clientInfo.icons[town.fortLevel > 0][town.built >= CGI->settings()->getInteger(EGameSettings::INT_MAX_BUILDING_PER_TURN)];
 
 	build = std::make_shared<CAnimImage>("itpt", iconIndex, 0, 3, 2);
 

+ 3 - 2
client/windows/CCastleInterface.cpp

@@ -37,6 +37,7 @@
 #include "../../lib/CCreatureHandler.h"
 #include "../../lib/CGeneralTextHandler.h"
 #include "../../lib/CModHandler.h"
+#include "../../lib/GameSettings.h"
 #include "../../lib/spells/CSpellHandler.h"
 #include "../../lib/CTownHandler.h"
 #include "../../lib/GameConstants.h"
@@ -407,7 +408,7 @@ void CHeroGSlot::clickLeft(tribool down, bool previousState)
 			bool allow = true;
 			if(upg) //moving hero out of town - check if it is allowed
 			{
-				if(!hero && LOCPLINT->cb->howManyHeroes(false) >= VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER)
+				if(!hero && LOCPLINT->cb->howManyHeroes(false) >= CGI->settings()->getInteger(EGameSettings::INT_MAX_HEROES_ON_MAP_PER_PLAYER))
 				{
 					std::string tmp = CGI->generaltexth->allTexts[18]; //You already have %d adventuring heroes under your command.
 					boost::algorithm::replace_first(tmp,"%d",std::to_string(LOCPLINT->cb->howManyHeroes(false)));
@@ -1269,7 +1270,7 @@ void CCastleInterface::removeBuilding(BuildingID bid)
 void CCastleInterface::recreateIcons()
 {
 	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
-	size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->builded >= CGI->modh->settings.MAX_BUILDING_PER_TURN];
+	size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->builded >= CGI->settings()->getInteger(EGameSettings::INT_MAX_BUILDING_PER_TURN)];
 
 	icon->setFrame(iconIndex);
 	TResources townIncome = town->dailyIncome();

+ 3 - 2
client/windows/CCreatureWindow.cpp

@@ -29,6 +29,7 @@
 #include "../../lib/CBonusTypeHandler.h"
 #include "../../lib/CGeneralTextHandler.h"
 #include "../../lib/CModHandler.h"
+#include "../../lib/GameSettings.h"
 #include "../../lib/CHeroHandler.h"
 #include "../../lib/CGameState.h"
 #include "../../lib/TextOperations.h"
@@ -777,8 +778,8 @@ void CStackWindow::initSections()
 {
 	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
 
-	bool showArt = CGI->modh->modules.STACK_ARTIFACT && info->commander == nullptr && info->stackNode;
-	bool showExp = (CGI->modh->modules.STACK_EXP || info->commander != nullptr) && info->stackNode;
+	bool showArt = CGI->settings()->getBoolean(EGameSettings::MODULE_STACK_ARTIFACT) && info->commander == nullptr && info->stackNode;
+	bool showExp = (CGI->settings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE) || info->commander != nullptr) && info->stackNode;
 
 	mainSection = std::make_shared<MainSection>(this, pos.h, showExp, showArt);
 

+ 2 - 1
client/windows/CKingdomInterface.cpp

@@ -31,6 +31,7 @@
 #include "../../lib/CGeneralTextHandler.h"
 #include "../../lib/CHeroHandler.h"
 #include "../../lib/CModHandler.h"
+#include "../../lib/GameSettings.h"
 #include "../../lib/CSkillHandler.h"
 #include "../../lib/CTownHandler.h"
 #include "../../lib/mapObjects/CGHeroInstance.h"
@@ -778,7 +779,7 @@ CTownItem::CTownItem(const CGTownInstance * Town)
 	garr = std::make_shared<CGarrisonInt>(313, 3, 4, Point(232,0), town->getUpperArmy(), town->visitingHero, true, true, true);
 	heroes = std::make_shared<HeroSlots>(town, Point(244,6), Point(475,6), garr, false);
 
-	size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->builded >= CGI->modh->settings.MAX_BUILDING_PER_TURN];
+	size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->builded >= CGI->settings()->getInteger(EGameSettings::INT_MAX_BUILDING_PER_TURN)];
 
 	picture = std::make_shared<CAnimImage>("ITPT", iconIndex, 0, 5, 6);
 	openTown = std::make_shared<LRClickableAreaOpenTown>(Rect(5, 6, 58, 64), town);

+ 4 - 2
client/windows/GUIClasses.cpp

@@ -52,9 +52,11 @@
 #include "../lib/CGeneralTextHandler.h"
 #include "../lib/CHeroHandler.h"
 #include "../lib/CModHandler.h"
+#include "../lib/GameSettings.h"
 #include "../lib/CondSh.h"
 #include "../lib/CSkillHandler.h"
 #include "../lib/spells/CSpellHandler.h"
+#include "../lib/filesystem/Filesystem.h"
 #include "../lib/CStopWatch.h"
 #include "../lib/CTownHandler.h"
 #include "../lib/GameConstants.h"
@@ -466,13 +468,13 @@ CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj)
 		recruit->addHoverText(CButton::NORMAL, CGI->generaltexth->tavernInfo[0]); //Cannot afford a Hero
 		recruit->block(true);
 	}
-	else if(LOCPLINT->cb->howManyHeroes(true) >= VLC->modh->settings.MAX_HEROES_AVAILABLE_PER_PLAYER)
+	else if(LOCPLINT->cb->howManyHeroes(true) >= CGI->settings()->getInteger(EGameSettings::INT_MAX_HEROES_AVAILABLE_PER_PLAYER))
 	{
 		//Cannot recruit. You already have %d Heroes.
 		recruit->addHoverText(CButton::NORMAL, boost::str(boost::format(CGI->generaltexth->tavernInfo[1]) % LOCPLINT->cb->howManyHeroes(true)));
 		recruit->block(true);
 	}
-	else if(LOCPLINT->cb->howManyHeroes(false) >= VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER)
+	else if(LOCPLINT->cb->howManyHeroes(false) >= CGI->settings()->getInteger(EGameSettings::INT_MAX_HEROES_ON_MAP_PER_PLAYER))
 	{
 		//Cannot recruit. You already have %d Heroes.
 		recruit->addHoverText(CButton::NORMAL, boost::str(boost::format(CGI->generaltexth->tavernInfo[1]) % LOCPLINT->cb->howManyHeroes(false)));

+ 2 - 0
cmake_modules/VCMI_lib.cmake

@@ -182,6 +182,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
 		${MAIN_LIB_DIR}/CThreadHelper.cpp
 		${MAIN_LIB_DIR}/CTownHandler.cpp
 		${MAIN_LIB_DIR}/GameConstants.cpp
+		${MAIN_LIB_DIR}/GameSettings.cpp
 		${MAIN_LIB_DIR}/HeroBonus.cpp
 		${MAIN_LIB_DIR}/IGameCallback.cpp
 		${MAIN_LIB_DIR}/IHandlerBase.cpp
@@ -426,6 +427,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
 		${MAIN_LIB_DIR}/CTownHandler.h
 		${MAIN_LIB_DIR}/FunctionList.h
 		${MAIN_LIB_DIR}/GameConstants.h
+		${MAIN_LIB_DIR}/GameSettings.h
 		${MAIN_LIB_DIR}/HeroBonus.h
 		${MAIN_LIB_DIR}/IBonusTypeHandler.h
 		${MAIN_LIB_DIR}/IGameCallback.h

+ 0 - 102
config/defaultMods.json

@@ -1,102 +0,0 @@
-// default configuration for mod system loaded at launch
-
-{
-	"textData" :
-	{
-		"heroClass"  : 18,
-		"artifact"   : 144,
-		"creature"   : 150,
-		"faction"    : 9,
-		"hero"       : 156,
-		"spell"      : 81,
-		"object"     : 256,
-		"terrain"    : 10,
-		"river"      : 5,
-		"road"       : 4,
-		"mapVersion" : 28 // max supported version, SoD
-	},
-
-	"hardcodedFeatures" :
-	{
-		"CREEP_SIZE": 4000,
-		"WEEKLY_GROWTH_PERCENT" : 10,
-		"NEUTRAL_STACK_EXP_DAILY" : 500,
-		"MAX_BUILDING_PER_TURN" : 1,
-		"DWELLINGS_ACCUMULATE_CREATURES" : false,
-		"ALL_CREATURES_GET_DOUBLE_MONTHS" : false,
-		"NEGATIVE_LUCK" : false,
-		"MAX_HEROES_AVAILABLE_PER_PLAYER" : 16,
-		"MAX_HEROES_ON_MAP_PER_PLAYER" : 8,
-		"WINNING_HERO_WITH_NO_TROOPS_RETREATS": true,
-		"BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE": true,
-		"NO_RANDOM_SPECIAL_WEEKS_AND_MONTHS": false,
-		"ATTACK_POINT_DMG_MULTIPLIER": 0.05, //every 1 attack point damage influence in battle when attack points > defense points during creature attack
-		"ATTACK_POINTS_DMG_MULTIPLIER_CAP": 4.0, //limit of damage increase that can be achieved by overpowering attack points
-		"DEFENSE_POINT_DMG_MULTIPLIER": 0.025, //every 1 defense point damage influence in battle when defense points > attack points during creature attack
-		"DEFENSE_POINTS_DMG_MULTIPLIER_CAP": 0.7, //limit of damage reduction that can be achieved by overpowering defense points
-		//chances for new hero units count - technically random number 1-100, first element in list below generated number sets count, if none then result is number of elements + 1
-		"HERO_STARTING_ARMY_STACKS_COUNT_CHANCES": [10, 80], //example: [10,80] gives 10% chance for 1 stack, 70% for 2, 20% for 3. Additionally you can add -1 as last special value to start counting from 0 and allowing empty armies
-		"DEFAULT_BUILDING_SET_DWELLING_CHANCES": [100, 50] //percent chance for dwellings to appear - for example [30,10,0,100] means 30% chance for 1st level dwelling, 10% for 2nd, 0% for 3rd, and guaranteed 4th level, no 5th, no 6th, no 7th
-	},
-	"modules":
-	{
-		"STACK_EXPERIENCE": false,
-		"STACK_ARTIFACTS": false,
-		"COMMANDERS": false,
-		"MITHRIL": false //so far unused
-	},
-	"baseBonuses" : [
-		{
-			"type" : "SPELL_DAMAGE", //Default spell damage
-			"val" : 100,
-			"valueType" : "BASE_NUMBER"
-		},
-		{
-			"type" : "MAX_LEARNABLE_SPELL_LEVEL", //Hero can always learn level 1 and 2 spells
-			"val" : 2,
-			"valueType" : "BASE_NUMBER"
-		}
-	],
-	"heroBaseBonuses":
-	[
-		{
-			"type" : "MANA_REGENERATION", //default mana regeneration
-			"val" : 1,
-			"valueType" : "BASE_NUMBER"
-		},
-		{
-			"type" : "SIGHT_RADIUS", //default sight radius
-			"val" : 5,
-			"valueType" : "BASE_NUMBER"
-		},
-		{
-			"type" : "HERO_EXPERIENCE_GAIN_PERCENT", //default hero xp
-			"val" : 100,
-			"valueType" : "BASE_NUMBER"
-		},
-		{
-			"type" : "MANA_PER_KNOWLEDGE", //10 knowledge to 100 mana is default
-			"val" : 10,
-			"valueType" : "BASE_NUMBER"
-		},
-		{
-			"type" : "MOVEMENT", //Basic land movement
-			"subtype" : 1,
-			"val" : 1300,
-			"valueType" : "BASE_NUMBER",
-			"updater" : {
-				"type" : "ARMY_MOVEMENT", //Enable army movement bonus
-				"parameters" : [20, //Movement points for lowest speed numerator
-							 	3, //Movement points for lowest speed denominator
-								10, //Resulting improper fraction will be multiplied by this number
-								700] //All army movement bonus cannot be higher than this value (so, max movement will be 1300 + 700 for this settings)
-			}
-		},
-		{
-			"type" : "MOVEMENT", //Basic sea movement
-			"subtype" : 0,
-			"val" : 1500,
-			"valueType" : "BASE_NUMBER"
-		}
-	]
-}

+ 117 - 1
config/gameConfig.json

@@ -104,5 +104,121 @@
 	"obstacles":
 	[
 		"config/obstacles.json"
-	]
+	],
+	
+	"settings":
+	{
+		"textData" :
+		{
+			"heroClass"  : 18,
+			"artifact"   : 144,
+			"creature"   : 150,
+			"faction"    : 9,
+			"hero"       : 156,
+			"spell"      : 81,
+			"object"     : 256,
+			"terrain"    : 10,
+			"river"      : 5,
+			"road"       : 4,
+			"mapVersion" : 28 // max supported version, SoD
+		},
+
+		"hardcodedFeatures" :
+		{
+			"CREEP_SIZE": 4000,
+			"WEEKLY_GROWTH_PERCENT" : 10,
+			"NEUTRAL_STACK_EXP_DAILY" : 500,
+			"MAX_BUILDING_PER_TURN" : 1,
+			"DWELLINGS_ACCUMULATE_CREATURES" : false,
+			"ALL_CREATURES_GET_DOUBLE_MONTHS" : false,
+			"NEGATIVE_LUCK" : false,
+			"MAX_HEROES_AVAILABLE_PER_PLAYER" : 16,
+			"MAX_HEROES_ON_MAP_PER_PLAYER" : 8,
+			"WINNING_HERO_WITH_NO_TROOPS_RETREATS": true,
+			"BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE": true,
+			"NO_RANDOM_SPECIAL_WEEKS_AND_MONTHS": false,
+			"ATTACK_POINT_DMG_MULTIPLIER": 0.05, //every 1 attack point damage influence in battle when attack points > defense points during creature attack
+			"ATTACK_POINTS_DMG_MULTIPLIER_CAP": 4.0, //limit of damage increase that can be achieved by overpowering attack points
+			"DEFENSE_POINT_DMG_MULTIPLIER": 0.025, //every 1 defense point damage influence in battle when defense points > attack points during creature attack
+			"DEFENSE_POINTS_DMG_MULTIPLIER_CAP": 0.7, //limit of damage reduction that can be achieved by overpowering defense points
+			//chances for new hero units count - technically random number 1-100, first element in list below generated number sets count, if none then result is number of elements + 1
+			"HERO_STARTING_ARMY_STACKS_COUNT_CHANCES": [10, 80], //example: [10,80] gives 10% chance for 1 stack, 70% for 2, 20% for 3. Additionally you can add -1 as last special value to start counting from 0 and allowing empty armies
+			"DEFAULT_BUILDING_SET_DWELLING_CHANCES": [100, 50] //percent chance for dwellings to appear - for example [30,10,0,100] means 30% chance for 1st level dwelling, 10% for 2nd, 0% for 3rd, and guaranteed 4th level, no 5th, no 6th, no 7th
+		},
+		"modules":
+		{
+			"STACK_EXPERIENCE": false,
+			"STACK_ARTIFACTS": false,
+			"COMMANDERS": false
+		},
+		
+		"bonuses" : 
+		{
+			"global" : 
+			{
+				"spellDamage" : 
+				{
+					"type" : "SPELL_DAMAGE", //Default spell damage
+					"val" : 100,
+					"valueType" : "BASE_NUMBER"
+				},
+				"wisdomBase" : 
+				{
+					"type" : "MAX_LEARNABLE_SPELL_LEVEL", //Hero can always learn level 1 and 2 spells
+					"val" : 2,
+					"valueType" : "BASE_NUMBER"
+				}
+			},
+			"heroes":
+			{
+				"manaRegeneration" :
+				{
+					"type" : "MANA_REGENERATION", //default mana regeneration
+					"val" : 1,
+					"valueType" : "BASE_NUMBER"
+				},
+				"sightRadius" :
+				{
+					"type" : "SIGHT_RADIUS", //default sight radius
+					"val" : 5,
+					"valueType" : "BASE_NUMBER"
+				},
+				"experienceGain" : 
+				{
+					"type" : "HERO_EXPERIENCE_GAIN_PERCENT", //default hero xp
+					"val" : 100,
+					"valueType" : "BASE_NUMBER"
+				},
+				"manaPerKnowledge" :
+				{
+					"type" : "MANA_PER_KNOWLEDGE", //10 knowledge to 100 mana is default
+					"val" : 10,
+					"valueType" : "BASE_NUMBER"
+				},
+				"landMovement" :
+				{
+					"type" : "MOVEMENT", //Basic land movement
+					"subtype" : 1,
+					"val" : 1300,
+					"valueType" : "BASE_NUMBER",
+					"updater" : {
+						"type" : "ARMY_MOVEMENT", //Enable army movement bonus
+						"parameters" : [
+							20, // Movement points for lowest speed numerator
+							3,  // Movement points for lowest speed denominator
+							10, // Resulting value, rounded down, will be multiplied by this number
+							700 // All army movement bonus cannot be higher than this value (so, max movement will be 1300 + 700 for this settings)
+						]
+					}
+				},
+				"seaMovement" :
+				{
+					"type" : "MOVEMENT", //Basic sea movement
+					"subtype" : 0,
+					"val" : 1500,
+					"valueType" : "BASE_NUMBER"
+				}
+			}
+		}
+	}
 }

+ 2 - 0
include/vcmi/Services.h

@@ -23,6 +23,7 @@ class SkillService;
 class JsonNode;
 class BattleFieldService;
 class ObstacleService;
+class IGameSettings;
 
 namespace spells
 {
@@ -58,6 +59,7 @@ public:
 	virtual const SkillService * skills() const = 0;
 	virtual const BattleFieldService * battlefields() const = 0;
 	virtual const ObstacleService * obstacles() const = 0;
+	virtual const IGameSettings * settings() const = 0;
 
 	virtual void updateEntity(Metatype metatype, int32_t index, const JsonNode & data) = 0;
 

+ 1 - 1
lib/BattleFieldHandler.cpp

@@ -41,7 +41,7 @@ BattleFieldInfo * BattleFieldHandler::loadFromJson(const std::string & scope, co
 	return info;
 }
 
-std::vector<JsonNode> BattleFieldHandler::loadLegacyData(size_t dataSize)
+std::vector<JsonNode> BattleFieldHandler::loadLegacyData()
 {
 	return std::vector<JsonNode>();
 }

+ 1 - 1
lib/BattleFieldHandler.h

@@ -78,7 +78,7 @@ public:
 		size_t index) override;
 
 	virtual const std::vector<std::string> & getTypeNames() const override;
-	virtual std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+	virtual std::vector<JsonNode> loadLegacyData() override;
 	virtual std::vector<bool> getDefaultAllowed() const override;
 
 	template <typename Handler> void serialize(Handler & h, const int version)

+ 22 - 8
lib/CArtHandler.cpp

@@ -15,6 +15,7 @@
 #include "CGeneralTextHandler.h"
 #include "VCMI_Lib.h"
 #include "CModHandler.h"
+#include "GameSettings.h"
 #include "CCreatureHandler.h"
 #include "spells/CSpellHandler.h"
 #include "mapObjects/MapObjects.h"
@@ -219,8 +220,10 @@ void CGrowingArtifact::levelUpArtifact (CArtifactInstance * art)
 
 CArtHandler::~CArtHandler() = default;
 
-std::vector<JsonNode> CArtHandler::loadLegacyData(size_t dataSize)
+std::vector<JsonNode> CArtHandler::loadLegacyData()
 {
+	size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_ARTIFACT);
+
 	objects.resize(dataSize);
 	std::vector<JsonNode> h3Data;
 	h3Data.reserve(dataSize);
@@ -300,7 +303,7 @@ CArtifact * CArtHandler::loadFromJson(const std::string & scope, const JsonNode
 
 	CArtifact * art = nullptr;
 
-	if(!VLC->modh->modules.COMMANDERS || node["growing"].isNull())
+	if(!VLC->settings()->getBoolean(EGameSettings::MODULE_COMMANDERS) || node["growing"].isNull())
 	{
 		art = new CArtifact();
 	}
@@ -604,12 +607,23 @@ bool CArtHandler::legalArtifact(const ArtifactID & id)
 {
 	auto art = objects[id];
 	//assert ( (!art->constituents) || art->constituents->size() ); //artifacts is not combined or has some components
-	return ((!art->possibleSlots[ArtBearer::HERO].empty() ||
-		(!art->possibleSlots[ArtBearer::COMMANDER].empty() && VLC->modh->modules.COMMANDERS) ||
-		(!art->possibleSlots[ArtBearer::CREATURE].empty() && VLC->modh->modules.STACK_ARTIFACT)) &&
-		!(art->constituents) && //no combo artifacts spawning
-		art->aClass >= CArtifact::ART_TREASURE &&
-		art->aClass <= CArtifact::ART_RELIC);
+
+	if(art->constituents)
+		return false; //no combo artifacts spawning
+
+	if(art->aClass < CArtifact::ART_TREASURE || art->aClass > CArtifact::ART_RELIC)
+		return false; // invalid class
+
+	if(!art->possibleSlots[ArtBearer::HERO].empty())
+		return true;
+
+	if(!art->possibleSlots[ArtBearer::CREATURE].empty() && VLC->settings()->getBoolean(EGameSettings::MODULE_STACK_ARTIFACT))
+		return true;
+
+	if(!art->possibleSlots[ArtBearer::COMMANDER].empty() && VLC->settings()->getBoolean(EGameSettings::MODULE_COMMANDERS))
+		return true;
+
+	return false;
 }
 
 void CArtHandler::initAllowedArtifactsList(const std::vector<bool> &allowed)

+ 1 - 1
lib/CArtHandler.h

@@ -261,7 +261,7 @@ public:
 
 	~CArtHandler();
 
-	std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+	std::vector<JsonNode> loadLegacyData() override;
 
 	void loadObject(std::string scope, std::string name, const JsonNode & data) override;
 	void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;

+ 6 - 3
lib/CCreatureHandler.cpp

@@ -16,6 +16,7 @@
 #include "CGameState.h"
 #include "CTownHandler.h"
 #include "CModHandler.h"
+#include "GameSettings.h"
 #include "StringConstants.h"
 #include "serializer/JsonDeserializer.h"
 #include "serializer/JsonUpdater.h"
@@ -512,8 +513,10 @@ void CCreatureHandler::loadBonuses(JsonNode & creature, std::string bonuses) con
 	}
 }
 
-std::vector<JsonNode> CCreatureHandler::loadLegacyData(size_t dataSize)
+std::vector<JsonNode> CCreatureHandler::loadLegacyData()
 {
+	size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_CREATURE);
+
 	objects.resize(dataSize);
 	std::vector<JsonNode> h3Data;
 	h3Data.reserve(dataSize);
@@ -677,7 +680,7 @@ std::vector<bool> CCreatureHandler::getDefaultAllowed() const
 
 void CCreatureHandler::loadCrExpBon()
 {
-	if (VLC->modh->modules.STACK_EXP) 	//reading default stack experience bonuses
+	if (VLC->settings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE)) 	//reading default stack experience bonuses
 	{
 		CLegacyConfigParser parser("DATA/CREXPBON.TXT");
 
@@ -793,7 +796,7 @@ void CCreatureHandler::loadAnimationInfo(std::vector<JsonNode> &h3Data) const
 	parser.endLine(); // header
 	parser.endLine();
 
-	for(int dd=0; dd<VLC->modh->settings.data["textData"]["creature"].Float(); ++dd)
+	for(int dd = 0; dd < VLC->settings()->getInteger(EGameSettings::TEXTS_CREATURE); ++dd)
 	{
 		while (parser.isNextEntryEmpty() && parser.endLine()) // skip empty lines
 			;

+ 1 - 1
lib/CCreatureHandler.h

@@ -317,7 +317,7 @@ public:
 
 	void afterLoadFinalization() override;
 
-	std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+	std::vector<JsonNode> loadLegacyData() override;
 
 	std::vector<bool> getDefaultAllowed() const override;
 

+ 4 - 3
lib/CCreatureSet.cpp

@@ -14,6 +14,7 @@
 #include "CCreatureHandler.h"
 #include "VCMI_Lib.h"
 #include "CModHandler.h"
+#include "GameSettings.h"
 #include "mapObjects/CGHeroInstance.h"
 #include "IGameCallback.h"
 #include "CGameState.h"
@@ -421,7 +422,7 @@ void CCreatureSet::setStackCount(const SlotID & slot, TQuantity count)
 {
 	assert(hasStackAtSlot(slot));
 	assert(stacks[slot]->count + count > 0);
-	if (VLC->modh->modules.STACK_EXP && count > stacks[slot]->count)
+	if (VLC->settings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE) && count > stacks[slot]->count)
 		stacks[slot]->experience = static_cast<TExpType>(stacks[slot]->experience * (count / static_cast<double>(stacks[slot]->count)));
 	stacks[slot]->count = count;
 	armyChanged();
@@ -703,7 +704,7 @@ CCreature::CreatureQuantityId CStackInstance::getQuantityID() const
 
 int CStackInstance::getExpRank() const
 {
-	if (!VLC->modh->modules.STACK_EXP)
+	if (!VLC->settings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE))
 		return 0;
 	int tier = type->level;
 	if (vstd::iswithin(tier, 1, 7))
@@ -765,7 +766,7 @@ void CStackInstance::setType(const CCreature *c)
 	if(type)
 	{
 		detachFrom(const_cast<CCreature&>(*type));
-		if (type->isMyUpgrade(c) && VLC->modh->modules.STACK_EXP)
+		if (type->isMyUpgrade(c) && VLC->settings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE))
 			experience = static_cast<TExpType>(experience * VLC->creh->expAfterUpgrade / 100.0);
 	}
 

+ 2 - 1
lib/CGameInfoCallback.cpp

@@ -17,6 +17,7 @@
 #include "battle/BattleInfo.h" // for BattleInfo
 #include "NetPacks.h" // for InfoWindow
 #include "CModHandler.h"
+#include "GameSettings.h"
 #include "TerrainHandler.h"
 #include "spells/CSpellHandler.h"
 #include "mapping/CMap.h"
@@ -603,7 +604,7 @@ EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTow
 	if (!t->genBuildingRequirements(ID).test(buildTest))
 		return EBuildingState::PREREQUIRES;
 
-	if(t->builded >= VLC->modh->settings.MAX_BUILDING_PER_TURN)
+	if(t->builded >= VLC->settings()->getInteger(EGameSettings::INT_MAX_BUILDING_PER_TURN))
 		return EBuildingState::CANT_BUILD_TODAY; //building limit
 
 	//checking resources

+ 5 - 4
lib/CGameState.cpp

@@ -20,6 +20,7 @@
 #include "CHeroHandler.h"
 #include "mapObjects/CObjectHandler.h"
 #include "CModHandler.h"
+#include "GameSettings.h"
 #include "TerrainHandler.h"
 #include "CSkillHandler.h"
 #include "mapping/CMap.h"
@@ -948,11 +949,11 @@ void CGameState::checkMapChecksum()
 
 void CGameState::initGlobalBonuses()
 {
-	const JsonNode & baseBonuses = VLC->modh->settings.data["baseBonuses"];
+	const JsonNode & baseBonuses = VLC->settings()->getValue(EGameSettings::BONUSES_LIST_GLOBAL);
 	logGlobal->debug("\tLoading global bonuses");
-	for(const auto & b : baseBonuses.Vector())
+	for(const auto & b : baseBonuses.Struct())
 	{
-		auto bonus = JsonUtils::parseBonus(b);
+		auto bonus = JsonUtils::parseBonus(b.second);
 		bonus->source = Bonus::GLOBAL;//for all
 		bonus->sid = -1; //there is one global object
 		globalEffects.addNewBonus(bonus);
@@ -1747,7 +1748,7 @@ void CGameState::initTowns()
 			if(vti->tempOwner != PlayerColor::NEUTRAL)
 				vti->builtBuildings.insert(BuildingID::TAVERN);
 
-			auto definesBuildingsChances = VLC->modh->settings.DEFAULT_BUILDING_SET_DWELLING_CHANCES;
+			auto definesBuildingsChances = VLC->settings()->getValue(EGameSettings::VECTOR_DEFAULT_BUILDING_SET_DWELLING_CHANCES).convertTo<std::vector<int32_t>>();
 
 			BuildingID basicDwellings[] = { BuildingID::DWELL_FIRST, BuildingID::DWELL_LVL_2, BuildingID::DWELL_LVL_3, BuildingID::DWELL_LVL_4, BuildingID::DWELL_LVL_5, BuildingID::DWELL_LVL_6, BuildingID::DWELL_LVL_7 };
 

+ 2 - 1
lib/CGeneralTextHandler.cpp

@@ -13,6 +13,7 @@
 #include "filesystem/Filesystem.h"
 #include "CConfigHandler.h"
 #include "CModHandler.h"
+#include "GameSettings.h"
 #include "mapObjects/CQuest.h"
 #include "VCMI_Lib.h"
 #include "Languages.h"
@@ -555,7 +556,7 @@ CGeneralTextHandler::CGeneralTextHandler():
 			scenariosCountPerCampaign.push_back(region);
 		}
 	}
-	if (VLC->modh->modules.COMMANDERS)
+	if (VLC->settings()->getBoolean(EGameSettings::MODULE_COMMANDERS))
 	{
 		if(CResourceHandler::get()->existsResource(ResourceID("DATA/ZNPC00.TXT", EResType::TEXT)))
 			readToVector("vcmi.znpc00", "DATA/ZNPC00.TXT" );

+ 7 - 2
lib/CHeroHandler.cpp

@@ -17,6 +17,7 @@
 #include "StringConstants.h"
 #include "battle/BattleHex.h"
 #include "CCreatureHandler.h"
+#include "GameSettings.h"
 #include "CModHandler.h"
 #include "CTownHandler.h"
 #include "mapObjects/CObjectHandler.h" //for hero specialty
@@ -309,8 +310,10 @@ CHeroClass * CHeroClassHandler::loadFromJson(const std::string & scope, const Js
 	return heroClass;
 }
 
-std::vector<JsonNode> CHeroClassHandler::loadLegacyData(size_t dataSize)
+std::vector<JsonNode> CHeroClassHandler::loadLegacyData()
 {
+	size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_HERO_CLASS);
+
 	objects.resize(dataSize);
 	std::vector<JsonNode> h3Data;
 	h3Data.reserve(dataSize);
@@ -777,8 +780,10 @@ static std::string genRefName(std::string input)
 	return input;
 }
 
-std::vector<JsonNode> CHeroHandler::loadLegacyData(size_t dataSize)
+std::vector<JsonNode> CHeroHandler::loadLegacyData()
 {
+	size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_HERO);
+
 	objects.resize(dataSize);
 	std::vector<JsonNode> h3Data;
 	h3Data.reserve(dataSize);

+ 2 - 2
lib/CHeroHandler.h

@@ -223,7 +223,7 @@ class DLL_LINKAGE CHeroClassHandler : public CHandlerBase<HeroClassID, HeroClass
 	void fillPrimarySkillData(const JsonNode & node, CHeroClass * heroClass, PrimarySkill::PrimarySkill pSkill) const;
 
 public:
-	std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+	std::vector<JsonNode> loadLegacyData() override;
 
 	void afterLoadFinalization() override;
 
@@ -264,7 +264,7 @@ public:
 	ui32 level(ui64 experience) const; //calculates level corresponding to given experience amount
 	ui64 reqExp(ui32 level) const; //calculates experience required for given level
 
-	std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+	std::vector<JsonNode> loadLegacyData() override;
 
 	void beforeValidate(JsonNode & object) override;
 	void loadObject(std::string scope, std::string name, const JsonNode & data) override;

+ 10 - 72
lib/CModHandler.cpp

@@ -14,6 +14,7 @@
 #include "filesystem/FileStream.h"
 #include "filesystem/AdapterLoaders.h"
 #include "filesystem/CFilesystemLoader.h"
+#include "filesystem/Filesystem.h"
 
 #include "CCreatureHandler.h"
 #include "CArtHandler.h"
@@ -29,6 +30,7 @@
 #include "Languages.h"
 #include "ScriptHandler.h"
 #include "RoadHandler.h"
+#include "GameSettings.h"
 #include "RiverHandler.h"
 #include "TerrainHandler.h"
 #include "BattleFieldHandler.h"
@@ -343,7 +345,7 @@ void CIdentifierStorage::finalize()
 ContentTypeHandler::ContentTypeHandler(IHandlerBase * handler, const std::string & objectName):
 	handler(handler),
 	objectName(objectName),
-	originalData(handler->loadLegacyData(static_cast<size_t>(VLC->modh->settings.data["textData"][objectName].Float())))
+	originalData(handler->loadLegacyData())
 {
 	for(auto & node : originalData)
 	{
@@ -729,10 +731,6 @@ void CModInfo::setEnabled(bool on)
 
 CModHandler::CModHandler() : content(std::make_shared<CContentHandler>())
 {
-	modules.COMMANDERS = false;
-	modules.STACK_ARTIFACT = false;
-	modules.STACK_EXP = false;
-	modules.MITHRIL = false;
 	for (int i = 0; i < GameConstants::RESOURCE_QUANTITY; ++i)
 	{
 		identifiers.registerObject(CModHandler::scopeBuiltin(), "resource", GameConstants::RESOURCE_NAMES[i], i);
@@ -745,72 +743,6 @@ CModHandler::CModHandler() : content(std::make_shared<CContentHandler>())
 	}
 }
 
-void CModHandler::loadConfigFromFile(const std::string & name)
-{
-	std::string paths;
-	for(const auto & p : CResourceHandler::get()->getResourceNames(ResourceID("config/" + name)))
-	{
-		paths += p.string() + ", ";
-	}
-	paths = paths.substr(0, paths.size() - 2);
-	logMod->debug("Loading hardcoded features settings from [%s], result:", paths);
-	settings.data = JsonUtils::assembleFromFiles("config/" + name);
-	const JsonNode & hardcodedFeatures = settings.data["hardcodedFeatures"];
-	settings.MAX_HEROES_AVAILABLE_PER_PLAYER = static_cast<int>(hardcodedFeatures["MAX_HEROES_AVAILABLE_PER_PLAYER"].Integer());
-	logMod->debug("\tMAX_HEROES_AVAILABLE_PER_PLAYER\t%d", settings.MAX_HEROES_AVAILABLE_PER_PLAYER);
-	settings.MAX_HEROES_ON_MAP_PER_PLAYER = static_cast<int>(hardcodedFeatures["MAX_HEROES_ON_MAP_PER_PLAYER"].Integer());
-	logMod->debug("\tMAX_HEROES_ON_MAP_PER_PLAYER\t%d", settings.MAX_HEROES_ON_MAP_PER_PLAYER);
-	settings.CREEP_SIZE = static_cast<int>(hardcodedFeatures["CREEP_SIZE"].Integer());
-	logMod->debug("\tCREEP_SIZE\t%d", settings.CREEP_SIZE);
-	settings.WEEKLY_GROWTH = static_cast<int>(hardcodedFeatures["WEEKLY_GROWTH_PERCENT"].Integer());
-	logMod->debug("\tWEEKLY_GROWTH\t%d", settings.WEEKLY_GROWTH);
-	settings.NEUTRAL_STACK_EXP = static_cast<int>(hardcodedFeatures["NEUTRAL_STACK_EXP_DAILY"].Integer());
-	logMod->debug("\tNEUTRAL_STACK_EXP\t%d", settings.NEUTRAL_STACK_EXP);
-	settings.MAX_BUILDING_PER_TURN = static_cast<int>(hardcodedFeatures["MAX_BUILDING_PER_TURN"].Integer());
-	logMod->debug("\tMAX_BUILDING_PER_TURN\t%d", settings.MAX_BUILDING_PER_TURN);
-	settings.DWELLINGS_ACCUMULATE_CREATURES = hardcodedFeatures["DWELLINGS_ACCUMULATE_CREATURES"].Bool();
-	logMod->debug("\tDWELLINGS_ACCUMULATE_CREATURES\t%d", static_cast<int>(settings.DWELLINGS_ACCUMULATE_CREATURES));
-	settings.ALL_CREATURES_GET_DOUBLE_MONTHS = hardcodedFeatures["ALL_CREATURES_GET_DOUBLE_MONTHS"].Bool();
-	logMod->debug("\tALL_CREATURES_GET_DOUBLE_MONTHS\t%d", static_cast<int>(settings.ALL_CREATURES_GET_DOUBLE_MONTHS));
-	settings.WINNING_HERO_WITH_NO_TROOPS_RETREATS = hardcodedFeatures["WINNING_HERO_WITH_NO_TROOPS_RETREATS"].Bool();
-	logMod->debug("\tWINNING_HERO_WITH_NO_TROOPS_RETREATS\t%d", static_cast<int>(settings.WINNING_HERO_WITH_NO_TROOPS_RETREATS));
-	settings.BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE = hardcodedFeatures["BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE"].Bool();
-	logMod->debug("\tBLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE\t%d", static_cast<int>(settings.BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE));
-	settings.NO_RANDOM_SPECIAL_WEEKS_AND_MONTHS = hardcodedFeatures["NO_RANDOM_SPECIAL_WEEKS_AND_MONTHS"].Bool();
-	logMod->debug("\tNO_RANDOM_SPECIAL_WEEKS_AND_MONTHS\t%d", static_cast<int>(settings.NO_RANDOM_SPECIAL_WEEKS_AND_MONTHS));
-	settings.ATTACK_POINT_DMG_MULTIPLIER = hardcodedFeatures["ATTACK_POINT_DMG_MULTIPLIER"].Float();
-	logMod->debug("\tATTACK_POINT_DMG_MULTIPLIER\t%f", settings.ATTACK_POINT_DMG_MULTIPLIER);
-	settings.ATTACK_POINTS_DMG_MULTIPLIER_CAP = hardcodedFeatures["ATTACK_POINTS_DMG_MULTIPLIER_CAP"].Float();
-	logMod->debug("\tATTACK_POINTS_DMG_MULTIPLIER_CAP\t%f", settings.ATTACK_POINTS_DMG_MULTIPLIER_CAP);
-	settings.DEFENSE_POINT_DMG_MULTIPLIER = hardcodedFeatures["DEFENSE_POINT_DMG_MULTIPLIER"].Float();
-	logMod->debug("\tDEFENSE_POINT_DMG_MULTIPLIER\t%f", settings.DEFENSE_POINT_DMG_MULTIPLIER);
-	settings.DEFENSE_POINTS_DMG_MULTIPLIER_CAP = hardcodedFeatures["DEFENSE_POINTS_DMG_MULTIPLIER_CAP"].Float();
-	logMod->debug("\tDEFENSE_POINTS_DMG_MULTIPLIER_CAP\t%f", settings.DEFENSE_POINTS_DMG_MULTIPLIER_CAP);
-
-	settings.HERO_STARTING_ARMY_STACKS_COUNT_CHANCES = hardcodedFeatures["HERO_STARTING_ARMY_STACKS_COUNT_CHANCES"].convertTo<std::vector<int32_t>>();
-	for (auto const & entry : settings.HERO_STARTING_ARMY_STACKS_COUNT_CHANCES)
-		logMod->debug("\tHERO_STARTING_ARMY_STACKS_COUNT_CHANCES\t%d", entry);
-
-	settings.DEFAULT_BUILDING_SET_DWELLING_CHANCES = hardcodedFeatures["DEFAULT_BUILDING_SET_DWELLING_CHANCES"].convertTo<std::vector<int32_t>>();
-	for (auto const & entry : settings.DEFAULT_BUILDING_SET_DWELLING_CHANCES)
-		logMod->debug("\tDEFAULT_BUILDING_SET_DWELLING_CHANCES\t%d", entry);
-
-	const JsonNode & gameModules = settings.data["modules"];
-	modules.STACK_EXP = gameModules["STACK_EXPERIENCE"].Bool();
-	logMod->debug("\tSTACK_EXP\t%d", static_cast<int>(modules.STACK_EXP));
-	modules.STACK_ARTIFACT = gameModules["STACK_ARTIFACTS"].Bool();
-	logMod->debug("\tSTACK_ARTIFACT\t%d", static_cast<int>(modules.STACK_ARTIFACT));
-	modules.COMMANDERS = gameModules["COMMANDERS"].Bool();
-	logMod->debug("\tCOMMANDERS\t%d", static_cast<int>(modules.COMMANDERS));
-	modules.MITHRIL = gameModules["MITHRIL"].Bool();
-	logMod->debug("\tMITHRIL\t%d", static_cast<int>(modules.MITHRIL));
-
-	const JsonNode & baseBonuses = VLC->modh->settings.data["heroBaseBonuses"];
-	logMod->debug("\tLoading base hero bonuses");
-	for(const auto & b : baseBonuses.Vector())
-		heroBaseBonuses.emplace_back(JsonUtils::parseBonus(b));
-}
-
 // currentList is passed by value to get current list of depending mods
 bool CModHandler::hasCircularDependency(const TModID & modID, std::set<TModID> currentList) const
 {
@@ -1127,7 +1059,13 @@ std::set<TModID> CModHandler::getModDependencies(const TModID & modId, bool & is
 
 void CModHandler::initializeConfig()
 {
-	loadConfigFromFile("defaultMods.json");
+	VLC->settingsHandler->load(coreMod.config["settings"]);
+
+	for(const TModID & modName : activeMods)
+	{
+		const auto & mod = allMods[modName];
+		VLC->settingsHandler->load(mod.config["settings"]);
+	}
 }
 
 bool CModHandler::validateTranslations(TModID modName) const

+ 1 - 74
lib/CModHandler.h

@@ -9,9 +9,6 @@
  */
 #pragma once
 
-#include "filesystem/Filesystem.h"
-
-#include "VCMI_Lib.h"
 #include "JsonNode.h"
 
 #ifdef __UCLIBC__
@@ -267,8 +264,6 @@ class DLL_LINKAGE CModHandler
 	std::vector <TModID> activeMods;//active mods, in order in which they were loaded
 	CModInfo coreMod;
 
-	void loadConfigFromFile(const std::string & name);
-
 	bool hasCircularDependency(const TModID & mod, std::set<TModID> currentList = std::set<TModID>()) const;
 
 	/**
@@ -353,72 +348,6 @@ public:
 	void load();
 	void afterLoad(bool onlyEssential);
 
-	std::vector<std::shared_ptr<Bonus>> heroBaseBonuses; //these bonuses will be applied to every hero on map
-
-	struct DLL_LINKAGE hardcodedFeatures
-	{
-		JsonNode data;
-
-		int CREEP_SIZE; // neutral stacks won't grow beyond this number
-		int WEEKLY_GROWTH; //percent
-		int NEUTRAL_STACK_EXP;
-		int MAX_BUILDING_PER_TURN;
-		bool DWELLINGS_ACCUMULATE_CREATURES;
-		bool ALL_CREATURES_GET_DOUBLE_MONTHS;
-		int MAX_HEROES_AVAILABLE_PER_PLAYER;
-		int MAX_HEROES_ON_MAP_PER_PLAYER;
-		bool WINNING_HERO_WITH_NO_TROOPS_RETREATS;
-		bool BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE;
-		bool NO_RANDOM_SPECIAL_WEEKS_AND_MONTHS;
-		double ATTACK_POINT_DMG_MULTIPLIER;
-		double ATTACK_POINTS_DMG_MULTIPLIER_CAP;
-		double DEFENSE_POINT_DMG_MULTIPLIER;
-		double DEFENSE_POINTS_DMG_MULTIPLIER_CAP;
-		std::vector<int32_t> HERO_STARTING_ARMY_STACKS_COUNT_CHANCES;
-		std::vector<int32_t> DEFAULT_BUILDING_SET_DWELLING_CHANCES;
-
-		template <typename Handler> void serialize(Handler &h, const int version)
-		{
-			h & data;
-			h & CREEP_SIZE;
-			h & WEEKLY_GROWTH;
-			h & NEUTRAL_STACK_EXP;
-			h & MAX_BUILDING_PER_TURN;
-			h & DWELLINGS_ACCUMULATE_CREATURES;
-			h & ALL_CREATURES_GET_DOUBLE_MONTHS;
-			h & MAX_HEROES_AVAILABLE_PER_PLAYER;
-			h & MAX_HEROES_ON_MAP_PER_PLAYER;
-			h & WINNING_HERO_WITH_NO_TROOPS_RETREATS;
-			h & BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE;
-			h & NO_RANDOM_SPECIAL_WEEKS_AND_MONTHS;
-			h & ATTACK_POINT_DMG_MULTIPLIER;
-			h & ATTACK_POINTS_DMG_MULTIPLIER_CAP;
-			h & DEFENSE_POINT_DMG_MULTIPLIER;
-			h & DEFENSE_POINTS_DMG_MULTIPLIER_CAP;
-			if(version >= 815)
-			{
-				h & HERO_STARTING_ARMY_STACKS_COUNT_CHANCES;
-				h & DEFAULT_BUILDING_SET_DWELLING_CHANCES;
-			}
-		}
-	} settings;
-
-	struct DLL_LINKAGE gameModules
-	{
-		bool STACK_EXP;
-		bool STACK_ARTIFACT;
-		bool COMMANDERS;
-		bool MITHRIL;
-
-		template <typename Handler> void serialize(Handler &h, const int version)
-		{
-			h & STACK_EXP;
-			h & STACK_ARTIFACT;
-			h & COMMANDERS;
-			h & MITHRIL;
-		}
-	} modules;
-
 	CModHandler();
 	virtual ~CModHandler() = default;
 
@@ -460,9 +389,7 @@ public:
 			
 			std::swap(activeMods, newActiveMods);
 		}
-				
-		h & settings;
-		h & modules;
+
 		h & identifiers;
 	}
 };

+ 1 - 1
lib/CSkillHandler.cpp

@@ -142,7 +142,7 @@ void CSkill::serializeJson(JsonSerializeFormat & handler)
 }
 
 ///CSkillHandler
-std::vector<JsonNode> CSkillHandler::loadLegacyData(size_t dataSize)
+std::vector<JsonNode> CSkillHandler::loadLegacyData()
 {
 	CLegacyConfigParser parser("DATA/SSTRAITS.TXT");
 

+ 1 - 1
lib/CSkillHandler.h

@@ -102,7 +102,7 @@ class DLL_LINKAGE CSkillHandler: public CHandlerBase<SecondarySkill, Skill, CSki
 {
 public:
 	///IHandler base
-	std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+	std::vector<JsonNode> loadLegacyData() override;
 	void afterLoadFinalization() override;
 	void beforeValidate(JsonNode & object) override;
 

+ 4 - 1
lib/CTownHandler.cpp

@@ -18,6 +18,7 @@
 #include "CModHandler.h"
 #include "CHeroHandler.h"
 #include "CArtHandler.h"
+#include "GameSettings.h"
 #include "spells/CSpellHandler.h"
 #include "filesystem/Filesystem.h"
 #include "mapObjects/CObjectClassesHandler.h"
@@ -284,8 +285,10 @@ TPropagatorPtr & CTownHandler::emptyPropagator()
 	return emptyProp;
 }
 
-std::vector<JsonNode> CTownHandler::loadLegacyData(size_t dataSize)
+std::vector<JsonNode> CTownHandler::loadLegacyData()
 {
+	size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_FACTION);
+
 	std::vector<JsonNode> dest(dataSize);
 	objects.resize(dataSize);
 

+ 1 - 1
lib/CTownHandler.h

@@ -411,7 +411,7 @@ public:
 	CTownHandler();
 	~CTownHandler();
 
-	std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+	std::vector<JsonNode> loadLegacyData() override;
 
 	void loadObject(std::string scope, std::string name, const JsonNode & data) override;
 	void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;

+ 99 - 0
lib/GameSettings.cpp

@@ -0,0 +1,99 @@
+/*
+ * GameSettings.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#include "StdInc.h"
+#include "GameSettings.h"
+
+#include "JsonNode.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+bool IGameSettings::getBoolean(EGameSettings option) const
+{
+	return getValue(option).Bool();
+}
+
+int64_t IGameSettings::getInteger(EGameSettings option) const
+{
+	return getValue(option).Integer();
+}
+
+double IGameSettings::getDouble(EGameSettings option) const
+{
+	return getValue(option).Float();
+}
+
+GameSettings::GameSettings():
+	gameSettings(static_cast<size_t>(EGameSettings::OPTIONS_COUNT))
+{
+}
+
+void GameSettings::load(const JsonNode & input)
+{
+	static std::array<std::array<std::string, 2>, 34> optionPath =
+	{ {
+		{"textData", "heroClass"},
+		{"textData", "artifact"},
+		{"textData", "creature"},
+		{"textData", "faction"},
+		{"textData", "hero"},
+		{"textData", "spell"},
+		{"textData", "object"},
+		{"textData", "terrain"},
+		{"textData", "river"},
+		{"textData", "road"},
+		{"textData", "mapVersion"},
+		{"modules", "STACK_EXPERIENCE"},
+		{"modules", "STACK_ARTIFACTS"},
+		{"modules", "COMMANDERS"},
+		{"hardcodedFeatures", "DWELLINGS_ACCUMULATE_CREATURES"},
+		{"hardcodedFeatures", "NO_RANDOM_SPECIAL_WEEKS_AND_MONTHS"},
+		{"hardcodedFeatures", "BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE"},
+		{"hardcodedFeatures", "WINNING_HERO_WITH_NO_TROOPS_RETREATS"},
+		{"hardcodedFeatures", "ALL_CREATURES_GET_DOUBLE_MONTHS"},
+		{"hardcodedFeatures", "NEGATIVE_LUCK"},
+		{"hardcodedFeatures", "CREEP_SIZE"},
+		{"hardcodedFeatures", "WEEKLY_GROWTH"},
+		{"hardcodedFeatures", "NEUTRAL_STACK_EXP"},
+		{"hardcodedFeatures", "MAX_BUILDING_PER_TURN"},
+		{"hardcodedFeatures", "MAX_HEROES_AVAILABLE_PER_PLAYER"},
+		{"hardcodedFeatures", "MAX_HEROES_ON_MAP_PER_PLAYER"},
+		{"hardcodedFeatures", "ATTACK_POINT_DMG_MULTIPLIER"},
+		{"hardcodedFeatures", "ATTACK_POINTS_DMG_MULTIPLIER_CAP"},
+		{"hardcodedFeatures", "DEFENSE_POINT_DMG_MULTIPLIER"},
+		{"hardcodedFeatures", "DEFENSE_POINTS_DMG_MULTIPLIER_CAP"},
+		{"hardcodedFeatures", "HERO_STARTING_ARMY_STACKS_COUNT_CHANCES"},
+		{"hardcodedFeatures", "DEFAULT_BUILDING_SET_DWELLING_CHANCES"},
+		{"bonuses", "global"},
+		{"bonuses", "heroes"},
+	} };
+	static_assert(static_cast<size_t>(EGameSettings::OPTIONS_COUNT) == optionPath.size(), "Missing option path");
+
+	for (size_t i = 0; i < optionPath.size(); ++i)
+	{
+		const std::string & group = optionPath[i][0];
+		const std::string & key = optionPath[i][1];
+
+		const JsonNode & optionValue = input[group][key];
+
+		if (!optionValue.isNull())
+			gameSettings[i] = optionValue;
+	}
+}
+
+const JsonNode & GameSettings::getValue(EGameSettings option) const
+{
+	assert(option < EGameSettings::OPTIONS_COUNT);
+	auto index = static_cast<size_t>(option);
+
+	return gameSettings[index];
+}
+
+
+VCMI_LIB_NAMESPACE_END

+ 88 - 0
lib/GameSettings.h

@@ -0,0 +1,88 @@
+/*
+ * GameSettings.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+class JsonNode;
+
+enum class EGameSettings
+{
+	TEXTS_HERO_CLASS,
+	TEXTS_ARTIFACT,
+	TEXTS_CREATURE,
+	TEXTS_FACTION,
+	TEXTS_HERO,
+	TEXTS_SPELL,
+	TEXTS_OBJECT,
+	TEXTS_TERRAIN,
+	TEXTS_RIVER,
+	TEXTS_ROAD,
+	TEXTS_MAP_VERSION,
+
+	MODULE_STACK_EXPERIENCE,
+	MODULE_STACK_ARTIFACT,
+	MODULE_COMMANDERS,
+
+	BOOL_WINNING_HERO_WITH_NO_TROOPS_RETREATS,
+	BOOL_BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE,
+	BOOL_NO_RANDOM_SPECIAL_WEEKS_AND_MONTHS,
+	BOOL_DWELLINGS_ACCUMULATE_CREATURES,
+	BOOL_ALL_CREATURES_GET_DOUBLE_MONTHS,
+	BOOL_NEGATIVE_LUCK,
+
+	INT_CREEP_SIZE,
+	INT_WEEKLY_GROWTH,
+	INT_NEUTRAL_STACK_EXP,
+	INT_MAX_BUILDING_PER_TURN,
+	INT_MAX_HEROES_AVAILABLE_PER_PLAYER,
+	INT_MAX_HEROES_ON_MAP_PER_PLAYER,
+	DOUBLE_ATTACK_POINT_DMG_MULTIPLIER,
+	DOUBLE_ATTACK_POINTS_DMG_MULTIPLIER_CAP,
+	DOUBLE_DEFENSE_POINT_DMG_MULTIPLIER,
+	DOUBLE_DEFENSE_POINTS_DMG_MULTIPLIER_CAP,
+	VECTOR_HERO_STARTING_ARMY_STACKS_COUNT_CHANCES,
+	VECTOR_DEFAULT_BUILDING_SET_DWELLING_CHANCES,
+
+	BONUSES_LIST_GLOBAL,
+	BONUSES_LIST_HERO,
+
+	OPTIONS_COUNT
+};
+
+class DLL_LINKAGE IGameSettings
+{
+public:
+	virtual const JsonNode & getValue(EGameSettings option) const = 0;
+
+	bool getBoolean(EGameSettings option) const;
+	int64_t getInteger(EGameSettings option) const;
+	double getDouble(EGameSettings option) const;
+};
+
+class DLL_LINKAGE GameSettings final : public IGameSettings
+{
+	std::vector<JsonNode> gameSettings;
+
+public:
+	GameSettings();
+
+	void load(const JsonNode & input);
+
+	const JsonNode & getValue(EGameSettings option) const override;
+
+	template<typename Handler>
+	void serialize(Handler & h, const int version)
+	{
+		h & gameSettings;
+	}
+};
+
+VCMI_LIB_NAMESPACE_END

+ 1 - 1
lib/IHandlerBase.h

@@ -29,7 +29,7 @@ protected:
 public:
 	/// loads all original game data in vector of json nodes
 	/// dataSize - is number of items that must be loaded (normally - constant from GameConstants)
-	virtual std::vector<JsonNode> loadLegacyData(size_t dataSize) = 0;
+	virtual std::vector<JsonNode> loadLegacyData() = 0;
 
 	/// loads single object into game. Scope is namespace of this object, same as name of source mod
 	virtual void loadObject(std::string scope, std::string name, const JsonNode & data) = 0;

+ 3 - 2
lib/NetPacksLib.cpp

@@ -29,6 +29,7 @@
 #include "CPlayerState.h"
 #include "TerrainHandler.h"
 #include "mapping/CCampaignHandler.h"
+#include "GameSettings.h"
 
 
 VCMI_LIB_NAMESPACE_BEGIN
@@ -1675,7 +1676,7 @@ void RebalanceStacks::applyGs(CGameState * gs)
 
 	const CCreature * srcType = src.army->getCreature(src.slot);
 	TQuantity srcCount = src.army->getStackCount(src.slot);
-	bool stackExp = VLC->modh->modules.STACK_EXP;
+	bool stackExp = VLC->settings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE);
 
 	if(srcCount == count) //moving whole stack
 	{
@@ -2201,7 +2202,7 @@ void BattleResult::applyGs(CGameState *gs)
 		}
 	}
 
-	if(VLC->modh->modules.STACK_EXP)
+	if(VLC->settings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE))
 	{
 		for(int i = 0; i < 2; i++)
 			if(exp[i])

+ 1 - 1
lib/ObstacleHandler.cpp

@@ -109,7 +109,7 @@ ObstacleInfo * ObstacleHandler::loadFromJson(const std::string & scope, const Js
 	return info;
 }
 
-std::vector<JsonNode> ObstacleHandler::loadLegacyData(size_t dataSize)
+std::vector<JsonNode> ObstacleHandler::loadLegacyData()
 {
 	return {};
 }

+ 1 - 1
lib/ObstacleHandler.h

@@ -91,7 +91,7 @@ public:
 										size_t index) override;
 	
 	const std::vector<std::string> & getTypeNames() const override;
-	std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+	std::vector<JsonNode> loadLegacyData() override;
 	std::vector<bool> getDefaultAllowed() const override;
 	
 	template <typename Handler> void serialize(Handler & h, const int version)

+ 4 - 1
lib/RiverHandler.cpp

@@ -12,6 +12,7 @@
 #include "RiverHandler.h"
 #include "CModHandler.h"
 #include "CGeneralTextHandler.h"
+#include "GameSettings.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -50,8 +51,10 @@ const std::vector<std::string> & RiverTypeHandler::getTypeNames() const
 	return typeNames;
 }
 
-std::vector<JsonNode> RiverTypeHandler::loadLegacyData(size_t dataSize)
+std::vector<JsonNode> RiverTypeHandler::loadLegacyData()
 {
+	size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_RIVER);
+
 	objects.resize(dataSize);
 	return {};
 }

+ 1 - 1
lib/RiverHandler.h

@@ -68,7 +68,7 @@ public:
 	RiverTypeHandler();
 
 	virtual const std::vector<std::string> & getTypeNames() const override;
-	virtual std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+	virtual std::vector<JsonNode> loadLegacyData() override;
 	virtual std::vector<bool> getDefaultAllowed() const override;
 
 	template <typename Handler> void serialize(Handler & h, const int version)

+ 4 - 1
lib/RoadHandler.cpp

@@ -12,6 +12,7 @@
 #include "RoadHandler.h"
 #include "CModHandler.h"
 #include "CGeneralTextHandler.h"
+#include "GameSettings.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -50,8 +51,10 @@ const std::vector<std::string> & RoadTypeHandler::getTypeNames() const
 	return typeNames;
 }
 
-std::vector<JsonNode> RoadTypeHandler::loadLegacyData(size_t dataSize)
+std::vector<JsonNode> RoadTypeHandler::loadLegacyData()
 {
+	size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_ROAD);
+
 	objects.resize(dataSize);
 	return {};
 }

+ 1 - 1
lib/RoadHandler.h

@@ -68,7 +68,7 @@ public:
 	RoadTypeHandler();
 
 	virtual const std::vector<std::string> & getTypeNames() const override;
-	virtual std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+	virtual std::vector<JsonNode> loadLegacyData() override;
 	virtual std::vector<bool> getDefaultAllowed() const override;
 
 	template <typename Handler> void serialize(Handler & h, const int version)

+ 1 - 1
lib/ScriptHandler.cpp

@@ -223,7 +223,7 @@ std::vector<bool> ScriptHandler::getDefaultAllowed() const
 	return std::vector<bool>();
 }
 
-std::vector<JsonNode> ScriptHandler::loadLegacyData(size_t dataSize)
+std::vector<JsonNode> ScriptHandler::loadLegacyData()
 {
 	return std::vector<JsonNode>();
 }

+ 1 - 1
lib/ScriptHandler.h

@@ -98,7 +98,7 @@ public:
 	const Script * resolveScript(const std::string & name) const;
 
 	std::vector<bool> getDefaultAllowed() const override;
-	std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+	std::vector<JsonNode> loadLegacyData() override;
 
 	ScriptPtr loadFromJson(vstd::CLoggerBase * logger, const std::string & scope, const JsonNode & json, const std::string & identifier) const;
 

+ 4 - 1
lib/TerrainHandler.cpp

@@ -12,6 +12,7 @@
 #include "TerrainHandler.h"
 #include "CModHandler.h"
 #include "CGeneralTextHandler.h"
+#include "GameSettings.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -110,8 +111,10 @@ const std::vector<std::string> & TerrainTypeHandler::getTypeNames() const
 	return typeNames;
 }
 
-std::vector<JsonNode> TerrainTypeHandler::loadLegacyData(size_t dataSize)
+std::vector<JsonNode> TerrainTypeHandler::loadLegacyData()
 {
+	size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_TERRAIN);
+
 	objects.resize(dataSize);
 
 	CLegacyConfigParser terrainParser("DATA/TERRNAME.TXT");

+ 1 - 1
lib/TerrainHandler.h

@@ -112,7 +112,7 @@ public:
 		size_t index) override;
 
 	virtual const std::vector<std::string> & getTypeNames() const override;
-	virtual std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+	virtual std::vector<JsonNode> loadLegacyData() override;
 	virtual std::vector<bool> getDefaultAllowed() const override;
 
 	template <typename Handler> void serialize(Handler & h, const int version)

+ 7 - 0
lib/VCMI_Lib.cpp

@@ -38,6 +38,7 @@
 #include "ScriptHandler.h"
 #include "BattleFieldHandler.h"
 #include "ObstacleHandler.h"
+#include "GameSettings.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -132,6 +133,11 @@ const ObstacleService * LibClasses::obstacles() const
 	return obstacleHandler;
 }
 
+const IGameSettings * LibClasses::settings() const
+{
+	return settingsHandler;
+}
+
 void LibClasses::updateEntity(Metatype metatype, int32_t index, const JsonNode & data)
 {
 	switch(metatype)
@@ -201,6 +207,7 @@ void LibClasses::init(bool onlyEssential)
 	CStopWatch pomtime;
 	CStopWatch totalTime;
 
+	createHandler(settingsHandler, "Game Settings", pomtime);
 	modh->initializeConfig();
 
 	createHandler(generaltexth, "General text", pomtime);

+ 4 - 0
lib/VCMI_Lib.h

@@ -36,6 +36,8 @@ class ObstacleHandler;
 class CTerrainViewPatternConfig;
 class CRmgTemplateStorage;
 class IHandlerBase;
+class IGameSettings;
+class GameSettings;
 
 #if SCRIPTING_ENABLED
 namespace scripting
@@ -70,6 +72,7 @@ public:
 	const SkillService * skills() const override;
 	const BattleFieldService * battlefields() const override;
 	const ObstacleService * obstacles() const override;
+	const IGameSettings * settings() const override;
 
 	void updateEntity(Metatype metatype, int32_t index, const JsonNode & data) override;
 
@@ -97,6 +100,7 @@ public:
 	CRmgTemplateStorage * tplh;
 	BattleFieldHandler * battlefieldsHandler;
 	ObstacleHandler * obstacleHandler;
+	GameSettings * settingsHandler;
 #if SCRIPTING_ENABLED
 	scripting::ScriptHandler * scriptHandler;
 #endif

+ 5 - 5
lib/battle/DamageCalculator.cpp

@@ -16,7 +16,7 @@
 #include "../HeroBonus.h"
 #include "../mapObjects/CGTownInstance.h"
 #include "../spells/CSpellHandler.h"
-#include "../CModHandler.h"
+#include "../GameSettings.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -183,8 +183,8 @@ double DamageCalculator::getAttackSkillFactor() const
 
 	if(attackAdvantage > 0)
 	{
-		const double attackMultiplier = VLC->modh->settings.ATTACK_POINT_DMG_MULTIPLIER;
-		const double attackMultiplierCap = VLC->modh->settings.ATTACK_POINTS_DMG_MULTIPLIER_CAP;
+		const double attackMultiplier = VLC->settings()->getDouble(EGameSettings::DOUBLE_ATTACK_POINT_DMG_MULTIPLIER);
+		const double attackMultiplierCap = VLC->settings()->getDouble(EGameSettings::DOUBLE_ATTACK_POINTS_DMG_MULTIPLIER_CAP);
 		const double attackFactor = std::min(attackMultiplier * attackAdvantage, attackMultiplierCap);
 
 		return attackFactor;
@@ -269,8 +269,8 @@ double DamageCalculator::getDefenseSkillFactor() const
 	//bonus from attack/defense skills
 	if(defenseAdvantage > 0) //decreasing dmg
 	{
-		const double defenseMultiplier = VLC->modh->settings.DEFENSE_POINT_DMG_MULTIPLIER;
-		const double defenseMultiplierCap = VLC->modh->settings.DEFENSE_POINTS_DMG_MULTIPLIER_CAP;
+		const double defenseMultiplier = VLC->settings()->getDouble(EGameSettings::DOUBLE_DEFENSE_POINT_DMG_MULTIPLIER);
+		const double defenseMultiplierCap = VLC->settings()->getDouble(EGameSettings::DOUBLE_DEFENSE_POINTS_DMG_MULTIPLIER_CAP);
 
 		const double dec = std::min(defenseMultiplier * defenseAdvantage, defenseMultiplierCap);
 		return dec;

+ 8 - 6
lib/mapObjects/CGHeroInstance.cpp

@@ -19,6 +19,7 @@
 #include "../CHeroHandler.h"
 #include "../TerrainHandler.h"
 #include "../RoadHandler.h"
+#include "../GameSettings.h"
 #include "../CModHandler.h"
 #include "../CSoundBase.h"
 #include "../spells/CSpellHandler.h"
@@ -312,16 +313,17 @@ void CGHeroInstance::initHero(CRandomGenerator & rand)
 	// are not attached to global bonus node but need access to some global bonuses
 	// e.g. MANA_PER_KNOWLEDGE for correct preview and initial state after recruit	for(const auto & ob : VLC->modh->heroBaseBonuses)
 	// or MOVEMENT to compute initial movement before recruiting is finished
-	for(const auto & ob : VLC->modh->heroBaseBonuses)
+	const JsonNode & baseBonuses = VLC->settings()->getValue(EGameSettings::BONUSES_LIST_HERO);
+	for(const auto & b : baseBonuses.Struct())
 	{
-		auto bonus = ob;
+		auto bonus = JsonUtils::parseBonus(b.second);
 		bonus->source = Bonus::HERO_BASE_SKILL;
 		bonus->sid = id.getNum();
 		bonus->duration = Bonus::PERMANENT;
 		addNewBonus(bonus);
 	}
 
-	if (VLC->modh->modules.COMMANDERS && !commander)
+	if (VLC->settings()->getBoolean(EGameSettings::MODULE_COMMANDERS) && !commander)
 	{
 		commander = new CCommanderInstance(type->heroClass->commander->idNumber);
 		commander->setArmyObj (castToArmyObj()); //TODO: separate function for setting commanders
@@ -339,7 +341,7 @@ void CGHeroInstance::initArmy(CRandomGenerator & rand, IArmyDescriptor * dst)
 
 	int warMachinesGiven = 0;
 
-	std::vector<int32_t> stacksCountChances = VLC->modh->settings.HERO_STARTING_ARMY_STACKS_COUNT_CHANCES;
+	auto stacksCountChances = VLC->settings()->getValue(EGameSettings::VECTOR_HERO_STARTING_ARMY_STACKS_COUNT_CHANCES).convertTo<std::vector<int32_t>>();
 
 	const int zeroStacksAllowingValue = -1;
 	bool allowZeroStacksArmy = !stacksCountChances.empty() && stacksCountChances.back() == zeroStacksAllowingValue;
@@ -436,7 +438,7 @@ void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const
 	{
 		int txt_id;
 
-		if (cb->getHeroCount(h->tempOwner, false) < VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER)//free hero slot
+		if (cb->getHeroCount(h->tempOwner, false) < VLC->settings()->getInteger(EGameSettings::INT_MAX_HEROES_ON_MAP_PER_PLAYER))//free hero slot
 		{
 			//update hero parameters
 			SetMovePoints smp;
@@ -1473,7 +1475,7 @@ void CGHeroInstance::serializeCommonOptions(JsonSerializeFormat & handler)
 	handler.serializeBool<ui8>("female", sex, 1, 0, 0xFF);
 
 	{
-		const int legacyHeroes = static_cast<int>(VLC->modh->settings.data["textData"]["hero"].Integer());
+		const int legacyHeroes = VLC->settings()->getInteger(EGameSettings::TEXTS_HERO);
 		const int moddedStart = legacyHeroes + GameConstants::HERO_PORTRAIT_SHIFT;
 
 		if(handler.saving)

+ 2 - 2
lib/mapObjects/CGMarket.cpp

@@ -17,7 +17,7 @@
 #include "../CCreatureHandler.h"
 #include "../CGameState.h"
 #include "CGTownInstance.h"
-#include "../CModHandler.h"
+#include "../GameSettings.h"
 #include "../CSkillHandler.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
@@ -277,7 +277,7 @@ std::vector<int> CGBlackMarket::availableItemsIds(EMarketMode::EMarketMode mode)
 
 void CGBlackMarket::newTurn(CRandomGenerator & rand) const
 {
-	if(!VLC->modh->settings.BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE) //check if feature changing OH3 behavior is enabled
+	if(!VLC->settings()->getBoolean(EGameSettings::BOOL_BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE)) //check if feature changing OH3 behavior is enabled
 		return;
 
 	if(cb->getDate(Date::DAY_OF_MONTH) != 1) //new month

+ 2 - 1
lib/mapObjects/CGTownInstance.cpp

@@ -17,6 +17,7 @@
 #include "../CConfigHandler.h"
 #include "../CGeneralTextHandler.h"
 #include "../CModHandler.h"
+#include "../GameSettings.h"
 #include "../IGameCallback.h"
 #include "../CGameState.h"
 #include "../mapping/CMap.h"
@@ -256,7 +257,7 @@ void CGDwelling::newTurn(CRandomGenerator & rand) const
 		{
 			CCreature *cre = VLC->creh->objects[creatures[i].second[0]];
 			TQuantity amount = cre->growth * (1 + cre->valOfBonuses(Bonus::CREATURE_GROWTH_PERCENT)/100) + cre->valOfBonuses(Bonus::CREATURE_GROWTH);
-			if (VLC->modh->settings.DWELLINGS_ACCUMULATE_CREATURES && ID != Obj::REFUGEE_CAMP) //camp should not try to accumulate different kinds of creatures
+			if (VLC->settings()->getBoolean(EGameSettings::BOOL_DWELLINGS_ACCUMULATE_CREATURES) && ID != Obj::REFUGEE_CAMP) //camp should not try to accumulate different kinds of creatures
 				sac.creatures[i].first += amount;
 			else
 				sac.creatures[i].first = amount;

+ 4 - 1
lib/mapObjects/CObjectClassesHandler.cpp

@@ -17,6 +17,7 @@
 #include "../StringConstants.h"
 #include "../CGeneralTextHandler.h"
 #include "../CModHandler.h"
+#include "../GameSettings.h"
 #include "../JsonNode.h"
 #include "../CSoundBase.h"
 
@@ -95,8 +96,10 @@ CObjectClassesHandler::~CObjectClassesHandler()
 		delete p;
 }
 
-std::vector<JsonNode> CObjectClassesHandler::loadLegacyData(size_t dataSize)
+std::vector<JsonNode> CObjectClassesHandler::loadLegacyData()
 {
+	size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_OBJECT);
+
 	CLegacyConfigParser parser("Data/Objects.txt");
 	auto totalNumber = static_cast<size_t>(parser.readNumber()); // first line contains number of objects to read and nothing else
 	parser.endLine();

+ 1 - 1
lib/mapObjects/CObjectClassesHandler.h

@@ -296,7 +296,7 @@ public:
 	CObjectClassesHandler();
 	~CObjectClassesHandler();
 
-	std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+	std::vector<JsonNode> loadLegacyData() override;
 
 	void loadObject(std::string scope, std::string name, const JsonNode & data) override;
 	void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;

+ 6 - 5
lib/mapObjects/MiscObjects.cpp

@@ -25,6 +25,7 @@
 #include "../CGameState.h"
 #include "../mapping/CMap.h"
 #include "../CPlayerState.h"
+#include "../GameSettings.h"
 #include "../serializer/JsonSerializeFormat.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
@@ -232,15 +233,15 @@ void CGCreature::newTurn(CRandomGenerator & rand) const
 {//Works only for stacks of single type of size up to 2 millions
 	if (!notGrowingTeam)
 	{
-		if (stacks.begin()->second->count < VLC->modh->settings.CREEP_SIZE && cb->getDate(Date::DAY_OF_WEEK) == 1 && cb->getDate(Date::DAY) > 1)
+		if (stacks.begin()->second->count < VLC->settings()->getInteger(EGameSettings::INT_CREEP_SIZE) && cb->getDate(Date::DAY_OF_WEEK) == 1 && cb->getDate(Date::DAY) > 1)
 		{
-			ui32 power = static_cast<ui32>(temppower * (100 + VLC->modh->settings.WEEKLY_GROWTH) / 100);
-			cb->setObjProperty(id, ObjProperty::MONSTER_COUNT, std::min(power / 1000, static_cast<ui32>(VLC->modh->settings.CREEP_SIZE))); //set new amount
+			ui32 power = static_cast<ui32>(temppower * (100 + VLC->settings()->getInteger(EGameSettings::INT_WEEKLY_GROWTH)) / 100);
+			cb->setObjProperty(id, ObjProperty::MONSTER_COUNT, std::min<uint32_t>(power / 1000, VLC->settings()->getInteger(EGameSettings::INT_CREEP_SIZE))); //set new amount
 			cb->setObjProperty(id, ObjProperty::MONSTER_POWER, power); //increase temppower
 		}
 	}
-	if (VLC->modh->modules.STACK_EXP)
-		cb->setObjProperty(id, ObjProperty::MONSTER_EXP, VLC->modh->settings.NEUTRAL_STACK_EXP); //for testing purpose
+	if (VLC->settings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE))
+		cb->setObjProperty(id, ObjProperty::MONSTER_EXP, VLC->settings()->getInteger(EGameSettings::INT_NEUTRAL_STACK_EXP)); //for testing purpose
 }
 void CGCreature::setPropertyDer(ui8 what, ui32 val)
 {

+ 1 - 1
lib/rmg/CRmgTemplateStorage.cpp

@@ -49,7 +49,7 @@ std::vector<bool> CRmgTemplateStorage::getDefaultAllowed() const
 	return std::vector<bool>();
 }
 
-std::vector<JsonNode> CRmgTemplateStorage::loadLegacyData(size_t dataSize)
+std::vector<JsonNode> CRmgTemplateStorage::loadLegacyData()
 {
 	return std::vector<JsonNode>();
 	//it would be cool to load old rmg.txt files

+ 1 - 1
lib/rmg/CRmgTemplateStorage.h

@@ -25,7 +25,7 @@ public:
 	CRmgTemplateStorage() = default;
 	
 	std::vector<bool> getDefaultAllowed() const override;
-	std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+	std::vector<JsonNode> loadLegacyData() override;
 
 	/// loads single object into game. Scope is namespace of this object, same as name of source mod
 	virtual void loadObject(std::string scope, std::string name, const JsonNode & data) override;

+ 1 - 1
lib/spells/CSpellHandler.cpp

@@ -559,7 +559,7 @@ bool DLL_LINKAGE isInScreenRange(const int3 & center, const int3 & pos)
 }
 
 ///CSpellHandler
-std::vector<JsonNode> CSpellHandler::loadLegacyData(size_t dataSize)
+std::vector<JsonNode> CSpellHandler::loadLegacyData()
 {
 	using namespace SpellConfig;
 	std::vector<JsonNode> legacyData;

+ 1 - 1
lib/spells/CSpellHandler.h

@@ -365,7 +365,7 @@ class DLL_LINKAGE CSpellHandler: public CHandlerBase<SpellID, spells::Spell, CSp
 {
 public:
 	///IHandler base
-	std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
+	std::vector<JsonNode> loadLegacyData() override;
 	void afterLoadFinalization() override;
 	void beforeValidate(JsonNode & object) override;
 

+ 8 - 6
server/CGameHandler.cpp

@@ -28,6 +28,7 @@
 #include "../lib/CCreatureHandler.h"
 #include "../lib/CGameState.h"
 #include "../lib/CStack.h"
+#include "../lib/GameSettings.h"
 #include "../lib/battle/BattleInfo.h"
 #include "../lib/CondSh.h"
 #include "ServerNetPackVisitors.h"
@@ -987,7 +988,7 @@ void CGameHandler::battleAfterLevelUp(const BattleResult &result)
 		RemoveObject ro(finishingBattle->winnerHero->id);
 		sendAndApply(&ro);
 
-		if (VLC->modh->settings.WINNING_HERO_WITH_NO_TROOPS_RETREATS)
+		if (VLC->settings()->getBoolean(EGameSettings::BOOL_WINNING_HERO_WITH_NO_TROOPS_RETREATS))
 		{
 			SetAvailableHeroes sah;
 			sah.player = finishingBattle->victor;
@@ -1029,7 +1030,8 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
 	{
 		bat.flags |= BattleAttack::LUCKY;
 	}
-	if (VLC->modh->settings.data["hardcodedFeatures"]["NEGATIVE_LUCK"].Bool()) // negative luck enabled
+
+	if (VLC->settings()->getBoolean(EGameSettings::BOOL_NEGATIVE_LUCK)) // negative luck enabled
 	{
 		if (attackerLuck < 0 && getRandomGenerator().nextInt(23) < abs(attackerLuck))
 		{
@@ -1777,7 +1779,7 @@ void CGameHandler::newTurn()
 			n.specialWeek = NewTurn::DEITYOFFIRE;
 			n.creatureid = CreatureID::IMP;
 		}
-		else if(!VLC->modh->settings.NO_RANDOM_SPECIAL_WEEKS_AND_MONTHS)
+		else if(!VLC->settings()->getBoolean(EGameSettings::BOOL_NO_RANDOM_SPECIAL_WEEKS_AND_MONTHS))
 		{
 			int monthType = getRandomGenerator().nextInt(99);
 			if (newMonth) //new month
@@ -1785,7 +1787,7 @@ void CGameHandler::newTurn()
 				if (monthType < 40) //double growth
 				{
 					n.specialWeek = NewTurn::DOUBLE_GROWTH;
-					if (VLC->modh->settings.ALL_CREATURES_GET_DOUBLE_MONTHS)
+					if (VLC->settings()->getBoolean(EGameSettings::BOOL_ALL_CREATURES_GET_DOUBLE_MONTHS))
 					{
 						std::pair<int, CreatureID> newMonster(54, VLC->creh->pickRandomMonster(getRandomGenerator()));
 						n.creatureid = newMonster.second;
@@ -4364,8 +4366,8 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, PlayerColor pl
 //	if ((p->resources.at(Res::GOLD)<GOLD_NEEDED  && complain("Not enough gold for buying hero!"))
 //		|| (getHeroCount(player, false) >= GameConstants::MAX_HEROES_PER_PLAYER && complain("Cannot hire hero, only 8 wandering heroes are allowed!")))
 	if ((p->resources.at(Res::GOLD) < GameConstants::HERO_GOLD_COST && complain("Not enough gold for buying hero!"))
-		|| ((getHeroCount(player, false) >= VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER && complain("Cannot hire hero, too many wandering heroes already!")))
-		|| ((getHeroCount(player, true) >= VLC->modh->settings.MAX_HEROES_AVAILABLE_PER_PLAYER && complain("Cannot hire hero, too many heroes garrizoned and wandering already!"))))
+		|| ((getHeroCount(player, false) >= VLC->settings()->getInteger(EGameSettings::INT_MAX_HEROES_ON_MAP_PER_PLAYER) && complain("Cannot hire hero, too many wandering heroes already!")))
+		|| ((getHeroCount(player, true) >= VLC->settings()->getInteger(EGameSettings::INT_MAX_HEROES_AVAILABLE_PER_PLAYER) && complain("Cannot hire hero, too many heroes garrizoned and wandering already!"))))
 	{
 		return false;
 	}