diff --git a/lib/rmg/modificators/ObjectManager.cpp b/lib/rmg/modificators/ObjectManager.cpp index f05ab1bc9..111cec60c 100644 --- a/lib/rmg/modificators/ObjectManager.cpp +++ b/lib/rmg/modificators/ObjectManager.cpp @@ -238,15 +238,14 @@ rmg::Path ObjectManager::placeAndConnectObject(const rmg::Area & searchArea, rmg RecursiveLock lock(externalAccessMutex); return placeAndConnectObject(searchArea, obj, [this, min_dist, &obj](const int3 & tile) { - auto ti = map.getTileInfo(tile); - float dist = ti.getNearestObjectDistance(); - if(dist < min_dist) - return -1.f; - + float bestDistance = 10e9; 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; + else + vstd::amin(bestDistance, distance); } rmg::Area perimeter; @@ -298,7 +297,7 @@ rmg::Path ObjectManager::placeAndConnectObject(const rmg::Area & searchArea, rmg } } - return dist; + return bestDistance; }, isGuarded, onlyStraight, optimizer); } @@ -513,6 +512,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD if(map.isOnMap(i) && map.isPossible(i)) map.setOccupied(i, ETileType::BLOCKED); } + lock.unlock(); if (updateDistance) { @@ -535,6 +535,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD auto manager = map.getZones().at(id)->getModificator(); if (manager) { + // TODO: Update distances for perimeter of guarded object, not just treasures manager->updateDistances(object); } } diff --git a/lib/rmg/modificators/ObjectManager.h b/lib/rmg/modificators/ObjectManager.h index f346a921a..2e0ed7f71 100644 --- a/lib/rmg/modificators/ObjectManager.h +++ b/lib/rmg/modificators/ObjectManager.h @@ -48,7 +48,8 @@ public: { NONE = 0x00000000, WEIGHT = 0x00000001, - DISTANCE = 0x00000010 + DISTANCE = 0x00000010, + BOTH = 0x00000011 }; public: diff --git a/lib/rmg/modificators/TreasurePlacer.cpp b/lib/rmg/modificators/TreasurePlacer.cpp index 755bda88a..8adbcb1ac 100644 --- a/lib/rmg/modificators/TreasurePlacer.cpp +++ b/lib/rmg/modificators/TreasurePlacer.cpp @@ -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; }); const ui32 maxPileGenerationAttemps = 2; - for (ui32 attempt = 0; attempt <= maxPileGenerationAttemps; attempt++) + for (ui32 attempt = 0; attempt < maxPileGenerationAttemps; attempt++) { auto rmgObject = constructTreasurePile(treasurePileInfos, attempt == maxAttempts); @@ -865,61 +865,67 @@ void TreasurePlacer::createTreasures(ObjectManager& manager) { 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 - auto possibleArea = zone.areaPossible(); - - 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) + if (guarded) + { + path = manager.placeAndConnectObject(possibleArea, rmgObject, [this, &rmgObject, &minDistance, &manager](const int3& tile) { - 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 areaToBlock = rmgObject.getAccessibleArea(true); areaToBlock.subtract(guardedArea); - treasureBlockArea.unite(areaToBlock); - } - zone.connectPath(path); - manager.placeObject(rmgObject, guarded, true); - break; - } - else + + // TODO: Does it help? + areaToBlock.erase_if([this](const int3& tile) -> bool + { + //Don't block tiles outside the map + return (!map.isOnMap(tile)); + }); + + 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); } } }