1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-17 00:07:41 +02:00

Remove pointer to objects from TerrainTile

This commit is contained in:
Ivan Savenko
2025-03-19 14:40:45 +00:00
parent 63d00b080e
commit cd7732456a
26 changed files with 164 additions and 113 deletions

View File

@ -1332,8 +1332,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
{
auto tile = cb->getTile(coord, false);
assert(tile);
return tile->topVisitableObj(ignoreHero);
//return cb->getTile(coord,false)->topVisitableObj(ignoreHero);
return cb->getObj(tile->topVisitableObj(ignoreHero));
};
auto isTeleportAction = [&](EPathNodeAction action) -> bool

View File

@ -202,7 +202,7 @@ bool canBeEmbarkmentPoint(const TerrainTile * t, bool fromWater)
}
else if(!fromWater) // do not try to board when in water sector
{
if(t->visitableObjects.size() == 1 && t->topVisitableId() == Obj::BOAT)
if(t->visitableObjects.size() == 1 && cb->getObjInstance(t->topVisitableObj())->ID == Obj::BOAT)
return true;
}
return false;

View File

@ -192,7 +192,7 @@ bool canBeEmbarkmentPoint(const TerrainTile * t, bool fromWater)
}
else if(!fromWater) // do not try to board when in water sector
{
if(t->visitableObjects.size() == 1 && t->topVisitableId() == Obj::BOAT)
if(t->visitableObjects.size() == 1 && cb->getObjInstance(t->topVisitableObj())->ID == Obj::BOAT)
return true;
}
return false;
@ -200,9 +200,11 @@ bool canBeEmbarkmentPoint(const TerrainTile * t, bool fromWater)
bool isBlockedBorderGate(int3 tileToHit) //TODO: is that function needed? should be handled by pathfinder
{
if(cb->getTile(tileToHit)->topVisitableId() != Obj::BORDER_GATE)
const auto * object = cb->getTopObj(tileToHit);
if( object && object->id != Obj::BORDER_GATE)
return false;
auto gate = dynamic_cast<const CGKeys *>(cb->getTile(tileToHit)->topVisitableObj());
auto gate = dynamic_cast<const CGKeys *>(object);
return !gate->passableFor(ai->playerID);
}

View File

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

View File

@ -1868,10 +1868,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
auto getObj = [&](int3 coord, bool ignoreHero)
{
auto tile = cb->getTile(coord, false);
assert(tile);
return tile->topVisitableObj(ignoreHero);
//return cb->getTile(coord,false)->topVisitableObj(ignoreHero);
return cb->getObj(cb->getTile(coord)->topVisitableObj(ignoreHero));
};
auto isTeleportAction = [&](EPathNodeAction action) -> bool

View File

