Browse Source

Fix client & server compilation

Ivan Savenko 2 years ago
parent
commit
910ad50417

+ 5 - 5
AI/Nullkiller/Engine/PriorityEvaluator.cpp

@@ -242,13 +242,13 @@ uint64_t evaluateArtifactArmyValue(CArtifactInstance * art)
 		return 1500;
 		return 1500;
 
 
 	auto statsValue =
 	auto statsValue =
-		10 * art->valOfBonuses(BonusType::MOVEMENT, 1)
+		10 * art->valOfBonuses(BonusType::MOVEMENT, BonusSubtypes::heroMovementLand)
 		+ 1200 * art->valOfBonuses(BonusType::STACKS_SPEED)
 		+ 1200 * art->valOfBonuses(BonusType::STACKS_SPEED)
 		+ 700 * art->valOfBonuses(BonusType::MORALE)
 		+ 700 * art->valOfBonuses(BonusType::MORALE)
-		+ 700 * art->valOfBonuses(BonusType::PRIMARY_SKILL, static_cast<int>(PrimarySkill::ATTACK))
-		+ 700 * art->valOfBonuses(BonusType::PRIMARY_SKILL, static_cast<int>(PrimarySkill::DEFENSE))
-		+ 700 * art->valOfBonuses(BonusType::PRIMARY_SKILL, static_cast<int>(PrimarySkill::KNOWLEDGE))
-		+ 700 * art->valOfBonuses(BonusType::PRIMARY_SKILL, static_cast<int>(PrimarySkill::SPELL_POWER))
+		+ 700 * art->valOfBonuses(BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::ATTACK))
+		+ 700 * art->valOfBonuses(BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::DEFENSE))
+		+ 700 * art->valOfBonuses(BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::KNOWLEDGE))
+		+ 700 * art->valOfBonuses(BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::SPELL_POWER))
 		+ 500 * art->valOfBonuses(BonusType::LUCK);
 		+ 500 * art->valOfBonuses(BonusType::LUCK);
 
 
 	auto classValue = 0;
 	auto classValue = 0;

+ 2 - 2
AI/Nullkiller/Pathfinding/AINodeStorage.cpp

@@ -984,7 +984,7 @@ std::vector<CGPathNode *> AINodeStorage::calculateTeleportations(
 struct TowmPortalFinder
 struct TowmPortalFinder
 {
 {
 	const std::vector<CGPathNode *> & initialNodes;
 	const std::vector<CGPathNode *> & initialNodes;
-	MasteryLevel townPortalSkillLevel;
+	MasteryLevel::Type townPortalSkillLevel;
 	uint64_t movementNeeded;
 	uint64_t movementNeeded;
 	const ChainActor * actor;
 	const ChainActor * actor;
 	const CGHeroInstance * hero;
 	const CGHeroInstance * hero;
@@ -1006,7 +1006,7 @@ struct TowmPortalFinder
 		townPortal = spellID.toSpell();
 		townPortal = spellID.toSpell();
 
 
 		// TODO: Copy/Paste from TownPortalMechanics
 		// TODO: Copy/Paste from TownPortalMechanics
-		townPortalSkillLevel = MasteryLevel(hero->getSpellSchoolLevel(townPortal));
+		townPortalSkillLevel = MasteryLevel::Type(hero->getSpellSchoolLevel(townPortal));
 		movementNeeded = GameConstants::BASE_MOVEMENT_COST * (townPortalSkillLevel >= MasteryLevel::EXPERT ? 2 : 3);
 		movementNeeded = GameConstants::BASE_MOVEMENT_COST * (townPortalSkillLevel >= MasteryLevel::EXPERT ? 2 : 3);
 	}
 	}
 
 

+ 0 - 2
docs/modders/Bonus/Bonus_Types.md

@@ -118,14 +118,12 @@ Determines chance for affected heroes to learn spell casted by enemy hero after
 
 
 Allows affected heroes to learn spell casted by enemy hero after battle
 Allows affected heroes to learn spell casted by enemy hero after battle
 
 
-- subtype: must be set to -1
 - val: maximal level of spell that can be learned
 - val: maximal level of spell that can be learned
 
 
 ### LEARN_MEETING_SPELL_LIMIT
 ### LEARN_MEETING_SPELL_LIMIT
 
 
 Allows affected heroes to learn spells from each other during hero exchange
 Allows affected heroes to learn spells from each other during hero exchange
 
 
-- subtype: must be set to -1
 - val: maximal level of spell that can be learned
 - val: maximal level of spell that can be learned
 
 
 ### ROUGH_TERRAIN_DISCOUNT
 ### ROUGH_TERRAIN_DISCOUNT

+ 9 - 0
lib/bonuses/Bonus.h

@@ -60,6 +60,15 @@ static const TBonusSubtype visionsTowns;  // 2
 static const TBonusSubtype immunityBattleWide; // 0
 static const TBonusSubtype immunityBattleWide; // 0
 static const TBonusSubtype immunityEnemyHero; // 1
 static const TBonusSubtype immunityEnemyHero; // 1
 
 
+static const TBonusSubtype transmutationPerHealth; // 0
+static const TBonusSubtype transmutationPerUnit; // 1
+
+static const TBonusSubtype destructionKillPercentage; // 0
+static const TBonusSubtype destructionKillAmount; // 1
+
+static const TBonusSubtype soulStealPermanent; // 0
+static const TBonusSubtype soulStealBattle; // 1
+
 TBonusSubtype spellLevel(int level);
 TBonusSubtype spellLevel(int level);
 TBonusSubtype creatureLevel(int level);
 TBonusSubtype creatureLevel(int level);
 
 

+ 5 - 5
lib/bonuses/BonusParams.cpp

@@ -81,7 +81,7 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
 		else if(deprecatedSubtype == SecondarySkill::SORCERY || deprecatedSubtypeStr == "skill.sorcery")
 		else if(deprecatedSubtype == SecondarySkill::SORCERY || deprecatedSubtypeStr == "skill.sorcery")
 		{
 		{
 			type = BonusType::SPELL_DAMAGE;
 			type = BonusType::SPELL_DAMAGE;
-			subtype = TBonusSubtype(ESpellSchool::ANY);
+			subtype = TBonusSubtype(SpellSchool::ANY);
 		}
 		}
 		else if(deprecatedSubtype == SecondarySkill::SCHOLAR || deprecatedSubtypeStr == "skill.scholar")
 		else if(deprecatedSubtype == SecondarySkill::SCHOLAR || deprecatedSubtypeStr == "skill.scholar")
 			type = BonusType::LEARN_MEETING_SPELL_LIMIT;
 			type = BonusType::LEARN_MEETING_SPELL_LIMIT;
@@ -120,22 +120,22 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
 		else if(deprecatedSubtype == SecondarySkill::AIR_MAGIC || deprecatedSubtypeStr == "skill.airMagic")
 		else if(deprecatedSubtype == SecondarySkill::AIR_MAGIC || deprecatedSubtypeStr == "skill.airMagic")
 		{
 		{
 			type = BonusType::MAGIC_SCHOOL_SKILL;
 			type = BonusType::MAGIC_SCHOOL_SKILL;
-			subtype = TBonusSubtype(ESpellSchool::AIR);
+			subtype = TBonusSubtype(SpellSchool::AIR);
 		}
 		}
 		else if(deprecatedSubtype == SecondarySkill::WATER_MAGIC || deprecatedSubtypeStr == "skill.waterMagic")
 		else if(deprecatedSubtype == SecondarySkill::WATER_MAGIC || deprecatedSubtypeStr == "skill.waterMagic")
 		{
 		{
 			type = BonusType::MAGIC_SCHOOL_SKILL;
 			type = BonusType::MAGIC_SCHOOL_SKILL;
-			subtype = TBonusSubtype(ESpellSchool::WATER);
+			subtype = TBonusSubtype(SpellSchool::WATER);
 		}
 		}
 		else if(deprecatedSubtype == SecondarySkill::FIRE_MAGIC || deprecatedSubtypeStr == "skill.fireMagic")
 		else if(deprecatedSubtype == SecondarySkill::FIRE_MAGIC || deprecatedSubtypeStr == "skill.fireMagic")
 		{
 		{
 			type = BonusType::MAGIC_SCHOOL_SKILL;
 			type = BonusType::MAGIC_SCHOOL_SKILL;
-			subtype = TBonusSubtype(ESpellSchool::FIRE);
+			subtype = TBonusSubtype(SpellSchool::FIRE);
 		}
 		}
 		else if(deprecatedSubtype == SecondarySkill::EARTH_MAGIC || deprecatedSubtypeStr == "skill.earthMagic")
 		else if(deprecatedSubtype == SecondarySkill::EARTH_MAGIC || deprecatedSubtypeStr == "skill.earthMagic")
 		{
 		{
 			type = BonusType::MAGIC_SCHOOL_SKILL;
 			type = BonusType::MAGIC_SCHOOL_SKILL;
-			subtype = TBonusSubtype(ESpellSchool::EARTH);
+			subtype = TBonusSubtype(SpellSchool::EARTH);
 		}
 		}
 		else if (deprecatedSubtype == SecondarySkill::ARTILLERY || deprecatedSubtypeStr == "skill.artillery")
 		else if (deprecatedSubtype == SecondarySkill::ARTILLERY || deprecatedSubtypeStr == "skill.artillery")
 		{
 		{

+ 0 - 1
lib/constants/EntityIdentifiers.h

@@ -978,7 +978,6 @@ public:
 
 
 // Deprecated
 // Deprecated
 // TODO: remove
 // TODO: remove
-using ESpellSchool = SpellSchool;
 using ETownType = FactionID;
 using ETownType = FactionID;
 using EGameResID = GameResID;
 using EGameResID = GameResID;
 using River = RiverId;
 using River = RiverId;

+ 1 - 1
lib/modding/IdentifierStorage.cpp

@@ -28,7 +28,7 @@ CIdentifierStorage::CIdentifierStorage()
 	for (auto i = 0; i < GameConstants::DEFAULT_SCHOOLS; ++i)
 	for (auto i = 0; i < GameConstants::DEFAULT_SCHOOLS; ++i)
 		registerObject(ModScope::scopeBuiltin(), "spellSchool", SpellConfig::SCHOOL[i].jsonName, SpellConfig::SCHOOL[i].id);
 		registerObject(ModScope::scopeBuiltin(), "spellSchool", SpellConfig::SCHOOL[i].jsonName, SpellConfig::SCHOOL[i].id);
 
 
-	registerObject(ModScope::scopeBuiltin(), "spellSchool", "any", SpellSchool(ESpellSchool::ANY));
+	registerObject(ModScope::scopeBuiltin(), "spellSchool", "any", SpellSchool(SpellSchool::ANY));
 
 
 	for (int i = 0; i < GameConstants::RESOURCE_QUANTITY; ++i)
 	for (int i = 0; i < GameConstants::RESOURCE_QUANTITY; ++i)
 		registerObject(ModScope::scopeBuiltin(), "resource", GameConstants::RESOURCE_NAMES[i], i);
 		registerObject(ModScope::scopeBuiltin(), "resource", GameConstants::RESOURCE_NAMES[i], i);

+ 8 - 8
lib/spells/CSpellHandler.cpp

@@ -42,19 +42,19 @@ static const std::string LEVEL_NAMES[] = {"none", "basic", "advanced", "expert"}
 const spells::SchoolInfo SCHOOL[4] =
 const spells::SchoolInfo SCHOOL[4] =
 {
 {
 	{
 	{
-		ESpellSchool::AIR,
+		SpellSchool::AIR,
 		"air"
 		"air"
 	},
 	},
 	{
 	{
-		ESpellSchool::FIRE,
+		SpellSchool::FIRE,
 		"fire"
 		"fire"
 	},
 	},
 	{
 	{
-		ESpellSchool::WATER,
+		SpellSchool::WATER,
 		"water"
 		"water"
 	},
 	},
 	{
 	{
-		ESpellSchool::EARTH,
+		SpellSchool::EARTH,
 		"earth"
 		"earth"
 	}
 	}
 };
 };
@@ -62,10 +62,10 @@ const spells::SchoolInfo SCHOOL[4] =
 //order as described in http://bugs.vcmi.eu/view.php?id=91
 //order as described in http://bugs.vcmi.eu/view.php?id=91
 static const SpellSchool SCHOOL_ORDER[4] =
 static const SpellSchool SCHOOL_ORDER[4] =
 {
 {
-	ESpellSchool::AIR,  //=0
-	ESpellSchool::FIRE, //=1
-	ESpellSchool::EARTH,//=3(!)
-	ESpellSchool::WATER //=2(!)
+	SpellSchool::AIR,  //=0
+	SpellSchool::FIRE, //=1
+	SpellSchool::EARTH,//=3(!)
+	SpellSchool::WATER //=2(!)
 };
 };
 } //namespace SpellConfig
 } //namespace SpellConfig
 
 

+ 6 - 8
server/CGameHandler.cpp

@@ -229,7 +229,6 @@ void CGameHandler::levelUpCommander (const CCommanderInstance * c, int skill)
 		return;
 		return;
 	}
 	}
 
 
