production_system.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #include "production_system.h"
  2. #include "../core/component.h"
  3. #include "../core/ownership_constants.h"
  4. #include "../core/world.h"
  5. #include "../game_config.h"
  6. #include "../map/map_transformer.h"
  7. #include "../units/factory.h"
  8. #include "../units/troop_config.h"
  9. #include "nation_registry.h"
  10. #include "troop_profile_service.h"
  11. #include "units/spawn_type.h"
  12. #include "units/unit.h"
  13. #include <cmath>
  14. #include <qvectornd.h>
  15. namespace Game::Systems {
  16. namespace {
  17. void apply_production_profile(Engine::Core::ProductionComponent *prod,
  18. const std::string &nation_id,
  19. Game::Units::TroopType troop_type) {
  20. if (prod == nullptr) {
  21. return;
  22. }
  23. const auto profile =
  24. TroopProfileService::instance().get_profile(nation_id, troop_type);
  25. prod->buildTime = profile.production.build_time;
  26. prod->villagerCost = profile.individuals_per_unit;
  27. }
  28. auto resolve_nation_id(const Engine::Core::UnitComponent *unit,
  29. int owner_id) -> std::string {
  30. if ((unit != nullptr) && !unit->nation_id.empty()) {
  31. return unit->nation_id;
  32. }
  33. auto &registry = NationRegistry::instance();
  34. if (const auto *nation = registry.getNationForPlayer(owner_id)) {
  35. return nation->id;
  36. }
  37. return registry.default_nation_id();
  38. }
  39. } // namespace
  40. void ProductionSystem::update(Engine::Core::World *world, float deltaTime) {
  41. if (world == nullptr) {
  42. return;
  43. }
  44. auto entities = world->getEntitiesWith<Engine::Core::ProductionComponent>();
  45. for (auto *e : entities) {
  46. auto *prod = e->getComponent<Engine::Core::ProductionComponent>();
  47. if (prod == nullptr) {
  48. continue;
  49. }
  50. auto *unit_comp = e->getComponent<Engine::Core::UnitComponent>();
  51. if ((unit_comp != nullptr) &&
  52. Game::Core::isNeutralOwner(unit_comp->owner_id)) {
  53. continue;
  54. }
  55. if (!prod->inProgress) {
  56. continue;
  57. }
  58. const int owner_id = (unit_comp != nullptr) ? unit_comp->owner_id : -1;
  59. const std::string nation_id = resolve_nation_id(unit_comp, owner_id);
  60. const auto current_profile = TroopProfileService::instance().get_profile(
  61. nation_id, prod->product_type);
  62. int const individuals_per_unit = current_profile.individuals_per_unit;
  63. if (prod->producedCount + individuals_per_unit > prod->maxUnits) {
  64. prod->inProgress = false;
  65. continue;
  66. }
  67. prod->timeRemaining -= deltaTime;
  68. if (prod->timeRemaining <= 0.0F) {
  69. auto *t = e->getComponent<Engine::Core::TransformComponent>();
  70. auto *u = e->getComponent<Engine::Core::UnitComponent>();
  71. if ((t != nullptr) && (u != nullptr)) {
  72. int const current_troops =
  73. Engine::Core::World::countTroopsForPlayer(u->owner_id);
  74. int const max_troops =
  75. Game::GameConfig::instance().getMaxTroopsPerPlayer();
  76. if (current_troops + individuals_per_unit > max_troops) {
  77. prod->inProgress = false;
  78. prod->timeRemaining = 0.0F;
  79. continue;
  80. }
  81. float const exit_offset = 2.5F + 0.2F * float(prod->producedCount % 5);
  82. float const exit_angle = 0.5F * float(prod->producedCount % 8);
  83. QVector3D const exit_pos =
  84. QVector3D(t->position.x + exit_offset * std::cos(exit_angle), 0.0F,
  85. t->position.z + exit_offset * std::sin(exit_angle));
  86. auto reg = Game::Map::MapTransformer::getFactoryRegistry();
  87. if (reg) {
  88. Game::Units::SpawnParams sp;
  89. sp.position = exit_pos;
  90. sp.player_id = u->owner_id;
  91. sp.spawn_type =
  92. Game::Units::spawn_typeFromTroopType(prod->product_type);
  93. sp.aiControlled =
  94. e->hasComponent<Engine::Core::AIControlledComponent>();
  95. sp.nation_id = nation_id;
  96. auto unit = reg->create(sp.spawn_type, *world, sp);
  97. if (unit && prod->rallySet) {
  98. unit->moveTo(prod->rallyX, prod->rallyZ);
  99. }
  100. }
  101. prod->producedCount += individuals_per_unit;
  102. }
  103. prod->inProgress = false;
  104. prod->timeRemaining = 0.0F;
  105. if (!prod->productionQueue.empty()) {
  106. prod->product_type = prod->productionQueue.front();
  107. prod->productionQueue.erase(prod->productionQueue.begin());
  108. apply_production_profile(prod, nation_id, prod->product_type);
  109. prod->timeRemaining = prod->buildTime;
  110. prod->inProgress = true;
  111. }
  112. }
  113. }
  114. }
  115. } // namespace Game::Systems