Ver Fonte

vcmi: massive refactoring v1

Konstantin há 2 anos atrás
pai
commit
11b237a23c
100 ficheiros alterados com 642 adições e 597 exclusões
  1. 1 1
      AI/BattleAI/BattleAI.cpp
  2. 1 1
      AI/BattleAI/StackWithBonuses.cpp
  3. 6 6
      AI/Nullkiller/AIGateway.cpp
  4. 7 5
      AI/Nullkiller/AIUtility.cpp
  5. 1 1
      AI/Nullkiller/AIUtility.h
  6. 20 19
      AI/Nullkiller/Analyzers/ArmyManager.cpp
  7. 11 11
      AI/Nullkiller/Analyzers/BuildAnalyzer.cpp
  8. 1 1
      AI/Nullkiller/Behaviors/BuildingBehavior.cpp
  9. 1 1
      AI/Nullkiller/Behaviors/DefenceBehavior.cpp
  10. 1 1
      AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp
  11. 1 1
      AI/Nullkiller/Behaviors/StartupBehavior.cpp
  12. 4 4
      AI/Nullkiller/Engine/FuzzyEngines.cpp
  13. 1 1
      AI/Nullkiller/Engine/Nullkiller.h
  14. 21 20
      AI/Nullkiller/Engine/PriorityEvaluator.cpp
  15. 2 2
      AI/Nullkiller/Goals/BuyArmy.cpp
  16. 1 1
      AI/Nullkiller/Goals/CompleteQuest.cpp
  17. 1 1
      AI/Nullkiller/Goals/GatherArmy.cpp
  18. 2 2
      AI/Nullkiller/Goals/Trade.h
  19. 1 1
      AI/Nullkiller/Markers/ArmyUpgrade.cpp
  20. 6 6
      AI/Nullkiller/Pathfinding/Actors.cpp
  21. 1 1
      AI/StupidAI/StupidAI.cpp
  22. 2 2
      AI/VCAI/AIUtility.cpp
  23. 1 1
      AI/VCAI/AIUtility.h
  24. 8 7
      AI/VCAI/ArmyManager.cpp
  25. 4 4
      AI/VCAI/FuzzyEngines.cpp
  26. 1 1
      AI/VCAI/Goals/BuyArmy.cpp
  27. 11 11
      AI/VCAI/Goals/CollectRes.cpp
  28. 2 2
      AI/VCAI/Goals/CollectRes.h
  29. 2 2
      AI/VCAI/Goals/CompleteQuest.cpp
  30. 1 1
      AI/VCAI/Goals/GatherArmy.cpp
  31. 8 8
      AI/VCAI/Goals/GatherTroops.cpp
  32. 1 1
      AI/VCAI/Goals/RecruitHero.cpp
  33. 2 2
      AI/VCAI/Goals/Trade.h
  34. 1 1
      AI/VCAI/Goals/Win.cpp
  35. 2 2
      AI/VCAI/MapObjectsEvaluator.cpp
  36. 16 16
      AI/VCAI/ResourceManager.cpp
  37. 11 11
      AI/VCAI/VCAI.cpp
  38. 1 1
      Global.h
  39. 1 1
      client/Client.h
  40. 1 1
      client/adventureMap/CResDataBar.cpp
  41. 1 1
      client/battle/BattleAnimationClasses.cpp
  42. 2 2
      client/battle/BattleInterfaceClasses.cpp
  43. 1 1
      client/battle/BattleProjectileController.cpp
  44. 1 1
      client/battle/BattleStacksController.cpp
  45. 1 1
      client/battle/BattleWindow.cpp
  46. 22 22
      client/lobby/OptionsTab.cpp
  47. 1 1
      client/widgets/CreatureCostBox.h
  48. 6 6
      client/widgets/MiscWidgets.cpp
  49. 8 7
      client/windows/CCastleInterface.cpp
  50. 2 2
      client/windows/CCreatureWindow.cpp
  51. 6 6
      client/windows/CKingdomInterface.cpp
  52. 6 6
      client/windows/CTradeWindow.cpp
  53. 4 4
      client/windows/CreaturePurchaseCard.cpp
  54. 18 18
      client/windows/GUIClasses.cpp
  55. 4 4
      client/windows/QuickRecruitmentWindow.cpp
  56. 6 1
      include/vcmi/Creature.h
  57. 7 3
      include/vcmi/Entity.h
  58. 1 1
      lib/CArtHandler.cpp
  59. 1 1
      lib/CArtHandler.h
  60. 20 10
      lib/CCreatureHandler.cpp
  61. 15 9
      lib/CCreatureHandler.h
  62. 9 9
      lib/CCreatureSet.cpp
  63. 2 2
      lib/CCreatureSet.h
  64. 6 6
      lib/CGameInfoCallback.cpp
  65. 4 4
      lib/CGameInfoCallback.h
  66. 33 29
      lib/CGameState.cpp
  67. 1 1
      lib/CGameStateFwd.h
  68. 1 1
      lib/CHeroHandler.cpp
  69. 1 1
      lib/CPlayerState.cpp
  70. 1 1
      lib/CPlayerState.h
  71. 2 2
      lib/CStack.cpp
  72. 13 12
      lib/CTownHandler.cpp
  73. 1 1
      lib/CTownHandler.h
  74. 10 0
      lib/GameConstants.h
  75. 3 3
      lib/HeroBonus.cpp
  76. 1 1
      lib/IGameCallback.h
  77. 2 2
      lib/NetPacksLib.cpp
  78. 37 37
      lib/ResourceSet.cpp
  79. 160 162
      lib/ResourceSet.h
  80. 1 1
      lib/battle/BattleInfo.cpp
  81. 1 1
      lib/battle/BattleInfo.h
  82. 2 2
      lib/battle/BattleProxy.cpp
  83. 1 1
      lib/battle/BattleProxy.h
  84. 1 1
      lib/battle/BattleStateInfoForRetreat.cpp
  85. 2 2
      lib/battle/CBattleInfoCallback.cpp
  86. 2 2
      lib/battle/CBattleInfoEssentials.cpp
  87. 1 1
      lib/battle/CBattleInfoEssentials.h
  88. 4 4
      lib/battle/CUnitState.cpp
  89. 1 1
      lib/battle/DamageCalculator.cpp
  90. 3 1
      lib/battle/IBattleInfoCallback.h
  91. 1 3
      lib/battle/IBattleState.h
  92. 1 1
      lib/mapObjects/CArmedInstance.cpp
  93. 4 4
      lib/mapObjects/CBank.cpp
  94. 5 5
      lib/mapObjects/CGHeroInstance.cpp
  95. 2 2
      lib/mapObjects/CGMarket.cpp
  96. 15 15
      lib/mapObjects/CGTownInstance.cpp
  97. 2 2
      lib/mapObjects/CObjectHandler.cpp
  98. 3 3
      lib/mapObjects/CQuest.cpp
  99. 2 1
      lib/mapObjects/CQuest.h
  100. 1 1
      lib/mapObjects/CRewardableObject.cpp

+ 1 - 1
AI/BattleAI/BattleAI.cpp

