Browse Source

Reduced number of accesses to CGObjectInstance::subID

Ivan Savenko 2 years ago
parent
commit
03e1169781

+ 4 - 5
lib/campaign/CampaignState.cpp

@@ -274,17 +274,16 @@ void CampaignState::setCurrentMapAsConquered(std::vector<CGHeroInstance *> heroe
 
 	for (auto * hero : heroes)
 	{
-		HeroTypeID heroType(hero->subID);
 		JsonNode node = CampaignState::crossoverSerialize(hero);
 
-		if (reservedHeroes.count(heroType))
+		if (reservedHeroes.count(hero->getHeroType()))
 		{
-			logGlobal->info("Hero crossover: %d (%s) exported to global pool", hero->subID, hero->getNameTranslated());
-			globalHeroPool[heroType] = node;
+			logGlobal->info("Hero crossover: %d (%s) exported to global pool", hero->getHeroType(), hero->getNameTranslated());
+			globalHeroPool[hero->getHeroType()] = node;
 		}
 		else
 		{
-			logGlobal->info("Hero crossover: %d (%s) exported to scenario pool", hero->subID, hero->getNameTranslated());
+			logGlobal->info("Hero crossover: %d (%s) exported to scenario pool", hero->getHeroType(), hero->getNameTranslated());
 			scenarioHeroPool[*currentMap].push_back(node);
 		}
 	}

+ 27 - 3
lib/constants/EntityIdentifiers.h

@@ -407,7 +407,7 @@ public:
 	static std::string entityType();
 };
 
-class ObjBase : public IdentifierBase
+class MapObjectBaseID : public IdentifierBase
 {
 public:
 	enum Type
@@ -552,15 +552,38 @@ public:
 	};
 };
 
-class DLL_LINKAGE Obj : public IdentifierWithEnum<Obj, ObjBase>
+class DLL_LINKAGE MapObjectID : public IdentifierWithEnum<MapObjectID, MapObjectBaseID>
 {
 public:
-	using IdentifierWithEnum<Obj, ObjBase>::IdentifierWithEnum;
+	using IdentifierWithEnum<MapObjectID, MapObjectBaseID>::IdentifierWithEnum;
 
 	static std::string encode(int32_t index);
 	static si32 decode(const std::string & identifier);
 };
 
+class MapObjectSubID : public Identifier<MapObjectSubID>
+{
+public:
+	constexpr MapObjectSubID(const IdentifierBase & value):
+		Identifier<MapObjectSubID>(value.getNum())
+	{}
+	constexpr MapObjectSubID(int32_t value):
+		Identifier<MapObjectSubID>(value)
+	{}
+
+	MapObjectSubID & operator =(int32_t value)
+	{
+		this->num = value;
+		return *this;
+	}
+
+	MapObjectSubID & operator =(const IdentifierBase & value)
+	{
+		this->num = value.getNum();
+		return *this;
+	}
+};
+
 class DLL_LINKAGE RoadId : public Identifier<RoadId>
 {
 public:
@@ -966,6 +989,7 @@ public:
 
 // Deprecated
 // TODO: remove
+using Obj = MapObjectID;
 using ETownType = FactionID;
 using EGameResID = GameResID;
 using River = RiverId;

+ 2 - 4
lib/gameState/CGameState.cpp

@@ -77,7 +77,7 @@ public:
 	}
 };
 
-static CGObjectInstance * createObject(const Obj & id, int subid, const int3 & pos, const PlayerColor & owner)
+static CGObjectInstance * createObject(MapObjectID id, MapObjectSubID subid, const int3 & pos, const PlayerColor & owner)
 {
 	CGObjectInstance * nobj;
 	switch(id)
@@ -810,7 +810,7 @@ void CGameState::placeStartingHero(const PlayerColor & playerColor, const HeroTy
 		}
 	}
 
-	CGObjectInstance * hero = createObject(Obj::HERO, heroTypeId.getNum(), townPos, playerColor);
+	CGObjectInstance * hero = createObject(Obj::HERO, heroTypeId, townPos, playerColor);
 	hero->pos += hero->getVisitableOffset();
 	map->getEditManager()->insertObject(hero);
 }
@@ -880,8 +880,6 @@ void CGameState::initHeroes()
 			CGBoat * boat = dynamic_cast<CGBoat*>(handler->create());
 			handler->configureObject(boat, gs->getRandomGenerator());
 
