CDrawRoadsOperation.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /*
  2. * CDrawRoadsOperation.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 "CDrawRoadsOperation.h"
  12. #include "CMap.h"
  13. #include "../RoadHandler.h"
  14. #include "../RiverHandler.h"
  15. #include "../VCMI_Lib.h"
  16. #include <vstd/RNG.h>
  17. VCMI_LIB_NAMESPACE_BEGIN
  18. const std::vector<CDrawLinesOperation::LinePattern> CDrawLinesOperation::patterns =
  19. {
  20. //single tile. fall-back pattern
  21. {
  22. {
  23. "-","-","-",
  24. "-","+","-",
  25. "-","-","-"
  26. },
  27. {14,14},
  28. {9,9},
  29. false,
  30. false
  31. },
  32. //Road straight with angle
  33. {
  34. {
  35. "?","-","+",
  36. "-","+","+",
  37. "+","+","?"
  38. },
  39. {2,5},
  40. {-1,-1},
  41. true,
  42. true
  43. },
  44. //Turn
  45. {
  46. {
  47. "?","-","?",
  48. "-","+","+",
  49. "?","+","?"
  50. },
  51. {0,1},
  52. {0,3},
  53. true,
  54. true
  55. },
  56. //Dead end horizontal
  57. {
  58. {
  59. "?","-","?",
  60. "-","+","+",
  61. "?","-","?"
  62. },
  63. {15,15},{11,12},
  64. true,
  65. false
  66. },
  67. //Dead end vertical
  68. {
  69. {
  70. "?","-","?",
  71. "-","+","-",
  72. "?","+","?"
  73. },
  74. {14,14},{9,10},
  75. false,
  76. true
  77. },
  78. //T-cross horizontal
  79. {
  80. {
  81. "?","+","?",
  82. "-","+","+",
  83. "?","+","?"
  84. },
  85. {6,7},{7,8},
  86. true,
  87. false
  88. },
  89. //T-cross vertical
  90. {
  91. {
  92. "?","-","?",
  93. "+","+","+",
  94. "?","+","?"
  95. },
  96. {8,9},{5,6},
  97. false,
  98. true
  99. },
  100. //Straight Horizontal
  101. {
  102. {
  103. "?","-","?",
  104. "+","+","+",
  105. "?","-","?"
  106. },
  107. {12,13},{11,12},
  108. false,
  109. false
  110. },
  111. //Straight Vertical
  112. {
  113. {
  114. "?","+","?",
  115. "-","+","-",
  116. "?","+","?"
  117. },
  118. {10,11},{9,10},
  119. false,
  120. false
  121. },
  122. //X-cross
  123. {
  124. {
  125. "?","+","?",
  126. "+","+","+",
  127. "?","+","?"
  128. },
  129. {16,16},{4,4},
  130. false,
  131. false
  132. }
  133. };
  134. static bool ruleIsNone(const std::string & rule)
  135. {
  136. return rule == "-";
  137. }
  138. static bool ruleIsSomething(const std::string & rule)
  139. {
  140. return rule == "+";
  141. }
  142. #ifndef NDEBUG
  143. static bool ruleIsAny(const std::string & rule)
  144. {
  145. return rule == "?";
  146. }
  147. #endif
  148. ///CDrawLinesOperation
  149. CDrawLinesOperation::CDrawLinesOperation(CMap * map, CTerrainSelection terrainSel, vstd::RNG * gen):
  150. CMapOperation(map),
  151. terrainSel(std::move(terrainSel)),
  152. gen(gen)
  153. {
  154. }
  155. ///CDrawRoadsOperation
  156. CDrawRoadsOperation::CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, RoadId roadType, vstd::RNG * gen):
  157. CDrawLinesOperation(map, terrainSel,gen),
  158. roadType(roadType)
  159. {
  160. }
  161. ///CDrawRiversOperation
  162. CDrawRiversOperation::CDrawRiversOperation(CMap * map, const CTerrainSelection & terrainSel, RiverId riverType, vstd::RNG * gen):
  163. CDrawLinesOperation(map, terrainSel, gen),
  164. riverType(riverType)
  165. {
  166. }
  167. void CDrawLinesOperation::execute()
  168. {
  169. std::set<int3> invalidated;
  170. for(const auto & pos : terrainSel.getSelectedItems())
  171. {
  172. executeTile(map->getTile(pos));
  173. auto rect = extendTileAroundSafely(pos);
  174. rect.forEach([&invalidated](const int3 & pos)
  175. {
  176. invalidated.insert(pos);
  177. });
  178. }
  179. updateTiles(invalidated);
  180. }
  181. void CDrawLinesOperation::undo()
  182. {
  183. //TODO
  184. }
  185. void CDrawLinesOperation::redo()
  186. {
  187. //TODO
  188. }
  189. void CDrawLinesOperation::flipPattern(LinePattern& pattern, int flip) const
  190. {
  191. //todo: use cashing here and also in terrain patterns
  192. if(flip == 0)
  193. {
  194. return;
  195. }
  196. if(flip == FLIP_PATTERN_HORIZONTAL || flip == FLIP_PATTERN_BOTH)
  197. {
  198. for(int i = 0; i < 3; ++i)
  199. {
  200. int y = i * 3;
  201. std::swap(pattern.data[y], pattern.data[y + 2]);
  202. }
  203. }
  204. if(flip == FLIP_PATTERN_VERTICAL || flip == FLIP_PATTERN_BOTH)
  205. {
  206. for(int i = 0; i < 3; ++i)
  207. {
  208. std::swap(pattern.data[i], pattern.data[6 + i]);
  209. }
  210. }
  211. }
  212. void CDrawLinesOperation::updateTiles(std::set<int3> & invalidated)
  213. {
  214. for(const int3 & coord : invalidated)
  215. {
  216. TerrainTile & tile = map->getTile(coord);
  217. ValidationResult result(false);
  218. if(!needUpdateTile(tile))
  219. continue;
  220. int bestPattern = -1;
  221. for(int k = 0; k < patterns.size(); ++k)
  222. {
  223. result = validateTile(patterns[k], coord);
  224. if(result.result)
  225. {
  226. bestPattern = k;
  227. break;
  228. }
  229. }
  230. if(bestPattern != -1)
  231. {
  232. updateTile(tile, patterns[bestPattern], result.flip);
  233. }
  234. }
  235. }
  236. CDrawLinesOperation::ValidationResult CDrawLinesOperation::validateTile(const LinePattern & pattern, const int3 & pos)
  237. {
  238. ValidationResult result(false);
  239. if(!canApplyPattern(pattern))
  240. return result;
  241. for(int flip = 0; flip < 4; ++flip)
  242. {
  243. if((flip == FLIP_PATTERN_BOTH) && !(pattern.hasHFlip && pattern.hasVFlip))
  244. continue;
  245. if((flip == FLIP_PATTERN_HORIZONTAL) && !pattern.hasHFlip)
  246. continue;
  247. if((flip == FLIP_PATTERN_VERTICAL) && !(pattern.hasVFlip))
  248. continue;
  249. LinePattern flipped = pattern;
  250. flipPattern(flipped, flip);
  251. bool validated = true;
  252. for(int i = 0; i < 9; ++i)
  253. {
  254. if(4 == i)
  255. continue;
  256. int cx = pos.x + (i % 3) - 1;
  257. int cy = pos.y + (i / 3) - 1;
  258. int3 currentPos(cx, cy, pos.z);
  259. bool hasSomething = map->isInTheMap(currentPos) && tileHasSomething(currentPos);
  260. if(ruleIsSomething(flipped.data[i]))
  261. {
  262. if(!hasSomething)
  263. {
  264. validated = false;
  265. break;
  266. }
  267. }
  268. else if(ruleIsNone(flipped.data[i]))
  269. {
  270. if(hasSomething)
  271. {
  272. validated = false;
  273. break;
  274. }
  275. }
  276. else
  277. {
  278. assert(ruleIsAny(flipped.data[i]));
  279. }
  280. }
  281. if(validated)
  282. {
  283. result.result = true;
  284. result.flip = flip;
  285. return result;
  286. }
  287. }
  288. return result;
  289. }
  290. std::string CDrawRoadsOperation::getLabel() const
  291. {
  292. return "Draw Roads";
  293. }
  294. std::string CDrawRiversOperation::getLabel() const
  295. {
  296. return "Draw Rivers";
  297. }
  298. void CDrawRoadsOperation::executeTile(TerrainTile & tile)
  299. {
  300. tile.roadType = const_cast<RoadType*>(VLC->roadTypeHandler->getByIndex(roadType.getNum()));
  301. }
  302. void CDrawRiversOperation::executeTile(TerrainTile & tile)
  303. {
  304. tile.riverType = const_cast<RiverType*>(VLC->riverTypeHandler->getByIndex(riverType.getNum()));
  305. }
  306. bool CDrawRoadsOperation::canApplyPattern(const LinePattern & pattern) const
  307. {
  308. return pattern.roadMapping.first >= 0;
  309. }
  310. bool CDrawRiversOperation::canApplyPattern(const LinePattern & pattern) const
  311. {
  312. return pattern.riverMapping.first >= 0;
  313. }
  314. bool CDrawRoadsOperation::needUpdateTile(const TerrainTile & tile) const
  315. {
  316. return tile.roadType->getId() != Road::NO_ROAD;
  317. }
  318. bool CDrawRiversOperation::needUpdateTile(const TerrainTile & tile) const
  319. {
  320. return tile.riverType->getId() != River::NO_RIVER;
  321. }
  322. bool CDrawRoadsOperation::tileHasSomething(const int3& pos) const
  323. {
  324. return map->getTile(pos).roadType->getId() != Road::NO_ROAD;
  325. }
  326. bool CDrawRiversOperation::tileHasSomething(const int3& pos) const
  327. {
  328. return map->getTile(pos).riverType->getId() != River::NO_RIVER;
  329. }
  330. void CDrawRoadsOperation::updateTile(TerrainTile & tile, const LinePattern & pattern, const int flip)
  331. {
  332. const std::pair<int, int> & mapping = pattern.roadMapping;
  333. tile.roadDir = gen->nextInt(mapping.first, mapping.second);
  334. tile.extTileFlags = (tile.extTileFlags & 0b11001111) | (flip << 4);
  335. }
  336. void CDrawRiversOperation::updateTile(TerrainTile & tile, const LinePattern & pattern, const int flip)
  337. {
  338. const std::pair<int, int> & mapping = pattern.riverMapping;
  339. tile.riverDir = gen->nextInt(mapping.first, mapping.second);
  340. tile.extTileFlags = (tile.extTileFlags & 0b00111111) | (flip << 2);
  341. }
  342. VCMI_LIB_NAMESPACE_END