CDrawRoadsOperation.cpp 7.2 KB

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