-			boat->ID = Obj::BOAT;
-			boat->subID = hero->getBoatType().getNum();
 			boat->pos = hero->pos;
 			boat->appearance = handler->getTemplates().front();
 			boat->id = ObjectInstanceID(static_cast<si32>(gs->map->objects.size()));

+ 6 - 6
lib/gameState/CGameStateCampaign.cpp

@@ -213,7 +213,7 @@ void CGameStateCampaign::placeCampaignHeroes()
 	std::set<HeroTypeID> heroesToRemove = campaignState->getReservedHeroes();
 
 	for(auto & campaignHeroReplacement : campaignHeroReplacements)
-		heroesToRemove.insert(HeroTypeID(campaignHeroReplacement.hero->subID));
+		heroesToRemove.insert(campaignHeroReplacement.hero->getHeroType());
 
 	for(auto & heroID : heroesToRemove)
 	{
@@ -339,7 +339,7 @@ void CGameStateCampaign::replaceHeroesPlaceholders(const std::vector<CampaignHer
 		if(heroPlaceholder->tempOwner.isValidPlayer())
 			heroToPlace->tempOwner = heroPlaceholder->tempOwner;
 		heroToPlace->pos = heroPlaceholder->pos;
-		heroToPlace->type = VLC->heroh->objects[heroToPlace->subID];
+		heroToPlace->type = VLC->heroh->objects[heroToPlace->getHeroType().getNum()];
 		heroToPlace->appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, heroToPlace->type->heroClass->getIndex())->getTemplates().front();
 
 		gameState->map->removeBlockVisTiles(heroPlaceholder, true);
@@ -396,7 +396,7 @@ std::vector<CampaignHeroReplacement> CGameStateCampaign::generateCampaignHeroesT
 
 		CGHeroInstance * hero = CampaignState::crossoverDeserialize(node, gameState->map);
 
-		logGlobal->info("Hero crossover: Loading placeholder for %d (%s)", hero->subID, hero->getNameTranslated());
+		logGlobal->info("Hero crossover: Loading placeholder for %d (%s)", hero->getHeroType(), hero->getNameTranslated());
 
 		campaignHeroReplacements.emplace_back(hero, placeholder->id);
 	}
@@ -422,7 +422,7 @@ std::vector<CampaignHeroReplacement> CGameStateCampaign::generateCampaignHeroesT
 			CGHeroInstance * hero = CampaignState::crossoverDeserialize(*nodeListIter, gameState->map);
 			nodeListIter++;
 
-			logGlobal->info("Hero crossover: Loading placeholder as %d (%s)", hero->subID, hero->getNameTranslated());
+			logGlobal->info("Hero crossover: Loading placeholder as %d (%s)", hero->getHeroType(), hero->getNameTranslated());
 
 			campaignHeroReplacements.emplace_back(hero, placeholder->id);
 		}
