Selaa lähdekoodia

MetaIdentifier now uses std::variant internally

Ivan Savenko 2 vuotta sitten
vanhempi
sitoutus
80e6485965
61 muutettua tiedostoa jossa 487 lisäystä ja 421 poistoa
  1. 1 2
      AI/Nullkiller/Engine/PriorityEvaluator.cpp
  2. 1 2
      client/battle/BattleStacksController.cpp
  3. 2 3
      cmake_modules/VCMI_lib.cmake
  4. 2 3
      lib/BasicTypes.cpp
  5. 2 3
      lib/CBonusTypeHandler.cpp
  6. 11 12
      lib/CCreatureHandler.cpp
  7. 2 3
      lib/CGameInfoCallback.cpp
  8. 1 2
      lib/CStack.cpp
  9. 6 6
      lib/CTownHandler.cpp
  10. 1 0
      lib/CTownHandler.h
  11. 5 5
      lib/JsonNode.cpp
  12. 1 1
      lib/JsonNode.h
  13. 1 1
      lib/NetPacksLib.cpp
  14. 3 3
      lib/battle/BattleInfo.cpp
  15. 2 4
      lib/battle/CUnitState.cpp
  16. 6 7
      lib/battle/DamageCalculator.cpp
  17. 4 4
      lib/bonuses/Bonus.cpp
  18. 4 2
      lib/bonuses/Bonus.h
  19. 1 1
      lib/bonuses/BonusList.cpp
  20. 1 1
      lib/bonuses/BonusList.h
  21. 26 24
      lib/bonuses/BonusParams.cpp
  22. 76 0
      lib/bonuses/BonusSubtypeID.cpp
  23. 78 0
      lib/bonuses/BonusSubtypeID.h
  24. 0 56
      lib/bonuses/BonusSubtypes.cpp
  25. 0 64
      lib/bonuses/BonusSubtypes.h
  26. 79 2
      lib/constants/EntityIdentifiers.cpp
  27. 13 1
      lib/constants/EntityIdentifiers.h
  28. 0 67
      lib/constants/MetaIdentifier.cpp
  29. 44 24
      lib/constants/MetaIdentifier.h
  30. 1 1
      lib/gameState/CGameState.cpp
  31. 5 0
      lib/mapObjectConstructors/CObjectClassesHandler.cpp
  32. 2 0
      lib/mapObjectConstructors/CObjectClassesHandler.h
  33. 3 4
      lib/mapObjects/CArmedInstance.cpp
  34. 1 2
      lib/mapObjects/CGCreature.cpp
  35. 3 4
      lib/mapObjects/CGHeroInstance.cpp
  36. 1 2
      lib/mapObjects/CGTownBuilding.cpp
  37. 2 3
      lib/mapObjects/CGTownInstance.cpp
  38. 1 2
      lib/mapObjects/MiscObjects.cpp
  39. 2 2
      lib/pathfinder/TurnInfo.cpp
  40. 2 3
      lib/spells/TargetCondition.cpp
  41. 18 19
      server/battles/BattleActionProcessor.cpp
  42. 2 3
      server/processors/PlayerMessageProcessor.cpp
  43. 10 10
      test/battle/CBattleInfoCallbackTest.cpp
  44. 2 2
      test/battle/CHealthTest.cpp
  45. 6 6
      test/battle/CUnitStateMagicTest.cpp
  46. 15 16
      test/battle/CUnitStateTest.cpp
  47. 2 2
      test/spells/AbilityCasterTest.cpp
  48. 3 3
      test/spells/effects/DamageTest.cpp
  49. 5 5
      test/spells/effects/HealTest.cpp
  50. 2 2
      test/spells/effects/SacrificeTest.cpp
  51. 2 2
      test/spells/effects/SummonTest.cpp
  52. 2 2
      test/spells/effects/TimedTest.cpp
  53. 4 4
      test/spells/targetConditions/AbsoluteLevelConditionTest.cpp
  54. 2 2
      test/spells/targetConditions/AbsoluteSpellConditionTest.cpp
  55. 2 2
      test/spells/targetConditions/BonusConditionTest.cpp
  56. 5 5
      test/spells/targetConditions/ElementalConditionTest.cpp
  57. 2 3
      test/spells/targetConditions/ImmunityNegationConditionTest.cpp
  58. 3 3
      test/spells/targetConditions/NormalLevelConditionTest.cpp
  59. 2 2
      test/spells/targetConditions/NormalSpellConditionTest.cpp
  60. 1 1
      test/spells/targetConditions/ReceptiveFeatureConditionTest.cpp
  61. 1 1
      test/spells/targetConditions/SpellEffectConditionTest.cpp

+ 1 - 2
AI/Nullkiller/Engine/PriorityEvaluator.cpp

@@ -11,7 +11,6 @@
 #include <limits>
 
 #include "Nullkiller.h"
-#include "../../../lib/bonuses/BonusSubtypes.h"
 #include "../../../lib/mapObjectConstructors/AObjectTypeHandler.h"
 #include "../../../lib/mapObjectConstructors/CObjectClassesHandler.h"
 #include "../../../lib/mapObjectConstructors/CBankInstanceConstructor.h"
@@ -243,7 +242,7 @@ uint64_t evaluateArtifactArmyValue(CArtifactInstance * art)
 		return 1500;
 
 	auto statsValue =
-		10 * art->valOfBonuses(BonusType::MOVEMENT, BonusSubtypes::heroMovementLand)
+		10 * art->valOfBonuses(BonusType::MOVEMENT, BonusSubtypeID::heroMovementLand)
 		+ 1200 * art->valOfBonuses(BonusType::STACKS_SPEED)
 		+ 700 * art->valOfBonuses(BonusType::MORALE)
 		+ 700 * art->valOfBonuses(BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::ATTACK))

+ 1 - 2
client/battle/BattleStacksController.cpp

@@ -34,7 +34,6 @@
 #include "../../lib/spells/ISpellMechanics.h"
 #include "../../lib/battle/BattleAction.h"
 #include "../../lib/battle/BattleHex.h"
-#include "../../lib/bonuses/BonusSubtypes.h"
 #include "../../lib/CStack.h"
 #include "../../lib/CondSh.h"
 #include "../../lib/TextOperations.h"
@@ -535,7 +534,7 @@ void BattleStacksController::stackMoved(const CStack *stack, std::vector<BattleH
 		addNewAnim(new MovementStartAnimation(owner, stack));
 	});
 
-	if (!stack->hasBonus(Selector::typeSubtype(BonusType::FLYING, BonusSubtypes::movementFlying)))
+	if (!stack->hasBonus(Selector::typeSubtype(BonusType::FLYING, BonusSubtypeID::movementFlying)))
 	{
 		owner.addToAnimationStage(EAnimationEvents::MOVEMENT, [&]()
 		{

+ 2 - 3
cmake_modules/VCMI_lib.cmake

@@ -31,7 +31,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
 		${MAIN_LIB_DIR}/bonuses/BonusList.cpp
 		${MAIN_LIB_DIR}/bonuses/BonusParams.cpp
 		${MAIN_LIB_DIR}/bonuses/BonusSelector.cpp
-		${MAIN_LIB_DIR}/bonuses/BonusSubtypes.cpp
+		${MAIN_LIB_DIR}/bonuses/BonusSubtypeID.cpp
 		${MAIN_LIB_DIR}/bonuses/CBonusProxy.cpp
 		${MAIN_LIB_DIR}/bonuses/CBonusSystemNode.cpp
 		${MAIN_LIB_DIR}/bonuses/IBonusBearer.cpp
@@ -43,7 +43,6 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
 		${MAIN_LIB_DIR}/campaign/CampaignState.cpp
 
 		${MAIN_LIB_DIR}/constants/EntityIdentifiers.cpp
-		${MAIN_LIB_DIR}/constants/MetaIdentifier.cpp
 
 		${MAIN_LIB_DIR}/events/ApplyDamage.cpp
 		${MAIN_LIB_DIR}/events/GameResumed.cpp
@@ -359,7 +358,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
 		${MAIN_LIB_DIR}/bonuses/BonusList.h
 		${MAIN_LIB_DIR}/bonuses/BonusParams.h
 		${MAIN_LIB_DIR}/bonuses/BonusSelector.h
-		${MAIN_LIB_DIR}/bonuses/BonusSubtypes.h
+		${MAIN_LIB_DIR}/bonuses/BonusSubtypeID.h
 		${MAIN_LIB_DIR}/bonuses/CBonusProxy.h
 		${MAIN_LIB_DIR}/bonuses/CBonusSystemNode.h
 		${MAIN_LIB_DIR}/bonuses/IBonusBearer.h

+ 2 - 3
lib/BasicTypes.cpp

@@ -17,7 +17,6 @@
 #include "bonuses/BonusList.h"
 #include "bonuses/Bonus.h"
 #include "bonuses/IBonusBearer.h"
-#include "bonuses/BonusSubtypes.h"
 
 #include <vcmi/Creature.h>
 #include <vcmi/Faction.h>
@@ -72,14 +71,14 @@ int AFactionMember::getDefense(bool ranged) const
 int AFactionMember::getMinDamage(bool ranged) const
 {
 	const std::string cachingStr = "type_CREATURE_DAMAGEs_0Otype_CREATURE_DAMAGEs_1";
-	static const auto selector = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageBoth).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMin));
+	static const auto selector = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypeID::creatureDamageBoth).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypeID::creatureDamageMin));
 	return getBonusBearer()->valOfBonuses(selector, cachingStr);
 }
 
 int AFactionMember::getMaxDamage(bool ranged) const
 {
 	const std::string cachingStr = "type_CREATURE_DAMAGEs_0Otype_CREATURE_DAMAGEs_2";
-	static const auto selector = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageBoth).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMax));
+	static const auto selector = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypeID::creatureDamageBoth).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypeID::creatureDamageMax));
 	return getBonusBearer()->valOfBonuses(selector, cachingStr);
 }
 

+ 2 - 3
lib/CBonusTypeHandler.cpp

@@ -20,7 +20,6 @@
 #include "CCreatureHandler.h"
 #include "CGeneralTextHandler.h"
 #include "spells/CSpellHandler.h"
-#include "bonuses/BonusSubtypes.h"
 
 template class std::vector<VCMI_LIB_WRAP_NAMESPACE(CBonusType)>;
 
@@ -169,10 +168,10 @@ ImagePath CBonusTypeHandler::bonusToGraphics(const std::shared_ptr<Bonus> & bonu
 	}
 	case BonusType::GENERAL_DAMAGE_REDUCTION:
 	{
-		if (bonus->subtype == BonusSubtypes::damageTypeMelee)
+		if (bonus->subtype == BonusSubtypeID::damageTypeMelee)
 			fileName = "DamageReductionMelee.bmp";
 
-		if (bonus->subtype == BonusSubtypes::damageTypeRanged)
+		if (bonus->subtype == BonusSubtypeID::damageTypeRanged)
 			fileName = "DamageReductionRanged.bmp";
 
 		break;

+ 11 - 12
lib/CCreatureHandler.cpp

@@ -19,7 +19,6 @@
 #include "constants/StringConstants.h"
 #include "bonuses/Limiters.h"
 #include "bonuses/Updaters.h"
-#include "bonuses/BonusSubtypes.h"
 #include "serializer/JsonDeserializer.h"
 #include "serializer/JsonUpdater.h"
 #include "mapObjectConstructors/AObjectTypeHandler.h"
@@ -126,13 +125,13 @@ int32_t CCreature::getBaseDefense() const
 
 int32_t CCreature::getBaseDamageMin() const
 {
-	static const auto SELECTOR = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMin).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
+	static const auto SELECTOR = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypeID::creatureDamageMin).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
 	return getExportedBonusList().valOfBonuses(SELECTOR);
 }
 
 int32_t CCreature::getBaseDamageMax() const
 {
-	static const auto SELECTOR = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMax).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
+	static const auto SELECTOR = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypeID::creatureDamageMax).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
 	return getExportedBonusList().valOfBonuses(SELECTOR);
 }
 
@@ -294,7 +293,7 @@ CCreature::CCreature()
 
 void CCreature::addBonus(int val, BonusType type)
 {
-	addBonus(val, type, TBonusSubtype::NONE);
+	addBonus(val, type, TBonusSubtype());
 }
 
 void CCreature::addBonus(int val, BonusType type, TBonusSubtype subtype)
@@ -357,10 +356,10 @@ void CCreature::updateFrom(const JsonNode & data)
 			addBonus(configNode["defense"].Integer(), BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::DEFENSE));
 
 		if(!configNode["damage"]["min"].isNull())
-			addBonus(configNode["damage"]["min"].Integer(), BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMin);
+			addBonus(configNode["damage"]["min"].Integer(), BonusType::CREATURE_DAMAGE, BonusSubtypeID::creatureDamageMin);
 
 		if(!configNode["damage"]["max"].isNull())
-			addBonus(configNode["damage"]["max"].Integer(), BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMax);
+			addBonus(configNode["damage"]["max"].Integer(), BonusType::CREATURE_DAMAGE, BonusSubtypeID::creatureDamageMax);
 
 		if(!configNode["shots"].isNull())
 			addBonus(configNode["shots"].Integer(), BonusType::SHOTS);
@@ -613,8 +612,8 @@ CCreature * CCreatureHandler::loadFromJson(const std::string & scope, const Json
 	cre->addBonus(node["attack"].Integer(), BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::ATTACK));
 	cre->addBonus(node["defense"].Integer(), BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::DEFENSE));
 
-	cre->addBonus(node["damage"]["min"].Integer(), BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMin);
-	cre->addBonus(node["damage"]["max"].Integer(), BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMax);
+	cre->addBonus(node["damage"]["min"].Integer(), BonusType::CREATURE_DAMAGE, BonusSubtypeID::creatureDamageMin);
+	cre->addBonus(node["damage"]["max"].Integer(), BonusType::CREATURE_DAMAGE, BonusSubtypeID::creatureDamageMax);
 
 	assert(node["damage"]["min"].Integer() <= node["damage"]["max"].Integer());
 
@@ -1039,11 +1038,11 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
 		break;
 	case 'M': //Max damage
 		b.type = BonusType::CREATURE_DAMAGE;
-		b.subtype = BonusSubtypes::creatureDamageMax;
+		b.subtype = BonusSubtypeID::creatureDamageMax;
 		break;
 	case 'm': //Min damage
 		b.type = BonusType::CREATURE_DAMAGE;
-		b.subtype = BonusSubtypes::creatureDamageMin;
+		b.subtype = BonusSubtypeID::creatureDamageMin;
 		break;
 	case 'S':
 		b.type = BonusType::STACKS_SPEED; break;
@@ -1060,7 +1059,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
 		break;
 	case 'E':
 		b.type = BonusType::DEATH_STARE;
