Przeglądaj źródła

more sensible road placement

AlexVinS 10 lat temu
rodzic
commit
eb60d9737f

+ 14 - 2
lib/rmg/CMapGenerator.cpp

@@ -13,6 +13,8 @@
 #include "CZonePlacer.h"
 #include "../mapObjects/CObjectClassesHandler.h"
 
+static const int3 dirs4[] = {int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0)};
+
 void CMapGenerator::foreach_neighbour(const int3 &pos, std::function<void(int3& pos)> foo)
 {
 	for(const int3 &dir : dirs)
@@ -23,6 +25,16 @@ void CMapGenerator::foreach_neighbour(const int3 &pos, std::function<void(int3&
 	}
 }
 
+void CMapGenerator::foreachDirectNeighbour(const int3& pos, std::function<void(int3& pos)> foo)
+{
+	for(const int3 &dir : dirs4)
+	{
+		int3 n = pos + dir;
+		if(map->isInTheMap(n))
+			foo(n);
+	}	
+}
+
 
 CMapGenerator::CMapGenerator() :
     zonesTotal(0), monolithIndex(0)
@@ -421,8 +433,8 @@ void CMapGenerator::createConnections()
 					setOccupied (guardPos, ETileType::FREE); //just in case monster is too weak to spawn
 					zoneA->addMonster (this, guardPos, connection.getGuardStrength(), false, true);
 					//zones can make paths only in their own area
-					zoneA->crunchPath (this, guardPos, posA, zoneA->getId(), zoneA->getFreePaths()); //make connection towards our zone center
-					zoneB->crunchPath (this, guardPos, posB, zoneB->getId(), zoneB->getFreePaths()); //make connection towards other zone center
+					zoneA->crunchRoad(this, guardPos, posA, zoneA->getFreePaths()); //make connection towards our zone center
+					zoneB->crunchRoad(this, guardPos, posB, zoneB->getFreePaths()); //make connection towards other zone center
 					break; //we're done with this connection
 				}
 			}

+ 1 - 0
lib/rmg/CMapGenerator.h

@@ -66,6 +66,7 @@ public:
 	void createConnections();
 	void findZonesForQuestArts();
 	void foreach_neighbour(const int3 &pos, std::function<void(int3& pos)> foo);
+	void foreachDirectNeighbour(const int3 &pos, std::function<void(int3& pos)> foo);
 
 	bool isBlocked(const int3 &tile) const;
 	bool shouldBeBlocked(const int3 &tile) const;

+ 59 - 10
lib/rmg/CRmgTemplateZone.cpp

@@ -575,7 +575,7 @@ void CRmgTemplateZone::fractalize(CMapGenerator* gen)
 	//logGlobal->infoStream() << boost::format ("Zone %d subdivided fractally") %id;
 }
 