@@ -468,7 +468,7 @@ void CGameStateCampaign::initHeroes()
 		{
 			for (auto & heroe : heroes)
 			{
-				if (heroe->subID == chosenBonus->info1)
+				if (heroe->getHeroType().getNum() == chosenBonus->info1)
 				{
 					giveCampaignBonusToHero(heroe);
 					break;
@@ -557,7 +557,7 @@ void CGameStateCampaign::initTowns()
 		if(gameState->scenarioOps->campState->formatVCMI())
 			newBuilding = BuildingID(chosenBonus->info1);
 		else
-			newBuilding = CBuildingHandler::campToERMU(chosenBonus->info1, town->subID, town->builtBuildings);
+			newBuilding = CBuildingHandler::campToERMU(chosenBonus->info1, town->getFaction(), town->builtBuildings);
 
 		// Build granted building & all prerequisites - e.g. Mages Guild Lvl 3 should also give Mages Guild Lvl 1 & 2
 		while(true)

+ 3 - 3
lib/gameState/TavernHeroesPool.cpp

@@ -25,7 +25,7 @@ std::map<HeroTypeID, CGHeroInstance*> TavernHeroesPool::unusedHeroesFromPool() c
 {
 	std::map<HeroTypeID, CGHeroInstance*> pool = heroesPool;
 	for(const auto & slot : currentTavern)
-		pool.erase(HeroTypeID(slot.hero->subID));
+		pool.erase(slot.hero->getHeroType());
 
 	return pool;
 }
@@ -34,7 +34,7 @@ TavernSlotRole TavernHeroesPool::getSlotRole(HeroTypeID hero) const
 {
 	for (auto const & slot : currentTavern)
 	{
-		if (HeroTypeID(slot.hero->subID) == hero)
+		if (slot.hero->getHeroType() == hero)
 			return slot.role;
 	}
 	return TavernSlotRole::NONE;
@@ -132,7 +132,7 @@ void TavernHeroesPool::onNewDay()
 
 void TavernHeroesPool::addHeroToPool(CGHeroInstance * hero)
 {
-	heroesPool[HeroTypeID(hero->subID)] = hero;
+	heroesPool[hero->getHeroType()] = hero;
 }
 
 void TavernHeroesPool::setAvailability(HeroTypeID hero, std::set<PlayerColor> mask)

+ 1 - 1
lib/mapObjects/CBank.cpp

@@ -46,7 +46,7 @@ void CBank::initObj(CRandomGenerator & rand)
 {
 	daycounter = 0;
 	resetDuration = 0;
-	VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, rand);
+	getObjectHandler()->configureObject(this, rand);
 }
 
 bool CBank::isCoastVisitable() const

+ 17 - 12
lib/mapObjects/CGCreature.cpp

@@ -28,7 +28,7 @@ std::string CGCreature::getHoverText(PlayerColor player) const
 	if(stacks.empty())
 	{
 		//should not happen...
-		logGlobal->error("Invalid stack at tile %s: subID=%d; id=%d", pos.toString(), subID, id.getNum());
+		logGlobal->error("Invalid stack at tile %s: subID=%d; id=%d", pos.toString(), getCreature(), id.getNum());
 		return "INVALID_STACK";
 	}
 
@@ -41,7 +41,7 @@ std::string CGCreature::getHoverText(PlayerColor player) const
 	else
 		ms.appendLocalString(EMetaText::ARRAY_TXT, quantityTextIndex);
 	ms.appendRawString(" ");
-	ms.appendLocalString(EMetaText::CRE_PL_NAMES,subID);
+	ms.appendLocalString(EMetaText::CRE_PL_NAMES, getCreature());
 	hoverName = ms.toString();
 	return hoverName;
 }
@@ -54,7 +54,7 @@ std::string CGCreature::getHoverText(const CGHeroInstance * hero) const
 		MetaString ms;
 		ms.appendNumber(stacks.begin()->second->count);
 		ms.appendRawString(" ");
-		ms.appendLocalString(EMetaText::CRE_PL_NAMES,subID);
+		ms.appendLocalString(EMetaText::CRE_PL_NAMES, getCreature());
 
 		ms.appendRawString("\n\n");
 
@@ -132,7 +132,7 @@ void CGCreature::onHeroVisit( const CGHeroInstance * h ) const
 			BlockingDialog ynd(true,false);
 			ynd.player = h->tempOwner;
 			ynd.text.appendLocalString(EMetaText::ADVOB_TXT, 86);
-			ynd.text.replaceLocalString(EMetaText::CRE_PL_NAMES, subID);
+			ynd.text.replaceLocalString(EMetaText::CRE_PL_NAMES, getCreature());
 			cb->showBlockingDialog(&ynd);
 			break;
 		}
@@ -146,7 +146,7 @@ void CGCreature::onHeroVisit( const CGHeroInstance * h ) const
 			std::string tmp = VLC->generaltexth->advobtxt[90];
 			boost::algorithm::replace_first(tmp, "%d", std::to_string(getStackCount(SlotID(0))));
 			boost::algorithm::replace_first(tmp, "%d", std::to_string(action));
-			boost::algorithm::replace_first(tmp,"%s",VLC->creh->objects[subID]->getNamePluralTranslated());
+			boost::algorithm::replace_first(tmp,"%s",VLC->creatures()->getById(getCreature())->getNamePluralTranslated());
 			ynd.text.appendRawString(tmp);
 			cb->showBlockingDialog(&ynd);
 			break;
@@ -155,6 +155,11 @@ void CGCreature::onHeroVisit( const CGHeroInstance * h ) const
 
 }
 
+CreatureID CGCreature::getCreature() const
+{
+	return CreatureID(getObjTypeIndex().getNum());
+}
+
 void CGCreature::initObj(CRandomGenerator & rand)
 {
 	blockVisit = true;
@@ -177,16 +182,16 @@ void CGCreature::initObj(CRandomGenerator & rand)
 		break;
 	}
 
