diff --git a/AUTHORS b/AUTHORS index 2a96de947..f6e78f8f4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -75,3 +75,6 @@ Andrzej Żak aka godric3 Andrii Danylchenko * VCAI improvements + +Dmitry Orlov, + * special buildings support in fan towns, new features and bug fixes diff --git a/lib/CHeroHandler.cpp b/lib/CHeroHandler.cpp index d05c4d6d6..930dc69e6 100644 --- a/lib/CHeroHandler.cpp +++ b/lib/CHeroHandler.cpp @@ -96,6 +96,24 @@ bool CObstacleInfo::isAppropriate(ETerrainType terrainType, int specialBattlefie return vstd::contains(allowedTerrains, terrainType); } +void CHeroClassHandler::fillPrimarySkillData(const JsonNode & node, CHeroClass * heroClass, PrimarySkill::PrimarySkill pSkill) +{ + const auto & skillName = PrimarySkill::names[pSkill]; + auto currentPrimarySkillValue = (int)node["primarySkills"][skillName].Integer(); + //minimal value is 0 for attack and defense and 1 for spell power and knowledge + auto primarySkillLegalMinimum = (pSkill == PrimarySkill::ATTACK || pSkill == PrimarySkill::DEFENSE) ? 0 : 1; + + if(currentPrimarySkillValue < primarySkillLegalMinimum) + { + logMod->error("Hero class '%s' has incorrect initial value '%d' for skill '%s'. Value '%d' will be used instead.", + heroClass->identifier, currentPrimarySkillValue, skillName, primarySkillLegalMinimum); + currentPrimarySkillValue = primarySkillLegalMinimum; + } + heroClass->primarySkillInitial.push_back(currentPrimarySkillValue); + heroClass->primarySkillLowLevel.push_back((int)node["lowLevelChance"][skillName].Float()); + heroClass->primarySkillHighLevel.push_back((int)node["highLevelChance"][skillName].Float()); +} + CHeroClass * CHeroClassHandler::loadFromJson(const JsonNode & node, const std::string & identifier) { std::string affinityStr[2] = { "might", "magic" }; @@ -111,12 +129,10 @@ CHeroClass * CHeroClassHandler::loadFromJson(const JsonNode & node, const std::s heroClass->name = node["name"].String(); heroClass->affinity = vstd::find_pos(affinityStr, node["affinity"].String()); - for(const std::string & pSkill : PrimarySkill::names) - { - heroClass->primarySkillInitial.push_back((int)node["primarySkills"][pSkill].Float()); - heroClass->primarySkillLowLevel.push_back((int)node["lowLevelChance"][pSkill].Float()); - heroClass->primarySkillHighLevel.push_back((int)node["highLevelChance"][pSkill].Float()); - } + fillPrimarySkillData(node, heroClass, PrimarySkill::ATTACK); + fillPrimarySkillData(node, heroClass, PrimarySkill::DEFENSE); + fillPrimarySkillData(node, heroClass, PrimarySkill::SPELL_POWER); + fillPrimarySkillData(node, heroClass, PrimarySkill::KNOWLEDGE); for(auto skillPair : node["secondarySkills"].Struct()) { diff --git a/lib/CHeroHandler.h b/lib/CHeroHandler.h index b8b2f5e61..ca740dd7f 100644 --- a/lib/CHeroHandler.h +++ b/lib/CHeroHandler.h @@ -236,6 +236,7 @@ struct DLL_LINKAGE CObstacleInfo class DLL_LINKAGE CHeroClassHandler : public IHandlerBase { + void fillPrimarySkillData(const JsonNode & node, CHeroClass * heroClass, PrimarySkill::PrimarySkill pSkill); CHeroClass *loadFromJson(const JsonNode & node, const std::string & identifier); public: std::vector< ConstTransitivePtr > heroClasses; diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index 19c56c4db..1b6c8f4a0 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -786,13 +786,9 @@ int IBonusBearer::getPrimSkillLevel(PrimarySkill::PrimarySkill id) const { static const CSelector selectorAllSkills = Selector::type()(Bonus::PRIMARY_SKILL); static const std::string keyAllSkills = "type_PRIMARY_SKILL"; - auto allSkills = getBonuses(selectorAllSkills, keyAllSkills); - - int ret = allSkills->valOfBonuses(Selector::subtype()(id)); - - vstd::amax(ret, id/2); //minimal value is 0 for attack and defense and 1 for spell power and knowledge - return ret; + auto ret = allSkills->valOfBonuses(Selector::subtype()(id)); + return ret; //sp=0 works in old saves } si32 IBonusBearer::magicResistance() const diff --git a/lib/rmg/CMapGenerator.cpp b/lib/rmg/CMapGenerator.cpp index ab653efea..95f453430 100644 --- a/lib/rmg/CMapGenerator.cpp +++ b/lib/rmg/CMapGenerator.cpp @@ -167,10 +167,14 @@ std::string CMapGenerator::getMapDescription() const const std::string monsterStrengthStr[3] = { "weak", "normal", "strong" }; int monsterStrengthIndex = mapGenOptions->getMonsterStrength() - EMonsterStrength::GLOBAL_WEAK; //does not start from 0 + const auto * mapTemplate = mapGenOptions->getMapTemplate(); + + if(!mapTemplate) + throw rmgException("Map template for Random Map Generator is not found. Could not start the game."); std::stringstream ss; ss << boost::str(boost::format(std::string("Map created by the Random Map Generator.\nTemplate was %s, Random seed was %d, size %dx%d") + - ", levels %s, players %d, computers %d, water %s, monster %s, VCMI map") % mapGenOptions->getMapTemplate()->getName() % + ", levels %s, players %d, computers %d, water %s, monster %s, VCMI map") % mapTemplate->getName() % randomSeed % map->width % map->height % (map->twoLevel ? "2" : "1") % static_cast(mapGenOptions->getPlayerCount()) % static_cast(mapGenOptions->getCompOnlyPlayerCount()) % waterContentStr[mapGenOptions->getWaterContent()] % monsterStrengthStr[monsterStrengthIndex]);