mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-10 00:43:59 +02:00
Merge remote-tracking branch 'upstream/develop' into develop
This commit is contained in:
commit
3f073507a1
@ -24,6 +24,23 @@
|
|||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
void replaceWithCurvedPath(rmg::Path & path, const Zone & zone, const int3 & src, bool onlyStraight)
|
||||||
|
{
|
||||||
|
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, onlyStraight, 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)
|
rmg::Tileset collectDistantTiles(const Zone& zone, int distance)
|
||||||
{
|
{
|
||||||
uint32_t distanceSq = distance * distance;
|
uint32_t distanceSq = distance * distance;
|
||||||
|
@ -34,6 +34,8 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void replaceWithCurvedPath(rmg::Path & path, const Zone & zone, const int3 & src, bool onlyStraight = true);
|
||||||
|
|
||||||
rmg::Tileset collectDistantTiles(const Zone & zone, int distance);
|
rmg::Tileset collectDistantTiles(const Zone & zone, int distance);
|
||||||
|
|
||||||
int chooseRandomAppearance(vstd::RNG & generator, si32 ObjID, TerrainId terrain);
|
int chooseRandomAppearance(vstd::RNG & generator, si32 ObjID, TerrainId terrain);
|
||||||
|
@ -116,8 +116,7 @@ Path Path::search(const Tileset & dst, bool straight, std::function<float(const
|
|||||||
if(!result.dArea->contains(pos))
|
if(!result.dArea->contains(pos))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
float movementCost = moveCostFunction(currentNode, pos) + currentNode.dist2d(pos);
|
float movementCost = moveCostFunction(currentNode, pos);
|
||||||
|
|
||||||
float distance = distances[currentNode] + movementCost; //we prefer to use already free paths
|
float distance = distances[currentNode] + movementCost; //we prefer to use already free paths
|
||||||
int bestDistanceSoFar = std::numeric_limits<int>::max();
|
int bestDistanceSoFar = std::numeric_limits<int>::max();
|
||||||
auto it = distances.find(pos);
|
auto it = distances.find(pos);
|
||||||
@ -190,4 +189,21 @@ const Area & Path::getPathArea() const
|
|||||||
return dPath;
|
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 dist = border.distanceSqr(dst);
|
||||||
|
|
||||||
|
if(dist > 1.0f)
|
||||||
|
{
|
||||||
|
ret /= dist;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@ -21,7 +21,8 @@ namespace rmg
|
|||||||
class Path
|
class Path
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const static std::function<float(const int3 &, const int3 &)> DEFAULT_MOVEMENT_FUNCTION;
|
using MoveCostFunction = std::function<float(const int3 &, const int3 &)>;
|
||||||
|
const static MoveCostFunction DEFAULT_MOVEMENT_FUNCTION;
|
||||||
|
|
||||||
Path(const Area & area);
|
Path(const Area & area);
|
||||||
Path(const Area & area, const int3 & src);
|
Path(const Area & area, const int3 & src);
|
||||||
@ -42,6 +43,7 @@ public:
|
|||||||
const Area & getPathArea() const;
|
const Area & getPathArea() const;
|
||||||
|
|
||||||
static Path invalid();
|
static Path invalid();
|
||||||
|
static MoveCostFunction createCurvedCostFunction(const Area & border);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -121,6 +121,11 @@ ThreadSafeProxy<const rmg::Area> Zone::areaUsed() const
|
|||||||
return ThreadSafeProxy<const rmg::Area>(dAreaUsed, areaMutex);
|
return ThreadSafeProxy<const rmg::Area>(dAreaUsed, areaMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rmg::Area Zone::areaForRoads() const
|
||||||
|
{
|
||||||
|
return areaPossible() + freePaths();
|
||||||
|
}
|
||||||
|
|
||||||
void Zone::clearTiles()
|
void Zone::clearTiles()
|
||||||
{
|
{
|
||||||
Lock lock(areaMutex);
|
Lock lock(areaMutex);
|
||||||
@ -299,7 +304,6 @@ void Zone::fractalize()
|
|||||||
logGlobal->trace("Zone %d: treasureValue %d blockDistance: %2.f, freeDistance: %2.f", getId(), treasureValue, blockDistance, freeDistance);
|
logGlobal->trace("Zone %d: treasureValue %d blockDistance: %2.f, freeDistance: %2.f", getId(), treasureValue, blockDistance, freeDistance);
|
||||||
|
|
||||||
Lock lock(areaMutex);
|
Lock lock(areaMutex);
|
||||||
// FIXME: Do not access Area directly
|
|
||||||
|
|
||||||
rmg::Area clearedTiles(dAreaFree);
|
rmg::Area clearedTiles(dAreaFree);
|
||||||
rmg::Area possibleTiles(dAreaPossible);
|
rmg::Area possibleTiles(dAreaPossible);
|
||||||
|
@ -93,6 +93,8 @@ public:
|
|||||||
ThreadSafeProxy<rmg::Area> areaUsed();
|
ThreadSafeProxy<rmg::Area> areaUsed();
|
||||||
ThreadSafeProxy<const rmg::Area> areaUsed() const;
|
ThreadSafeProxy<const rmg::Area> areaUsed() const;
|
||||||
|
|
||||||
|
rmg::Area areaForRoads() const;
|
||||||
|
|
||||||
void initFreeTiles();
|
void initFreeTiles();
|
||||||
void clearTiles();
|
void clearTiles();
|
||||||
void fractalize();
|
void fractalize();
|
||||||
|
@ -185,8 +185,8 @@ void ConnectionsPlacer::selfSideDirectConnection(const rmg::ZoneConnection & con
|
|||||||
return 1.f / (1.f + border.distanceSqr(d));
|
return 1.f / (1.f + border.distanceSqr(d));
|
||||||
};
|
};
|
||||||
|
|
||||||
auto ourArea = zone.areaPossible() + zone.freePaths();
|
auto ourArea = zone.areaForRoads();
|
||||||
auto theirArea = otherZone->areaPossible() + otherZone->freePaths();
|
auto theirArea = otherZone->areaForRoads();
|
||||||
theirArea.add(potentialPos);
|
theirArea.add(potentialPos);
|
||||||
rmg::Path ourPath(ourArea);
|
rmg::Path ourPath(ourArea);
|
||||||
rmg::Path theirPath(theirArea);
|
rmg::Path theirPath(theirArea);
|
||||||
@ -282,20 +282,18 @@ void ConnectionsPlacer::selfSideDirectConnection(const rmg::ZoneConnection & con
|
|||||||
rmg::Area border(zone.area()->getBorder());
|
rmg::Area border(zone.area()->getBorder());
|
||||||
border.unite(otherZone->area()->getBorder());
|
border.unite(otherZone->area()->getBorder());
|
||||||
|
|
||||||
auto costFunction = [&border](const int3 & s, const int3 & d)
|
auto localCostFunction = rmg::Path::createCurvedCostFunction(zone.area()->getBorder());
|
||||||
{
|
auto otherCostFunction = rmg::Path::createCurvedCostFunction(otherZone->area()->getBorder());
|
||||||
return 1.f / (1.f + border.distanceSqr(d));
|
|
||||||
};
|
|
||||||
|
|
||||||
auto ourArea = zone.areaPossible() + zone.freePaths();
|
auto ourArea = zone.areaForRoads();
|
||||||
auto theirArea = otherZone->areaPossible() + otherZone->freePaths();
|
auto theirArea = otherZone->areaForRoads();
|
||||||
theirArea.add(guardPos);
|
theirArea.add(guardPos);
|
||||||
rmg::Path ourPath(ourArea);
|
rmg::Path ourPath(ourArea);
|
||||||
rmg::Path theirPath(theirArea);
|
rmg::Path theirPath(theirArea);
|
||||||
ourPath.connect(zone.freePaths().get());
|
ourPath.connect(zone.freePaths().get());
|
||||||
ourPath = ourPath.search(guardPos, true, costFunction);
|
ourPath = ourPath.search(guardPos, true, localCostFunction);
|
||||||
theirPath.connect(otherZone->freePaths().get());
|
theirPath.connect(otherZone->freePaths().get());
|
||||||
theirPath = theirPath.search(guardPos, true, costFunction);
|
theirPath = theirPath.search(guardPos, true, otherCostFunction);
|
||||||
|
|
||||||
if(ourPath.valid() && theirPath.valid())
|
if(ourPath.valid() && theirPath.valid())
|
||||||
{
|
{
|
||||||
@ -417,12 +415,15 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c
|
|||||||
|
|
||||||
if(path1.valid() && path2.valid())
|
if(path1.valid() && path2.valid())
|
||||||
{
|
{
|
||||||
zone.connectPath(path1);
|
|
||||||
otherZone->connectPath(path2);
|
|
||||||
|
|
||||||
manager.placeObject(rmgGate1, guarded1, true, allowRoad);
|
manager.placeObject(rmgGate1, guarded1, true, allowRoad);
|
||||||
managerOther.placeObject(rmgGate2, guarded2, true, allowRoad);
|
managerOther.placeObject(rmgGate2, guarded2, true, allowRoad);
|
||||||
|
|
||||||
|
replaceWithCurvedPath(path1, zone, rmgGate1.getVisitablePosition());
|
||||||
|
replaceWithCurvedPath(path2, *otherZone, rmgGate2.getVisitablePosition());
|
||||||
|
|
||||||
|
zone.connectPath(path1);
|
||||||
|
otherZone->connectPath(path2);
|
||||||
|
|
||||||
assert(otherZone->getModificator<ConnectionsPlacer>());
|
assert(otherZone->getModificator<ConnectionsPlacer>());
|
||||||
otherZone->getModificator<ConnectionsPlacer>()->otherSideConnection(connection);
|
otherZone->getModificator<ConnectionsPlacer>()->otherSideConnection(connection);
|
||||||
|
|
||||||
|
@ -344,7 +344,7 @@ rmg::Path ObjectManager::placeAndConnectObject(const rmg::Area & searchArea, rmg
|
|||||||
{
|
{
|
||||||
int3 pos;
|
int3 pos;
|
||||||
auto possibleArea = searchArea;
|
auto possibleArea = searchArea;
|
||||||
auto cachedArea = zone.areaPossible() + zone.freePaths();
|
auto cachedArea = zone.areaForRoads();
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
pos = findPlaceForObject(possibleArea, obj, weightFunction, optimizer);
|
pos = findPlaceForObject(possibleArea, obj, weightFunction, optimizer);
|
||||||
@ -419,6 +419,9 @@ bool ObjectManager::createMonoliths()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Once it can be created, replace with curved path
|
||||||
|
replaceWithCurvedPath(path, zone, rmgObject.getVisitablePosition());
|
||||||
|
|
||||||
zone.connectPath(path);
|
zone.connectPath(path);
|
||||||
placeObject(rmgObject, guarded, true, objInfo.createRoad);
|
placeObject(rmgObject, guarded, true, objInfo.createRoad);
|
||||||
}
|
}
|
||||||
@ -449,6 +452,11 @@ bool ObjectManager::createRequiredObjects()
|
|||||||
logGlobal->error("Failed to fill zone %d due to lack of space", zone.getId());
|
logGlobal->error("Failed to fill zone %d due to lack of space", zone.getId());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (objInfo.createRoad)
|
||||||
|
{
|
||||||
|
// Once valid path can be created, replace with curved path
|
||||||
|
replaceWithCurvedPath(path, zone, rmgObject.getVisitablePosition());
|
||||||
|
}
|
||||||
|
|
||||||
zone.connectPath(path);
|
zone.connectPath(path);
|
||||||
placeObject(rmgObject, guarded, true, objInfo.createRoad);
|
placeObject(rmgObject, guarded, true, objInfo.createRoad);
|
||||||
|
@ -212,7 +212,7 @@ void RiverPlacer::preprocess()
|
|||||||
{
|
{
|
||||||
auto river = VLC->terrainTypeHandler->getById(zone.getTerrainType())->river;
|
auto river = VLC->terrainTypeHandler->getById(zone.getTerrainType())->river;
|
||||||
auto & a = neighbourZonesTiles[connectedToWaterZoneId];
|
auto & a = neighbourZonesTiles[connectedToWaterZoneId];
|
||||||
auto availableArea = zone.areaPossible() + zone.freePaths();
|
auto availableArea = zone.areaForRoads();
|
||||||
for(const auto & tileToProcess : availableArea.getTilesVector())
|
for(const auto & tileToProcess : availableArea.getTilesVector())
|
||||||
{
|
{
|
||||||
int templateId = -1;
|
int templateId = -1;
|
||||||
|
@ -266,9 +266,9 @@ bool WaterProxy::placeBoat(Zone & land, const Lake & lake, bool createRoad, Rout
|
|||||||
rmg::Object rmgObject(*boat);
|
rmg::Object rmgObject(*boat);
|
||||||
rmgObject.setTemplate(zone.getTerrainType(), zone.getRand());
|
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
|
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
|
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
|
//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());
|
rmgObject.setTemplate(land.getTerrainType(), zone.getRand());
|
||||||
bool guarded = manager->addGuard(rmgObject, guard);
|
bool guarded = manager->addGuard(rmgObject, guard);
|
||||||
|
|
||||||
auto waterAvailable = zone.areaPossible() + zone.freePaths();
|
auto waterAvailable = zone.areaForRoads();
|
||||||
waterAvailable.intersect(lake.area);
|
waterAvailable.intersect(lake.area);
|
||||||
rmg::Area coast = lake.neighbourZones.at(land.getId()); //having land tiles
|
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
|
auto boardingPositions = coast.getSubarea([&waterAvailable](const int3 & tile) //tiles where boarding is possible
|
||||||
{
|
{
|
||||||
rmg::Area a({tile});
|
rmg::Area a({tile});
|
||||||
|
Loading…
Reference in New Issue
Block a user