diff --git a/lib/rmg/CMapGenerator.cpp b/lib/rmg/CMapGenerator.cpp index 5ea3e8b54..4e388a6dc 100644 --- a/lib/rmg/CMapGenerator.cpp +++ b/lib/rmg/CMapGenerator.cpp @@ -60,6 +60,8 @@ void CMapGenerator::initTiles() tiles[i][j] = new CTileInfo[level]; } } + + zoneColouring.resize(boost::extents[map->twoLevel ? 2 : 1][map->width][map->height]); } CMapGenerator::~CMapGenerator() @@ -697,6 +699,20 @@ CTileInfo CMapGenerator::getTile(const int3& tile) const return tiles[tile.x][tile.y][tile.z]; } +TRmgTemplateZoneId CMapGenerator::getZoneID(const int3& tile) const +{ + checkIsOnMap(tile); + + return zoneColouring[tile.z][tile.x][tile.y]; +} + +void CMapGenerator::setZoneID(const int3& tile, TRmgTemplateZoneId zid) +{ + checkIsOnMap(tile); + + zoneColouring[tile.z][tile.x][tile.y] = zid; +} + bool CMapGenerator::isAllowedSpell(SpellID sid) const { assert(sid >= 0); diff --git a/lib/rmg/CMapGenerator.h b/lib/rmg/CMapGenerator.h index 122b25581..a52b0b67d 100644 --- a/lib/rmg/CMapGenerator.h +++ b/lib/rmg/CMapGenerator.h @@ -94,12 +94,16 @@ public: ui32 getZoneCount(TFaction faction); ui32 getTotalZoneCount() const; + TRmgTemplateZoneId getZoneID(const int3& tile) const; + void setZoneID(const int3& tile, TRmgTemplateZoneId zid); + private: std::map zones; std::map zonesPerFaction; ui32 zonesTotal; //zones that have their main town only CTileInfo*** tiles; + boost::multi_array zoneColouring; //[z][x][y] int prisonsRemaining; //int questArtsRemaining; diff --git a/lib/rmg/CRmgTemplateZone.cpp b/lib/rmg/CRmgTemplateZone.cpp index 940996269..fdd8b811e 100644 --- a/lib/rmg/CRmgTemplateZone.cpp +++ b/lib/rmg/CRmgTemplateZone.cpp @@ -430,15 +430,21 @@ void CRmgTemplateZone::createBorder(CMapGenerator* gen) { for (auto tile : tileinfo) { - gen->foreach_neighbour (tile, [this, gen](int3 &pos) + bool edge = false; + gen->foreach_neighbour(tile, [this, gen, &edge](int3 &pos) { - if (!vstd::contains(this->tileinfo, pos)) + if (edge) + return; //optimization - do it only once + if (gen->getZoneID(pos) != id) //optimization - better than set search { - gen->foreach_neighbour (pos, [this, gen](int3 &pos) + //we are edge if at least one tile does not belong to zone + //mark all nearby tiles blocked and we're done + gen->foreach_neighbour (pos, [this, gen](int3 &nearbyPos) { - if (gen->isPossible(pos)) - gen->setOccupied (pos, ETileType::BLOCKED); + if (gen->isPossible(nearbyPos)) + gen->setOccupied(nearbyPos, ETileType::BLOCKED); }); + edge = true; } }); } @@ -663,7 +669,7 @@ do not leave zone border { if (!gen->isBlocked(pos)) { - if (vstd::contains (tileinfo, pos)) + if (gen->getZoneID(pos) == id) { if (gen->isPossible(pos)) { @@ -700,7 +706,7 @@ do not leave zone border { if (currentPos.dist2dSQ(dst) < lastDistance) //try closest tiles from all surrounding unused tiles { - if (vstd::contains(tileinfo, pos)) + if (gen->getZoneID(pos) == id) { if (gen->isPossible(pos)) { @@ -799,7 +805,7 @@ bool CRmgTemplateZone::createRoad(CMapGenerator* gen, const int3& src, const int //if (gen->map->checkForVisitableDir(currentNode, &gen->map->getTile(pos), pos)) //TODO: why it has no effect? if (gen->isFree(pos) || pos == dst || (obj && obj->ID == Obj::MONSTER)) { - if (vstd::contains(this->tileinfo, pos) || pos == dst) //otherwise guard position may appear already connected to other zone. + if (gen->getZoneID(pos) == id || pos == dst) //otherwise guard position may appear already connected to other zone. { cameFrom[pos] = currentNode; open.insert(pos); @@ -867,18 +873,19 @@ bool CRmgTemplateZone::connectPath(CMapGenerator* gen, const int3& src, bool onl { auto foo = [gen, this, &open, &closed, &cameFrom, ¤tNode, &distances](int3& pos) -> void { + if (gen->isBlocked(pos)) //no paths through blocked or occupied tiles + return; + int distance = distances[currentNode] + 1; int bestDistanceSoFar = 1e6; //FIXME: boost::limits auto it = distances.find(pos); if (it != distances.end()) bestDistanceSoFar = it->second; - if (gen->isBlocked(pos)) //no paths through blocked or occupied tiles - return; if (distance < bestDistanceSoFar || !vstd::contains(closed, pos)) { //auto obj = gen->map->getTile(pos).topVisitableObj(); - if (vstd::contains(this->tileinfo, pos)) + if (gen->getZoneID(pos) == id) { cameFrom[pos] = currentNode; open.insert(pos); @@ -962,7 +969,7 @@ bool CRmgTemplateZone::connectWithCenter(CMapGenerator* gen, const int3& src, bo if (distance < bestDistanceSoFar || !vstd::contains(closed, pos)) { //auto obj = gen->map->getTile(pos).topVisitableObj(); - if (vstd::contains(this->tileinfo, pos)) + if (gen->getZoneID(pos) == id) { cameFrom[pos] = currentNode; open.insert(pos); @@ -1879,7 +1886,7 @@ void CRmgTemplateZone::drawRoads(CMapGenerator* gen) } for (auto tile : roadNodes) { - if (vstd::contains(tileinfo, tile)) //mark roads for our nodes, but not for zone guards in other zones + if (gen->getZoneID(tile) == id) //mark roads for our nodes, but not for zone guards in other zones tiles.push_back(tile); } diff --git a/lib/rmg/CZonePlacer.cpp b/lib/rmg/CZonePlacer.cpp index c90907dca..a6b35201d 100644 --- a/lib/rmg/CZonePlacer.cpp +++ b/lib/rmg/CZonePlacer.cpp @@ -541,7 +541,9 @@ void CZonePlacer::assignZones(const CMapGenOptions * mapGenOptions) else distances.push_back (std::make_pair(zone.second, std::numeric_limits::max())); } - boost::min_element(distances, compareByDistance)->first->addTile(pos); //closest tile belongs to zone + auto zone = boost::min_element(distances, compareByDistance)->first; //closest tile belongs to zone + zone->addTile(pos); + gen->setZoneID(pos, zone->getId()); } } }