Browse Source

Fix problems with water zone (#784)

Nordsoft91 3 years ago
parent
commit
8f0dcf928c

+ 7 - 2
lib/rmg/RmgArea.cpp

@@ -85,8 +85,13 @@ bool Area::connected() const
 	return connected.empty();
 }
 
-std::list<Area> connectedAreas(const Area & area)
+std::list<Area> connectedAreas(const Area & area, bool disableDiagonalConnections)
 {
+	auto allDirs = int3::getDirs();
+	std::vector<int3> dirs(allDirs.begin(), allDirs.end());
+	if(disableDiagonalConnections)
+		dirs.assign(rmg::dirs4.begin(), rmg::dirs4.end());
+	
 	std::list<Area> result;
 	Tileset connected = area.getTiles();
 	while(!connected.empty())
@@ -101,7 +106,7 @@ std::list<Area> connectedAreas(const Area & area)
 			result.back().add(t);
 			queue.pop_front();
 			
-			for(auto & i : int3::getDirs())
+			for(auto & i : dirs)
 			{
 				auto tile = t + i;
 				if(!queueSet.count(tile) && connected.count(tile) && !result.back().contains(tile))

+ 4 - 1
lib/rmg/RmgArea.h

@@ -15,6 +15,9 @@
 
 namespace rmg
 {
+	static const std::array<int3, 4> dirs4 = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0) };
+	static const std::array<int3, 4> dirsDiagonal= { int3(1,1,0),int3(1,-1,0),int3(-1,1,0),int3(-1,-1,0) };
+
 	using Tileset = std::set<int3>;
 	using DistanceMap = std::map<int3, int>;
 	void toAbsolute(Tileset & tiles, const int3 & position);
@@ -66,7 +69,7 @@ namespace rmg
 		friend Area operator* (const Area & l, const Area & r); //intersection
 		friend Area operator- (const Area & l, const Area & r); //AreaL reduced by tiles from AreaR
 		friend bool operator== (const Area & l, const Area & r);
-		friend std::list<Area> connectedAreas(const Area & area);
+		friend std::list<Area> connectedAreas(const Area & area, bool disableDiagonalConnections);
 		
 	private:
 		

+ 2 - 5
lib/rmg/RmgMap.cpp

@@ -30,9 +30,6 @@
 #include "Functions.h"
 #include "CMapGenerator.h"
 
-static const int3 dirs4[] = {int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0)};
-static const int3 dirsDiagonal[] = { int3(1,1,0),int3(1,-1,0),int3(-1,1,0),int3(-1,-1,0) };
-
 RmgMap::RmgMap(const CMapGenOptions& mapGenOptions) :
 	mapGenOptions(mapGenOptions), zonesTotal(0)
 {
@@ -54,7 +51,7 @@ void RmgMap::foreach_neighbour(const int3 &pos, std::function<void(int3& pos)> f
 
 void RmgMap::foreachDirectNeighbour(const int3& pos, std::function<void(int3& pos)> foo)
 {
-	for(const int3 &dir : dirs4)
+	for(const int3 &dir : rmg::dirs4)
 	{
 		int3 n = pos + dir;
 		if(mapInstance->isInTheMap(n))
@@ -64,7 +61,7 @@ void RmgMap::foreachDirectNeighbour(const int3& pos, std::function<void(int3& po
 
 void RmgMap::foreachDiagonalNeighbour(const int3& pos, std::function<void(int3& pos)> foo)
 {
-	for (const int3 &dir : dirsDiagonal)
+	for (const int3 &dir : rmg::dirsDiagonal)
 	{
 		int3 n = pos + dir;
 		if (mapInstance->isInTheMap(n))

+ 1 - 1
lib/rmg/RmgPath.cpp

@@ -137,7 +137,7 @@ Path Path::search(const Tileset & dst, bool straight, std::function<float(const
 			auto dirs = int3::getDirs();
 			std::vector<int3> neighbors(dirs.begin(), dirs.end());
 			if(straight)
-				neighbors = { { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0) } };
+				neighbors.assign(rmg::dirs4.begin(), rmg::dirs4.end());
 			for(auto & i : neighbors)
 			{
 				computeTileScore(currentNode + i);

+ 4 - 1
lib/rmg/TreasurePlacer.cpp

@@ -715,7 +715,10 @@ void TreasurePlacer::createTreasures(ObjectManager & manager)
 		{
 			auto treasurePileInfos = prepareTreasurePile(t);
 			if(treasurePileInfos.empty())
-				break;
+			{
+				++attempt;
+				continue;
+			}
 			
 			int value = std::accumulate(treasurePileInfos.begin(), treasurePileInfos.end(), 0, [](int v, const ObjectInfo * oi){return v + oi->value;});
 			

+ 2 - 1
lib/rmg/WaterProxy.cpp

@@ -93,7 +93,7 @@ const std::vector<WaterProxy::Lake> & WaterProxy::getLakes() const
 void WaterProxy::collectLakes()
 {
 	int lakeId = 0;
-	for(auto lake : connectedAreas(zone.getArea()))
+	for(auto lake : connectedAreas(zone.getArea(), true))
 	{
 		lakes.push_back(Lake{});
 		lakes.back().area = lake;
@@ -267,6 +267,7 @@ bool WaterProxy::placeShipyard(Zone & land, const Lake & lake, si32 guard, Route
 	bool guarded = manager->addGuard(rmgObject, guard);
 	
 	auto waterAvailable = zone.areaPossible() + zone.freePaths();
+	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
 	auto boardingPositions = coast.getSubarea([&waterAvailable](const int3 & tile) //tiles where boarding is possible

+ 3 - 0
lib/rmg/WaterRoutes.cpp

@@ -34,6 +34,9 @@ void WaterRoutes::process()
 	if(!wproxy)
 		return;
 	
+	if(auto * manager = zone.getModificator<ObjectManager>())
+		manager->createDistancesPriorityQueue();
+	
 	for(auto & z : map.getZones())
 	{
 		if(z.first != zone.getId())

+ 2 - 2
lib/rmg/Zone.cpp

@@ -159,7 +159,7 @@ rmg::Path Zone::searchPath(const rmg::Area & src, bool onlyStraight, std::functi
 	freePath.connect(dAreaFree);
 	
 	//connect to all pieces
-	auto goals = connectedAreas(src);
+	auto goals = connectedAreas(src, onlyStraight);
 	for(auto & goal : goals)
 	{
 		auto path = freePath.search(goal, onlyStraight, movementCost);
@@ -235,7 +235,7 @@ void Zone::fractalize()
 	}
 	
 	//cut straight paths towards the center. A* is too slow for that.
-	auto areas = connectedAreas(clearedTiles);
+	auto areas = connectedAreas(clearedTiles, false);
 	for(auto & area : areas)
 	{
 		if(dAreaFree.overlap(area))