From 1e1dce20a8bae7d118b496956fad6beb9bacc0f2 Mon Sep 17 00:00:00 2001 From: DjWarmonger Date: Thu, 22 May 2014 19:25:17 +0200 Subject: [PATCH] Something that compiles, but crashes when launching RMG map. --- lib/CGameState.cpp | 4 +- lib/rmg/CMapGenOptions.cpp | 10 +- lib/rmg/CMapGenOptions.h | 42 +- lib/rmg/CMapGenerator.cpp | 1380 +------------------------------ lib/rmg/CMapGenerator.h | 405 +-------- lib/rmg/CRmgTemplateStorage.cpp | 2 +- lib/rmg/CRmgTemplateZone.cpp | 328 ++++++++ lib/rmg/CRmgTemplateZone.h | 39 +- 8 files changed, 417 insertions(+), 1793 deletions(-) diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 0752eef9b..8d740018f 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -840,8 +840,8 @@ void CGameState::initNewGame() CStopWatch sw; // Gen map - CMapGenerator mapGenerator; - map = mapGenerator.generate(scenarioOps->mapGenOptions.get(), scenarioOps->seedToBeUsed).release(); + CMapGenerator mapGenerator(*scenarioOps->mapGenOptions, std::time(nullptr)); + map = mapGenerator.generate(); // Update starting options for(int i = 0; i < map->players.size(); ++i) diff --git a/lib/rmg/CMapGenOptions.cpp b/lib/rmg/CMapGenOptions.cpp index 089cba908..b2835020d 100644 --- a/lib/rmg/CMapGenOptions.cpp +++ b/lib/rmg/CMapGenOptions.cpp @@ -194,17 +194,17 @@ void CMapGenOptions::finalize(CRandomGenerator & rand) auto possiblePlayers = mapTemplate->getPlayers().getNumbers(); possiblePlayers.erase(possiblePlayers.begin(), possiblePlayers.lower_bound(countHumanPlayers())); assert(!possiblePlayers.empty()); - playerCount = *RandomGeneratorUtil::nextItem(possiblePlayers, rand); + playerCount = *std::next(possiblePlayers.begin(), rand.nextInt(8)); updatePlayers(); } if(teamCount == RANDOM_SIZE) { - teamCount = rand.nextInt(playerCount - 1); + teamCount = rand.nextInt(8); } if(compOnlyPlayerCount == RANDOM_SIZE) { auto possiblePlayers = mapTemplate->getCpuPlayers().getNumbers(); - compOnlyPlayerCount = *RandomGeneratorUtil::nextItem(possiblePlayers, rand); + compOnlyPlayerCount = *std::next(possiblePlayers.begin(), rand.nextInt(8)); updateCompOnlyPlayers(); } if(compOnlyTeamCount == RANDOM_SIZE) @@ -220,11 +220,11 @@ void CMapGenOptions::finalize(CRandomGenerator & rand) if(waterContent == EWaterContent::RANDOM) { - waterContent = static_cast(rand.nextInt(2)); + waterContent = static_cast(rand.nextInt(EWaterContent::TOTAL_COUNT)); } if(monsterStrength == EMonsterStrength::RANDOM) { - monsterStrength = static_cast(rand.nextInt(2)); + monsterStrength = static_cast(rand.nextInt(EMonsterStrength::TOTAL_COUNT)); } } diff --git a/lib/rmg/CMapGenOptions.h b/lib/rmg/CMapGenOptions.h index 2c23eb181..8319bba50 100644 --- a/lib/rmg/CMapGenOptions.h +++ b/lib/rmg/CMapGenOptions.h @@ -18,34 +18,36 @@ class CRmgTemplate; namespace EWaterContent { -enum EWaterContent -{ - RANDOM = -1, - NONE, - NORMAL, - ISLANDS -}; + enum EWaterContent + { + RANDOM = -1, + NONE, + NORMAL, + ISLANDS, + TOTAL_COUNT + }; } namespace EMonsterStrength { -enum EMonsterStrength -{ - RANDOM = -1, - WEAK, - NORMAL, - STRONG -}; + enum EMonsterStrength + { + RANDOM = -1, + WEAK, + NORMAL, + STRONG, + TOTAL_COUNT + }; } namespace EPlayerType { -enum EPlayerType -{ - HUMAN, - AI, - COMP_ONLY -}; + enum EPlayerType + { + HUMAN, + AI, + COMP_ONLY + }; } /// The map gen options class holds values about general map generation settings diff --git a/lib/rmg/CMapGenerator.cpp b/lib/rmg/CMapGenerator.cpp index c9d72aa24..5c4bc42e9 100644 --- a/lib/rmg/CMapGenerator.cpp +++ b/lib/rmg/CMapGenerator.cpp @@ -10,401 +10,13 @@ #include "../CTownHandler.h" #include "../StringConstants.h" #include "../filesystem/Filesystem.h" - -CMapGenOptions::CMapGenOptions() : width(CMapHeader::MAP_SIZE_MIDDLE), height(CMapHeader::MAP_SIZE_MIDDLE), hasTwoLevels(false), - playerCount(RANDOM_SIZE), teamCount(RANDOM_SIZE), compOnlyPlayerCount(0), compOnlyTeamCount(RANDOM_SIZE), - waterContent(EWaterContent::RANDOM), monsterStrength(EMonsterStrength::RANDOM), mapTemplate(nullptr) -{ - resetPlayersMap(); -} - -si32 CMapGenOptions::getWidth() const -{ - return width; -} - -void CMapGenOptions::setWidth(si32 value) -{ - assert(value >= 1); - width = value; -} - -si32 CMapGenOptions::getHeight() const -{ - return height; -} - -void CMapGenOptions::setHeight(si32 value) -{ - assert(value >= 1); - height = value; -} - -bool CMapGenOptions::getHasTwoLevels() const -{ - return hasTwoLevels; -} - -void CMapGenOptions::setHasTwoLevels(bool value) -{ - hasTwoLevels = value; -} - -si8 CMapGenOptions::getPlayerCount() const -{ - return playerCount; -} - -void CMapGenOptions::setPlayerCount(si8 value) -{ - assert((value >= 1 && value <= PlayerColor::PLAYER_LIMIT_I) || value == RANDOM_SIZE); - playerCount = value; - resetPlayersMap(); -} - -si8 CMapGenOptions::getTeamCount() const -{ - return teamCount; -} - -void CMapGenOptions::setTeamCount(si8 value) -{ - assert(playerCount == RANDOM_SIZE || (value >= 0 && value < playerCount) || value == RANDOM_SIZE); - teamCount = value; -} - -si8 CMapGenOptions::getCompOnlyPlayerCount() const -{ - return compOnlyPlayerCount; -} - -void CMapGenOptions::setCompOnlyPlayerCount(si8 value) -{ - assert(value == RANDOM_SIZE || (value >= 0 && value <= PlayerColor::PLAYER_LIMIT_I - playerCount)); - compOnlyPlayerCount = value; - resetPlayersMap(); -} - -si8 CMapGenOptions::getCompOnlyTeamCount() const -{ - return compOnlyTeamCount; -} - -void CMapGenOptions::setCompOnlyTeamCount(si8 value) -{ - assert(value == RANDOM_SIZE || compOnlyPlayerCount == RANDOM_SIZE || (value >= 0 && value <= std::max(compOnlyPlayerCount - 1, 0))); - compOnlyTeamCount = value; -} - -EWaterContent::EWaterContent CMapGenOptions::getWaterContent() const -{ - return waterContent; -} - -void CMapGenOptions::setWaterContent(EWaterContent::EWaterContent value) -{ - waterContent = value; -} - -EMonsterStrength::EMonsterStrength CMapGenOptions::getMonsterStrength() const -{ - return monsterStrength; -} - -void CMapGenOptions::setMonsterStrength(EMonsterStrength::EMonsterStrength value) -{ - monsterStrength = value; -} - -void CMapGenOptions::resetPlayersMap() -{ - players.clear(); - int realPlayersCnt = playerCount == RANDOM_SIZE ? static_cast(PlayerColor::PLAYER_LIMIT_I) : playerCount; - int realCompOnlyPlayersCnt = compOnlyPlayerCount == RANDOM_SIZE ? (PlayerColor::PLAYER_LIMIT_I - realPlayersCnt) : compOnlyPlayerCount; - for(int color = 0; color < (realPlayersCnt + realCompOnlyPlayersCnt); ++color) - { - CPlayerSettings player; - player.setColor(PlayerColor(color)); - player.setPlayerType((color >= realPlayersCnt) ? EPlayerType::COMP_ONLY : EPlayerType::AI); - players[PlayerColor(color)] = player; - } -} - -const std::map & CMapGenOptions::getPlayersSettings() const -{ - return players; -} - -void CMapGenOptions::setStartingTownForPlayer(PlayerColor color, si32 town) -{ - auto it = players.find(color); - if(it == players.end()) assert(0); - it->second.setStartingTown(town); -} - -void CMapGenOptions::setPlayerTypeForStandardPlayer(PlayerColor color, EPlayerType::EPlayerType playerType) -{ - assert(playerType != EPlayerType::COMP_ONLY); - auto it = players.find(color); - if(it == players.end()) assert(0); - it->second.setPlayerType(playerType); -} - -const CRmgTemplate * CMapGenOptions::getMapTemplate() const -{ - return mapTemplate; -} - -void CMapGenOptions::setMapTemplate(const CRmgTemplate * value) -{ - mapTemplate = value; - //TODO validate & adapt options according to template - assert(0); -} - -const std::map & CMapGenOptions::getAvailableTemplates() const -{ - return CRmgTemplateStorage::get().getTemplates(); -} - -void CMapGenOptions::finalize() -{ - CRandomGenerator gen; - finalize(gen); -} - -void CMapGenOptions::finalize(CRandomGenerator & gen) -{ - if(!mapTemplate) - { - mapTemplate = getPossibleTemplate(gen); - assert(mapTemplate); - } - - if(playerCount == RANDOM_SIZE) - { - auto possiblePlayers = mapTemplate->getPlayers().getNumbers(); - possiblePlayers.erase(possiblePlayers.begin(), possiblePlayers.lower_bound(countHumanPlayers())); - assert(!possiblePlayers.empty()); - playerCount = *std::next(possiblePlayers.begin(), gen.getInteger(0, possiblePlayers.size() - 1)); - updatePlayers(); - } - if(teamCount == RANDOM_SIZE) - { - teamCount = gen.getInteger(0, playerCount - 1); - } - if(compOnlyPlayerCount == RANDOM_SIZE) - { - auto possiblePlayers = mapTemplate->getCpuPlayers().getNumbers(); - compOnlyPlayerCount = *std::next(possiblePlayers.begin(), gen.getInteger(0, possiblePlayers.size() - 1)); - updateCompOnlyPlayers(); - } - if(compOnlyTeamCount == RANDOM_SIZE) - { - compOnlyTeamCount = gen.getInteger(0, std::max(compOnlyPlayerCount - 1, 0)); - } - - // 1 team isn't allowed - if(teamCount == 1 && compOnlyPlayerCount == 0) - { - teamCount = 0; - } - - if(waterContent == EWaterContent::RANDOM) - { - waterContent = static_cast(gen.getInteger(0, 2)); - } - if(monsterStrength == EMonsterStrength::RANDOM) - { - monsterStrength = static_cast(gen.getInteger(0, 2)); - } -} - -void CMapGenOptions::updatePlayers() -{ - // Remove AI players only from the end of the players map if necessary - for(auto itrev = players.end(); itrev != players.begin();) - { - auto it = itrev; - --it; - if(players.size() == playerCount) break; - if(it->second.getPlayerType() == EPlayerType::AI) - { - players.erase(it); - } - else - { - --itrev; - } - } -} - -void CMapGenOptions::updateCompOnlyPlayers() -{ - auto totalPlayersCnt = playerCount + compOnlyPlayerCount; - - // Remove comp only players only from the end of the players map if necessary - for(auto itrev = players.end(); itrev != players.begin();) - { - auto it = itrev; - --it; - if(players.size() <= totalPlayersCnt) break; - if(it->second.getPlayerType() == EPlayerType::COMP_ONLY) - { - players.erase(it); - } - else - { - --itrev; - } - } - - // Add some comp only players if necessary - auto compOnlyPlayersToAdd = totalPlayersCnt - players.size(); - for(int i = 0; i < compOnlyPlayersToAdd; ++i) - { - CPlayerSettings pSettings; - pSettings.setPlayerType(EPlayerType::COMP_ONLY); - pSettings.setColor(getNextPlayerColor()); - players[pSettings.getColor()] = pSettings; - } -} - -int CMapGenOptions::countHumanPlayers() const -{ - return static_cast(boost::count_if(players, [](const std::pair & pair) - { - return pair.second.getPlayerType() == EPlayerType::HUMAN; - })); -} - -PlayerColor CMapGenOptions::getNextPlayerColor() const -{ - for(PlayerColor i = PlayerColor(0); i < PlayerColor::PLAYER_LIMIT; i.advance(1)) - { - if(!players.count(i)) - { - return i; - } - } - assert(0); - return PlayerColor(0); -} - -bool CMapGenOptions::checkOptions() const -{ - assert(countHumanPlayers() > 0); - if(mapTemplate) - { - return true; - } - else - { - CRandomGenerator gen; - return getPossibleTemplate(gen) != nullptr; - } -} - -const CRmgTemplate * CMapGenOptions::getPossibleTemplate(CRandomGenerator & gen) const -{ - // Find potential templates - const auto & tpls = getAvailableTemplates(); - std::list potentialTpls; - for(const auto & tplPair : tpls) - { - const auto & tpl = tplPair.second; - CRmgTemplate::CSize tplSize(width, height, hasTwoLevels); - if(tplSize >= tpl.getMinSize() && tplSize <= tpl.getMaxSize()) - { - bool isPlayerCountValid = false; - if(playerCount != RANDOM_SIZE) - { - if(tpl.getPlayers().isInRange(playerCount)) isPlayerCountValid = true; - } - else - { - // Human players shouldn't be banned when playing with random player count - auto playerNumbers = tpl.getPlayers().getNumbers(); - if(playerNumbers.lower_bound(countHumanPlayers()) != playerNumbers.end()) - { - isPlayerCountValid = true; - } - } - - if(isPlayerCountValid) - { - bool isCpuPlayerCountValid = false; - if(compOnlyPlayerCount != RANDOM_SIZE) - { - if(tpl.getCpuPlayers().isInRange(compOnlyPlayerCount)) isCpuPlayerCountValid = true; - } - else - { - isCpuPlayerCountValid = true; - } - - if(isCpuPlayerCountValid) potentialTpls.push_back(&tpl); - } - } - } - - // Select tpl - if(potentialTpls.empty()) - { - return nullptr; - } - else - { - return *std::next(potentialTpls.begin(), gen.getInteger(0, potentialTpls.size() - 1)); - } -} - -CMapGenOptions::CPlayerSettings::CPlayerSettings() : color(0), startingTown(RANDOM_TOWN), playerType(EPlayerType::AI) -{ - -} - -PlayerColor CMapGenOptions::CPlayerSettings::getColor() const -{ - return color; -} - -void CMapGenOptions::CPlayerSettings::setColor(PlayerColor value) -{ - assert(value >= PlayerColor(0) && value < PlayerColor::PLAYER_LIMIT); - color = value; -} - -si32 CMapGenOptions::CPlayerSettings::getStartingTown() const -{ - return startingTown; -} - -void CMapGenOptions::CPlayerSettings::setStartingTown(si32 value) -{ - assert(value >= -1); - if(value >= 0) - { - assert(value < static_cast(VLC->townh->factions.size())); - assert(VLC->townh->factions[value]->town != nullptr); - } - startingTown = value; -} - -EPlayerType::EPlayerType CMapGenOptions::CPlayerSettings::getPlayerType() const -{ - return playerType; -} - -void CMapGenOptions::CPlayerSettings::setPlayerType(EPlayerType::EPlayerType value) -{ - playerType = value; -} +#include "CRmgTemplate.h" +#include "CRmgTemplateZone.h" CMapGenerator::CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed /*= std::time(nullptr)*/) : mapGenOptions(mapGenOptions), randomSeed(randomSeed) { - gen.seed(randomSeed); + rand.setSeed(randomSeed); } CMapGenerator::~CMapGenerator() @@ -412,11 +24,11 @@ CMapGenerator::~CMapGenerator() } -std::unique_ptr CMapGenerator::generate() +ConstTransitivePtr CMapGenerator::generate() { - mapGenOptions.finalize(gen); + mapGenOptions.finalize(rand); - map = make_unique(); + //map = make_unique(); editManager = map->getEditManager(); editManager->getUndoManager().setUndoRedoLimit(0); addHeaderInfo(); @@ -502,7 +114,7 @@ void CMapGenerator::addPlayerInfo() { player.canHumanPlay = true; } - auto itTeam = std::next(teamNumbers[j].begin(), gen.getInteger(0, teamNumbers[j].size() - 1)); + auto itTeam = std::next(teamNumbers[j].begin(), rand.nextInt (teamNumbers[j].size())); player.team = TeamID(*itTeam); teamNumbers[j].erase(itTeam); map->players[pSettings.getColor().getNum()] = player; @@ -515,9 +127,9 @@ void CMapGenerator::addPlayerInfo() void CMapGenerator::genZones() { map->initTerrain(); - editManager->clearTerrain(&gen); + editManager->clearTerrain(&rand); editManager->getTerrainSelection().selectRange(MapRect(int3(0, 0, 0), mapGenOptions.getWidth(), mapGenOptions.getHeight())); - editManager->drawTerrain(ETerrainType::GRASS, &gen); + editManager->drawTerrain(ETerrainType::GRASS, &rand); auto pcnt = mapGenOptions.getPlayerCount(); auto w = mapGenOptions.getWidth(); @@ -537,7 +149,7 @@ void CMapGenerator::genZones() int part_h = h/player_per_side; for(auto const it : zones) { - CRmgTemplateZone zone = it.second; + CRmgTemplateZone * zone = it.second; std::vector shape; int left = part_w*(i%player_per_side); int top = part_h*(i/player_per_side); @@ -545,8 +157,8 @@ void CMapGenerator::genZones() shape.push_back(int3(left + part_w, top, 0)); shape.push_back(int3(left + part_w, top + part_h, 0)); shape.push_back(int3(left, top + part_h, 0)); - zone.setShape(shape); - zone.setType(i < pcnt ? ETemplateZoneType::PLAYER_START : ETemplateZoneType::TREASURE); + zone->setShape(shape); + zone->setType(i < pcnt ? ETemplateZoneType::PLAYER_START : ETemplateZoneType::TREASURE); this->zones[it.first] = zone; ++i; } @@ -556,9 +168,9 @@ void CMapGenerator::genZones() void CMapGenerator::fillZones() { logGlobal->infoStream() << "Started filling zones"; - for(auto it = zones.begin(); it != zones.end(); ++it) + for(auto it : zones) { - it->second.fill(this); + it.second->fill(this); } logGlobal->infoStream() << "Zones filled successfully"; } @@ -573,966 +185,4 @@ void CMapGenerator::addHeaderInfo() map->description = getMapDescription(); map->difficulty = 1; addPlayerInfo(); -} - -CRmgTemplateZone::CTownInfo::CTownInfo() : townCount(0), castleCount(0), townDensity(0), castleDensity(0) -{ - -} - -int CRmgTemplateZone::CTownInfo::getTownCount() const -{ - return townCount; -} - -void CRmgTemplateZone::CTownInfo::setTownCount(int value) -{ - if(value < 0) throw std::runtime_error("Negative value for town count not allowed."); - townCount = value; -} - -int CRmgTemplateZone::CTownInfo::getCastleCount() const -{ - return castleCount; -} - -void CRmgTemplateZone::CTownInfo::setCastleCount(int value) -{ - if(value < 0) throw std::runtime_error("Negative value for castle count not allowed."); - castleCount = value; -} - -int CRmgTemplateZone::CTownInfo::getTownDensity() const -{ - return townDensity; -} - -void CRmgTemplateZone::CTownInfo::setTownDensity(int value) -{ - if(value < 0) throw std::runtime_error("Negative value for town density not allowed."); - townDensity = value; -} - -int CRmgTemplateZone::CTownInfo::getCastleDensity() const -{ - return castleDensity; -} - -void CRmgTemplateZone::CTownInfo::setCastleDensity(int value) -{ - if(value < 0) throw std::runtime_error("Negative value for castle density not allowed."); - castleDensity = value; -} - -CRmgTemplateZone::CTileInfo::CTileInfo():nearestObjectDistance(INT_MAX), obstacle(false), occupied(false), terrain(ETerrainType::WRONG) -{ - -} - -int CRmgTemplateZone::CTileInfo::getNearestObjectDistance() const -{ - return nearestObjectDistance; -} - -void CRmgTemplateZone::CTileInfo::setNearestObjectDistance(int value) -{ - if(value < 0) throw std::runtime_error("Negative value for nearest object distance not allowed."); - nearestObjectDistance = value; -} - -bool CRmgTemplateZone::CTileInfo::isObstacle() const -{ - return obstacle; -} - -void CRmgTemplateZone::CTileInfo::setObstacle(bool value) -{ - obstacle = value; -} - -bool CRmgTemplateZone::CTileInfo::isOccupied() const -{ - return occupied; -} - -void CRmgTemplateZone::CTileInfo::setOccupied(bool value) -{ - occupied = value; -} - -ETerrainType CRmgTemplateZone::CTileInfo::getTerrainType() const -{ - return terrain; -} - -void CRmgTemplateZone::CTileInfo::setTerrainType(ETerrainType value) -{ - terrain = value; -} - -CRmgTemplateZone::CRmgTemplateZone() : id(0), type(ETemplateZoneType::PLAYER_START), size(1), - townsAreSameType(false), matchTerrainToTown(true) -{ - townTypes = getDefaultTownTypes(); - terrainTypes = getDefaultTerrainTypes(); -} - -TRmgTemplateZoneId CRmgTemplateZone::getId() const -{ - return id; -} - -void CRmgTemplateZone::setId(TRmgTemplateZoneId value) -{ - if(value <= 0) throw std::runtime_error("Zone id should be greater than 0."); - id = value; -} - -ETemplateZoneType::ETemplateZoneType CRmgTemplateZone::getType() const -{ - return type; -} -void CRmgTemplateZone::setType(ETemplateZoneType::ETemplateZoneType value) -{ - type = value; -} - -int CRmgTemplateZone::getSize() const -{ - return size; -} - -void CRmgTemplateZone::setSize(int value) -{ - if(value <= 0) throw std::runtime_error("Zone size needs to be greater than 0."); - size = value; -} - -boost::optional CRmgTemplateZone::getOwner() const -{ - return owner; -} - -void CRmgTemplateZone::setOwner(boost::optional value) -{ - if(!(*value >= 0 && *value <= PlayerColor::PLAYER_LIMIT_I)) throw std::runtime_error("Owner has to be in range 0 to max player count."); - owner = value; -} - -const CRmgTemplateZone::CTownInfo & CRmgTemplateZone::getPlayerTowns() const -{ - return playerTowns; -} - -void CRmgTemplateZone::setPlayerTowns(const CTownInfo & value) -{ - playerTowns = value; -} - -const CRmgTemplateZone::CTownInfo & CRmgTemplateZone::getNeutralTowns() const -{ - return neutralTowns; -} - -void CRmgTemplateZone::setNeutralTowns(const CTownInfo & value) -{ - neutralTowns = value; -} - -bool CRmgTemplateZone::getTownsAreSameType() const -{ - return townsAreSameType; -} - -void CRmgTemplateZone::setTownsAreSameType(bool value) -{ - townsAreSameType = value; -} - -const std::set & CRmgTemplateZone::getTownTypes() const -{ - return townTypes; -} - -void CRmgTemplateZone::setTownTypes(const std::set & value) -{ - townTypes = value; -} - -std::set CRmgTemplateZone::getDefaultTownTypes() const -{ - std::set defaultTowns; - auto towns = VLC->townh->getDefaultAllowed(); - for(int i = 0; i < towns.size(); ++i) - { - if(towns[i]) defaultTowns.insert(i); - } - return defaultTowns; -} - -bool CRmgTemplateZone::getMatchTerrainToTown() const -{ - return matchTerrainToTown; -} - -void CRmgTemplateZone::setMatchTerrainToTown(bool value) -{ - matchTerrainToTown = value; -} - -const std::set & CRmgTemplateZone::getTerrainTypes() const -{ - return terrainTypes; -} - -void CRmgTemplateZone::setTerrainTypes(const std::set & value) -{ - assert(value.find(ETerrainType::WRONG) == value.end() && value.find(ETerrainType::BORDER) == value.end() && - value.find(ETerrainType::WATER) == value.end() && value.find(ETerrainType::ROCK) == value.end()); - terrainTypes = value; -} - -std::set CRmgTemplateZone::getDefaultTerrainTypes() const -{ - std::set terTypes; - static const ETerrainType::EETerrainType allowedTerTypes[] = { ETerrainType::DIRT, ETerrainType::SAND, ETerrainType::GRASS, ETerrainType::SNOW, - ETerrainType::SWAMP, ETerrainType::ROUGH, ETerrainType::SUBTERRANEAN, ETerrainType::LAVA }; - for(auto & allowedTerType : allowedTerTypes) terTypes.insert(allowedTerType); - return terTypes; -} - -boost::optional CRmgTemplateZone::getTerrainTypeLikeZone() const -{ - return terrainTypeLikeZone; -} - -void CRmgTemplateZone::setTerrainTypeLikeZone(boost::optional value) -{ - terrainTypeLikeZone = value; -} - -boost::optional CRmgTemplateZone::getTownTypeLikeZone() const -{ - return townTypeLikeZone; -} - -void CRmgTemplateZone::setTownTypeLikeZone(boost::optional value) -{ - townTypeLikeZone = value; -} - -bool CRmgTemplateZone::pointIsIn(int x, int y) -{ - int i, j; - bool c = false; - int nvert = shape.size(); - for (i = 0, j = nvert-1; i < nvert; j = i++) { - if ( ((shape[i].y>y) != (shape[j].y>y)) && - (x < (shape[j].x-shape[i].x) * (y-shape[i].y) / (shape[j].y-shape[i].y) + shape[i].x) ) - c = !c; - } - return c; -} - -void CRmgTemplateZone::setShape(std::vector shape) -{ - int z = -1; - si32 minx = INT_MAX; - si32 maxx = -1; - si32 miny = INT_MAX; - si32 maxy = -1; - for(auto &point : shape) - { - if (z == -1) - z = point.z; - if (point.z != z) - throw std::runtime_error("Zone shape points should lie on same z."); - minx = std::min(minx, point.x); - maxx = std::max(maxx, point.x); - miny = std::min(miny, point.y); - maxy = std::max(maxy, point.y); - } - this->shape = shape; - for(int x = minx; x <= maxx; ++x) - { - for(int y = miny; y <= maxy; ++y) - { - if (pointIsIn(x, y)) - { - tileinfo[int3(x,y,z)] = CTileInfo(); - } - } - } -} - -int3 CRmgTemplateZone::getCenter() -{ - si32 cx = 0; - si32 cy = 0; - si32 area = 0; - si32 sz = shape.size(); - //include last->first too - for(si32 i = 0, j = sz-1; i < sz; j = i++) { - si32 sf = (shape[i].x * shape[j].y - shape[j].x * shape[i].y); - cx += (shape[i].x + shape[j].x) * sf; - cy += (shape[i].y + shape[j].y) * sf; - area += sf; - } - area /= 2; - return int3(std::abs(cx/area/6), std::abs(cy/area/6), shape[0].z); -} - -bool CRmgTemplateZone::fill(CMapGenerator* gen) -{ - std::vector required_objects; - if ((type == ETemplateZoneType::CPU_START) || (type == ETemplateZoneType::PLAYER_START)) - { - logGlobal->infoStream() << "Preparing playing zone"; - int player_id = *owner - 1; - auto & playerInfo = gen->map->players[player_id]; - if (playerInfo.canAnyonePlay()) - { - PlayerColor player(player_id); - auto town = new CGTownInstance(); - town->ID = Obj::TOWN; - int townId = gen->mapGenOptions.getPlayersSettings().find(player)->second.getStartingTown(); - - static auto town_gen = gen->gen.getRangeI(0, 8); - - if(townId == CMapGenOptions::CPlayerSettings::RANDOM_TOWN) townId = town_gen(); // Default towns - town->subID = townId; - town->tempOwner = player; - town->defInfo = VLC->dobjinfo->gobjs[town->ID][town->subID]; - town->builtBuildings.insert(BuildingID::FORT); - town->builtBuildings.insert(BuildingID::DEFAULT); - - placeObject(gen, town, getCenter()); - logGlobal->infoStream() << "Placed object"; - - logGlobal->infoStream() << "Fill player info " << player_id; - auto & playerInfo = gen->map->players[player_id]; - // Update player info - playerInfo.allowedFactions.clear(); - playerInfo.allowedFactions.insert(town->subID); - playerInfo.hasMainTown = true; - playerInfo.posOfMainTown = town->pos - int3(2, 0, 0); - playerInfo.generateHeroAtMainTown = true; - - //required_objects.push_back(town); - - std::vector required_mines; - required_mines.push_back(Res::ERes::WOOD); - required_mines.push_back(Res::ERes::ORE); - - for(const auto res : required_mines) - { - auto mine = new CGMine(); - mine->ID = Obj::MINE; - mine->subID = static_cast(res); - mine->producedResource = res; - mine->producedQuantity = mine->defaultResProduction(); - mine->defInfo = VLC->dobjinfo->gobjs[mine->ID][mine->subID]; - required_objects.push_back(mine); - } - } - else - { - type = ETemplateZoneType::TREASURE; - logGlobal->infoStream() << "Skipping this zone cause no player"; - } - } - logGlobal->infoStream() << "Creating required objects"; - for(const auto &obj : required_objects) - { - int3 pos; - logGlobal->infoStream() << "Looking for place"; - if ( ! findPlaceForObject(gen, obj, 3, pos)) - { - logGlobal->errorStream() << "Failed to fill zone due to lack of space"; - //TODO CLEANUP! - return false; - } - logGlobal->infoStream() << "Place found"; - - placeObject(gen, obj, pos); - logGlobal->infoStream() << "Placed object"; - } - std::vector guarded_objects; - static auto res_gen = gen->gen.getRangeI(Res::ERes::WOOD, Res::ERes::GOLD); - const double res_mindist = 5; - do { - auto obj = new CGResource(); - auto restype = static_cast(res_gen()); - obj->ID = Obj::RESOURCE; - obj->subID = static_cast(restype); - obj->amount = 0; - obj->defInfo = VLC->dobjinfo->gobjs[obj->ID][obj->subID]; - - int3 pos; - if ( ! findPlaceForObject(gen, obj, res_mindist, pos)) - { - delete obj; - break; - } - placeObject(gen, obj, pos); - if ((restype != Res::ERes::WOOD) && (restype != Res::ERes::ORE)) - { - guarded_objects.push_back(obj); - } - } while(true); - - for(const auto &obj : guarded_objects) - { - if ( ! guardObject(gen, obj, 500)) - { - //TODO, DEL obj from map - } - } - - auto sel = gen->editManager->getTerrainSelection(); - sel.clearSelection(); - for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it) - { - if (it->second.isObstacle()) - { - auto obj = new CGObjectInstance(); - obj->ID = static_cast(130); - obj->subID = 0; - obj->defInfo = VLC->dobjinfo->gobjs[obj->ID][obj->subID]; - placeObject(gen, obj, it->first); - } - } - logGlobal->infoStream() << boost::format("Filling %d with ROCK") % sel.getSelectedItems().size(); - //gen->editManager->drawTerrain(ETerrainType::ROCK, &gen->gen); - logGlobal->infoStream() << "Zone filled successfully"; - return true; -} - -bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos) -{ - //si32 min_dist = sqrt(tileinfo.size()/density); - int best_distance = 0; - bool result = false; - si32 w = gen->map->width; - si32 h = gen->map->height; - 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) - { - auto &ti = it->second; - auto p = it->first; - auto dist = ti.getNearestObjectDistance(); - //avoid borders - if ((p.x < 3) || (w - p.x < 3) || (p.y < 3) || (h - p.y < 3)) - continue; - if (!ti.isOccupied() && !ti.isObstacle() && (dist >= min_dist) && (dist > best_distance)) - { - best_distance = dist; - pos = p; - result = true; - } - } - return result; -} - -void CRmgTemplateZone::placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos) -{ - logGlobal->infoStream() << boost::format("Insert object at %d %d") % pos.x % pos.y; - object->pos = pos; - gen->editManager->insertObject(object, pos); - logGlobal->infoStream() << "Inserted object"; - auto points = object->getBlockedPos(); - if (object->isVisitable()) - points.emplace(pos + object->getVisitableOffset()); - points.emplace(pos); - for(auto const &p : points) - { - if (tileinfo.find(pos + p) != tileinfo.end()) - { - tileinfo[pos + p].setOccupied(true); - } - } - for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it) - { - si32 d = pos.dist2d(it->first); - it->second.setNearestObjectDistance(std::min(d, it->second.getNearestObjectDistance())); - } -} - -bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str) -{ - - logGlobal->infoStream() << boost::format("Guard object at %d %d") % object->pos.x % object->pos.y; - int3 visitable = object->pos + object->getVisitableOffset(); - std::vector tiles; - for(int i = -1; i < 2; ++i) - { - for(int j = -1; j < 2; ++j) - { - auto it = tileinfo.find(visitable + int3(i, j, 0)); - if (it != tileinfo.end()) - { - logGlobal->infoStream() << boost::format("Block at %d %d") % it->first.x % it->first.y; - if ( ! it->second.isOccupied() && ! it->second.isObstacle()) - { - tiles.push_back(it->first); - it->second.setObstacle(true); - } - } - } - } - if ( ! tiles.size()) - { - logGlobal->infoStream() << "Failed"; - return false; - } - auto guard_tile = *std::next(tiles.begin(), gen->gen.getInteger(0, tiles.size() - 1)); - tileinfo[guard_tile].setObstacle(false); - auto guard = new CGCreature(); - guard->ID = Obj::RANDOM_MONSTER; - guard->subID = 0; - auto hlp = new CStackInstance(); - hlp->count = 10; - //type will be set during initialization - guard->putStack(SlotID(0), hlp); - - guard->defInfo = VLC->dobjinfo->gobjs[guard->ID][guard->subID]; - guard->pos = guard_tile; - gen->editManager->insertObject(guard, guard->pos); - return true; -} - -CRmgTemplateZoneConnection::CRmgTemplateZoneConnection() : zoneA(0), zoneB(0), guardStrength(0) -{ - -} - -TRmgTemplateZoneId CRmgTemplateZoneConnection::getZoneA() const -{ - return zoneA; -} - -void CRmgTemplateZoneConnection::setZoneA(TRmgTemplateZoneId value) -{ - zoneA = value; -} - -TRmgTemplateZoneId CRmgTemplateZoneConnection::getZoneB() const -{ - return zoneB; -} - -void CRmgTemplateZoneConnection::setZoneB(TRmgTemplateZoneId value) -{ - zoneB = value; -} - -int CRmgTemplateZoneConnection::getGuardStrength() const -{ - return guardStrength; -} - -void CRmgTemplateZoneConnection::setGuardStrength(int value) -{ - if(value < 0) throw std::runtime_error("Negative value for guard strenth not allowed."); - guardStrength = value; -} - -CRmgTemplate::CSize::CSize() : width(CMapHeader::MAP_SIZE_MIDDLE), height(CMapHeader::MAP_SIZE_MIDDLE), under(true) -{ - -} - -CRmgTemplate::CSize::CSize(int width, int height, bool under) : under(under) -{ - setWidth(width); - setHeight(height); -} - -int CRmgTemplate::CSize::getWidth() const -{ - return width; -} - -void CRmgTemplate::CSize::setWidth(int value) -{ - if(value <= 0) throw std::runtime_error("Width > 0 failed."); - width = value; -} - -int CRmgTemplate::CSize::getHeight() const -{ - return height; -} - -void CRmgTemplate::CSize::setHeight(int value) -{ - if(value <= 0) throw std::runtime_error("Height > 0 failed."); - height = value; -} - -bool CRmgTemplate::CSize::getUnder() const -{ - return under; -} - -void CRmgTemplate::CSize::setUnder(bool value) -{ - under = value; -} - -bool CRmgTemplate::CSize::operator<=(const CSize & value) const -{ - if(width < value.width && height < value.height) - { - return true; - } - else if(width == value.width && height == value.height) - { - return under ? value.under : true; - } - else - { - return false; - } -} - -bool CRmgTemplate::CSize::operator>=(const CSize & value) const -{ - if(width > value.width && height > value.height) - { - return true; - } - else if(width == value.width && height == value.height) - { - return under ? true : !value.under; - } - else - { - return false; - } -} - -CRmgTemplate::CRmgTemplate() -{ - -} - -const std::string & CRmgTemplate::getName() const -{ - return name; -} - -void CRmgTemplate::setName(const std::string & value) -{ - name = value; -} - -const CRmgTemplate::CSize & CRmgTemplate::getMinSize() const -{ - return minSize; -} - -void CRmgTemplate::setMinSize(const CSize & value) -{ - minSize = value; -} - -const CRmgTemplate::CSize & CRmgTemplate::getMaxSize() const -{ - return maxSize; -} - -void CRmgTemplate::setMaxSize(const CSize & value) -{ - maxSize = value; -} - -const CRmgTemplate::CPlayerCountRange & CRmgTemplate::getPlayers() const -{ - return players; -} - -void CRmgTemplate::setPlayers(const CPlayerCountRange & value) -{ - players = value; -} - -const CRmgTemplate::CPlayerCountRange & CRmgTemplate::getCpuPlayers() const -{ - return cpuPlayers; -} - -void CRmgTemplate::setCpuPlayers(const CPlayerCountRange & value) -{ - cpuPlayers = value; -} - -const std::map & CRmgTemplate::getZones() const -{ - return zones; -} - -void CRmgTemplate::setZones(const std::map & value) -{ - zones = value; -} - -const std::list & CRmgTemplate::getConnections() const -{ - return connections; -} - -void CRmgTemplate::setConnections(const std::list & value) -{ - connections = value; -} - -void CRmgTemplate::validate() const -{ - //TODO add some validation checks, throw on failure -} - -void CRmgTemplate::CPlayerCountRange::addRange(int lower, int upper) -{ - range.push_back(std::make_pair(lower, upper)); -} - -void CRmgTemplate::CPlayerCountRange::addNumber(int value) -{ - range.push_back(std::make_pair(value, value)); -} - -bool CRmgTemplate::CPlayerCountRange::isInRange(int count) const -{ - for(const auto & pair : range) - { - if(count >= pair.first && count <= pair.second) return true; - } - return false; -} - -std::set CRmgTemplate::CPlayerCountRange::getNumbers() const -{ - std::set numbers; - for(const auto & pair : range) - { - for(int i = pair.first; i <= pair.second; ++i) numbers.insert(i); - } - return numbers; -} - -const std::map & CRmgTemplateLoader::getTemplates() const -{ - return templates; -} - -void CJsonRmgTemplateLoader::loadTemplates() -{ - const JsonNode rootNode(ResourceID("config/rmg.json")); - for(const auto & templatePair : rootNode.Struct()) - { - CRmgTemplate tpl; - try - { - tpl.setName(templatePair.first); - const auto & templateNode = templatePair.second; - - // Parse main template data - tpl.setMinSize(parseMapTemplateSize(templateNode["minSize"].String())); - tpl.setMaxSize(parseMapTemplateSize(templateNode["maxSize"].String())); - tpl.setPlayers(parsePlayers(templateNode["players"].String())); - tpl.setCpuPlayers(parsePlayers(templateNode["cpu"].String())); - - // Parse zones - std::map zones; - for(const auto & zonePair : templateNode["zones"].Struct()) - { - CRmgTemplateZone zone; - auto zoneId = boost::lexical_cast(zonePair.first); - zone.setId(zoneId); - const auto & zoneNode = zonePair.second; - zone.setType(parseZoneType(zoneNode["type"].String())); - zone.setSize(zoneNode["size"].Float()); - if(!zoneNode["owner"].isNull()) zone.setOwner(zoneNode["owner"].Float()); - zone.setPlayerTowns(parseTemplateZoneTowns(zoneNode["playerTowns"])); - zone.setNeutralTowns(parseTemplateZoneTowns(zoneNode["neutralTowns"])); - zone.setTownTypes(parseTownTypes(zoneNode["townTypes"].Vector(), zone.getDefaultTownTypes())); - zone.setMatchTerrainToTown(zoneNode["matchTerrainToTown"].Bool()); - zone.setTerrainTypes(parseTerrainTypes(zoneNode["terrainTypes"].Vector(), zone.getDefaultTerrainTypes())); - zone.setTownsAreSameType((zoneNode["townsAreSameType"].Bool())); - if(!zoneNode["terrainTypeLikeZone"].isNull()) zone.setTerrainTypeLikeZone(boost::lexical_cast(zoneNode["terrainTypeLikeZone"].String())); - if(!zoneNode["townTypeLikeZone"].isNull()) zone.setTownTypeLikeZone(boost::lexical_cast(zoneNode["townTypeLikeZone"].String())); - zones[zone.getId()] = zone; - } - tpl.setZones(zones); - - // Parse connections - std::list connections; - for(const auto & connPair : templateNode["connections"].Vector()) - { - CRmgTemplateZoneConnection conn; - conn.setZoneA(boost::lexical_cast(connPair["a"].String())); - conn.setZoneB(boost::lexical_cast(connPair["b"].String())); - conn.setGuardStrength(connPair["guard"].Float()); - connections.push_back(conn); - } - tpl.setConnections(connections); - tpl.validate(); - templates[tpl.getName()] = tpl; - } - catch(const std::exception & e) - { - logGlobal->errorStream() << boost::format("Template %s has errors. Message: %s.") % tpl.getName() % std::string(e.what()); - } - } -} - -CRmgTemplate::CSize CJsonRmgTemplateLoader::parseMapTemplateSize(const std::string & text) const -{ - CRmgTemplate::CSize size; - if(text.empty()) return size; - - std::vector parts; - boost::split(parts, text, boost::is_any_of("+")); - static const std::map mapSizeMapping = boost::assign::map_list_of("s", CMapHeader::MAP_SIZE_SMALL) - ("m", CMapHeader::MAP_SIZE_MIDDLE)("l", CMapHeader::MAP_SIZE_LARGE)("xl", CMapHeader::MAP_SIZE_XLARGE); - auto it = mapSizeMapping.find(parts[0]); - if(it == mapSizeMapping.end()) - { - // Map size is given as a number representation - const auto & numericalRep = parts[0]; - parts.clear(); - boost::split(parts, numericalRep, boost::is_any_of("x")); - assert(parts.size() == 3); - size.setWidth(boost::lexical_cast(parts[0])); - size.setHeight(boost::lexical_cast(parts[1])); - size.setUnder(boost::lexical_cast(parts[2]) == 1); - } - else - { - size.setWidth(it->second); - size.setHeight(it->second); - size.setUnder(parts.size() > 1 ? parts[1] == std::string("u") : false); - } - return size; -} - -ETemplateZoneType::ETemplateZoneType CJsonRmgTemplateLoader::parseZoneType(const std::string & type) const -{ - static const std::map zoneTypeMapping = boost::assign::map_list_of - ("playerStart", ETemplateZoneType::PLAYER_START)("cpuStart", ETemplateZoneType::CPU_START) - ("treasure", ETemplateZoneType::TREASURE)("junction", ETemplateZoneType::JUNCTION); - auto it = zoneTypeMapping.find(type); - if(it == zoneTypeMapping.end()) throw std::runtime_error("Zone type unknown."); - return it->second; -} - -CRmgTemplateZone::CTownInfo CJsonRmgTemplateLoader::parseTemplateZoneTowns(const JsonNode & node) const -{ - CRmgTemplateZone::CTownInfo towns; - towns.setTownCount(node["towns"].Float()); - towns.setCastleCount(node["castles"].Float()); - towns.setTownDensity(node["townDensity"].Float()); - towns.setCastleDensity(node["castleDensity"].Float()); - return towns; -} - -std::set CJsonRmgTemplateLoader::parseTownTypes(const JsonVector & townTypesVector, const std::set & defaultTownTypes) const -{ - std::set townTypes; - for(const auto & townTypeNode : townTypesVector) - { - auto townTypeStr = townTypeNode.String(); - if(townTypeStr == "all") return defaultTownTypes; - - bool foundFaction = false; - for(auto factionPtr : VLC->townh->factions) - { - if(factionPtr->town != nullptr && townTypeStr == factionPtr->name) - { - townTypes.insert(factionPtr->index); - foundFaction = true; - } - } - if(!foundFaction) throw std::runtime_error("Given faction is invalid."); - } - return townTypes; -} - -std::set CJsonRmgTemplateLoader::parseTerrainTypes(const JsonVector & terTypeStrings, const std::set & defaultTerrainTypes) const -{ - std::set terTypes; - for(const auto & node : terTypeStrings) - { - const auto & terTypeStr = node.String(); - if(terTypeStr == "all") return defaultTerrainTypes; - auto pos = vstd::find_pos(GameConstants::TERRAIN_NAMES, terTypeStr); - if (pos != -1) - { - terTypes.insert(ETerrainType(pos)); - } - else - { - throw std::runtime_error("Terrain type is invalid."); - } - } - return terTypes; -} - -CRmgTemplate::CPlayerCountRange CJsonRmgTemplateLoader::parsePlayers(const std::string & players) const -{ - CRmgTemplate::CPlayerCountRange playerRange; - if(players.empty()) - { - playerRange.addNumber(0); - return playerRange; - } - std::vector commaParts; - boost::split(commaParts, players, boost::is_any_of(",")); - for(const auto & commaPart : commaParts) - { - std::vector rangeParts; - boost::split(rangeParts, commaPart, boost::is_any_of("-")); - if(rangeParts.size() == 2) - { - auto lower = boost::lexical_cast(rangeParts[0]); - auto upper = boost::lexical_cast(rangeParts[1]); - playerRange.addRange(lower, upper); - } - else if(rangeParts.size() == 1) - { - auto val = boost::lexical_cast(rangeParts.front()); - playerRange.addNumber(val); - } - } - return playerRange; -} - -boost::mutex CRmgTemplateStorage::smx; - -CRmgTemplateStorage & CRmgTemplateStorage::get() -{ - TLockGuard _(smx); - static CRmgTemplateStorage storage; - return storage; -} - -const std::map & CRmgTemplateStorage::getTemplates() const -{ - return templates; -} - -CRmgTemplateStorage::CRmgTemplateStorage() -{ - auto jsonLoader = make_unique(); - jsonLoader->loadTemplates(); - const auto & tpls = jsonLoader->getTemplates(); - templates.insert(tpls.begin(), tpls.end()); -} - -CRmgTemplateStorage::~CRmgTemplateStorage() -{ - -} +} \ No newline at end of file diff --git a/lib/rmg/CMapGenerator.h b/lib/rmg/CMapGenerator.h index ce276deeb..6f2a84f34 100644 --- a/lib/rmg/CMapGenerator.h +++ b/lib/rmg/CMapGenerator.h @@ -13,369 +13,22 @@ #include "../GameConstants.h" #include "../CRandomGenerator.h" +#include "CMapGenOptions.h" #include "../CObjectHandler.h" #include "../int3.h" class CMap; +class CRmgTemplate; +class CRmgTemplateZone; +class CMapGenOptions; class CTerrainViewPatternConfig; class CMapEditManager; class JsonNode; typedef std::vector JsonVector; -namespace ETemplateZoneType -{ -enum ETemplateZoneType -{ - PLAYER_START, - CPU_START, - TREASURE, - JUNCTION -}; -} - -typedef int TRmgTemplateZoneId; - class CMapGenerator; -/// The CRmgTemplateZone describes a zone in a template. -class DLL_LINKAGE CRmgTemplateZone -{ -public: - class DLL_LINKAGE CTownInfo - { - public: - CTownInfo(); - - int getTownCount() const; /// Default: 0 - void setTownCount(int value); - int getCastleCount() const; /// Default: 0 - void setCastleCount(int value); - int getTownDensity() const; /// Default: 0 - void setTownDensity(int value); - int getCastleDensity() const; /// Default: 0 - void setCastleDensity(int value); - - private: - int townCount, castleCount, townDensity, castleDensity; - }; - - class DLL_LINKAGE CTileInfo - { - public: - CTileInfo(); - - int getNearestObjectDistance() const; - void setNearestObjectDistance(int value); - bool isObstacle() const; - void setObstacle(bool value); - bool isOccupied() const; - void setOccupied(bool value); - ETerrainType getTerrainType() const; - void setTerrainType(ETerrainType value); - - private: - int nearestObjectDistance; - bool obstacle; - bool occupied; - ETerrainType terrain; - }; - - CRmgTemplateZone(); - - TRmgTemplateZoneId getId() const; /// Default: 0 - void setId(TRmgTemplateZoneId value); - ETemplateZoneType::ETemplateZoneType getType() const; /// Default: ETemplateZoneType::PLAYER_START - void setType(ETemplateZoneType::ETemplateZoneType value); - int getSize() const; /// Default: 1 - void setSize(int value); - boost::optional getOwner() const; - void setOwner(boost::optional value); - const CTownInfo & getPlayerTowns() const; - void setPlayerTowns(const CTownInfo & value); - const CTownInfo & getNeutralTowns() const; - void setNeutralTowns(const CTownInfo & value); - bool getTownsAreSameType() const; /// Default: false - void setTownsAreSameType(bool value); - const std::set & getTownTypes() const; /// Default: all - void setTownTypes(const std::set & value); - std::set getDefaultTownTypes() const; - bool getMatchTerrainToTown() const; /// Default: true - void setMatchTerrainToTown(bool value); - const std::set & getTerrainTypes() const; /// Default: all - void setTerrainTypes(const std::set & value); - std::set getDefaultTerrainTypes() const; - boost::optional getTerrainTypeLikeZone() const; - void setTerrainTypeLikeZone(boost::optional value); - boost::optional getTownTypeLikeZone() const; - void setTownTypeLikeZone(boost::optional value); - void setShape(std::vector shape); - bool fill(CMapGenerator* gen); - -private: - TRmgTemplateZoneId id; - ETemplateZoneType::ETemplateZoneType type; - int size; - boost::optional owner; - CTownInfo playerTowns, neutralTowns; - bool townsAreSameType; - std::set townTypes; - bool matchTerrainToTown; - std::set terrainTypes; - boost::optional terrainTypeLikeZone, townTypeLikeZone; - - std::vector shape; - std::map tileinfo; - std::vector objects; - - int3 getCenter(); - bool pointIsIn(int x, int y); - bool findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos); - void placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos); - bool guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str); -}; - -/// The CRmgTemplateZoneConnection describes the connection between two zones. -class DLL_LINKAGE CRmgTemplateZoneConnection -{ -public: - CRmgTemplateZoneConnection(); - - TRmgTemplateZoneId getZoneA() const; /// Default: 0 - void setZoneA(TRmgTemplateZoneId value); - TRmgTemplateZoneId getZoneB() const; /// Default: 0 - void setZoneB(TRmgTemplateZoneId value); - int getGuardStrength() const; /// Default: 0 - void setGuardStrength(int value); - -private: - TRmgTemplateZoneId zoneA, zoneB; - int guardStrength; -}; - -/// The CRmgTemplate describes a random map template. -class DLL_LINKAGE CRmgTemplate -{ -public: - class CSize - { - public: - CSize(); - CSize(int width, int height, bool under); - - int getWidth() const; /// Default: CMapHeader::MAP_SIZE_MIDDLE - void setWidth(int value); - int getHeight() const; /// Default: CMapHeader::MAP_SIZE_MIDDLE - void setHeight(int value); - bool getUnder() const; /// Default: true - void setUnder(bool value); - bool operator<=(const CSize & value) const; - bool operator>=(const CSize & value) const; - - private: - int width, height; - bool under; - }; - - class CPlayerCountRange - { - public: - void addRange(int lower, int upper); - void addNumber(int value); - bool isInRange(int count) const; - std::set getNumbers() const; - - private: - std::list > range; - }; - - CRmgTemplate(); - - const std::string & getName() const; - void setName(const std::string & value); - const CSize & getMinSize() const; - void setMinSize(const CSize & value); - const CSize & getMaxSize() const; - void setMaxSize(const CSize & value); - const CPlayerCountRange & getPlayers() const; - void setPlayers(const CPlayerCountRange & value); - const CPlayerCountRange & getCpuPlayers() const; - void setCpuPlayers(const CPlayerCountRange & value); - const std::map & getZones() const; - void setZones(const std::map & value); - const std::list & getConnections() const; - void setConnections(const std::list & value); - - void validate() const; /// Tests template on validity and throws exception on failure - -private: - std::string name; - CSize minSize, maxSize; - CPlayerCountRange players, cpuPlayers; - std::map zones; - std::list connections; -}; - -namespace EWaterContent -{ -enum EWaterContent -{ - RANDOM = -1, - NONE, - NORMAL, - ISLANDS -}; -} - -namespace EMonsterStrength -{ -enum EMonsterStrength -{ - RANDOM = -1, - WEAK, - NORMAL, - STRONG -}; -} - -namespace EPlayerType -{ -enum EPlayerType -{ - HUMAN, - AI, - COMP_ONLY -}; -} - -/// The map gen options class holds values about general map generation settings -/// e.g. the size of the map, the count of players,... -class DLL_LINKAGE CMapGenOptions -{ -public: - /// The player settings class maps the player color, starting town and human player flag. - class DLL_LINKAGE CPlayerSettings - { - public: - CPlayerSettings(); - - /// The color of the player ranging from 0 to PlayerColor::PLAYER_LIMIT - 1. - /// The default value is 0. - PlayerColor getColor() const; - void setColor(PlayerColor value); - - /// The starting town of the player ranging from 0 to town max count or RANDOM_TOWN. - /// The default value is RANDOM_TOWN. - si32 getStartingTown() const; - void setStartingTown(si32 value); - - /// The default value is EPlayerType::AI. - EPlayerType::EPlayerType getPlayerType() const; - void setPlayerType(EPlayerType::EPlayerType value); - - /// Constant for a random town selection. - static const si32 RANDOM_TOWN = -1; - - private: - PlayerColor color; - si32 startingTown; - EPlayerType::EPlayerType playerType; - - public: - template - void serialize(Handler & h, const int version) - { - h & color & startingTown & playerType; - } - }; - - CMapGenOptions(); - - si32 getWidth() const; - void setWidth(si32 value); - - si32 getHeight() const; - void setHeight(si32 value); - - bool getHasTwoLevels() const; - void setHasTwoLevels(bool value); - - /// The count of the players ranging from 1 to PlayerColor::PLAYER_LIMIT or RANDOM_SIZE for random. If you call - /// this method, all player settings are reset to default settings. - si8 getPlayerCount() const; - void setPlayerCount(si8 value); - - /// The count of the teams ranging from 0 to or RANDOM_SIZE for random. - si8 getTeamCount() const; - void setTeamCount(si8 value); - - /// The count of the computer only players ranging from 0 to or RANDOM_SIZE for random. - /// If you call this method, all player settings are reset to default settings. - si8 getCompOnlyPlayerCount() const; - void setCompOnlyPlayerCount(si8 value); - - /// The count of the computer only teams ranging from 0 to or RANDOM_SIZE for random. - si8 getCompOnlyTeamCount() const; - void setCompOnlyTeamCount(si8 value); - - EWaterContent::EWaterContent getWaterContent() const; - void setWaterContent(EWaterContent::EWaterContent value); - - EMonsterStrength::EMonsterStrength getMonsterStrength() const; - void setMonsterStrength(EMonsterStrength::EMonsterStrength value); - - /// The first player colors belong to standard players and the last player colors belong to comp only players. - /// All standard players are by default of type EPlayerType::AI. - const std::map & getPlayersSettings() const; - void setStartingTownForPlayer(PlayerColor color, si32 town); - /// Sets a player type for a standard player. A standard player is the opposite of a computer only player. The - /// values which can be chosen for the player type are EPlayerType::AI or EPlayerType::HUMAN. - void setPlayerTypeForStandardPlayer(PlayerColor color, EPlayerType::EPlayerType playerType); - - /// The random map template to generate the map with or empty/not set if the template should be chosen randomly. - /// Default: Not set/random. - const CRmgTemplate * getMapTemplate() const; - void setMapTemplate(const CRmgTemplate * value); - - const std::map & getAvailableTemplates() const; - - /// Finalizes the options. All random sizes for various properties will be overwritten by numbers from - /// a random number generator by keeping the options in a valid state. Check options should return true, otherwise - /// this function fails. - void finalize(); - void finalize(CRandomGenerator & gen); - - /// Returns false if there is no template available which fits to the currently selected options. - bool checkOptions() const; - - static const si8 RANDOM_SIZE = -1; - -private: - void resetPlayersMap(); - int countHumanPlayers() const; - PlayerColor getNextPlayerColor() const; - void updateCompOnlyPlayers(); - void updatePlayers(); - const CRmgTemplate * getPossibleTemplate(CRandomGenerator & gen) const; - - si32 width, height; - bool hasTwoLevels; - si8 playerCount, teamCount, compOnlyPlayerCount, compOnlyTeamCount; - EWaterContent::EWaterContent waterContent; - EMonsterStrength::EMonsterStrength monsterStrength; - std::map players; - const CRmgTemplate * mapTemplate; - -public: - template - void serialize(Handler & h, const int version) - { - h & width & height & hasTwoLevels & playerCount & teamCount & compOnlyPlayerCount; - h & compOnlyTeamCount & waterContent & monsterStrength & players; - //TODO add name of template to class, enables selection of a template by a user - } -}; - /// The map generator creates a map randomly. class DLL_LINKAGE CMapGenerator { @@ -383,16 +36,16 @@ public: explicit CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed = std::time(nullptr)); ~CMapGenerator(); // required due to unique_ptr - std::unique_ptr generate(); + ConstTransitivePtr generate(); CMapGenOptions mapGenOptions; - std::unique_ptr map; - CRandomGenerator gen; + ConstTransitivePtr map; + CRandomGenerator rand; int randomSeed; CMapEditManager * editManager; private: - std::map zones; + std::map zones; /// Generation methods std::string getMapDescription() const; @@ -407,45 +60,3 @@ private: /* Implementation/Detail classes, Private API */ /* ---------------------------------------------------------------------------- */ -/// The CRmgTemplateLoader is a abstract base class for loading templates. -class DLL_LINKAGE CRmgTemplateLoader -{ -public: - virtual ~CRmgTemplateLoader() { }; - virtual void loadTemplates() = 0; - const std::map & getTemplates() const; - -protected: - std::map templates; -}; - -/// The CJsonRmgTemplateLoader loads templates from a JSON file. -class DLL_LINKAGE CJsonRmgTemplateLoader : public CRmgTemplateLoader -{ -public: - void loadTemplates() override; - -private: - CRmgTemplate::CSize parseMapTemplateSize(const std::string & text) const; - CRmgTemplateZone::CTownInfo parseTemplateZoneTowns(const JsonNode & node) const; - ETemplateZoneType::ETemplateZoneType parseZoneType(const std::string & type) const; - std::set parseTownTypes(const JsonVector & townTypesVector, const std::set & defaultTownTypes) const; - std::set parseTerrainTypes(const JsonVector & terTypeStrings, const std::set & defaultTerrainTypes) const; - CRmgTemplate::CPlayerCountRange parsePlayers(const std::string & players) const; -}; - -/// The CRmgTemplateStorage is a singleton object where templates are stored and which can be accessed from anywhere. -class DLL_LINKAGE CRmgTemplateStorage -{ -public: - static CRmgTemplateStorage & get(); - - const std::map & getTemplates() const; - -private: - CRmgTemplateStorage(); - ~CRmgTemplateStorage(); - - static boost::mutex smx; - std::map templates; /// Key: Template name -}; diff --git a/lib/rmg/CRmgTemplateStorage.cpp b/lib/rmg/CRmgTemplateStorage.cpp index 2e12dc9bf..38af91529 100644 --- a/lib/rmg/CRmgTemplateStorage.cpp +++ b/lib/rmg/CRmgTemplateStorage.cpp @@ -229,4 +229,4 @@ CRmgTemplateStorage::CRmgTemplateStorage() CRmgTemplateStorage::~CRmgTemplateStorage() { for (auto & pair : templates) delete pair.second; -} +} \ No newline at end of file diff --git a/lib/rmg/CRmgTemplateZone.cpp b/lib/rmg/CRmgTemplateZone.cpp index 658a0b8cb..001034fad 100644 --- a/lib/rmg/CRmgTemplateZone.cpp +++ b/lib/rmg/CRmgTemplateZone.cpp @@ -11,10 +11,15 @@ #include "StdInc.h" #include "CRmgTemplateZone.h" +#include "../mapping/CMapEditManager.h" +#include "../mapping/CMap.h" #include "../VCMI_Lib.h" #include "../CTownHandler.h" +class CMap; +class CMapEditManager; + CRmgTemplateZone::CTownInfo::CTownInfo() : townCount(0), castleCount(0), townDensity(0), castleDensity(0) { @@ -64,6 +69,52 @@ void CRmgTemplateZone::CTownInfo::setCastleDensity(int value) castleDensity = value; } +CRmgTemplateZone::CTileInfo::CTileInfo():nearestObjectDistance(INT_MAX), obstacle(false), occupied(false), terrain(ETerrainType::WRONG) +{ + +} + +int CRmgTemplateZone::CTileInfo::getNearestObjectDistance() const +{ + return nearestObjectDistance; +} + +void CRmgTemplateZone::CTileInfo::setNearestObjectDistance(int value) +{ + if(value < 0) throw std::runtime_error("Negative value for nearest object distance not allowed."); + nearestObjectDistance = value; +} + +bool CRmgTemplateZone::CTileInfo::isObstacle() const +{ + return obstacle; +} + +void CRmgTemplateZone::CTileInfo::setObstacle(bool value) +{ + obstacle = value; +} + +bool CRmgTemplateZone::CTileInfo::isOccupied() const +{ + return occupied; +} + +void CRmgTemplateZone::CTileInfo::setOccupied(bool value) +{ + occupied = value; +} + +ETerrainType CRmgTemplateZone::CTileInfo::getTerrainType() const +{ + return terrain; +} + +void CRmgTemplateZone::CTileInfo::setTerrainType(ETerrainType value) +{ + terrain = value; +} + CRmgTemplateZone::CRmgTemplateZone() : id(0), type(ETemplateZoneType::PLAYER_START), size(1), townsAreSameType(false), matchTerrainToTown(true) { @@ -214,3 +265,280 @@ void CRmgTemplateZone::setTownTypeLikeZone(boost::optional v { townTypeLikeZone = value; } + +bool CRmgTemplateZone::pointIsIn(int x, int y) +{ + int i, j; + bool c = false; + int nvert = shape.size(); + for (i = 0, j = nvert-1; i < nvert; j = i++) { + if ( ((shape[i].y>y) != (shape[j].y>y)) && + (x < (shape[j].x-shape[i].x) * (y-shape[i].y) / (shape[j].y-shape[i].y) + shape[i].x) ) + c = !c; + } + return c; +} + +void CRmgTemplateZone::setShape(std::vector shape) +{ + int z = -1; + si32 minx = INT_MAX; + si32 maxx = -1; + si32 miny = INT_MAX; + si32 maxy = -1; + for(auto &point : shape) + { + if (z == -1) + z = point.z; + if (point.z != z) + throw std::runtime_error("Zone shape points should lie on same z."); + minx = std::min(minx, point.x); + maxx = std::max(maxx, point.x); + miny = std::min(miny, point.y); + maxy = std::max(maxy, point.y); + } + this->shape = shape; + for(int x = minx; x <= maxx; ++x) + { + for(int y = miny; y <= maxy; ++y) + { + if (pointIsIn(x, y)) + { + tileinfo[int3(x,y,z)] = CTileInfo(); + } + } + } +} + +int3 CRmgTemplateZone::getCenter() +{ + si32 cx = 0; + si32 cy = 0; + si32 area = 0; + si32 sz = shape.size(); + //include last->first too + for(si32 i = 0, j = sz-1; i < sz; j = i++) { + si32 sf = (shape[i].x * shape[j].y - shape[j].x * shape[i].y); + cx += (shape[i].x + shape[j].x) * sf; + cy += (shape[i].y + shape[j].y) * sf; + area += sf; + } + area /= 2; + return int3(std::abs(cx/area/6), std::abs(cy/area/6), shape[0].z); +} + +bool CRmgTemplateZone::fill(CMapGenerator* gen) +{ + std::vector required_objects; + if ((type == ETemplateZoneType::CPU_START) || (type == ETemplateZoneType::PLAYER_START)) + { + logGlobal->infoStream() << "Preparing playing zone"; + int player_id = *owner - 1; + auto & playerInfo = gen->map->players[player_id]; + if (playerInfo.canAnyonePlay()) + { + PlayerColor player(player_id); + auto town = new CGTownInstance(); + town->ID = Obj::TOWN; + int townId = gen->mapGenOptions.getPlayersSettings().find(player)->second.getStartingTown(); + + if(townId == CMapGenOptions::CPlayerSettings::RANDOM_TOWN) + townId = gen->rand.nextInt (VLC->townh->factions.size()); // all possible towns + + town->subID = townId; + town->tempOwner = player; + town->builtBuildings.insert(BuildingID::FORT); + town->builtBuildings.insert(BuildingID::DEFAULT); + + placeObject(gen, town, getCenter()); + logGlobal->infoStream() << "Placed object"; + + logGlobal->infoStream() << "Fill player info " << player_id; + auto & playerInfo = gen->map->players[player_id]; + // Update player info + playerInfo.allowedFactions.clear(); + playerInfo.allowedFactions.insert(town->subID); + playerInfo.hasMainTown = true; + playerInfo.posOfMainTown = town->pos - int3(2, 0, 0); + playerInfo.generateHeroAtMainTown = true; + + //required_objects.push_back(town); + + std::vector required_mines; + required_mines.push_back(Res::ERes::WOOD); + required_mines.push_back(Res::ERes::ORE); + + for(const auto res : required_mines) + { + auto mine = new CGMine(); + mine->ID = Obj::MINE; + mine->subID = static_cast(res); + mine->producedResource = res; + mine->producedQuantity = mine->defaultResProduction(); + required_objects.push_back(mine); + } + } + else + { + type = ETemplateZoneType::TREASURE; + logGlobal->infoStream() << "Skipping this zone cause no player"; + } + } + logGlobal->infoStream() << "Creating required objects"; + for(const auto &obj : required_objects) + { + int3 pos; + logGlobal->infoStream() << "Looking for place"; + if ( ! findPlaceForObject(gen, obj, 3, pos)) + { + logGlobal->errorStream() << "Failed to fill zone due to lack of space"; + //TODO CLEANUP! + return false; + } + logGlobal->infoStream() << "Place found"; + + placeObject(gen, obj, pos); + logGlobal->infoStream() << "Placed object"; + } + std::vector guarded_objects; + static auto res_gen = gen->rand.getIntRange(Res::ERes::WOOD, Res::ERes::GOLD); + const double res_mindist = 5; + do { + auto obj = new CGResource(); + auto restype = static_cast(res_gen()); + obj->ID = Obj::RESOURCE; + obj->subID = static_cast(restype); + obj->amount = 0; + + int3 pos; + if ( ! findPlaceForObject(gen, obj, res_mindist, pos)) + { + delete obj; + break; + } + placeObject(gen, obj, pos); + if ((restype != Res::ERes::WOOD) && (restype != Res::ERes::ORE)) + { + guarded_objects.push_back(obj); + } + } while(true); + + for(const auto &obj : guarded_objects) + { + if ( ! guardObject(gen, obj, 500)) + { + //TODO, DEL obj from map + } + } + + auto sel = gen->editManager->getTerrainSelection(); + sel.clearSelection(); + for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it) + { + if (it->second.isObstacle()) + { + auto obj = new CGObjectInstance(); + obj->ID = static_cast(130); + obj->subID = 0; + placeObject(gen, obj, it->first); + } + } + logGlobal->infoStream() << boost::format("Filling %d with ROCK") % sel.getSelectedItems().size(); + //gen->editManager->drawTerrain(ETerrainType::ROCK, &gen->gen); + logGlobal->infoStream() << "Zone filled successfully"; + return true; +} + +bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos) +{ + //si32 min_dist = sqrt(tileinfo.size()/density); + int best_distance = 0; + bool result = false; + si32 w = gen->map->width; + si32 h = gen->map->height; + 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) + { + auto &ti = it->second; + auto p = it->first; + auto dist = ti.getNearestObjectDistance(); + //avoid borders + if ((p.x < 3) || (w - p.x < 3) || (p.y < 3) || (h - p.y < 3)) + continue; + if (!ti.isOccupied() && !ti.isObstacle() && (dist >= min_dist) && (dist > best_distance)) + { + best_distance = dist; + pos = p; + result = true; + } + } + return result; +} + +void CRmgTemplateZone::placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos) +{ + logGlobal->infoStream() << boost::format("Insert object at %d %d") % pos.x % pos.y; + object->pos = pos; + gen->editManager->insertObject(object, pos); + logGlobal->infoStream() << "Inserted object"; + auto points = object->getBlockedPos(); + if (object->isVisitable()) + points.emplace(pos + object->getVisitableOffset()); + points.emplace(pos); + for(auto const &p : points) + { + if (tileinfo.find(pos + p) != tileinfo.end()) + { + tileinfo[pos + p].setOccupied(true); + } + } + for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it) + { + si32 d = pos.dist2d(it->first); + it->second.setNearestObjectDistance(std::min(d, it->second.getNearestObjectDistance())); + } +} + +bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str) +{ + + logGlobal->infoStream() << boost::format("Guard object at %d %d") % object->pos.x % object->pos.y; + int3 visitable = object->pos + object->getVisitableOffset(); + std::vector tiles; + for(int i = -1; i < 2; ++i) + { + for(int j = -1; j < 2; ++j) + { + auto it = tileinfo.find(visitable + int3(i, j, 0)); + if (it != tileinfo.end()) + { + logGlobal->infoStream() << boost::format("Block at %d %d") % it->first.x % it->first.y; + if ( ! it->second.isOccupied() && ! it->second.isObstacle()) + { + tiles.push_back(it->first); + it->second.setObstacle(true); + } + } + } + } + if ( ! tiles.size()) + { + logGlobal->infoStream() << "Failed"; + return false; + } + auto guard_tile = *std::next(tiles.begin(), gen->rand.nextInt(tiles.size())); + tileinfo[guard_tile].setObstacle(false); + auto guard = new CGCreature(); + guard->ID = Obj::RANDOM_MONSTER; + guard->subID = 0; + auto hlp = new CStackInstance(); + hlp->count = 10; + //type will be set during initialization + guard->putStack(SlotID(0), hlp); + + guard->pos = guard_tile; + gen->editManager->insertObject(guard, guard->pos); + return true; +} diff --git a/lib/rmg/CRmgTemplateZone.h b/lib/rmg/CRmgTemplateZone.h index 082f00719..112c58a56 100644 --- a/lib/rmg/CRmgTemplateZone.h +++ b/lib/rmg/CRmgTemplateZone.h @@ -12,6 +12,9 @@ #pragma once #include "../GameConstants.h" +#include "CMapGenerator.h" + +class CMapgenerator; namespace ETemplateZoneType { @@ -45,6 +48,27 @@ public: private: int townCount, castleCount, townDensity, castleDensity; }; + + class DLL_LINKAGE CTileInfo + { + public: + CTileInfo(); + + int getNearestObjectDistance() const; + void setNearestObjectDistance(int value); + bool isObstacle() const; + void setObstacle(bool value); + bool isOccupied() const; + void setOccupied(bool value); + ETerrainType getTerrainType() const; + void setTerrainType(ETerrainType value); + + private: + int nearestObjectDistance; + bool obstacle; + bool occupied; + ETerrainType terrain; + }; CRmgTemplateZone(); @@ -52,12 +76,10 @@ public: void setId(TRmgTemplateZoneId value); ETemplateZoneType::ETemplateZoneType getType() const; /// Default: ETemplateZoneType::PLAYER_START void setType(ETemplateZoneType::ETemplateZoneType value); - int getSize() const; /// Default: 1 void setSize(int value); boost::optional getOwner() const; void setOwner(boost::optional value); - const CTownInfo & getPlayerTowns() const; void setPlayerTowns(const CTownInfo & value); const CTownInfo & getNeutralTowns() const; @@ -69,7 +91,6 @@ public: std::set getDefaultTownTypes() const; bool getMatchTerrainToTown() const; /// Default: true void setMatchTerrainToTown(bool value); - const std::set & getTerrainTypes() const; /// Default: all void setTerrainTypes(const std::set & value); std::set getDefaultTerrainTypes() const; @@ -77,6 +98,8 @@ public: void setTerrainTypeLikeZone(boost::optional value); boost::optional getTownTypeLikeZone() const; void setTownTypeLikeZone(boost::optional value); + void setShape(std::vector shape); + bool fill(CMapGenerator* gen); private: TRmgTemplateZoneId id; @@ -89,4 +112,14 @@ private: bool matchTerrainToTown; std::set terrainTypes; boost::optional terrainTypeLikeZone, townTypeLikeZone; + + std::vector shape; + std::map tileinfo; + std::vector objects; + + int3 getCenter(); + bool pointIsIn(int x, int y); + bool findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos); + void placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos); + bool guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str); };