-	stacks[SlotID(0)]->setType(CreatureID(subID));
+	stacks[SlotID(0)]->setType(getCreature());
 	TQuantity &amount = stacks[SlotID(0)]->count;
-	CCreature &c = *VLC->creh->objects[subID];
+	const Creature * c = VLC->creatures()->getById(getCreature());
 	if(amount == 0)
 	{
-		amount = rand.nextInt(c.ammMin, c.ammMax);
+		amount = rand.nextInt(c->getAdvMapAmountMin(), c->getAdvMapAmountMax());
 
 		if(amount == 0) //armies with 0 creatures are illegal
 		{
-			logGlobal->warn("Stack %s cannot have 0 creatures. Check properties of %s", nodeName(), c.nodeName());
+			logGlobal->warn("Stack cannot have 0 creatures. Check properties of %s", c->getJsonKey());
 			amount = 1;
 		}
 	}
@@ -252,7 +257,7 @@ int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const
 		powerFactor = -3;
 
 	std::set<CreatureID> myKindCres; //what creatures are the same kind as we
-	const CCreature * myCreature = VLC->creh->objects[subID];
+	const CCreature * myCreature = VLC->creh->objects[getCreature().getNum()];
 	myKindCres.insert(myCreature->getId()); //we
 	myKindCres.insert(myCreature->upgrades.begin(), myCreature->upgrades.end()); //our upgrades
 
@@ -290,7 +295,7 @@ int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const
 			return JOIN_FOR_FREE;
 
 		else if(diplomacy * 2  +  sympathy  +  1 >= character)
-			return VLC->creatures()->getByIndex(subID)->getRecruitCost(EGameResID::GOLD) * getStackCount(SlotID(0)); //join for gold
+			return VLC->creatures()->getById(getCreature())->getRecruitCost(EGameResID::GOLD) * getStackCount(SlotID(0)); //join for gold
 	}
 
 	//we are still here - creatures have not joined hero, flee or fight
@@ -404,7 +409,7 @@ void CGCreature::flee( const CGHeroInstance * h ) const
 	BlockingDialog ynd(true,false);
 	ynd.player = h->tempOwner;
 	ynd.text.appendLocalString(EMetaText::ADVOB_TXT,91);
-	ynd.text.replaceLocalString(EMetaText::CRE_PL_NAMES, subID);
+	ynd.text.replaceLocalString(EMetaText::CRE_PL_NAMES, getCreature());
 	cb->showBlockingDialog(&ynd);
 }
 

+ 1 - 0
lib/mapObjects/CGCreature.h

@@ -44,6 +44,7 @@ public:
 	void newTurn(CRandomGenerator & rand) const override;
 	void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
 	void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
+	CreatureID getCreature() const;
 
 	//stack formation depends on position,
 	bool containsUpgradedStack() const;

+ 1 - 1
lib/mapObjects/CGDwelling.cpp

@@ -95,7 +95,7 @@ void CGDwelling::initObj(CRandomGenerator & rand)
 	case Obj::CREATURE_GENERATOR1:
 	case Obj::CREATURE_GENERATOR4:
 		{
-			VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, rand);
+			getObjectHandler()->configureObject(this, rand);
 
 			if (getOwner() != PlayerColor::NEUTRAL)
 				cb->gameState()->players[getOwner()].dwellings.emplace_back(this);

+ 9 - 4
lib/mapObjects/CGHeroInstance.cpp

@@ -285,6 +285,11 @@ PlayerColor CGHeroInstance::getOwner() const
 	return tempOwner;
 }
 
+HeroTypeID CGHeroInstance::getHeroType() const
+{
+	return HeroTypeID(getObjTypeIndex().getNum());
+}
+
 void CGHeroInstance::initHero(CRandomGenerator & rand, const HeroTypeID & SUBID)
 {
 	subID = SUBID.getNum();
@@ -305,7 +310,7 @@ void CGHeroInstance::initHero(CRandomGenerator & rand)
 {
 	assert(validTypes(true));
 	if(!type)
-		type = VLC->heroh->objects[subID];
+		type = VLC->heroh->objects[getHeroType().getNum()];
 
 	if (ID == Obj::HERO)
 		appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, type->heroClass->getIndex())->getTemplates().front();
@@ -1050,7 +1055,7 @@ HeroTypeID CGHeroInstance::getPortraitSource() const
 	if (customPortraitSource.isValid())
 		return customPortraitSource;
 	else
-		return HeroTypeID(subID);
+		return getHeroType();
 }
 
 int32_t CGHeroInstance::getIconIndex() const
