Browse Source

Definitive solution for Corpse

Tomasz Zieliński 1 year ago
parent
commit
d5f9de5beb

+ 24 - 6
lib/rmg/RmgObject.cpp

@@ -313,6 +313,19 @@ const rmg::Area & Object::getRemovableArea() const
 	return dRemovableAreaCache;
 }
 
+const rmg::Area & Object::getVisitableArea() const
+{
+	if(dVisitableCache.empty())
+	{
+		for(const auto & i : dInstances)
+		{
+			// FIXME: Account for bjects with multiple visitable tiles
+			dVisitableCache.add(i.getVisitablePosition());
+		}
+	}
+	return dVisitableCache;
+}
+
 const rmg::Area Object::getEntrableArea() const
 {
 	// Calculate Area that hero can freely pass
@@ -320,7 +333,8 @@ const rmg::Area Object::getEntrableArea() const
 	// Do not use blockVisitTiles, unless they belong to removable objects (resources etc.)
 	// area = accessibleArea - (blockVisitableArea - removableArea)
 
-	rmg::Area entrableArea = getAccessibleArea();
+	// FIXME: What does it do? AccessibleArea means area AROUND the object 
+	rmg::Area entrableArea = getVisitableArea();
 	rmg::Area blockVisitableArea = getBlockVisitableArea();
 	blockVisitableArea.subtract(getRemovableArea());
 	entrableArea.subtract(blockVisitableArea);
@@ -330,11 +344,14 @@ const rmg::Area Object::getEntrableArea() const
 
 void Object::setPosition(const int3 & position)
 {
-	dAccessibleAreaCache.translate(position - dPosition);
-	dAccessibleAreaFullCache.translate(position - dPosition);
-	dBlockVisitableCache.translate(position - dPosition);
-	dRemovableAreaCache.translate(position - dPosition);
-	dFullAreaCache.translate(position - dPosition);
+	auto shift = position - dPosition;
+
+	dAccessibleAreaCache.translate(shift);
+	dAccessibleAreaFullCache.translate(shift);
+	dBlockVisitableCache.translate(shift);
+	dVisitableCache.translate(shift);
+	dRemovableAreaCache.translate(shift);
+	dFullAreaCache.translate(shift);
 	
 	dPosition = position;
 	for(auto& i : dInstances)
@@ -450,6 +467,7 @@ void Object::clearCachedArea() const
 	dAccessibleAreaCache.clear();
 	dAccessibleAreaFullCache.clear();
 	dBlockVisitableCache.clear();
+	dVisitableCache.clear();
 	dRemovableAreaCache.clear();
 }
 

+ 2 - 0
lib/rmg/RmgObject.h

@@ -74,6 +74,7 @@ public:
 	int3 getVisitablePosition() const;
 	const Area & getAccessibleArea(bool exceptLast = false) const;
 	const Area & getBlockVisitableArea() const;
+	const Area & getVisitableArea() const;
 	const Area & getRemovableArea() const;
 	const Area getEntrableArea() const;
 	
@@ -96,6 +97,7 @@ private:
 	mutable Area dFullAreaCache;
 	mutable Area dAccessibleAreaCache, dAccessibleAreaFullCache;
 	mutable Area dBlockVisitableCache;
+	mutable Area dVisitableCache;
 	mutable Area dRemovableAreaCache;
 	int3 dPosition;
 	mutable std::optional<int3> visibleTopOffset;

+ 15 - 15
lib/rmg/modificators/ObjectManager.cpp

@@ -600,11 +600,13 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
 				//Cannot be trespassed (Corpse)
 				continue;
 			}
-			else if(instance->object().appearance->isVisitableFromTop())
-				m->areaForRoads().add(instance->getVisitablePosition());
-			else
+			else if(!instance->object().appearance->isVisitableFromTop())
 			{
-				m->areaIsolated().add(instance->getVisitablePosition() + int3(0, -1, 0));
+				auto abovePos = instance->getVisitablePosition() + int3(0, -1, 0);
+				if (!instance->object().blockingAt(abovePos))
+				{
+					m->areaIsolated().add(abovePos);
+				}
 			}
 		}
 