-	scp.accumulatedBonus.subtype = 0;
 	scp.accumulatedBonus.additionalInfo = 0;
 	scp.accumulatedBonus.additionalInfo = 0;
 	scp.accumulatedBonus.duration = BonusDuration::PERMANENT;
 	scp.accumulatedBonus.duration = BonusDuration::PERMANENT;
 	scp.accumulatedBonus.turnsRemain = 0;
 	scp.accumulatedBonus.turnsRemain = 0;
@@ -249,11 +248,11 @@ void CGameHandler::levelUpCommander (const CCommanderInstance * c, int skill)
 		{
 		{
 			case ECommander::ATTACK:
 			case ECommander::ATTACK:
 				scp.accumulatedBonus.type = BonusType::PRIMARY_SKILL;
 				scp.accumulatedBonus.type = BonusType::PRIMARY_SKILL;
-				scp.accumulatedBonus.subtype = static_cast<int>(PrimarySkill::ATTACK);
+				scp.accumulatedBonus.subtype = TBonusSubtype(PrimarySkill::ATTACK);
 				break;
 				break;
 			case ECommander::DEFENSE:
 			case ECommander::DEFENSE:
 				scp.accumulatedBonus.type = BonusType::PRIMARY_SKILL;
 				scp.accumulatedBonus.type = BonusType::PRIMARY_SKILL;
-				scp.accumulatedBonus.subtype = static_cast<int>(PrimarySkill::DEFENSE);
+				scp.accumulatedBonus.subtype = TBonusSubtype(PrimarySkill::DEFENSE);
 				break;
 				break;
 			case ECommander::HEALTH:
 			case ECommander::HEALTH:
 				scp.accumulatedBonus.type = BonusType::STACK_HEALTH;
 				scp.accumulatedBonus.type = BonusType::STACK_HEALTH;
@@ -261,7 +260,6 @@ void CGameHandler::levelUpCommander (const CCommanderInstance * c, int skill)
 				break;
 				break;
 			case ECommander::DAMAGE:
 			case ECommander::DAMAGE:
 				scp.accumulatedBonus.type = BonusType::CREATURE_DAMAGE;
 				scp.accumulatedBonus.type = BonusType::CREATURE_DAMAGE;
-				scp.accumulatedBonus.subtype = 0;
 				scp.accumulatedBonus.valType = BonusValueType::PERCENT_TO_BASE;
 				scp.accumulatedBonus.valType = BonusValueType::PERCENT_TO_BASE;
 				break;
 				break;
 			case ECommander::SPEED:
 			case ECommander::SPEED:
@@ -788,9 +786,9 @@ void CGameHandler::onNewTurn()
 
 
 			if (!firstTurn) //not first day
 			if (!firstTurn) //not first day
 			{
 			{
-				for (int k = 0; k < GameConstants::RESOURCE_QUANTITY; k++)
+				for (GameResID k = GameResID::WOOD; k < GameResID::COUNT; k++)
 				{
 				{
-					n.res[elem.first][k] += h->valOfBonuses(BonusType::GENERATE_RESOURCE, k);
+					n.res[elem.first][k] += h->valOfBonuses(BonusType::GENERATE_RESOURCE, TBonusSubtype(k));
 				}
 				}
 			}
 			}
 		}
 		}