@@ -1502,7 +1507,7 @@ std::string CGHeroInstance::getHeroTypeName() const
 		}
 		else
 		{
-			return VLC->heroh->objects[subID]->getJsonKey();
+			return VLC->heroh->objects[getHeroType()]->getJsonKey();
 		}
 	}
 	return "";
@@ -1736,7 +1741,7 @@ void CGHeroInstance::serializeJsonOptions(JsonSerializeFormat & handler)
 			if(!appearance)
 			{
 				// crossoverDeserialize
-				type = VLC->heroh->objects[subID];
+				type = VLC->heroh->objects[getHeroType()];
 				appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, type->heroClass->getIndex())->getTemplates().front();
 			}
 

+ 1 - 0
lib/mapObjects/CGHeroInstance.h

@@ -231,6 +231,7 @@ public:
 
 	//////////////////////////////////////////////////////////////////////////
 
+	HeroTypeID getHeroType() const;
 	void setType(si32 ID, si32 subID) override;
 
 	void initHero(CRandomGenerator & rand);

+ 1 - 1
lib/mapObjects/CGMarket.cpp

@@ -25,7 +25,7 @@ VCMI_LIB_NAMESPACE_BEGIN
 
 void CGMarket::initObj(CRandomGenerator & rand)
 {
-	VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, rand);
+	getObjectHandler()->configureObject(this, rand);
 }
 
 void CGMarket::onHeroVisit(const CGHeroInstance * h) const

+ 8 - 3
lib/mapObjects/CGObjectInstance.cpp

@@ -40,12 +40,12 @@ CGObjectInstance::CGObjectInstance():
 //must be instantiated in .cpp file for access to complete types of all member fields
 CGObjectInstance::~CGObjectInstance() = default;
 
-int32_t CGObjectInstance::getObjGroupIndex() const
+MapObjectID CGObjectInstance::getObjGroupIndex() const
 {
-	return ID.num;
+	return ID;
 }
 
-int32_t CGObjectInstance::getObjTypeIndex() const
+MapObjectSubID CGObjectInstance::getObjTypeIndex() const
 {
 	return subID;
 }
@@ -197,6 +197,11 @@ void CGObjectInstance::setProperty( ui8 what, ui32 val )
 	}
 }
 
+TObjectTypeHandler CGObjectInstance::getObjectHandler() const
+{
+	return VLC->objtypeh->getHandlerFor(ID, subID);
+}
+
 void CGObjectInstance::setPropertyDer( ui8 what, ui32 val )
 {}
 

+ 8 - 4
lib/mapObjects/CGObjectInstance.h

@@ -21,6 +21,8 @@ struct Component;
 class JsonSerializeFormat;
 class ObjectTemplate;
 class CMap;
+class AObjectTypeHandler;
+using TObjectTypeHandler = std::shared_ptr<AObjectTypeHandler>;
 
 class DLL_LINKAGE CGObjectInstance : public IObjectInterface
 {
@@ -28,9 +30,9 @@ public:
 	/// Position of bottom-right corner of object on map
 	int3 pos;
 	/// Type of object, e.g. town, hero, creature.
-	Obj ID;
+	MapObjectID ID;
 	/// Subtype of object, depends on type
-	si32 subID;
+	MapObjectSubID subID;
 	/// Current owner of an object (when below PLAYER_LIMIT)
 	PlayerColor tempOwner;
 	/// Index of object in map's list of objects
@@ -45,8 +47,8 @@ public:
 	CGObjectInstance(); //TODO: remove constructor
 	~CGObjectInstance() override;
 
-	int32_t getObjGroupIndex() const override;
-	int32_t getObjTypeIndex() const override;
+	MapObjectID getObjGroupIndex() const override;
+	MapObjectSubID getObjTypeIndex() const override;
 
 	/// "center" tile from which the sight distance is calculated
 	int3 getSightCenter() const;
@@ -94,6 +96,8 @@ public:
 	std::optional<AudioPath> getVisitSound() const;
 	std::optional<AudioPath> getRemovalSound() const;
 
+	TObjectTypeHandler getObjectHandler() const;
+
 	/** VIRTUAL METHODS **/
 
 	/// Returns true if player can pass through visitable tiles of this object

+ 2 - 2
lib/mapObjects/CGTownBuilding.cpp

@@ -24,12 +24,12 @@ PlayerColor CGTownBuilding::getOwner() const
 	return town->getOwner();
 }
 
