1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-26 22:57:00 +02:00

Better object placement and accessibility.

This commit is contained in:
DjWarmonger 2014-07-09 09:22:50 +02:00
parent 22d26db694
commit 2a8ae6310e
2 changed files with 85 additions and 24 deletions

View File

@ -656,8 +656,9 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
CGObjectInstance * object = nullptr;
while (currentValue < minValue)
{
//make sure our shape is consistent
treasures[info.nextTreasurePos] = nullptr;
//not sure if this code makes sense anymore when we can have multiple-tile objects
for (auto treasurePos : treasures)
{
gen->foreach_neighbour (treasurePos.first, [gen, &boundary](int3 pos)
@ -670,6 +671,28 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
//leaving only boundary around objects
vstd::erase_if_present (boundary, treasurePos.first);
}
//for (auto tile : info.visitableFromTopPositions)
//{
// gen->foreach_neighbour (tile, [gen, &boundary](int3 pos)
// {
// boundary.insert(pos);
// });
//}
//for (auto tile : info.visitableFromBottomPositions)
//{
// gen->foreach_neighbour (tile, [gen, tile, &boundary](int3 pos)
// {
// if (pos.y <= tile.y) //objects are accessible and need to be blocked only from the bottom
// boundary.insert(pos);
// });
//}
//for (auto tile : info.occupiedPositions)
//{
// //leaving only boundary around objects
// vstd::erase_if_present (boundary, tile);
//}
for (auto tile : boundary)
{
//we can't extend boundary anymore
@ -691,12 +714,17 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
//update treasure pile area
int3 visitablePos = oi.templ.getVisitableOffset() + info.nextTreasurePos;
info.visitablePositions.insert(visitablePos); //can be accessed only from bottom or side
//TODO: actually we need to check is object is either !blockVisit or removable after visit - this means object below can be accessed
if (oi.templ.isVisitableFromTop())
info.visitableFromTopPositions.insert(visitablePos); //can be accessed from any direction
else
info.visitableFromBottomPositions.insert(visitablePos); //can be accessed only from bottom or side
for (auto blockedOffset : oi.templ.getBlockedOffsets())
{
info.occupiedPositions.insert(info.nextTreasurePos + blockedOffset);
info.blockedPositions.insert(info.nextTreasurePos + blockedOffset);
}
info.occupiedPositions.insert(visitablePos);
}
@ -707,10 +735,6 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
//now find place for next object
int3 placeFound(-1,-1,-1);
//FIXME: find out why teh following code causes crashes
//std::vector<int3> boundaryVec(boundary.begin(), boundary.end());
//RandomGeneratorUtil::randomShuffle(boundaryVec, gen->rand);
//for (auto tile : boundaryVec)
for (auto tile : boundary)
{
if (gen->isPossible(tile)) //we can place new treasure only on possible tile
@ -734,19 +758,37 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
if (treasures.size())
{
//find object closest to zone center, then con nect it to the middle of the zone
//find object closest to zone center, then connect it to the middle of the zone
int3 zoneCenter = getPos();
int3 closestTile = int3(-1,-1,-1);
float minDistance = 1e10;
for (auto treasure : treasures)
for (auto visitablePos : info.visitableFromBottomPositions) //objects that are not visitable from top must be accessible from bottom or side
{
if (zoneCenter.dist2d(treasure.first) < minDistance)
if (zoneCenter.dist2d(visitablePos) < minDistance)
{
closestTile = treasure.first;
minDistance = zoneCenter.dist2d(treasure.first);
closestTile = visitablePos - int3 (0,-1, 0); //start below object, possibly even outside the map (?)
minDistance = zoneCenter.dist2d(visitablePos);
}
}
if (!closestTile.valid())
{
for (auto visitablePos : info.visitableFromTopPositions) //all objects are accessible from any direction
{
if (zoneCenter.dist2d(visitablePos) < minDistance)
{
closestTile = visitablePos;
minDistance = zoneCenter.dist2d(visitablePos);
}
}
}
assert (closestTile.valid());
for (auto tile : info.blockedPositions)
{
if (gen->map->isInTheMap(tile)) //pile boundary may reach map border
gen->setOccupied(tile, ETileType::USED); //so that crunch path doesn't cut through objects
}
if (!crunchPath (gen, closestTile, findClosestTile(freePaths, closestTile), id)) //make sure pile is connected to the middle of zone
{
for (auto treasure : treasures)
@ -1380,16 +1422,27 @@ ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, CTreasurePileI
if (oi.value >= minValue && oi.value <= value)
{
int3 visitableOffset = oi.templ.getVisitableOffset(); //visitablePos assumes object will be shifter by visitableOffset
if (info.visitablePositions.size()) //do not try to match first object in zone
int3 visitablePos = info.nextTreasurePos;
if (info.visitableFromBottomPositions.size() + info.visitableFromTopPositions.size()) //do not try to match first object in zone
{
bool fitsHere = false;
int3 visitablePos = info.nextTreasurePos;
if (oi.templ.isVisitableFromTop())
if (oi.templ.isVisitableFromTop()) //can be accessed from any direction
{
for (auto tile : info.visitablePositions)
for (auto tile : info.visitableFromTopPositions)
{
int3 actualTile = tile + visitableOffset;
if (visitablePos.areNeighbours(actualTile)) //we access object from any position
if (visitablePos.areNeighbours(actualTile)) //we access other removable object from any position
{
fitsHere = true;
break;
}
}
for (auto tile : info.visitableFromBottomPositions)
{
int3 actualTile = tile + visitableOffset;
if (visitablePos.areNeighbours(actualTile) && visitablePos.y <= actualTile.y) //we access existing static object from side or bottom only
{
fitsHere = true;
break;
@ -1398,26 +1451,33 @@ ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, CTreasurePileI
}
else
{
//if object is not visitable from top, it must be accessible from below or side
//if object is not visitable from top, it must be accessible from below or side
for (auto tile : info.visitableFromTopPositions)
{
int3 actualTile = tile + visitableOffset;
if (visitablePos.areNeighbours(actualTile) && visitablePos.y >= actualTile.y) //we access object from below or side
if (visitablePos.areNeighbours(actualTile) && visitablePos.y >= actualTile.y) //we access existing removable object from top or side only
{
fitsHere = true;
break;
}
}
for (auto tile : info.visitableFromBottomPositions)
{
int3 actualTile = tile + visitableOffset;
if (visitablePos.areNeighbours(actualTile) && visitablePos.y == actualTile.y) //we access other static object from side only
{
fitsHere = true;
break;
}
}
}
if (!fitsHere)
continue;
}
//now check blockmap, including our already reserved pile area
//now check blockmap, including our already reserved pile area
bool fitsBlockmap = true;
std::set<int3> blockedOffsets = oi.templ.getBlockedOffsets();
blockedOffsets.insert (visitableOffset);
for (auto blockingTile : blockedOffsets)

View File

@ -78,9 +78,10 @@ struct DLL_LINKAGE ObjectInfo
struct DLL_LINKAGE CTreasurePileInfo
{
std::set<int3> visitablePositions; //can be visited only from bottom or side
std::set<int3> visitableFromBottomPositions; //can be visited only from bottom or side
std::set<int3> visitableFromTopPositions; //they can be visited from any direction
std::set<int3> occupiedPositions;
std::set<int3> blockedPositions;
std::set<int3> occupiedPositions; //blocked + visitable
int3 nextTreasurePos;
};