map_transformer.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. #include "map_transformer.h"
  2. #include "../core/component.h"
  3. #include "../core/ownership_constants.h"
  4. #include "../core/world.h"
  5. #include "../systems/owner_registry.h"
  6. #include "../units/factory.h"
  7. #include "../visuals/team_colors.h"
  8. #include "terrain_service.h"
  9. #include <QDebug>
  10. #include <QVector3D>
  11. #include <set>
  12. #include <unordered_map>
  13. namespace Game::Map {
  14. namespace {
  15. std::shared_ptr<Game::Units::UnitFactoryRegistry> s_registry;
  16. std::unordered_map<int, int> s_playerTeamOverrides;
  17. } // namespace
  18. void MapTransformer::setFactoryRegistry(
  19. std::shared_ptr<Game::Units::UnitFactoryRegistry> reg) {
  20. s_registry = std::move(reg);
  21. }
  22. std::shared_ptr<Game::Units::UnitFactoryRegistry>
  23. MapTransformer::getFactoryRegistry() {
  24. return s_registry;
  25. }
  26. void MapTransformer::setLocalOwnerId(int ownerId) {
  27. auto &owners = Game::Systems::OwnerRegistry::instance();
  28. owners.setLocalPlayerId(ownerId);
  29. }
  30. int MapTransformer::localOwnerId() {
  31. auto &owners = Game::Systems::OwnerRegistry::instance();
  32. return owners.getLocalPlayerId();
  33. }
  34. void MapTransformer::setPlayerTeamOverrides(
  35. const std::unordered_map<int, int> &overrides) {
  36. s_playerTeamOverrides = overrides;
  37. }
  38. void MapTransformer::clearPlayerTeamOverrides() {
  39. s_playerTeamOverrides.clear();
  40. }
  41. MapRuntime
  42. MapTransformer::applyToWorld(const MapDefinition &def,
  43. Engine::Core::World &world,
  44. const Game::Visuals::VisualCatalog *visuals) {
  45. MapRuntime rt;
  46. rt.unitIds.reserve(def.spawns.size());
  47. auto &ownerRegistry = Game::Systems::OwnerRegistry::instance();
  48. std::set<int> uniquePlayerIds;
  49. std::unordered_map<int, int> playerIdToTeam;
  50. for (const auto &spawn : def.spawns) {
  51. if (spawn.playerId == Game::Core::NEUTRAL_OWNER_ID) {
  52. continue;
  53. }
  54. uniquePlayerIds.insert(spawn.playerId);
  55. if (spawn.teamId > 0) {
  56. playerIdToTeam[spawn.playerId] = spawn.teamId;
  57. }
  58. }
  59. for (int playerId : uniquePlayerIds) {
  60. if (ownerRegistry.getOwnerType(playerId) ==
  61. Game::Systems::OwnerType::Neutral) {
  62. bool isLocalPlayer = (playerId == ownerRegistry.getLocalPlayerId());
  63. Game::Systems::OwnerType ownerType =
  64. isLocalPlayer ? Game::Systems::OwnerType::Player
  65. : Game::Systems::OwnerType::AI;
  66. std::string ownerName = isLocalPlayer
  67. ? "Player " + std::to_string(playerId)
  68. : "AI Player " + std::to_string(playerId);
  69. ownerRegistry.registerOwnerWithId(playerId, ownerType, ownerName);
  70. }
  71. int finalTeamId = 0;
  72. auto overrideIt = s_playerTeamOverrides.find(playerId);
  73. if (overrideIt != s_playerTeamOverrides.end()) {
  74. finalTeamId = overrideIt->second;
  75. } else {
  76. auto teamIt = playerIdToTeam.find(playerId);
  77. if (teamIt != playerIdToTeam.end()) {
  78. finalTeamId = teamIt->second;
  79. } else {
  80. }
  81. }
  82. ownerRegistry.setOwnerTeam(playerId, finalTeamId);
  83. }
  84. for (const auto &s : def.spawns) {
  85. float worldX = s.x;
  86. float worldZ = s.z;
  87. if (def.coordSystem == CoordSystem::Grid) {
  88. const float tile = std::max(0.0001f, def.grid.tileSize);
  89. worldX = (s.x - (def.grid.width * 0.5f - 0.5f)) * tile;
  90. worldZ = (s.z - (def.grid.height * 0.5f - 0.5f)) * tile;
  91. }
  92. auto &terrain = Game::Map::TerrainService::instance();
  93. if (terrain.isInitialized() && terrain.isForbiddenWorld(worldX, worldZ)) {
  94. const float tile = std::max(0.0001f, def.grid.tileSize);
  95. bool found = false;
  96. const int maxRadius = 12;
  97. for (int r = 1; r <= maxRadius && !found; ++r) {
  98. for (int ox = -r; ox <= r && !found; ++ox) {
  99. for (int oz = -r; oz <= r && !found; ++oz) {
  100. if (std::abs(ox) != r && std::abs(oz) != r)
  101. continue;
  102. float candX = worldX + float(ox) * tile;
  103. float candZ = worldZ + float(oz) * tile;
  104. if (!terrain.isForbiddenWorld(candX, candZ)) {
  105. worldX = candX;
  106. worldZ = candZ;
  107. found = true;
  108. }
  109. }
  110. }
  111. }
  112. if (!found) {
  113. qWarning()
  114. << "MapTransformer: spawn at" << s.x << s.z
  115. << "is forbidden and no nearby free tile found; spawning anyway";
  116. }
  117. }
  118. Engine::Core::Entity *e = nullptr;
  119. if (s_registry) {
  120. Game::Units::SpawnParams sp;
  121. sp.position = QVector3D(worldX, 0.0f, worldZ);
  122. sp.playerId = s.playerId;
  123. sp.unitType = s.type.toStdString();
  124. sp.aiControlled = !ownerRegistry.isPlayer(s.playerId);
  125. sp.maxPopulation = s.maxPopulation;
  126. auto obj = s_registry->create(s.type.toStdString(), world, sp);
  127. if (obj) {
  128. e = world.getEntity(obj->id());
  129. rt.unitIds.push_back(obj->id());
  130. }
  131. }
  132. if (!e) {
  133. e = world.createEntity();
  134. if (!e)
  135. continue;
  136. auto *t = e->addComponent<Engine::Core::TransformComponent>();
  137. t->position = {worldX, 0.0f, worldZ};
  138. t->scale = {0.5f, 0.5f, 0.5f};
  139. auto *r = e->addComponent<Engine::Core::RenderableComponent>("", "");
  140. r->visible = true;
  141. auto *u = e->addComponent<Engine::Core::UnitComponent>();
  142. u->unitType = s.type.toStdString();
  143. u->ownerId = s.playerId;
  144. u->visionRange = 14.0f;
  145. bool isAI = !ownerRegistry.isPlayer(s.playerId);
  146. if (isAI) {
  147. e->addComponent<Engine::Core::AIControlledComponent>();
  148. } else {
  149. }
  150. if (auto *existingMv =
  151. e->getComponent<Engine::Core::MovementComponent>()) {
  152. existingMv->goalX = worldX;
  153. existingMv->goalY = worldZ;
  154. existingMv->targetX = worldX;
  155. existingMv->targetY = worldZ;
  156. } else if (auto *mv =
  157. e->addComponent<Engine::Core::MovementComponent>()) {
  158. mv->goalX = worldX;
  159. mv->goalY = worldZ;
  160. mv->targetX = worldX;
  161. mv->targetY = worldZ;
  162. }
  163. QVector3D tc = Game::Visuals::teamColorForOwner(u->ownerId);
  164. r->color[0] = tc.x();
  165. r->color[1] = tc.y();
  166. r->color[2] = tc.z();
  167. if (s.type == "archer") {
  168. u->health = 80;
  169. u->maxHealth = 80;
  170. u->speed = 3.0f;
  171. u->visionRange = 16.0f;
  172. auto *atk = e->addComponent<Engine::Core::AttackComponent>();
  173. atk->range = 6.0f;
  174. atk->damage = 12;
  175. atk->cooldown = 1.2f;
  176. }
  177. if (!e->getComponent<Engine::Core::MovementComponent>()) {
  178. auto *mv = e->addComponent<Engine::Core::MovementComponent>();
  179. if (mv) {
  180. mv->goalX = worldX;
  181. mv->goalY = worldZ;
  182. mv->targetX = worldX;
  183. mv->targetY = worldZ;
  184. }
  185. }
  186. rt.unitIds.push_back(e->getId());
  187. }
  188. if (auto *r = e->getComponent<Engine::Core::RenderableComponent>()) {
  189. if (visuals) {
  190. Game::Visuals::VisualDef defv;
  191. if (visuals->lookup(s.type.toStdString(), defv)) {
  192. Game::Visuals::applyToRenderable(defv, *r);
  193. }
  194. }
  195. if (r->color[0] == 0.0f && r->color[1] == 0.0f && r->color[2] == 0.0f) {
  196. r->color[0] = r->color[1] = r->color[2] = 1.0f;
  197. }
  198. }
  199. if (auto *t = e->getComponent<Engine::Core::TransformComponent>()) {
  200. qInfo() << "Spawned" << s.type << "id=" << e->getId() << "at"
  201. << QVector3D(t->position.x, t->position.y, t->position.z)
  202. << "(coordSystem="
  203. << (def.coordSystem == CoordSystem::Grid ? "Grid" : "World")
  204. << ")";
  205. }
  206. }
  207. return rt;
  208. }
  209. } // namespace Game::Map