diff --git a/ChangeLog b/ChangeLog index 64ba175f1..963c4e4e4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,7 +15,7 @@ SPELLS: * New configuration format: http://wiki.vcmi.eu/index.php?title=Spell_Format RANDOM MAP GENERATOR -* Towns form mods cna be used +* Towns from mods can be used * Reading connections, terrains, towns and mines from template * Zone placement * Zone borders and connections, fractalized paths inside zones diff --git a/lib/mapObjects/CObjectHandler.cpp b/lib/mapObjects/CObjectHandler.cpp index b03980f8c..a08e77bf0 100644 --- a/lib/mapObjects/CObjectHandler.cpp +++ b/lib/mapObjects/CObjectHandler.cpp @@ -178,16 +178,7 @@ std::set CGObjectInstance::getBlockedPos() const std::set CGObjectInstance::getBlockedOffsets() const { - std::set ret; - for(int w=0; w ObjectTemplate::getBlockedOffsets() const +{ + std::set ret; + for(int w = 0; w < getWidth(); ++w) + { + for(int h = 0; h < getHeight(); ++h) + { + if (isBlockedAt(w, h)) + ret.insert(int3(-w, -h, 0)); + } + } + return ret; +} + +int3 ObjectTemplate::getBlockMapOffset() const +{ + for(int w = 0; w < getWidth(); ++w) + { + for(int h = 0; h < getHeight(); ++h) + { + if (isBlockedAt(w, h)) + return int3(-w, -h, 0); + } + } + return int3(-1,-1,-1); +} + bool ObjectTemplate::isVisitableFrom(si8 X, si8 Y) const { // visitDir uses format diff --git a/lib/mapObjects/ObjectTemplate.h b/lib/mapObjects/ObjectTemplate.h index 89353b26c..62320363e 100644 --- a/lib/mapObjects/ObjectTemplate.h +++ b/lib/mapObjects/ObjectTemplate.h @@ -15,6 +15,7 @@ class CBinaryReader; class CLegacyConfigParser; class JsonNode; +class int3; class DLL_LINKAGE ObjectTemplate { @@ -56,6 +57,8 @@ public: bool isVisitableAt(si32 X, si32 Y) const; bool isVisibleAt(si32 X, si32 Y) const; bool isBlockedAt(si32 X, si32 Y) const; + std::set getBlockedOffsets() const; + int3 getBlockMapOffset() const; //bottom-right corner when firts blocked tile is // Checks if object is visitable from certain direction. X and Y must be between -1..+1 bool isVisitableFrom(si8 X, si8 Y) const; diff --git a/lib/rmg/CRmgTemplateZone.cpp b/lib/rmg/CRmgTemplateZone.cpp index 2a12ee9b4..598231ee2 100644 --- a/lib/rmg/CRmgTemplateZone.cpp +++ b/lib/rmg/CRmgTemplateZone.cpp @@ -962,20 +962,49 @@ void CRmgTemplateZone::createTreasures(CMapGenerator* gen) void CRmgTemplateZone::createObstacles(CMapGenerator* gen) { + //get all possible obstacles for this terrain + for (auto primaryID : VLC->objtypeh->knownObjects()) + { + for (auto secondaryID : VLC->objtypeh->knownSubObjects(primaryID)) + { + auto handler = VLC->objtypeh->getHandlerFor(primaryID, secondaryID); + if (handler->isStaticObject()) + { + for (auto temp : handler->getTemplates()) + { + if (temp.canBePlacedAt(terrainType) && temp.getBlockMapOffset().valid()) + possibleObstacles.push_back(temp); + } + } + } + } + auto sel = gen->editManager->getTerrainSelection(); sel.clearSelection(); + + auto tryToPlaceObstacleHere = [this, gen](int3& tile)-> bool + { + auto temp = *RandomGeneratorUtil::nextItem(possibleObstacles, gen->rand); + int3 obstaclePos = tile + temp.getBlockMapOffset(); + if (canObstacleBePlacedHere(gen, temp, obstaclePos)) //can be placed here + { + auto obj = VLC->objtypeh->getHandlerFor(temp.id, temp.subid)->create(temp); + placeObject(gen, obj, obstaclePos); + return true; + } + return false; + }; + for (auto tile : tileinfo) { - //test code - block all the map to show paths clearly - //if (gen->isPossible(tile)) - // gen->setOccupied(tile, ETileType::BLOCKED); - if (gen->shouldBeBlocked(tile)) //fill tiles that should be blocked with obstacles { - auto obj = new CGObjectInstance(); - obj->ID = static_cast(57); - obj->subID = 0; - placeObject(gen, obj, tile); + while (!tryToPlaceObstacleHere(tile)); + } + else if (gen->isPossible(tile)) + { + //try to place random obstacle once - if not possible, leave it clear + tryToPlaceObstacleHere(tile); } } } @@ -1031,6 +1060,23 @@ bool CRmgTemplateZone::findPlaceForTreasurePile(CMapGenerator* gen, si32 min_dis return result; } +bool CRmgTemplateZone::canObstacleBePlacedHere(CMapGenerator* gen, ObjectTemplate &temp, int3 &pos) +{ + auto tilesBlockedByObject = temp.getBlockedOffsets(); + + bool allTilesAvailable = true; + for (auto blockingTile : tilesBlockedByObject) + { + int3 t = pos + blockingTile; + if (!gen->map->isInTheMap(t) || !(gen->isPossible(t) || gen->shouldBeBlocked(t))) + { + allTilesAvailable = false; //if at least one tile is not possible, object can't be placed here + break; + } + } + return allTilesAvailable; +} + bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos) { //we need object apperance to deduce free tiles diff --git a/lib/rmg/CRmgTemplateZone.h b/lib/rmg/CRmgTemplateZone.h index 3eb277b94..03532719d 100644 --- a/lib/rmg/CRmgTemplateZone.h +++ b/lib/rmg/CRmgTemplateZone.h @@ -21,6 +21,7 @@ class CMapGenerator; class CTileInfo; class int3; class CGObjectInstance; +class ObjectTemplate; namespace ETemplateZoneType { @@ -173,6 +174,7 @@ private: ui16 totalDensity; std::vector treasureInfo; std::vector possibleObjects; + std::vector possibleObstacles; //content info std::vector> requiredObjects; @@ -189,6 +191,7 @@ private: void addAllPossibleObjects (CMapGenerator* gen); //add objects, including zone-specific, to possibleObjects 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); void checkAndPlaceObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos); void placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos); bool guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str);