@@ -1539,8 +1537,8 @@ void CGameHandler::useScholarSkill(ObjectInstanceID fromHero, ObjectInstanceID t
 {
 {
 	const CGHeroInstance * h1 = getHero(fromHero);
 	const CGHeroInstance * h1 = getHero(fromHero);
 	const CGHeroInstance * h2 = getHero(toHero);
 	const CGHeroInstance * h2 = getHero(toHero);
-	int h1_scholarSpellLevel = h1->valOfBonuses(BonusType::LEARN_MEETING_SPELL_LIMIT, -1);
-	int h2_scholarSpellLevel = h2->valOfBonuses(BonusType::LEARN_MEETING_SPELL_LIMIT, -1);
+	int h1_scholarSpellLevel = h1->valOfBonuses(BonusType::LEARN_MEETING_SPELL_LIMIT);
+	int h2_scholarSpellLevel = h2->valOfBonuses(BonusType::LEARN_MEETING_SPELL_LIMIT);
 
 
 	if (h1_scholarSpellLevel < h2_scholarSpellLevel)
 	if (h1_scholarSpellLevel < h2_scholarSpellLevel)
 	{
 	{

+ 34 - 33
server/battles/BattleActionProcessor.cpp

@@ -162,11 +162,11 @@ bool BattleActionProcessor::doDefendAction(const CBattleInfoCallback & battle, c
 	SetStackEffect sse;
 	SetStackEffect sse;
 	sse.battleID = battle.getBattle()->getBattleID();
 	sse.battleID = battle.getBattle()->getBattleID();
 
 
-	Bonus defenseBonusToAdd(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 20, -1, static_cast<int32_t>(PrimarySkill::DEFENSE), BonusValueType::PERCENT_TO_ALL);
-	Bonus bonus2(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, stack->valOfBonuses(BonusType::DEFENSIVE_STANCE), -1, static_cast<int32_t>(PrimarySkill::DEFENSE), BonusValueType::ADDITIVE_VALUE);
-	Bonus alternativeWeakCreatureBonus(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 1, -1, static_cast<int32_t>(PrimarySkill::DEFENSE), BonusValueType::ADDITIVE_VALUE);
+	Bonus defenseBonusToAdd(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 20, -1, TBonusSubtype(PrimarySkill::DEFENSE), BonusValueType::PERCENT_TO_ALL);
+	Bonus bonus2(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, stack->valOfBonuses(BonusType::DEFENSIVE_STANCE), -1, TBonusSubtype(PrimarySkill::DEFENSE), BonusValueType::ADDITIVE_VALUE);
+	Bonus alternativeWeakCreatureBonus(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 1, -1, TBonusSubtype(PrimarySkill::DEFENSE), BonusValueType::ADDITIVE_VALUE);
 
 
-	BonusList defence = *stack->getBonuses(Selector::typeSubtype(BonusType::PRIMARY_SKILL, static_cast<int32_t>(PrimarySkill::DEFENSE)));
+	BonusList defence = *stack->getBonuses(Selector::typeSubtype(BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::DEFENSE)));
 	int oldDefenceValue = defence.totalValue();
 	int oldDefenceValue = defence.totalValue();
 
 
 	defence.push_back(std::make_shared<Bonus>(defenseBonusToAdd));
 	defence.push_back(std::make_shared<Bonus>(defenseBonusToAdd));
@@ -263,7 +263,7 @@ bool BattleActionProcessor::doAttackAction(const CBattleInfoCallback & battle, c
 	const auto * attackingHero = battle.battleGetFightingHero(ba.side);
 	const auto * attackingHero = battle.battleGetFightingHero(ba.side);
 	if(attackingHero)
 	if(attackingHero)
 	{
 	{
-		totalAttacks += attackingHero->valOfBonuses(BonusType::HERO_GRANTS_ATTACKS, stack->creatureIndex());
+		totalAttacks += attackingHero->valOfBonuses(BonusType::HERO_GRANTS_ATTACKS, TBonusSubtype(stack->creatureId()));
 	}
 	}
 
 
 	const bool firstStrike = destinationStack->hasBonusOfType(BonusType::FIRST_STRIKE);
 	const bool firstStrike = destinationStack->hasBonusOfType(BonusType::FIRST_STRIKE);
@@ -355,7 +355,7 @@ bool BattleActionProcessor::doShootAction(const CBattleInfoCallback & battle, co
 	const auto * attackingHero = battle.battleGetFightingHero(ba.side);
 	const auto * attackingHero = battle.battleGetFightingHero(ba.side);
 	if(attackingHero)
 	if(attackingHero)
 	{
 	{
-		totalRangedAttacks += attackingHero->valOfBonuses(BonusType::HERO_GRANTS_ATTACKS, stack->creatureIndex());
+		totalRangedAttacks += attackingHero->valOfBonuses(BonusType::HERO_GRANTS_ATTACKS, TBonusSubtype(stack->creatureId()));
 	}
 	}
 
 
 	for(int i = 1; i < totalRangedAttacks; ++i)
 	for(int i = 1; i < totalRangedAttacks; ++i)
@@ -382,13 +382,13 @@ bool BattleActionProcessor::doCatapultAction(const CBattleInfoCallback & battle,
 		return false;
 		return false;
 
 
 	std::shared_ptr<const Bonus> catapultAbility = stack->getBonusLocalFirst(Selector::type()(BonusType::CATAPULT));
 	std::shared_ptr<const Bonus> catapultAbility = stack->getBonusLocalFirst(Selector::type()(BonusType::CATAPULT));
-	if(!catapultAbility || catapultAbility->subtype < 0)
+	if(!catapultAbility || catapultAbility->subtype == TBonusSubtype::NONE)
 	{
 	{
 		gameHandler->complain("We do not know how to shoot :P");
 		gameHandler->complain("We do not know how to shoot :P");
 	}
 	}
 	else
 	else
 	{
 	{
-		const CSpell * spell = SpellID(catapultAbility->subtype).toSpell();
+		const CSpell * spell = catapultAbility->subtype.as<SpellID>().toSpell();
 		spells::BattleCast parameters(&battle, stack, spells::Mode::SPELL_LIKE_ATTACK, spell); //We can shot infinitely by catapult
 		spells::BattleCast parameters(&battle, stack, spells::Mode::SPELL_LIKE_ATTACK, spell); //We can shot infinitely by catapult
 		auto shotLevel = stack->valOfBonuses(Selector::typeSubtype(BonusType::CATAPULT_EXTRA_SHOTS, catapultAbility->subtype));
 		auto shotLevel = stack->valOfBonuses(Selector::typeSubtype(BonusType::CATAPULT_EXTRA_SHOTS, catapultAbility->subtype));
 		parameters.setSpellLevel(shotLevel);
 		parameters.setSpellLevel(shotLevel);
@@ -407,7 +407,7 @@ bool BattleActionProcessor::doUnitSpellAction(const CBattleInfoCallback & battle
 		return false;
 		return false;
 
 
 	std::shared_ptr<const Bonus> randSpellcaster = stack->getBonus(Selector::type()(BonusType::RANDOM_SPELLCASTER));
 	std::shared_ptr<const Bonus> randSpellcaster = stack->getBonus(Selector::type()(BonusType::RANDOM_SPELLCASTER));
-	std::shared_ptr<const Bonus> spellcaster = stack->getBonus(Selector::typeSubtype(BonusType::SPELLCASTER, spellID));
+	std::shared_ptr<const Bonus> spellcaster = stack->getBonus(Selector::typeSubtype(BonusType::SPELLCASTER, TBonusSubtype(spellID)));
 
 
 	//TODO special bonus for genies ability
 	//TODO special bonus for genies ability
 	if (randSpellcaster && battle.battleGetRandomStackSpell(gameHandler->getRandomGenerator(), stack, CBattleInfoCallback::RANDOM_AIMED) == SpellID::NONE)
 	if (randSpellcaster && battle.battleGetRandomStackSpell(gameHandler->getRandomGenerator(), stack, CBattleInfoCallback::RANDOM_AIMED) == SpellID::NONE)
@@ -452,13 +452,13 @@ bool BattleActionProcessor::doHealAction(const CBattleInfoCallback & battle, con
 	else
 	else
 		destStack = battle.battleGetUnitByPos(target.at(0).hexValue);
 		destStack = battle.battleGetUnitByPos(target.at(0).hexValue);
 
 
-	if(stack == nullptr || destStack == nullptr || !healerAbility || healerAbility->subtype < 0)
+	if(stack == nullptr || destStack == nullptr || !healerAbility || healerAbility->subtype == TBonusSubtype::NONE)
 	{
 	{
 		gameHandler->complain("There is either no healer, no destination, or healer cannot heal :P");
 		gameHandler->complain("There is either no healer, no destination, or healer cannot heal :P");
 	}
 	}
 	else
 	else
 	{
 	{
-		const CSpell * spell = SpellID(healerAbility->subtype).toSpell();
+		const CSpell * spell = healerAbility->subtype.as<SpellID>().toSpell();
 		spells::BattleCast parameters(&battle, stack, spells::Mode::SPELL_LIKE_ATTACK, spell); //We can heal infinitely by first aid tent
 		spells::BattleCast parameters(&battle, stack, spells::Mode::SPELL_LIKE_ATTACK, spell); //We can heal infinitely by first aid tent
 		auto dest = battle::Destination(destStack, target.at(0).hexValue);
 		auto dest = battle::Destination(destStack, target.at(0).hexValue);
 		parameters.setSpellLevel(0);
 		parameters.setSpellLevel(0);
@@ -907,7 +907,7 @@ void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const
 	const auto * owner = battle.battleGetFightingHero(attacker->unitSide());
 	const auto * owner = battle.battleGetFightingHero(attacker->unitSide());
 	if(owner)
 	if(owner)
 	{
 	{
-		int chance = owner->valOfBonuses(BonusType::BONUS_DAMAGE_CHANCE, attacker->creatureIndex());
+		int chance = owner->valOfBonuses(BonusType::BONUS_DAMAGE_CHANCE, TBonusSubtype(attacker->creatureId()));
 		if (chance > gameHandler->getRandomGenerator().nextInt(99))
 		if (chance > gameHandler->getRandomGenerator().nextInt(99))
 			bat.flags |= BattleAttack::BALLISTA_DOUBLE_DMG;
 			bat.flags |= BattleAttack::BALLISTA_DOUBLE_DMG;
 	}
 	}
@@ -931,7 +931,7 @@ void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const
 	{
 	{
 		//this is need for displaying hit animation
 		//this is need for displaying hit animation
 		bat.flags |= BattleAttack::SPELL_LIKE;
 		bat.flags |= BattleAttack::SPELL_LIKE;
-		bat.spellID = SpellID(bonus->subtype);
+		bat.spellID = bonus->subtype.as<SpellID>();
 
 
 		//TODO: should spell override creature`s projectile?
 		//TODO: should spell override creature`s projectile?
 
 
@@ -962,7 +962,7 @@ void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const
 			{
 			{
 				//this is need for displaying affect animation
 				//this is need for displaying affect animation
 				bsa.flags |= BattleStackAttacked::SPELL_EFFECT;
 				bsa.flags |= BattleStackAttacked::SPELL_EFFECT;
-				bsa.spellID = SpellID(bonus->subtype);
+				bsa.spellID = bonus->subtype.as<SpellID>();
 			}
 			}
 		}
 		}
 	}
 	}
@@ -1084,7 +1084,7 @@ void BattleActionProcessor::attackCasting(const CBattleInfoCallback & battle, bo
 		TConstBonusListPtr spells = attacker->getBonuses(Selector::type()(attackMode));
 		TConstBonusListPtr spells = attacker->getBonuses(Selector::type()(attackMode));
 		for(const auto & sf : *spells)
 		for(const auto & sf : *spells)
 		{
 		{
-			spellsToCast.insert(SpellID(sf->subtype));
+			spellsToCast.insert(sf->subtype.as<SpellID>());
 		}
 		}
 		for(SpellID spellID : spellsToCast)
 		for(SpellID spellID : spellsToCast)
 		{
 		{
@@ -1095,7 +1095,7 @@ void BattleActionProcessor::attackCasting(const CBattleInfoCallback & battle, bo
 				return;
 				return;
 			}
 			}
 			int32_t spellLevel = 0;
 			int32_t spellLevel = 0;
-			TConstBonusListPtr spellsByType = attacker->getBonuses(Selector::typeSubtype(attackMode, spellID));
+			TConstBonusListPtr spellsByType = attacker->getBonuses(Selector::typeSubtype(attackMode, TBonusSubtype(spellID)));
 			for(const auto & sf : *spellsByType)
 			for(const auto & sf : *spellsByType)
 			{
 			{
 				int meleeRanged;
 				int meleeRanged;
@@ -1113,7 +1113,7 @@ void BattleActionProcessor::attackCasting(const CBattleInfoCallback & battle, bo
 				if (meleeRanged == 0 || (meleeRanged == 1 && ranged) || (meleeRanged == 2 && !ranged))
 				if (meleeRanged == 0 || (meleeRanged == 1 && ranged) || (meleeRanged == 2 && !ranged))
 					castMe = true;
 					castMe = true;
 			}
 			}
-			int chance = attacker->valOfBonuses((Selector::typeSubtype(attackMode, spellID)));
+			int chance = attacker->valOfBonuses((Selector::typeSubtype(attackMode, TBonusSubtype(spellID))));
 			vstd::amin(chance, 100);
 			vstd::amin(chance, 100);
 
 
 			const CSpell * spell = SpellID(spellID).toSpell();
 			const CSpell * spell = SpellID(spellID).toSpell();
@@ -1168,7 +1168,7 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
 		// each gorgon have 10% chance to kill (counted separately in H3) -> binomial distribution
 		// each gorgon have 10% chance to kill (counted separately in H3) -> binomial distribution
 		//original formula x = min(x, (gorgons_count + 9)/10);
 		//original formula x = min(x, (gorgons_count + 9)/10);
 
 
-		double chanceToKill = attacker->valOfBonuses(BonusType::DEATH_STARE, 0) / 100.0f;
+		double chanceToKill = attacker->valOfBonuses(BonusType::DEATH_STARE, BonusSubtypes::deathStareGorgon) / 100.0f;
 		vstd::amin(chanceToKill, 1); //cap at 100%
 		vstd::amin(chanceToKill, 1); //cap at 100%
 
 
 		std::binomial_distribution<> distribution(attacker->getCount(), chanceToKill);
 		std::binomial_distribution<> distribution(attacker->getCount(), chanceToKill);
@@ -1179,7 +1179,7 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
 		int maxToKill = static_cast<int>((attacker->getCount() + cap - 1) / cap); //not much more than chance * count
 		int maxToKill = static_cast<int>((attacker->getCount() + cap - 1) / cap); //not much more than chance * count
 		vstd::amin(staredCreatures, maxToKill);
 		vstd::amin(staredCreatures, maxToKill);
 
 
-		staredCreatures += (attacker->level() * attacker->valOfBonuses(BonusType::DEATH_STARE, 1)) / defender->level();
+		staredCreatures += (attacker->level() * attacker->valOfBonuses(BonusType::DEATH_STARE, BonusSubtypes::deathStareCommander)) / defender->level();
 		if(staredCreatures)
 		if(staredCreatures)
 		{
 		{
 			//TODO: death stare was not originally available for multiple-hex attacks, but...
 			//TODO: death stare was not originally available for multiple-hex attacks, but...
@@ -1249,9 +1249,9 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
 		else
 		else
 			resurrectInfo.type = attacker->creatureId();
 			resurrectInfo.type = attacker->creatureId();
 
 
-		if(attacker->hasBonusOfType((BonusType::TRANSMUTATION), 0))
+		if(attacker->hasBonusOfType((BonusType::TRANSMUTATION), BonusSubtypes::transmutationPerHealth))
 			resurrectInfo.count = std::max((defender->getCount() * defender->getMaxHealth()) / resurrectInfo.type.toCreature()->getMaxHealth(), 1u);
 			resurrectInfo.count = std::max((defender->getCount() * defender->getMaxHealth()) / resurrectInfo.type.toCreature()->getMaxHealth(), 1u);
-		else if (attacker->hasBonusOfType((BonusType::TRANSMUTATION), 1))
+		else if (attacker->hasBonusOfType((BonusType::TRANSMUTATION), BonusSubtypes::transmutationPerUnit))
 			resurrectInfo.count = defender->getCount();
 			resurrectInfo.count = defender->getCount();
 		else
 		else
 			return; //wrong subtype
 			return; //wrong subtype
@@ -1273,21 +1273,21 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
 		gameHandler->sendAndApply(&fakeEvent);
 		gameHandler->sendAndApply(&fakeEvent);
 	}
 	}
 
 
-	if(attacker->hasBonusOfType(BonusType::DESTRUCTION, 0) || attacker->hasBonusOfType(BonusType::DESTRUCTION, 1))
+	if(attacker->hasBonusOfType(BonusType::DESTRUCTION, BonusSubtypes::destructionKillPercentage) || attacker->hasBonusOfType(BonusType::DESTRUCTION, BonusSubtypes::destructionKillAmount))
 	{
 	{
 		double chanceToTrigger = 0;
 		double chanceToTrigger = 0;
 		int amountToDie = 0;
 		int amountToDie = 0;
 
 
-		if(attacker->hasBonusOfType(BonusType::DESTRUCTION, 0)) //killing by percentage
+		if(attacker->hasBonusOfType(BonusType::DESTRUCTION, BonusSubtypes::destructionKillPercentage)) //killing by percentage
 		{
 		{
-			chanceToTrigger = attacker->valOfBonuses(BonusType::DESTRUCTION, 0) / 100.0f;
-			int percentageToDie = attacker->getBonus(Selector::type()(BonusType::DESTRUCTION).And(Selector::subtype()(0)))->additionalInfo[0];
+			chanceToTrigger = attacker->valOfBonuses(BonusType::DESTRUCTION, BonusSubtypes::destructionKillPercentage) / 100.0f;
+			int percentageToDie = attacker->getBonus(Selector::type()(BonusType::DESTRUCTION).And(Selector::subtype()(BonusSubtypes::destructionKillPercentage)))->additionalInfo[0];
 			amountToDie = static_cast<int>(defender->getCount() * percentageToDie * 0.01f);
 			amountToDie = static_cast<int>(defender->getCount() * percentageToDie * 0.01f);
 		}
 		}
-		else if(attacker->hasBonusOfType(BonusType::DESTRUCTION, 1)) //killing by count
+		else if(attacker->hasBonusOfType(BonusType::DESTRUCTION, BonusSubtypes::destructionKillAmount)) //killing by count
 		{
 		{
-			chanceToTrigger = attacker->valOfBonuses(BonusType::DESTRUCTION, 1) / 100.0f;
-			amountToDie = attacker->getBonus(Selector::type()(BonusType::DESTRUCTION).And(Selector::subtype()(1)))->additionalInfo[0];
+			chanceToTrigger = attacker->valOfBonuses(BonusType::DESTRUCTION, BonusSubtypes::destructionKillAmount) / 100.0f;
+			amountToDie = attacker->getBonus(Selector::type()(BonusType::DESTRUCTION).And(Selector::subtype()(BonusSubtypes::destructionKillAmount)))->additionalInfo[0];
 		}
 		}
 
 
 		vstd::amin(chanceToTrigger, 1); //cap trigger chance at 100%
 		vstd::amin(chanceToTrigger, 1); //cap trigger chance at 100%
@@ -1348,12 +1348,13 @@ int64_t BattleActionProcessor::applyBattleEffects(const CBattleInfoCallback & ba
 	{
 	{
 		//we can have two bonuses - one with subtype 0 and another with subtype 1
 		//we can have two bonuses - one with subtype 0 and another with subtype 1
 		//try to use permanent first, use only one of two
 		//try to use permanent first, use only one of two
-		for(si32 subtype = 1; subtype >= 0; subtype--)
+		for(const auto & subtype : { BonusSubtypes::soulStealBattle, BonusSubtypes::soulStealPermanent})
 		{
 		{
 			if(attackerState->hasBonusOfType(BonusType::SOUL_STEAL, subtype))
 			if(attackerState->hasBonusOfType(BonusType::SOUL_STEAL, subtype))
 			{
 			{
 				int64_t toHeal = bsa.killedAmount * attackerState->valOfBonuses(BonusType::SOUL_STEAL, subtype) * attackerState->getMaxHealth();
 				int64_t toHeal = bsa.killedAmount * attackerState->valOfBonuses(BonusType::SOUL_STEAL, subtype) * attackerState->getMaxHealth();
-				attackerState->heal(toHeal, EHealLevel::OVERHEAL, ((subtype == 0) ? EHealPower::ONE_BATTLE : EHealPower::PERMANENT));
+				bool permanent = subtype == BonusSubtypes::soulStealPermanent;
+				attackerState->heal(toHeal, EHealLevel::OVERHEAL, (permanent ? EHealPower::PERMANENT : EHealPower::ONE_BATTLE));
 				drainedLife += toHeal;
 				drainedLife += toHeal;
 				break;
 				break;
 			}
 			}
@@ -1365,9 +1366,9 @@ int64_t BattleActionProcessor::applyBattleEffects(const CBattleInfoCallback & ba
 	if(!bat.shot() &&
 	if(!bat.shot() &&
 		!def->isClone() &&
 		!def->isClone() &&
 		def->hasBonusOfType(BonusType::FIRE_SHIELD) &&
 		def->hasBonusOfType(BonusType::FIRE_SHIELD) &&
-		!attackerState->hasBonusOfType(BonusType::SPELL_SCHOOL_IMMUNITY, SpellSchool(ESpellSchool::FIRE)) &&
-		!attackerState->hasBonusOfType(BonusType::NEGATIVE_EFFECTS_IMMUNITY, SpellSchool(ESpellSchool::FIRE)) &&
-		attackerState->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, SpellSchool(ESpellSchool::FIRE)) < 100 &&
+		!attackerState->hasBonusOfType(BonusType::SPELL_SCHOOL_IMMUNITY, TBonusSubtype(SpellSchool::FIRE)) &&
+		!attackerState->hasBonusOfType(BonusType::NEGATIVE_EFFECTS_IMMUNITY, TBonusSubtype(SpellSchool::FIRE)) &&
+		attackerState->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, TBonusSubtype(SpellSchool::FIRE)) < 100 &&
 		CStack::isMeleeAttackPossible(attackerState.get(), def) // attacked needs to be adjacent to defender for fire shield to trigger (e.g. Dragon Breath attack)
 		CStack::isMeleeAttackPossible(attackerState.get(), def) // attacked needs to be adjacent to defender for fire shield to trigger (e.g. Dragon Breath attack)
 			)
 			)
 	{
 	{

+ 8 - 8
server/battles/BattleFlowProcessor.cpp

@@ -144,7 +144,7 @@ void BattleFlowProcessor::trySummonGuardians(const CBattleInfoCallback & battle,
 
 
 	std::shared_ptr<const Bonus> summonInfo = stack->getBonus(Selector::type()(BonusType::SUMMON_GUARDIANS));
 	std::shared_ptr<const Bonus> summonInfo = stack->getBonus(Selector::type()(BonusType::SUMMON_GUARDIANS));
 	auto accessibility = battle.getAccesibility();
 	auto accessibility = battle.getAccesibility();
-	CreatureID creatureData = CreatureID(summonInfo->subtype);
+	CreatureID creatureData = summonInfo->subtype.as<CreatureID>();
 	std::vector<BattleHex> targetHexes;
 	std::vector<BattleHex> targetHexes;
 	const bool targetIsBig = stack->unitType()->isDoubleWide(); //target = creature to guard
 	const bool targetIsBig = stack->unitType()->isDoubleWide(); //target = creature to guard
 	const bool guardianIsBig = creatureData.toCreature()->isDoubleWide();
 	const bool guardianIsBig = creatureData.toCreature()->isDoubleWide();
@@ -198,7 +198,7 @@ void BattleFlowProcessor::castOpeningSpells(const CBattleInfoCallback & battle)
 		{
 		{
 			spells::BonusCaster caster(h, b);
 			spells::BonusCaster caster(h, b);
 
 
-			const CSpell * spell = SpellID(b->subtype).toSpell();
+			const CSpell * spell = b->subtype.as<SpellID>().toSpell();
 
 
 			spells::BattleCast parameters(&battle, &caster, spells::Mode::PASSIVE, spell);
 			spells::BattleCast parameters(&battle, &caster, spells::Mode::PASSIVE, spell);
 			parameters.setSpellLevel(3);
 			parameters.setSpellLevel(3);
@@ -380,10 +380,10 @@ bool BattleFlowProcessor::tryMakeAutomaticAction(const CBattleInfoCallback & bat
 	}
 	}
 
 
 	const CGHeroInstance * curOwner = battle.battleGetOwnerHero(next);
 	const CGHeroInstance * curOwner = battle.battleGetOwnerHero(next);
-	const int stackCreatureId = next->unitType()->getId();
+	const CreatureID stackCreatureId = next->unitType()->getId();
 
 
 	if ((stackCreatureId == CreatureID::ARROW_TOWERS || stackCreatureId == CreatureID::BALLISTA)
 	if ((stackCreatureId == CreatureID::ARROW_TOWERS || stackCreatureId == CreatureID::BALLISTA)
-		&& (!curOwner || gameHandler->getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(BonusType::MANUAL_CONTROL, stackCreatureId)))
+		&& (!curOwner || gameHandler->getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(BonusType::MANUAL_CONTROL, TBonusSubtype(stackCreatureId))))
 	{
 	{
 		BattleAction attack;
 		BattleAction attack;
 		attack.actionType = EActionType::SHOOT;
 		attack.actionType = EActionType::SHOOT;
@@ -428,7 +428,7 @@ bool BattleFlowProcessor::tryMakeAutomaticAction(const CBattleInfoCallback & bat
 			return true;
 			return true;
 		}
 		}
 
 
-		if (!curOwner || gameHandler->getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(BonusType::MANUAL_CONTROL, CreatureID::CATAPULT))
+		if (!curOwner || gameHandler->getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(BonusType::MANUAL_CONTROL, TBonusSubtype(CreatureID(CreatureID::CATAPULT))))
 		{
 		{
 			BattleAction attack;
 			BattleAction attack;
 			attack.actionType = EActionType::CATAPULT;
 			attack.actionType = EActionType::CATAPULT;
@@ -453,7 +453,7 @@ bool BattleFlowProcessor::tryMakeAutomaticAction(const CBattleInfoCallback & bat
 			return true;
 			return true;
 		}
 		}
 
 
-		if (!curOwner || gameHandler->getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(BonusType::MANUAL_CONTROL, CreatureID::FIRST_AID_TENT))
+		if (!curOwner || gameHandler->getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(BonusType::MANUAL_CONTROL, TBonusSubtype(CreatureID(CreatureID::FIRST_AID_TENT))))
 		{
 		{
 			RandomGeneratorUtil::randomShuffle(possibleStacks, gameHandler->getRandomGenerator());
 			RandomGeneratorUtil::randomShuffle(possibleStacks, gameHandler->getRandomGenerator());
 			const CStack * toBeHealed = possibleStacks.front();
 			const CStack * toBeHealed = possibleStacks.front();
@@ -583,7 +583,7 @@ void BattleFlowProcessor::stackEnchantedTrigger(const CBattleInfoCallback & batt
 	auto bl = *(st->getBonuses(Selector::type()(BonusType::ENCHANTED)));
 	auto bl = *(st->getBonuses(Selector::type()(BonusType::ENCHANTED)));
 	for(auto b : bl)
 	for(auto b : bl)
 	{
 	{
-		const CSpell * sp = SpellID(b->subtype).toSpell();
+		const CSpell * sp = b->subtype.as<SpellID>().toSpell();
 		if(!sp)
 		if(!sp)
 			continue;
 			continue;
 
 
@@ -719,7 +719,7 @@ void BattleFlowProcessor::stackTurnTrigger(const CBattleInfoCallback & battle, c
 			while(!bl.empty() && !cast)
 			while(!bl.empty() && !cast)
 			{
 			{
 				auto bonus = *RandomGeneratorUtil::nextItem(bl, gameHandler->getRandomGenerator());
 				auto bonus = *RandomGeneratorUtil::nextItem(bl, gameHandler->getRandomGenerator());
-				auto spellID = SpellID(bonus->subtype);
+				auto spellID = bonus->subtype.as<SpellID>();
 				const CSpell * spell = SpellID(spellID).toSpell();
 				const CSpell * spell = SpellID(spellID).toSpell();
 				bl.remove_if([&bonus](const Bonus * b)
 				bl.remove_if([&bonus](const Bonus * b)
 				{
 				{

+ 2 - 2
server/battles/BattleResultProcessor.cpp

@@ -316,9 +316,9 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
 
 
 	if(!finishingBattle->isDraw() && finishingBattle->winnerHero)
 	if(!finishingBattle->isDraw() && finishingBattle->winnerHero)
 	{
 	{
-		if (int eagleEyeLevel = finishingBattle->winnerHero->valOfBonuses(BonusType::LEARN_BATTLE_SPELL_LEVEL_LIMIT, -1))
+		if (int eagleEyeLevel = finishingBattle->winnerHero->valOfBonuses(BonusType::LEARN_BATTLE_SPELL_LEVEL_LIMIT))
 		{
 		{
-			double eagleEyeChance = finishingBattle->winnerHero->valOfBonuses(BonusType::LEARN_BATTLE_SPELL_CHANCE, 0);
+			double eagleEyeChance = finishingBattle->winnerHero->valOfBonuses(BonusType::LEARN_BATTLE_SPELL_CHANCE);
 			for(auto & spellId : battle.getBattle()->getUsedSpells(battle.otherSide(battleResult->winner)))
 			for(auto & spellId : battle.getBattle()->getUsedSpells(battle.otherSide(battleResult->winner)))
 			{
 			{
 				auto spell = spellId.toSpell(VLC->spells());
 				auto spell = spellId.toSpell(VLC->spells());

+ 1 - 1
server/processors/PlayerMessageProcessor.cpp

@@ -144,7 +144,7 @@ void PlayerMessageProcessor::cheatGiveSpells(PlayerColor player, const CGHeroIns
 	//start with level 0 to skip abilities
 	//start with level 0 to skip abilities
 	for (int level = 1; level <= GameConstants::SPELL_LEVELS; level++)
 	for (int level = 1; level <= GameConstants::SPELL_LEVELS; level++)
 	{
 	{
-		giveBonus.bonus.subtype = level;
+		giveBonus.bonus.subtype = BonusSubtypes::spellLevel(level);
 		gameHandler->sendAndApply(&giveBonus);
 		gameHandler->sendAndApply(&giveBonus);
 	}
 	}
 
 

+ 2 - 2
test/battle/CUnitStateMagicTest.cpp

@@ -55,7 +55,7 @@ public:
 
 
 	void makeNormalCaster()
 	void makeNormalCaster()
 	{
 	{
-		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SPELLCASTER, BonusSource::CREATURE_ABILITY, DEFAULT_SCHOOL_LEVEL, 0, DEFAULT_SPELL_INDEX));
+		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SPELLCASTER, BonusSource::CREATURE_ABILITY, DEFAULT_SCHOOL_LEVEL, 0, TBonusSubtype(SpellID(DEFAULT_SPELL_INDEX))));
 	}
 	}
 };
 };
 
 
@@ -171,7 +171,7 @@ TEST_F(UnitStateMagicTest, effectValue)
 
 
 	const int32_t EFFECT_VALUE = 456;
 	const int32_t EFFECT_VALUE = 456;
 
 
-	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SPECIFIC_SPELL_POWER, BonusSource::CREATURE_ABILITY, EFFECT_VALUE, 0, DEFAULT_SPELL_INDEX));
+	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SPECIFIC_SPELL_POWER, BonusSource::CREATURE_ABILITY, EFFECT_VALUE, 0, TBonusSubtype(SpellID(DEFAULT_SPELL_INDEX))));
 
 
 	makeNormalCaster();
 	makeNormalCaster();
 	EXPECT_EQ(subject.getEffectValue(&spellMock), EFFECT_VALUE * DEFAULT_AMOUNT);
 	EXPECT_EQ(subject.getEffectValue(&spellMock), EFFECT_VALUE * DEFAULT_AMOUNT);

+ 6 - 6
test/battle/CUnitStateTest.cpp

@@ -53,8 +53,8 @@ public:
 	{
 	{
 		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACKS_SPEED, BonusSource::CREATURE_ABILITY, DEFAULT_SPEED, 0));
 		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACKS_SPEED, BonusSource::CREATURE_ABILITY, DEFAULT_SPEED, 0));
 
 
-		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::CREATURE_ABILITY, DEFAULT_ATTACK, 0, static_cast<int>(PrimarySkill::ATTACK)));
-		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::CREATURE_ABILITY, DEFAULT_DEFENCE, 0, static_cast<int>(PrimarySkill::DEFENSE)));
+		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::CREATURE_ABILITY, DEFAULT_ATTACK, 0, TBonusSubtype(PrimarySkill::ATTACK)));
+		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::CREATURE_ABILITY, DEFAULT_DEFENCE, 0, TBonusSubtype(PrimarySkill::DEFENSE)));
 
 
 		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, DEFAULT_HP, 0));
 		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, DEFAULT_HP, 0));
 
 
@@ -248,10 +248,10 @@ TEST_F(UnitStateTest, getMinDamage)
 	setDefaultExpectations();
 	setDefaultExpectations();
 
 
 	{
 	{
-		auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_DAMAGE, BonusSource::SPELL_EFFECT, 30, 0, 0);
+		auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_DAMAGE, BonusSource::SPELL_EFFECT, 30, 0, BonusSubtypes::creatureDamageBoth);
 		bonusMock.addNewBonus(bonus);
 		bonusMock.addNewBonus(bonus);
 
 
-		bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_DAMAGE, BonusSource::SPELL_EFFECT, -20, 0, 1);
+		bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_DAMAGE, BonusSource::SPELL_EFFECT, -20, 0, BonusSubtypes::creatureDamageMin);
 		bonusMock.addNewBonus(bonus);
 		bonusMock.addNewBonus(bonus);
 	}
 	}
 
 
@@ -264,10 +264,10 @@ TEST_F(UnitStateTest, getMaxDamage)
 	setDefaultExpectations();
 	setDefaultExpectations();
 
 
 	{
 	{
-		auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_DAMAGE, BonusSource::SPELL_EFFECT, 30, 0, 0);
+		auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_DAMAGE, BonusSource::SPELL_EFFECT, 30, 0, BonusSubtypes::creatureDamageBoth);
 		bonusMock.addNewBonus(bonus);
 		bonusMock.addNewBonus(bonus);
 
 
-		bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_DAMAGE, BonusSource::SPELL_EFFECT, -20, 0, 2);
+		bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_DAMAGE, BonusSource::SPELL_EFFECT, -20, 0, BonusSubtypes::creatureDamageMax);
 		bonusMock.addNewBonus(bonus);
 		bonusMock.addNewBonus(bonus);
 	}
 	}
 
 

+ 5 - 6
test/entity/CCreatureTest.cpp

@@ -107,7 +107,7 @@ TEST_F(CCreatureTest, JsonAddBonus)
 {
 {
 	JsonNode data(JsonNode::JsonType::DATA_STRUCT);
 	JsonNode data(JsonNode::JsonType::DATA_STRUCT);
 
 
-	std::shared_ptr<Bonus> b = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::BLOCKS_RETALIATION, BonusSource::CREATURE_ABILITY, 17, 42, 43, BonusValueType::BASE_NUMBER);
+	std::shared_ptr<Bonus> b = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::BLOCKS_RETALIATION, BonusSource::CREATURE_ABILITY, 17, 42, TBonusSubtype(CreatureID(43)), BonusValueType::BASE_NUMBER);
 
 
 	JsonNode & toAdd = data["bonuses"]["toAdd"];
 	JsonNode & toAdd = data["bonuses"]["toAdd"];
 
 
@@ -122,7 +122,7 @@ TEST_F(CCreatureTest, JsonAddBonus)
 			&& (bonus->source == BonusSource::CREATURE_ABILITY)
 			&& (bonus->source == BonusSource::CREATURE_ABILITY)
 			&& (bonus->val == 17)
 			&& (bonus->val == 17)
 			&& (bonus->sid == 42)
 			&& (bonus->sid == 42)
-			&& (bonus->subtype == 43)
+			&& (bonus->subtype.as<CreatureID>().getNum() == 43)
 			&& (bonus->valType == BonusValueType::BASE_NUMBER);
 			&& (bonus->valType == BonusValueType::BASE_NUMBER);
 	};
 	};
 
 
@@ -133,10 +133,10 @@ TEST_F(CCreatureTest, JsonRemoveBonus)
 {
 {
 	JsonNode data(JsonNode::JsonType::DATA_STRUCT);
 	JsonNode data(JsonNode::JsonType::DATA_STRUCT);
 
 
-	std::shared_ptr<Bonus> b1 = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::BLOCKS_RETALIATION, BonusSource::CREATURE_ABILITY, 17, 42, 43, BonusValueType::BASE_NUMBER);
+	std::shared_ptr<Bonus> b1 = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::BLOCKS_RETALIATION, BonusSource::CREATURE_ABILITY, 17, 42, TBonusSubtype(CreatureID(43)), BonusValueType::BASE_NUMBER);
 	subject->addNewBonus(b1);
 	subject->addNewBonus(b1);
 
 
-	std::shared_ptr<Bonus> b2 = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::BLOCKS_RETALIATION, BonusSource::CREATURE_ABILITY, 18, 42, 43, BonusValueType::BASE_NUMBER);
+	std::shared_ptr<Bonus> b2 = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::BLOCKS_RETALIATION, BonusSource::CREATURE_ABILITY, 18, 42, TBonusSubtype(CreatureID(43)), BonusValueType::BASE_NUMBER);
 	subject->addNewBonus(b2);
 	subject->addNewBonus(b2);
 
 
 
 
@@ -153,7 +153,7 @@ TEST_F(CCreatureTest, JsonRemoveBonus)
 			&& (bonus->source == BonusSource::CREATURE_ABILITY)
 			&& (bonus->source == BonusSource::CREATURE_ABILITY)
 			&& (bonus->val == 17)
 			&& (bonus->val == 17)
 			&& (bonus->sid == 42)
 			&& (bonus->sid == 42)
-			&& (bonus->subtype == 43)
+			&& (bonus->subtype.as<CreatureID>().getNum() == 43)
 			&& (bonus->valType == BonusValueType::BASE_NUMBER);
 			&& (bonus->valType == BonusValueType::BASE_NUMBER);
 	};
 	};
 
 
@@ -166,7 +166,6 @@ TEST_F(CCreatureTest, JsonRemoveBonus)
 			&& (bonus->source == BonusSource::CREATURE_ABILITY)
 			&& (bonus->source == BonusSource::CREATURE_ABILITY)
 			&& (bonus->val == 18)
 			&& (bonus->val == 18)
 			&& (bonus->sid == 42)
 			&& (bonus->sid == 42)
-			&& (bonus->subtype == 43)
 			&& (bonus->valType == BonusValueType::BASE_NUMBER);
 			&& (bonus->valType == BonusValueType::BASE_NUMBER);
 	};
 	};
 
 

+ 2 - 2
test/spells/AbilityCasterTest.cpp

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

+ 2 - 2
test/spells/effects/TimedTest.cpp

@@ -71,9 +71,9 @@ protected:
 
 
 TEST_P(TimedApplyTest, ChangesBonuses)
 TEST_P(TimedApplyTest, ChangesBonuses)
 {
 {
-	Bonus testBonus1(BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 3, 0, static_cast<int>(PrimarySkill::KNOWLEDGE));
+	Bonus testBonus1(BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 3, 0, TBonusSubtype(PrimarySkill::KNOWLEDGE));
 
 
-	Bonus testBonus2(BonusDuration::N_TURNS, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 3, 0, static_cast<int>(PrimarySkill::KNOWLEDGE));
+	Bonus testBonus2(BonusDuration::N_TURNS, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 3, 0, TBonusSubtype(PrimarySkill::KNOWLEDGE));
 	testBonus2.turnsRemain = 4;
 	testBonus2.turnsRemain = 4;
 
 
 	JsonNode options(JsonNode::JsonType::DATA_STRUCT);
 	JsonNode options(JsonNode::JsonType::DATA_STRUCT);

+ 2 - 2
test/spells/targetConditions/AbsoluteSpellConditionTest.cpp

@@ -43,7 +43,7 @@ public:
 TEST_P(AbsoluteSpellConditionTest, ChecksAbsoluteCase)
 TEST_P(AbsoluteSpellConditionTest, ChecksAbsoluteCase)
 {
 {
 	setDefaultExpectations();
 	setDefaultExpectations();
-	auto bonus = std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_IMMUNITY, BonusSource::OTHER, 4, 0, immuneSpell);
+	auto bonus = std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_IMMUNITY, BonusSource::OTHER, 4, 0, TBonusSubtype(SpellID(immuneSpell)));
 	bonus->additionalInfo = 1;
 	bonus->additionalInfo = 1;
 
 
 	unitBonuses.addNewBonus(bonus);
 	unitBonuses.addNewBonus(bonus);
@@ -57,7 +57,7 @@ TEST_P(AbsoluteSpellConditionTest, ChecksAbsoluteCase)
 TEST_P(AbsoluteSpellConditionTest, IgnoresNormalCase)
 TEST_P(AbsoluteSpellConditionTest, IgnoresNormalCase)
 {
 {
 	setDefaultExpectations();
 	setDefaultExpectations();
-	auto bonus = std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_IMMUNITY, BonusSource::OTHER, 4, 0, immuneSpell);
+	auto bonus = std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_IMMUNITY, BonusSource::OTHER, 4, 0, TBonusSubtype(SpellID(immuneSpell)));
 	unitBonuses.addNewBonus(bonus);
 	unitBonuses.addNewBonus(bonus);
 	EXPECT_TRUE(subject->isReceptive(&mechanicsMock, &unitMock));
 	EXPECT_TRUE(subject->isReceptive(&mechanicsMock, &unitMock));
 }
 }

+ 1 - 1
test/spells/targetConditions/BonusConditionTest.cpp

@@ -49,7 +49,7 @@ TEST_F(BonusConditionTest, ReceptiveIfMatchesType)
 TEST_F(BonusConditionTest, ImmuneIfTypeMismatch)
 TEST_F(BonusConditionTest, ImmuneIfTypeMismatch)
 {
 {
 	setDefaultExpectations();
 	setDefaultExpectations();
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::OTHER, 0, SpellSchool(ESpellSchool::FIRE)));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::OTHER, 0, SpellSchool(SpellSchool::FIRE)));
 	EXPECT_FALSE(subject->isReceptive(&mechanicsMock, &unitMock));
 	EXPECT_FALSE(subject->isReceptive(&mechanicsMock, &unitMock));
 }
 }
 
 

+ 7 - 7
test/spells/targetConditions/ElementalConditionTest.cpp

@@ -30,8 +30,8 @@ public:
 		EXPECT_CALL(spellMock, forEachSchool(NotNull())).Times(AtLeast(1)).WillRepeatedly([](const spells::Spell::SchoolCallback & cb)
 		EXPECT_CALL(spellMock, forEachSchool(NotNull())).Times(AtLeast(1)).WillRepeatedly([](const spells::Spell::SchoolCallback & cb)
 		{
 		{
 			bool stop = false;
 			bool stop = false;
-			cb(SpellSchool(ESpellSchool::AIR), stop);
-			cb(SpellSchool(ESpellSchool::FIRE), stop);
+			cb(SpellSchool(SpellSchool::AIR), stop);
+			cb(SpellSchool(SpellSchool::FIRE), stop);
 		});
 		});
 
 
 		EXPECT_CALL(mechanicsMock, isPositiveSpell()).WillRepeatedly(Return(isPositive));
 		EXPECT_CALL(mechanicsMock, isPositiveSpell()).WillRepeatedly(Return(isPositive));
@@ -56,7 +56,7 @@ TEST_P(ElementalConditionTest, ReceptiveIfNoBonus)
 TEST_P(ElementalConditionTest, ImmuneIfBonusMatches)
 TEST_P(ElementalConditionTest, ImmuneIfBonusMatches)
 {
 {
 	setDefaultExpectations();
 	setDefaultExpectations();
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, SpellSchool(ESpellSchool::AIR)));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, TBonusSubtype(SpellSchool::AIR)));
 
 
 	EXPECT_FALSE(subject->isReceptive(&mechanicsMock, &unitMock));
 	EXPECT_FALSE(subject->isReceptive(&mechanicsMock, &unitMock));
 }
 }
