浏览代码

SpellSchool: use identifier instead of int

Needs redifinition of MAGIC_SCHOOL_SKILL in all mods
Konstantin P 2 年之前
父节点
当前提交
057a33c508

+ 4 - 4
client/windows/CSpellWindow.cpp

@@ -82,11 +82,11 @@ public:
 			return false;
 
 
-		for(ui8 schoolId = 0; schoolId < 4; schoolId++)
+		for(auto schoolId = 0; schoolId < GameConstants::DEFAULT_SCHOOLS; schoolId++)
 		{
-			if(A->school.at((ESpellSchool)schoolId) && !B->school.at((ESpellSchool)schoolId))
+			if(A->school.at(SpellSchool(schoolId)) && !B->school.at(SpellSchool(schoolId)))
 				return true;
-			if(!A->school.at((ESpellSchool)schoolId) && B->school.at((ESpellSchool)schoolId))
+			if(!A->school.at(SpellSchool(schoolId)) && B->school.at(SpellSchool(schoolId)))
 				return false;
 		}
 
@@ -320,7 +320,7 @@ void CSpellWindow::computeSpellsPerArea()
 	for(const CSpell * spell : mySpells)
 	{
 		if(spell->isCombat() ^ !battleSpellsOnly
-			&& ((selectedTab == 4) || spell->school.at((ESpellSchool)selectedTab))
+			&& ((selectedTab == 4) || spell->school.at(SpellSchool(selectedTab)))
 			)
 		{
 			spellsCurSite.push_back(spell);

+ 4 - 4
config/artifacts.json

@@ -1185,7 +1185,7 @@
 		"bonuses" : [
 			{
 				"type" : "SPELL_DAMAGE",
-				"subtype" : 0,
+				"subtype" : "spellSchool.air",
 				"val" : 50,
 				"valueType" : "BASE_NUMBER"
 			}
@@ -1198,7 +1198,7 @@
 		"bonuses" : [
 			{
 				"type" : "SPELL_DAMAGE",
-				"subtype" : 3,
+				"subtype" : "spellSchool.earth",
 				"val" : 50,
 				"valueType" : "BASE_NUMBER"
 			}
@@ -1211,7 +1211,7 @@
 		"bonuses" : [
 			{
 				"type" : "SPELL_DAMAGE",
-				"subtype" : 1,
+				"subtype" : "spellSchool.fire",
 				"val" : 50,
 				"valueType" : "BASE_NUMBER"
 			}
@@ -1224,7 +1224,7 @@
 		"bonuses" : [
 			{
 				"type" : "SPELL_DAMAGE",
-				"subtype" : 2,
+				"subtype" : "spellSchool.water",
 				"val" : 50,
 				"valueType" : "BASE_NUMBER"
 			}

+ 5 - 5
config/battlefields.json

@@ -13,7 +13,7 @@
 		"bonuses": [
 			{
 				"type" : "MAGIC_SCHOOL_SKILL",
-				"subtype" : 0,
+				"subtype" : "spellSchool.any",
 				"val" : 3,
 				"valueType" : "BASE_NUMBER"
 			}
@@ -29,7 +29,7 @@
 		"bonuses": [
 			{
 				"type" : "MAGIC_SCHOOL_SKILL",
-				"subtype" : 2,
+				"subtype" : "spellSchool.fire",
 				"val" : 3,
 				"valueType" : "BASE_NUMBER"
 			}
@@ -41,7 +41,7 @@
 		"bonuses": [
 			{
 				"type" : "MAGIC_SCHOOL_SKILL",
-				"subtype" : 8,
+				"subtype" : "spellSchool.earth",
 				"val" : 3,
 				"valueType" : "BASE_NUMBER"
 			}
@@ -53,7 +53,7 @@
 		"bonuses": [
 			{
 				"type" : "MAGIC_SCHOOL_SKILL",
-				"subtype" : 1,
+				"subtype" : "spellSchool.air",
 				"val" : 3,
 				"valueType" : "BASE_NUMBER"
 			}
@@ -65,7 +65,7 @@
 		"bonuses": [
 			{
 				"type" : "MAGIC_SCHOOL_SKILL",
-				"subtype" : 4,
+				"subtype" : "spellSchool.water",
 				"val" : 3,
 				"valueType" : "BASE_NUMBER"
 			}

+ 2 - 2
config/creatures/neutral.json

@@ -10,7 +10,7 @@
 			"magicResistance" :
 			{
 				"type" : "SPELL_DAMAGE_REDUCTION",
-				"subtype" : -1,
+				"subtype" : "spellSchool.any",
 				"val" : 85
 			},
 			"nonliving" :
@@ -41,7 +41,7 @@
 			"magicResistance" :
 			{
 				"type" : "SPELL_DAMAGE_REDUCTION",
-				"subtype" : -1,
+				"subtype" : "spellSchool.any",
 				"val" : 95
 			},
 			"nonliving" :

+ 2 - 2
config/creatures/tower.json

@@ -105,7 +105,7 @@
 			"magicResistance" :
 			{
 				"type" : "SPELL_DAMAGE_REDUCTION",
-				"subtype" : -1,
+				"subtype" : "spellSchool.any",
 				"val" : 50
 			},
 			"nonliving" :
@@ -137,7 +137,7 @@
 			"magicResistance" :
 			{
 				"type" : "SPELL_DAMAGE_REDUCTION",
-				"subtype" : -1,
+				"subtype" : "spellSchool.any",
 				"val" : 75
 			},
 			"nonliving" :

+ 1 - 0
config/gameConfig.json

@@ -215,6 +215,7 @@
 				"spellDamage" : 
 				{
 					"type" : "SPELL_DAMAGE",
+					"subtype" : "spellSchool.any",
 					"val" : 100,
 					"valueType" : "BASE_NUMBER"
 				},

+ 1 - 0
config/heroes/dungeon.json

@@ -186,6 +186,7 @@
 				"sorcery" : {
 					"targetSourceType" : "SECONDARY_SKILL",
 					"type" : "SPELL_DAMAGE",
+					"subtype" : "spellSchool.any",
 					"updater" : "TIMES_HERO_LEVEL",
 					"val" : 5,
 					"valueType" : "PERCENT_TO_TARGET_TYPE"

+ 1 - 0
config/heroes/fortress.json

@@ -262,6 +262,7 @@
 				"sorcery" : {
 					"targetSourceType" : "SECONDARY_SKILL",
 					"type" : "SPELL_DAMAGE",
+					"subtype" : "spellSchool.any",
 					"updater" : "TIMES_HERO_LEVEL",
 					"val" : 5,
 					"valueType" : "PERCENT_TO_TARGET_TYPE"

+ 1 - 0
config/heroes/inferno.json

@@ -261,6 +261,7 @@
 				"sorcery" : {
 					"targetSourceType" : "SECONDARY_SKILL",
 					"type" : "SPELL_DAMAGE",
+					"subtype" : "spellSchool.any",
 					"updater" : "TIMES_HERO_LEVEL",
 					"val" : 5,
 					"valueType" : "PERCENT_TO_TARGET_TYPE"

+ 1 - 0
config/heroes/necropolis.json

@@ -192,6 +192,7 @@
 				"sorcery" : {
 					"targetSourceType" : "SECONDARY_SKILL",
 					"type" : "SPELL_DAMAGE",
+					"subtype" : "spellSchool.any",
 					"updater" : "TIMES_HERO_LEVEL",
 					"val" : 5,
 					"valueType" : "PERCENT_TO_TARGET_TYPE"

+ 2 - 0
config/heroes/stronghold.json

@@ -135,6 +135,7 @@
 				"sorcery" : {
 					"targetSourceType" : "SECONDARY_SKILL",
 					"type" : "SPELL_DAMAGE",
+					"subtype" : "spellSchool.any",
 					"updater" : "TIMES_HERO_LEVEL",
 					"val" : 5,
 					"valueType" : "PERCENT_TO_TARGET_TYPE"
@@ -239,6 +240,7 @@
 				"sorcery" : {
 					"targetSourceType" : "SECONDARY_SKILL",
 					"type" : "SPELL_DAMAGE",
+					"subtype" : "spellSchool.any",
 					"updater" : "TIMES_HERO_LEVEL",
 					"val" : 5,
 					"valueType" : "PERCENT_TO_TARGET_TYPE"

+ 5 - 4
config/skills.json

@@ -406,7 +406,7 @@
 		"base" : {
 			"effects" : {
 				"main" : {
-					"subtype" : 2,
+					"subtype" : "spellSchool.fire",
 					"type" : "MAGIC_SCHOOL_SKILL",
 					"valueType" : "BASE_NUMBER"
 				}
@@ -434,7 +434,7 @@
 		"base" : {
 			"effects" : {
 				"main" : {
-					"subtype" : 1,
+					"subtype" : "spellSchool.air",
 					"type" : "MAGIC_SCHOOL_SKILL",
 					"valueType" : "BASE_NUMBER"
 				}
@@ -462,7 +462,7 @@
 		"base" : {
 			"effects" : {
 				"main" : {
-					"subtype" : 4,
+					"subtype" : "spellSchool.water",
 					"type" : "MAGIC_SCHOOL_SKILL",
 					"valueType" : "BASE_NUMBER"
 				}
@@ -490,7 +490,7 @@
 		"base" : {
 			"effects" : {
 				"main" : {
-					"subtype" : 8,
+					"subtype" : "spellSchool.earth",
 					"type" : "MAGIC_SCHOOL_SKILL",
 					"valueType" : "BASE_NUMBER"
 				}
@@ -737,6 +737,7 @@
 			"effects" : {
 				"main" : {
 					"type" : "SPELL_DAMAGE",
+					"subtype" : "spellSchool.any",
 					"valueType" : "BASE_NUMBER"
 				}
 			}

+ 4 - 4
config/spells/timed.json

@@ -104,7 +104,7 @@
 				"effects" : {
 					"spellDamageReduction" : {
 						"type" : "SPELL_DAMAGE_REDUCTION",
-						"subtype" : 0,
+						"subtype" : "spellSchool.air",
 						"duration" : "N_TURNS",
 						"val" : 30
 					}
@@ -147,7 +147,7 @@
 				"effects" : {
 					"spellDamageReduction" : {
 						"type" : "SPELL_DAMAGE_REDUCTION",
-						"subtype" : 1,
+						"subtype" : "spellSchool.fire",
 						"duration" : "N_TURNS",
 						"val" : 30
 					}
@@ -190,7 +190,7 @@
 				"effects" : {
 					"spellDamageReduction" : {
 						"type" : "SPELL_DAMAGE_REDUCTION",
-						"subtype" : 2,
+						"subtype" : "spellSchool.water",
 						"duration" : "N_TURNS",
 						"val" : 30
 					}
@@ -233,7 +233,7 @@
 				"effects" : {
 					"spellDamageReduction" : {
 						"type" : "SPELL_DAMAGE_REDUCTION",
-						"subtype" : 3,
+						"subtype" : "spellSchool.earth",
 						"duration" : "N_TURNS",
 						"val" : 30
 					}

+ 6 - 6
lib/CCreatureHandler.cpp

@@ -1059,7 +1059,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
 		b.type = BonusType::FEAR; break;
 	case 'g':
 		b.type = BonusType::SPELL_DAMAGE_REDUCTION;
-		b.subtype = -1; //all magic schools
+		b.subtype = SpellSchool(ESpellSchool::ANY);
 		break;
 	case 'P':
 		b.type = BonusType::CASTS; break;
@@ -1179,7 +1179,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
 				break;
 			case 'O':
 				b.type = BonusType::SPELL_DAMAGE_REDUCTION;
-				b.subtype = 1; //Fire school
+				b.subtype = SpellSchool(ESpellSchool::FIRE);
 				b.val = 100; //Full damage immunity
 				break;
 			case 'f':
@@ -1192,7 +1192,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
 				break;
 			case 'W':
 				b.type = BonusType::SPELL_DAMAGE_REDUCTION;
-				b.subtype = 2; //Water school
+				b.subtype = SpellSchool(ESpellSchool::WATER);
 				b.val = 100; //Full damage immunity
 				break;
 			case 'w':
@@ -1201,7 +1201,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
 				break;
 			case 'E':
 				b.type = BonusType::SPELL_DAMAGE_REDUCTION;
-				b.subtype = 3; //Earth school
+				b.subtype = SpellSchool(ESpellSchool::EARTH);
 				b.val = 100; //Full damage immunity
 				break;
 			case 'e':
@@ -1210,7 +1210,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
 				break;
 			case 'A':
 				b.type = BonusType::SPELL_DAMAGE_REDUCTION;
-				b.subtype = 0; //Air school
+				b.subtype = SpellSchool(ESpellSchool::AIR);
 				b.val = 100; //Full damage immunity
 				break;
 			case 'a':
@@ -1219,7 +1219,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
 				break;
 			case 'D':
 				b.type = BonusType::SPELL_DAMAGE_REDUCTION;
-				b.subtype = -1; //all
+				b.subtype = SpellSchool(ESpellSchool::ANY);
 				b.val = 100; //Full damage immunity
 				break;
 			case '0':

+ 7 - 0
lib/CModHandler.cpp

@@ -7,6 +7,7 @@
  * Full text of license available in license.txt file, in main folder
  *
  */
+#include "GameConstants.h"
 #include "StdInc.h"
 #include "CModHandler.h"
 #include "mapObjects/CObjectClassesHandler.h"
@@ -745,6 +746,12 @@ void CModInfo::setEnabled(bool on)
 
 CModHandler::CModHandler() : content(std::make_shared<CContentHandler>())
 {
+	//TODO: moddable spell schools
+	for (auto i = 0; i < GameConstants::DEFAULT_SCHOOLS; ++i)
+		identifiers.registerObject(CModHandler::scopeBuiltin(), "spellSchool", SpellConfig::SCHOOL[i].jsonName, SpellConfig::SCHOOL[i].id);
+
+	identifiers.registerObject(CModHandler::scopeBuiltin(), "spellSchool", "any", SpellSchool(ESpellSchool::ANY));
+
 	for (int i = 0; i < GameConstants::RESOURCE_QUANTITY; ++i)
 	{
 		identifiers.registerObject(CModHandler::scopeBuiltin(), "resource", GameConstants::RESOURCE_NAMES[i], i);

+ 6 - 2
lib/GameConstants.h

@@ -50,6 +50,7 @@ namespace GameConstants
 	constexpr int CREATURES_PER_TOWN = 7; //without upgrades
 	constexpr int SPELL_LEVELS = 5;
 	constexpr int SPELL_SCHOOL_LEVELS = 4;
+	constexpr int DEFAULT_SCHOOLS = 4;
 	constexpr int CRE_LEVELS = 10; // number of creature experience levels
 
 	constexpr int HERO_GOLD_COST = 2500;
@@ -1296,14 +1297,17 @@ class Obstacle : public BaseForID<Obstacle, si32>
 	DLL_LINKAGE static Obstacle fromString(const std::string & identifier);
 };
 
-enum class ESpellSchool: ui8
+enum class ESpellSchool: int8_t
 {
+	ANY 	= -1,
 	AIR 	= 0,
 	FIRE 	= 1,
 	WATER 	= 2,
-	EARTH 	= 3
+	EARTH 	= 3,
 };
 
+using SpellSchool = Identifier<ESpellSchool>;
+
 enum class EMetaclass: ui8
 {
 	INVALID = 0,

+ 16 - 12
lib/bonuses/BonusParams.cpp

@@ -74,7 +74,10 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
 			valueType = BonusValueType::PERCENT_TO_BASE;
 		}
 		else if(deprecatedSubtype == SecondarySkill::SORCERY || deprecatedSubtypeStr == "skill.sorcery")
+		{
 			type = BonusType::SPELL_DAMAGE;
+			subtype = SpellSchool(ESpellSchool::ANY);
+		}
 		else if(deprecatedSubtype == SecondarySkill::SCHOLAR || deprecatedSubtypeStr == "skill.scholar")
 			type = BonusType::LEARN_MEETING_SPELL_LIMIT;
 		else if(deprecatedSubtype == SecondarySkill::ARCHERY|| deprecatedSubtypeStr == "skill.archery")
@@ -112,22 +115,22 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
 		else if(deprecatedSubtype == SecondarySkill::AIR_MAGIC || deprecatedSubtypeStr == "skill.airMagic")
 		{
 			type = BonusType::MAGIC_SCHOOL_SKILL;
-			subtype = 4;
+			subtype = SpellSchool(ESpellSchool::AIR);
 		}
 		else if(deprecatedSubtype == SecondarySkill::WATER_MAGIC || deprecatedSubtypeStr == "skill.waterMagic")
 		{
 			type = BonusType::MAGIC_SCHOOL_SKILL;
-			subtype = 1;
+			subtype = SpellSchool(ESpellSchool::WATER);
 		}
 		else if(deprecatedSubtype == SecondarySkill::FIRE_MAGIC || deprecatedSubtypeStr == "skill.fireMagic")
 		{
 			type = BonusType::MAGIC_SCHOOL_SKILL;
-			subtype = 2;
+			subtype = SpellSchool(ESpellSchool::FIRE);
 		}
 		else if(deprecatedSubtype == SecondarySkill::EARTH_MAGIC || deprecatedSubtypeStr == "skill.earthMagic")
 		{
 			type = BonusType::MAGIC_SCHOOL_SKILL;
-			subtype = 8;
+			subtype = SpellSchool(ESpellSchool::EARTH);
 		}
 		else if (deprecatedSubtype == SecondarySkill::ARTILLERY || deprecatedSubtypeStr == "skill.artillery")
 		{
@@ -215,47 +218,48 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
 	else if (deprecatedTypeStr == "DIRECT_DAMAGE_IMMUNITY")
 	{
 		type = BonusType::SPELL_DAMAGE_REDUCTION;
+		subtype = SpellSchool(ESpellSchool::ANY);
 		val = 100;
 	}
 	else if (deprecatedTypeStr == "AIR_SPELL_DMG_PREMY")
 	{
 		type = BonusType::SPELL_DAMAGE;
-		subtype = 0;
+		subtype = SpellSchool(ESpellSchool::AIR);
 	}
 	else if (deprecatedTypeStr == "FIRE_SPELL_DMG_PREMY")
 	{
 		type = BonusType::SPELL_DAMAGE;
-		subtype = 1;
+		subtype = SpellSchool(ESpellSchool::FIRE);
 	}
 	else if (deprecatedTypeStr == "WATER_SPELL_DMG_PREMY")
 	{
 		type = BonusType::SPELL_DAMAGE;
-		subtype = 2;
+		subtype = SpellSchool(ESpellSchool::WATER);
 	}
 	else if (deprecatedTypeStr == "EARTH_SPELL_DMG_PREMY")
 	{
 		type = BonusType::SPELL_DAMAGE;
-		subtype = 3;
+		subtype = SpellSchool(ESpellSchool::EARTH);
 	}
 	else if (deprecatedTypeStr == "AIR_SPELLS")
 	{
 		type = BonusType::SPELLS_OF_SCHOOL;
-		subtype = 0;
+		subtype = SpellSchool(ESpellSchool::AIR);
 	}
 	else if (deprecatedTypeStr == "FIRE_SPELLS")
 	{
 		type = BonusType::SPELLS_OF_SCHOOL;
-		subtype = 1;
+		subtype = SpellSchool(ESpellSchool::FIRE);
 	}
 	else if (deprecatedTypeStr == "WATER_SPELLS")
 	{
 		type = BonusType::SPELLS_OF_SCHOOL;
-		subtype = 2;
+		subtype = SpellSchool(ESpellSchool::WATER);
 	}
 	else if (deprecatedTypeStr == "EARTH_SPELLS")
 	{
 		type = BonusType::SPELLS_OF_SCHOOL;
-		subtype = 3;
+		subtype = SpellSchool(ESpellSchool::EARTH);
 	}
 	else
 		isConverted = false;

+ 5 - 5
lib/mapObjects/CGHeroInstance.cpp

@@ -589,7 +589,7 @@ int32_t CGHeroInstance::getSpellSchoolLevel(const spells::Spell * spell, int32_t
 
 	spell->forEachSchool([&, this](const spells::SchoolInfo & cnf, bool & stop)
 	{
-		int32_t thisSchool = valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, 1 << (static_cast<ui8>(cnf.id))); //FIXME: Bonus shouldn't be additive (Witchking Artifacts : Crown of Skies)
+		int32_t thisSchool = valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, cnf.id); //FIXME: Bonus shouldn't be additive (Witchking Artifacts : Crown of Skies)
 		if(thisSchool > skill)
 		{
 			skill = thisSchool;
@@ -598,7 +598,7 @@ int32_t CGHeroInstance::getSpellSchoolLevel(const spells::Spell * spell, int32_t
 		}
 	});
 
-	vstd::amax(skill, valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, 0)); //any school bonus
+	vstd::amax(skill, valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, SpellSchool(ESpellSchool::ANY))); //any school bonus
 	vstd::amax(skill, valOfBonuses(BonusType::SPELL, spell->getIndex())); //given by artifact or other effect
 
 	vstd::amax(skill, 0); //in case we don't know any school
@@ -611,7 +611,7 @@ int64_t CGHeroInstance::getSpellBonus(const spells::Spell * spell, int64_t base,
 	//applying sorcery secondary skill
 
 	if(spell->isMagical())
-		base = static_cast<int64_t>(base * (valOfBonuses(BonusType::SPELL_DAMAGE)) / 100.0);
+		base = static_cast<int64_t>(base * (valOfBonuses(BonusType::SPELL_DAMAGE, SpellSchool(ESpellSchool::ANY))) / 100.0);
 
 	base = static_cast<int64_t>(base * (100 + valOfBonuses(BonusType::SPECIFIC_SPELL_DAMAGE, spell->getIndex())) / 100.0);
 
@@ -619,7 +619,7 @@ int64_t CGHeroInstance::getSpellBonus(const spells::Spell * spell, int64_t base,
 
 	spell->forEachSchool([&maxSchoolBonus, this](const spells::SchoolInfo & cnf, bool & stop)
 	{
-		vstd::amax(maxSchoolBonus, valOfBonuses(BonusType::SPELL_DAMAGE, vstd::to_underlying(cnf.id)));
+		vstd::amax(maxSchoolBonus, valOfBonuses(BonusType::SPELL_DAMAGE, cnf.id));
 	});
 
 	base = static_cast<int64_t>(base * (100 + maxSchoolBonus) / 100.0);
@@ -708,7 +708,7 @@ bool CGHeroInstance::canCastThisSpell(const spells::Spell * spell) const
 
 	spell->forEachSchool([this, &schoolBonus](const spells::SchoolInfo & cnf, bool & stop)
 	{
-		if(hasBonusOfType(BonusType::SPELLS_OF_SCHOOL, vstd::to_underlying(cnf.id)))
+		if(hasBonusOfType(BonusType::SPELLS_OF_SCHOOL, cnf.id))
 		{
 			schoolBonus = stop = true;
 		}

+ 1 - 1
lib/rmg/TreasurePlacer.cpp

@@ -343,7 +343,7 @@ void TreasurePlacer::addAllPossibleObjects()
 			std::vector <CSpell *> spells;
 			for(auto spell : VLC->spellh->objects)
 			{
-				if(map.isAllowedSpell(spell->id) && spell->school[static_cast<ESpellSchool>(i)])
+				if(map.isAllowedSpell(spell->id) && spell->school[SpellSchool(i)])
 					spells.push_back(spell);
 			}
 			

+ 1 - 1
lib/spells/AbilityCaster.cpp

@@ -35,7 +35,7 @@ int32_t AbilityCaster::getSpellSchoolLevel(const Spell * spell, int32_t * outSel
 
 	if(spell->getLevel() > 0)
 	{
-		vstd::amax(skill, unit->valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, 0));
+		vstd::amax(skill, unit->valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, SpellSchool(ESpellSchool::ANY)));
 	}
 
 	vstd::amax(skill, 0);

+ 7 - 7
lib/spells/CSpellHandler.cpp

@@ -38,7 +38,7 @@ namespace SpellConfig
 {
 static const std::string LEVEL_NAMES[] = {"none", "basic", "advanced", "expert"};
 
-static const spells::SchoolInfo SCHOOL[4] =
+const spells::SchoolInfo SCHOOL[4] =
 {
 	{
 		ESpellSchool::AIR,
@@ -63,7 +63,7 @@ static const spells::SchoolInfo SCHOOL[4] =
 };
 
 //order as described in http://bugs.vcmi.eu/view.php?id=91
-static const ESpellSchool SCHOOL_ORDER[4] =
+static const SpellSchool SCHOOL_ORDER[4] =
 {
 	ESpellSchool::AIR,  //=0
 	ESpellSchool::FIRE, //=1
@@ -150,9 +150,9 @@ spells::AimType CSpell::getTargetType() const
 void CSpell::forEachSchool(const std::function<void(const spells::SchoolInfo &, bool &)>& cb) const
 {
 	bool stop = false;
-	for(ESpellSchool iter : SpellConfig::SCHOOL_ORDER)
+	for(auto iter : SpellConfig::SCHOOL_ORDER)
 	{
-		const spells::SchoolInfo & cnf = SpellConfig::SCHOOL[static_cast<ui8>(iter)];
+		const spells::SchoolInfo & cnf = SpellConfig::SCHOOL[iter];
 		if(school.at(cnf.id))
 		{
 			cb(cnf, stop);
@@ -381,15 +381,15 @@ int64_t CSpell::adjustRawDamage(const spells::Caster * caster, const battle::Uni
 		//applying protections - when spell has more then one elements, only one protection should be applied (I think)
 		forEachSchool([&](const spells::SchoolInfo & cnf, bool & stop)
 		{
-			if(bearer->hasBonusOfType(BonusType::SPELL_DAMAGE_REDUCTION, static_cast<ui8>(cnf.id)))
+			if(bearer->hasBonusOfType(BonusType::SPELL_DAMAGE_REDUCTION, cnf.id))
 			{
-				ret *= 100 - bearer->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, static_cast<ui8>(cnf.id));
+				ret *= 100 - bearer->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, cnf.id);
 				ret /= 100;
 				stop = true; //only bonus from one school is used
 			}
 		});
 
-		CSelector selector = Selector::type()(BonusType::SPELL_DAMAGE_REDUCTION).And(Selector::subtype()(-1));
+		CSelector selector = Selector::typeSubtype(BonusType::SPELL_DAMAGE_REDUCTION, SpellSchool(ESpellSchool::ANY));
 
 		//general spell dmg reduction, works only on magical effects
 		if(bearer->hasBonus(selector) && isMagical())

+ 7 - 2
lib/spells/CSpellHandler.h

@@ -43,13 +43,18 @@ class IBattleCast;
 
 struct SchoolInfo
 {
-	ESpellSchool id; //backlink
+	SpellSchool id; //backlink
 	BonusType immunityBonus;
 	std::string jsonName;
 };
 
 }
 
+namespace SpellConfig
+{
+	extern const spells::SchoolInfo SCHOOL[4];
+}
+
 enum class VerticalPosition : ui8{TOP, CENTER, BOTTOM};
 
 class DLL_LINKAGE CSpell : public spells::Spell
@@ -185,7 +190,7 @@ public:
 
 	si32 level;
 
-	std::map<ESpellSchool, bool> school;
+	std::map<SpellSchool, bool> school;
 
 	si32 power; //spell's power
 

+ 2 - 2
lib/spells/effects/Damage.cpp

@@ -85,11 +85,11 @@ bool Damage::isReceptive(const Mechanics * m, const battle::Unit * unit) const
 	if(!UnitEffect::isReceptive(m, unit))
 		return false;
 
-	bool isImmune = m->getSpell()->isMagical() && (unit->getBonusBearer()->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, -1) >= 100); //General spell damage immunity
+	bool isImmune = m->getSpell()->isMagical() && (unit->getBonusBearer()->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, SpellSchool(ESpellSchool::ANY)) >= 100); //General spell damage immunity
 	//elemental immunity for damage
 	m->getSpell()->forEachSchool([&](const SchoolInfo & cnf, bool & stop)
 	{
-		isImmune |= (unit->getBonusBearer()->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, static_cast<ui8>(cnf.id)) >= 100); //100% reduction is immunity
+		isImmune |= (unit->getBonusBearer()->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, cnf.id) >= 100); //100% reduction is immunity
 	});
 
 	return !isImmune;

+ 2 - 2
test/spells/AbilityCasterTest.cpp

@@ -56,7 +56,7 @@ TEST_F(AbilityCasterTest, MagicAbilityAffectedByGenericBonus)
 {
 	EXPECT_CALL(spellMock, getLevel()).WillRepeatedly(Return(1));
 
-	casterBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::MAGIC_SCHOOL_SKILL, BonusSource::OTHER, 2, 0, 0));
+	casterBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::MAGIC_SCHOOL_SKILL, BonusSource::OTHER, 2, 0, SpellSchool(ESpellSchool::ANY)));
 
 	EXPECT_CALL(actualCaster, getAllBonuses(_, _, _, _)).Times(AtLeast(1));
 	EXPECT_CALL(actualCaster, getTreeVersion()).Times(AtLeast(0));
@@ -70,7 +70,7 @@ TEST_F(AbilityCasterTest, MagicAbilityIngoresSchoolBonus)
 {
 	EXPECT_CALL(spellMock, getLevel()).WillRepeatedly(Return(1));
 
-	casterBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::MAGIC_SCHOOL_SKILL, BonusSource::OTHER, 2, 0, 1));
+	casterBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::MAGIC_SCHOOL_SKILL, BonusSource::OTHER, 2, 0, SpellSchool(ESpellSchool::AIR)));
 
 	EXPECT_CALL(actualCaster, getAllBonuses(_, _, _, _)).Times(AtLeast(1));
 	EXPECT_CALL(actualCaster, getTreeVersion()).Times(AtLeast(0));