@ -595,7 +595,7 @@ void ApplyClientNetPackVisitor::visitSetAvailableCreatures(SetAvailableCreatures
PlayerColor p;
if(dw->ID == Obj::WAR_MACHINE_FACTORY) //War Machines Factory is not flaggable, it's "owned" by visitor
p = cl.getTile(dw->visitablePos())->visitableObjects.back()->tempOwner;
p = cl.getObjInstance(cl.getTile(dw->visitablePos())->visitableObjects.back())->getOwner();
else
p = dw->tempOwner;
@ -1016,7 +1016,9 @@ void ApplyClientNetPackVisitor::visitOpenWindow(OpenWindow & pack)
const CGObjectInstance *obj = cl.getObj(ObjectInstanceID(pack.object));
const CGHeroInstance *hero = cl.getHero(ObjectInstanceID(pack.visitor));
const auto market = cl.getMarket(pack.object);
callInterfaceIfPresent(cl, cl.getTile(obj->visitablePos())->visitableObjects.back()->tempOwner, &IGameEventsReceiver::showMarketWindow, market, hero, pack.queryID);
const auto * tile = cl.getTile(obj->visitablePos());
const auto * topObject = cl.getObjInstance(tile->visitableObjects.back());
callInterfaceIfPresent(cl, topObject->getOwner(), &IGameEventsReceiver::showMarketWindow, market, hero, pack.queryID);
}
break;
case EOpenWindowMode::HILL_FORT_WINDOW:
@ -1025,7 +1027,9 @@ void ApplyClientNetPackVisitor::visitOpenWindow(OpenWindow & pack)
//displays Hill fort window
const CGObjectInstance *obj = cl.getObj(ObjectInstanceID(pack.object));
const CGHeroInstance *hero = cl.getHero(ObjectInstanceID(pack.visitor));
callInterfaceIfPresent(cl, cl.getTile(obj->visitablePos())->visitableObjects.back()->tempOwner, &IGameEventsReceiver::showHillFortWindow, obj, hero);
const auto * tile = cl.getTile(obj->visitablePos());
const auto * topObject = cl.getObjInstance(tile->visitableObjects.back());
callInterfaceIfPresent(cl, topObject->getOwner(), &IGameEventsReceiver::showHillFortWindow, obj, hero);
}
break;
case EOpenWindowMode::PUZZLE_MAP:
@ -1076,7 +1080,10 @@ void ApplyClientNetPackVisitor::visitSetAvailableArtifacts(SetAvailableArtifacts
{
const CGBlackMarket *bm = dynamic_cast<const CGBlackMarket *>(cl.getObj(ObjectInstanceID(pack.id)));
assert(bm);
callInterfaceIfPresent(cl, cl.getTile(bm->visitablePos())->visitableObjects.back()->tempOwner, &IGameEventsReceiver::availableArtifactsChanged, bm);
const auto * tile = cl.getTile(bm->visitablePos());
const auto * topObject = cl.getObjInstance(tile->visitableObjects.back());
callInterfaceIfPresent(cl, topObject->getOwner(), &IGameEventsReceiver::availableArtifactsChanged, bm);
}
}

View File

