CMapGenerator.cpp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538
  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. genZones();
  368. fillZones();
  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::genZones()
  449. {
  450. map->initTerrain();
  451. editManager->clearTerrain(&gen);
  452. editManager->getTerrainSelection().selectRange(MapRect(int3(0, 0, 0), mapGenOptions.getWidth(), mapGenOptions.getHeight()));
  453. editManager->drawTerrain(ETerrainType::GRASS, &gen);
  454. auto pcnt = mapGenOptions.getPlayerCount();
  455. auto w = mapGenOptions.getWidth();
  456. auto h = mapGenOptions.getHeight();
  457. auto tmpl = mapGenOptions.getMapTemplate();
  458. auto zones = tmpl->getZones();
  459. int player_per_side = zones.size() > 4 ? 3 : 2;
  460. int zones_cnt = zones.size() > 4 ? 9 : 4;
  461. logGlobal->infoStream() << boost::format("Map size %d %d, players per side %d") % w % h % player_per_side;
  462. int i = 0;
  463. int part_w = w/player_per_side;
  464. int part_h = h/player_per_side;
  465. for(auto const it : zones)
  466. {
  467. CRmgTemplateZone zone = it.second;
  468. std::vector<int3> shape;
  469. int left = part_w*(i%player_per_side);
  470. int top = part_h*(i/player_per_side);
  471. shape.push_back(int3(left, top, 0));
  472. shape.push_back(int3(left + part_w, top, 0));
  473. shape.push_back(int3(left + part_w, top + part_h, 0));
  474. shape.push_back(int3(left, top + part_h, 0));
  475. zone.setShape(shape);
  476. zone.setType(i < pcnt ? ETemplateZoneType::PLAYER_START : ETemplateZoneType::TREASURE);
  477. this->zones[it.first] = zone;
  478. ++i;
  479. }
  480. logGlobal->infoStream() << "Zones generated successfully";
  481. }
  482. void CMapGenerator::fillZones()
  483. {
  484. logGlobal->infoStream() << "Started filling zones";
  485. for(auto it = zones.begin(); it != zones.end(); ++it)
  486. {
  487. it->second.fill(this);
  488. }
  489. logGlobal->infoStream() << "Zones filled successfully";
  490. }
  491. void CMapGenerator::addHeaderInfo()
  492. {
  493. map->version = EMapFormat::SOD;
  494. map->width = mapGenOptions.getWidth();
  495. map->height = mapGenOptions.getHeight();
  496. map->twoLevel = mapGenOptions.getHasTwoLevels();
  497. map->name = VLC->generaltexth->allTexts[740];
  498. map->description = getMapDescription();
  499. map->difficulty = 1;
  500. addPlayerInfo();
  501. }
  502. CRmgTemplateZone::CTownInfo::CTownInfo() : townCount(0), castleCount(0), townDensity(0), castleDensity(0)
  503. {
  504. }
  505. int CRmgTemplateZone::CTownInfo::getTownCount() const
  506. {
  507. return townCount;
  508. }
  509. void CRmgTemplateZone::CTownInfo::setTownCount(int value)
  510. {
  511. if(value < 0) throw std::runtime_error("Negative value for town count not allowed.");
  512. townCount = value;
  513. }
  514. int CRmgTemplateZone::CTownInfo::getCastleCount() const
  515. {
  516. return castleCount;
  517. }
  518. void CRmgTemplateZone::CTownInfo::setCastleCount(int value)
  519. {
  520. if(value < 0) throw std::runtime_error("Negative value for castle count not allowed.");
  521. castleCount = value;
  522. }
  523. int CRmgTemplateZone::CTownInfo::getTownDensity() const
  524. {
  525. return townDensity;
  526. }
  527. void CRmgTemplateZone::CTownInfo::setTownDensity(int value)
  528. {
  529. if(value < 0) throw std::runtime_error("Negative value for town density not allowed.");
  530. townDensity = value;
  531. }
  532. int CRmgTemplateZone::CTownInfo::getCastleDensity() const
  533. {
  534. return castleDensity;
  535. }
  536. void CRmgTemplateZone::CTownInfo::setCastleDensity(int value)
  537. {
  538. if(value < 0) throw std::runtime_error("Negative value for castle density not allowed.");
  539. castleDensity = value;
  540. }
  541. CRmgTemplateZone::CTileInfo::CTileInfo():nearestObjectDistance(INT_MAX), obstacle(false), occupied(false), terrain(ETerrainType::WRONG)
  542. {
  543. }
  544. int CRmgTemplateZone::CTileInfo::getNearestObjectDistance() const
  545. {
  546. return nearestObjectDistance;
  547. }
  548. void CRmgTemplateZone::CTileInfo::setNearestObjectDistance(int value)
  549. {
  550. if(value < 0) throw std::runtime_error("Negative value for nearest object distance not allowed.");
  551. nearestObjectDistance = value;
  552. }
  553. bool CRmgTemplateZone::CTileInfo::isObstacle() const
  554. {
  555. return obstacle;
  556. }
  557. void CRmgTemplateZone::CTileInfo::setObstacle(bool value)
  558. {
  559. obstacle = value;
  560. }
  561. bool CRmgTemplateZone::CTileInfo::isOccupied() const
  562. {
  563. return occupied;
  564. }
  565. void CRmgTemplateZone::CTileInfo::setOccupied(bool value)
  566. {
  567. occupied = value;
  568. }
  569. ETerrainType CRmgTemplateZone::CTileInfo::getTerrainType() const
  570. {
  571. return terrain;
  572. }
  573. void CRmgTemplateZone::CTileInfo::setTerrainType(ETerrainType value)
  574. {
  575. terrain = value;
  576. }
  577. CRmgTemplateZone::CRmgTemplateZone() : id(0), type(ETemplateZoneType::PLAYER_START), size(1),
  578. townsAreSameType(false), matchTerrainToTown(true)
  579. {
  580. townTypes = getDefaultTownTypes();
  581. terrainTypes = getDefaultTerrainTypes();
  582. }
  583. TRmgTemplateZoneId CRmgTemplateZone::getId() const
  584. {
  585. return id;
  586. }
  587. void CRmgTemplateZone::setId(TRmgTemplateZoneId value)
  588. {
  589. if(value <= 0) throw std::runtime_error("Zone id should be greater than 0.");
  590. id = value;
  591. }
  592. ETemplateZoneType::ETemplateZoneType CRmgTemplateZone::getType() const
  593. {
  594. return type;
  595. }
  596. void CRmgTemplateZone::setType(ETemplateZoneType::ETemplateZoneType value)
  597. {
  598. type = value;
  599. }
  600. int CRmgTemplateZone::getSize() const
  601. {
  602. return size;
  603. }
  604. void CRmgTemplateZone::setSize(int value)
  605. {
  606. if(value <= 0) throw std::runtime_error("Zone size needs to be greater than 0.");
  607. size = value;
  608. }
  609. boost::optional<int> CRmgTemplateZone::getOwner() const
  610. {
  611. return owner;
  612. }
  613. void CRmgTemplateZone::setOwner(boost::optional<int> value)
  614. {
  615. if(!(*value >= 0 && *value <= PlayerColor::PLAYER_LIMIT_I)) throw std::runtime_error("Owner has to be in range 0 to max player count.");
  616. owner = value;
  617. }
  618. const CRmgTemplateZone::CTownInfo & CRmgTemplateZone::getPlayerTowns() const
  619. {
  620. return playerTowns;
  621. }
  622. void CRmgTemplateZone::setPlayerTowns(const CTownInfo & value)
  623. {
  624. playerTowns = value;
  625. }
  626. const CRmgTemplateZone::CTownInfo & CRmgTemplateZone::getNeutralTowns() const
  627. {
  628. return neutralTowns;
  629. }
  630. void CRmgTemplateZone::setNeutralTowns(const CTownInfo & value)
  631. {
  632. neutralTowns = value;
  633. }
  634. bool CRmgTemplateZone::getTownsAreSameType() const
  635. {
  636. return townsAreSameType;
  637. }
  638. void CRmgTemplateZone::setTownsAreSameType(bool value)
  639. {
  640. townsAreSameType = value;
  641. }
  642. const std::set<TFaction> & CRmgTemplateZone::getTownTypes() const
  643. {
  644. return townTypes;
  645. }
  646. void CRmgTemplateZone::setTownTypes(const std::set<TFaction> & value)
  647. {
  648. townTypes = value;
  649. }
  650. std::set<TFaction> CRmgTemplateZone::getDefaultTownTypes() const
  651. {
  652. std::set<TFaction> defaultTowns;
  653. auto towns = VLC->townh->getDefaultAllowed();
  654. for(int i = 0; i < towns.size(); ++i)
  655. {
  656. if(towns[i]) defaultTowns.insert(i);
  657. }
  658. return defaultTowns;
  659. }
  660. bool CRmgTemplateZone::getMatchTerrainToTown() const
  661. {
  662. return matchTerrainToTown;
  663. }
  664. void CRmgTemplateZone::setMatchTerrainToTown(bool value)
  665. {
  666. matchTerrainToTown = value;
  667. }
  668. const std::set<ETerrainType> & CRmgTemplateZone::getTerrainTypes() const
  669. {
  670. return terrainTypes;
  671. }
  672. void CRmgTemplateZone::setTerrainTypes(const std::set<ETerrainType> & value)
  673. {
  674. assert(value.find(ETerrainType::WRONG) == value.end() && value.find(ETerrainType::BORDER) == value.end() &&
  675. value.find(ETerrainType::WATER) == value.end() && value.find(ETerrainType::ROCK) == value.end());
  676. terrainTypes = value;
  677. }
  678. std::set<ETerrainType> CRmgTemplateZone::getDefaultTerrainTypes() const
  679. {
  680. std::set<ETerrainType> terTypes;
  681. static const ETerrainType::EETerrainType allowedTerTypes[] = { ETerrainType::DIRT, ETerrainType::SAND, ETerrainType::GRASS, ETerrainType::SNOW,
  682. ETerrainType::SWAMP, ETerrainType::ROUGH, ETerrainType::SUBTERRANEAN, ETerrainType::LAVA };
  683. for(auto & allowedTerType : allowedTerTypes) terTypes.insert(allowedTerType);
  684. return terTypes;
  685. }
  686. boost::optional<TRmgTemplateZoneId> CRmgTemplateZone::getTerrainTypeLikeZone() const
  687. {
  688. return terrainTypeLikeZone;
  689. }
  690. void CRmgTemplateZone::setTerrainTypeLikeZone(boost::optional<TRmgTemplateZoneId> value)
  691. {
  692. terrainTypeLikeZone = value;
  693. }
  694. boost::optional<TRmgTemplateZoneId> CRmgTemplateZone::getTownTypeLikeZone() const
  695. {
  696. return townTypeLikeZone;
  697. }
  698. void CRmgTemplateZone::setTownTypeLikeZone(boost::optional<TRmgTemplateZoneId> value)
  699. {
  700. townTypeLikeZone = value;
  701. }
  702. bool CRmgTemplateZone::pointIsIn(int x, int y)
  703. {
  704. int i, j;
  705. bool c = false;
  706. int nvert = shape.size();
  707. for (i = 0, j = nvert-1; i < nvert; j = i++) {
  708. if ( ((shape[i].y>y) != (shape[j].y>y)) &&
  709. (x < (shape[j].x-shape[i].x) * (y-shape[i].y) / (shape[j].y-shape[i].y) + shape[i].x) )
  710. c = !c;
  711. }
  712. return c;
  713. }
  714. void CRmgTemplateZone::setShape(std::vector<int3> shape)
  715. {
  716. int z = -1;
  717. si32 minx = INT_MAX;
  718. si32 maxx = -1;
  719. si32 miny = INT_MAX;
  720. si32 maxy = -1;
  721. for(auto &point : shape)
  722. {
  723. if (z == -1)
  724. z = point.z;
  725. if (point.z != z)
  726. throw std::runtime_error("Zone shape points should lie on same z.");
  727. minx = std::min(minx, point.x);
  728. maxx = std::max(maxx, point.x);
  729. miny = std::min(miny, point.y);
  730. maxy = std::max(maxy, point.y);
  731. }
  732. this->shape = shape;
  733. for(int x = minx; x <= maxx; ++x)
  734. {
  735. for(int y = miny; y <= maxy; ++y)
  736. {
  737. if (pointIsIn(x, y))
  738. {
  739. tileinfo[int3(x,y,z)] = CTileInfo();
  740. }
  741. }
  742. }
  743. }
  744. int3 CRmgTemplateZone::getCenter()
  745. {
  746. si32 cx = 0;
  747. si32 cy = 0;
  748. si32 area = 0;
  749. si32 sz = shape.size();
  750. //include last->first too
  751. for(si32 i = 0, j = sz-1; i < sz; j = i++) {
  752. si32 sf = (shape[i].x * shape[j].y - shape[j].x * shape[i].y);
  753. cx += (shape[i].x + shape[j].x) * sf;
  754. cy += (shape[i].y + shape[j].y) * sf;
  755. area += sf;
  756. }
  757. area /= 2;
  758. return int3(std::abs(cx/area/6), std::abs(cy/area/6), shape[0].z);
  759. }
  760. bool CRmgTemplateZone::fill(CMapGenerator* gen)
  761. {
  762. std::vector<CGObjectInstance*> required_objects;
  763. if ((type == ETemplateZoneType::CPU_START) || (type == ETemplateZoneType::PLAYER_START))
  764. {
  765. logGlobal->infoStream() << "Preparing playing zone";
  766. int player_id = *owner - 1;
  767. auto & playerInfo = gen->map->players[player_id];
  768. if (playerInfo.canAnyonePlay())
  769. {
  770. PlayerColor player(player_id);
  771. auto town = new CGTownInstance();
  772. town->ID = Obj::TOWN;
  773. int townId = gen->mapGenOptions.getPlayersSettings().find(player)->second.getStartingTown();
  774. static auto town_gen = gen->gen.getRangeI(0, 8);
  775. if(townId == CMapGenOptions::CPlayerSettings::RANDOM_TOWN) townId = town_gen(); // Default towns
  776. town->subID = townId;
  777. town->tempOwner = player;
  778. town->defInfo = VLC->dobjinfo->gobjs[town->ID][town->subID];
  779. town->builtBuildings.insert(BuildingID::FORT);
  780. town->builtBuildings.insert(BuildingID::DEFAULT);
  781. placeObject(gen, town, getCenter());
  782. logGlobal->infoStream() << "Placed object";
  783. logGlobal->infoStream() << "Fill player info " << player_id;
  784. auto & playerInfo = gen->map->players[player_id];
  785. // Update player info
  786. playerInfo.allowedFactions.clear();
  787. playerInfo.allowedFactions.insert(town->subID);
  788. playerInfo.hasMainTown = true;
  789. playerInfo.posOfMainTown = town->pos - int3(2, 0, 0);
  790. playerInfo.generateHeroAtMainTown = true;
  791. //required_objects.push_back(town);
  792. std::vector<Res::ERes> required_mines;
  793. required_mines.push_back(Res::ERes::WOOD);
  794. required_mines.push_back(Res::ERes::ORE);
  795. for(const auto res : required_mines)
  796. {
  797. auto mine = new CGMine();
  798. mine->ID = Obj::MINE;
  799. mine->subID = static_cast<si32>(res);
  800. mine->producedResource = res;
  801. mine->producedQuantity = mine->defaultResProduction();
  802. mine->defInfo = VLC->dobjinfo->gobjs[mine->ID][mine->subID];
  803. required_objects.push_back(mine);
  804. }
  805. }
  806. else
  807. {
  808. type = ETemplateZoneType::TREASURE;
  809. logGlobal->infoStream() << "Skipping this zone cause no player";
  810. }
  811. }
  812. logGlobal->infoStream() << "Creating required objects";
  813. for(const auto &obj : required_objects)
  814. {
  815. int3 pos;
  816. logGlobal->infoStream() << "Looking for place";
  817. if ( ! findPlaceForObject(gen, obj, 3, pos))
  818. {
  819. logGlobal->errorStream() << "Failed to fill zone due to lack of space";
  820. //TODO CLEANUP!
  821. return false;
  822. }
  823. logGlobal->infoStream() << "Place found";
  824. placeObject(gen, obj, pos);
  825. logGlobal->infoStream() << "Placed object";
  826. }
  827. std::vector<CGObjectInstance*> guarded_objects;
  828. static auto res_gen = gen->gen.getRangeI(Res::ERes::WOOD, Res::ERes::GOLD);
  829. const double res_mindist = 5;
  830. do {
  831. auto obj = new CGResource();
  832. auto restype = static_cast<Res::ERes>(res_gen());
  833. obj->ID = Obj::RESOURCE;
  834. obj->subID = static_cast<si32>(restype);
  835. obj->amount = 0;
  836. obj->defInfo = VLC->dobjinfo->gobjs[obj->ID][obj->subID];
  837. int3 pos;
  838. if ( ! findPlaceForObject(gen, obj, res_mindist, pos))
  839. {
  840. delete obj;
  841. break;
  842. }
  843. placeObject(gen, obj, pos);
  844. if ((restype != Res::ERes::WOOD) && (restype != Res::ERes::ORE))
  845. {
  846. guarded_objects.push_back(obj);
  847. }
  848. } while(true);
  849. for(const auto &obj : guarded_objects)
  850. {
  851. if ( ! guardObject(gen, obj, 500))
  852. {
  853. //TODO, DEL obj from map
  854. }
  855. }
  856. auto sel = gen->editManager->getTerrainSelection();
  857. sel.clearSelection();
  858. for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it)
  859. {
  860. if (it->second.isObstacle())
  861. {
  862. auto obj = new CGObjectInstance();
  863. obj->ID = static_cast<Obj>(130);
  864. obj->subID = 0;
  865. obj->defInfo = VLC->dobjinfo->gobjs[obj->ID][obj->subID];
  866. placeObject(gen, obj, it->first);
  867. }
  868. }
  869. logGlobal->infoStream() << boost::format("Filling %d with ROCK") % sel.getSelectedItems().size();
  870. //gen->editManager->drawTerrain(ETerrainType::ROCK, &gen->gen);
  871. logGlobal->infoStream() << "Zone filled successfully";
  872. return true;
  873. }
  874. bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos)
  875. {
  876. //si32 min_dist = sqrt(tileinfo.size()/density);
  877. int best_distance = 0;
  878. bool result = false;
  879. si32 w = gen->map->width;
  880. si32 h = gen->map->height;
  881. auto ow = obj->getWidth();
  882. auto oh = obj->getHeight();
  883. //logGlobal->infoStream() << boost::format("Min dist for density %f is %d") % density % min_dist;
  884. for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it)
  885. {
  886. auto &ti = it->second;
  887. auto p = it->first;
  888. auto dist = ti.getNearestObjectDistance();
  889. //avoid borders
  890. if ((p.x < 3) || (w - p.x < 3) || (p.y < 3) || (h - p.y < 3))
  891. continue;
  892. if (!ti.isOccupied() && !ti.isObstacle() && (dist >= min_dist) && (dist > best_distance))
  893. {
  894. best_distance = dist;
  895. pos = p;
  896. result = true;
  897. }
  898. }
  899. return result;
  900. }
  901. void CRmgTemplateZone::placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos)
  902. {
  903. logGlobal->infoStream() << boost::format("Insert object at %d %d") % pos.x % pos.y;
  904. object->pos = pos;
  905. gen->editManager->insertObject(object, pos);
  906. logGlobal->infoStream() << "Inserted object";
  907. auto points = object->getBlockedPos();
  908. if (object->isVisitable())
  909. points.emplace(pos + object->getVisitableOffset());
  910. points.emplace(pos);
  911. for(auto const &p : points)
  912. {
  913. if (tileinfo.find(pos + p) != tileinfo.end())
  914. {
  915. tileinfo[pos + p].setOccupied(true);
  916. }
  917. }
  918. for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it)
  919. {
  920. si32 d = pos.dist2d(it->first);
  921. it->second.setNearestObjectDistance(std::min(d, it->second.getNearestObjectDistance()));
  922. }
  923. }
  924. bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str)
  925. {
  926. logGlobal->infoStream() << boost::format("Guard object at %d %d") % object->pos.x % object->pos.y;
  927. int3 visitable = object->pos + object->getVisitableOffset();
  928. std::vector<int3> tiles;
  929. for(int i = -1; i < 2; ++i)
  930. {
  931. for(int j = -1; j < 2; ++j)
  932. {
  933. auto it = tileinfo.find(visitable + int3(i, j, 0));
  934. if (it != tileinfo.end())
  935. {
  936. logGlobal->infoStream() << boost::format("Block at %d %d") % it->first.x % it->first.y;
  937. if ( ! it->second.isOccupied() && ! it->second.isObstacle())
  938. {
  939. tiles.push_back(it->first);
  940. it->second.setObstacle(true);
  941. }
  942. }
  943. }
  944. }
  945. if ( ! tiles.size())
  946. {
  947. logGlobal->infoStream() << "Failed";
  948. return false;
  949. }
  950. auto guard_tile = *std::next(tiles.begin(), gen->gen.getInteger(0, tiles.size() - 1));
  951. tileinfo[guard_tile].setObstacle(false);
  952. auto guard = new CGCreature();
  953. guard->ID = Obj::RANDOM_MONSTER;
  954. guard->subID = 0;
  955. auto hlp = new CStackInstance();
  956. hlp->count = 10;
  957. //type will be set during initialization
  958. guard->putStack(SlotID(0), hlp);
  959. guard->defInfo = VLC->dobjinfo->gobjs[guard->ID][guard->subID];
  960. guard->pos = guard_tile;
  961. gen->editManager->insertObject(guard, guard->pos);
  962. return true;
  963. }
  964. CRmgTemplateZoneConnection::CRmgTemplateZoneConnection() : zoneA(0), zoneB(0), guardStrength(0)
  965. {
  966. }
  967. TRmgTemplateZoneId CRmgTemplateZoneConnection::getZoneA() const
  968. {
  969. return zoneA;
  970. }
  971. void CRmgTemplateZoneConnection::setZoneA(TRmgTemplateZoneId value)
  972. {
  973. zoneA = value;
  974. }
  975. TRmgTemplateZoneId CRmgTemplateZoneConnection::getZoneB() const
  976. {
  977. return zoneB;
  978. }
  979. void CRmgTemplateZoneConnection::setZoneB(TRmgTemplateZoneId value)
  980. {
  981. zoneB = value;
  982. }
  983. int CRmgTemplateZoneConnection::getGuardStrength() const
  984. {
  985. return guardStrength;
  986. }
  987. void CRmgTemplateZoneConnection::setGuardStrength(int value)
  988. {
  989. if(value < 0) throw std::runtime_error("Negative value for guard strenth not allowed.");
  990. guardStrength = value;
  991. }
  992. CRmgTemplate::CSize::CSize() : width(CMapHeader::MAP_SIZE_MIDDLE), height(CMapHeader::MAP_SIZE_MIDDLE), under(true)
  993. {
  994. }
  995. CRmgTemplate::CSize::CSize(int width, int height, bool under) : under(under)
  996. {
  997. setWidth(width);
  998. setHeight(height);
  999. }
  1000. int CRmgTemplate::CSize::getWidth() const
  1001. {
  1002. return width;
  1003. }
  1004. void CRmgTemplate::CSize::setWidth(int value)
  1005. {
  1006. if(value <= 0) throw std::runtime_error("Width > 0 failed.");
  1007. width = value;
  1008. }
  1009. int CRmgTemplate::CSize::getHeight() const
  1010. {
  1011. return height;
  1012. }
  1013. void CRmgTemplate::CSize::setHeight(int value)
  1014. {
  1015. if(value <= 0) throw std::runtime_error("Height > 0 failed.");
  1016. height = value;
  1017. }
  1018. bool CRmgTemplate::CSize::getUnder() const
  1019. {
  1020. return under;
  1021. }
  1022. void CRmgTemplate::CSize::setUnder(bool value)
  1023. {
  1024. under = value;
  1025. }
  1026. bool CRmgTemplate::CSize::operator<=(const CSize & value) const
  1027. {
  1028. if(width < value.width && height < value.height)
  1029. {
  1030. return true;
  1031. }
  1032. else if(width == value.width && height == value.height)
  1033. {
  1034. return under ? value.under : true;
  1035. }
  1036. else
  1037. {
  1038. return false;
  1039. }
  1040. }
  1041. bool CRmgTemplate::CSize::operator>=(const CSize & value) const
  1042. {
  1043. if(width > value.width && height > value.height)
  1044. {
  1045. return true;
  1046. }
  1047. else if(width == value.width && height == value.height)
  1048. {
  1049. return under ? true : !value.under;
  1050. }
  1051. else
  1052. {
  1053. return false;
  1054. }
  1055. }
  1056. CRmgTemplate::CRmgTemplate()
  1057. {
  1058. }
  1059. const std::string & CRmgTemplate::getName() const
  1060. {
  1061. return name;
  1062. }
  1063. void CRmgTemplate::setName(const std::string & value)
  1064. {
  1065. name = value;
  1066. }
  1067. const CRmgTemplate::CSize & CRmgTemplate::getMinSize() const
  1068. {
  1069. return minSize;
  1070. }
  1071. void CRmgTemplate::setMinSize(const CSize & value)
  1072. {
  1073. minSize = value;
  1074. }
  1075. const CRmgTemplate::CSize & CRmgTemplate::getMaxSize() const
  1076. {
  1077. return maxSize;
  1078. }
  1079. void CRmgTemplate::setMaxSize(const CSize & value)
  1080. {
  1081. maxSize = value;
  1082. }
  1083. const CRmgTemplate::CPlayerCountRange & CRmgTemplate::getPlayers() const
  1084. {
  1085. return players;
  1086. }
  1087. void CRmgTemplate::setPlayers(const CPlayerCountRange & value)
  1088. {
  1089. players = value;
  1090. }
  1091. const CRmgTemplate::CPlayerCountRange & CRmgTemplate::getCpuPlayers() const
  1092. {
  1093. return cpuPlayers;
  1094. }
  1095. void CRmgTemplate::setCpuPlayers(const CPlayerCountRange & value)
  1096. {
  1097. cpuPlayers = value;
  1098. }
  1099. const std::map<TRmgTemplateZoneId, CRmgTemplateZone> & CRmgTemplate::getZones() const
  1100. {
  1101. return zones;
  1102. }
  1103. void CRmgTemplate::setZones(const std::map<TRmgTemplateZoneId, CRmgTemplateZone> & value)
  1104. {
  1105. zones = value;
  1106. }
  1107. const std::list<CRmgTemplateZoneConnection> & CRmgTemplate::getConnections() const
  1108. {
  1109. return connections;
  1110. }
  1111. void CRmgTemplate::setConnections(const std::list<CRmgTemplateZoneConnection> & value)
  1112. {
  1113. connections = value;
  1114. }
  1115. void CRmgTemplate::validate() const
  1116. {
  1117. //TODO add some validation checks, throw on failure
  1118. }
  1119. void CRmgTemplate::CPlayerCountRange::addRange(int lower, int upper)
  1120. {
  1121. range.push_back(std::make_pair(lower, upper));
  1122. }
  1123. void CRmgTemplate::CPlayerCountRange::addNumber(int value)
  1124. {
  1125. range.push_back(std::make_pair(value, value));
  1126. }
  1127. bool CRmgTemplate::CPlayerCountRange::isInRange(int count) const
  1128. {
  1129. for(const auto & pair : range)
  1130. {
  1131. if(count >= pair.first && count <= pair.second) return true;
  1132. }
  1133. return false;
  1134. }
  1135. std::set<int> CRmgTemplate::CPlayerCountRange::getNumbers() const
  1136. {
  1137. std::set<int> numbers;
  1138. for(const auto & pair : range)
  1139. {
  1140. for(int i = pair.first; i <= pair.second; ++i) numbers.insert(i);
  1141. }
  1142. return numbers;
  1143. }
  1144. const std::map<std::string, CRmgTemplate> & CRmgTemplateLoader::getTemplates() const
  1145. {
  1146. return templates;
  1147. }
  1148. void CJsonRmgTemplateLoader::loadTemplates()
  1149. {
  1150. const JsonNode rootNode(ResourceID("config/rmg.json"));
  1151. for(const auto & templatePair : rootNode.Struct())
  1152. {
  1153. CRmgTemplate tpl;
  1154. try
  1155. {
  1156. tpl.setName(templatePair.first);
  1157. const auto & templateNode = templatePair.second;
  1158. // Parse main template data
  1159. tpl.setMinSize(parseMapTemplateSize(templateNode["minSize"].String()));
  1160. tpl.setMaxSize(parseMapTemplateSize(templateNode["maxSize"].String()));
  1161. tpl.setPlayers(parsePlayers(templateNode["players"].String()));
  1162. tpl.setCpuPlayers(parsePlayers(templateNode["cpu"].String()));
  1163. // Parse zones
  1164. std::map<TRmgTemplateZoneId, CRmgTemplateZone> zones;
  1165. for(const auto & zonePair : templateNode["zones"].Struct())
  1166. {
  1167. CRmgTemplateZone zone;
  1168. auto zoneId = boost::lexical_cast<TRmgTemplateZoneId>(zonePair.first);
  1169. zone.setId(zoneId);
  1170. const auto & zoneNode = zonePair.second;
  1171. zone.setType(parseZoneType(zoneNode["type"].String()));
  1172. zone.setSize(zoneNode["size"].Float());
  1173. if(!zoneNode["owner"].isNull()) zone.setOwner(zoneNode["owner"].Float());
  1174. zone.setPlayerTowns(parseTemplateZoneTowns(zoneNode["playerTowns"]));
  1175. zone.setNeutralTowns(parseTemplateZoneTowns(zoneNode["neutralTowns"]));
  1176. zone.setTownTypes(parseTownTypes(zoneNode["townTypes"].Vector(), zone.getDefaultTownTypes()));
  1177. zone.setMatchTerrainToTown(zoneNode["matchTerrainToTown"].Bool());
  1178. zone.setTerrainTypes(parseTerrainTypes(zoneNode["terrainTypes"].Vector(), zone.getDefaultTerrainTypes()));
  1179. zone.setTownsAreSameType((zoneNode["townsAreSameType"].Bool()));
  1180. if(!zoneNode["terrainTypeLikeZone"].isNull()) zone.setTerrainTypeLikeZone(boost::lexical_cast<int>(zoneNode["terrainTypeLikeZone"].String()));
  1181. if(!zoneNode["townTypeLikeZone"].isNull()) zone.setTownTypeLikeZone(boost::lexical_cast<int>(zoneNode["townTypeLikeZone"].String()));
  1182. zones[zone.getId()] = zone;
  1183. }
  1184. tpl.setZones(zones);
  1185. // Parse connections
  1186. std::list<CRmgTemplateZoneConnection> connections;
  1187. for(const auto & connPair : templateNode["connections"].Vector())
  1188. {
  1189. CRmgTemplateZoneConnection conn;
  1190. conn.setZoneA(boost::lexical_cast<TRmgTemplateZoneId>(connPair["a"].String()));
  1191. conn.setZoneB(boost::lexical_cast<TRmgTemplateZoneId>(connPair["b"].String()));
  1192. conn.setGuardStrength(connPair["guard"].Float());
  1193. connections.push_back(conn);
  1194. }
  1195. tpl.setConnections(connections);
  1196. tpl.validate();
  1197. templates[tpl.getName()] = tpl;
  1198. }
  1199. catch(const std::exception & e)
  1200. {
  1201. logGlobal->errorStream() << boost::format("Template %s has errors. Message: %s.") % tpl.getName() % std::string(e.what());
  1202. }
  1203. }
  1204. }
  1205. CRmgTemplate::CSize CJsonRmgTemplateLoader::parseMapTemplateSize(const std::string & text) const
  1206. {
  1207. CRmgTemplate::CSize size;
  1208. if(text.empty()) return size;
  1209. std::vector<std::string> parts;
  1210. boost::split(parts, text, boost::is_any_of("+"));
  1211. static const std::map<std::string, int> mapSizeMapping = boost::assign::map_list_of("s", CMapHeader::MAP_SIZE_SMALL)
  1212. ("m", CMapHeader::MAP_SIZE_MIDDLE)("l", CMapHeader::MAP_SIZE_LARGE)("xl", CMapHeader::MAP_SIZE_XLARGE);
  1213. auto it = mapSizeMapping.find(parts[0]);
  1214. if(it == mapSizeMapping.end())
  1215. {
  1216. // Map size is given as a number representation
  1217. const auto & numericalRep = parts[0];
  1218. parts.clear();
  1219. boost::split(parts, numericalRep, boost::is_any_of("x"));
  1220. assert(parts.size() == 3);
  1221. size.setWidth(boost::lexical_cast<int>(parts[0]));
  1222. size.setHeight(boost::lexical_cast<int>(parts[1]));
  1223. size.setUnder(boost::lexical_cast<int>(parts[2]) == 1);
  1224. }
  1225. else
  1226. {
  1227. size.setWidth(it->second);
  1228. size.setHeight(it->second);
  1229. size.setUnder(parts.size() > 1 ? parts[1] == std::string("u") : false);
  1230. }
  1231. return size;
  1232. }
  1233. ETemplateZoneType::ETemplateZoneType CJsonRmgTemplateLoader::parseZoneType(const std::string & type) const
  1234. {
  1235. static const std::map<std::string, ETemplateZoneType::ETemplateZoneType> zoneTypeMapping = boost::assign::map_list_of
  1236. ("playerStart", ETemplateZoneType::PLAYER_START)("cpuStart", ETemplateZoneType::CPU_START)
  1237. ("treasure", ETemplateZoneType::TREASURE)("junction", ETemplateZoneType::JUNCTION);
  1238. auto it = zoneTypeMapping.find(type);
  1239. if(it == zoneTypeMapping.end()) throw std::runtime_error("Zone type unknown.");
  1240. return it->second;
  1241. }
  1242. CRmgTemplateZone::CTownInfo CJsonRmgTemplateLoader::parseTemplateZoneTowns(const JsonNode & node) const
  1243. {
  1244. CRmgTemplateZone::CTownInfo towns;
  1245. towns.setTownCount(node["towns"].Float());
  1246. towns.setCastleCount(node["castles"].Float());
  1247. towns.setTownDensity(node["townDensity"].Float());
  1248. towns.setCastleDensity(node["castleDensity"].Float());
  1249. return towns;
  1250. }
  1251. std::set<TFaction> CJsonRmgTemplateLoader::parseTownTypes(const JsonVector & townTypesVector, const std::set<TFaction> & defaultTownTypes) const
  1252. {
  1253. std::set<TFaction> townTypes;
  1254. for(const auto & townTypeNode : townTypesVector)
  1255. {
  1256. auto townTypeStr = townTypeNode.String();
  1257. if(townTypeStr == "all") return defaultTownTypes;
  1258. bool foundFaction = false;
  1259. for(auto factionPtr : VLC->townh->factions)
  1260. {
  1261. if(factionPtr->town != nullptr && townTypeStr == factionPtr->name)
  1262. {
  1263. townTypes.insert(factionPtr->index);
  1264. foundFaction = true;
  1265. }
  1266. }
  1267. if(!foundFaction) throw std::runtime_error("Given faction is invalid.");
  1268. }
  1269. return townTypes;
  1270. }
  1271. std::set<ETerrainType> CJsonRmgTemplateLoader::parseTerrainTypes(const JsonVector & terTypeStrings, const std::set<ETerrainType> & defaultTerrainTypes) const
  1272. {
  1273. std::set<ETerrainType> terTypes;
  1274. for(const auto & node : terTypeStrings)
  1275. {
  1276. const auto & terTypeStr = node.String();
  1277. if(terTypeStr == "all") return defaultTerrainTypes;
  1278. auto pos = vstd::find_pos(GameConstants::TERRAIN_NAMES, terTypeStr);
  1279. if (pos != -1)
  1280. {
  1281. terTypes.insert(ETerrainType(pos));
  1282. }
  1283. else
  1284. {
  1285. throw std::runtime_error("Terrain type is invalid.");
  1286. }
  1287. }
  1288. return terTypes;
  1289. }
  1290. CRmgTemplate::CPlayerCountRange CJsonRmgTemplateLoader::parsePlayers(const std::string & players) const
  1291. {
  1292. CRmgTemplate::CPlayerCountRange playerRange;
  1293. if(players.empty())
  1294. {
  1295. playerRange.addNumber(0);
  1296. return playerRange;
  1297. }
  1298. std::vector<std::string> commaParts;
  1299. boost::split(commaParts, players, boost::is_any_of(","));
  1300. for(const auto & commaPart : commaParts)
  1301. {
  1302. std::vector<std::string> rangeParts;
  1303. boost::split(rangeParts, commaPart, boost::is_any_of("-"));
  1304. if(rangeParts.size() == 2)
  1305. {
  1306. auto lower = boost::lexical_cast<int>(rangeParts[0]);
  1307. auto upper = boost::lexical_cast<int>(rangeParts[1]);
  1308. playerRange.addRange(lower, upper);
  1309. }
  1310. else if(rangeParts.size() == 1)
  1311. {
  1312. auto val = boost::lexical_cast<int>(rangeParts.front());
  1313. playerRange.addNumber(val);
  1314. }
  1315. }
  1316. return playerRange;
  1317. }
  1318. boost::mutex CRmgTemplateStorage::smx;
  1319. CRmgTemplateStorage & CRmgTemplateStorage::get()
  1320. {
  1321. TLockGuard _(smx);
  1322. static CRmgTemplateStorage storage;
  1323. return storage;
  1324. }
  1325. const std::map<std::string, CRmgTemplate> & CRmgTemplateStorage::getTemplates() const
  1326. {
  1327. return templates;
  1328. }
  1329. CRmgTemplateStorage::CRmgTemplateStorage()
  1330. {
  1331. auto jsonLoader = make_unique<CJsonRmgTemplateLoader>();
  1332. jsonLoader->loadTemplates();
  1333. const auto & tpls = jsonLoader->getTemplates();
  1334. templates.insert(tpls.begin(), tpls.end());
  1335. }
  1336. CRmgTemplateStorage::~CRmgTemplateStorage()
  1337. {
  1338. }