diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 242479ff0..011097569 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -740,6 +740,7 @@ void CGameState::init(const IMapService * mapService, StartInfo * si, bool allow logGlobal->debug("Initialization:"); + initGlobalBonuses(); initPlayerStates(); placeCampaignHeroes(); initGrailPosition(); @@ -934,6 +935,19 @@ void CGameState::checkMapChecksum() } } +void CGameState::initGlobalBonuses() +{ + const JsonNode & baseBonuses = VLC->modh->settings.data["baseBonuses"]; + logGlobal->debug("\tLoading global bonuses"); + for(const auto & b : baseBonuses.Vector()) + { + auto bonus = JsonUtils::parseBonus(b); + bonus->source = Bonus::GLOBAL;//for all + bonus->sid = -1; //there is one global object + globalEffects.addNewBonus(bonus); + } +} + void CGameState::initGrailPosition() { logGlobal->debug("\tPicking grail position"); diff --git a/lib/CGameState.h b/lib/CGameState.h index 1e747fc4b..c839c9283 100644 --- a/lib/CGameState.h +++ b/lib/CGameState.h @@ -252,6 +252,7 @@ private: void initNewGame(const IMapService * mapService, bool allowSavingRandomMap); void initCampaign(); void checkMapChecksum(); + void initGlobalBonuses(); void initGrailPosition(); void initRandomFactionsForPlayers(); void randomizeMapObjects(); diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp index 7516bfc84..281e915ba 100644 --- a/lib/CModHandler.cpp +++ b/lib/CModHandler.cpp @@ -812,6 +812,11 @@ void CModHandler::loadConfigFromFile (std::string name) 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 diff --git a/lib/CModHandler.h b/lib/CModHandler.h index a3953e7be..2af8a1227 100644 --- a/lib/CModHandler.h +++ b/lib/CModHandler.h @@ -354,6 +354,8 @@ 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; diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index 35fecc5dc..d3e9f582c 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -356,6 +356,7 @@ public: BONUS_SOURCE(SPECIAL_WEEK)\ BONUS_SOURCE(STACK_EXPERIENCE)\ BONUS_SOURCE(COMMANDER) /*TODO: consider using simply STACK_INSTANCE */\ + BONUS_SOURCE(GLOBAL) /*used for base bonuses which all heroes or all stacks should have*/\ BONUS_SOURCE(OTHER) /*used for defensive stance and default value of spell level limit*/ #define BONUS_VALUE_LIST \ diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 5b024e1bb..0ab64f8c2 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -311,6 +311,20 @@ void CGHeroInstance::initHero(CRandomGenerator & rand) levelUpAutomatically(rand); } + // load base hero bonuses, TODO: per-map loading of base hero bonuses + // must be done separately from global bonuses since recruitable heroes in taverns + // 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) + { + auto bonus = ob; + bonus->source = Bonus::HERO_BASE_SKILL; + bonus->sid = id.getNum(); + bonus->duration = Bonus::PERMANENT; + addNewBonus(bonus); + } + if (VLC->modh->modules.COMMANDERS && !commander) { commander = new CCommanderInstance(type->heroClass->commander->idNumber);