-		b.subtype = BonusSubtypes::deathStareGorgon;
+		b.subtype = BonusSubtypeID::deathStareGorgon;
 		break;
 	case 'F':
 		b.type = BonusType::FEAR; break;
@@ -1107,7 +1106,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
 				b.type = BonusType::MIND_IMMUNITY; break;
 			case 'r':
 				b.type = BonusType::REBIRTH; //on/off? makes sense?
-				b.subtype = BonusSubtypes::rebirthRegular;
+				b.subtype = BonusSubtypeID::rebirthRegular;
 				b.val = 20; //arbitrary value
 				break;
 			case 'R':

+ 2 - 3
lib/CGameInfoCallback.cpp

@@ -17,7 +17,6 @@
 #include "CGeneralTextHandler.h"
 #include "StartInfo.h" // for StartInfo
 #include "battle/BattleInfo.h" // for BattleInfo
-#include "bonuses/BonusSubtypes.h"
 #include "NetPacks.h" // for InfoWindow
 #include "GameSettings.h"
 #include "TerrainHandler.h"
@@ -269,7 +268,7 @@ bool CGameInfoCallback::getTownInfo(const CGObjectInstance * town, InfoAboutTown
 		{
 			const auto * selectedHero = dynamic_cast<const CGHeroInstance *>(selectedObject);
 			if(nullptr != selectedHero)
-				detailed = selectedHero->hasVisions(town, BonusSubtypes::visionsTowns);
+				detailed = selectedHero->hasVisions(town, BonusSubtypeID::visionsTowns);
 		}
 
 		dest.initFromTown(dynamic_cast<const CGTownInstance *>(town), detailed);
@@ -323,7 +322,7 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
 	{
 		const auto * selectedHero = dynamic_cast<const CGHeroInstance *>(selectedObject);
 		if(nullptr != selectedHero)
-			if(selectedHero->hasVisions(hero, BonusSubtypes::visionsHeroes))
+			if(selectedHero->hasVisions(hero, BonusSubtypeID::visionsHeroes))
 				infoLevel = InfoAboutHero::EInfoLevel::DETAILED;
 	}
 

+ 1 - 2
lib/CStack.cpp

@@ -17,7 +17,6 @@
 
 #include "CGeneralTextHandler.h"
 #include "battle/BattleInfo.h"
-#include "bonuses/BonusSubtypes.h"
 #include "spells/CSpellHandler.h"
 #include "NetPacks.h"
 
@@ -221,7 +220,7 @@ void CStack::prepareAttacked(BattleStackAttacked & bsa, vstd::RNG & rand, const
 					resurrectedCount += 1;
 			}
 
-			if(customState->hasBonusOfType(BonusType::REBIRTH, BonusSubtypes::rebirthSpecial))
+			if(customState->hasBonusOfType(BonusType::REBIRTH, BonusSubtypeID::rebirthSpecial))
 			{
 				// resurrect at least one Sacred Phoenix
 				vstd::amax(resurrectedCount, 1);

+ 6 - 6
lib/CTownHandler.cpp

@@ -23,7 +23,6 @@
 #include "filesystem/Filesystem.h"
 #include "bonuses/Bonus.h"
 #include "bonuses/Propagators.h"
-#include "bonuses/BonusSubtypes.h"
 #include "ResourceSet.h"
 #include "mapObjectConstructors/AObjectTypeHandler.h"
 #include "mapObjectConstructors/CObjectClassesHandler.h"
@@ -561,7 +560,7 @@ void CTownHandler::addBonusesForVanilaBuilding(CBuilding * building) const
 		b = createBonus(building, BonusType::PRIMARY_SKILL, +2, TBonusSubtype(PrimarySkill::DEFENSE));
 		break;
 	case BuildingSubID::LIGHTHOUSE:
-		b = createBonus(building, BonusType::MOVEMENT, +500, BonusSubtypes::heroMovementSea, playerPropagator);
+		b = createBonus(building, BonusType::MOVEMENT, +500, BonusSubtypeID::heroMovementSea, playerPropagator);
 		break;
 	}
 
@@ -571,7 +570,7 @@ void CTownHandler::addBonusesForVanilaBuilding(CBuilding * building) const
 
 std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, BonusType type, int val) const
 {
-	return createBonus(build, type, val, TBonusSubtype::NONE, emptyPropagator());
+	return createBonus(build, type, val, TBonusSubtype(), emptyPropagator());
 }
 
 std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, BonusType type, int val, TBonusSubtype subtype) const
@@ -583,17 +582,18 @@ std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, BonusType ty
 {
 	std::ostringstream descr;
 	descr << build->getNameTranslated();
-	return createBonusImpl(build->bid, type, val, prop, descr.str(), subtype);
+	return createBonusImpl(build->bid, build->town->faction->getId(), type, val, prop, descr.str(), subtype);
 }
 
 std::shared_ptr<Bonus> CTownHandler::createBonusImpl(const BuildingID & building,
+													 const FactionID & faction,
 													 BonusType type,
 													 int val,
 													 TPropagatorPtr & prop,
 													 const std::string & description,
 													 TBonusSubtype subtype) const
 {
-	auto b = std::make_shared<Bonus>(BonusDuration::PERMANENT, type, BonusSource::TOWN_STRUCTURE, val, TBonusSourceID(building), subtype, description);
+	auto b = std::make_shared<Bonus>(BonusDuration::PERMANENT, type, BonusSource::TOWN_STRUCTURE, val, BuildingTypeUniqueID(faction, building), subtype, description);
 
 	if(prop)
 		b->addPropagator(prop);
@@ -605,7 +605,7 @@ void CTownHandler::loadSpecialBuildingBonuses(const JsonNode & source, BonusList
 {
 	for(const auto & b : source.Vector())
 	{
-		auto bonus = JsonUtils::parseBuildingBonus(b, building->bid, building->getNameTranslated());
+		auto bonus = JsonUtils::parseBuildingBonus(b, building->town->faction->getId(), building->bid, building->getNameTranslated());
 
 		if(bonus == nullptr)
 			continue;

+ 1 - 0
lib/CTownHandler.h

@@ -395,6 +395,7 @@ class DLL_LINKAGE CTownHandler : public CHandlerBase<FactionID, Faction, CFactio
 	std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, TBonusSubtype subtype) const;
 	std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, TBonusSubtype subtype, TPropagatorPtr & prop) const;
 	std::shared_ptr<Bonus> createBonusImpl(const BuildingID & building,
+										   const FactionID & faction,
 												  BonusType type,
 												  int val,
 												  TPropagatorPtr & prop,

+ 5 - 5
lib/JsonNode.cpp

@@ -421,21 +421,21 @@ static void loadBonusSubtype(TBonusSubtype & subtype, BonusType type, const Json
 {
 	if (node.isNull())
 	{
-		subtype = TBonusSubtype::NONE;
+		subtype = TBonusSubtype();
 		return;
 	}
 
 	if (!node.isString())
 	{
 		logMod->warn("Bonus subtype must be string!");
-		subtype = TBonusSubtype::NONE;
+		subtype = TBonusSubtype();
 		return;
 	}
 
 	VLC->identifiers()->requestIdentifier(node, [&subtype, node](int32_t identifier)
 	{
 		assert(0); //TODO
-		subtype = TBonusSubtype("type", node.String(), identifier);
+		subtype = BonusSubtypeID(identifier);
 	});
 }
 
@@ -735,13 +735,13 @@ std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonNode &ability)
 	return b;
 }
 
-std::shared_ptr<Bonus> JsonUtils::parseBuildingBonus(const JsonNode & ability, const BuildingID & building, const std::string & description)
+std::shared_ptr<Bonus> JsonUtils::parseBuildingBonus(const JsonNode & ability, const FactionID & faction, const BuildingID & building, const std::string & description)
 {
 	/*	duration = BonusDuration::PERMANENT
 		source = BonusSource::TOWN_STRUCTURE
 		bonusType, val, subtype - get from json
 	*/
-	auto b = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::NONE, BonusSource::TOWN_STRUCTURE, 0, TBonusSourceID(building), description);
+	auto b = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::NONE, BonusSource::TOWN_STRUCTURE, 0, BuildingTypeUniqueID(faction, building), description);
 
 	if(!parseBonus(ability, b.get()))
 		return nullptr;

+ 1 - 1
lib/JsonNode.h

@@ -129,7 +129,7 @@ namespace JsonUtils
 {
 	DLL_LINKAGE std::shared_ptr<Bonus> parseBonus(const JsonVector & ability_vec);
 	DLL_LINKAGE std::shared_ptr<Bonus> parseBonus(const JsonNode & ability);
-	DLL_LINKAGE std::shared_ptr<Bonus> parseBuildingBonus(const JsonNode & ability, const BuildingID & building, const std::string & description);
+	DLL_LINKAGE std::shared_ptr<Bonus> parseBuildingBonus(const JsonNode & ability, const FactionID & faction, const BuildingID & building, const std::string & description);
 	DLL_LINKAGE bool parseBonus(const JsonNode & ability, Bonus * placement);
 	DLL_LINKAGE std::shared_ptr<ILimiter> parseLimiter(const JsonNode & limiter);
 	DLL_LINKAGE CSelector parseSelector(const JsonNode &ability);

+ 1 - 1
lib/NetPacksLib.cpp

@@ -2201,7 +2201,7 @@ void BattleTriggerEffect::applyGs(CGameState * gs) const
 	}
 	case BonusType::POISON:
 	{
-		auto b = st->getBonusLocalFirst(Selector::source(BonusSource::SPELL_EFFECT, TBonusSubtype(SpellID(SpellID::POISON)))
+		auto b = st->getBonusLocalFirst(Selector::source(BonusSource::SPELL_EFFECT, SpellID(SpellID::POISON))
 				.And(Selector::type()(BonusType::STACK_HEALTH)));
 		if (b)
 			b->val = val;

+ 3 - 3
lib/battle/BattleInfo.cpp

@@ -442,9 +442,9 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
 	//native terrain bonuses
 	static auto nativeTerrain = std::make_shared<CreatureTerrainLimiter>();
 	
-	curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::STACKS_SPEED, BonusSource::TERRAIN_NATIVE, 1,  TBonusSourceID::NONE)->addLimiter(nativeTerrain));
-	curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::PRIMARY_SKILL, BonusSource::TERRAIN_NATIVE, 1, TBonusSourceID::NONE, TBonusSubtype(PrimarySkill::ATTACK))->addLimiter(nativeTerrain));
-	curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::PRIMARY_SKILL, BonusSource::TERRAIN_NATIVE, 1, TBonusSourceID::NONE, TBonusSubtype(PrimarySkill::DEFENSE))->addLimiter(nativeTerrain));
+	curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::STACKS_SPEED, BonusSource::TERRAIN_NATIVE, 1,  TBonusSourceID())->addLimiter(nativeTerrain));
+	curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::PRIMARY_SKILL, BonusSource::TERRAIN_NATIVE, 1, TBonusSourceID(), TBonusSubtype(PrimarySkill::ATTACK))->addLimiter(nativeTerrain));
+	curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::PRIMARY_SKILL, BonusSource::TERRAIN_NATIVE, 1, TBonusSourceID(), TBonusSubtype(PrimarySkill::DEFENSE))->addLimiter(nativeTerrain));
 	//////////////////////////////////////////////////////////////////////////
 
 	//tactics

+ 2 - 4
lib/battle/CUnitState.cpp

@@ -16,8 +16,6 @@
 #include "../NetPacks.h"
 #include "../CCreatureHandler.h"
 
-#include "../bonuses/BonusSubtypes.h"
-
 #include "../serializer/JsonDeserializer.h"
 #include "../serializer/JsonSerializer.h"
 
@@ -342,8 +340,8 @@ CUnitState::CUnitState():
 	health(this),
 	shots(this),
 	totalAttacks(this, Selector::type()(BonusType::ADDITIONAL_ATTACK), 1),
-	minDamage(this, Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageBoth).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMin)), 0),
-	maxDamage(this, Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageBoth).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMax)), 0),
+	minDamage(this, Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypeID::creatureDamageBoth).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypeID::creatureDamageMin)), 0),
+	maxDamage(this, Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypeID::creatureDamageBoth).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypeID::creatureDamageMax)), 0),
 	attack(this, Selector::typeSubtype(BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::ATTACK)), 0),
 	defence(this, Selector::typeSubtype(BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::DEFENSE)), 0),
 	inFrenzy(this, Selector::type()(BonusType::IN_FRENZY)),

+ 6 - 7
lib/battle/DamageCalculator.cpp

@@ -14,7 +14,6 @@
 #include "Unit.h"
 
 #include "../bonuses/Bonus.h"
-#include "../bonuses/BonusSubtypes.h"
 #include "../mapObjects/CGTownInstance.h"
 #include "../spells/CSpellHandler.h"
 #include "../GameSettings.h"
@@ -207,11 +206,11 @@ double DamageCalculator::getAttackOffenseArcheryFactor() const
 	if(info.shooting)
 	{
 		const std::string cachingStrArchery = "type_PERCENTAGE_DAMAGE_BOOSTs_1";
-		static const auto selectorArchery = Selector::typeSubtype(BonusType::PERCENTAGE_DAMAGE_BOOST, BonusSubtypes::damageTypeRanged);
+		static const auto selectorArchery = Selector::typeSubtype(BonusType::PERCENTAGE_DAMAGE_BOOST, BonusSubtypeID::damageTypeRanged);
 		return info.attacker->valOfBonuses(selectorArchery, cachingStrArchery) / 100.0;
 	}
 	const std::string cachingStrOffence = "type_PERCENTAGE_DAMAGE_BOOSTs_0";
-	static const auto selectorOffence = Selector::typeSubtype(BonusType::PERCENTAGE_DAMAGE_BOOST, BonusSubtypes::damageTypeMelee);
+	static const auto selectorOffence = Selector::typeSubtype(BonusType::PERCENTAGE_DAMAGE_BOOST, BonusSubtypeID::damageTypeMelee);
 	return info.attacker->valOfBonuses(selectorOffence, cachingStrOffence) / 100.0;
 }
 
@@ -283,7 +282,7 @@ double DamageCalculator::getDefenseSkillFactor() const
 double DamageCalculator::getDefenseArmorerFactor() const
 {
 	const std::string cachingStrArmorer = "type_GENERAL_DAMAGE_REDUCTIONs_N1_NsrcSPELL_EFFECT";
-	static const auto selectorArmorer = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, BonusSubtypes::damageTypeAll).And(Selector::sourceTypeSel(BonusSource::SPELL_EFFECT).Not());
+	static const auto selectorArmorer = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, BonusSubtypeID::damageTypeAll).And(Selector::sourceTypeSel(BonusSource::SPELL_EFFECT).Not());
 	return info.defender->valOfBonuses(selectorArmorer, cachingStrArmorer) / 100.0;
 
 }