@@ -64,7 +64,7 @@ TEST_P(ElementalConditionTest, ImmuneIfBonusMatches)
 TEST_P(ElementalConditionTest, NotImmuneIfBonusMismatches)
 TEST_P(ElementalConditionTest, NotImmuneIfBonusMismatches)
 {
 {
 	setDefaultExpectations();
 	setDefaultExpectations();
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, SpellSchool(ESpellSchool::WATER)));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, TBonusSubtype(SpellSchool::WATER)));
 
 
 	EXPECT_TRUE(subject->isReceptive(&mechanicsMock, &unitMock));
 	EXPECT_TRUE(subject->isReceptive(&mechanicsMock, &unitMock));
 }
 }
@@ -72,7 +72,7 @@ TEST_P(ElementalConditionTest, NotImmuneIfBonusMismatches)
 TEST_P(ElementalConditionTest, DependsOnPositivness)
 TEST_P(ElementalConditionTest, DependsOnPositivness)
 {
 {
 	setDefaultExpectations();
 	setDefaultExpectations();
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATIVE_EFFECTS_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, SpellSchool(ESpellSchool::AIR)));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATIVE_EFFECTS_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, TBonusSubtype(SpellSchool::AIR)));
 
 
 	EXPECT_EQ(isPositive, subject->isReceptive(&mechanicsMock, &unitMock));
 	EXPECT_EQ(isPositive, subject->isReceptive(&mechanicsMock, &unitMock));
 }
 }
