1
0
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:
DjWarmonger 2016-07-12 11:42:03 +02:00
parent e1e520f0a2
commit aecf834cc1
2 changed files with 86 additions and 60 deletions

View File

@ -1551,23 +1551,8 @@ bool CRmgTemplateZone::placeMines (CMapGenerator* gen)
return true; return true;
} }
bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen) EObjectPlacingResult::EObjectPlacingResult CRmgTemplateZone::tryToPlaceObjectAndConnectToPath(CMapGenerator* gen, CGObjectInstance *obj, int3 &pos)
{ {
logGlobal->traceStream() << "Creating required objects";
for(const auto &object : requiredObjects)
{
auto obj = object.first;
int3 pos;
int3 accessibleOffset;
while (true)
{
if (!findPlaceForObject(gen, obj, 3, pos))
{
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. //check if we can find a path around this object. Tiles will be set to "USED" after object is successfully placed.
obj->pos = pos; obj->pos = pos;
gen->setOccupied(obj->visitablePos(), ETileType::BLOCKED); gen->setOccupied(obj->visitablePos(), ETileType::BLOCKED);
@ -1576,30 +1561,62 @@ bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
if (gen->map->isInTheMap(tile)) if (gen->map->isInTheMap(tile))
gen->setOccupied(tile, ETileType::BLOCKED); gen->setOccupied(tile, ETileType::BLOCKED);
} }
accessibleOffset = getAccessibleOffset(gen, obj->appearance, pos); int3 accessibleOffset = getAccessibleOffset(gen, obj->appearance, pos);
if (!accessibleOffset.valid()) if (!accessibleOffset.valid())
{ {
logGlobal->warnStream() << boost::format("Cannot access required object at position %s, retrying") % pos; logGlobal->warnStream() << boost::format("Cannot access required object at position %s, retrying") % pos;
continue; return EObjectPlacingResult::CANNOT_FIT;
} }
if (!connectPath(gen, accessibleOffset, true)) if (!connectPath(gen, accessibleOffset, true))
{ {
logGlobal->traceStream() << boost::format("Failed to create path to required object at position %s, retrying") % pos; logGlobal->traceStream() << boost::format("Failed to create path to required object at position %s, retrying") % pos;
continue; return EObjectPlacingResult::SEALED_OFF;
} }
else else
break; return EObjectPlacingResult::SUCCESS;
} }
bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
{
logGlobal->traceStream() << "Creating required objects";
for(const auto &object : requiredObjects)
{
auto obj = object.first;
int3 pos;
while (true)
{
if (!findPlaceForObject(gen, obj, 3, pos))
{
logGlobal->errorStream() << boost::format("Failed to fill zone %d due to lack of space") % id;
return false;
}
if (tryToPlaceObjectAndConnectToPath(gen, obj, pos) == EObjectPlacingResult::SUCCESS)
{
//paths to required objects constitute main paths of zone. otherwise they just may lead to middle and create dead zones
placeObject(gen, obj, pos); placeObject(gen, obj, pos);
guardObject(gen, obj, object.second, (obj->ID == Obj::MONOLITH_TWO_WAY), true); 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 break;
}
}
} }
for (const auto &obj : closeObjects) 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 // smallest distance to zone center, greatest distance to nearest object
auto isCloser = [this, gen](const int3 & lhs, const int3 & rhs) -> bool auto isCloser = [this, gen](const int3 & lhs, const int3 & rhs) -> bool
@ -1614,33 +1631,37 @@ bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
boost::sort(tiles, isCloser); boost::sort(tiles, isCloser);
setTemplateForObject(gen, obj.first); if (tiles.empty())
auto tilesBlockedByObject = obj.first->getBlockedOffsets(); {
bool result = false; logGlobal->errorStream() << boost::format("Failed to fill zone %d due to lack of space") % id;
return false;
}
for (auto tile : tiles) for (auto tile : tiles)
{ {
//object must be accessible from at least one surounding tile //code partially adapted from findPlaceForObject()
if (!isAccessibleFromAnywhere(gen, obj.first->appearance, tile))
if (areAllTilesAvailable(gen, obj.first, tile, tilesBlockedByObject))
gen->setOccupied(pos, ETileType::BLOCKED); //why?
else
continue; continue;
//avoid borders EObjectPlacingResult::EObjectPlacingResult result = tryToPlaceObjectAndConnectToPath(gen, obj.first, tile);
if (gen->isPossible(tile)) if (result == EObjectPlacingResult::SUCCESS)
{
if (areAllTilesAvailable(gen, obj.first, tile, tilesBlockedByObject))
{ {
placeObject(gen, obj.first, tile); placeObject(gen, obj.first, tile);
guardObject(gen, obj.first, obj.second, (obj.first->ID == Obj::MONOLITH_TWO_WAY), true); guardObject(gen, obj.first, obj.second, (obj.first->ID == Obj::MONOLITH_TWO_WAY), true);
result = true; finished = true;
break; break;
} }
} else if (result == EObjectPlacingResult::CANNOT_FIT)
} continue; // next tile
if (!result) else if (result == EObjectPlacingResult::SEALED_OFF)
{ {
logGlobal->errorStream() << boost::format("Failed to fill zone %d due to lack of space") % id; break; //tiles expired, pick new ones
//TODO CLEANUP! }
return false; 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 //we need object apperance to deduce free tile
setTemplateForObject(gen, obj); setTemplateForObject(gen, obj);
//si32 min_dist = sqrt(tileinfo.size()/density);
int best_distance = 0; int best_distance = 0;
bool result = false; 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(); auto tilesBlockedByObject = obj->getBlockedOffsets();

View File

@ -34,6 +34,15 @@ namespace ETemplateZoneType
JUNCTION JUNCTION
}; };
} }
namespace EObjectPlacingResult
{
enum EObjectPlacingResult
{
SUCCESS,
CANNOT_FIT,
SEALED_OFF
};
}
class DLL_LINKAGE CTileInfo class DLL_LINKAGE CTileInfo
{ {
public: public:
@ -170,6 +179,7 @@ public:
void createBorder(CMapGenerator* gen); void createBorder(CMapGenerator* gen);
void fractalize(CMapGenerator* gen); void fractalize(CMapGenerator* gen);
void connectLater(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); bool createRequiredObjects(CMapGenerator* gen);
void createTreasures(CMapGenerator* gen); void createTreasures(CMapGenerator* gen);
void createObstacles1(CMapGenerator* gen); void createObstacles1(CMapGenerator* gen);