浏览代码

Fixed Scholar handling

Ivan Savenko 2 年之前
父节点
当前提交
ce480c8c84

+ 5 - 9
config/objects/rewardableScholar.json

@@ -41,7 +41,7 @@
 						"appearChance" : { "min" : 0, "max" : 33 },
 						"message" : 115,
 						"limiter" : {
-							"canLearnSpell" : [
+							"canLearnSpells" : [
 								"@gainedSpell"
 							]
 						},
@@ -57,7 +57,7 @@
 							// Hero does not have this skill at expert
 							"noneOf" : [
 									{
-									"secondarySkill" : {
+									"secondary" : {
 										"@gainedSkill" : 3
 									}
 								}
@@ -68,13 +68,9 @@
 									"canLearnSkills" : true
 								},
 								{
-									"noneOf" : [
-										{
-											"secondarySkill" : {
-												"@gainedSkill" : 1
-											}
-										}
-									]
+									"secondary" : {
+										"@gainedSkill" : 1
+									}
 								}
 							]
 						},

+ 20 - 12
lib/JsonRandom.cpp

@@ -107,6 +107,15 @@ namespace JsonRandom
 		return PrimarySkill(*VLC->identifiers()->getIdentifier("primarySkill", value));
 	}
 
+	template<>
+	PrimarySkill decodeKey(const std::string & modScope, const std::string & value, const Variables & variables)
+	{
+		if (value.empty() || value[0] != '@')
+			return PrimarySkill(*VLC->identifiers()->getIdentifier(modScope, "primarySkill", value));
+		else
+			return PrimarySkill(loadVariable("primarySkill", value, variables, static_cast<int>(PrimarySkill::NONE)));
+	}
+
 	/// Method that allows type-specific object filtering
 	/// Default implementation is to accept all input objects
 	template<typename IdentifierType>
@@ -300,25 +309,24 @@ namespace JsonRandom
 
 	std::vector<si32> loadPrimaries(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
 	{
-		std::vector<si32> ret;
+		std::vector<si32> ret(GameConstants::PRIMARY_SKILLS, 0);
+		std::set<PrimarySkill> defaultSkills{
+			PrimarySkill::ATTACK,
+			PrimarySkill::DEFENSE,
+			PrimarySkill::SPELL_POWER,
+			PrimarySkill::KNOWLEDGE
+		};
+
 		if(value.isStruct())
 		{
-			for(const auto & name : NPrimarySkill::names)
+			for(const auto & pair : value.Struct())
 			{
-				ret.push_back(loadValue(value[name], rng, variables));
+				PrimarySkill id = decodeKey<PrimarySkill>(pair.second.meta, pair.first, variables);
+				ret[static_cast<int>(id)] += loadValue(pair.second, rng, variables);
 			}
 		}
 		if(value.isVector())
 		{
-			std::set<PrimarySkill> defaultSkills{
-				PrimarySkill::ATTACK,
-				PrimarySkill::DEFENSE,
-				PrimarySkill::SPELL_POWER,
-				PrimarySkill::KNOWLEDGE
-			};
-
-			ret.resize(GameConstants::PRIMARY_SKILLS, 0);
-
 			for(const auto & element : value.Vector())
 			{
 				std::set<PrimarySkill> potentialPicks = filterKeys(element, defaultSkills, variables);

+ 9 - 3
lib/mapObjects/CRewardableObject.cpp

@@ -55,12 +55,18 @@ std::vector<Component> CRewardableObject::loadComponents(const CGHeroInstance *
 {
 	std::vector<Component> result;
 
-	if (rewardIndices.size() > 1)
+	if (rewardIndices.empty())
+		return result;
+
+	if (configuration.selectMode != Rewardable::SELECT_FIRST)
+	{
 		for (auto index : rewardIndices)
 			result.push_back(configuration.info.at(index).reward.getDisplayedComponent(contextHero));
-
-	if (rewardIndices.size() == 1)
+	}
+	else
+	{
 		configuration.info.at(rewardIndices.front()).reward.loadComponents(result, contextHero);
+	}
 
 	return result;
 }

+ 47 - 4
lib/mapping/MapFormatH3M.cpp

@@ -27,6 +27,7 @@
 #include "../TerrainHandler.h"
 #include "../TextOperations.h"
 #include "../VCMI_Lib.h"
+#include "../constants/StringConstants.h"
 #include "../filesystem/CBinaryReader.h"
 #include "../filesystem/Filesystem.h"
 #include "../mapObjectConstructors/AObjectTypeHandler.h"
@@ -1189,11 +1190,53 @@ CGObjectInstance * CMapLoaderH3M::readScholar(const int3 & position, std::shared
 	};
 
 	auto * object = readGeneric(position, objectTemplate);
-	//auto * rewardable = dynamic_cast<CRewardableObject*>(object);
+	auto * rewardable = dynamic_cast<CRewardableObject*>(object);
+
+	uint8_t bonusTypeRaw = reader->readUInt8();
+	auto bonusType = static_cast<ScholarBonusType>(bonusTypeRaw);
+	auto bonusID = reader->readUInt8();
+
+	switch (bonusType)
+	{
+		case ScholarBonusType::PRIM_SKILL:
+		{
+			JsonNode variable;
+			JsonNode dice;
+			variable.String() = NPrimarySkill::names[bonusID];
+			variable.setMeta(ModScope::scopeGame());
+			dice.Integer() = 80;
+			rewardable->configuration.presetVariable("primarySkill", "gainedStat", variable);
+			rewardable->configuration.presetVariable("dice", "0", dice);
+			break;
+		}
+		case ScholarBonusType::SECONDARY_SKILL:
+		{
+			JsonNode variable;
+			JsonNode dice;
+			variable.String() = VLC->skills()->getByIndex(bonusID)->getJsonKey();
+			variable.setMeta(ModScope::scopeGame());
+			dice.Integer() = 50;
+			rewardable->configuration.presetVariable("secondarySkill", "gainedSkill", variable);
+			rewardable->configuration.presetVariable("dice", "0", dice);
+			break;
+		}
+		case ScholarBonusType::SPELL:
+		{
+			JsonNode variable;
+			JsonNode dice;
+			variable.String() = VLC->spells()->getByIndex(bonusID)->getJsonKey();
+			variable.setMeta(ModScope::scopeGame());
+			dice.Integer() = 20;
+			rewardable->configuration.presetVariable("spell", "gainedSpell", variable);
+			rewardable->configuration.presetVariable("dice", "0", dice);
+			break;
+		}
+		case ScholarBonusType::RANDOM:
+			break;// No-op
+		default:
+			logGlobal->warn("Map '%s': Invalid Scholar settings! Ignoring...", mapName);
+	}
 
-	/*uint8_t bonusTypeRaw =*/ reader->readUInt8();
-	/*auto bonusType = static_cast<ScholarBonusType>(bonusTypeRaw);*/
-	/*auto bonusID =*/ reader->readUInt8();
 	reader->skipZero(6);
 	return object;
 }

+ 6 - 1
lib/rewardable/Info.cpp

@@ -268,7 +268,12 @@ void Rewardable::Info::configureRewards(
 
 			if (!diceValue.has_value())
 			{
-				object.initVariable("dice", diceID, rng.getIntRange(0, 99)());
+				const JsonNode & preset = object.getPresetVariable("dice", diceID);
+				if (preset.isNull())
+					object.initVariable("dice", diceID, rng.getIntRange(0, 99)());
+				else
+					object.initVariable("dice", diceID, preset.Integer());
+
 				diceValue = object.getVariable("dice", diceID);
 			}
 			assert(diceValue.has_value());