@@ -291,10 +290,10 @@ double DamageCalculator::getDefenseArmorerFactor() const
 double DamageCalculator::getDefenseMagicShieldFactor() const
 {
 	const std::string cachingStrMeleeReduction = "type_GENERAL_DAMAGE_REDUCTIONs_0";
-	static const auto selectorMeleeReduction = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, BonusSubtypes::damageTypeMelee);
+	static const auto selectorMeleeReduction = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, BonusSubtypeID::damageTypeMelee);
 
 	const std::string cachingStrRangedReduction = "type_GENERAL_DAMAGE_REDUCTIONs_1";
-	static const auto selectorRangedReduction = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, BonusSubtypes::damageTypeRanged);
+	static const auto selectorRangedReduction = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, BonusSubtypeID::damageTypeRanged);
 
 	//handling spell effects - shield and air shield
 	if(info.shooting)
@@ -388,7 +387,7 @@ double DamageCalculator::getDefensePetrificationFactor() const
 {
 	// Creatures that are petrified by a Basilisk's Petrifying attack or a Medusa's Stone gaze take 50% damage (R8 = 0.50) from ranged and melee attacks. Taking damage also deactivates the effect.
 	const std::string cachingStrAllReduction = "type_GENERAL_DAMAGE_REDUCTIONs_N1_srcSPELL_EFFECT";
-	static const auto selectorAllReduction = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, BonusSubtypes::damageTypeAll).And(Selector::sourceTypeSel(BonusSource::SPELL_EFFECT));
+	static const auto selectorAllReduction = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, BonusSubtypeID::damageTypeAll).And(Selector::sourceTypeSel(BonusSource::SPELL_EFFECT));
 
 	return info.defender->valOfBonuses(selectorAllReduction, cachingStrAllReduction) / 100.0;
 }

+ 4 - 4
lib/bonuses/Bonus.cpp

@@ -150,7 +150,7 @@ JsonNode Bonus::toJsonNode() const
 	JsonNode root(JsonNode::JsonType::DATA_STRUCT);
 	// only add values that might reasonably be found in config files
 	root["type"].String() = vstd::findKey(bonusNameMap, type);
-	if(subtype != TBonusSubtype::NONE)
+	if(subtype != TBonusSubtype())
 		root["subtype"].String() = subtype.toString();
 	if(additionalInfo != CAddInfo::NONE)
 		root["addInfo"] = additionalInfoToJson(type, additionalInfo);
@@ -158,7 +158,7 @@ JsonNode Bonus::toJsonNode() const
 		root["sourceType"].String() = vstd::findKey(bonusSourceMap, source);
 	if(targetSourceType != BonusSource::OTHER)
 		root["targetSourceType"].String() = vstd::findKey(bonusSourceMap, targetSourceType);
-	if(sid != TBonusSourceID::NONE)
+	if(sid != TBonusSourceID())
 		root["sourceID"].String() = sid.toString();
 	if(val != 0)
 		root["val"].Integer() = val;
@@ -184,11 +184,11 @@ JsonNode Bonus::toJsonNode() const
 }
 
 Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, TBonusSourceID ID)
-	: Bonus(Duration, Type, Src, Val, ID, TBonusSubtype::NONE, std::string())
+	: Bonus(Duration, Type, Src, Val, ID, TBonusSubtype(), std::string())
 {}
 
 Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, TBonusSourceID ID, std::string Desc)
-	: Bonus(Duration, Type, Src, Val, ID, TBonusSubtype::NONE, Desc)
+	: Bonus(Duration, Type, Src, Val, ID, TBonusSubtype(), Desc)
 {}
 
 Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, TBonusSourceID ID, TBonusSubtype Subtype)

+ 4 - 2
lib/bonuses/Bonus.h

@@ -10,7 +10,9 @@
 #pragma once
 
 #include "BonusEnum.h"
+#include "BonusSubtypeID.h"
 #include "../constants/MetaIdentifier.h"
+#include "../constants/EntityIdentifiers.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -23,8 +25,8 @@ class IUpdater;
 class BonusList;
 class CSelector;
 
-using TBonusSubtype = MetaIdentifier;
-using TBonusSourceID = MetaIdentifier;
+using TBonusSubtype = MetaIdentifier<BonusSubtypeID, SpellID, CreatureID, PrimarySkill, TerrainId, GameResID, SpellSchool>;
+using TBonusSourceID = MetaIdentifier<BonusSourceID, SpellID, CreatureID, ArtifactID, CampaignScenarioID, SecondarySkill, HeroTypeID, Obj, ObjectInstanceID, BuildingTypeUniqueID, BattleField>;
 using TBonusListPtr = std::shared_ptr<BonusList>;
 using TConstBonusListPtr = std::shared_ptr<const BonusList>;
 using TLimiterPtr = std::shared_ptr<ILimiter>;

+ 1 - 1
lib/bonuses/BonusList.cpp

@@ -275,4 +275,4 @@ DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const BonusList &bonusL
 	return out;
 }
 
-VCMI_LIB_NAMESPACE_END
+VCMI_LIB_NAMESPACE_END

+ 1 - 1
lib/bonuses/BonusList.h

@@ -111,4 +111,4 @@ public:
 DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const BonusList &bonusList);
 
 
-VCMI_LIB_NAMESPACE_END
+VCMI_LIB_NAMESPACE_END

+ 26 - 24
lib/bonuses/BonusParams.cpp

@@ -13,9 +13,11 @@
 #include "BonusEnum.h"
 #include "BonusParams.h"
 #include "BonusSelector.h"
-#include "BonusSubtypes.h"
 
 #include "../ResourceSet.h"
+#include "../VCMI_Lib.h"
+#include "../modding/IdentifierStorage.h"
+#include "../modding/ModScope.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -88,28 +90,28 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
 			type = BonusType::LEARN_MEETING_SPELL_LIMIT;
 		else if(deprecatedSubtype == SecondarySkill::ARCHERY|| deprecatedSubtypeStr == "skill.archery")
 		{
-			subtype = BonusSubtypes::damageTypeRanged;
+			subtype = BonusSubtypeID::damageTypeRanged;
 			type = BonusType::PERCENTAGE_DAMAGE_BOOST;
 		}
 		else if(deprecatedSubtype == SecondarySkill::OFFENCE || deprecatedSubtypeStr == "skill.offence")
 		{
-			subtype = BonusSubtypes::damageTypeMelee;
+			subtype = BonusSubtypeID::damageTypeMelee;
 			type = BonusType::PERCENTAGE_DAMAGE_BOOST;
 		}
 		else if(deprecatedSubtype == SecondarySkill::ARMORER || deprecatedSubtypeStr == "skill.armorer")
 		{
-			subtype = BonusSubtypes::damageTypeAll;
+			subtype = BonusSubtypeID::damageTypeAll;
 			type = BonusType::GENERAL_DAMAGE_REDUCTION;
 		}
 		else if(deprecatedSubtype == SecondarySkill::NAVIGATION || deprecatedSubtypeStr == "skill.navigation")
 		{
-			subtype = BonusSubtypes::heroMovementSea;
+			subtype = BonusSubtypeID::heroMovementSea;
 			valueType = BonusValueType::PERCENT_TO_BASE;
 			type = BonusType::MOVEMENT;
 		}
 		else if(deprecatedSubtype == SecondarySkill::LOGISTICS || deprecatedSubtypeStr == "skill.logistics")
 		{
-			subtype = BonusSubtypes::heroMovementLand;
+			subtype = BonusSubtypeID::heroMovementLand;
 			valueType = BonusValueType::PERCENT_TO_BASE;
 			type = BonusType::MOVEMENT;
 		}
@@ -146,12 +148,12 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
 		else if (deprecatedSubtype == SecondarySkill::FIRST_AID || deprecatedSubtypeStr == "skill.firstAid")
 		{
 			type = BonusType::SPECIFIC_SPELL_POWER;
-			subtype = TBonusSubtype("spell", "firstAid");
+			subtype = SpellID(*VLC->identifiers()->getIdentifier( ModScope::scopeGame(), "spell", "firstAid"));
 		}
 		else if (deprecatedSubtype == SecondarySkill::BALLISTICS || deprecatedSubtypeStr == "skill.ballistics")
 		{
 			type = BonusType::CATAPULT_EXTRA_SHOTS;
-			subtype = TBonusSubtype("spell", "catapultShot");
+			subtype = SpellID(*VLC->identifiers()->getIdentifier( ModScope::scopeGame(), "spell", "catapultShot"));
 		}
 		else
 			isConverted = false;
@@ -170,20 +172,20 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
 	}
 	else if (deprecatedTypeStr == "SEA_MOVEMENT")
 	{
-		subtype = BonusSubtypes::heroMovementSea;
+		subtype = BonusSubtypeID::heroMovementSea;
 		valueType = BonusValueType::ADDITIVE_VALUE;
 		type = BonusType::MOVEMENT;
 	}
 	else if (deprecatedTypeStr == "LAND_MOVEMENT")
 	{
-		subtype = BonusSubtypes::heroMovementLand;
+		subtype = BonusSubtypeID::heroMovementLand;
 		valueType = BonusValueType::ADDITIVE_VALUE;
 		type = BonusType::MOVEMENT;
 	}
 	else if (deprecatedTypeStr == "MAXED_SPELL")
 	{
 		type = BonusType::SPELL;
-		subtype = TBonusSubtype("spell", deprecatedSubtypeStr);
+		subtype = SpellID(*VLC->identifiers()->getIdentifier( ModScope::scopeGame(), "spell", deprecatedSubtypeStr));
 		valueType = BonusValueType::INDEPENDENT_MAX;
 		val = 3;
 	}
