diff --git a/lib/rmg/CMapGenerator.cpp b/lib/rmg/CMapGenerator.cpp index f0965ba30..696142763 100644 --- a/lib/rmg/CMapGenerator.cpp +++ b/lib/rmg/CMapGenerator.cpp @@ -14,11 +14,11 @@ #include "CRmgTemplateZone.h" #include "CZonePlacer.h" -void CMapGenerator::foreach_neighbour(const int3 &pos, std::function foo) +void CMapGenerator::foreach_neighbour(const int3 &pos, std::function foo) { for(const int3 &dir : dirs) { - const int3 n = pos + dir; + int3 n = pos + dir; if(map->isInTheMap(n)) foo(pos+dir); } @@ -227,6 +227,7 @@ void CMapGenerator::fillZones() logGlobal->infoStream() << "Started filling zones"; for(auto it : zones) { + it.second->createBorder(this); it.second->fill(this); } logGlobal->infoStream() << "Zones filled successfully"; @@ -249,28 +250,28 @@ std::map CMapGenerator::getZones() const return zones; } -bool CMapGenerator::isBlocked(int3 &tile) const +bool CMapGenerator::isBlocked(const int3 &tile) const { if (!map->isInTheMap(tile)) throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile)); return tiles[tile.x][tile.y][tile.z].isBlocked(); } -bool CMapGenerator::shouldBeBlocked(int3 &tile) const +bool CMapGenerator::shouldBeBlocked(const int3 &tile) const { if (!map->isInTheMap(tile)) throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile)); return tiles[tile.x][tile.y][tile.z].shouldBeBlocked(); } -bool CMapGenerator::isPossible(int3 &tile) const +bool CMapGenerator::isPossible(const int3 &tile) const { if (!map->isInTheMap(tile)) throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile)); return tiles[tile.x][tile.y][tile.z].isPossible(); } -bool CMapGenerator::isFree(int3 &tile) const +bool CMapGenerator::isFree(const int3 &tile) const { if (!map->isInTheMap(tile)) throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile)); @@ -284,3 +285,27 @@ void CMapGenerator::setOccupied(int3 &tile, ETileType::ETileType state) tiles[tile.x][tile.y][tile.z].setOccupied(state); } + +CTileInfo CMapGenerator::getTile(int3 tile) const +{ + if (!map->isInTheMap(tile)) + throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile)); + + return tiles[tile.x][tile.y][tile.z]; +} + +void CMapGenerator::setNearestObjectDistance(int3 &tile, int value) +{ + if (!map->isInTheMap(tile)) + throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile)); + + tiles[tile.x][tile.y][tile.z].setNearestObjectDistance(value); +} + +int CMapGenerator::getNearestObjectDistance(const int3 &tile) const +{ + if (!map->isInTheMap(tile)) + throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile)); + + return tiles[tile.x][tile.y][tile.z].getNearestObjectDistance(); +} \ No newline at end of file diff --git a/lib/rmg/CMapGenerator.h b/lib/rmg/CMapGenerator.h index e5872926c..9d53a7059 100644 --- a/lib/rmg/CMapGenerator.h +++ b/lib/rmg/CMapGenerator.h @@ -64,13 +64,17 @@ public: CMapEditManager * editManager; std::map getZones() const; - void foreach_neighbour(const int3 &pos, std::function foo); + void foreach_neighbour(const int3 &pos, std::function foo); - bool isBlocked(int3 &tile) const; - bool shouldBeBlocked(int3 &tile) const; - bool isPossible(int3 &tile) const; - bool isFree(int3 &tile) const; + bool isBlocked(const int3 &tile) const; + bool shouldBeBlocked(const int3 &tile) const; + bool isPossible(const int3 &tile) const; + bool isFree(const int3 &tile) const; void setOccupied(int3 &tile, ETileType::ETileType state); + CTileInfo getTile(int3 tile) const; + + int getNearestObjectDistance(const int3 &tile) const; + void setNearestObjectDistance(int3 &tile, int value); private: std::map zones; diff --git a/lib/rmg/CRmgTemplateZone.cpp b/lib/rmg/CRmgTemplateZone.cpp index 49730b6da..32ec68c3d 100644 --- a/lib/rmg/CRmgTemplateZone.cpp +++ b/lib/rmg/CRmgTemplateZone.cpp @@ -313,7 +313,19 @@ void CRmgTemplateZone::setPos(const int3 &Pos) void CRmgTemplateZone::addTile (const int3 &pos) { - tileinfo[pos] = CTileInfo(); + tileinfo.insert(pos); +} + +void CRmgTemplateZone::createBorder(CMapGenerator* gen) +{ + for (auto tile : tileinfo) + { + gen->foreach_neighbour (tile, [this, gen](int3 &pos) + { + if (!vstd::contains(this->tileinfo, pos)) + gen->setOccupied (pos, ETileType::BLOCKED); + }); + } } bool CRmgTemplateZone::fill(CMapGenerator* gen) @@ -385,7 +397,7 @@ bool CRmgTemplateZone::fill(CMapGenerator* gen) std::vector tiles; for (auto tile : tileinfo) { - tiles.push_back (tile.first); + tiles.push_back (tile); } gen->editManager->getTerrainSelection().setSelection(tiles); gen->editManager->drawTerrain(VLC->townh->factions[townId]->nativeTerrain, &gen->rand); @@ -439,14 +451,14 @@ bool CRmgTemplateZone::fill(CMapGenerator* gen) auto sel = gen->editManager->getTerrainSelection(); sel.clearSelection(); - for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it) + for (auto tile : tileinfo) { - if (it->second.shouldBeBlocked()) //fill tiles that should be blocked with obstacles + if (gen->shouldBeBlocked(tile)) //fill tiles that should be blocked with obstacles { auto obj = new CGObjectInstance(); obj->ID = static_cast(130); obj->subID = 0; - placeObject(gen, obj, it->first); + placeObject(gen, obj, tile); } } //logGlobal->infoStream() << boost::format("Filling %d with ROCK") % sel.getSelectedItems().size(); @@ -465,18 +477,18 @@ bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance* auto ow = obj->getWidth(); auto oh = obj->getHeight(); //logGlobal->infoStream() << boost::format("Min dist for density %f is %d") % density % min_dist; - for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it) + for(auto tile : tileinfo) { - auto &ti = it->second; - auto p = it->first; + auto &ti = gen->getTile(tile); auto dist = ti.getNearestObjectDistance(); //avoid borders - if ((p.x < 3) || (w - p.x < 3) || (p.y < 3) || (h - p.y < 3)) + if ((tile.x < 3) || (w - tile.x < 3) || (tile.y < 3) || (h - tile.y < 3)) continue; - if (!ti.isBlocked() && (dist >= min_dist) && (dist > best_distance)) + if (gen->isPossible(tile) && (dist >= min_dist) && (dist > best_distance)) { best_distance = dist; - pos = p; + pos = tile; + gen->setOccupied(pos, ETileType::BLOCKED); result = true; } } @@ -519,15 +531,15 @@ void CRmgTemplateZone::placeObject(CMapGenerator* gen, CGObjectInstance* object, points.insert(pos); for(auto const &p : points) { - if (tileinfo.find(pos + p) != tileinfo.end()) + if (vstd::contains(tileinfo, pos + p)) { - tileinfo[pos + p].setOccupied(ETileType::USED); + gen->setOccupied(pos + p, ETileType::USED); } } - for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it) + for(auto tile : tileinfo) { - si32 d = pos.dist2d(it->first); - it->second.setNearestObjectDistance(std::min(d, it->second.getNearestObjectDistance())); + si32 d = pos.dist2d(tile); + gen->setNearestObjectDistance(tile, std::min(d, gen->getNearestObjectDistance(tile))); } } @@ -537,32 +549,22 @@ bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object, logGlobal->traceStream() << boost::format("Guard object at %d %d") % object->pos.x % object->pos.y; int3 visitable = object->visitablePos(); std::vector tiles; - for(int i = -1; i < 2; ++i) + gen->foreach_neighbour(visitable, [&](int3& pos) { - for(int j = -1; j < 2; ++j) + logGlobal->traceStream() << boost::format("Block at %d %d") % pos.x % pos.y; + if (gen->isPossible(pos)) { - auto it = tileinfo.find(visitable + int3(i, j, 0)); - if (it != tileinfo.end()) - { - if (it->first != visitable) - { - logGlobal->traceStream() << boost::format("Block at %d %d") % it->first.x % it->first.y; - if (it->second.isPossible()) - { - tiles.push_back(it->first); - it->second.setOccupied(ETileType::BLOCKED); - } - } - } - } - } + tiles.push_back(pos); + gen->setOccupied(pos, ETileType::BLOCKED); + }; + }); if ( ! tiles.size()) { logGlobal->infoStream() << "Failed"; return false; } auto guard_tile = *RandomGeneratorUtil::nextItem(tiles, gen->rand); - tileinfo[guard_tile].setOccupied(ETileType::USED); + gen->setOccupied (guard_tile, ETileType::USED); auto guard = new CGCreature(); guard->ID = Obj::RANDOM_MONSTER; guard->subID = 0; diff --git a/lib/rmg/CRmgTemplateZone.h b/lib/rmg/CRmgTemplateZone.h index b318ae9f2..19174d442 100644 --- a/lib/rmg/CRmgTemplateZone.h +++ b/lib/rmg/CRmgTemplateZone.h @@ -112,6 +112,7 @@ public: void addTile (const int3 &pos); void setShape(std::vector shape); bool fill(CMapGenerator* gen); + void createBorder(CMapGenerator* gen); void addConnection(TRmgTemplateZoneId otherZone); std::vector getConnections() const; @@ -136,7 +137,7 @@ private: //placement info int3 pos; float3 center; - std::map tileinfo; //irregular area assined to zone + std::set tileinfo; //irregular area assined to zone std::vector connections; //list of adjacent zones std::map alreadyConnected; //TODO: allow multiple connections between two zones?