CMapGenerator.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986
  1. #include "StdInc.h"
  2. #include "CMapGenerator.h"
  3. #include "../mapping/CMap.h"
  4. #include "../VCMI_Lib.h"
  5. #include "../CGeneralTextHandler.h"
  6. #include "../mapping/CMapEditManager.h"
  7. #include "../CObjectHandler.h"
  8. #include "../CDefObjInfoHandler.h"
  9. #include "../CTownHandler.h"
  10. #include "../StringConstants.h"
  11. #include "../filesystem/CResourceLoader.h"
  12. CMapGenOptions::CMapGenOptions() : width(CMapHeader::MAP_SIZE_MIDDLE), height(CMapHeader::MAP_SIZE_MIDDLE), hasTwoLevels(true),
  13. playersCnt(RANDOM_SIZE), teamsCnt(RANDOM_SIZE), compOnlyPlayersCnt(0), compOnlyTeamsCnt(RANDOM_SIZE),
  14. waterContent(EWaterContent::RANDOM), monsterStrength(EMonsterStrength::RANDOM)
  15. {
  16. resetPlayersMap();
  17. }
  18. si32 CMapGenOptions::getWidth() const
  19. {
  20. return width;
  21. }
  22. void CMapGenOptions::setWidth(si32 value)
  23. {
  24. assert(value >= 1);
  25. width = value;
  26. }
  27. si32 CMapGenOptions::getHeight() const
  28. {
  29. return height;
  30. }
  31. void CMapGenOptions::setHeight(si32 value)
  32. {
  33. assert(value >= 1);
  34. height = value;
  35. }
  36. bool CMapGenOptions::getHasTwoLevels() const
  37. {
  38. return hasTwoLevels;
  39. }
  40. void CMapGenOptions::setHasTwoLevels(bool value)
  41. {
  42. hasTwoLevels = value;
  43. }
  44. si8 CMapGenOptions::getPlayersCnt() const
  45. {
  46. return playersCnt;
  47. }
  48. void CMapGenOptions::setPlayersCnt(si8 value)
  49. {
  50. assert((value >= 1 && value <= PlayerColor::PLAYER_LIMIT_I) || value == RANDOM_SIZE);
  51. playersCnt = value;
  52. resetPlayersMap();
  53. }
  54. si8 CMapGenOptions::getTeamsCnt() const
  55. {
  56. return teamsCnt;
  57. }
  58. void CMapGenOptions::setTeamsCnt(si8 value)
  59. {
  60. assert(playersCnt == RANDOM_SIZE || (value >= 0 && value < playersCnt) || value == RANDOM_SIZE);
  61. teamsCnt = value;
  62. }
  63. si8 CMapGenOptions::getCompOnlyPlayersCnt() const
  64. {
  65. return compOnlyPlayersCnt;
  66. }
  67. void CMapGenOptions::setCompOnlyPlayersCnt(si8 value)
  68. {
  69. assert(value == RANDOM_SIZE || (value >= 0 && value <= PlayerColor::PLAYER_LIMIT_I - playersCnt));
  70. compOnlyPlayersCnt = value;
  71. resetPlayersMap();
  72. }
  73. si8 CMapGenOptions::getCompOnlyTeamsCnt() const
  74. {
  75. return compOnlyTeamsCnt;
  76. }
  77. void CMapGenOptions::setCompOnlyTeamsCnt(si8 value)
  78. {
  79. assert(value == RANDOM_SIZE || compOnlyPlayersCnt == RANDOM_SIZE || (value >= 0 && value <= std::max(compOnlyPlayersCnt - 1, 0)));
  80. compOnlyTeamsCnt = value;
  81. }
  82. EWaterContent::EWaterContent CMapGenOptions::getWaterContent() const
  83. {
  84. return waterContent;
  85. }
  86. void CMapGenOptions::setWaterContent(EWaterContent::EWaterContent value)
  87. {
  88. waterContent = value;
  89. }
  90. EMonsterStrength::EMonsterStrength CMapGenOptions::getMonsterStrength() const
  91. {
  92. return monsterStrength;
  93. }
  94. void CMapGenOptions::setMonsterStrength(EMonsterStrength::EMonsterStrength value)
  95. {
  96. monsterStrength = value;
  97. }
  98. void CMapGenOptions::resetPlayersMap()
  99. {
  100. players.clear();
  101. int realPlayersCnt = playersCnt == RANDOM_SIZE ? static_cast<int>(PlayerColor::PLAYER_LIMIT_I) : playersCnt;
  102. int realCompOnlyPlayersCnt = compOnlyPlayersCnt == RANDOM_SIZE ? (PlayerColor::PLAYER_LIMIT_I - realPlayersCnt) : compOnlyPlayersCnt;
  103. for(int color = 0; color < (realPlayersCnt + realCompOnlyPlayersCnt); ++color)
  104. {
  105. CPlayerSettings player;
  106. player.setColor(PlayerColor(color));
  107. player.setPlayerType((color >= realPlayersCnt) ? EPlayerType::COMP_ONLY : EPlayerType::AI);
  108. players[PlayerColor(color)] = player;
  109. }
  110. }
  111. const std::map<PlayerColor, CMapGenOptions::CPlayerSettings> & CMapGenOptions::getPlayersSettings() const
  112. {
  113. return players;
  114. }
  115. void CMapGenOptions::setStartingTownForPlayer(PlayerColor color, si32 town)
  116. {
  117. auto it = players.find(color);
  118. if(it == players.end()) assert(0);
  119. it->second.setStartingTown(town);
  120. }
  121. void CMapGenOptions::setPlayerTypeForStandardPlayer(PlayerColor color, EPlayerType::EPlayerType playerType)
  122. {
  123. assert(playerType != EPlayerType::COMP_ONLY);
  124. auto it = players.find(color);
  125. if(it == players.end()) assert(0);
  126. it->second.setPlayerType(playerType);
  127. }
  128. void CMapGenOptions::finalize()
  129. {
  130. CRandomGenerator gen;
  131. finalize(gen);
  132. }
  133. void CMapGenOptions::finalize(CRandomGenerator & gen)
  134. {
  135. if(playersCnt == RANDOM_SIZE)
  136. {
  137. // 1 human is required at least
  138. auto humanPlayers = countHumanPlayers();
  139. if(humanPlayers == 0) humanPlayers = 1;
  140. playersCnt = gen.getInteger(humanPlayers, PlayerColor::PLAYER_LIMIT_I);
  141. // Remove AI players only from the end of the players map if necessary
  142. for(auto itrev = players.end(); itrev != players.begin();)
  143. {
  144. auto it = itrev;
  145. --it;
  146. if(players.size() == playersCnt) break;
  147. if(it->second.getPlayerType() == EPlayerType::AI)
  148. {
  149. players.erase(it);
  150. }
  151. else
  152. {
  153. --itrev;
  154. }
  155. }
  156. }
  157. if(teamsCnt == RANDOM_SIZE)
  158. {
  159. teamsCnt = gen.getInteger(0, playersCnt - 1);
  160. }
  161. if(compOnlyPlayersCnt == RANDOM_SIZE)
  162. {
  163. compOnlyPlayersCnt = gen.getInteger(0, 8 - playersCnt);
  164. auto totalPlayersCnt = playersCnt + compOnlyPlayersCnt;
  165. // Remove comp only players only from the end of the players map if necessary
  166. for(auto itrev = players.end(); itrev != players.begin();)
  167. {
  168. auto it = itrev;
  169. --it;
  170. if(players.size() <= totalPlayersCnt) break;
  171. if(it->second.getPlayerType() == EPlayerType::COMP_ONLY)
  172. {
  173. players.erase(it);
  174. }
  175. else
  176. {
  177. --itrev;
  178. }
  179. }
  180. // Add some comp only players if necessary
  181. auto compOnlyPlayersToAdd = totalPlayersCnt - players.size();
  182. for(int i = 0; i < compOnlyPlayersToAdd; ++i)
  183. {
  184. CPlayerSettings pSettings;
  185. pSettings.setPlayerType(EPlayerType::COMP_ONLY);
  186. pSettings.setColor(getNextPlayerColor());
  187. players[pSettings.getColor()] = pSettings;
  188. }
  189. }
  190. if(compOnlyTeamsCnt == RANDOM_SIZE)
  191. {
  192. compOnlyTeamsCnt = gen.getInteger(0, std::max(compOnlyPlayersCnt - 1, 0));
  193. }
  194. // There should be at least 2 players (1-player-maps aren't allowed)
  195. if(playersCnt + compOnlyPlayersCnt < 2)
  196. {
  197. CPlayerSettings pSettings;
  198. pSettings.setPlayerType(EPlayerType::AI);
  199. pSettings.setColor(getNextPlayerColor());
  200. players[pSettings.getColor()] = pSettings;
  201. playersCnt = 2;
  202. }
  203. // 1 team isn't allowed
  204. if(teamsCnt == 1 && compOnlyPlayersCnt == 0)
  205. {
  206. teamsCnt = 0;
  207. }
  208. if(waterContent == EWaterContent::RANDOM)
  209. {
  210. waterContent = static_cast<EWaterContent::EWaterContent>(gen.getInteger(0, 2));
  211. }
  212. if(monsterStrength == EMonsterStrength::RANDOM)
  213. {
  214. monsterStrength = static_cast<EMonsterStrength::EMonsterStrength>(gen.getInteger(0, 2));
  215. }
  216. }
  217. int CMapGenOptions::countHumanPlayers() const
  218. {
  219. return static_cast<int>(boost::count_if(players, [](const std::pair<PlayerColor, CPlayerSettings> & pair)
  220. {
  221. return pair.second.getPlayerType() == EPlayerType::HUMAN;
  222. }));
  223. }
  224. PlayerColor CMapGenOptions::getNextPlayerColor() const
  225. {
  226. for(PlayerColor i = PlayerColor(0); i < PlayerColor::PLAYER_LIMIT; i.advance(1))
  227. {
  228. if(!players.count(i))
  229. {
  230. return i;
  231. }
  232. }
  233. assert(0);
  234. return PlayerColor(0);
  235. }
  236. CMapGenOptions::CPlayerSettings::CPlayerSettings() : color(0), startingTown(RANDOM_TOWN), playerType(EPlayerType::AI)
  237. {
  238. }
  239. PlayerColor CMapGenOptions::CPlayerSettings::getColor() const
  240. {
  241. return color;
  242. }
  243. void CMapGenOptions::CPlayerSettings::setColor(PlayerColor value)
  244. {
  245. assert(value >= PlayerColor(0) && value < PlayerColor::PLAYER_LIMIT);
  246. color = value;
  247. }
  248. si32 CMapGenOptions::CPlayerSettings::getStartingTown() const
  249. {
  250. return startingTown;
  251. }
  252. void CMapGenOptions::CPlayerSettings::setStartingTown(si32 value)
  253. {
  254. assert(value >= -1 && value < static_cast<int>(VLC->townh->factions.size()));
  255. startingTown = value;
  256. }
  257. EPlayerType::EPlayerType CMapGenOptions::CPlayerSettings::getPlayerType() const
  258. {
  259. return playerType;
  260. }
  261. void CMapGenOptions::CPlayerSettings::setPlayerType(EPlayerType::EPlayerType value)
  262. {
  263. playerType = value;
  264. }
  265. CMapGenerator::CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed /*= std::time(nullptr)*/) :
  266. mapGenOptions(mapGenOptions), randomSeed(randomSeed)
  267. {
  268. gen.seed(randomSeed);
  269. }
  270. CMapGenerator::~CMapGenerator()
  271. {
  272. }
  273. std::unique_ptr<CMap> CMapGenerator::generate()
  274. {
  275. mapGenOptions.finalize(gen);
  276. //TODO select a template based on the map gen options or adapt it if necessary
  277. CRandomMapTemplateStorage::get();
  278. map = make_unique<CMap>();
  279. editManager = map->getEditManager();
  280. editManager->getUndoManager().setUndoRedoLimit(0);
  281. addHeaderInfo();
  282. genTerrain();
  283. genTowns();
  284. return std::move(map);
  285. }
  286. std::string CMapGenerator::getMapDescription() const
  287. {
  288. const std::string waterContentStr[3] = { "none", "normal", "islands" };
  289. const std::string monsterStrengthStr[3] = { "weak", "normal", "strong" };
  290. std::stringstream ss;
  291. ss << "Map created by the Random Map Generator.\nTemplate was <MOCK>, ";
  292. ss << "Random seed was " << randomSeed << ", size " << map->width << "x";
  293. ss << map->height << ", levels " << (map->twoLevel ? "2" : "1") << ", ";
  294. ss << "humans " << static_cast<int>(mapGenOptions.getPlayersCnt()) << ", computers ";
  295. ss << static_cast<int>(mapGenOptions.getCompOnlyPlayersCnt()) << ", water " << waterContentStr[mapGenOptions.getWaterContent()];
  296. ss << ", monster " << monsterStrengthStr[mapGenOptions.getMonsterStrength()] << ", second expansion map";
  297. BOOST_FOREACH(const auto & pair, mapGenOptions.getPlayersSettings())
  298. {
  299. const auto & pSettings = pair.second;
  300. if(pSettings.getPlayerType() == EPlayerType::HUMAN)
  301. {
  302. ss << ", " << GameConstants::PLAYER_COLOR_NAMES[pSettings.getColor().getNum()] << " is human";
  303. }
  304. if(pSettings.getStartingTown() != CMapGenOptions::CPlayerSettings::RANDOM_TOWN)
  305. {
  306. ss << ", " << GameConstants::PLAYER_COLOR_NAMES[pSettings.getColor().getNum()]
  307. << " town choice is " << ETownType::names[pSettings.getStartingTown()];
  308. }
  309. }
  310. return ss.str();
  311. }
  312. void CMapGenerator::addPlayerInfo()
  313. {
  314. // Calculate which team numbers exist
  315. std::array<std::list<int>, 2> teamNumbers; // 0= cpu/human, 1= cpu only
  316. int teamOffset = 0;
  317. for(int i = 0; i < 2; ++i)
  318. {
  319. int playersCnt = i == 0 ? mapGenOptions.getPlayersCnt() : mapGenOptions.getCompOnlyPlayersCnt();
  320. int teamsCnt = i == 0 ? mapGenOptions.getTeamsCnt() : mapGenOptions.getCompOnlyTeamsCnt();
  321. if(playersCnt == 0)
  322. {
  323. continue;
  324. }
  325. int playersPerTeam = playersCnt /
  326. (teamsCnt == 0 ? playersCnt : teamsCnt);
  327. int teamsCntNorm = teamsCnt;
  328. if(teamsCntNorm == 0)
  329. {
  330. teamsCntNorm = playersCnt;
  331. }
  332. for(int j = 0; j < teamsCntNorm; ++j)
  333. {
  334. for(int k = 0; k < playersPerTeam; ++k)
  335. {
  336. teamNumbers[i].push_back(j + teamOffset);
  337. }
  338. }
  339. for(int j = 0; j < playersCnt - teamsCntNorm * playersPerTeam; ++j)
  340. {
  341. teamNumbers[i].push_back(j + teamOffset);
  342. }
  343. teamOffset += teamsCntNorm;
  344. }
  345. // Team numbers are assigned randomly to every player
  346. BOOST_FOREACH(const auto & pair, mapGenOptions.getPlayersSettings())
  347. {
  348. const auto & pSettings = pair.second;
  349. PlayerInfo player;
  350. player.canComputerPlay = true;
  351. int j = pSettings.getPlayerType() == EPlayerType::COMP_ONLY ? 1 : 0;
  352. if(j == 0)
  353. {
  354. player.canHumanPlay = true;
  355. }
  356. auto itTeam = std::next(teamNumbers[j].begin(), gen.getInteger(0, teamNumbers[j].size() - 1));
  357. player.team = TeamID(*itTeam);
  358. teamNumbers[j].erase(itTeam);
  359. map->players[pSettings.getColor().getNum()] = player;
  360. }
  361. map->howManyTeams = (mapGenOptions.getTeamsCnt() == 0 ? mapGenOptions.getPlayersCnt() : mapGenOptions.getTeamsCnt())
  362. + (mapGenOptions.getCompOnlyTeamsCnt() == 0 ? mapGenOptions.getCompOnlyPlayersCnt() : mapGenOptions.getCompOnlyTeamsCnt());
  363. }
  364. void CMapGenerator::genTerrain()
  365. {
  366. map->initTerrain();
  367. editManager->clearTerrain(&gen);
  368. editManager->getTerrainSelection().selectRange(MapRect(int3(10, 10, 0), 20, 30));
  369. editManager->drawTerrain(ETerrainType::GRASS, &gen);
  370. }
  371. void CMapGenerator::genTowns()
  372. {
  373. //FIXME mock gen
  374. const int3 townPos[2] = { int3(17, 13, 0), int3(25,13, 0) };
  375. const int townTypes[2] = { ETownType::CASTLE, ETownType::DUNGEON };
  376. for(size_t i = 0; i < map->players.size(); ++i)
  377. {
  378. auto & playerInfo = map->players[i];
  379. if(!playerInfo.canAnyonePlay()) break;
  380. PlayerColor owner(i);
  381. int side = i % 2;
  382. CGTownInstance * town = new CGTownInstance();
  383. town->ID = Obj::TOWN;
  384. town->subID = townTypes[side];
  385. town->tempOwner = owner;
  386. town->defInfo = VLC->dobjinfo->gobjs[town->ID][town->subID];
  387. town->builtBuildings.insert(BuildingID::FORT);
  388. town->builtBuildings.insert(BuildingID::DEFAULT);
  389. editManager->insertObject(town, int3(townPos[side].x, townPos[side].y + (i / 2) * 5, 0));
  390. // Update player info
  391. playerInfo.allowedFactions.clear();
  392. playerInfo.allowedFactions.insert(townTypes[side]);
  393. playerInfo.hasMainTown = true;
  394. playerInfo.posOfMainTown = town->pos - int3(2, 0, 0);
  395. playerInfo.generateHeroAtMainTown = true;
  396. }
  397. }
  398. void CMapGenerator::addHeaderInfo()
  399. {
  400. map->version = EMapFormat::SOD;
  401. map->width = mapGenOptions.getWidth();
  402. map->height = mapGenOptions.getHeight();
  403. map->twoLevel = mapGenOptions.getHasTwoLevels();
  404. map->name = VLC->generaltexth->allTexts[740];
  405. map->description = getMapDescription();
  406. map->difficulty = 1;
  407. addPlayerInfo();
  408. }
  409. CTemplateZoneTowns::CTemplateZoneTowns() : minTowns(0), minCastles(0), townDensity(0), castleDensity(0)
  410. {
  411. }
  412. int CTemplateZoneTowns::getMinTowns() const
  413. {
  414. return minTowns;
  415. }
  416. void CTemplateZoneTowns::setMinTowns(int value)
  417. {
  418. assert(value >= 0);
  419. minTowns = value;
  420. }
  421. int CTemplateZoneTowns::getMinCastles() const
  422. {
  423. return minCastles;
  424. }
  425. void CTemplateZoneTowns::setMinCastles(int value)
  426. {
  427. assert(value >= 0);
  428. minCastles = value;
  429. }
  430. int CTemplateZoneTowns::getTownDensity() const
  431. {
  432. return townDensity;
  433. }
  434. void CTemplateZoneTowns::setTownDensity(int value)
  435. {
  436. assert(value >= 0);
  437. townDensity = value;
  438. }
  439. int CTemplateZoneTowns::getCastleDensity() const
  440. {
  441. return castleDensity;
  442. }
  443. void CTemplateZoneTowns::setCastleDensity(int value)
  444. {
  445. assert(value >= 0);
  446. castleDensity = value;
  447. }
  448. CTemplateZone::CTemplateZone() : id(0), type(ETemplateZoneType::HUMAN_START), baseSize(0), owner(0),
  449. neutralTownsAreSameType(false), matchTerrainToTown(true)
  450. {
  451. }
  452. TTemplateZoneId CTemplateZone::getId() const
  453. {
  454. return id;
  455. }
  456. void CTemplateZone::setId(TTemplateZoneId value)
  457. {
  458. id = value;
  459. }
  460. ETemplateZoneType::ETemplateZoneType CTemplateZone::getType() const
  461. {
  462. return type;
  463. }
  464. void CTemplateZone::setType(ETemplateZoneType::ETemplateZoneType value)
  465. {
  466. type = value;
  467. }
  468. int CTemplateZone::getBaseSize() const
  469. {
  470. return baseSize;
  471. }
  472. void CTemplateZone::setBaseSize(int value)
  473. {
  474. assert(value >= 0);
  475. baseSize = value;
  476. }
  477. int CTemplateZone::getOwner() const
  478. {
  479. return owner;
  480. }
  481. void CTemplateZone::setOwner(int value)
  482. {
  483. owner = value;
  484. }
  485. const CTemplateZoneTowns & CTemplateZone::getPlayerTowns() const
  486. {
  487. return playerTowns;
  488. }
  489. void CTemplateZone::setPlayerTowns(const CTemplateZoneTowns & value)
  490. {
  491. playerTowns = value;
  492. }
  493. const CTemplateZoneTowns & CTemplateZone::getNeutralTowns() const
  494. {
  495. return neutralTowns;
  496. }
  497. void CTemplateZone::setNeutralTowns(const CTemplateZoneTowns & value)
  498. {
  499. neutralTowns = value;
  500. }
  501. bool CTemplateZone::getNeutralTownsAreSameType() const
  502. {
  503. return neutralTownsAreSameType;
  504. }
  505. void CTemplateZone::setNeutralTownsAreSameType(bool value)
  506. {
  507. neutralTownsAreSameType = value;
  508. }
  509. const std::set<TFaction> & CTemplateZone::getAllowedTownTypes() const
  510. {
  511. return allowedTownTypes;
  512. }
  513. void CTemplateZone::setAllowedTownTypes(const std::set<TFaction> & value)
  514. {
  515. allowedTownTypes = value;
  516. }
  517. bool CTemplateZone::getMatchTerrainToTown() const
  518. {
  519. return matchTerrainToTown;
  520. }
  521. void CTemplateZone::setMatchTerrainToTown(bool value)
  522. {
  523. matchTerrainToTown = value;
  524. }
  525. const std::set<ETerrainType> & CTemplateZone::getTerrainTypes() const
  526. {
  527. return terrainTypes;
  528. }
  529. void CTemplateZone::setTerrainTypes(const std::set<ETerrainType> & value)
  530. {
  531. assert(value.find(ETerrainType::WRONG) == value.end() && value.find(ETerrainType::BORDER) == value.end() &&
  532. value.find(ETerrainType::WATER) == value.end());
  533. terrainTypes = value;
  534. }
  535. CTemplateZoneConnection::CTemplateZoneConnection() : zoneA(0), zoneB(0), guardStrength(0)
  536. {
  537. }
  538. TTemplateZoneId CTemplateZoneConnection::getZoneA() const
  539. {
  540. return zoneA;
  541. }
  542. void CTemplateZoneConnection::setZoneA(TTemplateZoneId value)
  543. {
  544. zoneA = value;
  545. }
  546. TTemplateZoneId CTemplateZoneConnection::getZoneB() const
  547. {
  548. return zoneB;
  549. }
  550. void CTemplateZoneConnection::setZoneB(TTemplateZoneId value)
  551. {
  552. zoneB = value;
  553. }
  554. int CTemplateZoneConnection::getGuardStrength() const
  555. {
  556. return guardStrength;
  557. }
  558. void CTemplateZoneConnection::setGuardStrength(int value)
  559. {
  560. assert(value >= 0);
  561. guardStrength = value;
  562. }
  563. CRandomMapTemplateSize::CRandomMapTemplateSize() : width(CMapHeader::MAP_SIZE_MIDDLE), height(CMapHeader::MAP_SIZE_MIDDLE), under(true)
  564. {
  565. }
  566. CRandomMapTemplateSize::CRandomMapTemplateSize(int width, int height, bool under) : width(width), height(height), under(under)
  567. {
  568. }
  569. int CRandomMapTemplateSize::getWidth() const
  570. {
  571. return width;
  572. }
  573. void CRandomMapTemplateSize::setWidth(int value)
  574. {
  575. assert(value >= 1);
  576. width = value;
  577. }
  578. int CRandomMapTemplateSize::getHeight() const
  579. {
  580. return height;
  581. }
  582. void CRandomMapTemplateSize::setHeight(int value)
  583. {
  584. assert(value >= 1);
  585. height = value;
  586. }
  587. bool CRandomMapTemplateSize::getUnder() const
  588. {
  589. return under;
  590. }
  591. void CRandomMapTemplateSize::setUnder(bool value)
  592. {
  593. under = value;
  594. }
  595. CRandomMapTemplate::CRandomMapTemplate() : minHumanCnt(1), maxHumanCnt(PlayerColor::PLAYER_LIMIT_I), minTotalCnt(2),
  596. maxTotalCnt(PlayerColor::PLAYER_LIMIT_I)
  597. {
  598. minSize = CRandomMapTemplateSize(CMapHeader::MAP_SIZE_SMALL, CMapHeader::MAP_SIZE_SMALL, false);
  599. maxSize = CRandomMapTemplateSize(CMapHeader::MAP_SIZE_XLARGE, CMapHeader::MAP_SIZE_XLARGE, true);
  600. }
  601. const std::string & CRandomMapTemplate::getName() const
  602. {
  603. return name;
  604. }
  605. void CRandomMapTemplate::setName(const std::string & value)
  606. {
  607. name = value;
  608. }
  609. const CRandomMapTemplateSize & CRandomMapTemplate::getMinSize() const
  610. {
  611. return minSize;
  612. }
  613. void CRandomMapTemplate::setMinSize(const CRandomMapTemplateSize & value)
  614. {
  615. minSize = value;
  616. }
  617. const CRandomMapTemplateSize & CRandomMapTemplate::getMaxSize() const
  618. {
  619. return maxSize;
  620. }
  621. void CRandomMapTemplate::setMaxSize(const CRandomMapTemplateSize & value)
  622. {
  623. maxSize = value;
  624. }
  625. int CRandomMapTemplate::getMinHumanCnt() const
  626. {
  627. return minHumanCnt;
  628. }
  629. void CRandomMapTemplate::setMinHumanCnt(int value)
  630. {
  631. assert(value >= 1 && value <= PlayerColor::PLAYER_LIMIT_I);
  632. minHumanCnt = value;
  633. }
  634. int CRandomMapTemplate::getMaxHumanCnt() const
  635. {
  636. return maxHumanCnt;
  637. }
  638. void CRandomMapTemplate::setMaxHumanCnt(int value)
  639. {
  640. assert(value >= 1 && value <= PlayerColor::PLAYER_LIMIT_I);
  641. maxHumanCnt = value;
  642. }
  643. int CRandomMapTemplate::getMinTotalCnt() const
  644. {
  645. return minTotalCnt;
  646. }
  647. void CRandomMapTemplate::setMinTotalCnt(int value)
  648. {
  649. assert(value >= 2 && value <= PlayerColor::PLAYER_LIMIT_I);
  650. minTotalCnt = value;
  651. }
  652. int CRandomMapTemplate::getMaxTotalCnt() const
  653. {
  654. return maxTotalCnt;
  655. }
  656. void CRandomMapTemplate::setMaxTotalCnt(int value)
  657. {
  658. assert(value >= 2 && value <= PlayerColor::PLAYER_LIMIT_I);
  659. maxTotalCnt = value;
  660. }
  661. const std::map<TTemplateZoneId, CTemplateZone> & CRandomMapTemplate::getZones() const
  662. {
  663. return zones;
  664. }
  665. void CRandomMapTemplate::setZones(const std::map<TTemplateZoneId, CTemplateZone> & value)
  666. {
  667. zones = value;
  668. }
  669. const std::list<CTemplateZoneConnection> & CRandomMapTemplate::getConnections() const
  670. {
  671. return connections;
  672. }
  673. void CRandomMapTemplate::setConnections(const std::list<CTemplateZoneConnection> & value)
  674. {
  675. connections = value;
  676. }
  677. const std::map<std::string, CRandomMapTemplate> & CRmTemplateLoader::getTemplates() const
  678. {
  679. return templates;
  680. }
  681. void CJsonRmTemplateLoader::loadTemplates()
  682. {
  683. const JsonNode rootNode(ResourceID("config/rmg.json"));
  684. BOOST_FOREACH(const auto & templatePair, rootNode.Struct())
  685. {
  686. CRandomMapTemplate tpl;
  687. tpl.setName(templatePair.first);
  688. const auto & templateNode = templatePair.second;
  689. // Parse main template data
  690. tpl.setMinSize(parseMapTemplateSize(templateNode["minSize"].String()));
  691. tpl.setMaxSize(parseMapTemplateSize(templateNode["maxSize"].String()));
  692. tpl.setMinHumanCnt(templateNode["minHumanCnt"].Float());
  693. tpl.setMaxHumanCnt(templateNode["maxHumanCnt"].Float());
  694. tpl.setMinTotalCnt(templateNode["minTotalCnt"].Float());
  695. tpl.setMaxTotalCnt(templateNode["maxTotalCnt"].Float());
  696. // Parse zones
  697. std::map<TTemplateZoneId, CTemplateZone> zones;
  698. BOOST_FOREACH(const auto & zonePair, templateNode["zones"].Struct())
  699. {
  700. CTemplateZone zone;
  701. auto zoneId = boost::lexical_cast<TTemplateZoneId>(zonePair.first);
  702. zone.setId(zoneId);
  703. const auto & zoneNode = zonePair.second;
  704. zone.setType(getZoneType(zoneNode["type"].String()));
  705. zone.setBaseSize(zoneNode["baseSize"].Float());
  706. zone.setOwner(zoneNode["owner"].Float());
  707. zone.setPlayerTowns(parseTemplateZoneTowns(zoneNode["playerTowns"]));
  708. zone.setNeutralTowns(parseTemplateZoneTowns(zoneNode["neutralTowns"]));
  709. zone.setAllowedTownTypes(getFactions(zoneNode["allowedTownTypes"].Vector()));
  710. zone.setMatchTerrainToTown(zoneNode["matchTerrainToTown"].Bool());
  711. zone.setTerrainTypes(parseTerrainTypes(zoneNode["terrainTypes"].Vector()));
  712. zone.setNeutralTownsAreSameType((zoneNode["neutralTownsAreSameType"].Bool()));
  713. zones[zone.getId()] = zone;
  714. }
  715. tpl.setZones(zones);
  716. // Parse connections
  717. std::list<CTemplateZoneConnection> connections;
  718. BOOST_FOREACH(const auto & connPair, templateNode["connections"].Vector())
  719. {
  720. CTemplateZoneConnection conn;
  721. conn.setZoneA(boost::lexical_cast<TTemplateZoneId>(connPair["a"].String()));
  722. conn.setZoneB(boost::lexical_cast<TTemplateZoneId>(connPair["b"].String()));
  723. conn.setGuardStrength(connPair["guardStrength"].Float());
  724. connections.push_back(conn);
  725. }
  726. tpl.setConnections(connections);
  727. templates[tpl.getName()] = tpl;
  728. }
  729. }
  730. CRandomMapTemplateSize CJsonRmTemplateLoader::parseMapTemplateSize(const std::string & text) const
  731. {
  732. CRandomMapTemplateSize size;
  733. if(text.empty()) return size;
  734. std::vector<std::string> parts;
  735. boost::split(parts, text, boost::is_any_of("+"));
  736. static const std::map<std::string, int> mapSizeMapping = boost::assign::map_list_of("s", CMapHeader::MAP_SIZE_SMALL)
  737. ("m", CMapHeader::MAP_SIZE_MIDDLE)("l", CMapHeader::MAP_SIZE_LARGE)("xl", CMapHeader::MAP_SIZE_XLARGE);
  738. auto it = mapSizeMapping.find(parts[0]);
  739. if(it == mapSizeMapping.end())
  740. {
  741. // Map size is given as a number representation
  742. const auto & numericalRep = parts[0];
  743. parts.clear();
  744. boost::split(parts, numericalRep, boost::is_any_of("x"));
  745. assert(parts.size() == 3);
  746. size.setWidth(boost::lexical_cast<int>(parts[0]));
  747. size.setHeight(boost::lexical_cast<int>(parts[1]));
  748. size.setUnder(boost::lexical_cast<int>(parts[2]) == 1);
  749. }
  750. else
  751. {
  752. size.setWidth(it->second);
  753. size.setHeight(it->second);
  754. size.setUnder(parts.size() > 1 ? parts[1] == std::string("u") : false);
  755. }
  756. return size;
  757. }
  758. ETemplateZoneType::ETemplateZoneType CJsonRmTemplateLoader::getZoneType(const std::string & type) const
  759. {
  760. static const std::map<std::string, ETemplateZoneType::ETemplateZoneType> zoneTypeMapping = boost::assign::map_list_of
  761. ("humanStart", ETemplateZoneType::HUMAN_START)("computerStart", ETemplateZoneType::COMPUTER_START)
  762. ("treasure", ETemplateZoneType::TREASURE)("junction", ETemplateZoneType::JUNCTION);
  763. auto it = zoneTypeMapping.find(type);
  764. assert(it != zoneTypeMapping.end());
  765. return it->second;
  766. }
  767. CTemplateZoneTowns CJsonRmTemplateLoader::parseTemplateZoneTowns(const JsonNode & node) const
  768. {
  769. CTemplateZoneTowns towns;
  770. towns.setMinTowns(node["minTowns"].Float());
  771. towns.setMinCastles(node["minCastles"].Float());
  772. towns.setTownDensity(node["townDensity"].Float());
  773. towns.setCastleDensity(node["castleDensity"].Float());
  774. return towns;
  775. }
  776. std::set<TFaction> CJsonRmTemplateLoader::getFactions(const std::vector<JsonNode> factionStrings) const
  777. {
  778. std::set<TFaction> factions;
  779. BOOST_FOREACH(const auto & factionNode, factionStrings)
  780. {
  781. auto factionStr = factionNode.String();
  782. if(factionStr == "all")
  783. {
  784. factions.clear();
  785. BOOST_FOREACH(auto factionPtr, VLC->townh->factions)
  786. {
  787. factions.insert(factionPtr->index);
  788. }
  789. return factions;
  790. }
  791. BOOST_FOREACH(auto factionPtr, VLC->townh->factions)
  792. {
  793. if(factionStr == factionPtr->name)
  794. {
  795. factions.insert(factionPtr->index);
  796. break;
  797. }
  798. }
  799. }
  800. return factions;
  801. }
  802. std::set<ETerrainType> CJsonRmTemplateLoader::parseTerrainTypes(const std::vector<JsonNode> terTypeStrings) const
  803. {
  804. std::set<ETerrainType> terTypes;
  805. BOOST_FOREACH(const auto & node, terTypeStrings)
  806. {
  807. const auto & terTypeStr = node.String();
  808. if(terTypeStr == "all")
  809. {
  810. for(int i = 0; i < GameConstants::TERRAIN_TYPES; ++i) terTypes.insert(ETerrainType(i));
  811. break;
  812. }
  813. terTypes.insert(ETerrainType(vstd::find_pos(GameConstants::TERRAIN_NAMES, terTypeStr)));
  814. }
  815. return terTypes;
  816. }
  817. boost::mutex CRandomMapTemplateStorage::smx;
  818. CRandomMapTemplateStorage & CRandomMapTemplateStorage::get()
  819. {
  820. TLockGuard _(smx);
  821. static CRandomMapTemplateStorage storage;
  822. return storage;
  823. }
  824. const std::map<std::string, CRandomMapTemplate> & CRandomMapTemplateStorage::getTemplates() const
  825. {
  826. return templates;
  827. }
  828. CRandomMapTemplateStorage::CRandomMapTemplateStorage()
  829. {
  830. auto jsonLoader = make_unique<CJsonRmTemplateLoader>();
  831. jsonLoader->loadTemplates();
  832. const auto & tpls = jsonLoader->getTemplates();
  833. templates.insert(tpls.begin(), tpls.end());
  834. }
  835. CRandomMapTemplateStorage::~CRandomMapTemplateStorage()
  836. {
  837. }