@@ -224,52 +226,52 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
 	else if (deprecatedTypeStr == "DIRECT_DAMAGE_IMMUNITY")
 	{
 		type = BonusType::SPELL_DAMAGE_REDUCTION;
-		subtype = MetaIdentifier(SpellSchool::ANY);
+		subtype = TBonusSubtype(SpellSchool::ANY);
 		val = 100;
 	}
 	else if (deprecatedTypeStr == "AIR_SPELL_DMG_PREMY")
 	{
 		type = BonusType::SPELL_DAMAGE;
-		subtype = MetaIdentifier(SpellSchool::AIR);
+		subtype = TBonusSubtype(SpellSchool::AIR);
 	}
 	else if (deprecatedTypeStr == "FIRE_SPELL_DMG_PREMY")
 	{
 		type = BonusType::SPELL_DAMAGE;
-		subtype = MetaIdentifier(SpellSchool::FIRE);
+		subtype = TBonusSubtype(SpellSchool::FIRE);
 	}
 	else if (deprecatedTypeStr == "WATER_SPELL_DMG_PREMY")
 	{
 		type = BonusType::SPELL_DAMAGE;
-		subtype = MetaIdentifier(SpellSchool::WATER);
+		subtype = TBonusSubtype(SpellSchool::WATER);
 	}
 	else if (deprecatedTypeStr == "EARTH_SPELL_DMG_PREMY")
 	{
 		type = BonusType::SPELL_DAMAGE;
-		subtype = MetaIdentifier(SpellSchool::EARTH);
+		subtype = TBonusSubtype(SpellSchool::EARTH);
 	}
 	else if (deprecatedTypeStr == "AIR_SPELLS")
 	{
 		type = BonusType::SPELLS_OF_SCHOOL;
-		subtype = MetaIdentifier(SpellSchool::AIR);
+		subtype = TBonusSubtype(SpellSchool::AIR);
 	}
 	else if (deprecatedTypeStr == "FIRE_SPELLS")
 	{
 		type = BonusType::SPELLS_OF_SCHOOL;
-		subtype = MetaIdentifier(SpellSchool::FIRE);
+		subtype = TBonusSubtype(SpellSchool::FIRE);
 	}
 	else if (deprecatedTypeStr == "WATER_SPELLS")
 	{
 		type = BonusType::SPELLS_OF_SCHOOL;
-		subtype = MetaIdentifier(SpellSchool::WATER);
+		subtype = TBonusSubtype(SpellSchool::WATER);
 	}
 	else if (deprecatedTypeStr == "EARTH_SPELLS")
 	{
 		type = BonusType::SPELLS_OF_SCHOOL;
-		subtype = MetaIdentifier(SpellSchool::EARTH);
+		subtype = TBonusSubtype(SpellSchool::EARTH);
 	}
 	else if (deprecatedTypeStr == "AIR_IMMUNITY")
 	{
-		subtype = MetaIdentifier(SpellSchool::AIR);
+		subtype = TBonusSubtype(SpellSchool::AIR);
 		switch(deprecatedSubtype)
 		{
 			case 0:
@@ -285,7 +287,7 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
 	}
 	else if (deprecatedTypeStr == "FIRE_IMMUNITY")
 	{
-		subtype = MetaIdentifier(SpellSchool::FIRE);
+		subtype = TBonusSubtype(SpellSchool::FIRE);
 		switch(deprecatedSubtype)
 		{
 			case 0:
@@ -301,7 +303,7 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
 	}
 	else if (deprecatedTypeStr == "WATER_IMMUNITY")
 	{
-		subtype = MetaIdentifier(SpellSchool::WATER);
+		subtype = TBonusSubtype(SpellSchool::WATER);
 		switch(deprecatedSubtype)
 		{
 			case 0:
@@ -317,7 +319,7 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
 	}
 	else if (deprecatedTypeStr == "EARTH_IMMUNITY")
 	{
-		subtype = MetaIdentifier(SpellSchool::EARTH);
+		subtype = TBonusSubtype(SpellSchool::EARTH);
 		switch(deprecatedSubtype)
 		{
 			case 0:

+ 76 - 0
lib/bonuses/BonusSubtypeID.cpp

@@ -0,0 +1,76 @@
+/*
+ * Bonus.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#include "StdInc.h"
+#include "BonusSubtypeID.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+const BonusSubtypeID BonusSubtypeID::creatureDamageBoth(0);
+const BonusSubtypeID BonusSubtypeID::creatureDamageMin(1);
+const BonusSubtypeID BonusSubtypeID::creatureDamageMax(2);
+const BonusSubtypeID BonusSubtypeID::damageTypeAll(-1);
+const BonusSubtypeID BonusSubtypeID::damageTypeMelee(0);
+const BonusSubtypeID BonusSubtypeID::damageTypeRanged(1);
+const BonusSubtypeID BonusSubtypeID::heroMovementLand(1);
+const BonusSubtypeID BonusSubtypeID::heroMovementSea(0);
+const BonusSubtypeID BonusSubtypeID::heroMovementPenalty(2);
+const BonusSubtypeID BonusSubtypeID::heroMovementFull(1);
+const BonusSubtypeID BonusSubtypeID::deathStareGorgon(0);
+const BonusSubtypeID BonusSubtypeID::deathStareCommander(1);
+const BonusSubtypeID BonusSubtypeID::rebirthRegular(0);
+const BonusSubtypeID BonusSubtypeID::rebirthSpecial(1);
+const BonusSubtypeID BonusSubtypeID::visionsMonsters(0);
+const BonusSubtypeID BonusSubtypeID::visionsHeroes(1);
+const BonusSubtypeID BonusSubtypeID::visionsTowns(2);
+const BonusSubtypeID BonusSubtypeID::immunityBattleWide(0);
+const BonusSubtypeID BonusSubtypeID::immunityEnemyHero(1);
+const BonusSubtypeID BonusSubtypeID::transmutationPerHealth(0);
+const BonusSubtypeID BonusSubtypeID::transmutationPerUnit(1);
+const BonusSubtypeID BonusSubtypeID::destructionKillPercentage(0);
+const BonusSubtypeID BonusSubtypeID::destructionKillAmount(1);
+const BonusSubtypeID BonusSubtypeID::soulStealPermanent(0);
+const BonusSubtypeID BonusSubtypeID::soulStealBattle(1);
+const BonusSubtypeID BonusSubtypeID::movementFlying(0);
+const BonusSubtypeID BonusSubtypeID::movementTeleporting(1);
+
+const BonusSourceID BonusSourceID::undeadMoraleDebuff(-2);
+
+BonusSubtypeID BonusSubtypeID::spellLevel(int level)
+{
+	return BonusSubtypeID(level);
+}
+
+BonusSubtypeID BonusSubtypeID::creatureLevel(int level)
+{
+	return BonusSubtypeID(level);
+}
+
+si32 BonusSubtypeID::decode(const std::string & identifier)
+{
+	return std::stoi(identifier);
+}
+
+std::string BonusSubtypeID::encode(const si32 index)
+{
+	return std::to_string(index);
+}
+
+si32 BonusSourceID::decode(const std::string & identifier)
+{
+	return std::stoi(identifier);
+}
+
+std::string BonusSourceID::encode(const si32 index)
+{
+	return std::to_string(index);
+}
+
+VCMI_LIB_NAMESPACE_END

+ 78 - 0
lib/bonuses/BonusSubtypeID.h

@@ -0,0 +1,78 @@
+/*
+ * BonusSubtypeID.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+#include "../constants/EntityIdentifiers.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+class DLL_LINKAGE BonusSourceID : public Identifier<BonusSourceID>
+{
+public:
+	using Identifier<BonusSourceID>::Identifier;
+
+	static std::string encode(int32_t index);
+	static si32 decode(const std::string & identifier);
+
+	static const BonusSourceID undeadMoraleDebuff; // -2
+};
+
+class DLL_LINKAGE BonusSubtypeID : public Identifier<BonusSubtypeID>
+{
+public:
+	using Identifier<BonusSubtypeID>::Identifier;
+
+	static std::string encode(int32_t index);
+	static si32 decode(const std::string & identifier);
+
+	static const BonusSubtypeID creatureDamageBoth; // 0
+	static const BonusSubtypeID creatureDamageMin; // 1
+	static const BonusSubtypeID creatureDamageMax; // 2
+
+	static const BonusSubtypeID damageTypeAll; // -1
+	static const BonusSubtypeID damageTypeMelee; // 0
+	static const BonusSubtypeID damageTypeRanged; // 1
+
+	static const BonusSubtypeID heroMovementLand; // 1
+	static const BonusSubtypeID heroMovementSea; // 0
+
+	static const BonusSubtypeID heroMovementPenalty; // 2
+	static const BonusSubtypeID heroMovementFull; // 1
+
+	static const BonusSubtypeID deathStareGorgon; // 0
+	static const BonusSubtypeID deathStareCommander;
+
+	static const BonusSubtypeID rebirthRegular; // 0
+	static const BonusSubtypeID rebirthSpecial; // 1
+
+	static const BonusSubtypeID visionsMonsters; // 0
+	static const BonusSubtypeID visionsHeroes; // 1
+	static const BonusSubtypeID visionsTowns; // 2
+
+	static const BonusSubtypeID immunityBattleWide; // 0
+	static const BonusSubtypeID immunityEnemyHero; // 1
+
+	static const BonusSubtypeID transmutationPerHealth; // 0
+	static const BonusSubtypeID transmutationPerUnit; // 1
+
+	static const BonusSubtypeID destructionKillPercentage; // 0
+	static const BonusSubtypeID destructionKillAmount; // 1
+
+	static const BonusSubtypeID soulStealPermanent; // 0
+	static const BonusSubtypeID soulStealBattle; // 1
+
+	static const BonusSubtypeID movementFlying; // 0
+	static const BonusSubtypeID movementTeleporting; // 1
+
+	static BonusSubtypeID spellLevel(int level);
+	static BonusSubtypeID creatureLevel(int level);
+};
+
+VCMI_LIB_NAMESPACE_END

+ 0 - 56
lib/bonuses/BonusSubtypes.cpp

@@ -1,56 +0,0 @@
-/*
- * Bonus.cpp, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-
-#include "StdInc.h"
-#include "BonusSubtypes.h"
-
-VCMI_LIB_NAMESPACE_BEGIN
-
-const TBonusSubtype BonusSubtypes::creatureDamageBoth("", "", 0);
-const TBonusSubtype BonusSubtypes::creatureDamageMin("", "", 1);
-const TBonusSubtype BonusSubtypes::creatureDamageMax("", "", 2);
-const TBonusSubtype BonusSubtypes::damageTypeAll("", "", -1);
-const TBonusSubtype BonusSubtypes::damageTypeMelee("", "", 0);
-const TBonusSubtype BonusSubtypes::damageTypeRanged("", "", 1);
-const TBonusSubtype BonusSubtypes::heroMovementLand("", "", 1);
-const TBonusSubtype BonusSubtypes::heroMovementSea("", "", 0);
-const TBonusSubtype BonusSubtypes::heroMovementPenalty("", "", 2);
-const TBonusSubtype BonusSubtypes::heroMovementFull("", "", 1);
-const TBonusSubtype BonusSubtypes::deathStareGorgon("", "", 0);
-const TBonusSubtype BonusSubtypes::deathStareCommander("", "", 1);
-const TBonusSubtype BonusSubtypes::rebirthRegular("", "", 0);
-const TBonusSubtype BonusSubtypes::rebirthSpecial("", "", 1);
-const TBonusSubtype BonusSubtypes::visionsMonsters("", "", 0);
-const TBonusSubtype BonusSubtypes::visionsHeroes("", "", 1);
-const TBonusSubtype BonusSubtypes::visionsTowns("", "", 2);
-const TBonusSubtype BonusSubtypes::immunityBattleWide("", "", 0);
-const TBonusSubtype BonusSubtypes::immunityEnemyHero("", "", 1);
-const TBonusSubtype BonusSubtypes::transmutationPerHealth("", "", 0);
-const TBonusSubtype BonusSubtypes::transmutationPerUnit("", "", 1);
-const TBonusSubtype BonusSubtypes::destructionKillPercentage("", "", 0);
-const TBonusSubtype BonusSubtypes::destructionKillAmount("", "", 1);
-const TBonusSubtype BonusSubtypes::soulStealPermanent("", "", 0);
-const TBonusSubtype BonusSubtypes::soulStealBattle("", "", 1);
-const TBonusSubtype BonusSubtypes::movementFlying("", "", 0);
-const TBonusSubtype BonusSubtypes::movementTeleporting("", "", 1);
-
-TBonusSubtype BonusSubtypes::spellLevel(int level)
-{
-	assert(0); //todo
-	return TBonusSubtype();
-}
-
-TBonusSubtype BonusSubtypes::creatureLevel(int level)
-{
-	assert(0); //todo
-	return TBonusSubtype();
-}
-
-VCMI_LIB_NAMESPACE_END

+ 0 - 64
lib/bonuses/BonusSubtypes.h

@@ -1,64 +0,0 @@
-/*
- * BonusSubtypes.h, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-#pragma once
-
-#include "../constants/MetaIdentifier.h"
-
-VCMI_LIB_NAMESPACE_BEGIN
-
-using TBonusSubtype = MetaIdentifier;
-
-class DLL_LINKAGE BonusSubtypes
-{
-public:
-	static const TBonusSubtype creatureDamageBoth; // 0
-	static const TBonusSubtype creatureDamageMin; // 1
-	static const TBonusSubtype creatureDamageMax; // 2
-
-	static const TBonusSubtype damageTypeAll; // -1
-	static const TBonusSubtype damageTypeMelee; // 0
-	static const TBonusSubtype damageTypeRanged; // 1
-
-	static const TBonusSubtype heroMovementLand; // 1
-	static const TBonusSubtype heroMovementSea; // 0
-
-	static const TBonusSubtype heroMovementPenalty; // 2
-	static const TBonusSubtype heroMovementFull; // 1
-
-	static const TBonusSubtype deathStareGorgon; // 0
-	static const TBonusSubtype deathStareCommander;
-
-	static const TBonusSubtype rebirthRegular; // 0
-	static const TBonusSubtype rebirthSpecial; // 1
-
-	static const TBonusSubtype visionsMonsters; // 0
-	static const TBonusSubtype visionsHeroes; // 1
-	static const TBonusSubtype visionsTowns; // 2
-
-	static const TBonusSubtype immunityBattleWide; // 0
-	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
-
-	static const TBonusSubtype movementFlying; // 0
-	static const TBonusSubtype movementTeleporting; // 1
-
-	static TBonusSubtype spellLevel(int level);
-	static TBonusSubtype creatureLevel(int level);
-};
-
-VCMI_LIB_NAMESPACE_END

+ 79 - 2
lib/constants/EntityIdentifiers.cpp

@@ -37,6 +37,8 @@
 #include "TerrainHandler.h" //TODO: remove
 #include "BattleFieldHandler.h"
 #include "ObstacleHandler.h"
+#include "CTownHandler.h"
+#include "mapObjectConstructors/CObjectClassesHandler.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -134,6 +136,40 @@ std::string HeroClassID::entityType()
 	return "heroClass";
 }
 
+si32 ObjectInstanceID::decode(const std::string & identifier)
+{
+	return std::stoi(identifier);
+}
+
+std::string ObjectInstanceID::encode(const si32 index)
+{
+	return std::to_string(index);
+}
+
+si32 CampaignScenarioID::decode(const std::string & identifier)
+{
+	return std::stoi(identifier);
+}
+
+std::string CampaignScenarioID::encode(const si32 index)
+{
+	return std::to_string(index);
+}
+
+std::string Obj::encode(int32_t index)
+{
+	return VLC->objtypeh->getObjectHandlerName(index);
+}
+
+si32 Obj::decode(const std::string & identifier)
+{
+	auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), "objects", identifier);
+	if(rawId)
+		return rawId.value();
+	else
+		return -1;
+}
+
 si32 HeroTypeID::decode(const std::string & identifier)
 {
 	auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeMap(), "hero", identifier);
@@ -182,6 +218,20 @@ std::string ArtifactID::entityType()
 	return "artifact";
 }
 
+si32 SecondarySkill::decode(const std::string& identifier)
+{
+	auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), "secondarySkill", identifier);
+	if(rawId)
+		return rawId.value();
+	else
+		return -1;
+}
+
+std::string SecondarySkill::encode(const si32 index)
+{
+	return VLC->skills()->getById(SecondarySkill(index))->getJsonKey();
+}
+
 const CCreature * CreatureIDBase::toCreature() const
 {
 	return VLC->creh->objects.at(num);
@@ -240,6 +290,20 @@ std::string SpellID::encode(const si32 index)
 	return VLC->spells()->getByIndex(index)->getJsonKey();
 }
 
+si32 BattleField::decode(const std::string & identifier)
+{
+	auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), "spell", identifier);
+	if(rawId)
+		return rawId.value();
+	else
+		return -1;
+}
+
+std::string BattleField::encode(const si32 index)
+{
+	return VLC->spells()->getByIndex(index)->getJsonKey();
+}
+
 std::string SpellID::entityType()
 {
 	return "spell";
@@ -257,8 +321,6 @@ bool PlayerColor::isSpectator() const
 
 std::string PlayerColor::toString() const
 {
-	if (num == -1)
-		return "neutral";
 	return encode(num);
 }
 
@@ -269,6 +331,9 @@ si32 PlayerColor::decode(const std::string & identifier)
 
 std::string PlayerColor::encode(const si32 index)
 {
+	if (index == -1)
+		return "neutral";
+
 	if (index < 0 || index >= std::size(GameConstants::PLAYER_COLOR_NAMES))
 	{
 		assert(0);
@@ -373,6 +438,18 @@ std::string GameResID::encode(const si32 index)
 	return GameConstants::RESOURCE_NAMES[index];
 }
 
+si32 BuildingTypeUniqueID::decode(const std::string & identifier)
+{
+	assert(0); //TODO
+	return -1;
+}
+
+std::string BuildingTypeUniqueID::encode(const si32 index)
+{
+	assert(0); // TODO
+	return "";
+}
+
 std::string GameResID::entityType()
 {
 	return "resource";

+ 13 - 1
lib/constants/EntityIdentifiers.h

@@ -552,10 +552,13 @@ public:
 	};
 };
 
-class Obj : public IdentifierWithEnum<Obj, ObjBase>
+class DLL_LINKAGE Obj : public IdentifierWithEnum<Obj, ObjBase>
 {
 public:
 	using IdentifierWithEnum<Obj, ObjBase>::IdentifierWithEnum;
+
+	static std::string encode(int32_t index);
+	static si32 decode(const std::string & identifier);
 };
 
 class DLL_LINKAGE RoadId : public Identifier<RoadId>
@@ -830,6 +833,9 @@ public:
 
 	static const BattleField NONE;
 	const BattleFieldInfo * getInfo() const;
+
+	static si32 decode(const std::string & identifier);
+	static std::string encode(const si32 index);
 };
 
 class DLL_LINKAGE BoatId : public Identifier<BoatId>
@@ -935,6 +941,9 @@ class BuildingTypeUniqueID : public Identifier<BuildingTypeUniqueID>
 public:
 	BuildingTypeUniqueID(FactionID faction, BuildingID building );
 
+	static si32 decode(const std::string & identifier);
+	static std::string encode(const si32 index);
+
 	BuildingID getBuilding() const;
 	FactionID getFaction() const;
 
@@ -946,6 +955,9 @@ class DLL_LINKAGE CampaignScenarioID : public Identifier<CampaignScenarioID>
 public:
 	using Identifier<CampaignScenarioID>::Identifier;
 
+	static si32 decode(const std::string & identifier);
+	static std::string encode(int32_t index);
+
 	static const CampaignScenarioID NONE;
 };
 

+ 0 - 67
lib/constants/MetaIdentifier.cpp

@@ -1,67 +0,0 @@
-/*
- * EntityIdentifiers.cpp, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-
-#include "StdInc.h"
-#include "MetaIdentifier.h"
-
-VCMI_LIB_NAMESPACE_BEGIN
-
-const MetaIdentifier MetaIdentifier::NONE("", "", -1);
-
-MetaIdentifier::MetaIdentifier():
-	integerForm(-1)
-{}
-
-MetaIdentifier::MetaIdentifier(const std::string & entityType, const std::string & identifier)
-	: stringForm(identifier)
-	, integerForm(-1)
-{
-	onDeserialized();
-}
-
-MetaIdentifier::MetaIdentifier(const std::string & entityType, const std::string & identifier, int32_t value)
-	: stringForm(identifier)
-	, integerForm(value)
-{
-}
-
-bool MetaIdentifier::operator == (const MetaIdentifier & other) const
-{
-	assert( (stringForm == other.stringForm) ? (integerForm == other.integerForm) : true );
-
-	return stringForm == other.stringForm;
-}
-
-bool MetaIdentifier::operator != (const MetaIdentifier & other) const
-{
-	return !(*this == other);
-}
-
-bool MetaIdentifier::operator < (const MetaIdentifier & other) const
-{
-	assert(0);
-}
-
-int32_t MetaIdentifier::getNum() const
-{
-	return integerForm;
-}
-
-std::string MetaIdentifier::toString() const
-{
-	return stringForm;
-}
-
-void MetaIdentifier::onDeserialized()
-{
-	assert(0); //TODO
-}
-
-VCMI_LIB_NAMESPACE_END

+ 44 - 24
lib/constants/MetaIdentifier.h

@@ -14,49 +14,69 @@
 VCMI_LIB_NAMESPACE_BEGIN
 
 /// This class represents field that may contain value of multiple different identifer types
+template<typename... Types>
 class DLL_LINKAGE MetaIdentifier
 {
-	std::string stringForm;
-	int32_t integerForm;
-
-	void onDeserialized();
+	std::variant<Types...> value;
 public:
 
-	static const MetaIdentifier NONE;
-
-	MetaIdentifier();
-	MetaIdentifier(const std::string & entityType, const std::string & identifier);
-	MetaIdentifier(const std::string & entityType, const std::string & identifier, int32_t value);
+	MetaIdentifier()
+	{}
 
 	template<typename IdentifierType>
-	explicit MetaIdentifier(const IdentifierType & identifier)
-		: integerForm(identifier.getNum())
+	MetaIdentifier(const IdentifierType & identifier)
+		: value(identifier)
+	{}
+
+	int32_t getNum() const
 	{
-		static_assert(std::is_base_of<IdentifierBase, IdentifierType>::value, "MetaIdentifier can only be constructed from Identifer class");
+		std::optional<int32_t> result;
+
+		std::visit([&result] (const auto& v) { result = v.getNum(); }, value);
+
+		assert(result.has_value());
+		return result.value_or(-1);
 	}
 
-	int32_t getNum() const;
-	std::string toString() const;
+	std::string toString() const
+	{
+		std::optional<std::string> result;
+
+		std::visit([&result] (const auto& v) { result = v.encode(v.getNum()); }, value);
+
+		assert(result.has_value());
+		return result.value_or("");
+	}
 
 	template<typename IdentifierType>
 	IdentifierType as() const
 	{
-		static_assert(std::is_base_of<IdentifierBase, IdentifierType>::value, "MetaIdentifier can only be converted to Identifer class");
-		IdentifierType result(integerForm);
-		return result;
+		auto * result = std::get_if<IdentifierType>(&value);
+		assert(result);
+
+		if (result)
+			return *result;
+		else
+			return IdentifierType();
 	}
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & integerForm;
-
-		if (!h.saving)
-			onDeserialized();
+		h & value;
 	}
 
-	bool operator == (const MetaIdentifier & other) const;
-	bool operator != (const MetaIdentifier & other) const;
-	bool operator < (const MetaIdentifier & other) const;
+	bool operator == (const MetaIdentifier & other) const
+	{
+		return value == other.value;
+	}
+	bool operator != (const MetaIdentifier & other) const
+	{
+		return value != other.value;
+	}
+	bool operator < (const MetaIdentifier & other) const
+	{
+		return value < other.value;
+	}
 };
 
 VCMI_LIB_NAMESPACE_END

+ 1 - 1
lib/gameState/CGameState.cpp

@@ -655,7 +655,7 @@ void CGameState::initGlobalBonuses()
 	{
 		auto bonus = JsonUtils::parseBonus(b.second);
 		bonus->source = BonusSource::GLOBAL;//for all
-		bonus->sid = TBonusSourceID::NONE; //there is one global object
+		bonus->sid = TBonusSourceID(); //there is one global object
 		globalEffects.addNewBonus(bonus);
 	}
 	VLC->creh->loadCrExpBon(globalEffects);

+ 5 - 0
lib/mapObjectConstructors/CObjectClassesHandler.cpp

@@ -488,4 +488,9 @@ std::string CObjectClassesHandler::getObjectHandlerName(si32 type) const
 	return objects.at(type)->handlerName;
 }
 
+std::string CObjectClassesHandler::getJsonKey(si32 type) const
+{
+	return objects.at(type)->getJsonKey();
+}
+
 VCMI_LIB_NAMESPACE_END

+ 2 - 0
lib/mapObjectConstructors/CObjectClassesHandler.h

@@ -129,6 +129,8 @@ public:
 	/// Returns handler string describing the handler (for use in client)
 	std::string getObjectHandlerName(si32 type) const;
 
+	std::string getJsonKey(si32 type) const;
+
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & objects;

+ 3 - 4
lib/mapObjects/CArmedInstance.cpp

@@ -59,7 +59,7 @@ void CArmedInstance::updateMoraleBonusFromArmy()
 	auto b = getExportedBonusList().getFirst(Selector::sourceType()(BonusSource::ARMY).And(Selector::type()(BonusType::MORALE)));
  	if(!b)
 	{
-		b = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::MORALE, BonusSource::ARMY, 0, TBonusSourceID::NONE);
+		b = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::MORALE, BonusSource::ARMY, 0, TBonusSourceID());
 		addNewBonus(b);
 	}
 
@@ -120,13 +120,12 @@ void CArmedInstance::updateMoraleBonusFromArmy()
 	CBonusSystemNode::treeHasChanged();
 
 	//-1 modifier for any Undead unit in army
-	const TBonusSourceID UNDEAD_MODIFIER_ID( "", "", -2);
-	auto undeadModifier = getExportedBonusList().getFirst(Selector::source(BonusSource::ARMY, UNDEAD_MODIFIER_ID));
+	auto undeadModifier = getExportedBonusList().getFirst(Selector::source(BonusSource::ARMY, BonusSourceID::undeadMoraleDebuff));
  	if(hasUndead)
 	{
 		if(!undeadModifier)
 		{
-			undeadModifier = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::MORALE, BonusSource::ARMY, -1, UNDEAD_MODIFIER_ID, VLC->generaltexth->arraytxt[116]);
+			undeadModifier = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::MORALE, BonusSource::ARMY, -1, BonusSourceID::undeadMoraleDebuff, VLC->generaltexth->arraytxt[116]);
 			undeadModifier->description = undeadModifier->description.substr(0, undeadModifier->description.size()-2);//trim value
 			addNewBonus(undeadModifier);
 		}

+ 1 - 2
lib/mapObjects/CGCreature.cpp

@@ -16,7 +16,6 @@
 #include "../CConfigHandler.h"
 #include "../GameSettings.h"
 #include "../IGameCallback.h"
-#include "../bonuses/BonusSubtypes.h"
 #include "../serializer/JsonSerializeFormat.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
@@ -47,7 +46,7 @@ std::string CGCreature::getHoverText(PlayerColor player) const
 std::string CGCreature::getHoverText(const CGHeroInstance * hero) const
 {
 	std::string hoverName;
-	if(hero->hasVisions(this, BonusSubtypes::visionsMonsters))
+	if(hero->hasVisions(this, BonusSubtypeID::visionsMonsters))
 	{
 		MetaString ms;
 		ms.appendNumber(stacks.begin()->second->count);

+ 3 - 4
lib/mapObjects/CGHeroInstance.cpp

@@ -37,7 +37,6 @@
 #include "../modding/ModScope.h"
 #include "../constants/StringConstants.h"
 #include "../battle/Unit.h"
-#include "../bonuses/BonusSubtypes.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -250,14 +249,14 @@ void CGHeroInstance::updateArmyMovementBonus(bool onLand, const TurnInfo * ti) c
 		lowestCreatureSpeed = realLowestSpeed;
 		//Let updaters run again
 		treeHasChanged();
-		ti->updateHeroBonuses(BonusType::MOVEMENT, Selector::subtype()(onLand ? BonusSubtypes::heroMovementLand : BonusSubtypes::heroMovementSea));
+		ti->updateHeroBonuses(BonusType::MOVEMENT, Selector::subtype()(onLand ? BonusSubtypeID::heroMovementLand : BonusSubtypeID::heroMovementSea));
 	}
 }
 
 int CGHeroInstance::movementPointsLimitCached(bool onLand, const TurnInfo * ti) const
 {
 	updateArmyMovementBonus(onLand, ti);
-	return ti->valOfBonuses(BonusType::MOVEMENT, onLand ? BonusSubtypes::heroMovementLand : BonusSubtypes::heroMovementSea);
+	return ti->valOfBonuses(BonusType::MOVEMENT, onLand ? BonusSubtypeID::heroMovementLand : BonusSubtypeID::heroMovementSea);
 }
 
 CGHeroInstance::CGHeroInstance():
@@ -764,7 +763,7 @@ bool CGHeroInstance::canCastThisSpell(const spells::Spell * spell) const
 		}
 	});
 
-	const bool levelBonus = hasBonusOfType(BonusType::SPELLS_OF_LEVEL, BonusSubtypes::spellLevel(spell->getLevel()));
+	const bool levelBonus = hasBonusOfType(BonusType::SPELLS_OF_LEVEL, BonusSubtypeID::spellLevel(spell->getLevel()));
 
 	if(spell->isSpecial())
 	{

+ 1 - 2
lib/mapObjects/CGTownBuilding.cpp

@@ -15,7 +15,6 @@
 #include "../NetPacks.h"
 #include "../IGameCallback.h"
 #include "../gameState/CGameState.h"
-#include "../bonuses/BonusSubtypes.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -147,7 +146,7 @@ void COPWBonus::onHeroVisit (const CGHeroInstance * h) const
 			if(!h->hasBonusFrom(BonusSource::OBJECT, TBonusSourceID(Obj(Obj::STABLES)))) //does not stack with advMap Stables
 			{
 				GiveBonus gb;
-				gb.bonus = Bonus(BonusDuration::ONE_WEEK, BonusType::MOVEMENT, BonusSource::OBJECT, 600, TBonusSourceID(Obj(Obj::STABLES)), BonusSubtypes::heroMovementLand, VLC->generaltexth->arraytxt[100]);
+				gb.bonus = Bonus(BonusDuration::ONE_WEEK, BonusType::MOVEMENT, BonusSource::OBJECT, 600, TBonusSourceID(Obj(Obj::STABLES)), BonusSubtypeID::heroMovementLand, VLC->generaltexth->arraytxt[100]);
 				gb.id = heroID.getNum();
 				cb->giveHeroBonus(&gb);
 

+ 2 - 3
lib/mapObjects/CGTownInstance.cpp

@@ -13,7 +13,6 @@
 #include "CGTownBuilding.h"
 #include "../spells/CSpellHandler.h"
 #include "../bonuses/Bonus.h"
-#include "../bonuses/BonusSubtypes.h"
 #include "../battle/IBattleInfoCallback.h"
 #include "../NetPacks.h"
 #include "../CConfigHandler.h"
@@ -161,7 +160,7 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const
 	}
 
 	//other *-of-legion-like bonuses (%d to growth cumulative with grail)
-	TConstBonusListPtr bonuses = getBonuses(Selector::typeSubtype(BonusType::CREATURE_GROWTH, BonusSubtypes::creatureLevel(level)));
+	TConstBonusListPtr bonuses = getBonuses(Selector::typeSubtype(BonusType::CREATURE_GROWTH, BonusSubtypeID::creatureLevel(level)));
 	for(const auto & b : *bonuses)
 		ret.entries.emplace_back(b->val, b->Description());
 
@@ -788,7 +787,7 @@ void CGTownInstance::updateMoraleBonusFromArmy()
 	auto b = getExportedBonusList().getFirst(Selector::sourceType()(BonusSource::ARMY).And(Selector::type()(BonusType::MORALE)));
 	if(!b)
 	{
-		b = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::MORALE, BonusSource::ARMY, 0, TBonusSourceID::NONE);
+		b = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::MORALE, BonusSource::ARMY, 0, TBonusSourceID());
 		addNewBonus(b);
 	}
 

+ 1 - 2
lib/mapObjects/MiscObjects.cpp

@@ -25,7 +25,6 @@
 #include "../mapObjectConstructors/AObjectTypeHandler.h"
 #include "../mapObjectConstructors/CObjectClassesHandler.h"
 #include "../modding/ModScope.h"
-#include "../bonuses/BonusSubtypes.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -1205,7 +1204,7 @@ void CGLighthouse::giveBonusTo(const PlayerColor & player, bool onInit) const
 	gb.bonus.duration = BonusDuration::PERMANENT;
 	gb.bonus.source = BonusSource::OBJECT;
 	gb.bonus.sid = TBonusSourceID(id);
-	gb.bonus.subtype = BonusSubtypes::heroMovementSea;
+	gb.bonus.subtype = BonusSubtypeID::heroMovementSea;
 
 	// FIXME: This is really dirty hack
 	// Proper fix would be to make CGLighthouse into bonus system node

+ 2 - 2
lib/pathfinder/TurnInfo.cpp

@@ -73,7 +73,7 @@ bool TurnInfo::isLayerAvailable(const EPathfindingLayer & layer) const
 
 bool TurnInfo::hasBonusOfType(BonusType type) const
 {
-	return hasBonusOfType(type, TBonusSubtype::NONE);
+	return hasBonusOfType(type, TBonusSubtype());
 }
 
 bool TurnInfo::hasBonusOfType(BonusType type, TBonusSubtype subtype) const
@@ -96,7 +96,7 @@ bool TurnInfo::hasBonusOfType(BonusType type, TBonusSubtype subtype) const
 
 int TurnInfo::valOfBonuses(BonusType type) const
 {
-	return valOfBonuses(type, TBonusSubtype::NONE);
+	return valOfBonuses(type, TBonusSubtype());
 }
 
 int TurnInfo::valOfBonuses(BonusType type, TBonusSubtype subtype) const

+ 2 - 3
lib/spells/TargetCondition.cpp

@@ -17,7 +17,6 @@
 #include "../battle/Unit.h"
 #include "../bonuses/BonusParams.h"
 #include "../bonuses/BonusList.h"
-#include "../bonuses/BonusSubtypes.h"
 
 #include "../modding/IdentifierStorage.h"
 #include "../modding/ModUtility.h"
@@ -293,8 +292,8 @@ class ImmunityNegationCondition : public TargetConditionItemBase
 protected:
 	bool check(const Mechanics * m, const battle::Unit * target) const override
 	{
-		const bool battleWideNegation = target->hasBonusOfType(BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, BonusSubtypes::immunityBattleWide);
-		const bool heroNegation = target->hasBonusOfType(BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, BonusSubtypes::immunityEnemyHero);
+		const bool battleWideNegation = target->hasBonusOfType(BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, BonusSubtypeID::immunityBattleWide);
+		const bool heroNegation = target->hasBonusOfType(BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, BonusSubtypeID::immunityEnemyHero);
 		//Non-magical effects is not affected by orb of vulnerability
 		if(!m->isMagicalEffect())
 			return false;

+ 18 - 19
server/battles/BattleActionProcessor.cpp

@@ -20,7 +20,6 @@
 #include "../../lib/battle/CBattleInfoCallback.h"
 #include "../../lib/battle/IBattleState.h"
 #include "../../lib/battle/BattleAction.h"
-#include "../../lib/bonuses/BonusSubtypes.h"
 #include "../../lib/gameState/CGameState.h"
 #include "../../lib/NetPacks.h"
 #include "../../lib/spells/AbilityCaster.h"
@@ -163,9 +162,9 @@ bool BattleActionProcessor::doDefendAction(const CBattleInfoCallback & battle, c
 	SetStackEffect sse;
 	sse.battleID = battle.getBattle()->getBattleID();
 
-	Bonus defenseBonusToAdd(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 20, TBonusSourceID::NONE, TBonusSubtype(PrimarySkill::DEFENSE), BonusValueType::PERCENT_TO_ALL);
-	Bonus bonus2(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, stack->valOfBonuses(BonusType::DEFENSIVE_STANCE), TBonusSourceID::NONE, TBonusSubtype(PrimarySkill::DEFENSE), BonusValueType::ADDITIVE_VALUE);
-	Bonus alternativeWeakCreatureBonus(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 1, TBonusSourceID::NONE, TBonusSubtype(PrimarySkill::DEFENSE), BonusValueType::ADDITIVE_VALUE);
+	Bonus defenseBonusToAdd(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 20, TBonusSourceID(), TBonusSubtype(PrimarySkill::DEFENSE), BonusValueType::PERCENT_TO_ALL);
+	Bonus bonus2(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, stack->valOfBonuses(BonusType::DEFENSIVE_STANCE), TBonusSourceID(), TBonusSubtype(PrimarySkill::DEFENSE), BonusValueType::ADDITIVE_VALUE);
+	Bonus alternativeWeakCreatureBonus(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 1, TBonusSourceID(), TBonusSubtype(PrimarySkill::DEFENSE), BonusValueType::ADDITIVE_VALUE);
 
 	BonusList defence = *stack->getBonuses(Selector::typeSubtype(BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::DEFENSE)));
 	int oldDefenceValue = defence.totalValue();
@@ -383,7 +382,7 @@ bool BattleActionProcessor::doCatapultAction(const CBattleInfoCallback & battle,
 		return false;
 
 	std::shared_ptr<const Bonus> catapultAbility = stack->getBonusLocalFirst(Selector::type()(BonusType::CATAPULT));
-	if(!catapultAbility || catapultAbility->subtype == TBonusSubtype::NONE)
+	if(!catapultAbility || catapultAbility->subtype == TBonusSubtype())
 	{
 		gameHandler->complain("We do not know how to shoot :P");
 	}
@@ -453,7 +452,7 @@ bool BattleActionProcessor::doHealAction(const CBattleInfoCallback & battle, con
 	else
 		destStack = battle.battleGetUnitByPos(target.at(0).hexValue);
 
-	if(stack == nullptr || destStack == nullptr || !healerAbility || healerAbility->subtype == TBonusSubtype::NONE)
+	if(stack == nullptr || destStack == nullptr || !healerAbility || healerAbility->subtype == TBonusSubtype())
 	{
 		gameHandler->complain("There is either no healer, no destination, or healer cannot heal :P");
 	}
@@ -1169,7 +1168,7 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
 		// each gorgon have 10% chance to kill (counted separately in H3) -> binomial distribution
 		//original formula x = min(x, (gorgons_count + 9)/10);
 
-		double chanceToKill = attacker->valOfBonuses(BonusType::DEATH_STARE, BonusSubtypes::deathStareGorgon) / 100.0f;
+		double chanceToKill = attacker->valOfBonuses(BonusType::DEATH_STARE, BonusSubtypeID::deathStareGorgon) / 100.0f;
 		vstd::amin(chanceToKill, 1); //cap at 100%
 
 		std::binomial_distribution<> distribution(attacker->getCount(), chanceToKill);
@@ -1180,7 +1179,7 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
 		int maxToKill = static_cast<int>((attacker->getCount() + cap - 1) / cap); //not much more than chance * count
 		vstd::amin(staredCreatures, maxToKill);
 
-		staredCreatures += (attacker->level() * attacker->valOfBonuses(BonusType::DEATH_STARE, BonusSubtypes::deathStareCommander)) / defender->level();
+		staredCreatures += (attacker->level() * attacker->valOfBonuses(BonusType::DEATH_STARE, BonusSubtypeID::deathStareCommander)) / defender->level();
 		if(staredCreatures)
 		{
 			//TODO: death stare was not originally available for multiple-hex attacks, but...
@@ -1250,9 +1249,9 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
 		else
 			resurrectInfo.type = attacker->creatureId();
 
-		if(attacker->hasBonusOfType((BonusType::TRANSMUTATION), BonusSubtypes::transmutationPerHealth))
+		if(attacker->hasBonusOfType((BonusType::TRANSMUTATION), BonusSubtypeID::transmutationPerHealth))
 			resurrectInfo.count = std::max((defender->getCount() * defender->getMaxHealth()) / resurrectInfo.type.toCreature()->getMaxHealth(), 1u);
-		else if (attacker->hasBonusOfType((BonusType::TRANSMUTATION), BonusSubtypes::transmutationPerUnit))
+		else if (attacker->hasBonusOfType((BonusType::TRANSMUTATION), BonusSubtypeID::transmutationPerUnit))
 			resurrectInfo.count = defender->getCount();
 		else
 			return; //wrong subtype
@@ -1274,21 +1273,21 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
 		gameHandler->sendAndApply(&fakeEvent);
 	}
 
-	if(attacker->hasBonusOfType(BonusType::DESTRUCTION, BonusSubtypes::destructionKillPercentage) || attacker->hasBonusOfType(BonusType::DESTRUCTION, BonusSubtypes::destructionKillAmount))
+	if(attacker->hasBonusOfType(BonusType::DESTRUCTION, BonusSubtypeID::destructionKillPercentage) || attacker->hasBonusOfType(BonusType::DESTRUCTION, BonusSubtypeID::destructionKillAmount))
 	{
 		double chanceToTrigger = 0;
 		int amountToDie = 0;
 
-		if(attacker->hasBonusOfType(BonusType::DESTRUCTION, BonusSubtypes::destructionKillPercentage)) //killing by percentage
+		if(attacker->hasBonusOfType(BonusType::DESTRUCTION, BonusSubtypeID::destructionKillPercentage)) //killing by percentage
 		{
-			chanceToTrigger = attacker->valOfBonuses(BonusType::DESTRUCTION, BonusSubtypes::destructionKillPercentage) / 100.0f;
-			int percentageToDie = attacker->getBonus(Selector::type()(BonusType::DESTRUCTION).And(Selector::subtype()(BonusSubtypes::destructionKillPercentage)))->additionalInfo[0];
+			chanceToTrigger = attacker->valOfBonuses(BonusType::DESTRUCTION, BonusSubtypeID::destructionKillPercentage) / 100.0f;
+			int percentageToDie = attacker->getBonus(Selector::type()(BonusType::DESTRUCTION).And(Selector::subtype()(BonusSubtypeID::destructionKillPercentage)))->additionalInfo[0];
 			amountToDie = static_cast<int>(defender->getCount() * percentageToDie * 0.01f);
 		}
-		else if(attacker->hasBonusOfType(BonusType::DESTRUCTION, BonusSubtypes::destructionKillAmount)) //killing by count
+		else if(attacker->hasBonusOfType(BonusType::DESTRUCTION, BonusSubtypeID::destructionKillAmount)) //killing by count
 		{
-			chanceToTrigger = attacker->valOfBonuses(BonusType::DESTRUCTION, BonusSubtypes::destructionKillAmount) / 100.0f;
-			amountToDie = attacker->getBonus(Selector::type()(BonusType::DESTRUCTION).And(Selector::subtype()(BonusSubtypes::destructionKillAmount)))->additionalInfo[0];
+			chanceToTrigger = attacker->valOfBonuses(BonusType::DESTRUCTION, BonusSubtypeID::destructionKillAmount) / 100.0f;
+			amountToDie = attacker->getBonus(Selector::type()(BonusType::DESTRUCTION).And(Selector::subtype()(BonusSubtypeID::destructionKillAmount)))->additionalInfo[0];
 		}
 
 		vstd::amin(chanceToTrigger, 1); //cap trigger chance at 100%
@@ -1349,12 +1348,12 @@ int64_t BattleActionProcessor::applyBattleEffects(const CBattleInfoCallback & ba
 	{
 		//we can have two bonuses - one with subtype 0 and another with subtype 1
 		//try to use permanent first, use only one of two
-		for(const auto & subtype : { BonusSubtypes::soulStealBattle, BonusSubtypes::soulStealPermanent})
+		for(const auto & subtype : { BonusSubtypeID::soulStealBattle, BonusSubtypeID::soulStealPermanent})
 		{
 			if(attackerState->hasBonusOfType(BonusType::SOUL_STEAL, subtype))
 			{
 				int64_t toHeal = bsa.killedAmount * attackerState->valOfBonuses(BonusType::SOUL_STEAL, subtype) * attackerState->getMaxHealth();
-				bool permanent = subtype == BonusSubtypes::soulStealPermanent;
+				bool permanent = subtype == BonusSubtypeID::soulStealPermanent;
 				attackerState->heal(toHeal, EHealLevel::OVERHEAL, (permanent ? EHealPower::PERMANENT : EHealPower::ONE_BATTLE));
 				drainedLife += toHeal;
 				break;

+ 2 - 3
server/processors/PlayerMessageProcessor.cpp

@@ -16,7 +16,6 @@
 #include "../../lib/serializer/Connection.h"
 #include "../../lib/CGeneralTextHandler.h"
 #include "../../lib/CHeroHandler.h"
-#include "../../lib/bonuses/BonusSubtypes.h"
 #include "../../lib/modding/IdentifierStorage.h"
 #include "../../lib/CPlayerState.h"
 #include "../../lib/GameConstants.h"
@@ -141,11 +140,11 @@ void PlayerMessageProcessor::cheatGiveSpells(PlayerColor player, const CGHeroIns
 	///Give all spells with bonus (to allow banned spells)
 	GiveBonus giveBonus(GiveBonus::ETarget::HERO);
 	giveBonus.id = hero->id.getNum();
-	giveBonus.bonus = Bonus(BonusDuration::PERMANENT, BonusType::SPELLS_OF_LEVEL, BonusSource::OTHER, 0, TBonusSourceID::NONE);
+	giveBonus.bonus = Bonus(BonusDuration::PERMANENT, BonusType::SPELLS_OF_LEVEL, BonusSource::OTHER, 0, TBonusSourceID());
 	//start with level 0 to skip abilities
 	for (int level = 1; level <= GameConstants::SPELL_LEVELS; level++)
 	{
-		giveBonus.bonus.subtype = BonusSubtypes::spellLevel(level);
+		giveBonus.bonus.subtype = BonusSubtypeID::spellLevel(level);
 		gameHandler->sendAndApply(&giveBonus);
 	}
 

+ 10 - 10
test/battle/CBattleInfoCallbackTest.cpp

@@ -49,7 +49,7 @@ public:
 
 	void makeWarMachine()
 	{
-		addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SIEGE_WEAPON, BonusSource::CREATURE_ABILITY, 1, TBonusSourceID::NONE));
+		addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SIEGE_WEAPON, BonusSource::CREATURE_ABILITY, 1, TBonusSourceID()));
 	}
 
 	void redirectBonusesToFake()
@@ -331,7 +331,7 @@ TEST_F(BattleMatchOwnerTest, hypnotizedToSelf)
 {
 	UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
 	EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
-	unit1.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID::NONE));
+	unit1.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID()));
 
 	setDefaultExpectations();
 
@@ -362,7 +362,7 @@ TEST_F(BattleMatchOwnerTest, hypnotizedToNormalAlly)
 {
 	UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
 	EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
-	unit1.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID::NONE));
+	unit1.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID()));
 
 	UnitFake & unit2 = unitsFake.add(BattleSide::ATTACKER);
 	EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
@@ -382,7 +382,7 @@ TEST_F(BattleMatchOwnerTest, normalToHypnotizedAlly)
 	EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
 	UnitFake & unit2 = unitsFake.add(BattleSide::ATTACKER);
 	EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
-	unit2.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID::NONE));
+	unit2.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID()));
 
 	setDefaultExpectations();
 
@@ -397,11 +397,11 @@ TEST_F(BattleMatchOwnerTest, hypnotizedToHypnotizedAlly)
 {
 	UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
 	EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
-	unit1.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID::NONE));
+	unit1.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID()));
 
 	UnitFake & unit2 = unitsFake.add(BattleSide::ATTACKER);
 	EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
-	unit2.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID::NONE));
+	unit2.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID()));
 
 	setDefaultExpectations();
 
@@ -433,7 +433,7 @@ TEST_F(BattleMatchOwnerTest, hypnotizedToNormalEnemy)
 {
 	UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
 	EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
-	unit1.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID::NONE));
+	unit1.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID()));
 
 	UnitFake & unit2 = unitsFake.add(BattleSide::DEFENDER);
 	EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
@@ -453,7 +453,7 @@ TEST_F(BattleMatchOwnerTest, normalToHypnotizedEnemy)
 	EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
 	UnitFake & unit2 = unitsFake.add(BattleSide::DEFENDER);
 	EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
-	unit2.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID::NONE));
+	unit2.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID()));
 
 	setDefaultExpectations();
 
@@ -468,11 +468,11 @@ TEST_F(BattleMatchOwnerTest, hypnotizedToHypnotizedEnemy)
 {
 	UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
 	EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
-	unit1.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID::NONE));
+	unit1.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID()));
 
 	UnitFake & unit2 = unitsFake.add(BattleSide::DEFENDER);
 	EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
-	unit2.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID::NONE));
+	unit2.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, TBonusSourceID()));
 
 	setDefaultExpectations();
 

+ 2 - 2
test/battle/CHealthTest.cpp

@@ -33,7 +33,7 @@ public:
 		EXPECT_CALL(mock, getAllBonuses(_, _, _, _)).WillRepeatedly(Invoke(&bonusMock, &BonusBearerMock::getAllBonuses));
 		EXPECT_CALL(mock, getTreeVersion()).WillRepeatedly(Return(1));
 
-		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, UNIT_HEALTH, TBonusSourceID::NONE));
+		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, UNIT_HEALTH, TBonusSourceID()));
 
 		EXPECT_CALL(mock, unitBaseAmount()).WillRepeatedly(Return(UNIT_AMOUNT));
 	}
@@ -239,7 +239,7 @@ TEST_F(HealthTest, singleUnitStack)
 	EXPECT_CALL(mock, getAllBonuses(_, _, _, _)).WillRepeatedly(Invoke(&bonusMock, &BonusBearerMock::getAllBonuses));
 	EXPECT_CALL(mock, getTreeVersion()).WillRepeatedly(Return(1));
 
-	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, 300, TBonusSourceID::NONE));
+	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, 300, TBonusSourceID()));
 
 	EXPECT_CALL(mock, unitBaseAmount()).WillRepeatedly(Return(1));
 

+ 6 - 6
test/battle/CUnitStateMagicTest.cpp

@@ -55,7 +55,7 @@ public:
 
 	void makeNormalCaster()
 	{
-		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SPELLCASTER, BonusSource::CREATURE_ABILITY, DEFAULT_SCHOOL_LEVEL, TBonusSourceID::NONE, TBonusSubtype(SpellID(DEFAULT_SPELL_INDEX))));
+		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SPELLCASTER, BonusSource::CREATURE_ABILITY, DEFAULT_SCHOOL_LEVEL, TBonusSourceID(), TBonusSubtype(SpellID(DEFAULT_SPELL_INDEX))));
 	}
 };
 
@@ -63,7 +63,7 @@ TEST_F(UnitStateMagicTest, initialNormal)
 {
 	setDefaultExpectations();
 
-	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CASTS, BonusSource::CREATURE_ABILITY, 567, TBonusSourceID::NONE));
+	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CASTS, BonusSource::CREATURE_ABILITY, 567, TBonusSourceID()));
 
 	initUnit();
 
@@ -125,7 +125,7 @@ TEST_F(UnitStateMagicTest, effectPower)
 
 	const int32_t EFFECT_POWER = 12 * 100;
 
-	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_SPELL_POWER, BonusSource::CREATURE_ABILITY, EFFECT_POWER, TBonusSourceID::NONE));
+	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_SPELL_POWER, BonusSource::CREATURE_ABILITY, EFFECT_POWER, TBonusSourceID()));
 
 	makeNormalCaster();
 	EXPECT_EQ(subject.getEffectPower(&spellMock), 12 * DEFAULT_AMOUNT);
@@ -148,7 +148,7 @@ TEST_F(UnitStateMagicTest, enchantPower)
 
 	const int32_t ENCHANT_POWER = 42;
 
-	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_ENCHANT_POWER, BonusSource::CREATURE_ABILITY, ENCHANT_POWER, TBonusSourceID::NONE));
+	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_ENCHANT_POWER, BonusSource::CREATURE_ABILITY, ENCHANT_POWER, TBonusSourceID()));
 
 	makeNormalCaster();
 
@@ -171,7 +171,7 @@ TEST_F(UnitStateMagicTest, effectValue)
 
 	const int32_t EFFECT_VALUE = 456;
 
-	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SPECIFIC_SPELL_POWER, BonusSource::CREATURE_ABILITY, EFFECT_VALUE, TBonusSourceID::NONE, TBonusSubtype(SpellID(DEFAULT_SPELL_INDEX))));
+	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SPECIFIC_SPELL_POWER, BonusSource::CREATURE_ABILITY, EFFECT_VALUE, TBonusSourceID(), TBonusSubtype(SpellID(DEFAULT_SPELL_INDEX))));
 
 	makeNormalCaster();
 	EXPECT_EQ(subject.getEffectValue(&spellMock), EFFECT_VALUE * DEFAULT_AMOUNT);
@@ -201,7 +201,7 @@ TEST_F(UnitStateMagicTest, spendMana)
 {
 	setDefaultExpectations();
 
-	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CASTS, BonusSource::CREATURE_ABILITY, 1, TBonusSourceID::NONE));
+	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CASTS, BonusSource::CREATURE_ABILITY, 1, TBonusSourceID()));
 
 	initUnit();
 

+ 15 - 16
test/battle/CUnitStateTest.cpp

@@ -12,7 +12,6 @@
 #include "mock/mock_BonusBearer.h"
 #include "mock/mock_UnitInfo.h"
 #include "mock/mock_UnitEnvironment.h"
-#include "../../lib/bonuses/BonusSubtypes.h"
 #include "../../lib/battle/CUnitState.h"
 #include "../../lib/CCreatureHandler.h"
 
@@ -52,12 +51,12 @@ public:
 
 	void setDefaultExpectations()
 	{
-		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACKS_SPEED, BonusSource::CREATURE_ABILITY, DEFAULT_SPEED, TBonusSourceID::NONE));
+		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACKS_SPEED, BonusSource::CREATURE_ABILITY, DEFAULT_SPEED, TBonusSourceID()));
 
-		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::CREATURE_ABILITY, DEFAULT_ATTACK, TBonusSourceID::NONE, TBonusSubtype(PrimarySkill::ATTACK)));
-		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::CREATURE_ABILITY, DEFAULT_DEFENCE, TBonusSourceID::NONE, TBonusSubtype(PrimarySkill::DEFENSE)));
+		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::CREATURE_ABILITY, DEFAULT_ATTACK, TBonusSourceID(), TBonusSubtype(PrimarySkill::ATTACK)));
+		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::CREATURE_ABILITY, DEFAULT_DEFENCE, TBonusSourceID(), TBonusSubtype(PrimarySkill::DEFENSE)));
 
-		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, DEFAULT_HP, TBonusSourceID::NONE));
+		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, DEFAULT_HP, TBonusSourceID()));
 
 		EXPECT_CALL(infoMock, unitBaseAmount()).WillRepeatedly(Return(DEFAULT_AMOUNT));
 		EXPECT_CALL(infoMock, unitType()).WillRepeatedly(Return(pikeman));
@@ -67,8 +66,8 @@ public:
 
 	void makeShooter(int32_t ammo)
 	{
-		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SHOOTER, BonusSource::CREATURE_ABILITY, 1, TBonusSourceID::NONE));
-		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SHOTS, BonusSource::CREATURE_ABILITY, ammo, TBonusSourceID::NONE));
+		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SHOOTER, BonusSource::CREATURE_ABILITY, 1, TBonusSourceID()));
+		bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SHOTS, BonusSource::CREATURE_ABILITY, ammo, TBonusSourceID()));
 	}
 
 	void initUnit()
@@ -180,7 +179,7 @@ TEST_F(UnitStateTest, attackWithFrenzy)
 {
 	setDefaultExpectations();
 
-	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::IN_FRENZY, BonusSource::SPELL_EFFECT, 50, TBonusSourceID::NONE));
+	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::IN_FRENZY, BonusSource::SPELL_EFFECT, 50, TBonusSourceID()));
 
 	int expectedAttack = static_cast<int>(DEFAULT_ATTACK + 0.5 * DEFAULT_DEFENCE);
 
@@ -192,7 +191,7 @@ TEST_F(UnitStateTest, defenceWithFrenzy)
 {
 	setDefaultExpectations();
 
-	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::IN_FRENZY, BonusSource::SPELL_EFFECT, 50, TBonusSourceID::NONE));
+	bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::IN_FRENZY, BonusSource::SPELL_EFFECT, 50, TBonusSourceID()));
 
 	int expectedDefence = 0;
 
@@ -205,7 +204,7 @@ TEST_F(UnitStateTest, additionalAttack)
 	setDefaultExpectations();
 
 	{
-		auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::ADDITIONAL_ATTACK, BonusSource::SPELL_EFFECT, 41, TBonusSourceID::NONE);
+		auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::ADDITIONAL_ATTACK, BonusSource::SPELL_EFFECT, 41, TBonusSourceID());
 
 		bonusMock.addNewBonus(bonus);
 	}
@@ -219,7 +218,7 @@ TEST_F(UnitStateTest, additionalMeleeAttack)
 	setDefaultExpectations();
 
 	{
-		auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::ADDITIONAL_ATTACK, BonusSource::SPELL_EFFECT, 41, TBonusSourceID::NONE);
+		auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::ADDITIONAL_ATTACK, BonusSource::SPELL_EFFECT, 41, TBonusSourceID());
 		bonus->effectRange = BonusLimitEffect::ONLY_MELEE_FIGHT;
 
 		bonusMock.addNewBonus(bonus);
@@ -234,7 +233,7 @@ TEST_F(UnitStateTest, additionalRangedAttack)
 	setDefaultExpectations();
 
 	{
-		auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::ADDITIONAL_ATTACK, BonusSource::SPELL_EFFECT, 41, TBonusSourceID::NONE);
+		auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::ADDITIONAL_ATTACK, BonusSource::SPELL_EFFECT, 41, TBonusSourceID());
 		bonus->effectRange = BonusLimitEffect::ONLY_DISTANCE_FIGHT;
 
 		bonusMock.addNewBonus(bonus);
@@ -249,10 +248,10 @@ TEST_F(UnitStateTest, getMinDamage)
 	setDefaultExpectations();
 
 	{
-		auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_DAMAGE, BonusSource::SPELL_EFFECT, 30, TBonusSourceID::NONE, BonusSubtypes::creatureDamageBoth);
+		auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_DAMAGE, BonusSource::SPELL_EFFECT, 30, TBonusSourceID(), BonusSubtypeID::creatureDamageBoth);
 		bonusMock.addNewBonus(bonus);
 
-		bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_DAMAGE, BonusSource::SPELL_EFFECT, -20, TBonusSourceID::NONE, BonusSubtypes::creatureDamageMin);
+		bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_DAMAGE, BonusSource::SPELL_EFFECT, -20, TBonusSourceID(), BonusSubtypeID::creatureDamageMin);
 		bonusMock.addNewBonus(bonus);
 	}
 
@@ -265,10 +264,10 @@ TEST_F(UnitStateTest, getMaxDamage)
 	setDefaultExpectations();
 
 	{
-		auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_DAMAGE, BonusSource::SPELL_EFFECT, 30, TBonusSourceID::NONE, BonusSubtypes::creatureDamageBoth);
+		auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_DAMAGE, BonusSource::SPELL_EFFECT, 30, TBonusSourceID(), BonusSubtypeID::creatureDamageBoth);
 		bonusMock.addNewBonus(bonus);
 
-		bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_DAMAGE, BonusSource::SPELL_EFFECT, -20, TBonusSourceID::NONE, BonusSubtypes::creatureDamageMax);
+		bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::CREATURE_DAMAGE, BonusSource::SPELL_EFFECT, -20, TBonusSourceID(), BonusSubtypeID::creatureDamageMax);
 		bonusMock.addNewBonus(bonus);
 	}
 

+ 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, TBonusSourceID::NONE, TBonusSubtype(SpellSchool::ANY)));
+	casterBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::MAGIC_SCHOOL_SKILL, BonusSource::OTHER, 2, TBonusSourceID(), TBonusSubtype(SpellSchool::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, TBonusSourceID::NONE, TBonusSubtype(SpellSchool::AIR)));
+	casterBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::MAGIC_SCHOOL_SKILL, BonusSource::OTHER, 2, TBonusSourceID(), TBonusSubtype(SpellSchool::AIR)));
 
 	EXPECT_CALL(actualCaster, getAllBonuses(_, _, _, _)).Times(AtLeast(1));
 	EXPECT_CALL(actualCaster, getTreeVersion()).Times(AtLeast(0));

+ 3 - 3
test/spells/effects/DamageTest.cpp

@@ -95,7 +95,7 @@ TEST_F(DamageApplyTest, DoesDamageToAliveUnit)
 	const uint32_t unitId = 42;
 	auto & targetUnit = unitsFake.add(BattleSide::ATTACKER);
 
-	targetUnit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, unitHP, TBonusSourceID::NONE));
+	targetUnit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, unitHP, TBonusSourceID()));
 	EXPECT_CALL(targetUnit, unitId()).WillRepeatedly(Return(unitId));
 	EXPECT_CALL(targetUnit, unitBaseAmount()).WillRepeatedly(Return(unitAmount));
 	EXPECT_CALL(targetUnit, alive()).WillRepeatedly(Return(true));
@@ -157,7 +157,7 @@ TEST_F(DamageApplyTest, DoesDamageByPercent)
 	const uint32_t unitId = 42;
 	auto & targetUnit = unitsFake.add(BattleSide::ATTACKER);
 
-	targetUnit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, unitHP, TBonusSourceID::NONE));
+	targetUnit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, unitHP, TBonusSourceID()));
 	EXPECT_CALL(targetUnit, unitId()).WillRepeatedly(Return(unitId));
 	EXPECT_CALL(targetUnit, unitBaseAmount()).WillRepeatedly(Return(unitAmount));
 	EXPECT_CALL(targetUnit, getCount()).WillOnce(Return(unitAmount));
@@ -202,7 +202,7 @@ TEST_F(DamageApplyTest, DoesDamageByCount)
 	const uint32_t unitId = 42;
 	auto & targetUnit = unitsFake.add(BattleSide::ATTACKER);
 
-	targetUnit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, unitHP, TBonusSourceID::NONE));
+	targetUnit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, unitHP, TBonusSourceID()));
 	EXPECT_CALL(targetUnit, unitId()).WillRepeatedly(Return(unitId));
 	EXPECT_CALL(targetUnit, unitBaseAmount()).WillRepeatedly(Return(unitAmount));
 	EXPECT_CALL(targetUnit, alive()).WillRepeatedly(Return(true));

+ 5 - 5
test/spells/effects/HealTest.cpp

@@ -91,7 +91,7 @@ TEST_F(HealTest, ApplicableIfActuallyResurrects)
 	EXPECT_CALL(mechanicsMock, getEffectValue()).Times(AtLeast(1)).WillRepeatedly(Return(1000));
 	EXPECT_CALL(mechanicsMock, isSmart()).WillOnce(Return(false));
 
-	unit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, 200, TBonusSourceID::NONE));
+	unit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, 200, TBonusSourceID()));
 	unitsFake.setDefaultBonusExpectations();
 
 	EffectTarget target;
@@ -117,7 +117,7 @@ TEST_F(HealTest, NotApplicableIfNotEnoughCasualties)
 	EXPECT_CALL(mechanicsMock, getEffectValue()).Times(AtLeast(1)).WillRepeatedly(Return(999));
 	EXPECT_CALL(mechanicsMock, isSmart()).WillRepeatedly(Return(false));
 
-	unit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, 200, TBonusSourceID::NONE));
+	unit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, 200, TBonusSourceID()));
 	unitsFake.setDefaultBonusExpectations();
 
 	EffectTarget target;
@@ -143,7 +143,7 @@ TEST_F(HealTest, NotApplicableIfResurrectsLessThanRequired)
 	EXPECT_CALL(mechanicsMock, getEffectValue()).Times(AtLeast(1)).WillRepeatedly(Return(999));
 	EXPECT_CALL(mechanicsMock, isSmart()).WillRepeatedly(Return(false));
 
-	unit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, 200, TBonusSourceID::NONE));
+	unit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, 200, TBonusSourceID()));
 	unitsFake.setDefaultBonusExpectations();
 
 	EffectTarget target;
@@ -271,7 +271,7 @@ TEST_F(HealTest, NotApplicableIfEffectValueTooLow)
 	EXPECT_CALL(unit, getTotalHealth()).WillOnce(Return(200));
 	EXPECT_CALL(unit, getAvailableHealth()).WillOnce(Return(100));
 
-	unit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, 200, TBonusSourceID::NONE));
+	unit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, 200, TBonusSourceID()));
 
 	EXPECT_CALL(mechanicsMock, getEffectValue()).Times(AtLeast(1)).WillRepeatedly(Return(199));
 
@@ -348,7 +348,7 @@ TEST_P(HealApplyTest, Heals)
 	EXPECT_CALL(targetUnit, unitId()).WillRepeatedly(Return(unitId));
 	EXPECT_CALL(targetUnit, unitType()).WillRepeatedly(Return(pikeman));
 
-	targetUnit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, unitHP, TBonusSourceID::NONE));
+	targetUnit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, unitHP, TBonusSourceID()));
 
 	unitsFake.setDefaultBonusExpectations();
 

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

@@ -179,13 +179,13 @@ TEST_F(SacrificeApplyTest, ResurrectsTarget)
 	EXPECT_CALL(mechanicsMock, applySpellBonus(_, Eq(&targetUnit))).WillOnce(ReturnArg<0>());
 	EXPECT_CALL(mechanicsMock, calculateRawEffectValue(_,_)).WillOnce(Return(effectValue));
 
-	targetUnit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, unitHP, TBonusSourceID::NONE));
+	targetUnit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, unitHP, TBonusSourceID()));
 
 	auto & victim = unitsFake.add(BattleSide::ATTACKER);
 	EXPECT_CALL(victim, unitId()).Times(AtLeast(1)).WillRepeatedly(Return(victimId));
 	EXPECT_CALL(victim, getCount()).Times(AtLeast(1)).WillRepeatedly(Return(victimCount));
 
-	victim.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, victimUnitHP, TBonusSourceID::NONE));
+	victim.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, victimUnitHP, TBonusSourceID()));
 
 	EXPECT_CALL(*battleFake, setUnitState(Eq(unitId), _, Eq(expectedHealValue))).Times(1);
 

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

@@ -244,12 +244,12 @@ TEST_P(SummonApplyTest, UpdatesOldUnit)
 	setDefaultExpectaions();
 
 	acquired = std::make_shared<battle::UnitFake>();
-	acquired->addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, unitHealth, TBonusSourceID::NONE));
+	acquired->addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, unitHealth, TBonusSourceID()));
 	acquired->redirectBonusesToFake();
 	acquired->expectAnyBonusSystemCall();
 
 	auto & unit = unitsFake.add(BattleSide::ATTACKER);
-	unit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, unitHealth, TBonusSourceID::NONE));
+	unit.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, unitHealth, TBonusSourceID()));
 
 	{
 		EXPECT_CALL(unit, acquire()).WillOnce(Return(acquired));

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

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

+ 4 - 4
test/spells/targetConditions/AbsoluteLevelConditionTest.cpp

@@ -54,7 +54,7 @@ TEST_F(AbsoluteLevelConditionTest, ReceptiveNormalSpell)
 {
 	setDefaultExpectations();
 
-	auto bonus = std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LEVEL_SPELL_IMMUNITY, BonusSource::OTHER, 3, TBonusSourceID::NONE);
+	auto bonus = std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LEVEL_SPELL_IMMUNITY, BonusSource::OTHER, 3, TBonusSourceID());
 	bonus->additionalInfo = 1;
 	unitBonuses.addNewBonus(bonus);
 
@@ -67,7 +67,7 @@ TEST_F(AbsoluteLevelConditionTest, ReceptiveAbility)
 {
 	setDefaultExpectations();
 
-	auto bonus = std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LEVEL_SPELL_IMMUNITY, BonusSource::OTHER, 5, TBonusSourceID::NONE);
+	auto bonus = std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LEVEL_SPELL_IMMUNITY, BonusSource::OTHER, 5, TBonusSourceID());
 	bonus->additionalInfo = 1;
 	unitBonuses.addNewBonus(bonus);
 
@@ -79,7 +79,7 @@ TEST_F(AbsoluteLevelConditionTest, ImmuneNormalSpell)
 {
 	setDefaultExpectations();
 
-	auto bonus = std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LEVEL_SPELL_IMMUNITY, BonusSource::OTHER, 4, TBonusSourceID::NONE);
+	auto bonus = std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LEVEL_SPELL_IMMUNITY, BonusSource::OTHER, 4, TBonusSourceID());
 	bonus->additionalInfo = 1;
 	unitBonuses.addNewBonus(bonus);
 
@@ -90,7 +90,7 @@ TEST_F(AbsoluteLevelConditionTest, ImmuneNormalSpell)
 TEST_F(AbsoluteLevelConditionTest, IgnoresNormalCase)
 {
 	setDefaultExpectations();
-	auto bonus = std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LEVEL_SPELL_IMMUNITY, BonusSource::OTHER, 4, TBonusSourceID::NONE);
+	auto bonus = std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LEVEL_SPELL_IMMUNITY, BonusSource::OTHER, 4, TBonusSourceID());
 	unitBonuses.addNewBonus(bonus);
 	EXPECT_TRUE(subject->isReceptive(&mechanicsMock, &unitMock));
 }

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

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

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

@@ -42,14 +42,14 @@ TEST_F(BonusConditionTest, ImmuneByDefault)
 TEST_F(BonusConditionTest, ReceptiveIfMatchesType)
 {
 	setDefaultExpectations();
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_DAMAGE_REDUCTION, BonusSource::OTHER, 100, TBonusSourceID::NONE));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_DAMAGE_REDUCTION, BonusSource::OTHER, 100, TBonusSourceID()));
 	EXPECT_TRUE(subject->isReceptive(&mechanicsMock, &unitMock));
 }
 
 TEST_F(BonusConditionTest, ImmuneIfTypeMismatch)
 {
 	setDefaultExpectations();
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::OTHER, 0, TBonusSourceID(SpellSchool::FIRE)));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::OTHER, 0, TBonusSourceID(), TBonusSubtype(SpellSchool::FIRE)));
 	EXPECT_FALSE(subject->isReceptive(&mechanicsMock, &unitMock));
 }
 

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

@@ -56,7 +56,7 @@ TEST_P(ElementalConditionTest, ReceptiveIfNoBonus)
 TEST_P(ElementalConditionTest, ImmuneIfBonusMatches)
 {
 	setDefaultExpectations();
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::SPELL_EFFECT, 0, TBonusSourceID::NONE, TBonusSubtype(SpellSchool::AIR)));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::SPELL_EFFECT, 0, TBonusSourceID(), TBonusSubtype(SpellSchool::AIR)));
 
 	EXPECT_FALSE(subject->isReceptive(&mechanicsMock, &unitMock));
 }
@@ -64,7 +64,7 @@ TEST_P(ElementalConditionTest, ImmuneIfBonusMatches)
 TEST_P(ElementalConditionTest, NotImmuneIfBonusMismatches)
 {
 	setDefaultExpectations();
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::SPELL_EFFECT, 0, TBonusSourceID::NONE, TBonusSubtype(SpellSchool::WATER)));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::SPELL_EFFECT, 0, TBonusSourceID(), TBonusSubtype(SpellSchool::WATER)));
 
 	EXPECT_TRUE(subject->isReceptive(&mechanicsMock, &unitMock));
 }
@@ -72,7 +72,7 @@ TEST_P(ElementalConditionTest, NotImmuneIfBonusMismatches)
 TEST_P(ElementalConditionTest, DependsOnPositivness)
 {
 	setDefaultExpectations();
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATIVE_EFFECTS_IMMUNITY, BonusSource::SPELL_EFFECT, 0, TBonusSourceID::NONE, TBonusSubtype(SpellSchool::AIR)));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATIVE_EFFECTS_IMMUNITY, BonusSource::SPELL_EFFECT, 0, TBonusSourceID(), TBonusSubtype(SpellSchool::AIR)));
 
 	EXPECT_EQ(isPositive, subject->isReceptive(&mechanicsMock, &unitMock));
 }
@@ -80,8 +80,8 @@ TEST_P(ElementalConditionTest, DependsOnPositivness)
 TEST_P(ElementalConditionTest, ImmuneIfBothBonusesPresent)
 {
 	setDefaultExpectations();
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::SPELL_EFFECT, 0, TBonusSourceID::NONE, TBonusSubtype(SpellSchool::AIR)));
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATIVE_EFFECTS_IMMUNITY, BonusSource::SPELL_EFFECT, 0, TBonusSourceID::NONE, TBonusSubtype(SpellSchool::AIR)));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::SPELL_SCHOOL_IMMUNITY, BonusSource::SPELL_EFFECT, 0, TBonusSourceID(), TBonusSubtype(SpellSchool::AIR)));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATIVE_EFFECTS_IMMUNITY, BonusSource::SPELL_EFFECT, 0, TBonusSourceID(), TBonusSubtype(SpellSchool::AIR)));
 
 	EXPECT_FALSE(subject->isReceptive(&mechanicsMock, &unitMock));
 }

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

@@ -10,7 +10,6 @@
 #include "StdInc.h"
 
 #include "TargetConditionItemFixture.h"
-#include "../../../lib/bonuses/BonusSubtypes.h"
 
 //FIXME: Orb of vulnerability mechanics is not such trivial (mantis issue 1791)
 //TODO: NEGATE_ALL_NATURAL_IMMUNITIES special cases: dispel, chain lightning
@@ -58,7 +57,7 @@ TEST_P(ImmunityNegationConditionTest, WithHeroNegation)
 {
 	setDefaultExpectations();
 
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, BonusSource::OTHER, 0, TBonusSourceID::NONE, BonusSubtypes::immunityEnemyHero));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, BonusSource::OTHER, 0, TBonusSourceID(), BonusSubtypeID::immunityEnemyHero));
 
 	EXPECT_EQ(isMagicalEffect, subject->isReceptive(&mechanicsMock, &unitMock));
 }
@@ -67,7 +66,7 @@ TEST_P(ImmunityNegationConditionTest, WithBattleWideNegation)
 {
 	setDefaultExpectations();
 
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, BonusSource::OTHER, 0, TBonusSourceID::NONE, BonusSubtypes::immunityBattleWide));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, BonusSource::OTHER, 0, TBonusSourceID(), BonusSubtypeID::immunityBattleWide));
 
 	//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));

+ 3 - 3
test/spells/targetConditions/NormalLevelConditionTest.cpp

@@ -56,7 +56,7 @@ TEST_P(NormalLevelConditionTest, DefaultForNormal)
 TEST_P(NormalLevelConditionTest, ReceptiveNormal)
 {
 	setDefaultExpectations();
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LEVEL_SPELL_IMMUNITY, BonusSource::OTHER, 3, TBonusSourceID::NONE));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LEVEL_SPELL_IMMUNITY, BonusSource::OTHER, 3, TBonusSourceID()));
 	if(isMagicalEffect)
 		EXPECT_CALL(mechanicsMock, getSpellLevel()).Times(AtLeast(1)).WillRepeatedly(Return(4));
 	EXPECT_TRUE(subject->isReceptive(&mechanicsMock, &unitMock));
@@ -66,7 +66,7 @@ TEST_P(NormalLevelConditionTest, ReceptiveNormal)
 TEST_P(NormalLevelConditionTest, ReceptiveAbility)
 {
 	setDefaultExpectations();
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LEVEL_SPELL_IMMUNITY, BonusSource::OTHER, 5, TBonusSourceID::NONE));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LEVEL_SPELL_IMMUNITY, BonusSource::OTHER, 5, TBonusSourceID()));
 	if(isMagicalEffect)
 		EXPECT_CALL(mechanicsMock, getSpellLevel()).Times(AtLeast(1)).WillRepeatedly(Return(0));
 	EXPECT_TRUE(subject->isReceptive(&mechanicsMock, &unitMock));
@@ -75,7 +75,7 @@ TEST_P(NormalLevelConditionTest, ReceptiveAbility)
 TEST_P(NormalLevelConditionTest, ImmuneNormal)
 {
 	setDefaultExpectations();
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LEVEL_SPELL_IMMUNITY, BonusSource::OTHER, 4, TBonusSourceID::NONE));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::LEVEL_SPELL_IMMUNITY, BonusSource::OTHER, 4, TBonusSourceID()));
 	if(isMagicalEffect)
 		EXPECT_CALL(mechanicsMock, getSpellLevel()).Times(AtLeast(1)).WillRepeatedly(Return(2));
 	EXPECT_EQ(!isMagicalEffect, subject->isReceptive(&mechanicsMock, &unitMock));

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

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

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

@@ -31,7 +31,7 @@ public:
 		EXPECT_CALL(unitMock, getTreeVersion()).Times(AtLeast(0));
 		EXPECT_CALL(mechanicsMock, isPositiveSpell()).WillRepeatedly(Return(isPositive));
 		if(hasBonus)
-			unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::RECEPTIVE, BonusSource::OTHER, 0, TBonusSourceID::NONE));
+			unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::RECEPTIVE, BonusSource::OTHER, 0, TBonusSourceID()));
 	}
 
 protected:

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

@@ -60,7 +60,7 @@ TEST_F(SpellEffectConditionTest, ImmuneIfHasEffectFromOtherSpell)
 TEST_F(SpellEffectConditionTest, ImmuneIfHasNoSpellEffects)
 {
 	setDefaultExpectations();
-	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, 3, TBonusSourceID::NONE));
+	unitBonuses.addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, 3, TBonusSourceID()));
 	EXPECT_FALSE(subject->isReceptive(&mechanicsMock, &unitMock));
 }