@@ -101,7 +101,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
 
 	try
 	{
-		if(stack->type->idNumber == CreatureID::CATAPULT)
+		if(stack->type->getId() == CreatureID::CATAPULT)
 			return useCatapult(stack);
 		if(stack->hasBonusOfType(Bonus::SIEGE_WEAPON) && stack->hasBonusOfType(Bonus::HEALER))
 		{

+ 1 - 1
AI/BattleAI/StackWithBonuses.cpp

@@ -435,7 +435,7 @@ int64_t HypotheticBattle::getActualDamage(const DamageRange & damage, int32_t at
 
 int64_t HypotheticBattle::getTreeVersion() const
 {
-	return getBattleNode()->getTreeVersion() + bonusTreeVersion;
+	return getBonusBearer()->getTreeVersion() + bonusTreeVersion;
 }
 
 #if SCRIPTING_ENABLED

+ 6 - 6
AI/Nullkiller/AIGateway.cpp

@@ -1053,7 +1053,7 @@ void AIGateway::recruitCreatures(const CGDwelling * d, const CArmedInstance * re
 		int count = d->creatures[i].first;
 		CreatureID creID = d->creatures[i].second.back();
 
-		vstd::amin(count, cb->getResourceAmount() / VLC->creh->objects[creID]->cost);
+		vstd::amin(count, cb->getResourceAmount() / creID.toCreature()->getFullRecruitCost());
 		if(count > 0)
 			cb->recruitCreatures(d, recruiter, creID, count, i);
 	}
@@ -1068,7 +1068,7 @@ bool AIGateway::canRecruitAnyHero(const CGTownInstance * t) const
 	if(!t || !townHasFreeTavern(t))
 		return false;
 
-	if(cb->getResourceAmount(Res::GOLD) < GameConstants::HERO_GOLD_COST) //TODO: use ResourceManager
+	if(cb->getResourceAmount(EGameResID::GOLD) < GameConstants::HERO_GOLD_COST) //TODO: use ResourceManager
 		return false;
 	if(cb->getHeroesInfo().size() >= ALLOWED_ROAMING_HEROES)
 		return false;
@@ -1390,7 +1390,7 @@ void AIGateway::tryRealize(Goals::DigAtTile & g)
 
 void AIGateway::tryRealize(Goals::Trade & g) //trade
 {
-	if(cb->getResourceAmount((Res::ERes)g.resID) >= g.value) //goal is already fulfilled. Why we need this check, anyway?
+	if(cb->getResourceAmount(GameResID(g.resID)) >= g.value) //goal is already fulfilled. Why we need this check, anyway?
 		throw goalFulfilledException(sptr(g));
 
 	int accquiredResources = 0;
@@ -1399,10 +1399,10 @@ void AIGateway::tryRealize(Goals::Trade & g) //trade
 		if(const IMarket * m = IMarket::castFrom(obj, false))
 		{
 			auto freeRes = cb->getResourceAmount(); //trade only resources which are not reserved
-			for(auto it = Res::ResourceSet::nziterator(freeRes); it.valid(); it++)
+			for(auto it = ResourceSet::nziterator(freeRes); it.valid(); it++)
 			{
 				auto res = it->resType;
-				if(res == g.resID) //sell any other resource
+				if(res.getNum() == g.resID) //sell any other resource
 					continue;
 
 				int toGive, toGet;
@@ -1415,7 +1415,7 @@ void AIGateway::tryRealize(Goals::Trade & g) //trade
 					accquiredResources = static_cast<int>(toGet * (it->resVal / toGive));
 					logAi->debug("Traded %d of %s for %d of %s at %s", toGive, res, accquiredResources, g.resID, obj->getObjectName());
 				}
-				if (cb->getResourceAmount((Res::ERes)g.resID) >= g.value)
+				if (cb->getResourceAmount(GameResID(g.resID)))
 					throw goalFulfilledException(sptr(g)); //we traded all we needed
 			}
 

+ 7 - 5
AI/Nullkiller/AIUtility.cpp

@@ -20,6 +20,8 @@
 
 #include "../../lib/GameSettings.h"
 
+#include <vcmi/CreatureService.h>
+
 namespace NKAI
 {
 
@@ -278,8 +280,8 @@ creInfo infoFromDC(const dwellingContent & dc)
 	ci.creID = dc.second.size() ? dc.second.back() : CreatureID(-1); //should never be accessed
 	if (ci.creID != -1)
 	{
-		ci.cre = VLC->creh->objects[ci.creID].get();
-		ci.level = ci.cre->level; //this is cretaure tier, while tryRealize expects dwelling level. Ignore.
+		ci.cre = VLC->creatures()->getById(ci.creID);
+		ci.level = ci.cre->getLevel(); //this is creature tier, while tryRealize expects dwelling level. Ignore.
 	}
 	else
 	{
@@ -398,7 +400,7 @@ bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObject
 			{
 				if(level.first
 					&& h->getSlotFor(CreatureID(c)) != SlotID()
-					&& ai->cb->getResourceAmount().canAfford(c.toCreature()->cost))
+					&& ai->cb->getResourceAmount().canAfford(c.toCreature()->getFullRecruitCost()))
 				{
 					return true;
 				}
@@ -411,7 +413,7 @@ bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObject
 	{
 		for(auto slot : h->Slots())
 		{
-			if(slot.second->type->upgrades.size())
+			if(slot.second->type->hasUpgrades())
 				return true; //TODO: check price?
 		}
 		return false;
@@ -438,7 +440,7 @@ bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObject
 			return false;
 
 		TResources myRes = ai->getFreeResources();
-		if(myRes[Res::GOLD] < 2000 || myRes[Res::GEMS] < 10)
+		if(myRes[EGameResID::GOLD] < 2000 || myRes[EGameResID::GEMS] < 10)
 			return false;
 		break;
 	}

+ 1 - 1
AI/Nullkiller/AIUtility.h

@@ -161,7 +161,7 @@ struct creInfo
 {
 	int count;
 	CreatureID creID;
-	CCreature * cre;
+	const Creature * cre;
 	int level;
 };
 creInfo infoFromDC(const dwellingContent & dc);

+ 20 - 19
AI/Nullkiller/Analyzers/ArmyManager.cpp

@@ -28,8 +28,8 @@ public:
 	StackUpgradeInfo(CreatureID initial, CreatureID upgraded, int count)
 		:initialCreature(initial), upgradedCreature(upgraded), count(count)
 	{
-		cost = (upgradedCreature.toCreature()->cost - initialCreature.toCreature()->cost) * count;
-		upgradeValue = (upgradedCreature.toCreature()->AIValue - initialCreature.toCreature()->AIValue) * count;
+		cost = (upgradedCreature.toCreature()->getFullRecruitCost() - initialCreature.toCreature()->getFullRecruitCost()) * count;
+		upgradeValue = (upgradedCreature.toCreature()->getAIValue() - initialCreature.toCreature()->getAIValue()) * count;
 	}
 };
 
@@ -50,9 +50,10 @@ std::vector<SlotInfo> ArmyManager::getSortedSlots(const CCreatureSet * target, c
 	{
 		for(auto & i : armyPtr->Slots())
 		{
-			auto & slotInfp = creToPower[i.second->type];
+			auto cre = dynamic_cast<const CCreature*>(i.second->type);
+			auto & slotInfp = creToPower[cre];
 
-			slotInfp.creature = i.second->type;
+			slotInfp.creature = cre;
 			slotInfp.power += i.second->getPower();
 			slotInfp.count += i.second->count;
 		}
@@ -73,8 +74,8 @@ std::vector<SlotInfo>::iterator ArmyManager::getWeakestCreature(std::vector<Slot
 {
 	auto weakest = boost::min_element(army, [](const SlotInfo & left, const SlotInfo & right) -> bool
 	{
-		if(left.creature->level != right.creature->level)
-			return left.creature->level < right.creature->level;
+		if(left.creature->getLevel() != right.creature->getLevel())
+			return left.creature->getLevel() < right.creature->getLevel();
 		
 		return left.creature->Speed() > right.creature->Speed();
 	});
@@ -99,7 +100,7 @@ std::vector<SlotInfo> ArmyManager::getBestArmy(const IBonusBearer * armyCarrier,
 
 	for(auto & slot : sortedSlots)
 	{
-		alignmentMap[slot.creature->faction] += slot.power;
+		alignmentMap[slot.creature->getFactionIndex()] += slot.power;
 	}
 
 	std::set<TFaction> allowedFactions;
@@ -133,13 +134,13 @@ std::vector<SlotInfo> ArmyManager::getBestArmy(const IBonusBearer * armyCarrier,
 
 		for(auto & slot : sortedSlots)
 		{
-			if(vstd::contains(allowedFactions, slot.creature->faction))
+			if(vstd::contains(allowedFactions, slot.creature->getFactionIndex()))
 			{
 				auto slotID = newArmyInstance.getSlotFor(slot.creature);
 
 				if(slotID.validSlot())
 				{
-					newArmyInstance.setCreature(slotID, slot.creature->idNumber, slot.count);
+					newArmyInstance.setCreature(slotID, slot.creature->getId(), slot.count);
 					newArmy.push_back(slot);
 				}
 			}
@@ -217,7 +218,7 @@ std::shared_ptr<CCreatureSet> ArmyManager::getArmyAvailableToBuyAsCCreatureSet(
 		if(!ci.count || ci.creID == -1)
 			continue;
 
-		vstd::amin(ci.count, availableRes / ci.cre->cost); //max count we can afford
+		vstd::amin(ci.count, availableRes / ci.cre->getFullRecruitCost()); //max count we can afford
 
 		if(!ci.count)
 			continue;
@@ -228,7 +229,7 @@ std::shared_ptr<CCreatureSet> ArmyManager::getArmyAvailableToBuyAsCCreatureSet(
 			break;
 
 		army->setCreature(dst, ci.creID, ci.count);
-		availableRes -= ci.cre->cost * ci.count;
+		availableRes -= ci.cre->getFullRecruitCost() * ci.count;
 	}
 
 	return army;
@@ -244,7 +245,7 @@ ui64 ArmyManager::howManyReinforcementsCanBuy(
 
 	for(const creInfo & ci : army)
 	{
-		aivalue += ci.count * ci.cre->AIValue;
+		aivalue += ci.count * ci.cre->getAIValue();
 	}
 
 	return aivalue;
@@ -279,14 +280,14 @@ std::vector<creInfo> ArmyManager::getArmyAvailableToBuy(
 				freeHeroSlots--; //new slot will be occupied
 		}
 
-		vstd::amin(ci.count, availableRes / ci.cre->cost); //max count we can afford
+		vstd::amin(ci.count, availableRes / ci.cre->getFullRecruitCost()); //max count we can afford
 
 		if(!ci.count)
 			continue;
 
 		ci.level = i; //this is important for Dungeon Summoning Portal
 		creaturesInDwellings.push_back(ci);
-		availableRes -= ci.cre->cost * ci.count;
+		availableRes -= ci.cre->getFullRecruitCost() * ci.count;
 	}
 
 	return creaturesInDwellings;
@@ -308,7 +309,7 @@ ui64 ArmyManager::howManyReinforcementsCanGet(const IBonusBearer * armyCarrier,
 
 uint64_t ArmyManager::evaluateStackPower(const CCreature * creature, int count) const
 {
-	return creature->AIValue * count;
+	return creature->getAIValue() * count;
 }
 
 SlotInfo ArmyManager::getTotalCreaturesAvailable(CreatureID creatureID) const
@@ -378,12 +379,12 @@ std::vector<StackUpgradeInfo> ArmyManager::getHillFortUpgrades(const CCreatureSe
 
 		CreatureID strongestUpgrade = *vstd::minElementByFun(possibleUpgrades, [](CreatureID cre) -> uint64_t
 		{
-			return cre.toCreature()->AIValue;
+			return cre.toCreature()->getAIValue();
 		});
 
 		StackUpgradeInfo upgrade = StackUpgradeInfo(initial, strongestUpgrade, creature.second->count);
 
-		if(initial.toCreature()->level == 1)
+		if(initial.toCreature()->getLevel() == 1)
 			upgrade.cost = TResources();
 
 		upgrades.push_back(upgrade);
@@ -417,7 +418,7 @@ std::vector<StackUpgradeInfo> ArmyManager::getDwellingUpgrades(const CCreatureSe
 
 		CreatureID strongestUpgrade = *vstd::minElementByFun(possibleUpgrades, [](CreatureID cre) -> uint64_t
 		{
-			return cre.toCreature()->AIValue;
+			return cre.toCreature()->getAIValue();
 		});
 
 		StackUpgradeInfo upgrade = StackUpgradeInfo(initial, strongestUpgrade, creature.second->count);
@@ -488,7 +489,7 @@ ArmyUpgradeInfo ArmyManager::calculateCreaturesUpgrade(
 			upgradedArmy.power = evaluateStackPower(upgradedArmy.creature, upgradedArmy.count);
 
 			auto slotToReplace = std::find_if(result.resultingArmy.begin(), result.resultingArmy.end(), [&](const SlotInfo & slot) -> bool {
-				return slot.count == upgradedArmy.count && slot.creature->idNumber == upgrade.initialCreature;
+				return slot.count == upgradedArmy.count && slot.creature->getId() == upgrade.initialCreature;
 			});
 
 			resourcesLeft -= upgrade.cost;

+ 11 - 11
AI/Nullkiller/Analyzers/BuildAnalyzer.cpp

@@ -93,9 +93,9 @@ void BuildAnalyzer::updateOtherBuildings(TownDevelopmentInfo & developmentInfo)
 
 int32_t convertToGold(const TResources & res)
 {
-	return res[Res::GOLD] 
-		+ 75 * (res[Res::WOOD] + res[Res::ORE]) 
-		+ 125 * (res[Res::GEMS] + res[Res::CRYSTAL] + res[Res::MERCURY] + res[Res::SULFUR]);
+	return res[EGameResID::GOLD] 
+		+ 75 * (res[EGameResID::WOOD] + res[EGameResID::ORE]) 
+		+ 125 * (res[EGameResID::GEMS] + res[EGameResID::CRYSTAL] + res[EGameResID::MERCURY] + res[EGameResID::SULFUR]);
 }
 
 TResources BuildAnalyzer::getResourcesRequiredNow() const
@@ -164,8 +164,8 @@ void BuildAnalyzer::update()
 	}
 	else
 	{
-		goldPreasure = ai->getLockedResources()[Res::GOLD] / 10000.0f
-			+ (float)armyCost[Res::GOLD] / (1 + ai->getFreeGold() + (float)dailyIncome[Res::GOLD] * 7.0f);
+		goldPreasure = ai->getLockedResources()[EGameResID::GOLD] / 10000.0f
+			+ (float)armyCost[EGameResID::GOLD] / (1 + ai->getFreeGold() + (float)dailyIncome[EGameResID::GOLD] * 7.0f);
 	}
 
 	logAi->trace("Gold preasure: %f", goldPreasure);
@@ -280,7 +280,7 @@ void BuildAnalyzer::updateDailyIncome()
 
 		if(mine)
 		{
-			dailyIncome[mine->producedResource] += mine->producedQuantity;
+			dailyIncome[mine->producedResource.getNum()] += mine->producedQuantity;
 		}
 	}
 
@@ -355,10 +355,10 @@ BuildingInfo::BuildingInfo(
 
 	if(creature)
 	{
-		creatureGrows = creature->growth;
-		creatureID = creature->idNumber;
-		creatureCost = creature->cost;
-		creatureLevel = creature->level;
+		creatureGrows = creature->getGrowth();
+		creatureID = creature->getId();
+		creatureCost = creature->getFullRecruitCost();
+		creatureLevel = creature->getLevel();
 		baseCreatureID = baseCreature;
 
 		if(exists)
@@ -367,7 +367,7 @@ BuildingInfo::BuildingInfo(
 		}
 		else
 		{
-			creatureGrows = creature->growth;
+			creatureGrows = creature->getGrowth();
 
 			if(town->hasBuilt(BuildingID::CASTLE))
 				creatureGrows *= 2;

+ 1 - 1
AI/Nullkiller/Behaviors/BuildingBehavior.cpp

@@ -58,7 +58,7 @@ Goals::TGoalVec BuildingBehavior::decompose() const
 	{
 		for(auto & buildingInfo : developmentInfo.toBuild)
 		{
-			if(goldPreasure < MAX_GOLD_PEASURE || buildingInfo.dailyIncome[Res::GOLD] > 0)
+			if(goldPreasure < MAX_GOLD_PEASURE || buildingInfo.dailyIncome[EGameResID::GOLD] > 0)
 			{
 				if(buildingInfo.notEnoughRes)
 				{

+ 1 - 1
AI/Nullkiller/Behaviors/DefenceBehavior.cpp

@@ -162,7 +162,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
 
 		if(!town->visitingHero
 			&& town->hasBuilt(BuildingID::TAVERN)
-			&& cb->getResourceAmount(Res::GOLD) > GameConstants::HERO_GOLD_COST)
+			&& cb->getResourceAmount(EGameResID::GOLD) > GameConstants::HERO_GOLD_COST)
 		{
 			auto heroesInTavern = cb->getAvailableHeroes(town);
 

+ 1 - 1
AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp

@@ -69,7 +69,7 @@ Goals::TGoalVec RecruitHeroBehavior::decompose() const
 			}
 
 			if(cb->getHeroesInfo().size() < cb->getTownsInfo().size() + 1
-				|| (ai->nullkiller->getFreeResources()[Res::GOLD] > 10000
+				|| (ai->nullkiller->getFreeResources()[EGameResID::GOLD] > 10000
 					&& ai->nullkiller->buildAnalyzer->getGoldPreasure() < MAX_GOLD_PEASURE))
 			{
 				tasks.push_back(Goals::sptr(Goals::RecruitHero(town).setpriority(3)));

+ 1 - 1
AI/Nullkiller/Behaviors/StartupBehavior.cpp

@@ -76,7 +76,7 @@ bool needToRecruitHero(const CGTownInstance * startupTown)
 
 	for(auto obj : ai->nullkiller->objectClusterizer->getNearbyObjects())
 	{
-		if((obj->ID == Obj::RESOURCE && obj->subID == Res::GOLD)
+		if((obj->ID == Obj::RESOURCE && obj->subID == GameResID(EGameResID::GOLD))
 			|| obj->ID == Obj::TREASURE_CHEST
 			|| obj->ID == Obj::CAMPFIRE
 			|| obj->ID == Obj::WATER_WHEEL)

+ 4 - 4
AI/Nullkiller/Engine/FuzzyEngines.cpp

@@ -65,13 +65,13 @@ armyStructure evaluateArmyStructure(const CArmedInstance * army)
 	for(auto s : army->Slots())
 	{
 		bool walker = true;
-		const CCreature * creature = s.second->type;
-		if(creature->hasBonus(selectorSHOOTER, keySHOOTER))
+		auto bearer = s.second->getType()->getBonusBearer();
+		if(bearer->hasBonus(selectorSHOOTER, keySHOOTER))
 		{
 			shootersStrength += s.second->getPower();
 			walker = false;
 		}
-		if(creature->hasBonus(selectorFLYING, keyFLYING))
+		if(bearer->hasBonus(selectorFLYING, keyFLYING))
 		{
 			flyersStrength += s.second->getPower();
 			walker = false;
@@ -79,7 +79,7 @@ armyStructure evaluateArmyStructure(const CArmedInstance * army)
 		if(walker)
 			walkersStrength += s.second->getPower();
 
-		vstd::amax(maxSpeed, creature->valOfBonuses(selectorSTACKS_SPEED, keySTACKS_SPEED));
+		vstd::amax(maxSpeed, bearer->valOfBonuses(selectorSTACKS_SPEED, keySTACKS_SPEED));
 	}
 	armyStructure as;
 	as.walkers = static_cast<float>(walkersStrength / totalStrength);

+ 1 - 1
AI/Nullkiller/Engine/Nullkiller.h

@@ -85,7 +85,7 @@ public:
 	void unlockHero(const CGHeroInstance * hero) { lockedHeroes.erase(hero); }
 	bool arePathHeroesLocked(const AIPath & path) const;
 	TResources getFreeResources() const;
-	int32_t getFreeGold() const { return getFreeResources()[Res::GOLD]; }
+	int32_t getFreeGold() const { return getFreeResources()[EGameResID::GOLD]; }
 	void lockResources(const TResources & res);
 	const TResources & getLockedResources() const { return lockedResources; }
 

+ 21 - 20
AI/Nullkiller/Engine/PriorityEvaluator.cpp

@@ -148,14 +148,15 @@ uint64_t getCreatureBankArmyReward(const CGObjectInstance * target, const CGHero
 	for (auto c : creatures)
 	{
 		//Only if hero has slot for this creature in the army
-		if (hero->getSlotFor(c.data.type).validSlot())
+		auto ccre = dynamic_cast<const CCreature*>(c.data.type);
+		if (hero->getSlotFor(ccre).validSlot())
 		{
-			result += (c.data.type->AIValue * c.data.count) * c.chance;
+			result += (c.data.type->getAIValue() * c.data.count) * c.chance;
 		}
 		else
 		{
 			//we will need to discard the weakest stack
-			result += (c.data.type->AIValue * c.data.count - weakestStackPower) * c.chance;
+			result += (c.data.type->getAIValue() * c.data.count - weakestStackPower) * c.chance;
 		}
 	}
 	result /= 100; //divide by total chance
@@ -173,11 +174,11 @@ uint64_t getDwellingScore(CCallback * cb, const CGObjectInstance * target, bool
 		if(creLevel.first && creLevel.second.size())
 		{
 			auto creature = creLevel.second.back().toCreature();
-			auto creaturesAreFree = creature->level == 1;
-			if(!creaturesAreFree && checkGold && !cb->getResourceAmount().canAfford(creature->cost * creLevel.first))
+			auto creaturesAreFree = creature->getLevel() == 1;
+			if(!creaturesAreFree && checkGold && !cb->getResourceAmount().canAfford(creature->getFullRecruitCost() * creLevel.first))
 				continue;
 
-			score += creature->AIValue * creLevel.first;
+			score += creature->getAIValue() * creLevel.first;
 		}
 	}
 
@@ -194,9 +195,9 @@ int getDwellingArmyCost(const CGObjectInstance * target)
 		if(creLevel.first && creLevel.second.size())
 		{
 			auto creature = creLevel.second.back().toCreature();
-			auto creaturesAreFree = creature->level == 1;
+			auto creaturesAreFree = creature->getLevel() == 1;
 			if(!creaturesAreFree)
-				cost += creature->cost[Res::GOLD] * creLevel.first;
+				cost += creature->getRecruitCost(EGameResID::GOLD) * creLevel.first;
 		}
 	}
 
@@ -300,7 +301,7 @@ int RewardEvaluator::getGoldCost(const CGObjectInstance * target, const CGHeroIn
 	switch(target->ID)
 	{
 	case Obj::HILL_FORT:
-		return ai->armyManager->calculateCreaturesUpgrade(army, target, ai->cb->getResourceAmount()).upgradeCost[Res::GOLD];
+		return ai->armyManager->calculateCreaturesUpgrade(army, target, ai->cb->getResourceAmount()).upgradeCost[EGameResID::GOLD];
 	case Obj::SCHOOL_OF_MAGIC:
 	case Obj::SCHOOL_OF_WAR:
 		return 1000;
@@ -375,12 +376,12 @@ float RewardEvaluator::getStrategicalValue(const CGObjectInstance * target) cons
 	switch(target->ID)
 	{
 	case Obj::MINE:
-		return target->subID == Res::GOLD 
+		return target->subID == GameResID(EGameResID::GOLD)
 			? 0.5f 
 			: 0.4f * getTotalResourceRequirementStrength(target->subID) + 0.1f * getResourceRequirementStrength(target->subID);
 
 	case Obj::RESOURCE:
-		return target->subID == Res::GOLD
+		return target->subID == GameResID(EGameResID::GOLD)
 			? 0
 			: 0.2f * getTotalResourceRequirementStrength(target->subID) + 0.4f * getResourceRequirementStrength(target->subID);
 
@@ -391,7 +392,7 @@ float RewardEvaluator::getStrategicalValue(const CGObjectInstance * target) cons
 		for (TResources::nziterator it (resourceReward); it.valid(); it++)
 		{
 			//Evaluate resources used for construction. Gold is evaluated separately.
-			if (it->resType != Res::GOLD)
+			if (it->resType != EGameResID::GOLD)
 			{
 				sum += 0.1f * getResourceRequirementStrength(it->resType);
 			}
@@ -502,7 +503,7 @@ int32_t getArmyCost(const CArmedInstance * army)
 
 	for(auto stack : army->Slots())
 	{
-		value += stack.second->getCreatureID().toCreature()->cost[Res::GOLD] * stack.second->count;
+		value += stack.second->getCreatureID().toCreature()->getRecruitCost(EGameResID::GOLD) * stack.second->count;
 	}
 
 	return value;
@@ -517,7 +518,7 @@ int32_t RewardEvaluator::getGoldReward(const CGObjectInstance * target, const CG
 	const int dailyIncomeMultiplier = 5;
 	const float enemyArmyEliminationGoldRewardRatio = 0.2f;
 	const int32_t heroEliminationBonus = GameConstants::HERO_GOLD_COST / 2;
-	auto isGold = target->subID == Res::GOLD; // TODO: other resorces could be sold but need to evaluate market power
+	auto isGold = target->subID == GameResID(EGameResID::GOLD); // TODO: other resorces could be sold but need to evaluate market power
 
 	switch(target->ID)
 	{
@@ -540,7 +541,7 @@ int32_t RewardEvaluator::getGoldReward(const CGObjectInstance * target, const CG
 	case Obj::WAGON:
 		return 100;
 	case Obj::CREATURE_BANK:
-		return getCreatureBankResources(target, hero)[Res::GOLD];
+		return getCreatureBankResources(target, hero)[EGameResID::GOLD];
 	case Obj::CRYPT:
 	case Obj::DERELICT_SHIP:
 		return 3000;
@@ -627,7 +628,7 @@ private:
 				continue;
 
 			auto creature = creatureInfo.second.back().toCreature();
-			result += creature->AIValue * town->getGrowthInfo(creature->getLevel() - 1).totalGrowth();
+			result += creature->getAIValue() * town->getGrowthInfo(creature->getLevel() - 1).totalGrowth();
 		}
 
 		return result;
@@ -644,7 +645,7 @@ public:
 		auto & treat = defendTown.getTreat();
 
 		auto armyIncome = townArmyIncome(town);
-		auto dailyIncome = town->dailyIncome()[Res::GOLD];
+		auto dailyIncome = town->dailyIncome()[EGameResID::GOLD];
 
 		auto strategicalValue = std::sqrt(armyIncome / 20000.0f) + dailyIncome / 3000.0f;
 
@@ -804,10 +805,10 @@ public:
 		Goals::BuildThis & buildThis = dynamic_cast<Goals::BuildThis &>(*task);
 		auto & bi = buildThis.buildingInfo;
 		
-		evaluationContext.goldReward += 7 * bi.dailyIncome[Res::GOLD] / 2; // 7 day income but half we already have
+		evaluationContext.goldReward += 7 * bi.dailyIncome[EGameResID::GOLD] / 2; // 7 day income but half we already have
 		evaluationContext.heroRole = HeroRole::MAIN;
 		evaluationContext.movementCostByRole[evaluationContext.heroRole] += bi.prerequisitesCount;
-		evaluationContext.goldCost += bi.buildCostWithPrerequisits[Res::GOLD];
+		evaluationContext.goldCost += bi.buildCostWithPrerequisits[EGameResID::GOLD];
 
 		if(bi.creatureID != CreatureID::NONE)
 		{
@@ -921,7 +922,7 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task)
 		closestHeroRatioVariable->setValue(evaluationContext.closestWayRatio);
 		strategicalValueVariable->setValue(evaluationContext.strategicalValue);
 		goldPreasureVariable->setValue(ai->buildAnalyzer->getGoldPreasure());
-		goldCostVariable->setValue(evaluationContext.goldCost / ((float)ai->getFreeResources()[Res::GOLD] + (float)ai->buildAnalyzer->getDailyIncome()[Res::GOLD] + 1.0f));
+		goldCostVariable->setValue(evaluationContext.goldCost / ((float)ai->getFreeResources()[EGameResID::GOLD] + (float)ai->buildAnalyzer->getDailyIncome()[EGameResID::GOLD] + 1.0f));
 		turnVariable->setValue(evaluationContext.turn);
 		fearVariable->setValue(evaluationContext.enemyHeroDangerRatio);
 

+ 2 - 2
AI/Nullkiller/Goals/BuyArmy.cpp

@@ -57,12 +57,12 @@ void BuyArmy::accept(AIGateway * ai)
 		if(objid != -1 && ci.creID != objid)
 			continue;
 
-		vstd::amin(ci.count, res / ci.cre->cost);
+		vstd::amin(ci.count, res / ci.cre->getFullRecruitCost());
 
 		if(ci.count)
 		{
 			cb->recruitCreatures(town, town->getUpperArmy(), ci.creID, ci.count, ci.level);
-			valueBought += ci.count * ci.cre->AIValue;
+			valueBought += ci.count * ci.cre->getAIValue();
 		}
 	}
 

+ 1 - 1
AI/Nullkiller/Goals/CompleteQuest.cpp

@@ -214,7 +214,7 @@ TGoalVec CompleteQuest::missionResources() const
 			for(int i = 0; i < q.quest->m7resources.size(); ++i)
 			{
 				if(q.quest->m7resources[i])
-					solutions.push_back(sptr(CollectRes(i, q.quest->m7resources[i])));
+					solutions.push_back(sptr(CollectRes(static_cast<EGameResID>(i), q.quest->m7resources[i])));
 			}
 		}
 	}

+ 1 - 1
AI/Nullkiller/Goals/GatherArmy.cpp

@@ -162,7 +162,7 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
 							for(auto & creatureID : creLevel.second)
 							{
 								auto creature = VLC->creh->creatures[creatureID];
-								if(ai->ah->freeResources().canAfford(creature->cost))
+								if(ai->ah->freeResources().canAfford(creature->getFullRecruitCost()))
 									objs.push_back(obj); //TODO: reserve resources?
 							}
 						}

+ 2 - 2
AI/Nullkiller/Goals/Trade.h

@@ -27,10 +27,10 @@ namespace Goals
 			: CGoal(Goals::TRADE)
 		{
 		}
-		Trade(int rid, int val, int Objid)
+		Trade(GameResID rid, int val, int Objid)
 			: CGoal(Goals::TRADE)
 		{
-			resID = rid;
+			resID = rid.getNum();
 			value = val;
 			objid = Objid;
 		}

+ 1 - 1
AI/Nullkiller/Markers/ArmyUpgrade.cpp

@@ -23,7 +23,7 @@ using namespace Goals;
 
 ArmyUpgrade::ArmyUpgrade(const AIPath & upgradePath, const CGObjectInstance * upgrader, const ArmyUpgradeInfo & upgrade)
 	: CGoal(Goals::ARMY_UPGRADE), upgrader(upgrader), upgradeValue(upgrade.upgradeValue),
-	initialValue(upgradePath.heroArmy->getArmyStrength()), goldCost(upgrade.upgradeCost[Res::GOLD])
+	initialValue(upgradePath.heroArmy->getArmyStrength()), goldCost(upgrade.upgradeCost[EGameResID::GOLD])
 {
 	sethero(upgradePath.targetHero);
 }

+ 6 - 6
AI/Nullkiller/Pathfinding/Actors.cpp

@@ -350,7 +350,7 @@ HeroExchangeArmy * HeroExchangeMap::tryUpgrade(
 		{
 			auto targetSlot = target->getFreeSlot();
 
-			target->addToSlot(targetSlot, slotInfo.creature->idNumber, TQuantity(slotInfo.count));
+			target->addToSlot(targetSlot, slotInfo.creature->getId(), TQuantity(slotInfo.count));
 		}
 
 		resources -= upgradeInfo.upgradeCost;
@@ -372,10 +372,10 @@ HeroExchangeArmy * HeroExchangeMap::tryUpgrade(
 
 		for(auto & creatureToBuy : buyArmy)
 		{
-			auto targetSlot = target->getSlotFor(creatureToBuy.cre);
+			auto targetSlot = target->getSlotFor(dynamic_cast<const CCreature*>(creatureToBuy.cre));
 
 			target->addToSlot(targetSlot, creatureToBuy.creID, creatureToBuy.count);
-			target->armyCost += creatureToBuy.cre->cost * creatureToBuy.count;
+			target->armyCost += creatureToBuy.cre->getFullRecruitCost() * creatureToBuy.count;
 			target->requireBuyArmy = true;
 		}
 	}
@@ -399,7 +399,7 @@ HeroExchangeArmy * HeroExchangeMap::pickBestCreatures(const CCreatureSet * army1
 	{
 		auto targetSlot = target->getFreeSlot();
 
-		target->addToSlot(targetSlot, slotInfo.creature->idNumber, TQuantity(slotInfo.count));
+		target->addToSlot(targetSlot, slotInfo.creature->getId(), TQuantity(slotInfo.count));
 	}
 
 	return target;
@@ -420,7 +420,7 @@ DwellingActor::DwellingActor(const CGDwelling * dwelling, uint64_t chainMask, bo
 {
 	for(auto & slot : creatureSet->Slots())
 	{
-		armyCost += slot.second->getCreatureID().toCreature()->cost * slot.second->count;
+		armyCost += slot.second->getCreatureID().toCreature()->getFullRecruitCost() * slot.second->count;
 	}
 }
 
@@ -454,7 +454,7 @@ CCreatureSet * DwellingActor::getDwellingCreatures(const CGDwelling * dwelling,
 		auto creature = creatureInfo.second.back().toCreature();
 		dwellingCreatures->addToSlot(
 			dwellingCreatures->getSlotFor(creature),
-			creature->idNumber,
+			creature->getId(),
 			TQuantity(creatureInfo.first));
 	}
 

+ 1 - 1
AI/StupidAI/StupidAI.cpp

@@ -95,7 +95,7 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
 	ReachabilityInfo dists = cb->getReachability(stack);
 	std::vector<EnemyInfo> enemiesShootable, enemiesReachable, enemiesUnreachable;
 
-	if(stack->type->idNumber == CreatureID::CATAPULT)
+	if(stack->type->getId() == CreatureID::CATAPULT)
 	{
 		BattleAction attack;
 		static const std::vector<int> wallHexes = {50, 183, 182, 130, 78, 29, 12, 95};

+ 2 - 2
AI/VCAI/AIUtility.cpp

@@ -230,8 +230,8 @@ creInfo infoFromDC(const dwellingContent & dc)
 	ci.creID = dc.second.size() ? dc.second.back() : CreatureID(-1); //should never be accessed
 	if (ci.creID != -1)
 	{
-		ci.cre = VLC->creh->objects[ci.creID];
-		ci.level = ci.cre->level; //this is cretaure tier, while tryRealize expects dwelling level. Ignore.
+		ci.cre = VLC->creatures()->getById(ci.creID);
+		ci.level = ci.cre->getLevel(); //this is creature tier, while tryRealize expects dwelling level. Ignore.
 	}
 	else
 	{

+ 1 - 1
AI/VCAI/AIUtility.h

@@ -152,7 +152,7 @@ struct creInfo
 {
 	int count;
 	CreatureID creID;
-	CCreature * cre;
+	const Creature * cre;
 	int level;
 };
 creInfo infoFromDC(const dwellingContent & dc);

+ 8 - 7
AI/VCAI/ArmyManager.cpp

@@ -36,9 +36,10 @@ std::vector<SlotInfo> ArmyManager::getSortedSlots(const CCreatureSet * target, c
 	{
 		for(auto & i : armyPtr->Slots())
 		{
-			auto & slotInfp = creToPower[i.second->type];
+			auto cre = dynamic_cast<const CCreature*>(i.second->type);
+			auto & slotInfp = creToPower[cre];
 
-			slotInfp.creature = i.second->type;
+			slotInfp.creature = cre;
 			slotInfp.power += i.second->getPower();
 			slotInfp.count += i.second->count;
 		}
@@ -59,8 +60,8 @@ std::vector<SlotInfo>::iterator ArmyManager::getWeakestCreature(std::vector<Slot
 {
 	auto weakest = boost::min_element(army, [](const SlotInfo & left, const SlotInfo & right) -> bool
 	{
-		if(left.creature->level != right.creature->level)
-			return left.creature->level < right.creature->level;
+		if(left.creature->getLevel() != right.creature->getLevel())
+			return left.creature->getLevel() < right.creature->getLevel();
 		
 		return left.creature->Speed() > right.creature->Speed();
 	});
@@ -120,7 +121,7 @@ ui64 ArmyManager::howManyReinforcementsCanBuy(const CCreatureSet * h, const CGDw
 		if(!ci.count || ci.creID == -1)
 			continue;
 
-		vstd::amin(ci.count, availableRes / ci.cre->cost); //max count we can afford
+		vstd::amin(ci.count, availableRes / ci.cre->getFullRecruitCost()); //max count we can afford
 
 		if(ci.count && ci.creID != -1) //valid creature at this level
 		{
@@ -135,8 +136,8 @@ ui64 ArmyManager::howManyReinforcementsCanBuy(const CCreatureSet * h, const CGDw
 			}
 
 			//we found matching occupied or free slot
-			aivalue += ci.count * ci.cre->AIValue;
-			availableRes -= ci.cre->cost * ci.count;
+			aivalue += ci.count * ci.cre->getAIValue();
+			availableRes -= ci.cre->getFullRecruitCost() * ci.count;
 		}
 	}
 

+ 4 - 4
AI/VCAI/FuzzyEngines.cpp

@@ -64,13 +64,13 @@ armyStructure evaluateArmyStructure(const CArmedInstance * army)
 	for(auto s : army->Slots())
 	{
 		bool walker = true;
-		const CCreature * creature = s.second->type;
-		if(creature->hasBonus(selectorSHOOTER, keySHOOTER))
+		auto bearer = s.second->getType()->getBonusBearer();
+		if(bearer->hasBonus(selectorSHOOTER, keySHOOTER))
 		{
 			shootersStrength += s.second->getPower();
 			walker = false;
 		}
-		if(creature->hasBonus(selectorFLYING, keyFLYING))
+		if(bearer->hasBonus(selectorFLYING, keyFLYING))
 		{
 			flyersStrength += s.second->getPower();
 			walker = false;
@@ -78,7 +78,7 @@ armyStructure evaluateArmyStructure(const CArmedInstance * army)
 		if(walker)
 			walkersStrength += s.second->getPower();
 
-		vstd::amax(maxSpeed, creature->valOfBonuses(selectorSTACKS_SPEED, keySTACKS_SPEED));
+		vstd::amax(maxSpeed, bearer->valOfBonuses(selectorSTACKS_SPEED, keySTACKS_SPEED));
 	}
 	armyStructure as;
 	as.walkers = static_cast<float>(walkersStrength / totalStrength);

+ 1 - 1
AI/VCAI/Goals/BuyArmy.cpp

@@ -35,7 +35,7 @@ TSubgoal BuyArmy::whatToDoToAchieve()
 {
 	//TODO: calculate the actual cost of units instead
 	TResources price;
-	price[Res::GOLD] = static_cast<int>(value * 0.4f); //some approximate value
+	price[EGameResID::GOLD] = static_cast<int>(value * 0.4f); //some approximate value
 	return ai->ah->whatToDo(price, iAmElementar()); //buy right now or gather resources
 }
 

+ 11 - 11
AI/VCAI/Goals/CollectRes.cpp

@@ -46,7 +46,7 @@ TGoalVec CollectRes::getAllPossibleSubgoals()
 		switch (obj->ID.num)
 		{
 		case Obj::TREASURE_CHEST:
-			return resID == Res::GOLD;
+			return resID == GameResID(EGameResID::GOLD);
 			break;
 		case Obj::RESOURCE:
 			return obj->subID == resID;
@@ -59,24 +59,24 @@ TGoalVec CollectRes::getAllPossibleSubgoals()
 			return true; //contains all resources
 			break;
 		case Obj::WINDMILL:
-			switch (resID)
+			switch (GameResID(resID).toEnum())
 			{
-			case Res::GOLD:
-			case Res::WOOD:
+			case EGameResID::GOLD:
+			case EGameResID::WOOD:
 				return false;
 			}
 			break;
 		case Obj::WATER_WHEEL:
-			if (resID != Res::GOLD)
+			if (resID != GameResID(EGameResID::GOLD))
 				return false;
 			break;
 		case Obj::MYSTICAL_GARDEN:
-			if ((resID != Res::GOLD) && (resID != Res::GEMS))
+			if ((resID != GameResID(EGameResID::GOLD)) && (resID != GameResID(EGameResID::GEMS)))
 				return false;
 			break;
 		case Obj::LEAN_TO:
 		case Obj::WAGON:
-			if (resID != Res::GOLD)
+			if (resID != GameResID(EGameResID::GOLD))
 				return false;
 			break;
 		default:
@@ -170,12 +170,12 @@ TSubgoal CollectRes::whatToDoToTrade()
 		const IMarket * m = markets.back();
 		//attempt trade at back (best prices)
 		int howManyCanWeBuy = 0;
-		for (Res::ERes i = Res::WOOD; i <= Res::GOLD; vstd::advance(i, 1))
+		for (auto i = EGameResID::WOOD; i <= EGameResID::GOLD; vstd::advance(i, 1))
 		{
-			if (i == resID)
+			if (GameResID(i) == resID)
 				continue;
 			int toGive = -1, toReceive = -1;
-			m->getOffer(i, resID, toGive, toReceive, EMarketMode::RESOURCE_RESOURCE);
+			m->getOffer(GameResID(i), resID, toGive, toReceive, EMarketMode::RESOURCE_RESOURCE);
 			assert(toGive > 0 && toReceive > 0);
 			howManyCanWeBuy += toReceive * (ai->ah->freeResources()[i] / toGive);
 		}
@@ -191,7 +191,7 @@ TSubgoal CollectRes::whatToDoToTrade()
 			}
 			else //either it's our town, or we have hero there
 			{
-				return sptr(Trade(resID, value, objid).setisElementar(true)); //we can do this immediately
+				return sptr(Trade(static_cast<EGameResID>(resID), value, objid).setisElementar(true)); //we can do this immediately
 			}
 		}
 	}

+ 2 - 2
AI/VCAI/Goals/CollectRes.h

@@ -24,10 +24,10 @@ namespace Goals
 			: CGoal(Goals::COLLECT_RES)
 		{
 		}
-		CollectRes(int rid, int val)
+		CollectRes(GameResID rid, int val)
 			: CGoal(Goals::COLLECT_RES)
 		{
-			resID = rid;
+			resID = rid.getNum();
 			value = val;
 			priority = 2;
 		}

+ 2 - 2
AI/VCAI/Goals/CompleteQuest.cpp

@@ -172,7 +172,7 @@ TGoalVec CompleteQuest::missionArmy() const
 
 	for(auto creature : q.quest->m6creatures)
 	{
-		solutions.push_back(sptr(GatherTroops(creature.type->idNumber, creature.count)));
+		solutions.push_back(sptr(GatherTroops(creature.type->getId(), creature.count)));
 	}
 
 	return solutions;
@@ -235,7 +235,7 @@ TGoalVec CompleteQuest::missionResources() const
 			for(int i = 0; i < q.quest->m7resources.size(); ++i)
 			{
 				if(q.quest->m7resources[i])
-					solutions.push_back(sptr(CollectRes(i, q.quest->m7resources[i])));
+					solutions.push_back(sptr(CollectRes(static_cast<EGameResID>(i), q.quest->m7resources[i])));
 			}
 		}
 	}

+ 1 - 1
AI/VCAI/Goals/GatherArmy.cpp

@@ -159,7 +159,7 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
 							for(auto & creatureID : creLevel.second)
 							{
 								auto creature = VLC->creh->objects[creatureID];
-								if(ai->ah->freeResources().canAfford(creature->cost))
+								if(ai->ah->freeResources().canAfford(creature->getFullRecruitCost()))
 									objs.push_back(obj); //TODO: reserve resources?
 							}
 						}

+ 8 - 8
AI/VCAI/Goals/GatherTroops.cpp

@@ -93,21 +93,21 @@ TGoalVec GatherTroops::getAllPossibleSubgoals()
 			continue;
 		}
 
-		auto creature = VLC->creh->objects[objid];
-		if(t->subID == creature->faction) //TODO: how to force AI to build unupgraded creatures? :O
+		auto creature = VLC->creatures()->getByIndex(objid);
+		if(t->subID == creature->getFactionIndex()) //TODO: how to force AI to build unupgraded creatures? :O
 		{
-			auto creatures = vstd::tryAt(t->town->creatures, creature->level - 1);
+			auto creatures = vstd::tryAt(t->town->creatures, creature->getLevel() - 1);
 			if(!creatures)
 				continue;
 
-			int upgradeNumber = vstd::find_pos(*creatures, creature->idNumber);
+			int upgradeNumber = vstd::find_pos(*creatures, creature->getId());
 			if(upgradeNumber < 0)
 				continue;
 
-			BuildingID bid(BuildingID::DWELL_FIRST + creature->level - 1 + upgradeNumber * GameConstants::CREATURES_PER_TOWN);
-			if(t->hasBuilt(bid) && ai->ah->freeResources().canAfford(creature->cost)) //this assumes only creatures with dwellings are assigned to faction
+			BuildingID bid(BuildingID::DWELL_FIRST + creature->getLevel() - 1 + upgradeNumber * GameConstants::CREATURES_PER_TOWN);
+			if(t->hasBuilt(bid) && ai->ah->freeResources().canAfford(creature->getFullRecruitCost())) //this assumes only creatures with dwellings are assigned to faction
 			{
-				solutions.push_back(sptr(BuyArmy(t, creature->AIValue * this->value).setobjid(objid)));
+				solutions.push_back(sptr(BuyArmy(t, creature->getAIValue() * this->value).setobjid(objid)));
 			}
 			/*else //disable random building requests for now - this code needs to know a lot of town/resource context to do more good than harm
 			{
@@ -129,7 +129,7 @@ TGoalVec GatherTroops::getAllPossibleSubgoals()
 			{
 				for(auto type : creature.second)
 				{
-					if(type == objid && ai->ah->freeResources().canAfford(VLC->creh->objects[type]->cost))
+					if(type == objid && ai->ah->freeResources().canAfford(VLC->creatures()->getById(type)->getFullRecruitCost()))
 						vstd::concatenate(solutions, ai->ah->howToVisitObj(obj));
 				}
 			}

+ 1 - 1
AI/VCAI/Goals/RecruitHero.cpp

@@ -33,6 +33,6 @@ TSubgoal RecruitHero::whatToDoToAchieve()
 		return sptr(BuildThis(BuildingID::TAVERN).setpriority(2));
 
 	TResources res;
-	res[Res::GOLD] = GameConstants::HERO_GOLD_COST;
+	res[EGameResID::GOLD] = GameConstants::HERO_GOLD_COST;
 	return ai->ah->whatToDo(res, iAmElementar()); //either buy immediately, or collect res
 }

+ 2 - 2
AI/VCAI/Goals/Trade.h

@@ -24,10 +24,10 @@ namespace Goals
 			: CGoal(Goals::TRADE)
 		{
 		}
-		Trade(int rid, int val, int Objid)
+		Trade(GameResID rid, int val, int Objid)
 			: CGoal(Goals::TRADE)
 		{
-			resID = rid;
+			resID = rid.getNum();
 			value = val;
 			objid = Objid;
 			priority = 3; //trading is instant, but picking resources is free

+ 1 - 1
AI/VCAI/Goals/Win.cpp

@@ -154,7 +154,7 @@ TSubgoal Win::whatToDoToAchieve()
 		case EventCondition::HAVE_RESOURCES:
 			//TODO mines? piles? marketplace?
 			//save?
-			return sptr(CollectRes(static_cast<Res::ERes>(goal.objectType), goal.value));
+			return sptr(CollectRes(static_cast<EGameResID>(goal.objectType), goal.value));
 		case EventCondition::HAVE_CREATURES:
 			return sptr(GatherTroops(goal.objectType, goal.value));
 		case EventCondition::TRANSPORT:

+ 2 - 2
AI/VCAI/MapObjectsEvaluator.cpp

@@ -73,8 +73,8 @@ boost::optional<int> MapObjectsEvaluator::getObjectValue(const CGObjectInstance
 		{
 			for(auto & creatureID : creLevel.second)
 			{
-				auto creature = VLC->creh->objects[creatureID];
-				aiValue += (creature->AIValue * creature->growth);
+				auto creature = VLC->creatures()->getById(creatureID);
+				aiValue += (creature->getAIValue() * creature->getGrowth());
 			}
 		}
 		return aiValue;

+ 16 - 16
AI/VCAI/ResourceManager.cpp

@@ -58,15 +58,15 @@ TResources ResourceManager::estimateIncome() const
 	{
 		if (obj->ID == Obj::MINE)
 		{
-			switch (obj->subID)
+			auto mine = dynamic_cast<const CGMine*>(obj);
+			switch (mine->producedResource.toEnum())
 			{
-			case Res::WOOD:
-			case Res::ORE:
+			case EGameResID::WOOD:
+			case EGameResID::ORE:
 				ret[obj->subID] += WOOD_ORE_MINE_PRODUCTION;
 				break;
-			case Res::GOLD:
-			case 7: //abandoned mine -> also gold
-				ret[Res::GOLD] += GOLD_MINE_PRODUCTION;
+			case EGameResID::GOLD:
+				ret[EGameResID::GOLD] += GOLD_MINE_PRODUCTION;
 				break;
 			default:
 				ret[obj->subID] += RESOURCE_MINE_PRODUCTION;
@@ -90,11 +90,11 @@ Goals::TSubgoal ResourceManager::collectResourcesForOurGoal(ResourceObjective &o
 {
 	auto allResources = cb->getResourceAmount();
 	auto income = estimateIncome();
-	Res::ERes resourceType = Res::INVALID;
+	GameResID resourceType = EGameResID::INVALID;
 	TResource amountToCollect = 0;
 
-	typedef std::pair<Res::ERes, TResource> resPair;
-	std::map<Res::ERes, TResource> missingResources;
+	using resPair = std::pair<GameResID, TResource>;
+	std::map<GameResID, TResource> missingResources;
 
 	//TODO: unit test for complex resource sets
 
@@ -102,10 +102,10 @@ Goals::TSubgoal ResourceManager::collectResourcesForOurGoal(ResourceObjective &o
 	for (auto it = queue.ordered_begin(); it != queue.ordered_end(); it++)
 	{
 		//choose specific resources we need for this goal (not 0)
-		for (auto r = Res::ResourceSet::nziterator(o.resources); r.valid(); r++)
+		for (auto r = ResourceSet::nziterator(o.resources); r.valid(); r++)
 			missingResources[r->resType] += it->resources[r->resType]; //goal it costs r units of resType
 	}
-	for (auto it = Res::ResourceSet::nziterator(o.resources); it.valid(); it++)
+	for (auto it = ResourceSet::nziterator(o.resources); it.valid(); it++)
 	{
 		missingResources[it->resType] -= allResources[it->resType]; //missing = (what we need) - (what we have)
 		vstd::amax(missingResources[it->resType], 0); // if we have more resources than reserved, we don't need them
@@ -129,11 +129,11 @@ Goals::TSubgoal ResourceManager::collectResourcesForOurGoal(ResourceObjective &o
 			break;
 		}
 	}
-	if (resourceType == Res::INVALID) //no needed resources has 0 income,
+	if (resourceType == EGameResID::INVALID) //no needed resources has 0 income,
 	{
 		//find the one which takes longest to collect
-		typedef std::pair<Res::ERes, float> timePair;
-		std::map<Res::ERes, float> daysToEarn;
+		using timePair = std::pair<GameResID, float>;
+		std::map<GameResID, float> daysToEarn;
 		for (auto it : missingResources)
 			daysToEarn[it.first] = (float)missingResources[it.first] / income[it.first];
 		auto incomeComparer = [](const timePair & lhs, const timePair & rhs) -> bool
@@ -345,7 +345,7 @@ TResources ResourceManager::freeResources() const
 
 TResource ResourceManager::freeGold() const
 {
-	return freeResources()[Res::GOLD];
+	return freeResources()[EGameResID::GOLD];
 }
 
 TResources ResourceManager::allResources() const
@@ -355,5 +355,5 @@ TResources ResourceManager::allResources() const
 
 TResource ResourceManager::allGold() const
 {
-	return cb->getResourceAmount()[Res::GOLD];
+	return cb->getResourceAmount()[EGameResID::GOLD];
 }

+ 11 - 11
AI/VCAI/VCAI.cpp

@@ -1235,7 +1235,7 @@ void VCAI::recruitCreatures(const CGDwelling * d, const CArmedInstance * recruit
 		int count = d->creatures[i].first;
 		CreatureID creID = d->creatures[i].second.back();
 
-		vstd::amin(count, ah->freeResources() / VLC->creh->objects[creID]->cost);
+		vstd::amin(count, ah->freeResources() / VLC->creatures()->getById(creID)->getFullRecruitCost());
 		if(count > 0)
 			cb->recruitCreatures(d, recruiter, creID, count, i);
 	}
@@ -1314,7 +1314,7 @@ bool VCAI::canRecruitAnyHero(const CGTownInstance * t) const
 		t = findTownWithTavern();
 	if(!t)
 		return false;
-	if(cb->getResourceAmount(Res::GOLD) < GameConstants::HERO_GOLD_COST) //TODO: use ResourceManager
+	if(cb->getResourceAmount(EGameResID::GOLD) < GameConstants::HERO_GOLD_COST) //TODO: use ResourceManager
 		return false;
 	if(cb->getHeroesInfo().size() >= ALLOWED_ROAMING_HEROES)
 		return false;
@@ -1434,7 +1434,7 @@ void VCAI::wander(HeroPtr h)
 				}
 				break;
 			}
-			else if(cb->getResourceAmount(Res::GOLD) >= GameConstants::HERO_GOLD_COST)
+			else if(cb->getResourceAmount(EGameResID::GOLD) >= GameConstants::HERO_GOLD_COST)
 			{
 				std::vector<const CGTownInstance *> towns = cb->getTownsInfo();
 				vstd::erase_if(towns, [&](const CGTownInstance * t) -> bool
@@ -2117,10 +2117,10 @@ void VCAI::tryRealize(Goals::Trade & g) //trade
 		if(const IMarket * m = IMarket::castFrom(obj, false))
 		{
 			auto freeRes = ah->freeResources(); //trade only resources which are not reserved
-			for(auto it = Res::ResourceSet::nziterator(freeRes); it.valid(); it++)
+			for(auto it = ResourceSet::nziterator(freeRes); it.valid(); it++)
 			{
 				auto res = it->resType;
-				if(res == g.resID) //sell any other resource
+				if(res.getNum() == g.resID) //sell any other resource
 					continue;
 
 				int toGive, toGet;
@@ -2174,7 +2174,7 @@ void VCAI::tryRealize(Goals::BuyArmy & g)
 				|| t->getUpperArmy()->getSlotFor(ci.creID) == SlotID())
 				continue;
 
-			vstd::amin(ci.count, res / ci.cre->cost); //max count we can afford
+			vstd::amin(ci.count, res / ci.cre->getFullRecruitCost()); //max count we can afford
 
 			if(!ci.count)
 				continue;
@@ -2190,15 +2190,15 @@ void VCAI::tryRealize(Goals::BuyArmy & g)
 			*boost::max_element(creaturesInDwellings, [](const creInfo & lhs, const creInfo & rhs)
 		{
 			//max value of creatures we can buy with our res
-			int value1 = lhs.cre->AIValue * lhs.count,
-				value2 = rhs.cre->AIValue * rhs.count;
+			int value1 = lhs.cre->getAIValue() * lhs.count,
+				value2 = rhs.cre->getAIValue() * rhs.count;
 
 			return value1 < value2;
 		});
 
 
 		cb->recruitCreatures(t, t->getUpperArmy(), ci.creID, ci.count, ci.level);
-		valueBought += ci.count * ci.cre->AIValue;
+		valueBought += ci.count * ci.cre->getAIValue();
 	}
 
 	throw goalFulfilledException(sptr(g)); //we bought as many creatures as we wanted
@@ -2820,7 +2820,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
 	{
 		for(auto slot : h->Slots())
 		{
-			if(slot.second->type->upgrades.size())
+			if(slot.second->type->hasUpgrades())
 				return true; //TODO: check price?
 		}
 		return false;
@@ -2844,7 +2844,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
 	case Obj::TREE_OF_KNOWLEDGE:
 	{
 		TResources myRes = ai->ah->freeResources();
-		if(myRes[Res::GOLD] < 2000 || myRes[Res::GEMS] < 10)
+		if(myRes[EGameResID::GOLD] < 2000 || myRes[EGameResID::GEMS] < 10)
 			return false;
 		break;
 	}

+ 1 - 1
Global.h

@@ -279,7 +279,7 @@ template<typename T, size_t N> char (&_ArrayCountObj(const T (&)[N]))[N];
 #define VCMI_LIB_NAMESPACE_BEGIN
 #define VCMI_LIB_NAMESPACE_END
 #define VCMI_LIB_USING_NAMESPACE
-#define VCMI_LIB_WRAP_NAMESPACE(x) x
+#define VCMI_LIB_WRAP_NAMESPACE(x) ::x
 #endif
 
 /* ---------------------------------------------------------------------------- */

+ 1 - 1
client/Client.h

@@ -195,7 +195,7 @@ public:
 	void showGarrisonDialog(ObjectInstanceID upobj, ObjectInstanceID hid, bool removableUnits) override {};
 	void showTeleportDialog(TeleportDialog * iw) override {};
 	void showThievesGuildWindow(PlayerColor player, ObjectInstanceID requestingObjId) override {};
-	void giveResource(PlayerColor player, Res::ERes which, int val) override {};
+	void giveResource(PlayerColor player, GameResID which, int val) override {};
 	virtual void giveResources(PlayerColor player, TResources resources) override {};
 
 	void giveCreatures(const CArmedInstance * objid, const CGHeroInstance * h, const CCreatureSet & creatures, bool remove) override {};

+ 1 - 1
client/adventureMap/CResDataBar.cpp

@@ -80,7 +80,7 @@ std::string CResDataBar::buildDateString()
 void CResDataBar::draw(SDL_Surface * to)
 {
 	//TODO: all this should be labels, but they require proper text update on change
-	for (auto i=Res::WOOD; i<=Res::GOLD; vstd::advance(i, 1))
+	for (auto i=GameResID(EGameResID::WOOD); i <= GameResID(EGameResID::GOLD); vstd::advance(i, 1))
 	{
 		std::string text = std::to_string(LOCPLINT->cb->getResourceAmount(i));
 

+ 1 - 1
client/battle/BattleAnimationClasses.cpp

@@ -158,7 +158,7 @@ ECreatureAnimType AttackAnimation::findValidGroup( const std::vector<ECreatureAn
 
 const CCreature * AttackAnimation::getCreature() const
 {
-	if (attackingStack->getCreature()->idNumber == CreatureID::ARROW_TOWERS)
+	if (attackingStack->getCreature()->getId() == CreatureID::ARROW_TOWERS)
 		return owner.siegeController->getTurretCreature();
 	else
 		return attackingStack->getCreature();

+ 2 - 2
client/battle/BattleInterfaceClasses.cpp

@@ -453,7 +453,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
 
 			auto best = vstd::maxElementByFun(stacks, [](const CStack * stack)
 			{
-				return stack->type->AIValue;
+				return stack->type->getAIValue();
 			});
 
 			if(best != stacks.end()) //should be always but to be safe...
@@ -715,7 +715,7 @@ void StackQueue::StackBox::setUnit(const battle::Unit * unit, size_t turn)
 		// if mod is not up to date and does have arrow tower icon yet - second setFrame call will fail and retain previously set image
 		// for 1.2 release & later next line should be moved into 'else' block
 		icon->setFrame(unit->creatureIconIndex(), 0);
-		if (unit->unitType()->idNumber == CreatureID::ARROW_TOWERS)
+		if (unit->unitType()->getId() == CreatureID::ARROW_TOWERS)
 			icon->setFrame(owner->getSiegeShooterIconID(), 1);
 
 		amount->setText(TextOperations::formatMetric(unit->getCount(), 4));

+ 1 - 1
client/battle/BattleProjectileController.cpp

@@ -148,7 +148,7 @@ const CCreature & BattleProjectileController::getShooter(const CStack * stack) c
 {
 	const CCreature * creature = stack->getCreature();
 
-	if(creature->idNumber == CreatureID::ARROW_TOWERS)
+	if(creature->getId() == CreatureID::ARROW_TOWERS)
 		creature = owner.siegeController->getTurretCreature();
 
 	if(creature->animation.missleFrameAngles.empty())

+ 1 - 1
client/battle/BattleStacksController.cpp

@@ -200,7 +200,7 @@ void BattleStacksController::stackAdded(const CStack * stack, bool instant)
 		stackAnimation[stack->ID]->pos.w = stackAnimation[stack->ID]->getWidth();
 
 		// FIXME: workaround for visible animation of Medusa tails (animation disabled in H3)
-		if (turretCreature->idNumber == CreatureID::MEDUSA )
+		if (turretCreature->getId() == CreatureID::MEDUSA )
 			stackAnimation[stack->ID]->pos.w = 250;
 
 		coords = owner.siegeController->getTurretCreaturePosition(stack->initialPosition);

+ 1 - 1
client/battle/BattleWindow.cpp

@@ -309,7 +309,7 @@ void BattleWindow::reallyFlee()
 
 void BattleWindow::reallySurrender()
 {
-	if (owner.curInt->cb->getResourceAmount(Res::GOLD) < owner.curInt->cb->battleGetSurrenderCost())
+	if (owner.curInt->cb->getResourceAmount(EGameResID::GOLD) < owner.curInt->cb->battleGetSurrenderCost())
 	{
 		owner.curInt->showInfoDialog(CGI->generaltexth->allTexts[29]); //You don't have enough gold!
 	}

+ 22 - 22
client/lobby/OptionsTab.cpp

@@ -126,25 +126,25 @@ size_t OptionsTab::CPlayerSettingsHelper::getImageIndex()
 			return GOLD;
 		case PlayerSettings::RESOURCE:
 		{
-			switch((*CGI->townh)[factionIndex]->town->primaryRes)
+			switch((*CGI->townh)[factionIndex]->town->primaryRes.toEnum())
 			{
-			case Res::WOOD_AND_ORE:
+			case EGameResID::WOOD_AND_ORE:
 				return WOOD_ORE;
-			case Res::WOOD:
+			case EGameResID::WOOD:
 				return WOOD;
-			case Res::MERCURY:
+			case EGameResID::MERCURY:
 				return MERCURY;
-			case Res::ORE:
+			case EGameResID::ORE:
 				return ORE;
-			case Res::SULFUR:
+			case EGameResID::SULFUR:
 				return SULFUR;
-			case Res::CRYSTAL:
+			case EGameResID::CRYSTAL:
 				return CRYSTAL;
-			case Res::GEMS:
+			case EGameResID::GEMS:
 				return GEM;
-			case Res::GOLD:
+			case EGameResID::GOLD:
 				return GOLD;
-			case Res::MITHRIL:
+			case EGameResID::MITHRIL:
 				return MITHRIL;
 			}
 		}
@@ -268,17 +268,17 @@ std::string OptionsTab::CPlayerSettingsHelper::getSubtitle()
 			return CGI->generaltexth->allTexts[87]; //500-1000
 		case PlayerSettings::RESOURCE:
 		{
-			switch((*CGI->townh)[factionIndex]->town->primaryRes)
+			switch((*CGI->townh)[factionIndex]->town->primaryRes.toEnum())
 			{
-			case Res::MERCURY:
+			case EGameResID::MERCURY:
 				return CGI->generaltexth->allTexts[694];
-			case Res::SULFUR:
+			case EGameResID::SULFUR:
 				return CGI->generaltexth->allTexts[695];
-			case Res::CRYSTAL:
+			case EGameResID::CRYSTAL:
 				return CGI->generaltexth->allTexts[692];
-			case Res::GEMS:
+			case EGameResID::GEMS:
 				return CGI->generaltexth->allTexts[693];
-			case Res::WOOD_AND_ORE:
+			case EGameResID::WOOD_AND_ORE:
 				return CGI->generaltexth->allTexts[89]; //At the start of the game, 5-10 wood and 5-10 ore are added to your Kingdom's resource pool
 			}
 		}
@@ -310,17 +310,17 @@ std::string OptionsTab::CPlayerSettingsHelper::getDescription()
 			return CGI->generaltexth->allTexts[92]; //At the start of the game, 500-1000 gold is added to your Kingdom's resource pool
 		case PlayerSettings::RESOURCE:
 		{
-			switch((*CGI->townh)[factionIndex]->town->primaryRes)
+			switch((*CGI->townh)[factionIndex]->town->primaryRes.toEnum())
 			{
-			case Res::MERCURY:
+			case EGameResID::MERCURY:
 				return CGI->generaltexth->allTexts[690];
-			case Res::SULFUR:
+			case EGameResID::SULFUR:
 				return CGI->generaltexth->allTexts[691];
-			case Res::CRYSTAL:
+			case EGameResID::CRYSTAL:
 				return CGI->generaltexth->allTexts[688];
-			case Res::GEMS:
+			case EGameResID::GEMS:
 				return CGI->generaltexth->allTexts[689];
-			case Res::WOOD_AND_ORE:
+			case EGameResID::WOOD_AND_ORE:
 				return CGI->generaltexth->allTexts[93]; //At the start of the game, 5-10 wood and 5-10 ore are added to your Kingdom's resource pool
 			}
 		}

+ 1 - 1
client/widgets/CreatureCostBox.h

@@ -26,5 +26,5 @@ private:
 	using ImagePtr = std::shared_ptr<CAnimImage>;
 
 	LabelPtr title;
-	std::map<int, std::pair<LabelPtr, ImagePtr>> resources;
+	std::map<GameResID, std::pair<LabelPtr, ImagePtr>> resources;
 };

+ 6 - 6
client/widgets/MiscWidgets.cpp

@@ -200,11 +200,11 @@ void CMinorResDataBar::showAll(SDL_Surface * to)
 {
 	CIntObject::showAll(to);
 
-	for (Res::ERes i=Res::WOOD; i<=Res::GOLD; vstd::advance(i, 1))
+	for (EGameResID i=EGameResID::WOOD; i<=EGameResID::GOLD; vstd::advance(i, 1))
 	{
 		std::string text = std::to_string(LOCPLINT->cb->getResourceAmount(i));
 
-		graphics->fonts[FONT_SMALL]->renderTextCenter(to, text, Colors::WHITE, Point(pos.x + 50 + 76 * i, pos.y + pos.h/2));
+		graphics->fonts[FONT_SMALL]->renderTextCenter(to, text, Colors::WHITE, Point(pos.x + 50 + 76 * GameResID(i), pos.y + pos.h/2));
 	}
 	graphics->fonts[FONT_SMALL]->renderTextCenter(to, buildDateString(), Colors::WHITE, Point(pos.x+545+(pos.w-545)/2,pos.y+pos.h/2));
 }
@@ -347,10 +347,10 @@ void CTownTooltip::init(const InfoAboutTown & town)
 
 		if(town.details->customRes)//silo is built
 		{
-			if(town.tType->primaryRes == Res::WOOD_AND_ORE )// wood & ore
+			if(town.tType->primaryRes == EGameResID::WOOD_AND_ORE )// wood & ore
 			{
-				res1 = std::make_shared<CAnimImage>("SMALRES", Res::WOOD, 0, 7, 75);
-				res2 = std::make_shared<CAnimImage>("SMALRES", Res::ORE , 0, 7, 88);
+				res1 = std::make_shared<CAnimImage>("SMALRES", GameResID(EGameResID::WOOD), 0, 7, 75);
+				res2 = std::make_shared<CAnimImage>("SMALRES", GameResID(EGameResID::ORE), 0, 7, 88);
 			}
 			else
 			{
@@ -448,7 +448,7 @@ CCreaturePic::CCreaturePic(int x, int y, const CCreature * cre, bool Big, bool A
 	pos.x+=x;
 	pos.y+=y;
 
-	TFaction faction = cre->faction;
+	TFaction faction = cre->getFactionIndex();
 
 	assert(CGI->townh->size() > faction);
 

+ 8 - 7
client/windows/CCastleInterface.cpp

@@ -292,10 +292,11 @@ CDwellingInfoBox::CDwellingInfoBox(int centerX, int centerY, const CGTownInstanc
 
 	for(int i = 0; i<GameConstants::RESOURCE_QUANTITY; i++)
 	{
-		if(creature->cost[i])
+		auto res = static_cast<EGameResID>(i);
+		if(creature->getRecruitCost(res))
 		{
 			resPicture.push_back(std::make_shared<CAnimImage>("RESOURCE", i, 0, 0, 0));
-			resAmount.push_back(std::make_shared<CLabel>(0,0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, std::to_string(creature->cost[i])));
+			resAmount.push_back(std::make_shared<CLabel>(0,0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, std::to_string(creature->getRecruitCost(res))));
 		}
 	}
 
@@ -810,7 +811,7 @@ void CCastleBuildings::enterBlacksmith(ArtifactID artifactID)
 	auto art = artifactID.toArtifact();
 
 	int price = art->getPrice();
-	bool possible = LOCPLINT->cb->getResourceAmount(Res::GOLD) >= price;
+	bool possible = LOCPLINT->cb->getResourceAmount(EGameResID::GOLD) >= price;
 	if(possible)
 	{
 		for(auto slot : art->possibleSlots.at(ArtBearer::HERO))
@@ -942,7 +943,7 @@ void CCastleBuildings::enterMagesGuild()
 			// "Yog has given up magic in all its forms..."
 			LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[736]);
 		}
-		else if(LOCPLINT->cb->getResourceAmount(Res::GOLD) < 500) //not enough gold to buy spellbook
+		else if(LOCPLINT->cb->getResourceAmount(EGameResID::GOLD) < 500) //not enough gold to buy spellbook
 		{
 			openMagesGuild();
 			LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[213]);
@@ -1100,7 +1101,7 @@ void CCreaInfo::clickRight(tribool down, bool previousState)
 		if (showAvailable)
 			GH.pushIntT<CDwellingInfoBox>(GH.screenDimensions().x / 2, GH.screenDimensions().y / 2, town, level);
 		else
-			CRClickPopup::createAndPush(genGrowthText(), std::make_shared<CComponent>(CComponent::creature, creature->idNumber));
+			CRClickPopup::createAndPush(genGrowthText(), std::make_shared<CComponent>(CComponent::creature, creature->getId()));
 	}
 }
 
@@ -1279,7 +1280,7 @@ void CCastleInterface::recreateIcons()
 
 	icon->setFrame(iconIndex);
 	TResources townIncome = town->dailyIncome();
-	income->setText(std::to_string(townIncome[Res::GOLD]));
+	income->setText(std::to_string(townIncome[EGameResID::GOLD]));
 
 	hall = std::make_shared<CTownInfo>(80, 413, town, true);
 	fort = std::make_shared<CTownInfo>(122, 413, town, false);
@@ -1870,5 +1871,5 @@ CBlacksmithDialog::CBlacksmithDialog(bool possible, CreatureID creMachineID, Art
 	else
 		buy->block(true);
 
-	costIcon = std::make_shared<CAnimImage>("RESOURCE", Res::GOLD, 0, 148, 244);
+	costIcon = std::make_shared<CAnimImage>("RESOURCE", GameResID(EGameResID::GOLD), 0, 148, 244);
 }

+ 2 - 2
client/windows/CCreatureWindow.cpp

@@ -323,7 +323,7 @@ CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset)
 			};
 			auto upgradeBtn = std::make_shared<CButton>(Point(221 + (int)buttonIndex * 40, 5), "stackWindow/upgradeButton", CGI->generaltexth->zelp[446], onClick, SDLK_1);
 
-			upgradeBtn->addOverlay(std::make_shared<CAnimImage>("CPRSMALL", VLC->creh->objects[upgradeInfo.info.newID[buttonIndex]]->iconIndex));
+			upgradeBtn->addOverlay(std::make_shared<CAnimImage>("CPRSMALL", VLC->creh->objects[upgradeInfo.info.newID[buttonIndex]]->getIconIndex()));
 
 			if(buttonsToCreate == 1) // single upgrade avaialbe
 			{
@@ -844,7 +844,7 @@ std::string CStackWindow::generateStackExpDescription()
 	const CStackInstance * stack = info->stackNode;
 	const CCreature * creature = info->creature;
 
-	int tier = stack->type->level;
+	int tier = stack->type->getLevel();
 	int rank = stack->getExpRank();
 	if (!vstd::iswithin(tier, 1, 7))
 		tier = 0;

+ 6 - 6
client/windows/CKingdomInterface.cpp

@@ -564,7 +564,7 @@ std::shared_ptr<CIntObject> CKingdomInterface::createMainTab(size_t index)
 void CKingdomInterface::generateMinesList(const std::vector<const CGObjectInstance *> & ownedObjects)
 {
 	ui32 footerPos = conf.go()->ac.overviewSize * 116;
-	std::vector<int> minesCount(GameConstants::RESOURCE_QUANTITY, 0);
+	TResources minesCount(GameConstants::RESOURCE_QUANTITY, 0);
 	int totalIncome=0;
 
 	for(const CGObjectInstance * object : ownedObjects)
@@ -576,7 +576,7 @@ void CKingdomInterface::generateMinesList(const std::vector<const CGObjectInstan
 			assert(mine);
 			minesCount[mine->producedResource]++;
 
-			if (mine->producedResource == Res::GOLD)
+			if (mine->producedResource == EGameResID::GOLD)
 				totalIncome += mine->producedQuantity;
 		}
 	}
@@ -585,14 +585,14 @@ void CKingdomInterface::generateMinesList(const std::vector<const CGObjectInstan
 	std::vector<const CGHeroInstance*> heroes = LOCPLINT->cb->getHeroesInfo(true);
 	for(auto & heroe : heroes)
 	{
-		totalIncome += heroe->valOfBonuses(Selector::typeSubtype(Bonus::GENERATE_RESOURCE, Res::GOLD));
+		totalIncome += heroe->valOfBonuses(Selector::typeSubtype(Bonus::GENERATE_RESOURCE, GameResID(EGameResID::GOLD)));
 	}
 
 	//Add town income of all towns
 	std::vector<const CGTownInstance*> towns = LOCPLINT->cb->getTownsInfo(true);
 	for(auto & town : towns)
 	{
-		totalIncome += town->dailyIncome()[Res::GOLD];
+		totalIncome += town->dailyIncome()[EGameResID::GOLD];
 	}
 	for(int i=0; i<7; i++)
 	{
@@ -772,7 +772,7 @@ CTownItem::CTownItem(const CGTownInstance * Town)
 	background = std::make_shared<CAnimImage>("OVSLOT", 6);
 	name = std::make_shared<CLabel>(74, 8, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, town->getNameTranslated());
 
-	income = std::make_shared<CLabel>( 190, 60, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, std::to_string(town->dailyIncome()[Res::GOLD]));
+	income = std::make_shared<CLabel>( 190, 60, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, std::to_string(town->dailyIncome()[EGameResID::GOLD]));
 	hall = std::make_shared<CTownInfo>( 69, 31, town, true);
 	fort = std::make_shared<CTownInfo>(111, 31, town, false);
 
@@ -801,7 +801,7 @@ void CTownItem::updateGarrisons()
 
 void CTownItem::update()
 {
-	std::string incomeVal = std::to_string(town->dailyIncome()[Res::GOLD]);
+	std::string incomeVal = std::to_string(town->dailyIncome()[EGameResID::GOLD]);
 	if (incomeVal != income->getText())
 		income->setText(incomeVal);
 

+ 6 - 6
client/windows/CTradeWindow.cpp

@@ -191,7 +191,7 @@ void CTradeWindow::CTradeableItem::clickLeft(tribool down, bool previousState)
 				aw->arts->markPossibleSlots(art);
 
 				//aw->arts->commonInfo->dst.AOH = aw->arts;
-				CCS->curh->dragAndDropCursor("artifact", art->artType->iconIndex);
+				CCS->curh->dragAndDropCursor("artifact", art->artType->getIconIndex());
 
 				aw->arts->artifactsOnAltar.erase(art);
 				setID(-1);
@@ -447,7 +447,7 @@ std::vector<int> *CTradeWindow::getItemsIds(bool Left)
 			for(int i = 0; i < 7; i++)
 			{
 				if(const CCreature *c = hero->getCreature(SlotID(i)))
-					ids->push_back(c->idNumber);
+					ids->push_back(c->getId());
 				else
 					ids->push_back(-1);
 			}
@@ -535,7 +535,7 @@ void CTradeWindow::initSubs(bool Left)
 				item->subtitle = std::to_string(hero->getStackCount(SlotID(item->serial)));
 				break;
 			case RESOURCE:
-				item->subtitle = std::to_string(LOCPLINT->cb->getResourceAmount(static_cast<Res::ERes>(item->serial)));
+				item->subtitle = std::to_string(LOCPLINT->cb->getResourceAmount(static_cast<EGameResID>(item->serial)));
 				break;
 			}
 		}
@@ -869,7 +869,7 @@ void CMarketplaceWindow::selectionChanged(bool side)
 		{
 			int newAmount = -1;
 			if(itemsType[1] == RESOURCE)
-				newAmount = LOCPLINT->cb->getResourceAmount(static_cast<Res::ERes>(soldItemId));
+				newAmount = LOCPLINT->cb->getResourceAmount(static_cast<EGameResID>(soldItemId));
 			else if(itemsType[1] ==  CREATURE)
 				newAmount = hero->getStackCount(SlotID(hLeft->serial)) - (hero->stacksCount() == 1  &&  hero->needsLastStack());
 			else
@@ -882,7 +882,7 @@ void CMarketplaceWindow::selectionChanged(bool side)
 		}
 		else if(itemsType[1] == RESOURCE) //buying -> check if we can afford transaction
 		{
-			deal->block(LOCPLINT->cb->getResourceAmount(static_cast<Res::ERes>(soldItemId)) < r1);
+			deal->block(LOCPLINT->cb->getResourceAmount(static_cast<EGameResID>(soldItemId)) < r1);
 		}
 		else
 			deal->block(false);
@@ -1486,7 +1486,7 @@ void CAltarWindow::showAll(SDL_Surface * to)
 	CTradeWindow::showAll(to);
 	if(mode == EMarketMode::ARTIFACT_EXP && arts && arts->commonInfo->src.art)
 	{
-		artIcon->setFrame(arts->commonInfo->src.art->artType->iconIndex);
+		artIcon->setFrame(arts->commonInfo->src.art->artType->getIconIndex());
 		artIcon->showAll(to);
 
 		int dmp, val;

+ 4 - 4
client/windows/CreaturePurchaseCard.cpp

@@ -48,13 +48,13 @@ void CreaturePurchaseCard::initCreatureSwitcherButton()
 void CreaturePurchaseCard::switchCreatureLevel()
 {
 	OBJECT_CONSTRUCTION_CAPTURING(ACTIVATE + DEACTIVATE + UPDATE + SHOWALL + SHARE_POS);
-	auto index = vstd::find_pos(upgradesID, creatureOnTheCard->idNumber);
+	auto index = vstd::find_pos(upgradesID, creatureOnTheCard->getId());
 	auto nextCreatureId = vstd::circularAt(upgradesID, ++index);
 	creatureOnTheCard = nextCreatureId.toCreature();
 	picture = std::make_shared<CCreaturePic>(parent->pos.x, parent->pos.y, creatureOnTheCard);
 	creatureClickArea = std::make_shared<CCreatureClickArea>(Point(parent->pos.x, parent->pos.y), picture, creatureOnTheCard);
 	parent->updateAllSliders();
-	cost->set(creatureOnTheCard->cost * slider->getValue());
+	cost->set(creatureOnTheCard->getFullRecruitCost() * slider->getValue());
 }
 
 void CreaturePurchaseCard::initAmountInfo()
@@ -78,13 +78,13 @@ void CreaturePurchaseCard::initSlider()
 void CreaturePurchaseCard::initCostBox()
 {
 	cost = std::make_shared<CreatureCostBox>(Rect(pos.x+2, pos.y + 194, 97, 74), "");
-	cost->createItems(creatureOnTheCard->cost);
+	cost->createItems(creatureOnTheCard->getFullRecruitCost());
 }
 
 void CreaturePurchaseCard::sliderMoved(int to)
 {
 	updateAmountInfo(to);
-	cost->set(creatureOnTheCard->cost * to);
+	cost->set(creatureOnTheCard->getFullRecruitCost() * to);
 	parent->updateAllSliders();
 }
 

+ 18 - 18
client/windows/GUIClasses.cpp

@@ -135,11 +135,11 @@ void CRecruitmentWindow::select(std::shared_ptr<CCreatureCard> card)
 		else // if slider already at 0 - emulate call to sliderMoved()
 			sliderMoved(maxAmount);
 
-		costPerTroopValue->createItems(card->creature->cost);
-		totalCostValue->createItems(card->creature->cost);
+		costPerTroopValue->createItems(card->creature->getFullRecruitCost());
+		totalCostValue->createItems(card->creature->getFullRecruitCost());
 
-		costPerTroopValue->set(card->creature->cost);
-		totalCostValue->set(card->creature->cost * maxAmount);
+		costPerTroopValue->set(card->creature->getFullRecruitCost());
+		totalCostValue->set(card->creature->getFullRecruitCost() * maxAmount);
 
 		//Recruit %s
 		title->setText(boost::str(boost::format(CGI->generaltexth->tcommands[21]) % card->creature->getNamePluralTranslated()));
@@ -151,7 +151,7 @@ void CRecruitmentWindow::select(std::shared_ptr<CCreatureCard> card)
 
 void CRecruitmentWindow::buy()
 {
-	CreatureID crid =  selected->creature->idNumber;
+	CreatureID crid =  selected->creature->getId();
 	SlotID dstslot = dst-> getSlotFor(crid);
 
 	if(!dstslot.validSlot() && (selected->creature->warMachine == ArtifactID::NONE)) //no available slot
@@ -296,7 +296,7 @@ void CRecruitmentWindow::sliderMoved(int to)
 	availableValue->setText(std::to_string(selected->amount - to));
 	toRecruitValue->setText(std::to_string(to));
 
-	totalCostValue->set(selected->creature->cost * to);
+	totalCostValue->set(selected->creature->getFullRecruitCost() * to);
 }
 
 CSplitWindow::CSplitWindow(const CCreature * creature, std::function<void(int, int)> callback_, int leftMin_, int rightMin_, int leftAmount_, int rightAmount_)
@@ -463,7 +463,7 @@ CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj)
 	recruit = std::make_shared<CButton>(Point(272, 355), "TPTAV01.DEF", CButton::tooltip(), std::bind(&CTavernWindow::recruitb, this), SDLK_RETURN);
 	thiefGuild = std::make_shared<CButton>(Point(22, 428), "TPTAV02.DEF", CButton::tooltip(CGI->generaltexth->tavernInfo[5]), std::bind(&CTavernWindow::thievesguildb, this), SDLK_t);
 
-	if(LOCPLINT->cb->getResourceAmount(Res::GOLD) < GameConstants::HERO_GOLD_COST) //not enough gold
+	if(LOCPLINT->cb->getResourceAmount(EGameResID::GOLD) < GameConstants::HERO_GOLD_COST) //not enough gold
 	{
 		recruit->addHoverText(CButton::NORMAL, CGI->generaltexth->tavernInfo[0]); //Cannot afford a Hero
 		recruit->block(true);
@@ -811,7 +811,7 @@ void CExchangeController::moveArmy(bool leftToRight)
 			source->Slots(), 
 			[](const std::pair<SlotID, CStackInstance *> & s) -> int
 			{
-				return s.second->getCreatureID().toCreature()->AIValue;
+				return s.second->getCreatureID().toCreature()->getAIValue();
 			});
 
 		slot = weakestSlot->first;
@@ -1093,20 +1093,20 @@ CShipyardWindow::CShipyardWindow(const TResources & cost, int state, int boatTyp
 	bgShip->center(waterCenter);
 
 	// Create resource icons and costs.
-	std::string goldValue = std::to_string(cost[Res::GOLD]);
-	std::string woodValue = std::to_string(cost[Res::WOOD]);
+	std::string goldValue = std::to_string(cost[EGameResID::GOLD]);
+	std::string woodValue = std::to_string(cost[EGameResID::WOOD]);
 
 	goldCost = std::make_shared<CLabel>(118, 294, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, goldValue);
 	woodCost = std::make_shared<CLabel>(212, 294, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, woodValue);
 
-	goldPic = std::make_shared<CAnimImage>("RESOURCE", Res::GOLD, 0, 100, 244);
-	woodPic = std::make_shared<CAnimImage>("RESOURCE", Res::WOOD, 0, 196, 244);
+	goldPic = std::make_shared<CAnimImage>("RESOURCE",GameResID(EGameResID::GOLD), 0, 100, 244);
+	woodPic = std::make_shared<CAnimImage>("RESOURCE", GameResID(EGameResID::WOOD), 0, 196, 244);
 
 	quit = std::make_shared<CButton>(Point(224, 312), "ICANCEL", CButton::tooltip(CGI->generaltexth->allTexts[599]), std::bind(&CShipyardWindow::close, this), SDLK_ESCAPE);
 	build = std::make_shared<CButton>(Point(42, 312), "IBUY30", CButton::tooltip(CGI->generaltexth->allTexts[598]), std::bind(&CShipyardWindow::close, this), SDLK_RETURN);
 	build->addCallback(onBuy);
 
-	for(Res::ERes i = Res::WOOD; i <= Res::GOLD; vstd::advance(i, 1))
+	for(auto i = EGameResID::WOOD; i <= EGameResID::GOLD; vstd::advance(i, 1))
 	{
 		if(cost[i] > LOCPLINT->cb->getResourceAmount(i))
 		{
@@ -1141,7 +1141,7 @@ void CTransformerWindow::CItem::clickLeft(tribool down, bool previousState)
 
 void CTransformerWindow::CItem::update()
 {
-	icon->setFrame(parent->army->getCreature(SlotID(id))->idNumber + 2);
+	icon->setFrame(parent->army->getCreature(SlotID(id))->getId() + 2);
 }
 
 CTransformerWindow::CItem::CItem(CTransformerWindow * parent_, int size_, int id_)
@@ -1157,7 +1157,7 @@ CTransformerWindow::CItem::CItem(CTransformerWindow * parent_, int size_, int id
 
 	pos.x += 45  + (id%3)*83 + id/6*83;
 	pos.y += 109 + (id/3)*98;
-	icon = std::make_shared<CAnimImage>("TWCRPORT", parent->army->getCreature(SlotID(id))->idNumber + 2);
+	icon = std::make_shared<CAnimImage>("TWCRPORT", parent->army->getCreature(SlotID(id))->getId() + 2);
 	count = std::make_shared<CLabel>(28, 76,FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, std::to_string(size));
 }
 
@@ -1240,7 +1240,7 @@ void CUniversityWindow::CItem::clickLeft(tribool down, bool previousState)
 	if(previousState && (!down))
 	{
 		if(state() == 2)
-			GH.pushIntT<CUnivConfirmWindow>(parent, ID, LOCPLINT->cb->getResourceAmount(Res::GOLD) >= 2000);
+			GH.pushIntT<CUnivConfirmWindow>(parent, ID, LOCPLINT->cb->getResourceAmount(EGameResID::GOLD) >= 2000);
 	}
 }
 
@@ -1346,7 +1346,7 @@ CUnivConfirmWindow::CUnivConfirmWindow(CUniversityWindow * owner_, int SKILL, bo
 	icon = std::make_shared<CAnimImage>("SECSKILL", SKILL*3+3, 0, 211, 51);
 	level = std::make_shared<CLabel>(230, 107, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->levels[1]);
 
-	costIcon = std::make_shared<CAnimImage>("RESOURCE", Res::GOLD, 0, 210, 210);
+	costIcon = std::make_shared<CAnimImage>("RESOURCE", GameResID(EGameResID::GOLD), 0, 210, 210);
 	cost = std::make_shared<CLabel>(230, 267, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, "2000");
 
 	std::string hoverText = CGI->generaltexth->allTexts[609];
@@ -1531,7 +1531,7 @@ void CHillFortWindow::updateGarrisons()
 			else//free upgrade - print gold image and "Free" text
 			{
 				slotIcons[i][0]->visible = true;
-				slotIcons[i][0]->setFrame(Res::GOLD);
+				slotIcons[i][0]->setFrame(GameResID(EGameResID::GOLD));
 				slotLabels[i][0]->setText(CGI->generaltexth->allTexts[344]);
 			}
 		}

+ 4 - 4
client/windows/QuickRecruitmentWindow.cpp

@@ -93,7 +93,7 @@ void QuickRecruitmentWindow::maxAllCards(std::vector<std::shared_ptr<CreaturePur
 			i->sliderMoved(maxAmount);
 
 		i->slider->moveToMax();
-		allAvailableResources -= (i->creatureOnTheCard->cost * maxAmount);
+		allAvailableResources -= (i->creatureOnTheCard->getFullRecruitCost() * maxAmount);
 	}
 	maxButton->block(allAvailableResources == LOCPLINT->cb->getResourceAmount());
 }
@@ -105,8 +105,8 @@ void QuickRecruitmentWindow::purchaseUnits()
 	{
 		if(selected->slider->getValue())
 		{
-			auto onRecruit = [=](CreatureID id, int count){ LOCPLINT->cb->recruitCreatures(town, town->getUpperArmy(), id, count, selected->creatureOnTheCard->level-1); };
-			CreatureID crid =  selected->creatureOnTheCard->idNumber;
+			auto onRecruit = [=](CreatureID id, int count){ LOCPLINT->cb->recruitCreatures(town, town->getUpperArmy(), id, count, selected->creatureOnTheCard->getLevel()-1); };
+			CreatureID crid =  selected->creatureOnTheCard->getId();
 			SlotID dstslot = town -> getSlotFor(crid);
 			if(!dstslot.validSlot())
 				continue;
@@ -129,7 +129,7 @@ void QuickRecruitmentWindow::updateAllSliders()
 {
 	auto allAvailableResources = LOCPLINT->cb->getResourceAmount();
 	for(auto i : boost::adaptors::reverse(cards))
-		allAvailableResources -= (i->creatureOnTheCard->cost * i->slider->getValue());
+		allAvailableResources -= (i->creatureOnTheCard->getFullRecruitCost() * i->slider->getValue());
 	for(auto i : cards)
 	{
 		si32 maxAmount = i->creatureOnTheCard->maxAmount(allAvailableResources);

+ 6 - 1
include/vcmi/Creature.h

@@ -15,6 +15,8 @@
 VCMI_LIB_NAMESPACE_BEGIN
 
 class CreatureID;
+class ResourceSet;
+enum class EGameResID : int8_t;
 
 class DLL_LINKAGE Creature : public EntityWithBonuses<CreatureID>
 {
@@ -50,7 +52,10 @@ public:
 	virtual int32_t getBaseSpeed() const = 0;
 	virtual int32_t getBaseShots() const = 0;
 
-	virtual int32_t getCost(int32_t resIndex) const = 0;
+	virtual int32_t getRecruitCost(Identifier<EGameResID> resIndex) const = 0;
+	virtual ResourceSet getFullRecruitCost() const = 0;
+	
+	virtual bool hasUpgrades() const = 0;
 
 	virtual bool isDoubleWide() const = 0;
 };

+ 7 - 3
include/vcmi/Entity.h

@@ -14,6 +14,12 @@ VCMI_LIB_NAMESPACE_BEGIN
 
 class IBonusBearer;
 
+class DLL_LINKAGE WithBonuses
+{
+public:
+	virtual const IBonusBearer * getBonusBearer() const = 0;
+};
+
 class DLL_LINKAGE Entity
 {
 public:
@@ -38,10 +44,8 @@ public:
 };
 
 template <typename IdType>
-class DLL_LINKAGE EntityWithBonuses : public EntityT<IdType>
+class DLL_LINKAGE EntityWithBonuses : public EntityT<IdType>, public WithBonuses
 {
-public:
-	virtual const IBonusBearer * accessBonuses() const = 0;
 };
 
 VCMI_LIB_NAMESPACE_END

+ 1 - 1
lib/CArtHandler.cpp

@@ -77,7 +77,7 @@ ArtifactID CArtifact::getId() const
 	return id;
 }
 
-const IBonusBearer * CArtifact::accessBonuses() const
+const IBonusBearer * CArtifact::getBonusBearer() const
 {
 	return this;
 }

+ 1 - 1
lib/CArtHandler.h

@@ -69,7 +69,7 @@ public:
 	std::string getJsonKey() const override;
 	void registerIcons(const IconRegistar & cb) const override;
 	ArtifactID getId() const override;
-	virtual const IBonusBearer * accessBonuses() const override;
+	virtual const IBonusBearer * getBonusBearer() const override;
 
 	std::string getDescriptionTranslated() const override;
 	std::string getEventTranslated() const override;

+ 20 - 10
lib/CCreatureHandler.cpp

@@ -64,7 +64,7 @@ CreatureID CCreature::getId() const
 	return idNumber;
 }
 
-const IBonusBearer * CCreature::accessBonuses() const
+const IBonusBearer * CCreature::getBonusBearer() const
 {
 	return this;
 }
@@ -162,7 +162,7 @@ int32_t CCreature::getBaseShots() const
 	return getExportedBonusList().valOfBonuses(SELECTOR);
 }
 
-int32_t CCreature::getCost(int32_t resIndex) const
+int32_t CCreature::getRecruitCost(GameResID resIndex) const
 {
 	if(resIndex >= 0 && resIndex < cost.size())
 		return cost[resIndex];
@@ -170,6 +170,16 @@ int32_t CCreature::getCost(int32_t resIndex) const
 		return 0;
 }
 
+TResources CCreature::getFullRecruitCost() const
+{
+	return cost;
+}
+
+bool CCreature::hasUpgrades() const 
+{
+	return !upgrades.empty();
+}
+
 std::string CCreature::getNameTranslated() const
 {
 	return getNameSingularTranslated();
@@ -307,7 +317,7 @@ void CCreature::addBonus(int val, Bonus::BonusType type, int subtype)
 bool CCreature::isMyUpgrade(const CCreature *anotherCre) const
 {
 	//TODO upgrade of upgrade?
-	return vstd::contains(upgrades, anotherCre->idNumber);
+	return vstd::contains(upgrades, anotherCre->getId());
 }
 
 bool CCreature::valid() const
@@ -614,7 +624,7 @@ CCreature * CCreatureHandler::loadFromJson(const std::string & scope, const Json
 	JsonDeserializer handler(nullptr, node);
 	cre->serializeJson(handler);
 
-	cre->cost = Res::ResourceSet(node["cost"]);
+	cre->cost = ResourceSet(node["cost"]);
 
 	VLC->generaltexth->registerString(scope, cre->getNameSingularTextID(), node["name"]["singular"].String());
 	VLC->generaltexth->registerString(scope, cre->getNamePluralTextID(), node["name"]["plural"].String());
@@ -647,18 +657,18 @@ CCreature * CCreatureHandler::loadFromJson(const std::string & scope, const Json
 		JsonNode conf;
 		conf.setMeta(scope);
 
-		VLC->objtypeh->loadSubObject(cre->identifier, conf, Obj::MONSTER, cre->idNumber.num);
+		VLC->objtypeh->loadSubObject(cre->identifier, conf, Obj::MONSTER, cre->getId().num);
 		if (!cre->advMapDef.empty())
 		{
 			JsonNode templ;
 			templ["animation"].String() = cre->advMapDef;
 			templ.setMeta(scope);
-			VLC->objtypeh->getHandlerFor(Obj::MONSTER, cre->idNumber.num)->addTemplate(templ);
+			VLC->objtypeh->getHandlerFor(Obj::MONSTER, cre->getId().num)->addTemplate(templ);
 		}
 
 		// object does not have any templates - this is not usable object (e.g. pseudo-creature like Arrow Tower)
-		if (VLC->objtypeh->getHandlerFor(Obj::MONSTER, cre->idNumber.num)->getTemplates().empty())
-			VLC->objtypeh->removeSubObject(Obj::MONSTER, cre->idNumber.num);
+		if (VLC->objtypeh->getHandlerFor(Obj::MONSTER, cre->getId().num)->getTemplates().empty())
+			VLC->objtypeh->removeSubObject(Obj::MONSTER, cre->getId().num);
 	});
 
 	return cre;
@@ -1335,7 +1345,7 @@ CreatureID CCreatureHandler::pickRandomMonster(CRandomGenerator & rand, int tier
 	{
 		do
 		{
-			r = (*RandomGeneratorUtil::nextItem(objects, rand))->idNumber;
+			r = (*RandomGeneratorUtil::nextItem(objects, rand))->getId();
 		} while (objects[r] && objects[r]->special); // find first "not special" creature
 	}
 	else
@@ -1347,7 +1357,7 @@ CreatureID CCreatureHandler::pickRandomMonster(CRandomGenerator & rand, int tier
 			assert(b->getNodeType() == CBonusSystemNode::CREATURE);
 			const auto * crea = dynamic_cast<const CCreature *>(b);
 			if(crea && !crea->special)
-				allowed.push_back(crea->idNumber);
+				allowed.push_back(crea->getId());
 		}
 
 		if(allowed.empty())

+ 15 - 9
lib/CCreatureHandler.h

@@ -9,9 +9,6 @@
  */
 #pragma once
 
-#include <vcmi/Creature.h>
-#include <vcmi/CreatureService.h>
-
 #include "HeroBonus.h"
 #include "ConstTransitivePtr.h"
 #include "ResourceSet.h"
@@ -21,6 +18,9 @@
 #include "CRandomGenerator.h"
 #include "Color.h"
 
+#include <vcmi/Creature.h>
+#include <vcmi/CreatureService.h>
+
 VCMI_LIB_NAMESPACE_BEGIN
 
 class CLegacyConfigParser;
@@ -37,7 +37,6 @@ class DLL_LINKAGE CCreature : public Creature, public CBonusSystemNode
 	std::string getNameTranslated() const override;
 	std::string getNameTextID() const override;
 
-public:
 	CreatureID idNumber;
 
 	TFaction faction = 0;
@@ -45,17 +44,22 @@ public:
 
 	//stats that are not handled by bonus system
 	ui32 fightValue, AIValue, growth, hordeGrowth;
-	ui32 ammMin, ammMax; // initial size of stack of these creatures on adventure map (if not set in editor)
 
 	bool doubleWide = false;
-	bool special = true; // Creature is not available normally (war machines, commanders, several unused creatures, etc
+
+	si32 iconIndex = -1; // index of icon in files like twcrport
 
 	TResources cost; //cost[res_id] - amount of that resource required to buy creature from dwelling
+
+public:
+	ui32 ammMin, ammMax; // initial size of stack of these creatures on adventure map (if not set in editor)
+
+	bool special = true; // Creature is not available normally (war machines, commanders, several unused creatures, etc
+
 	std::set<CreatureID> upgrades; // IDs of creatures to which this creature can be upgraded
 
 	std::string animDefName; // creature animation used during battles
 	std::string advMapDef; //for new creatures only, image for adventure map
-	si32 iconIndex = -1; // index of icon in files like twcrport
 
 	/// names of files with appropriate icons. Used only during loading
 	std::string smallIconName;
@@ -168,7 +172,7 @@ public:
 	std::string getJsonKey() const override;
 	void registerIcons(const IconRegistar & cb) const override;
 	CreatureID getId() const override;
-	virtual const IBonusBearer * accessBonuses() const override;
+	virtual const IBonusBearer * getBonusBearer() const override;
 	uint32_t getMaxHealth() const override;
 
 	int32_t getAdvMapAmountMin() const override;
@@ -189,8 +193,10 @@ public:
 	int32_t getBaseSpeed() const override;
 	int32_t getBaseShots() const override;
 
-	int32_t getCost(int32_t resIndex) const override;
+	int32_t getRecruitCost(GameResID resIndex) const override;
+	TResources getFullRecruitCost() const override;
 	bool isDoubleWide() const override; //returns true if unit is double wide on battlefield
+	bool hasUpgrades() const override;
 
 	bool isGood () const;
 	bool isEvil () const;

+ 9 - 9
lib/CCreatureSet.cpp

@@ -590,12 +590,12 @@ bool CCreatureSet::canBeMergedWith(const CCreatureSet &cs, bool allowMergingStac
 		//get types of creatures that need their own slot
 		for(const auto & elem : cs.stacks)
 			if ((j = cres.getSlotFor(elem.second->type)).validSlot())
-				cres.addToSlot(j, elem.second->type->idNumber, 1, true);  //merge if possible
-			//cres.addToSlot(elem.first, elem.second->type->idNumber, 1, true);
+				cres.addToSlot(j, elem.second->type->getId(), 1, true);  //merge if possible
+			//cres.addToSlot(elem.first, elem.second->type->getId(), 1, true);
 		for(const auto & elem : stacks)
 		{
 			if ((j = cres.getSlotFor(elem.second->type)).validSlot())
-				cres.addToSlot(j, elem.second->type->idNumber, 1, true);  //merge if possible
+				cres.addToSlot(j, elem.second->type->getId(), 1, true);  //merge if possible
 			else
 				return false; //no place found
 		}
@@ -706,7 +706,7 @@ int CStackInstance::getExpRank() const
 {
 	if (!VLC->settings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE))
 		return 0;
-	int tier = type->level;
+	int tier = type->getLevel();
 	if (vstd::iswithin(tier, 1, 7))
 	{
 		for(int i = static_cast<int>(VLC->creh->expRanks[tier].size()) - 2; i > -1; --i) //sic!
@@ -729,7 +729,7 @@ int CStackInstance::getExpRank() const
 
 int CStackInstance::getLevel() const
 {
-	return std::max(1, static_cast<int>(type->level));
+	return std::max(1, static_cast<int>(type->getLevel()));
 }
 
 si32 CStackInstance::magicResistance() const
@@ -741,7 +741,7 @@ si32 CStackInstance::magicResistance() const
 
 void CStackInstance::giveStackExp(TExpType exp)
 {
-	int level = type->level;
+	int level = type->getLevel();
 	if (!vstd::iswithin(level, 1, 7))
 		level = 0;
 
@@ -816,7 +816,7 @@ bool CStackInstance::valid(bool allowUnrandomized) const
 	bool isRand = (idRand != -1);
 	if(!isRand)
 	{
-		return (type  &&  type == VLC->creh->objects[type->idNumber]);
+		return (type  &&  type == VLC->creh->objects[type->getId()]);
 	}
 	else
 		return allowUnrandomized;
@@ -852,7 +852,7 @@ void CStackInstance::deserializationFix()
 CreatureID CStackInstance::getCreatureID() const
 {
 	if(type)
-		return type->idNumber;
+		return type->getId();
 	else
 		return CreatureID::NONE;
 }
@@ -865,7 +865,7 @@ std::string CStackInstance::getName() const
 ui64 CStackInstance::getPower() const
 {
 	assert(type);
-	return type->AIValue * count;
+	return type->getAIValue() * count;
 }
 
 ArtBearer::ArtBearer CStackInstance::bearerType() const

+ 2 - 2
lib/CCreatureSet.h

@@ -43,7 +43,7 @@ public:
 	{
 		if(h.saving)
 		{
-			CreatureID idNumber = type ? type->idNumber : CreatureID(CreatureID::NONE);
+			auto idNumber = type ? type->getId() : CreatureID(CreatureID::NONE);
 			h & idNumber;
 		}
 		else
@@ -51,7 +51,7 @@ public:
 			CreatureID idNumber;
 			h & idNumber;
 			if(idNumber != CreatureID::NONE)
-				setType(VLC->creh->objects[idNumber]);
+				setType(dynamic_cast<const CCreature*>(VLC->creatures()->getByIndex(idNumber)));
 			else
 				type = nullptr;
 		}

+ 6 - 6
lib/CGameInfoCallback.cpp

@@ -37,7 +37,7 @@ PlayerColor CGameInfoCallback::getOwner(ObjectInstanceID heroID) const
 	return obj->tempOwner;
 }
 
-int CGameInfoCallback::getResource(PlayerColor Player, Res::ERes which) const
+int CGameInfoCallback::getResource(PlayerColor Player, GameResID which) const
 {
 	const PlayerState *p = getPlayerState(Player);
 	ERROR_RET_VAL_IF(!p, "No player info!", -1);
@@ -323,9 +323,9 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
 
 			for(auto & elem : info.army)
 			{
-				if(static_cast<int>(elem.second.type->AIValue) > maxAIValue)
+				if(static_cast<int>(elem.second.type->getAIValue()) > maxAIValue)
 				{
-					maxAIValue = elem.second.type->AIValue;
+					maxAIValue = elem.second.type->getAIValue();
 					mostStrong = elem.second.type;
 				}
 			}
@@ -359,9 +359,9 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
 
 			for(auto creature : VLC->creh->objects)
 			{
-				if(static_cast<si16>(creature->faction) == factionIndex && static_cast<int>(creature->AIValue) > maxAIValue)
+				if(static_cast<si16>(creature->getFactionIndex()) == factionIndex && static_cast<int>(creature->getAIValue()) > maxAIValue)
 				{
-					maxAIValue = creature->AIValue;
+					maxAIValue = creature->getAIValue();
 					mostStrong = creature;
 				}
 			}
@@ -860,7 +860,7 @@ const CGTownInstance* CPlayerSpecificInfoCallback::getTownBySerial(int serialId)
 	return p->towns[serialId];
 }
 
-int CPlayerSpecificInfoCallback::getResourceAmount(Res::ERes type) const
+int CPlayerSpecificInfoCallback::getResourceAmount(GameResID type) const
 {
 	//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", -1);

+ 4 - 4
lib/CGameInfoCallback.h

@@ -10,7 +10,7 @@
 #pragma once
 
 #include "int3.h"
-#include "ResourceSet.h" // for Res::ERes
+#include "ResourceSet.h" // for Res
 #include "battle/CCallbackBase.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
@@ -58,7 +58,7 @@ public:
 
 	//player
 	virtual const Player * getPlayer(PlayerColor color) const = 0;
-//	virtual int getResource(PlayerColor Player, Res::ERes which) const = 0;
+//	virtual int getResource(PlayerColor Player, EGameResID which) const = 0;
 //	bool isVisible(int3 pos) const;
 //	PlayerRelations::PlayerRelations getPlayerRelations(PlayerColor color1, PlayerColor color2) const;
 //	void getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInstance * obj); //get thieves' guild info obtainable while visiting given object
@@ -148,7 +148,7 @@ public:
 	//player
 	const Player * getPlayer(PlayerColor color) const override;
 	virtual const PlayerState * getPlayerState(PlayerColor color, bool verbose = true) const;
-	virtual int getResource(PlayerColor Player, Res::ERes which) const;
+	virtual int getResource(PlayerColor Player, GameResID which) const;
 	virtual PlayerRelations::PlayerRelations getPlayerRelations(PlayerColor color1, PlayerColor color2) const;
 	virtual void getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInstance * obj); //get thieves' guild info obtainable while visiting given object
 	virtual EPlayerStatus::EStatus getPlayerStatus(PlayerColor player, bool verbose = true) const; //-1 if no such player
@@ -245,7 +245,7 @@ public:
 	virtual std::vector <const CGObjectInstance * > getMyObjects() const; //returns all objects flagged by belonging player
 	virtual std::vector <QuestInfo> getMyQuests() const;
 
-	virtual int getResourceAmount(Res::ERes type) const;
+	virtual int getResourceAmount(GameResID type) const;
 	virtual TResources getResourceAmount() const;
 	virtual std::shared_ptr<const boost::multi_array<ui8, 3>> getVisibilityMap() const; //returns visibility map
 	//virtual const PlayerSettings * getPlayerSettings(PlayerColor color) const;

+ 33 - 29
lib/CGameState.cpp

@@ -293,7 +293,7 @@ void MetaString::addCreReplacement(const CreatureID & id, TQuantity count) //add
 void MetaString::addReplacement(const CStackBasicDescriptor & stack)
 {
 	assert(stack.type); //valid type
-	addCreReplacement(stack.type->idNumber, stack.count);
+	addCreReplacement(stack.type->getId(), stack.count);
 }
 
 static CGObjectInstance * createObject(const Obj & id, int subid, const int3 & pos, const PlayerColor & owner)
@@ -1443,10 +1443,14 @@ void CGameState::initStartingResources()
 					res.push_back(chosenBonus->info1);
 					break;
 				case 0xFD: //wood+ore
-					res.push_back(Res::WOOD); res.push_back(Res::ORE);
+					res.push_back(GameResID(EGameResID::WOOD)); 
+					res.push_back(GameResID(EGameResID::ORE));
 					break;
 				case 0xFE:  //rare
-					res.push_back(Res::MERCURY); res.push_back(Res::SULFUR); res.push_back(Res::CRYSTAL); res.push_back(Res::GEMS);
+					res.push_back(GameResID(EGameResID::MERCURY));
+					res.push_back(GameResID(EGameResID::SULFUR));
+					res.push_back(GameResID(EGameResID::CRYSTAL));
+					res.push_back(GameResID(EGameResID::GEMS));
 					break;
 				default:
 					assert(0);
@@ -1664,16 +1668,16 @@ void CGameState::initStartingBonus()
 		switch(scenarioOps->playerInfos[elem.first].bonus)
 		{
 		case PlayerSettings::GOLD:
-			elem.second.resources[Res::GOLD] += getRandomGenerator().nextInt(5, 10) * 100;
+			elem.second.resources[EGameResID::GOLD] += getRandomGenerator().nextInt(5, 10) * 100;
 			break;
 		case PlayerSettings::RESOURCE:
 			{
-				int res = (*VLC->townh)[scenarioOps->playerInfos[elem.first].castle]->town->primaryRes;
-				if(res == Res::WOOD_AND_ORE)
+				auto res = (*VLC->townh)[scenarioOps->playerInfos[elem.first].castle]->town->primaryRes;
+				if(res == EGameResID::WOOD_AND_ORE)
 				{
 					int amount = getRandomGenerator().nextInt(5, 10);
-					elem.second.resources[Res::WOOD] += amount;
-					elem.second.resources[Res::ORE] += amount;
+					elem.second.resources[EGameResID::WOOD] += amount;
+					elem.second.resources[EGameResID::ORE] += amount;
 				}
 				else
 				{
@@ -2016,14 +2020,14 @@ UpgradeInfo CGameState::fillUpgradeInfo(const CStackInstance &stack) const
 		t = dynamic_cast<const CGTownInstance *>(stack.armyObj);
 	else if(h)
 	{	//hero specialty
-		TConstBonusListPtr lista = h->getBonuses(Selector::typeSubtype(Bonus::SPECIAL_UPGRADE, base->idNumber));
+		TConstBonusListPtr lista = h->getBonuses(Selector::typeSubtype(Bonus::SPECIAL_UPGRADE, base->getId()));
 		for(const auto & it : *lista)
 		{
 			auto nid = CreatureID(it->additionalInfo[0]);
-			if (nid != base->idNumber) //in very specific case the upgrade is available by default (?)
+			if (nid != base->getId()) //in very specific case the upgrade is available by default (?)
 			{
 				ret.newID.push_back(nid);
-				ret.cost.push_back(VLC->creh->objects[nid]->cost - base->cost);
+				ret.cost.push_back(nid.toCreature()->getFullRecruitCost() - base->getFullRecruitCost());
 			}
 		}
 		t = h->visitedTown;
@@ -2032,14 +2036,14 @@ UpgradeInfo CGameState::fillUpgradeInfo(const CStackInstance &stack) const
 	{
 		for(const CGTownInstance::TCreaturesSet::value_type & dwelling : t->creatures)
 		{
-			if (vstd::contains(dwelling.second, base->idNumber)) //Dwelling with our creature
+			if (vstd::contains(dwelling.second, base->getId())) //Dwelling with our creature
 			{
 				for(const auto & upgrID : dwelling.second)
 				{
 					if(vstd::contains(base->upgrades, upgrID)) //possible upgrade
 					{
 						ret.newID.push_back(upgrID);
-						ret.cost.push_back(VLC->creh->objects[upgrID]->cost - base->cost);
+						ret.cost.push_back(upgrID.toCreature()->getFullRecruitCost() - base->getFullRecruitCost());
 					}
 				}
 			}
@@ -2050,19 +2054,19 @@ UpgradeInfo CGameState::fillUpgradeInfo(const CStackInstance &stack) const
 	if(h && map->getTile(h->visitablePos()).visitableObjects.front()->ID == Obj::HILL_FORT)
 	{
 		static const int costModifiers[] = {0, 25, 50, 75, 100}; //we get cheaper upgrades depending on level
-		const int costModifier = costModifiers[std::min<int>(std::max((int)base->level - 1, 0), ARRAY_COUNT(costModifiers) - 1)];
+		const int costModifier = costModifiers[std::min<int>(std::max((int)base->getLevel() - 1, 0), ARRAY_COUNT(costModifiers) - 1)];
 
 		for(const auto & nid : base->upgrades)
 		{
 			ret.newID.push_back(nid);
-			ret.cost.push_back((VLC->creh->objects[nid]->cost - base->cost) * costModifier / 100);
+			ret.cost.push_back((nid.toCreature()->getFullRecruitCost() - base->getFullRecruitCost()) * costModifier / 100);
 		}
 	}
 
 	if(!ret.newID.empty())
-		ret.oldID = base->idNumber;
+		ret.oldID = base->getId();
 
-	for (Res::ResourceSet &cost : ret.cost)
+	for (ResourceSet &cost : ret.cost)
 		cost.positive(); //upgrade cost can't be negative, ignore missing resources
 
 	return ret;
@@ -2346,7 +2350,7 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio
 					&& (ai = dynamic_cast<const CArmedInstance *>(object.get()))) //contains army
 				{
 					for(const auto & elem : ai->Slots()) //iterate through army
-						if(elem.second->type->idNumber == condition.objectType) //it's searched creature
+						if(elem.second->type->getId() == condition.objectType) //it's searched creature
 							total += elem.second->count;
 				}
 			}
@@ -2584,7 +2588,7 @@ struct statsHLP
 		//Heroes can produce gold as well - skill, specialty or arts
 		for(const auto & h : ps->heroes)
 		{
-			totalIncome += h->valOfBonuses(Selector::typeSubtype(Bonus::GENERATE_RESOURCE, Res::GOLD));
+			totalIncome += h->valOfBonuses(Selector::typeSubtype(Bonus::GENERATE_RESOURCE, GameResID(EGameResID::GOLD)));
 
 			if(!heroOrTown)
 				heroOrTown = h;
@@ -2593,7 +2597,7 @@ struct statsHLP
 		//Add town income of all towns
 		for(const auto & t : ps->towns)
 		{
-			totalIncome += t->dailyIncome()[Res::GOLD];
+			totalIncome += t->dailyIncome()[EGameResID::GOLD];
 
 			if(!heroOrTown)
 				heroOrTown = t;
@@ -2618,7 +2622,7 @@ struct statsHLP
 				const auto * mine = dynamic_cast<const CGMine *>(object);
 				assert(mine);
 
-				if (mine->producedResource == Res::GOLD)
+				if (mine->producedResource == EGameResID::GOLD)
 					totalIncome += mine->producedQuantity;
 			}
 		}
@@ -2677,15 +2681,15 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level)
 	}
 	if(level >= 2) //gold
 	{
-		FILL_FIELD(gold, g->second.resources[Res::GOLD])
+		FILL_FIELD(gold, g->second.resources[EGameResID::GOLD])
 	}
 	if(level >= 2) //wood & ore
 	{
-		FILL_FIELD(woodOre, g->second.resources[Res::WOOD] + g->second.resources[Res::ORE])
+		FILL_FIELD(woodOre, g->second.resources[EGameResID::WOOD] + g->second.resources[EGameResID::ORE])
 	}
 	if(level >= 3) //mercury, sulfur, crystal, gems
 	{
-		FILL_FIELD(mercSulfCrystGems, g->second.resources[Res::MERCURY] + g->second.resources[Res::SULFUR] + g->second.resources[Res::CRYSTAL] + g->second.resources[Res::GEMS])
+		FILL_FIELD(mercSulfCrystGems, g->second.resources[EGameResID::MERCURY] + g->second.resources[EGameResID::SULFUR] + g->second.resources[EGameResID::CRYSTAL] + g->second.resources[EGameResID::GEMS])
 	}
 	if(level >= 3) //obelisks found
 	{
@@ -2744,8 +2748,8 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level)
 			{
 				for(const auto & it : elem->Slots())
 				{
-					int toCmp = it.second->type->idNumber; //ID of creature we should compare with the best one
-					if(bestCre == -1 || VLC->creh->objects[bestCre]->AIValue < VLC->creh->objects[toCmp]->AIValue)
+					int toCmp = it.second->type->getId(); //ID of creature we should compare with the best one
+					if(bestCre == -1 || VLC->creh->objects[bestCre]->getAIValue() < VLC->creh->objects[toCmp]->getAIValue())
 					{
 						bestCre = toCmp;
 					}
@@ -3138,7 +3142,7 @@ void InfoAboutTown::initFromTown(const CGTownInstance *t, bool detailed)
 		//include details about hero
 		details = new Details();
 		TResources income = t->dailyIncome();
-		details->goldIncome = income[Res::GOLD];
+		details->goldIncome = income[EGameResID::GOLD];
 		details->customRes = t->hasBuilt(BuildingID::RESOURCE_SILO);
 		details->hallLevel = t->hallLevel();
 		details->garrisonedHero = t->garrisonHero;
@@ -3169,12 +3173,12 @@ int ArmyDescriptor::getStrength() const
 	if(isDetailed)
 	{
 		for(const auto & elem : *this)
-			ret += elem.second.type->AIValue * elem.second.count;
+			ret += elem.second.type->getAIValue() * elem.second.count;
 	}
 	else
 	{
 		for(const auto & elem : *this)
-			ret += elem.second.type->AIValue * CCreature::estimateCreatureCount(elem.second.count);
+			ret += elem.second.type->getAIValue() * CCreature::estimateCreatureCount(elem.second.count);
 	}
 	return static_cast<int>(ret);
 }

+ 1 - 1
lib/CGameStateFwd.h

@@ -164,7 +164,7 @@ private:
 	{
 	}
 
-	si32 intValue; // uses EResult
+	si32 intValue; // uses EResultult
 };
 
 /*static std::ostream & operator<<(std::ostream & os, const EVictoryLossCheckResult & victoryLossCheckResult)

+ 1 - 1
lib/CHeroHandler.cpp

@@ -529,7 +529,7 @@ static std::vector<std::shared_ptr<Bonus>> createCreatureSpecialty(CreatureID ba
 	for(CreatureID cid : targets)
 	{
 		const CCreature &specCreature = *VLC->creh->objects[cid];
-		int stepSize = specCreature.level ? specCreature.level : 5;
+		int stepSize = specCreature.getLevel() ? specCreature.getLevel() : 5;
 
 		{
 			std::shared_ptr<Bonus> bonus = std::make_shared<Bonus>();

+ 1 - 1
lib/CPlayerState.cpp

@@ -86,7 +86,7 @@ bool PlayerState::isHuman() const
 	return human;
 }
 
-const IBonusBearer * PlayerState::accessBonuses() const
+const IBonusBearer * PlayerState::getBonusBearer() const
 {
 	return this;
 }

+ 1 - 1
lib/CPlayerState.h

@@ -48,7 +48,7 @@ public:
 	PlayerColor getId() const override;
 	TeamID getTeam() const override;
 	bool isHuman() const override;
-	const IBonusBearer * accessBonuses() const override;
+	const IBonusBearer * getBonusBearer() const override;
 	int getResourceAmount(int type) const override;
 
 	int32_t getIndex() const override;

+ 2 - 2
lib/CStack.cpp

@@ -88,7 +88,7 @@ ui32 CStack::level() const
 	if(base)
 		return base->getLevel(); //creature or commander
 	else
-		return std::max(1, static_cast<int>(getCreature()->level)); //war machine, clone etc
+		return std::max(1, static_cast<int>(getCreature()->getLevel())); //war machine, clone etc
 }
 
 si32 CStack::magicResistance() const
@@ -342,7 +342,7 @@ bool CStack::unitHasAmmoCart(const battle::Unit * unit) const
 {
 	for(const CStack * st : battle->stacks)
 	{
-		if(battle->battleMatchOwner(st, unit, true) && st->getCreature()->idNumber == CreatureID::AMMO_CART)
+		if(battle->battleMatchOwner(st, unit, true) && st->getCreature()->getId() == CreatureID::AMMO_CART)
 		{
 			return st->alive();
 		}

+ 13 - 12
lib/CTownHandler.cpp

@@ -24,6 +24,7 @@
 #include "mapObjects/CObjectClassesHandler.h"
 #include "mapObjects/CObjectHandler.h"
 #include "HeroBonus.h"
+#include "ResourceSet.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -635,21 +636,21 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons
 	if(!ret->produce.nonZero())
 	{
 		switch (ret->bid) {
-			break; case BuildingID::VILLAGE_HALL: ret->produce[Res::GOLD] = 500;
-			break; case BuildingID::TOWN_HALL :   ret->produce[Res::GOLD] = 1000;
-			break; case BuildingID::CITY_HALL :   ret->produce[Res::GOLD] = 2000;
-			break; case BuildingID::CAPITOL :     ret->produce[Res::GOLD] = 4000;
-			break; case BuildingID::GRAIL :       ret->produce[Res::GOLD] = 5000;
+			break; case BuildingID::VILLAGE_HALL: ret->produce[EGameResID::GOLD] = 500;
+			break; case BuildingID::TOWN_HALL :   ret->produce[EGameResID::GOLD] = 1000;
+			break; case BuildingID::CITY_HALL :   ret->produce[EGameResID::GOLD] = 2000;
+			break; case BuildingID::CAPITOL :     ret->produce[EGameResID::GOLD] = 4000;
+			break; case BuildingID::GRAIL :       ret->produce[EGameResID::GOLD] = 5000;
 			break; case BuildingID::RESOURCE_SILO :
 			{
-				switch (ret->town->primaryRes)
+				switch (ret->town->primaryRes.toEnum())
 				{
-					case Res::GOLD:
+					case EGameResID::GOLD:
 						ret->produce[ret->town->primaryRes] = 500;
 						break;
-					case Res::WOOD_AND_ORE:
-						ret->produce[Res::WOOD] = 1;
-						ret->produce[Res::ORE] = 1;
+					case EGameResID::WOOD_AND_ORE:
+						ret->produce[EGameResID::WOOD] = 1;
+						ret->produce[EGameResID::ORE] = 1;
 						break;
 					default:
 						ret->produce[ret->town->primaryRes] = 1;
@@ -880,9 +881,9 @@ void CTownHandler::loadTown(CTown * town, const JsonNode & source)
 {
 	const auto * resIter = boost::find(GameConstants::RESOURCE_NAMES, source["primaryResource"].String());
 	if(resIter == std::end(GameConstants::RESOURCE_NAMES))
-		town->primaryRes = Res::WOOD_AND_ORE; //Wood + Ore
+		town->primaryRes = GameResID(EGameResID::WOOD_AND_ORE); //Wood + Ore
 	else
-		town->primaryRes = static_cast<ui16>(resIter - std::begin(GameConstants::RESOURCE_NAMES));
+		town->primaryRes = GameResID(resIter - std::begin(GameConstants::RESOURCE_NAMES));
 
 	warMachinesToLoad[town] = source["warMachine"];
 

+ 1 - 1
lib/CTownHandler.h

@@ -271,7 +271,7 @@ public:
 	// should be removed at least from configs in favor of auto-detection
 	std::map<int,int> hordeLvl; //[0] - first horde building creature level; [1] - second horde building (-1 if not present)
 	ui32 mageLevel; //max available mage guild level
-	ui16 primaryRes;
+	GameResID primaryRes;
 	ArtifactID warMachine;
 	SpellID moatAbility;
 	// default chance for hero of specific class to appear in tavern, if field "tavern" was not set

+ 10 - 0
lib/GameConstants.h

@@ -205,6 +205,11 @@ public:
 	bool operator >  (const BaseForID & b) const { return num >  b.num; }
 
 	BaseForID & operator++() { ++num; return *this; }
+
+	operator NumericType() const
+	{
+		return num;
+	}
 };
 
 template < typename T>
@@ -267,6 +272,11 @@ public:
 		++num;
 		return ret;
 	}
+
+	operator NumericType() const
+	{
+		return num;
+	}
 };
 
 

+ 3 - 3
lib/HeroBonus.cpp

@@ -1775,7 +1775,7 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
 		else if(deprecatedSubtype == SecondarySkill::ESTATES || deprecatedSubtypeStr == "skill.estates")
 		{
 			type = Bonus::GENERATE_RESOURCE;
-			subtype = Res::GOLD;
+			subtype = GameResID(EGameResID::GOLD);
 			subtypeRelevant = true;
 		}
 		else if(deprecatedSubtype == SecondarySkill::AIR_MAGIC || deprecatedSubtypeStr == "skill.airMagic")
@@ -2380,7 +2380,7 @@ CreatureFactionLimiter::CreatureFactionLimiter():
 ILimiter::EDecision CreatureFactionLimiter::limit(const BonusLimitationContext &context) const
 {
 	const CCreature *c = retrieveCreature(&context.node);
-	auto accept = c && c->faction == faction;
+	auto accept = c && c->getFactionIndex() == faction;
 	return accept ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD; //drop bonus for non-creatures or non-native residents
 }
 
@@ -2731,7 +2731,7 @@ std::shared_ptr<Bonus> TimesStackLevelUpdater::createUpdatedBonus(const std::sha
 		//otherwise we'd end up multiplying twice
 		if(stack.base == nullptr)
 		{
-			int level = stack.type->level;
+			int level = stack.type->getLevel();
 			std::shared_ptr<Bonus> newBonus = std::make_shared<Bonus>(*b);
 			newBonus->val *= level;
 			return newBonus;

+ 1 - 1
lib/IGameCallback.h

@@ -93,7 +93,7 @@ public:
 	virtual void showGarrisonDialog(ObjectInstanceID upobj, ObjectInstanceID hid, bool removableUnits) =0; //cb will be called when player closes garrison window
 	virtual void showTeleportDialog(TeleportDialog *iw) =0;
 	virtual void showThievesGuildWindow(PlayerColor player, ObjectInstanceID requestingObjId) =0;
-	virtual void giveResource(PlayerColor player, Res::ERes which, int val)=0;
+	virtual void giveResource(PlayerColor player, GameResID which, int val)=0;
 	virtual void giveResources(PlayerColor player, TResources resources)=0;
 
 	virtual void giveCreatures(const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) =0;

+ 2 - 2
lib/NetPacksLib.cpp

@@ -1759,7 +1759,7 @@ void RebalanceStacks::applyGs(CGameState * gs)
 		else //split stack to an empty slot
 		{
 			src.army->changeStackCount(src.slot, -count);
-			dst.army->addToSlot(dst.slot, srcType->idNumber, count, false);
+			dst.army->addToSlot(dst.slot, srcType->getId(), count, false);
 			if (stackExp)
 				dst.army->setStackExp(dst.slot, src.army->getStackExperience(src.slot));
 		}
@@ -2508,7 +2508,7 @@ void YourTurn::applyGs(CGameState * gs) const
 
 Component::Component(const CStackBasicDescriptor & stack)
 	: id(EComponentType::CREATURE)
-	, subtype(stack.type->idNumber)
+	, subtype(stack.type->getId())
 	, val(stack.count)
 {
 }

+ 37 - 37
lib/ResourceSet.cpp

@@ -19,26 +19,26 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-Res::ResourceSet::ResourceSet(const JsonNode & node)
+ResourceSet::ResourceSet(const JsonNode & node)
 {
 	for(auto i = 0; i < GameConstants::RESOURCE_QUANTITY; i++)
 		container[i] = static_cast<int>(node[GameConstants::RESOURCE_NAMES[i]].Float());
 }
 
-Res::ResourceSet::ResourceSet(TResource wood, TResource mercury, TResource ore, TResource sulfur, TResource crystal,
+ResourceSet::ResourceSet(TResource wood, TResource mercury, TResource ore, TResource sulfur, TResource crystal,
 							TResource gems, TResource gold, TResource mithril)
 {
-	container[Res::WOOD] = wood;
-	container[Res::MERCURY] = mercury;
-	container[Res::ORE] = ore;
-	container[Res::SULFUR] = sulfur;
-	container[Res::CRYSTAL] = crystal;
-	container[Res::GEMS] = gems;
-	container[Res::GOLD] = gold;
-	container[Res::MITHRIL] = mithril;
+	container[GameResID(EGameResID::WOOD)] = wood;
+	container[GameResID(EGameResID::MERCURY)] = mercury;
+	container[GameResID(EGameResID::ORE)] = ore;
+	container[GameResID(EGameResID::SULFUR)] = sulfur;
+	container[GameResID(EGameResID::CRYSTAL)] = crystal;
+	container[GameResID(EGameResID::GEMS)] = gems;
+	container[GameResID(EGameResID::GOLD)] = gold;
+	container[GameResID(EGameResID::MITHRIL)] = mithril;
 }
 
-void Res::ResourceSet::serializeJson(JsonSerializeFormat & handler, const std::string & fieldName)
+void ResourceSet::serializeJson(JsonSerializeFormat & handler, const std::string & fieldName)
 {
 	if(handler.saving && !nonZero())
 		return;
@@ -49,7 +49,7 @@ void Res::ResourceSet::serializeJson(JsonSerializeFormat & handler, const std::s
 		handler.serializeInt(GameConstants::RESOURCE_NAMES[idx], this->operator[](idx), 0);
 }
 
-bool Res::ResourceSet::nonZero() const
+bool ResourceSet::nonZero() const
 {
 	for(const auto & elem : *this)
 		if(elem)
@@ -58,35 +58,25 @@ bool Res::ResourceSet::nonZero() const
 	return false;
 }
 
-void Res::ResourceSet::amax(const TResourceCap &val)
+void ResourceSet::amax(const TResourceCap &val)
 {
 	for(auto & elem : *this)
 		vstd::amax(elem, val);
 }
 
-void Res::ResourceSet::amin(const TResourceCap &val)
+void ResourceSet::amin(const TResourceCap &val)
 {
 	for(auto & elem : *this)
 		vstd::amin(elem, val);
 }
 
-void Res::ResourceSet::positive()
+void ResourceSet::positive()
 {
 	for(auto & elem : *this)
 		vstd::amax(elem, 0);
 }
 
-bool Res::ResourceSet::canBeAfforded(const ResourceSet &res) const
-{
-	return Res::canAfford(res, *this);
-}
-
-bool Res::ResourceSet::canAfford(const ResourceSet &price) const
-{
-	return Res::canAfford(*this, price);
-}
-
-bool Res::canAfford(const ResourceSet &res, const ResourceSet &price)
+static bool canAfford(const ResourceSet &res, const ResourceSet &price)
 {
 	assert(res.size() == price.size() && price.size() == GameConstants::RESOURCE_QUANTITY);
 	for(int i = 0; i < GameConstants::RESOURCE_QUANTITY; i++)
@@ -96,7 +86,17 @@ bool Res::canAfford(const ResourceSet &res, const ResourceSet &price)
 	return true;
 }
 
-TResourceCap Res::ResourceSet::marketValue() const
+bool ResourceSet::canBeAfforded(const ResourceSet &res) const
+{
+	return VCMI_LIB_WRAP_NAMESPACE(canAfford(res, *this));
+}
+
+bool ResourceSet::canAfford(const ResourceSet &price) const
+{
+	return VCMI_LIB_WRAP_NAMESPACE(canAfford(*this, price));
+}
+
+TResourceCap ResourceSet::marketValue() const
 {
 	TResourceCap total = 0;
 	for(int i = 0; i < GameConstants::RESOURCE_QUANTITY; i++)
@@ -104,7 +104,7 @@ TResourceCap Res::ResourceSet::marketValue() const
 	return total;
 }
 
-std::string Res::ResourceSet::toString() const
+std::string ResourceSet::toString() const
 {
 	std::ostringstream out;
 	out << "[";
@@ -117,35 +117,35 @@ std::string Res::ResourceSet::toString() const
 	return out.str();
 }
 
-bool Res::ResourceSet::nziterator::valid() const
+bool ResourceSet::nziterator::valid() const
 {
 	return cur.resType < GameConstants::RESOURCE_QUANTITY && cur.resVal;
 }
 
-Res::ResourceSet::nziterator Res::ResourceSet::nziterator::operator++()
+ResourceSet::nziterator ResourceSet::nziterator::operator++()
 {
 	advance();
 	return *this;
 }
 
-Res::ResourceSet::nziterator Res::ResourceSet::nziterator::operator++(int)
+ResourceSet::nziterator ResourceSet::nziterator::operator++(int)
 {
 	nziterator ret = *this;
 	advance();
 	return ret;
 }
 
-const Res::ResourceSet::nziterator::ResEntry& Res::ResourceSet::nziterator::operator*() const
+const ResourceSet::nziterator::ResEntry& ResourceSet::nziterator::operator*() const
 {
 	return cur;
 }
 
-const Res::ResourceSet::nziterator::ResEntry * Res::ResourceSet::nziterator::operator->() const
+const ResourceSet::nziterator::ResEntry * ResourceSet::nziterator::operator->() const
 {
 	return &cur;
 }
 
-void Res::ResourceSet::nziterator::advance()
+void ResourceSet::nziterator::advance()
 {
 	do
 	{
@@ -156,11 +156,11 @@ void Res::ResourceSet::nziterator::advance()
 		cur.resVal = -1;
 }
 
-Res::ResourceSet::nziterator::nziterator(const ResourceSet &RS)
+ResourceSet::nziterator::nziterator(const ResourceSet &RS)
 	: rs(RS)
 {
-	cur.resType = WOOD;
-	cur.resVal = rs[WOOD];
+	cur.resType = EGameResID::WOOD;
+	cur.resVal = rs[EGameResID::WOOD];
 
 	if(!valid())
 		advance();

+ 160 - 162
lib/ResourceSet.h

@@ -11,6 +11,7 @@
 #pragma once
 
 #include "GameConstants.h"
+
 VCMI_LIB_NAMESPACE_BEGIN
 
 using TResource = int32_t;
@@ -19,169 +20,168 @@ using TResourceCap = int64_t; //to avoid overflow when adding integers. Signed v
 class JsonNode;
 class JsonSerializeFormat;
 
-namespace Res
+class ResourceSet;
+
+enum class EGameResID : int8_t
 {
-	class ResourceSet;
-	bool canAfford(const ResourceSet &res, const ResourceSet &price); //can a be used to pay price b
+	WOOD = 0, MERCURY, ORE, SULFUR, CRYSTAL, GEMS, GOLD, MITHRIL,
 
-	enum ERes
-	{
-		WOOD = 0, MERCURY, ORE, SULFUR, CRYSTAL, GEMS, GOLD, MITHRIL,
+	WOOD_AND_ORE = 127,  // special case for town bonus resource
+	INVALID = -1
+};
 
-		WOOD_AND_ORE = 127,  // special case for town bonus resource
-		INVALID = -1
-	};
+using GameResID = Identifier<EGameResID>;
 
-	//class to be representing a vector of resource
-	class ResourceSet
-	{
-	private:
-		std::array<TResource, GameConstants::RESOURCE_QUANTITY> container;
-	public:
-		// read resources set from json. Format example: { "gold": 500, "wood":5 }
-		DLL_LINKAGE ResourceSet(const JsonNode & node);
-		DLL_LINKAGE ResourceSet(TResource wood = 0, TResource mercury = 0, TResource ore = 0, TResource sulfur = 0, TResource crystal = 0,
-								TResource gems = 0, TResource gold = 0, TResource mithril = 0);
+//class to be representing a vector of resource
+class ResourceSet
+{
+private:
+	std::array<TResource, GameConstants::RESOURCE_QUANTITY> container;
+public:
+	// read resources set from json. Format example: { "gold": 500, "wood":5 }
+	DLL_LINKAGE ResourceSet(const JsonNode & node);
+	DLL_LINKAGE ResourceSet(TResource wood = 0, TResource mercury = 0, TResource ore = 0, TResource sulfur = 0, TResource crystal = 0,
+							TResource gems = 0, TResource gold = 0, TResource mithril = 0);
 
 
 #define scalarOperator(OPSIGN)									\
-		ResourceSet& operator OPSIGN ## =(const TResource &rhs) \
-		{														\
-			for(auto i = 0; i < container.size(); i++)						\
-				container.at(i) OPSIGN ## = rhs;						\
-																\
-			return *this;											\
-		}
+	ResourceSet& operator OPSIGN ## =(const TResource &rhs) \
+	{														\
+		for(auto i = 0; i < container.size(); i++)						\
+			container.at(i) OPSIGN ## = rhs;						\
+															\
+		return *this;											\
+	}
 
 #define vectorOperator(OPSIGN)										\
-		ResourceSet& operator OPSIGN ## =(const ResourceSet &rhs)	\
-		{															\
-			for(auto i = 0; i < container.size(); i++)							\
-				container.at(i) OPSIGN ## = rhs[i];						\
-																	\
-			return *this;												\
-		}
+	ResourceSet& operator OPSIGN ## =(const ResourceSet &rhs)	\
+	{															\
+		for(auto i = 0; i < container.size(); i++)							\
+			container.at(i) OPSIGN ## = rhs[i];						\
+																\
+		return *this;												\
+	}
 
 #define twoOperands(OPSIGN, RHS_TYPE) \
-		friend ResourceSet operator OPSIGN(ResourceSet lhs, const RHS_TYPE &rhs) \
-		{ \
-			lhs OPSIGN ## = rhs; \
-			return lhs; \
-		}
-
-		scalarOperator(+)
-		scalarOperator(-)
-		scalarOperator(*)
-		scalarOperator(/)
-		vectorOperator(+)
-		vectorOperator(-)
-		twoOperands(+, TResource)
-		twoOperands(-, TResource)
-		twoOperands(*, TResource)
-		twoOperands(/, TResource)
-		twoOperands(+, ResourceSet)
-		twoOperands(-, ResourceSet)
+	friend ResourceSet operator OPSIGN(ResourceSet lhs, const RHS_TYPE &rhs) \
+	{ \
+		lhs OPSIGN ## = rhs; \
+		return lhs; \
+	}
+
+	scalarOperator(+)
+	scalarOperator(-)
+	scalarOperator(*)
+	scalarOperator(/)
+	vectorOperator(+)
+	vectorOperator(-)
+	twoOperands(+, TResource)
+	twoOperands(-, TResource)
+	twoOperands(*, TResource)
+	twoOperands(/, TResource)
+	twoOperands(+, ResourceSet)
+	twoOperands(-, ResourceSet)
 
 
 #undef scalarOperator
 #undef vectorOperator
 #undef twoOperands
 
-		using const_reference = decltype(container)::const_reference;
-		using value_type = decltype(container)::value_type;
-		using const_iterator = decltype(container)::const_iterator;
-		using iterator = decltype(container)::iterator;
+	using const_reference = decltype(container)::const_reference;
+	using value_type = decltype(container)::value_type;
+	using const_iterator = decltype(container)::const_iterator;
+	using iterator = decltype(container)::iterator;
 
-		// Array-like interface
-		TResource & operator[](Res::ERes index)
-		{
-			return operator[](static_cast<size_t>(index));
-		}
+	// Array-like interface
+	TResource & operator[](GameResID index)
+	{
+		return operator[](index.getNum());
+	}
 
-		const TResource & operator[](Res::ERes index) const 
-		{
-			return operator[](static_cast<size_t>(index));
-		}
+	const TResource & operator[](GameResID index) const 
+	{
+		return operator[](index.getNum());
+	}
 
-		TResource & operator[](size_t index)
-		{
-			return container.at(index);
-		}
+	TResource & operator[](size_t index)
+	{
+		return container.at(index);
+	}
 
-		const TResource & operator[](size_t index) const 
-		{
-			return container.at(index);
-		}
+	const TResource & operator[](size_t index) const 
+	{
+		return container.at(index);
+	}
 
-		bool empty () const
-		{
-			for(const auto & res : *this)
-				if(res)
-					return false;
+	bool empty () const
+	{
+		for(const auto & res : *this)
+			if(res)
+				return false;
 
-			return true;
-		}
+		return true;
+	}
 
-		// C++ range-based for support
-		auto begin () -> decltype (container.begin())
-		{
-			return container.begin();
-		}
+	// C++ range-based for support
+	auto begin () -> decltype (container.begin())
+	{
+		return container.begin();
+	}
 
-		auto end () -> decltype (container.end())
-		{
-			return container.end();
-		}
+	auto end () -> decltype (container.end())
+	{
+		return container.end();
+	}
 
-		auto begin () const -> decltype (container.cbegin())
-		{
-			return container.cbegin();
-		}
+	auto begin () const -> decltype (container.cbegin())
+	{
+		return container.cbegin();
+	}
 
-		auto end () const -> decltype (container.cend())
-		{
-			return container.cend();
-		}
+	auto end () const -> decltype (container.cend())
+	{
+		return container.cend();
+	}
 
-		auto size () const -> decltype (container.size())
-		{
-			return container.size();
-		}
+	auto size () const -> decltype (container.size())
+	{
+		return container.size();
+	}
 
-		//to be used for calculations of type "how many units of sth can I afford?"
-		int operator/(const ResourceSet &rhs)
-		{
-			int ret = INT_MAX;
-			for(int i = 0; i < container.size(); i++)
-				if(rhs[i])
-					vstd::amin(ret, container.at(i) / rhs[i]);
+	//to be used for calculations of type "how many units of sth can I afford?"
+	int operator/(const ResourceSet &rhs)
+	{
+		int ret = INT_MAX;
+		for(int i = 0; i < container.size(); i++)
+			if(rhs[i])
+				vstd::amin(ret, container.at(i) / rhs[i]);
 
-			return ret;
-		}
+		return ret;
+	}
 
-		ResourceSet & operator=(const TResource &rhs)
-		{
-			for(int i = 0; i < container.size(); i++)
-				container.at(i) = rhs;
+	ResourceSet & operator=(const TResource &rhs)
+	{
+		for(int i = 0; i < container.size(); i++)
+			container.at(i) = rhs;
 
-			return *this;
-		}
+		return *this;
+	}
 
-		ResourceSet operator-() const
-		{
-			ResourceSet ret;
-			for(int i = 0; i < container.size(); i++)
-				ret[i] = -container.at(i);
-			return ret;
-		}
+	ResourceSet operator-() const
+	{
+		ResourceSet ret;
+		for(int i = 0; i < container.size(); i++)
+			ret[i] = -container.at(i);
+		return ret;
+	}
 
-		bool operator==(const ResourceSet &rhs) const
-		{
-			return this->container == rhs.container;
-		}
+	bool operator==(const ResourceSet &rhs) const
+	{
+		return this->container == rhs.container;
+	}
 
-	// WARNING: comparison operators are used for "can afford" relation: a <= b means that foreach i a[i] <= b[i]
-	// that doesn't work the other way: a > b doesn't mean that a cannot be afforded with b, it's still b can afford a
+// WARNING: comparison operators are used for "can afford" relation: a <= b means that foreach i a[i] <= b[i]
+// that doesn't work the other way: a > b doesn't mean that a cannot be afforded with b, it's still b can afford a
 // 		bool operator<(const ResourceSet &rhs)
 // 		{
 // 			for(int i = 0; i < size(); i++)
@@ -191,49 +191,47 @@ namespace Res
 // 			return true;
 // 		}
 
-		template <typename Handler> void serialize(Handler &h, const int version)
-		{
-			h & container;
-		}
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & container;
+	}
 
-		DLL_LINKAGE void serializeJson(JsonSerializeFormat & handler, const std::string & fieldName);
+	DLL_LINKAGE void serializeJson(JsonSerializeFormat & handler, const std::string & fieldName);
 
-		DLL_LINKAGE void amax(const TResourceCap &val); //performs vstd::amax on each element
-		DLL_LINKAGE void amin(const TResourceCap &val); //performs vstd::amin on each element
-		DLL_LINKAGE void positive(); //values below 0 are set to 0 - upgrade cost can't be negative, for example
-		DLL_LINKAGE bool nonZero() const; //returns true if at least one value is non-zero;
-		DLL_LINKAGE bool canAfford(const ResourceSet &price) const;
-		DLL_LINKAGE bool canBeAfforded(const ResourceSet &res) const;
-		DLL_LINKAGE TResourceCap marketValue() const;
+	DLL_LINKAGE void amax(const TResourceCap &val); //performs vstd::amax on each element
+	DLL_LINKAGE void amin(const TResourceCap &val); //performs vstd::amin on each element
+	DLL_LINKAGE void positive(); //values below 0 are set to 0 - upgrade cost can't be negative, for example
+	DLL_LINKAGE bool nonZero() const; //returns true if at least one value is non-zero;
+	DLL_LINKAGE bool canAfford(const ResourceSet &price) const;
+	DLL_LINKAGE bool canBeAfforded(const ResourceSet &res) const;
+	DLL_LINKAGE TResourceCap marketValue() const;
 
-		DLL_LINKAGE std::string toString() const;
+	DLL_LINKAGE std::string toString() const;
 
-		//special iterator of iterating over non-zero resources in set
-		class DLL_LINKAGE nziterator
+	//special iterator of iterating over non-zero resources in set
+	class DLL_LINKAGE nziterator
+	{
+		struct ResEntry
 		{
-			struct ResEntry
-			{
-				Res::ERes resType;
-				TResourceCap resVal;
-			} cur;
-			const ResourceSet &rs;
-			void advance();
-
-		public:
-			nziterator(const ResourceSet &RS);
-			bool valid() const;
-			nziterator operator++();
-			nziterator operator++(int);
-			const ResEntry& operator*() const;
-			const ResEntry* operator->() const;
+			GameResID resType;
+			TResourceCap resVal;
+		} cur;
+		const ResourceSet &rs;
+		void advance();
 
-		};
+	public:
+		nziterator(const ResourceSet &RS);
+		bool valid() const;
+		nziterator operator++();
+		nziterator operator++(int);
+		const ResEntry& operator*() const;
+		const ResEntry* operator->() const;
+	};
 
 
-	};
-}
+};
 
-using TResources = Res::ResourceSet;
+using TResources = ResourceSet;
 
 
 VCMI_LIB_NAMESPACE_END

+ 1 - 1
lib/battle/BattleInfo.cpp

@@ -653,7 +653,7 @@ int32_t BattleInfo::getEnchanterCounter(ui8 side) const
 	return sides.at(side).enchanterCounter;
 }
 
-const IBonusBearer * BattleInfo::asBearer() const
+const IBonusBearer * BattleInfo::getBonusBearer() const
 {
 	return this;
 }

+ 1 - 1
lib/battle/BattleInfo.h

@@ -93,7 +93,7 @@ public:
 	uint32_t getCastSpells(ui8 side) const override;
 	int32_t getEnchanterCounter(ui8 side) const override;
 
-	const IBonusBearer * asBearer() const override;
+	const IBonusBearer * getBonusBearer() const override;
 
 	uint32_t nextUnitId() const override;
 

+ 2 - 2
lib/battle/BattleProxy.cpp

@@ -108,9 +108,9 @@ int32_t BattleProxy::getEnchanterCounter(ui8 side) const
 	return subject->battleGetEnchanterCounter(side);
 }
 
-const IBonusBearer * BattleProxy::asBearer() const
+const IBonusBearer * BattleProxy::getBonusBearer() const
 {
-	return subject->getBattleNode();
+	return subject->getBonusBearer();
 }
 
 

+ 1 - 1
lib/battle/BattleProxy.h

@@ -50,7 +50,7 @@ public:
 	uint32_t getCastSpells(ui8 side) const override;
 	int32_t getEnchanterCounter(ui8 side) const override;
 
-	const IBonusBearer * asBearer() const override;
+	const IBonusBearer * getBonusBearer() const override;
 protected:
 	Subject subject;
 };

+ 1 - 1
lib/battle/BattleStateInfoForRetreat.cpp

@@ -33,7 +33,7 @@ uint64_t getFightingStrength(const std::vector<const battle::Unit *> & stacks, c
 
 	for(const battle::Unit * stack : stacks)
 	{
-		result += stack->creatureId().toCreature()->AIValue * stack->getCount();
+		result += stack->creatureId().toCreature()->getAIValue() * stack->getCount();
 	}
 
 	if(hero)

+ 2 - 2
lib/battle/CBattleInfoCallback.cpp

@@ -1721,7 +1721,7 @@ si8 CBattleInfoCallback::battleMinSpellLevel(ui8 side) const
 	if(const CGHeroInstance * h = battleGetFightingHero(side))
 		node = h;
 	else
-		node = getBattleNode();
+		node = getBonusBearer();
 
 	if(!node)
 		return 0;
@@ -1739,7 +1739,7 @@ si8 CBattleInfoCallback::battleMaxSpellLevel(ui8 side) const
 	if(const CGHeroInstance * h = battleGetFightingHero(side))
 		node = h;
 	else
-		node = getBattleNode();
+		node = getBonusBearer();
 
 	if(!node)
 		return GameConstants::SPELL_LEVELS;

+ 2 - 2
lib/battle/CBattleInfoEssentials.cpp

@@ -252,9 +252,9 @@ uint32_t CBattleInfoEssentials::battleCastSpells(ui8 side) const
 	return getBattle()->getCastSpells(side);
 }
 
-const IBonusBearer * CBattleInfoEssentials::getBattleNode() const
+const IBonusBearer * CBattleInfoEssentials::getBonusBearer() const
 {
-	return getBattle()->asBearer();
+	return getBattle()->getBonusBearer();
 }
 
 bool CBattleInfoEssentials::battleCanFlee(const PlayerColor & player) const

+ 1 - 1
lib/battle/CBattleInfoEssentials.h

@@ -46,7 +46,7 @@ public:
 	};
 
 	BattlePerspective::BattlePerspective battleGetMySide() const;
-	const IBonusBearer * getBattleNode() const;
+	const IBonusBearer * getBonusBearer() const override;
 
 	TerrainId battleTerrainType() const override;
 	BattleField battleGetBattlefieldType() const override;

+ 4 - 4
lib/battle/CUnitState.cpp

@@ -395,22 +395,22 @@ CreatureID CUnitState::creatureId() const
 
 int32_t CUnitState::creatureLevel() const
 {
-	return static_cast<int32_t>(unitType()->level);
+	return static_cast<int32_t>(unitType()->getLevel());
 }
 
 bool CUnitState::doubleWide() const
 {
-	return unitType()->doubleWide;
+	return unitType()->isDoubleWide();
 }
 
 int32_t CUnitState::creatureCost() const
 {
-	return unitType()->cost[Res::GOLD];
+	return unitType()->getRecruitCost(EGameResID::GOLD);
 }
 
 int32_t CUnitState::creatureIconIndex() const
 {
-	return unitType()->iconIndex;
+	return unitType()->getIconIndex();
 }
 
 int32_t CUnitState::getCasterUnitId() const

+ 1 - 1
lib/battle/DamageCalculator.cpp

@@ -145,7 +145,7 @@ int DamageCalculator::getActorAttackSlayer() const
 			int attackBonus = SpellID(SpellID::SLAYER).toSpell()->getLevelPower(spLevel);
 			if(info.attacker->hasBonusOfType(Bonus::SPECIAL_PECULIAR_ENCHANT, SpellID::SLAYER))
 			{
-				ui8 attackerTier = info.attacker->unitType()->level;
+				ui8 attackerTier = info.attacker->unitType()->getLevel();
 				ui8 specialtyBonus = std::max(5 - attackerTier, 0);
 				attackBonus += specialtyBonus;
 			}

+ 3 - 1
lib/battle/IBattleInfoCallback.h

@@ -13,6 +13,8 @@
 #include "GameConstants.h"
 #include "BattleHex.h"
 
+#include <vcmi/Entity.h>
+
 VCMI_LIB_NAMESPACE_BEGIN
 
 struct CObstacleInstance;
@@ -45,7 +47,7 @@ namespace scripting
 }
 #endif
 
-class DLL_LINKAGE IBattleInfoCallback
+class DLL_LINKAGE IBattleInfoCallback : public WithBonuses
 {
 public:
 #if SCRIPTING_ENABLED

+ 1 - 3
lib/battle/IBattleState.h

@@ -30,7 +30,7 @@ namespace battle
 	class UnitInfo;
 }
 
-class DLL_LINKAGE IBattleInfo
+class DLL_LINKAGE IBattleInfo : public WithBonuses
 {
 public:
 	using ObstacleCList = std::vector<std::shared_ptr<const CObstacleInstance>>;
@@ -62,8 +62,6 @@ public:
 	virtual ui8 getTacticDist() const = 0;
 	virtual ui8 getTacticsSide() const = 0;
 
-	virtual const IBonusBearer * asBearer() const = 0;
-
 	virtual uint32_t nextUnitId() const = 0;
 
 	virtual int64_t getActualDamage(const DamageRange & damage, int32_t attackerCount, vstd::RNG & rng) const = 0;

+ 1 - 1
lib/mapObjects/CArmedInstance.cpp

@@ -76,7 +76,7 @@ void CArmedInstance::updateMoraleBonusFromArmy()
 		const CStackInstance * inst = slot.second;
 		const CCreature * creature  = VLC->creh->objects[inst->getCreatureID()];
 
-		factions.insert(creature->faction);
+		factions.insert(creature->getFactionIndex());
 		// Check for undead flag instead of faction (undead mummies are neutral)
 		if (!hasUndead)
 		{

+ 4 - 4
lib/mapObjects/CBank.cpp

@@ -229,7 +229,7 @@ void CBank::doVisit(const CGHeroInstance * hero) const
 				loot << "%d %s";
 				loot.addReplacement(iw.components.back().val);
 				loot.addReplacement(MetaString::RES_NAMES, iw.components.back().subtype);
-				cb->giveResource(hero->getOwner(), static_cast<Res::ERes>(it), bc->resources[it]);
+				cb->giveResource(hero->getOwner(), static_cast<EGameResID>(it), bc->resources[it]);
 			}
 		}
 		//grant artifacts
@@ -246,9 +246,9 @@ void CBank::doVisit(const CGHeroInstance * hero) const
 			iw.text.addTxt(MetaString::ADVOB_TXT, textID);
 			if (textID == 34)
 			{
-				const CCreature * strongest = boost::range::max_element(bc->guards, [](const CStackBasicDescriptor & a, const CStackBasicDescriptor & b)
+				const auto * strongest = boost::range::max_element(bc->guards, [](const CStackBasicDescriptor & a, const CStackBasicDescriptor & b)
 				{
-					return a.type->fightValue < b.type->fightValue;
+					return a.type->getFightValue() < b.type->getFightValue();
 				})->type;
 
 				iw.text.addReplacement(MetaString::CRE_PL_NAMES, strongest->getId());
@@ -305,7 +305,7 @@ void CBank::doVisit(const CGHeroInstance * hero) const
 		CCreatureSet ourArmy;
 		for(const auto & slot : bc->creatures)
 		{
-			ourArmy.addToSlot(ourArmy.getSlotFor(slot.type->idNumber), slot.type->getId(), slot.count);
+			ourArmy.addToSlot(ourArmy.getSlotFor(slot.type->getId()), slot.type->getId(), slot.count);
 		}
 
 		for(const auto & elem : ourArmy.Slots())

+ 5 - 5
lib/mapObjects/CGHeroInstance.cpp

@@ -325,7 +325,7 @@ void CGHeroInstance::initHero(CRandomGenerator & rand)
 
 	if (VLC->settings()->getBoolean(EGameSettings::MODULE_COMMANDERS) && !commander)
 	{
-		commander = new CCommanderInstance(type->heroClass->commander->idNumber);
+		commander = new CCommanderInstance(type->heroClass->commander->getId());
 		commander->setArmyObj (castToArmyObj()); //TODO: separate function for setting commanders
 		commander->giveStackExp (exp); //after our exp is set
 	}
@@ -790,7 +790,7 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
 			};
 			int maxCasualtyLevel = 1;
 			for(const auto & casualty : casualties)
-				vstd::amax(maxCasualtyLevel, VLC->creh->objects[casualty.first]->level);
+				vstd::amax(maxCasualtyLevel, VLC->creatures()->getByIndex(casualty.first)->getLevel());
 			// pick best bonus available
 			std::shared_ptr<Bonus> topPick;
 			for(const std::shared_ptr<Bonus> & newPick : *improvedNecromancy)
@@ -806,8 +806,8 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
 				{
 					auto quality = [getCreatureID](const std::shared_ptr<Bonus> & pick) -> std::tuple<int, int, int>
 					{
-						const CCreature * c = VLC->creh->objects[getCreatureID(pick)];
-						return std::tuple<int, int, int> {c->level, static_cast<int>(c->cost.marketValue()), -pick->additionalInfo[1]};
+						const auto * c = getCreatureID(pick).toCreature();
+						return std::tuple<int, int, int> {c->getLevel(), static_cast<int>(c->getFullRecruitCost().marketValue()), -pick->additionalInfo[1]};
 					};
 					if(quality(topPick) < quality(newPick))
 						topPick = newPick;
@@ -840,7 +840,7 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
 		{
 			const CCreature * c = VLC->creh->objects[casualty.first];
 			double raisedFromCasualty = std::min(c->MaxHealth() / raisedUnitHealth, 1.0) * casualty.second * necromancySkill;
-			if(c->level < requiredCasualtyLevel)
+			if(c->getLevel() < requiredCasualtyLevel)
 				raisedFromCasualty *= 0.5;
 			raisedUnits += raisedFromCasualty;
 		}

+ 2 - 2
lib/mapObjects/CGMarket.cpp

@@ -50,7 +50,7 @@ bool IMarket::getOffer(int id1, int id2, int &val1, int &val2, EMarketMode::EMar
 			const double effectivenessArray[] = {0.0, 0.3, 0.45, 0.50, 0.65, 0.7, 0.85, 0.9, 1.0};
 			double effectiveness = effectivenessArray[std::min(getMarketEfficiency(), 8)];
 
-			double r = VLC->creh->objects[id1]->cost[6]; //value of given creature in gold
+			double r = VLC->creatures()->getByIndex(id1)->getRecruitCost(EGameResID::GOLD); //value of given creature in gold
 			double g = VLC->objh->resVals[id2] / effectiveness; //value of wanted resource
 
 			if(r>g) //if given resource is more expensive than wanted
@@ -98,7 +98,7 @@ bool IMarket::getOffer(int id1, int id2, int &val1, int &val2, EMarketMode::EMar
 	case EMarketMode::CREATURE_EXP:
 		{
 			val1 = 1;
-			val2 = (VLC->creh->objects[id1]->AIValue / 40) * 5;
+			val2 = (VLC->creh->objects[id1]->getAIValue() / 40) * 5;
 		}
 		break;
 	case EMarketMode::ARTIFACT_EXP:

+ 15 - 15
lib/mapObjects/CGTownInstance.cpp

@@ -263,7 +263,7 @@ void CGDwelling::newTurn(CRandomGenerator & rand) const
 				creaturesAccumulate = VLC->settings()->getBoolean(EGameSettings::DWELLINGS_ACCUMULATE_WHEN_NEUTRAL);
 
 			CCreature *cre = VLC->creh->objects[creatures[i].second[0]];
-			TQuantity amount = cre->growth * (1 + cre->valOfBonuses(Bonus::CREATURE_GROWTH_PERCENT)/100) + cre->valOfBonuses(Bonus::CREATURE_GROWTH);
+			TQuantity amount = cre->getGrowth() * (1 + cre->valOfBonuses(Bonus::CREATURE_GROWTH_PERCENT)/100) + cre->valOfBonuses(Bonus::CREATURE_GROWTH);
 			if (creaturesAccumulate && ID != Obj::REFUGEE_CAMP) //camp should not try to accumulate different kinds of creatures
 				sac.creatures[i].first += amount;
 			else
@@ -287,7 +287,7 @@ void CGDwelling::updateGuards() const
 	//default condition - creatures are of level 5 or higher
 	for (auto creatureEntry : creatures)
 	{
-		if (VLC->creh->objects[creatureEntry.second.at(0)]->level >= 5 && ID != Obj::REFUGEE_CAMP)
+		if (VLC->creatures()->getByIndex(creatureEntry.second.at(0))->getLevel() >= 5 && ID != Obj::REFUGEE_CAMP)
 		{
 			guarded = true;
 			break;
@@ -299,14 +299,14 @@ void CGDwelling::updateGuards() const
 		for (auto creatureEntry : creatures)
 		{
 			const CCreature * crea = VLC->creh->objects[creatureEntry.second.at(0)];
-			SlotID slot = getSlotFor(crea->idNumber);
+			SlotID slot = getSlotFor(crea->getId());
 
 			if (hasStackAtSlot(slot)) //stack already exists, overwrite it
 			{
 				ChangeStackCount csc;
 				csc.army = this->id;
 				csc.slot = slot;
-				csc.count = crea->growth * 3;
+				csc.count = crea->getGrowth() * 3;
 				csc.absoluteValue = true;
 				cb->sendAndApply(&csc);
 			}
@@ -315,8 +315,8 @@ void CGDwelling::updateGuards() const
 				InsertNewStack ns;
 				ns.army = this->id;
 				ns.slot = slot;
-				ns.type = crea->idNumber;
-				ns.count = crea->growth * 3;
+				ns.type = crea->getId();
+				ns.count = crea->getGrowth() * 3;
 				cb->sendAndApply(&ns);
 			}
 		}
@@ -326,10 +326,10 @@ void CGDwelling::updateGuards() const
 void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h) const
 {
 	CreatureID crid = creatures[0].second[0];
-	CCreature *crs = VLC->creh->objects[crid];
+	auto *crs = crid.toCreature();
 	TQuantity count = creatures[0].first;
 
-	if(crs->level == 1  &&  ID != Obj::REFUGEE_CAMP) //first level - creatures are for free
+	if(crs->getLevel() == 1  &&  ID != Obj::REFUGEE_CAMP) //first level - creatures are for free
 	{
 		if(count) //there are available creatures
 		{
@@ -538,7 +538,7 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const
 		return ret; //no dwelling
 
 	const CCreature *creature = VLC->creh->objects[creatures[level].second.back()];
-	const int base = creature->growth;
+	const int base = creature->getGrowth();
 	int castleBonus = 0;
 
 	ret.entries.emplace_back(VLC->generaltexth->allTexts[590], base); // \n\nBasic growth %d"
@@ -550,11 +550,11 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const
 
 	if(town->hordeLvl.at(0) == level)//horde 1
 		if(hasBuilt(BuildingID::HORDE_1))
-			ret.entries.emplace_back(subID, BuildingID::HORDE_1, creature->hordeGrowth);
+			ret.entries.emplace_back(subID, BuildingID::HORDE_1, creature->getHorde());
 
 	if(town->hordeLvl.at(1) == level)//horde 2
 		if(hasBuilt(BuildingID::HORDE_2))
-			ret.entries.emplace_back(subID, BuildingID::HORDE_2, creature->hordeGrowth);
+			ret.entries.emplace_back(subID, BuildingID::HORDE_2, creature->getHorde());
 
 	//statue-of-legion-like bonus: % to base+castle
 	TConstBonusListPtr bonuses2 = getBonuses(Selector::type()(Bonus::CREATURE_GROWTH_PERCENT));
@@ -915,7 +915,7 @@ void CGTownInstance::newTurn(CRandomGenerator & rand) const
 			int resID = rand.nextInt(2, 5); //bonus to random rare resource
 			resID = (resID==2)?1:resID;
 			int resVal = rand.nextInt(1, 4);//with size 1..4
-			cb->giveResource(tempOwner, static_cast<Res::ERes>(resID), resVal);
+			cb->giveResource(tempOwner, static_cast<EGameResID>(resID), resVal);
 			cb->setObjProperty (id, ObjProperty::BONUS_VALUE_FIRST, resID);
 			cb->setObjProperty (id, ObjProperty::BONUS_VALUE_SECOND, resVal);
 		}
@@ -938,7 +938,7 @@ void CGTownInstance::newTurn(CRandomGenerator & rand) const
 				std::vector<SlotID> nativeCrits; //slots
 				for(const auto & elem : Slots())
 				{
-					if (elem.second->type->faction == subID) //native
+					if (elem.second->type->getFactionIndex() == subID) //native
 					{
 						nativeCrits.push_back(elem.first); //collect matching slots
 					}
@@ -951,7 +951,7 @@ void CGTownInstance::newTurn(CRandomGenerator & rand) const
 					const CCreature *c = getCreature(pos);
 					if (rand.nextInt(99) < 90 || c->upgrades.empty()) //increase number if no upgrade available
 					{
-						cb->changeStackCount(sl, c->growth);
+						cb->changeStackCount(sl, c->getGrowth());
 					}
 					else //upgrade
 					{
@@ -968,7 +968,7 @@ void CGTownInstance::newTurn(CRandomGenerator & rand) const
 
 						TQuantity count = creatureGrowth(i);
 						if (!count) // no dwelling
-							count = VLC->creh->objects[c]->growth;
+							count = VLC->creh->objects[c]->getGrowth();
 
 						{//no lower tiers or above current month
 

+ 2 - 2
lib/mapObjects/CObjectHandler.cpp

@@ -494,8 +494,8 @@ void IBoatGenerator::getProblemText(MetaString &out, const CGHeroInstance *visit
 
 void IShipyard::getBoatCost(TResources & cost) const
 {
-	cost[Res::WOOD] = 10;
-	cost[Res::GOLD] = 1000;
+	cost[EGameResID::WOOD] = 10;
+	cost[EGameResID::GOLD] = 1000;
 }
 
 IShipyard::IShipyard(const CGObjectInstance *O)

+ 3 - 3
lib/mapObjects/CQuest.cpp

@@ -163,7 +163,7 @@ bool CQuest::checkQuest(const CGHeroInstance * h) const
 		case MISSION_ARMY:
 			return checkMissionArmy(this, h);
 		case MISSION_RESOURCES:
-			for(Res::ERes i = Res::WOOD; i <= Res::GOLD; vstd::advance(i, +1)) //including Mithril ?
+			for(auto i = EGameResID::WOOD; i <= EGameResID::GOLD; vstd::advance(i, +1)) //including Mithril ?
 			{	//Quest has no direct access to callback
 				if(CGHeroInstance::cb->getResource(h->tempOwner, i) < static_cast<int>(m7resources[i]))
 					return false;
@@ -821,7 +821,7 @@ void CGSeerHut::finishQuest(const CGHeroInstance * h, ui32 accept) const
 			case CQuest::MISSION_RESOURCES:
 				for (int i = 0; i < 7; ++i)
 				{
-					cb->giveResource(h->getOwner(), static_cast<Res::ERes>(i), -static_cast<int>(quest->m7resources[i]));
+					cb->giveResource(h->getOwner(), static_cast<EGameResID>(i), -static_cast<int>(quest->m7resources[i]));
 				}
 				break;
 			default:
@@ -858,7 +858,7 @@ void CGSeerHut::completeQuest (const CGHeroInstance * h) const //reward
 		}
 			break;
 		case RESOURCES:
-			cb->giveResource(h->getOwner(), static_cast<Res::ERes>(rID), rVal);
+			cb->giveResource(h->getOwner(), static_cast<EGameResID>(rID), rVal);
 			break;
 		case PRIMARY_SKILL:
 			cb->changePrimSkill(h, static_cast<PrimarySkill::PrimarySkill>(rID), rVal, false);

+ 2 - 1
lib/mapObjects/CQuest.h

@@ -12,6 +12,7 @@
 #include "CObjectHandler.h"
 #include "CArmedInstance.h"
 
+#include "../ResourceSet.h"
 #include "../CCreatureSet.h"
 #include "../NetPacksBase.h"
 
@@ -58,7 +59,7 @@ public:
 	std::vector<ui32> m2stats;
 	std::vector<ArtifactID> m5arts; // artifact IDs. Add IDs through addArtifactID(), not directly to the field.
 	std::vector<CStackBasicDescriptor> m6creatures; //pair[cre id, cre count], CreatureSet info irrelevant
-	std::vector<ui32> m7resources; //TODO: use resourceset?
+	TResources m7resources;
 
 	// following fields are used only for kill creature/hero missions, the original
 	// objects became inaccessible after their removal, so we need to store info

+ 1 - 1
lib/mapObjects/CRewardableObject.cpp

@@ -455,7 +455,7 @@ void CRewardInfo::loadComponents(std::vector<Component> & comps,
 		comps.emplace_back(Component::EComponentType::SPELL, entry, 1, 0);
 
 	for(const auto & entry : creatures)
-		comps.emplace_back(Component::EComponentType::CREATURE, entry.type->idNumber, entry.count, 0);
+		comps.emplace_back(Component::EComponentType::CREATURE, entry.type->getId(), entry.count, 0);
 
 	for (size_t i=0; i<resources.size(); i++)
 	{

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff