Browse Source

Wood & ore mines will be placed close to zone center.

DjWarmonger 11 years ago
parent
commit
fee2184996
2 changed files with 76 additions and 19 deletions
  1. 72 19
      lib/rmg/CRmgTemplateZone.cpp
  2. 4 0
      lib/rmg/CRmgTemplateZone.h

+ 72 - 19
lib/rmg/CRmgTemplateZone.cpp

@@ -605,6 +605,10 @@ void CRmgTemplateZone::addRequiredObject(CGObjectInstance * obj, si32 strength)
 {
 	requiredObjects.push_back(std::make_pair(obj, strength));
 }
+void CRmgTemplateZone::addCloseObject(CGObjectInstance * obj, si32 strength)
+{
+	closeObjects.push_back(std::make_pair(obj, strength));
+}
 
 bool CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength, bool clearSurroundingTiles, bool zoneGuard)
 {
@@ -1109,11 +1113,8 @@ bool CRmgTemplateZone::placeMines (CMapGenerator* gen)
 	static const Res::ERes woodOre[] = {Res::ERes::WOOD, Res::ERes::ORE};
 	static const Res::ERes preciousResources[] = {Res::ERes::GEMS, Res::ERes::CRYSTAL, Res::ERes::MERCURY, Res::ERes::SULFUR};
 
-
-	//TODO: factory / copy constructor?
 	for (const auto & res : woodOre)
 	{
-		//TODO: these 2 should be close to town (within 12 tiles radius)
 		for (int i = 0; i < mines[res]; i++)
 		{
 			auto mine = new CGMine();
@@ -1121,7 +1122,7 @@ bool CRmgTemplateZone::placeMines (CMapGenerator* gen)
 			mine->subID = static_cast<si32>(res);
 			mine->producedResource = res;
 			mine->producedQuantity = mine->defaultResProduction();
-			addRequiredObject(mine, 1500);
+			addCloseObject(mine, 1500);
 		}
 	}
 	for (const auto & res : preciousResources)
@@ -1166,6 +1167,49 @@ bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
 		guardObject (gen, obj.first, obj.second, (obj.first->ID == Obj::MONOLITH_TWO_WAY), true);
 		//paths to required objects constitute main paths of zone. otherwise they just may lead to middle and create dead zones
 	}
+
+	for (const auto &obj : closeObjects)
+	{
+		std::vector<int3> tiles(possibleTiles.begin(), possibleTiles.end()); //new tiles vector after each object has been placed
+		
+		// smallest distance to zone center, greatest distance to nearest object
+		auto isCloser = [this, gen](const int3 & lhs, const int3 & rhs) -> bool
+		{
+			return (this->pos.dist2dSQ(lhs) * 0.5f - gen->getNearestObjectDistance(lhs)) < (this->pos.dist2dSQ(rhs) * 0.5f - gen->getNearestObjectDistance(rhs));
+		};
+
+		boost::sort (tiles, isCloser);
+
+		setTemplateForObject(gen, obj.first);
+		auto tilesBlockedByObject = obj.first->getBlockedOffsets();
+		bool result = false;
+
+		for (auto tile : tiles)
+		{
+			//object must be accessible from at least one surounding tile
+			if (!isAccessibleFromAnywhere(gen, obj.first->appearance, tile, tilesBlockedByObject))
+				continue;
+
+			//avoid borders
+			if (gen->isPossible(tile))
+			{
+				if (areAllTilesAvailable(gen, obj.first, tile, tilesBlockedByObject))
+				{
+					placeObject(gen, obj.first, tile);
+					guardObject(gen, obj.first, obj.second, (obj.first->ID == Obj::MONOLITH_TWO_WAY), true);
+					result = true;
+					break;
+				}
+			}
+		}
+		if (!result)
+		{
+			logGlobal->errorStream() << boost::format("Failed to fill zone %d due to lack of space") % id;
+			//TODO CLEANUP!
+			return false;
+		}
+	}
+
 	return true;
 }
 