-bool CRmgTemplateZone::crunchPath (CMapGenerator* gen, const int3 &src, const int3 &dst, TRmgTemplateZoneId zone, std::set<int3>* clearedTiles)
+bool CRmgTemplateZone::crunchPath(CMapGenerator* gen, const int3 &src, const int3 &dst, std::set<int3>* clearedTiles, bool forRoad)
 {
 /*
 make shortest path with free tiles, reachning dst or closest already free tile. Avoid blocks.
@@ -596,7 +596,8 @@ do not leave zone border
 		}
 
 		auto lastDistance = distance;
-		gen->foreach_neighbour (currentPos, [this, gen, &currentPos, dst, &distance, &result, &end, clearedTiles](int3 &pos)
+			
+		auto processNeighbours = [this, gen, &currentPos, dst, &distance, &result, &end, clearedTiles](int3 &pos)
 		{
 			if (!result) //not sure if lambda is worth it...
 			{
@@ -628,15 +629,21 @@ do not leave zone border
 					}
 				}
 			}
-		});
-
+		};
+		
+		if(forRoad)
+			gen->foreachDirectNeighbour(currentPos,processNeighbours);
+		else
+			gen->foreach_neighbour (currentPos,processNeighbours);
+						
 		int3 anotherPos(-1, -1, -1);
 
-		if (!(result || distance < lastDistance)) //we do not advance, use more advaced pathfinding algorithm?
+		if (!(result || distance < lastDistance)) //we do not advance, use more advanced pathfinding algorithm?
 		{
 			//try any nearby tiles, even if its not closer than current
 			float lastDistance = 2 * distance; //start with significantly larger value
-			gen->foreach_neighbour(currentPos, [this, gen, &currentPos, dst, &lastDistance, &anotherPos, &end, clearedTiles](int3 &pos)
+			
+			auto processNeighbours2 = [this, gen, &currentPos, dst, &lastDistance, &anotherPos, &end, clearedTiles](int3 &pos)
 			{
 				if (currentPos.dist2dSQ(dst) < lastDistance) //try closest tiles from all surrounding unused tiles
 				{
@@ -651,7 +658,14 @@ do not leave zone border
 						}
 					}
 				}
-			});
+			};			
+		
+			if(forRoad)
+				gen->foreachDirectNeighbour(currentPos,processNeighbours2);
+			else
+				gen->foreach_neighbour (currentPos,processNeighbours2);
+						
+			
 			if (anotherPos.valid())
 			{
 				if (clearedTiles)
@@ -671,6 +685,26 @@ do not leave zone border
 	return result;
 }
 
+bool CRmgTemplateZone::crunchRoad(CMapGenerator* gen, const int3& src, const int3& dst, std::set<int3>* clearedTiles)
+{
+	std::set<int3> currentClearedTiles;
+	
+	if(crunchPath(gen, src, dst, &currentClearedTiles, true))
+	{
+		roads.insert(std::begin(currentClearedTiles), std::end(currentClearedTiles));		
+		
+		if(nullptr != clearedTiles)
+			clearedTiles->insert(std::begin(currentClearedTiles), std::end(currentClearedTiles));
+		
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+
 void CRmgTemplateZone::addRequiredObject(CGObjectInstance * obj, si32 strength)
 {
 	requiredObjects.push_back(std::make_pair(obj, strength));
@@ -904,7 +938,7 @@ bool CRmgTemplateZone::createTreasurePile(CMapGenerator* gen, int3 &pos, float m
 				gen->setOccupied(tile, ETileType::BLOCKED); //so that crunch path doesn't cut through objects
 		}
 
-		if (!crunchPath (gen, closestTile, closestFreeTile, id))
+		if (!crunchPath (gen, closestTile, closestFreeTile))
 		{
 			//we can't connect this pile, just block it off and start over
 			for (auto treasure : treasures)
@@ -1239,7 +1273,22 @@ bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
 			logGlobal->errorStream() << boost::format("Failed to fill zone %d due to lack of space") %id;
 			//TODO CLEANUP!
 			return false;
+		}		
+	
+		switch (obj.first->ID)
+		{
+		case Obj::TOWN:
+		case Obj::MONOLITH_TWO_WAY:
+		case Obj::SUBTERRANEAN_GATE:
+			{
+				crunchRoad(gen, this->pos, pos + obj.first->getVisitableOffset(), &freePaths);				
+			}
+			break;
+		
+		default:
+			break;
 		}
+		
 
 		placeObject (gen, obj.first, pos);
 		guardObject (gen, obj.first, obj.second, (obj.first->ID == Obj::MONOLITH_TWO_WAY), true);
@@ -1434,7 +1483,7 @@ void CRmgTemplateZone::createObstacles2(CMapGenerator* gen)
 void CRmgTemplateZone::drawRoads(CMapGenerator* gen)
 {
 	std::vector<int3> tiles;
-	for (auto tile : freePaths)
+	for (auto tile : roads)
 	{
 		tiles.push_back (tile);
 	}
@@ -1715,7 +1764,7 @@ bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object,
 	{
 		//crunching path may fail if center of the zone is directly over wide object
 		//make sure object is accessible before surrounding it with blocked tiles
-		if (crunchPath (gen, tile, findClosestTile(freePaths, tile), id, addToFreePaths ? &freePaths : nullptr))
+		if (crunchPath (gen, tile, findClosestTile(freePaths, tile), addToFreePaths ? &freePaths : nullptr))
 		{
 			guardTile = tile;
 			break;

+ 4 - 1
lib/rmg/CRmgTemplateZone.h

@@ -167,7 +167,8 @@ public:
 	void createTreasures(CMapGenerator* gen);
 	void createObstacles1(CMapGenerator* gen);
 	void createObstacles2(CMapGenerator* gen);
-	bool crunchPath (CMapGenerator* gen, const int3 &src, const int3 &dst, TRmgTemplateZoneId zone, std::set<int3>* clearedTiles = nullptr);
+	bool crunchPath(CMapGenerator* gen, const int3 &src, const int3 &dst, std::set<int3>* clearedTiles = nullptr, bool forRoad = false);
+	bool crunchRoad(CMapGenerator* gen, const int3 &src, const int3 &dst, std::set<int3>* clearedTiles = nullptr);
 	std::vector<int3> getAccessibleOffsets (CMapGenerator* gen, CGObjectInstance* object);
 
 	void addConnection(TRmgTemplateZoneId otherZone);
@@ -217,6 +218,8 @@ private:
 	std::vector<TRmgTemplateZoneId> connections; //list of adjacent zones
 	std::set<int3> freePaths; //core paths of free tiles that all other objects will be linked to
 	
+	std::set<int3> roads;
+	
 	void drawRoads(CMapGenerator* gen);
 
 	bool pointIsIn(int x, int y);