@@ -80,8 +80,8 @@ TEST_P(ElementalConditionTest, DependsOnPositivness)
 TEST_P(ElementalConditionTest, ImmuneIfBothBonusesPresent)
 TEST_P(ElementalConditionTest, ImmuneIfBothBonusesPresent)
 {
 {
 	setDefaultExpectations();
 	setDefaultExpectations();
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, SpellSchool(ESpellSchool::AIR)));
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATIVE_EFFECTS_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, SpellSchool(ESpellSchool::AIR)));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, TBonusSubtype(SpellSchool::AIR)));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATIVE_EFFECTS_IMMUNITY, BonusSource::SPELL_EFFECT, 0, 0, TBonusSubtype(SpellSchool::AIR)));
 
 
 	EXPECT_FALSE(subject->isReceptive(&mechanicsMock, &unitMock));
 	EXPECT_FALSE(subject->isReceptive(&mechanicsMock, &unitMock));
 }
 }

+ 2 - 2
test/spells/targetConditions/ImmunityNegationConditionTest.cpp

@@ -57,7 +57,7 @@ TEST_P(ImmunityNegationConditionTest, WithHeroNegation)
 {
 {
 	setDefaultExpectations();
 	setDefaultExpectations();
 
 
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, BonusSource::OTHER, 0, 0, 1));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, BonusSource::OTHER, 0, 0, BonusSubtypes::immunityEnemyHero));
 
 
 	EXPECT_EQ(isMagicalEffect, subject->isReceptive(&mechanicsMock, &unitMock));
 	EXPECT_EQ(isMagicalEffect, subject->isReceptive(&mechanicsMock, &unitMock));
 }
 }
