diff --git a/lib/rmg/CMapGenerator.cpp b/lib/rmg/CMapGenerator.cpp index 97b94240a..eef894a84 100644 --- a/lib/rmg/CMapGenerator.cpp +++ b/lib/rmg/CMapGenerator.cpp @@ -433,8 +433,11 @@ void CMapGenerator::createConnections() setOccupied (guardPos, ETileType::FREE); //just in case monster is too weak to spawn zoneA->addMonster (this, guardPos, connection.getGuardStrength(), false, true); //zones can make paths only in their own area - zoneA->crunchRoad(this, guardPos, posA, zoneA->getFreePaths()); //make connection towards our zone center - zoneB->crunchRoad(this, guardPos, posB, zoneB->getFreePaths()); //make connection towards other zone center + zoneA->crunchPath(this, guardPos, posA, zoneA->getFreePaths()); //make connection towards our zone center + zoneB->crunchPath(this, guardPos, posB, zoneB->getFreePaths()); //make connection towards other zone center + + zoneA->addRoadNode(guardPos); + zoneB->addRoadNode(guardPos); break; //we're done with this connection } } @@ -528,6 +531,13 @@ void CMapGenerator::addHeaderInfo() addPlayerInfo(); } +void CMapGenerator::checkIsOnMap(const int3& tile) const +{ + if (!map->isInTheMap(tile)) + throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile)); +} + + std::map CMapGenerator::getZones() const { return zones; @@ -535,67 +545,74 @@ std::map CMapGenerator::getZones() 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)); + checkIsOnMap(tile); return tiles[tile.x][tile.y][tile.z].isBlocked(); } 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)); + checkIsOnMap(tile); return tiles[tile.x][tile.y][tile.z].shouldBeBlocked(); } 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)); + checkIsOnMap(tile); return tiles[tile.x][tile.y][tile.z].isPossible(); } 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)); + checkIsOnMap(tile); return tiles[tile.x][tile.y][tile.z].isFree(); } bool CMapGenerator::isUsed(const int3 &tile) const { - if (!map->isInTheMap(tile)) - throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile)); + checkIsOnMap(tile); return tiles[tile.x][tile.y][tile.z].isUsed(); } + +bool CMapGenerator::isRoad(const int3& tile) const +{ + checkIsOnMap(tile); + + return tiles[tile.x][tile.y][tile.z].isRoad(); +} + void CMapGenerator::setOccupied(const int3 &tile, ETileType::ETileType state) { - if (!map->isInTheMap(tile)) - throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile)); + checkIsOnMap(tile); tiles[tile.x][tile.y][tile.z].setOccupied(state); } -CTileInfo CMapGenerator::getTile(const int3& tile) const +void CMapGenerator::setRoad(const int3& tile, ERoadType::ERoadType roadType) { - if (!map->isInTheMap(tile)) - throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile)); + checkIsOnMap(tile); + + tiles[tile.x][tile.y][tile.z].setRoadType(roadType); +} + + +CTileInfo CMapGenerator::getTile(const int3& tile) const +{ + checkIsOnMap(tile); return tiles[tile.x][tile.y][tile.z]; } void CMapGenerator::setNearestObjectDistance(int3 &tile, float value) { - if (!map->isInTheMap(tile)) - throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile)); + checkIsOnMap(tile); tiles[tile.x][tile.y][tile.z].setNearestObjectDistance(value); } float CMapGenerator::getNearestObjectDistance(const int3 &tile) const { - if (!map->isInTheMap(tile)) - throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile)); + checkIsOnMap(tile); return tiles[tile.x][tile.y][tile.z].getNearestObjectDistance(); } diff --git a/lib/rmg/CMapGenerator.h b/lib/rmg/CMapGenerator.h index bca10f076..41abdf74a 100644 --- a/lib/rmg/CMapGenerator.h +++ b/lib/rmg/CMapGenerator.h @@ -73,7 +73,11 @@ public: bool isPossible(const int3 &tile) const; bool isFree(const int3 &tile) const; bool isUsed(const int3 &tile) const; + bool isRoad(const int3 &tile) const; + void setOccupied(const int3 &tile, ETileType::ETileType state); + void setRoad(const int3 &tile, ERoadType::ERoadType roadType); + CTileInfo getTile(const int3 & tile) const; float getNearestObjectDistance(const int3 &tile) const; @@ -100,6 +104,7 @@ private: //int questArtsRemaining; int monolithIndex; std::vector questArtifacts; + void checkIsOnMap(const int3 &tile) const; //throws /// Generation methods std::string getMapDescription() const; diff --git a/lib/rmg/CRmgTemplateZone.cpp b/lib/rmg/CRmgTemplateZone.cpp index 2fa921761..8115b5a1a 100644 --- a/lib/rmg/CRmgTemplateZone.cpp +++ b/lib/rmg/CRmgTemplateZone.cpp @@ -33,6 +33,11 @@ CRmgTemplateZone::CTownInfo::CTownInfo() : townCount(0), castleCount(0), townDen } +void CRmgTemplateZone::addRoadNode(const int3& node) +{ + roadNodes.insert(node); +} + int CRmgTemplateZone::CTownInfo::getTownCount() const { return townCount; @@ -111,6 +116,12 @@ bool CTileInfo::isFree() const { return occupied == ETileType::FREE; } + +bool CTileInfo::isRoad() const +{ + return roadType != ERoadType::NO_ROAD; +} + bool CTileInfo::isUsed() const { return occupied == ETileType::USED; @@ -692,6 +703,8 @@ bool CRmgTemplateZone::crunchRoad(CMapGenerator* gen, const int3& src, const int if(crunchPath(gen, src, dst, ¤tClearedTiles, true)) { roads.insert(std::begin(currentClearedTiles), std::end(currentClearedTiles)); + roads.insert(src); + roads.insert(dst); if(nullptr != clearedTiles) clearedTiles->insert(std::begin(currentClearedTiles), std::end(currentClearedTiles)); @@ -700,7 +713,8 @@ bool CRmgTemplateZone::crunchRoad(CMapGenerator* gen, const int3& src, const int } else { - return false; + logGlobal->warnStream() << boost::format("Failed to crunch road from %s to %s") %src %dst; + return crunchPath(gen, src, dst, clearedTiles, false); } } @@ -1265,6 +1279,7 @@ bool CRmgTemplateZone::placeMines (CMapGenerator* gen) bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen) { logGlobal->traceStream() << "Creating required objects"; + for(const auto &obj : requiredObjects) { int3 pos; @@ -1275,24 +1290,9 @@ bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen) return false; } - switch (obj.first->ID) - { - case Obj::TOWN: - case Obj::MONOLITH_TWO_WAY: - case Obj::SUBTERRANEAN_GATE: - { - crunchRoad(gen, this->pos, pos + obj.first->getVisitableOffset(), &freePaths); - } - break; - - default: - break; - } - - placeObject (gen, obj.first, pos); guardObject (gen, obj.first, obj.second, (obj.first->ID == Obj::MONOLITH_TWO_WAY), true); - //paths to required objects constitute main paths of zone. otherwise they just may lead to middle and create dead zones + //paths to required objects constitute main paths of zone. otherwise they just may lead to middle and create dead zones } for (const auto &obj : closeObjects) @@ -1481,18 +1481,45 @@ void CRmgTemplateZone::createObstacles2(CMapGenerator* gen) } void CRmgTemplateZone::drawRoads(CMapGenerator* gen) +{ + + auto doDrawRoad = []() + { + + }; + + while(!roadNodes.empty()) + { + int3 node = *roadNodes.begin(); + roadNodes.erase(node); + if(roads.empty()) + { + //start road network + roads.insert(node); + } + else + { + + int3 cross = *RandomGeneratorUtil::nextItem(roads, gen->rand); + + crunchRoad(gen, node, cross, &freePaths); + } + } +} + +void CRmgTemplateZone::buildRoads(CMapGenerator* gen) { std::vector tiles; for (auto tile : roads) { - tiles.push_back (tile); + if(gen->map->isInTheMap(tile)) + tiles.push_back (tile); } gen->editManager->getTerrainSelection().setSelection(tiles); - gen->editManager->drawRoad(ERoadType::COBBLESTONE_ROAD, &gen->rand); + gen->editManager->drawRoad(ERoadType::COBBLESTONE_ROAD, &gen->rand); } - bool CRmgTemplateZone::fill(CMapGenerator* gen) { initTerrainType(gen); @@ -1503,11 +1530,11 @@ bool CRmgTemplateZone::fill(CMapGenerator* gen) placeMines(gen); createRequiredObjects(gen); + drawRoads(gen); + buildRoads(gen); fractalize(gen); //after required objects are created and linked with their own paths createTreasures(gen); - drawRoads(gen); - logGlobal->infoStream() << boost::format ("Zone %d filled successfully") %id; return true; } @@ -1718,6 +1745,24 @@ void CRmgTemplateZone::placeObject(CMapGenerator* gen, CGObjectInstance* object, auto artid = sh->quest->m5arts.front(); logGlobal->warnStream() << boost::format("Placed Seer Hut at %s, quest artifact %d is %s") % object->pos % artid % VLC->arth->artifacts[artid]->Name(); } + + + switch (object->ID) + { + case Obj::TOWN: + case Obj::RANDOM_TOWN: + case Obj::MONOLITH_TWO_WAY: + case Obj::MONOLITH_ONE_WAY_ENTRANCE: + case Obj::MONOLITH_ONE_WAY_EXIT: + case Obj::SUBTERRANEAN_GATE: + { + roadNodes.insert(pos + object->getVisitableOffset()); + } + break; + + default: + break; + } } void CRmgTemplateZone::placeAndGuardObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos, si32 str, bool zoneGuard) diff --git a/lib/rmg/CRmgTemplateZone.h b/lib/rmg/CRmgTemplateZone.h index 0726c3d16..1076ceb57 100644 --- a/lib/rmg/CRmgTemplateZone.h +++ b/lib/rmg/CRmgTemplateZone.h @@ -47,10 +47,12 @@ public: bool isPossible() const; bool isFree() const; bool isUsed() const; + bool isRoad() const; void setOccupied(ETileType::ETileType value); ETerrainType getTerrainType() const; ETileType::ETileType getTileType() const; void setTerrainType(ETerrainType value); + void setRoadType(ERoadType::ERoadType value); private: float nearestObjectDistance; @@ -168,7 +170,7 @@ public: void createObstacles1(CMapGenerator* gen); void createObstacles2(CMapGenerator* gen); bool crunchPath(CMapGenerator* gen, const int3 &src, const int3 &dst, std::set* clearedTiles = nullptr, bool forRoad = false); - bool crunchRoad(CMapGenerator* gen, const int3 &src, const int3 &dst, std::set* clearedTiles = nullptr); + std::vector getAccessibleOffsets (CMapGenerator* gen, CGObjectInstance* object); void addConnection(TRmgTemplateZoneId otherZone); @@ -181,7 +183,7 @@ public: ObjectInfo getRandomObject (CMapGenerator* gen, CTreasurePileInfo &info, ui32 desiredValue, ui32 maxValue, ui32 currentValue); void placeAndGuardObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos, si32 str, bool zoneGuard = false); - + void addRoadNode(const int3 & node); private: //template info TRmgTemplateZoneId id; @@ -218,9 +220,11 @@ private: std::vector connections; //list of adjacent zones std::set freePaths; //core paths of free tiles that all other objects will be linked to - std::set roads; + std::set roadNodes; //tiles to be connected with roads + std::set roads; //all tiles with roads - void drawRoads(CMapGenerator* gen); + void drawRoads(CMapGenerator* gen); //fills "roads" according to "roadNodes" + void buildRoads(CMapGenerator* gen); //actually updates tiles bool pointIsIn(int x, int y); void addAllPossibleObjects (CMapGenerator* gen); //add objects, including zone-specific, to possibleObjects @@ -233,4 +237,6 @@ private: void checkAndPlaceObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos); void placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos, bool updateDistance = true); bool guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str, bool zoneGuard = false, bool addToFreePaths = false); + //TODO:replace with A*-based algorithm on whole road network + bool crunchRoad(CMapGenerator* gen, const int3 &src, const int3 &dst, std::set* clearedTiles = nullptr); };