From 927e16d9f56bbff58a8fb7244dacef669e453c6b Mon Sep 17 00:00:00 2001 From: DjWarmonger Date: Wed, 9 Jul 2014 11:38:16 +0200 Subject: [PATCH] Almost correct placement of all objects. --- lib/rmg/CRmgTemplateZone.cpp | 127 +++++++++++++++++------------------ lib/rmg/CRmgTemplateZone.h | 1 + 2 files changed, 64 insertions(+), 64 deletions(-) diff --git a/lib/rmg/CRmgTemplateZone.cpp b/lib/rmg/CRmgTemplateZone.cpp index 3824451d7..bdb68fc41 100644 --- a/lib/rmg/CRmgTemplateZone.cpp +++ b/lib/rmg/CRmgTemplateZone.cpp @@ -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 &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 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 diff --git a/lib/rmg/CRmgTemplateZone.h b/lib/rmg/CRmgTemplateZone.h index b1f34da87..5eeba6cc7 100644 --- a/lib/rmg/CRmgTemplateZone.h +++ b/lib/rmg/CRmgTemplateZone.h @@ -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 &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);