@@ -66,7 +66,7 @@ TEST_P(ImmunityNegationConditionTest, WithBattleWideNegation)
 {
 {
 	setDefaultExpectations();
 	setDefaultExpectations();
 
 
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, BonusSource::OTHER, 0, 0, 0));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, BonusSource::OTHER, 0, 0, BonusSubtypes::immunityBattleWide));
 
 
 	//This should return if ownerMatches, because anyone should cast onto owner's stacks, but not on enemyStacks
 	//This should return if ownerMatches, because anyone should cast onto owner's stacks, but not on enemyStacks
 	EXPECT_EQ(ownerMatches && isMagicalEffect, subject->isReceptive(&mechanicsMock, &unitMock));
 	EXPECT_EQ(ownerMatches && isMagicalEffect, subject->isReceptive(&mechanicsMock, &unitMock));

+ 2 - 2
test/spells/targetConditions/NormalSpellConditionTest.cpp

@@ -43,7 +43,7 @@ public:
 TEST_P(NormalSpellConditionTest, ChecksAbsoluteCase)
 TEST_P(NormalSpellConditionTest, ChecksAbsoluteCase)
 {
 {
 	setDefaultExpectations();
 	setDefaultExpectations();
-	auto bonus = std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_IMMUNITY, BonusSource::OTHER, 4, 0, immuneSpell);
+	auto bonus = std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_IMMUNITY, BonusSource::OTHER, 4, 0, TBonusSubtype(SpellID(immuneSpell)));
 	bonus->additionalInfo = 1;
 	bonus->additionalInfo = 1;
 
 
 	unitBonuses.addNewBonus(bonus);
 	unitBonuses.addNewBonus(bonus);
@@ -57,7 +57,7 @@ TEST_P(NormalSpellConditionTest, ChecksAbsoluteCase)
 TEST_P(NormalSpellConditionTest, ChecksNormalCase)
 TEST_P(NormalSpellConditionTest, ChecksNormalCase)
 {
 {
 	setDefaultExpectations();
 	setDefaultExpectations();
-	auto bonus = std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_IMMUNITY, BonusSource::OTHER, 4, 0, immuneSpell);
+	auto bonus = std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_IMMUNITY, BonusSource::OTHER, 4, 0, TBonusSubtype(SpellID(immuneSpell)));
 	unitBonuses.addNewBonus(bonus);
 	unitBonuses.addNewBonus(bonus);
 	if(immuneSpell == castSpell)
 	if(immuneSpell == castSpell)
 		EXPECT_FALSE(subject->isReceptive(&mechanicsMock, &unitMock));
 		EXPECT_FALSE(subject->isReceptive(&mechanicsMock, &unitMock));