-int32_t CGTownBuilding::getObjGroupIndex() const
+MapObjectID CGTownBuilding::getObjGroupIndex() const
 {
 	return -1;
 }
 
-int32_t CGTownBuilding::getObjTypeIndex() const
+MapObjectSubID CGTownBuilding::getObjTypeIndex() const
 {
 	return 0;
 }

+ 2 - 2
lib/mapObjects/CGTownBuilding.h

@@ -45,8 +45,8 @@ public:
 	}
 
 	PlayerColor getOwner() const override;
-	int32_t getObjGroupIndex() const override;
-	int32_t getObjTypeIndex() const override;
+	MapObjectID getObjGroupIndex() const override;
+	MapObjectSubID getObjTypeIndex() const override;
 
 	int3 visitablePos() const override;
 	int3 getPosition() const override;

+ 1 - 1
lib/mapObjects/CGTownInstance.cpp

@@ -763,7 +763,7 @@ void CGTownInstance::updateAppearance()
 {
 	auto terrain = cb->gameState()->getTile(visitablePos())->terType->getId();
 	//FIXME: not the best way to do this
-	auto app = VLC->objtypeh->getHandlerFor(ID, subID)->getOverride(terrain, this);
+	auto app = getObjectHandler()->getOverride(terrain, this);
 	if (app)
 		appearance = app;
 }

+ 0 - 10
lib/mapObjects/CObjectHandler.cpp

@@ -28,14 +28,4 @@ CObjectHandler::CObjectHandler()
 	logGlobal->trace("\t\tDone loading resource prices!");
 }
 
-CGObjectInstanceBySubIdFinder::CGObjectInstanceBySubIdFinder(CGObjectInstance * obj) : obj(obj)
-{
-
-}
-
-bool CGObjectInstanceBySubIdFinder::operator()(CGObjectInstance * obj) const
-{
-	return this->obj->subID == obj->subID;
-}
-
 VCMI_LIB_NAMESPACE_END

+ 0 - 11
lib/mapObjects/CObjectHandler.h

@@ -16,17 +16,6 @@ VCMI_LIB_NAMESPACE_BEGIN
 class CGObjectInstance;
 class int3;
 
-/// function object which can be used to find an object with an specific sub ID
-class CGObjectInstanceBySubIdFinder
-{
-public:
-	CGObjectInstanceBySubIdFinder(CGObjectInstance * obj);
-	bool operator()(CGObjectInstance * obj) const;
-
-private:
-	CGObjectInstance * obj;
-};
-
 class DLL_LINKAGE CObjectHandler
 {
 public:

+ 1 - 1
lib/mapObjects/CRewardableObject.cpp

@@ -373,7 +373,7 @@ void CRewardableObject::newTurn(CRandomGenerator & rand) const
 
 void CRewardableObject::initObj(CRandomGenerator & rand)
 {
-	VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, rand);
+	getObjectHandler()->configureObject(this, rand);
 }
 
 CRewardableObject::CRewardableObject()

+ 3 - 2
lib/mapObjects/IObjectInterface.h

@@ -10,6 +10,7 @@
 #pragma once
 
 #include "../networkPacks/EInfoWindowMode.h"
+#include "../constants/EntityIdentifiers.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -33,8 +34,8 @@ public:
 
 	virtual ~IObjectInterface() = default;
 
-	virtual int32_t getObjGroupIndex() const = 0;
-	virtual int32_t getObjTypeIndex() const = 0;
+	virtual MapObjectID getObjGroupIndex() const = 0;
+	virtual MapObjectSubID getObjTypeIndex() const = 0;
 
 	virtual PlayerColor getOwner() const = 0;
 	virtual int3 visitablePos() const = 0;

+ 27 - 14
lib/mapObjects/MiscObjects.cpp

@@ -85,7 +85,7 @@ void CGMine::onHeroVisit( const CGHeroInstance * h ) const
 	{
 		BlockingDialog ynd(true,false);
 		ynd.player = h->tempOwner;
-		ynd.text.appendLocalString(EMetaText::ADVOB_TXT, subID == 7 ? 84 : 187);
+		ynd.text.appendLocalString(EMetaText::ADVOB_TXT, isAbandoned() ? 84 : 187);
 		cb->showBlockingDialog(&ynd);
 		return;
 	}
