浏览代码

Implement curved paths for all road node objects

Tomasz Zieliński 1 年之前
父节点
当前提交
f95bb58433

+ 17 - 0
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;

+ 2 - 0
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);

+ 5 - 0
lib/rmg/Zone.cpp

@@ -121,6 +121,11 @@ ThreadSafeProxy<const rmg::Area> Zone::areaUsed() const
 	return ThreadSafeProxy<const rmg::Area>(dAreaUsed, areaMutex);
 }
 
+rmg::Area Zone::areaForRoads() const
+{
+	return areaPossible() + freePaths();
+}
+
 void Zone::clearTiles()
 {
 	Lock lock(areaMutex);

+ 2 - 0
lib/rmg/Zone.h

@@ -92,6 +92,8 @@ public:
 	ThreadSafeProxy<const rmg::Area> freePaths() const;
 	ThreadSafeProxy<rmg::Area> areaUsed();
 	ThreadSafeProxy<const rmg::Area> areaUsed() const;
+	
+	rmg::Area areaForRoads() const;
 
 	void initFreeTiles();
 	void clearTiles();

+ 11 - 8
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<ConnectionsPlacer>());
 				otherZone->getModificator<ConnectionsPlacer>()->otherSideConnection(connection);

+ 3 - 18
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);

+ 1 - 1
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;

+ 4 - 4
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});