@@ -718,22 +720,20 @@ bool ObjectManager::addGuard(rmg::Object & object, si32 strength, bool zoneGuard
 		return false;
 	
 	// Prefer non-blocking tiles, if any
-	const auto & entrableTiles = object.getEntrableArea().getTilesVector();
-	int3 entrableTile(-1, -1, -1);
-	if (entrableTiles.empty())
+	auto entrableArea = object.getEntrableArea();
+	if (entrableArea.empty())
 	{
-		entrableTile = object.getVisitablePosition();
-	}
-	else
-	{
-		entrableTile = *RandomGeneratorUtil::nextItem(entrableTiles, zone.getRand());
+		entrableArea.add(object.getVisitablePosition());
 	}
 
-	rmg::Area visitablePos({entrableTile});
-	visitablePos.unite(visitablePos.getBorderOutside());
+	rmg::Area entrableBorder = entrableArea.getBorderOutside();
 	
 	auto accessibleArea = object.getAccessibleArea();
-	accessibleArea.intersect(visitablePos);
+	accessibleArea.erase_if([&](const int3 & tile)
+	{
+		return !entrableBorder.contains(tile);
+	});
+	
 	if(accessibleArea.empty())
 	{
 		delete guard;

+ 28 - 16
lib/rmg/modificators/TreasurePlacer.cpp

@@ -633,9 +633,12 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
 	{
 		auto blockedArea = rmgObject.getArea();
 		auto entrableArea = rmgObject.getEntrableArea();
+		auto accessibleArea = rmgObject.getAccessibleArea();
 		
 		if(rmgObject.instances().empty())
-			entrableArea.add(int3());
+		{
+			accessibleArea.add(int3());
+		}
 		
 		auto * object = oi->generateObject();
 		if(oi->templates.empty())
@@ -650,20 +653,21 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
 
 		object->appearance = *RandomGeneratorUtil::nextItem(templates, zone.getRand());
 
-		auto blockingIssue = object->isBlockedVisitable() && !object->isRemovable();
-		if (blockingIssue)
+		//Put object in accessible area next to entrable area (excluding blockvis tiles)
+		if (!entrableArea.empty())
 		{
-			// Do not place next to another such object (Corpse issue)
-			// Calculate this before instance is added to rmgObject
-			auto blockVisitProximity = rmgObject.getBlockVisitableArea().getBorderOutside();
-			entrableArea.subtract(blockVisitProximity);
+			auto entrableBorder = entrableArea.getBorderOutside();
+			accessibleArea.erase_if([&](const int3 & tile)
+			{
+				return !entrableBorder.count(tile);
+			});
 		}
 
 		auto & instance = rmgObject.addInstance(*object);
 
 		do
 		{
-			if(entrableArea.empty())
+			if(accessibleArea.empty())
 			{
 				//fail - fallback
 				rmgObject.clear();
@@ -671,15 +675,24 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
 			}
 			
 			std::vector<int3> bestPositions;
-			if(densePlacement)
+			if(densePlacement && !entrableArea.empty())
 			{
+				// Choose positon which has access to as many entrable tiles as possible
 				int bestPositionsWeight = std::numeric_limits<int>::max();
-				for(const auto & t : entrableArea.getTilesVector())
+				for(const auto & t : accessibleArea.getTilesVector())
 				{
 					instance.setPosition(t);
-					int w = rmgObject.getEntrableArea().getTilesVector().size();
 
-					if(w && w < bestPositionsWeight)
+					auto currentAccessibleArea = rmgObject.getAccessibleArea();
+					auto currentEntrableBorder = rmgObject.getEntrableArea().getBorderOutside();
+					currentAccessibleArea.erase_if([&](const int3 & tile)
+					{
+						return !currentEntrableBorder.count(tile);
+					});
+
+					size_t w = currentAccessibleArea.getTilesVector().size();
+
+					if(w > bestPositionsWeight)
 					{
 						// Minimum 1 position must be entrable
 						bestPositions.clear();
@@ -691,12 +704,11 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
 						bestPositions.push_back(t);
 					}
 				}
-
 			}
 
 			if (bestPositions.empty())
 			{
-				bestPositions = entrableArea.getTilesVector();
+				bestPositions = accessibleArea.getTilesVector();
 			}
 			
 			int3 nextPos = *RandomGeneratorUtil::nextItem(bestPositions, zone.getRand());
@@ -713,11 +725,11 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
 			if(rmgObject.instances().size() == 1)
 				break;
 
-			if(!blockedArea.overlap(instance.getBlockedArea()) && entrableArea.overlap(instanceAccessibleArea))
+			if(!blockedArea.overlap(instance.getBlockedArea()) && accessibleArea.overlap(instanceAccessibleArea))
 				break;
 
 			//fail - new position
-			entrableArea.erase(nextPos);
+			accessibleArea.erase(nextPos);
 		} while(true);
 	}
 	return rmgObject;