Explorar o código

Ground connections between adjacent zones.

DjWarmonger %!s(int64=11) %!d(string=hai) anos
pai
achega
8e8b27087a

+ 15 - 0
lib/CObjectHandler.cpp

@@ -350,6 +350,21 @@ std::set<int3> CGObjectInstance::getBlockedPos() const
 	return ret;
 }
 
+std::set<int3> CGObjectInstance::getBlockedOffsets() const
+{
+	std::set<int3> ret;
+	for(int w=0; w<getWidth(); ++w)
+	{
+		for(int h=0; h<getHeight(); ++h)
+		{
+			if (appearance.isBlockedAt(w, h))
+				ret.insert(int3(-w, -h, 0));
+		}
+	}
+	return ret;
+}
+
+
 bool CGObjectInstance::operator<(const CGObjectInstance & cmp) const  //screen printing priority comparing
 {
 	if (appearance.printPriority != cmp.appearance.printPriority)

+ 1 - 0
lib/CObjectHandler.h

@@ -227,6 +227,7 @@ public:
 	bool blockingAt(int x, int y) const; //returns true if object is blocking location (x, y) (h3m pos)
 	bool coveringAt(int x, int y) const; //returns true if object covers with picture location (x, y) (h3m pos)
 	std::set<int3> getBlockedPos() const; //returns set of positions blocked by this object
+	std::set<int3> getBlockedOffsets() const; //returns set of relative positions blocked by this object
 	bool isVisitable() const; //returns true if object is visitable
 	bool operator<(const CGObjectInstance & cmp) const;  //screen printing priority comparing
 	void hideTiles(PlayerColor ourplayer, int radius) const;

+ 7 - 9
lib/rmg/CMapGenerator.cpp

@@ -207,14 +207,6 @@ void CMapGenerator::genZones()
 	for(auto const it : zones)
 	{
 		CRmgTemplateZone * zone = it.second;
-		std::vector<int3> shape;
-		int left = part_w*(i%player_per_side);
-		int top = part_h*(i/player_per_side);
-		shape.push_back(int3(left, top,  0));
-		shape.push_back(int3(left + part_w, top,  0));
-		shape.push_back(int3(left + part_w, top + part_h,  0));
-		shape.push_back(int3(left, top + part_h,  0));
-		zone->setShape(shape);
 		zone->setType(i < pcnt ? ETemplateZoneType::PLAYER_START : ETemplateZoneType::TREASURE);
 		this->zones[it.first] = zone;
 		++i;
@@ -225,8 +217,14 @@ void CMapGenerator::genZones()
 void CMapGenerator::fillZones()
 {	
 	logGlobal->infoStream() << "Started filling zones";
-	for(auto it : zones)
+
+	for (auto it : zones)
+	{
+		it.second->createConnections(this);
+	}
+	for (auto it : zones)
 	{
+		//make sure all connections are passable before creating borders
 		it.second->createBorder(this);
 		it.second->fill(this);
 	}	

+ 125 - 10
lib/rmg/CRmgTemplateZone.cpp

@@ -297,11 +297,6 @@ bool CRmgTemplateZone::pointIsIn(int x, int y)
 	return true;
 }
 
-void CRmgTemplateZone::setShape(std::vector<int3> shape)
-{
-	this->shape = shape;
-}
-
 int3 CRmgTemplateZone::getPos() const
 {
 	return pos;
@@ -316,6 +311,44 @@ void CRmgTemplateZone::addTile (const int3 &pos)
 	tileinfo.insert(pos);
 }
 
+std::set<int3> CRmgTemplateZone::getTileInfo () const
+{
+	return tileinfo;
+}
+
+void CRmgTemplateZone::createConnections(CMapGenerator* gen)
+{
+	for (auto connection : connections)
+	{
+		if (getId() > connection) //only one connection between each pair
+			continue;
+
+		int3 guardPos(-1,-1,-1);
+
+		auto otherZoneTiles = gen->getZones()[connection]->getTileInfo();
+		auto otherZoneCenter = gen->getZones()[connection]->getPos();
+
+		for (auto tile : tileinfo)
+		{
+			gen->foreach_neighbour (tile, [&guardPos, tile, &otherZoneTiles](int3 &pos)
+			{
+				if (vstd::contains(otherZoneTiles, pos))
+					guardPos = tile;
+			});
+			if (guardPos.valid())
+			{
+				gen->setOccupied (pos, ETileType::FREE); //TODO: place monster here
+				//zones can make paths only in their own area
+				this->crunchPath (gen, guardPos, this->getPos(), this->getId()); //make connection towards our zone center
+				gen->getZones()[connection]->crunchPath (gen, guardPos, otherZoneCenter, connection); //make connection towards other zone center
+				break; //we're done with this connection
+			}
+		}
+		if (!guardPos.valid())
+			logGlobal->warnStream() << boost::format ("Did not find connection between zones %d and %d") %getId() %connection;
+	}
+}
+
 void CRmgTemplateZone::createBorder(CMapGenerator* gen)
 {
 	for (auto tile : tileinfo)
@@ -323,11 +356,78 @@ void CRmgTemplateZone::createBorder(CMapGenerator* gen)
 		gen->foreach_neighbour (tile, [this, gen](int3 &pos)
 		{
 			if (!vstd::contains(this->tileinfo, pos))
-				gen->setOccupied (pos, ETileType::BLOCKED);
+			{
+				gen->foreach_neighbour (pos, [this, gen](int3 &pos)
+				{
+					if (gen->isPossible(pos))
+						gen->setOccupied (pos, ETileType::BLOCKED);
+				});
+			}
 		});
 	}
 }
 
+bool CRmgTemplateZone::crunchPath (CMapGenerator* gen, int3 &src, int3 &dst, TRmgTemplateZoneId zone)
+{
+/*
+make shortest path with free tiles, reachning dst or closest already free tile. Avoid blocks.
+do not leave zone border
+*/
+	bool result = false;
+	bool end = false;
+
+	int3 currentPos = src;
+	float distance = currentPos.dist2dSQ (dst);
+
+	while (!end)
+	{
+		if (currentPos == dst)
+			break;
+
+		auto lastDistance = distance;
+		gen->foreach_neighbour (currentPos, [this, gen, &currentPos, dst, &distance, &result, &end](int3 &pos)
+		{
+			if (!result) //not sure if lambda is worth it...
+			{
+				if (pos == dst)
+				{
+					result = true;
+					end = true;
+				}
+				if (pos.dist2dSQ (dst) < distance)
+				{
+					if (!gen->isBlocked(pos))
+					{
+						if (vstd::contains (tileinfo, pos))
+						{
+							if (gen->isPossible(pos))
+							{
+								gen->setOccupied (pos, ETileType::FREE);
+								currentPos = pos;
+								distance = currentPos.dist2dSQ (dst);
+							}
+							else if (gen->isFree(pos))
+							{
+								end = true;
+								result = true;
+							}
+							else
+								throw rmgException(boost::to_string(boost::format("Tile %s of uknown type found on path") % pos()));
+						}
+					}
+				}
+			}
+		});
+		if (!(result || distance < lastDistance)) //we do not advance, use more avdnaced pathfinding algorithm?
+		{
+			logGlobal->warnStream() << boost::format ("No tile closer than %s found on path from %s to %s") %currentPos %src %dst;
+			break;
+		}
+	}
+
+	return result;
+}
+
 bool CRmgTemplateZone::fill(CMapGenerator* gen)
 {
 	std::vector<CGObjectInstance*> required_objects;
@@ -486,12 +586,27 @@ bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance*
 			continue;
 		if (gen->isPossible(tile) && (dist >= min_dist) && (dist > best_distance))
 		{
-			best_distance = dist;
-			pos = tile;
-			gen->setOccupied(pos, ETileType::BLOCKED);
-			result = true;
+			bool allTilesAvailable = true;
+			for (auto blockingTile : obj->getBlockedOffsets())
+			{
+				if (!gen->isPossible(pos + blockingTile))
+				{
+					allTilesAvailable = false; //if at least one tile is not possible, object can't be placed here
+					break;
+				}
+			}
+			if (allTilesAvailable)
+			{
+				best_distance = dist;
+				pos = tile;
+				result = true;
+			}
 		}
 	}
+	if (result)
+	{
+		gen->setOccupied(pos, ETileType::BLOCKED); //block that tile
+	}
 	return result;
 }
 

+ 4 - 1
lib/rmg/CRmgTemplateZone.h

@@ -110,9 +110,12 @@ public:
 	void setPos(const int3 &pos);
 
 	void addTile (const int3 &pos);
-	void setShape(std::vector<int3> shape);
+	std::set<int3> getTileInfo () const;
+
 	bool fill(CMapGenerator* gen);
+	void createConnections(CMapGenerator* gen);
 	void createBorder(CMapGenerator* gen);
+	bool crunchPath (CMapGenerator* gen, int3 &src, int3 &dst, TRmgTemplateZoneId zone);
 
 	void addConnection(TRmgTemplateZoneId otherZone);
 	std::vector<TRmgTemplateZoneId> getConnections() const;