CDrawRoadsOperation.cpp 7.3 KB

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