1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Place proper towns in underground (#743)

Implement feature of proper town selection in underground and surface
* Some minor refactoring of rmg
This commit is contained in:
Nordsoft91 2022-05-28 16:03:50 +03:00 committed by GitHub
parent d92356f085
commit 9d06e51631
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 214 additions and 196 deletions

View File

@ -4,6 +4,7 @@
"index" : 5,
"nativeTerrain": "subterra",
"alignment" : "evil",
"preferUndergroundPlacement": true,
"creatureBackground" :
{
"120px" : "TPCASDUN",

View File

@ -4,6 +4,7 @@
"index" : 3,
"nativeTerrain": "lava",
"alignment" : "evil",
"preferUndergroundPlacement": true,
"creatureBackground" :
{
"120px" : "TPCASINF",

View File

@ -4,6 +4,7 @@
"index" : 4,
"nativeTerrain": "dirt",
"alignment" : "evil",
"preferUndergroundPlacement": true,
"creatureBackground" :
{
"120px" : "TPCASNEC",

View File

@ -73,6 +73,10 @@
"type":"string",
"description": "Native terrain for creatures. Creatures fighting on native terrain receive several bonuses"
},
"preferUndergroundPlacement": {
"type":"bool",
"description": "Random map generator places player/cpu-owned towns underground if true is specified and on the ground otherwise. Parameter is unused for maps without underground. False by default."
},
"puzzleMap": {
"type":"object",
"additionalProperties" : false,

View File

@ -853,9 +853,9 @@ void CGameState::initNewGame(const IMapService * mapService, bool allowSavingRan
CStopWatch sw;
// Gen map
CMapGenerator mapGenerator;
CMapGenerator mapGenerator(*scenarioOps->mapGenOptions, scenarioOps->seedToBeUsed);
std::unique_ptr<CMap> randomMap = mapGenerator.generate(scenarioOps->mapGenOptions.get(), scenarioOps->seedToBeUsed);
std::unique_ptr<CMap> randomMap = mapGenerator.generate();
if(allowSavingRandomMap)
{

View File

@ -211,6 +211,7 @@ CFaction::CFaction()
town = nullptr;
index = 0;
alignment = EAlignment::NEUTRAL;
preferUndergroundPlacement = false;
}
CFaction::~CFaction()
@ -1100,6 +1101,9 @@ CFaction * CTownHandler::loadFromJson(const std::string & scope, const JsonNode
? -1
: vstd::find_pos(GameConstants::TERRAIN_NAMES, nativeTerrain.String());
auto preferUndergound = source["preferUndergroundPlacement"];
faction->preferUndergroundPlacement = preferUndergound.isNull() ? false : preferUndergound.Bool();
//Contructor is not called here, but operator=
faction->nativeTerrain = terrainNum < 0
? getDefaultTerrainForAlignment(faction->alignment)

View File

@ -207,6 +207,7 @@ public:
ETerrainType nativeTerrain;
EAlignment::EAlignment alignment;
bool preferUndergroundPlacement;
CTown * town; //NOTE: can be null

View File

@ -205,11 +205,6 @@ void CMapGenOptions::setMapTemplate(const CRmgTemplate * value)
assert(0);
}
const std::map<std::string, CRmgTemplate *> & CMapGenOptions::getAvailableTemplates() const
{
return VLC->tplh->getTemplates();
}
void CMapGenOptions::finalize(CRandomGenerator & rand)
{
logGlobal->info("RMG settings: players %d, teams %d, computer players %d, computer teams %d, water %d, monsters %d",
@ -394,59 +389,15 @@ bool CMapGenOptions::checkOptions() const
const CRmgTemplate * CMapGenOptions::getPossibleTemplate(CRandomGenerator & rand) const
{
// Find potential templates
const auto & tpls = getAvailableTemplates();
std::list<const CRmgTemplate *> potentialTpls;
for(const auto & tplPair : tpls)
{
const auto & tpl = tplPair.second;
int3 tplSize(width, height, (hasTwoLevels ? 2 : 1));
if(tpl->matchesSize(tplSize))
{
bool isPlayerCountValid = false;
if (getPlayerCount() != RANDOM_SIZE)
{
if (tpl->getPlayers().isInRange(getPlayerCount()))
isPlayerCountValid = true;
}
else
{
// Human players shouldn't be banned when playing with random player count
auto playerNumbers = tpl->getPlayers().getNumbers();
if(countHumanPlayers() <= *boost::min_element(playerNumbers))
{
isPlayerCountValid = true;
}
}
int3 tplSize(width, height, (hasTwoLevels ? 2 : 1));
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);
}
}
}
auto templates = VLC->tplh->getTemplates(tplSize, getPlayerCount(), countHumanPlayers(), compOnlyPlayerCount);
// Select tpl
if(potentialTpls.empty())
{
if(templates.empty())
return nullptr;
}
else
{
return *RandomGeneratorUtil::nextItem(potentialTpls, rand);
}
return *RandomGeneratorUtil::nextItem(templates, rand);
}
CMapGenOptions::CPlayerSettings::CPlayerSettings() : color(0), startingTown(RANDOM_TOWN), playerType(EPlayerType::AI)

View File

@ -94,6 +94,7 @@ public:
};
CMapGenOptions();
CMapGenOptions(const CMapGenOptions&) = delete;
si32 getWidth() const;
void setWidth(si32 value);
@ -141,8 +142,6 @@ public:
const CRmgTemplate * getMapTemplate() const;
void setMapTemplate(const CRmgTemplate * value);
const std::map<std::string, CRmgTemplate *> & 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.

View File

@ -46,7 +46,7 @@ void CMapGenerator::foreachDirectNeighbour(const int3& pos, std::function<void(i
}
}
void CMapGenerator::foreachDiagonaltNeighbour(const int3& pos, std::function<void(int3& pos)> foo)
void CMapGenerator::foreachDiagonalNeighbour(const int3& pos, std::function<void(int3& pos)> foo)
{
for (const int3 &dir : dirsDiagonal)
{
@ -57,11 +57,13 @@ void CMapGenerator::foreachDiagonaltNeighbour(const int3& pos, std::function<voi
}
CMapGenerator::CMapGenerator() :
mapGenOptions(nullptr), randomSeed(0), editManager(nullptr),
CMapGenerator::CMapGenerator(CMapGenOptions& mapGenOptions, int RandomSeed) :
mapGenOptions(mapGenOptions), randomSeed(RandomSeed),
zonesTotal(0), tiles(nullptr), prisonsRemaining(0),
monolithIndex(0)
{
rand.setSeed(this->randomSeed);
mapGenOptions.finalize(rand);
}
void CMapGenerator::initTiles()
@ -89,8 +91,8 @@ CMapGenerator::~CMapGenerator()
{
if (tiles)
{
int width = mapGenOptions->getWidth();
int height = mapGenOptions->getHeight();
int width = mapGenOptions.getWidth();
int height = mapGenOptions.getHeight();
for (int i=0; i < width; i++)
{
for(int j=0; j < height; j++)
@ -111,7 +113,7 @@ void CMapGenerator::initPrisonsRemaining()
if (isAllowed)
prisonsRemaining++;
}
prisonsRemaining = std::max<int> (0, prisonsRemaining - 16 * mapGenOptions->getPlayerCount()); //so at least 16 heroes will be available for every player
prisonsRemaining = std::max<int> (0, prisonsRemaining - 16 * mapGenOptions.getPlayerCount()); //so at least 16 heroes will be available for every player
}
void CMapGenerator::initQuestArtsRemaining()
@ -123,26 +125,27 @@ void CMapGenerator::initQuestArtsRemaining()
}
}
std::unique_ptr<CMap> CMapGenerator::generate(CMapGenOptions * mapGenOptions, int randomSeed)
const CMapGenOptions& CMapGenerator::getMapGenOptions() const
{
this->mapGenOptions = mapGenOptions;
this->randomSeed = randomSeed;
return mapGenOptions;
}
assert(mapGenOptions);
rand.setSeed(this->randomSeed);
mapGenOptions->finalize(rand);
CMapEditManager* CMapGenerator::getEditManager() const
{
if(!map)
return nullptr;
return map->getEditManager();
}
std::unique_ptr<CMap> CMapGenerator::generate()
{
map = make_unique<CMap>();
editManager = map->getEditManager();
try
{
editManager->getUndoManager().setUndoRedoLimit(0);
map->getEditManager()->getUndoManager().setUndoRedoLimit(0);
//FIXME: somehow mapGenOption is nullptr at this point :?
addHeaderInfo();
initTiles();
initPrisonsRemaining();
initQuestArtsRemaining();
genZones();
@ -160,14 +163,13 @@ std::unique_ptr<CMap> CMapGenerator::generate(CMapGenOptions * mapGenOptions, in
std::string CMapGenerator::getMapDescription() const
{
assert(mapGenOptions);
assert(map);
const std::string waterContentStr[3] = { "none", "normal", "islands" };
const std::string monsterStrengthStr[3] = { "weak", "normal", "strong" };
int monsterStrengthIndex = mapGenOptions->getMonsterStrength() - EMonsterStrength::GLOBAL_WEAK; //does not start from 0
const auto * mapTemplate = mapGenOptions->getMapTemplate();
int monsterStrengthIndex = mapGenOptions.getMonsterStrength() - EMonsterStrength::GLOBAL_WEAK; //does not start from 0
const auto * mapTemplate = mapGenOptions.getMapTemplate();
if(!mapTemplate)
throw rmgException("Map template for Random Map Generator is not found. Could not start the game.");
@ -175,11 +177,11 @@ std::string CMapGenerator::getMapDescription() const
std::stringstream ss;
ss << boost::str(boost::format(std::string("Map created by the Random Map Generator.\nTemplate was %s, Random seed was %d, size %dx%d") +
", levels %s, players %d, computers %d, water %s, monster %s, VCMI map") % mapTemplate->getName() %
randomSeed % map->width % map->height % (map->twoLevel ? "2" : "1") % static_cast<int>(mapGenOptions->getPlayerCount()) %
static_cast<int>(mapGenOptions->getCompOnlyPlayerCount()) % waterContentStr[mapGenOptions->getWaterContent()] %
randomSeed % map->width % map->height % (map->twoLevel ? "2" : "1") % static_cast<int>(mapGenOptions.getPlayerCount()) %
static_cast<int>(mapGenOptions.getCompOnlyPlayerCount()) % waterContentStr[mapGenOptions.getWaterContent()] %
monsterStrengthStr[monsterStrengthIndex]);
for(const auto & pair : mapGenOptions->getPlayersSettings())
for(const auto & pair : mapGenOptions.getPlayersSettings())
{
const auto & pSettings = pair.second;
if(pSettings.getPlayerType() == EPlayerType::HUMAN)
@ -211,13 +213,13 @@ void CMapGenerator::addPlayerInfo()
{
if (i == CPHUMAN)
{
playerCount = mapGenOptions->getPlayerCount();
teamCount = mapGenOptions->getTeamCount();
playerCount = mapGenOptions.getPlayerCount();
teamCount = mapGenOptions.getTeamCount();
}
else
{
playerCount = mapGenOptions->getCompOnlyPlayerCount();
teamCount = mapGenOptions->getCompOnlyTeamCount();
playerCount = mapGenOptions.getCompOnlyPlayerCount();
teamCount = mapGenOptions.getCompOnlyTeamCount();
}
if(playerCount == 0)
@ -246,7 +248,7 @@ void CMapGenerator::addPlayerInfo()
// Team numbers are assigned randomly to every player
//TODO: allow customize teams in rmg template
for(const auto & pair : mapGenOptions->getPlayersSettings())
for(const auto & pair : mapGenOptions.getPlayersSettings())
{
const auto & pSettings = pair.second;
PlayerInfo player;
@ -262,36 +264,34 @@ void CMapGenerator::addPlayerInfo()
logGlobal->error("Not enough places in team for %s player", ((j == CPUONLY) ? "CPU" : "CPU or human"));
assert (teamNumbers[j].size());
}
auto itTeam = RandomGeneratorUtil::nextItem(teamNumbers[j], rand);
auto itTeam = RandomGeneratorUtil::nextItem(teamNumbers[j], rand);
player.team = TeamID(*itTeam);
teamNumbers[j].erase(itTeam);
map->players[pSettings.getColor().getNum()] = player;
}
map->howManyTeams = (mapGenOptions->getTeamCount() == 0 ? mapGenOptions->getPlayerCount() : mapGenOptions->getTeamCount())
+ (mapGenOptions->getCompOnlyTeamCount() == 0 ? mapGenOptions->getCompOnlyPlayerCount() : mapGenOptions->getCompOnlyTeamCount());
map->howManyTeams = (mapGenOptions.getTeamCount() == 0 ? mapGenOptions.getPlayerCount() : mapGenOptions.getTeamCount())
+ (mapGenOptions.getCompOnlyTeamCount() == 0 ? mapGenOptions.getCompOnlyPlayerCount() : mapGenOptions.getCompOnlyTeamCount());
}
void CMapGenerator::genZones()
{
editManager->clearTerrain(&rand);
editManager->getTerrainSelection().selectRange(MapRect(int3(0, 0, 0), mapGenOptions->getWidth(), mapGenOptions->getHeight()));
editManager->drawTerrain(ETerrainType::GRASS, &rand);
getEditManager()->clearTerrain(&rand);
getEditManager()->getTerrainSelection().selectRange(MapRect(int3(0, 0, 0), mapGenOptions.getWidth(), mapGenOptions.getHeight()));
getEditManager()->drawTerrain(ETerrainType::GRASS, &rand);
auto tmpl = mapGenOptions->getMapTemplate();
auto tmpl = mapGenOptions.getMapTemplate();
zones.clear();
for(const auto & option : tmpl->getZones())
{
auto zone = std::make_shared<CRmgTemplateZone>();
auto zone = std::make_shared<CRmgTemplateZone>(this);
zone->setOptions(option.second.get());
zones[zone->getId()] = zone;
//todo: move to CRmgTemplateZone constructor
zone->setGenPtr(this);//immediately set gen pointer before taking any actions on zones
}
CZonePlacer placer(this);
placer.placeZones(mapGenOptions, &rand);
placer.assignZones(mapGenOptions);
placer.placeZones(&rand);
placer.assignZones();
logGlobal->info("Zones generated successfully");
}
@ -316,6 +316,7 @@ void CMapGenerator::fillZones()
it.second->initFreeTiles();
createDirectConnections(); //direct
//make sure all connections are passable before creating borders
for (auto it : zones)
it.second->createBorder(); //once direct connections are done
@ -335,6 +336,7 @@ void CMapGenerator::fillZones()
//set back original terrain for underground zones
for (auto it : zones)
it.second->createObstacles1();
createObstaclesCommon2();
//place actual obstacles matching zone terrain
for (auto it : zones)
@ -345,7 +347,7 @@ void CMapGenerator::fillZones()
#define PRINT_MAP_BEFORE_ROADS false
if (PRINT_MAP_BEFORE_ROADS) //enable to debug
{
std::ofstream out("road debug");
std::ofstream out("road_debug.txt");
int levels = map->twoLevel ? 2 : 1;
int width = map->width;
int height = map->height;
@ -413,8 +415,8 @@ void CMapGenerator::createObstaclesCommon1()
}
}
}
editManager->getTerrainSelection().setSelection(rockTiles);
editManager->drawTerrain(ETerrainType::ROCK, &rand);
getEditManager()->getTerrainSelection().setSelection(rockTiles);
getEditManager()->drawTerrain(ETerrainType::ROCK, &rand);
}
}
@ -483,7 +485,7 @@ void CMapGenerator::findZonesForQuestArts()
{
//we want to place arties in zones that were not yet filled (higher index)
for (auto connection : mapGenOptions->getMapTemplate()->getConnections())
for (auto connection : mapGenOptions.getMapTemplate()->getConnections())
{
auto zoneA = zones[connection.getZoneA()];
auto zoneB = zones[connection.getZoneB()];
@ -501,7 +503,7 @@ void CMapGenerator::findZonesForQuestArts()
void CMapGenerator::createDirectConnections()
{
for (auto connection : mapGenOptions->getMapTemplate()->getConnections())
for (auto connection : mapGenOptions.getMapTemplate()->getConnections())
{
auto zoneA = zones[connection.getZoneA()];
auto zoneB = zones[connection.getZoneB()];
@ -703,9 +705,9 @@ void CMapGenerator::createConnections2()
void CMapGenerator::addHeaderInfo()
{
map->version = EMapFormat::VCMI;
map->width = mapGenOptions->getWidth();
map->height = mapGenOptions->getHeight();
map->twoLevel = mapGenOptions->getHasTwoLevels();
map->width = mapGenOptions.getWidth();
map->height = mapGenOptions.getHeight();
map->twoLevel = mapGenOptions.getHasTwoLevels();
map->name = VLC->generaltexth->allTexts[740];
map->description = getMapDescription();
map->difficulty = 1;

View File

@ -52,16 +52,16 @@ class DLL_LINKAGE CMapGenerator
public:
using Zones = std::map<TRmgTemplateZoneId, std::shared_ptr<CRmgTemplateZone>>;
explicit CMapGenerator();
explicit CMapGenerator(CMapGenOptions& mapGenOptions, int RandomSeed = std::time(nullptr));
~CMapGenerator(); // required due to std::unique_ptr
std::unique_ptr<CMap> generate(CMapGenOptions * mapGenOptions, int RandomSeed = std::time(nullptr));
CMapGenOptions * mapGenOptions;
std::unique_ptr<CMap> map;
mutable std::unique_ptr<CMap> map;
CRandomGenerator rand;
int randomSeed;
CMapEditManager * editManager;
CMapEditManager* getEditManager() const;
const CMapGenOptions& getMapGenOptions() const;
std::unique_ptr<CMap> generate();
Zones & getZones();
void createDirectConnections();
@ -69,7 +69,7 @@ public:
void findZonesForQuestArts();
void foreach_neighbour(const int3 &pos, std::function<void(int3& pos)> foo);
void foreachDirectNeighbour(const int3 &pos, std::function<void(int3& pos)> foo);
void foreachDiagonaltNeighbour(const int3& pos, std::function<void(int3& pos)> foo);
void foreachDiagonalNeighbour(const int3& pos, std::function<void(int3& pos)> foo);
bool isBlocked(const int3 &tile) const;
bool shouldBeBlocked(const int3 &tile) const;
@ -101,6 +101,9 @@ public:
void setZoneID(const int3& tile, TRmgTemplateZoneId zid);
private:
int randomSeed;
CMapGenOptions& mapGenOptions;
std::list<rmg::ZoneConnection> connectionsLeft;
Zones zones;
std::map<TFaction, ui32> zonesPerFaction;

View File

@ -17,11 +17,6 @@
using namespace rmg;
const std::map<std::string, CRmgTemplate *> & CRmgTemplateStorage::getTemplates() const
{
return templates;
}
void CRmgTemplateStorage::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
{
//unused
@ -30,31 +25,20 @@ void CRmgTemplateStorage::loadObject(std::string scope, std::string name, const
void CRmgTemplateStorage::loadObject(std::string scope, std::string name, const JsonNode & data)
{
auto tpl = new CRmgTemplate();
try
{
JsonDeserializer handler(nullptr, data);
auto fullKey = normalizeIdentifier(scope, "core", name);
tpl->setId(name);
tpl->serializeJson(handler);
tpl->validate();
templates[fullKey] = tpl;
auto fullKey = normalizeIdentifier(scope, "core", name); //actually it's not used
templates[fullKey].setId(name);
templates[fullKey].serializeJson(handler);
templates[fullKey].validate();
}
catch(const std::exception & e)
{
logGlobal->error("Template %s has errors. Message: %s.", tpl->getName(), std::string(e.what()));
logGlobal->error("Template %s has errors. Message: %s.", name, std::string(e.what()));
}
}
CRmgTemplateStorage::CRmgTemplateStorage()
{
}
CRmgTemplateStorage::~CRmgTemplateStorage()
{
for (auto & pair : templates) delete pair.second;
}
std::vector<bool> CRmgTemplateStorage::getDefaultAllowed() const
{
//all templates are allowed
@ -66,3 +50,54 @@ std::vector<JsonNode> CRmgTemplateStorage::loadLegacyData(size_t dataSize)
return std::vector<JsonNode>();
//it would be cool to load old rmg.txt files
}
const CRmgTemplate * CRmgTemplateStorage::getTemplate(const std::string & templateName) const
{
auto iter = templates.find(templateName);
if(iter==templates.end())
return nullptr;
return &iter->second;
}
std::vector<const CRmgTemplate *> CRmgTemplateStorage::getTemplates() const
{
std::vector<const CRmgTemplate *> result;
for(auto i=templates.cbegin(); i!=templates.cend(); ++i)
{
result.push_back(&i->second);
}
return result;
}
std::vector<const CRmgTemplate *> CRmgTemplateStorage::getTemplates(const int3& filterSize, si8 filterPlayers, si8 filterHumanPlayers, si8 filterCpuPlayers) const
{
std::vector<const CRmgTemplate *> result;
for(auto i=templates.cbegin(); i!=templates.cend(); ++i)
{
auto& tmpl = i->second;
if (!tmpl.matchesSize(filterSize))
continue;
if (filterPlayers != -1)
{
if (!tmpl.getPlayers().isInRange(filterPlayers))
continue;
}
else
{
// Human players shouldn't be banned when playing with random player count
if (filterHumanPlayers > *boost::min_element(tmpl.getPlayers().getNumbers()))
continue;
}
if(filterCpuPlayers != -1)
{
if (!tmpl.getCpuPlayers().isInRange(filterCpuPlayers))
continue;
}
result.push_back(&i->second);
}
return result;
}

View File

@ -11,18 +11,16 @@
#pragma once
#include "../IHandlerBase.h"
#include "../int3.h"
#include "CRmgTemplate.h"
class JsonNode;
class CRmgTemplate;
/// The CJsonRmgTemplateLoader loads templates from a JSON file.
class DLL_LINKAGE CRmgTemplateStorage : public IHandlerBase
{
public:
CRmgTemplateStorage();
~CRmgTemplateStorage();
const std::map<std::string, CRmgTemplate *> & getTemplates() const;
CRmgTemplateStorage() = default;
std::vector<bool> getDefaultAllowed() const override;
std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
@ -31,7 +29,11 @@ public:
virtual void loadObject(std::string scope, std::string name, const JsonNode & data) override;
virtual void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;
const CRmgTemplate * getTemplate(const std::string & templateName) const;
std::vector<const CRmgTemplate *> getTemplates() const;
std::vector<const CRmgTemplate *> getTemplates(const int3& filterSize, si8 filterPlayers, si8 filterHumanPlayers, si8 filterCpuPlayers) const;
private:
std::map<std::string, CRmgTemplate *> templates;
std::map<std::string, CRmgTemplate> templates;
};

View File

@ -103,27 +103,27 @@ void CTileInfo::setRoadType(ERoadType::ERoadType value)
}
CRmgTemplateZone::CRmgTemplateZone()
CRmgTemplateZone::CRmgTemplateZone(CMapGenerator * Gen)
: ZoneOptions(),
townType(ETownType::NEUTRAL),
terrainType (ETerrainType::GRASS),
minGuardedValue(0),
questArtZone(),
gen(nullptr)
gen(Gen)
{
}
bool CRmgTemplateZone::isUnderground() const
{
return getPos().z;
}
void CRmgTemplateZone::setOptions(const ZoneOptions * options)
{
ZoneOptions::operator=(*options);
}
void CRmgTemplateZone::setGenPtr(CMapGenerator * Gen)
{
gen = Gen;
}
void CRmgTemplateZone::setQuestArtZone(std::shared_ptr<CRmgTemplateZone> otherZone)
{
questArtZone = otherZone;
@ -384,7 +384,7 @@ void CRmgTemplateZone::fractalize()
#define PRINT_FRACTALIZED_MAP false
if (PRINT_FRACTALIZED_MAP) //enable to debug
{
std::ofstream out(boost::to_string(boost::format("zone %d") % id));
std::ofstream out(boost::to_string(boost::format("zone_%d.txt") % id));
int levels = gen->map->twoLevel ? 2 : 1;
int width = gen->map->width;
int height = gen->map->height;
@ -618,7 +618,7 @@ bool CRmgTemplateZone::createRoad(const int3& src, const int3& dst)
if (!directNeighbourFound)
{
movementCost = 2.1f; //moving diagonally is penalized over moving two tiles straight
gen->foreachDiagonaltNeighbour(currentNode, foo);
gen->foreachDiagonalNeighbour(currentNode, foo);
}
}
@ -805,7 +805,7 @@ bool CRmgTemplateZone::addMonster(int3 &pos, si32 strength, bool clearSurroundin
//precalculate actual (randomized) monster strength based on this post
//http://forum.vcmi.eu/viewtopic.php?p=12426#12426
int mapMonsterStrength = gen->mapGenOptions->getMonsterStrength();
int mapMonsterStrength = gen->getMapGenOptions().getMonsterStrength();
int monsterStrength = (zoneGuard ? 0 : zoneMonsterStrength) + mapMonsterStrength - 1; //array index from 0 to 4
static const int value1[] = {2500, 1500, 1000, 500, 0};
static const int value2[] = {7500, 7500, 7500, 5000, 5000};
@ -1181,10 +1181,10 @@ void CRmgTemplateZone::initTownType ()
if (playerInfo.canAnyonePlay())
{
player = PlayerColor(player_id);
townType = gen->mapGenOptions->getPlayersSettings().find(player)->second.getStartingTown();
townType = gen->getMapGenOptions().getPlayersSettings().find(player)->second.getStartingTown();
if (townType == CMapGenOptions::CPlayerSettings::RANDOM_TOWN)
randomizeTownType();
randomizeTownType(true);
}
else //no player - randomize town
{
@ -1261,12 +1261,25 @@ void CRmgTemplateZone::initTownType ()
}
}
void CRmgTemplateZone::randomizeTownType ()
void CRmgTemplateZone::randomizeTownType(bool matchUndergroundType)
{
if (townTypes.size())
townType = *RandomGeneratorUtil::nextItem(townTypes, gen->rand);
else
townType = *RandomGeneratorUtil::nextItem(getDefaultTownTypes(), gen->rand); //it is possible to have zone with no towns allowed, we still need some
auto townTypesAllowed = (townTypes.size() ? townTypes : getDefaultTownTypes());
if(matchUndergroundType && gen->getMapGenOptions().getHasTwoLevels())
{
std::set<TFaction> townTypesVerify;
for(TFaction factionIdx : townTypesAllowed)
{
bool preferUnderground = (*VLC->townh)[factionIdx]->preferUndergroundPlacement;
if(isUnderground() ? preferUnderground : !preferUnderground)
{
townTypesVerify.insert(factionIdx);
}
}
if(!townTypesVerify.empty())
townTypesAllowed = townTypesVerify;
}
townType = *RandomGeneratorUtil::nextItem(townTypesAllowed, gen->rand);
}
void CRmgTemplateZone::initTerrainType ()
@ -1278,7 +1291,7 @@ void CRmgTemplateZone::initTerrainType ()
terrainType = *RandomGeneratorUtil::nextItem(terrainTypes, gen->rand);
//TODO: allow new types of terrain?
if (pos.z)
if (isUnderground())
{
if (terrainType != ETerrainType::LAVA)
terrainType = ETerrainType::SUBTERRANEAN;
@ -1295,8 +1308,8 @@ void CRmgTemplateZone::initTerrainType ()
void CRmgTemplateZone::paintZoneTerrain (ETerrainType terrainType)
{
std::vector<int3> tiles(tileinfo.begin(), tileinfo.end());
gen->editManager->getTerrainSelection().setSelection(tiles);
gen->editManager->drawTerrain(terrainType, &gen->rand);
gen->getEditManager()->getTerrainSelection().setSelection(tiles);
gen->getEditManager()->drawTerrain(terrainType, &gen->rand);
}
bool CRmgTemplateZone::placeMines ()
@ -1493,7 +1506,7 @@ bool CRmgTemplateZone::createRequiredObjects()
void CRmgTemplateZone::createTreasures()
{
int mapMonsterStrength = gen->mapGenOptions->getMonsterStrength();
int mapMonsterStrength = gen->getMapGenOptions().getMonsterStrength();
int monsterStrength = zoneMonsterStrength + mapMonsterStrength - 1; //array index from 0 to 4
static int minGuardedValues[] = { 6500, 4167, 3000, 1833, 1333 };
@ -1570,8 +1583,8 @@ void CRmgTemplateZone::createObstacles1()
accessibleTiles.push_back(tile);
}
}
gen->editManager->getTerrainSelection().setSelection(accessibleTiles);
gen->editManager->drawTerrain(terrainType, &gen->rand);
gen->getEditManager()->getTerrainSelection().setSelection(accessibleTiles);
gen->getEditManager()->drawTerrain(terrainType, &gen->rand);
}
}
@ -1610,7 +1623,7 @@ void CRmgTemplateZone::createObstacles2()
return p1.first > p2.first; //bigger obstacles first
});
auto sel = gen->editManager->getTerrainSelection();
auto sel = gen->getEditManager()->getTerrainSelection();
sel.clearSelection();
auto tryToPlaceObstacleHere = [this, &possibleObstacles](int3& tile, int index)-> bool
@ -1705,8 +1718,8 @@ void CRmgTemplateZone::drawRoads()
tiles.push_back(tile);
}
gen->editManager->getTerrainSelection().setSelection(tiles);
gen->editManager->drawRoad(ERoadType::COBBLESTONE_ROAD, &gen->rand);
gen->getEditManager()->getTerrainSelection().setSelection(tiles);
gen->getEditManager()->drawRoad(ERoadType::COBBLESTONE_ROAD, &gen->rand);
}
@ -1903,7 +1916,7 @@ void CRmgTemplateZone::checkAndPlaceObject(CGObjectInstance* object, const int3
object->appearance = templates.front();
}
gen->editManager->insertObject(object);
gen->getEditManager()->insertObject(object);
}
void CRmgTemplateZone::placeObject(CGObjectInstance* object, const int3 &pos, bool updateDistance)

View File

@ -89,11 +89,10 @@ struct DLL_LINKAGE CTreasurePileInfo
class DLL_LINKAGE CRmgTemplateZone : public rmg::ZoneOptions
{
public:
CRmgTemplateZone();
CRmgTemplateZone(CMapGenerator * Gen);
void setOptions(const rmg::ZoneOptions * options);
void setGenPtr(CMapGenerator * Gen);
bool isUnderground() const;
float3 getCenter() const;
void setCenter(const float3 &f);
@ -119,7 +118,7 @@ public:
bool placeMines ();
void initTownType ();
void paintZoneTerrain (ETerrainType terrainType);
void randomizeTownType(); //helper function
void randomizeTownType(bool matchUndergroundType = false); //helper function
void initTerrainType ();
void createBorder();
void fractalize();

View File

@ -40,15 +40,15 @@ float CZonePlacer::getDistance (float distance) const
return (distance ? distance * distance : 1e-6f);
}
void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenerator * rand)
void CZonePlacer::placeZones(CRandomGenerator * rand)
{
logGlobal->info("Starting zone placement");
width = mapGenOptions->getWidth();
height = mapGenOptions->getHeight();
width = gen->getMapGenOptions().getWidth();
height = gen->getMapGenOptions().getHeight();
auto zones = gen->getZones();
bool underground = mapGenOptions->getHasTwoLevels();
bool underground = gen->getMapGenOptions().getHasTwoLevels();
/*
gravity-based algorithm
@ -174,7 +174,7 @@ void CZonePlacer::prepareZones(TZoneMap &zones, TZoneVector &zonesVector, const
if (boost::optional<int> owner = zone.second->getOwner())
{
auto player = PlayerColor(*owner - 1);
auto playerSettings = gen->mapGenOptions->getPlayersSettings();
auto playerSettings = gen->getMapGenOptions().getPlayersSettings();
si32 faction = CMapGenOptions::CPlayerSettings::RANDOM_TOWN;
if (vstd::contains(playerSettings, player))
faction = playerSettings[player].getStartingTown();
@ -453,12 +453,12 @@ d = 0.01 * dx^3 - 0.1618 * dx^2 + 1 * dx + ...
return dx * (1.0f + dx * (0.1f + dx * 0.01f)) + dy * (1.618f + dy * (-0.1618f + dy * 0.01618f));
}
void CZonePlacer::assignZones(const CMapGenOptions * mapGenOptions)
void CZonePlacer::assignZones()
{
logGlobal->info("Starting zone colouring");
auto width = mapGenOptions->getWidth();
auto height = mapGenOptions->getHeight();
auto width = gen->getMapGenOptions().getWidth();
auto height = gen->getMapGenOptions().getHeight();
//scale to Medium map to ensure smooth results
scaleX = 72.f / width;
@ -554,7 +554,7 @@ void CZonePlacer::assignZones(const CMapGenOptions * mapGenOptions)
//TODO: similiar for islands
#define CREATE_FULL_UNDERGROUND true //consider linking this with water amount
if (zone.second->getPos().z)
if (zone.second->isUnderground())
{
if (!CREATE_FULL_UNDERGROUND)
zone.second->discardDistantTiles((float)(zone.second->getSize() + 1));

View File

@ -34,12 +34,14 @@ public:
float getDistance(float distance) const; //additional scaling without 0 divison
~CZonePlacer();
void placeZones(CRandomGenerator * rand);
void assignZones();
private:
void prepareZones(TZoneMap &zones, TZoneVector &zonesVector, const bool underground, CRandomGenerator * rand);
void attractConnectedZones(TZoneMap &zones, TForceVector &forces, TDistanceVector &distances);
void separateOverlappingZones(TZoneMap &zones, TForceVector &forces, TDistanceVector &overlaps);
void moveOneZone(TZoneMap &zones, TForceVector &totalForces, TDistanceVector &distances, TDistanceVector &overlaps);
void placeZones(const CMapGenOptions * mapGenOptions, CRandomGenerator * rand);
void assignZones(const CMapGenOptions * mapGenOptions);
private:
int width;

View File

@ -59,9 +59,9 @@ TEST(MapFormat, Random)
opt.setPlayerTypeForStandardPlayer(PlayerColor(2), EPlayerType::AI);
opt.setPlayerTypeForStandardPlayer(PlayerColor(3), EPlayerType::AI);
CMapGenerator gen;
CMapGenerator gen(opt, TEST_RANDOM_SEED);
std::unique_ptr<CMap> initialMap = gen.generate(&opt, TEST_RANDOM_SEED);
std::unique_ptr<CMap> initialMap = gen.generate();
initialMap->name = "Test";
SCOPED_TRACE("MapFormat_Random generated");