1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

Almost correct placement of all objects.

This commit is contained in:
DjWarmonger 2014-07-09 11:38:16 +02:00
parent 2a8ae6310e
commit 927e16d9f5
2 changed files with 64 additions and 64 deletions

View File

@ -657,7 +657,6 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
while (currentValue < minValue)
{
treasures[info.nextTreasurePos] = nullptr;
//not sure if this code makes sense anymore when we can have multiple-tile objects
for (auto treasurePos : treasures)
{
@ -672,27 +671,6 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
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
@ -759,38 +737,44 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
if (treasures.size())
{
//find object closest to zone center, then connect it to the middle of the zone
int3 zoneCenter = getPos();
int3 closestFreeTile (-1,-1,-1);
if (info.visitableFromBottomPositions.size()) //get random treasure tile, starting from objects accessible only from bottom
closestFreeTile = findClosestTile (freePaths, *RandomGeneratorUtil::nextItem(info.visitableFromBottomPositions, gen->rand));
else
closestFreeTile = findClosestTile (freePaths, *RandomGeneratorUtil::nextItem(info.visitableFromTopPositions, gen->rand));
int3 closestTile = int3(-1,-1,-1);
float minDistance = 1e10;
for (auto visitablePos : info.visitableFromBottomPositions) //objects that are not visitable from top must be accessible from bottom or side
{
if (zoneCenter.dist2d(visitablePos) < minDistance)
if (closestFreeTile.dist2d(visitablePos) < minDistance)
{
closestTile = visitablePos - int3 (0,-1, 0); //start below object, possibly even outside the map (?)
minDistance = zoneCenter.dist2d(visitablePos);
minDistance = closestFreeTile.dist2d(visitablePos);
}
}
if (!closestTile.valid())
{
for (auto visitablePos : info.visitableFromTopPositions) //all objects are accessible from any direction
{
if (zoneCenter.dist2d(visitablePos) < minDistance)
if (closestFreeTile.dist2d(visitablePos) < minDistance)
{
closestTile = visitablePos;
minDistance = zoneCenter.dist2d(visitablePos);
minDistance = closestFreeTile.dist2d(visitablePos);
}
}
}
assert (closestTile.valid());
for (auto tile : info.blockedPositions)
for (auto tile : info.occupiedPositions)
{
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
gen->setOccupied(tile, ETileType::BLOCKED); //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
if (!crunchPath (gen, closestTile, closestFreeTile, id))
{
//we can't connect this pile, just block it off and start over
for (auto treasure : treasures)
{
if (gen->isPossible(treasure.first))
@ -1206,6 +1190,31 @@ bool CRmgTemplateZone::canObstacleBePlacedHere(CMapGenerator* gen, ObjectTemplat
return true;
}
bool CRmgTemplateZone::isAccessibleFromAnywhere (CMapGenerator* gen, ObjectTemplate &appearance, int3 &tile, std::set<int3> &tilesBlockedByObject) const
{
bool accessible = false;
for (int x = -1; x < 2; x++)
{
for (int y = -1; y <2; y++)
{
if (x && y) //check only if object is visitable from another tile
{
int3 offset = appearance.getVisitableOffset() + int3(x, y, 0);
if (!vstd::contains(tilesBlockedByObject, offset))
{
int3 nearbyPos = tile + offset;
if (gen->map->isInTheMap(nearbyPos))
{
if (appearance.isVisitableFrom(x, y) && !gen->isBlocked(nearbyPos))
accessible = true;
}
}
}
};
}
return accessible;
}
bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos)
{
//we need object apperance to deduce free tiles
@ -1231,25 +1240,7 @@ bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance*
for (auto tile : tileinfo)
{
//object must be accessible from at least one surounding tile
bool accessible = false;
for (int x = -1; x < 2; x++)
for (int y = -1; y <2; y++)
{
if (x && y) //check only if object is visitable from another tile
{
int3 offset = obj->getVisitableOffset() + int3(x, y, 0);
if (!vstd::contains(tilesBlockedByObject, offset))
{
int3 nearbyPos = tile + offset;
if (gen->map->isInTheMap(nearbyPos))
{
if (obj->appearance.isVisitableFrom(x, y) && !gen->isBlocked(nearbyPos))
accessible = true;
}
}
}
};
if (!accessible)
if (!isAccessibleFromAnywhere(gen, obj->appearance, tile, tilesBlockedByObject))
continue;
auto ti = gen->getTile(tile);
@ -1421,19 +1412,26 @@ 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
int3 visitablePos = info.nextTreasurePos;
int3 newVisitableOffset = oi.templ.getVisitableOffset(); //visitablePos assumes object will be shifter by visitableOffset
int3 newVisitablePos = info.nextTreasurePos;
if (!oi.templ.isVisitableFromTop())
{
//there must be free tiles under object
if (!isAccessibleFromAnywhere(gen, oi.templ, newVisitablePos, oi.templ.getBlockedOffsets()))
continue;
}
if (info.visitableFromBottomPositions.size() + info.visitableFromTopPositions.size()) //do not try to match first object in zone
{
bool fitsHere = false;
if (oi.templ.isVisitableFromTop()) //can be accessed from any direction
if (oi.templ.isVisitableFromTop()) //new can be accessed from any direction
{
for (auto tile : info.visitableFromTopPositions)
{
int3 actualTile = tile + visitableOffset;
if (visitablePos.areNeighbours(actualTile)) //we access other removable object from any position
int3 actualTile = tile + newVisitableOffset;
if (newVisitablePos.areNeighbours(actualTile)) //we access other removable object from any position
{
fitsHere = true;
break;
@ -1441,21 +1439,20 @@ ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, CTreasurePileI
}
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
int3 actualTile = tile + newVisitableOffset;
if (newVisitablePos.areNeighbours(actualTile) && newVisitablePos.y <= actualTile.y) //we access existing static object from side or bottom only
{
fitsHere = true;
break;
}
}
}
else
else //if new 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 existing removable object from top or side only
int3 actualTile = tile + newVisitableOffset;
if (newVisitablePos.areNeighbours(actualTile) && newVisitablePos.y >= actualTile.y) //we access existing removable object from top or side only
{
fitsHere = true;
break;
@ -1463,14 +1460,16 @@ ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, CTreasurePileI
}
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
int3 actualTile = tile + newVisitableOffset;
if (newVisitablePos.areNeighbours(actualTile) && newVisitablePos.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
@ -1479,10 +1478,10 @@ ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, CTreasurePileI
std::set<int3> blockedOffsets = oi.templ.getBlockedOffsets();
blockedOffsets.insert (visitableOffset);
blockedOffsets.insert (newVisitableOffset);
for (auto blockingTile : blockedOffsets)
{
int3 t = info.nextTreasurePos + visitableOffset + blockingTile;
int3 t = info.nextTreasurePos + newVisitableOffset + blockingTile;
if (!gen->map->isInTheMap(t) || vstd::contains(info.occupiedPositions, t))
{
fitsBlockmap = false; //if at least one tile is not possible, object can't be placed here

View File

@ -207,6 +207,7 @@ private:
bool pointIsIn(int x, int y);
void addAllPossibleObjects (CMapGenerator* gen); //add objects, including zone-specific, to possibleObjects
bool isAccessibleFromAnywhere (CMapGenerator* gen, ObjectTemplate &appearance, int3 &tile, std::set<int3> &tilesBlockedByObject) const;
bool findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos);
bool findPlaceForTreasurePile(CMapGenerator* gen, si32 min_dist, int3 &pos);
bool canObstacleBePlacedHere(CMapGenerator* gen, ObjectTemplate &temp, int3 &pos);