@@ -119,19 +119,19 @@ void CGMine::initObj(CRandomGenerator & rand)
 	}
 	else
 	{
-		producedResource = GameResID(subID);
+		producedResource = GameResID(getObjTypeIndex());
 	}
 	producedQuantity = defaultResProduction();
 }
 
 bool CGMine::isAbandoned() const
 {
-	return (subID >= 7);
+	return (getObjTypeIndex() >= 7);
 }
 
 std::string CGMine::getObjectName() const
 {
-	return VLC->generaltexth->translate("core.minename", subID);
+	return VLC->generaltexth->translate("core.minename", getObjTypeIndex());
 }
 
 std::string CGMine::getHoverText(PlayerColor player) const
@@ -206,7 +206,7 @@ void CGMine::serializeJsonOptions(JsonSerializeFormat & handler)
 		if(handler.saving)
 		{
 			JsonNode node(JsonNode::JsonType::DATA_VECTOR);
-			for(auto const & resID : abandonedMineResources)
+			for(const auto & resID : abandonedMineResources)
 			{
 				JsonNode one(JsonNode::JsonType::DATA_STRING);
 				one.String() = GameConstants::RESOURCE_NAMES[resID];
@@ -237,9 +237,14 @@ void CGMine::serializeJsonOptions(JsonSerializeFormat & handler)
 	}
 }
 
+GameResID CGResource::resourceID() const
+{
+	return getObjTypeIndex().getNum();
+}
+
 std::string CGResource::getHoverText(PlayerColor player) const
 {
-	return VLC->generaltexth->restypes[subID];
+	return VLC->generaltexth->restypes[resourceID()];
 }
 
 void CGResource::initObj(CRandomGenerator & rand)
