mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-06 09:09:40 +02:00
- Check full object area for minimum distance requirement
- Add option to optimize both for max distance and custom weight
This commit is contained in:
@@ -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 bestDistance = 10e9;
|
||||||
float dist = ti.getNearestObjectDistance();
|
|
||||||
if(dist < min_dist)
|
|
||||||
return -1.f;
|
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ public:
|
|||||||
{
|
{
|
||||||
NONE = 0x00000000,
|
NONE = 0x00000000,
|
||||||
WEIGHT = 0x00000001,
|
WEIGHT = 0x00000001,
|
||||||
DISTANCE = 0x00000010
|
DISTANCE = 0x00000010,
|
||||||
|
BOTH = 0x00000011
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
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 path = rmg::Path::invalid();
|
auto ti = map.getTileInfo(tile);
|
||||||
|
return (ti.getNearestObjectDistance() < minDistance);
|
||||||
|
});
|
||||||
|
|
||||||
Zone::Lock lock(zone.areaMutex); //We are going to subtract this area
|
if (guarded)
|
||||||
auto possibleArea = zone.areaPossible();
|
{
|
||||||
|
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)
|
|
||||||
{
|
|
||||||
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()))
|
|
||||||
return -1.f;
|
|
||||||
|
|
||||||
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());
|
float bestDistance = 10e9;
|
||||||
|
for (const auto& t : rmgObject.getArea().getTilesVector())
|
||||||
|
{
|
||||||
|
float distance = map.getTileInfo(t).getNearestObjectDistance();
|
||||||
|
if (distance < minDistance)
|
||||||
|
return -1.f;
|
||||||
|
else
|
||||||
|
vstd::amin(bestDistance, distance);
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
// TODO: Does it help?
|
||||||
zone.connectPath(path);
|
areaToBlock.erase_if([this](const int3& tile) -> bool
|
||||||
manager.placeObject(rmgObject, guarded, true);
|
{
|
||||||
break;
|
//Don't block tiles outside the map
|
||||||
}
|
return (!map.isOnMap(tile));
|
||||||
else
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user