map_canvas.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. #include "map_canvas.h"
  2. #include <QInputDialog>
  3. #include <QMouseEvent>
  4. #include <QPainter>
  5. #include <QWheelEvent>
  6. #include <cmath>
  7. namespace MapEditor {
  8. MapCanvas::MapCanvas(QWidget *parent) : QWidget(parent) {
  9. setMouseTracking(true);
  10. setFocusPolicy(Qt::StrongFocus);
  11. setMinimumSize(400, 400);
  12. setAutoFillBackground(true);
  13. QPalette pal = palette();
  14. pal.setColor(QPalette::Window, QColor(40, 50, 60));
  15. setPalette(pal);
  16. }
  17. void MapCanvas::setMapData(MapData *data) {
  18. m_mapData = data;
  19. if (m_mapData) {
  20. connect(m_mapData, &MapData::dataChanged, this,
  21. qOverload<>(&QWidget::update));
  22. }
  23. update();
  24. }
  25. void MapCanvas::setCurrentTool(ToolType tool) {
  26. m_currentTool = tool;
  27. m_isPlacingLinear = false;
  28. update();
  29. }
  30. void MapCanvas::clearTool() {
  31. m_currentTool = ToolType::Select;
  32. m_isPlacingLinear = false;
  33. emit toolCleared();
  34. update();
  35. }
  36. QPointF MapCanvas::mapToGrid(const QPoint &widgetPos) const {
  37. float x = (widgetPos.x() - m_panOffset.x()) / (GRID_CELL_SIZE * m_zoom);
  38. float z = (widgetPos.y() - m_panOffset.y()) / (GRID_CELL_SIZE * m_zoom);
  39. return QPointF(x, z);
  40. }
  41. QPoint MapCanvas::gridToWidget(float gridX, float gridZ) const {
  42. float x =
  43. gridX * GRID_CELL_SIZE * m_zoom + static_cast<float>(m_panOffset.x());
  44. float y =
  45. gridZ * GRID_CELL_SIZE * m_zoom + static_cast<float>(m_panOffset.y());
  46. return QPoint(static_cast<int>(x), static_cast<int>(y));
  47. }
  48. void MapCanvas::paintEvent(QPaintEvent *) {
  49. QPainter painter(this);
  50. painter.setRenderHint(QPainter::Antialiasing);
  51. painter.fillRect(rect(), QColor(40, 50, 60));
  52. if (!m_mapData) {
  53. painter.setPen(Qt::white);
  54. painter.drawText(rect(), Qt::AlignCenter, "No map loaded");
  55. return;
  56. }
  57. drawGrid(painter);
  58. drawLinearElements(painter);
  59. drawTerrainElements(painter);
  60. drawFirecamps(painter);
  61. drawStructures(painter);
  62. drawCurrentPlacement(painter);
  63. }
  64. void MapCanvas::drawGrid(QPainter &painter) {
  65. if (!m_mapData) {
  66. return;
  67. }
  68. const GridSettings &grid = m_mapData->grid();
  69. float cellSize = GRID_CELL_SIZE * m_zoom;
  70. if (cellSize < 2) {
  71. return;
  72. }
  73. painter.setPen(QPen(QColor(60, 70, 80), 1));
  74. float startX = static_cast<float>(m_panOffset.x());
  75. float startY = static_cast<float>(m_panOffset.y());
  76. float endX = startX + grid.width * cellSize;
  77. float endY = startY + grid.height * cellSize;
  78. for (int i = 0; i <= grid.width; i += 10) {
  79. float x = startX + i * cellSize;
  80. if (x >= 0 && x <= width()) {
  81. painter.drawLine(
  82. QPointF(x, std::max(0.0F, startY)),
  83. QPointF(x, std::min(static_cast<float>(height()), endY)));
  84. }
  85. }
  86. for (int i = 0; i <= grid.height; i += 10) {
  87. float y = startY + i * cellSize;
  88. if (y >= 0 && y <= height()) {
  89. painter.drawLine(QPointF(std::max(0.0F, startX), y),
  90. QPointF(std::min(static_cast<float>(width()), endX), y));
  91. }
  92. }
  93. painter.setPen(QPen(QColor(100, 120, 140), 2));
  94. painter.drawRect(
  95. QRectF(startX, startY, grid.width * cellSize, grid.height * cellSize));
  96. QFont font = painter.font();
  97. font.setPointSize(9);
  98. painter.setFont(font);
  99. painter.setPen(QColor(180, 180, 180));
  100. painter.drawText(QPointF(startX + 2, startY + 12), "0,0");
  101. QString topRight = QString("%1,0").arg(grid.width);
  102. painter.drawText(QPointF(endX - 30, startY + 12), topRight);
  103. QString bottomLeft = QString("0,%1").arg(grid.height);
  104. painter.drawText(QPointF(startX + 2, endY - 4), bottomLeft);
  105. QString bottomRight = QString("%1,%2").arg(grid.width).arg(grid.height);
  106. painter.drawText(QPointF(endX - 40, endY - 4), bottomRight);
  107. }
  108. void MapCanvas::drawTerrainElements(QPainter &painter) {
  109. if (!m_mapData) {
  110. return;
  111. }
  112. const auto &terrain = m_mapData->terrainElements();
  113. for (int i = 0; i < terrain.size(); ++i) {
  114. const auto &elem = terrain[i];
  115. QPoint pos = gridToWidget(elem.x, elem.z);
  116. bool isSelected = (m_selectedType == 0 && m_selectedIndex == i);
  117. if (isSelected) {
  118. painter.setPen(QPen(Qt::yellow, 2));
  119. } else {
  120. painter.setPen(QPen(Qt::white, 1));
  121. }
  122. drawElement(painter, elem.type, pos);
  123. }
  124. }
  125. void MapCanvas::drawFirecamps(QPainter &painter) {
  126. if (!m_mapData) {
  127. return;
  128. }
  129. const auto &firecamps = m_mapData->firecamps();
  130. for (int i = 0; i < firecamps.size(); ++i) {
  131. const auto &elem = firecamps[i];
  132. QPoint pos = gridToWidget(elem.x, elem.z);
  133. bool isSelected = (m_selectedType == 1 && m_selectedIndex == i);
  134. if (isSelected) {
  135. painter.setPen(QPen(Qt::yellow, 2));
  136. } else {
  137. painter.setPen(QPen(Qt::white, 1));
  138. }
  139. drawElement(painter, "firecamp", pos);
  140. }
  141. }
  142. void MapCanvas::drawStructures(QPainter &painter) {
  143. if (!m_mapData) {
  144. return;
  145. }
  146. const auto &structures = m_mapData->structures();
  147. for (int i = 0; i < structures.size(); ++i) {
  148. const auto &elem = structures[i];
  149. QPoint pos = gridToWidget(elem.x, elem.z);
  150. bool isSelected = (m_selectedType == 3 && m_selectedIndex == i);
  151. if (isSelected) {
  152. painter.setPen(QPen(Qt::yellow, 2));
  153. } else {
  154. painter.setPen(QPen(Qt::white, 1));
  155. }
  156. drawElement(painter, elem.type, pos, elem.playerId);
  157. }
  158. }
  159. void MapCanvas::drawLinearElements(QPainter &painter) {
  160. if (!m_mapData) {
  161. return;
  162. }
  163. const auto &linear = m_mapData->linearElements();
  164. for (int i = 0; i < linear.size(); ++i) {
  165. const auto &elem = linear[i];
  166. QPoint startPos = gridToWidget(elem.start.x(), elem.start.y());
  167. QPoint endPos = gridToWidget(elem.end.x(), elem.end.y());
  168. bool isSelected = (m_selectedType == 2 && m_selectedIndex == i);
  169. QColor color;
  170. int lineWidth = static_cast<int>(elem.width * m_zoom);
  171. lineWidth = std::max(2, std::min(lineWidth, 20));
  172. if (elem.type == "river") {
  173. color = QColor(70, 130, 200);
  174. } else if (elem.type == "road") {
  175. color = QColor(139, 119, 101);
  176. } else if (elem.type == "bridge") {
  177. color = QColor(160, 140, 100);
  178. }
  179. if (isSelected) {
  180. painter.setPen(QPen(Qt::yellow, lineWidth + 2));
  181. painter.drawLine(startPos, endPos);
  182. }
  183. painter.setPen(QPen(color, lineWidth));
  184. painter.drawLine(startPos, endPos);
  185. int endpointSize = 6;
  186. painter.setBrush(color.lighter());
  187. painter.setPen(Qt::white);
  188. painter.drawEllipse(startPos, endpointSize, endpointSize);
  189. painter.drawEllipse(endPos, endpointSize, endpointSize);
  190. }
  191. if (m_isPlacingLinear) {
  192. QPoint startPos = gridToWidget(static_cast<float>(m_linearStart.x()),
  193. static_cast<float>(m_linearStart.y()));
  194. QPointF currentGrid = mapToGrid(m_lastMousePos);
  195. QPoint endPos = gridToWidget(static_cast<float>(currentGrid.x()),
  196. static_cast<float>(currentGrid.y()));
  197. QPen pen(Qt::white, 2, Qt::DashLine);
  198. painter.setPen(pen);
  199. painter.drawLine(startPos, endPos);
  200. }
  201. }
  202. void MapCanvas::drawCurrentPlacement(QPainter &painter) {
  203. if (m_currentTool == ToolType::Select || m_currentTool == ToolType::Eraser) {
  204. return;
  205. }
  206. QPointF gridPos = mapToGrid(m_lastMousePos);
  207. QPoint widgetPos = gridToWidget(static_cast<float>(gridPos.x()),
  208. static_cast<float>(gridPos.y()));
  209. painter.setOpacity(0.5);
  210. painter.setPen(QPen(Qt::white, 1, Qt::DashLine));
  211. QString type;
  212. switch (m_currentTool) {
  213. case ToolType::Hill:
  214. type = "hill";
  215. break;
  216. case ToolType::Mountain:
  217. type = "mountain";
  218. break;
  219. case ToolType::Firecamp:
  220. type = "firecamp";
  221. break;
  222. case ToolType::Barracks:
  223. type = "barracks";
  224. break;
  225. case ToolType::Village:
  226. type = "village";
  227. break;
  228. default:
  229. break;
  230. }
  231. if (!type.isEmpty()) {
  232. drawElement(painter, type, widgetPos);
  233. }
  234. painter.setOpacity(1.0);
  235. }
  236. void MapCanvas::drawElement(QPainter &painter, const QString &type,
  237. const QPoint &pos, int playerId) {
  238. int size = ICON_SIZE;
  239. QColor fillColor;
  240. QString symbol;
  241. if (type == "hill") {
  242. fillColor = QColor(139, 137, 112);
  243. symbol = "⛰";
  244. } else if (type == "mountain") {
  245. fillColor = QColor(105, 105, 105);
  246. symbol = "🏔";
  247. } else if (type == "firecamp") {
  248. fillColor = QColor(255, 140, 0);
  249. symbol = "🔥";
  250. } else if (type == "barracks") {
  251. if (playerId == 0) {
  252. fillColor = QColor(180, 180, 180);
  253. } else if (playerId == 1) {
  254. fillColor = QColor(100, 150, 255);
  255. } else if (playerId == 2) {
  256. fillColor = QColor(255, 100, 100);
  257. } else {
  258. fillColor = QColor(100, 255, 100);
  259. }
  260. symbol = "🏛";
  261. } else if (type == "village") {
  262. if (playerId == 0) {
  263. fillColor = QColor(180, 180, 180);
  264. } else if (playerId == 1) {
  265. fillColor = QColor(100, 150, 255);
  266. } else if (playerId == 2) {
  267. fillColor = QColor(255, 100, 100);
  268. } else {
  269. fillColor = QColor(100, 255, 100);
  270. }
  271. symbol = "🏘";
  272. } else {
  273. fillColor = QColor(128, 128, 128);
  274. symbol = "?";
  275. }
  276. painter.setBrush(fillColor);
  277. painter.drawEllipse(pos, size, size);
  278. QFont font = painter.font();
  279. font.setPointSize(12);
  280. painter.setFont(font);
  281. painter.setPen(Qt::white);
  282. painter.drawText(QRect(pos.x() - size, pos.y() - size, size * 2, size * 2),
  283. Qt::AlignCenter, symbol);
  284. if ((type == "barracks" || type == "village") && playerId >= 0) {
  285. QString playerText = playerId == 0 ? "N" : QString::number(playerId);
  286. font.setPointSize(8);
  287. font.setBold(true);
  288. painter.setFont(font);
  289. painter.setPen(Qt::black);
  290. painter.drawText(pos.x() + size - 6, pos.y() - size + 10, playerText);
  291. }
  292. }
  293. void MapCanvas::mousePressEvent(QMouseEvent *event) {
  294. m_lastMousePos = event->pos();
  295. if (event->button() == Qt::RightButton) {
  296. clearTool();
  297. return;
  298. }
  299. if (event->button() == Qt::MiddleButton ||
  300. (event->button() == Qt::LeftButton &&
  301. event->modifiers() & Qt::ControlModifier)) {
  302. m_isPanning = true;
  303. setCursor(Qt::ClosedHandCursor);
  304. return;
  305. }
  306. if (event->button() == Qt::LeftButton && m_mapData) {
  307. QPointF gridPos = mapToGrid(event->pos());
  308. switch (m_currentTool) {
  309. case ToolType::Select: {
  310. HitResult hit = hitTest(event->pos());
  311. m_selectedType = hit.elementType;
  312. m_selectedIndex = hit.index;
  313. m_draggedEndpoint = hit.endpoint;
  314. if (hit.elementType >= 0) {
  315. m_isDragging = true;
  316. }
  317. update();
  318. break;
  319. }
  320. case ToolType::Hill:
  321. case ToolType::Mountain:
  322. case ToolType::Firecamp:
  323. case ToolType::Barracks:
  324. case ToolType::Village:
  325. placeElement(gridPos);
  326. break;
  327. case ToolType::River:
  328. case ToolType::Road:
  329. case ToolType::Bridge:
  330. if (!m_isPlacingLinear) {
  331. startLinearElement(gridPos);
  332. } else {
  333. finishLinearElement(gridPos);
  334. }
  335. break;
  336. case ToolType::Eraser:
  337. eraseAtPosition(gridPos);
  338. break;
  339. }
  340. }
  341. }
  342. void MapCanvas::mouseReleaseEvent(QMouseEvent *event) {
  343. if (event->button() == Qt::MiddleButton ||
  344. (event->button() == Qt::LeftButton && m_isPanning)) {
  345. m_isPanning = false;
  346. setCursor(Qt::ArrowCursor);
  347. }
  348. m_isDragging = false;
  349. m_draggedEndpoint = -1;
  350. }
  351. void MapCanvas::mouseMoveEvent(QMouseEvent *event) {
  352. QPoint delta = event->pos() - m_lastMousePos;
  353. m_lastMousePos = event->pos();
  354. if (m_isPanning) {
  355. m_panOffset += QPointF(delta.x(), delta.y());
  356. update();
  357. return;
  358. }
  359. if (m_isDragging && m_mapData && m_selectedType >= 0 &&
  360. m_selectedIndex >= 0) {
  361. QPointF gridPos = mapToGrid(event->pos());
  362. if (m_selectedType == 0) {
  363. auto terrain = m_mapData->terrainElements();
  364. if (m_selectedIndex < terrain.size()) {
  365. TerrainElement elem = terrain[m_selectedIndex];
  366. elem.x = static_cast<float>(gridPos.x());
  367. elem.z = static_cast<float>(gridPos.y());
  368. m_mapData->updateTerrainElement(m_selectedIndex, elem);
  369. }
  370. } else if (m_selectedType == 1) {
  371. auto firecamps = m_mapData->firecamps();
  372. if (m_selectedIndex < firecamps.size()) {
  373. FirecampElement elem = firecamps[m_selectedIndex];
  374. elem.x = static_cast<float>(gridPos.x());
  375. elem.z = static_cast<float>(gridPos.y());
  376. m_mapData->updateFirecamp(m_selectedIndex, elem);
  377. }
  378. } else if (m_selectedType == 2) {
  379. auto linear = m_mapData->linearElements();
  380. if (m_selectedIndex < linear.size() && m_draggedEndpoint >= 0) {
  381. LinearElement elem = linear[m_selectedIndex];
  382. QVector2D newPos(static_cast<float>(gridPos.x()),
  383. static_cast<float>(gridPos.y()));
  384. if (m_draggedEndpoint == 0) {
  385. elem.start = newPos;
  386. } else if (m_draggedEndpoint == 1) {
  387. elem.end = newPos;
  388. }
  389. m_mapData->updateLinearElement(m_selectedIndex, elem);
  390. }
  391. } else if (m_selectedType == 3) {
  392. auto structures = m_mapData->structures();
  393. if (m_selectedIndex < structures.size()) {
  394. StructureElement elem = structures[m_selectedIndex];
  395. elem.x = static_cast<float>(gridPos.x());
  396. elem.z = static_cast<float>(gridPos.y());
  397. m_mapData->updateStructure(m_selectedIndex, elem);
  398. }
  399. }
  400. }
  401. if (m_currentTool != ToolType::Select) {
  402. update();
  403. }
  404. }
  405. void MapCanvas::mouseDoubleClickEvent(QMouseEvent *event) {
  406. if (event->button() == Qt::LeftButton) {
  407. HitResult hit = hitTest(event->pos());
  408. if (hit.elementType >= 0 && hit.index >= 0) {
  409. emit elementDoubleClicked(hit.elementType, hit.index);
  410. } else {
  411. emit gridDoubleClicked();
  412. }
  413. }
  414. }
  415. void MapCanvas::wheelEvent(QWheelEvent *event) {
  416. float oldZoom = m_zoom;
  417. if (event->angleDelta().y() > 0) {
  418. m_zoom *= 1.1F;
  419. } else {
  420. m_zoom /= 1.1F;
  421. }
  422. m_zoom = std::clamp(m_zoom, 0.1F, 5.0F);
  423. #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
  424. QPointF cursorPos = event->position();
  425. #else
  426. QPointF cursorPos = event->posF();
  427. #endif
  428. m_panOffset = cursorPos - (cursorPos - m_panOffset) * (m_zoom / oldZoom);
  429. update();
  430. }
  431. void MapCanvas::resizeEvent(QResizeEvent *) {
  432. if (m_panOffset.isNull() && m_mapData) {
  433. m_panOffset = QPointF(50, 50);
  434. }
  435. }
  436. MapCanvas::HitResult MapCanvas::hitTest(const QPoint &pos) const {
  437. HitResult result;
  438. if (!m_mapData) {
  439. return result;
  440. }
  441. QPointF gridPos = mapToGrid(pos);
  442. const auto &structures = m_mapData->structures();
  443. for (int i = 0; i < structures.size(); ++i) {
  444. const auto &elem = structures[i];
  445. float dx = static_cast<float>(gridPos.x()) - elem.x;
  446. float dz = static_cast<float>(gridPos.y()) - elem.z;
  447. float dist = std::sqrt(dx * dx + dz * dz);
  448. if (dist <= HIT_RADIUS) {
  449. result.elementType = 3;
  450. result.index = i;
  451. return result;
  452. }
  453. }
  454. const auto &terrain = m_mapData->terrainElements();
  455. for (int i = 0; i < terrain.size(); ++i) {
  456. const auto &elem = terrain[i];
  457. float dx = static_cast<float>(gridPos.x()) - elem.x;
  458. float dz = static_cast<float>(gridPos.y()) - elem.z;
  459. float dist = std::sqrt(dx * dx + dz * dz);
  460. if (dist <= HIT_RADIUS) {
  461. result.elementType = 0;
  462. result.index = i;
  463. return result;
  464. }
  465. }
  466. const auto &firecamps = m_mapData->firecamps();
  467. for (int i = 0; i < firecamps.size(); ++i) {
  468. const auto &elem = firecamps[i];
  469. float dx = static_cast<float>(gridPos.x()) - elem.x;
  470. float dz = static_cast<float>(gridPos.y()) - elem.z;
  471. float dist = std::sqrt(dx * dx + dz * dz);
  472. if (dist <= HIT_RADIUS) {
  473. result.elementType = 1;
  474. result.index = i;
  475. return result;
  476. }
  477. }
  478. const auto &linear = m_mapData->linearElements();
  479. for (int i = 0; i < linear.size(); ++i) {
  480. const auto &elem = linear[i];
  481. QVector2D p(static_cast<float>(gridPos.x()),
  482. static_cast<float>(gridPos.y()));
  483. float startDist = (p - elem.start).length();
  484. if (startDist <= ENDPOINT_HIT_RADIUS) {
  485. result.elementType = 2;
  486. result.index = i;
  487. result.endpoint = 0;
  488. return result;
  489. }
  490. float endDist = (p - elem.end).length();
  491. if (endDist <= ENDPOINT_HIT_RADIUS) {
  492. result.elementType = 2;
  493. result.index = i;
  494. result.endpoint = 1;
  495. return result;
  496. }
  497. }
  498. for (int i = 0; i < linear.size(); ++i) {
  499. const auto &elem = linear[i];
  500. QVector2D p(static_cast<float>(gridPos.x()),
  501. static_cast<float>(gridPos.y()));
  502. QVector2D a = elem.start;
  503. QVector2D b = elem.end;
  504. QVector2D ab = b - a;
  505. float abLengthSq = QVector2D::dotProduct(ab, ab);
  506. float dist;
  507. if (abLengthSq < 0.0001F) {
  508. dist = (p - a).length();
  509. } else {
  510. float t =
  511. std::clamp(QVector2D::dotProduct(p - a, ab) / abLengthSq, 0.0F, 1.0F);
  512. QVector2D closest = a + t * ab;
  513. dist = (p - closest).length();
  514. }
  515. if (dist <= elem.width + 2.0F) {
  516. result.elementType = 2;
  517. result.index = i;
  518. result.endpoint = -1;
  519. return result;
  520. }
  521. }
  522. return result;
  523. }
  524. void MapCanvas::placeElement(const QPointF &gridPos) {
  525. if (!m_mapData) {
  526. return;
  527. }
  528. if (m_currentTool == ToolType::Hill || m_currentTool == ToolType::Mountain) {
  529. TerrainElement elem;
  530. elem.type = (m_currentTool == ToolType::Hill) ? "hill" : "mountain";
  531. elem.x = static_cast<float>(gridPos.x());
  532. elem.z = static_cast<float>(gridPos.y());
  533. elem.radius = 10.0F;
  534. elem.height = (m_currentTool == ToolType::Hill) ? 3.0F : 8.0F;
  535. m_mapData->addTerrainElement(elem);
  536. } else if (m_currentTool == ToolType::Firecamp) {
  537. FirecampElement elem;
  538. elem.x = static_cast<float>(gridPos.x());
  539. elem.z = static_cast<float>(gridPos.y());
  540. elem.intensity = 1.0F;
  541. elem.radius = 3.0F;
  542. m_mapData->addFirecamp(elem);
  543. } else if (m_currentTool == ToolType::Barracks ||
  544. m_currentTool == ToolType::Village) {
  545. bool ok;
  546. int playerId = QInputDialog::getInt(
  547. this, "Assign Team",
  548. QString("Enter player ID (%1 = neutral, %2-%3 = players):")
  549. .arg(MIN_PLAYER_ID)
  550. .arg(MIN_PLAYER_ID + 1)
  551. .arg(MAX_PLAYER_ID),
  552. m_currentPlayerId, MIN_PLAYER_ID, MAX_PLAYER_ID, 1, &ok);
  553. if (ok) {
  554. m_currentPlayerId = playerId;
  555. StructureElement elem;
  556. elem.type =
  557. (m_currentTool == ToolType::Barracks) ? "barracks" : "village";
  558. elem.x = static_cast<float>(gridPos.x());
  559. elem.z = static_cast<float>(gridPos.y());
  560. elem.playerId = playerId;
  561. elem.maxPopulation = DEFAULT_MAX_POPULATION;
  562. elem.nation = DEFAULT_NATION;
  563. m_mapData->addStructure(elem);
  564. }
  565. }
  566. }
  567. void MapCanvas::startLinearElement(const QPointF &gridPos) {
  568. m_isPlacingLinear = true;
  569. m_linearStart = gridPos;
  570. }
  571. void MapCanvas::finishLinearElement(const QPointF &gridPos) {
  572. if (!m_mapData) {
  573. return;
  574. }
  575. LinearElement elem;
  576. elem.start = QVector2D(static_cast<float>(m_linearStart.x()),
  577. static_cast<float>(m_linearStart.y()));
  578. elem.end = QVector2D(static_cast<float>(gridPos.x()),
  579. static_cast<float>(gridPos.y()));
  580. switch (m_currentTool) {
  581. case ToolType::River:
  582. elem.type = "river";
  583. elem.width = 3.0F;
  584. break;
  585. case ToolType::Road:
  586. elem.type = "road";
  587. elem.width = 3.0F;
  588. elem.style = "default";
  589. break;
  590. case ToolType::Bridge:
  591. elem.type = "bridge";
  592. elem.width = 4.0F;
  593. elem.height = 0.5F;
  594. break;
  595. default:
  596. break;
  597. }
  598. m_mapData->addLinearElement(elem);
  599. m_isPlacingLinear = false;
  600. }
  601. void MapCanvas::eraseAtPosition(const QPointF &gridPos) {
  602. if (!m_mapData) {
  603. return;
  604. }
  605. HitResult hit = hitTest(gridToWidget(static_cast<float>(gridPos.x()),
  606. static_cast<float>(gridPos.y())));
  607. if (hit.elementType == 0) {
  608. m_mapData->removeTerrainElement(hit.index);
  609. } else if (hit.elementType == 1) {
  610. m_mapData->removeFirecamp(hit.index);
  611. } else if (hit.elementType == 2) {
  612. m_mapData->removeLinearElement(hit.index);
  613. } else if (hit.elementType == 3) {
  614. m_mapData->removeStructure(hit.index);
  615. }
  616. }
  617. } // namespace MapEditor