diff --git a/lib/rmg/Functions.cpp b/lib/rmg/Functions.cpp index fd855e6be..62e56154c 100644 --- a/lib/rmg/Functions.cpp +++ b/lib/rmg/Functions.cpp @@ -24,6 +24,23 @@ VCMI_LIB_NAMESPACE_BEGIN +void replaceWithCurvedPath(rmg::Path & path, const Zone & zone, const int3 & src) +{ + auto costFunction = rmg::Path::createCurvedCostFunction(zone.area()->getBorder()); + auto pathArea = zone.areaForRoads(); + rmg::Path curvedPath(pathArea); + curvedPath.connect(zone.freePaths().get()); + curvedPath = curvedPath.search(src, false, costFunction); + if (curvedPath.valid()) + { + path = curvedPath; + } + else + { + logGlobal->warn("Failed to create curved path to %s", src.toString()); + } +} + rmg::Tileset collectDistantTiles(const Zone& zone, int distance) { uint32_t distanceSq = distance * distance; diff --git a/lib/rmg/Functions.h b/lib/rmg/Functions.h index 2756d0897..012178401 100644 --- a/lib/rmg/Functions.h +++ b/lib/rmg/Functions.h @@ -34,6 +34,8 @@ public: } }; +void replaceWithCurvedPath(rmg::Path & path, const Zone & zone, const int3 & src); + rmg::Tileset collectDistantTiles(const Zone & zone, int distance); int chooseRandomAppearance(vstd::RNG & generator, si32 ObjID, TerrainId terrain); diff --git a/lib/rmg/Zone.cpp b/lib/rmg/Zone.cpp index 273dc226e..8a4972e65 100644 --- a/lib/rmg/Zone.cpp +++ b/lib/rmg/Zone.cpp @@ -121,6 +121,11 @@ ThreadSafeProxy Zone::areaUsed() const return ThreadSafeProxy(dAreaUsed, areaMutex); } +rmg::Area Zone::areaForRoads() const +{ + return areaPossible() + freePaths(); +} + void Zone::clearTiles() { Lock lock(areaMutex); diff --git a/lib/rmg/Zone.h b/lib/rmg/Zone.h index 4ae2c7a13..5b18a6fe8 100644 --- a/lib/rmg/Zone.h +++ b/lib/rmg/Zone.h @@ -92,6 +92,8 @@ public: ThreadSafeProxy freePaths() const; ThreadSafeProxy areaUsed(); ThreadSafeProxy areaUsed() const; + + rmg::Area areaForRoads() const; void initFreeTiles(); void clearTiles(); diff --git a/lib/rmg/modificators/ConnectionsPlacer.cpp b/lib/rmg/modificators/ConnectionsPlacer.cpp index a36de74ef..98311055c 100644 --- a/lib/rmg/modificators/ConnectionsPlacer.cpp +++ b/lib/rmg/modificators/ConnectionsPlacer.cpp @@ -185,8 +185,8 @@ void ConnectionsPlacer::selfSideDirectConnection(const rmg::ZoneConnection & con return 1.f / (1.f + border.distanceSqr(d)); }; - auto ourArea = zone.areaPossible() + zone.freePaths(); - auto theirArea = otherZone->areaPossible() + otherZone->freePaths(); + auto ourArea = zone.areaForRoads(); + auto theirArea = otherZone->areaForRoads(); theirArea.add(potentialPos); rmg::Path ourPath(ourArea); rmg::Path theirPath(theirArea); @@ -285,9 +285,8 @@ void ConnectionsPlacer::selfSideDirectConnection(const rmg::ZoneConnection & con auto localCostFunction = rmg::Path::createCurvedCostFunction(zone.area()->getBorder()); auto otherCostFunction = rmg::Path::createCurvedCostFunction(otherZone->area()->getBorder()); - // TODO: helper function for this sum? - auto ourArea = zone.areaPossible() + zone.freePaths(); - auto theirArea = otherZone->areaPossible() + otherZone->freePaths(); + auto ourArea = zone.areaForRoads(); + auto theirArea = otherZone->areaForRoads(); theirArea.add(guardPos); rmg::Path ourPath(ourArea); rmg::Path theirPath(theirArea); @@ -417,11 +416,15 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c if(path1.valid() && path2.valid()) { - zone.connectPath(path1); - otherZone->connectPath(path2); - manager.placeObject(rmgGate1, guarded1, true, allowRoad); managerOther.placeObject(rmgGate2, guarded2, true, allowRoad); + + // FIXME: Guard can still be placed on the object + replaceWithCurvedPath(path1, zone, rmgGate1.getVisitablePosition()); + replaceWithCurvedPath(path2, *otherZone, rmgGate2.getVisitablePosition()); + + zone.connectPath(path1); + otherZone->connectPath(path2); assert(otherZone->getModificator()); otherZone->getModificator()->otherSideConnection(connection); diff --git a/lib/rmg/modificators/ObjectManager.cpp b/lib/rmg/modificators/ObjectManager.cpp index 32e89cb67..13b8b3000 100644 --- a/lib/rmg/modificators/ObjectManager.cpp +++ b/lib/rmg/modificators/ObjectManager.cpp @@ -344,7 +344,7 @@ rmg::Path ObjectManager::placeAndConnectObject(const rmg::Area & searchArea, rmg { int3 pos; auto possibleArea = searchArea; - auto cachedArea = zone.areaPossible() + zone.freePaths(); + auto cachedArea = zone.areaForRoads(); while(true) { pos = findPlaceForObject(possibleArea, obj, weightFunction, optimizer); @@ -420,9 +420,7 @@ bool ObjectManager::createMonoliths() } // Once it can be created, replace with curved path - auto costFunction = rmg::Path::createCurvedCostFunction(zone.area()->getBorder()); - rmg::Path curvedPath(zone.areaPossible() + zone.freePaths()); - path = curvedPath.search(rmgObject.getVisitablePosition(), true, costFunction); + replaceWithCurvedPath(path, zone, rmgObject.getVisitablePosition()); zone.connectPath(path); placeObject(rmgObject, guarded, true, objInfo.createRoad); @@ -457,20 +455,7 @@ bool ObjectManager::createRequiredObjects() if (objInfo.createRoad) { // Once valid path can be created, replace with curved path - - auto costFunction = rmg::Path::createCurvedCostFunction(zone.area()->getBorder()); - auto pathArea = zone.areaPossible() + zone.freePaths(); - rmg::Path curvedPath(pathArea); - curvedPath.connect(zone.freePaths().get()); - curvedPath = curvedPath.search(rmgObject.getVisitablePosition(), false, costFunction); - if (curvedPath.valid()) - { - path = curvedPath; - } - else - { - logGlobal->warn("Failed to create curved path for required object at %s", rmgObject.getPosition().toString()); - } + replaceWithCurvedPath(path, zone, rmgObject.getVisitablePosition()); } zone.connectPath(path); diff --git a/lib/rmg/modificators/RiverPlacer.cpp b/lib/rmg/modificators/RiverPlacer.cpp index dd4150627..9983d2011 100644 --- a/lib/rmg/modificators/RiverPlacer.cpp +++ b/lib/rmg/modificators/RiverPlacer.cpp @@ -212,7 +212,7 @@ void RiverPlacer::preprocess() { auto river = VLC->terrainTypeHandler->getById(zone.getTerrainType())->river; auto & a = neighbourZonesTiles[connectedToWaterZoneId]; - auto availableArea = zone.areaPossible() + zone.freePaths(); + auto availableArea = zone.areaForRoads(); for(const auto & tileToProcess : availableArea.getTilesVector()) { int templateId = -1; diff --git a/lib/rmg/modificators/WaterProxy.cpp b/lib/rmg/modificators/WaterProxy.cpp index 544c6f197..5172910fa 100644 --- a/lib/rmg/modificators/WaterProxy.cpp +++ b/lib/rmg/modificators/WaterProxy.cpp @@ -266,9 +266,9 @@ bool WaterProxy::placeBoat(Zone & land, const Lake & lake, bool createRoad, Rout rmg::Object rmgObject(*boat); rmgObject.setTemplate(zone.getTerrainType(), zone.getRand()); - auto waterAvailable = zone.areaPossible() + zone.freePaths(); + auto waterAvailable = zone.areaForRoads(); rmg::Area coast = lake.neighbourZones.at(land.getId()); //having land tiles - coast.intersect(land.areaPossible() + land.freePaths()); //having only available land tiles + coast.intersect(land.areaForRoads()); //having only available land tiles auto boardingPositions = coast.getSubarea([&waterAvailable, this](const int3 & tile) //tiles where boarding is possible { //We don't want place boat right to any land object, especiallly the zone guard @@ -332,10 +332,10 @@ bool WaterProxy::placeShipyard(Zone & land, const Lake & lake, si32 guard, bool rmgObject.setTemplate(land.getTerrainType(), zone.getRand()); bool guarded = manager->addGuard(rmgObject, guard); - auto waterAvailable = zone.areaPossible() + zone.freePaths(); + auto waterAvailable = zone.areaForRoads(); waterAvailable.intersect(lake.area); rmg::Area coast = lake.neighbourZones.at(land.getId()); //having land tiles - coast.intersect(land.areaPossible() + land.freePaths()); //having only available land tiles + coast.intersect(land.areaForRoads()); //having only available land tiles auto boardingPositions = coast.getSubarea([&waterAvailable](const int3 & tile) //tiles where boarding is possible { rmg::Area a({tile});