Browse Source

- Check full object area for minimum distance requirement
- Add option to optimize both for max distance and custom weight

Tomasz Zieliński 1 year ago
parent
commit
e5f60f063c

+ 8 - 7
lib/rmg/modificators/ObjectManager.cpp

@@ -238,15 +238,14 @@ rmg::Path ObjectManager::placeAndConnectObject(const rmg::Area & searchArea, rmg
 	RecursiveLock lock(externalAccessMutex);
 	RecursiveLock lock(externalAccessMutex);
 	return placeAndConnectObject(searchArea, obj, [this, min_dist, &obj](const int3 & tile)
 	return placeAndConnectObject(searchArea, obj, [this, min_dist, &obj](const int3 & tile)
 	{
 	{
-		auto ti = map.getTileInfo(tile);
-		float dist = ti.getNearestObjectDistance();
-		if(dist < min_dist)
-			return -1.f;
-
+		float bestDistance = 10e9;
 		for(const auto & t : obj.getArea().getTilesVector())
 		for(const auto & t : obj.getArea().getTilesVector())
 		{
 		{
-			if(map.getTileInfo(t).getNearestObjectDistance() < min_dist)
+			float distance = map.getTileInfo(t).getNearestObjectDistance();
+			if(distance < min_dist)
 				return -1.f;
 				return -1.f;
+			else
+				vstd::amin(bestDistance, distance);
 		}
 		}
 		
 		
 		rmg::Area perimeter;
 		rmg::Area perimeter;
@@ -298,7 +297,7 @@ rmg::Path ObjectManager::placeAndConnectObject(const rmg::Area & searchArea, rmg
 			}
 			}
 		}
 		}
 		
 		
-		return dist;
+		return bestDistance;
 	}, isGuarded, onlyStraight, optimizer);
 	}, isGuarded, onlyStraight, optimizer);
 }
 }
 
 
@@ -513,6 +512,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
 			if(map.isOnMap(i) && map.isPossible(i))
 			if(map.isOnMap(i) && map.isPossible(i))
 				map.setOccupied(i, ETileType::BLOCKED);
 				map.setOccupied(i, ETileType::BLOCKED);
 	}
 	}
+	lock.unlock();
 	
 	
 	if (updateDistance)
 	if (updateDistance)
 	{
 	{
@@ -535,6 +535,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
 			auto manager = map.getZones().at(id)->getModificator<ObjectManager>();
 			auto manager = map.getZones().at(id)->getModificator<ObjectManager>();
 			if (manager)
 			if (manager)
 			{
 			{
+				// TODO: Update distances for perimeter of guarded object, not just treasures
 				manager->updateDistances(object);
 				manager->updateDistances(object);
 			}
 			}
 		}
 		}

+ 2 - 1
lib/rmg/modificators/ObjectManager.h

@@ -48,7 +48,8 @@ public:
 	{
 	{
 		NONE = 0x00000000,
 		NONE = 0x00000000,
 		WEIGHT = 0x00000001,
 		WEIGHT = 0x00000001,
-		DISTANCE = 0x00000010
+		DISTANCE = 0x00000010,
+		BOTH = 0x00000011
 	};
 	};
 
 
 public:
 public:

+ 52 - 46
lib/rmg/modificators/TreasurePlacer.cpp

@@ -837,7 +837,7 @@ void TreasurePlacer::createTreasures(ObjectManager& manager)
 			int value = std::accumulate(treasurePileInfos.begin(), treasurePileInfos.end(), 0, [](int v, const ObjectInfo* oi) {return v + oi->value; });
 			int value = std::accumulate(treasurePileInfos.begin(), treasurePileInfos.end(), 0, [](int v, const ObjectInfo* oi) {return v + oi->value; });
 
 
 			const ui32 maxPileGenerationAttemps = 2;
 			const ui32 maxPileGenerationAttemps = 2;
