production_service.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #include "production_service.h"
  2. #include "../core/component.h"
  3. #include "../core/world.h"
  4. #include "../game_config.h"
  5. #include "../systems/nation_registry.h"
  6. #include "../systems/troop_profile_service.h"
  7. #include "../units/troop_config.h"
  8. #include "core/entity.h"
  9. #include "units/spawn_type.h"
  10. #include "units/troop_type.h"
  11. #include <vector>
  12. namespace Game::Systems {
  13. static auto
  14. findFirstSelectedBarracks(Engine::Core::World &world,
  15. const std::vector<Engine::Core::EntityID> &selected,
  16. int owner_id) -> Engine::Core::Entity * {
  17. for (auto id : selected) {
  18. if (auto *e = world.get_entity(id)) {
  19. auto *u = e->get_component<Engine::Core::UnitComponent>();
  20. if ((u == nullptr) || u->owner_id != owner_id) {
  21. continue;
  22. }
  23. if (u->spawn_type == Game::Units::SpawnType::Barracks) {
  24. return e;
  25. }
  26. }
  27. }
  28. return nullptr;
  29. }
  30. namespace {
  31. auto resolve_nation_id(const Engine::Core::UnitComponent *unit,
  32. int owner_id) -> Game::Systems::NationID {
  33. auto &registry = NationRegistry::instance();
  34. if (const auto *nation = registry.get_nation_for_player(owner_id)) {
  35. return nation->id;
  36. }
  37. return registry.default_nation_id();
  38. }
  39. void apply_production_profile(Engine::Core::ProductionComponent *prod,
  40. Game::Systems::NationID nation_id,
  41. Game::Units::TroopType unit_type) {
  42. if (prod == nullptr) {
  43. return;
  44. }
  45. const auto profile =
  46. TroopProfileService::instance().get_profile(nation_id, unit_type);
  47. prod->build_time = profile.production.build_time;
  48. prod->villager_cost = profile.production.cost;
  49. }
  50. } // namespace
  51. auto ProductionService::start_production_for_first_selected_barracks(
  52. Engine::Core::World &world,
  53. const std::vector<Engine::Core::EntityID> &selected, int owner_id,
  54. Game::Units::TroopType unit_type) -> ProductionResult {
  55. auto *e = findFirstSelectedBarracks(world, selected, owner_id);
  56. if (e == nullptr) {
  57. return ProductionResult::NoBarracks;
  58. }
  59. auto *unit = e->get_component<Engine::Core::UnitComponent>();
  60. const auto nation_id = resolve_nation_id(unit, owner_id);
  61. const auto profile =
  62. TroopProfileService::instance().get_profile(nation_id, unit_type);
  63. auto *p = e->get_component<Engine::Core::ProductionComponent>();
  64. if (p == nullptr) {
  65. p = e->add_component<Engine::Core::ProductionComponent>();
  66. }
  67. if (p == nullptr) {
  68. return ProductionResult::NoBarracks;
  69. }
  70. int const individuals_per_unit = profile.individuals_per_unit;
  71. int const production_cost = profile.production.cost;
  72. if (p->produced_count + production_cost > p->max_units) {
  73. return ProductionResult::PerBarracksLimitReached;
  74. }
  75. int const current_troops =
  76. Engine::Core::World::count_troops_for_player(owner_id);
  77. int const max_troops =
  78. Game::GameConfig::instance().get_max_troops_per_player();
  79. if (current_troops + production_cost > max_troops) {
  80. return ProductionResult::GlobalTroopLimitReached;
  81. }
  82. const int max_queue_size = 5;
  83. int total_in_queue = p->in_progress ? 1 : 0;
  84. total_in_queue += static_cast<int>(p->production_queue.size());
  85. if (total_in_queue >= max_queue_size) {
  86. return ProductionResult::QueueFull;
  87. }
  88. if (p->in_progress) {
  89. p->production_queue.push_back(unit_type);
  90. } else {
  91. p->product_type = unit_type;
  92. apply_production_profile(p, nation_id, unit_type);
  93. p->time_remaining = p->build_time;
  94. p->in_progress = true;
  95. }
  96. return ProductionResult::Success;
  97. }
  98. auto ProductionService::set_rally_for_first_selected_barracks(
  99. Engine::Core::World &world,
  100. const std::vector<Engine::Core::EntityID> &selected, int owner_id, float x,
  101. float z) -> bool {
  102. auto *e = findFirstSelectedBarracks(world, selected, owner_id);
  103. if (e == nullptr) {
  104. return false;
  105. }
  106. auto *p = e->get_component<Engine::Core::ProductionComponent>();
  107. if (p == nullptr) {
  108. p = e->add_component<Engine::Core::ProductionComponent>();
  109. }
  110. if (p == nullptr) {
  111. return false;
  112. }
  113. p->rally_x = x;
  114. p->rally_z = z;
  115. p->rally_set = true;
  116. return true;
  117. }
  118. auto ProductionService::get_selected_barracks_state(
  119. Engine::Core::World &world,
  120. const std::vector<Engine::Core::EntityID> &selected, int owner_id,
  121. ProductionState &outState) -> bool {
  122. auto *e = findFirstSelectedBarracks(world, selected, owner_id);
  123. if (e == nullptr) {
  124. outState = {};
  125. return false;
  126. }
  127. outState.has_barracks = true;
  128. if (auto *unit = e->get_component<Engine::Core::UnitComponent>()) {
  129. outState.nation_id = resolve_nation_id(unit, owner_id);
  130. } else {
  131. outState.nation_id = NationRegistry::instance().default_nation_id();
  132. }
  133. if (auto *p = e->get_component<Engine::Core::ProductionComponent>()) {
  134. outState.in_progress = p->in_progress;
  135. outState.product_type = p->product_type;
  136. outState.time_remaining = p->time_remaining;
  137. outState.build_time = p->build_time;
  138. outState.produced_count = p->produced_count;
  139. outState.max_units = p->max_units;
  140. outState.villager_cost = p->villager_cost;
  141. outState.queue_size = static_cast<int>(p->production_queue.size());
  142. outState.production_queue = p->production_queue;
  143. }
  144. return true;
  145. }
  146. } // namespace Game::Systems