CRmgTemplate.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. /*
  2. * CRmgTemplate.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include <vstd/ContainerUtils.h>
  12. #include <boost/bimap.hpp>
  13. #include "CRmgTemplate.h"
  14. #include "../VCMI_Lib.h"
  15. #include "../CTownHandler.h"
  16. #include "../CModHandler.h"
  17. #include "../TerrainHandler.h"
  18. #include "../serializer/JsonSerializeFormat.h"
  19. #include "../StringConstants.h"
  20. VCMI_LIB_NAMESPACE_BEGIN
  21. namespace
  22. {
  23. si32 decodeZoneId(const std::string & json)
  24. {
  25. return boost::lexical_cast<si32>(json);
  26. }
  27. std::string encodeZoneId(si32 id)
  28. {
  29. return std::to_string(id);
  30. }
  31. }
  32. CTreasureInfo::CTreasureInfo()
  33. : min(0),
  34. max(0),
  35. density(0)
  36. {
  37. }
  38. CTreasureInfo::CTreasureInfo(ui32 imin, ui32 imax, ui16 idensity)
  39. : min(imin), max(imax), density(idensity)
  40. {
  41. }
  42. bool CTreasureInfo::operator==(const CTreasureInfo & other) const
  43. {
  44. return (min == other.min) && (max == other.max) && (density == other.density);
  45. }
  46. void CTreasureInfo::serializeJson(JsonSerializeFormat & handler)
  47. {
  48. handler.serializeInt("min", min, 0);
  49. handler.serializeInt("max", max, 0);
  50. handler.serializeInt("density", density, 0);
  51. }
  52. namespace rmg
  53. {
  54. class TerrainEncoder
  55. {
  56. public:
  57. static si32 decode(const std::string & identifier)
  58. {
  59. return *VLC->modh->identifiers.getIdentifier(CModHandler::scopeGame(), "terrain", identifier);
  60. }
  61. static std::string encode(const si32 index)
  62. {
  63. return VLC->terrainTypeHandler->getByIndex(index)->getJsonKey();
  64. }
  65. };
  66. class ZoneEncoder
  67. {
  68. public:
  69. static si32 decode(const std::string & json)
  70. {
  71. return std::stoi(json);
  72. }
  73. static std::string encode(si32 id)
  74. {
  75. return std::to_string(id);
  76. }
  77. };
  78. const TRmgTemplateZoneId ZoneOptions::NO_ZONE = -1;
  79. ZoneOptions::CTownInfo::CTownInfo()
  80. : townCount(0),
  81. castleCount(0),
  82. townDensity(0),
  83. castleDensity(0)
  84. {
  85. }
  86. int ZoneOptions::CTownInfo::getTownCount() const
  87. {
  88. return townCount;
  89. }
  90. int ZoneOptions::CTownInfo::getCastleCount() const
  91. {
  92. return castleCount;
  93. }
  94. int ZoneOptions::CTownInfo::getTownDensity() const
  95. {
  96. return townDensity;
  97. }
  98. int ZoneOptions::CTownInfo::getCastleDensity() const
  99. {
  100. return castleDensity;
  101. }
  102. void ZoneOptions::CTownInfo::serializeJson(JsonSerializeFormat & handler)
  103. {
  104. handler.serializeInt("towns", townCount, 0);
  105. handler.serializeInt("castles", castleCount, 0);
  106. handler.serializeInt("townDensity", townDensity, 0);
  107. handler.serializeInt("castleDensity", castleDensity, 0);
  108. }
  109. ZoneOptions::ZoneOptions():
  110. id(0),
  111. type(ETemplateZoneType::PLAYER_START),
  112. size(1),
  113. maxTreasureValue(0),
  114. owner(std::nullopt),
  115. matchTerrainToTown(true),
  116. townsAreSameType(false),
  117. monsterStrength(EMonsterStrength::ZONE_NORMAL),
  118. minesLikeZone(NO_ZONE),
  119. terrainTypeLikeZone(NO_ZONE),
  120. treasureLikeZone(NO_ZONE)
  121. {
  122. for(const auto & terr : VLC->terrainTypeHandler->objects)
  123. if(terr->isLand() && terr->isPassable())
  124. terrainTypes.insert(terr->getId());
  125. }
  126. TRmgTemplateZoneId ZoneOptions::getId() const
  127. {
  128. return id;
  129. }
  130. void ZoneOptions::setId(TRmgTemplateZoneId value)
  131. {
  132. if(value <= 0)
  133. throw std::runtime_error(boost::to_string(boost::format("Zone %d id should be greater than 0.") % id));
  134. id = value;
  135. }
  136. ETemplateZoneType ZoneOptions::getType() const
  137. {
  138. return type;
  139. }
  140. void ZoneOptions::setType(ETemplateZoneType value)
  141. {
  142. type = value;
  143. }
  144. int ZoneOptions::getSize() const
  145. {
  146. return size;
  147. }
  148. void ZoneOptions::setSize(int value)
  149. {
  150. size = value;
  151. }
  152. std::optional<int> ZoneOptions::getOwner() const
  153. {
  154. return owner;
  155. }
  156. const std::set<TerrainId> & ZoneOptions::getTerrainTypes() const
  157. {
  158. return terrainTypes;
  159. }
  160. void ZoneOptions::setTerrainTypes(const std::set<TerrainId> & value)
  161. {
  162. //assert(value.find(ETerrainType::NONE) == value.end() &&
  163. // value.find(ETerrainType::WATER) == value.end() && value.find(ETerrainType::ROCK) == value.end());
  164. terrainTypes = value;
  165. }
  166. std::set<FactionID> ZoneOptions::getDefaultTownTypes() const
  167. {
  168. std::set<FactionID> defaultTowns;
  169. auto towns = VLC->townh->getDefaultAllowed();
  170. for(int i = 0; i < towns.size(); ++i)
  171. {
  172. if(towns[i]) defaultTowns.insert(FactionID(i));
  173. }
  174. return defaultTowns;
  175. }
  176. const std::set<FactionID> & ZoneOptions::getTownTypes() const
  177. {
  178. return townTypes;
  179. }
  180. void ZoneOptions::setTownTypes(const std::set<FactionID> & value)
  181. {
  182. townTypes = value;
  183. }
  184. void ZoneOptions::setMonsterTypes(const std::set<FactionID> & value)
  185. {
  186. monsterTypes = value;
  187. }
  188. const std::set<FactionID> & ZoneOptions::getMonsterTypes() const
  189. {
  190. return monsterTypes;
  191. }
  192. void ZoneOptions::setMinesInfo(const std::map<TResource, ui16> & value)
  193. {
  194. mines = value;
  195. }
  196. std::map<TResource, ui16> ZoneOptions::getMinesInfo() const
  197. {
  198. return mines;
  199. }
  200. void ZoneOptions::setTreasureInfo(const std::vector<CTreasureInfo> & value)
  201. {
  202. treasureInfo = value;
  203. recalculateMaxTreasureValue();
  204. }
  205. void ZoneOptions::recalculateMaxTreasureValue()
  206. {
  207. maxTreasureValue = 0;
  208. for (const auto& ti : treasureInfo)
  209. {
  210. vstd::amax(maxTreasureValue, ti.max);
  211. }
  212. }
  213. void ZoneOptions::addTreasureInfo(const CTreasureInfo & value)
  214. {
  215. treasureInfo.push_back(value);
  216. vstd::amax(maxTreasureValue, value.max);
  217. }
  218. const std::vector<CTreasureInfo> & ZoneOptions::getTreasureInfo() const
  219. {
  220. return treasureInfo;
  221. }
  222. ui32 ZoneOptions::getMaxTreasureValue() const
  223. {
  224. return maxTreasureValue;
  225. }
  226. TRmgTemplateZoneId ZoneOptions::getMinesLikeZone() const
  227. {
  228. return minesLikeZone;
  229. }
  230. TRmgTemplateZoneId ZoneOptions::getTerrainTypeLikeZone() const
  231. {
  232. return terrainTypeLikeZone;
  233. }
  234. TRmgTemplateZoneId ZoneOptions::getTreasureLikeZone() const
  235. {
  236. return treasureLikeZone;
  237. }
  238. void ZoneOptions::addConnection(TRmgTemplateZoneId otherZone)
  239. {
  240. connections.push_back (otherZone);
  241. }
  242. std::vector<TRmgTemplateZoneId> ZoneOptions::getConnections() const
  243. {
  244. return connections;
  245. }
  246. bool ZoneOptions::areTownsSameType() const
  247. {
  248. return townsAreSameType;
  249. }
  250. bool ZoneOptions::isMatchTerrainToTown() const
  251. {
  252. return matchTerrainToTown;
  253. }
  254. const ZoneOptions::CTownInfo & ZoneOptions::getPlayerTowns() const
  255. {
  256. return playerTowns;
  257. }
  258. const ZoneOptions::CTownInfo & ZoneOptions::getNeutralTowns() const
  259. {
  260. return neutralTowns;
  261. }
  262. void ZoneOptions::serializeJson(JsonSerializeFormat & handler)
  263. {
  264. static const std::vector<std::string> zoneTypes =
  265. {
  266. "playerStart",
  267. "cpuStart",
  268. "treasure",
  269. "junction",
  270. "water"
  271. };
  272. handler.serializeEnum("type", type, zoneTypes);
  273. handler.serializeInt("size", size, 1);
  274. handler.serializeInt("owner", owner);
  275. handler.serializeStruct("playerTowns", playerTowns);
  276. handler.serializeStruct("neutralTowns", neutralTowns);
  277. handler.serializeBool("matchTerrainToTown", matchTerrainToTown, true);
  278. #define SERIALIZE_ZONE_LINK(fieldName) handler.serializeInt(#fieldName, fieldName, NO_ZONE);
  279. SERIALIZE_ZONE_LINK(minesLikeZone);
  280. SERIALIZE_ZONE_LINK(terrainTypeLikeZone);
  281. SERIALIZE_ZONE_LINK(treasureLikeZone);
  282. #undef SERIALIZE_ZONE_LINK
  283. if(terrainTypeLikeZone == NO_ZONE)
  284. {
  285. JsonNode node;
  286. if(handler.saving)
  287. {
  288. node.setType(JsonNode::JsonType::DATA_VECTOR);
  289. for(const auto & ttype : terrainTypes)
  290. {
  291. JsonNode n;
  292. n.String() = VLC->terrainTypeHandler->getById(ttype)->getJsonKey();
  293. node.Vector().push_back(n);
  294. }
  295. }
  296. handler.serializeRaw("terrainTypes", node, std::nullopt);
  297. if(!handler.saving)
  298. {
  299. if(!node.Vector().empty())
  300. {
  301. terrainTypes.clear();
  302. for(const auto & ttype : node.Vector())
  303. {
  304. VLC->modh->identifiers.requestIdentifier("terrain", ttype, [this](int32_t identifier)
  305. {
  306. terrainTypes.emplace(identifier);
  307. });
  308. }
  309. }
  310. }
  311. }
  312. handler.serializeBool("townsAreSameType", townsAreSameType, false);
  313. handler.serializeIdArray<FactionID, FactionID>("allowedMonsters", monsterTypes, VLC->townh->getAllowedFactions(false));
  314. handler.serializeIdArray<FactionID, FactionID>("allowedTowns", townTypes, VLC->townh->getAllowedFactions(true));
  315. {
  316. //TODO: add support for std::map to serializeEnum
  317. static const std::vector<std::string> zoneMonsterStrengths =
  318. {
  319. "none",
  320. "weak",
  321. "normal",
  322. "strong"
  323. };
  324. int temporaryZoneMonsterStrengthIndex = monsterStrength == EMonsterStrength::ZONE_NONE ? 0 : monsterStrength - EMonsterStrength::ZONE_WEAK + 1 ; // temporary until serializeEnum starts supporting std::map
  325. // temporaryZoneMonsterStrengthIndex = 0, 1, 2 and 3 for monsterStrength = ZONE_NONE, ZONE_WEAK, ZONE_NORMAL and ZONE_STRONG respectively
  326. handler.serializeEnum("monsters", temporaryZoneMonsterStrengthIndex, 2, zoneMonsterStrengths); // default is normal monsters
  327. switch (temporaryZoneMonsterStrengthIndex)
  328. {
  329. case 0:
  330. monsterStrength = EMonsterStrength::ZONE_NONE;
  331. break;
  332. case 1:
  333. monsterStrength = EMonsterStrength::ZONE_WEAK;
  334. break;
  335. case 2:
  336. monsterStrength = EMonsterStrength::ZONE_NORMAL;
  337. break;
  338. case 3:
  339. monsterStrength = EMonsterStrength::ZONE_STRONG;
  340. break;
  341. }
  342. }
  343. if(treasureLikeZone == NO_ZONE)
  344. {
  345. auto treasureData = handler.enterArray("treasure");
  346. treasureData.serializeStruct(treasureInfo);
  347. if (!handler.saving)
  348. {
  349. recalculateMaxTreasureValue();
  350. }
  351. }
  352. if((minesLikeZone == NO_ZONE) && (!handler.saving || !mines.empty()))
  353. {
  354. auto minesData = handler.enterStruct("mines");
  355. for(TResource idx = 0; idx < (GameConstants::RESOURCE_QUANTITY - 1); idx++)
  356. {
  357. handler.serializeInt(GameConstants::RESOURCE_NAMES[idx], mines[idx], 0);
  358. }
  359. }
  360. }
  361. ZoneConnection::ZoneConnection()
  362. : zoneA(-1),
  363. zoneB(-1),
  364. guardStrength(0)
  365. {
  366. }
  367. TRmgTemplateZoneId ZoneConnection::getZoneA() const
  368. {
  369. return zoneA;
  370. }
  371. TRmgTemplateZoneId ZoneConnection::getZoneB() const
  372. {
  373. return zoneB;
  374. }
  375. int ZoneConnection::getGuardStrength() const
  376. {
  377. return guardStrength;
  378. }
  379. bool operator==(const ZoneConnection & l, const ZoneConnection & r)
  380. {
  381. return l.zoneA == r.zoneA && l.zoneB == r.zoneB && l.guardStrength == r.guardStrength;
  382. }
  383. void ZoneConnection::serializeJson(JsonSerializeFormat & handler)
  384. {
  385. handler.serializeId<TRmgTemplateZoneId, TRmgTemplateZoneId, ZoneEncoder>("a", zoneA, -1);
  386. handler.serializeId<TRmgTemplateZoneId, TRmgTemplateZoneId, ZoneEncoder>("b", zoneB, -1);
  387. handler.serializeInt("guard", guardStrength, 0);
  388. }
  389. }
  390. using namespace rmg;//todo: remove
  391. CRmgTemplate::CRmgTemplate()
  392. : minSize(72, 72, 2),
  393. maxSize(72, 72, 2)
  394. {
  395. }
  396. bool CRmgTemplate::matchesSize(const int3 & value) const
  397. {
  398. const int64_t square = value.x * value.y * value.z;
  399. const int64_t minSquare = minSize.x * minSize.y * minSize.z;
  400. const int64_t maxSquare = maxSize.x * maxSize.y * maxSize.z;
  401. return minSquare <= square && square <= maxSquare;
  402. }
  403. bool CRmgTemplate::isWaterContentAllowed(EWaterContent::EWaterContent waterContent) const
  404. {
  405. return waterContent == EWaterContent::RANDOM || allowedWaterContent.count(waterContent);
  406. }
  407. const std::set<EWaterContent::EWaterContent> & CRmgTemplate::getWaterContentAllowed() const
  408. {
  409. return allowedWaterContent;
  410. }
  411. void CRmgTemplate::setId(const std::string & value)
  412. {
  413. id = value;
  414. }
  415. void CRmgTemplate::setName(const std::string & value)
  416. {
  417. name = value;
  418. }
  419. const std::string & CRmgTemplate::getName() const
  420. {
  421. return name;
  422. }
  423. const std::string & CRmgTemplate::getId() const
  424. {
  425. return id;
  426. }
  427. const CRmgTemplate::CPlayerCountRange & CRmgTemplate::getPlayers() const
  428. {
  429. return players;
  430. }
  431. const CRmgTemplate::CPlayerCountRange & CRmgTemplate::getCpuPlayers() const
  432. {
  433. return cpuPlayers;
  434. }
  435. const CRmgTemplate::Zones & CRmgTemplate::getZones() const
  436. {
  437. return zones;
  438. }
  439. const std::vector<ZoneConnection> & CRmgTemplate::getConnections() const
  440. {
  441. return connections;
  442. }
  443. void CRmgTemplate::validate() const
  444. {
  445. //TODO add some validation checks, throw on failure
  446. }
  447. std::pair<int3, int3> CRmgTemplate::getMapSizes() const
  448. {
  449. return {minSize, maxSize};
  450. }
  451. void CRmgTemplate::CPlayerCountRange::addRange(int lower, int upper)
  452. {
  453. range.emplace_back(lower, upper);
  454. }
  455. void CRmgTemplate::CPlayerCountRange::addNumber(int value)
  456. {
  457. range.emplace_back(value, value);
  458. }
  459. bool CRmgTemplate::CPlayerCountRange::isInRange(int count) const
  460. {
  461. for(const auto & pair : range)
  462. {
  463. if(count >= pair.first && count <= pair.second) return true;
  464. }
  465. return false;
  466. }
  467. std::set<int> CRmgTemplate::CPlayerCountRange::getNumbers() const
  468. {
  469. std::set<int> numbers;
  470. for(const auto & pair : range)
  471. {
  472. for(int i = pair.first; i <= pair.second; ++i) numbers.insert(i);
  473. }
  474. return numbers;
  475. }
  476. std::string CRmgTemplate::CPlayerCountRange::toString() const
  477. {
  478. if(range.size() == 1)
  479. {
  480. const auto & p = range.front();
  481. if((p.first == p.second) && (p.first == 0))
  482. return "";
  483. }
  484. std::string ret;
  485. bool first = true;
  486. for(const auto & p : range)
  487. {
  488. if(!first)
  489. ret +=",";
  490. else
  491. first = false;
  492. if(p.first == p.second)
  493. {
  494. ret += std::to_string(p.first);
  495. }
  496. else
  497. {
  498. ret += boost::to_string(boost::format("%d-%d") % p.first % p.second);
  499. }
  500. }
  501. return ret;
  502. }
  503. void CRmgTemplate::CPlayerCountRange::fromString(const std::string & value)
  504. {
  505. range.clear();
  506. if(value.empty())
  507. {
  508. addNumber(0);
  509. }
  510. else
  511. {
  512. std::vector<std::string> commaParts;
  513. boost::split(commaParts, value, boost::is_any_of(","));
  514. for(const auto & commaPart : commaParts)
  515. {
  516. std::vector<std::string> rangeParts;
  517. boost::split(rangeParts, commaPart, boost::is_any_of("-"));
  518. if(rangeParts.size() == 2)
  519. {
  520. auto lower = boost::lexical_cast<int>(rangeParts[0]);
  521. auto upper = boost::lexical_cast<int>(rangeParts[1]);
  522. addRange(lower, upper);
  523. }
  524. else if(rangeParts.size() == 1)
  525. {
  526. auto val = boost::lexical_cast<int>(rangeParts.front());
  527. addNumber(val);
  528. }
  529. }
  530. }
  531. }
  532. void CRmgTemplate::serializeJson(JsonSerializeFormat & handler)
  533. {
  534. handler.serializeString("name", name);
  535. serializeSize(handler, minSize, "minSize");
  536. serializeSize(handler, maxSize, "maxSize");
  537. serializePlayers(handler, players, "players");
  538. serializePlayers(handler, cpuPlayers, "cpu");
  539. {
  540. auto connectionsData = handler.enterArray("connections");
  541. connectionsData.serializeStruct(connections);
  542. }
  543. {
  544. boost::bimap<EWaterContent::EWaterContent, std::string> enc;
  545. enc.insert({EWaterContent::NONE, "none"});
  546. enc.insert({EWaterContent::NORMAL, "normal"});
  547. enc.insert({EWaterContent::ISLANDS, "islands"});
  548. JsonNode node;
  549. if(handler.saving)
  550. {
  551. node.setType(JsonNode::JsonType::DATA_VECTOR);
  552. for(auto wc : allowedWaterContent)
  553. {
  554. JsonNode n;
  555. n.String() = enc.left.at(wc);
  556. node.Vector().push_back(n);
  557. }
  558. }
  559. handler.serializeRaw("allowedWaterContent", node, std::nullopt);
  560. if(!handler.saving)
  561. {
  562. for(auto wc : node.Vector())
  563. {
  564. allowedWaterContent.insert(enc.right.at(std::string(wc.String())));
  565. }
  566. }
  567. }
  568. {
  569. auto zonesData = handler.enterStruct("zones");
  570. if(handler.saving)
  571. {
  572. for(auto & idAndZone : zones)
  573. {
  574. auto guard = handler.enterStruct(encodeZoneId(idAndZone.first));
  575. idAndZone.second->serializeJson(handler);
  576. }
  577. }
  578. else
  579. {
  580. for(const auto & idAndZone : zonesData->getCurrent().Struct())
  581. {
  582. auto guard = handler.enterStruct(idAndZone.first);
  583. auto zone = std::make_shared<ZoneOptions>();
  584. zone->setId(decodeZoneId(idAndZone.first));
  585. zone->serializeJson(handler);
  586. zones[zone->getId()] = zone;
  587. }
  588. }
  589. }
  590. if(!handler.saving)
  591. afterLoad();
  592. }
  593. std::set<TerrainId> CRmgTemplate::inheritTerrainType(std::shared_ptr<ZoneOptions> zone, uint32_t iteration /* = 0 */)
  594. {
  595. if (iteration >= 50)
  596. {
  597. logGlobal->error("Infinite recursion for terrain types detected in template %s", name);
  598. return std::set<TerrainId>();
  599. }
  600. if (zone->getTerrainTypeLikeZone() != ZoneOptions::NO_ZONE)
  601. {
  602. iteration++;
  603. const auto otherZone = zones.at(zone->getTerrainTypeLikeZone());
  604. zone->setTerrainTypes(inheritTerrainType(otherZone, iteration));
  605. }
  606. return zone->getTerrainTypes();
  607. }
  608. std::map<TResource, ui16> CRmgTemplate::inheritMineTypes(std::shared_ptr<ZoneOptions> zone, uint32_t iteration /* = 0 */)
  609. {
  610. if (iteration >= 50)
  611. {
  612. logGlobal->error("Infinite recursion for mine types detected in template %s", name);
  613. return std::map<TResource, ui16>();
  614. }
  615. if (zone->getMinesLikeZone() != ZoneOptions::NO_ZONE)
  616. {
  617. iteration++;
  618. const auto otherZone = zones.at(zone->getMinesLikeZone());
  619. zone->setMinesInfo(inheritMineTypes(otherZone, iteration));
  620. }
  621. return zone->getMinesInfo();
  622. }
  623. std::vector<CTreasureInfo> CRmgTemplate::inheritTreasureInfo(std::shared_ptr<ZoneOptions> zone, uint32_t iteration /* = 0 */)
  624. {
  625. if (iteration >= 50)
  626. {
  627. logGlobal->error("Infinite recursion for treasures detected in template %s", name);
  628. return std::vector<CTreasureInfo>();
  629. }
  630. if (zone->getTreasureLikeZone() != ZoneOptions::NO_ZONE)
  631. {
  632. iteration++;
  633. const auto otherZone = zones.at(zone->getTreasureLikeZone());
  634. zone->setTreasureInfo(inheritTreasureInfo(otherZone, iteration));
  635. }
  636. return zone->getTreasureInfo();
  637. }
  638. void CRmgTemplate::afterLoad()
  639. {
  640. for(auto & idAndZone : zones)
  641. {
  642. auto zone = idAndZone.second;
  643. //Inherit properties recursively.
  644. inheritTerrainType(zone);
  645. inheritMineTypes(zone);
  646. inheritTreasureInfo(zone);
  647. }
  648. for(const auto & connection : connections)
  649. {
  650. auto id1 = connection.getZoneA();
  651. auto id2 = connection.getZoneB();
  652. auto zone1 = zones.at(id1);
  653. auto zone2 = zones.at(id2);
  654. zone1->addConnection(id2);
  655. zone2->addConnection(id1);
  656. }
  657. if(allowedWaterContent.empty() || allowedWaterContent.count(EWaterContent::RANDOM))
  658. {
  659. allowedWaterContent.insert(EWaterContent::NONE);
  660. allowedWaterContent.insert(EWaterContent::NORMAL);
  661. allowedWaterContent.insert(EWaterContent::ISLANDS);
  662. }
  663. allowedWaterContent.erase(EWaterContent::RANDOM);
  664. }
  665. void CRmgTemplate::serializeSize(JsonSerializeFormat & handler, int3 & value, const std::string & fieldName)
  666. {
  667. static const std::map<std::string, int3> sizeMapping =
  668. {
  669. {"s", { 36, 36, 1}},
  670. {"s+u", { 36, 36, 2}},
  671. {"m", { 72, 72, 1}},
  672. {"m+u", { 72, 72, 2}},
  673. {"l", {108, 108, 1}},
  674. {"l+u", {108, 108, 2}},
  675. {"xl", {144, 144, 1}},
  676. {"xl+u", {144, 144, 2}},
  677. {"h", {180, 180, 1}},
  678. {"h+u", {180, 180, 2}},
  679. {"xh", {216, 216, 1}},
  680. {"xh+u", {216, 216, 2}},
  681. {"g", {252, 252, 1}},
  682. {"g+u", {252, 252, 2}}
  683. };
  684. static const std::map<int3, std::string> sizeReverseMapping = vstd::invertMap(sizeMapping);
  685. std::string encodedValue;
  686. if(handler.saving)
  687. {
  688. auto iter = sizeReverseMapping.find(value);
  689. if(iter == sizeReverseMapping.end())
  690. encodedValue = boost::str(boost::format("%dx%dx%d") % value.x % value.y % value.z);
  691. else
  692. encodedValue = iter->second;
  693. }
  694. handler.serializeString(fieldName, encodedValue);
  695. if(!handler.saving)
  696. {
  697. auto iter = sizeMapping.find(encodedValue);
  698. if(iter == sizeMapping.end())
  699. {
  700. std::vector<std::string> parts;
  701. boost::split(parts, encodedValue, boost::is_any_of("x"));
  702. value.x = (boost::lexical_cast<int>(parts.at(0)));
  703. value.y = (boost::lexical_cast<int>(parts.at(1)));
  704. value.z = (boost::lexical_cast<int>(parts.at(2)));
  705. }
  706. else
  707. {
  708. value = iter->second;
  709. }
  710. }
  711. }
  712. void CRmgTemplate::serializePlayers(JsonSerializeFormat & handler, CPlayerCountRange & value, const std::string & fieldName)
  713. {
  714. std::string encodedValue;
  715. if(handler.saving)
  716. encodedValue = value.toString();
  717. handler.serializeString(fieldName, encodedValue);
  718. if(!handler.saving)
  719. value.fromString(encodedValue);
  720. }
  721. VCMI_LIB_NAMESPACE_END