diff --git a/lib/rmg/RmgPath.cpp b/lib/rmg/RmgPath.cpp index 134f08267..62f31a8fc 100644 --- a/lib/rmg/RmgPath.cpp +++ b/lib/rmg/RmgPath.cpp @@ -190,4 +190,24 @@ const Area & Path::getPathArea() const return dPath; } +Path::MoveCostFunction Path::createCurvedCostFunction(const Area & border) +{ + // Capture by value to ensure the Area object persists + return [border = border](const int3& src, const int3& dst) -> float + { + // Route main roads far from border + //float ret = dst.dist2d(src); + float ret = dst.dist2d(src); + + float dist = border.distanceSqr(dst); + //int3 closestTile = border.nearest(dst); + //float dist = dst.chebdist2d(closestTile); + if(dist > 1.0f) + { + ret /= dist * dist; + } + return ret; + }; +} + VCMI_LIB_NAMESPACE_END diff --git a/lib/rmg/RmgPath.h b/lib/rmg/RmgPath.h index a76df8cfa..8cfe9e59f 100644 --- a/lib/rmg/RmgPath.h +++ b/lib/rmg/RmgPath.h @@ -21,7 +21,8 @@ namespace rmg class Path { public: - const static std::function DEFAULT_MOVEMENT_FUNCTION; + typedef std::function MoveCostFunction; + const static MoveCostFunction DEFAULT_MOVEMENT_FUNCTION; Path(const Area & area); Path(const Area & area, const int3 & src); @@ -42,6 +43,7 @@ public: const Area & getPathArea() const; static Path invalid(); + static MoveCostFunction createCurvedCostFunction(const Area & border); private: diff --git a/lib/rmg/modificators/ConnectionsPlacer.cpp b/lib/rmg/modificators/ConnectionsPlacer.cpp index 79c4ff438..a36de74ef 100644 --- a/lib/rmg/modificators/ConnectionsPlacer.cpp +++ b/lib/rmg/modificators/ConnectionsPlacer.cpp @@ -278,24 +278,23 @@ void ConnectionsPlacer::selfSideDirectConnection(const rmg::ZoneConnection & con assert(zone.getModificator()); auto & manager = *zone.getModificator(); auto * monsterType = manager.chooseGuard(connection.getGuardStrength(), true); - + rmg::Area border(zone.area()->getBorder()); border.unite(otherZone->area()->getBorder()); - - auto costFunction = [&border](const int3 & s, const int3 & d) - { - return 1.f / (1.f + border.distanceSqr(d)); - }; - + + 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(); theirArea.add(guardPos); rmg::Path ourPath(ourArea); rmg::Path theirPath(theirArea); ourPath.connect(zone.freePaths().get()); - ourPath = ourPath.search(guardPos, true, costFunction); + ourPath = ourPath.search(guardPos, true, localCostFunction); theirPath.connect(otherZone->freePaths().get()); - theirPath = theirPath.search(guardPos, true, costFunction); + theirPath = theirPath.search(guardPos, true, otherCostFunction); if(ourPath.valid() && theirPath.valid()) { diff --git a/lib/rmg/modificators/ObjectManager.cpp b/lib/rmg/modificators/ObjectManager.cpp index c256a85c1..32e89cb67 100644 --- a/lib/rmg/modificators/ObjectManager.cpp +++ b/lib/rmg/modificators/ObjectManager.cpp @@ -419,6 +419,11 @@ bool ObjectManager::createMonoliths() return false; } + // 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); + zone.connectPath(path); placeObject(rmgObject, guarded, true, objInfo.createRoad); } @@ -449,6 +454,24 @@ bool ObjectManager::createRequiredObjects() logGlobal->error("Failed to fill zone %d due to lack of space", zone.getId()); return false; } + 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()); + } + } zone.connectPath(path); placeObject(rmgObject, guarded, true, objInfo.createRoad); diff --git a/lib/rmg/modificators/RoadPlacer.cpp b/lib/rmg/modificators/RoadPlacer.cpp index a2a404766..482515bc9 100644 --- a/lib/rmg/modificators/RoadPlacer.cpp +++ b/lib/rmg/modificators/RoadPlacer.cpp @@ -91,7 +91,7 @@ bool RoadPlacer::createRoad(const int3 & destination) float dist = border.distanceSqr(dst); if(dist > 1.0f) { - ret /= dist; + ret /= dist * dist; } return ret; }