CRmgTemplate.cpp 18 KB

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