Browse Source

Merge pull request #5525 from vcmi/fix_small_rmg_zones

Move main town to the tile with highest distance to water shore
DjWarmonger 7 months ago
parent
commit
daa57f30d5
6 changed files with 33 additions and 19 deletions
  1. 2 17
      lib/rmg/CZonePlacer.cpp
  2. 13 0
      lib/rmg/RmgArea.cpp
  3. 1 0
      lib/rmg/RmgArea.h
  4. 9 0
      lib/rmg/Zone.cpp
  5. 1 0
      lib/rmg/Zone.h
  6. 7 2
      lib/rmg/modificators/WaterAdopter.cpp

+ 2 - 17
lib/rmg/CZonePlacer.cpp

@@ -881,21 +881,6 @@ void CZonePlacer::assignZones(vstd::RNG * rand)
 		return lhs.second < rhs.second;
 	};
 
-	auto moveZoneToCenterOfMass = [width, height](const std::shared_ptr<Zone> & zone) -> void
-	{
-		int3 total(0, 0, 0);
-		auto tiles = zone->area()->getTiles();
-		for(const auto & tile : tiles)
-		{
-			total += tile;
-		}
-		int size = static_cast<int>(tiles.size());
-		assert(size);
-		auto newPos = int3(total.x / size, total.y / size, total.z / size);
-		zone->setPos(newPos);
-		zone->setCenter(float3(float(newPos.x) / width, float(newPos.y) / height, newPos.z));
-	};
-
 	int levels = map.levels();
 
 	// Find current center of mass for each zone. Move zone to that center to balance zones sizes
@@ -928,7 +913,7 @@ void CZonePlacer::assignZones(vstd::RNG * rand)
 		if(zone.second->area()->empty())
 			throw rmgException("Empty zone is generated, probably RMG template is inappropriate for map size");
 		
-		moveZoneToCenterOfMass(zone.second);
+		zone.second->moveToCenterOfMass();
 	}
 
 	for(const auto & zone : zones)
@@ -997,7 +982,7 @@ void CZonePlacer::assignZones(vstd::RNG * rand)
 	//set position (town position) to center of mass of irregular zone
 	for(const auto & zone : zones)
 	{
-		moveZoneToCenterOfMass(zone.second);
+		zone.second->moveToCenterOfMass();
 
 		//TODO: similar for islands
 		#define	CREATE_FULL_UNDERGROUND true //consider linking this with water amount

+ 13 - 0
lib/rmg/RmgArea.cpp

@@ -213,6 +213,19 @@ DistanceMap Area::computeDistanceMap(std::map<int, Tileset> & reverseDistanceMap
 	return result;
 }
 
+int3 Area::getCenterOfMass() const
+{
+	auto tiles = getTilesVector();
+	int3 total(0, 0, 0);
+	for(const auto & tile : tiles)
+	{
+		total += tile;
+	}
+	int size = static_cast<int>(tiles.size());
+	assert(size);
+	return int3(total.x / size, total.y / size, total.z / size);
+}
+
 bool Area::empty() const
 {
 	return dTiles.empty();

+ 1 - 0
lib/rmg/RmgArea.h

@@ -41,6 +41,7 @@ namespace rmg
 		const Tileset & getBorderOutside() const; //lazy cache invalidation
 		
 		DistanceMap computeDistanceMap(std::map<int, Tileset> & reverseDistanceMap) const;
+		int3 getCenterOfMass() const;
 
 		Area getSubarea(const std::function<bool(const int3 &)> & filter) const;
 

+ 9 - 0
lib/rmg/Zone.cpp

@@ -171,6 +171,15 @@ void Zone::setTerrainType(TerrainId terrain)
 	terrainType = terrain;
 }
 
+void Zone::moveToCenterOfMass()
+{
+	auto newPos = area()->getCenterOfMass();
+	setPos(newPos);
+	setCenter(float3(float(newPos.x) / map.getMapGenOptions().getWidth(), 
+		float(newPos.y) / map.getMapGenOptions().getHeight(), 
+		newPos.z));
+}
+
 rmg::Path Zone::searchPath(const rmg::Area & src, bool onlyStraight, const std::function<bool(const int3 &)> & areafilter) const
 ///connect current tile to any other free tile within zone
 {

+ 1 - 0
lib/rmg/Zone.h

@@ -83,6 +83,7 @@ public:
 	void setCenter(const float3 &f);
 	int3 getPos() const;
 	void setPos(const int3 &pos);
+	void moveToCenterOfMass();
 	
 	ThreadSafeProxy<rmg::Area> area(); 
 	ThreadSafeProxy<const rmg::Area> area() const;

+ 7 - 2
lib/rmg/modificators/WaterAdopter.cpp

@@ -34,8 +34,7 @@ void WaterAdopter::process()
 
 void WaterAdopter::init()
 {
-	//make dependencies
-	DEPENDENCY(TownPlacer);
+	POSTFUNCTION(TownPlacer);
 	POSTFUNCTION(ConnectionsPlacer);
 	POSTFUNCTION(TreasurePlacer);
 }
@@ -230,6 +229,12 @@ void WaterAdopter::createWater(EWaterContent::EWaterContent waterContent)
 	Zone::Lock lock(zone.areaMutex);
 	zone.area()->subtract(waterArea);
 	zone.areaPossible()->subtract(waterArea);
+	auto centerSet = std::max_element(reverseDistanceMap.begin(), reverseDistanceMap.end(), 
+		[](const auto &a, const auto &b) 
+		{
+			return a.first < b.first;
+		});
+	zone.setPos(rmg::Area(centerSet->second).getCenterOfMass());
 	distanceMap = zone.area()->computeDistanceMap(reverseDistanceMap);
 }