1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-22 22:13:35 +02:00

Replaced most of accesses to CGObjectInstance::pos with anchorPoint()

This commit is contained in:
Ivan Savenko 2024-10-02 16:40:06 +00:00
parent 7694e2da4b
commit a8f8c3f4b1
40 changed files with 142 additions and 150 deletions

View File

@ -864,7 +864,7 @@ void AIGateway::makeTurn()
void AIGateway::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
{
LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->getNameTranslated() % obj->getObjectName() % obj->pos.toString());
LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->getNameTranslated() % obj->getObjectName() % obj->anchorPos().toString());
switch(obj->ID)
{
case Obj::TOWN:
@ -1455,7 +1455,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
void AIGateway::buildStructure(const CGTownInstance * t, BuildingID building)
{
auto name = t->town->buildings.at(building)->getNameTranslated();
logAi->debug("Player %d will build %s in town of %s at %s", ai->playerID, name, t->getNameTranslated(), t->pos.toString());
logAi->debug("Player %d will build %s in town of %s at %s", ai->playerID, name, t->getNameTranslated(), t->anchorPos().toString());
cb->buildBuilding(t, building); //just do this;
}

View File

@ -52,7 +52,7 @@ void BuildThis::accept(AIGateway * ai)
if(cb->canBuildStructure(town, b) == EBuildingState::ALLOWED)
{
logAi->debug("Player %d will build %s in town of %s at %s",
ai->playerID, town->town->buildings.at(b)->getNameTranslated(), town->getNameTranslated(), town->pos.toString());
ai->playerID, town->town->buildings.at(b)->getNameTranslated(), town->getNameTranslated(), town->anchorPos().toString());
cb->buildBuilding(town, b);
return;

View File

@ -46,7 +46,7 @@ TSubgoal FindObj::whatToDoToAchieve()
}
}
}
if(o && ai->isAccessible(o->pos)) //we don't use isAccessibleForHero as we don't know which hero it is
if(o && ai->isAccessible(o->visitablePos())) //we don't use isAccessibleForHero as we don't know which hero it is
return sptr(VisitObj(o->id.getNum()));
else
return sptr(Explore());

View File