@ -39,8 +39,9 @@ ColorRGBA CMinimapInstance::getTileColor(const int3 & pos) const
return Colors::BLACK;
// if object at tile is owned - it will be colored as its owner
for (const CGObjectInstance *obj : tile->blockingObjects)
for (const ObjectInstanceID objectID : tile->blockingObjects)
{
const auto * obj = GAME->interface()->cb->getObj(objectID);
PlayerColor player = obj->getOwner();
if(player == PlayerColor::NEUTRAL)
return graphics->neutralColor;

View File

@ -278,10 +278,12 @@ std::string MapRendererAdventureContext::overlayText(const int3 & coordinates) c
if (!tile.visitable())
return {};
if ( tile.visitableObjects.back()->ID == Obj::EVENT)
const auto * object = getObject(tile.visitableObjects.back());
if ( object->ID == Obj::EVENT)
return {};
return tile.visitableObjects.back()->getObjectName();
return object->getObjectName();
}
ColorRGBA MapRendererAdventureContext::overlayTextColor(const int3 & coordinates) const
@ -294,7 +296,7 @@ ColorRGBA MapRendererAdventureContext::overlayTextColor(const int3 & coordinates
if (!tile.visitable())
return {};
const auto * object = tile.visitableObjects.back();
const auto * object = getObject(tile.visitableObjects.back());
if (object->getOwner() == GAME->interface()->playerID)
return { 0, 192, 0};

View File

@ -74,9 +74,10 @@ std::shared_ptr<CanvasImage> CMapOverviewWidget::createMinimapForLayer(std::uniq
if(drawPlayerElements)
// if object at tile is owned - it will be colored as its owner
for (const CGObjectInstance *obj : tile.blockingObjects)
for (ObjectInstanceID objectID : tile.blockingObjects)
{
PlayerColor player = obj->getOwner();
const auto * object = map->getObject(objectID);
PlayerColor player = object->getOwner();
if(player == PlayerColor::NEUTRAL)
{
color = graphics->neutralColor;

View File

@ -866,7 +866,7 @@ TerrainId CStackInstance::getNativeTerrain() const
TerrainId CStackInstance::getCurrentTerrain() const
{
return armyObj->getCurrentTerrain();
return getArmy()->getCurrentTerrain();
}
void CStackInstance::deserializationFix()

View File

@ -453,8 +453,8 @@ std::vector <const CGObjectInstance *> CGameInfoCallback::getBlockingObjs( int3
const TerrainTile *t = getTile(pos);
ERROR_RET_VAL_IF(!t, "Not a valid tile requested!", ret);
for(const CGObjectInstance * obj : t->blockingObjects)
ret.push_back(obj);
for(const auto & objID : t->blockingObjects)
ret.push_back(getObj(objID));
return ret;
}
@ -464,10 +464,12 @@ std::vector <const CGObjectInstance *> CGameInfoCallback::getVisitableObjs(int3
const TerrainTile *t = getTile(pos, verbose);
ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!t, verbose, pos.toString() + " is not visible!", ret);
for(const CGObjectInstance * obj : t->visitableObjects)
for(const auto & objID : t->visitableObjects)
{
if(!getPlayerID().has_value() || obj->ID != Obj::EVENT) //hide events from players
ret.push_back(obj);
const auto & object = getObj(objID);
if(!getPlayerID().has_value() || object->ID != Obj::EVENT) //hide events from players
ret.push_back(object);
}
return ret;
}
@ -492,9 +494,12 @@ std::vector <const CGObjectInstance *> CGameInfoCallback::getFlaggableObjects(in
std::vector<const CGObjectInstance *> ret;
const TerrainTile *t = getTile(pos);
ERROR_RET_VAL_IF(!t, "Not a valid tile requested!", ret);
for(const CGObjectInstance *obj : t->blockingObjects)
for(const auto & objectID : t->blockingObjects)
{
const auto * obj = getObj(objectID);
if(obj->tempOwner != PlayerColor::UNFLAGGABLE)
ret.push_back(obj);
}
return ret;
}
@ -724,7 +729,8 @@ bool CGameInfoCallback::isOwnedOrVisited(const CGObjectInstance *obj) const
return true;
const TerrainTile *t = getTile(obj->visitablePos()); //get entrance tile
const CGObjectInstance *visitor = t->visitableObjects.back(); //visitong hero if present or the object itself at last
const ObjectInstanceID visitorID = t->visitableObjects.back(); //visitong hero if present or the object itself at last
const CGObjectInstance * visitor = getObj(visitorID);
return visitor->ID == Obj::HERO && canGetFullInfo(visitor); //owned or allied hero is a visitor
}

View File

@ -1030,7 +1030,8 @@ BattleField CGameState::battleGetBattlefieldType(int3 tile, vstd::RNG & rand)
const TerrainTile &t = map->getTile(tile);
auto * topObject = t.visitableObjects.front();
ObjectInstanceID topObjectID = t.visitableObjects.front();
const CGObjectInstance * topObject = gs->getObjInstance(topObjectID);
if(topObject && topObject->getBattlefield() != BattleField::NONE)
{
return topObject->getBattlefield();
@ -1129,9 +1130,9 @@ void CGameState::calculatePaths(const std::shared_ptr<PathfinderConfig> & config
* @return int3(-1, -1, -1) if the tile is unguarded, or the position of
* the monster guarding the tile.
*/
std::vector<CGObjectInstance*> CGameState::guardingCreatures (int3 pos) const
std::vector<const CGObjectInstance*> CGameState::guardingCreatures (int3 pos) const
{
std::vector<CGObjectInstance*> guards;
std::vector<const CGObjectInstance*> guards;
const int3 originalPos = pos;
if (!map->isInTheMap(pos))
return guards;
@ -1139,12 +1140,13 @@ std::vector<CGObjectInstance*> CGameState::guardingCreatures (int3 pos) const
const TerrainTile &posTile = map->getTile(pos);
if (posTile.visitable())
{
for (CGObjectInstance* obj : posTile.visitableObjects)
for (ObjectInstanceID objectID : posTile.visitableObjects)
{
if(obj->isBlockedVisitable())
const CGObjectInstance * object = getObjInstance(objectID);
if(object->isBlockedVisitable())
{
if (obj->ID == Obj::MONSTER) // Monster
guards.push_back(obj);
if (object->ID == Obj::MONSTER) // Monster
guards.push_back(object);
}
}
}
@ -1158,11 +1160,13 @@ std::vector<CGObjectInstance*> CGameState::guardingCreatures (int3 pos) const
const auto & tile = map->getTile(pos);
if (tile.visitable() && (tile.isWater() == posTile.isWater()))
{
for (CGObjectInstance* obj : tile.visitableObjects)
for (ObjectInstanceID objectID : tile.visitableObjects)
{
if (obj->ID == Obj::MONSTER && map->checkForVisitableDir(pos, &map->getTile(originalPos), originalPos)) // Monster being able to attack investigated tile
const CGObjectInstance * object = getObjInstance(objectID);
if (object->ID == Obj::MONSTER && map->checkForVisitableDir(pos, &map->getTile(originalPos), originalPos)) // Monster being able to attack investigated tile
{
guards.push_back(obj);
guards.push_back(object);
}
}
}

View File

@ -99,7 +99,7 @@ public:
bool checkForVisitableDir(const int3 & src, const int3 & dst) const; //check if src tile is visitable from dst tile
void calculatePaths(const std::shared_ptr<PathfinderConfig> & config) const override;
int3 guardingCreaturePosition (int3 pos) const override;
std::vector<CGObjectInstance*> guardingCreatures (int3 pos) const;
std::vector<const CGObjectInstance*> guardingCreatures (int3 pos) const;
/// Gets a artifact ID randomly and removes the selected artifact from this handler.
ArtifactID pickRandomArtifact(vstd::RNG & rand, int flags);

View File

@ -96,9 +96,12 @@ int3 IBoatGenerator::bestLocation() const
if (tile->blocked())
{
bool hasBoat = false;
for (auto const * object : tile->blockingObjects)
for (auto const & objectID : tile->blockingObjects)
{
const auto * object = getObject()->cb->getObj(objectID);
if (object->ID == Obj::BOAT || object->ID == Obj::HERO)
hasBoat = true;
}
if (!hasBoat)
continue; // tile is blocked, but not by boat -> check next potential position
@ -122,7 +125,9 @@ IBoatGenerator::EGeneratorState IBoatGenerator::shipyardStatus() const
if(t->blockingObjects.empty())
return GOOD; //OK
if(t->blockingObjects.front()->ID == Obj::BOAT || t->blockingObjects.front()->ID == Obj::HERO)
auto blockerObject = getObject()->cb->getObjInstance(t->blockingObjects.front());
if(blockerObject->ID == Obj::BOAT || blockerObject->ID == Obj::HERO)
return BOAT_ALREADY_BUILT; //blocked with boat
return TILE_BLOCKED; //blocked

View File

@ -322,14 +322,16 @@ bool CGTeleport::isConnected(const CGObjectInstance * src, const CGObjectInstanc
bool CGTeleport::isExitPassable(CGameState * gs, const CGHeroInstance * h, const CGObjectInstance * obj)
{
auto * objTopVisObj = gs->getMap().getTile(obj->visitablePos()).topVisitableObj();
if(objTopVisObj->ID == Obj::HERO)
ObjectInstanceID topObjectID = gs->getMap().getTile(obj->visitablePos()).topVisitableObj();
const CGObjectInstance * topObject = gs->getObjInstance(topObjectID);
if(topObject->ID == Obj::HERO)
{
if(h->id == objTopVisObj->id) // Just to be sure it's won't happen.
if(h->id == topObject->id) // Just to be sure it's won't happen.
return false;
// Check if it's friendly hero or not
if(gs->getPlayerRelations(h->tempOwner, objTopVisObj->tempOwner) != PlayerRelations::ENEMIES)
if(gs->getPlayerRelations(h->tempOwner, topObject->tempOwner) != PlayerRelations::ENEMIES)
{
// Exchange between heroes only possible via subterranean gates
if(!dynamic_cast<const CGSubterraneanGate *>(obj))

View File

@ -143,15 +143,10 @@ bool TerrainTile::isClear(const TerrainTile * from) const
return entrableTerrain(from) && !blocked();
}
Obj TerrainTile::topVisitableId(bool excludeTop) const
{
return topVisitableObj(excludeTop) ? topVisitableObj(excludeTop)->ID : Obj(Obj::NO_OBJ);
}
CGObjectInstance * TerrainTile::topVisitableObj(bool excludeTop) const
ObjectInstanceID TerrainTile::topVisitableObj(bool excludeTop) const
{
if(visitableObjects.empty() || (excludeTop && visitableObjects.size() == 1))
return nullptr;
return {};
if(excludeTop)
return visitableObjects[visitableObjects.size()-2];
@ -202,10 +197,10 @@ void CMap::removeBlockVisTiles(CGObjectInstance * obj, bool total)
{
TerrainTile & curt = terrain[zVal][xVal][yVal];
if(total || obj->visitableAt(int3(xVal, yVal, zVal)))
curt.visitableObjects -= obj;
curt.visitableObjects -= obj->id;
if(total || obj->blockingAt(int3(xVal, yVal, zVal)))
curt.blockingObjects -= obj;
curt.blockingObjects -= obj->id;
}
}
}
@ -224,10 +219,10 @@ void CMap::addBlockVisTiles(CGObjectInstance * obj)
{
TerrainTile & curt = terrain[zVal][xVal][yVal];
if(obj->visitableAt(int3(xVal, yVal, zVal)))
curt.visitableObjects.push_back(obj);
curt.visitableObjects.push_back(obj->id);
if(obj->blockingAt(int3(xVal, yVal, zVal)))
curt.blockingObjects.push_back(obj);
curt.blockingObjects.push_back(obj->id);
}
}
}
@ -300,12 +295,12 @@ bool CMap::checkForVisitableDir(const int3 & src, const TerrainTile * pom, const
{
if (!pom->entrableTerrain()) //rock is never accessible
return false;
for(auto * obj : pom->visitableObjects) //checking destination tile
for(const auto & objID : pom->visitableObjects) //checking destination tile
{
if(!vstd::contains(pom->blockingObjects, obj)) //this visitable object is not blocking, ignore
if(!vstd::contains(pom->blockingObjects, objID)) //this visitable object is not blocking, ignore
continue;
if (!obj->appearance->isVisitableFrom(src.x - dst.x, src.y - dst.y))
if (!getObject(objID)->appearance->isVisitableFrom(src.x - dst.x, src.y - dst.y))
return false;
}
return true;
@ -320,9 +315,10 @@ int3 CMap::guardingCreaturePosition (int3 pos) const
const TerrainTile &posTile = getTile(pos);
if (posTile.visitable())
{
for (CGObjectInstance* obj : posTile.visitableObjects)
for (const auto & objID : posTile.visitableObjects)
{
if (obj->ID == Obj::MONSTER)
const auto * object = getObject(objID);
if (object->ID == Obj::MONSTER)
return pos;
}
}
@ -340,12 +336,11 @@ int3 CMap::guardingCreaturePosition (int3 pos) const
const auto & tile = getTile(pos);
if (tile.visitable() && (tile.isWater() == water))
{
for (CGObjectInstance* obj : tile.visitableObjects)
for (const auto & objID : tile.visitableObjects)
{
if (obj->ID == Obj::MONSTER && checkForVisitableDir(pos, &posTile, originalPos)) // Monster being able to attack investigated tile
{
const auto * object = getObject(objID);
if (object->ID == Obj::MONSTER && checkForVisitableDir(pos, &posTile, originalPos)) // Monster being able to attack investigated tile
return pos;
}
}
}
}
@ -361,8 +356,9 @@ int3 CMap::guardingCreaturePosition (int3 pos) const
const CGObjectInstance * CMap::getObjectiveObjectFrom(const int3 & pos, Obj type)
{
for (CGObjectInstance * object : getTile(pos).visitableObjects)
for(const auto & objID : getTile(pos).visitableObjects)
{
const auto * object = getObject(objID);
if (object->ID == type)
return object;
}

View File

@ -96,8 +96,7 @@ struct DLL_LINKAGE TerrainTile
/// Checks for blocking objects and terraint type (water / land).
bool isClear(const TerrainTile * from = nullptr) const;
/// Gets the ID of the top visitable object or -1 if there is none.
Obj topVisitableId(bool excludeTop = false) const;
CGObjectInstance * topVisitableObj(bool excludeTop = false) const;
ObjectInstanceID topVisitableObj(bool excludeTop = false) const;
inline bool isWater() const;
inline bool isLand() const;
EDiggingStatus getDiggingStatus(bool excludeTop = true) const;
@ -127,8 +126,8 @@ struct DLL_LINKAGE TerrainTile
/// 7th bit - whether tile is coastal (allows disembarking if land or block movement if water); 8th bit - Favorable Winds effect
ui8 extTileFlags;
std::vector<CGObjectInstance *> visitableObjects;
std::vector<CGObjectInstance *> blockingObjects;
std::vector<ObjectInstanceID> visitableObjects;
std::vector<ObjectInstanceID> blockingObjects;
template <typename Handler>
void serialize(Handler & h)

View File

@ -2741,11 +2741,13 @@ void CMapLoaderH3M::afterRead()
const CGObjectInstance * mainTown = nullptr;
for(auto * obj : t.visitableObjects)
for(ObjectInstanceID objID : t.visitableObjects)
{
if(obj->ID == Obj::TOWN || obj->ID == Obj::RANDOM_TOWN)
const CGObjectInstance * object = map->getObject(objID);
if(object->ID == Obj::TOWN || object->ID == Obj::RANDOM_TOWN)
{
mainTown = obj;
mainTown = object;
break;
}
}

View File

@ -1313,9 +1313,11 @@ void TryMoveHero::applyGs(CGameState *gs)
if(result == EMBARK) //hero enters boat at destination tile
{
assert(destTile.visitableObjects.size() >= 1 && destTile.visitableObjects.back()->ID == Obj::BOAT); //the only visitable object at destination is Boat
auto * boat = dynamic_cast<CGBoat *>(destTile.visitableObjects.back());
const TerrainTile &tt = gs->getMap().getTile(h->convertToVisitablePos(end));
ObjectInstanceID topObjectID = tt.visitableObjects.back();
CGObjectInstance * topObject = gs->getObjInstance(topObjectID);
assert(tt.visitableObjects.size() >= 1 && topObject->ID == Obj::BOAT); //the only visitable object at destination is Boat
auto * boat = dynamic_cast<CGBoat *>(topObject);
assert(boat);
gs->getMap().removeBlockVisTiles(boat); //hero blockvis mask will be used, we don't need to duplicate it with boat

View File

@ -103,6 +103,7 @@ PathNodeInfo::PathNodeInfo()
void PathNodeInfo::setNode(CGameState * gs, CGPathNode * n)
{
node = n;
guarded = false;
if(coord != node->coord)
{
@ -110,23 +111,25 @@ void PathNodeInfo::setNode(CGameState * gs, CGPathNode * n)
coord = node->coord;
tile = gs->getTile(coord);
nodeObject = tile->topVisitableObj();
nodeObject = nullptr;
nodeHero = nullptr;
if(nodeObject && nodeObject->ID == Obj::HERO)
ObjectInstanceID topObjectID = tile->topVisitableObj();
if (topObjectID.hasValue())
{
nodeHero = dynamic_cast<const CGHeroInstance *>(nodeObject);
nodeObject = tile->topVisitableObj(true);
nodeObject = gs->getObjInstance(topObjectID);
if(!nodeObject)
nodeObject = nodeHero;
}
else
{
nodeHero = nullptr;
if (nodeObject->ID == Obj::HERO)
{
nodeHero = dynamic_cast<const CGHeroInstance *>(nodeObject);
ObjectInstanceID bottomObjectID = tile->topVisitableObj(true);
if (bottomObjectID.hasValue())
nodeObject = gs->getObjInstance(bottomObjectID);
}
}
}
guarded = false;
}
void PathNodeInfo::updateInfo(CPathfinderHelper * hlp, CGameState * gs)

View File

@ -251,7 +251,8 @@ TeleporterTilesVector CPathfinderHelper::getAllowedTeleportChannelExits(const Te
auto pos = obj->getBlockedPos();
for(const auto & p : pos)
{
if(gs->getMap().getTile(p).topVisitableId() == obj->ID)
ObjectInstanceID topObject = gs->getMap().getTile(p).topVisitableObj();
if(topObject.hasValue() && getObj(topObject)->ID == obj->ID)
allowedExits.push_back(p);
}
}

View File

@ -34,7 +34,10 @@ namespace PathfinderUtil
case ELayer::SAIL:
if(tinfo.visitable())
{
if(tinfo.visitableObjects.front()->ID == Obj::SANCTUARY && tinfo.visitableObjects.back()->ID == Obj::HERO && tinfo.visitableObjects.back()->tempOwner != player) //non-owned hero stands on Sanctuary
auto frontVisitable = gs->getObjInstance(tinfo.visitableObjects.front());
auto backVisitable = gs->getObjInstance(tinfo.visitableObjects.front());
if(frontVisitable->ID == Obj::SANCTUARY && backVisitable->ID == Obj::HERO && backVisitable->getOwner() != player) //non-owned hero stands on Sanctuary
{
return EPathAccessibility::BLOCKED;
}
@ -43,8 +46,10 @@ namespace PathfinderUtil
bool hasBlockedVisitable = false;
bool hasVisitable = false;
for(const CGObjectInstance * obj : tinfo.visitableObjects)
for(const auto objID : tinfo.visitableObjects)
{
auto obj = gs->getObjInstance(objID);
if(obj->isBlockedVisitable())
hasBlockedVisitable = true;
else if(!obj->passableFor(player) && obj->ID != Obj::EVENT)

View File

@ -262,7 +262,11 @@ bool ScuttleBoatMechanics::canBeCastAtImpl(spells::Problem & problem, const CGam
return false;
const TerrainTile * t = cb->getTile(pos);
if(!t || t->visitableObjects.empty() || t->visitableObjects.back()->ID != Obj::BOAT)
if(!t || t->visitableObjects.empty())
return false;
const CGObjectInstance * topObject = cb->getObj(t->visitableObjects.back());
if (topObject->ID != Obj::BOAT)
return false;
return true;
@ -286,7 +290,7 @@ ESpellCastResult ScuttleBoatMechanics::applyAdventureEffects(SpellCastEnvironmen
RemoveObject ro;
ro.initiator = parameters.caster->getCasterOwner();
ro.objectID = t.visitableObjects.back()->id;
ro.objectID = t.visitableObjects.back();
env->apply(ro);
return ESpellCastResult::OK;
}
@ -476,7 +480,8 @@ ESpellCastResult TownPortalMechanics::applyAdventureEffects(SpellCastEnvironment
{
const TerrainTile & tile = env->getMap()->getTile(parameters.pos);
auto * const topObj = tile.topVisitableObj(false);
ObjectInstanceID topObjID = tile.topVisitableObj(false);
const CGObjectInstance * topObj = env->getMap()->getObject(topObjID);
if(!topObj)
{
@ -556,7 +561,9 @@ void TownPortalMechanics::endCast(SpellCastEnvironment * env, const AdventureSpe
else
{
const TerrainTile & tile = env->getMap()->getTile(parameters.pos);
auto * const topObj = tile.topVisitableObj(false);
ObjectInstanceID topObjID = tile.topVisitableObj(false);
const CGObjectInstance * topObj = env->getMap()->getObject(topObjID);
destination = dynamic_cast<const CGTownInstance*>(topObj);
}

View File

@ -128,12 +128,17 @@ void ObjectPickerLayer::highlight(std::function<bool(const CGObjectInstance *)>
for(int i = 0; i < map->width; ++i)
{
auto tl = map->getTile(int3(i, j, scene->level));
auto * obj = tl.topVisitableObj();
if(!obj && !tl.blockingObjects.empty())
obj = tl.blockingObjects.front();
ObjectInstanceID objID = tl.topVisitableObj();
if(!objID.hasValue() && !tl.blockingObjects.empty())
objID = tl.blockingObjects.front();
if (objID.hasValue())
{
const CGObjectInstance * obj = map->getObject(objID);
if(obj && predicate(obj))
possibleObjects.insert(obj);
if(obj && predicate(obj))
possibleObjects.insert(obj);
}
}
}
}

View File

@ -826,13 +826,17 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, EMovementMode moveme
CGObjectInstance * guardian = nullptr;
if (!t.visitableObjects.empty())
objectToVisit = t.visitableObjects.back();
objectToVisit = gameState()->getObjInstance(t.visitableObjects.back());
if (isInTheMap(guardPos))
{
for (auto const & object : getTile(guardPos)->visitableObjects)
for (auto const & objectID : getTile(guardPos)->visitableObjects)
{
auto object = gameState()->getObjInstance(objectID);
if (object->ID == MapObjectID::MONSTER) // exclude other objects, such as hero flying above monster
guardian = object;
}
}
const bool embarking = !h->boat && objectToVisit && objectToVisit->ID == Obj::BOAT;
@ -909,10 +913,9 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, EMovementMode moveme
// should be called if hero changes tile but before applying TryMoveHero package
auto leaveTile = [&]()
{
for (CGObjectInstance *obj : gs->getMap().getTile(h->visitablePos()).visitableObjects)
{
obj->onHeroLeave(h);
}
for(const auto & objID : gs->getMap().getTile(h->visitablePos()).visitableObjects)
gameState()->getObjInstance(objID)->onHeroLeave(h);
this->getTilesInRange(tmh.fowRevealed, h->getSightCenter()+(tmh.end-tmh.start), h->getSightRadius(), ETileVisibility::HIDDEN, h->tempOwner);
};
@ -956,12 +959,14 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, EMovementMode moveme
//interaction with blocking object (like resources)
auto blockingVisit = [&]() -> bool
{
for (CGObjectInstance *obj : t.visitableObjects)
for (ObjectInstanceID objectID : t.visitableObjects)
{
if(h->boat && !obj->isBlockedVisitable() && !h->boat->onboardVisitAllowed)
const CGObjectInstance * object = getObj(objectID);
if(h->boat && !object->isBlockedVisitable() && !h->boat->onboardVisitAllowed)
return doMove(TryMoveHero::SUCCESS, this->IGNORE_GUARDS, DONT_VISIT_DEST, REMAINING_ON_TILE);
if (obj != h && obj->isBlockedVisitable() && !obj->passableFor(h->tempOwner))
if (object != h && object->isBlockedVisitable() && !object->passableFor(h->tempOwner))
{
EVisitDest visitDest = VISIT_DEST;
if(h->boat && !h->boat->onboardVisitAllowed)
@ -3657,10 +3662,10 @@ void CGameHandler::visitObjectOnTile(const TerrainTile &t, const CGHeroInstance
if (!t.visitableObjects.empty())
{
//to prevent self-visiting heroes on space press
if (t.visitableObjects.back() != h)
objectVisited(t.visitableObjects.back(), h);
if (t.visitableObjects.back() != h->id)
objectVisited(gameState()->getObjInstance(t.visitableObjects.back()), h);
else if (t.visitableObjects.size() > 1)
objectVisited(*(t.visitableObjects.end()-2),h);
objectVisited(gameState()->getObjInstance(*(t.visitableObjects.end()-2)),h);
}
}

View File

@ -199,7 +199,7 @@ bool HeroPoolProcessor::hireHero(const ObjectInstanceID & objectID, const HeroTy
return false;
}
if(gameHandler->getTile(mapObject->visitablePos())->visitableObjects.back() != mapObject && gameHandler->complain("Tavern entry must be unoccupied!"))
if(gameHandler->getTile(mapObject->visitablePos())->visitableObjects.back() != mapObject->id && gameHandler->complain("Tavern entry must be unoccupied!"))
return false;
}