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;
|
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)
|
bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
|
||||||
{
|
{
|
||||||
logGlobal->traceStream() << "Creating required objects";
|
logGlobal->traceStream() << "Creating required objects";
|
||||||
@ -1559,7 +1584,6 @@ bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
|
|||||||
{
|
{
|
||||||
auto obj = object.first;
|
auto obj = object.first;
|
||||||
int3 pos;
|
int3 pos;
|
||||||
int3 accessibleOffset;
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (!findPlaceForObject(gen, obj, 3, pos))
|
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;
|
logGlobal->errorStream() << boost::format("Failed to fill zone %d due to lack of space") % id;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (tryToPlaceObjectAndConnectToPath(gen, obj, pos) == EObjectPlacingResult::SUCCESS)
|
||||||
//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))
|
//paths to required objects constitute main paths of zone. otherwise they just may lead to middle and create dead zones
|
||||||
gen->setOccupied(tile, ETileType::BLOCKED);
|
placeObject(gen, obj, pos);
|
||||||
}
|
guardObject(gen, obj, object.second, (obj->ID == Obj::MONOLITH_TWO_WAY), true);
|
||||||
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
|
|
||||||
break;
|
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)
|
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
|
||||||
@ -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)));
|
return (lDist * 0.5f - std::sqrt(gen->getNearestObjectDistance(lhs))) < (rDist * 0.5f - std::sqrt(gen->getNearestObjectDistance(rhs)));
|
||||||
};
|
};
|
||||||
|
|
||||||
boost::sort (tiles, isCloser);
|
boost::sort(tiles, isCloser);
|
||||||
|
|
||||||
setTemplateForObject(gen, obj.first);
|
|
||||||
auto tilesBlockedByObject = obj.first->getBlockedOffsets();
|
|
||||||
bool result = false;
|
|
||||||
|
|
||||||
|
if (tiles.empty())
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user