Procházet zdrojové kódy

Fix: nextPrimarySkill crash in case when probability values are incorrect

Dmitry Orlov před 4 roky
rodič
revize
b1db6e26d1
3 změnil soubory, kde provedl 18 přidání a 3 odebrání
  1. 8 0
      lib/CHeroHandler.cpp
  2. 2 1
      lib/GameConstants.h
  3. 8 2
      lib/mapObjects/CGHeroInstance.cpp

+ 8 - 0
lib/CHeroHandler.cpp

@@ -230,6 +230,14 @@ CHeroClass * CHeroClassHandler::loadFromJson(const std::string & scope, const Js
 	fillPrimarySkillData(node, heroClass, PrimarySkill::SPELL_POWER);
 	fillPrimarySkillData(node, heroClass, PrimarySkill::KNOWLEDGE);
 
+	auto percentSumm = std::accumulate(heroClass->primarySkillLowLevel.begin(), heroClass->primarySkillLowLevel.end(), 0);
+	if(percentSumm != 100)
+		logMod->error("Hero class %s has wrong lowLevelChance values: summ should be 100, but %d instead", heroClass->identifier, percentSumm);
+
+	percentSumm = std::accumulate(heroClass->primarySkillHighLevel.begin(), heroClass->primarySkillHighLevel.end(), 0);
+	if(percentSumm != 100)
+		logMod->error("Hero class %s has wrong highLevelChance values: summ should be 100, but %d instead", heroClass->identifier, percentSumm);
+
 	for(auto skillPair : node["secondarySkills"].Struct())
 	{
 		int probability = static_cast<int>(skillPair.second.Integer());

+ 2 - 1
lib/GameConstants.h

@@ -56,7 +56,8 @@ namespace GameConstants
 	const int SKILL_GOLD_COST = 2000;
 	const int BATTLE_PENALTY_DISTANCE = 10; //if the distance is > than this, then shooting stack has distance penalty
 	const int ARMY_SIZE = 7;
-	const int SKILL_PER_HERO=8;
+	const int SKILL_PER_HERO = 8;
+	const ui32 HERO_HIGH_LEVEL = 10; // affects primary skill upgrade order
 
 	const int SKILL_QUANTITY=28;
 	const int PRIMARY_SKILLS=4;

+ 8 - 2
lib/mapObjects/CGHeroInstance.cpp

@@ -1213,7 +1213,8 @@ PrimarySkill::PrimarySkill CGHeroInstance::nextPrimarySkill(CRandomGenerator & r
 {
 	assert(gainsLevel());
 	int randomValue = rand.nextInt(99), pom = 0, primarySkill = 0;
-	const auto & skillChances = (level > 9) ? type->heroClass->primarySkillLowLevel : type->heroClass->primarySkillHighLevel;
+	const auto isLowLevelHero = level < GameConstants::HERO_HIGH_LEVEL;
+	const auto & skillChances = isLowLevelHero ? type->heroClass->primarySkillLowLevel : type->heroClass->primarySkillHighLevel;
 
 	for(; primarySkill < GameConstants::PRIMARY_SKILLS; ++primarySkill)
 	{
@@ -1223,7 +1224,12 @@ PrimarySkill::PrimarySkill CGHeroInstance::nextPrimarySkill(CRandomGenerator & r
 			break;
 		}
 	}
-
+	if(primarySkill >= GameConstants::PRIMARY_SKILLS)
+	{
+		primarySkill = rand.nextInt(GameConstants::PRIMARY_SKILLS - 1);
+		logGlobal->error("Wrong values in primarySkill%sLevel for hero class %s", isLowLevelHero ? "Low" : "High", type->heroClass->identifier);
+		randomValue = 100 / GameConstants::PRIMARY_SKILLS;
+	}
 	logGlobal->trace("The hero gets the primary skill %d with a probability of %d %%.", primarySkill, randomValue);
 	return static_cast<PrimarySkill::PrimarySkill>(primarySkill);
 }