浏览代码

Do not hide roads behind objects

Tomasz Zieliński 1 年之前
父节点
当前提交
186b6629c7

+ 26 - 0
lib/rmg/RmgObject.cpp

@@ -359,6 +359,7 @@ void Object::setPosition(const int3 & position)
 	dVisitableCache.translate(shift);
 	dRemovableAreaCache.translate(shift);
 	dFullAreaCache.translate(shift);
+	dBorderAboveCache.translate(shift);
 	
 	dPosition = position;
 	for(auto& i : dInstances)
@@ -386,6 +387,16 @@ const Area & Object::getArea() const
 	return dFullAreaCache;
 }
 
+const Area & Object::getBorderAbove() const
+{
+	if(dBorderAboveCache.empty())
+	{
+		for(const auto & instance : dInstances)
+			dBorderAboveCache.unite(instance.getBorderAbove());
+	}
+	return dBorderAboveCache;
+}
+
 const int3 Object::getVisibleTop() const
 {
 	if (visibleTopOffset)
@@ -445,6 +456,20 @@ uint32_t rmg::Object::getValue() const
 	return value;
 }
 
+rmg::Area Object::Instance::getBorderAbove() const
+{
+	int3 visitablePos = getVisitablePosition();
+	auto areaVisitable = rmg::Area({visitablePos});
+	auto borderAbove = areaVisitable.getBorderOutside();
+	vstd::erase_if(borderAbove, [&](const int3 & tile)
+	{
+		return tile.y >= visitablePos.y ||
+		(!object().blockingAt(tile + int3(0, 1, 0)) && 
+		object().blockingAt(tile));
+	});
+	return borderAbove;
+}
+
 void Object::Instance::finalize(RmgMap & map, CRandomGenerator & rng)
 {
 	if(!map.isOnMap(getPosition(true)))
@@ -501,6 +526,7 @@ void Object::clearCachedArea() const
 	dBlockVisitableCache.clear();
 	dVisitableCache.clear();
 	dRemovableAreaCache.clear();
+	dBorderAboveCache.clear();
 }
 
 void Object::clear()

+ 3 - 0
lib/rmg/RmgObject.h

@@ -38,6 +38,7 @@ public:
 		bool isBlockedVisitable() const;
 		bool isRemovable() const;
 		const Area & getAccessibleArea() const;
+		Area getBorderAbove() const;
 		void setTemplate(TerrainId terrain, CRandomGenerator &); //cache invalidation
 		void setAnyTemplate(CRandomGenerator &); //cache invalidation
 		
@@ -78,6 +79,7 @@ public:
 	const Area & getVisitableArea() const;
 	const Area & getRemovableArea() const;
 	const Area getEntrableArea() const;
+	const Area & getBorderAbove() const;
 	
 	const int3 & getPosition() const;
 	void setPosition(const int3 & position);
@@ -104,6 +106,7 @@ private:
 	mutable Area dBlockVisitableCache;
 	mutable Area dVisitableCache;
 	mutable Area dRemovableAreaCache;
+	mutable Area dBorderAboveCache;
 	int3 dPosition;
 	mutable std::optional<int3> visibleTopOffset;
 	mutable std::list<Object::Instance*> cachedInstanceList;

+ 1 - 9
lib/rmg/modificators/ObjectManager.cpp

@@ -648,15 +648,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
 			else if(!instance->object().appearance->isVisitableFromTop())
 			{
 				// Do not route road behind visitable tile
-				int3 visitablePos = instance->getVisitablePosition();
-				auto areaVisitable = rmg::Area({visitablePos});
-				auto borderAbove = areaVisitable.getBorderOutside();
-				vstd::erase_if(borderAbove, [&](const int3 & tile)
-				{
-					return tile.y >= visitablePos.y ||
-					(!instance->object().blockingAt(tile + int3(0, 1, 0)) && 
-					instance->object().blockingAt(tile));
-				});				
+				auto borderAbove = instance->getBorderAbove();
 				rp->areaIsolated().unite(borderAbove);
 			}
 

+ 4 - 2
lib/rmg/modificators/RoadPlacer.cpp

@@ -77,11 +77,13 @@ bool RoadPlacer::createRoad(const int3 & dst)
 	{
 		if(areaIsolated().contains(dst))
 		{
-			return 1000.0f; //Do not route road behind objects that are not visitable from top
+			return 1000.0f; //Do not route road behind objects that are not visitable from top, such as Monoliths
 		}
 		else
 		{
-			auto ret = 1.0f;
+			float weight = dst.dist2dSQ(src);
+			auto ret =  weight * weight;
+
 			if (visitableTiles.contains(src) || visitableTiles.contains(dst))
 			{
 				ret *= VISITABLE_PENALTY;

+ 4 - 0
lib/rmg/modificators/TreasurePlacer.cpp

@@ -966,6 +966,10 @@ void TreasurePlacer::createTreasures(ObjectManager& manager)
 							if (zone.freePaths()->overlap(areaToBlock) || roads.overlap(areaToBlock) || manager.getVisitableArea().overlap(areaToBlock))
 								return -1.f;
 
+							// Add huge penalty for objects hiding roads
+							if (rmgObject.getBorderAbove().overlap(roads))
+								bestDistance /= 10.0f;
+
 							return bestDistance;
 						}, guarded, false, ObjectManager::OptimizeType::BOTH);
 				}