CMapGenerator.cpp 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199
  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/Filesystem.h"
  12. CMapGenOptions::CMapGenOptions() : width(CMapHeader::MAP_SIZE_MIDDLE), height(CMapHeader::MAP_SIZE_MIDDLE), hasTwoLevels(false),
  13. playerCount(RANDOM_SIZE), teamCount(RANDOM_SIZE), compOnlyPlayerCount(0), compOnlyTeamCount(RANDOM_SIZE),
  14. waterContent(EWaterContent::RANDOM), monsterStrength(EMonsterStrength::RANDOM), mapTemplate(nullptr)
  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::getPlayerCount() const
  45. {
  46. return playerCount;
  47. }
  48. void CMapGenOptions::setPlayerCount(si8 value)
  49. {
  50. assert((value >= 1 && value <= PlayerColor::PLAYER_LIMIT_I) || value == RANDOM_SIZE);
  51. playerCount = value;
  52. resetPlayersMap();
  53. }
  54. si8 CMapGenOptions::getTeamCount() const
  55. {
  56. return teamCount;
  57. }
  58. void CMapGenOptions::setTeamCount(si8 value)
  59. {
  60. assert(playerCount == RANDOM_SIZE || (value >= 0 && value < playerCount) || value == RANDOM_SIZE);
  61. teamCount = value;
  62. }
  63. si8 CMapGenOptions::getCompOnlyPlayerCount() const
  64. {
  65. return compOnlyPlayerCount;
  66. }
  67. void CMapGenOptions::setCompOnlyPlayerCount(si8 value)
  68. {
  69. assert(value == RANDOM_SIZE || (value >= 0 && value <= PlayerColor::PLAYER_LIMIT_I - playerCount));
  70. compOnlyPlayerCount = value;
  71. resetPlayersMap();
  72. }
  73. si8 CMapGenOptions::getCompOnlyTeamCount() const
  74. {
  75. return compOnlyTeamCount;
  76. }
  77. void CMapGenOptions::setCompOnlyTeamCount(si8 value)
  78. {
  79. assert(value == RANDOM_SIZE || compOnlyPlayerCount == RANDOM_SIZE || (value >= 0 && value <= std::max(compOnlyPlayerCount - 1, 0)));
  80. compOnlyTeamCount = 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 = playerCount == RANDOM_SIZE ? static_cast<int>(PlayerColor::PLAYER_LIMIT_I) : playerCount;
  102. int realCompOnlyPlayersCnt = compOnlyPlayerCount == RANDOM_SIZE ? (PlayerColor::PLAYER_LIMIT_I - realPlayersCnt) : compOnlyPlayerCount;
  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. const CRmgTemplate * CMapGenOptions::getMapTemplate() const
  129. {
  130. return mapTemplate;
  131. }
  132. void CMapGenOptions::setMapTemplate(const CRmgTemplate * value)
  133. {
  134. mapTemplate = value;
  135. //TODO validate & adapt options according to template
  136. assert(0);
  137. }
  138. const std::map<std::string, CRmgTemplate> & CMapGenOptions::getAvailableTemplates() const
  139. {
  140. return CRmgTemplateStorage::get().getTemplates();
  141. }
  142. void CMapGenOptions::finalize()
  143. {
  144. CRandomGenerator gen;
  145. finalize(gen);
  146. }
  147. void CMapGenOptions::finalize(CRandomGenerator & gen)
  148. {
  149. if(!mapTemplate)
  150. {
  151. mapTemplate = getPossibleTemplate(gen);
  152. assert(mapTemplate);
  153. }
  154. if(playerCount == RANDOM_SIZE)
  155. {
  156. auto possiblePlayers = mapTemplate->getPlayers().getNumbers();
  157. possiblePlayers.erase(possiblePlayers.begin(), possiblePlayers.lower_bound(countHumanPlayers()));
  158. assert(!possiblePlayers.empty());
  159. playerCount = *std::next(possiblePlayers.begin(), gen.getInteger(0, possiblePlayers.size() - 1));
  160. updatePlayers();
  161. }
  162. if(teamCount == RANDOM_SIZE)
  163. {
  164. teamCount = gen.getInteger(0, playerCount - 1);
  165. }
  166. if(compOnlyPlayerCount == RANDOM_SIZE)
  167. {
  168. auto possiblePlayers = mapTemplate->getCpuPlayers().getNumbers();
  169. compOnlyPlayerCount = *std::next(possiblePlayers.begin(), gen.getInteger(0, possiblePlayers.size() - 1));
  170. updateCompOnlyPlayers();
  171. }
  172. if(compOnlyTeamCount == RANDOM_SIZE)
  173. {
  174. compOnlyTeamCount = gen.getInteger(0, std::max(compOnlyPlayerCount - 1, 0));
  175. }
  176. // 1 team isn't allowed
  177. if(teamCount == 1 && compOnlyPlayerCount == 0)
  178. {
  179. teamCount = 0;
  180. }
  181. if(waterContent == EWaterContent::RANDOM)
  182. {
  183. waterContent = static_cast<EWaterContent::EWaterContent>(gen.getInteger(0, 2));
  184. }
  185. if(monsterStrength == EMonsterStrength::RANDOM)
  186. {
  187. monsterStrength = static_cast<EMonsterStrength::EMonsterStrength>(gen.getInteger(0, 2));
  188. }
  189. }
  190. void CMapGenOptions::updatePlayers()
  191. {
  192. // Remove AI players only from the end of the players map if necessary
  193. for(auto itrev = players.end(); itrev != players.begin();)
  194. {
  195. auto it = itrev;
  196. --it;
  197. if(players.size() == playerCount) break;
  198. if(it->second.getPlayerType() == EPlayerType::AI)
  199. {
  200. players.erase(it);
  201. }
  202. else
  203. {
  204. --itrev;
  205. }
  206. }
  207. }
  208. void CMapGenOptions::updateCompOnlyPlayers()
  209. {
  210. auto totalPlayersCnt = playerCount + compOnlyPlayerCount;
  211. // Remove comp only players only from the end of the players map if necessary
  212. for(auto itrev = players.end(); itrev != players.begin();)
  213. {
  214. auto it = itrev;
  215. --it;
  216. if(players.size() <= totalPlayersCnt) break;
  217. if(it->second.getPlayerType() == EPlayerType::COMP_ONLY)
  218. {
  219. players.erase(it);
  220. }
  221. else
  222. {
  223. --itrev;
  224. }
  225. }
  226. // Add some comp only players if necessary
  227. auto compOnlyPlayersToAdd = totalPlayersCnt - players.size();
  228. for(int i = 0; i < compOnlyPlayersToAdd; ++i)
  229. {
  230. CPlayerSettings pSettings;
  231. pSettings.setPlayerType(EPlayerType::COMP_ONLY);
  232. pSettings.setColor(getNextPlayerColor());
  233. players[pSettings.getColor()] = pSettings;
  234. }
  235. }
  236. int CMapGenOptions::countHumanPlayers() const
  237. {
  238. return static_cast<int>(boost::count_if(players, [](const std::pair<PlayerColor, CPlayerSettings> & pair)
  239. {
  240. return pair.second.getPlayerType() == EPlayerType::HUMAN;
  241. }));
  242. }
  243. PlayerColor CMapGenOptions::getNextPlayerColor() const
  244. {
  245. for(PlayerColor i = PlayerColor(0); i < PlayerColor::PLAYER_LIMIT; i.advance(1))
  246. {
  247. if(!players.count(i))
  248. {
  249. return i;
  250. }
  251. }
  252. assert(0);
  253. return PlayerColor(0);
  254. }
  255. bool CMapGenOptions::checkOptions() const
  256. {
  257. assert(countHumanPlayers() > 0);
  258. if(mapTemplate)
  259. {
  260. return true;
  261. }
  262. else
  263. {
  264. CRandomGenerator gen;
  265. return getPossibleTemplate(gen) != nullptr;
  266. }
  267. }
  268. const CRmgTemplate * CMapGenOptions::getPossibleTemplate(CRandomGenerator & gen) const
  269. {
  270. // Find potential templates
  271. const auto & tpls = getAvailableTemplates();
  272. std::list<const CRmgTemplate *> potentialTpls;
  273. for(const auto & tplPair : tpls)
  274. {
  275. const auto & tpl = tplPair.second;
  276. CRmgTemplate::CSize tplSize(width, height, hasTwoLevels);
  277. if(tplSize >= tpl.getMinSize() && tplSize <= tpl.getMaxSize())
  278. {
  279. bool isPlayerCountValid = false;
  280. if(playerCount != RANDOM_SIZE)
  281. {
  282. if(tpl.getPlayers().isInRange(playerCount)) isPlayerCountValid = true;
  283. }
  284. else
  285. {
  286. // Human players shouldn't be banned when playing with random player count
  287. auto playerNumbers = tpl.getPlayers().getNumbers();
  288. if(playerNumbers.lower_bound(countHumanPlayers()) != playerNumbers.end())
  289. {
  290. isPlayerCountValid = true;
  291. }
  292. }
  293. if(isPlayerCountValid)
  294. {
  295. bool isCpuPlayerCountValid = false;
  296. if(compOnlyPlayerCount != RANDOM_SIZE)
  297. {
  298. if(tpl.getCpuPlayers().isInRange(compOnlyPlayerCount)) isCpuPlayerCountValid = true;
  299. }
  300. else
  301. {
  302. isCpuPlayerCountValid = true;
  303. }
  304. if(isCpuPlayerCountValid) potentialTpls.push_back(&tpl);
  305. }
  306. }
  307. }
  308. // Select tpl
  309. if(potentialTpls.empty())
  310. {
  311. return nullptr;
  312. }
  313. else
  314. {
  315. return *std::next(potentialTpls.begin(), gen.getInteger(0, potentialTpls.size() - 1));
  316. }
  317. }
  318. CMapGenOptions::CPlayerSettings::CPlayerSettings() : color(0), startingTown(RANDOM_TOWN), playerType(EPlayerType::AI)
  319. {
  320. }
  321. PlayerColor CMapGenOptions::CPlayerSettings::getColor() const
  322. {
  323. return color;
  324. }
  325. void CMapGenOptions::CPlayerSettings::setColor(PlayerColor value)
  326. {
  327. assert(value >= PlayerColor(0) && value < PlayerColor::PLAYER_LIMIT);
  328. color = value;
  329. }
  330. si32 CMapGenOptions::CPlayerSettings::getStartingTown() const
  331. {
  332. return startingTown;
  333. }
  334. void CMapGenOptions::CPlayerSettings::setStartingTown(si32 value)
  335. {
  336. assert(value >= -1);
  337. if(value >= 0)
  338. {
  339. assert(value < static_cast<int>(VLC->townh->factions.size()));
  340. assert(VLC->townh->factions[value]->town != nullptr);
  341. }
  342. startingTown = value;
  343. }
  344. EPlayerType::EPlayerType CMapGenOptions::CPlayerSettings::getPlayerType() const
  345. {
  346. return playerType;
  347. }
  348. void CMapGenOptions::CPlayerSettings::setPlayerType(EPlayerType::EPlayerType value)
  349. {
  350. playerType = value;
  351. }
  352. CMapGenerator::CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed /*= std::time(nullptr)*/) :
  353. mapGenOptions(mapGenOptions), randomSeed(randomSeed)
  354. {
  355. gen.seed(randomSeed);
  356. }
  357. CMapGenerator::~CMapGenerator()
  358. {
  359. }
  360. std::unique_ptr<CMap> CMapGenerator::generate()
  361. {
  362. mapGenOptions.finalize(gen);
  363. map = make_unique<CMap>();
  364. editManager = map->getEditManager();
  365. editManager->getUndoManager().setUndoRedoLimit(0);
  366. addHeaderInfo();
  367. genTerrain();
  368. genTowns();
  369. return std::move(map);
  370. }
  371. std::string CMapGenerator::getMapDescription() const
  372. {
  373. const std::string waterContentStr[3] = { "none", "normal", "islands" };
  374. const std::string monsterStrengthStr[3] = { "weak", "normal", "strong" };
  375. std::stringstream ss;
  376. ss << boost::str(boost::format(std::string("Map created by the Random Map Generator.\nTemplate was %s, Random seed was %d, size %dx%d") +
  377. ", levels %s, humans %d, computers %d, water %s, monster %s, second expansion map") % mapGenOptions.getMapTemplate()->getName() %
  378. randomSeed % map->width % map->height % (map->twoLevel ? "2" : "1") % static_cast<int>(mapGenOptions.getPlayerCount()) %
  379. static_cast<int>(mapGenOptions.getCompOnlyPlayerCount()) % waterContentStr[mapGenOptions.getWaterContent()] %
  380. monsterStrengthStr[mapGenOptions.getMonsterStrength()]);
  381. for(const auto & pair : mapGenOptions.getPlayersSettings())
  382. {
  383. const auto & pSettings = pair.second;
  384. if(pSettings.getPlayerType() == EPlayerType::HUMAN)
  385. {
  386. ss << ", " << GameConstants::PLAYER_COLOR_NAMES[pSettings.getColor().getNum()] << " is human";
  387. }
  388. if(pSettings.getStartingTown() != CMapGenOptions::CPlayerSettings::RANDOM_TOWN)
  389. {
  390. ss << ", " << GameConstants::PLAYER_COLOR_NAMES[pSettings.getColor().getNum()]
  391. << " town choice is " << ETownType::names[pSettings.getStartingTown()];
  392. }
  393. }
  394. return ss.str();
  395. }
  396. void CMapGenerator::addPlayerInfo()
  397. {
  398. // Calculate which team numbers exist
  399. std::array<std::list<int>, 2> teamNumbers; // 0= cpu/human, 1= cpu only
  400. int teamOffset = 0;
  401. for(int i = 0; i < 2; ++i)
  402. {
  403. int playerCount = i == 0 ? mapGenOptions.getPlayerCount() : mapGenOptions.getCompOnlyPlayerCount();
  404. int teamCount = i == 0 ? mapGenOptions.getTeamCount() : mapGenOptions.getCompOnlyTeamCount();
  405. if(playerCount == 0)
  406. {
  407. continue;
  408. }
  409. int playersPerTeam = playerCount /
  410. (teamCount == 0 ? playerCount : teamCount);
  411. int teamCountNorm = teamCount;
  412. if(teamCountNorm == 0)
  413. {
  414. teamCountNorm = playerCount;
  415. }
  416. for(int j = 0; j < teamCountNorm; ++j)
  417. {
  418. for(int k = 0; k < playersPerTeam; ++k)
  419. {
  420. teamNumbers[i].push_back(j + teamOffset);
  421. }
  422. }
  423. for(int j = 0; j < playerCount - teamCountNorm * playersPerTeam; ++j)
  424. {
  425. teamNumbers[i].push_back(j + teamOffset);
  426. }
  427. teamOffset += teamCountNorm;
  428. }
  429. // Team numbers are assigned randomly to every player
  430. for(const auto & pair : mapGenOptions.getPlayersSettings())
  431. {
  432. const auto & pSettings = pair.second;
  433. PlayerInfo player;
  434. player.canComputerPlay = true;
  435. int j = pSettings.getPlayerType() == EPlayerType::COMP_ONLY ? 1 : 0;
  436. if(j == 0)
  437. {
  438. player.canHumanPlay = true;
  439. }
  440. auto itTeam = std::next(teamNumbers[j].begin(), gen.getInteger(0, teamNumbers[j].size() - 1));
  441. player.team = TeamID(*itTeam);
  442. teamNumbers[j].erase(itTeam);
  443. map->players[pSettings.getColor().getNum()] = player;
  444. }
  445. map->howManyTeams = (mapGenOptions.getTeamCount() == 0 ? mapGenOptions.getPlayerCount() : mapGenOptions.getTeamCount())
  446. + (mapGenOptions.getCompOnlyTeamCount() == 0 ? mapGenOptions.getCompOnlyPlayerCount() : mapGenOptions.getCompOnlyTeamCount());
  447. }
  448. void CMapGenerator::genTerrain()
  449. {
  450. map->initTerrain();
  451. editManager->clearTerrain(&gen);
  452. editManager->getTerrainSelection().selectRange(MapRect(int3(4, 4, 0), 24, 30));
  453. editManager->drawTerrain(ETerrainType::GRASS, &gen);
  454. }
  455. void CMapGenerator::genTowns()
  456. {
  457. //FIXME mock gen
  458. const int3 townPos[2] = { int3(11, 7, 0), int3(19,7, 0) };
  459. for(size_t i = 0; i < map->players.size(); ++i)
  460. {
  461. auto & playerInfo = map->players[i];
  462. if(!playerInfo.canAnyonePlay()) break;
  463. PlayerColor owner(i);
  464. int side = i % 2;
  465. auto town = new CGTownInstance();
  466. town->ID = Obj::TOWN;
  467. int townId = mapGenOptions.getPlayersSettings().find(PlayerColor(i))->second.getStartingTown();
  468. if(townId == CMapGenOptions::CPlayerSettings::RANDOM_TOWN) townId = gen.getInteger(0, 8); // Default towns
  469. town->subID = townId;
  470. town->tempOwner = owner;
  471. town->defInfo = VLC->dobjinfo->gobjs[town->ID][town->subID];
  472. town->builtBuildings.insert(BuildingID::FORT);
  473. town->builtBuildings.insert(BuildingID::DEFAULT);
  474. editManager->insertObject(town, int3(townPos[side].x, townPos[side].y + (i / 2) * 5, 0));
  475. // Update player info
  476. playerInfo.allowedFactions.clear();
  477. playerInfo.allowedFactions.insert(townId);
  478. playerInfo.hasMainTown = true;
  479. playerInfo.posOfMainTown = town->pos - int3(2, 0, 0);
  480. playerInfo.generateHeroAtMainTown = true;
  481. }
  482. }
  483. void CMapGenerator::addHeaderInfo()
  484. {
  485. map->version = EMapFormat::SOD;
  486. map->width = mapGenOptions.getWidth();
  487. map->height = mapGenOptions.getHeight();
  488. map->twoLevel = mapGenOptions.getHasTwoLevels();
  489. map->name = VLC->generaltexth->allTexts[740];
  490. map->description = getMapDescription();
  491. map->difficulty = 1;
  492. addPlayerInfo();
  493. }
  494. CRmgTemplateZone::CTownInfo::CTownInfo() : townCount(0), castleCount(0), townDensity(0), castleDensity(0)
  495. {
  496. }
  497. int CRmgTemplateZone::CTownInfo::getTownCount() const
  498. {
  499. return townCount;
  500. }
  501. void CRmgTemplateZone::CTownInfo::setTownCount(int value)
  502. {
  503. if(value < 0) throw std::runtime_error("Negative value for town count not allowed.");
  504. townCount = value;
  505. }
  506. int CRmgTemplateZone::CTownInfo::getCastleCount() const
  507. {
  508. return castleCount;
  509. }
  510. void CRmgTemplateZone::CTownInfo::setCastleCount(int value)
  511. {
  512. if(value < 0) throw std::runtime_error("Negative value for castle count not allowed.");
  513. castleCount = value;
  514. }
  515. int CRmgTemplateZone::CTownInfo::getTownDensity() const
  516. {
  517. return townDensity;
  518. }
  519. void CRmgTemplateZone::CTownInfo::setTownDensity(int value)
  520. {
  521. if(value < 0) throw std::runtime_error("Negative value for town density not allowed.");
  522. townDensity = value;
  523. }
  524. int CRmgTemplateZone::CTownInfo::getCastleDensity() const
  525. {
  526. return castleDensity;
  527. }
  528. void CRmgTemplateZone::CTownInfo::setCastleDensity(int value)
  529. {
  530. if(value < 0) throw std::runtime_error("Negative value for castle density not allowed.");
  531. castleDensity = value;
  532. }
  533. CRmgTemplateZone::CRmgTemplateZone() : id(0), type(ETemplateZoneType::PLAYER_START), size(1),
  534. townsAreSameType(false), matchTerrainToTown(true)
  535. {
  536. townTypes = getDefaultTownTypes();
  537. terrainTypes = getDefaultTerrainTypes();
  538. }
  539. TRmgTemplateZoneId CRmgTemplateZone::getId() const
  540. {
  541. return id;
  542. }
  543. void CRmgTemplateZone::setId(TRmgTemplateZoneId value)
  544. {
  545. if(value <= 0) throw std::runtime_error("Zone id should be greater than 0.");
  546. id = value;
  547. }
  548. ETemplateZoneType::ETemplateZoneType CRmgTemplateZone::getType() const
  549. {
  550. return type;
  551. }
  552. void CRmgTemplateZone::setType(ETemplateZoneType::ETemplateZoneType value)
  553. {
  554. type = value;
  555. }
  556. int CRmgTemplateZone::getSize() const
  557. {
  558. return size;
  559. }
  560. void CRmgTemplateZone::setSize(int value)
  561. {
  562. if(value <= 0) throw std::runtime_error("Zone size needs to be greater than 0.");
  563. size = value;
  564. }
  565. boost::optional<int> CRmgTemplateZone::getOwner() const
  566. {
  567. return owner;
  568. }
  569. void CRmgTemplateZone::setOwner(boost::optional<int> value)
  570. {
  571. if(!(*value >= 0 && *value <= PlayerColor::PLAYER_LIMIT_I)) throw std::runtime_error("Owner has to be in range 0 to max player count.");
  572. owner = value;
  573. }
  574. const CRmgTemplateZone::CTownInfo & CRmgTemplateZone::getPlayerTowns() const
  575. {
  576. return playerTowns;
  577. }
  578. void CRmgTemplateZone::setPlayerTowns(const CTownInfo & value)
  579. {
  580. playerTowns = value;
  581. }
  582. const CRmgTemplateZone::CTownInfo & CRmgTemplateZone::getNeutralTowns() const
  583. {
  584. return neutralTowns;
  585. }
  586. void CRmgTemplateZone::setNeutralTowns(const CTownInfo & value)
  587. {
  588. neutralTowns = value;
  589. }
  590. bool CRmgTemplateZone::getTownsAreSameType() const
  591. {
  592. return townsAreSameType;
  593. }
  594. void CRmgTemplateZone::setTownsAreSameType(bool value)
  595. {
  596. townsAreSameType = value;
  597. }
  598. const std::set<TFaction> & CRmgTemplateZone::getTownTypes() const
  599. {
  600. return townTypes;
  601. }
  602. void CRmgTemplateZone::setTownTypes(const std::set<TFaction> & value)
  603. {
  604. townTypes = value;
  605. }
  606. std::set<TFaction> CRmgTemplateZone::getDefaultTownTypes() const
  607. {
  608. std::set<TFaction> defaultTowns;
  609. auto towns = VLC->townh->getDefaultAllowed();
  610. for(int i = 0; i < towns.size(); ++i)
  611. {
  612. if(towns[i]) defaultTowns.insert(i);
  613. }
  614. return defaultTowns;
  615. }
  616. bool CRmgTemplateZone::getMatchTerrainToTown() const
  617. {
  618. return matchTerrainToTown;
  619. }
  620. void CRmgTemplateZone::setMatchTerrainToTown(bool value)
  621. {
  622. matchTerrainToTown = value;
  623. }
  624. const std::set<ETerrainType> & CRmgTemplateZone::getTerrainTypes() const
  625. {
  626. return terrainTypes;
  627. }
  628. void CRmgTemplateZone::setTerrainTypes(const std::set<ETerrainType> & value)
  629. {
  630. assert(value.find(ETerrainType::WRONG) == value.end() && value.find(ETerrainType::BORDER) == value.end() &&
  631. value.find(ETerrainType::WATER) == value.end() && value.find(ETerrainType::ROCK) == value.end());
  632. terrainTypes = value;
  633. }
  634. std::set<ETerrainType> CRmgTemplateZone::getDefaultTerrainTypes() const
  635. {
  636. std::set<ETerrainType> terTypes;
  637. static const ETerrainType::EETerrainType allowedTerTypes[] = { ETerrainType::DIRT, ETerrainType::SAND, ETerrainType::GRASS, ETerrainType::SNOW,
  638. ETerrainType::SWAMP, ETerrainType::ROUGH, ETerrainType::SUBTERRANEAN, ETerrainType::LAVA };
  639. for(auto & allowedTerType : allowedTerTypes) terTypes.insert(allowedTerType);
  640. return terTypes;
  641. }
  642. boost::optional<TRmgTemplateZoneId> CRmgTemplateZone::getTerrainTypeLikeZone() const
  643. {
  644. return terrainTypeLikeZone;
  645. }
  646. void CRmgTemplateZone::setTerrainTypeLikeZone(boost::optional<TRmgTemplateZoneId> value)
  647. {
  648. terrainTypeLikeZone = value;
  649. }
  650. boost::optional<TRmgTemplateZoneId> CRmgTemplateZone::getTownTypeLikeZone() const
  651. {
  652. return townTypeLikeZone;
  653. }
  654. void CRmgTemplateZone::setTownTypeLikeZone(boost::optional<TRmgTemplateZoneId> value)
  655. {
  656. townTypeLikeZone = value;
  657. }
  658. CRmgTemplateZoneConnection::CRmgTemplateZoneConnection() : zoneA(0), zoneB(0), guardStrength(0)
  659. {
  660. }
  661. TRmgTemplateZoneId CRmgTemplateZoneConnection::getZoneA() const
  662. {
  663. return zoneA;
  664. }
  665. void CRmgTemplateZoneConnection::setZoneA(TRmgTemplateZoneId value)
  666. {
  667. zoneA = value;
  668. }
  669. TRmgTemplateZoneId CRmgTemplateZoneConnection::getZoneB() const
  670. {
  671. return zoneB;
  672. }
  673. void CRmgTemplateZoneConnection::setZoneB(TRmgTemplateZoneId value)
  674. {
  675. zoneB = value;
  676. }
  677. int CRmgTemplateZoneConnection::getGuardStrength() const
  678. {
  679. return guardStrength;
  680. }
  681. void CRmgTemplateZoneConnection::setGuardStrength(int value)
  682. {
  683. if(value < 0) throw std::runtime_error("Negative value for guard strenth not allowed.");
  684. guardStrength = value;
  685. }
  686. CRmgTemplate::CSize::CSize() : width(CMapHeader::MAP_SIZE_MIDDLE), height(CMapHeader::MAP_SIZE_MIDDLE), under(true)
  687. {
  688. }
  689. CRmgTemplate::CSize::CSize(int width, int height, bool under) : under(under)
  690. {
  691. setWidth(width);
  692. setHeight(height);
  693. }
  694. int CRmgTemplate::CSize::getWidth() const
  695. {
  696. return width;
  697. }
  698. void CRmgTemplate::CSize::setWidth(int value)
  699. {
  700. if(value <= 0) throw std::runtime_error("Width > 0 failed.");
  701. width = value;
  702. }
  703. int CRmgTemplate::CSize::getHeight() const
  704. {
  705. return height;
  706. }
  707. void CRmgTemplate::CSize::setHeight(int value)
  708. {
  709. if(value <= 0) throw std::runtime_error("Height > 0 failed.");
  710. height = value;
  711. }
  712. bool CRmgTemplate::CSize::getUnder() const
  713. {
  714. return under;
  715. }
  716. void CRmgTemplate::CSize::setUnder(bool value)
  717. {
  718. under = value;
  719. }
  720. bool CRmgTemplate::CSize::operator<=(const CSize & value) const
  721. {
  722. if(width < value.width && height < value.height)
  723. {
  724. return true;
  725. }
  726. else if(width == value.width && height == value.height)
  727. {
  728. return under ? value.under : true;
  729. }
  730. else
  731. {
  732. return false;
  733. }
  734. }
  735. bool CRmgTemplate::CSize::operator>=(const CSize & value) const
  736. {
  737. if(width > value.width && height > value.height)
  738. {
  739. return true;
  740. }
  741. else if(width == value.width && height == value.height)
  742. {
  743. return under ? true : !value.under;
  744. }
  745. else
  746. {
  747. return false;
  748. }
  749. }
  750. CRmgTemplate::CRmgTemplate()
  751. {
  752. }
  753. const std::string & CRmgTemplate::getName() const
  754. {
  755. return name;
  756. }
  757. void CRmgTemplate::setName(const std::string & value)
  758. {
  759. name = value;
  760. }
  761. const CRmgTemplate::CSize & CRmgTemplate::getMinSize() const
  762. {
  763. return minSize;
  764. }
  765. void CRmgTemplate::setMinSize(const CSize & value)
  766. {
  767. minSize = value;
  768. }
  769. const CRmgTemplate::CSize & CRmgTemplate::getMaxSize() const
  770. {
  771. return maxSize;
  772. }
  773. void CRmgTemplate::setMaxSize(const CSize & value)
  774. {
  775. maxSize = value;
  776. }
  777. const CRmgTemplate::CPlayerCountRange & CRmgTemplate::getPlayers() const
  778. {
  779. return players;
  780. }
  781. void CRmgTemplate::setPlayers(const CPlayerCountRange & value)
  782. {
  783. players = value;
  784. }
  785. const CRmgTemplate::CPlayerCountRange & CRmgTemplate::getCpuPlayers() const
  786. {
  787. return cpuPlayers;
  788. }
  789. void CRmgTemplate::setCpuPlayers(const CPlayerCountRange & value)
  790. {
  791. cpuPlayers = value;
  792. }
  793. const std::map<TRmgTemplateZoneId, CRmgTemplateZone> & CRmgTemplate::getZones() const
  794. {
  795. return zones;
  796. }
  797. void CRmgTemplate::setZones(const std::map<TRmgTemplateZoneId, CRmgTemplateZone> & value)
  798. {
  799. zones = value;
  800. }
  801. const std::list<CRmgTemplateZoneConnection> & CRmgTemplate::getConnections() const
  802. {
  803. return connections;
  804. }
  805. void CRmgTemplate::setConnections(const std::list<CRmgTemplateZoneConnection> & value)
  806. {
  807. connections = value;
  808. }
  809. void CRmgTemplate::validate() const
  810. {
  811. //TODO add some validation checks, throw on failure
  812. }
  813. void CRmgTemplate::CPlayerCountRange::addRange(int lower, int upper)
  814. {
  815. range.push_back(std::make_pair(lower, upper));
  816. }
  817. void CRmgTemplate::CPlayerCountRange::addNumber(int value)
  818. {
  819. range.push_back(std::make_pair(value, value));
  820. }
  821. bool CRmgTemplate::CPlayerCountRange::isInRange(int count) const
  822. {
  823. for(const auto & pair : range)
  824. {
  825. if(count >= pair.first && count <= pair.second) return true;
  826. }
  827. return false;
  828. }
  829. std::set<int> CRmgTemplate::CPlayerCountRange::getNumbers() const
  830. {
  831. std::set<int> numbers;
  832. for(const auto & pair : range)
  833. {
  834. for(int i = pair.first; i <= pair.second; ++i) numbers.insert(i);
  835. }
  836. return numbers;
  837. }
  838. const std::map<std::string, CRmgTemplate> & CRmgTemplateLoader::getTemplates() const
  839. {
  840. return templates;
  841. }
  842. void CJsonRmgTemplateLoader::loadTemplates()
  843. {
  844. const JsonNode rootNode(ResourceID("config/rmg.json"));
  845. for(const auto & templatePair : rootNode.Struct())
  846. {
  847. CRmgTemplate tpl;
  848. try
  849. {
  850. tpl.setName(templatePair.first);
  851. const auto & templateNode = templatePair.second;
  852. // Parse main template data
  853. tpl.setMinSize(parseMapTemplateSize(templateNode["minSize"].String()));
  854. tpl.setMaxSize(parseMapTemplateSize(templateNode["maxSize"].String()));
  855. tpl.setPlayers(parsePlayers(templateNode["players"].String()));
  856. tpl.setCpuPlayers(parsePlayers(templateNode["cpu"].String()));
  857. // Parse zones
  858. std::map<TRmgTemplateZoneId, CRmgTemplateZone> zones;
  859. for(const auto & zonePair : templateNode["zones"].Struct())
  860. {
  861. CRmgTemplateZone zone;
  862. auto zoneId = boost::lexical_cast<TRmgTemplateZoneId>(zonePair.first);
  863. zone.setId(zoneId);
  864. const auto & zoneNode = zonePair.second;
  865. zone.setType(parseZoneType(zoneNode["type"].String()));
  866. zone.setSize(zoneNode["size"].Float());
  867. if(!zoneNode["owner"].isNull()) zone.setOwner(zoneNode["owner"].Float());
  868. zone.setPlayerTowns(parseTemplateZoneTowns(zoneNode["playerTowns"]));
  869. zone.setNeutralTowns(parseTemplateZoneTowns(zoneNode["neutralTowns"]));
  870. zone.setTownTypes(parseTownTypes(zoneNode["townTypes"].Vector(), zone.getDefaultTownTypes()));
  871. zone.setMatchTerrainToTown(zoneNode["matchTerrainToTown"].Bool());
  872. zone.setTerrainTypes(parseTerrainTypes(zoneNode["terrainTypes"].Vector(), zone.getDefaultTerrainTypes()));
  873. zone.setTownsAreSameType((zoneNode["townsAreSameType"].Bool()));
  874. if(!zoneNode["terrainTypeLikeZone"].isNull()) zone.setTerrainTypeLikeZone(boost::lexical_cast<int>(zoneNode["terrainTypeLikeZone"].String()));
  875. if(!zoneNode["townTypeLikeZone"].isNull()) zone.setTownTypeLikeZone(boost::lexical_cast<int>(zoneNode["townTypeLikeZone"].String()));
  876. zones[zone.getId()] = zone;
  877. }
  878. tpl.setZones(zones);
  879. // Parse connections
  880. std::list<CRmgTemplateZoneConnection> connections;
  881. for(const auto & connPair : templateNode["connections"].Vector())
  882. {
  883. CRmgTemplateZoneConnection conn;
  884. conn.setZoneA(boost::lexical_cast<TRmgTemplateZoneId>(connPair["a"].String()));
  885. conn.setZoneB(boost::lexical_cast<TRmgTemplateZoneId>(connPair["b"].String()));
  886. conn.setGuardStrength(connPair["guard"].Float());
  887. connections.push_back(conn);
  888. }
  889. tpl.setConnections(connections);
  890. tpl.validate();
  891. templates[tpl.getName()] = tpl;
  892. }
  893. catch(const std::exception & e)
  894. {
  895. logGlobal->errorStream() << boost::format("Template %s has errors. Message: %s.") % tpl.getName() % std::string(e.what());
  896. }
  897. }
  898. }
  899. CRmgTemplate::CSize CJsonRmgTemplateLoader::parseMapTemplateSize(const std::string & text) const
  900. {
  901. CRmgTemplate::CSize size;
  902. if(text.empty()) return size;
  903. std::vector<std::string> parts;
  904. boost::split(parts, text, boost::is_any_of("+"));
  905. static const std::map<std::string, int> mapSizeMapping = boost::assign::map_list_of("s", CMapHeader::MAP_SIZE_SMALL)
  906. ("m", CMapHeader::MAP_SIZE_MIDDLE)("l", CMapHeader::MAP_SIZE_LARGE)("xl", CMapHeader::MAP_SIZE_XLARGE);
  907. auto it = mapSizeMapping.find(parts[0]);
  908. if(it == mapSizeMapping.end())
  909. {
  910. // Map size is given as a number representation
  911. const auto & numericalRep = parts[0];
  912. parts.clear();
  913. boost::split(parts, numericalRep, boost::is_any_of("x"));
  914. assert(parts.size() == 3);
  915. size.setWidth(boost::lexical_cast<int>(parts[0]));
  916. size.setHeight(boost::lexical_cast<int>(parts[1]));
  917. size.setUnder(boost::lexical_cast<int>(parts[2]) == 1);
  918. }
  919. else
  920. {
  921. size.setWidth(it->second);
  922. size.setHeight(it->second);
  923. size.setUnder(parts.size() > 1 ? parts[1] == std::string("u") : false);
  924. }
  925. return size;
  926. }
  927. ETemplateZoneType::ETemplateZoneType CJsonRmgTemplateLoader::parseZoneType(const std::string & type) const
  928. {
  929. static const std::map<std::string, ETemplateZoneType::ETemplateZoneType> zoneTypeMapping = boost::assign::map_list_of
  930. ("playerStart", ETemplateZoneType::PLAYER_START)("cpuStart", ETemplateZoneType::CPU_START)
  931. ("treasure", ETemplateZoneType::TREASURE)("junction", ETemplateZoneType::JUNCTION);
  932. auto it = zoneTypeMapping.find(type);
  933. if(it == zoneTypeMapping.end()) throw std::runtime_error("Zone type unknown.");
  934. return it->second;
  935. }
  936. CRmgTemplateZone::CTownInfo CJsonRmgTemplateLoader::parseTemplateZoneTowns(const JsonNode & node) const
  937. {
  938. CRmgTemplateZone::CTownInfo towns;
  939. towns.setTownCount(node["towns"].Float());
  940. towns.setCastleCount(node["castles"].Float());
  941. towns.setTownDensity(node["townDensity"].Float());
  942. towns.setCastleDensity(node["castleDensity"].Float());
  943. return towns;
  944. }
  945. std::set<TFaction> CJsonRmgTemplateLoader::parseTownTypes(const JsonVector & townTypesVector, const std::set<TFaction> & defaultTownTypes) const
  946. {
  947. std::set<TFaction> townTypes;
  948. for(const auto & townTypeNode : townTypesVector)
  949. {
  950. auto townTypeStr = townTypeNode.String();
  951. if(townTypeStr == "all") return defaultTownTypes;
  952. bool foundFaction = false;
  953. for(auto factionPtr : VLC->townh->factions)
  954. {
  955. if(factionPtr->town != nullptr && townTypeStr == factionPtr->name)
  956. {
  957. townTypes.insert(factionPtr->index);
  958. foundFaction = true;
  959. }
  960. }
  961. if(!foundFaction) throw std::runtime_error("Given faction is invalid.");
  962. }
  963. return townTypes;
  964. }
  965. std::set<ETerrainType> CJsonRmgTemplateLoader::parseTerrainTypes(const JsonVector & terTypeStrings, const std::set<ETerrainType> & defaultTerrainTypes) const
  966. {
  967. std::set<ETerrainType> terTypes;
  968. for(const auto & node : terTypeStrings)
  969. {
  970. const auto & terTypeStr = node.String();
  971. if(terTypeStr == "all") return defaultTerrainTypes;
  972. auto pos = vstd::find_pos(GameConstants::TERRAIN_NAMES, terTypeStr);
  973. if (pos != -1)
  974. {
  975. terTypes.insert(ETerrainType(pos));
  976. }
  977. else
  978. {
  979. throw std::runtime_error("Terrain type is invalid.");
  980. }
  981. }
  982. return terTypes;
  983. }
  984. CRmgTemplate::CPlayerCountRange CJsonRmgTemplateLoader::parsePlayers(const std::string & players) const
  985. {
  986. CRmgTemplate::CPlayerCountRange playerRange;
  987. if(players.empty())
  988. {
  989. playerRange.addNumber(0);
  990. return playerRange;
  991. }
  992. std::vector<std::string> commaParts;
  993. boost::split(commaParts, players, boost::is_any_of(","));
  994. for(const auto & commaPart : commaParts)
  995. {
  996. std::vector<std::string> rangeParts;
  997. boost::split(rangeParts, commaPart, boost::is_any_of("-"));
  998. if(rangeParts.size() == 2)
  999. {
  1000. auto lower = boost::lexical_cast<int>(rangeParts[0]);
  1001. auto upper = boost::lexical_cast<int>(rangeParts[1]);
  1002. playerRange.addRange(lower, upper);
  1003. }
  1004. else if(rangeParts.size() == 1)
  1005. {
  1006. auto val = boost::lexical_cast<int>(rangeParts.front());
  1007. playerRange.addNumber(val);
  1008. }
  1009. }
  1010. return playerRange;
  1011. }
  1012. boost::mutex CRmgTemplateStorage::smx;
  1013. CRmgTemplateStorage & CRmgTemplateStorage::get()
  1014. {
  1015. TLockGuard _(smx);
  1016. static CRmgTemplateStorage storage;
  1017. return storage;
  1018. }
  1019. const std::map<std::string, CRmgTemplate> & CRmgTemplateStorage::getTemplates() const
  1020. {
  1021. return templates;
  1022. }
  1023. CRmgTemplateStorage::CRmgTemplateStorage()
  1024. {
  1025. auto jsonLoader = make_unique<CJsonRmgTemplateLoader>();
  1026. jsonLoader->loadTemplates();
  1027. const auto & tpls = jsonLoader->getTemplates();
  1028. templates.insert(tpls.begin(), tpls.end());
  1029. }
  1030. CRmgTemplateStorage::~CRmgTemplateStorage()
  1031. {
  1032. }