mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-30 08:57:00 +02:00
Fixed placing of close objects #2447. Some additional refactoring.
This commit is contained in:
parent
e1e520f0a2
commit
aecf834cc1
@ -1551,6 +1551,31 @@ bool CRmgTemplateZone::placeMines (CMapGenerator* gen)
|
||||
return true;
|
||||
}
|
||||
|
||||
EObjectPlacingResult::EObjectPlacingResult CRmgTemplateZone::tryToPlaceObjectAndConnectToPath(CMapGenerator* gen, CGObjectInstance *obj, int3 &pos)
|
||||
{
|
||||
//check if we can find a path around this object. Tiles will be set to "USED" after object is successfully placed.
|
||||
obj->pos = pos;
|
||||
gen->setOccupied(obj->visitablePos(), ETileType::BLOCKED);
|
||||
for (auto tile : obj->getBlockedPos())
|
||||
{
|
||||
if (gen->map->isInTheMap(tile))
|
||||
gen->setOccupied(tile, ETileType::BLOCKED);
|
||||
}
|
||||
int3 accessibleOffset = getAccessibleOffset(gen, obj->appearance, pos);
|
||||
if (!accessibleOffset.valid())
|
||||
{
|
||||
logGlobal->warnStream() << boost::format("Cannot access required object at position %s, retrying") % pos;
|
||||
return EObjectPlacingResult::CANNOT_FIT;
|
||||
}
|
||||
if (!connectPath(gen, accessibleOffset, true))
|
||||
{
|
||||
logGlobal->traceStream() << boost::format("Failed to create path to required object at position %s, retrying") % pos;
|
||||
return EObjectPlacingResult::SEALED_OFF;
|
||||
}
|
||||
else
|
||||
return EObjectPlacingResult::SUCCESS;
|
||||
}
|
||||
|
||||
bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
|
||||
{
|
||||
logGlobal->traceStream() << "Creating required objects";
|
||||
@ -1559,7 +1584,6 @@ bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
|
||||
{
|
||||
auto obj = object.first;
|
||||
int3 pos;
|
||||
int3 accessibleOffset;
|
||||
while (true)
|
||||
{
|
||||
if (!findPlaceForObject(gen, obj, 3, pos))
|
||||
@ -1567,39 +1591,32 @@ bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
|
||||
logGlobal->errorStream() << boost::format("Failed to fill zone %d due to lack of space") % id;
|
||||
return false;
|
||||
}
|
||||
|
||||
//check if we can find a path around this object. Tiles will be set to "USED" after object is successfully placed.
|
||||
obj->pos = pos;
|
||||
gen->setOccupied (obj->visitablePos(), ETileType::BLOCKED);
|
||||
for (auto tile : obj->getBlockedPos())
|
||||
if (tryToPlaceObjectAndConnectToPath(gen, obj, pos) == EObjectPlacingResult::SUCCESS)
|
||||
{
|
||||
if (gen->map->isInTheMap(tile))
|
||||
gen->setOccupied(tile, ETileType::BLOCKED);
|
||||
}
|
||||
accessibleOffset = getAccessibleOffset(gen, obj->appearance, pos);
|
||||
if (!accessibleOffset.valid())
|
||||
{
|
||||
logGlobal->warnStream() << boost::format("Cannot access required object at position %s, retrying") % pos;
|
||||
continue;
|
||||
}
|
||||
if (!connectPath(gen, accessibleOffset, true))
|
||||
{
|
||||
logGlobal->traceStream() << boost::format("Failed to create path to required object at position %s, retrying") % pos;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
//paths to required objects constitute main paths of zone. otherwise they just may lead to middle and create dead zones
|
||||
placeObject(gen, obj, pos);
|
||||
guardObject(gen, obj, object.second, (obj->ID == Obj::MONOLITH_TWO_WAY), true);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
placeObject(gen, obj, pos);
|
||||
guardObject (gen, obj, object.second, (obj->ID == Obj::MONOLITH_TWO_WAY), true);
|
||||
//paths to required objects constitute main paths of zone. otherwise they just may lead to middle and create dead zones
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &obj : closeObjects)
|
||||
{
|
||||
std::vector<int3> tiles(possibleTiles.begin(), possibleTiles.end()); //new tiles vector after each object has been placed
|
||||
setTemplateForObject(gen, obj.first);
|
||||
auto tilesBlockedByObject = obj.first->getBlockedOffsets();
|
||||
|
||||
bool finished = false;
|
||||
while (!finished)
|
||||
{
|
||||
std::vector<int3> tiles(possibleTiles.begin(), possibleTiles.end());
|
||||
//new tiles vector after each object has been placed, OR misplaced area has been sealed off
|
||||
|
||||
boost::remove_if(tiles, [gen, obj, this](int3 &tile)-> bool
|
||||
{
|
||||
//object must be accessible from at least one surounding tile
|
||||
return !this->isAccessibleFromAnywhere(gen, obj.first->appearance, tile);
|
||||
});
|
||||
|
||||
// smallest distance to zone center, greatest distance to nearest object
|
||||
auto isCloser = [this, gen](const int3 & lhs, const int3 & rhs) -> bool
|
||||
@ -1612,35 +1629,39 @@ bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
|
||||
return (lDist * 0.5f - std::sqrt(gen->getNearestObjectDistance(lhs))) < (rDist * 0.5f - std::sqrt(gen->getNearestObjectDistance(rhs)));
|
||||
};
|
||||
|
||||
boost::sort (tiles, isCloser);
|
||||
|
||||
setTemplateForObject(gen, obj.first);
|
||||
auto tilesBlockedByObject = obj.first->getBlockedOffsets();
|
||||
bool result = false;
|
||||
boost::sort(tiles, isCloser);
|
||||
|
||||
if (tiles.empty())
|
||||
{
|
||||
logGlobal->errorStream() << boost::format("Failed to fill zone %d due to lack of space") % id;
|
||||
return false;
|
||||
}
|
||||
for (auto tile : tiles)
|
||||
{
|
||||
//object must be accessible from at least one surounding tile
|
||||
if (!isAccessibleFromAnywhere(gen, obj.first->appearance, tile))
|
||||
//code partially adapted from findPlaceForObject()
|
||||
|
||||
if (areAllTilesAvailable(gen, obj.first, tile, tilesBlockedByObject))
|
||||
gen->setOccupied(pos, ETileType::BLOCKED); //why?
|
||||
else
|
||||
continue;
|
||||
|
||||
//avoid borders
|
||||
if (gen->isPossible(tile))
|
||||
{
|
||||
if (areAllTilesAvailable(gen, obj.first, tile, tilesBlockedByObject))
|
||||
EObjectPlacingResult::EObjectPlacingResult result = tryToPlaceObjectAndConnectToPath(gen, obj.first, tile);
|
||||
if (result == EObjectPlacingResult::SUCCESS)
|
||||
{
|
||||
placeObject(gen, obj.first, tile);
|
||||
guardObject(gen, obj.first, obj.second, (obj.first->ID == Obj::MONOLITH_TWO_WAY), true);
|
||||
result = true;
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!result)
|
||||
else if (result == EObjectPlacingResult::CANNOT_FIT)
|
||||
continue; // next tile
|
||||
else if (result == EObjectPlacingResult::SEALED_OFF)
|
||||
{
|
||||
logGlobal->errorStream() << boost::format("Failed to fill zone %d due to lack of space") % id;
|
||||
//TODO CLEANUP!
|
||||
return false;
|
||||
break; //tiles expired, pick new ones
|
||||
}
|
||||
else
|
||||
throw (rmgException("Wrong result of tryToPlaceObjectAndConnectToPath()"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2004,13 +2025,8 @@ bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance*
|
||||
//we need object apperance to deduce free tile
|
||||
setTemplateForObject(gen, obj);
|
||||
|
||||
//si32 min_dist = sqrt(tileinfo.size()/density);
|
||||
int best_distance = 0;
|
||||
bool result = false;
|
||||
//si32 w = gen->map->width;
|
||||
//si32 h = gen->map->height;
|
||||
|
||||
//logGlobal->infoStream() << boost::format("Min dist for density %f is %d") % density % min_dist;
|
||||
|
||||
auto tilesBlockedByObject = obj->getBlockedOffsets();
|
||||
|
||||
|
@ -34,6 +34,15 @@ namespace ETemplateZoneType
|
||||
JUNCTION
|
||||
};
|
||||
}
|
||||
namespace EObjectPlacingResult
|
||||
{
|
||||
enum EObjectPlacingResult
|
||||
{
|
||||
SUCCESS,
|
||||
CANNOT_FIT,
|
||||
SEALED_OFF
|
||||
};
|
||||
}
|
||||
class DLL_LINKAGE CTileInfo
|
||||
{
|
||||
public:
|
||||
@ -170,6 +179,7 @@ public:
|
||||
void createBorder(CMapGenerator* gen);
|
||||
void fractalize(CMapGenerator* gen);
|
||||
void connectLater(CMapGenerator* gen);
|
||||
EObjectPlacingResult::EObjectPlacingResult tryToPlaceObjectAndConnectToPath(CMapGenerator* gen, CGObjectInstance *obj, int3 &pos); //return true if the position cna be connected
|
||||
bool createRequiredObjects(CMapGenerator* gen);
|
||||
void createTreasures(CMapGenerator* gen);
|
||||
void createObstacles1(CMapGenerator* gen);
|
||||
|
Loading…
Reference in New Issue
Block a user