@ -1032,7 +1032,7 @@ void VCAI::mainLoop()
void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
{
LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->getNameTranslated() % obj->getObjectName() % obj->pos.toString());
LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->getNameTranslated() % obj->getObjectName() % obj->anchorPos().toString());
switch(obj->ID)
{
case Obj::TOWN:
@ -1417,11 +1417,11 @@ void VCAI::wander(HeroPtr h)
//TODO pick the truly best
const CGTownInstance * t = *boost::max_element(townsNotReachable, compareReinforcements);
logAi->debug("%s can't reach any town, we'll try to make our way to %s at %s", h->getNameTranslated(), t->getNameTranslated(), t->visitablePos().toString());
int3 pos1 = h->pos;
int3 posBefore = h->visitablePos();
striveToGoal(sptr(Goals::ClearWayTo(t->visitablePos()).sethero(h))); //TODO: drop "strive", add to mainLoop
//if out hero is stuck, we may need to request another hero to clear the way we see
if(pos1 == h->pos && h == primaryHero()) //hero can't move
if(posBefore == h->visitablePos() && h == primaryHero()) //hero can't move
{
if(canRecruitAnyHero(t))
recruitHero(t);
@ -1471,7 +1471,7 @@ void VCAI::wander(HeroPtr h)
{
auto chosenObject = cb->getObjInstance(ObjectInstanceID(bestObjectGoal->objid));
if(chosenObject != nullptr)
logAi->debug("Of all %d destinations, object %s at pos=%s seems nice", dests.size(), chosenObject->getObjectName(), chosenObject->pos.toString());
logAi->debug("Of all %d destinations, object %s at pos=%s seems nice", dests.size(), chosenObject->getObjectName(), chosenObject->anchorPos().toString());
}
else
logAi->debug("Trying to realize goal of type %s as part of wandering.", bestObjectGoal->name());
@ -1995,7 +1995,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
void VCAI::buildStructure(const CGTownInstance * t, BuildingID building)
{
auto name = t->town->buildings.at(building)->getNameTranslated();
logAi->debug("Player %d will build %s in town of %s at %s", ai->playerID, name, t->getNameTranslated(), t->pos.toString());
logAi->debug("Player %d will build %s in town of %s at %s", ai->playerID, name, t->getNameTranslated(), t->anchorPos().toString());
cb->buildBuilding(t, building); //just do this;
}
@ -2081,7 +2081,7 @@ void VCAI::tryRealize(Goals::BuildThis & g)
if (cb->canBuildStructure(t, b) == EBuildingState::ALLOWED)
{
logAi->debug("Player %d will build %s in town of %s at %s",
playerID, t->town->buildings.at(b)->getNameTranslated(), t->getNameTranslated(), t->pos.toString());
playerID, t->town->buildings.at(b)->getNameTranslated(), t->getNameTranslated(), t->anchorPos().toString());
cb->buildBuilding(t, b);
throw goalFulfilledException(sptr(g));
}

View File

@ -375,7 +375,7 @@ void HeroMovementController::sendMovementRequest(const CGHeroInstance * h, const
{
updateMovementSound(h, currNode.coord, nextNode.coord, nextNode.action);
assert(h->pos.z == nextNode.coord.z); // Z should change only if it's movement via teleporter and in this case this code shouldn't be executed at all
assert(h->anchorPos().z == nextNode.coord.z); // Z should change only if it's movement via teleporter and in this case this code shouldn't be executed at all
logGlobal->trace("Requesting hero movement to %s", nextNode.coord.toString());

View File

@ -81,9 +81,9 @@ void MapAudioPlayer::addObject(const CGObjectInstance * obj)
{
for(int fy = 0; fy < obj->getHeight(); ++fy)
{
int3 currTile(obj->pos.x - fx, obj->pos.y - fy, obj->pos.z);
int3 currTile(obj->anchorPos().x - fx, obj->anchorPos().y - fy, obj->anchorPos().z);
if(LOCPLINT->cb->isInTheMap(currTile) && obj->coveringAt(currTile.x, currTile.y))
if(LOCPLINT->cb->isInTheMap(currTile) && obj->coveringAt(currTile))
objects[currTile.z][currTile.x][currTile.y].push_back(obj->id);
}
}
@ -108,7 +108,7 @@ void MapAudioPlayer::addObject(const CGObjectInstance * obj)
for(const auto & tile : tiles)
{
int3 currTile = obj->pos + tile;
int3 currTile = obj->anchorPos() + tile;
if(LOCPLINT->cb->isInTheMap(currTile))
objects[currTile.z][currTile.x][currTile.y].push_back(obj->id);

View File

@ -591,8 +591,8 @@ void MapRendererOverlay::renderTile(IMapRendererContext & context, Canvas & targ
if(context.objectTransparency(objectID, coordinates) > 0 && !context.isActiveHero(object))
{
visitable |= object->visitableAt(coordinates.x, coordinates.y);
blocking |= object->blockingAt(coordinates.x, coordinates.y);
visitable |= object->visitableAt(coordinates);
blocking |= object->blockingAt(coordinates);
}
}

View File

@ -120,7 +120,7 @@ size_t MapRendererBaseContext::objectGroupIndex(ObjectInstanceID objectID) const
Point MapRendererBaseContext::objectImageOffset(ObjectInstanceID objectID, const int3 & coordinates) const
{
const CGObjectInstance * object = getObject(objectID);
int3 offsetTiles(object->getPosition() - coordinates);
int3 offsetTiles(object->anchorPos() - coordinates);
return Point(offsetTiles) * Point(32, 32);
}
@ -498,7 +498,7 @@ size_t MapRendererWorldViewContext::overlayImageIndex(const int3 & coordinates)
{
const auto * object = getObject(objectID);
if(!object->visitableAt(coordinates.x, coordinates.y))
if(!object->visitableAt(coordinates))
continue;
ObjectPosInfo info(object);

View File

@ -49,9 +49,9 @@ void MapRendererContextState::addObject(const CGObjectInstance * obj)
{
for(int fy = 0; fy < obj->getHeight(); ++fy)
{
int3 currTile(obj->pos.x - fx, obj->pos.y - fy, obj->pos.z);
int3 currTile(obj->anchorPos().x - fx, obj->anchorPos().y - fy, obj->anchorPos().z);
if(LOCPLINT->cb->isInTheMap(currTile) && obj->coveringAt(currTile.x, currTile.y))
if(LOCPLINT->cb->isInTheMap(currTile) && obj->coveringAt(currTile))
{
auto & container = objects[currTile.z][currTile.x][currTile.y];
@ -73,7 +73,7 @@ void MapRendererContextState::addMovingObject(const CGObjectInstance * object, c
{
for(int y = yFrom; y <= yDest; ++y)
{
int3 currTile(x, y, object->pos.z);
int3 currTile(x, y, object->anchorPos().z);
if(LOCPLINT->cb->isInTheMap(currTile))
{

View File

@ -317,7 +317,7 @@ bool MapViewController::isEventVisible(const CGObjectInstance * obj, const Playe
if(obj->isVisitable())
return context->isVisible(obj->visitablePos());
else
return context->isVisible(obj->pos);
return context->isVisible(obj->anchorPos());
}
bool MapViewController::isEventVisible(const CGHeroInstance * obj, const int3 & from, const int3 & dest)

View File

@ -59,7 +59,7 @@ std::string CMapHandler::getTerrainDescr(const int3 & pos, bool rightClick) cons
for(const auto & object : map->objects)
{
if(object && object->coveringAt(pos.x, pos.y) && object->pos.z == pos.z && object->isTile2Terrain())
if(object && object->coveringAt(pos) && object->isTile2Terrain())
{
result = object->getObjectName();
break;
@ -103,15 +103,15 @@ bool CMapHandler::compareObjectBlitOrder(const CGObjectInstance * a, const CGObj
for(const auto & aOffset : a->getBlockedOffsets())
{
int3 testTarget = a->pos + aOffset + int3(0, 1, 0);
if(b->blockingAt(testTarget.x, testTarget.y))
int3 testTarget = a->anchorPos() + aOffset + int3(0, 1, 0);
if(b->blockingAt(testTarget))
bBlocksA += 1;
}
for(const auto & bOffset : b->getBlockedOffsets())
{
int3 testTarget = b->pos + bOffset + int3(0, 1, 0);
if(a->blockingAt(testTarget.x, testTarget.y))
int3 testTarget = b->anchorPos() + bOffset + int3(0, 1, 0);
if(a->blockingAt(testTarget))
aBlocksB += 1;
}
@ -126,8 +126,8 @@ bool CMapHandler::compareObjectBlitOrder(const CGObjectInstance * a, const CGObj
return aBlocksB < bBlocksA;
// object that don't have clear priority via tile blocking will appear based on their row
if(a->pos.y != b->pos.y)
return a->pos.y < b->pos.y;
if(a->anchorPos().y != b->anchorPos().y)
return a->anchorPos().y < b->anchorPos().y;
// heroes should appear on top of objects on the same tile
if(b->ID==Obj::HERO && a->ID!=Obj::HERO)

View File

@ -78,7 +78,7 @@ void CQuestMinimap::addQuestMarks (const QuestInfo * q)
int3 tile;
if (q->obj)
tile = q->obj->pos;
tile = q->obj->visitablePos();
else
tile = q->tile;
@ -104,7 +104,7 @@ void CQuestMinimap::update()
void CQuestMinimap::iconClicked()
{
if(currentQuest->obj)
adventureInt->centerOnTile(currentQuest->obj->pos);
adventureInt->centerOnTile(currentQuest->obj->visitablePos());
//moveAdvMapSelection();
}

View File

@ -539,7 +539,7 @@ EDiggingStatus CGameInfoCallback::getTileDigStatus(int3 tile, bool verbose) cons
for(const auto & object : gs->map->objects)
{
if(object && object->ID == Obj::HOLE && object->pos == tile)
if(object && object->ID == Obj::HOLE && object->anchorPos() == tile)
return EDiggingStatus::TILE_OCCUPIED;
}
return getTile(tile)->getDiggingStatus();

View File

@ -449,7 +449,7 @@ void CGameState::initGrailPosition()
//remove tiles with holes
for(auto & elem : map->objects)
if(elem && elem->ID == Obj::HOLE)
allowedPos -= elem->pos;
allowedPos -= elem->anchorPos();
if(!allowedPos.empty())
{
@ -495,7 +495,7 @@ void CGameState::randomizeMapObjects()
{
for (int j = 0; j < object->getHeight() ; j++)
{
int3 pos = object->pos - int3(i,j,0);
int3 pos = object->anchorPos() - int3(i,j,0);
if(map->isInTheMap(pos)) map->getTile(pos).extTileFlags |= 128;
}
}
@ -530,7 +530,7 @@ void CGameState::placeStartingHero(const PlayerColor & playerColor, const HeroTy
{
for(auto town : map->towns)
{
if(town->getPosition() == townPos)
if(town->anchorPos() == townPos)
{
townPos = town->visitablePos();
break;
@ -545,8 +545,7 @@ void CGameState::placeStartingHero(const PlayerColor & playerColor, const HeroTy
hero->setHeroType(heroTypeId);
hero->tempOwner = playerColor;
hero->pos = townPos;
hero->pos += hero->getVisitableOffset();
hero->setAnchorPos(townPos + hero->getVisitableOffset());
map->getEditManager()->insertObject(hero);
}
@ -614,7 +613,7 @@ void CGameState::initHeroes()
auto boat = dynamic_cast<CGBoat*>(handler->create(callback, nullptr));
handler->configureObject(boat, gs->getRandomGenerator());
boat->pos = hero->pos;
boat->setAnchorPos(hero->anchorPos());
boat->appearance = handler->getTemplates().front();
boat->id = ObjectInstanceID(static_cast<si32>(gs->map->objects.size()));
@ -964,22 +963,18 @@ void CGameState::placeHeroesInTowns()
{
for(CGTownInstance * t : player.second.getTowns())
{
if(h->visitablePos().z != t->visitablePos().z)
continue;
bool heroOnTownBlockableTile = t->blockingAt(h->visitablePos().x, h->visitablePos().y);
bool heroOnTownBlockableTile = t->blockingAt(h->visitablePos());
// current hero position is at one of blocking tiles of current town
// assume that this hero should be visiting the town (H3M format quirk) and move hero to correct position
if (heroOnTownBlockableTile)
{
int3 correctedPos = h->convertFromVisitablePos(t->visitablePos());
map->removeBlockVisTiles(h);
h->pos = correctedPos;
int3 correctedPos = h->convertFromVisitablePos(t->visitablePos());
h->setAnchorPos(correctedPos);
map->addBlockVisTiles(h);
assert(t->visitableAt(h->visitablePos().x, h->visitablePos().y));
assert(t->visitableAt(h->visitablePos()));
}
}
}
@ -1001,7 +996,7 @@ void CGameState::initVisitingAndGarrisonedHeroes()
if(h->visitablePos().z != t->visitablePos().z)
continue;
if (t->visitableAt(h->visitablePos().x, h->visitablePos().y))
if (t->visitableAt(h->visitablePos()))
{
assert(t->visitingHero == nullptr);
t->setVisitingHero(h);
@ -1066,7 +1061,7 @@ BattleField CGameState::battleGetBattlefieldType(int3 tile, vstd::RNG & rand)
for(auto &obj : map->objects)
{
//look only for objects covering given tile
if( !obj || obj->pos.z != tile.z || !obj->coveringAt(tile.x, tile.y))
if( !obj || !obj->coveringAt(tile))
continue;
auto customBattlefield = obj->getBattlefield();
@ -1250,10 +1245,10 @@ bool CGameState::isVisible(const CGObjectInstance * obj, const std::optional<Pla
{
for(int fx=0; fx < obj->getWidth(); ++fx)
{
int3 pos = obj->pos + int3(-fx, -fy, 0);
int3 pos = obj->anchorPos() + int3(-fx, -fy, 0);
if ( map->isInTheMap(pos) &&
obj->coveringAt(pos.x, pos.y) &&
obj->coveringAt(pos) &&
isVisible(pos, *player))
return true;
}

View File

@ -368,7 +368,7 @@ void CGameStateCampaign::replaceHeroesPlaceholders()
heroToPlace->id = campaignHeroReplacement.heroPlaceholderId;
if(heroPlaceholder->tempOwner.isValidPlayer())
heroToPlace->tempOwner = heroPlaceholder->tempOwner;
heroToPlace->pos = heroPlaceholder->pos;
heroToPlace->setAnchorPos(heroPlaceholder->anchorPos());
heroToPlace->type = heroToPlace->getHeroType().toHeroType();
heroToPlace->appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, heroToPlace->type->heroClass->getIndex())->getTemplates().front();
@ -655,7 +655,7 @@ void CGameStateCampaign::initTowns()
if (!owner->human)
continue;
if (town->pos != pi.posOfMainTown)
if (town->anchorPos() != pi.posOfMainTown)
continue;
BuildingID newBuilding;

View File

@ -33,7 +33,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(), getCreature(), id.getNum());
logGlobal->error("Invalid stack at tile %s: subID=%d; id=%d", anchorPos().toString(), getCreature(), id.getNum());
return "INVALID_STACK";
}
@ -562,7 +562,7 @@ bool CGCreature::containsUpgradedStack() const
float c = 5325.181015f;
float d = 32788.727920f;
int val = static_cast<int>(std::floor(a * pos.x + b * pos.y + c * pos.z + d));
int val = static_cast<int>(std::floor(a * visitablePos().x + b * visitablePos().y + c * visitablePos().z + d));
return ((val % 32768) % 100) < 50;
}
@ -591,7 +591,7 @@ int CGCreature::getNumberOfStacks(const CGHeroInstance *hero) const
ui32 c = 1943276003u;
ui32 d = 3174620878u;
ui32 R1 = a * static_cast<ui32>(pos.x) + b * static_cast<ui32>(pos.y) + c * static_cast<ui32>(pos.z) + d;
ui32 R1 = a * static_cast<ui32>(visitablePos().x) + b * static_cast<ui32>(visitablePos().y) + c * static_cast<ui32>(visitablePos().z) + d;
ui32 R2 = (R1 >> 16) & 0x7fff;
int R4 = R2 % 100 + 1;

View File

@ -1514,11 +1514,11 @@ bool CGHeroInstance::hasVisions(const CGObjectInstance * target, BonusSubtypeID
if (visionsMultiplier > 0)
vstd::amax(visionsRange, 3); //minimum range is 3 tiles, but only if VISIONS bonus present
const int distance = static_cast<int>(target->pos.dist2d(visitablePos()));
const int distance = static_cast<int>(target->anchorPos().dist2d(visitablePos()));
//logGlobal->debug(boost::str(boost::format("Visions: dist %d, mult %d, range %d") % distance % visionsMultiplier % visionsRange));
return (distance < visionsRange) && (target->pos.z == pos.z);
return (distance < visionsRange) && (target->anchorPos().z == anchorPos().z);
}
std::string CGHeroInstance::getHeroTypeName() const

View File

@ -54,14 +54,14 @@ MapObjectSubID CGObjectInstance::getObjTypeIndex() const
return subID;
}
int3 CGObjectInstance::getPosition() const
int3 CGObjectInstance::anchorPos() const
{
return pos;
}
int3 CGObjectInstance::getTopVisiblePos() const
{
return pos - appearance->getTopVisibleOffset();
return anchorPos() - appearance->getTopVisibleOffset();
}
void CGObjectInstance::setOwner(const PlayerColor & ow)
@ -69,6 +69,11 @@ void CGObjectInstance::setOwner(const PlayerColor & ow)
tempOwner = ow;
}
void CGObjectInstance::setAnchorPos(int3 newPos)
{
pos = newPos;
}
int CGObjectInstance::getWidth() const
{
return appearance->getWidth();
@ -79,32 +84,19 @@ int CGObjectInstance::getHeight() const
return appearance->getHeight();
}
bool CGObjectInstance::visitableAt(int x, int y) const
{
return appearance->isVisitableAt(pos.x - x, pos.y - y);
}
bool CGObjectInstance::blockingAt(int x, int y) const
{
return appearance->isBlockedAt(pos.x - x, pos.y - y);
}
bool CGObjectInstance::coveringAt(int x, int y) const
{
return appearance->isVisibleAt(pos.x - x, pos.y - y);
}
bool CGObjectInstance::visitableAt(const int3 & testPos) const
{
return pos.z == testPos.z && appearance->isVisitableAt(pos.x - testPos.x, pos.y - testPos.y);
return anchorPos().z == testPos.z && appearance->isVisitableAt(anchorPos().x - testPos.x, anchorPos().y - testPos.y);
}
bool CGObjectInstance::blockingAt(const int3 & testPos) const
{
return pos.z == testPos.z && appearance->isBlockedAt(pos.x - testPos.x, pos.y - testPos.y);
return anchorPos().z == testPos.z && appearance->isBlockedAt(anchorPos().x - testPos.x, anchorPos().y - testPos.y);
}
bool CGObjectInstance::coveringAt(const int3 & testPos) const
{
return pos.z == testPos.z && appearance->isVisibleAt(pos.x - testPos.x, pos.y - testPos.y);
return anchorPos().z == testPos.z && appearance->isVisibleAt(anchorPos().x - testPos.x, anchorPos().y - testPos.y);
}
std::set<int3> CGObjectInstance::getBlockedPos() const
@ -115,7 +107,7 @@ std::set<int3> CGObjectInstance::getBlockedPos() const
for(int h=0; h<getHeight(); ++h)
{
if(appearance->isBlockedAt(w, h))
ret.insert(int3(pos.x - w, pos.y - h, pos.z));
ret.insert(int3(anchorPos().x - w, anchorPos().y - h, anchorPos().z));
}
}
return ret;
@ -215,6 +207,8 @@ int CGObjectInstance::getSightRadius() const
int3 CGObjectInstance::getVisitableOffset() const
{
if (!isVisitable())
throw std::runtime_error("Attempt to access visitable offset of a non-visitable object!");
return appearance->getVisitableOffset();
}
@ -313,6 +307,9 @@ void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const
int3 CGObjectInstance::visitablePos() const
{
if (!isVisitable())
throw std::runtime_error("Attempt to access visitable position on a non-visitable object!");
return pos - getVisitableOffset();
}

View File

@ -28,8 +28,6 @@ using TObjectTypeHandler = std::shared_ptr<AObjectTypeHandler>;
class DLL_LINKAGE CGObjectInstance : public IObjectInterface
{
public:
/// Position of bottom-right corner of object on map
int3 pos;
/// Type of object, e.g. town, hero, creature.
MapObjectID ID;
/// Subtype of object, depends on type
@ -41,6 +39,9 @@ public:
/// Defines appearance of object on map (animation, blocked tiles, blit order, etc)
std::shared_ptr<const ObjectTemplate> appearance;
/// Position of bottom-right corner of object on map
int3 pos;
std::string instanceName;
std::string typeName;
std::string subTypeName;
@ -62,21 +63,19 @@ public:
return this->tempOwner;
}
void setOwner(const PlayerColor & ow);
void setAnchorPos(int3 pos);
/** APPEARANCE ACCESSORS **/
int getWidth() const; //returns width of object graphic in tiles
int getHeight() const; //returns height of object graphic in tiles
int3 visitablePos() const override;
int3 getPosition() const override;
int3 anchorPos() const override;
int3 getTopVisiblePos() const;
bool visitableAt(int x, int y) const; //returns true if object is visitable at location (x, y) (h3m pos)
bool blockingAt(int x, int y) const; //returns true if object is blocking location (x, y) (h3m pos)
bool coveringAt(int x, int y) const; //returns true if object covers with picture location (x, y) (h3m pos)
bool visitableAt(const int3 & pos) const; //returns true if object is visitable at location (x, y) (h3m pos)
bool blockingAt (const int3 & pos) const; //returns true if object is blocking location (x, y) (h3m pos)
bool coveringAt (const int3 & pos) const; //returns true if object covers with picture location (x, y) (h3m pos)
bool visitableAt(const int3 & pos) const; //returns true if object is visitable at location
bool blockingAt (const int3 & pos) const; //returns true if object is blocking location
bool coveringAt (const int3 & pos) const; //returns true if object covers with picture location
std::set<int3> getBlockedPos() const; //returns set of positions blocked by this object
const std::set<int3> & getBlockedOffsets() const; //returns set of relative positions blocked by this object

View File

@ -954,7 +954,7 @@ TResources CGTownInstance::getBuildingCost(const BuildingID & buildingID) const
return town->buildings.at(buildingID)->resources;
else
{
logGlobal->error("Town %s at %s has no possible building %d!", getNameTranslated(), pos.toString(), buildingID.toEnum());
logGlobal->error("Town %s at %s has no possible building %d!", getNameTranslated(), anchorPos().toString(), buildingID.toEnum());
return TResources();
}

View File

@ -56,8 +56,6 @@ class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public I
std::set<BuildingID> builtBuildings;
public:
using CGDwelling::getPosition;
enum EFortLevel {NONE = 0, FORT = 1, CITADEL = 2, CASTLE = 3};
CTownAndVisitingHero townAndVis;

View File

@ -614,7 +614,7 @@ void CGSeerHut::onHeroVisit(const CGHeroInstance * h) const
int CGSeerHut::checkDirection() const
{
int3 cord = getCreatureToKill(false)->pos;
int3 cord = getCreatureToKill(false)->visitablePos();
if(static_cast<double>(cord.x) / static_cast<double>(cb->getMapSize().x) < 0.34) //north
{
if(static_cast<double>(cord.y) / static_cast<double>(cb->getMapSize().y) < 0.34) //northwest

View File

@ -145,7 +145,7 @@ void IBoatGenerator::getProblemText(MetaString &out, const CGHeroInstance *visit
out.appendLocalString(EMetaText::ADVOB_TXT, 189);
break;
case NO_WATER:
logGlobal->error("Shipyard without water at tile %s! ", getObject()->getPosition().toString());
logGlobal->error("Shipyard without water at tile %s! ", getObject()->anchorPos().toString());
return;
}
}

View File

@ -47,7 +47,7 @@ public:
virtual PlayerColor getOwner() const = 0;
virtual int3 visitablePos() const = 0;
virtual int3 getPosition() const = 0;
virtual int3 anchorPos() const = 0;
virtual void onHeroVisit(const CGHeroInstance * h) const;
virtual void onHeroLeave(const CGHeroInstance * h) const;

View File

@ -111,7 +111,7 @@ void CGMine::initObj(vstd::RNG & rand)
}
else
{
logGlobal->error("Abandoned mine at (%s) has no valid resource candidates!", pos.toString());
logGlobal->error("Abandoned mine at (%s) has no valid resource candidates!", anchorPos().toString());
producedResource = GameResID::GOLD;
}
}
@ -510,11 +510,11 @@ void CGMonolith::onHeroVisit( const CGHeroInstance * h ) const
if(cb->isTeleportChannelImpassable(channel))
{
logGlobal->debug("Cannot find corresponding exit monolith for %d at %s", id.getNum(), pos.toString());
logGlobal->debug("Cannot find corresponding exit monolith for %d at %s", id.getNum(), anchorPos().toString());
td.impassable = true;
}
else if(getRandomExit(h) == ObjectInstanceID())
logGlobal->debug("All exits blocked for monolith %d at %s", id.getNum(), pos.toString());
logGlobal->debug("All exits blocked for monolith %d at %s", id.getNum(), anchorPos().toString());
}
else
h->showInfoDialog(70);
@ -574,7 +574,7 @@ void CGSubterraneanGate::onHeroVisit( const CGHeroInstance * h ) const
if(cb->isTeleportChannelImpassable(channel))
{
h->showInfoDialog(153);//Just inside the entrance you find a large pile of rubble blocking the tunnel. You leave discouraged.
logGlobal->debug("Cannot find exit subterranean gate for %d at %s", id.getNum(), pos.toString());
logGlobal->debug("Cannot find exit subterranean gate for %d at %s", id.getNum(), anchorPos().toString());
td.impassable = true;
}
else
@ -602,13 +602,13 @@ void CGSubterraneanGate::postInit(IGameCallback * cb) //matches subterranean gat
auto * hlp = dynamic_cast<CGSubterraneanGate *>(cb->gameState()->getObjInstance(obj->id));
if(hlp)
gatesSplit[hlp->pos.z].push_back(hlp);
gatesSplit[hlp->visitablePos().z].push_back(hlp);
}
//sort by position
std::sort(gatesSplit[0].begin(), gatesSplit[0].end(), [](const CGObjectInstance * a, const CGObjectInstance * b)
{
return a->pos < b->pos;
return a->visitablePos() < b->visitablePos();
});
auto assignToChannel = [&](CGSubterraneanGate * obj)
@ -631,7 +631,7 @@ void CGSubterraneanGate::postInit(IGameCallback * cb) //matches subterranean gat
CGSubterraneanGate *checked = gatesSplit[1][j];
if(checked->channel != TeleportChannelID())
continue;
si32 hlp = checked->pos.dist2dSQ(objCurrent->pos);
si32 hlp = checked->visitablePos().dist2dSQ(objCurrent->visitablePos());
if(hlp < best.second)
{
best.first = j;
@ -657,11 +657,11 @@ void CGWhirlpool::onHeroVisit( const CGHeroInstance * h ) const
TeleportDialog td(h->id, channel);
if(cb->isTeleportChannelImpassable(channel))
{
logGlobal->debug("Cannot find exit whirlpool for %d at %s", id.getNum(), pos.toString());
logGlobal->debug("Cannot find exit whirlpool for %d at %s", id.getNum(), anchorPos().toString());
td.impassable = true;
}
else if(getRandomExit(h) == ObjectInstanceID())
logGlobal->debug("All exits are blocked for whirlpool %d at %s", id.getNum(), pos.toString());
logGlobal->debug("All exits are blocked for whirlpool %d at %s", id.getNum(), anchorPos().toString());
if(!isProtected(h))
{
@ -1086,9 +1086,9 @@ void CGMagi::onHeroVisit(const CGHeroInstance * h) const
for(const auto & eye : eyes)
{
cb->getTilesInRange (fw.tiles, eye->pos, 10, ETileVisibility::HIDDEN, h->tempOwner);
cb->getTilesInRange (fw.tiles, eye->visitablePos(), 10, ETileVisibility::HIDDEN, h->tempOwner);
cb->sendAndApply(fw);
cv.pos = eye->pos;
cv.pos = eye->visitablePos();
cb->sendAndApply(cv);
}

View File

@ -56,9 +56,9 @@ int3 TownBuildingInstance::visitablePos() const
return town->visitablePos();
}
int3 TownBuildingInstance::getPosition() const
int3 TownBuildingInstance::anchorPos() const
{
return town->getPosition();
return town->anchorPos();
}
TownRewardableBuildingInstance::TownRewardableBuildingInstance(IGameCallback *cb)

View File

@ -38,7 +38,7 @@ public:
const IOwnableObject * asOwnable() const override;
int3 visitablePos() const override;
int3 getPosition() const override;
int3 anchorPos() const override;
template <typename Handler> void serialize(Handler &h)
{

View File

@ -232,22 +232,22 @@ CMap::~CMap()
void CMap::removeBlockVisTiles(CGObjectInstance * obj, bool total)
{
const int zVal = obj->pos.z;
const int zVal = obj->anchorPos().z;
for(int fx = 0; fx < obj->getWidth(); ++fx)
{
int xVal = obj->pos.x - fx;
int xVal = obj->anchorPos().x - fx;
for(int fy = 0; fy < obj->getHeight(); ++fy)
{
int yVal = obj->pos.y - fy;
int yVal = obj->anchorPos().y - fy;
if(xVal>=0 && xVal < width && yVal>=0 && yVal < height)
{
TerrainTile & curt = terrain[zVal][xVal][yVal];
if(total || obj->visitableAt(xVal, yVal))
if(total || obj->visitableAt(int3(xVal, yVal, zVal)))
{
curt.visitableObjects -= obj;
curt.visitable = curt.visitableObjects.size();
}
if(total || obj->blockingAt(xVal, yVal))
if(total || obj->blockingAt(int3(xVal, yVal, zVal)))
{
curt.blockingObjects -= obj;
curt.blocked = curt.blockingObjects.size();
@ -259,22 +259,22 @@ void CMap::removeBlockVisTiles(CGObjectInstance * obj, bool total)
void CMap::addBlockVisTiles(CGObjectInstance * obj)
{
const int zVal = obj->pos.z;
const int zVal = obj->anchorPos().z;
for(int fx = 0; fx < obj->getWidth(); ++fx)
{
int xVal = obj->pos.x - fx;
int xVal = obj->anchorPos().x - fx;
for(int fy = 0; fy < obj->getHeight(); ++fy)
{
int yVal = obj->pos.y - fy;
int yVal = obj->anchorPos().y - fy;
if(xVal>=0 && xVal < width && yVal >= 0 && yVal < height)
{
TerrainTile & curt = terrain[zVal][xVal][yVal];
if(obj->visitableAt(xVal, yVal))
if(obj->visitableAt(int3(xVal, yVal, zVal)))
{
curt.visitableObjects.push_back(obj);
curt.visitable = true;
}
if(obj->blockingAt(xVal, yVal))
if(obj->blockingAt(int3(xVal, yVal, zVal)))
{
curt.blockingObjects.push_back(obj);
curt.blocked = true;
@ -444,14 +444,14 @@ const CGObjectInstance * CMap::getObjectiveObjectFrom(const int3 & pos, Obj type
bestMatch = object;
else
{
if (object->pos.dist2dSQ(pos) < bestMatch->pos.dist2dSQ(pos))
if (object->anchorPos().dist2dSQ(pos) < bestMatch->anchorPos().dist2dSQ(pos))
bestMatch = object;// closer than one we already found
}
}
}
assert(bestMatch != nullptr); // if this happens - victory conditions or map itself is very, very broken
logGlobal->error("Will use %s from %s", bestMatch->getObjectName(), bestMatch->pos.toString());
logGlobal->error("Will use %s from %s", bestMatch->getObjectName(), bestMatch->anchorPos().toString());
return bestMatch;
}
@ -635,7 +635,7 @@ void CMap::addNewObject(CGObjectInstance * obj)
void CMap::moveObject(CGObjectInstance * obj, const int3 & pos)
{
removeBlockVisTiles(obj);
obj->pos = pos;
obj->setAnchorPos(pos);
addBlockVisTiles(obj);
}
@ -803,7 +803,7 @@ void CMap::reindexObjects()
if (lhs->isRemovable() && !rhs->isRemovable())
return false;
return lhs->pos.y < rhs->pos.y;
return lhs->anchorPos().y < rhs->anchorPos().y;
});
// instanceNames don't change

View File

@ -615,7 +615,7 @@ std::string CInsertObjectOperation::getLabel() const
CMoveObjectOperation::CMoveObjectOperation(CMap* map, CGObjectInstance* obj, const int3& targetPosition)
: CMapOperation(map),
obj(obj),
initialPos(obj->pos),
initialPos(obj->anchorPos()),
targetPos(targetPosition)
{
}

View File

@ -913,7 +913,7 @@ void CMapLoaderH3M::loadArtifactsOfHero(CGHeroInstance * hero)
if(!hero->artifactsWorn.empty() || !hero->artifactsInBackpack.empty())
{
logGlobal->debug("Hero %d at %s has set artifacts twice (in map properties and on adventure map instance). Using the latter set...", hero->getHeroType().getNum(), hero->pos.toString());
logGlobal->debug("Hero %d at %s has set artifacts twice (in map properties and on adventure map instance). Using the latter set...", hero->getHeroType().getNum(), hero->anchorPos().toString());
hero->artifactsInBackpack.clear();
while(!hero->artifactsWorn.empty())
@ -1651,7 +1651,7 @@ void CMapLoaderH3M::readObjects()
if(!newObject)
continue;
newObject->pos = mapPosition;
newObject->setAnchorPos(mapPosition);
newObject->ID = objectTemplate->id;
newObject->id = objectInstanceID;
if(newObject->ID != Obj::HERO && newObject->ID != Obj::HERO_PLACEHOLDER && newObject->ID != Obj::PRISON)

View File

@ -1072,7 +1072,7 @@ void CMapLoaderJson::MapObjectLoader::construct()
instance->id = ObjectInstanceID(static_cast<si32>(owner->map->objects.size()));
instance->instanceName = jsonKey;
instance->pos = pos;
instance->setAnchorPos(pos);
owner->map->addNewObject(instance);
}

View File

@ -1047,7 +1047,7 @@ void ChangeObjPos::applyGs(CGameState *gs)
return;
}
gs->map->removeBlockVisTiles(obj);
obj->pos = nPos + obj->getVisitableOffset();
obj->setAnchorPos(nPos + obj->getVisitableOffset());
gs->map->addBlockVisTiles(obj);
}
@ -1467,7 +1467,7 @@ void GiveHero::applyGs(CGameState *gs)
h->setOwner(player);
h->setMovementPoints(h->movementPointsLimit(true));
h->pos = h->convertFromVisitablePos(oldVisitablePos);
h->setAnchorPos(h->convertFromVisitablePos(oldVisitablePos));
gs->map->heroesOnMap.emplace_back(h);
gs->getPlayerState(h->getOwner())->addOwnedObject(h);

View File

@ -87,7 +87,7 @@ const rmg::Area & Object::Instance::getAccessibleArea() const
void Object::Instance::setPosition(const int3 & position)
{
dPosition = position;
dObject.pos = dPosition + dParent.getPosition();
dObject.setAnchorPos(dPosition + dParent.getPosition());
dBlockedAreaCache.clear();
dAccessibleAreaCache.clear();
@ -96,21 +96,21 @@ void Object::Instance::setPosition(const int3 & position)
void Object::Instance::setPositionRaw(const int3 & position)
{
if(!dObject.pos.valid())
if(!dObject.anchorPos().valid())
{
dObject.pos = dPosition + dParent.getPosition();
dObject.setAnchorPos(dPosition + dParent.getPosition());
dBlockedAreaCache.clear();
dAccessibleAreaCache.clear();
dParent.clearCachedArea();
}
auto shift = position + dParent.getPosition() - dObject.pos;
auto shift = position + dParent.getPosition() - dObject.anchorPos();
dAccessibleAreaCache.translate(shift);
dBlockedAreaCache.translate(shift);
dPosition = position;
dObject.pos = dPosition + dParent.getPosition();
dObject.setAnchorPos(dPosition + dParent.getPosition());
}
void Object::Instance::setAnyTemplate(vstd::RNG & rng)
@ -497,12 +497,12 @@ void Object::Instance::finalize(RmgMap & map, vstd::RNG & rng)
}
if (dObject.isVisitable() && !map.isOnMap(dObject.visitablePos()))
throw rmgException(boost::str(boost::format("Visitable tile %s of object %d at %s is outside the map") % dObject.visitablePos().toString() % dObject.id % dObject.pos.toString()));
throw rmgException(boost::str(boost::format("Visitable tile %s of object %d at %s is outside the map") % dObject.visitablePos().toString() % dObject.id % dObject.anchorPos().toString()));
for(const auto & tile : dObject.getBlockedPos())
{
if(!map.isOnMap(tile))
throw rmgException(boost::str(boost::format("Tile %s of object %d at %s is outside the map") % tile.toString() % dObject.id % dObject.pos.toString()));
throw rmgException(boost::str(boost::format("Tile %s of object %d at %s is outside the map") % tile.toString() % dObject.id % dObject.anchorPos().toString()));
}
for(const auto & tile : getBlockedArea().getTilesVector())

View File

@ -112,7 +112,7 @@ void QuestArtifactPlacer::placeQuestArtifacts(vstd::RNG & rand)
logGlobal->trace("Replacing %s at %s with the quest artifact %s",
objectToReplace->getObjectName(),
objectToReplace->getPosition().toString(),
objectToReplace->anchorPos().toString(),
VLC->artifacts()->getById(artifactToPlace)->getNameTranslated());
//Update appearance. Terrain is irrelevant.
@ -121,7 +121,7 @@ void QuestArtifactPlacer::placeQuestArtifacts(vstd::RNG & rand)
auto templates = handler->getTemplates();
//artifactToReplace->appearance = templates.front();
newObj->appearance = templates.front();
newObj->pos = objectToReplace->pos;
newObj->setAnchorPos(objectToReplace->anchorPos());
mapProxy->insertObject(newObj);
mapProxy->removeObject(objectToReplace);
break;

View File

@ -209,7 +209,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
if(b->hero || b->layer != EPathfindingLayer::SAIL)
continue; //we're looking for unoccupied boat
double nDist = b->pos.dist2d(parameters.caster->getHeroCaster()->visitablePos());
double nDist = b->visitablePos().dist2d(parameters.caster->getHeroCaster()->visitablePos());
if(!nearest || nDist < dist) //it's first boat or closer than previous
{
nearest = b;
@ -669,11 +669,11 @@ const CGTownInstance * TownPortalMechanics::findNearestTown(SpellCastEnvironment
return nullptr;
auto nearest = pool.cbegin(); //nearest town's iterator
si32 dist = (*nearest)->pos.dist2dSQ(parameters.caster->getHeroCaster()->pos);
si32 dist = (*nearest)->visitablePos().dist2dSQ(parameters.caster->getHeroCaster()->visitablePos());
for(auto i = nearest + 1; i != pool.cend(); ++i)
{
si32 curDist = (*i)->pos.dist2dSQ(parameters.caster->getHeroCaster()->pos);
si32 curDist = (*i)->visitablePos().dist2dSQ(parameters.caster->getHeroCaster()->visitablePos());
if(curDist < dist)
{

View File

@ -379,7 +379,7 @@ void MapHandler::drawObjects(QPainter & painter, int x, int y, int z, const std:
if(objData.objBitmap)
{
auto pos = obj->getPosition();
auto pos = obj->anchorPos();
painter.drawImage(QPoint(x * tileSize, y * tileSize), *objData.objBitmap, object.rect, Qt::AutoColor | Qt::NoOpaqueDetection);

View File

@ -115,7 +115,7 @@ std::string AbstractSettings::getMonsterName(const CMap & map, int objectIdx)
std::string name;
if(auto monster = dynamic_cast<const CGCreature*>(map.objects[objectIdx].get()))
{
name = boost::str(boost::format("%1% at %2%") % monster->getObjectName() % monster->getPosition().toString());
name = boost::str(boost::format("%1% at %2%") % monster->getObjectName() % monster->anchorPos().toString());
}
return name;
}

View File

@ -425,7 +425,7 @@ void ObjectsLayer::setDirty(const CGObjectInstance * object)
{
for(int i = 0; i < object->getWidth(); ++i)
{
setDirty(object->getPosition().x - i, object->getPosition().y - j);
setDirty(object->anchorPos().x - i, object->anchorPos().y - j);
}
}
}
@ -479,7 +479,7 @@ void SelectionObjectsLayer::draw()
{
if(obj != newObject)
{
QRect bbox(obj->getPosition().x, obj->getPosition().y, 1, 1);
QRect bbox(obj->anchorPos().x, obj->anchorPos().y, 1, 1);
for(auto & t : obj->getBlockedPos())
{
QPoint topLeft(std::min(t.x, bbox.topLeft().x()), std::min(t.y, bbox.topLeft().y()));
@ -496,7 +496,7 @@ void SelectionObjectsLayer::draw()
if(selectionMode == SelectionMode::MOVEMENT && (shift.x() || shift.y()))
{
painter.setOpacity(0.7);
auto newPos = QPoint(obj->getPosition().x, obj->getPosition().y) + shift;
auto newPos = QPoint(obj->anchorPos().x, obj->anchorPos().y) + shift;
handler->drawObjectAt(painter, obj, newPos.x(), newPos.y());
}
}
@ -517,7 +517,7 @@ CGObjectInstance * SelectionObjectsLayer::selectObjectAt(int x, int y, const CGO
if(!object.obj || object.obj == ignore || lockedObjects.count(object.obj))
continue;
if(object.obj->visitableAt(x, y))
if(object.obj->visitableAt(int3(x, y, scene->level)))
{
return const_cast<CGObjectInstance*>(object.obj);
}
@ -529,7 +529,7 @@ CGObjectInstance * SelectionObjectsLayer::selectObjectAt(int x, int y, const CGO
if(!object.obj || object.obj == ignore || lockedObjects.count(object.obj))
continue;
if(object.obj->blockingAt(x, y))
if(object.obj->blockingAt(int3(x, y, scene->level)))
{
return const_cast<CGObjectInstance*>(object.obj);
}
@ -541,7 +541,7 @@ CGObjectInstance * SelectionObjectsLayer::selectObjectAt(int x, int y, const CGO
if(!object.obj || object.obj == ignore || lockedObjects.count(object.obj))
continue;
if(object.obj->coveringAt(x, y))
if(object.obj->coveringAt(int3(x, y, scene->level)))
{
return const_cast<CGObjectInstance*>(object.obj);
}

View File

@ -803,7 +803,7 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, EMovementMode moveme
return false;
}
logGlobal->trace("Player %d (%s) wants to move hero %d from %s to %s", asker, asker.toString(), hid.getNum(), h->pos.toString(), dst.toString());
logGlobal->trace("Player %d (%s) wants to move hero %d from %s to %s", asker, asker.toString(), hid.getNum(), h->anchorPos().toString(), dst.toString());
const int3 hmpos = h->convertToVisitablePos(dst);
if (!gs->map->isInTheMap(hmpos))
@ -902,7 +902,7 @@ 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->map->getTile(int3(h->pos.x-1, h->pos.y, h->pos.z)).visitableObjects)
for (CGObjectInstance *obj : gs->map->getTile(h->visitablePos()).visitableObjects)
{
obj->onHeroLeave(h);
}
@ -4222,8 +4222,11 @@ CGObjectInstance * CGameHandler::createNewObject(const int3 & visitablePosition,
else
o->appearance = handler->getTemplates().front();
if (o->isVisitable())
o->setAnchorPos(visitablePosition + o->getVisitableOffset());
else
o->setAnchorPos(visitablePosition);
o->pos = visitablePosition + o->getVisitableOffset();
return o;
}

View File

@ -283,7 +283,7 @@ void ApplyGhNetPackVisitor::visitTradeOnMarketplace(TradeOnMarketplace & pack)
gh.throwAndComplain(&pack, "Can not trade - no hero!");
// TODO: check that object is actually being visited (e.g. Query exists)
if (!object->visitableAt(hero->visitablePos().x, hero->visitablePos().y))
if (!object->visitableAt(hero->visitablePos()))
gh.throwAndComplain(&pack, "Can not trade - object not visited!");
if (object->getOwner().isValidPlayer() && gh.getPlayerRelations(object->getOwner(), hero->getOwner()) == PlayerRelations::ENEMIES)