@@ -1441,17 +1485,36 @@ bool CRmgTemplateZone::isAccessibleFromAnywhere (CMapGenerator* gen, ObjectTempl
 	return accessible;
 }
 
-bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos)
+void CRmgTemplateZone::setTemplateForObject(CMapGenerator* gen, CGObjectInstance* obj)
 {
-	//we need object apperance to deduce free tiles
 	if (obj->appearance.id == Obj::NO_OBJ)
 	{
 		auto templates = VLC->objtypeh->getHandlerFor(obj->ID, obj->subID)->getTemplates(gen->map->getTile(getPos()).terType);
 		if (templates.empty())
-			throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s") %obj->ID %obj->subID %pos));
-	
+			throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s") % obj->ID %obj->subID %pos));
+
 		obj->appearance = templates.front();
 	}
+}
+
+bool CRmgTemplateZone::areAllTilesAvailable(CMapGenerator* gen, CGObjectInstance* obj, int3& tile, std::set<int3>& tilesBlockedByObject) const
+{
+	for (auto blockingTile : tilesBlockedByObject)
+	{
+		int3 t = tile + blockingTile;
+		if (!gen->map->isInTheMap(t) || !gen->isPossible(t))
+		{
+			//if at least one tile is not possible, object can't be placed here
+			return false;
+		}
+	}
+	return true;
+}
+
+bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos)
+{
+	//we need object apperance to deduce free tile
+	setTemplateForObject(gen, obj);
 
 	//si32 min_dist = sqrt(tileinfo.size()/density);
 	int best_distance = 0;
@@ -1474,17 +1537,7 @@ bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance*
 		//avoid borders
 		if (gen->isPossible(tile) && (dist >= min_dist) && (dist > best_distance))
 		{
-			bool allTilesAvailable = true;
-			for (auto blockingTile : tilesBlockedByObject)
-			{
-				int3 t = tile + blockingTile;
-				if (!gen->map->isInTheMap(t) || !gen->isPossible(t))
-				{
-					allTilesAvailable = false; //if at least one tile is not possible, object can't be placed here
-					break;
-				}
-			}
-			if (allTilesAvailable)
+			if (areAllTilesAvailable(gen, obj, tile, tilesBlockedByObject))
 			{
 				best_distance = dist;
 				pos = tile;

+ 4 - 0
lib/rmg/CRmgTemplateZone.h

@@ -150,6 +150,7 @@ public:
 	void discardDistantTiles (CMapGenerator* gen, float distance);
 
 	void addRequiredObject(CGObjectInstance * obj, si32 guardStrength=0);
+	void addCloseObject(CGObjectInstance * obj, si32 guardStrength = 0);
 	bool addMonster(CMapGenerator* gen, int3 &pos, si32 strength, bool clearSurroundingTiles = true, bool zoneGuard = false);
 	bool createTreasurePile(CMapGenerator* gen, int3 &pos, float minDistance, const CTreasureInfo& treasureInfo);
 	bool fill (CMapGenerator* gen);
@@ -198,6 +199,7 @@ private:
 
 	//content info
 	std::vector<std::pair<CGObjectInstance*, ui32>> requiredObjects;
+	std::vector<std::pair<CGObjectInstance*, ui32>> closeObjects;
 	std::vector<CGObjectInstance*> objects;
 
 	//placement info
@@ -214,6 +216,8 @@ private:
 	bool findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos);
 	bool findPlaceForTreasurePile(CMapGenerator* gen, float min_dist, int3 &pos);
 	bool canObstacleBePlacedHere(CMapGenerator* gen, ObjectTemplate &temp, int3 &pos);
+	void setTemplateForObject(CMapGenerator* gen, CGObjectInstance* obj);
+	bool areAllTilesAvailable(CMapGenerator* gen, CGObjectInstance* obj, int3& tile, std::set<int3>& tilesBlockedByObject) const;
 	void checkAndPlaceObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos);
 	void placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos, bool updateDistance = true);
 	bool guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str, bool zoneGuard = false, bool addToFreePaths = false);