CRmgTemplate.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845
  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. zoneMonsterStrength(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::ETemplateZoneType ZoneOptions::getType() const
  137. {
  138. return type;
  139. }
  140. void ZoneOptions::setType(ETemplateZoneType::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> STRENGTH =
  318. {
  319. "weak",
  320. "normal",
  321. "strong"
  322. };
  323. si32 rawStrength = 0;
  324. if(handler.saving)
  325. {
  326. rawStrength = static_cast<decltype(rawStrength)>(zoneMonsterStrength);
  327. rawStrength++;
  328. }
  329. handler.serializeEnum("monsters", rawStrength, EMonsterStrength::ZONE_NORMAL + 1, STRENGTH);
  330. if(!handler.saving)
  331. {
  332. rawStrength--;
  333. zoneMonsterStrength = static_cast<decltype(zoneMonsterStrength)>(rawStrength);
  334. }
  335. }
  336. if(treasureLikeZone == NO_ZONE)
  337. {
  338. auto treasureData = handler.enterArray("treasure");
  339. treasureData.serializeStruct(treasureInfo);
  340. if (!handler.saving)
  341. {
  342. recalculateMaxTreasureValue();
  343. }
  344. }
  345. if((minesLikeZone == NO_ZONE) && (!handler.saving || !mines.empty()))
  346. {
  347. auto minesData = handler.enterStruct("mines");
  348. for(TResource idx = 0; idx < (GameConstants::RESOURCE_QUANTITY - 1); idx++)
  349. {
  350. handler.serializeInt(GameConstants::RESOURCE_NAMES[idx], mines[idx], 0);
  351. }
  352. }
  353. }
  354. ZoneConnection::ZoneConnection()
  355. : zoneA(-1),
  356. zoneB(-1),
  357. guardStrength(0)
  358. {
  359. }
  360. TRmgTemplateZoneId ZoneConnection::getZoneA() const
  361. {
  362. return zoneA;
  363. }
  364. TRmgTemplateZoneId ZoneConnection::getZoneB() const
  365. {
  366. return zoneB;
  367. }
  368. int ZoneConnection::getGuardStrength() const
  369. {
  370. return guardStrength;
  371. }
  372. bool operator==(const ZoneConnection & l, const ZoneConnection & r)
  373. {
  374. return l.zoneA == r.zoneA && l.zoneB == r.zoneB && l.guardStrength == r.guardStrength;
  375. }
  376. void ZoneConnection::serializeJson(JsonSerializeFormat & handler)
  377. {
  378. handler.serializeId<TRmgTemplateZoneId, TRmgTemplateZoneId, ZoneEncoder>("a", zoneA, -1);
  379. handler.serializeId<TRmgTemplateZoneId, TRmgTemplateZoneId, ZoneEncoder>("b", zoneB, -1);
  380. handler.serializeInt("guard", guardStrength, 0);
  381. }
  382. }
  383. using namespace rmg;//todo: remove
  384. CRmgTemplate::CRmgTemplate()
  385. : minSize(72, 72, 2),
  386. maxSize(72, 72, 2)
  387. {
  388. }
  389. bool CRmgTemplate::matchesSize(const int3 & value) const
  390. {
  391. const int64_t square = value.x * value.y * value.z;
  392. const int64_t minSquare = minSize.x * minSize.y * minSize.z;
  393. const int64_t maxSquare = maxSize.x * maxSize.y * maxSize.z;
  394. return minSquare <= square && square <= maxSquare;
  395. }
  396. bool CRmgTemplate::isWaterContentAllowed(EWaterContent::EWaterContent waterContent) const
  397. {
  398. return waterContent == EWaterContent::EWaterContent::RANDOM || allowedWaterContent.count(waterContent);
  399. }
  400. const std::set<EWaterContent::EWaterContent> & CRmgTemplate::getWaterContentAllowed() const
  401. {
  402. return allowedWaterContent;
  403. }
  404. void CRmgTemplate::setId(const std::string & value)
  405. {
  406. id = value;
  407. }
  408. void CRmgTemplate::setName(const std::string & value)
  409. {
  410. name = value;
  411. }
  412. const std::string & CRmgTemplate::getName() const
  413. {
  414. return name;
  415. }
  416. const std::string & CRmgTemplate::getId() const
  417. {
  418. return id;
  419. }
  420. const CRmgTemplate::CPlayerCountRange & CRmgTemplate::getPlayers() const
  421. {
  422. return players;
  423. }
  424. const CRmgTemplate::CPlayerCountRange & CRmgTemplate::getCpuPlayers() const
  425. {
  426. return cpuPlayers;
  427. }
  428. const CRmgTemplate::Zones & CRmgTemplate::getZones() const
  429. {
  430. return zones;
  431. }
  432. const std::vector<ZoneConnection> & CRmgTemplate::getConnections() const
  433. {
  434. return connections;
  435. }
  436. void CRmgTemplate::validate() const
  437. {
  438. //TODO add some validation checks, throw on failure
  439. }
  440. std::pair<int3, int3> CRmgTemplate::getMapSizes() const
  441. {
  442. return {minSize, maxSize};
  443. }
  444. void CRmgTemplate::CPlayerCountRange::addRange(int lower, int upper)
  445. {
  446. range.emplace_back(lower, upper);
  447. }
  448. void CRmgTemplate::CPlayerCountRange::addNumber(int value)
  449. {
  450. range.emplace_back(value, value);
  451. }
  452. bool CRmgTemplate::CPlayerCountRange::isInRange(int count) const
  453. {
  454. for(const auto & pair : range)
  455. {
  456. if(count >= pair.first && count <= pair.second) return true;
  457. }
  458. return false;
  459. }
  460. std::set<int> CRmgTemplate::CPlayerCountRange::getNumbers() const
  461. {
  462. std::set<int> numbers;
  463. for(const auto & pair : range)
  464. {
  465. for(int i = pair.first; i <= pair.second; ++i) numbers.insert(i);
  466. }
  467. return numbers;
  468. }
  469. std::string CRmgTemplate::CPlayerCountRange::toString() const
  470. {
  471. if(range.size() == 1)
  472. {
  473. const auto & p = range.front();
  474. if((p.first == p.second) && (p.first == 0))
  475. return "";
  476. }
  477. std::string ret;
  478. bool first = true;
  479. for(const auto & p : range)
  480. {
  481. if(!first)
  482. ret +=",";
  483. else
  484. first = false;
  485. if(p.first == p.second)
  486. {
  487. ret += std::to_string(p.first);
  488. }
  489. else
  490. {
  491. ret += boost::to_string(boost::format("%d-%d") % p.first % p.second);
  492. }
  493. }
  494. return ret;
  495. }
  496. void CRmgTemplate::CPlayerCountRange::fromString(const std::string & value)
  497. {
  498. range.clear();
  499. if(value.empty())
  500. {
  501. addNumber(0);
  502. }
  503. else
  504. {
  505. std::vector<std::string> commaParts;
  506. boost::split(commaParts, value, boost::is_any_of(","));
  507. for(const auto & commaPart : commaParts)
  508. {
  509. std::vector<std::string> rangeParts;
  510. boost::split(rangeParts, commaPart, boost::is_any_of("-"));
  511. if(rangeParts.size() == 2)
  512. {
  513. auto lower = boost::lexical_cast<int>(rangeParts[0]);
  514. auto upper = boost::lexical_cast<int>(rangeParts[1]);
  515. addRange(lower, upper);
  516. }
  517. else if(rangeParts.size() == 1)
  518. {
  519. auto val = boost::lexical_cast<int>(rangeParts.front());
  520. addNumber(val);
  521. }
  522. }
  523. }
  524. }
  525. void CRmgTemplate::serializeJson(JsonSerializeFormat & handler)
  526. {
  527. handler.serializeString("name", name);
  528. serializeSize(handler, minSize, "minSize");
  529. serializeSize(handler, maxSize, "maxSize");
  530. serializePlayers(handler, players, "players");
  531. serializePlayers(handler, cpuPlayers, "cpu");
  532. {
  533. auto connectionsData = handler.enterArray("connections");
  534. connectionsData.serializeStruct(connections);
  535. }
  536. {
  537. boost::bimap<EWaterContent::EWaterContent, std::string> enc;
  538. enc.insert({EWaterContent::NONE, "none"});
  539. enc.insert({EWaterContent::NORMAL, "normal"});
  540. enc.insert({EWaterContent::ISLANDS, "islands"});
  541. JsonNode node;
  542. if(handler.saving)
  543. {
  544. node.setType(JsonNode::JsonType::DATA_VECTOR);
  545. for(auto wc : allowedWaterContent)
  546. {
  547. JsonNode n;
  548. n.String() = enc.left.at(wc);
  549. node.Vector().push_back(n);
  550. }
  551. }
  552. handler.serializeRaw("allowedWaterContent", node, std::nullopt);
  553. if(!handler.saving)
  554. {
  555. for(auto wc : node.Vector())
  556. {
  557. allowedWaterContent.insert(enc.right.at(std::string(wc.String())));
  558. }
  559. }
  560. }
  561. {
  562. auto zonesData = handler.enterStruct("zones");
  563. if(handler.saving)
  564. {
  565. for(auto & idAndZone : zones)
  566. {
  567. auto guard = handler.enterStruct(encodeZoneId(idAndZone.first));
  568. idAndZone.second->serializeJson(handler);
  569. }
  570. }
  571. else
  572. {
  573. for(const auto & idAndZone : zonesData->getCurrent().Struct())
  574. {
  575. auto guard = handler.enterStruct(idAndZone.first);
  576. auto zone = std::make_shared<ZoneOptions>();
  577. zone->setId(decodeZoneId(idAndZone.first));
  578. zone->serializeJson(handler);
  579. zones[zone->getId()] = zone;
  580. }
  581. }
  582. }
  583. if(!handler.saving)
  584. afterLoad();
  585. }
  586. std::set<TerrainId> CRmgTemplate::inheritTerrainType(std::shared_ptr<ZoneOptions> zone, uint32_t iteration /* = 0 */)
  587. {
  588. if (iteration >= 50)
  589. {
  590. logGlobal->error("Infinite recursion for terrain types detected in template %s", name);
  591. return std::set<TerrainId>();
  592. }
  593. if (zone->getTerrainTypeLikeZone() != ZoneOptions::NO_ZONE)
  594. {
  595. iteration++;
  596. const auto otherZone = zones.at(zone->getTerrainTypeLikeZone());
  597. zone->setTerrainTypes(inheritTerrainType(otherZone, iteration));
  598. }
  599. return zone->getTerrainTypes();
  600. }
  601. std::map<TResource, ui16> CRmgTemplate::inheritMineTypes(std::shared_ptr<ZoneOptions> zone, uint32_t iteration /* = 0 */)
  602. {
  603. if (iteration >= 50)
  604. {
  605. logGlobal->error("Infinite recursion for mine types detected in template %s", name);
  606. return std::map<TResource, ui16>();
  607. }
  608. if (zone->getMinesLikeZone() != ZoneOptions::NO_ZONE)
  609. {
  610. iteration++;
  611. const auto otherZone = zones.at(zone->getMinesLikeZone());
  612. zone->setMinesInfo(inheritMineTypes(otherZone, iteration));
  613. }
  614. return zone->getMinesInfo();
  615. }
  616. std::vector<CTreasureInfo> CRmgTemplate::inheritTreasureInfo(std::shared_ptr<ZoneOptions> zone, uint32_t iteration /* = 0 */)
  617. {
  618. if (iteration >= 50)
  619. {
  620. logGlobal->error("Infinite recursion for treasures detected in template %s", name);
  621. return std::vector<CTreasureInfo>();
  622. }
  623. if (zone->getTreasureLikeZone() != ZoneOptions::NO_ZONE)
  624. {
  625. iteration++;
  626. const auto otherZone = zones.at(zone->getTreasureLikeZone());
  627. zone->setTreasureInfo(inheritTreasureInfo(otherZone, iteration));
  628. }
  629. return zone->getTreasureInfo();
  630. }
  631. void CRmgTemplate::afterLoad()
  632. {
  633. for(auto & idAndZone : zones)
  634. {
  635. auto zone = idAndZone.second;
  636. //Inherit properties recursively.
  637. inheritTerrainType(zone);
  638. inheritMineTypes(zone);
  639. inheritTreasureInfo(zone);
  640. }
  641. for(const auto & connection : connections)
  642. {
  643. auto id1 = connection.getZoneA();
  644. auto id2 = connection.getZoneB();
  645. auto zone1 = zones.at(id1);
  646. auto zone2 = zones.at(id2);
  647. zone1->addConnection(id2);
  648. zone2->addConnection(id1);
  649. }
  650. if(allowedWaterContent.empty() || allowedWaterContent.count(EWaterContent::EWaterContent::RANDOM))
  651. {
  652. allowedWaterContent.insert(EWaterContent::EWaterContent::NONE);
  653. allowedWaterContent.insert(EWaterContent::EWaterContent::NORMAL);
  654. allowedWaterContent.insert(EWaterContent::EWaterContent::ISLANDS);
  655. }
  656. allowedWaterContent.erase(EWaterContent::EWaterContent::RANDOM);
  657. }
  658. void CRmgTemplate::serializeSize(JsonSerializeFormat & handler, int3 & value, const std::string & fieldName)
  659. {
  660. static const std::map<std::string, int3> sizeMapping =
  661. {
  662. {"s", { 36, 36, 1}},
  663. {"s+u", { 36, 36, 2}},
  664. {"m", { 72, 72, 1}},
  665. {"m+u", { 72, 72, 2}},
  666. {"l", {108, 108, 1}},
  667. {"l+u", {108, 108, 2}},
  668. {"xl", {144, 144, 1}},
  669. {"xl+u", {144, 144, 2}},
  670. {"h", {180, 180, 1}},
  671. {"h+u", {180, 180, 2}},
  672. {"xh", {216, 216, 1}},
  673. {"xh+u", {216, 216, 2}},
  674. {"g", {252, 252, 1}},
  675. {"g+u", {252, 252, 2}}
  676. };
  677. static const std::map<int3, std::string> sizeReverseMapping = vstd::invertMap(sizeMapping);
  678. std::string encodedValue;
  679. if(handler.saving)
  680. {
  681. auto iter = sizeReverseMapping.find(value);
  682. if(iter == sizeReverseMapping.end())
  683. encodedValue = boost::str(boost::format("%dx%dx%d") % value.x % value.y % value.z);
  684. else
  685. encodedValue = iter->second;
  686. }
  687. handler.serializeString(fieldName, encodedValue);
  688. if(!handler.saving)
  689. {
  690. auto iter = sizeMapping.find(encodedValue);
  691. if(iter == sizeMapping.end())
  692. {
  693. std::vector<std::string> parts;
  694. boost::split(parts, encodedValue, boost::is_any_of("x"));
  695. value.x = (boost::lexical_cast<int>(parts.at(0)));
  696. value.y = (boost::lexical_cast<int>(parts.at(1)));
  697. value.z = (boost::lexical_cast<int>(parts.at(2)));
  698. }
  699. else
  700. {
  701. value = iter->second;
  702. }
  703. }
  704. }
  705. void CRmgTemplate::serializePlayers(JsonSerializeFormat & handler, CPlayerCountRange & value, const std::string & fieldName)
  706. {
  707. std::string encodedValue;
  708. if(handler.saving)
  709. encodedValue = value.toString();
  710. handler.serializeString(fieldName, encodedValue);
  711. if(!handler.saving)
  712. value.fromString(encodedValue);
  713. }
  714. VCMI_LIB_NAMESPACE_END