@@ -248,7 +253,7 @@ void CGResource::initObj(CRandomGenerator & rand)
 
 	if(amount == CGResource::RANDOM_AMOUNT)
 	{
-		switch(static_cast<EGameResID>(subID))
+		switch(resourceID())
 		{
 		case EGameResID::GOLD:
 			amount = rand.nextInt(5, 10) * 100;
@@ -285,7 +290,7 @@ void CGResource::onHeroVisit( const CGHeroInstance * h ) const
 
 void CGResource::collectRes(const PlayerColor & player) const
 {
-	cb->giveResource(player, static_cast<EGameResID>(subID), amount);
+	cb->giveResource(player, resourceID(), amount);
 	InfoWindow sii;
 	sii.player = player;
 	if(!message.empty())
@@ -297,9 +302,9 @@ void CGResource::collectRes(const PlayerColor & player) const
 	{
 		sii.type = EInfoWindowMode::INFO;
 		sii.text.appendLocalString(EMetaText::ADVOB_TXT,113);
-		sii.text.replaceLocalString(EMetaText::RES_NAMES, subID);
+		sii.text.replaceLocalString(EMetaText::RES_NAMES, resourceID());
 	}
-	sii.components.emplace_back(Component::EComponentType::RESOURCE,subID,amount,0);
+	sii.components.emplace_back(Component::EComponentType::RESOURCE, resourceID(), amount, 0);
 	sii.soundID = soundBase::pickup01 + CRandomGenerator::getDefault().nextInt(6);
 	cb->showInfoDialog(&sii);
 	cb->removeObject(this, player);
@@ -688,6 +693,14 @@ bool CGWhirlpool::isProtected(const CGHeroInstance * h)
 	|| (h->stacksCount() == 1 && h->Slots().begin()->second->count == 1);
 }
 
+ArtifactID CGArtifact::getArtifact() const
+{
+	if(ID == Obj::SPELL_SCROLL)
+		return ArtifactID::SPELL_SCROLL;
+	else
+		return getObjTypeIndex().getNum();
+}
+
 void CGArtifact::initObj(CRandomGenerator & rand)
 {
 	blockVisit = true;
@@ -700,7 +713,7 @@ void CGArtifact::initObj(CRandomGenerator & rand)
 			storedArtifact = a;
 		}
 		if(!storedArtifact->artType)
-			storedArtifact->setType(VLC->arth->objects[subID]);
+			storedArtifact->setType(VLC->arth->objects[getArtifact()]);
 	}
 	if(ID == Obj::SPELL_SCROLL)
 		subID = 1;
@@ -713,7 +726,7 @@ void CGArtifact::initObj(CRandomGenerator & rand)
 
 std::string CGArtifact::getObjectName() const
 {
-	return VLC->artifacts()->getByIndex(subID)->getNameTranslated();
+	return VLC->artifacts()->getByIndex(getArtifact())->getNameTranslated();
 }
 
 void CGArtifact::onHeroVisit(const CGHeroInstance * h) const
@@ -730,11 +743,11 @@ void CGArtifact::onHeroVisit(const CGHeroInstance * h) const
 			{
 			case Obj::ARTIFACT:
 			{
-				iw.components.emplace_back(Component::EComponentType::ARTIFACT, subID, 0, 0);
+				iw.components.emplace_back(Component::EComponentType::ARTIFACT, getArtifact(), 0, 0);
 				if(!message.empty())
 					iw.text = message;
 				else
-					iw.text.appendLocalString(EMetaText::ART_EVNTS, subID);
+					iw.text.appendLocalString(EMetaText::ART_EVNTS, getArtifact());
 			}
 			break;
 			case Obj::SPELL_SCROLL:

+ 3 - 0
lib/mapObjects/MiscObjects.h

@@ -93,6 +93,8 @@ public:
 	void afterAddToMap(CMap * map) override;
 	BattleField getBattlefield() const override;
 
+	ArtifactID getArtifact() const;
+
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & static_cast<CArmedInstance&>(*this);
@@ -118,6 +120,7 @@ public:
 	std::string getHoverText(PlayerColor player) const override;
 
 	void collectRes(const PlayerColor & player) const;
+	GameResID resourceID() const;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{

+ 2 - 2
lib/mapping/CMap.cpp

@@ -250,10 +250,10 @@ void CMap::calculateGuardingGreaturePositions()
 	}
 }
 
-CGHeroInstance * CMap::getHero(int heroID)
+CGHeroInstance * CMap::getHero(HeroTypeID heroID)
 {
 	for(auto & elem : heroesOnMap)
-		if(elem->subID == heroID)
+		if(elem->getObjTypeIndex() == heroID.getNum())
 			return elem;
 	return nullptr;
 }

+ 1 - 1
lib/mapping/CMap.h

@@ -118,7 +118,7 @@ public:
 
 	/// Gets object of specified type on requested position
 	const CGObjectInstance * getObjectiveObjectFrom(const int3 & pos, Obj type);
-	CGHeroInstance * getHero(int heroId);
+	CGHeroInstance * getHero(HeroTypeID heroId);
 
 	/// Sets the victory/loss condition objectives ??
 	void checkForObjectives();

+ 1 - 1
lib/mapping/MapFormatJson.cpp

@@ -1229,7 +1229,7 @@ void CMapLoaderJson::MapObjectLoader::configure()
 		else if(art->ID  == Obj::ARTIFACT)
 		{
 			//specific artifact
-			artID = ArtifactID(art->subID);
+			artID = art->getArtifact();
 		}
 
 		art->storedArtifact = ArtifactUtils::createArtifact(owner->map, artID, spellID.getNum());

+ 3 - 3
lib/rmg/RmgObject.cpp

@@ -113,7 +113,7 @@ void Object::Instance::setPositionRaw(const int3 & position)
 
 void Object::Instance::setAnyTemplate(CRandomGenerator & rng)
 {
-	auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates();
+	auto templates = dObject.getObjectHandler()->getTemplates();
 	if(templates.empty())
 		throw rmgException(boost::str(boost::format("Did not find any graphics for object (%d,%d)") % dObject.ID % dObject.subID));
 
@@ -124,7 +124,7 @@ void Object::Instance::setAnyTemplate(CRandomGenerator & rng)
 
 void Object::Instance::setTemplate(TerrainId terrain, CRandomGenerator & rng)
 {
-	auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrain);
+	auto templates = dObject.getObjectHandler()->getTemplates(terrain);
 	if (templates.empty())
 	{
 		auto terrainName = VLC->terrainTypeHandler->getById(terrain)->getNameTranslated();
@@ -335,7 +335,7 @@ void Object::Instance::finalize(RmgMap & map, CRandomGenerator & rng)
 	if (!dObject.appearance)
 	{
 		const auto * terrainType = map.getTile(getPosition(true)).terType;
-		auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrainType->getId());
+		auto templates = dObject.getObjectHandler()->getTemplates(terrainType->getId());
 		if (templates.empty())
 		{
 			throw rmgException(boost::str(boost::format("Did not find graphics for object (%d,%d) at %s (terrain %d)") % dObject.ID % dObject.subID % getPosition(true).toString() % terrainType));