1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

Merge pull request #1698 from vcmi/object_placement_tweaks

No objections, works fine for me as well.
This commit is contained in:
DjWarmonger
2023-03-25 18:13:15 +01:00
committed by GitHub
2 changed files with 40 additions and 26 deletions

View File

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

View File

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