2
0

command_controller.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. #include "command_controller.h"
  2. #include "../../game/core/component.h"
  3. #include "../../game/core/entity.h"
  4. #include "../../game/core/world.h"
  5. #include "../../game/systems/command_service.h"
  6. #include "../../game/systems/picking_service.h"
  7. #include "../../game/systems/production_service.h"
  8. #include "../../game/systems/selection_system.h"
  9. #include "../../render/gl/camera.h"
  10. #include "../utils/movement_utils.h"
  11. #include "units/spawn_type.h"
  12. #include <QPointF>
  13. #include <qglobal.h>
  14. #include <qobject.h>
  15. #include <qtmetamacros.h>
  16. #include <qvectornd.h>
  17. namespace App::Controllers {
  18. CommandController::CommandController(
  19. Engine::Core::World *world,
  20. Game::Systems::SelectionSystem *selection_system,
  21. Game::Systems::PickingService *picking_service, QObject *parent)
  22. : QObject(parent), m_world(world), m_selection_system(selection_system),
  23. m_picking_service(picking_service) {}
  24. auto CommandController::on_attack_click(qreal sx, qreal sy, int viewport_width,
  25. int viewport_height,
  26. void *camera) -> CommandResult {
  27. CommandResult result;
  28. if ((m_selection_system == nullptr) || (m_picking_service == nullptr) ||
  29. (camera == nullptr) || (m_world == nullptr)) {
  30. result.reset_cursor_to_normal = true;
  31. return result;
  32. }
  33. const auto &selected = m_selection_system->get_selected_units();
  34. if (selected.empty()) {
  35. result.reset_cursor_to_normal = true;
  36. return result;
  37. }
  38. auto *cam = static_cast<Render::GL::Camera *>(camera);
  39. Engine::Core::EntityID const target_id =
  40. Game::Systems::PickingService::pick_unit_first(
  41. float(sx), float(sy), *m_world, *cam, viewport_width, viewport_height,
  42. 0);
  43. if (target_id == 0) {
  44. result.reset_cursor_to_normal = true;
  45. return result;
  46. }
  47. auto *target_entity = m_world->get_entity(target_id);
  48. if (target_entity == nullptr) {
  49. return result;
  50. }
  51. auto *target_unit =
  52. target_entity->get_component<Engine::Core::UnitComponent>();
  53. if (target_unit == nullptr) {
  54. return result;
  55. }
  56. Game::Systems::CommandService::attack_target(*m_world, selected, target_id,
  57. true);
  58. emit attack_target_selected();
  59. result.input_consumed = true;
  60. result.reset_cursor_to_normal = true;
  61. return result;
  62. }
  63. auto CommandController::on_stop_command() -> CommandResult {
  64. CommandResult result;
  65. if ((m_selection_system == nullptr) || (m_world == nullptr)) {
  66. return result;
  67. }
  68. const auto &selected = m_selection_system->get_selected_units();
  69. if (selected.empty()) {
  70. return result;
  71. }
  72. for (auto id : selected) {
  73. auto *entity = m_world->get_entity(id);
  74. if (entity == nullptr) {
  75. continue;
  76. }
  77. reset_movement(entity);
  78. entity->remove_component<Engine::Core::AttackTargetComponent>();
  79. if (auto *patrol = entity->get_component<Engine::Core::PatrolComponent>()) {
  80. patrol->patrolling = false;
  81. patrol->waypoints.clear();
  82. }
  83. auto *hold_mode = entity->get_component<Engine::Core::HoldModeComponent>();
  84. if ((hold_mode != nullptr) && hold_mode->active) {
  85. hold_mode->active = false;
  86. hold_mode->exit_cooldown = hold_mode->stand_up_duration;
  87. emit hold_mode_changed(false);
  88. }
  89. }
  90. result.input_consumed = true;
  91. result.reset_cursor_to_normal = true;
  92. return result;
  93. }
  94. auto CommandController::on_hold_command() -> CommandResult {
  95. CommandResult result;
  96. if ((m_selection_system == nullptr) || (m_world == nullptr)) {
  97. return result;
  98. }
  99. const auto &selected = m_selection_system->get_selected_units();
  100. if (selected.empty()) {
  101. return result;
  102. }
  103. int eligible_count = 0;
  104. int hold_active_count = 0;
  105. for (auto id : selected) {
  106. auto *entity = m_world->get_entity(id);
  107. if (entity == nullptr) {
  108. continue;
  109. }
  110. auto *unit = entity->get_component<Engine::Core::UnitComponent>();
  111. if (unit == nullptr) {
  112. continue;
  113. }
  114. if (unit->spawn_type == Game::Units::SpawnType::Barracks) {
  115. continue;
  116. }
  117. eligible_count++;
  118. auto *hold_mode = entity->get_component<Engine::Core::HoldModeComponent>();
  119. if ((hold_mode != nullptr) && hold_mode->active) {
  120. hold_active_count++;
  121. }
  122. }
  123. if (eligible_count == 0) {
  124. return result;
  125. }
  126. const bool should_enable_hold = (hold_active_count < eligible_count);
  127. for (auto id : selected) {
  128. auto *entity = m_world->get_entity(id);
  129. if (entity == nullptr) {
  130. continue;
  131. }
  132. auto *unit = entity->get_component<Engine::Core::UnitComponent>();
  133. if (unit == nullptr) {
  134. continue;
  135. }
  136. if (unit->spawn_type == Game::Units::SpawnType::Barracks) {
  137. continue;
  138. }
  139. auto *hold_mode = entity->get_component<Engine::Core::HoldModeComponent>();
  140. if (should_enable_hold) {
  141. reset_movement(entity);
  142. entity->remove_component<Engine::Core::AttackTargetComponent>();
  143. if (auto *patrol =
  144. entity->get_component<Engine::Core::PatrolComponent>()) {
  145. patrol->patrolling = false;
  146. patrol->waypoints.clear();
  147. }
  148. if (hold_mode == nullptr) {
  149. hold_mode = entity->add_component<Engine::Core::HoldModeComponent>();
  150. }
  151. hold_mode->active = true;
  152. hold_mode->exit_cooldown = 0.0F;
  153. auto *movement = entity->get_component<Engine::Core::MovementComponent>();
  154. if (movement != nullptr) {
  155. movement->has_target = false;
  156. movement->path.clear();
  157. movement->path_pending = false;
  158. movement->vx = 0.0F;
  159. movement->vz = 0.0F;
  160. }
  161. } else {
  162. if ((hold_mode != nullptr) && hold_mode->active) {
  163. hold_mode->active = false;
  164. hold_mode->exit_cooldown = hold_mode->stand_up_duration;
  165. }
  166. }
  167. }
  168. emit hold_mode_changed(should_enable_hold);
  169. result.input_consumed = true;
  170. result.reset_cursor_to_normal = true;
  171. return result;
  172. }
  173. auto CommandController::on_patrol_click(qreal sx, qreal sy, int viewport_width,
  174. int viewport_height,
  175. void *camera) -> CommandResult {
  176. CommandResult result;
  177. if ((m_selection_system == nullptr) || (m_world == nullptr) ||
  178. (m_picking_service == nullptr) || (camera == nullptr)) {
  179. if (m_has_patrol_first_waypoint) {
  180. clear_patrol_first_waypoint();
  181. result.reset_cursor_to_normal = true;
  182. }
  183. return result;
  184. }
  185. const auto &selected = m_selection_system->get_selected_units();
  186. if (selected.empty()) {
  187. if (m_has_patrol_first_waypoint) {
  188. clear_patrol_first_waypoint();
  189. result.reset_cursor_to_normal = true;
  190. }
  191. return result;
  192. }
  193. auto *cam = static_cast<Render::GL::Camera *>(camera);
  194. QVector3D hit;
  195. if (!Game::Systems::PickingService::screen_to_ground(
  196. QPointF(sx, sy), *cam, viewport_width, viewport_height, hit)) {
  197. if (m_has_patrol_first_waypoint) {
  198. clear_patrol_first_waypoint();
  199. result.reset_cursor_to_normal = true;
  200. }
  201. return result;
  202. }
  203. if (!m_has_patrol_first_waypoint) {
  204. m_has_patrol_first_waypoint = true;
  205. m_patrol_first_waypoint = hit;
  206. result.input_consumed = true;
  207. return result;
  208. }
  209. QVector3D const second_waypoint = hit;
  210. for (auto id : selected) {
  211. auto *entity = m_world->get_entity(id);
  212. if (entity == nullptr) {
  213. continue;
  214. }
  215. auto *building = entity->get_component<Engine::Core::BuildingComponent>();
  216. if (building != nullptr) {
  217. continue;
  218. }
  219. auto *patrol = entity->get_component<Engine::Core::PatrolComponent>();
  220. if (patrol == nullptr) {
  221. patrol = entity->add_component<Engine::Core::PatrolComponent>();
  222. }
  223. if (patrol != nullptr) {
  224. patrol->waypoints.clear();
  225. patrol->waypoints.emplace_back(m_patrol_first_waypoint.x(),
  226. m_patrol_first_waypoint.z());
  227. patrol->waypoints.emplace_back(second_waypoint.x(), second_waypoint.z());
  228. patrol->current_waypoint = 0;
  229. patrol->patrolling = true;
  230. }
  231. reset_movement(entity);
  232. entity->remove_component<Engine::Core::AttackTargetComponent>();
  233. }
  234. clear_patrol_first_waypoint();
  235. result.input_consumed = true;
  236. result.reset_cursor_to_normal = true;
  237. return result;
  238. }
  239. auto CommandController::set_rally_at_screen(
  240. qreal sx, qreal sy, int viewport_width, int viewport_height, void *camera,
  241. int local_owner_id) -> CommandResult {
  242. CommandResult result;
  243. if ((m_world == nullptr) || (m_selection_system == nullptr) ||
  244. (m_picking_service == nullptr) || (camera == nullptr)) {
  245. return result;
  246. }
  247. auto *cam = static_cast<Render::GL::Camera *>(camera);
  248. QVector3D hit;
  249. if (!Game::Systems::PickingService::screen_to_ground(
  250. QPointF(sx, sy), *cam, viewport_width, viewport_height, hit)) {
  251. return result;
  252. }
  253. Game::Systems::ProductionService::setRallyForFirstSelectedBarracks(
  254. *m_world, m_selection_system->get_selected_units(), local_owner_id,
  255. hit.x(), hit.z());
  256. result.input_consumed = true;
  257. return result;
  258. }
  259. void CommandController::recruit_near_selected(const QString &unit_type,
  260. int local_owner_id) {
  261. if ((m_world == nullptr) || (m_selection_system == nullptr)) {
  262. return;
  263. }
  264. const auto &sel = m_selection_system->get_selected_units();
  265. if (sel.empty()) {
  266. return;
  267. }
  268. auto result =
  269. Game::Systems::ProductionService::startProductionForFirstSelectedBarracks(
  270. *m_world, sel, local_owner_id, unit_type.toStdString());
  271. if (result == Game::Systems::ProductionResult::GlobalTroopLimitReached) {
  272. emit troop_limit_reached();
  273. }
  274. }
  275. void CommandController::reset_movement(Engine::Core::Entity *entity) {
  276. App::Utils::reset_movement(entity);
  277. }
  278. auto CommandController::any_selected_in_hold_mode() const -> bool {
  279. if ((m_selection_system == nullptr) || (m_world == nullptr)) {
  280. return false;
  281. }
  282. const auto &selected = m_selection_system->get_selected_units();
  283. for (Engine::Core::EntityID const entity_id : selected) {
  284. Engine::Core::Entity *entity = m_world->get_entity(entity_id);
  285. if (entity == nullptr) {
  286. continue;
  287. }
  288. auto *hold_mode = entity->get_component<Engine::Core::HoldModeComponent>();
  289. if ((hold_mode != nullptr) && hold_mode->active) {
  290. return true;
  291. }
  292. }
  293. return false;
  294. }
  295. auto CommandController::any_selected_in_guard_mode() const -> bool {
  296. if ((m_selection_system == nullptr) || (m_world == nullptr)) {
  297. return false;
  298. }
  299. const auto &selected = m_selection_system->get_selected_units();
  300. for (Engine::Core::EntityID const entity_id : selected) {
  301. Engine::Core::Entity *entity = m_world->get_entity(entity_id);
  302. if (entity == nullptr) {
  303. continue;
  304. }
  305. auto *guard_mode =
  306. entity->get_component<Engine::Core::GuardModeComponent>();
  307. if ((guard_mode != nullptr) && guard_mode->active) {
  308. return true;
  309. }
  310. }
  311. return false;
  312. }
  313. auto CommandController::on_guard_command() -> CommandResult {
  314. CommandResult result;
  315. if ((m_selection_system == nullptr) || (m_world == nullptr)) {
  316. return result;
  317. }
  318. const auto &selected = m_selection_system->get_selected_units();
  319. if (selected.empty()) {
  320. return result;
  321. }
  322. int eligible_count = 0;
  323. int guard_active_count = 0;
  324. for (auto id : selected) {
  325. auto *entity = m_world->get_entity(id);
  326. if (entity == nullptr) {
  327. continue;
  328. }
  329. auto *unit = entity->get_component<Engine::Core::UnitComponent>();
  330. if (unit == nullptr) {
  331. continue;
  332. }
  333. if (unit->spawn_type == Game::Units::SpawnType::Barracks) {
  334. continue;
  335. }
  336. eligible_count++;
  337. auto *guard_mode =
  338. entity->get_component<Engine::Core::GuardModeComponent>();
  339. if ((guard_mode != nullptr) && guard_mode->active) {
  340. guard_active_count++;
  341. }
  342. }
  343. if (eligible_count == 0) {
  344. return result;
  345. }
  346. const bool should_enable_guard = (guard_active_count < eligible_count);
  347. for (auto id : selected) {
  348. auto *entity = m_world->get_entity(id);
  349. if (entity == nullptr) {
  350. continue;
  351. }
  352. auto *unit = entity->get_component<Engine::Core::UnitComponent>();
  353. if (unit == nullptr) {
  354. continue;
  355. }
  356. if (unit->spawn_type == Game::Units::SpawnType::Barracks) {
  357. continue;
  358. }
  359. auto *guard_mode =
  360. entity->get_component<Engine::Core::GuardModeComponent>();
  361. if (should_enable_guard) {
  362. if (guard_mode == nullptr) {
  363. guard_mode = entity->add_component<Engine::Core::GuardModeComponent>();
  364. }
  365. guard_mode->active = true;
  366. guard_mode->returning_to_guard_position = false;
  367. auto *transform =
  368. entity->get_component<Engine::Core::TransformComponent>();
  369. if (transform != nullptr) {
  370. guard_mode->guard_position_x = transform->position.x;
  371. guard_mode->guard_position_z = transform->position.z;
  372. guard_mode->has_guard_target = true;
  373. guard_mode->guarded_entity_id = 0;
  374. }
  375. auto *hold_mode =
  376. entity->get_component<Engine::Core::HoldModeComponent>();
  377. if ((hold_mode != nullptr) && hold_mode->active) {
  378. hold_mode->active = false;
  379. }
  380. if (auto *patrol =
  381. entity->get_component<Engine::Core::PatrolComponent>()) {
  382. patrol->patrolling = false;
  383. patrol->waypoints.clear();
  384. }
  385. } else {
  386. if ((guard_mode != nullptr) && guard_mode->active) {
  387. guard_mode->active = false;
  388. guard_mode->guarded_entity_id = 0;
  389. guard_mode->guard_position_x = 0.0F;
  390. guard_mode->guard_position_z = 0.0F;
  391. guard_mode->returning_to_guard_position = false;
  392. guard_mode->has_guard_target = false;
  393. }
  394. }
  395. }
  396. emit guard_mode_changed(should_enable_guard);
  397. result.input_consumed = true;
  398. result.reset_cursor_to_normal = true;
  399. return result;
  400. }
  401. auto CommandController::on_guard_click(qreal sx, qreal sy, int viewport_width,
  402. int viewport_height,
  403. void *camera) -> CommandResult {
  404. CommandResult result;
  405. if ((m_selection_system == nullptr) || (m_picking_service == nullptr) ||
  406. (camera == nullptr) || (m_world == nullptr)) {
  407. result.reset_cursor_to_normal = true;
  408. return result;
  409. }
  410. const auto &selected = m_selection_system->get_selected_units();
  411. if (selected.empty()) {
  412. result.reset_cursor_to_normal = true;
  413. return result;
  414. }
  415. auto *cam = static_cast<Render::GL::Camera *>(camera);
  416. QVector3D hit;
  417. if (!Game::Systems::PickingService::screen_to_ground(
  418. QPointF(sx, sy), *cam, viewport_width, viewport_height, hit)) {
  419. result.reset_cursor_to_normal = true;
  420. return result;
  421. }
  422. for (auto id : selected) {
  423. auto *entity = m_world->get_entity(id);
  424. if (entity == nullptr) {
  425. continue;
  426. }
  427. auto *building = entity->get_component<Engine::Core::BuildingComponent>();
  428. if (building != nullptr) {
  429. continue;
  430. }
  431. auto *guard_mode =
  432. entity->get_component<Engine::Core::GuardModeComponent>();
  433. if (guard_mode == nullptr) {
  434. guard_mode = entity->add_component<Engine::Core::GuardModeComponent>();
  435. }
  436. guard_mode->active = true;
  437. guard_mode->guarded_entity_id = 0;
  438. guard_mode->guard_position_x = hit.x();
  439. guard_mode->guard_position_z = hit.z();
  440. guard_mode->returning_to_guard_position = false;
  441. guard_mode->has_guard_target = true;
  442. auto *hold_mode = entity->get_component<Engine::Core::HoldModeComponent>();
  443. if ((hold_mode != nullptr) && hold_mode->active) {
  444. hold_mode->active = false;
  445. }
  446. if (auto *patrol = entity->get_component<Engine::Core::PatrolComponent>()) {
  447. patrol->patrolling = false;
  448. patrol->waypoints.clear();
  449. }
  450. reset_movement(entity);
  451. entity->remove_component<Engine::Core::AttackTargetComponent>();
  452. }
  453. emit guard_mode_changed(true);
  454. result.input_consumed = true;
  455. result.reset_cursor_to_normal = true;
  456. return result;
  457. }
  458. } // namespace App::Controllers