diff --git a/AI/Nullkiller/AIGateway.cpp b/AI/Nullkiller/AIGateway.cpp index 37e9d0d0d..9d57cbd93 100644 --- a/AI/Nullkiller/AIGateway.cpp +++ b/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; diff --git a/AI/Nullkiller/AIUtility.cpp b/AI/Nullkiller/AIUtility.cpp index 7bd82c32c..c7f6f419c 100644 --- a/AI/Nullkiller/AIUtility.cpp +++ b/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: diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index 83b272c9e..9f06ff2d6 100644 --- a/AI/VCAI/VCAI.cpp +++ b/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; diff --git a/client/CGameInfo.cpp b/client/CGameInfo.cpp index 0c56d91a7..59a523e2b 100644 --- a/client/CGameInfo.cpp +++ b/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."); diff --git a/client/CGameInfo.h b/client/CGameInfo.h index 042538337..76b58a610 100644 --- a/client/CGameInfo.h +++ b/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 modh; //public? ConstTransitivePtr battleFieldHandler; ConstTransitivePtr heroh; diff --git a/client/CServerHandler.cpp b/client/CServerHandler.cpp index b8f8900c4..6befa3694 100644 --- a/client/CServerHandler.cpp +++ b/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" diff --git a/client/Client.cpp b/client/Client.cpp index d00dcc5a1..2eb619a13 100644 --- a/client/Client.cpp +++ b/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 "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 "battle/BattleInterface.h" -#include "../lib/CThreadHelper.h" -#include "../lib/registerTypes/RegisterTypes.h" -#include "gui/CGuiHandler.h" #include "CServerHandler.h" -#include "serializer/BinaryDeserializer.h" +#include "ClientNetPackVisitors.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 "../lib/serializer/Connection.h" + #include #if SCRIPTING_ENABLED diff --git a/client/ClientCommandManager.cpp b/client/ClientCommandManager.cpp index 41d9dc73f..deb358c16 100644 --- a/client/ClientCommandManager.cpp +++ b/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" diff --git a/client/adventureMap/CList.cpp b/client/adventureMap/CList.cpp index bb08867d8..85aaa9383 100644 --- a/client/adventureMap/CList.cpp +++ b/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 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(); diff --git a/client/lobby/RandomMapTab.cpp b/client/lobby/RandomMapTab.cpp index caa03f400..5387c5467 100644 --- a/client/lobby/RandomMapTab.cpp +++ b/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(): diff --git a/client/lobby/SelectionTab.cpp b/client/lobby/SelectionTab.cpp index ab83cb5ab..d3c22e77c 100644 --- a/client/lobby/SelectionTab.cpp +++ b/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 & 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) diff --git a/client/renderSDL/CBitmapFont.cpp b/client/renderSDL/CBitmapFont.cpp index 37c88b867..93753f70c 100644 --- a/client/renderSDL/CBitmapFont.cpp +++ b/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 diff --git a/client/widgets/MiscWidgets.cpp b/client/widgets/MiscWidgets.cpp index 3de32df6e..cc2b5dc14 100644 --- a/client/widgets/MiscWidgets.cpp +++ b/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("itpt", iconIndex, 0, 3, 2); diff --git a/client/windows/CCastleInterface.cpp b/client/windows/CCastleInterface.cpp index 0d6e97de0..62c3b8807 100644 --- a/client/windows/CCastleInterface.cpp +++ b/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(); diff --git a/client/windows/CCreatureWindow.cpp b/client/windows/CCreatureWindow.cpp index 025848a0d..bb4113423 100644 --- a/client/windows/CCreatureWindow.cpp +++ b/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(this, pos.h, showExp, showArt); diff --git a/client/windows/CKingdomInterface.cpp b/client/windows/CKingdomInterface.cpp index e2b25c079..bbc0199df 100644 --- a/client/windows/CKingdomInterface.cpp +++ b/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(313, 3, 4, Point(232,0), town->getUpperArmy(), town->visitingHero, true, true, true); heroes = std::make_shared(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("ITPT", iconIndex, 0, 5, 6); openTown = std::make_shared(Rect(5, 6, 58, 64), town); diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index 444ec38ba..d82339ee3 100644 --- a/client/windows/GUIClasses.cpp +++ b/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))); diff --git a/cmake_modules/VCMI_lib.cmake b/cmake_modules/VCMI_lib.cmake index 041bc386b..db6360cea 100644 --- a/cmake_modules/VCMI_lib.cmake +++ b/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 diff --git a/config/defaultMods.json b/config/defaultMods.json deleted file mode 100644 index ea74236e0..000000000 --- a/config/defaultMods.json +++ /dev/null @@ -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" - } - ] -} diff --git a/config/gameConfig.json b/config/gameConfig.json index b96d7f028..40ea0ce3f 100644 --- a/config/gameConfig.json +++ b/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" + } + } + } + } } diff --git a/include/vcmi/Services.h b/include/vcmi/Services.h index 33535a1d4..ea7977331 100644 --- a/include/vcmi/Services.h +++ b/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; diff --git a/lib/BattleFieldHandler.cpp b/lib/BattleFieldHandler.cpp index 9a6f6b451..31e9813c3 100644 --- a/lib/BattleFieldHandler.cpp +++ b/lib/BattleFieldHandler.cpp @@ -41,7 +41,7 @@ BattleFieldInfo * BattleFieldHandler::loadFromJson(const std::string & scope, co return info; } -std::vector BattleFieldHandler::loadLegacyData(size_t dataSize) +std::vector BattleFieldHandler::loadLegacyData() { return std::vector(); } diff --git a/lib/BattleFieldHandler.h b/lib/BattleFieldHandler.h index 34d60d8be..ecc8ef227 100644 --- a/lib/BattleFieldHandler.h +++ b/lib/BattleFieldHandler.h @@ -78,7 +78,7 @@ public: size_t index) override; virtual const std::vector & getTypeNames() const override; - virtual std::vector loadLegacyData(size_t dataSize) override; + virtual std::vector loadLegacyData() override; virtual std::vector getDefaultAllowed() const override; template void serialize(Handler & h, const int version) diff --git a/lib/CArtHandler.cpp b/lib/CArtHandler.cpp index 3eb4f13a4..a0eefbeef 100644 --- a/lib/CArtHandler.cpp +++ b/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 CArtHandler::loadLegacyData(size_t dataSize) +std::vector CArtHandler::loadLegacyData() { + size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_ARTIFACT); + objects.resize(dataSize); std::vector 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 &allowed) diff --git a/lib/CArtHandler.h b/lib/CArtHandler.h index ccf18bde4..a943d409b 100644 --- a/lib/CArtHandler.h +++ b/lib/CArtHandler.h @@ -261,7 +261,7 @@ public: ~CArtHandler(); - std::vector loadLegacyData(size_t dataSize) override; + std::vector 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; diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index 55cf5f668..d07d876bc 100644 --- a/lib/CCreatureHandler.cpp +++ b/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 CCreatureHandler::loadLegacyData(size_t dataSize) +std::vector CCreatureHandler::loadLegacyData() { + size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_CREATURE); + objects.resize(dataSize); std::vector h3Data; h3Data.reserve(dataSize); @@ -677,7 +680,7 @@ std::vector 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 &h3Data) const parser.endLine(); // header parser.endLine(); - for(int dd=0; ddmodh->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 ; diff --git a/lib/CCreatureHandler.h b/lib/CCreatureHandler.h index 9c3b2d32d..3e6175dab 100644 --- a/lib/CCreatureHandler.h +++ b/lib/CCreatureHandler.h @@ -317,7 +317,7 @@ public: void afterLoadFinalization() override; - std::vector loadLegacyData(size_t dataSize) override; + std::vector loadLegacyData() override; std::vector getDefaultAllowed() const override; diff --git a/lib/CCreatureSet.cpp b/lib/CCreatureSet.cpp index cf69afdd9..6db38dfa0 100644 --- a/lib/CCreatureSet.cpp +++ b/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(stacks[slot]->experience * (count / static_cast(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(*type)); - if (type->isMyUpgrade(c) && VLC->modh->modules.STACK_EXP) + if (type->isMyUpgrade(c) && VLC->settings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE)) experience = static_cast(experience * VLC->creh->expAfterUpgrade / 100.0); } diff --git a/lib/CGameInfoCallback.cpp b/lib/CGameInfoCallback.cpp index 7c2a33d63..248eb6c86 100644 --- a/lib/CGameInfoCallback.cpp +++ b/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 diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index be5c92e15..272204af5 100644 --- a/lib/CGameState.cpp +++ b/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>(); 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 }; diff --git a/lib/CGeneralTextHandler.cpp b/lib/CGeneralTextHandler.cpp index 2d508be9e..3eae09b95 100644 --- a/lib/CGeneralTextHandler.cpp +++ b/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" ); diff --git a/lib/CHeroHandler.cpp b/lib/CHeroHandler.cpp index 8ac5ba2dd..fa9a0be05 100644 --- a/lib/CHeroHandler.cpp +++ b/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 CHeroClassHandler::loadLegacyData(size_t dataSize) +std::vector CHeroClassHandler::loadLegacyData() { + size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_HERO_CLASS); + objects.resize(dataSize); std::vector h3Data; h3Data.reserve(dataSize); @@ -777,8 +780,10 @@ static std::string genRefName(std::string input) return input; } -std::vector CHeroHandler::loadLegacyData(size_t dataSize) +std::vector CHeroHandler::loadLegacyData() { + size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_HERO); + objects.resize(dataSize); std::vector h3Data; h3Data.reserve(dataSize); diff --git a/lib/CHeroHandler.h b/lib/CHeroHandler.h index 91f97d5cc..4121d5b03 100644 --- a/lib/CHeroHandler.h +++ b/lib/CHeroHandler.h @@ -223,7 +223,7 @@ class DLL_LINKAGE CHeroClassHandler : public CHandlerBase loadLegacyData(size_t dataSize) override; + std::vector 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 loadLegacyData(size_t dataSize) override; + std::vector loadLegacyData() override; void beforeValidate(JsonNode & object) override; void loadObject(std::string scope, std::string name, const JsonNode & data) override; diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp index 3d4ce230e..efb06d4da 100644 --- a/lib/CModHandler.cpp +++ b/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(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()) { - 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()) } } -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(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(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(hardcodedFeatures["CREEP_SIZE"].Integer()); - logMod->debug("\tCREEP_SIZE\t%d", settings.CREEP_SIZE); - settings.WEEKLY_GROWTH = static_cast(hardcodedFeatures["WEEKLY_GROWTH_PERCENT"].Integer()); - logMod->debug("\tWEEKLY_GROWTH\t%d", settings.WEEKLY_GROWTH); - settings.NEUTRAL_STACK_EXP = static_cast(hardcodedFeatures["NEUTRAL_STACK_EXP_DAILY"].Integer()); - logMod->debug("\tNEUTRAL_STACK_EXP\t%d", settings.NEUTRAL_STACK_EXP); - settings.MAX_BUILDING_PER_TURN = static_cast(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(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(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(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(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(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>(); - 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>(); - 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(modules.STACK_EXP)); - modules.STACK_ARTIFACT = gameModules["STACK_ARTIFACTS"].Bool(); - logMod->debug("\tSTACK_ARTIFACT\t%d", static_cast(modules.STACK_ARTIFACT)); - modules.COMMANDERS = gameModules["COMMANDERS"].Bool(); - logMod->debug("\tCOMMANDERS\t%d", static_cast(modules.COMMANDERS)); - modules.MITHRIL = gameModules["MITHRIL"].Bool(); - logMod->debug("\tMITHRIL\t%d", static_cast(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 currentList) const { @@ -1127,7 +1059,13 @@ std::set 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 diff --git a/lib/CModHandler.h b/lib/CModHandler.h index 154a4a898..605ff3e93 100644 --- a/lib/CModHandler.h +++ b/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 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 currentList = std::set()) const; /** @@ -353,72 +348,6 @@ public: void load(); void afterLoad(bool onlyEssential); - std::vector> 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 HERO_STARTING_ARMY_STACKS_COUNT_CHANCES; - std::vector DEFAULT_BUILDING_SET_DWELLING_CHANCES; - - template 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 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; } }; diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 648fd2f7a..e1fc93801 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -142,7 +142,7 @@ void CSkill::serializeJson(JsonSerializeFormat & handler) } ///CSkillHandler -std::vector CSkillHandler::loadLegacyData(size_t dataSize) +std::vector CSkillHandler::loadLegacyData() { CLegacyConfigParser parser("DATA/SSTRAITS.TXT"); diff --git a/lib/CSkillHandler.h b/lib/CSkillHandler.h index 7f9cc1c16..173e53932 100644 --- a/lib/CSkillHandler.h +++ b/lib/CSkillHandler.h @@ -102,7 +102,7 @@ class DLL_LINKAGE CSkillHandler: public CHandlerBase loadLegacyData(size_t dataSize) override; + std::vector loadLegacyData() override; void afterLoadFinalization() override; void beforeValidate(JsonNode & object) override; diff --git a/lib/CTownHandler.cpp b/lib/CTownHandler.cpp index 920531d60..e76ee47cf 100644 --- a/lib/CTownHandler.cpp +++ b/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 CTownHandler::loadLegacyData(size_t dataSize) +std::vector CTownHandler::loadLegacyData() { + size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_FACTION); + std::vector dest(dataSize); objects.resize(dataSize); diff --git a/lib/CTownHandler.h b/lib/CTownHandler.h index 2e70f59eb..54ef3adec 100644 --- a/lib/CTownHandler.h +++ b/lib/CTownHandler.h @@ -411,7 +411,7 @@ public: CTownHandler(); ~CTownHandler(); - std::vector loadLegacyData(size_t dataSize) override; + std::vector 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; diff --git a/lib/GameSettings.cpp b/lib/GameSettings.cpp new file mode 100644 index 000000000..4d0f7d023 --- /dev/null +++ b/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(EGameSettings::OPTIONS_COUNT)) +{ +} + +void GameSettings::load(const JsonNode & input) +{ + static std::array, 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(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(option); + + return gameSettings[index]; +} + + +VCMI_LIB_NAMESPACE_END diff --git a/lib/GameSettings.h b/lib/GameSettings.h new file mode 100644 index 000000000..d3893fe1a --- /dev/null +++ b/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 gameSettings; + +public: + GameSettings(); + + void load(const JsonNode & input); + + const JsonNode & getValue(EGameSettings option) const override; + + template + void serialize(Handler & h, const int version) + { + h & gameSettings; + } +}; + +VCMI_LIB_NAMESPACE_END diff --git a/lib/IHandlerBase.h b/lib/IHandlerBase.h index 25daea223..5d4008a6f 100644 --- a/lib/IHandlerBase.h +++ b/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 loadLegacyData(size_t dataSize) = 0; + virtual std::vector 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; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 5e0de1263..fe93dc7a2 100644 --- a/lib/NetPacksLib.cpp +++ b/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]) diff --git a/lib/ObstacleHandler.cpp b/lib/ObstacleHandler.cpp index 225d7db79..f0b07ef15 100644 --- a/lib/ObstacleHandler.cpp +++ b/lib/ObstacleHandler.cpp @@ -109,7 +109,7 @@ ObstacleInfo * ObstacleHandler::loadFromJson(const std::string & scope, const Js return info; } -std::vector ObstacleHandler::loadLegacyData(size_t dataSize) +std::vector ObstacleHandler::loadLegacyData() { return {}; } diff --git a/lib/ObstacleHandler.h b/lib/ObstacleHandler.h index a7f38249f..9cb783162 100644 --- a/lib/ObstacleHandler.h +++ b/lib/ObstacleHandler.h @@ -91,7 +91,7 @@ public: size_t index) override; const std::vector & getTypeNames() const override; - std::vector loadLegacyData(size_t dataSize) override; + std::vector loadLegacyData() override; std::vector getDefaultAllowed() const override; template void serialize(Handler & h, const int version) diff --git a/lib/RiverHandler.cpp b/lib/RiverHandler.cpp index 8e79f507d..6710f46a2 100644 --- a/lib/RiverHandler.cpp +++ b/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 & RiverTypeHandler::getTypeNames() const return typeNames; } -std::vector RiverTypeHandler::loadLegacyData(size_t dataSize) +std::vector RiverTypeHandler::loadLegacyData() { + size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_RIVER); + objects.resize(dataSize); return {}; } diff --git a/lib/RiverHandler.h b/lib/RiverHandler.h index a8348bd9d..13444add2 100644 --- a/lib/RiverHandler.h +++ b/lib/RiverHandler.h @@ -68,7 +68,7 @@ public: RiverTypeHandler(); virtual const std::vector & getTypeNames() const override; - virtual std::vector loadLegacyData(size_t dataSize) override; + virtual std::vector loadLegacyData() override; virtual std::vector getDefaultAllowed() const override; template void serialize(Handler & h, const int version) diff --git a/lib/RoadHandler.cpp b/lib/RoadHandler.cpp index 25650b703..afaa1e282 100644 --- a/lib/RoadHandler.cpp +++ b/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 & RoadTypeHandler::getTypeNames() const return typeNames; } -std::vector RoadTypeHandler::loadLegacyData(size_t dataSize) +std::vector RoadTypeHandler::loadLegacyData() { + size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_ROAD); + objects.resize(dataSize); return {}; } diff --git a/lib/RoadHandler.h b/lib/RoadHandler.h index b31a886e6..156d7635d 100644 --- a/lib/RoadHandler.h +++ b/lib/RoadHandler.h @@ -68,7 +68,7 @@ public: RoadTypeHandler(); virtual const std::vector & getTypeNames() const override; - virtual std::vector loadLegacyData(size_t dataSize) override; + virtual std::vector loadLegacyData() override; virtual std::vector getDefaultAllowed() const override; template void serialize(Handler & h, const int version) diff --git a/lib/ScriptHandler.cpp b/lib/ScriptHandler.cpp index 4c2893d35..0fa1416af 100644 --- a/lib/ScriptHandler.cpp +++ b/lib/ScriptHandler.cpp @@ -223,7 +223,7 @@ std::vector ScriptHandler::getDefaultAllowed() const return std::vector(); } -std::vector ScriptHandler::loadLegacyData(size_t dataSize) +std::vector ScriptHandler::loadLegacyData() { return std::vector(); } diff --git a/lib/ScriptHandler.h b/lib/ScriptHandler.h index a4eda8ab2..e2ff3a7e4 100644 --- a/lib/ScriptHandler.h +++ b/lib/ScriptHandler.h @@ -98,7 +98,7 @@ public: const Script * resolveScript(const std::string & name) const; std::vector getDefaultAllowed() const override; - std::vector loadLegacyData(size_t dataSize) override; + std::vector loadLegacyData() override; ScriptPtr loadFromJson(vstd::CLoggerBase * logger, const std::string & scope, const JsonNode & json, const std::string & identifier) const; diff --git a/lib/TerrainHandler.cpp b/lib/TerrainHandler.cpp index 36f7b91ec..ec3b0c4c3 100644 --- a/lib/TerrainHandler.cpp +++ b/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 & TerrainTypeHandler::getTypeNames() const return typeNames; } -std::vector TerrainTypeHandler::loadLegacyData(size_t dataSize) +std::vector TerrainTypeHandler::loadLegacyData() { + size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_TERRAIN); + objects.resize(dataSize); CLegacyConfigParser terrainParser("DATA/TERRNAME.TXT"); diff --git a/lib/TerrainHandler.h b/lib/TerrainHandler.h index 04e3a2a6c..e9b2fa364 100644 --- a/lib/TerrainHandler.h +++ b/lib/TerrainHandler.h @@ -112,7 +112,7 @@ public: size_t index) override; virtual const std::vector & getTypeNames() const override; - virtual std::vector loadLegacyData(size_t dataSize) override; + virtual std::vector loadLegacyData() override; virtual std::vector getDefaultAllowed() const override; template void serialize(Handler & h, const int version) diff --git a/lib/VCMI_Lib.cpp b/lib/VCMI_Lib.cpp index 4f6332add..a108b8dd3 100644 --- a/lib/VCMI_Lib.cpp +++ b/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); diff --git a/lib/VCMI_Lib.h b/lib/VCMI_Lib.h index 6269e58e7..1df599701 100644 --- a/lib/VCMI_Lib.h +++ b/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 diff --git a/lib/battle/DamageCalculator.cpp b/lib/battle/DamageCalculator.cpp index fd66d745f..6cab73abb 100644 --- a/lib/battle/DamageCalculator.cpp +++ b/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; diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index f55eec2bc..33564fad4 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/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 stacksCountChances = VLC->modh->settings.HERO_STARTING_ARMY_STACKS_COUNT_CHANCES; + auto stacksCountChances = VLC->settings()->getValue(EGameSettings::VECTOR_HERO_STARTING_ARMY_STACKS_COUNT_CHANCES).convertTo>(); 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("female", sex, 1, 0, 0xFF); { - const int legacyHeroes = static_cast(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) diff --git a/lib/mapObjects/CGMarket.cpp b/lib/mapObjects/CGMarket.cpp index f711a3747..ca51f22d1 100644 --- a/lib/mapObjects/CGMarket.cpp +++ b/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 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 diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index 336889532..8ad574df6 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/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; diff --git a/lib/mapObjects/CObjectClassesHandler.cpp b/lib/mapObjects/CObjectClassesHandler.cpp index 2d25a7adf..0cc0029cb 100644 --- a/lib/mapObjects/CObjectClassesHandler.cpp +++ b/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 CObjectClassesHandler::loadLegacyData(size_t dataSize) +std::vector CObjectClassesHandler::loadLegacyData() { + size_t dataSize = VLC->settings()->getInteger(EGameSettings::TEXTS_OBJECT); + CLegacyConfigParser parser("Data/Objects.txt"); auto totalNumber = static_cast(parser.readNumber()); // first line contains number of objects to read and nothing else parser.endLine(); diff --git a/lib/mapObjects/CObjectClassesHandler.h b/lib/mapObjects/CObjectClassesHandler.h index bb8641a77..fed6b1dde 100644 --- a/lib/mapObjects/CObjectClassesHandler.h +++ b/lib/mapObjects/CObjectClassesHandler.h @@ -296,7 +296,7 @@ public: CObjectClassesHandler(); ~CObjectClassesHandler(); - std::vector loadLegacyData(size_t dataSize) override; + std::vector 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; diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index f71e00699..b2710ad84 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/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(temppower * (100 + VLC->modh->settings.WEEKLY_GROWTH) / 100); - cb->setObjProperty(id, ObjProperty::MONSTER_COUNT, std::min(power / 1000, static_cast(VLC->modh->settings.CREEP_SIZE))); //set new amount + ui32 power = static_cast(temppower * (100 + VLC->settings()->getInteger(EGameSettings::INT_WEEKLY_GROWTH)) / 100); + cb->setObjProperty(id, ObjProperty::MONSTER_COUNT, std::min(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) { diff --git a/lib/rmg/CRmgTemplateStorage.cpp b/lib/rmg/CRmgTemplateStorage.cpp index 36ba60d3d..1998c6da6 100644 --- a/lib/rmg/CRmgTemplateStorage.cpp +++ b/lib/rmg/CRmgTemplateStorage.cpp @@ -49,7 +49,7 @@ std::vector CRmgTemplateStorage::getDefaultAllowed() const return std::vector(); } -std::vector CRmgTemplateStorage::loadLegacyData(size_t dataSize) +std::vector CRmgTemplateStorage::loadLegacyData() { return std::vector(); //it would be cool to load old rmg.txt files diff --git a/lib/rmg/CRmgTemplateStorage.h b/lib/rmg/CRmgTemplateStorage.h index 8f7acef5e..64c2e2f17 100644 --- a/lib/rmg/CRmgTemplateStorage.h +++ b/lib/rmg/CRmgTemplateStorage.h @@ -25,7 +25,7 @@ public: CRmgTemplateStorage() = default; std::vector getDefaultAllowed() const override; - std::vector loadLegacyData(size_t dataSize) override; + std::vector 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; diff --git a/lib/spells/CSpellHandler.cpp b/lib/spells/CSpellHandler.cpp index 50a371fb7..e069e86c1 100644 --- a/lib/spells/CSpellHandler.cpp +++ b/lib/spells/CSpellHandler.cpp @@ -559,7 +559,7 @@ bool DLL_LINKAGE isInScreenRange(const int3 & center, const int3 & pos) } ///CSpellHandler -std::vector CSpellHandler::loadLegacyData(size_t dataSize) +std::vector CSpellHandler::loadLegacyData() { using namespace SpellConfig; std::vector legacyData; diff --git a/lib/spells/CSpellHandler.h b/lib/spells/CSpellHandler.h index a5f45874f..c00e40559 100644 --- a/lib/spells/CSpellHandler.h +++ b/lib/spells/CSpellHandler.h @@ -365,7 +365,7 @@ class DLL_LINKAGE CSpellHandler: public CHandlerBase loadLegacyData(size_t dataSize) override; + std::vector loadLegacyData() override; void afterLoadFinalization() override; void beforeValidate(JsonNode & object) override; diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index e5a41e9cc..e4fcbb9c7 100644 --- a/server/CGameHandler.cpp +++ b/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 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)= 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; }