-			for (ui32 attempt = 0; attempt <= maxPileGenerationAttemps; attempt++)
+			for (ui32 attempt = 0; attempt < maxPileGenerationAttemps; attempt++)
 			{
 			{
 				auto rmgObject = constructTreasurePile(treasurePileInfos, attempt == maxAttempts);
 				auto rmgObject = constructTreasurePile(treasurePileInfos, attempt == maxAttempts);
 
 
@@ -865,61 +865,67 @@ void TreasurePlacer::createTreasures(ObjectManager& manager)
 		{
 		{
 			const bool guarded = rmgObject.isGuarded();
 			const bool guarded = rmgObject.isGuarded();
 
 
-			for (int attempt = 0; attempt <= maxAttempts;)
-			{
-				auto path = rmg::Path::invalid();
+			auto path = rmg::Path::invalid();
 
 
-				Zone::Lock lock(zone.areaMutex); //We are going to subtract this area
-				auto possibleArea = zone.areaPossible();
+			Zone::Lock lock(zone.areaMutex); //We are going to subtract this area
+			auto possibleArea = zone.areaPossible();
+			possibleArea.erase_if([this, &minDistance](const int3& tile) -> bool
+			{
+				auto ti = map.getTileInfo(tile);
+				return (ti.getNearestObjectDistance() < minDistance);
+			});
 
 
-				if (guarded)
-				{
-					path = manager.placeAndConnectObject(possibleArea, rmgObject, [this, &rmgObject, &minDistance, &manager](const int3& tile)
+			if (guarded)
+			{
+				path = manager.placeAndConnectObject(possibleArea, rmgObject, [this, &rmgObject, &minDistance, &manager](const int3& tile)
+					{
+						float bestDistance = 10e9;
+						for (const auto& t : rmgObject.getArea().getTilesVector())
 						{
 						{
-							auto ti = map.getTileInfo(tile);
-							if (ti.getNearestObjectDistance() < minDistance)
-								return -1.f;
-
-							for (const auto& t : rmgObject.getArea().getTilesVector())
-							{
-								if (map.getTileInfo(t).getNearestObjectDistance() < minDistance)
-									return -1.f;
-							}
-
-							auto guardedArea = rmgObject.instances().back()->getAccessibleArea();
-							auto areaToBlock = rmgObject.getAccessibleArea(true);
-							areaToBlock.subtract(guardedArea);
-							if (areaToBlock.overlap(zone.freePaths()) || areaToBlock.overlap(manager.getVisitableArea()))
+							float distance = map.getTileInfo(t).getNearestObjectDistance();
+							if (distance < minDistance)
 								return -1.f;
 								return -1.f;
+							else
+								vstd::amin(bestDistance, distance);
+						}
 
 
-							return ti.getNearestObjectDistance();
-						}, guarded, false, ObjectManager::OptimizeType::DISTANCE);
-				}
-				else
-				{
-					path = manager.placeAndConnectObject(possibleArea, rmgObject, minDistance, guarded, false, ObjectManager::OptimizeType::DISTANCE);
-				}
-
-				if (path.valid())
-				{
-					//debug purposes
-					treasureArea.unite(rmgObject.getArea());
-					if (guarded)
-					{
-						guards.unite(rmgObject.instances().back()->getBlockedArea());
 						auto guardedArea = rmgObject.instances().back()->getAccessibleArea();
 						auto guardedArea = rmgObject.instances().back()->getAccessibleArea();
 						auto areaToBlock = rmgObject.getAccessibleArea(true);
 						auto areaToBlock = rmgObject.getAccessibleArea(true);
 						areaToBlock.subtract(guardedArea);
 						areaToBlock.subtract(guardedArea);
-						treasureBlockArea.unite(areaToBlock);
-					}
-					zone.connectPath(path);
-					manager.placeObject(rmgObject, guarded, true);
-					break;
-				}
-				else
+
+						// TODO: Does it help?
+						areaToBlock.erase_if([this](const int3& tile) -> bool
+						{
+							//Don't block tiles outside the map
+							return (!map.isOnMap(tile));
+						});
+
+						if (areaToBlock.overlap(zone.freePaths()) || areaToBlock.overlap(manager.getVisitableArea()))
+							return -1.f;
+
+						return bestDistance;
+					}, guarded, false, ObjectManager::OptimizeType::BOTH);
+			}
+			else
+			{
+				path = manager.placeAndConnectObject(possibleArea, rmgObject, minDistance, guarded, false, ObjectManager::OptimizeType::DISTANCE);
+			}
+			lock.unlock();
+
+			if (path.valid())
+			{
+				//debug purposes
+				treasureArea.unite(rmgObject.getArea());
+				if (guarded)
 				{
 				{
-					++attempt;
+					guards.unite(rmgObject.instances().back()->getBlockedArea());
+					auto guardedArea = rmgObject.instances().back()->getAccessibleArea();
+					auto areaToBlock = rmgObject.getAccessibleArea(true);
+					areaToBlock.subtract(guardedArea);
+					treasureBlockArea.unite(areaToBlock);
 				}
 				}
+				zone.connectPath(path);
+				manager.placeObject(rmgObject, guarded, true);
 			}
 			}
 		}
 		}
 	}
 	}