浏览代码

Merge pull request #1698 from vcmi/object_placement_tweaks

No objections, works fine for me as well.
DjWarmonger 2 年之前
父节点
当前提交
114e7d196b
共有 2 个文件被更改,包括 40 次插入26 次删除
  1. 20 11
      lib/rmg/ConnectionsPlacer.cpp
  2. 20 15
      lib/rmg/WaterProxy.cpp

+ 20 - 11
lib/rmg/ConnectionsPlacer.cpp

@@ -100,15 +100,20 @@ void ConnectionsPlacer::selfSideDirectConnection(const rmg::ZoneConnection & con
 			borderPos = *RandomGeneratorUtil::nextItem(directConnectionIterator->second, generator.rand);
 			guardPos = zone.areaPossible().nearest(borderPos);
 			assert(borderPos != guardPos);
-			
-			auto safetyGap = rmg::Area({guardPos});
-			safetyGap.unite(safetyGap.getBorderOutside());
-			safetyGap.intersect(zone.areaPossible());
-			if(!safetyGap.empty())
+
+			float dist = map.getTile(guardPos).getNearestObjectDistance();
+			if (dist >= 3) //Don't place guards at adjacent tiles
 			{
-				safetyGap.intersect(otherZone->areaPossible());
-				if(safetyGap.empty())
-					break; //successfull position
+
+				auto safetyGap = rmg::Area({ guardPos });
+				safetyGap.unite(safetyGap.getBorderOutside());
+				safetyGap.intersect(zone.areaPossible());
+				if (!safetyGap.empty())
+				{
+					safetyGap.intersect(otherZone->areaPossible());
+					if (safetyGap.empty())
+						break; //successfull position
+				}
 			}
 			
 			//failed position
@@ -150,6 +155,8 @@ void ConnectionsPlacer::selfSideDirectConnection(const rmg::ZoneConnection & con
 					rmg::Object monster(*monsterType);
 					monster.setPosition(guardPos);
 					manager.placeObject(monster, false, true);
+					//Place objects away from the monster in the other zone, too
+					otherZone->getModificator<ObjectManager>()->updateDistances(monster);
 				}
 				else
 				{
@@ -225,8 +232,10 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c
 			rmg::Path path1 = manager.placeAndConnectObject(commonArea, rmgGate1, [this, minDist, &path2, &rmgGate1, &zShift, guarded2, &managerOther, &rmgGate2	](const int3 & tile)
 			{
 				auto ti = map.getTile(tile);
+				auto otherTi = map.getTile(tile - zShift);
 				float dist = ti.getNearestObjectDistance();
-				if(dist < minDist)
+				float otherDist = otherTi.getNearestObjectDistance();
+				if(dist < minDist || otherDist < minDist)
 					return -1.f;
 				
 				rmg::Area toPlace(rmgGate1.getArea() + rmgGate1.getAccessibleArea());
@@ -234,8 +243,8 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c
 				
 				path2 = managerOther.placeAndConnectObject(toPlace, rmgGate2, minDist, guarded2, true, ObjectManager::OptimizeType::NONE);
 				
-				return path2.valid() ? 1.f : -1.f;
-			}, guarded1, true, ObjectManager::OptimizeType::NONE);
+				return path2.valid() ? (dist + otherDist) : -1.f;
+			}, guarded1, true, ObjectManager::OptimizeType::DISTANCE);
 			
 			if(path1.valid() && path2.valid())
 			{

+ 20 - 15
lib/rmg/WaterProxy.cpp

@@ -209,24 +209,28 @@ bool WaterProxy::placeBoat(Zone & land, const Lake & lake, RouteInfo & info)
 	auto * manager = zone.getModificator<ObjectManager>();
 	if(!manager)
 		return false;
-	
+
 	auto subObjects = VLC->objtypeh->knownSubObjects(Obj::BOAT);
 	auto * boat = dynamic_cast<CGBoat *>(VLC->objtypeh->getHandlerFor(Obj::BOAT, *RandomGeneratorUtil::nextItem(subObjects, generator.rand))->create());
 
 	rmg::Object rmgObject(*boat);
 	rmgObject.setTemplate(zone.getTerrainType());
-	
+
 	auto waterAvailable = zone.areaPossible() + zone.freePaths();
 	rmg::Area coast = lake.neighbourZones.at(land.getId()); //having land tiles
 	coast.intersect(land.areaPossible() + land.freePaths()); //having only available land tiles
-	auto boardingPositions = coast.getSubarea([&waterAvailable](const int3 & tile) //tiles where boarding is possible
-	{
-		rmg::Area a({tile});
-		a = a.getBorderOutside();
-		a.intersect(waterAvailable);
-		return !a.empty();
-	});
-	
+	auto boardingPositions = coast.getSubarea([&waterAvailable, this](const int3 & tile) //tiles where boarding is possible
+		{
+			//We don't want place boat right to any land object, especiallly the zone guard
+			if (map.getTile(tile).getNearestObjectDistance() <= 3)
+				return false;
+
+			rmg::Area a({tile});
+			a = a.getBorderOutside();
+			a.intersect(waterAvailable);
+			return !a.empty();
+		});
+
 	while(!boardingPositions.empty())
 	{
 		auto boardingPosition = *boardingPositions.getTiles().begin();
@@ -239,27 +243,28 @@ bool WaterProxy::placeBoat(Zone & land, const Lake & lake, RouteInfo & info)
 			boardingPositions.erase(boardingPosition);
 			continue;
 		}
-		
+
 		//try to place boat at water, create paths on water and land
-		auto path = manager->placeAndConnectObject(shipPositions, rmgObject, 2, false, true, ObjectManager::OptimizeType::NONE);
+		auto path = manager->placeAndConnectObject(shipPositions, rmgObject, 4, false, true, ObjectManager::OptimizeType::NONE);
 		auto landPath = land.searchPath(boardingPosition, false);
 		if(!path.valid() || !landPath.valid())
 		{
 			boardingPositions.erase(boardingPosition);
 			continue;
 		}
-		
+
 		info.blocked = rmgObject.getArea();
 		info.visitable = rmgObject.getVisitablePosition();
 		info.boarding = boardingPosition;
 		info.water = shipPositions;
-		
+
 		zone.connectPath(path);
 		land.connectPath(landPath);
 		manager->placeObject(rmgObject, false, true);
+		land.getModificator<ObjectManager>()->updateDistances(rmgObject); //Keep land objects away from the boat
 		break;
 	}
-	
+
 	return !boardingPositions.empty();
 }