1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-08 00:39:47 +02:00

Remove more subID access

This commit is contained in:
Ivan Savenko 2023-10-28 12:27:10 +03:00
parent 5cdbf408c7
commit 8346d71c98
33 changed files with 92 additions and 90 deletions

View File

@ -318,7 +318,7 @@ bool BuildAnalyzer::hasAnyBuilding(int32_t alignment, BuildingID bid) const
{ {
for(auto tdi : developmentInfos) for(auto tdi : developmentInfos)
{ {
if(tdi.town->subID == alignment && tdi.town->hasBuilt(bid)) if(tdi.town->getFaction() == alignment && tdi.town->hasBuilt(bid))
return true; return true;
} }

View File

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

View File

@ -24,7 +24,7 @@ ui64 FuzzyHelper::estimateBankDanger(const CBank * bank)
{ {
//this one is not fuzzy anymore, just calculate weighted average //this one is not fuzzy anymore, just calculate weighted average
auto objectInfo = VLC->objtypeh->getHandlerFor(bank->ID, bank->subID)->getObjectInfo(bank->appearance); auto objectInfo = bank->getObjectHandler()->getObjectInfo(bank->appearance);
CBankInfo * bankInfo = dynamic_cast<CBankInfo *>(objectInfo.get()); CBankInfo * bankInfo = dynamic_cast<CBankInfo *>(objectInfo.get());
@ -161,10 +161,7 @@ ui64 FuzzyHelper::evaluateDanger(const CGObjectInstance * obj)
} }
case Obj::PYRAMID: case Obj::PYRAMID:
{ {
if(obj->subID == 0) return estimateBankDanger(dynamic_cast<const CBank *>(obj));
return estimateBankDanger(dynamic_cast<const CBank *>(obj));
else
return 0;
} }
default: default:
return 0; return 0;

View File

@ -122,7 +122,7 @@ TResources getCreatureBankResources(const CGObjectInstance * target, const CGHer
{ {
//Fixme: unused variable hero //Fixme: unused variable hero
auto objectInfo = VLC->objtypeh->getHandlerFor(target->ID, target->subID)->getObjectInfo(target->appearance); auto objectInfo = target->getObjectHandler()->getObjectInfo(target->appearance);
CBankInfo * bankInfo = dynamic_cast<CBankInfo *>(objectInfo.get()); CBankInfo * bankInfo = dynamic_cast<CBankInfo *>(objectInfo.get());
auto resources = bankInfo->getPossibleResourcesReward(); auto resources = bankInfo->getPossibleResourcesReward();
TResources result = TResources(); TResources result = TResources();
@ -139,7 +139,7 @@ TResources getCreatureBankResources(const CGObjectInstance * target, const CGHer
uint64_t getCreatureBankArmyReward(const CGObjectInstance * target, const CGHeroInstance * hero) uint64_t getCreatureBankArmyReward(const CGObjectInstance * target, const CGHeroInstance * hero)
{ {
auto objectInfo = VLC->objtypeh->getHandlerFor(target->ID, target->subID)->getObjectInfo(target->appearance); auto objectInfo = target->getObjectHandler()->getObjectInfo(target->appearance);
CBankInfo * bankInfo = dynamic_cast<CBankInfo *>(objectInfo.get()); CBankInfo * bankInfo = dynamic_cast<CBankInfo *>(objectInfo.get());
auto creatures = bankInfo->getPossibleCreaturesReward(); auto creatures = bankInfo->getPossibleCreaturesReward();
uint64_t result = 0; uint64_t result = 0;
@ -467,14 +467,20 @@ float RewardEvaluator::getStrategicalValue(const CGObjectInstance * target) cons
switch(target->ID) switch(target->ID)
{ {
case Obj::MINE: case Obj::MINE:
return target->subID == GameResID(EGameResID::GOLD) {
auto mine = dynamic_cast<const CGMine *>(target);
return mine->producedResource == EGameResID::GOLD
? 0.5f ? 0.5f
: 0.4f * getTotalResourceRequirementStrength(target->subID) + 0.1f * getResourceRequirementStrength(target->subID); : 0.4f * getTotalResourceRequirementStrength(mine->producedResource) + 0.1f * getResourceRequirementStrength(mine->producedResource);
}
case Obj::RESOURCE: case Obj::RESOURCE:
return target->subID == GameResID(EGameResID::GOLD) {
auto resource = dynamic_cast<const CGResource *>(target);
return resource->resourceID() == EGameResID::GOLD
? 0 ? 0
: 0.2f * getTotalResourceRequirementStrength(target->subID) + 0.4f * getResourceRequirementStrength(target->subID); : 0.2f * getTotalResourceRequirementStrength(resource->resourceID()) + 0.4f * getResourceRequirementStrength(resource->resourceID());
}
case Obj::CREATURE_BANK: case Obj::CREATURE_BANK:
{ {
@ -626,12 +632,14 @@ int32_t RewardEvaluator::getGoldReward(const CGObjectInstance * target, const CG
const int dailyIncomeMultiplier = 5; const int dailyIncomeMultiplier = 5;
const float enemyArmyEliminationGoldRewardRatio = 0.2f; const float enemyArmyEliminationGoldRewardRatio = 0.2f;
const int32_t heroEliminationBonus = GameConstants::HERO_GOLD_COST / 2; const int32_t heroEliminationBonus = GameConstants::HERO_GOLD_COST / 2;
auto isGold = target->subID == GameResID(EGameResID::GOLD); // TODO: other resorces could be sold but need to evaluate market power
switch(target->ID) switch(target->ID)
{ {
case Obj::RESOURCE: case Obj::RESOURCE:
return isGold ? 600 : 100; {
auto * res = dynamic_cast<const CGResource*>(target);
return res->resourceID() == GameResID::GOLD ? 600 : 100;
}
case Obj::TREASURE_CHEST: case Obj::TREASURE_CHEST:
return 1500; return 1500;
case Obj::WATER_WHEEL: case Obj::WATER_WHEEL:
@ -640,7 +648,10 @@ int32_t RewardEvaluator::getGoldReward(const CGObjectInstance * target, const CG
return dailyIncomeMultiplier * estimateTownIncome(ai->cb.get(), target, hero); return dailyIncomeMultiplier * estimateTownIncome(ai->cb.get(), target, hero);
case Obj::MINE: case Obj::MINE:
case Obj::ABANDONED_MINE: case Obj::ABANDONED_MINE:
return dailyIncomeMultiplier * (isGold ? 1000 : 75); {
auto * mine = dynamic_cast<const CGMine*>(target);
return dailyIncomeMultiplier * (mine->producedResource == GameResID::GOLD ? 1000 : 75);
}
case Obj::MYSTICAL_GARDEN: case Obj::MYSTICAL_GARDEN:
case Obj::WINDMILL: case Obj::WINDMILL:
return 100; return 100;
@ -1005,7 +1016,7 @@ public:
uint64_t RewardEvaluator::getUpgradeArmyReward(const CGTownInstance * town, const BuildingInfo & bi) const uint64_t RewardEvaluator::getUpgradeArmyReward(const CGTownInstance * town, const BuildingInfo & bi) const
{ {
if(ai->buildAnalyzer->hasAnyBuilding(town->subID, bi.id)) if(ai->buildAnalyzer->hasAnyBuilding(town->getFaction(), bi.id))
return 0; return 0;
auto creaturesToUpgrade = ai->armyManager->getTotalCreaturesAvailable(bi.baseCreatureID); auto creaturesToUpgrade = ai->armyManager->getTotalCreaturesAvailable(bi.baseCreatureID);

View File

@ -26,7 +26,6 @@ using crint3 = const int3 &;
using crstring = const std::string &; using crstring = const std::string &;
using dwellingContent = std::pair<ui32, std::vector<CreatureID>>; using dwellingContent = std::pair<ui32, std::vector<CreatureID>>;
const int GOLD_MINE_PRODUCTION = 1000, WOOD_ORE_MINE_PRODUCTION = 2, RESOURCE_MINE_PRODUCTION = 1;
const int ACTUAL_RESOURCE_COUNT = 7; const int ACTUAL_RESOURCE_COUNT = 7;
const int ALLOWED_ROAMING_HEROES = 8; const int ALLOWED_ROAMING_HEROES = 8;

View File

@ -406,7 +406,7 @@ float VisitObjEngine::evaluate(Goals::VisitObj & goal)
else else
{ {
MapObjectsEvaluator::getInstance().addObjectData(obj->ID, obj->subID, 0); MapObjectsEvaluator::getInstance().addObjectData(obj->ID, obj->subID, 0);
logGlobal->error("AI met object type it doesn't know - ID: " + std::to_string(obj->ID) + ", subID: " + std::to_string(obj->subID) + " - adding to database with value " + std::to_string(objValue)); logGlobal->error("AI met object type it doesn't know - ID: %d, subID: %d - adding to database with value %d ", obj->ID, obj->subID, objValue);
} }
setSharedFuzzyVariables(goal); setSharedFuzzyVariables(goal);

View File

@ -66,7 +66,7 @@ ui64 FuzzyHelper::estimateBankDanger(const CBank * bank)
{ {
//this one is not fuzzy anymore, just calculate weighted average //this one is not fuzzy anymore, just calculate weighted average
auto objectInfo = VLC->objtypeh->getHandlerFor(bank->ID, bank->subID)->getObjectInfo(bank->appearance); auto objectInfo = bank->getObjectHandler()->getObjectInfo(bank->appearance);
CBankInfo * bankInfo = dynamic_cast<CBankInfo *>(objectInfo.get()); CBankInfo * bankInfo = dynamic_cast<CBankInfo *>(objectInfo.get());
@ -324,15 +324,8 @@ ui64 FuzzyHelper::evaluateDanger(const CGObjectInstance * obj, const VCAI * ai)
case Obj::DRAGON_UTOPIA: case Obj::DRAGON_UTOPIA:
case Obj::SHIPWRECK: //shipwreck case Obj::SHIPWRECK: //shipwreck
case Obj::DERELICT_SHIP: //derelict ship case Obj::DERELICT_SHIP: //derelict ship
// case Obj::PYRAMID:
return estimateBankDanger(dynamic_cast<const CBank *>(obj));
case Obj::PYRAMID: case Obj::PYRAMID:
{ return estimateBankDanger(dynamic_cast<const CBank *>(obj));
if(obj->subID == 0)
return estimateBankDanger(dynamic_cast<const CBank *>(obj));
else
return 0;
}
default: default:
return 0; return 0;
} }

View File

@ -43,10 +43,10 @@ TGoalVec CollectRes::getAllPossibleSubgoals()
return resID == GameResID(EGameResID::GOLD); return resID == GameResID(EGameResID::GOLD);
break; break;
case Obj::RESOURCE: case Obj::RESOURCE:
return obj->subID == resID; return dynamic_cast<const CGResource*>(obj)->resourceID() == GameResID(resID);
break; break;
case Obj::MINE: case Obj::MINE:
return (obj->subID == resID && return (dynamic_cast<const CGMine*>(obj)->producedResource == GameResID(resID) &&
(cb->getPlayerRelations(obj->tempOwner, ai->playerID) == PlayerRelations::ENEMIES)); //don't capture our mines (cb->getPlayerRelations(obj->tempOwner, ai->playerID) == PlayerRelations::ENEMIES)); //don't capture our mines
break; break;
case Obj::CAMPFIRE: case Obj::CAMPFIRE:

View File

@ -88,7 +88,7 @@ TGoalVec GatherTroops::getAllPossibleSubgoals()
} }
auto creature = VLC->creatures()->getByIndex(objid); auto creature = VLC->creatures()->getByIndex(objid);
if(t->subID == creature->getFaction()) //TODO: how to force AI to build unupgraded creatures? :O if(t->getFaction() == creature->getFaction()) //TODO: how to force AI to build unupgraded creatures? :O
{ {
auto tryFindCreature = [&]() -> std::optional<std::vector<CreatureID>> auto tryFindCreature = [&]() -> std::optional<std::vector<CreatureID>>
{ {

View File

@ -190,7 +190,7 @@ Goals::TSubgoal PathfindingManager::clearWayTo(HeroPtr hero, int3 firstTileToGet
if(isBlockedBorderGate(firstTileToGet)) if(isBlockedBorderGate(firstTileToGet))
{ {
//FIXME: this way we'll not visit gate and activate quest :? //FIXME: this way we'll not visit gate and activate quest :?
return sptr(Goals::FindObj(Obj::KEYMASTER, cb->getTile(firstTileToGet)->visitableObjects.back()->subID)); return sptr(Goals::FindObj(Obj::KEYMASTER, cb->getTile(firstTileToGet)->visitableObjects.back()->getObjTypeIndex()));
} }
auto topObj = cb->getTopObj(firstTileToGet); auto topObj = cb->getTopObj(firstTileToGet);

View File

@ -59,19 +59,7 @@ TResources ResourceManager::estimateIncome() const
if (obj->ID == Obj::MINE) if (obj->ID == Obj::MINE)
{ {
auto mine = dynamic_cast<const CGMine*>(obj); auto mine = dynamic_cast<const CGMine*>(obj);
switch (mine->producedResource.toEnum()) ret += mine->dailyIncome();
{
case EGameResID::WOOD:
case EGameResID::ORE:
ret[obj->subID] += WOOD_ORE_MINE_PRODUCTION;
break;
case EGameResID::GOLD:
ret[EGameResID::GOLD] += GOLD_MINE_PRODUCTION;
break;
default:
ret[obj->subID] += RESOURCE_MINE_PRODUCTION;
break;
}
} }
} }

View File

@ -1760,11 +1760,11 @@ void VCAI::addVisitableObj(const CGObjectInstance * obj)
CGTeleport::addToChannel(knownTeleportChannels, teleportObj); CGTeleport::addToChannel(knownTeleportChannels, teleportObj);
} }
const CGObjectInstance * VCAI::lookForArt(int aid) const const CGObjectInstance * VCAI::lookForArt(ArtifactID aid) const
{ {
for(const CGObjectInstance * obj : ai->visitableObjs) for(const CGObjectInstance * obj : ai->visitableObjs)
{ {
if(obj->ID == Obj::ARTIFACT && obj->subID == aid) if(obj->ID == Obj::ARTIFACT && dynamic_cast<const CGArtifact *>(obj)->getArtifact() == aid)
return obj; return obj;
} }

View File

@ -251,7 +251,7 @@ public:
void retrieveVisitableObjs(); void retrieveVisitableObjs();
virtual std::vector<const CGObjectInstance *> getFlaggedObjects() const; virtual std::vector<const CGObjectInstance *> getFlaggedObjects() const;
const CGObjectInstance * lookForArt(int aid) const; const CGObjectInstance * lookForArt(ArtifactID aid) const;
bool isAccessible(const int3 & pos) const; bool isAccessible(const int3 & pos) const;
HeroPtr getHeroWithGrail() const; HeroPtr getHeroWithGrail() const;

View File

@ -265,7 +265,7 @@ void CCallback::recruitHero(const CGObjectInstance *townOrTavern, const CGHeroIn
assert(townOrTavern); assert(townOrTavern);
assert(hero); assert(hero);
HireHero pack(HeroTypeID(hero->subID), townOrTavern->id); HireHero pack(hero->getHeroType(), townOrTavern->id);
pack.player = *player; pack.player = *player;
sendRequest(&pack); sendRequest(&pack);
} }

View File

@ -604,7 +604,7 @@ void ApplyClientNetPackVisitor::visitSetHeroesInTown(SetHeroesInTown & pack)
void ApplyClientNetPackVisitor::visitHeroRecruited(HeroRecruited & pack) void ApplyClientNetPackVisitor::visitHeroRecruited(HeroRecruited & pack)
{ {
CGHeroInstance *h = gs.map->heroesOnMap.back(); CGHeroInstance *h = gs.map->heroesOnMap.back();
if(h->subID != pack.hid) if(h->getHeroType() != pack.hid)
{ {
logNetwork->error("Something wrong with hero recruited!"); logNetwork->error("Something wrong with hero recruited!");
} }

View File

@ -427,11 +427,7 @@ size_t MapRendererWorldViewContext::overlayImageIndex(const int3 & coordinates)
if(!object->visitableAt(coordinates.x, coordinates.y)) if(!object->visitableAt(coordinates.x, coordinates.y))
continue; continue;
ObjectPosInfo info; ObjectPosInfo info(object);
info.pos = coordinates;
info.id = object->ID;
info.subId = object->subID;
info.owner = object->tempOwner;
size_t iconIndex = selectOverlayImageForObject(info); size_t iconIndex = selectOverlayImageForObject(info);

View File

@ -920,7 +920,7 @@ void CCastleBuildings::enterToTheQuickRecruitmentWindow()
void CCastleBuildings::enterFountain(const BuildingID & building, BuildingSubID::EBuildingSubID subID, BuildingID upgrades) void CCastleBuildings::enterFountain(const BuildingID & building, BuildingSubID::EBuildingSubID subID, BuildingID upgrades)
{ {
std::vector<std::shared_ptr<CComponent>> comps(1, std::make_shared<CComponent>(CComponent::building,town->subID,building)); std::vector<std::shared_ptr<CComponent>> comps(1, std::make_shared<CComponent>(CComponent::building,town->getFaction(),building));
std::string descr = town->town->buildings.find(building)->second->getDescriptionTranslated(); std::string descr = town->town->buildings.find(building)->second->getDescriptionTranslated();
std::string hasNotProduced; std::string hasNotProduced;
std::string hasProduced; std::string hasProduced;
@ -969,9 +969,9 @@ void CCastleBuildings::enterMagesGuild()
{ {
const StartInfo *si = LOCPLINT->cb->getStartInfo(); const StartInfo *si = LOCPLINT->cb->getStartInfo();
// it would be nice to find a way to move this hack to config/mapOverrides.json // it would be nice to find a way to move this hack to config/mapOverrides.json
if(si && si->campState && // We're in campaign, if(si && si->campState && // We're in campaign,
(si->campState->getFilename() == "DATA/YOG.H3C") && // which is "Birth of a Barbarian", (si->campState->getFilename() == "DATA/YOG.H3C") && // which is "Birth of a Barbarian",
(hero->subID == 45)) // and the hero is Yog (based on Solmyr) (hero->getHeroType() == 45)) // and the hero is Yog (based on Solmyr)
{ {
// "Yog has given up magic in all its forms..." // "Yog has given up magic in all its forms..."
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[736]); LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[736]);

View File

@ -667,10 +667,10 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket * Market, const CGHeroInsta
title = (*CGI->townh)[ETownType::STRONGHOLD]->town->buildings[BuildingID::FREELANCERS_GUILD]->getNameTranslated(); title = (*CGI->townh)[ETownType::STRONGHOLD]->town->buildings[BuildingID::FREELANCERS_GUILD]->getNameTranslated();
break; break;
case EMarketMode::RESOURCE_ARTIFACT: case EMarketMode::RESOURCE_ARTIFACT:
title = (*CGI->townh)[o->subID]->town->buildings[BuildingID::ARTIFACT_MERCHANT]->getNameTranslated(); title = (*CGI->townh)[o->getFaction()]->town->buildings[BuildingID::ARTIFACT_MERCHANT]->getNameTranslated();
break; break;
case EMarketMode::ARTIFACT_RESOURCE: case EMarketMode::ARTIFACT_RESOURCE:
title = (*CGI->townh)[o->subID]->town->buildings[BuildingID::ARTIFACT_MERCHANT]->getNameTranslated(); title = (*CGI->townh)[o->getFaction()]->town->buildings[BuildingID::ARTIFACT_MERCHANT]->getNameTranslated();
// create image that copies part of background containing slot MISC_1 into position of slot MISC_5 // create image that copies part of background containing slot MISC_1 into position of slot MISC_5
// this is workaround for bug in H3 files where this slot for ragdoll on this screen is missing // this is workaround for bug in H3 files where this slot for ragdoll on this screen is missing

View File

@ -580,7 +580,7 @@ void CGameState::placeStartingHero(const PlayerColor & playerColor, const HeroTy
CGHeroInstance * hero = dynamic_cast<CGHeroInstance *>(obj); CGHeroInstance * hero = dynamic_cast<CGHeroInstance *>(obj);
hero->ID = Obj::HERO; hero->ID = Obj::HERO;
hero->subID = heroTypeId; hero->setHeroType(heroTypeId);
hero->tempOwner = playerColor; hero->tempOwner = playerColor;
hero->pos = townPos; hero->pos = townPos;

View File

@ -256,7 +256,7 @@ void CGameStateCampaign::placeCampaignHeroes()
assert(0); // should not happen assert(0); // should not happen
} }
hero->subID = heroTypeId; hero->setHeroType(heroTypeId);
gameState->map->getEditManager()->insertObject(hero); gameState->map->getEditManager()->insertObject(hero);
} }
} }

View File

@ -290,6 +290,12 @@ HeroTypeID CGHeroInstance::getHeroType() const
return HeroTypeID(getObjTypeIndex().getNum()); return HeroTypeID(getObjTypeIndex().getNum());
} }
void CGHeroInstance::setHeroType(HeroTypeID heroType)
{
assert(type == nullptr);
subID = heroType;
}
void CGHeroInstance::initHero(CRandomGenerator & rand, const HeroTypeID & SUBID) void CGHeroInstance::initHero(CRandomGenerator & rand, const HeroTypeID & SUBID)
{ {
subID = SUBID.getNum(); subID = SUBID.getNum();

View File

@ -232,6 +232,7 @@ public:
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
HeroTypeID getHeroType() const; HeroTypeID getHeroType() const;
void setHeroType(HeroTypeID type);
void initHero(CRandomGenerator & rand); void initHero(CRandomGenerator & rand);
void initHero(CRandomGenerator & rand, const HeroTypeID & SUBID); void initHero(CRandomGenerator & rand, const HeroTypeID & SUBID);

View File

@ -129,6 +129,14 @@ bool CGMine::isAbandoned() const
return (getObjTypeIndex() >= 7); return (getObjTypeIndex() >= 7);
} }
ResourceSet CGMine::dailyIncome() const
{
ResourceSet result;
result[producedResource] += defaultResProduction();
return result;
}
std::string CGMine::getObjectName() const std::string CGMine::getObjectName() const
{ {
return VLC->generaltexth->translate("core.minename", getObjTypeIndex()); return VLC->generaltexth->translate("core.minename", getObjTypeIndex());
@ -466,7 +474,7 @@ TeleportChannelID CGMonolith::findMeChannel(const std::vector<Obj> & IDs, int Su
if(!obj) if(!obj)
continue; continue;
const auto * teleportObj = dynamic_cast<const CGTeleport *>(cb->getObj(obj->id)); const auto * teleportObj = dynamic_cast<const CGMonolith *>(cb->getObj(obj->id));
if(teleportObj && vstd::contains(IDs, teleportObj->ID) && teleportObj->subID == SubID) if(teleportObj && vstd::contains(IDs, teleportObj->ID) && teleportObj->subID == SubID)
return teleportObj->channel; return teleportObj->channel;
} }

View File

@ -142,6 +142,7 @@ public:
std::set<GameResID> abandonedMineResources; std::set<GameResID> abandonedMineResources;
bool isAbandoned() const; bool isAbandoned() const;
ResourceSet dailyIncome() const;
private: private:
void onHeroVisit(const CGHeroInstance * h) const override; void onHeroVisit(const CGHeroInstance * h) const override;

View File

@ -1263,7 +1263,7 @@ void CMapLoaderJson::readObjects()
std::sort(map->heroesOnMap.begin(), map->heroesOnMap.end(), [](const ConstTransitivePtr<CGHeroInstance> & a, const ConstTransitivePtr<CGHeroInstance> & b) std::sort(map->heroesOnMap.begin(), map->heroesOnMap.end(), [](const ConstTransitivePtr<CGHeroInstance> & a, const ConstTransitivePtr<CGHeroInstance> & b)
{ {
return a->subID < b->subID; return a->getObjTypeIndex() < b->getObjTypeIndex();
}); });
} }

View File

@ -1487,6 +1487,7 @@ void NewObject::applyGs(CGameState *gs)
CGObjectInstance * o = handler->create(); CGObjectInstance * o = handler->create();
handler->configureObject(o, gs->getRandomGenerator()); handler->configureObject(o, gs->getRandomGenerator());
assert(o->ID == this->ID);
if (ID == Obj::MONSTER) //probably more options will be needed if (ID == Obj::MONSTER) //probably more options will be needed
{ {
@ -1514,8 +1515,6 @@ void NewObject::applyGs(CGameState *gs)
o->appearance = handler->getTemplates().front(); o->appearance = handler->getTemplates().front();
o->id = ObjectInstanceID(static_cast<si32>(gs->map->objects.size())); o->id = ObjectInstanceID(static_cast<si32>(gs->map->objects.size()));
o->ID = ID;
o->subID = subID;
o->pos = targetPos + o->getVisitableOffset(); o->pos = targetPos + o->getVisitableOffset();
gs->map->objects.emplace_back(o); gs->map->objects.emplace_back(o);

View File

@ -260,15 +260,18 @@ std::vector<int3> CPathfinderHelper::getTeleportExits(const PathNodeInfo & sourc
teleportationExits.push_back(exit); teleportationExits.push_back(exit);
} }
} }
else if(options.useCastleGate else if(options.useCastleGate && source.nodeObject->ID == Obj::TOWN && source.objectRelations != PlayerRelations::ENEMIES)
&& (source.nodeObject->ID == Obj::TOWN && source.nodeObject->subID == ETownType::INFERNO
&& source.objectRelations != PlayerRelations::ENEMIES))
{ {
/// TODO: Find way to reuse CPlayerSpecificInfoCallback::getTownsInfo auto * town = dynamic_cast<const CGTownInstance *>(source.nodeObject);
/// This may be handy if we allow to use teleportation to friendly towns assert(town);
for(const auto & exit : getCastleGates(source)) if (town && town->getFaction() == FactionID::INFERNO)
{ {
teleportationExits.push_back(exit); /// TODO: Find way to reuse CPlayerSpecificInfoCallback::getTownsInfo
/// This may be handy if we allow to use teleportation to friendly towns
for(const auto & exit : getCastleGates(source))
{
teleportationExits.push_back(exit);
}
} }
} }

View File

@ -115,7 +115,7 @@ void Object::Instance::setAnyTemplate(CRandomGenerator & rng)
{ {
auto templates = dObject.getObjectHandler()->getTemplates(); auto templates = dObject.getObjectHandler()->getTemplates();
if(templates.empty()) if(templates.empty())
throw rmgException(boost::str(boost::format("Did not find any graphics for object (%d,%d)") % dObject.ID % dObject.subID)); throw rmgException(boost::str(boost::format("Did not find any graphics for object (%d,%d)") % dObject.ID % dObject.getObjTypeIndex()));
dObject.appearance = *RandomGeneratorUtil::nextItem(templates, rng); dObject.appearance = *RandomGeneratorUtil::nextItem(templates, rng);
dAccessibleAreaCache.clear(); dAccessibleAreaCache.clear();
@ -128,7 +128,7 @@ void Object::Instance::setTemplate(TerrainId terrain, CRandomGenerator & rng)
if (templates.empty()) if (templates.empty())
{ {
auto terrainName = VLC->terrainTypeHandler->getById(terrain)->getNameTranslated(); auto terrainName = VLC->terrainTypeHandler->getById(terrain)->getNameTranslated();
throw rmgException(boost::str(boost::format("Did not find graphics for object (%d,%d) at %s") % dObject.ID % dObject.subID % terrainName)); throw rmgException(boost::str(boost::format("Did not find graphics for object (%d,%d) at %s") % dObject.ID % dObject.getObjTypeIndex() % terrainName));
} }
dObject.appearance = *RandomGeneratorUtil::nextItem(templates, rng); dObject.appearance = *RandomGeneratorUtil::nextItem(templates, rng);
@ -338,7 +338,7 @@ void Object::Instance::finalize(RmgMap & map, CRandomGenerator & rng)
auto templates = dObject.getObjectHandler()->getTemplates(terrainType->getId()); auto templates = dObject.getObjectHandler()->getTemplates(terrainType->getId());
if (templates.empty()) 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)); throw rmgException(boost::str(boost::format("Did not find graphics for object (%d,%d) at %s (terrain %d)") % dObject.ID % dObject.getObjTypeIndex() % getPosition(true).toString() % terrainType));
} }
else else
{ {

View File

@ -111,7 +111,7 @@ void TreasurePlacer::addAllPossibleObjects()
auto factory = VLC->objtypeh->getHandlerFor(Obj::PRISON, 0); auto factory = VLC->objtypeh->getHandlerFor(Obj::PRISON, 0);
auto* obj = dynamic_cast<CGHeroInstance*>(factory->create()); auto* obj = dynamic_cast<CGHeroInstance*>(factory->create());
obj->subID = hid; //will be initialized later obj->setHeroType(hid); //will be initialized later
obj->exp = generator.getConfig().prisonExperience[i]; obj->exp = generator.getConfig().prisonExperience[i];
obj->setOwner(PlayerColor::NEUTRAL); obj->setOwner(PlayerColor::NEUTRAL);
generator.banHero(hid); generator.banHero(hid);

View File

@ -16,7 +16,7 @@
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
ObjectPosInfo::ObjectPosInfo(const CGObjectInstance * obj): ObjectPosInfo::ObjectPosInfo(const CGObjectInstance * obj):
pos(obj->visitablePos()), id(obj->ID), subId(obj->subID), owner(obj->tempOwner) pos(obj->visitablePos()), id(obj->ID), subId(obj->getObjTypeIndex()), owner(obj->tempOwner)
{ {
} }

View File

@ -217,7 +217,7 @@ void MapController::repairMap(CMap * map) const
art->storedArtifact = a; art->storedArtifact = a;
} }
else else
map->allowedArtifact.at(art->subID) = true; map->allowedArtifact.at(art->getArtifact()) = true;
} }
} }
} }
@ -623,7 +623,7 @@ ModCompatibilityInfo MapController::modAssessmentMap(const CMap & map)
if(obj->ID == Obj::HERO) if(obj->ID == Obj::HERO)
continue; //stub! continue; //stub!
auto handler = VLC->objtypeh->getHandlerFor(obj->ID, obj->subID); auto handler = obj->getObjectHandler();
auto modName = QString::fromStdString(handler->getJsonKey()).split(":").at(0).toStdString(); auto modName = QString::fromStdString(handler->getJsonKey()).split(":").at(0).toStdString();
if(modName != "core") if(modName != "core")
result[modName] = VLC->modh->getModInfo(modName).getVerificationInfo(); result[modName] = VLC->modh->getModInfo(modName).getVerificationInfo();

View File

@ -2315,7 +2315,7 @@ bool CGameHandler::buildStructure(ObjectInstanceID tid, BuildingID requestedID,
auto isLibrary = isMageGuild ? false auto isLibrary = isMageGuild ? false
: t->town->buildings.at(buildingID)->subId == BuildingSubID::EBuildingSubID::LIBRARY; : t->town->buildings.at(buildingID)->subId == BuildingSubID::EBuildingSubID::LIBRARY;
if(isMageGuild || isLibrary || (t->subID == ETownType::CONFLUX && buildingID == BuildingID::GRAIL)) if(isMageGuild || isLibrary || (t->getFaction() == ETownType::CONFLUX && buildingID == BuildingID::GRAIL))
{ {
if(t->visitingHero) if(t->visitingHero)
giveSpells(t,t->visitingHero); giveSpells(t,t->visitingHero);
@ -3284,7 +3284,7 @@ void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n)
if (!town->hasBuilt(i)) if (!town->hasBuilt(i))
{ {
buildStructure(town->id, i, true); buildStructure(town->id, i, true);
iw.components.emplace_back(Component::EComponentType::BUILDING, town->subID, i, 0); iw.components.emplace_back(Component::EComponentType::BUILDING, town->getFaction(), i, 0);
} }
} }
@ -3430,7 +3430,7 @@ void CGameHandler::objectVisited(const CGObjectInstance * obj, const CGHeroInsta
{ {
using events::ObjectVisitStarted; using events::ObjectVisitStarted;
logGlobal->debug("%s visits %s (%d:%d)", h->nodeName(), obj->getObjectName(), obj->ID, obj->subID); logGlobal->debug("%s visits %s (%d)", h->nodeName(), obj->getObjectName(), obj->ID);
if (getVisitingHero(obj) != nullptr) if (getVisitingHero(obj) != nullptr)
{ {

View File

@ -50,8 +50,8 @@ TavernHeroSlot HeroPoolProcessor::selectSlotForRole(const PlayerColor & player,
// try to find "better" slot to overwrite // try to find "better" slot to overwrite
// we want to avoid overwriting retreated heroes when tavern still has slot with random hero // we want to avoid overwriting retreated heroes when tavern still has slot with random hero
// as well as avoid overwriting surrendered heroes if we can overwrite retreated hero // as well as avoid overwriting surrendered heroes if we can overwrite retreated hero
auto roleLeft = heroesPool->getSlotRole(HeroTypeID(heroes[0]->subID)); auto roleLeft = heroesPool->getSlotRole(heroes[0]->getHeroType());
auto roleRight = heroesPool->getSlotRole(HeroTypeID(heroes[1]->subID)); auto roleRight = heroesPool->getSlotRole(heroes[1]->getHeroType());
if (roleLeft > roleRight) if (roleLeft > roleRight)
return TavernHeroSlot::RANDOM; return TavernHeroSlot::RANDOM;
@ -73,7 +73,7 @@ void HeroPoolProcessor::onHeroSurrendered(const PlayerColor & color, const CGHer
sah.slotID = selectSlotForRole(color, sah.roleID); sah.slotID = selectSlotForRole(color, sah.roleID);
sah.player = color; sah.player = color;
sah.hid.setNum(hero->subID); sah.hid = hero->getHeroType();
gameHandler->sendAndApply(&sah); gameHandler->sendAndApply(&sah);
} }
@ -84,7 +84,7 @@ void HeroPoolProcessor::onHeroEscaped(const PlayerColor & color, const CGHeroIns
sah.slotID = selectSlotForRole(color, sah.roleID); sah.slotID = selectSlotForRole(color, sah.roleID);
sah.player = color; sah.player = color;
sah.hid.setNum(hero->subID); sah.hid = hero->getHeroType();
sah.army.clearSlots(); sah.army.clearSlots();
sah.army.setCreature(SlotID(0), hero->type->initialArmy.at(0).creature, 1); sah.army.setCreature(SlotID(0), hero->type->initialArmy.at(0).creature, 1);
@ -111,7 +111,7 @@ void HeroPoolProcessor::selectNewHeroForSlot(const PlayerColor & color, TavernHe
if (newHero) if (newHero)
{ {
sah.hid.setNum(newHero->subID); sah.hid = newHero->getHeroType();
if (giveArmy) if (giveArmy)
{ {
@ -193,7 +193,7 @@ bool HeroPoolProcessor::hireHero(const ObjectInstanceID & objectID, const HeroTy
for(const auto & hero : recruitableHeroes) for(const auto & hero : recruitableHeroes)
{ {
if(hero->subID == heroToRecruit) if(hero->getHeroType() == heroToRecruit)
recruitedHero = hero; recruitedHero = hero;
} }
@ -206,7 +206,7 @@ bool HeroPoolProcessor::hireHero(const ObjectInstanceID & objectID, const HeroTy
HeroRecruited hr; HeroRecruited hr;
hr.tid = mapObject->id; hr.tid = mapObject->id;
hr.hid.setNum(recruitedHero->subID); hr.hid = recruitedHero->getHeroType();
hr.player = player; hr.player = player;
hr.tile = recruitedHero->convertFromVisitablePos(targetPos ); hr.tile = recruitedHero->convertFromVisitablePos(targetPos );
if(gameHandler->getTile(targetPos)->isWater() && !recruitedHero->boat) if(gameHandler->getTile(targetPos)->isWater() && !recruitedHero->boat)