gather_behavior.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #include "gather_behavior.h"
  2. #include "../../formation_system.h"
  3. #include "../../nation_registry.h"
  4. #include "../ai_utils.h"
  5. #include "systems/ai_system/ai_types.h"
  6. #include <QVector3D>
  7. #include <algorithm>
  8. #include <cstddef>
  9. #include <qvectornd.h>
  10. #include <utility>
  11. #include <vector>
  12. namespace Game::Systems::AI {
  13. void GatherBehavior::execute(const AISnapshot &snapshot, AIContext &context,
  14. float delta_time,
  15. std::vector<AICommand> &outCommands) {
  16. m_gatherTimer += delta_time;
  17. if (m_gatherTimer < 1.0F) {
  18. return;
  19. }
  20. m_gatherTimer = 0.0F;
  21. if (context.primaryBarracks == 0) {
  22. return;
  23. }
  24. QVector3D const rally_point(context.rally_x, 0.0F, context.rally_z);
  25. std::vector<const EntitySnapshot *> units_to_gather;
  26. units_to_gather.reserve(snapshot.friendlies.size());
  27. for (const auto &entity : snapshot.friendlies) {
  28. if (entity.is_building) {
  29. continue;
  30. }
  31. if (isEntityEngaged(entity, snapshot.visibleEnemies)) {
  32. continue;
  33. }
  34. const float dx = entity.posX - rally_point.x();
  35. const float dz = entity.posZ - rally_point.z();
  36. const float dist_sq = dx * dx + dz * dz;
  37. if (dist_sq > 2.0F * 2.0F) {
  38. units_to_gather.push_back(&entity);
  39. }
  40. }
  41. if (units_to_gather.empty()) {
  42. return;
  43. }
  44. const Nation *nation =
  45. NationRegistry::instance().get_nation_for_player(context.player_id);
  46. FormationType formation_type = FormationType::Roman;
  47. if (nation != nullptr) {
  48. formation_type = nation->formation_type;
  49. }
  50. auto formation_targets = FormationSystem::instance().get_formation_positions(
  51. formation_type, static_cast<int>(units_to_gather.size()), rally_point,
  52. 1.4F);
  53. std::vector<Engine::Core::EntityID> units_to_move;
  54. std::vector<float> target_x;
  55. std::vector<float> target_y;
  56. std::vector<float> target_z;
  57. units_to_move.reserve(units_to_gather.size());
  58. target_x.reserve(units_to_gather.size());
  59. target_y.reserve(units_to_gather.size());
  60. target_z.reserve(units_to_gather.size());
  61. for (size_t i = 0; i < units_to_gather.size(); ++i) {
  62. const auto *entity = units_to_gather[i];
  63. const auto &target = formation_targets[i];
  64. units_to_move.push_back(entity->id);
  65. target_x.push_back(target.x());
  66. target_y.push_back(target.y());
  67. target_z.push_back(target.z());
  68. }
  69. if (units_to_move.empty()) {
  70. return;
  71. }
  72. auto claimed_units = claimUnits(units_to_move, getPriority(), "gathering",
  73. context, m_gatherTimer + delta_time, 2.0F);
  74. if (claimed_units.empty()) {
  75. return;
  76. }
  77. std::vector<float> filtered_x;
  78. std::vector<float> filtered_y;
  79. std::vector<float> filtered_z;
  80. for (size_t i = 0; i < units_to_move.size(); ++i) {
  81. if (std::find(claimed_units.begin(), claimed_units.end(),
  82. units_to_move[i]) != claimed_units.end()) {
  83. filtered_x.push_back(target_x[i]);
  84. filtered_y.push_back(target_y[i]);
  85. filtered_z.push_back(target_z[i]);
  86. }
  87. }
  88. AICommand command;
  89. command.type = AICommandType::MoveUnits;
  90. command.units = std::move(claimed_units);
  91. command.moveTargetX = std::move(filtered_x);
  92. command.moveTargetY = std::move(filtered_y);
  93. command.moveTargetZ = std::move(filtered_z);
  94. outCommands.push_back(std::move(command));
  95. }
  96. auto GatherBehavior::should_execute(const AISnapshot &snapshot,
  97. const AIContext &context) const -> bool {
  98. if (context.primaryBarracks == 0) {
  99. return false;
  100. }
  101. if (context.state == AIState::Retreating) {
  102. return false;
  103. }
  104. if (context.state == AIState::Attacking) {
  105. return false;
  106. }
  107. if (context.state == AIState::Defending) {
  108. QVector3D const rally_point(context.rally_x, 0.0F, context.rally_z);
  109. for (const auto &entity : snapshot.friendlies) {
  110. if (entity.is_building) {
  111. continue;
  112. }
  113. const float dx = entity.posX - rally_point.x();
  114. const float dz = entity.posZ - rally_point.z();
  115. const float dist_sq = dx * dx + dz * dz;
  116. if (dist_sq > 10.0F * 10.0F) {
  117. return true;
  118. }
  119. }
  120. return false;
  121. }
  122. if (context.state == AIState::Gathering || context.state == AIState::Idle) {
  123. return true;
  124. }
  125. return false;
  126. }
  127. } // namespace Game::Systems::AI