Selaa lähdekoodia

vcmi: move obligatory marker to CSkillHandler

It is working, now it is possible to
define other obligatory skills than wisdom or magic schools,
but only 2 types of obligatory skills exists - like wisdom and
like magic school
Konstantin 2 vuotta sitten
vanhempi
sitoutus
f26fac5562
5 muutettua tiedostoa jossa 61 lisäystä ja 28 poistoa
  1. 8 0
      config/schemas/skill.json
  2. 5 0
      config/skills.json
  3. 6 3
      lib/CSkillHandler.cpp
  4. 13 1
      lib/CSkillHandler.h
  5. 29 24
      lib/mapObjects/CGHeroInstance.cpp

+ 8 - 0
config/schemas/skill.json

@@ -60,6 +60,14 @@
 			"type": "string",
 			"description": "localizable skill name"
 		},
+		"obligatoryMajor":{
+			"type": "boolean",
+			"description": "This skill is major obligatory (like H3 Wisdom)"
+		},
+		"obligatoryMinor":{
+			"type": "boolean",
+			"description": "This skill is minor obligatory (like H3 Magic school)"
+		},
 		"gainChance" : {
 			"description" : "Chance for the skill to be offered on level-up (heroClass may override)",
 			"anyOf" : [

+ 5 - 0
config/skills.json

@@ -196,6 +196,7 @@
 	},
 	"wisdom" : {
 		"index" : 7,
+		"obligatoryMajor" : true,
 		"base" : {
 			"effects" : {
 				"main" : {
@@ -401,6 +402,7 @@
 	},
 	"fireMagic" : {
 		"index" : 14,
+		"obligatoryMinor" : true,
 		"base" : {
 			"effects" : {
 				"main" : {
@@ -428,6 +430,7 @@
 	},
 	"airMagic" : {
 		"index" : 15,
+		"obligatoryMinor" : true,
 		"base" : {
 			"effects" : {
 				"main" : {
@@ -455,6 +458,7 @@
 	},
 	"waterMagic" : {
 		"index" : 16,
+		"obligatoryMinor" : true,
 		"base" : {
 			"effects" : {
 				"main" : {
@@ -482,6 +486,7 @@
 	},
 	"earthMagic" : {
 		"index" : 17,
+		"obligatoryMinor" : true,
 		"base" : {
 			"effects" : {
 				"main" : {

+ 6 - 3
lib/CSkillHandler.cpp

@@ -33,8 +33,8 @@ CSkill::LevelInfo::~LevelInfo()
 {
 }
 
-CSkill::CSkill(SecondarySkill id, std::string identifier)
-	: id(id), identifier(identifier)
+CSkill::CSkill(SecondarySkill id, std::string identifier, bool obligatoryMajor, bool obligatoryMinor)
+	: id(id), identifier(identifier), obligatoryMajor(obligatoryMajor), obligatoryMinor(obligatoryMinor)
 {
 	gainChance[0] = gainChance[1] = 0; //affects CHeroClassHandler::afterLoadFinalization()
 	levels.resize(NSecondarySkill::levels.size() - 1);
@@ -207,8 +207,11 @@ CSkill * CSkillHandler::loadFromJson(const std::string & scope, const JsonNode &
 {
 	assert(identifier.find(':') == std::string::npos);
 	assert(!scope.empty());
+	bool major, minor;
 
-	CSkill * skill = new CSkill(SecondarySkill((si32)index), identifier);
+	major = json["obligatoryMajor"].Bool();
+	minor = json["obligatoryMinor"].Bool();
+	CSkill * skill = new CSkill(SecondarySkill((si32)index), identifier, major, minor);
 	skill->modScope = scope;
 
 	VLC->generaltexth->registerString(scope, skill->getNameTextID(), json["name"].String());

+ 13 - 1
lib/CSkillHandler.h

@@ -51,9 +51,15 @@ private:
 	std::string identifier;
 
 public:
-	CSkill(SecondarySkill id = SecondarySkill::DEFAULT, std::string identifier = "default");
+	CSkill(SecondarySkill id = SecondarySkill::DEFAULT, std::string identifier = "default", bool obligatoryMajor = false, bool obligatoryMinor = false);
 	~CSkill();
 
+	enum class Obligatory : ui8
+	{
+		MAJOR = 0,
+		MINOR = 1,
+	};
+
 	int32_t getIndex() const override;
 	int32_t getIconIndex() const override;
 	std::string getJsonKey() const override;
@@ -70,6 +76,7 @@ public:
 	LevelInfo & at(int level);
 
 	std::string toString() const;
+	bool obligatory(Obligatory val) const { return val == Obligatory::MAJOR ? obligatoryMajor : obligatoryMinor; };
 
 	std::array<si32, 2> gainChance; // gainChance[0/1] = default gain chance on level-up for might/magic heroes
 
@@ -82,11 +89,16 @@ public:
 		h & identifier;
 		h & gainChance;
 		h & levels;
+		h & obligatoryMajor;
+		h & obligatoryMinor;
 	}
 
 	friend class CSkillHandler;
 	friend DLL_LINKAGE std::ostream & operator<<(std::ostream & out, const CSkill & skill);
 	friend DLL_LINKAGE std::ostream & operator<<(std::ostream & out, const CSkill::LevelInfo & info);
+private:
+	bool obligatoryMajor;
+	bool obligatoryMinor;
 };
 
 class DLL_LINKAGE CSkillHandler: public CHandlerBase<SecondarySkill, Skill, CSkill, SkillService>

+ 29 - 24
lib/mapObjects/CGHeroInstance.cpp

@@ -1145,28 +1145,41 @@ ArtBearer::ArtBearer CGHeroInstance::bearerType() const
 std::vector<SecondarySkill> CGHeroInstance::getLevelUpProposedSecondarySkills() const
 {
 	std::vector<SecondarySkill> obligatorySkills; //hero is offered magic school or wisdom if possible
-	if (!skillsInfo.wisdomCounter)
-	{
-		if (canLearnSkill(SecondarySkill::WISDOM))
-			obligatorySkills.emplace_back(SecondarySkill::WISDOM);
-	}
-	if (!skillsInfo.magicSchoolCounter)
-	{
-		std::vector<SecondarySkill> ss =
-		{
-			SecondarySkill::FIRE_MAGIC, SecondarySkill::AIR_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC
-		};
 
+	auto getObligatorySkills = [](CSkill::Obligatory obl){
+		std::vector<SecondarySkill> obligatory = {};
+		for(int i = 0; i < VLC->skillh->size(); i++)
+			if((*VLC->skillh)[SecondarySkill(i)]->obligatory(obl))
+			{
+				obligatory.emplace_back(i);
+				break;
+			}
+		return obligatory;
+	};
+
+	auto selectObligatorySkill = [&](std::vector<SecondarySkill>& ss) -> void
+	{
 		std::shuffle(ss.begin(), ss.end(), skillsInfo.rand.getStdGenerator());
 
 		for(const auto & skill : ss)
 		{
-			if (canLearnSkill(skill)) //only schools hero doesn't know yet
+			if (canLearnSkill(skill)) //only skills hero doesn't know yet
 			{
 				obligatorySkills.push_back(skill);
 				break; //only one
 			}
 		}
+	};
+
+	if (!skillsInfo.wisdomCounter)
+	{
+		auto obligatory = getObligatorySkills(CSkill::Obligatory::MAJOR);
+		selectObligatorySkill(obligatory);
+	}
+	if (!skillsInfo.magicSchoolCounter)
+	{
+		auto obligatory = getObligatorySkills(CSkill::Obligatory::MINOR);
+		selectObligatorySkill(obligatory);
 	}
 
 	std::vector<SecondarySkill> skills;
@@ -1339,20 +1352,12 @@ void CGHeroInstance::levelUp(const std::vector<SecondarySkill> & skills)
 	//deterministic secondary skills
 	skillsInfo.magicSchoolCounter = (skillsInfo.magicSchoolCounter + 1) % maxlevelsToMagicSchool();
 	skillsInfo.wisdomCounter = (skillsInfo.wisdomCounter + 1) % maxlevelsToWisdom();
-	if(vstd::contains(skills, SecondarySkill::WISDOM))
+	for(const auto & skill : skills)
 	{
-		skillsInfo.resetWisdomCounter();
-	}
-
-	SecondarySkill spellSchools[] = {
-		SecondarySkill::FIRE_MAGIC, SecondarySkill::AIR_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC};
-	for(const auto & skill : spellSchools)
-	{
-		if(vstd::contains(skills, skill))
-		{
+		if((*VLC->skillh)[skill]->obligatory(CSkill::Obligatory::MAJOR))
+			skillsInfo.resetWisdomCounter();
+		if((*VLC->skillh)[skill]->obligatory(CSkill::Obligatory::MINOR))
 			skillsInfo.resetMagicSchoolCounter();
-			break;
-		}
 	}
 
 	//update specialty and other bonuses that scale with level