diff --git a/AI/Nullkiller/AIGateway.cpp b/AI/Nullkiller/AIGateway.cpp index 3609182df..bf289681c 100644 --- a/AI/Nullkiller/AIGateway.cpp +++ b/AI/Nullkiller/AIGateway.cpp @@ -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; } diff --git a/AI/Nullkiller/Goals/BuildThis.cpp b/AI/Nullkiller/Goals/BuildThis.cpp index c9c89c0a9..4de43c060 100644 --- a/AI/Nullkiller/Goals/BuildThis.cpp +++ b/AI/Nullkiller/Goals/BuildThis.cpp @@ -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; diff --git a/AI/VCAI/Goals/FindObj.cpp b/AI/VCAI/Goals/FindObj.cpp index 189a5c44b..288474eaa 100644 --- a/AI/VCAI/Goals/FindObj.cpp +++ b/AI/VCAI/Goals/FindObj.cpp @@ -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()); diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index 3757c56d3..c72a2a655 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -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)); } diff --git a/client/HeroMovementController.cpp b/client/HeroMovementController.cpp index d402413e5..2ee599017 100644 --- a/client/HeroMovementController.cpp +++ b/client/HeroMovementController.cpp @@ -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()); diff --git a/client/adventureMap/MapAudioPlayer.cpp b/client/adventureMap/MapAudioPlayer.cpp index bac234103..356b5577b 100644 --- a/client/adventureMap/MapAudioPlayer.cpp +++ b/client/adventureMap/MapAudioPlayer.cpp @@ -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); diff --git a/client/mapView/MapRenderer.cpp b/client/mapView/MapRenderer.cpp index 6688812a6..a274fe5ec 100644 --- a/client/mapView/MapRenderer.cpp +++ b/client/mapView/MapRenderer.cpp @@ -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); } } diff --git a/client/mapView/MapRendererContext.cpp b/client/mapView/MapRendererContext.cpp index 239541ae5..291322f31 100644 --- a/client/mapView/MapRendererContext.cpp +++ b/client/mapView/MapRendererContext.cpp @@ -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); diff --git a/client/mapView/MapRendererContextState.cpp b/client/mapView/MapRendererContextState.cpp index aa1a6ab0a..bb2632ce3 100644 --- a/client/mapView/MapRendererContextState.cpp +++ b/client/mapView/MapRendererContextState.cpp @@ -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)) { diff --git a/client/mapView/MapViewController.cpp b/client/mapView/MapViewController.cpp index ec33d6f5b..fa653725b 100644 --- a/client/mapView/MapViewController.cpp +++ b/client/mapView/MapViewController.cpp @@ -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) diff --git a/client/mapView/mapHandler.cpp b/client/mapView/mapHandler.cpp index bd19e421a..ede4b3ea5 100644 --- a/client/mapView/mapHandler.cpp +++ b/client/mapView/mapHandler.cpp @@ -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) diff --git a/client/windows/CQuestLog.cpp b/client/windows/CQuestLog.cpp index 2e18ef424..dbc39d439 100644 --- a/client/windows/CQuestLog.cpp +++ b/client/windows/CQuestLog.cpp @@ -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(); } diff --git a/lib/CGameInfoCallback.cpp b/lib/CGameInfoCallback.cpp index 8e404e34c..fa5fe231d 100644 --- a/lib/CGameInfoCallback.cpp +++ b/lib/CGameInfoCallback.cpp @@ -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(); diff --git a/lib/gameState/CGameState.cpp b/lib/gameState/CGameState.cpp index e35432cef..d0cd98fae 100644 --- a/lib/gameState/CGameState.cpp +++ b/lib/gameState/CGameState.cpp @@ -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(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(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::optionalgetWidth(); ++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; } diff --git a/lib/gameState/CGameStateCampaign.cpp b/lib/gameState/CGameStateCampaign.cpp index 703f97667..b4bf3678c 100644 --- a/lib/gameState/CGameStateCampaign.cpp +++ b/lib/gameState/CGameStateCampaign.cpp @@ -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; diff --git a/lib/mapObjects/CGCreature.cpp b/lib/mapObjects/CGCreature.cpp index ffa7bf5a9..3ebead8cb 100644 --- a/lib/mapObjects/CGCreature.cpp +++ b/lib/mapObjects/CGCreature.cpp @@ -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(std::floor(a * pos.x + b * pos.y + c * pos.z + d)); + int val = static_cast(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(pos.x) + b * static_cast(pos.y) + c * static_cast(pos.z) + d; + ui32 R1 = a * static_cast(visitablePos().x) + b * static_cast(visitablePos().y) + c * static_cast(visitablePos().z) + d; ui32 R2 = (R1 >> 16) & 0x7fff; int R4 = R2 % 100 + 1; diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 53426d09b..080285a96 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -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(target->pos.dist2d(visitablePos())); + const int distance = static_cast(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 diff --git a/lib/mapObjects/CGObjectInstance.cpp b/lib/mapObjects/CGObjectInstance.cpp index 5cee078fe..c9d7b3eea 100644 --- a/lib/mapObjects/CGObjectInstance.cpp +++ b/lib/mapObjects/CGObjectInstance.cpp @@ -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 CGObjectInstance::getBlockedPos() const @@ -115,7 +107,7 @@ std::set CGObjectInstance::getBlockedPos() const for(int h=0; hisBlockedAt(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(); } diff --git a/lib/mapObjects/CGObjectInstance.h b/lib/mapObjects/CGObjectInstance.h index 130077ae1..b5fdd7142 100644 --- a/lib/mapObjects/CGObjectInstance.h +++ b/lib/mapObjects/CGObjectInstance.h @@ -28,8 +28,6 @@ using TObjectTypeHandler = std::shared_ptr; 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 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 getBlockedPos() const; //returns set of positions blocked by this object const std::set & getBlockedOffsets() const; //returns set of relative positions blocked by this object diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index 9d28aee82..614cd0477 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -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(); } diff --git a/lib/mapObjects/CGTownInstance.h b/lib/mapObjects/CGTownInstance.h index fe143c6fd..f3b1f90fc 100644 --- a/lib/mapObjects/CGTownInstance.h +++ b/lib/mapObjects/CGTownInstance.h @@ -56,8 +56,6 @@ class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public I std::set builtBuildings; public: - using CGDwelling::getPosition; - enum EFortLevel {NONE = 0, FORT = 1, CITADEL = 2, CASTLE = 3}; CTownAndVisitingHero townAndVis; diff --git a/lib/mapObjects/CQuest.cpp b/lib/mapObjects/CQuest.cpp index 7e1e00298..b49e169ea 100644 --- a/lib/mapObjects/CQuest.cpp +++ b/lib/mapObjects/CQuest.cpp @@ -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(cord.x) / static_cast(cb->getMapSize().x) < 0.34) //north { if(static_cast(cord.y) / static_cast(cb->getMapSize().y) < 0.34) //northwest diff --git a/lib/mapObjects/IObjectInterface.cpp b/lib/mapObjects/IObjectInterface.cpp index 432b9e35d..80cbec7e4 100644 --- a/lib/mapObjects/IObjectInterface.cpp +++ b/lib/mapObjects/IObjectInterface.cpp @@ -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; } } diff --git a/lib/mapObjects/IObjectInterface.h b/lib/mapObjects/IObjectInterface.h index 9ccda2c7c..4398c5a11 100644 --- a/lib/mapObjects/IObjectInterface.h +++ b/lib/mapObjects/IObjectInterface.h @@ -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; diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index 9956396f3..b8b95994d 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -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(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); } diff --git a/lib/mapObjects/TownBuildingInstance.cpp b/lib/mapObjects/TownBuildingInstance.cpp index 04d2dfbe5..cb8f2661b 100644 --- a/lib/mapObjects/TownBuildingInstance.cpp +++ b/lib/mapObjects/TownBuildingInstance.cpp @@ -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) diff --git a/lib/mapObjects/TownBuildingInstance.h b/lib/mapObjects/TownBuildingInstance.h index 8874793cf..015421448 100644 --- a/lib/mapObjects/TownBuildingInstance.h +++ b/lib/mapObjects/TownBuildingInstance.h @@ -38,7 +38,7 @@ public: const IOwnableObject * asOwnable() const override; int3 visitablePos() const override; - int3 getPosition() const override; + int3 anchorPos() const override; template void serialize(Handler &h) { diff --git a/lib/mapping/CMap.cpp b/lib/mapping/CMap.cpp index 77af471b0..afd1d610d 100644 --- a/lib/mapping/CMap.cpp +++ b/lib/mapping/CMap.cpp @@ -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 diff --git a/lib/mapping/CMapOperation.cpp b/lib/mapping/CMapOperation.cpp index 7aaf268fc..f6c8deb22 100644 --- a/lib/mapping/CMapOperation.cpp +++ b/lib/mapping/CMapOperation.cpp @@ -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) { } diff --git a/lib/mapping/MapFormatH3M.cpp b/lib/mapping/MapFormatH3M.cpp index 1826d34ea..bfdb2a289 100644 --- a/lib/mapping/MapFormatH3M.cpp +++ b/lib/mapping/MapFormatH3M.cpp @@ -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) diff --git a/lib/mapping/MapFormatJson.cpp b/lib/mapping/MapFormatJson.cpp index 753e235c7..b1a68b0ec 100644 --- a/lib/mapping/MapFormatJson.cpp +++ b/lib/mapping/MapFormatJson.cpp @@ -1072,7 +1072,7 @@ void CMapLoaderJson::MapObjectLoader::construct() instance->id = ObjectInstanceID(static_cast(owner->map->objects.size())); instance->instanceName = jsonKey; - instance->pos = pos; + instance->setAnchorPos(pos); owner->map->addNewObject(instance); } diff --git a/lib/networkPacks/NetPacksLib.cpp b/lib/networkPacks/NetPacksLib.cpp index 6e7229f98..9efe0025b 100644 --- a/lib/networkPacks/NetPacksLib.cpp +++ b/lib/networkPacks/NetPacksLib.cpp @@ -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); diff --git a/lib/rmg/RmgObject.cpp b/lib/rmg/RmgObject.cpp index 1004072cb..691bb23b8 100644 --- a/lib/rmg/RmgObject.cpp +++ b/lib/rmg/RmgObject.cpp @@ -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()) diff --git a/lib/rmg/modificators/QuestArtifactPlacer.cpp b/lib/rmg/modificators/QuestArtifactPlacer.cpp index 9117ab34c..31d9e5c05 100644 --- a/lib/rmg/modificators/QuestArtifactPlacer.cpp +++ b/lib/rmg/modificators/QuestArtifactPlacer.cpp @@ -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; diff --git a/lib/spells/AdventureSpellMechanics.cpp b/lib/spells/AdventureSpellMechanics.cpp index decfa7140..089c691b2 100644 --- a/lib/spells/AdventureSpellMechanics.cpp +++ b/lib/spells/AdventureSpellMechanics.cpp @@ -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) { diff --git a/mapeditor/maphandler.cpp b/mapeditor/maphandler.cpp index e42b84b78..c9b18ac32 100644 --- a/mapeditor/maphandler.cpp +++ b/mapeditor/maphandler.cpp @@ -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); diff --git a/mapeditor/mapsettings/abstractsettings.cpp b/mapeditor/mapsettings/abstractsettings.cpp index a1f4afc43..f75a77685 100644 --- a/mapeditor/mapsettings/abstractsettings.cpp +++ b/mapeditor/mapsettings/abstractsettings.cpp @@ -115,7 +115,7 @@ std::string AbstractSettings::getMonsterName(const CMap & map, int objectIdx) std::string name; if(auto monster = dynamic_cast(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; } diff --git a/mapeditor/scenelayer.cpp b/mapeditor/scenelayer.cpp index 32713ebef..628fb932c 100644 --- a/mapeditor/scenelayer.cpp +++ b/mapeditor/scenelayer.cpp @@ -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(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(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(object.obj); } diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 273379c1e..272e66004 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -804,7 +804,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)) @@ -903,7 +903,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); } @@ -4223,8 +4223,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; } diff --git a/server/NetPacksServer.cpp b/server/NetPacksServer.cpp index fe4607786..7818e3e5a 100644 --- a/server/NetPacksServer.cpp +++ b/server/NetPacksServer.cpp @@ -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)