Browse Source

clang tidy fixes

djeada 1 month ago
parent
commit
df7163b3b3
100 changed files with 4144 additions and 3563 deletions
  1. 1 1
      .clang-tidy
  2. 3 2
      CMakeLists.txt
  3. 16 5
      Makefile
  4. 4 4
      README.md
  5. 17 14
      app/controllers/action_vfx.cpp
  6. 3 5
      app/controllers/action_vfx.h
  7. 85 78
      app/controllers/command_controller.cpp
  8. 24 22
      app/controllers/command_controller.h
  9. 246 211
      app/core/game_engine.cpp
  10. 65 59
      app/core/game_engine.h
  11. 19 11
      app/core/language_manager.cpp
  12. 5 4
      app/core/language_manager.h
  13. 7 8
      app/models/audio_system_proxy.cpp
  14. 10 12
      app/models/audio_system_proxy.h
  15. 22 15
      app/models/cursor_manager.cpp
  16. 12 6
      app/models/cursor_manager.h
  17. 8 6
      app/models/cursor_mode.h
  18. 7 6
      app/models/hover_tracker.cpp
  19. 7 12
      app/models/hover_tracker.h
  20. 35 25
      app/models/selected_units_model.cpp
  21. 7 6
      app/models/selected_units_model.h
  22. 16 14
      app/utils/engine_view_helpers.h
  23. 10 9
      app/utils/json_vec_utils.cpp
  24. 5 6
      app/utils/json_vec_utils.h
  25. 14 14
      app/utils/movement_utils.h
  26. 14 12
      app/utils/selection_utils.h
  27. 1 1
      assets/shaders/basic.frag
  28. 60 50
      assets/shaders/bridge.frag
  29. 1 1
      assets/shaders/mounted_knight.frag
  30. 7 7
      assets/shaders/terrain_chunk.frag
  31. 27 24
      game/audio/AudioEventHandler.cpp
  32. 8 10
      game/audio/AudioEventHandler.h
  33. 120 114
      game/audio/AudioSystem.cpp
  34. 25 23
      game/audio/AudioSystem.h
  35. 2 1
      game/audio/CMakeLists.txt
  36. 81 68
      game/audio/MiniaudioBackend.cpp
  37. 11 13
      game/audio/MiniaudioBackend.h
  38. 1 1
      game/audio/Music.cpp
  39. 1 1
      game/audio/Music.h
  40. 39 29
      game/audio/MusicPlayer.cpp
  41. 12 15
      game/audio/MusicPlayer.h
  42. 15 9
      game/audio/Sound.cpp
  43. 3 3
      game/audio/Sound.h
  44. 0 1
      game/core/component.cpp
  45. 97 84
      game/core/component.h
  46. 1 2
      game/core/entity.cpp
  47. 6 5
      game/core/entity.h
  48. 0 1
      game/core/event_manager.cpp
  49. 67 54
      game/core/event_manager.h
  50. 5 5
      game/core/ownership_constants.h
  51. 523 466
      game/core/serialization.cpp
  52. 9 8
      game/core/serialization.h
  53. 2 2
      game/core/system.h
  54. 44 38
      game/core/world.cpp
  55. 20 20
      game/core/world.h
  56. 38 34
      game/game_config.h
  57. 14 15
      game/map/environment.cpp
  58. 4 8
      game/map/environment.h
  59. 93 0
      game/map/json_keys.h
  60. 54 50
      game/map/level_loader.cpp
  61. 19 24
      game/map/level_loader.h
  62. 85 69
      game/map/map_catalog.cpp
  63. 6 8
      game/map/map_catalog.h
  64. 18 18
      game/map/map_definition.h
  65. 300 235
      game/map/map_loader.cpp
  66. 2 2
      game/map/map_loader.h
  67. 75 66
      game/map/map_transformer.cpp
  68. 12 14
      game/map/map_transformer.h
  69. 222 186
      game/map/skirmish_loader.cpp
  70. 20 25
      game/map/skirmish_loader.h
  71. 321 303
      game/map/terrain.cpp
  72. 77 67
      game/map/terrain.h
  73. 72 53
      game/map/terrain_service.cpp
  74. 29 17
      game/map/terrain_service.h
  75. 131 105
      game/map/visibility_service.cpp
  76. 34 37
      game/map/visibility_service.h
  77. 10 12
      game/map/world_bootstrap.cpp
  78. 7 11
      game/map/world_bootstrap.h
  79. 20 13
      game/systems/ai_system.cpp
  80. 2 2
      game/systems/ai_system.h
  81. 7 4
      game/systems/ai_system/ai_behavior.h
  82. 5 5
      game/systems/ai_system/ai_behavior_registry.h
  83. 50 41
      game/systems/ai_system/ai_command_applier.cpp
  84. 3 3
      game/systems/ai_system/ai_command_applier.h
  85. 65 60
      game/systems/ai_system/ai_command_filter.cpp
  86. 15 11
      game/systems/ai_system/ai_command_filter.h
  87. 9 5
      game/systems/ai_system/ai_executor.cpp
  88. 4 3
      game/systems/ai_system/ai_executor.h
  89. 81 77
      game/systems/ai_system/ai_reasoner.cpp
  90. 3 3
      game/systems/ai_system/ai_reasoner.h
  91. 21 19
      game/systems/ai_system/ai_snapshot_builder.cpp
  92. 3 2
      game/systems/ai_system/ai_snapshot_builder.h
  93. 105 97
      game/systems/ai_system/ai_tactical.cpp
  94. 23 24
      game/systems/ai_system/ai_tactical.h
  95. 35 35
      game/systems/ai_system/ai_types.h
  96. 40 36
      game/systems/ai_system/ai_utils.h
  97. 20 9
      game/systems/ai_system/ai_worker.cpp
  98. 4 4
      game/systems/ai_system/ai_worker.h
  99. 127 122
      game/systems/ai_system/behaviors/attack_behavior.cpp
  100. 9 6
      game/systems/ai_system/behaviors/attack_behavior.h

+ 1 - 1
.clang-tidy

@@ -10,7 +10,7 @@ Checks: >
   -cppcoreguidelines-pro-type-reinterpret-cast
 
 WarningsAsErrors: ''
-HeaderFilterRegex: '.*'
+HeaderFilterRegex: '^(?!.*third_party/).*/Standard-of-Iron/.*'
 FormatStyle: file
 CheckOptions:
   - key: readability-identifier-naming.VariableCase

+ 3 - 2
CMakeLists.txt

@@ -10,12 +10,13 @@ option(ENABLE_CLANG_TIDY "Enable clang-tidy analysis" ON)
 if (ENABLE_CLANG_TIDY AND CLANG_TIDY_EXE)
     message(STATUS "Found clang-tidy: ${CLANG_TIDY_EXE}")
     # Prefer using .clang-tidy config, but define fallback checks for safety
-    set(CLANG_TIDY_ARGS "-header-filter=.*")
+    set(CLANG_TIDY_ARGS "-header-filter=^(?!.*third_party/).*/Standard-of-Iron/.*")
+    set(CLANG_TIDY_FILTER "${CMAKE_SOURCE_DIR}/tools/clang_tidy_filter.sh")
     if(NOT EXISTS "${CMAKE_SOURCE_DIR}/.clang-tidy")
         list(APPEND CLANG_TIDY_ARGS
             "-checks=bugprone-*,performance-*,readability-*,modernize-*,cppcoreguidelines-*,clang-analyzer-*")
     endif()
-    set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY_EXE} ${CLANG_TIDY_ARGS})
+    set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY_FILTER} ${CLANG_TIDY_EXE} ${CLANG_TIDY_ARGS})
 elseif (ENABLE_CLANG_TIDY)
     message(WARNING "clang-tidy requested but not found! Static analysis skipped.")
 else()

+ 16 - 5
Makefile

@@ -113,11 +113,23 @@ run: build
 		echo "$(RED)$(BINARY_NAME) not found at $$BIN_PATH$(RESET)"; \
 		exit 127; \
 	fi; \
-	if [ -n "$$DISPLAY" ]; then \
-		"$${BIN_PATH}"; \
+	PLATFORM="$$(uname -s)"; \
+	DEFAULT_QPA="offscreen"; \
+	case "$$PLATFORM" in \
+		Darwin) DEFAULT_QPA="cocoa" ;; \
+		MINGW*|MSYS*|CYGWIN*) DEFAULT_QPA="windows" ;; \
+		*) \
+			if [ -n "$$WAYLAND_DISPLAY" ]; then \
+				DEFAULT_QPA="wayland"; \
+			elif [ -n "$$DISPLAY" ]; then \
+				DEFAULT_QPA="xcb"; \
+			fi ;; \
+	esac; \
+	if [ -z "$$QT_QPA_PLATFORM" ]; then \
+		echo "$(YELLOW)QT_QPA_PLATFORM not set; defaulting to $$DEFAULT_QPA$(RESET)"; \
+		QT_QPA_PLATFORM="$$DEFAULT_QPA" "$${BIN_PATH}"; \
 	else \
-		echo "$(YELLOW)No DISPLAY detected; running with QT_QPA_PLATFORM=offscreen$(RESET)"; \
-		QT_QPA_PLATFORM=offscreen "$${BIN_PATH}"; \
+		"$${BIN_PATH}"; \
 	fi
 
 # Run with xvfb for headless environments (software rasterization)
@@ -322,4 +334,3 @@ quickstart:
 	@echo "3. Run the game: $(BLUE)make run$(RESET)"
 	@echo ""
 	@echo "Or use the shortcut: $(BLUE)make dev$(RESET)"
-

+ 4 - 4
README.md

@@ -241,7 +241,7 @@ void GameEngine::onMyCommand(qreal sx, qreal sy) {
     if (!screenToGround(QPointF(sx, sy), hit)) return;
     
     // Issue command to selected units
-    const auto& selected = m_selectionSystem->getSelectedUnits();
+    const auto& selected = m_selection_system->getSelectedUnits();
     for (auto id : selected) {
         // Process command...
     }
@@ -295,7 +295,7 @@ Maps can define custom victory and defeat conditions in their JSON files. Add a
 ### Neutral (Unowned) Barracks
 Maps can include neutral barracks that start without an owner. These barracks are inactive until captured by a player.
 
-**To create a neutral barracks, omit the `playerId` field:**
+**To create a neutral barracks, omit the `player_id` field:**
 ```json
 {
   "type": "barracks",
@@ -346,7 +346,7 @@ For detailed technical documentation, see `game/systems/CAPTURE_SYSTEM.md`.
     "type": "barracks",
     "x": 30,
     "z": 50,
-    "playerId": 1,
+    "player_id": 1,
     "maxPopulation": 100
   },
   {
@@ -359,7 +359,7 @@ For detailed technical documentation, see `game/systems/CAPTURE_SYSTEM.md`.
     "type": "barracks",
     "x": 70,
     "z": 50,
-    "playerId": 2,
+    "player_id": 2,
     "maxPopulation": 100
   }
 ]

+ 17 - 14
app/controllers/action_vfx.cpp

@@ -4,37 +4,40 @@
 #include "../../game/core/world.h"
 #include "../../game/game_config.h"
 #include "../../game/systems/arrow_system.h"
+#include <qvectornd.h>
 
 namespace App::Controllers {
 
 void ActionVFX::spawnAttackArrow(Engine::Core::World *world,
-                                 Engine::Core::EntityID targetId) {
-  if (!world) {
+                                 Engine::Core::EntityID target_id) {
+  if (world == nullptr) {
     return;
   }
 
-  auto *arrowSystem = world->getSystem<Game::Systems::ArrowSystem>();
-  if (!arrowSystem) {
+  auto *arrow_system = world->getSystem<Game::Systems::ArrowSystem>();
+  if (arrow_system == nullptr) {
     return;
   }
 
-  auto *targetEntity = world->getEntity(targetId);
-  if (!targetEntity) {
+  auto *target_entity = world->getEntity(target_id);
+  if (target_entity == nullptr) {
     return;
   }
 
-  auto *targetTrans =
-      targetEntity->getComponent<Engine::Core::TransformComponent>();
-  if (!targetTrans) {
+  auto *target_trans =
+      target_entity->getComponent<Engine::Core::TransformComponent>();
+  if (target_trans == nullptr) {
     return;
   }
 
-  QVector3D targetPos(targetTrans->position.x, targetTrans->position.y + 1.0f,
-                      targetTrans->position.z);
-  QVector3D aboveTarget = targetPos + QVector3D(0, 2.0f, 0);
+  QVector3D const target_pos(target_trans->position.x,
+                             target_trans->position.y + 1.0F,
+                             target_trans->position.z);
+  QVector3D const above_target = target_pos + QVector3D(0, 2.0F, 0);
 
-  arrowSystem->spawnArrow(aboveTarget, targetPos, QVector3D(1.0f, 0.2f, 0.2f),
-                          Game::GameConfig::instance().arrow().speedAttack);
+  arrow_system->spawnArrow(above_target, target_pos,
+                           QVector3D(1.0F, 0.2F, 0.2F),
+                           Game::GameConfig::instance().arrow().speedAttack);
 }
 
 } // namespace App::Controllers

+ 3 - 5
app/controllers/action_vfx.h

@@ -2,19 +2,17 @@
 
 #include <QVector3D>
 
-namespace Engine {
-namespace Core {
+namespace Engine::Core {
 class World;
 using EntityID = unsigned int;
-} // namespace Core
-} // namespace Engine
+} // namespace Engine::Core
 
 namespace App::Controllers {
 
 class ActionVFX {
 public:
   static void spawnAttackArrow(Engine::Core::World *world,
-                               Engine::Core::EntityID targetId);
+                               Engine::Core::EntityID target_id);
 };
 
 } // namespace App::Controllers

+ 85 - 78
app/controllers/command_controller.cpp

@@ -8,75 +8,82 @@
 #include "../../game/systems/selection_system.h"
 #include "../../render/gl/camera.h"
 #include "../utils/movement_utils.h"
+#include "units/spawn_type.h"
 #include <QPointF>
+#include <qglobal.h>
+#include <qobject.h>
+#include <qtmetamacros.h>
+#include <qvectornd.h>
 
 namespace App::Controllers {
 
 CommandController::CommandController(
-    Engine::Core::World *world, Game::Systems::SelectionSystem *selectionSystem,
+    Engine::Core::World *world,
+    Game::Systems::SelectionSystem *selection_system,
     Game::Systems::PickingService *pickingService, QObject *parent)
-    : QObject(parent), m_world(world), m_selectionSystem(selectionSystem),
+    : QObject(parent), m_world(world), m_selection_system(selection_system),
       m_pickingService(pickingService) {}
 
-CommandResult CommandController::onAttackClick(qreal sx, qreal sy,
-                                               int viewportWidth,
-                                               int viewportHeight,
-                                               void *camera) {
+auto CommandController::onAttackClick(qreal sx, qreal sy, int viewportWidth,
+                                      int viewportHeight,
+                                      void *camera) -> CommandResult {
   CommandResult result;
-  if (!m_selectionSystem || !m_pickingService || !camera || !m_world) {
+  if ((m_selection_system == nullptr) || (m_pickingService == nullptr) ||
+      (camera == nullptr) || (m_world == nullptr)) {
     result.resetCursorToNormal = true;
     return result;
   }
 
-  const auto &selected = m_selectionSystem->getSelectedUnits();
+  const auto &selected = m_selection_system->getSelectedUnits();
   if (selected.empty()) {
     result.resetCursorToNormal = true;
     return result;
   }
 
   auto *cam = static_cast<Render::GL::Camera *>(camera);
-  Engine::Core::EntityID targetId = m_pickingService->pickUnitFirst(
+  Engine::Core::EntityID const target_id = m_pickingService->pickUnitFirst(
       float(sx), float(sy), *m_world, *cam, viewportWidth, viewportHeight, 0);
 
-  if (targetId == 0) {
+  if (target_id == 0) {
     result.resetCursorToNormal = true;
     return result;
   }
 
-  auto *targetEntity = m_world->getEntity(targetId);
-  if (!targetEntity) {
+  auto *target_entity = m_world->getEntity(target_id);
+  if (target_entity == nullptr) {
     return result;
   }
 
-  auto *targetUnit = targetEntity->getComponent<Engine::Core::UnitComponent>();
-  if (!targetUnit) {
+  auto *target_unit =
+      target_entity->getComponent<Engine::Core::UnitComponent>();
+  if (target_unit == nullptr) {
     return result;
   }
 
-  Game::Systems::CommandService::attackTarget(*m_world, selected, targetId,
-                                              true);
+  Game::Systems::CommandService::attack_target(*m_world, selected, target_id,
+                                               true);
 
-  emit attackTargetSelected();
+  emit attack_targetSelected();
 
   result.inputConsumed = true;
   result.resetCursorToNormal = true;
   return result;
 }
 
-CommandResult CommandController::onStopCommand() {
+auto CommandController::onStopCommand() -> CommandResult {
   CommandResult result;
-  if (!m_selectionSystem || !m_world) {
+  if ((m_selection_system == nullptr) || (m_world == nullptr)) {
     return result;
   }
 
-  const auto &selected = m_selectionSystem->getSelectedUnits();
+  const auto &selected = m_selection_system->getSelectedUnits();
   if (selected.empty()) {
     return result;
   }
 
   for (auto id : selected) {
     auto *entity = m_world->getEntity(id);
-    if (!entity) {
+    if (entity == nullptr) {
       continue;
     }
 
@@ -88,11 +95,11 @@ CommandResult CommandController::onStopCommand() {
       patrol->waypoints.clear();
     }
 
-    auto *holdMode = entity->getComponent<Engine::Core::HoldModeComponent>();
-    if (holdMode && holdMode->active) {
-      holdMode->active = false;
-      holdMode->exitCooldown = holdMode->standUpDuration;
-      emit holdModeChanged(false);
+    auto *hold_mode = entity->getComponent<Engine::Core::HoldModeComponent>();
+    if ((hold_mode != nullptr) && hold_mode->active) {
+      hold_mode->active = false;
+      hold_mode->exitCooldown = hold_mode->standUpDuration;
+      emit hold_modeChanged(false);
     }
   }
 
@@ -101,36 +108,37 @@ CommandResult CommandController::onStopCommand() {
   return result;
 }
 
-CommandResult CommandController::onHoldCommand() {
+auto CommandController::onHoldCommand() -> CommandResult {
   CommandResult result;
-  if (!m_selectionSystem || !m_world) {
+  if ((m_selection_system == nullptr) || (m_world == nullptr)) {
     return result;
   }
 
-  const auto &selected = m_selectionSystem->getSelectedUnits();
+  const auto &selected = m_selection_system->getSelectedUnits();
   if (selected.empty()) {
     return result;
   }
 
   for (auto id : selected) {
     auto *entity = m_world->getEntity(id);
-    if (!entity) {
+    if (entity == nullptr) {
       continue;
     }
 
     auto *unit = entity->getComponent<Engine::Core::UnitComponent>();
 
-    if (!unit || (unit->spawnType != Game::Units::SpawnType::Archer &&
-                  unit->spawnType != Game::Units::SpawnType::Spearman)) {
+    if ((unit == nullptr) ||
+        (unit->spawn_type != Game::Units::SpawnType::Archer &&
+         unit->spawn_type != Game::Units::SpawnType::Spearman)) {
       continue;
     }
 
-    auto *holdMode = entity->getComponent<Engine::Core::HoldModeComponent>();
+    auto *hold_mode = entity->getComponent<Engine::Core::HoldModeComponent>();
 
-    if (holdMode && holdMode->active) {
-      holdMode->active = false;
-      holdMode->exitCooldown = holdMode->standUpDuration;
-      emit holdModeChanged(false);
+    if ((hold_mode != nullptr) && hold_mode->active) {
+      hold_mode->active = false;
+      hold_mode->exitCooldown = hold_mode->standUpDuration;
+      emit hold_modeChanged(false);
       continue;
     }
 
@@ -142,20 +150,20 @@ CommandResult CommandController::onHoldCommand() {
       patrol->waypoints.clear();
     }
 
-    if (!holdMode) {
-      holdMode = entity->addComponent<Engine::Core::HoldModeComponent>();
+    if (hold_mode == nullptr) {
+      hold_mode = entity->addComponent<Engine::Core::HoldModeComponent>();
     }
-    holdMode->active = true;
-    holdMode->exitCooldown = 0.0f;
-    emit holdModeChanged(true);
+    hold_mode->active = true;
+    hold_mode->exitCooldown = 0.0F;
+    emit hold_modeChanged(true);
 
     auto *movement = entity->getComponent<Engine::Core::MovementComponent>();
-    if (movement) {
+    if (movement != nullptr) {
       movement->hasTarget = false;
       movement->path.clear();
       movement->pathPending = false;
-      movement->vx = 0.0f;
-      movement->vz = 0.0f;
+      movement->vx = 0.0F;
+      movement->vz = 0.0F;
     }
   }
 
@@ -164,12 +172,12 @@ CommandResult CommandController::onHoldCommand() {
   return result;
 }
 
-CommandResult CommandController::onPatrolClick(qreal sx, qreal sy,
-                                               int viewportWidth,
-                                               int viewportHeight,
-                                               void *camera) {
+auto CommandController::onPatrolClick(qreal sx, qreal sy, int viewportWidth,
+                                      int viewportHeight,
+                                      void *camera) -> CommandResult {
   CommandResult result;
-  if (!m_selectionSystem || !m_world || !m_pickingService || !camera) {
+  if ((m_selection_system == nullptr) || (m_world == nullptr) ||
+      (m_pickingService == nullptr) || (camera == nullptr)) {
     if (m_hasPatrolFirstWaypoint) {
       clearPatrolFirstWaypoint();
       result.resetCursorToNormal = true;
@@ -177,7 +185,7 @@ CommandResult CommandController::onPatrolClick(qreal sx, qreal sy,
     return result;
   }
 
-  const auto &selected = m_selectionSystem->getSelectedUnits();
+  const auto &selected = m_selection_system->getSelectedUnits();
   if (selected.empty()) {
     if (m_hasPatrolFirstWaypoint) {
       clearPatrolFirstWaypoint();
@@ -204,29 +212,29 @@ CommandResult CommandController::onPatrolClick(qreal sx, qreal sy,
     return result;
   }
 
-  QVector3D secondWaypoint = hit;
+  QVector3D const second_waypoint = hit;
 
   for (auto id : selected) {
     auto *entity = m_world->getEntity(id);
-    if (!entity) {
+    if (entity == nullptr) {
       continue;
     }
 
     auto *building = entity->getComponent<Engine::Core::BuildingComponent>();
-    if (building) {
+    if (building != nullptr) {
       continue;
     }
 
     auto *patrol = entity->getComponent<Engine::Core::PatrolComponent>();
-    if (!patrol) {
+    if (patrol == nullptr) {
       patrol = entity->addComponent<Engine::Core::PatrolComponent>();
     }
 
-    if (patrol) {
+    if (patrol != nullptr) {
       patrol->waypoints.clear();
-      patrol->waypoints.push_back(
-          {m_patrolFirstWaypoint.x(), m_patrolFirstWaypoint.z()});
-      patrol->waypoints.push_back({secondWaypoint.x(), secondWaypoint.z()});
+      patrol->waypoints.emplace_back(m_patrolFirstWaypoint.x(),
+                                     m_patrolFirstWaypoint.z());
+      patrol->waypoints.emplace_back(second_waypoint.x(), second_waypoint.z());
       patrol->currentWaypoint = 0;
       patrol->patrolling = true;
     }
@@ -241,13 +249,12 @@ CommandResult CommandController::onPatrolClick(qreal sx, qreal sy,
   return result;
 }
 
-CommandResult CommandController::setRallyAtScreen(qreal sx, qreal sy,
-                                                  int viewportWidth,
-                                                  int viewportHeight,
-                                                  void *camera,
-                                                  int localOwnerId) {
+auto CommandController::setRallyAtScreen(qreal sx, qreal sy, int viewportWidth,
+                                         int viewportHeight, void *camera,
+                                         int localOwnerId) -> CommandResult {
   CommandResult result;
-  if (!m_world || !m_selectionSystem || !m_pickingService || !camera) {
+  if ((m_world == nullptr) || (m_selection_system == nullptr) ||
+      (m_pickingService == nullptr) || (camera == nullptr)) {
     return result;
   }
 
@@ -259,27 +266,27 @@ CommandResult CommandController::setRallyAtScreen(qreal sx, qreal sy,
   }
 
   Game::Systems::ProductionService::setRallyForFirstSelectedBarracks(
-      *m_world, m_selectionSystem->getSelectedUnits(), localOwnerId, hit.x(),
+      *m_world, m_selection_system->getSelectedUnits(), localOwnerId, hit.x(),
       hit.z());
 
   result.inputConsumed = true;
   return result;
 }
 
-void CommandController::recruitNearSelected(const QString &unitType,
+void CommandController::recruitNearSelected(const QString &unit_type,
                                             int localOwnerId) {
-  if (!m_world || !m_selectionSystem) {
+  if ((m_world == nullptr) || (m_selection_system == nullptr)) {
     return;
   }
 
-  const auto &sel = m_selectionSystem->getSelectedUnits();
+  const auto &sel = m_selection_system->getSelectedUnits();
   if (sel.empty()) {
     return;
   }
 
   auto result =
       Game::Systems::ProductionService::startProductionForFirstSelectedBarracks(
-          *m_world, sel, localOwnerId, unitType.toStdString());
+          *m_world, sel, localOwnerId, unit_type.toStdString());
 
   if (result == Game::Systems::ProductionResult::GlobalTroopLimitReached) {
     emit troopLimitReached();
@@ -290,20 +297,20 @@ void CommandController::resetMovement(Engine::Core::Entity *entity) {
   App::Utils::resetMovement(entity);
 }
 
-bool CommandController::anySelectedInHoldMode() const {
-  if (!m_selectionSystem || !m_world) {
+auto CommandController::anySelectedInHoldMode() const -> bool {
+  if ((m_selection_system == nullptr) || (m_world == nullptr)) {
     return false;
   }
 
-  const auto &selected = m_selectionSystem->getSelectedUnits();
-  for (Engine::Core::EntityID entityId : selected) {
-    Engine::Core::Entity *entity = m_world->getEntity(entityId);
-    if (!entity) {
+  const auto &selected = m_selection_system->getSelectedUnits();
+  for (Engine::Core::EntityID const entity_id : selected) {
+    Engine::Core::Entity *entity = m_world->getEntity(entity_id);
+    if (entity == nullptr) {
       continue;
     }
 
-    auto *holdMode = entity->getComponent<Engine::Core::HoldModeComponent>();
-    if (holdMode && holdMode->active) {
+    auto *hold_mode = entity->getComponent<Engine::Core::HoldModeComponent>();
+    if ((hold_mode != nullptr) && hold_mode->active) {
       return true;
     }
   }

+ 24 - 22
app/controllers/command_controller.h

@@ -5,13 +5,11 @@
 #include <QVector3D>
 #include <vector>
 
-namespace Engine {
-namespace Core {
+namespace Engine::Core {
 class World;
 class Entity;
 using EntityID = unsigned int;
-} // namespace Core
-} // namespace Engine
+} // namespace Engine::Core
 
 namespace Game::Systems {
 class SelectionSystem;
@@ -29,41 +27,45 @@ class CommandController : public QObject {
   Q_OBJECT
 public:
   CommandController(Engine::Core::World *world,
-                    Game::Systems::SelectionSystem *selectionSystem,
+                    Game::Systems::SelectionSystem *selection_system,
                     Game::Systems::PickingService *pickingService,
                     QObject *parent = nullptr);
 
-  CommandResult onAttackClick(qreal sx, qreal sy, int viewportWidth,
-                              int viewportHeight, void *camera);
-  CommandResult onStopCommand();
-  CommandResult onHoldCommand();
-  CommandResult onPatrolClick(qreal sx, qreal sy, int viewportWidth,
-                              int viewportHeight, void *camera);
-  CommandResult setRallyAtScreen(qreal sx, qreal sy, int viewportWidth,
-                                 int viewportHeight, void *camera,
-                                 int localOwnerId);
-  void recruitNearSelected(const QString &unitType, int localOwnerId);
+  auto onAttackClick(qreal sx, qreal sy, int viewportWidth, int viewportHeight,
+                     void *camera) -> CommandResult;
+  auto onStopCommand() -> CommandResult;
+  auto onHoldCommand() -> CommandResult;
+  auto onPatrolClick(qreal sx, qreal sy, int viewportWidth, int viewportHeight,
+                     void *camera) -> CommandResult;
+  auto setRallyAtScreen(qreal sx, qreal sy, int viewportWidth,
+                        int viewportHeight, void *camera,
+                        int localOwnerId) -> CommandResult;
+  void recruitNearSelected(const QString &unit_type, int localOwnerId);
 
-  bool hasPatrolFirstWaypoint() const { return m_hasPatrolFirstWaypoint; }
-  QVector3D getPatrolFirstWaypoint() const { return m_patrolFirstWaypoint; }
+  [[nodiscard]] auto hasPatrolFirstWaypoint() const -> bool {
+    return m_hasPatrolFirstWaypoint;
+  }
+  [[nodiscard]] auto getPatrolFirstWaypoint() const -> QVector3D {
+    return m_patrolFirstWaypoint;
+  }
   void clearPatrolFirstWaypoint() { m_hasPatrolFirstWaypoint = false; }
 
-  Q_INVOKABLE bool anySelectedInHoldMode() const;
+  Q_INVOKABLE [[nodiscard]] bool anySelectedInHoldMode() const;
 
 signals:
-  void attackTargetSelected();
+  void attack_targetSelected();
   void troopLimitReached();
-  void holdModeChanged(bool active);
+  void hold_modeChanged(bool active);
 
 private:
   Engine::Core::World *m_world;
-  Game::Systems::SelectionSystem *m_selectionSystem;
+  Game::Systems::SelectionSystem *m_selection_system;
   Game::Systems::PickingService *m_pickingService;
 
   bool m_hasPatrolFirstWaypoint = false;
   QVector3D m_patrolFirstWaypoint;
 
-  void resetMovement(Engine::Core::Entity *entity);
+  static void resetMovement(Engine::Core::Entity *entity);
 };
 
 } // namespace App::Controllers

File diff suppressed because it is too large
+ 246 - 211
app/core/game_engine.cpp


+ 65 - 59
app/core/game_engine.h

@@ -22,18 +22,15 @@
 #include <memory>
 #include <vector>
 
-namespace Engine {
-namespace Core {
+namespace Engine::Core {
 class World;
 using EntityID = unsigned int;
 struct MovementComponent;
 struct TransformComponent;
 struct RenderableComponent;
-} // namespace Core
-} // namespace Engine
+} // namespace Engine::Core
 
-namespace Render {
-namespace GL {
+namespace Render::GL {
 class Renderer;
 class Camera;
 class ResourceManager;
@@ -49,8 +46,7 @@ class PlantRenderer;
 class PineRenderer;
 class FireCampRenderer;
 struct IRenderPass;
-} // namespace GL
-} // namespace Render
+} // namespace Render::GL
 
 namespace Game {
 namespace Systems {
@@ -82,7 +78,7 @@ class GameEngine : public QObject {
   Q_OBJECT
 public:
   GameEngine();
-  ~GameEngine();
+  ~GameEngine() override;
 
   Q_PROPERTY(QObject *selectedUnitsModel READ selectedUnitsModel NOTIFY
                  selectedUnitsChanged)
@@ -96,9 +92,9 @@ public:
   Q_PROPERTY(
       bool hasUnitsSelected READ hasUnitsSelected NOTIFY selectedUnitsChanged)
   Q_PROPERTY(
-      int playerTroopCount READ playerTroopCount NOTIFY troopCountChanged)
-  Q_PROPERTY(
-      int maxTroopsPerPlayer READ maxTroopsPerPlayer NOTIFY troopCountChanged)
+      int playerTroopCount READ playerTroopCount NOTIFY troop_countChanged)
+  Q_PROPERTY(int max_troops_per_player READ max_troops_per_player NOTIFY
+                 troop_countChanged)
   Q_PROPERTY(
       QVariantList availableMaps READ availableMaps NOTIFY availableMapsChanged)
   Q_PROPERTY(bool mapsLoading READ mapsLoading NOTIFY mapsLoadingChanged)
@@ -108,7 +104,7 @@ public:
   Q_PROPERTY(int selectedPlayerId READ selectedPlayerId WRITE
                  setSelectedPlayerId NOTIFY selectedPlayerIdChanged)
   Q_PROPERTY(QString lastError READ lastError NOTIFY lastErrorChanged)
-  Q_PROPERTY(QObject *audioSystem READ audioSystem CONSTANT)
+  Q_PROPERTY(QObject *audio_system READ audio_system CONSTANT)
 
   Q_INVOKABLE void onMapClicked(qreal sx, qreal sy);
   Q_INVOKABLE void onRightClick(qreal sx, qreal sy);
@@ -120,16 +116,16 @@ public:
   Q_INVOKABLE void onAttackClick(qreal sx, qreal sy);
   Q_INVOKABLE void onStopCommand();
   Q_INVOKABLE void onHoldCommand();
-  Q_INVOKABLE bool anySelectedInHoldMode() const;
+  Q_INVOKABLE [[nodiscard]] bool anySelectedInHoldMode() const;
   Q_INVOKABLE void onPatrolClick(qreal sx, qreal sy);
 
   Q_INVOKABLE void cameraMove(float dx, float dz);
   Q_INVOKABLE void cameraElevate(float dy);
   Q_INVOKABLE void resetCamera();
   Q_INVOKABLE void cameraZoom(float delta);
-  Q_INVOKABLE float cameraDistance() const;
+  Q_INVOKABLE [[nodiscard]] float cameraDistance() const;
   Q_INVOKABLE void cameraYaw(float degrees);
-  Q_INVOKABLE void cameraOrbit(float yawDeg, float pitchDeg);
+  Q_INVOKABLE void cameraOrbit(float yaw_deg, float pitch_deg);
   Q_INVOKABLE void cameraOrbitDirection(int direction, bool shift);
   Q_INVOKABLE void cameraFollowSelection(bool enable);
   Q_INVOKABLE void cameraSetFollowLerp(float alpha);
@@ -137,31 +133,39 @@ public:
 
   Q_INVOKABLE void setPaused(bool paused) { m_runtime.paused = paused; }
   Q_INVOKABLE void setGameSpeed(float speed) {
-    m_runtime.timeScale = std::max(0.0f, speed);
+    m_runtime.timeScale = std::max(0.0F, speed);
+  }
+  [[nodiscard]] auto paused() const -> bool { return m_runtime.paused; }
+  [[nodiscard]] auto timeScale() const -> float { return m_runtime.timeScale; }
+  [[nodiscard]] auto victoryState() const -> QString {
+    return m_runtime.victoryState;
   }
-  bool paused() const { return m_runtime.paused; }
-  float timeScale() const { return m_runtime.timeScale; }
-  QString victoryState() const { return m_runtime.victoryState; }
-  QString cursorMode() const;
+  [[nodiscard]] auto cursorMode() const -> QString;
   void setCursorMode(CursorMode mode);
   void setCursorMode(const QString &mode);
-  qreal globalCursorX() const;
-  qreal globalCursorY() const;
-  bool hasUnitsSelected() const;
-  int playerTroopCount() const;
-  int maxTroopsPerPlayer() const { return m_level.maxTroopsPerPlayer; }
-  int enemyTroopsDefeated() const;
+  [[nodiscard]] auto globalCursorX() const -> qreal;
+  [[nodiscard]] auto globalCursorY() const -> qreal;
+  [[nodiscard]] auto hasUnitsSelected() const -> bool;
+  [[nodiscard]] auto playerTroopCount() const -> int;
+  [[nodiscard]] auto max_troops_per_player() const -> int {
+    return m_level.max_troops_per_player;
+  }
+  [[nodiscard]] auto enemyTroopsDefeated() const -> int;
 
-  Q_INVOKABLE QVariantMap getPlayerStats(int ownerId) const;
+  Q_INVOKABLE [[nodiscard]] static QVariantMap getPlayerStats(int owner_id);
 
-  int selectedPlayerId() const { return m_selectedPlayerId; }
+  [[nodiscard]] auto selectedPlayerId() const -> int {
+    return m_selectedPlayerId;
+  }
   void setSelectedPlayerId(int id) {
     if (m_selectedPlayerId != id) {
       m_selectedPlayerId = id;
       emit selectedPlayerIdChanged();
     }
   }
-  QString lastError() const { return m_runtime.lastError; }
+  [[nodiscard]] auto lastError() const -> QString {
+    return m_runtime.lastError;
+  }
   Q_INVOKABLE void clearError() {
     if (!m_runtime.lastError.isEmpty()) {
       m_runtime.lastError = "";
@@ -169,28 +173,28 @@ public:
     }
   }
 
-  Q_INVOKABLE bool hasSelectedType(const QString &type) const;
-  Q_INVOKABLE void recruitNearSelected(const QString &unitType);
-  Q_INVOKABLE QVariantMap getSelectedProductionState() const;
-  Q_INVOKABLE QString getSelectedUnitsCommandMode() const;
+  Q_INVOKABLE [[nodiscard]] bool hasSelectedType(const QString &type) const;
+  Q_INVOKABLE void recruitNearSelected(const QString &unit_type);
+  Q_INVOKABLE [[nodiscard]] QVariantMap getSelectedProductionState() const;
+  Q_INVOKABLE [[nodiscard]] QString getSelectedUnitsCommandMode() const;
   Q_INVOKABLE void setRallyAtScreen(qreal sx, qreal sy);
-  Q_INVOKABLE QVariantList availableMaps() const;
-  bool mapsLoading() const { return m_mapsLoading; }
+  Q_INVOKABLE [[nodiscard]] QVariantList availableMaps() const;
+  [[nodiscard]] auto mapsLoading() const -> bool { return m_mapsLoading; }
   Q_INVOKABLE void
-  startSkirmish(const QString &mapPath,
+  startSkirmish(const QString &map_path,
                 const QVariantList &playerConfigs = QVariantList());
   Q_INVOKABLE void openSettings();
   Q_INVOKABLE void loadSave();
   Q_INVOKABLE void saveGame(const QString &filename = "savegame.json");
   Q_INVOKABLE void saveGameToSlot(const QString &slotName);
   Q_INVOKABLE void loadGameFromSlot(const QString &slotName);
-  Q_INVOKABLE QVariantList getSaveSlots() const;
+  Q_INVOKABLE [[nodiscard]] QVariantList getSaveSlots() const;
   Q_INVOKABLE void refreshSaveSlots();
   Q_INVOKABLE bool deleteSaveSlot(const QString &slotName);
   Q_INVOKABLE void exitGame();
-  Q_INVOKABLE QVariantList getOwnerInfo() const;
+  Q_INVOKABLE [[nodiscard]] QVariantList getOwnerInfo() const;
 
-  QObject *audioSystem();
+  auto audio_system() -> QObject *;
 
   void setWindow(QQuickWindow *w) { m_window = w; }
 
@@ -199,18 +203,19 @@ public:
   void render(int pixelWidth, int pixelHeight);
 
   void getSelectedUnitIds(std::vector<Engine::Core::EntityID> &out) const;
-  bool getUnitInfo(Engine::Core::EntityID id, QString &name, int &health,
-                   int &maxHealth, bool &isBuilding, bool &alive) const;
+  auto getUnitInfo(Engine::Core::EntityID id, QString &name, int &health,
+                   int &max_health, bool &isBuilding,
+                   bool &alive) const -> bool;
 
-  bool hasPatrolPreviewWaypoint() const;
-  QVector3D getPatrolPreviewWaypoint() const;
+  [[nodiscard]] auto hasPatrolPreviewWaypoint() const -> bool;
+  [[nodiscard]] auto getPatrolPreviewWaypoint() const -> QVector3D;
 
 private:
   struct RuntimeState {
     bool initialized = false;
     bool paused = false;
     bool loading = false;
-    float timeScale = 1.0f;
+    float timeScale = 1.0F;
     int localOwnerId = 1;
     QString victoryState = "";
     CursorMode cursorMode{CursorMode::Normal};
@@ -218,7 +223,7 @@ private:
     Qt::CursorShape currentCursor = Qt::ArrowCursor;
     int lastTroopCount = 0;
     std::uint64_t visibilityVersion = 0;
-    float visibilityUpdateAccumulator = 0.0f;
+    float visibilityUpdateAccumulator = 0.0F;
     qreal lastCursorX = -1.0;
     qreal lastCursorY = -1.0;
     int selectionRefreshCounter = 0;
@@ -241,11 +246,11 @@ private:
     int height = 0;
   };
 
-  bool screenToGround(const QPointF &screenPt, QVector3D &outWorld);
-  bool worldToScreen(const QVector3D &world, QPointF &outScreen) const;
+  auto screenToGround(const QPointF &screenPt, QVector3D &outWorld) -> bool;
+  auto worldToScreen(const QVector3D &world, QPointF &outScreen) const -> bool;
   void syncSelectionFlags();
-  void resetMovement(Engine::Core::Entity *entity);
-  QObject *selectedUnitsModel();
+  static void resetMovement(Engine::Core::Entity *entity);
+  auto selectedUnitsModel() -> QObject *;
   void onUnitSpawned(const Engine::Core::UnitSpawnedEvent &event);
   void onUnitDied(const Engine::Core::UnitDiedEvent &event);
   void rebuildEntityCache();
@@ -254,11 +259,12 @@ private:
   void restoreEnvironmentFromMetadata(const QJsonObject &metadata);
   void updateCursor(Qt::CursorShape newCursor);
   void setError(const QString &errorMessage);
-  bool loadFromSlot(const QString &slot);
-  bool saveToSlot(const QString &slot, const QString &title);
-  Game::Systems::RuntimeSnapshot toRuntimeSnapshot() const;
+  auto loadFromSlot(const QString &slot) -> bool;
+  auto saveToSlot(const QString &slot, const QString &title) -> bool;
+  [[nodiscard]] auto
+  toRuntimeSnapshot() const -> Game::Systems::RuntimeSnapshot;
   void applyRuntimeSnapshot(const Game::Systems::RuntimeSnapshot &snapshot);
-  QByteArray captureScreenshot() const;
+  [[nodiscard]] auto captureScreenshot() const -> QByteArray;
 
   std::unique_ptr<Engine::Core::World> m_world;
   std::unique_ptr<Render::GL::Renderer> m_renderer;
@@ -286,7 +292,7 @@ private:
   std::unique_ptr<App::Controllers::CommandController> m_commandController;
   std::unique_ptr<Game::Map::MapCatalog> m_mapCatalog;
   std::unique_ptr<Game::Audio::AudioEventHandler> m_audioEventHandler;
-  std::unique_ptr<App::Models::AudioSystemProxy> m_audioSystemProxy;
+  std::unique_ptr<App::Models::AudioSystemProxy> m_audio_systemProxy;
   QQuickWindow *m_window = nullptr;
   RuntimeState m_runtime;
   ViewportState m_viewport;
@@ -304,11 +310,11 @@ private:
   EntityCache m_entityCache;
   Engine::Core::AmbientState m_currentAmbientState =
       Engine::Core::AmbientState::PEACEFUL;
-  float m_ambientCheckTimer = 0.0f;
+  float m_ambientCheckTimer = 0.0F;
 
   void updateAmbientState(float dt);
-  bool isPlayerInCombat() const;
-  void loadAudioResources();
+  [[nodiscard]] auto isPlayerInCombat() const -> bool;
+  static void loadAudioResources();
 signals:
   void selectedUnitsChanged();
   void selectedUnitsDataChanged();
@@ -316,7 +322,7 @@ signals:
   void victoryStateChanged();
   void cursorModeChanged();
   void globalCursorChanged();
-  void troopCountChanged();
+  void troop_countChanged();
   void availableMapsChanged();
   void ownerInfoChanged();
   void selectedPlayerIdChanged();

+ 19 - 11
app/core/language_manager.cpp

@@ -1,6 +1,11 @@
 #include "language_manager.h"
 #include <QCoreApplication>
 #include <QDebug>
+#include <qcoreapplication.h>
+#include <qglobal.h>
+#include <qobject.h>
+#include <qtmetamacros.h>
+#include <qtranslator.h>
 
 LanguageManager::LanguageManager(QObject *parent)
     : QObject(parent), m_currentLanguage("en"),
@@ -11,19 +16,21 @@ LanguageManager::LanguageManager(QObject *parent)
 #define DEFAULT_LANG "en"
 #endif
 
-  QString defaultLang = QString(DEFAULT_LANG);
-  if (m_availableLanguages.contains(defaultLang)) {
-    loadLanguage(defaultLang);
+  QString const default_lang = QString(DEFAULT_LANG);
+  if (m_availableLanguages.contains(default_lang)) {
+    loadLanguage(default_lang);
   } else {
     loadLanguage("en");
   }
 }
 
-LanguageManager::~LanguageManager() {}
+LanguageManager::~LanguageManager() = default;
 
-QString LanguageManager::currentLanguage() const { return m_currentLanguage; }
+auto LanguageManager::currentLanguage() const -> QString {
+  return m_currentLanguage;
+}
 
-QStringList LanguageManager::availableLanguages() const {
+auto LanguageManager::availableLanguages() const -> QStringList {
   return m_availableLanguages;
 }
 
@@ -39,23 +46,24 @@ void LanguageManager::setLanguage(const QString &language) {
 void LanguageManager::loadLanguage(const QString &language) {
   QCoreApplication::removeTranslator(m_translator);
 
-  QString qmFile =
+  QString const qm_file =
       QString(":/StandardOfIron/translations/app_%1.qm").arg(language);
 
-  if (m_translator->load(qmFile)) {
+  if (m_translator->load(qm_file)) {
     QCoreApplication::installTranslator(m_translator);
     m_currentLanguage = language;
     qInfo() << "Language changed to:" << language;
     emit languageChanged();
   } else {
-    qWarning() << "Failed to load translation file:" << qmFile;
+    qWarning() << "Failed to load translation file:" << qm_file;
   }
 }
 
-QString LanguageManager::languageDisplayName(const QString &language) const {
+QString LanguageManager::languageDisplayName(const QString &language) {
   if (language == "en") {
     return "English";
-  } else if (language == "de") {
+  }
+  if (language == "de") {
     return "Deutsch (German)";
   }
   return language;

+ 5 - 4
app/core/language_manager.h

@@ -12,13 +12,14 @@ class LanguageManager : public QObject {
 
 public:
   explicit LanguageManager(QObject *parent = nullptr);
-  ~LanguageManager();
+  ~LanguageManager() override;
 
-  QString currentLanguage() const;
-  QStringList availableLanguages() const;
+  [[nodiscard]] auto currentLanguage() const -> QString;
+  [[nodiscard]] auto availableLanguages() const -> QStringList;
 
   Q_INVOKABLE void setLanguage(const QString &language);
-  Q_INVOKABLE QString languageDisplayName(const QString &language) const;
+  Q_INVOKABLE [[nodiscard]] static QString
+  languageDisplayName(const QString &language);
 
 signals:
   void languageChanged();

+ 7 - 8
app/models/audio_system_proxy.cpp

@@ -1,8 +1,8 @@
 #include "audio_system_proxy.h"
 #include "game/audio/AudioSystem.h"
+#include <qobject.h>
 
-namespace App {
-namespace Models {
+namespace App::Models {
 
 AudioSystemProxy::AudioSystemProxy(QObject *parent) : QObject(parent) {}
 
@@ -22,21 +22,20 @@ void AudioSystemProxy::setVoiceVolume(float volume) {
   AudioSystem::getInstance().setVoiceVolume(volume);
 }
 
-float AudioSystemProxy::getMasterVolume() const {
+float AudioSystemProxy::getMasterVolume() {
   return AudioSystem::getInstance().getMasterVolume();
 }
 
-float AudioSystemProxy::getMusicVolume() const {
+float AudioSystemProxy::getMusicVolume() {
   return AudioSystem::getInstance().getMusicVolume();
 }
 
-float AudioSystemProxy::getSoundVolume() const {
+float AudioSystemProxy::getSoundVolume() {
   return AudioSystem::getInstance().getSoundVolume();
 }
 
-float AudioSystemProxy::getVoiceVolume() const {
+float AudioSystemProxy::getVoiceVolume() {
   return AudioSystem::getInstance().getVoiceVolume();
 }
 
-} // namespace Models
-} // namespace App
+} // namespace App::Models

+ 10 - 12
app/models/audio_system_proxy.h

@@ -2,8 +2,7 @@
 
 #include <QObject>
 
-namespace App {
-namespace Models {
+namespace App::Models {
 
 class AudioSystemProxy : public QObject {
   Q_OBJECT
@@ -11,16 +10,15 @@ public:
   explicit AudioSystemProxy(QObject *parent = nullptr);
   ~AudioSystemProxy() override = default;
 
-  Q_INVOKABLE void setMasterVolume(float volume);
-  Q_INVOKABLE void setMusicVolume(float volume);
-  Q_INVOKABLE void setSoundVolume(float volume);
-  Q_INVOKABLE void setVoiceVolume(float volume);
+  Q_INVOKABLE static void setMasterVolume(float volume);
+  Q_INVOKABLE static void setMusicVolume(float volume);
+  Q_INVOKABLE static void setSoundVolume(float volume);
+  Q_INVOKABLE static void setVoiceVolume(float volume);
 
-  Q_INVOKABLE float getMasterVolume() const;
-  Q_INVOKABLE float getMusicVolume() const;
-  Q_INVOKABLE float getSoundVolume() const;
-  Q_INVOKABLE float getVoiceVolume() const;
+  Q_INVOKABLE [[nodiscard]] static float getMasterVolume();
+  Q_INVOKABLE [[nodiscard]] static float getMusicVolume();
+  Q_INVOKABLE [[nodiscard]] static float getSoundVolume();
+  Q_INVOKABLE [[nodiscard]] static float getVoiceVolume();
 };
 
-} // namespace Models
-} // namespace App
+} // namespace App::Models

+ 22 - 15
app/models/cursor_manager.cpp

@@ -1,7 +1,14 @@
 #include "cursor_manager.h"
+#include "app/models/cursor_mode.h"
 #include <QCursor>
 #include <QPoint>
 #include <QQuickWindow>
+#include <qglobal.h>
+#include <qnamespace.h>
+#include <qobject.h>
+#include <qpoint.h>
+#include <qtmetamacros.h>
+#include <qvectornd.h>
 
 CursorManager::CursorManager(QObject *parent) : QObject(parent) {}
 
@@ -25,35 +32,35 @@ void CursorManager::setMode(const QString &mode) {
 }
 
 void CursorManager::updateCursorShape(QQuickWindow *window) {
-  if (!window) {
+  if (window == nullptr) {
     return;
   }
 
-  Qt::CursorShape desiredCursor =
+  Qt::CursorShape const desired_cursor =
       (m_cursorMode == CursorMode::Normal) ? Qt::ArrowCursor : Qt::BlankCursor;
 
-  if (m_currentCursor != desiredCursor) {
-    m_currentCursor = desiredCursor;
-    window->setCursor(desiredCursor);
+  if (m_currentCursor != desired_cursor) {
+    m_currentCursor = desired_cursor;
+    window->setCursor(desired_cursor);
   }
 }
 
-qreal CursorManager::globalCursorX(QQuickWindow *window) const {
-  if (!window) {
+qreal CursorManager::globalCursorX(QQuickWindow *window) {
+  if (window == nullptr) {
     return 0;
   }
-  QPoint globalPos = QCursor::pos();
-  QPoint localPos = window->mapFromGlobal(globalPos);
-  return localPos.x();
+  QPoint const global_pos = QCursor::pos();
+  QPoint const local_pos = window->mapFromGlobal(global_pos);
+  return local_pos.x();
 }
 
-qreal CursorManager::globalCursorY(QQuickWindow *window) const {
-  if (!window) {
+qreal CursorManager::globalCursorY(QQuickWindow *window) {
+  if (window == nullptr) {
     return 0;
   }
-  QPoint globalPos = QCursor::pos();
-  QPoint localPos = window->mapFromGlobal(globalPos);
-  return localPos.y();
+  QPoint const global_pos = QCursor::pos();
+  QPoint const local_pos = window->mapFromGlobal(global_pos);
+  return local_pos.y();
 }
 
 void CursorManager::setPatrolFirstWaypoint(const QVector3D &waypoint) {

+ 12 - 6
app/models/cursor_manager.h

@@ -13,20 +13,26 @@ class CursorManager : public QObject {
 public:
   explicit CursorManager(QObject *parent = nullptr);
 
-  CursorMode mode() const { return m_cursorMode; }
+  [[nodiscard]] auto mode() const -> CursorMode { return m_cursorMode; }
   void setMode(CursorMode mode);
   void setMode(const QString &mode);
-  QString modeString() const { return CursorModeUtils::toString(m_cursorMode); }
+  [[nodiscard]] auto modeString() const -> QString {
+    return CursorModeUtils::toString(m_cursorMode);
+  }
 
   void updateCursorShape(QQuickWindow *window);
 
-  qreal globalCursorX(QQuickWindow *window) const;
-  qreal globalCursorY(QQuickWindow *window) const;
+  static auto globalCursorX(QQuickWindow *window) -> qreal;
+  static auto globalCursorY(QQuickWindow *window) -> qreal;
 
-  bool hasPatrolFirstWaypoint() const { return m_hasFirstWaypoint; }
+  [[nodiscard]] auto hasPatrolFirstWaypoint() const -> bool {
+    return m_hasFirstWaypoint;
+  }
   void setPatrolFirstWaypoint(const QVector3D &waypoint);
   void clearPatrolFirstWaypoint();
-  QVector3D getPatrolFirstWaypoint() const { return m_firstWaypoint; }
+  [[nodiscard]] auto getPatrolFirstWaypoint() const -> QVector3D {
+    return m_firstWaypoint;
+  }
 
 signals:
   void modeChanged();

+ 8 - 6
app/models/cursor_mode.h

@@ -6,7 +6,7 @@ enum class CursorMode { Normal, Patrol, Attack };
 
 namespace CursorModeUtils {
 
-inline QString toString(CursorMode mode) {
+inline auto toString(CursorMode mode) -> QString {
   switch (mode) {
   case CursorMode::Normal:
     return "normal";
@@ -18,17 +18,19 @@ inline QString toString(CursorMode mode) {
   return "normal";
 }
 
-inline CursorMode fromString(const QString &str) {
-  if (str == "patrol")
+inline auto fromString(const QString &str) -> CursorMode {
+  if (str == "patrol") {
     return CursorMode::Patrol;
-  if (str == "attack")
+  }
+  if (str == "attack") {
     return CursorMode::Attack;
+  }
   return CursorMode::Normal;
 }
 
-inline int toInt(CursorMode mode) { return static_cast<int>(mode); }
+inline auto toInt(CursorMode mode) -> int { return static_cast<int>(mode); }
 
-inline CursorMode fromInt(int value) {
+inline auto fromInt(int value) -> CursorMode {
   switch (value) {
   case 0:
     return CursorMode::Normal;

+ 7 - 6
app/models/hover_tracker.cpp

@@ -1,15 +1,16 @@
 #include "hover_tracker.h"
 #include "game/core/world.h"
 #include "render/gl/camera.h"
+#include "systems/picking_service.h"
 
 HoverTracker::HoverTracker(Game::Systems::PickingService *pickingService)
-    : m_pickingService(pickingService), m_hoveredEntityId(0) {}
+    : m_pickingService(pickingService) {}
 
-Engine::Core::EntityID
-HoverTracker::updateHover(float sx, float sy, Engine::Core::World &world,
-                          const Render::GL::Camera &camera, int viewportWidth,
-                          int viewportHeight) {
-  if (!m_pickingService) {
+auto HoverTracker::updateHover(float sx, float sy, Engine::Core::World &world,
+                               const Render::GL::Camera &camera,
+                               int viewportWidth,
+                               int viewportHeight) -> Engine::Core::EntityID {
+  if (m_pickingService == nullptr) {
     return 0;
   }
 

+ 7 - 12
app/models/hover_tracker.h

@@ -3,29 +3,24 @@
 #include "game/systems/picking_service.h"
 #include <memory>
 
-namespace Engine {
-namespace Core {
+namespace Engine::Core {
 class World;
 using EntityID = unsigned int;
-} // namespace Core
-} // namespace Engine
+} // namespace Engine::Core
 
-namespace Render {
-namespace GL {
+namespace Render::GL {
 class Camera;
 }
-} // namespace Render
 
 class HoverTracker {
 public:
   HoverTracker(Game::Systems::PickingService *pickingService);
 
-  Engine::Core::EntityID updateHover(float sx, float sy,
-                                     Engine::Core::World &world,
-                                     const Render::GL::Camera &camera,
-                                     int viewportWidth, int viewportHeight);
+  auto updateHover(float sx, float sy, Engine::Core::World &world,
+                   const Render::GL::Camera &camera, int viewportWidth,
+                   int viewportHeight) -> Engine::Core::EntityID;
 
-  Engine::Core::EntityID getLastHoveredEntity() const {
+  [[nodiscard]] auto getLastHoveredEntity() const -> Engine::Core::EntityID {
     return m_hoveredEntityId;
   }
 

+ 35 - 25
app/models/selected_units_model.cpp

@@ -1,36 +1,44 @@
 #include "selected_units_model.h"
-#include "../../game/core/component.h"
-#include "../../game/core/world.h"
-#include "../../game/systems/selection_system.h"
 #include "../core/game_engine.h"
 #include <algorithm>
+#include <qabstractitemmodel.h>
+#include <qhash.h>
+#include <qhashfunctions.h>
+#include <qobject.h>
+#include <qstringview.h>
+#include <qtmetamacros.h>
+#include <qvariant.h>
+#include <vector>
 
 SelectedUnitsModel::SelectedUnitsModel(GameEngine *engine, QObject *parent)
     : QAbstractListModel(parent), m_engine(engine) {}
 
-int SelectedUnitsModel::rowCount(const QModelIndex &parent) const {
+auto SelectedUnitsModel::rowCount(const QModelIndex &parent) const -> int {
   if (parent.isValid()) {
     return 0;
   }
   return static_cast<int>(m_ids.size());
 }
 
-QVariant SelectedUnitsModel::data(const QModelIndex &index, int role) const {
+auto SelectedUnitsModel::data(const QModelIndex &index,
+                              int role) const -> QVariant {
   if (!index.isValid() || index.row() < 0 ||
       index.row() >= static_cast<int>(m_ids.size())) {
     return {};
   }
   auto id = m_ids[index.row()];
-  if (!m_engine) {
+  if (m_engine == nullptr) {
     return {};
   }
   QString name;
-  int hp = 0, maxHp = 0;
-  bool isB = false, alive = false;
+  int hp = 0;
+  int max_hp = 0;
+  bool isB = false;
+  bool alive = false;
   if (role == UnitIdRole) {
     return QVariant::fromValue<int>(static_cast<int>(id));
   }
-  if (!m_engine->getUnitInfo(id, name, hp, maxHp, isB, alive)) {
+  if (!m_engine->getUnitInfo(id, name, hp, max_hp, isB, alive)) {
     return {};
   }
   if (role == NameRole) {
@@ -39,27 +47,27 @@ QVariant SelectedUnitsModel::data(const QModelIndex &index, int role) const {
   if (role == HealthRole) {
     return hp;
   }
-  if (role == MaxHealthRole) {
-    return maxHp;
+  if (role == max_healthRole) {
+    return max_hp;
   }
   if (role == HealthRatioRole) {
-    return (maxHp > 0 ? static_cast<double>(std::clamp(hp, 0, maxHp)) /
-                            static_cast<double>(maxHp)
-                      : 0.0);
+    return (max_hp > 0 ? static_cast<double>(std::clamp(hp, 0, max_hp)) /
+                             static_cast<double>(max_hp)
+                       : 0.0);
   }
   return {};
 }
 
-QHash<int, QByteArray> SelectedUnitsModel::roleNames() const {
-  return {{UnitIdRole, "unitId"},
+auto SelectedUnitsModel::roleNames() const -> QHash<int, QByteArray> {
+  return {{UnitIdRole, "unit_id"},
           {NameRole, "name"},
           {HealthRole, "health"},
-          {MaxHealthRole, "maxHealth"},
-          {HealthRatioRole, "healthRatio"}};
+          {max_healthRole, "max_health"},
+          {HealthRatioRole, "health_ratio"}};
 }
 
 void SelectedUnitsModel::refresh() {
-  if (!m_engine) {
+  if (m_engine == nullptr) {
     return;
   }
   std::vector<Engine::Core::EntityID> ids;
@@ -68,10 +76,10 @@ void SelectedUnitsModel::refresh() {
   if (ids.size() == m_ids.size() &&
       std::equal(ids.begin(), ids.end(), m_ids.begin())) {
     if (!m_ids.empty()) {
-      QModelIndex first = index(0, 0);
-      QModelIndex last = index(static_cast<int>(m_ids.size()) - 1, 0);
+      QModelIndex const first = index(0, 0);
+      QModelIndex const last = index(static_cast<int>(m_ids.size()) - 1, 0);
       emit dataChanged(first, last,
-                       {HealthRole, MaxHealthRole, HealthRatioRole});
+                       {HealthRole, max_healthRole, HealthRatioRole});
     }
     return;
   }
@@ -81,9 +89,11 @@ void SelectedUnitsModel::refresh() {
   m_ids.clear();
   for (auto id : ids) {
     QString nm;
-    int hp = 0, maxHp = 0;
-    bool isB = false, alive = false;
-    if (!m_engine->getUnitInfo(id, nm, hp, maxHp, isB, alive)) {
+    int hp = 0;
+    int max_hp = 0;
+    bool isB = false;
+    bool alive = false;
+    if (!m_engine->getUnitInfo(id, nm, hp, max_hp, isB, alive)) {
       continue;
     }
     if (isB) {

+ 7 - 6
app/models/selected_units_model.h

@@ -13,18 +13,19 @@ public:
     UnitIdRole = Qt::UserRole + 1,
     NameRole,
     HealthRole,
-    MaxHealthRole,
+    max_healthRole,
     HealthRatioRole
   };
 
   explicit SelectedUnitsModel(GameEngine *engine, QObject *parent = nullptr);
 
-  int rowCount(const QModelIndex &parent = QModelIndex()) const override;
-  QVariant data(const QModelIndex &index,
-                int role = Qt::DisplayRole) const override;
-  QHash<int, QByteArray> roleNames() const override;
+  [[nodiscard]] auto
+  rowCount(const QModelIndex &parent = QModelIndex()) const -> int override;
+  [[nodiscard]] auto
+  data(const QModelIndex &index,
+       int role = Qt::DisplayRole) const -> QVariant override;
+  [[nodiscard]] auto roleNames() const -> QHash<int, QByteArray> override;
 
-public slots:
   void refresh();
 
 private:

+ 16 - 14
app/utils/engine_view_helpers.h

@@ -6,32 +6,34 @@
 #include <QQuickWindow>
 #include <QVector3D>
 
-namespace App {
-namespace Utils {
+namespace App::Utils {
 
-inline bool screenToGround(const Game::Systems::PickingService *pickingService,
+inline auto screenToGround(const Game::Systems::PickingService *pickingService,
                            const Render::GL::Camera *camera,
                            QQuickWindow *window, int viewportWidth,
                            int viewportHeight, const QPointF &screenPt,
-                           QVector3D &outWorld) {
-  if (!window || !camera || !pickingService)
+                           QVector3D &outWorld) -> bool {
+  if ((window == nullptr) || (camera == nullptr) ||
+      (pickingService == nullptr)) {
     return false;
-  int w = (viewportWidth > 0 ? viewportWidth : window->width());
-  int h = (viewportHeight > 0 ? viewportHeight : window->height());
+  }
+  int const w = (viewportWidth > 0 ? viewportWidth : window->width());
+  int const h = (viewportHeight > 0 ? viewportHeight : window->height());
   return pickingService->screenToGround(*camera, w, h, screenPt, outWorld);
 }
 
-inline bool worldToScreen(const Game::Systems::PickingService *pickingService,
+inline auto worldToScreen(const Game::Systems::PickingService *pickingService,
                           const Render::GL::Camera *camera,
                           QQuickWindow *window, int viewportWidth,
                           int viewportHeight, const QVector3D &world,
-                          QPointF &outScreen) {
-  if (!window || !camera || !pickingService)
+                          QPointF &outScreen) -> bool {
+  if ((window == nullptr) || (camera == nullptr) ||
+      (pickingService == nullptr)) {
     return false;
-  int w = (viewportWidth > 0 ? viewportWidth : window->width());
-  int h = (viewportHeight > 0 ? viewportHeight : window->height());
+  }
+  int const w = (viewportWidth > 0 ? viewportWidth : window->width());
+  int const h = (viewportHeight > 0 ? viewportHeight : window->height());
   return pickingService->worldToScreen(*camera, w, h, world, outScreen);
 }
 
-} // namespace Utils
-} // namespace App
+} // namespace App::Utils

+ 10 - 9
app/utils/json_vec_utils.cpp

@@ -1,9 +1,10 @@
 #include "json_vec_utils.h"
+#include <qjsonarray.h>
+#include <qvectornd.h>
 
-namespace App {
-namespace JsonUtils {
+namespace App::JsonUtils {
 
-QJsonArray vec3ToJsonArray(const QVector3D &vec) {
+auto vec3ToJsonArray(const QVector3D &vec) -> QJsonArray {
   QJsonArray arr;
   arr.append(vec.x());
   arr.append(vec.y());
@@ -11,7 +12,8 @@ QJsonArray vec3ToJsonArray(const QVector3D &vec) {
   return arr;
 }
 
-QVector3D jsonArrayToVec3(const QJsonValue &value, const QVector3D &fallback) {
+auto jsonArrayToVec3(const QJsonValue &value,
+                     const QVector3D &fallback) -> QVector3D {
   if (!value.isArray()) {
     return fallback;
   }
@@ -19,10 +21,9 @@ QVector3D jsonArrayToVec3(const QJsonValue &value, const QVector3D &fallback) {
   if (arr.size() < 3) {
     return fallback;
   }
-  return QVector3D(static_cast<float>(arr.at(0).toDouble(fallback.x())),
-                   static_cast<float>(arr.at(1).toDouble(fallback.y())),
-                   static_cast<float>(arr.at(2).toDouble(fallback.z())));
+  return {static_cast<float>(arr.at(0).toDouble(fallback.x())),
+          static_cast<float>(arr.at(1).toDouble(fallback.y())),
+          static_cast<float>(arr.at(2).toDouble(fallback.z()))};
 }
 
-} // namespace JsonUtils
-} // namespace App
+} // namespace App::JsonUtils

+ 5 - 6
app/utils/json_vec_utils.h

@@ -4,12 +4,11 @@
 #include <QJsonValue>
 #include <QVector3D>
 
-namespace App {
-namespace JsonUtils {
+namespace App::JsonUtils {
 
-QJsonArray vec3ToJsonArray(const QVector3D &vec);
+auto vec3ToJsonArray(const QVector3D &vec) -> QJsonArray;
 
-QVector3D jsonArrayToVec3(const QJsonValue &value, const QVector3D &fallback);
+auto jsonArrayToVec3(const QJsonValue &value,
+                     const QVector3D &fallback) -> QVector3D;
 
-} // namespace JsonUtils
-} // namespace App
+} // namespace App::JsonUtils

+ 14 - 14
app/utils/movement_utils.h

@@ -3,35 +3,35 @@
 #include "game/core/component.h"
 #include "game/core/entity.h"
 
-namespace App {
-namespace Utils {
+namespace App::Utils {
 
 inline void resetMovement(Engine::Core::Entity *entity) {
-  if (!entity)
+  if (entity == nullptr) {
     return;
+  }
 
   auto *movement = entity->getComponent<Engine::Core::MovementComponent>();
-  if (!movement)
+  if (movement == nullptr) {
     return;
+  }
 
   auto *transform = entity->getComponent<Engine::Core::TransformComponent>();
   movement->hasTarget = false;
   movement->path.clear();
   movement->pathPending = false;
   movement->pendingRequestId = 0;
-  movement->repathCooldown = 0.0f;
-  if (transform) {
-    movement->targetX = transform->position.x;
-    movement->targetY = transform->position.z;
+  movement->repathCooldown = 0.0F;
+  if (transform != nullptr) {
+    movement->target_x = transform->position.x;
+    movement->target_y = transform->position.z;
     movement->goalX = transform->position.x;
     movement->goalY = transform->position.z;
   } else {
-    movement->targetX = 0.0f;
-    movement->targetY = 0.0f;
-    movement->goalX = 0.0f;
-    movement->goalY = 0.0f;
+    movement->target_x = 0.0F;
+    movement->target_y = 0.0F;
+    movement->goalX = 0.0F;
+    movement->goalY = 0.0F;
   }
 }
 
-} // namespace Utils
-} // namespace App
+} // namespace App::Utils

+ 14 - 12
app/utils/selection_utils.h

@@ -7,31 +7,33 @@
 #include <algorithm>
 #include <vector>
 
-namespace App {
-namespace Utils {
+namespace App::Utils {
 
-inline void sanitizeSelection(Engine::Core::World *world,
-                              Game::Systems::SelectionSystem *selectionSystem) {
-  if (!world || !selectionSystem)
+inline void
+sanitizeSelection(Engine::Core::World *world,
+                  Game::Systems::SelectionSystem *selection_system) {
+  if ((world == nullptr) || (selection_system == nullptr)) {
     return;
-  const auto &sel = selectionSystem->getSelectedUnits();
+  }
+  const auto &sel = selection_system->getSelectedUnits();
   std::vector<Engine::Core::EntityID> toKeep;
   toKeep.reserve(sel.size());
   for (auto id : sel) {
     if (auto *e = world->getEntity(id)) {
       if (auto *u = e->getComponent<Engine::Core::UnitComponent>()) {
-        if (u->health > 0)
+        if (u->health > 0) {
           toKeep.push_back(id);
+        }
       }
     }
   }
   if (toKeep.size() != sel.size() ||
       !std::equal(toKeep.begin(), toKeep.end(), sel.begin())) {
-    selectionSystem->clearSelection();
-    for (auto id : toKeep)
-      selectionSystem->selectUnit(id);
+    selection_system->clearSelection();
+    for (auto id : toKeep) {
+      selection_system->selectUnit(id);
+    }
   }
 }
 
-} // namespace Utils
-} // namespace App
+} // namespace App::Utils

+ 1 - 1
assets/shaders/basic.frag

@@ -81,4 +81,4 @@ void main() {
 
   color *= diff;
   FragColor = vec4(color, u_alpha);
-}
+}

+ 60 - 50
assets/shaders/bridge.frag

@@ -1,12 +1,14 @@
 #version 330 core
 
-in vec3 v_normal;
-in vec2 v_texCoord;
-in vec3 v_worldPos;
+in vec3 v_normal;   // world-space normal
+in vec2 v_texCoord; // mesh UVs (used for optional fog/dirt overlay)
+in vec3 v_worldPos; // world-space position
 
-uniform vec3 u_color;
-uniform vec3 u_lightDirection;
-uniform sampler2D u_fogTexture;
+uniform vec3 u_color; // base stone tint
+uniform vec3
+    u_lightDirection; // world-space light dir (doesn't need to be normalized)
+uniform sampler2D
+    u_fogTexture; // optional fog/dirt mask (0..1), tiled in UV space
 
 out vec4 FragColor;
 
@@ -15,12 +17,14 @@ out vec4 FragColor;
 // ------------------------------------------------------------
 const float PI = 3.14159265359;
 
+float saturate(float x) { return clamp(x, 0.0, 1.0); }
+
 mat2 rot(float a) {
   float c = cos(a), s = sin(a);
   return mat2(c, -s, s, c);
 }
 
-// Simple hash / noise (compatible with your original)
+// Hash / Noise
 float hash(vec2 p) {
   vec3 p3 = fract(vec3(p.xyx) * 0.1031);
   p3 += dot(p3, p3.yzx + 33.33);
@@ -37,15 +41,16 @@ float noise(vec2 p) {
   return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
 }
 float fbm(vec2 p) {
-  float v = 0.0, a = 0.5, f = 1.0;
-  for (int i = 0; i < 5; i++) {
-    v += a * noise(p * f);
-    f *= 2.0;
+  float v = 0.0, a = 0.5;
+  for (int i = 0; i < 5; ++i) {
+    v += a * noise(p);
+    p *= 2.0;
     a *= 0.5;
   }
   return v;
 }
-// 2D random vector
+
+// 2D random vector for Worley
 vec2 hash2(vec2 p) {
   float n = sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123;
   return fract(vec2(n, n * 1.2154));
@@ -57,11 +62,13 @@ vec2 worleyF(vec2 p) {
   vec2 f = fract(p);
   float F1 = 1e9;
   float F2 = 1e9;
-  for (int j = -1; j <= 1; j++) {
-    for (int i = -1; i <= 1; i++) {
+  for (int j = -1; j <= 1; ++j) {
+    for (int i = -1; i <= 1; ++i) {
       vec2 g = vec2(float(i), float(j));
       vec2 o = hash2(n + g);
-      vec2 r = g + o - f;
+      vec2 r =
+          (g + o) -
+          f; // distance from current frac coord to neighbor's jittered center
       float d = dot(r, r);
       if (d < F1) {
         F2 = F1;
@@ -90,57 +97,52 @@ float ggxSpecular(vec3 N, vec3 V, vec3 L, float rough, float F0) {
   float a = max(rough * rough, 0.001);
   float a2 = a * a;
   float denom = (NdotH * NdotH * (a2 - 1.0) + 1.0);
-  float D = a2 / (PI * denom * denom);
+  float D = a2 / max(PI * denom * denom, 1e-4);
 
   float k = (a + 1.0);
-  k = (k * k) / 8.0;
+  k = (k * k) * 0.125; // (a+1)^2 / 8
   float Gv = NdotV / (NdotV * (1.0 - k) + k);
   float Gl = NdotL / (NdotL * (1.0 - k) + k);
   float G = Gv * Gl;
 
   float F = fresnelSchlick(VdotH, F0);
-  return (D * G * F) / max(4.0 * NdotV * NdotL, 0.001);
+  return (D * G * F) / max(4.0 * NdotV * NdotL, 1e-4);
 }
 
 // ------------------------------------------------------------
 // Main
 // ------------------------------------------------------------
 void main() {
-  // -----------------------------
-  // Procedural medieval stones
-  // -----------------------------
-  // World-anchored UVs to avoid tiling with mesh UVs
+  // World-anchored mapping to avoid UV tiling
   vec2 uv = v_worldPos.xz * 0.6;
 
-  // Irregular stone layout via Voronoi
-  // F1 = distance to cell center; F2-F1 is small near borders (mortar)
+  // Irregular stone layout via Worley
   vec2 F = worleyF(uv * 1.2);
-  float edgeMetric = F.y - F.x; // smaller near borders
+  float edgeMetric = F.y - F.x; // small near borders (mortar)
   float stoneMask =
-      smoothstep(0.05, 0.30, edgeMetric); // 1 inside stones, 0 at mortar
+      smoothstep(0.05, 0.30, edgeMetric); // 1 inside stones, 0 mortar
   float mortarMask = 1.0 - stoneMask;
 
-  // Subtly vary stone shapes (non-uniform scaling & rotation per cell)
+  // Per-cell jitter to vary stone shapes
   vec2 cell = floor(uv * 1.2);
   float cellRnd = hash(cell);
-  vec2 uvVar = (rot(cellRnd * 6.2831) * (uv - floor(uv))) + cell; // shape drift
+  vec2 local = fract(uv); // local coords inside cell (0..1)
+  vec2 uvVar = (rot(cellRnd * 6.2831853) * (local - 0.5) + 0.5) +
+               floor(uv); // shape drift
 
-  // Albedo variation: low-frequency tint + mid/high-frequency grain
+  // Albedo variation
   float varLow = (fbm(uv * 0.5) - 0.5) * 0.20;
   float varMid = (fbm(uvVar * 3.0) - 0.5) * 0.15;
   float grain = (noise(uvVar * 18.0) - 0.5) * 0.08;
 
-  vec3 stoneColor = u_color;
-  stoneColor *= (1.0 + varLow + varMid + grain);
+  vec3 stoneColor = u_color * (1.0 + varLow + varMid + grain);
+  vec3 mortarColor = u_color * 0.55; // keep mortar darker & flatter
 
-  // Damp variation in mortar so it stays darker & flatter
-  vec3 mortarColor = stoneColor * 0.55;
-
-  // Micro cracks inside stones (non-repeating lines)
+  // Micro cracks inside stones
   float crack = smoothstep(0.02, 0.0, abs(noise(uv * 10.0) - 0.5)) * 0.25;
   stoneColor *= (1.0 - crack * stoneMask);
 
-  // Ambient occlusion / cavity darkening near mortar edges
+  // Ambient occlusion / cavity
   float cavity = smoothstep(0.0, 0.18, edgeMetric); // 0 at border, 1 inside
   float ao = mix(0.55, 1.0, cavity) * (0.92 + 0.08 * fbm(uv * 2.5));
 
@@ -150,45 +152,53 @@ void main() {
   float mortarDip = -0.06 * mortarMask;
   float h = microBump + macroWarp + mortarDip;
 
-  // Normal from screen-space derivatives of height
+  // Normal perturbation from screen-space height derivatives
   float sx = dFdx(h);
   float sy = dFdy(h);
-  float strength = 14.0; // increase for sharper normals
-  vec3 N = normalize(vec3(-sx * strength, 1.0, -sy * strength));
+  float bumpStrength = 14.0; // increase for sharper normals
+  vec3 nBump = normalize(vec3(-sx * bumpStrength, 1.0, -sy * bumpStrength));
+
+  // Blend with geometric normal to keep stability
+  vec3 Ng = normalize(v_normal);
+  vec3 N = normalize(mix(Ng, nBump, 0.65));
 
   // Lighting vectors
   vec3 L = normalize(u_lightDirection);
-  vec3 V =
-      normalize(vec3(0.0, 0.9, 0.4)); // plausible view dir without new uniforms
+  vec3 V = normalize(vec3(0.0, 0.9, 0.4)); // plausible fixed view dir
 
   // Diffuse (Lambert) + AO
   float NdotL = max(dot(N, L), 0.0);
   float diffuse = NdotL;
 
   // Roughness varies: smoother on worn tops, rougher near edges
-  float steep = clamp(length(vec2(sx, sy)) * strength, 0.0, 1.0);
-  float roughness = mix(0.65, 0.95, steep); // chippy edges are rougher
-  float F0 = 0.035;                         // dielectric stone
+  float steep = saturate(length(vec2(sx, sy)) * bumpStrength);
+  float roughness = clamp(mix(0.65, 0.95, steep), 0.02, 1.0);
+  float F0 = 0.035; // dielectric stone
 
   float spec = ggxSpecular(N, V, L, roughness, F0);
 
-  // Base color blend: pick stone vs mortar, then apply AO
+  // Base color: stone vs mortar
   vec3 baseColor = mix(mortarColor, stoneColor, stoneMask);
-  vec3 litColor = baseColor * (0.35 + 0.70 * diffuse) * ao;
 
-  // Add subtle warm bounce and cool skylight without extra uniforms
+  // Simple hemispheric fill
   vec3 hemiSky = vec3(0.18, 0.24, 0.30);
   vec3 hemiGround = vec3(0.12, 0.10, 0.09);
   float hemi = N.y * 0.5 + 0.5;
-  litColor += mix(hemiGround, hemiSky, hemi) * 0.15;
 
-  // Specular highlight (very subtle on stone)
-  litColor += vec3(1.0) * spec * 0.25;
+  vec3 litColor = baseColor * (0.35 + 0.70 * diffuse) * ao;
+  litColor += mix(hemiGround, hemiSky, hemi) * 0.15; // skylight
+  litColor += vec3(1.0) * spec * 0.25;               // subtle spec
 
   // Dirt/grime accumulation in cavities (slight desaturation & darken)
   float grime = (1.0 - cavity) * 0.25 * (0.8 + 0.2 * noise(uv * 7.0));
   float gray = dot(litColor, vec3(0.299, 0.587, 0.114));
   litColor = mix(litColor, vec3(gray * 0.9), grime);
 
+  // Optional fog/dirt overlay from texture (soft multiply; leave at 1 if
+  // unused)
+  float fogMask = texture(u_fogTexture, v_texCoord).r; // 0..1
+  float fogAmt = 1.0 - fogMask; // treat dark as “more fog/dirt”
+  litColor *= mix(1.0, 0.85, fogAmt * 0.5);
+
   FragColor = vec4(litColor, 1.0);
 }

+ 1 - 1
assets/shaders/mounted_knight.frag

@@ -44,7 +44,7 @@ float fbm(vec2 p) {
     p *= 2.03;
     a *= 0.5;
   }
-  return f;
+  return F;
 }
 
 // anti-aliased step

+ 7 - 7
assets/shaders/terrain_chunk.frag

@@ -95,8 +95,8 @@ float sampleHeight(vec2 uv) {
 
 // --- world <-> UV helpers for height texture sampling (FIX ADD) ---
 vec2 uvToWorld(vec2 duv) {
-  // uv = worldXZ * u_heightUVScale + u_heightUVOffset
-  // => worldXZ delta per uv delta = duv / u_heightUVScale (component-wise)
+  // uv = world_xz * u_heightUVScale + u_heightUVOffset
+  // => world_xz delta per uv delta = duv / u_heightUVScale (component-wise)
   return duv / max(abs(u_heightUVScale), vec2(1e-6));
 }
 
@@ -146,15 +146,15 @@ void main() {
   float curvature = computeCurvature();
 
   float tileScale = max(u_tileSize, 0.0001);
-  vec2 worldCoord = (v_worldPos.xz / tileScale) + u_noiseOffset;
+  vec2 world_coord = (v_worldPos.xz / tileScale) + u_noiseOffset;
 
-  float macroNoise = fbm(worldCoord * u_macroNoiseScale);
+  float macroNoise = fbm(world_coord * u_macroNoiseScale);
   float detailNoise =
       triplanarNoise(v_worldPos, u_detailNoiseScale * 2.5 / tileScale);
   float erosionNoise =
       triplanarNoise(v_worldPos, u_detailNoiseScale * 4.0 / tileScale + 17.0);
 
-  float patchNoise = fbm(worldCoord * u_macroNoiseScale * 0.4);
+  float patchNoise = fbm(world_coord * u_macroNoiseScale * 0.4);
   float moistureVar = smoothstep(0.3, 0.7, patchNoise);
   float lushFactor = smoothstep(0.2, 0.8, macroNoise);
   lushFactor = mix(lushFactor, moistureVar, 0.3);
@@ -210,7 +210,7 @@ void main() {
                                    soilHeight + bandWidth, v_worldPos.y);
   soilMix = clamp(soilMix, 0.0, 1.0);
 
-  float mudPatch = fbm(worldCoord * 0.08 + vec2(7.3, 11.2));
+  float mudPatch = fbm(world_coord * 0.08 + vec2(7.3, 11.2));
   mudPatch = smoothstep(0.65, 0.75, mudPatch);
   soilMix = max(soilMix, mudPatch * 0.85 * (1.0 - slope * 0.6));
 
@@ -261,7 +261,7 @@ void main() {
   vec3 terrainColor = mix(soilBlend, rockColor, rockMask);
 
   // albedo jitter
-  float jitter = (hash21(worldCoord * 0.27 + vec2(17.0, 9.0)) - 0.5) * 0.06;
+  float jitter = (hash21(world_coord * 0.27 + vec2(17.0, 9.0)) - 0.5) * 0.06;
   float brightnessVar = (moistureVar - 0.5) * 0.08 * (1.0 - rockMask);
   terrainColor *= (1.0 + jitter + brightnessVar) * u_tint;
 

+ 27 - 24
game/audio/AudioEventHandler.cpp

@@ -3,16 +3,19 @@
 #include "../core/entity.h"
 #include "../core/world.h"
 #include "AudioSystem.h"
+#include "core/event_manager.h"
+#include "units/spawn_type.h"
+#include <chrono>
+#include <string>
 
-namespace Game {
-namespace Audio {
+namespace Game::Audio {
 
 AudioEventHandler::AudioEventHandler(Engine::Core::World *world)
-    : m_world(world), m_initialized(false), m_useVoiceCategory(true) {}
+    : m_world(world) {}
 
 AudioEventHandler::~AudioEventHandler() { shutdown(); }
 
-bool AudioEventHandler::initialize() {
+auto AudioEventHandler::initialize() -> bool {
   if (m_initialized) {
     return true;
   }
@@ -61,9 +64,9 @@ void AudioEventHandler::shutdown() {
   m_initialized = false;
 }
 
-void AudioEventHandler::loadUnitVoiceMapping(const std::string &unitType,
+void AudioEventHandler::loadUnitVoiceMapping(const std::string &unit_type,
                                              const std::string &soundId) {
-  m_unitVoiceMap[unitType] = soundId;
+  m_unitVoiceMap[unit_type] = soundId;
 }
 
 void AudioEventHandler::loadAmbientMusic(Engine::Core::AmbientState state,
@@ -77,47 +80,48 @@ void AudioEventHandler::setVoiceSoundCategory(bool useVoiceCategory) {
 
 void AudioEventHandler::onUnitSelected(
     const Engine::Core::UnitSelectedEvent &event) {
-  if (!m_world) {
+  if (m_world == nullptr) {
     return;
   }
 
-  auto *entity = m_world->getEntity(event.unitId);
-  if (!entity) {
+  auto *entity = m_world->getEntity(event.unit_id);
+  if (entity == nullptr) {
     return;
   }
 
-  auto *unitComponent = entity->getComponent<Engine::Core::UnitComponent>();
-  if (!unitComponent) {
+  auto *unit_component = entity->getComponent<Engine::Core::UnitComponent>();
+  if (unit_component == nullptr) {
     return;
   }
 
-  std::string unitTypeStr =
-      Game::Units::spawnTypeToString(unitComponent->spawnType);
-  auto it = m_unitVoiceMap.find(unitTypeStr);
+  std::string const unit_type_str =
+      Game::Units::spawn_typeToString(unit_component->spawn_type);
+  auto it = m_unitVoiceMap.find(unit_type_str);
   if (it != m_unitVoiceMap.end()) {
     auto now = std::chrono::steady_clock::now();
-    auto timeSinceLastSound =
+    auto time_since_last_sound =
         std::chrono::duration_cast<std::chrono::milliseconds>(
             now - m_lastSelectionSoundTime)
             .count();
 
-    bool shouldPlay = (timeSinceLastSound >= SELECTION_SOUND_COOLDOWN_MS) ||
-                      (unitTypeStr != m_lastSelectionUnitType);
+    bool const should_play =
+        (time_since_last_sound >= SELECTION_SOUND_COOLDOWN_MS) ||
+        (unit_type_str != m_lastSelectionUnitType);
 
-    if (shouldPlay) {
-      AudioCategory category =
+    if (should_play) {
+      AudioCategory const category =
           m_useVoiceCategory ? AudioCategory::VOICE : AudioCategory::SFX;
-      AudioSystem::getInstance().playSound(it->second, 1.0f, false, 5,
+      AudioSystem::getInstance().playSound(it->second, 1.0F, false, 5,
                                            category);
       m_lastSelectionSoundTime = now;
-      m_lastSelectionUnitType = unitTypeStr;
+      m_lastSelectionUnitType = unit_type_str;
     }
   }
 }
 
 void AudioEventHandler::onAmbientStateChanged(
     const Engine::Core::AmbientStateChangedEvent &event) {
-  auto it = m_ambientMusicMap.find(event.newState);
+  auto it = m_ambientMusicMap.find(event.new_state);
   if (it != m_ambientMusicMap.end()) {
     AudioSystem::getInstance().playMusic(it->second);
   }
@@ -135,5 +139,4 @@ void AudioEventHandler::onMusicTrigger(
                                        event.crossfade);
 }
 
-} // namespace Audio
-} // namespace Game
+} // namespace Game::Audio

+ 8 - 10
game/audio/AudioEventHandler.h

@@ -12,18 +12,17 @@ namespace Engine::Core {
 class World;
 }
 
-namespace Game {
-namespace Audio {
+namespace Game::Audio {
 
 class AudioEventHandler {
 public:
   AudioEventHandler(Engine::Core::World *world);
   ~AudioEventHandler();
 
-  bool initialize();
+  auto initialize() -> bool;
   void shutdown();
 
-  void loadUnitVoiceMapping(const std::string &unitType,
+  void loadUnitVoiceMapping(const std::string &unit_type,
                             const std::string &soundId);
   void loadAmbientMusic(Engine::Core::AmbientState state,
                         const std::string &musicId);
@@ -34,14 +33,14 @@ private:
   void onUnitSelected(const Engine::Core::UnitSelectedEvent &event);
   void
   onAmbientStateChanged(const Engine::Core::AmbientStateChangedEvent &event);
-  void onAudioTrigger(const Engine::Core::AudioTriggerEvent &event);
-  void onMusicTrigger(const Engine::Core::MusicTriggerEvent &event);
+  static void onAudioTrigger(const Engine::Core::AudioTriggerEvent &event);
+  static void onMusicTrigger(const Engine::Core::MusicTriggerEvent &event);
 
   Engine::Core::World *m_world;
   std::unordered_map<std::string, std::string> m_unitVoiceMap;
   std::unordered_map<Engine::Core::AmbientState, std::string> m_ambientMusicMap;
 
-  bool m_useVoiceCategory;
+  bool m_useVoiceCategory{true};
 
   std::chrono::steady_clock::time_point m_lastSelectionSoundTime;
   std::string m_lastSelectionUnitType;
@@ -56,8 +55,7 @@ private:
   Engine::Core::ScopedEventSubscription<Engine::Core::MusicTriggerEvent>
       m_musicTriggerSub;
 
-  bool m_initialized;
+  bool m_initialized{false};
 };
 
-} // namespace Audio
-} // namespace Game
+} // namespace Game::Audio

+ 120 - 114
game/audio/AudioSystem.cpp

@@ -1,23 +1,32 @@
 #include "AudioSystem.h"
+
 #include "MiniaudioBackend.h"
 #include "MusicPlayer.h"
 #include "Sound.h"
 #include <QDebug>
 #include <algorithm>
+#include <chrono>
+#include <cstddef>
+#include <math.h>
+#include <memory>
+#include <mutex>
+#include <qglobal.h>
+#include <string>
+#include <utility>
+#include <vector>
 
 AudioSystem::AudioSystem()
-    : isRunning(false), masterVolume(1.0f), soundVolume(1.0f),
-      musicVolume(1.0f), voiceVolume(1.0f), maxChannels(32),
-      m_musicPlayer(nullptr) {}
+    : isRunning(false), masterVolume(1.0F), soundVolume(1.0F),
+      musicVolume(1.0F), voiceVolume(1.0F) {}
 
 AudioSystem::~AudioSystem() { shutdown(); }
 
-AudioSystem &AudioSystem::getInstance() {
+auto AudioSystem::getInstance() -> AudioSystem & {
   static AudioSystem instance;
   return instance;
 }
 
-bool AudioSystem::initialize() {
+auto AudioSystem::initialize() -> bool {
   if (isRunning) {
     return true;
   }
@@ -40,8 +49,8 @@ void AudioSystem::shutdown() {
   }
 
   {
-    std::lock_guard<std::mutex> lock(queueMutex);
-    eventQueue.push(AudioEvent(AudioEventType::SHUTDOWN));
+    std::lock_guard<std::mutex> const lock(queueMutex);
+    eventQueue.emplace(AudioEventType::SHUTDOWN);
   }
   queueCondition.notify_one();
 
@@ -49,7 +58,7 @@ void AudioSystem::shutdown() {
     audioThread.join();
   }
 
-  if (m_musicPlayer) {
+  if (m_musicPlayer != nullptr) {
     m_musicPlayer->shutdown();
     m_musicPlayer = nullptr;
   }
@@ -59,109 +68,109 @@ void AudioSystem::shutdown() {
   activeResources.clear();
 
   {
-    std::lock_guard<std::mutex> lock(activeSoundsMutex);
+    std::lock_guard<std::mutex> const lock(activeSoundsMutex);
     activeSounds.clear();
   }
 }
 
 void AudioSystem::playSound(const std::string &soundId, float volume, bool loop,
                             int priority, AudioCategory category) {
-  std::lock_guard<std::mutex> lock(queueMutex);
-  eventQueue.push(AudioEvent(AudioEventType::PLAY_SOUND, soundId, volume, loop,
-                             priority, category));
+  std::lock_guard<std::mutex> const lock(queueMutex);
+  eventQueue.emplace(AudioEventType::PLAY_SOUND, soundId, volume, loop,
+                     priority, category);
   queueCondition.notify_one();
 }
 
 void AudioSystem::playMusic(const std::string &musicId, float volume,
                             bool crossfade) {
-  std::lock_guard<std::mutex> lock(queueMutex);
-  eventQueue.push(AudioEvent(AudioEventType::PLAY_MUSIC, musicId, volume));
+  std::lock_guard<std::mutex> const lock(queueMutex);
+  eventQueue.emplace(AudioEventType::PLAY_MUSIC, musicId, volume);
   queueCondition.notify_one();
 }
 
 void AudioSystem::stopSound(const std::string &soundId) {
-  std::lock_guard<std::mutex> lock(queueMutex);
-  eventQueue.push(AudioEvent(AudioEventType::STOP_SOUND, soundId));
+  std::lock_guard<std::mutex> const lock(queueMutex);
+  eventQueue.emplace(AudioEventType::STOP_SOUND, soundId);
   queueCondition.notify_one();
 }
 
 void AudioSystem::stopMusic() {
-  std::lock_guard<std::mutex> lock(queueMutex);
-  eventQueue.push(AudioEvent(AudioEventType::STOP_MUSIC));
+  std::lock_guard<std::mutex> const lock(queueMutex);
+  eventQueue.emplace(AudioEventType::STOP_MUSIC);
   queueCondition.notify_one();
 }
 
 void AudioSystem::setMasterVolume(float volume) {
-  masterVolume = std::clamp(volume, 0.0f, 1.0f);
+  masterVolume = std::clamp(volume, 0.0F, 1.0F);
 
-  std::lock_guard<std::mutex> lock(resourceMutex);
+  std::lock_guard<std::mutex> const lock(resourceMutex);
   for (auto &sound : sounds) {
     auto it = soundCategories.find(sound.first);
-    AudioCategory category =
+    AudioCategory const category =
         (it != soundCategories.end()) ? it->second : AudioCategory::SFX;
-    sound.second->setVolume(getEffectiveVolume(category, 1.0f));
+    sound.second->setVolume(getEffectiveVolume(category, 1.0F));
   }
 
-  if (m_musicPlayer) {
+  if (m_musicPlayer != nullptr) {
     m_musicPlayer->setVolume(masterVolume * musicVolume);
   }
 }
 
 void AudioSystem::setSoundVolume(float volume) {
-  soundVolume = std::clamp(volume, 0.0f, 1.0f);
+  soundVolume = std::clamp(volume, 0.0F, 1.0F);
 
-  std::lock_guard<std::mutex> lock(resourceMutex);
+  std::lock_guard<std::mutex> const lock(resourceMutex);
   for (auto &sound : sounds) {
     auto it = soundCategories.find(sound.first);
     if (it != soundCategories.end() && it->second == AudioCategory::SFX) {
-      sound.second->setVolume(getEffectiveVolume(AudioCategory::SFX, 1.0f));
+      sound.second->setVolume(getEffectiveVolume(AudioCategory::SFX, 1.0F));
     }
   }
 }
 
 void AudioSystem::setMusicVolume(float volume) {
-  musicVolume = std::clamp(volume, 0.0f, 1.0f);
+  musicVolume = std::clamp(volume, 0.0F, 1.0F);
 
-  std::lock_guard<std::mutex> lock(resourceMutex);
-  if (m_musicPlayer) {
+  std::lock_guard<std::mutex> const lock(resourceMutex);
+  if (m_musicPlayer != nullptr) {
     m_musicPlayer->setVolume(masterVolume * musicVolume);
   }
 }
 
 void AudioSystem::setVoiceVolume(float volume) {
-  voiceVolume = std::clamp(volume, 0.0f, 1.0f);
+  voiceVolume = std::clamp(volume, 0.0F, 1.0F);
 
-  std::lock_guard<std::mutex> lock(resourceMutex);
+  std::lock_guard<std::mutex> const lock(resourceMutex);
   for (auto &sound : sounds) {
     auto it = soundCategories.find(sound.first);
     if (it != soundCategories.end() && it->second == AudioCategory::VOICE) {
-      sound.second->setVolume(getEffectiveVolume(AudioCategory::VOICE, 1.0f));
+      sound.second->setVolume(getEffectiveVolume(AudioCategory::VOICE, 1.0F));
     }
   }
 }
 
 void AudioSystem::pauseAll() {
-  std::lock_guard<std::mutex> lock(queueMutex);
-  eventQueue.push(AudioEvent(AudioEventType::PAUSE));
+  std::lock_guard<std::mutex> const lock(queueMutex);
+  eventQueue.emplace(AudioEventType::PAUSE);
   queueCondition.notify_one();
 }
 
 void AudioSystem::resumeAll() {
-  std::lock_guard<std::mutex> lock(queueMutex);
-  eventQueue.push(AudioEvent(AudioEventType::RESUME));
+  std::lock_guard<std::mutex> const lock(queueMutex);
+  eventQueue.emplace(AudioEventType::RESUME);
   queueCondition.notify_one();
 }
 
-bool AudioSystem::loadSound(const std::string &soundId,
+auto AudioSystem::loadSound(const std::string &soundId,
                             const std::string &filePath,
-                            AudioCategory category) {
-  std::lock_guard<std::mutex> lock(resourceMutex);
+                            AudioCategory category) -> bool {
+  std::lock_guard<std::mutex> const lock(resourceMutex);
   if (sounds.find(soundId) != sounds.end()) {
     return true;
   }
 
   MiniaudioBackend *backend =
-      m_musicPlayer ? m_musicPlayer->getBackend() : nullptr;
+      (m_musicPlayer != nullptr) ? m_musicPlayer->getBackend() : nullptr;
   auto sound = std::make_unique<Sound>(filePath, backend);
   if (!sound || !sound->isLoaded()) {
     return false;
@@ -173,11 +182,11 @@ bool AudioSystem::loadSound(const std::string &soundId,
   return true;
 }
 
-bool AudioSystem::loadMusic(const std::string &musicId,
-                            const std::string &filePath) {
-  std::lock_guard<std::mutex> lock(resourceMutex);
+auto AudioSystem::loadMusic(const std::string &musicId,
+                            const std::string &filePath) -> bool {
+  std::lock_guard<std::mutex> const lock(resourceMutex);
 
-  if (!m_musicPlayer) {
+  if (m_musicPlayer == nullptr) {
     qWarning() << "MusicPlayer not initialized";
     return false;
   }
@@ -188,40 +197,40 @@ bool AudioSystem::loadMusic(const std::string &musicId,
 }
 
 void AudioSystem::unloadSound(const std::string &soundId) {
-  std::lock_guard<std::mutex> lock(queueMutex);
-  eventQueue.push(AudioEvent(AudioEventType::UNLOAD_RESOURCE, soundId));
+  std::lock_guard<std::mutex> const lock(queueMutex);
+  eventQueue.emplace(AudioEventType::UNLOAD_RESOURCE, soundId);
   queueCondition.notify_one();
 }
 
 void AudioSystem::unloadMusic(const std::string &musicId) {
-  std::lock_guard<std::mutex> lock(queueMutex);
-  eventQueue.push(AudioEvent(AudioEventType::UNLOAD_RESOURCE, musicId));
+  std::lock_guard<std::mutex> const lock(queueMutex);
+  eventQueue.emplace(AudioEventType::UNLOAD_RESOURCE, musicId);
   queueCondition.notify_one();
 }
 
 void AudioSystem::unloadAllSounds() {
-  std::lock_guard<std::mutex> lock(queueMutex);
+  std::lock_guard<std::mutex> const lock(queueMutex);
   for (const auto &sound : sounds) {
-    eventQueue.push(AudioEvent(AudioEventType::UNLOAD_RESOURCE, sound.first));
+    eventQueue.emplace(AudioEventType::UNLOAD_RESOURCE, sound.first);
   }
   queueCondition.notify_one();
 }
 
 void AudioSystem::unloadAllMusic() {
-  std::lock_guard<std::mutex> lock(resourceMutex);
+  std::lock_guard<std::mutex> const lock(resourceMutex);
 
-  if (m_musicPlayer) {
+  if (m_musicPlayer != nullptr) {
     m_musicPlayer->stop();
   }
 
-  std::vector<std::string> musicResources;
+  std::vector<std::string> music_resources;
   for (const auto &res : activeResources) {
 
     if (sounds.find(res) == sounds.end()) {
-      musicResources.push_back(res);
+      music_resources.push_back(res);
     }
   }
-  for (const auto &res : musicResources) {
+  for (const auto &res : music_resources) {
     activeResources.erase(res);
   }
 }
@@ -230,8 +239,8 @@ void AudioSystem::setMaxChannels(size_t channels) {
   maxChannels = std::max(size_t(1), channels);
 }
 
-size_t AudioSystem::getActiveChannelCount() const {
-  std::lock_guard<std::mutex> lock(activeSoundsMutex);
+auto AudioSystem::getActiveChannelCount() const -> size_t {
+  std::lock_guard<std::mutex> const lock(activeSoundsMutex);
   return activeSounds.size();
 }
 
@@ -241,7 +250,7 @@ void AudioSystem::audioThreadFunc() {
     queueCondition.wait(lock, [this] { return !eventQueue.empty(); });
 
     while (!eventQueue.empty()) {
-      AudioEvent event = eventQueue.front();
+      AudioEvent const event = eventQueue.front();
       eventQueue.pop();
       lock.unlock();
 
@@ -260,18 +269,19 @@ void AudioSystem::audioThreadFunc() {
 void AudioSystem::processEvent(const AudioEvent &event) {
   switch (event.type) {
   case AudioEventType::PLAY_SOUND: {
-    std::lock_guard<std::mutex> lock(resourceMutex);
+    std::lock_guard<std::mutex> const lock(resourceMutex);
     auto it = sounds.find(event.resourceId);
     if (it != sounds.end()) {
       if (!canPlaySound(event.priority)) {
         evictLowestPrioritySoundLocked();
       }
 
-      float effectiveVol = getEffectiveVolume(event.category, event.volume);
-      it->second->play(effectiveVol, event.loop);
+      float const effective_vol =
+          getEffectiveVolume(event.category, event.volume);
+      it->second->play(effective_vol, event.loop);
 
       {
-        std::lock_guard<std::mutex> activeLock(activeSoundsMutex);
+        std::lock_guard<std::mutex> const active_lock(activeSoundsMutex);
         activeSounds.push_back({event.resourceId, event.priority, event.loop,
                                 event.category,
                                 std::chrono::steady_clock::now()});
@@ -280,20 +290,20 @@ void AudioSystem::processEvent(const AudioEvent &event) {
     break;
   }
   case AudioEventType::PLAY_MUSIC: {
-    std::lock_guard<std::mutex> lock(resourceMutex);
-    if (m_musicPlayer) {
-      float effectiveVolume = masterVolume * musicVolume * event.volume;
-      m_musicPlayer->play(event.resourceId, effectiveVolume, event.loop);
+    std::lock_guard<std::mutex> const lock(resourceMutex);
+    if (m_musicPlayer != nullptr) {
+      float const effective_volume = masterVolume * musicVolume * event.volume;
+      m_musicPlayer->play(event.resourceId, effective_volume, event.loop);
     }
     break;
   }
   case AudioEventType::STOP_SOUND: {
-    std::lock_guard<std::mutex> lock(resourceMutex);
+    std::lock_guard<std::mutex> const lock(resourceMutex);
     auto it = sounds.find(event.resourceId);
     if (it != sounds.end()) {
       it->second->stop();
 
-      std::lock_guard<std::mutex> activeLock(activeSoundsMutex);
+      std::lock_guard<std::mutex> const active_lock(activeSoundsMutex);
       activeSounds.erase(std::remove_if(activeSounds.begin(),
                                         activeSounds.end(),
                                         [&](const ActiveSound &as) {
@@ -304,33 +314,33 @@ void AudioSystem::processEvent(const AudioEvent &event) {
     break;
   }
   case AudioEventType::STOP_MUSIC: {
-    std::lock_guard<std::mutex> lock(resourceMutex);
-    if (m_musicPlayer) {
+    std::lock_guard<std::mutex> const lock(resourceMutex);
+    if (m_musicPlayer != nullptr) {
       m_musicPlayer->stop();
     }
     break;
   }
   case AudioEventType::PAUSE: {
-    std::lock_guard<std::mutex> lock(resourceMutex);
-    if (m_musicPlayer) {
+    std::lock_guard<std::mutex> const lock(resourceMutex);
+    if (m_musicPlayer != nullptr) {
       m_musicPlayer->pause();
     }
     break;
   }
   case AudioEventType::RESUME: {
-    std::lock_guard<std::mutex> lock(resourceMutex);
-    if (m_musicPlayer) {
+    std::lock_guard<std::mutex> const lock(resourceMutex);
+    if (m_musicPlayer != nullptr) {
       m_musicPlayer->resume();
     }
     break;
   }
   case AudioEventType::UNLOAD_RESOURCE: {
-    std::lock_guard<std::mutex> lock(resourceMutex);
-    auto soundIt = sounds.find(event.resourceId);
-    if (soundIt != sounds.end()) {
-      soundIt->second->stop();
+    std::lock_guard<std::mutex> const lock(resourceMutex);
+    auto sound_it = sounds.find(event.resourceId);
+    if (sound_it != sounds.end()) {
+      sound_it->second->stop();
 
-      std::lock_guard<std::mutex> activeLock(activeSoundsMutex);
+      std::lock_guard<std::mutex> const active_lock(activeSoundsMutex);
       activeSounds.erase(std::remove_if(activeSounds.begin(),
                                         activeSounds.end(),
                                         [&](const ActiveSound &as) {
@@ -338,7 +348,7 @@ void AudioSystem::processEvent(const AudioEvent &event) {
                                         }),
                          activeSounds.end());
 
-      sounds.erase(soundIt);
+      sounds.erase(sound_it);
       soundCategories.erase(event.resourceId);
       activeResources.erase(event.resourceId);
     }
@@ -356,22 +366,22 @@ void AudioSystem::processEvent(const AudioEvent &event) {
   }
 }
 
-bool AudioSystem::canPlaySound(int priority) {
-  std::lock_guard<std::mutex> lock(activeSoundsMutex);
+auto AudioSystem::canPlaySound(int priority) -> bool {
+  std::lock_guard<std::mutex> const lock(activeSoundsMutex);
   return activeSounds.size() < maxChannels;
 }
 
 void AudioSystem::evictLowestPrioritySound() {
-  std::string soundIdToStop;
+  std::string sound_id_to_stop;
 
   {
-    std::lock_guard<std::mutex> activeLock(activeSoundsMutex);
+    std::lock_guard<std::mutex> const active_lock(activeSoundsMutex);
 
     if (activeSounds.empty()) {
       return;
     }
 
-    auto lowestIt =
+    auto lowest_it =
         std::min_element(activeSounds.begin(), activeSounds.end(),
                          [](const ActiveSound &a, const ActiveSound &b) {
                            if (a.priority != b.priority) {
@@ -380,15 +390,15 @@ void AudioSystem::evictLowestPrioritySound() {
                            return a.startTime < b.startTime;
                          });
 
-    if (lowestIt != activeSounds.end()) {
-      soundIdToStop = lowestIt->id;
-      activeSounds.erase(lowestIt);
+    if (lowest_it != activeSounds.end()) {
+      sound_id_to_stop = lowest_it->id;
+      activeSounds.erase(lowest_it);
     }
   }
 
-  if (!soundIdToStop.empty()) {
-    std::lock_guard<std::mutex> resourceLock(resourceMutex);
-    auto it = sounds.find(soundIdToStop);
+  if (!sound_id_to_stop.empty()) {
+    std::lock_guard<std::mutex> const resource_lock(resourceMutex);
+    auto it = sounds.find(sound_id_to_stop);
     if (it != sounds.end()) {
       it->second->stop();
     }
@@ -396,16 +406,16 @@ void AudioSystem::evictLowestPrioritySound() {
 }
 
 void AudioSystem::evictLowestPrioritySoundLocked() {
-  std::string soundIdToStop;
+  std::string sound_id_to_stop;
 
   {
-    std::lock_guard<std::mutex> activeLock(activeSoundsMutex);
+    std::lock_guard<std::mutex> const active_lock(activeSoundsMutex);
 
     if (activeSounds.empty()) {
       return;
     }
 
-    auto lowestIt =
+    auto lowest_it =
         std::min_element(activeSounds.begin(), activeSounds.end(),
                          [](const ActiveSound &a, const ActiveSound &b) {
                            if (a.priority != b.priority) {
@@ -414,14 +424,14 @@ void AudioSystem::evictLowestPrioritySoundLocked() {
                            return a.startTime < b.startTime;
                          });
 
-    if (lowestIt != activeSounds.end()) {
-      soundIdToStop = lowestIt->id;
-      activeSounds.erase(lowestIt);
+    if (lowest_it != activeSounds.end()) {
+      sound_id_to_stop = lowest_it->id;
+      activeSounds.erase(lowest_it);
     }
   }
 
-  if (!soundIdToStop.empty()) {
-    auto it = sounds.find(soundIdToStop);
+  if (!sound_id_to_stop.empty()) {
+    auto it = sounds.find(sound_id_to_stop);
     if (it != sounds.end()) {
       it->second->stop();
     }
@@ -429,8 +439,8 @@ void AudioSystem::evictLowestPrioritySoundLocked() {
 }
 
 void AudioSystem::cleanupInactiveSounds() {
-  std::lock_guard<std::mutex> resourceLock(resourceMutex);
-  std::lock_guard<std::mutex> activeLock(activeSoundsMutex);
+  std::lock_guard<std::mutex> const resource_lock(resourceMutex);
+  std::lock_guard<std::mutex> const active_lock(activeSoundsMutex);
 
   activeSounds.erase(std::remove_if(activeSounds.begin(), activeSounds.end(),
                                     [this](const ActiveSound &as) {
@@ -439,32 +449,28 @@ void AudioSystem::cleanupInactiveSounds() {
                                       }
 
                                       auto it = sounds.find(as.id);
-                                      if (it == sounds.end()) {
-                                        return true;
-                                      }
-
-                                      return false;
+                                      return it == sounds.end();
                                     }),
                      activeSounds.end());
 }
 
-float AudioSystem::getEffectiveVolume(AudioCategory category,
-                                      float eventVolume) const {
-  float categoryVolume;
+auto AudioSystem::getEffectiveVolume(AudioCategory category,
+                                     float eventVolume) const -> float {
+  float category_volume = NAN;
   switch (category) {
   case AudioCategory::SFX:
-    categoryVolume = soundVolume;
+    category_volume = soundVolume;
     break;
   case AudioCategory::VOICE:
-    categoryVolume = voiceVolume;
+    category_volume = voiceVolume;
     break;
   case AudioCategory::MUSIC:
-    categoryVolume = musicVolume;
+    category_volume = musicVolume;
     break;
   default:
-    categoryVolume = soundVolume;
+    category_volume = soundVolume;
     break;
   }
 
-  return masterVolume * categoryVolume * eventVolume;
+  return masterVolume * category_volume * eventVolume;
 }

+ 25 - 23
game/audio/AudioSystem.h

@@ -10,14 +10,14 @@
 #include <thread>
 #include <unordered_map>
 #include <unordered_set>
+#include <utility>
 #include <vector>
 
 class Sound;
-namespace Game {
-namespace Audio {
+
+namespace Game::Audio {
 class MusicPlayer;
 }
-} // namespace Game
 
 enum class AudioEventType {
   PLAY_SOUND,
@@ -37,28 +37,28 @@ enum class AudioCategory { SFX, VOICE, MUSIC };
 struct AudioEvent {
   AudioEventType type;
   std::string resourceId;
-  float volume = 1.0f;
+  float volume = 1.0F;
   bool loop = false;
   int priority = 0;
   AudioCategory category = AudioCategory::SFX;
 
-  AudioEvent(AudioEventType t, const std::string &id = "", float vol = 1.0f,
+  AudioEvent(AudioEventType t, std::string id = "", float vol = 1.0F,
              bool l = false, int p = 0, AudioCategory cat = AudioCategory::SFX)
-      : type(t), resourceId(id), volume(vol), loop(l), priority(p),
+      : type(t), resourceId(std::move(id)), volume(vol), loop(l), priority(p),
         category(cat) {}
 };
 
 class AudioSystem {
 public:
-  static AudioSystem &getInstance();
+  static auto getInstance() -> AudioSystem &;
 
-  bool initialize();
+  auto initialize() -> bool;
   void shutdown();
 
-  void playSound(const std::string &soundId, float volume = 1.0f,
+  void playSound(const std::string &soundId, float volume = 1.0F,
                  bool loop = false, int priority = 0,
                  AudioCategory category = AudioCategory::SFX);
-  void playMusic(const std::string &musicId, float volume = 1.0f,
+  void playMusic(const std::string &musicId, float volume = 1.0F,
                  bool crossfade = true);
   void stopSound(const std::string &soundId);
   void stopMusic();
@@ -69,43 +69,45 @@ public:
   void pauseAll();
   void resumeAll();
 
-  bool loadSound(const std::string &soundId, const std::string &filePath,
-                 AudioCategory category = AudioCategory::SFX);
-  bool loadMusic(const std::string &musicId, const std::string &filePath);
+  auto loadSound(const std::string &soundId, const std::string &filePath,
+                 AudioCategory category = AudioCategory::SFX) -> bool;
+  auto loadMusic(const std::string &musicId,
+                 const std::string &filePath) -> bool;
   void unloadSound(const std::string &soundId);
   void unloadMusic(const std::string &musicId);
   void unloadAllSounds();
   void unloadAllMusic();
 
   void setMaxChannels(size_t maxChannels);
-  size_t getActiveChannelCount() const;
+  auto getActiveChannelCount() const -> size_t;
 
-  float getMasterVolume() const { return masterVolume; }
-  float getSoundVolume() const { return soundVolume; }
-  float getMusicVolume() const { return musicVolume; }
-  float getVoiceVolume() const { return voiceVolume; }
+  auto getMasterVolume() const -> float { return masterVolume; }
+  auto getSoundVolume() const -> float { return soundVolume; }
+  auto getMusicVolume() const -> float { return musicVolume; }
+  auto getVoiceVolume() const -> float { return voiceVolume; }
 
 private:
   AudioSystem();
   ~AudioSystem();
 
   AudioSystem(const AudioSystem &) = delete;
-  AudioSystem &operator=(const AudioSystem &) = delete;
+  auto operator=(const AudioSystem &) -> AudioSystem & = delete;
 
   void audioThreadFunc();
   void processEvent(const AudioEvent &event);
   void cleanupInactiveSounds();
-  bool canPlaySound(int priority);
+  auto canPlaySound(int priority) -> bool;
   void evictLowestPrioritySound();
   void evictLowestPrioritySoundLocked();
-  float getEffectiveVolume(AudioCategory category, float eventVolume) const;
+  auto getEffectiveVolume(AudioCategory category,
+                          float eventVolume) const -> float;
 
   std::unordered_map<std::string, std::unique_ptr<Sound>> sounds;
   std::unordered_map<std::string, AudioCategory> soundCategories;
   std::unordered_set<std::string> activeResources;
   mutable std::mutex resourceMutex;
 
-  Game::Audio::MusicPlayer *m_musicPlayer;
+  Game::Audio::MusicPlayer *m_musicPlayer{nullptr};
 
   std::thread audioThread;
   std::queue<AudioEvent> eventQueue;
@@ -118,7 +120,7 @@ private:
   std::atomic<float> musicVolume;
   std::atomic<float> voiceVolume;
 
-  size_t maxChannels;
+  size_t maxChannels{32};
 
   struct ActiveSound {
     std::string id;

+ 2 - 1
game/audio/CMakeLists.txt

@@ -6,5 +6,6 @@ add_library(audio_system STATIC
     AudioEventHandler.cpp
 )
 
-target_include_directories(audio_system PUBLIC . PRIVATE ${CMAKE_SOURCE_DIR}/third_party)
+target_include_directories(audio_system PUBLIC .)
+target_include_directories(audio_system SYSTEM PRIVATE ${CMAKE_SOURCE_DIR}/third_party)
 target_link_libraries(audio_system PUBLIC Qt${QT_VERSION_MAJOR}::Core engine_core)

+ 81 - 68
game/audio/MiniaudioBackend.cpp

@@ -1,7 +1,13 @@
 #include "MiniaudioBackend.h"
 #include <QDebug>
+#include <algorithm>
 #include <cmath>
 #include <cstring>
+#include <qglobal.h>
+#include <qhashfunctions.h>
+#include <qmutex.h>
+#include <qobject.h>
+#include <utility>
 
 #define MINIAUDIO_IMPLEMENTATION
 #define MA_NO_ENCODING
@@ -15,7 +21,7 @@
 #define MA_ENABLE_MP3
 #define MA_ENABLE_FLAC
 #define MA_ENABLE_VORBIS
-#include "third_party/miniaudio.h"
+#include <miniaudio.h>
 
 struct DeviceWrapper {
   MiniaudioBackend *self;
@@ -24,7 +30,7 @@ struct DeviceWrapper {
 static void audioCallback(ma_device *device, void *pOutput, const void *,
                           ma_uint32 frameCount) {
   auto *w = reinterpret_cast<DeviceWrapper *>(device->pUserData);
-  if (!w || !w->self) {
+  if ((w == nullptr) || (w->self == nullptr)) {
     std::memset(pOutput, 0, frameCount * 2 * sizeof(float));
     return;
   }
@@ -34,8 +40,8 @@ static void audioCallback(ma_device *device, void *pOutput, const void *,
 MiniaudioBackend::MiniaudioBackend(QObject *parent) : QObject(parent) {}
 MiniaudioBackend::~MiniaudioBackend() { shutdown(); }
 
-bool MiniaudioBackend::initialize(int deviceRate, int outChannels,
-                                  int musicChannels) {
+auto MiniaudioBackend::initialize(int deviceRate, int outChannels,
+                                  int musicChannels) -> bool {
   m_rate = std::max(22050, deviceRate);
   m_outCh = 2;
 
@@ -87,14 +93,14 @@ bool MiniaudioBackend::initialize(int deviceRate, int outChannels,
 }
 
 void MiniaudioBackend::shutdown() {
-  QMutexLocker lk(&m_mutex);
+  QMutexLocker const lk(&m_mutex);
   stopDevice();
   m_tracks.clear();
   m_channels.clear();
 }
 
 void MiniaudioBackend::stopDevice() {
-  if (!m_device) {
+  if (m_device == nullptr) {
     return;
   }
   auto *wrap = reinterpret_cast<DeviceWrapper *>(m_device->pUserData);
@@ -105,9 +111,11 @@ void MiniaudioBackend::stopDevice() {
   delete wrap;
 }
 
-bool MiniaudioBackend::predecode(const QString &id, const QString &path) {
+auto MiniaudioBackend::predecode(const QString &id,
+                                 const QString &path) -> bool {
 
-  ma_decoder_config dc = ma_decoder_config_init(ma_format_f32, m_outCh, m_rate);
+  ma_decoder_config const dc =
+      ma_decoder_config_init(ma_format_f32, m_outCh, m_rate);
   ma_decoder dec;
   if (ma_decoder_init_file(path.toUtf8().constData(), &dc, &dec) !=
       MA_SUCCESS) {
@@ -118,10 +126,11 @@ bool MiniaudioBackend::predecode(const QString &id, const QString &path) {
   QVector<float> pcm;
   float buffer[4096 * 2];
   for (;;) {
-    ma_uint64 framesRead = 0;
-    ma_result r = ma_decoder_read_pcm_frames(&dec, buffer, 4096, &framesRead);
-    if (framesRead > 0) {
-      const size_t samples = size_t(framesRead) * 2;
+    ma_uint64 frames_read = 0;
+    ma_result const r =
+        ma_decoder_read_pcm_frames(&dec, buffer, 4096, &frames_read);
+    if (frames_read > 0) {
+      const size_t samples = size_t(frames_read) * 2;
       const size_t old = pcm.size();
       pcm.resize(old + samples);
       std::memcpy(pcm.data() + old, buffer, samples * sizeof(float));
@@ -136,7 +145,7 @@ bool MiniaudioBackend::predecode(const QString &id, const QString &path) {
   }
   ma_decoder_uninit(&dec);
 
-  QMutexLocker lk(&m_mutex);
+  QMutexLocker const lk(&m_mutex);
   DecodedTrack t;
   t.frames = pcm.size() / 2;
   t.pcm = std::move(pcm);
@@ -169,16 +178,17 @@ void MiniaudioBackend::play(int channel, const QString &id, float volume,
   ch.looping = loop;
   ch.paused = false;
   ch.active = true;
-  ch.tgtVol = std::clamp(volume, 0.0f, 1.0f);
-  ch.curVol = 0.0f;
+  ch.tgtVol = std::clamp(volume, 0.0F, 1.0F);
+  ch.curVol = 0.0F;
 
-  const unsigned fadeSamples = std::max(1u, unsigned((fadeMs * m_rate) / 1000));
-  ch.fadeSamples = fadeSamples;
-  ch.volStep = (ch.tgtVol - ch.curVol) / float(fadeSamples);
+  const unsigned fade_samples =
+      std::max(1U, unsigned((fadeMs * m_rate) / 1000));
+  ch.fade_samples = fade_samples;
+  ch.volStep = (ch.tgtVol - ch.curVol) / float(fade_samples);
 }
 
 void MiniaudioBackend::stop(int channel, int fadeMs) {
-  QMutexLocker lk(&m_mutex);
+  QMutexLocker const lk(&m_mutex);
   if (channel < 0 || channel >= m_channels.size()) {
     return;
   }
@@ -186,28 +196,29 @@ void MiniaudioBackend::stop(int channel, int fadeMs) {
   if (!ch.active) {
     return;
   }
-  const unsigned fadeSamples = std::max(1u, unsigned((fadeMs * m_rate) / 1000));
-  ch.tgtVol = 0.0f;
-  ch.fadeSamples = fadeSamples;
-  ch.volStep = (ch.tgtVol - ch.curVol) / float(fadeSamples);
+  const unsigned fade_samples =
+      std::max(1U, unsigned((fadeMs * m_rate) / 1000));
+  ch.tgtVol = 0.0F;
+  ch.fade_samples = fade_samples;
+  ch.volStep = (ch.tgtVol - ch.curVol) / float(fade_samples);
   ch.looping = false;
 }
 
 void MiniaudioBackend::pause(int channel) {
-  QMutexLocker lk(&m_mutex);
+  QMutexLocker const lk(&m_mutex);
   if (channel >= 0 && channel < m_channels.size()) {
     m_channels[channel].paused = true;
   }
 }
 void MiniaudioBackend::resume(int channel) {
-  QMutexLocker lk(&m_mutex);
+  QMutexLocker const lk(&m_mutex);
   if (channel >= 0 && channel < m_channels.size()) {
     m_channels[channel].paused = false;
   }
 }
 
 void MiniaudioBackend::setVolume(int channel, float volume, int fadeMs) {
-  QMutexLocker lk(&m_mutex);
+  QMutexLocker const lk(&m_mutex);
   if (channel < 0 || channel >= m_channels.size()) {
     return;
   }
@@ -215,33 +226,35 @@ void MiniaudioBackend::setVolume(int channel, float volume, int fadeMs) {
   if (!ch.active) {
     return;
   }
-  ch.tgtVol = std::clamp(volume, 0.0f, 1.0f);
-  const unsigned fadeSamples = std::max(1u, unsigned((fadeMs * m_rate) / 1000));
-  ch.fadeSamples = fadeSamples;
-  ch.volStep = (ch.tgtVol - ch.curVol) / float(fadeSamples);
+  ch.tgtVol = std::clamp(volume, 0.0F, 1.0F);
+  const unsigned fade_samples =
+      std::max(1U, unsigned((fadeMs * m_rate) / 1000));
+  ch.fade_samples = fade_samples;
+  ch.volStep = (ch.tgtVol - ch.curVol) / float(fade_samples);
 }
 
 void MiniaudioBackend::stopAll(int fadeMs) {
-  QMutexLocker lk(&m_mutex);
-  const unsigned fadeSamples = std::max(1u, unsigned((fadeMs * m_rate) / 1000));
+  QMutexLocker const lk(&m_mutex);
+  const unsigned fade_samples =
+      std::max(1U, unsigned((fadeMs * m_rate) / 1000));
   for (auto &ch : m_channels) {
     if (!ch.active) {
       continue;
     }
-    ch.tgtVol = 0.0f;
-    ch.fadeSamples = fadeSamples;
-    ch.volStep = (ch.tgtVol - ch.curVol) / float(fadeSamples);
+    ch.tgtVol = 0.0F;
+    ch.fade_samples = fade_samples;
+    ch.volStep = (ch.tgtVol - ch.curVol) / float(fade_samples);
     ch.looping = false;
   }
 }
 
 void MiniaudioBackend::setMasterVolume(float volume, int) {
-  QMutexLocker lk(&m_mutex);
-  m_masterVol = std::clamp(volume, 0.0f, 1.0f);
+  QMutexLocker const lk(&m_mutex);
+  m_masterVol = std::clamp(volume, 0.0F, 1.0F);
 }
 
-bool MiniaudioBackend::anyChannelPlaying() const {
-  QMutexLocker lk(&m_mutex);
+auto MiniaudioBackend::anyChannelPlaying() const -> bool {
+  QMutexLocker const lk(&m_mutex);
   for (const auto &ch : m_channels) {
     if (ch.active && !ch.paused) {
       return true;
@@ -249,8 +262,8 @@ bool MiniaudioBackend::anyChannelPlaying() const {
   }
   return false;
 }
-bool MiniaudioBackend::channelPlaying(int channel) const {
-  QMutexLocker lk(&m_mutex);
+auto MiniaudioBackend::channelPlaying(int channel) const -> bool {
+  QMutexLocker const lk(&m_mutex);
   if (channel < 0 || channel >= m_channels.size()) {
     return false;
   }
@@ -259,7 +272,7 @@ bool MiniaudioBackend::channelPlaying(int channel) const {
 }
 
 void MiniaudioBackend::playSound(const QString &id, float volume, bool loop) {
-  QMutexLocker lk(&m_mutex);
+  QMutexLocker const lk(&m_mutex);
 
   auto it = m_tracks.find(id);
   if (it == m_tracks.end()) {
@@ -267,7 +280,7 @@ void MiniaudioBackend::playSound(const QString &id, float volume, bool loop) {
     return;
   }
 
-  int slot = findFreeSoundSlot();
+  int const slot = findFreeSoundSlot();
   if (slot < 0) {
     qWarning() << "MiniaudioBackend: No free sound slots available";
     return;
@@ -276,12 +289,12 @@ void MiniaudioBackend::playSound(const QString &id, float volume, bool loop) {
   auto &sfx = m_soundEffects[slot];
   sfx.track = &it.value();
   sfx.framePos = 0;
-  sfx.volume = std::clamp(volume, 0.0f, 1.0f);
+  sfx.volume = std::clamp(volume, 0.0F, 1.0F);
   sfx.looping = loop;
   sfx.active = true;
 }
 
-int MiniaudioBackend::findFreeSoundSlot() const {
+auto MiniaudioBackend::findFreeSoundSlot() const -> int {
   for (int i = 0; i < m_soundEffects.size(); ++i) {
     if (!m_soundEffects[i].active) {
       return i;
@@ -295,7 +308,7 @@ void MiniaudioBackend::onAudio(float *out, unsigned frames) {
   const unsigned samples = frames * 2;
   std::memset(out, 0, samples * sizeof(float));
 
-  QMutexLocker lk(&m_mutex);
+  QMutexLocker const lk(&m_mutex);
 
   for (auto &ch : m_channels) {
     if (!ch.active || ch.paused || ch.track == nullptr) {
@@ -303,12 +316,12 @@ void MiniaudioBackend::onAudio(float *out, unsigned frames) {
     }
 
     const auto *pcm = ch.track->pcm.constData();
-    unsigned framesLeft = frames;
+    unsigned frames_left = frames;
     unsigned pos = ch.framePos;
 
     float *dst = out;
 
-    while (framesLeft > 0) {
+    while (frames_left > 0) {
       if (pos >= ch.track->frames) {
         if (ch.looping) {
           pos = 0;
@@ -316,36 +329,36 @@ void MiniaudioBackend::onAudio(float *out, unsigned frames) {
           break;
         }
       }
-      const unsigned canCopy = std::min(framesLeft, ch.track->frames - pos);
+      const unsigned can_copy = std::min(frames_left, ch.track->frames - pos);
       const float *src = pcm + pos * 2;
 
-      for (unsigned i = 0; i < canCopy; ++i) {
+      for (unsigned i = 0; i < can_copy; ++i) {
         const float vol = ch.curVol * m_masterVol;
         dst[0] += src[0] * vol;
         dst[1] += src[1] * vol;
         dst += 2;
         src += 2;
 
-        if (ch.fadeSamples > 0) {
+        if (ch.fade_samples > 0) {
           ch.curVol += ch.volStep;
-          --ch.fadeSamples;
-          if (ch.fadeSamples == 0) {
+          --ch.fade_samples;
+          if (ch.fade_samples == 0) {
             ch.curVol = ch.tgtVol;
           }
         }
       }
-      pos += canCopy;
-      framesLeft -= canCopy;
+      pos += can_copy;
+      frames_left -= can_copy;
     }
 
     ch.framePos = pos;
 
     if (!ch.looping && ch.framePos >= ch.track->frames) {
       ch.active = false;
-      ch.curVol = ch.tgtVol = 0.0f;
-      ch.fadeSamples = 0;
+      ch.curVol = ch.tgtVol = 0.0F;
+      ch.fade_samples = 0;
     }
-    if (ch.fadeSamples == 0 && ch.curVol == 0.0f && ch.tgtVol == 0.0f &&
+    if (ch.fade_samples == 0 && ch.curVol == 0.0F && ch.tgtVol == 0.0F &&
         !ch.looping) {
       ch.active = false;
     }
@@ -357,11 +370,11 @@ void MiniaudioBackend::onAudio(float *out, unsigned frames) {
     }
 
     const auto *pcm = sfx.track->pcm.constData();
-    unsigned framesLeft = frames;
+    unsigned frames_left = frames;
     unsigned pos = sfx.framePos;
     float *dst = out;
 
-    while (framesLeft > 0) {
+    while (frames_left > 0) {
       if (pos >= sfx.track->frames) {
         if (sfx.looping) {
           pos = 0;
@@ -371,10 +384,10 @@ void MiniaudioBackend::onAudio(float *out, unsigned frames) {
         }
       }
 
-      const unsigned canCopy = std::min(framesLeft, sfx.track->frames - pos);
+      const unsigned can_copy = std::min(frames_left, sfx.track->frames - pos);
       const float *src = pcm + pos * 2;
 
-      for (unsigned i = 0; i < canCopy; ++i) {
+      for (unsigned i = 0; i < can_copy; ++i) {
         const float vol = sfx.volume * m_masterVol;
         dst[0] += src[0] * vol;
         dst[1] += src[1] * vol;
@@ -382,18 +395,18 @@ void MiniaudioBackend::onAudio(float *out, unsigned frames) {
         src += 2;
       }
 
-      pos += canCopy;
-      framesLeft -= canCopy;
+      pos += can_copy;
+      frames_left -= can_copy;
     }
 
     sfx.framePos = pos;
   }
 
   for (unsigned i = 0; i < samples; ++i) {
-    if (out[i] > 1.0f) {
-      out[i] = 1.0f;
-    } else if (out[i] < -1.0f) {
-      out[i] = -1.0f;
+    if (out[i] > 1.0F) {
+      out[i] = 1.0F;
+    } else if (out[i] < -1.0F) {
+      out[i] = -1.0F;
     }
   }
 }

+ 11 - 13
game/audio/MiniaudioBackend.h

@@ -14,10 +14,10 @@ public:
   explicit MiniaudioBackend(QObject *parent = nullptr);
   ~MiniaudioBackend() override;
 
-  bool initialize(int deviceRate, int outChannels, int musicChannels);
+  auto initialize(int deviceRate, int outChannels, int musicChannels) -> bool;
   void shutdown();
 
-  bool predecode(const QString &id, const QString &path);
+  auto predecode(const QString &id, const QString &path) -> bool;
 
   void play(int channel, const QString &id, float volume, bool loop,
             int fadeMs);
@@ -28,8 +28,8 @@ public:
   void stopAll(int fadeMs);
   void setMasterVolume(float volume, int fadeMs);
 
-  bool anyChannelPlaying() const;
-  bool channelPlaying(int channel) const;
+  auto anyChannelPlaying() const -> bool;
+  auto channelPlaying(int channel) const -> bool;
 
   void playSound(const QString &id, float volume, bool loop = false);
 
@@ -44,10 +44,10 @@ private:
   struct Channel {
     const DecodedTrack *track = nullptr;
     unsigned framePos = 0;
-    float curVol = 0.0f;
-    float tgtVol = 1.0f;
-    float volStep = 0.0f;
-    unsigned fadeSamples = 0;
+    float curVol = 0.0F;
+    float tgtVol = 1.0F;
+    float volStep = 0.0F;
+    unsigned fade_samples = 0;
     bool looping = false;
     bool paused = false;
     bool active = false;
@@ -56,17 +56,15 @@ private:
   struct SoundEffect {
     const DecodedTrack *track = nullptr;
     unsigned framePos = 0;
-    float volume = 1.0f;
+    float volume = 1.0F;
     bool looping = false;
     bool active = false;
   };
 
-private:
   void startDevice();
   void stopDevice();
-  int findFreeSoundSlot() const;
+  auto findFreeSoundSlot() const -> int;
 
-private:
   ma_device *m_device{nullptr};
   int m_rate{48000};
   int m_outCh{2};
@@ -75,5 +73,5 @@ private:
   QMap<QString, DecodedTrack> m_tracks;
   QVector<Channel> m_channels;
   QVector<SoundEffect> m_soundEffects;
-  float m_masterVol{1.0f};
+  float m_masterVol{1.0F};
 };

+ 1 - 1
game/audio/Music.cpp

@@ -239,7 +239,7 @@ void Music::fadeOut() {
         }
 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
         if (p->audioOutput()) {
-          p->audioOutput()->setVolume(0.0f);
+          p->audioOutput()->setVolume(0.0F);
         }
 
         QTimer::singleShot(50, [p, this]() {

+ 1 - 1
game/audio/Music.h

@@ -15,7 +15,7 @@ public:
   ~Music();
 
   bool isLoaded() const;
-  void play(float volume = 1.0f, bool loop = true);
+  void play(float volume = 1.0F, bool loop = true);
   void stop();
   void pause();
   void resume();

+ 39 - 29
game/audio/MusicPlayer.cpp

@@ -5,17 +5,27 @@
 #include <QMetaObject>
 #include <QTimer>
 #include <QtGlobal>
+#include <algorithm>
+#include <qcoreapplication.h>
+#include <qfileinfo.h>
+#include <qglobal.h>
+#include <qhashfunctions.h>
+#include <qnamespace.h>
+#include <qobject.h>
+#include <qobjectdefs.h>
+#include <qthread.h>
+#include <string>
 
 using namespace Game::Audio;
 
 static inline void requireGuiThread(const char *where) {
-  if (!QCoreApplication::instance() ||
+  if ((QCoreApplication::instance() == nullptr) ||
       QThread::currentThread() != QCoreApplication::instance()->thread()) {
     qFatal("%s must be called on the GUI thread", where);
   }
 }
 
-MusicPlayer &MusicPlayer::getInstance() {
+auto MusicPlayer::getInstance() -> MusicPlayer & {
   static MusicPlayer instance;
   return instance;
 }
@@ -23,11 +33,11 @@ MusicPlayer &MusicPlayer::getInstance() {
 MusicPlayer::MusicPlayer() : QObject(nullptr) {}
 MusicPlayer::~MusicPlayer() { shutdown(); }
 
-bool MusicPlayer::initialize(int musicChannels) {
+auto MusicPlayer::initialize(int musicChannels) -> bool {
   if (m_initialized) {
     return true;
   }
-  if (!QCoreApplication::instance()) {
+  if (QCoreApplication::instance() == nullptr) {
     qWarning() << "MusicPlayer: no Q(Gui)Application instance";
     return false;
   }
@@ -53,7 +63,7 @@ void MusicPlayer::shutdown() {
     return;
   }
 
-  if (QCoreApplication::instance() &&
+  if ((QCoreApplication::instance() != nullptr) &&
       QThread::currentThread() != QCoreApplication::instance()->thread()) {
     QMetaObject::invokeMethod(
         this, [this]() { shutdown(); }, Qt::BlockingQueuedConnection);
@@ -61,7 +71,7 @@ void MusicPlayer::shutdown() {
   }
 
   ensureOnGuiThread("MusicPlayer::shutdown");
-  if (m_backend) {
+  if (m_backend != nullptr) {
     m_backend->shutdown();
     m_backend->deleteLater();
     m_backend = nullptr;
@@ -74,7 +84,7 @@ void MusicPlayer::shutdown() {
 void MusicPlayer::registerTrack(const std::string &trackId,
                                 const std::string &filePath) {
 
-  if (QCoreApplication::instance() &&
+  if ((QCoreApplication::instance() != nullptr) &&
       QThread::currentThread() != QCoreApplication::instance()->thread()) {
     QMetaObject::invokeMethod(
         this, [this, trackId, filePath]() { registerTrack(trackId, filePath); },
@@ -83,7 +93,7 @@ void MusicPlayer::registerTrack(const std::string &trackId,
   }
   ensureOnGuiThread("MusicPlayer::registerTrack");
 
-  QFileInfo fi(QString::fromStdString(filePath));
+  QFileInfo const fi(QString::fromStdString(filePath));
   if (!fi.exists()) {
     qWarning() << "MusicPlayer: Missing asset"
                << QString::fromStdString(trackId) << "->"
@@ -92,7 +102,7 @@ void MusicPlayer::registerTrack(const std::string &trackId,
   }
   m_tracks[trackId] = fi.absoluteFilePath();
 
-  if (m_backend) {
+  if (m_backend != nullptr) {
     if (!m_backend->predecode(QString::fromStdString(trackId),
                               fi.absoluteFilePath())) {
       qWarning() << "MusicPlayer: predecode failed for"
@@ -111,9 +121,9 @@ void MusicPlayer::pause() { pause(m_defaultChannel); }
 void MusicPlayer::resume() { resume(m_defaultChannel); }
 void MusicPlayer::setVolume(float v) { setVolume(m_defaultChannel, v, 0); }
 
-int MusicPlayer::play(const std::string &id, float vol, bool loop, int channel,
-                      int fadeMs) {
-  if (!m_initialized || !m_backend) {
+auto MusicPlayer::play(const std::string &id, float vol, bool loop, int channel,
+                       int fadeMs) -> int {
+  if (!m_initialized || (m_backend == nullptr)) {
     qWarning() << "MusicPlayer not initialized";
     return -1;
   }
@@ -122,22 +132,22 @@ int MusicPlayer::play(const std::string &id, float vol, bool loop, int channel,
     QMetaObject::invokeMethod(
         this,
         [this, id, vol, loop, channel, fadeMs, &result]() mutable {
-          int ch = channel < 0 ? findFreeChannel()
-                               : std::min(channel, m_channelCount - 1);
+          int const ch = channel < 0 ? findFreeChannel()
+                                     : std::min(channel, m_channelCount - 1);
           play_gui(id, vol, loop, ch, fadeMs);
           result = ch;
         },
         Qt::BlockingQueuedConnection);
     return result;
   }
-  int ch =
+  int const ch =
       channel < 0 ? findFreeChannel() : std::min(channel, m_channelCount - 1);
   play_gui(id, vol, loop, ch, fadeMs);
   return ch;
 }
 
 void MusicPlayer::stop(int ch, int ms) {
-  if (!m_initialized || !m_backend) {
+  if (!m_initialized || (m_backend == nullptr)) {
     return;
   }
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
@@ -148,7 +158,7 @@ void MusicPlayer::stop(int ch, int ms) {
   stop_gui(ch, ms);
 }
 void MusicPlayer::pause(int ch) {
-  if (!m_initialized || !m_backend) {
+  if (!m_initialized || (m_backend == nullptr)) {
     return;
   }
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
@@ -159,7 +169,7 @@ void MusicPlayer::pause(int ch) {
   pause_gui(ch);
 }
 void MusicPlayer::resume(int ch) {
-  if (!m_initialized || !m_backend) {
+  if (!m_initialized || (m_backend == nullptr)) {
     return;
   }
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
@@ -170,7 +180,7 @@ void MusicPlayer::resume(int ch) {
   resume_gui(ch);
 }
 void MusicPlayer::setVolume(int ch, float v, int ms) {
-  if (!m_initialized || !m_backend) {
+  if (!m_initialized || (m_backend == nullptr)) {
     return;
   }
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
@@ -182,7 +192,7 @@ void MusicPlayer::setVolume(int ch, float v, int ms) {
   setVolume_gui(ch, v, ms);
 }
 void MusicPlayer::stopAll(int ms) {
-  if (!m_initialized || !m_backend) {
+  if (!m_initialized || (m_backend == nullptr)) {
     return;
   }
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
@@ -193,7 +203,7 @@ void MusicPlayer::stopAll(int ms) {
   stopAll_gui(ms);
 }
 void MusicPlayer::setMasterVolume(float v, int ms) {
-  if (!m_initialized || !m_backend) {
+  if (!m_initialized || (m_backend == nullptr)) {
     return;
   }
   if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
@@ -205,18 +215,18 @@ void MusicPlayer::setMasterVolume(float v, int ms) {
   setMasterVolume_gui(v, ms);
 }
 
-bool MusicPlayer::isPlaying() const {
-  return m_backend && m_backend->anyChannelPlaying();
+auto MusicPlayer::isPlaying() const -> bool {
+  return (m_backend != nullptr) && m_backend->anyChannelPlaying();
 }
-bool MusicPlayer::isPlaying(int ch) const {
-  return m_backend && m_backend->channelPlaying(ch);
+auto MusicPlayer::isPlaying(int ch) const -> bool {
+  return (m_backend != nullptr) && m_backend->channelPlaying(ch);
 }
 
-void MusicPlayer::ensureOnGuiThread(const char *where) const {
+void MusicPlayer::ensureOnGuiThread(const char *where) {
   requireGuiThread(where);
 }
-int MusicPlayer::findFreeChannel() const {
-  if (!m_backend) {
+auto MusicPlayer::findFreeChannel() const -> int {
+  if (m_backend == nullptr) {
     return 0;
   }
   for (int i = 0; i < m_channelCount; ++i) {
@@ -229,7 +239,7 @@ int MusicPlayer::findFreeChannel() const {
 
 void MusicPlayer::play_gui(const std::string &id, float vol, bool loop, int ch,
                            int fadeMs) {
-  if (!m_backend) {
+  if (m_backend == nullptr) {
     return;
   }
   auto it = m_tracks.find(id);

+ 12 - 15
game/audio/MusicPlayer.h

@@ -8,27 +8,26 @@
 #include <string>
 #include <unordered_map>
 
-namespace Game {
-namespace Audio {
+namespace Game::Audio {
 
 class MusicPlayer final : public QObject {
   Q_OBJECT
 public:
-  static MusicPlayer &getInstance();
+  static auto getInstance() -> MusicPlayer &;
 
-  bool initialize(int musicChannels = 4);
+  auto initialize(int musicChannels = 4) -> bool;
   void shutdown();
 
   void registerTrack(const std::string &trackId, const std::string &filePath);
 
-  void play(const std::string &trackId, float volume = 1.0f, bool loop = true);
+  void play(const std::string &trackId, float volume = 1.0F, bool loop = true);
   void stop();
   void pause();
   void resume();
   void setVolume(float volume);
 
-  int play(const std::string &trackId, float volume, bool loop, int channel,
-           int fadeMs);
+  auto play(const std::string &trackId, float volume, bool loop, int channel,
+            int fadeMs) -> int;
   void stop(int channel, int fadeMs = 150);
   void pause(int channel);
   void resume(int channel);
@@ -37,16 +36,16 @@ public:
   void stopAll(int fadeMs = 150);
   void setMasterVolume(float volume, int fadeMs = 0);
 
-  bool isPlaying() const;
-  bool isPlaying(int channel) const;
+  auto isPlaying() const -> bool;
+  auto isPlaying(int channel) const -> bool;
 
-  MiniaudioBackend *getBackend() { return m_backend.data(); }
+  auto getBackend() -> MiniaudioBackend * { return m_backend.data(); }
 
 private:
   explicit MusicPlayer();
   ~MusicPlayer() override;
 
-  void ensureOnGuiThread(const char *where) const;
+  static void ensureOnGuiThread(const char *where);
 
   void play_gui(const std::string &trackId, float volume, bool loop,
                 int channel, int fadeMs);
@@ -56,9 +55,8 @@ private:
   void setVolume_gui(int channel, float volume, int fadeMs);
   void setMasterVolume_gui(float volume, int fadeMs);
   void stopAll_gui(int fadeMs);
-  int findFreeChannel() const;
+  auto findFreeChannel() const -> int;
 
-private:
   QPointer<MiniaudioBackend> m_backend;
   std::unordered_map<std::string, QString> m_tracks;
   int m_channelCount{0};
@@ -66,5 +64,4 @@ private:
   bool m_initialized{false};
 };
 
-} // namespace Audio
-} // namespace Game
+} // namespace Game::Audio

+ 15 - 9
game/audio/Sound.cpp

@@ -3,22 +3,28 @@
 #include <QCryptographicHash>
 #include <QDebug>
 #include <QFileInfo>
+#include <qcryptographichash.h>
+#include <qfileinfo.h>
+#include <qglobal.h>
+#include <qobject.h>
+#include <qstringview.h>
+#include <string>
 
 Sound::Sound(const std::string &filePath, MiniaudioBackend *backend)
     : QObject(nullptr), m_filepath(filePath), m_backend(backend),
-      m_loaded(false), m_volume(1.0f) {
+      m_loaded(false), m_volume(1.0F) {
 
-  QByteArray hash = QCryptographicHash::hash(
+  QByteArray const hash = QCryptographicHash::hash(
       QByteArray::fromStdString(filePath), QCryptographicHash::Md5);
   m_trackId = "sound_" + QString(hash.toHex());
 
-  QFileInfo fi(QString::fromStdString(m_filepath));
+  QFileInfo const fi(QString::fromStdString(m_filepath));
   if (!fi.exists()) {
     qWarning() << "Sound: File does not exist:" << fi.absoluteFilePath();
     return;
   }
 
-  if (m_backend) {
+  if (m_backend != nullptr) {
     m_loaded = m_backend->predecode(m_trackId, fi.absoluteFilePath());
     if (m_loaded) {
       qDebug() << "Sound: Loaded" << fi.absoluteFilePath();
@@ -26,7 +32,7 @@ Sound::Sound(const std::string &filePath, MiniaudioBackend *backend)
   }
 }
 
-Sound::~Sound() {}
+Sound::~Sound() = default;
 
 void Sound::setBackend(MiniaudioBackend *backend) {
   if (m_backend == backend) {
@@ -35,18 +41,18 @@ void Sound::setBackend(MiniaudioBackend *backend) {
 
   m_backend = backend;
 
-  if (m_backend && !m_loaded) {
-    QFileInfo fi(QString::fromStdString(m_filepath));
+  if ((m_backend != nullptr) && !m_loaded) {
+    QFileInfo const fi(QString::fromStdString(m_filepath));
     if (fi.exists()) {
       m_loaded = m_backend->predecode(m_trackId, fi.absoluteFilePath());
     }
   }
 }
 
-bool Sound::isLoaded() const { return m_loaded.load(); }
+auto Sound::isLoaded() const -> bool { return m_loaded.load(); }
 
 void Sound::play(float volume, bool loop) {
-  if (!m_backend || !m_loaded) {
+  if ((m_backend == nullptr) || !m_loaded) {
     qWarning() << "Sound: Cannot play - backend not available or not loaded";
     return;
   }

+ 3 - 3
game/audio/Sound.h

@@ -12,10 +12,10 @@ class Sound : public QObject {
 public:
   explicit Sound(const std::string &filePath,
                  MiniaudioBackend *backend = nullptr);
-  ~Sound();
+  ~Sound() override;
 
-  bool isLoaded() const;
-  void play(float volume = 1.0f, bool loop = false);
+  [[nodiscard]] auto isLoaded() const -> bool;
+  void play(float volume = 1.0F, bool loop = false);
   void stop();
   void setVolume(float volume);
 

+ 0 - 1
game/core/component.cpp

@@ -1,3 +1,2 @@
-#include "component.h"
 
 namespace Engine::Core {}

+ 97 - 84
game/core/component.h

@@ -3,21 +3,40 @@
 #include "../units/spawn_type.h"
 #include "../units/troop_type.h"
 #include "entity.h"
+#include <array>
 #include <cstdint>
 #include <optional>
 #include <string>
+#include <utility>
 #include <vector>
 
 namespace Engine::Core {
 
+namespace Defaults {
+inline constexpr int kUnitDefaultHealth = 100;
+inline constexpr float kUnitDefaultVisionRange = 12.0F;
+
+inline constexpr float kAttackDefaultRange = 2.0F;
+inline constexpr int kAttackDefaultDamage = 10;
+inline constexpr float kAttackMeleeRange = 1.5F;
+inline constexpr float kAttackHeightTolerance = 2.0F;
+
+inline constexpr float kProductionDefaultBuildTime = 4.0F;
+inline constexpr int kProductionMaxUnits = 5;
+
+inline constexpr float kCaptureRequiredTime = 15.0F;
+
+inline constexpr float kHoldStandUpDuration = 2.0F;
+} // namespace Defaults
+
 class TransformComponent : public Component {
 public:
-  TransformComponent(float x = 0.0f, float y = 0.0f, float z = 0.0f,
-                     float rotX = 0.0f, float rotY = 0.0f, float rotZ = 0.0f,
-                     float scaleX = 1.0f, float scaleY = 1.0f,
-                     float scaleZ = 1.0f)
+  TransformComponent(float x = 0.0F, float y = 0.0F, float z = 0.0F,
+                     float rotX = 0.0F, float rotY = 0.0F, float rotZ = 0.0F,
+                     float scale_x = 1.0F, float scaleY = 1.0F,
+                     float scale_z = 1.0F)
       : position{x, y, z}, rotation{rotX, rotY, rotZ},
-        scale{scaleX, scaleY, scaleZ} {}
+        scale{scale_x, scaleY, scale_z} {}
 
   struct Vec3 {
     float x, y, z;
@@ -26,7 +45,7 @@ public:
   Vec3 rotation;
   Vec3 scale;
 
-  float desiredYaw = 0.0f;
+  float desiredYaw = 0.0F;
   bool hasDesiredYaw = false;
 };
 
@@ -34,123 +53,121 @@ class RenderableComponent : public Component {
 public:
   enum class MeshKind { None, Quad, Plane, Cube, Capsule, Ring };
 
-  RenderableComponent(const std::string &meshPath,
-                      const std::string &texturePath)
-      : meshPath(meshPath), texturePath(texturePath), visible(true),
-        mesh(MeshKind::Cube) {
-    color[0] = color[1] = color[2] = 1.0f;
+  RenderableComponent(std::string meshPath, std::string texturePath)
+      : meshPath(std::move(meshPath)), texturePath(std::move(texturePath)) {
+    color.fill(1.0F);
   }
 
   std::string meshPath;
   std::string texturePath;
-  bool visible;
-  MeshKind mesh;
-  float color[3];
+  bool visible{true};
+  MeshKind mesh{MeshKind::Cube};
+  std::array<float, 3> color{};
 };
 
 class UnitComponent : public Component {
 public:
-  UnitComponent(int health = 100, int maxHealth = 100, float speed = 1.0f,
-                float vision = 12.0f)
-      : health(health), maxHealth(maxHealth), speed(speed), ownerId(0),
-        visionRange(vision), spawnType(Game::Units::SpawnType::Archer) {}
+  UnitComponent(int health = Defaults::kUnitDefaultHealth,
+                int max_health = Defaults::kUnitDefaultHealth,
+                float speed = 1.0F,
+                float vision = Defaults::kUnitDefaultVisionRange)
+      : health(health), max_health(max_health), speed(speed),
+        vision_range(vision) {}
 
   int health;
-  int maxHealth;
+  int max_health;
   float speed;
-  Game::Units::SpawnType spawnType;
-  int ownerId;
-  float visionRange;
+  Game::Units::SpawnType spawn_type{Game::Units::SpawnType::Archer};
+  int owner_id{0};
+  float vision_range;
 };
 
 class MovementComponent : public Component {
 public:
-  MovementComponent()
-      : hasTarget(false), targetX(0.0f), targetY(0.0f), goalX(0.0f),
-        goalY(0.0f), vx(0.0f), vz(0.0f), pathPending(false),
-        pendingRequestId(0), repathCooldown(0.0f), lastGoalX(0.0f),
-        lastGoalY(0.0f), timeSinceLastPathRequest(0.0f) {}
-
-  bool hasTarget;
-  float targetX, targetY;
-  float goalX, goalY;
-  float vx, vz;
+  MovementComponent() = default;
+
+  bool hasTarget{false};
+  float target_x{0.0F}, target_y{0.0F};
+  float goalX{0.0F}, goalY{0.0F};
+  float vx{0.0F}, vz{0.0F};
   std::vector<std::pair<float, float>> path;
-  bool pathPending;
-  std::uint64_t pendingRequestId;
-  float repathCooldown;
+  bool pathPending{false};
+  std::uint64_t pendingRequestId{0};
+  float repathCooldown{0.0F};
 
-  float lastGoalX, lastGoalY;
-  float timeSinceLastPathRequest;
+  float lastGoalX{0.0F}, lastGoalY{0.0F};
+  float timeSinceLastPathRequest{0.0F};
 };
 
 class AttackComponent : public Component {
 public:
   enum class CombatMode { Ranged, Melee, Auto };
 
-  AttackComponent(float range = 2.0f, int damage = 10, float cooldown = 1.0f)
-      : range(range), damage(damage), cooldown(cooldown), timeSinceLast(0.0f),
-        meleeRange(1.5f), meleeDamage(damage), meleeCooldown(cooldown),
-        preferredMode(CombatMode::Auto), currentMode(CombatMode::Ranged),
-        canMelee(true), canRanged(false), maxHeightDifference(2.0f),
-        inMeleeLock(false), meleeLockTargetId(0) {}
+  AttackComponent(float range = Defaults::kAttackDefaultRange,
+                  int damage = Defaults::kAttackDefaultDamage,
+                  float cooldown = 1.0F)
+      : range(range), damage(damage), cooldown(cooldown),
+        meleeRange(Defaults::kAttackMeleeRange), meleeDamage(damage),
+        meleeCooldown(cooldown),
+        max_heightDifference(Defaults::kAttackHeightTolerance) {}
 
   float range;
   int damage;
   float cooldown;
-  float timeSinceLast;
+  float timeSinceLast{0.0F};
 
   float meleeRange;
   int meleeDamage;
   float meleeCooldown;
 
-  CombatMode preferredMode;
-  CombatMode currentMode;
+  CombatMode preferredMode{CombatMode::Auto};
+  CombatMode currentMode{CombatMode::Ranged};
 
-  bool canMelee;
-  bool canRanged;
+  bool canMelee{true};
+  bool canRanged{false};
 
-  float maxHeightDifference;
+  float max_heightDifference;
 
-  bool inMeleeLock;
-  EntityID meleeLockTargetId;
+  bool inMeleeLock{false};
+  EntityID meleeLockTargetId{0};
 
-  bool isInMeleeRange(float distance, float heightDiff) const {
-    return distance <= meleeRange && heightDiff <= maxHeightDifference;
+  [[nodiscard]] auto isInMeleeRange(float distance,
+                                    float height_diff) const -> bool {
+    return distance <= meleeRange && height_diff <= max_heightDifference;
   }
 
-  bool isInRangedRange(float distance) const {
+  [[nodiscard]] auto isInRangedRange(float distance) const -> bool {
     return distance <= range && distance > meleeRange;
   }
 
-  int getCurrentDamage() const {
+  [[nodiscard]] auto getCurrentDamage() const -> int {
     return (currentMode == CombatMode::Melee) ? meleeDamage : damage;
   }
 
-  float getCurrentCooldown() const {
+  [[nodiscard]] auto getCurrentCooldown() const -> float {
     return (currentMode == CombatMode::Melee) ? meleeCooldown : cooldown;
   }
 
-  float getCurrentRange() const {
+  [[nodiscard]] auto getCurrentRange() const -> float {
     return (currentMode == CombatMode::Melee) ? meleeRange : range;
   }
 };
 
 class AttackTargetComponent : public Component {
 public:
-  AttackTargetComponent() : targetId(0), shouldChase(false) {}
+  AttackTargetComponent() = default;
 
-  EntityID targetId;
-  bool shouldChase;
+  EntityID target_id{0};
+  bool shouldChase{false};
 };
 
 class PatrolComponent : public Component {
 public:
-  PatrolComponent() : currentWaypoint(0), patrolling(false) {}
+  PatrolComponent() = default;
 
   std::vector<std::pair<float, float>> waypoints;
-  size_t currentWaypoint;
-  bool patrolling;
+  size_t currentWaypoint{0};
+  bool patrolling{false};
 };
 
 } // namespace Engine::Core
@@ -165,20 +182,19 @@ public:
 class ProductionComponent : public Component {
 public:
   ProductionComponent()
-      : inProgress(false), buildTime(4.0f), timeRemaining(0.0f),
-        producedCount(0), maxUnits(5),
-        productType(Game::Units::TroopType::Archer), rallyX(0.0f), rallyZ(0.0f),
-        rallySet(false), villagerCost(1) {}
+      : buildTime(Defaults::kProductionDefaultBuildTime),
+
+        maxUnits(Defaults::kProductionMaxUnits) {}
 
-  bool inProgress;
+  bool inProgress{false};
   float buildTime;
-  float timeRemaining;
-  int producedCount;
+  float timeRemaining{0.0F};
+  int producedCount{0};
   int maxUnits;
-  Game::Units::TroopType productType;
-  float rallyX, rallyZ;
-  bool rallySet;
-  int villagerCost;
+  Game::Units::TroopType product_type{Game::Units::TroopType::Archer};
+  float rallyX{0.0F}, rallyZ{0.0F};
+  bool rallySet{false};
+  int villagerCost{1};
   std::vector<Game::Units::TroopType> productionQueue;
 };
 
@@ -189,14 +205,12 @@ public:
 
 class CaptureComponent : public Component {
 public:
-  CaptureComponent()
-      : capturingPlayerId(-1), captureProgress(0.0f), requiredTime(15.0f),
-        isBeingCaptured(false) {}
+  CaptureComponent() : requiredTime(Defaults::kCaptureRequiredTime) {}
 
-  int capturingPlayerId;
-  float captureProgress;
+  int capturing_player_id{-1};
+  float captureProgress{0.0F};
   float requiredTime;
-  bool isBeingCaptured;
+  bool isBeingCaptured{false};
 };
 
 class PendingRemovalComponent : public Component {
@@ -206,11 +220,10 @@ public:
 
 class HoldModeComponent : public Component {
 public:
-  HoldModeComponent()
-      : active(true), exitCooldown(0.0f), standUpDuration(2.0f) {}
+  HoldModeComponent() : standUpDuration(Defaults::kHoldStandUpDuration) {}
 
-  bool active;
-  float exitCooldown;
+  bool active{true};
+  float exitCooldown{0.0F};
   float standUpDuration;
 };
 

+ 1 - 2
game/core/entity.cpp

@@ -1,10 +1,9 @@
 #include "entity.h"
-#include <typeindex>
 
 namespace Engine::Core {
 
 Entity::Entity(EntityID id) : m_id(id) {}
 
-EntityID Entity::getId() const { return m_id; }
+auto Entity::getId() const -> EntityID { return m_id; }
 
 } // namespace Engine::Core

+ 6 - 5
game/core/entity.h

@@ -21,9 +21,10 @@ class Entity {
 public:
   Entity(EntityID id);
 
-  EntityID getId() const;
+  auto getId() const -> EntityID;
 
-  template <typename T, typename... Args> T *addComponent(Args &&...args) {
+  template <typename T, typename... Args>
+  auto addComponent(Args &&...args) -> T * {
     static_assert(std::is_base_of_v<Component, T>,
                   "T must inherit from Component");
     auto component = std::make_unique<T>(std::forward<Args>(args)...);
@@ -32,7 +33,7 @@ public:
     return ptr;
   }
 
-  template <typename T> T *getComponent() {
+  template <typename T> auto getComponent() -> T * {
     auto it = m_components.find(std::type_index(typeid(T)));
     if (it != m_components.end()) {
       return static_cast<T *>(it->second.get());
@@ -40,7 +41,7 @@ public:
     return nullptr;
   }
 
-  template <typename T> const T *getComponent() const {
+  template <typename T> auto getComponent() const -> const T * {
     auto it = m_components.find(std::type_index(typeid(T)));
     if (it != m_components.end()) {
       return static_cast<const T *>(it->second.get());
@@ -52,7 +53,7 @@ public:
     m_components.erase(std::type_index(typeid(T)));
   }
 
-  template <typename T> bool hasComponent() const {
+  template <typename T> auto hasComponent() const -> bool {
     return m_components.find(std::type_index(typeid(T))) != m_components.end();
   }
 

+ 0 - 1
game/core/event_manager.cpp

@@ -1,3 +1,2 @@
-#include "event_manager.h"
 
 namespace Engine::Core {}

+ 67 - 54
game/core/event_manager.h

@@ -8,6 +8,7 @@
 #include <mutex>
 #include <typeindex>
 #include <unordered_map>
+#include <utility>
 #include <vector>
 
 namespace Engine::Core {
@@ -15,7 +16,9 @@ namespace Engine::Core {
 class Event {
 public:
   virtual ~Event() = default;
-  virtual const char *getTypeName() const { return "Event"; }
+  [[nodiscard]] virtual auto getTypeName() const -> const char * {
+    return "Event";
+  }
 };
 
 template <typename T> using EventHandler = std::function<void(const T &)>;
@@ -29,20 +32,21 @@ struct EventStats {
 
 class EventManager {
 public:
-  static EventManager &instance() {
+  static auto instance() -> EventManager & {
     static EventManager inst;
     return inst;
   }
 
-  template <typename T> SubscriptionHandle subscribe(EventHandler<T> handler) {
+  template <typename T>
+  auto subscribe(EventHandler<T> handler) -> SubscriptionHandle {
     static_assert(std::is_base_of_v<Event, T>, "T must inherit from Event");
-    std::lock_guard<std::mutex> lock(m_mutex);
+    std::lock_guard<std::mutex> const lock(m_mutex);
 
-    SubscriptionHandle handle = m_nextHandle++;
+    SubscriptionHandle const handle = m_nextHandle++;
     auto wrapper = [handler, handle](const void *event) {
       handler(*static_cast<const T *>(event));
     };
-    HandlerEntry entry{handle, wrapper};
+    HandlerEntry const entry{handle, wrapper};
     m_handlers[std::type_index(typeid(T))].push_back(entry);
 
     m_stats[std::type_index(typeid(T))].subscriberCount++;
@@ -52,7 +56,7 @@ public:
 
   template <typename T> void unsubscribe(SubscriptionHandle handle) {
     static_assert(std::is_base_of_v<Event, T>, "T must inherit from Event");
-    std::lock_guard<std::mutex> lock(m_mutex);
+    std::lock_guard<std::mutex> const lock(m_mutex);
 
     auto it = m_handlers.find(std::type_index(typeid(T)));
     if (it != m_handlers.end()) {
@@ -75,7 +79,7 @@ public:
     std::vector<HandlerEntry> handlersCopy;
 
     {
-      std::lock_guard<std::mutex> lock(m_mutex);
+      std::lock_guard<std::mutex> const lock(m_mutex);
       auto it = m_handlers.find(std::type_index(typeid(T)));
       if (it != m_handlers.end()) {
         handlersCopy = it->second;
@@ -88,8 +92,8 @@ public:
     }
   }
 
-  EventStats getStats(const std::type_index &eventType) const {
-    std::lock_guard<std::mutex> lock(m_mutex);
+  auto getStats(const std::type_index &eventType) const -> EventStats {
+    std::lock_guard<std::mutex> const lock(m_mutex);
     auto it = m_stats.find(eventType);
     if (it != m_stats.end()) {
       return it->second;
@@ -97,8 +101,8 @@ public:
     return EventStats{};
   }
 
-  size_t getSubscriberCount(const std::type_index &eventType) const {
-    std::lock_guard<std::mutex> lock(m_mutex);
+  auto getSubscriberCount(const std::type_index &eventType) const -> size_t {
+    std::lock_guard<std::mutex> const lock(m_mutex);
     auto it = m_handlers.find(eventType);
     if (it != m_handlers.end()) {
       return it->second.size();
@@ -107,7 +111,7 @@ public:
   }
 
   void clearAllSubscriptions() {
-    std::lock_guard<std::mutex> lock(m_mutex);
+    std::lock_guard<std::mutex> const lock(m_mutex);
     m_handlers.clear();
     m_stats.clear();
   }
@@ -134,14 +138,16 @@ public:
   ~ScopedEventSubscription() { unsubscribe(); }
 
   ScopedEventSubscription(const ScopedEventSubscription &) = delete;
-  ScopedEventSubscription &operator=(const ScopedEventSubscription &) = delete;
+  auto operator=(const ScopedEventSubscription &) -> ScopedEventSubscription & =
+                                                         delete;
 
   ScopedEventSubscription(ScopedEventSubscription &&other) noexcept
       : m_handle(other.m_handle) {
     other.m_handle = 0;
   }
 
-  ScopedEventSubscription &operator=(ScopedEventSubscription &&other) noexcept {
+  auto operator=(ScopedEventSubscription &&other) noexcept
+      -> ScopedEventSubscription & {
     if (this != &other) {
       unsubscribe();
       m_handle = other.m_handle;
@@ -163,66 +169,70 @@ private:
 
 class UnitSelectedEvent : public Event {
 public:
-  UnitSelectedEvent(EntityID unitId) : unitId(unitId) {}
-  EntityID unitId;
-  const char *getTypeName() const override { return "UNIT_SELECTED"; }
+  UnitSelectedEvent(EntityID unit_id) : unit_id(unit_id) {}
+  EntityID unit_id;
+  [[nodiscard]] auto getTypeName() const -> const char * override {
+    return "UNIT_SELECTED";
+  }
 };
 
 class UnitMovedEvent : public Event {
 public:
-  UnitMovedEvent(EntityID unitId, float x, float y)
-      : unitId(unitId), x(x), y(y) {}
-  EntityID unitId;
+  UnitMovedEvent(EntityID unit_id, float x, float y)
+      : unit_id(unit_id), x(x), y(y) {}
+  EntityID unit_id;
   float x, y;
 };
 
 class UnitDiedEvent : public Event {
 public:
-  UnitDiedEvent(EntityID unitId, int ownerId, Game::Units::SpawnType spawnType,
-                EntityID killerId = 0, int killerOwnerId = 0)
-      : unitId(unitId), ownerId(ownerId), spawnType(spawnType),
-        killerId(killerId), killerOwnerId(killerOwnerId) {}
-  EntityID unitId;
-  int ownerId;
-  Game::Units::SpawnType spawnType;
+  UnitDiedEvent(EntityID unit_id, int owner_id,
+                Game::Units::SpawnType spawn_type, EntityID killerId = 0,
+                int killer_owner_id = 0)
+      : unit_id(unit_id), owner_id(owner_id), spawn_type(spawn_type),
+        killerId(killerId), killer_owner_id(killer_owner_id) {}
+  EntityID unit_id;
+  int owner_id;
+  Game::Units::SpawnType spawn_type;
   EntityID killerId;
-  int killerOwnerId;
+  int killer_owner_id;
 };
 
 class UnitSpawnedEvent : public Event {
 public:
-  UnitSpawnedEvent(EntityID unitId, int ownerId,
-                   Game::Units::SpawnType spawnType)
-      : unitId(unitId), ownerId(ownerId), spawnType(spawnType) {}
-  EntityID unitId;
-  int ownerId;
-  Game::Units::SpawnType spawnType;
+  UnitSpawnedEvent(EntityID unit_id, int owner_id,
+                   Game::Units::SpawnType spawn_type)
+      : unit_id(unit_id), owner_id(owner_id), spawn_type(spawn_type) {}
+  EntityID unit_id;
+  int owner_id;
+  Game::Units::SpawnType spawn_type;
 };
 
 class BuildingAttackedEvent : public Event {
 public:
-  BuildingAttackedEvent(EntityID buildingId, int ownerId,
+  BuildingAttackedEvent(EntityID buildingId, int owner_id,
                         Game::Units::SpawnType buildingType,
-                        EntityID attackerId = 0, int attackerOwnerId = 0,
+                        EntityID attackerId = 0, int attacker_owner_id = 0,
                         int damage = 0)
-      : buildingId(buildingId), ownerId(ownerId), buildingType(buildingType),
-        attackerId(attackerId), attackerOwnerId(attackerOwnerId),
+      : buildingId(buildingId), owner_id(owner_id), buildingType(buildingType),
+        attackerId(attackerId), attacker_owner_id(attacker_owner_id),
         damage(damage) {}
   EntityID buildingId;
-  int ownerId;
+  int owner_id;
   Game::Units::SpawnType buildingType;
   EntityID attackerId;
-  int attackerOwnerId;
+  int attacker_owner_id;
   int damage;
 };
 
 class BarrackCapturedEvent : public Event {
 public:
-  BarrackCapturedEvent(EntityID barrackId, int previousOwnerId, int newOwnerId)
-      : barrackId(barrackId), previousOwnerId(previousOwnerId),
+  BarrackCapturedEvent(EntityID barrackId, int previous_owner_id,
+                       int newOwnerId)
+      : barrackId(barrackId), previous_owner_id(previous_owner_id),
         newOwnerId(newOwnerId) {}
   EntityID barrackId;
-  int previousOwnerId;
+  int previous_owner_id;
   int newOwnerId;
 };
 
@@ -230,18 +240,21 @@ enum class AmbientState { PEACEFUL, TENSE, COMBAT, VICTORY, DEFEAT };
 
 class AmbientStateChangedEvent : public Event {
 public:
-  AmbientStateChangedEvent(AmbientState newState, AmbientState previousState)
-      : newState(newState), previousState(previousState) {}
-  AmbientState newState;
-  AmbientState previousState;
-  const char *getTypeName() const override { return "AMBIENT_STATE_CHANGED"; }
+  AmbientStateChangedEvent(AmbientState new_state, AmbientState previous_state)
+      : new_state(new_state), previous_state(previous_state) {}
+  AmbientState new_state;
+  AmbientState previous_state;
+  [[nodiscard]] auto getTypeName() const -> const char * override {
+    return "AMBIENT_STATE_CHANGED";
+  }
 };
 
 class AudioTriggerEvent : public Event {
 public:
-  AudioTriggerEvent(const std::string &soundId, float volume = 1.0f,
-                    bool loop = false, int priority = 0)
-      : soundId(soundId), volume(volume), loop(loop), priority(priority) {}
+  AudioTriggerEvent(std::string soundId, float volume = 1.0F, bool loop = false,
+                    int priority = 0)
+      : soundId(std::move(soundId)), volume(volume), loop(loop),
+        priority(priority) {}
   std::string soundId;
   float volume;
   bool loop;
@@ -250,9 +263,9 @@ public:
 
 class MusicTriggerEvent : public Event {
 public:
-  MusicTriggerEvent(const std::string &musicId, float volume = 1.0f,
+  MusicTriggerEvent(std::string musicId, float volume = 1.0F,
                     bool crossfade = true)
-      : musicId(musicId), volume(volume), crossfade(crossfade) {}
+      : musicId(std::move(musicId)), volume(volume), crossfade(crossfade) {}
   std::string musicId;
   float volume;
   bool crossfade;

+ 5 - 5
game/core/ownership_constants.h

@@ -1,11 +1,11 @@
 #pragma once
 
-namespace Game {
-namespace Core {
+namespace Game::Core {
 
 constexpr int NEUTRAL_OWNER_ID = -1;
 
-inline bool isNeutralOwner(int ownerId) { return ownerId == NEUTRAL_OWNER_ID; }
+inline auto isNeutralOwner(int owner_id) -> bool {
+  return owner_id == NEUTRAL_OWNER_ID;
+}
 
-} // namespace Core
-} // namespace Game
+} // namespace Game::Core

File diff suppressed because it is too large
+ 523 - 466
game/core/serialization.cpp


+ 9 - 8
game/core/serialization.h

@@ -13,21 +13,22 @@ namespace Engine::Core {
 
 class Serialization {
 public:
-  static QJsonObject serializeEntity(const class Entity *entity);
+  static auto serializeEntity(const class Entity *entity) -> QJsonObject;
   static void deserializeEntity(class Entity *entity, const QJsonObject &json);
 
-  static QJsonDocument serializeWorld(const class World *world);
+  static auto serializeWorld(const class World *world) -> QJsonDocument;
   static void deserializeWorld(class World *world, const QJsonDocument &doc);
 
-  static QJsonObject
-  serializeTerrain(const Game::Map::TerrainHeightMap *heightMap,
-                   const Game::Map::BiomeSettings &biome);
-  static void deserializeTerrain(Game::Map::TerrainHeightMap *heightMap,
+  static auto
+  serializeTerrain(const Game::Map::TerrainHeightMap *height_map,
+                   const Game::Map::BiomeSettings &biome) -> QJsonObject;
+  static void deserializeTerrain(Game::Map::TerrainHeightMap *height_map,
                                  Game::Map::BiomeSettings &biome,
                                  const QJsonObject &json);
 
-  static bool saveToFile(const QString &filename, const QJsonDocument &doc);
-  static QJsonDocument loadFromFile(const QString &filename);
+  static auto saveToFile(const QString &filename,
+                         const QJsonDocument &doc) -> bool;
+  static auto loadFromFile(const QString &filename) -> QJsonDocument;
 };
 
 } // namespace Engine::Core

+ 2 - 2
game/core/system.h

@@ -11,8 +11,8 @@ public:
   System() = default;
   System(const System &) = default;
   System(System &&) noexcept = default;
-  System &operator=(const System &) = default;
-  System &operator=(System &&) noexcept = default;
+  auto operator=(const System &) -> System & = default;
+  auto operator=(System &&) noexcept -> System & = default;
   virtual ~System() = default;
   virtual void update(World *world, float deltaTime) = 0;
 };

+ 44 - 38
game/core/world.cpp

@@ -2,42 +2,48 @@
 #include "../systems/owner_registry.h"
 #include "../systems/troop_count_registry.h"
 #include "component.h"
+#include "core/entity.h"
+#include "core/system.h"
 #include <algorithm>
+#include <memory>
+#include <mutex>
+#include <utility>
+#include <vector>
 
 namespace Engine::Core {
 
 World::World() = default;
 World::~World() = default;
 
-Entity *World::createEntity() {
+auto World::createEntity() -> Entity * {
   const std::lock_guard<std::recursive_mutex> lock(m_entityMutex);
-  EntityID id = m_nextEntityId++;
+  EntityID const id = m_nextEntityId++;
   auto entity = std::make_unique<Entity>(id);
-  auto ptr = entity.get();
+  auto *ptr = entity.get();
   m_entities[id] = std::move(entity);
   return ptr;
 }
 
-Entity *World::createEntityWithId(EntityID entityId) {
+auto World::createEntityWithId(EntityID entity_id) -> Entity * {
   const std::lock_guard<std::recursive_mutex> lock(m_entityMutex);
-  if (entityId == NULL_ENTITY) {
+  if (entity_id == NULL_ENTITY) {
     return nullptr;
   }
 
-  auto entity = std::make_unique<Entity>(entityId);
-  auto ptr = entity.get();
-  m_entities[entityId] = std::move(entity);
+  auto entity = std::make_unique<Entity>(entity_id);
+  auto *ptr = entity.get();
+  m_entities[entity_id] = std::move(entity);
 
-  if (entityId >= m_nextEntityId) {
-    m_nextEntityId = entityId + 1;
+  if (entity_id >= m_nextEntityId) {
+    m_nextEntityId = entity_id + 1;
   }
 
   return ptr;
 }
 
-void World::destroyEntity(EntityID entityId) {
+void World::destroyEntity(EntityID entity_id) {
   const std::lock_guard<std::recursive_mutex> lock(m_entityMutex);
-  m_entities.erase(entityId);
+  m_entities.erase(entity_id);
 }
 
 void World::clear() {
@@ -46,9 +52,9 @@ void World::clear() {
   m_nextEntityId = 1;
 }
 
-Entity *World::getEntity(EntityID entityId) {
+auto World::getEntity(EntityID entity_id) -> Entity * {
   const std::lock_guard<std::recursive_mutex> lock(m_entityMutex);
-  auto it = m_entities.find(entityId);
+  auto it = m_entities.find(entity_id);
   return it != m_entities.end() ? it->second.get() : nullptr;
 }
 
@@ -62,89 +68,89 @@ void World::update(float deltaTime) {
   }
 }
 
-std::vector<Entity *> World::getUnitsOwnedBy(int ownerId) const {
+auto World::getUnitsOwnedBy(int owner_id) const -> std::vector<Entity *> {
   const std::lock_guard<std::recursive_mutex> lock(m_entityMutex);
   std::vector<Entity *> result;
   result.reserve(m_entities.size());
-  for (auto &[entityId, entity] : m_entities) {
+  for (const auto &[entity_id, entity] : m_entities) {
     auto *unit = entity->getComponent<UnitComponent>();
-    if (!unit) {
+    if (unit == nullptr) {
       continue;
     }
-    if (unit->ownerId == ownerId) {
+    if (unit->owner_id == owner_id) {
       result.push_back(entity.get());
     }
   }
   return result;
 }
 
-std::vector<Entity *> World::getUnitsNotOwnedBy(int ownerId) const {
+auto World::getUnitsNotOwnedBy(int owner_id) const -> std::vector<Entity *> {
   const std::lock_guard<std::recursive_mutex> lock(m_entityMutex);
   std::vector<Entity *> result;
   result.reserve(m_entities.size());
-  for (auto &[entityId, entity] : m_entities) {
+  for (const auto &[entity_id, entity] : m_entities) {
     auto *unit = entity->getComponent<UnitComponent>();
-    if (!unit) {
+    if (unit == nullptr) {
       continue;
     }
-    if (unit->ownerId != ownerId) {
+    if (unit->owner_id != owner_id) {
       result.push_back(entity.get());
     }
   }
   return result;
 }
 
-std::vector<Entity *> World::getAlliedUnits(int ownerId) const {
+auto World::getAlliedUnits(int owner_id) const -> std::vector<Entity *> {
   const std::lock_guard<std::recursive_mutex> lock(m_entityMutex);
   std::vector<Entity *> result;
   result.reserve(m_entities.size());
-  auto &ownerRegistry = Game::Systems::OwnerRegistry::instance();
+  auto &owner_registry = Game::Systems::OwnerRegistry::instance();
 
-  for (auto &[entityId, entity] : m_entities) {
+  for (const auto &[entity_id, entity] : m_entities) {
     auto *unit = entity->getComponent<UnitComponent>();
-    if (!unit) {
+    if (unit == nullptr) {
       continue;
     }
 
-    if (unit->ownerId == ownerId ||
-        ownerRegistry.areAllies(ownerId, unit->ownerId)) {
+    if (unit->owner_id == owner_id ||
+        owner_registry.areAllies(owner_id, unit->owner_id)) {
       result.push_back(entity.get());
     }
   }
   return result;
 }
 
-std::vector<Entity *> World::getEnemyUnits(int ownerId) const {
+auto World::getEnemyUnits(int owner_id) const -> std::vector<Entity *> {
   const std::lock_guard<std::recursive_mutex> lock(m_entityMutex);
   std::vector<Entity *> result;
   result.reserve(m_entities.size());
-  auto &ownerRegistry = Game::Systems::OwnerRegistry::instance();
+  auto &owner_registry = Game::Systems::OwnerRegistry::instance();
 
-  for (auto &[entityId, entity] : m_entities) {
+  for (const auto &[entity_id, entity] : m_entities) {
     auto *unit = entity->getComponent<UnitComponent>();
-    if (!unit) {
+    if (unit == nullptr) {
       continue;
     }
 
-    if (ownerRegistry.areEnemies(ownerId, unit->ownerId)) {
+    if (owner_registry.areEnemies(owner_id, unit->owner_id)) {
       result.push_back(entity.get());
     }
   }
   return result;
 }
 
-int World::countTroopsForPlayer(int ownerId) const {
-  return Game::Systems::TroopCountRegistry::instance().getTroopCount(ownerId);
+int World::countTroopsForPlayer(int owner_id) {
+  return Game::Systems::TroopCountRegistry::instance().getTroopCount(owner_id);
 }
 
-EntityID World::getNextEntityId() const {
+auto World::getNextEntityId() const -> EntityID {
   const std::lock_guard<std::recursive_mutex> lock(m_entityMutex);
   return m_nextEntityId;
 }
 
-void World::setNextEntityId(EntityID nextId) {
+void World::setNextEntityId(EntityID next_id) {
   const std::lock_guard<std::recursive_mutex> lock(m_entityMutex);
-  m_nextEntityId = std::max(nextId, m_nextEntityId);
+  m_nextEntityId = std::max(next_id, m_nextEntityId);
 }
 
 } // namespace Engine::Core

+ 20 - 20
game/core/world.h

@@ -16,21 +16,21 @@ public:
 
   World(const World &) = delete;
   World(World &&) = delete;
-  World &operator=(const World &) = delete;
-  World &operator=(World &&) = delete;
+  auto operator=(const World &) -> World & = delete;
+  auto operator=(World &&) -> World & = delete;
 
-  Entity *createEntity();
-  Entity *createEntityWithId(EntityID entityId);
-  void destroyEntity(EntityID entityId);
-  Entity *getEntity(EntityID entityId);
+  auto createEntity() -> Entity *;
+  auto createEntityWithId(EntityID entity_id) -> Entity *;
+  void destroyEntity(EntityID entity_id);
+  auto getEntity(EntityID entity_id) -> Entity *;
   void clear();
 
   void addSystem(std::unique_ptr<System> system);
   void update(float deltaTime);
 
-  std::vector<std::unique_ptr<System>> &systems() { return m_systems; }
+  auto systems() -> std::vector<std::unique_ptr<System>> & { return m_systems; }
 
-  template <typename T> T *getSystem() {
+  template <typename T> auto getSystem() -> T * {
     for (auto &system : m_systems) {
       if (auto *ptr = dynamic_cast<T *>(system.get())) {
         return ptr;
@@ -39,10 +39,10 @@ public:
     return nullptr;
   }
 
-  template <typename T> std::vector<Entity *> getEntitiesWith() {
+  template <typename T> auto getEntitiesWith() -> std::vector<Entity *> {
     const std::lock_guard<std::recursive_mutex> lock(m_entityMutex);
     std::vector<Entity *> result;
-    for (auto &[entityId, entity] : m_entities) {
+    for (auto &[entity_id, entity] : m_entities) {
       if (entity->template hasComponent<T>()) {
         result.push_back(entity.get());
       }
@@ -50,21 +50,21 @@ public:
     return result;
   }
 
-  std::vector<Entity *> getUnitsOwnedBy(int ownerId) const;
-  std::vector<Entity *> getUnitsNotOwnedBy(int ownerId) const;
-  std::vector<Entity *> getAlliedUnits(int ownerId) const;
-  std::vector<Entity *> getEnemyUnits(int ownerId) const;
-  int countTroopsForPlayer(int ownerId) const;
+  auto getUnitsOwnedBy(int owner_id) const -> std::vector<Entity *>;
+  auto getUnitsNotOwnedBy(int owner_id) const -> std::vector<Entity *>;
+  auto getAlliedUnits(int owner_id) const -> std::vector<Entity *>;
+  auto getEnemyUnits(int owner_id) const -> std::vector<Entity *>;
+  static auto countTroopsForPlayer(int owner_id) -> int;
 
-  const std::unordered_map<EntityID, std::unique_ptr<Entity>> &
-  getEntities() const {
+  auto getEntities() const
+      -> const std::unordered_map<EntityID, std::unique_ptr<Entity>> & {
     return m_entities;
   }
 
-  EntityID getNextEntityId() const;
-  void setNextEntityId(EntityID nextId);
+  auto getNextEntityId() const -> EntityID;
+  void setNextEntityId(EntityID next_id);
 
-  std::recursive_mutex &getEntityMutex() { return m_entityMutex; }
+  auto getEntityMutex() -> std::recursive_mutex & { return m_entityMutex; }
 
 private:
   EntityID m_nextEntityId = 1;

+ 38 - 34
game/game_config.h

@@ -3,79 +3,83 @@
 namespace Game {
 
 struct CameraConfig {
-  float defaultDistance = 12.0f;
-  float defaultPitch = 45.0f;
-  float defaultYaw = 225.0f;
-  float orbitStepNormal = 4.0f;
-  float orbitStepShift = 8.0f;
+  float defaultDistance = 12.0F;
+  float defaultPitch = 45.0F;
+  float defaultYaw = 225.0F;
+  float orbitStepNormal = 4.0F;
+  float orbitStepShift = 8.0F;
 };
 
 struct ArrowConfig {
-  float arcHeightMultiplier = 0.15f;
-  float arcHeightMin = 0.2f;
-  float arcHeightMax = 1.2f;
-  float speedDefault = 8.0f;
-  float speedAttack = 6.0f;
+  float arcHeightMultiplier = 0.15F;
+  float arcHeightMin = 0.2F;
+  float arcHeightMax = 1.2F;
+  float speedDefault = 8.0F;
+  float speedAttack = 6.0F;
 };
 
 struct GameplayConfig {
-  float visibilityUpdateInterval = 0.075f;
-  float formationSpacingDefault = 1.0f;
-  int maxTroopsPerPlayer = 50;
+  float visibility_update_interval = 0.075F;
+  float formationSpacingDefault = 1.0F;
+  int max_troops_per_player = 50;
 };
 
 class GameConfig {
 public:
-  static GameConfig &instance() noexcept {
+  static auto instance() noexcept -> GameConfig & {
     static GameConfig inst;
     return inst;
   }
 
-  [[nodiscard]] const CameraConfig &camera() const noexcept { return m_camera; }
-  [[nodiscard]] const ArrowConfig &arrow() const noexcept { return m_arrow; }
-  [[nodiscard]] const GameplayConfig &gameplay() const noexcept {
+  [[nodiscard]] auto camera() const noexcept -> const CameraConfig & {
+    return m_camera;
+  }
+  [[nodiscard]] auto arrow() const noexcept -> const ArrowConfig & {
+    return m_arrow;
+  }
+  [[nodiscard]] auto gameplay() const noexcept -> const GameplayConfig & {
     return m_gameplay;
   }
 
-  [[nodiscard]] float getCameraDefaultDistance() const noexcept {
+  [[nodiscard]] auto getCameraDefaultDistance() const noexcept -> float {
     return m_camera.defaultDistance;
   }
-  [[nodiscard]] float getCameraDefaultPitch() const noexcept {
+  [[nodiscard]] auto getCameraDefaultPitch() const noexcept -> float {
     return m_camera.defaultPitch;
   }
-  [[nodiscard]] float getCameraDefaultYaw() const noexcept {
+  [[nodiscard]] auto getCameraDefaultYaw() const noexcept -> float {
     return m_camera.defaultYaw;
   }
 
-  [[nodiscard]] float getArrowArcHeightMultiplier() const noexcept {
+  [[nodiscard]] auto getArrowArcHeightMultiplier() const noexcept -> float {
     return m_arrow.arcHeightMultiplier;
   }
-  [[nodiscard]] float getArrowArcHeightMin() const noexcept {
+  [[nodiscard]] auto getArrowArcHeightMin() const noexcept -> float {
     return m_arrow.arcHeightMin;
   }
-  [[nodiscard]] float getArrowArcHeightMax() const noexcept {
+  [[nodiscard]] auto getArrowArcHeightMax() const noexcept -> float {
     return m_arrow.arcHeightMax;
   }
 
-  [[nodiscard]] float getArrowSpeedDefault() const noexcept {
+  [[nodiscard]] auto getArrowSpeedDefault() const noexcept -> float {
     return m_arrow.speedDefault;
   }
-  [[nodiscard]] float getArrowSpeedAttack() const noexcept {
+  [[nodiscard]] auto getArrowSpeedAttack() const noexcept -> float {
     return m_arrow.speedAttack;
   }
 
-  [[nodiscard]] float getVisibilityUpdateInterval() const noexcept {
-    return m_gameplay.visibilityUpdateInterval;
+  [[nodiscard]] auto getVisibilityUpdateInterval() const noexcept -> float {
+    return m_gameplay.visibility_update_interval;
   }
 
-  [[nodiscard]] float getFormationSpacingDefault() const noexcept {
+  [[nodiscard]] auto getFormationSpacingDefault() const noexcept -> float {
     return m_gameplay.formationSpacingDefault;
   }
 
-  [[nodiscard]] float getCameraOrbitStepNormal() const noexcept {
+  [[nodiscard]] auto getCameraOrbitStepNormal() const noexcept -> float {
     return m_camera.orbitStepNormal;
   }
-  [[nodiscard]] float getCameraOrbitStepShift() const noexcept {
+  [[nodiscard]] auto getCameraOrbitStepShift() const noexcept -> float {
     return m_camera.orbitStepShift;
   }
 
@@ -107,7 +111,7 @@ public:
   }
 
   void setVisibilityUpdateInterval(float value) noexcept {
-    m_gameplay.visibilityUpdateInterval = value;
+    m_gameplay.visibility_update_interval = value;
   }
 
   void setFormationSpacingDefault(float value) noexcept {
@@ -121,12 +125,12 @@ public:
     m_camera.orbitStepShift = value;
   }
 
-  [[nodiscard]] int getMaxTroopsPerPlayer() const noexcept {
-    return m_gameplay.maxTroopsPerPlayer;
+  [[nodiscard]] auto getMaxTroopsPerPlayer() const noexcept -> int {
+    return m_gameplay.max_troops_per_player;
   }
 
   void setMaxTroopsPerPlayer(int value) noexcept {
-    m_gameplay.maxTroopsPerPlayer = value;
+    m_gameplay.max_troops_per_player = value;
   }
 
 private:

+ 14 - 15
game/map/environment.cpp

@@ -2,38 +2,37 @@
 #include "../../render/gl/camera.h"
 #include "../../render/scene_renderer.h"
 #include "../game_config.h"
+#include "map/map_definition.h"
 #include <algorithm>
 
-namespace Game {
-namespace Map {
+namespace Game::Map {
 
 void Environment::apply(const MapDefinition &def,
                         Render::GL::Renderer &renderer,
                         Render::GL::Camera &camera) {
 
   camera.setRTSView(def.camera.center, def.camera.distance, def.camera.tiltDeg,
-                    def.camera.yawDeg);
-  camera.setPerspective(def.camera.fovY, 16.0f / 9.0f, def.camera.nearPlane,
-                        def.camera.farPlane);
+                    def.camera.yaw_deg);
+  camera.setPerspective(def.camera.fovY, 16.0F / 9.0F, def.camera.near_plane,
+                        def.camera.far_plane);
   Render::GL::Renderer::GridParams gp;
-  gp.cellSize = def.grid.tileSize;
+  gp.cellSize = def.grid.tile_size;
   gp.extent =
-      std::max(def.grid.width, def.grid.height) * def.grid.tileSize * 0.5f;
+      std::max(def.grid.width, def.grid.height) * def.grid.tile_size * 0.5F;
   renderer.setGridParams(gp);
 }
 
 void Environment::applyDefault(Render::GL::Renderer &renderer,
                                Render::GL::Camera &camera) {
-  const auto &cameraConfig = Game::GameConfig::instance().camera();
-  camera.setRTSView(QVector3D(0, 0, 0), 15.0f, cameraConfig.defaultPitch,
-                    cameraConfig.defaultYaw);
+  const auto &camera_config = Game::GameConfig::instance().camera();
+  camera.setRTSView(QVector3D(0, 0, 0), 15.0F, camera_config.defaultPitch,
+                    camera_config.defaultYaw);
 
-  camera.setPerspective(45.0f, 16.0f / 9.0f, 1.0f, 200.0f);
+  camera.setPerspective(45.0F, 16.0F / 9.0F, 1.0F, 200.0F);
   Render::GL::Renderer::GridParams gp;
-  gp.cellSize = 1.0f;
-  gp.extent = 50.0f;
+  gp.cellSize = 1.0F;
+  gp.extent = 50.0F;
   renderer.setGridParams(gp);
 }
 
-} // namespace Map
-} // namespace Game
+} // namespace Game::Map

+ 4 - 8
game/map/environment.h

@@ -2,15 +2,12 @@
 
 #include "map_definition.h"
 
-namespace Render {
-namespace GL {
+namespace Render::GL {
 class Renderer;
 class Camera;
-} // namespace GL
-} // namespace Render
+} // namespace Render::GL
 
-namespace Game {
-namespace Map {
+namespace Game::Map {
 
 struct Environment {
   static void apply(const MapDefinition &def, Render::GL::Renderer &renderer,
@@ -19,5 +16,4 @@ struct Environment {
                            Render::GL::Camera &camera);
 };
 
-} // namespace Map
-} // namespace Game
+} // namespace Game::Map

+ 93 - 0
game/map/json_keys.h

@@ -0,0 +1,93 @@
+#pragma once
+
+namespace Game::Map::JsonKeys {
+
+inline constexpr const char *NAME = "name";
+inline constexpr const char *DESCRIPTION = "description";
+inline constexpr const char *COORD_SYSTEM = "coordSystem";
+inline constexpr const char *MAX_TROOPS_PER_PLAYER = "maxTroopsPerPlayer";
+inline constexpr const char *GRID = "grid";
+inline constexpr const char *BIOME = "biome";
+inline constexpr const char *CAMERA = "camera";
+inline constexpr const char *SPAWNS = "spawns";
+inline constexpr const char *FIRECAMPS = "firecamps";
+inline constexpr const char *TERRAIN = "terrain";
+inline constexpr const char *RIVERS = "rivers";
+inline constexpr const char *BRIDGES = "bridges";
+inline constexpr const char *VICTORY = "victory";
+inline constexpr const char *THUMBNAIL = "thumbnail";
+
+inline constexpr const char *WIDTH = "width";
+inline constexpr const char *HEIGHT = "height";
+inline constexpr const char *TILE_SIZE = "tileSize";
+
+inline constexpr const char *CENTER = "center";
+inline constexpr const char *DISTANCE = "distance";
+inline constexpr const char *TILT_DEG = "tiltDeg";
+inline constexpr const char *YAW = "yaw";
+inline constexpr const char *FOV_Y = "fovY";
+inline constexpr const char *NEAR = "near";
+inline constexpr const char *FAR = "far";
+
+inline constexpr const char *SEED = "seed";
+inline constexpr const char *PATCH_DENSITY = "patchDensity";
+inline constexpr const char *PATCH_JITTER = "patchJitter";
+inline constexpr const char *BLADE_HEIGHT = "bladeHeight";
+inline constexpr const char *BLADE_WIDTH = "bladeWidth";
+inline constexpr const char *SWAY_STRENGTH = "swayStrength";
+inline constexpr const char *SWAY_SPEED = "swaySpeed";
+inline constexpr const char *HEIGHT_NOISE = "heightNoise";
+inline constexpr const char *GRASS_PRIMARY = "grassPrimary";
+inline constexpr const char *GRASS_SECONDARY = "grassSecondary";
+inline constexpr const char *GRASS_DRY = "grassDry";
+inline constexpr const char *SOIL_COLOR = "soilColor";
+inline constexpr const char *ROCK_LOW = "rockLow";
+inline constexpr const char *ROCK_HIGH = "rockHigh";
+inline constexpr const char *PLANT_DENSITY = "plantDensity";
+inline constexpr const char *BACKGROUND_BLADE_DENSITY =
+    "backgroundBladeDensity";
+inline constexpr const char *TERRAIN_MACRO_NOISE_SCALE =
+    "terrainMacroNoiseScale";
+inline constexpr const char *TERRAIN_DETAIL_NOISE_SCALE =
+    "terrainDetailNoiseScale";
+inline constexpr const char *TERRAIN_SOIL_HEIGHT = "terrainSoilHeight";
+inline constexpr const char *TERRAIN_SOIL_SHARPNESS = "terrainSoilSharpness";
+inline constexpr const char *TERRAIN_ROCK_THRESHOLD = "terrainRockThreshold";
+inline constexpr const char *TERRAIN_ROCK_SHARPNESS = "terrainRockSharpness";
+inline constexpr const char *TERRAIN_AMBIENT_BOOST = "terrainAmbientBoost";
+inline constexpr const char *TERRAIN_ROCK_DETAIL_STRENGTH =
+    "terrainRockDetailStrength";
+inline constexpr const char *BACKGROUND_SWAY_VARIANCE =
+    "backgroundSwayVariance";
+inline constexpr const char *BACKGROUND_SCATTER_RADIUS =
+    "backgroundScatterRadius";
+
+inline constexpr const char *TYPE = "type";
+inline constexpr const char *X = "x";
+inline constexpr const char *Z = "z";
+inline constexpr const char *PLAYER_ID = "playerId";
+inline constexpr const char *TEAM_ID = "teamId";
+inline constexpr const char *MAX_POPULATION = "maxPopulation";
+
+inline constexpr const char *VICTORY_TYPE = "type";
+inline constexpr const char *KEY_STRUCTURES = "key_structures";
+inline constexpr const char *DEFEAT_CONDITIONS = "defeat_conditions";
+inline constexpr const char *SURVIVE_TIME_DURATION = "surviveTimeDuration";
+
+inline constexpr const char *RADIUS = "radius";
+inline constexpr const char *INTENSITY = "intensity";
+
+inline constexpr const char *TERRAIN_TYPE = "terrainType";
+inline constexpr const char *POSITION = "position";
+inline constexpr const char *SCALE = "scale";
+inline constexpr const char *ROTATION = "rotation";
+
+inline constexpr const char *POINTS = "points";
+inline constexpr const char *RIVER_WIDTH = "width";
+inline constexpr const char *FLOW_SPEED = "flowSpeed";
+
+inline constexpr const char *START = "start";
+inline constexpr const char *END = "end";
+inline constexpr const char *BRIDGE_WIDTH = "width";
+
+} // namespace Game::Map::JsonKeys

+ 54 - 50
game/map/level_loader.cpp

@@ -11,70 +11,75 @@
 #include "map_loader.h"
 #include "map_transformer.h"
 #include "terrain_service.h"
+#include "units/spawn_type.h"
+#include "units/troop_type.h"
+#include "units/unit.h"
 #include "utils/resource_utils.h"
 #include <QDebug>
+#include <memory>
+#include <qglobal.h>
+#include <qstringliteral.h>
 
-namespace Game {
-namespace Map {
+namespace Game::Map {
 
-LevelLoadResult LevelLoader::loadFromAssets(const QString &mapPath,
-                                            Engine::Core::World &world,
-                                            Render::GL::Renderer &renderer,
-                                            Render::GL::Camera &camera) {
+auto LevelLoader::loadFromAssets(
+    const QString &map_path, Engine::Core::World &world,
+    Render::GL::Renderer &renderer,
+    Render::GL::Camera &camera) -> LevelLoadResult {
   LevelLoadResult res;
 
   auto &owners = Game::Systems::OwnerRegistry::instance();
 
-  Game::Visuals::VisualCatalog visualCatalog;
-  QString visualsErr;
-  const QString visualsPath = Utils::Resources::resolveResourcePath(
+  Game::Visuals::VisualCatalog visual_catalog;
+  QString visuals_err;
+  const QString visuals_path = Utils::Resources::resolveResourcePath(
       QStringLiteral(":/assets/visuals/unit_visuals.json"));
-  if (!visualCatalog.loadFromJsonFile(visualsPath, &visualsErr)) {
+  if (!visual_catalog.loadFromJsonFile(visuals_path, &visuals_err)) {
     res.ok = false;
     res.errorMessage =
-        QString("Failed to load visual catalog: %1").arg(visualsErr);
+        QString("Failed to load visual catalog: %1").arg(visuals_err);
     qWarning() << res.errorMessage;
     return res;
   }
 
-  auto unitReg = std::make_shared<Game::Units::UnitFactoryRegistry>();
-  Game::Units::registerBuiltInUnits(*unitReg);
-  Game::Map::MapTransformer::setFactoryRegistry(unitReg);
+  auto unit_reg = std::make_shared<Game::Units::UnitFactoryRegistry>();
+  Game::Units::registerBuiltInUnits(*unit_reg);
+  Game::Map::MapTransformer::setFactoryRegistry(unit_reg);
 
-  const QString resolvedMapPath =
-      Utils::Resources::resolveResourcePath(mapPath);
+  const QString resolved_map_path =
+      Utils::Resources::resolveResourcePath(map_path);
 
   Game::Map::MapDefinition def;
   QString err;
-  if (Game::Map::MapLoader::loadFromJsonFile(resolvedMapPath, def, &err)) {
+  if (Game::Map::MapLoader::loadFromJsonFile(resolved_map_path, def, &err)) {
     res.ok = true;
-    res.mapName = def.name;
+    res.map_name = def.name;
 
     Game::Map::TerrainService::instance().initialize(def);
 
     Game::Map::Environment::apply(def, renderer, camera);
     res.camFov = def.camera.fovY;
-    res.camNear = def.camera.nearPlane;
-    res.camFar = def.camera.farPlane;
-    res.gridWidth = def.grid.width;
-    res.gridHeight = def.grid.height;
-    res.tileSize = def.grid.tileSize;
-    res.maxTroopsPerPlayer = def.maxTroopsPerPlayer;
+    res.camNear = def.camera.near_plane;
+    res.camFar = def.camera.far_plane;
+    res.grid_width = def.grid.width;
+    res.grid_height = def.grid.height;
+    res.tile_size = def.grid.tile_size;
+    res.max_troops_per_player = def.max_troops_per_player;
     res.victoryConfig = def.victory;
 
     auto rt =
-        Game::Map::MapTransformer::applyToWorld(def, world, &visualCatalog);
-    if (!rt.unitIds.empty()) {
-      res.playerUnitId = rt.unitIds.front();
+        Game::Map::MapTransformer::applyToWorld(def, world, &visual_catalog);
+    if (!rt.unit_ids.empty()) {
+      res.playerUnitId = rt.unit_ids.front();
     } else {
 
       auto reg = Game::Map::MapTransformer::getFactoryRegistry();
       if (reg) {
         Game::Units::SpawnParams sp;
-        sp.position = QVector3D(0.0f, 0.0f, 0.0f);
-        sp.playerId = 0;
-        sp.spawnType = Game::Units::SpawnType::Archer;
-        sp.aiControlled = !owners.isPlayer(sp.playerId);
+        sp.position = QVector3D(0.0F, 0.0F, 0.0F);
+        sp.player_id = 0;
+        sp.spawn_type = Game::Units::SpawnType::Archer;
+        sp.aiControlled = !owners.isPlayer(sp.player_id);
         if (auto unit =
                 reg->create(Game::Units::SpawnType::Archer, world, sp)) {
           res.playerUnitId = unit->id();
@@ -84,24 +89,24 @@ LevelLoadResult LevelLoader::loadFromAssets(const QString &mapPath,
       }
     }
 
-    bool hasBarracks = false;
+    bool has_barracks = false;
     for (auto *e : world.getEntitiesWith<Engine::Core::UnitComponent>()) {
       if (auto *u = e->getComponent<Engine::Core::UnitComponent>()) {
-        if (u->spawnType == Game::Units::SpawnType::Barracks &&
-            owners.isPlayer(u->ownerId)) {
-          hasBarracks = true;
+        if (u->spawn_type == Game::Units::SpawnType::Barracks &&
+            owners.isPlayer(u->owner_id)) {
+          has_barracks = true;
           break;
         }
       }
     }
-    if (!hasBarracks) {
+    if (!has_barracks) {
       auto reg2 = Game::Map::MapTransformer::getFactoryRegistry();
       if (reg2) {
         Game::Units::SpawnParams sp;
-        sp.position = QVector3D(-4.0f, 0.0f, -3.0f);
-        sp.playerId = owners.getLocalPlayerId();
-        sp.spawnType = Game::Units::SpawnType::Barracks;
-        sp.aiControlled = !owners.isPlayer(sp.playerId);
+        sp.position = QVector3D(-4.0F, 0.0F, -3.0F);
+        sp.player_id = owners.getLocalPlayerId();
+        sp.spawn_type = Game::Units::SpawnType::Barracks;
+        sp.aiControlled = !owners.isPlayer(sp.player_id);
         reg2->create(Game::Units::SpawnType::Barracks, world, sp);
       }
     }
@@ -109,24 +114,24 @@ LevelLoadResult LevelLoader::loadFromAssets(const QString &mapPath,
     res.ok = false;
     res.errorMessage = QString("Map load failed: %1").arg(err);
     qWarning() << "LevelLoader: Map load failed:" << err
-               << "(path:" << resolvedMapPath << ')'
+               << "(path:" << resolved_map_path << ')'
                << "- applying default environment";
     Game::Map::Environment::applyDefault(renderer, camera);
     res.ok = false;
     res.camFov = camera.getFOV();
     res.camNear = camera.getNear();
     res.camFar = camera.getFar();
-    res.gridWidth = 50;
-    res.gridHeight = 50;
-    res.tileSize = 1.0f;
+    res.grid_width = 50;
+    res.grid_height = 50;
+    res.tile_size = 1.0F;
 
     auto reg = Game::Map::MapTransformer::getFactoryRegistry();
     if (reg) {
       Game::Units::SpawnParams sp;
-      sp.position = QVector3D(0.0f, 0.0f, 0.0f);
-      sp.playerId = 0;
-      sp.spawnType = Game::Units::SpawnType::Archer;
-      sp.aiControlled = !owners.isPlayer(sp.playerId);
+      sp.position = QVector3D(0.0F, 0.0F, 0.0F);
+      sp.player_id = 0;
+      sp.spawn_type = Game::Units::SpawnType::Archer;
+      sp.aiControlled = !owners.isPlayer(sp.player_id);
       if (auto unit = reg->create(Game::Units::SpawnType::Archer, world, sp)) {
         res.playerUnitId = unit->id();
       }
@@ -136,5 +141,4 @@ LevelLoadResult LevelLoader::loadFromAssets(const QString &mapPath,
   return res;
 }
 
-} // namespace Map
-} // namespace Game
+} // namespace Game::Map

+ 19 - 24
game/map/level_loader.h

@@ -4,44 +4,39 @@
 #include <QString>
 #include <memory>
 
-namespace Engine {
-namespace Core {
+namespace Engine::Core {
 class World;
 using EntityID = unsigned int;
-} // namespace Core
-} // namespace Engine
-namespace Render {
-namespace GL {
+} // namespace Engine::Core
+
+namespace Render::GL {
 class Renderer;
 class Camera;
-} // namespace GL
-} // namespace Render
+} // namespace Render::GL
 
-namespace Game {
-namespace Map {
+namespace Game::Map {
 
 struct LevelLoadResult {
   bool ok = false;
-  QString mapName;
+  QString map_name;
   QString errorMessage;
   Engine::Core::EntityID playerUnitId = 0;
-  float camFov = 45.0f;
-  float camNear = 0.1f;
-  float camFar = 1000.0f;
-  int gridWidth = 50;
-  int gridHeight = 50;
-  float tileSize = 1.0f;
-  int maxTroopsPerPlayer = 50;
+  float camFov = 45.0F;
+  float camNear = 0.1F;
+  float camFar = 1000.0F;
+  int grid_width = 50;
+  int grid_height = 50;
+  float tile_size = 1.0F;
+  int max_troops_per_player = 50;
   VictoryConfig victoryConfig;
 };
 
 class LevelLoader {
 public:
-  static LevelLoadResult loadFromAssets(const QString &mapPath,
-                                        Engine::Core::World &world,
-                                        Render::GL::Renderer &renderer,
-                                        Render::GL::Camera &camera);
+  static auto loadFromAssets(const QString &map_path,
+                             Engine::Core::World &world,
+                             Render::GL::Renderer &renderer,
+                             Render::GL::Camera &camera) -> LevelLoadResult;
 };
 
-} // namespace Map
-} // namespace Game
+} // namespace Game::Map

+ 85 - 69
game/map/map_catalog.cpp

@@ -1,4 +1,5 @@
 #include "map_catalog.h"
+#include "json_keys.h"
 #include "utils/resource_utils.h"
 #include <QDir>
 #include <QFile>
@@ -6,57 +7,74 @@
 #include <QJsonArray>
 #include <QJsonDocument>
 #include <QJsonObject>
+#include <QJsonParseError>
 #include <QSet>
 #include <QStringList>
 #include <QTimer>
 #include <QVariantMap>
 #include <algorithm>
+#include <qdir.h>
+#include <qfiledevice.h>
+#include <qglobal.h>
+#include <qjsonarray.h>
+#include <qjsondocument.h>
+#include <qjsonobject.h>
+#include <qjsonvalue.h>
+#include <qlist.h>
+#include <qobject.h>
+#include <qset.h>
+#include <qstringliteral.h>
+#include <qstringview.h>
+#include <qtimer.h>
+#include <qtmetamacros.h>
 
-namespace Game {
-namespace Map {
+namespace Game::Map {
+
+using namespace JsonKeys;
 
 MapCatalog::MapCatalog(QObject *parent) : QObject(parent) {}
 
-QVariantList MapCatalog::availableMaps() {
+auto MapCatalog::availableMaps() -> QVariantList {
   QVariantList list;
   const QString mapsRoot =
       Utils::Resources::resolveResourcePath(QStringLiteral(":/assets/maps"));
-  QDir mapsDir(mapsRoot);
+  QDir const mapsDir(mapsRoot);
   if (!mapsDir.exists()) {
     return list;
   }
 
-  QStringList files =
+  QStringList const files =
       mapsDir.entryList(QStringList() << "*.json", QDir::Files, QDir::Name);
   for (const QString &f : files) {
-    QString path = Utils::Resources::resolveResourcePath(mapsDir.filePath(f));
+    QString const path =
+        Utils::Resources::resolveResourcePath(mapsDir.filePath(f));
     QFile file(path);
     QString name = f;
     QString desc;
-    QSet<int> playerIds;
+    QSet<int> player_ids;
     if (file.open(QIODevice::ReadOnly)) {
-      QByteArray data = file.readAll();
+      QByteArray const data = file.readAll();
       file.close();
       QJsonParseError err;
-      QJsonDocument doc = QJsonDocument::fromJson(data, &err);
+      QJsonDocument const doc = QJsonDocument::fromJson(data, &err);
       if (err.error == QJsonParseError::NoError && doc.isObject()) {
         QJsonObject obj = doc.object();
-        if (obj.contains("name") && obj["name"].isString()) {
-          name = obj["name"].toString();
+        if (obj.contains(NAME) && obj[NAME].isString()) {
+          name = obj[NAME].toString();
         }
-        if (obj.contains("description") && obj["description"].isString()) {
-          desc = obj["description"].toString();
+        if (obj.contains(DESCRIPTION) && obj[DESCRIPTION].isString()) {
+          desc = obj[DESCRIPTION].toString();
         }
 
-        if (obj.contains("spawns") && obj["spawns"].isArray()) {
-          QJsonArray spawns = obj["spawns"].toArray();
+        if (obj.contains(SPAWNS) && obj[SPAWNS].isArray()) {
+          QJsonArray const spawns = obj[SPAWNS].toArray();
           for (const QJsonValue &spawnVal : spawns) {
             if (spawnVal.isObject()) {
               QJsonObject spawn = spawnVal.toObject();
-              if (spawn.contains("playerId")) {
-                int playerId = spawn["playerId"].toInt();
-                if (playerId > 0) {
-                  playerIds.insert(playerId);
+              if (spawn.contains(PLAYER_ID)) {
+                int const player_id = spawn[PLAYER_ID].toInt();
+                if (player_id > 0) {
+                  player_ids.insert(player_id);
                 }
               }
             }
@@ -65,35 +83,35 @@ QVariantList MapCatalog::availableMaps() {
       }
     }
     QVariantMap entry;
-    entry["name"] = name;
-    entry["description"] = desc;
+    entry[NAME] = name;
+    entry[DESCRIPTION] = desc;
     entry["path"] = path;
-    entry["playerCount"] = playerIds.size();
-    QVariantList playerIdList;
-    QList<int> sortedIds = playerIds.values();
+    entry["playerCount"] = player_ids.size();
+    QVariantList player_idList;
+    QList<int> sortedIds = player_ids.values();
     std::sort(sortedIds.begin(), sortedIds.end());
-    for (int id : sortedIds) {
-      playerIdList.append(id);
+    for (int const id : sortedIds) {
+      player_idList.append(id);
     }
-    entry["playerIds"] = playerIdList;
+    entry["player_ids"] = player_idList;
 
     QString thumbnail;
     if (file.open(QIODevice::ReadOnly)) {
-      QByteArray data = file.readAll();
+      QByteArray const data = file.readAll();
       file.close();
       QJsonParseError err;
-      QJsonDocument doc = QJsonDocument::fromJson(data, &err);
+      QJsonDocument const doc = QJsonDocument::fromJson(data, &err);
       if (err.error == QJsonParseError::NoError && doc.isObject()) {
         QJsonObject obj = doc.object();
-        if (obj.contains("thumbnail") && obj["thumbnail"].isString()) {
-          thumbnail = obj["thumbnail"].toString();
+        if (obj.contains(THUMBNAIL) && obj[THUMBNAIL].isString()) {
+          thumbnail = obj[THUMBNAIL].toString();
         }
       }
     }
 
     if (thumbnail.isEmpty()) {
-      QString baseName = QFileInfo(f).baseName();
-      QString thumbCandidate = Utils::Resources::resolveResourcePath(
+      QString const baseName = QFileInfo(f).baseName();
+      QString const thumbCandidate = Utils::Resources::resolveResourcePath(
           QString(":/assets/maps/%1_thumb.png").arg(baseName));
 
       if (QFileInfo::exists(thumbCandidate)) {
@@ -121,7 +139,7 @@ void MapCatalog::loadMapsAsync() {
 
   const QString mapsRoot =
       Utils::Resources::resolveResourcePath(QStringLiteral(":/assets/maps"));
-  QDir mapsDir(mapsRoot);
+  QDir const mapsDir(mapsRoot);
   if (!mapsDir.exists()) {
     m_loading = false;
     emit loadingChanged(false);
@@ -150,14 +168,14 @@ void MapCatalog::loadNextMap() {
     return;
   }
 
-  QString fileName = m_pendingFiles.takeFirst();
+  QString const fileName = m_pendingFiles.takeFirst();
   const QString mapsRoot =
       Utils::Resources::resolveResourcePath(QStringLiteral(":/assets/maps"));
-  QDir mapsDir(mapsRoot);
-  QString path =
+  QDir const mapsDir(mapsRoot);
+  QString const path =
       Utils::Resources::resolveResourcePath(mapsDir.filePath(fileName));
 
-  QVariantMap entry = loadSingleMap(path);
+  QVariantMap const entry = loadSingleMap(path);
   if (!entry.isEmpty()) {
     m_maps.append(entry);
     emit mapLoaded(entry);
@@ -172,36 +190,36 @@ void MapCatalog::loadNextMap() {
   }
 }
 
-QVariantMap MapCatalog::loadSingleMap(const QString &path) {
+auto MapCatalog::loadSingleMap(const QString &path) -> QVariantMap {
   const QString resolvedPath = Utils::Resources::resolveResourcePath(path);
   QFile file(resolvedPath);
   QString name = QFileInfo(resolvedPath).fileName();
   QString desc;
-  QSet<int> playerIds;
+  QSet<int> player_ids;
 
   if (file.open(QIODevice::ReadOnly)) {
-    QByteArray data = file.readAll();
+    QByteArray const data = file.readAll();
     file.close();
     QJsonParseError err;
-    QJsonDocument doc = QJsonDocument::fromJson(data, &err);
+    QJsonDocument const doc = QJsonDocument::fromJson(data, &err);
     if (err.error == QJsonParseError::NoError && doc.isObject()) {
       QJsonObject obj = doc.object();
-      if (obj.contains("name") && obj["name"].isString()) {
-        name = obj["name"].toString();
+      if (obj.contains(NAME) && obj[NAME].isString()) {
+        name = obj[NAME].toString();
       }
-      if (obj.contains("description") && obj["description"].isString()) {
-        desc = obj["description"].toString();
+      if (obj.contains(DESCRIPTION) && obj[DESCRIPTION].isString()) {
+        desc = obj[DESCRIPTION].toString();
       }
 
-      if (obj.contains("spawns") && obj["spawns"].isArray()) {
-        QJsonArray spawns = obj["spawns"].toArray();
+      if (obj.contains(SPAWNS) && obj[SPAWNS].isArray()) {
+        QJsonArray const spawns = obj[SPAWNS].toArray();
         for (const QJsonValue &spawnVal : spawns) {
           if (spawnVal.isObject()) {
             QJsonObject spawn = spawnVal.toObject();
-            if (spawn.contains("playerId")) {
-              int playerId = spawn["playerId"].toInt();
-              if (playerId > 0) {
-                playerIds.insert(playerId);
+            if (spawn.contains(PLAYER_ID)) {
+              int const player_id = spawn[PLAYER_ID].toInt();
+              if (player_id > 0) {
+                player_ids.insert(player_id);
               }
             }
           }
@@ -211,36 +229,35 @@ QVariantMap MapCatalog::loadSingleMap(const QString &path) {
   }
 
   QVariantMap entry;
-  entry["name"] = name;
-  entry["description"] = desc;
+  entry[NAME] = name;
+  entry[DESCRIPTION] = desc;
   entry["path"] = resolvedPath;
-  entry["playerCount"] = playerIds.size();
+  entry["playerCount"] = player_ids.size();
 
-  QVariantList playerIdList;
-  QList<int> sortedIds = playerIds.values();
+  QVariantList player_idList;
+  QList<int> sortedIds = player_ids.values();
   std::sort(sortedIds.begin(), sortedIds.end());
-  for (int id : sortedIds) {
-    playerIdList.append(id);
+  for (int const id : sortedIds) {
+    player_idList.append(id);
   }
-  entry["playerIds"] = playerIdList;
+  entry["player_ids"] = player_idList;
 
   QString thumbnail;
   if (file.open(QIODevice::ReadOnly)) {
-    QByteArray data = file.readAll();
+    QByteArray const data = file.readAll();
     file.close();
     QJsonParseError err;
-    QJsonDocument doc = QJsonDocument::fromJson(data, &err);
+    QJsonDocument const doc = QJsonDocument::fromJson(data, &err);
     if (err.error == QJsonParseError::NoError && doc.isObject()) {
       QJsonObject obj = doc.object();
-      if (obj.contains("thumbnail") && obj["thumbnail"].isString()) {
-        thumbnail = obj["thumbnail"].toString();
+      if (obj.contains(THUMBNAIL) && obj[THUMBNAIL].isString()) {
+        thumbnail = obj[THUMBNAIL].toString();
       }
     }
   }
-
   if (thumbnail.isEmpty()) {
-    QString baseName = QFileInfo(resolvedPath).baseName();
-    QString thumbCandidate = Utils::Resources::resolveResourcePath(
+    QString const baseName = QFileInfo(resolvedPath).baseName();
+    QString const thumbCandidate = Utils::Resources::resolveResourcePath(
         QString(":/assets/maps/%1_thumb.png").arg(baseName));
 
     if (QFileInfo::exists(thumbCandidate)) {
@@ -254,5 +271,4 @@ QVariantMap MapCatalog::loadSingleMap(const QString &path) {
   return entry;
 }
 
-} // namespace Map
-} // namespace Game
+} // namespace Game::Map

+ 6 - 8
game/map/map_catalog.h

@@ -4,20 +4,19 @@
 #include <QVariantList>
 #include <QVariantMap>
 
-namespace Game {
-namespace Map {
+namespace Game::Map {
 
 class MapCatalog : public QObject {
   Q_OBJECT
 public:
   explicit MapCatalog(QObject *parent = nullptr);
 
-  static QVariantList availableMaps();
+  static auto availableMaps() -> QVariantList;
 
   Q_INVOKABLE void loadMapsAsync();
 
-  bool isLoading() const { return m_loading; }
-  const QVariantList &maps() const { return m_maps; }
+  [[nodiscard]] auto isLoading() const -> bool { return m_loading; }
+  [[nodiscard]] auto maps() const -> const QVariantList & { return m_maps; }
 
 signals:
   void mapLoaded(QVariantMap mapData);
@@ -26,12 +25,11 @@ signals:
 
 private:
   void loadNextMap();
-  QVariantMap loadSingleMap(const QString &filePath);
+  static auto loadSingleMap(const QString &filePath) -> QVariantMap;
 
   QStringList m_pendingFiles;
   QVariantList m_maps;
   bool m_loading = false;
 };
 
-} // namespace Map
-} // namespace Game
+} // namespace Game::Map

+ 18 - 18
game/map/map_definition.h

@@ -11,35 +11,35 @@ namespace Game::Map {
 struct GridDefinition {
   int width = 50;
   int height = 50;
-  float tileSize = 1.0f;
+  float tile_size = 1.0F;
 };
 
 struct CameraDefinition {
-  QVector3D center{0.0f, 0.0f, 0.0f};
-  float distance = 15.0f;
-  float tiltDeg = 45.0f;
-  float fovY = 45.0f;
+  QVector3D center{0.0F, 0.0F, 0.0F};
+  float distance = 15.0F;
+  float tiltDeg = 45.0F;
+  float fovY = 45.0F;
 
-  float nearPlane = 1.0f;
-  float farPlane = 200.0f;
+  float near_plane = 1.0F;
+  float far_plane = 200.0F;
 
-  float yawDeg = 225.0f;
+  float yaw_deg = 225.0F;
 };
 
 struct UnitSpawn {
   Game::Units::SpawnType type = Game::Units::SpawnType::Archer;
-  float x = 0.0f;
-  float z = 0.0f;
-  int playerId = 0;
-  int teamId = 0;
+  float x = 0.0F;
+  float z = 0.0F;
+  int player_id = 0;
+  int team_id = 0;
   int maxPopulation = 100;
 };
 
 struct FireCamp {
-  float x = 0.0f;
-  float z = 0.0f;
-  float intensity = 1.0f;
-  float radius = 3.0f;
+  float x = 0.0F;
+  float z = 0.0F;
+  float intensity = 1.0F;
+  float radius = 3.0F;
   bool persistent = true;
 };
 
@@ -48,7 +48,7 @@ enum class CoordSystem { Grid, World };
 struct VictoryConfig {
   QString victoryType = "elimination";
   std::vector<QString> keyStructures = {"barracks"};
-  float surviveTimeDuration = 0.0f;
+  float surviveTimeDuration = 0.0F;
   std::vector<QString> defeatConditions = {"no_key_structures"};
 };
 
@@ -63,7 +63,7 @@ struct MapDefinition {
   std::vector<FireCamp> firecamps;
   BiomeSettings biome;
   CoordSystem coordSystem = CoordSystem::Grid;
-  int maxTroopsPerPlayer = 50;
+  int max_troops_per_player = 50;
   VictoryConfig victory;
 };
 

+ 300 - 235
game/map/map_loader.cpp

@@ -1,62 +1,77 @@
 #include "map_loader.h"
+#include "json_keys.h"
+#include "map/map_definition.h"
+#include "map/terrain.h"
+#include "units/spawn_type.h"
 
 #include <QDebug>
 #include <QFile>
+#include <QIODevice>
 #include <QJsonArray>
 #include <QJsonDocument>
 #include <QJsonObject>
+#include <QJsonParseError>
 #include <QString>
 #include <algorithm>
 #include <cstdint>
+#include <qfiledevice.h>
+#include <qglobal.h>
+#include <qjsondocument.h>
+#include <qjsonobject.h>
+#include <vector>
 
 namespace Game::Map {
 
-static bool readGrid(const QJsonObject &obj, GridDefinition &grid) {
-  if (obj.contains("width")) {
-    grid.width = obj.value("width").toInt(grid.width);
+using namespace JsonKeys;
+
+namespace {
+
+auto readGrid(const QJsonObject &obj, GridDefinition &grid) -> bool {
+  if (obj.contains(WIDTH)) {
+    grid.width = obj.value(WIDTH).toInt(grid.width);
   }
-  if (obj.contains("height")) {
-    grid.height = obj.value("height").toInt(grid.height);
+  if (obj.contains(HEIGHT)) {
+    grid.height = obj.value(HEIGHT).toInt(grid.height);
   }
-  if (obj.contains("tileSize")) {
-    grid.tileSize = float(obj.value("tileSize").toDouble(grid.tileSize));
+  if (obj.contains(TILE_SIZE)) {
+    grid.tile_size = float(obj.value(TILE_SIZE).toDouble(grid.tile_size));
   }
-  return grid.width > 0 && grid.height > 0 && grid.tileSize > 0.0f;
+  return grid.width > 0 && grid.height > 0 && grid.tile_size > 0.0F;
 }
 
-static bool readCamera(const QJsonObject &obj, CameraDefinition &cam) {
-  if (obj.contains("center")) {
-    auto arr = obj.value("center").toArray();
+auto readCamera(const QJsonObject &obj, CameraDefinition &cam) -> bool {
+  if (obj.contains(CENTER)) {
+    auto arr = obj.value(CENTER).toArray();
     if (arr.size() == 3) {
       cam.center = {float(arr[0].toDouble(0.0)), float(arr[1].toDouble(0.0)),
                     float(arr[2].toDouble(0.0))};
     }
   }
-  if (obj.contains("distance")) {
-    cam.distance = float(obj.value("distance").toDouble(cam.distance));
+  if (obj.contains(DISTANCE)) {
+    cam.distance = float(obj.value(DISTANCE).toDouble(cam.distance));
   }
-  if (obj.contains("tiltDeg")) {
-    cam.tiltDeg = float(obj.value("tiltDeg").toDouble(cam.tiltDeg));
+  if (obj.contains(TILT_DEG)) {
+    cam.tiltDeg = float(obj.value(TILT_DEG).toDouble(cam.tiltDeg));
   }
-  if (obj.contains("fovY")) {
-    cam.fovY = float(obj.value("fovY").toDouble(cam.fovY));
+  if (obj.contains(FOV_Y)) {
+    cam.fovY = float(obj.value(FOV_Y).toDouble(cam.fovY));
   }
-  if (obj.contains("near")) {
-    cam.nearPlane = float(obj.value("near").toDouble(cam.nearPlane));
+  if (obj.contains(NEAR)) {
+    cam.near_plane = float(obj.value(NEAR).toDouble(cam.near_plane));
   }
-  if (obj.contains("far")) {
-    cam.farPlane = float(obj.value("far").toDouble(cam.farPlane));
+  if (obj.contains(FAR)) {
+    cam.far_plane = float(obj.value(FAR).toDouble(cam.far_plane));
   }
-  if (obj.contains("yaw") || obj.contains("yawDeg")) {
+  if (obj.contains(YAW) || obj.contains("yaw_deg")) {
 
-    const QString k = obj.contains("yaw") ? "yaw" : "yawDeg";
-    cam.yawDeg = float(obj.value(k).toDouble(cam.yawDeg));
+    const QString yaw_key = obj.contains(YAW) ? YAW : "yaw_deg";
+    cam.yaw_deg = float(obj.value(yaw_key).toDouble(cam.yaw_deg));
   }
   return true;
 }
 
-static QVector3D readVector3(const QJsonValue &value,
-                             const QVector3D &fallback) {
+auto readVector3(const QJsonValue &value,
+                 const QVector3D &fallback) -> QVector3D {
   if (!value.isArray()) {
     return fallback;
   }
@@ -64,51 +79,51 @@ static QVector3D readVector3(const QJsonValue &value,
   if (arr.size() != 3) {
     return fallback;
   }
-  return QVector3D(float(arr[0].toDouble(fallback.x())),
-                   float(arr[1].toDouble(fallback.y())),
-                   float(arr[2].toDouble(fallback.z())));
+  return {float(arr[0].toDouble(fallback.x())),
+          float(arr[1].toDouble(fallback.y())),
+          float(arr[2].toDouble(fallback.z()))};
 }
 
-static void readBiome(const QJsonObject &obj, BiomeSettings &out) {
-  if (obj.contains("seed")) {
+void readBiome(const QJsonObject &obj, BiomeSettings &out) {
+  if (obj.contains(SEED)) {
     out.seed = static_cast<std::uint32_t>(
-        std::max(0.0, obj.value("seed").toDouble(out.seed)));
+        std::max(0.0, obj.value(SEED).toDouble(out.seed)));
   }
-  if (obj.contains("patchDensity")) {
+  if (obj.contains(PATCH_DENSITY)) {
     out.patchDensity =
-        float(obj.value("patchDensity").toDouble(out.patchDensity));
+        float(obj.value(PATCH_DENSITY).toDouble(out.patchDensity));
   }
-  if (obj.contains("patchJitter")) {
-    out.patchJitter = float(obj.value("patchJitter").toDouble(out.patchJitter));
+  if (obj.contains(PATCH_JITTER)) {
+    out.patchJitter = float(obj.value(PATCH_JITTER).toDouble(out.patchJitter));
   }
-  if (obj.contains("bladeHeight")) {
-    auto arr = obj.value("bladeHeight").toArray();
+  if (obj.contains(BLADE_HEIGHT)) {
+    auto arr = obj.value(BLADE_HEIGHT).toArray();
     if (arr.size() == 2) {
       out.bladeHeightMin = float(arr[0].toDouble(out.bladeHeightMin));
       out.bladeHeightMax = float(arr[1].toDouble(out.bladeHeightMax));
     }
   }
-  if (obj.contains("bladeWidth")) {
-    auto arr = obj.value("bladeWidth").toArray();
+  if (obj.contains(BLADE_WIDTH)) {
+    auto arr = obj.value(BLADE_WIDTH).toArray();
     if (arr.size() == 2) {
       out.bladeWidthMin = float(arr[0].toDouble(out.bladeWidthMin));
       out.bladeWidthMax = float(arr[1].toDouble(out.bladeWidthMax));
     }
   }
-  if (obj.contains("backgroundBladeDensity")) {
+  if (obj.contains(BACKGROUND_BLADE_DENSITY)) {
     out.backgroundBladeDensity =
-        float(obj.value("backgroundBladeDensity")
+        float(obj.value(BACKGROUND_BLADE_DENSITY)
                   .toDouble(out.backgroundBladeDensity));
   }
-  if (obj.contains("swayStrength")) {
-    out.swayStrength =
-        float(obj.value("swayStrength").toDouble(out.swayStrength));
+  if (obj.contains(SWAY_STRENGTH)) {
+    out.sway_strength =
+        float(obj.value(SWAY_STRENGTH).toDouble(out.sway_strength));
   }
-  if (obj.contains("swaySpeed")) {
-    out.swaySpeed = float(obj.value("swaySpeed").toDouble(out.swaySpeed));
+  if (obj.contains(SWAY_SPEED)) {
+    out.sway_speed = float(obj.value(SWAY_SPEED).toDouble(out.sway_speed));
   }
-  if (obj.contains("heightNoise")) {
-    auto arr = obj.value("heightNoise").toArray();
+  if (obj.contains(HEIGHT_NOISE)) {
+    auto arr = obj.value(HEIGHT_NOISE).toArray();
     if (arr.size() == 2) {
       out.heightNoiseAmplitude =
           float(arr[0].toDouble(out.heightNoiseAmplitude));
@@ -117,77 +132,77 @@ static void readBiome(const QJsonObject &obj, BiomeSettings &out) {
     }
   }
 
-  if (obj.contains("grassPrimary")) {
-    out.grassPrimary = readVector3(obj.value("grassPrimary"), out.grassPrimary);
+  if (obj.contains(GRASS_PRIMARY)) {
+    out.grassPrimary = readVector3(obj.value(GRASS_PRIMARY), out.grassPrimary);
   }
-  if (obj.contains("grassSecondary")) {
+  if (obj.contains(GRASS_SECONDARY)) {
     out.grassSecondary =
-        readVector3(obj.value("grassSecondary"), out.grassSecondary);
+        readVector3(obj.value(GRASS_SECONDARY), out.grassSecondary);
   }
-  if (obj.contains("grassDry")) {
-    out.grassDry = readVector3(obj.value("grassDry"), out.grassDry);
+  if (obj.contains(GRASS_DRY)) {
+    out.grassDry = readVector3(obj.value(GRASS_DRY), out.grassDry);
   }
-  if (obj.contains("soilColor")) {
-    out.soilColor = readVector3(obj.value("soilColor"), out.soilColor);
+  if (obj.contains(SOIL_COLOR)) {
+    out.soilColor = readVector3(obj.value(SOIL_COLOR), out.soilColor);
   }
-  if (obj.contains("rockLow")) {
-    out.rockLow = readVector3(obj.value("rockLow"), out.rockLow);
+  if (obj.contains(ROCK_LOW)) {
+    out.rockLow = readVector3(obj.value(ROCK_LOW), out.rockLow);
   }
-  if (obj.contains("rockHigh")) {
-    out.rockHigh = readVector3(obj.value("rockHigh"), out.rockHigh);
+  if (obj.contains(ROCK_HIGH)) {
+    out.rockHigh = readVector3(obj.value(ROCK_HIGH), out.rockHigh);
   }
-  if (obj.contains("terrainMacroNoiseScale")) {
+  if (obj.contains(TERRAIN_MACRO_NOISE_SCALE)) {
     out.terrainMacroNoiseScale =
-        float(obj.value("terrainMacroNoiseScale")
+        float(obj.value(TERRAIN_MACRO_NOISE_SCALE)
                   .toDouble(out.terrainMacroNoiseScale));
   }
-  if (obj.contains("terrainDetailNoiseScale")) {
+  if (obj.contains(TERRAIN_DETAIL_NOISE_SCALE)) {
     out.terrainDetailNoiseScale =
-        float(obj.value("terrainDetailNoiseScale")
+        float(obj.value(TERRAIN_DETAIL_NOISE_SCALE)
                   .toDouble(out.terrainDetailNoiseScale));
   }
-  if (obj.contains("terrainSoilHeight")) {
+  if (obj.contains(TERRAIN_SOIL_HEIGHT)) {
     out.terrainSoilHeight =
-        float(obj.value("terrainSoilHeight").toDouble(out.terrainSoilHeight));
+        float(obj.value(TERRAIN_SOIL_HEIGHT).toDouble(out.terrainSoilHeight));
   }
-  if (obj.contains("terrainSoilSharpness")) {
+  if (obj.contains(TERRAIN_SOIL_SHARPNESS)) {
     out.terrainSoilSharpness = float(
-        obj.value("terrainSoilSharpness").toDouble(out.terrainSoilSharpness));
+        obj.value(TERRAIN_SOIL_SHARPNESS).toDouble(out.terrainSoilSharpness));
   }
-  if (obj.contains("terrainRockThreshold")) {
+  if (obj.contains(TERRAIN_ROCK_THRESHOLD)) {
     out.terrainRockThreshold = float(
-        obj.value("terrainRockThreshold").toDouble(out.terrainRockThreshold));
+        obj.value(TERRAIN_ROCK_THRESHOLD).toDouble(out.terrainRockThreshold));
   }
-  if (obj.contains("terrainRockSharpness")) {
+  if (obj.contains(TERRAIN_ROCK_SHARPNESS)) {
     out.terrainRockSharpness = float(
-        obj.value("terrainRockSharpness").toDouble(out.terrainRockSharpness));
+        obj.value(TERRAIN_ROCK_SHARPNESS).toDouble(out.terrainRockSharpness));
   }
-  if (obj.contains("terrainAmbientBoost")) {
+  if (obj.contains(TERRAIN_AMBIENT_BOOST)) {
     out.terrainAmbientBoost = float(
-        obj.value("terrainAmbientBoost").toDouble(out.terrainAmbientBoost));
+        obj.value(TERRAIN_AMBIENT_BOOST).toDouble(out.terrainAmbientBoost));
   }
-  if (obj.contains("terrainRockDetailStrength")) {
+  if (obj.contains(TERRAIN_ROCK_DETAIL_STRENGTH)) {
     out.terrainRockDetailStrength =
-        float(obj.value("terrainRockDetailStrength")
+        float(obj.value(TERRAIN_ROCK_DETAIL_STRENGTH)
                   .toDouble(out.terrainRockDetailStrength));
   }
-  if (obj.contains("backgroundSwayVariance")) {
+  if (obj.contains(BACKGROUND_SWAY_VARIANCE)) {
     out.backgroundSwayVariance =
-        float(obj.value("backgroundSwayVariance")
+        float(obj.value(BACKGROUND_SWAY_VARIANCE)
                   .toDouble(out.backgroundSwayVariance));
   }
-  if (obj.contains("backgroundScatterRadius")) {
+  if (obj.contains(BACKGROUND_SCATTER_RADIUS)) {
     out.backgroundScatterRadius =
-        float(obj.value("backgroundScatterRadius")
+        float(obj.value(BACKGROUND_SCATTER_RADIUS)
                   .toDouble(out.backgroundScatterRadius));
   }
-  if (obj.contains("plantDensity")) {
-    out.plantDensity =
-        float(obj.value("plantDensity").toDouble(out.plantDensity));
+  if (obj.contains(PLANT_DENSITY)) {
+    out.plant_density =
+        float(obj.value(PLANT_DENSITY).toDouble(out.plant_density));
   }
 }
 
-static void readVictoryConfig(const QJsonObject &obj, VictoryConfig &out) {
+void readVictoryConfig(const QJsonObject &obj, VictoryConfig &out) {
 
   if (obj.contains("type")) {
     out.victoryType = obj.value("type").toString("elimination");
@@ -196,8 +211,8 @@ static void readVictoryConfig(const QJsonObject &obj, VictoryConfig &out) {
   if (obj.contains("key_structures") && obj.value("key_structures").isArray()) {
     out.keyStructures.clear();
     auto arr = obj.value("key_structures").toArray();
-    for (const auto &v : arr) {
-      out.keyStructures.push_back(v.toString());
+    for (const auto &val : arr) {
+      out.keyStructures.push_back(val.toString());
     }
   }
 
@@ -209,101 +224,117 @@ static void readVictoryConfig(const QJsonObject &obj, VictoryConfig &out) {
       obj.value("defeat_conditions").isArray()) {
     out.defeatConditions.clear();
     auto arr = obj.value("defeat_conditions").toArray();
-    for (const auto &v : arr) {
-      out.defeatConditions.push_back(v.toString());
+    for (const auto &val : arr) {
+      out.defeatConditions.push_back(val.toString());
     }
   }
 }
 
-static void readSpawns(const QJsonArray &arr, std::vector<UnitSpawn> &out) {
+void readSpawns(const QJsonArray &arr, std::vector<UnitSpawn> &out) {
   out.clear();
   out.reserve(arr.size());
-  for (const auto &v : arr) {
-    auto o = v.toObject();
-    UnitSpawn s;
-    const QString typeStr = o.value("type").toString();
-    if (!Game::Units::tryParseSpawnType(typeStr, s.type)) {
-      qWarning() << "MapLoader: unknown spawn type" << typeStr << "- skipping";
+  for (const auto &spawn_val : arr) {
+    auto spawn_obj = spawn_val.toObject();
+    UnitSpawn spawn;
+    const QString type_str = spawn_obj.value(TYPE).toString();
+    if (!Game::Units::tryParseSpawnType(type_str, spawn.type)) {
+      qWarning() << "MapLoader: unknown spawn type" << type_str << "- skipping";
       continue;
     }
-    s.x = float(o.value("x").toDouble(0.0));
-    s.z = float(o.value("z").toDouble(0.0));
+    spawn.x = float(spawn_obj.value(X).toDouble(0.0));
+    spawn.z = float(spawn_obj.value(Z).toDouble(0.0));
 
-    if (o.contains("playerId") && !o.value("playerId").isNull()) {
-      s.playerId = o.value("playerId").toInt(0);
+    if (spawn_obj.contains(PLAYER_ID) && !spawn_obj.value(PLAYER_ID).isNull()) {
+      spawn.player_id = spawn_obj.value(PLAYER_ID).toInt(0);
     } else {
-      s.playerId = -1;
+      spawn.player_id = -1;
     }
 
-    s.teamId = o.value("teamId").toInt(0);
-    s.maxPopulation = o.value("maxPopulation").toInt(100);
-    out.push_back(s);
+    spawn.team_id = spawn_obj.value(TEAM_ID).toInt(0);
+    constexpr int default_max_population = 100;
+    spawn.maxPopulation =
+        spawn_obj.value(MAX_POPULATION).toInt(default_max_population);
+    out.push_back(spawn);
   }
 }
 
-static void readFireCamps(const QJsonArray &arr, std::vector<FireCamp> &out) {
+void readFireCamps(const QJsonArray &arr, std::vector<FireCamp> &out) {
   out.clear();
   out.reserve(arr.size());
-  for (const auto &v : arr) {
-    auto o = v.toObject();
-    FireCamp fc;
-    fc.x = float(o.value("x").toDouble(0.0));
-    fc.z = float(o.value("z").toDouble(0.0));
-    fc.intensity = float(o.value("intensity").toDouble(1.0));
-    fc.radius = float(o.value("radius").toDouble(3.0));
-    fc.persistent = o.value("persistent").toBool(true);
-    out.push_back(fc);
+  for (const auto &camp_val : arr) {
+    auto camp_obj = camp_val.toObject();
+    FireCamp fire_camp;
+    fire_camp.x = float(camp_obj.value("x").toDouble(0.0));
+    fire_camp.z = float(camp_obj.value("z").toDouble(0.0));
+    fire_camp.intensity = float(camp_obj.value("intensity").toDouble(1.0));
+    constexpr double default_firecamp_radius = 3.0;
+    fire_camp.radius =
+        float(camp_obj.value("radius").toDouble(default_firecamp_radius));
+    fire_camp.persistent = camp_obj.value("persistent").toBool(true);
+    out.push_back(fire_camp);
   }
 }
 
-static void readTerrain(const QJsonArray &arr, std::vector<TerrainFeature> &out,
-                        const GridDefinition &grid, CoordSystem coordSys) {
+void readTerrain(const QJsonArray &arr, std::vector<TerrainFeature> &out,
+                 const GridDefinition &grid, CoordSystem coordSys) {
   out.clear();
   out.reserve(arr.size());
 
-  for (const auto &v : arr) {
-    auto o = v.toObject();
+  constexpr float grid_center_offset = 0.5F;
+  constexpr float min_tile_size = 0.0001F;
+  constexpr double default_terrain_radius = 5.0;
+  constexpr double default_terrain_height = 2.0;
+
+  for (const auto &terrain_val : arr) {
+    auto terrain_obj = terrain_val.toObject();
     TerrainFeature feature;
 
-    const QString typeStr = o.value("type").toString("flat");
-    if (!tryParseTerrainType(typeStr, feature.type)) {
-      qWarning() << "MapLoader: unknown terrain type" << typeStr
+    const QString type_str = terrain_obj.value("type").toString("flat");
+    if (!tryParseTerrainType(type_str, feature.type)) {
+      qWarning() << "MapLoader: unknown terrain type" << type_str
                  << "- defaulting to flat";
       feature.type = TerrainType::Flat;
     }
 
-    float x = float(o.value("x").toDouble(0.0));
-    float z = float(o.value("z").toDouble(0.0));
+    const float coord_x = float(terrain_obj.value("x").toDouble(0.0));
+    const float coord_z = float(terrain_obj.value("z").toDouble(0.0));
 
     if (coordSys == CoordSystem::Grid) {
-      const float tile = std::max(0.0001f, grid.tileSize);
-      feature.centerX = (x - (grid.width * 0.5f - 0.5f)) * tile;
-      feature.centerZ = (z - (grid.height * 0.5f - 0.5f)) * tile;
+      const float tile = std::max(min_tile_size, grid.tile_size);
+      feature.center_x =
+          (coord_x - (grid.width * grid_center_offset - grid_center_offset)) *
+          tile;
+      feature.center_z =
+          (coord_z - (grid.height * grid_center_offset - grid_center_offset)) *
+          tile;
     } else {
-      feature.centerX = x;
-      feature.centerZ = z;
+      feature.center_x = coord_x;
+      feature.center_z = coord_z;
     }
 
-    feature.radius = float(o.value("radius").toDouble(5.0));
-    feature.width = float(o.value("width").toDouble(0.0));
-    feature.depth = float(o.value("depth").toDouble(0.0));
+    feature.radius =
+        float(terrain_obj.value("radius").toDouble(default_terrain_radius));
+    feature.width = float(terrain_obj.value("width").toDouble(0.0));
+    feature.depth = float(terrain_obj.value("depth").toDouble(0.0));
 
-    if (feature.width == 0.0f && feature.depth == 0.0f) {
+    if (feature.width == 0.0F && feature.depth == 0.0F) {
       feature.width = feature.radius;
       feature.depth = feature.radius;
     }
 
-    feature.height = float(o.value("height").toDouble(2.0));
-    feature.rotationDeg = float(o.value("rotation").toDouble(0.0));
+    feature.height =
+        float(terrain_obj.value("height").toDouble(default_terrain_height));
+    feature.rotationDeg = float(terrain_obj.value("rotation").toDouble(0.0));
 
-    if (o.contains("entrances") && o.value("entrances").isArray()) {
-      auto entranceArr = o.value("entrances").toArray();
-      for (const auto &e : entranceArr) {
-        auto eObj = e.toObject();
-        float ex = float(eObj.value("x").toDouble(0.0));
-        float ez = float(eObj.value("z").toDouble(0.0));
+    if (terrain_obj.contains("entrances") &&
+        terrain_obj.value("entrances").isArray()) {
+      auto entrance_arr = terrain_obj.value("entrances").toArray();
+      for (const auto &entrance_val : entrance_arr) {
+        auto entrance_obj = entrance_val.toObject();
+        const float entrance_x = float(entrance_obj.value("x").toDouble(0.0));
+        const float entrance_z = float(entrance_obj.value("z").toDouble(0.0));
 
-        feature.entrances.push_back(QVector3D(ex, 0.0f, ez));
+        feature.entrances.emplace_back(entrance_x, 0.0F, entrance_z);
       }
     }
 
@@ -311,199 +342,233 @@ static void readTerrain(const QJsonArray &arr, std::vector<TerrainFeature> &out,
   }
 }
 
-static void readRivers(const QJsonArray &arr, std::vector<RiverSegment> &out,
-                       const GridDefinition &grid, CoordSystem coordSys) {
+void readRivers(const QJsonArray &arr, std::vector<RiverSegment> &out,
+                const GridDefinition &grid, CoordSystem coordSys) {
   out.clear();
   out.reserve(arr.size());
 
-  for (const auto &v : arr) {
-    auto o = v.toObject();
+  constexpr float grid_center_offset = 0.5F;
+  constexpr float min_tile_size = 0.0001F;
+  constexpr double default_river_width = 2.0;
+
+  for (const auto &river_val : arr) {
+    auto river_obj = river_val.toObject();
     RiverSegment segment;
 
-    if (o.contains("start") && o.value("start").isArray()) {
-      auto startArr = o.value("start").toArray();
-      if (startArr.size() >= 2) {
-        float x = float(startArr[0].toDouble(0.0));
-        float z = float(startArr[1].toDouble(0.0));
+    if (river_obj.contains("start") && river_obj.value("start").isArray()) {
+      auto start_arr = river_obj.value("start").toArray();
+      if (start_arr.size() >= 2) {
+        const float start_x = float(start_arr[0].toDouble(0.0));
+        const float start_z = float(start_arr[1].toDouble(0.0));
 
         if (coordSys == CoordSystem::Grid) {
-          const float tile = std::max(0.0001f, grid.tileSize);
-          segment.start.setX((x - (grid.width * 0.5f - 0.5f)) * tile);
-          segment.start.setY(0.0f);
-          segment.start.setZ((z - (grid.height * 0.5f - 0.5f)) * tile);
+          const float tile = std::max(min_tile_size, grid.tile_size);
+          segment.start.setX((start_x - (grid.width * grid_center_offset -
+                                         grid_center_offset)) *
+                             tile);
+          segment.start.setY(0.0F);
+          segment.start.setZ((start_z - (grid.height * grid_center_offset -
+                                         grid_center_offset)) *
+                             tile);
         } else {
-          segment.start = QVector3D(x, 0.0f, z);
+          segment.start = QVector3D(start_x, 0.0F, start_z);
         }
       }
     }
 
-    if (o.contains("end") && o.value("end").isArray()) {
-      auto endArr = o.value("end").toArray();
-      if (endArr.size() >= 2) {
-        float x = float(endArr[0].toDouble(0.0));
-        float z = float(endArr[1].toDouble(0.0));
+    if (river_obj.contains("end") && river_obj.value("end").isArray()) {
+      auto end_arr = river_obj.value("end").toArray();
+      if (end_arr.size() >= 2) {
+        const float end_x = float(end_arr[0].toDouble(0.0));
+        const float end_z = float(end_arr[1].toDouble(0.0));
 
         if (coordSys == CoordSystem::Grid) {
-          const float tile = std::max(0.0001f, grid.tileSize);
-          segment.end.setX((x - (grid.width * 0.5f - 0.5f)) * tile);
-          segment.end.setY(0.0f);
-          segment.end.setZ((z - (grid.height * 0.5f - 0.5f)) * tile);
+          const float tile = std::max(min_tile_size, grid.tile_size);
+          segment.end.setX(
+              (end_x - (grid.width * grid_center_offset - grid_center_offset)) *
+              tile);
+          segment.end.setY(0.0F);
+          segment.end.setZ((end_z - (grid.height * grid_center_offset -
+                                     grid_center_offset)) *
+                           tile);
         } else {
-          segment.end = QVector3D(x, 0.0f, z);
+          segment.end = QVector3D(end_x, 0.0F, end_z);
         }
       }
     }
 
-    if (o.contains("width")) {
-      segment.width = float(o.value("width").toDouble(2.0));
+    if (river_obj.contains("width")) {
+      segment.width =
+          float(river_obj.value("width").toDouble(default_river_width));
     }
 
     out.push_back(segment);
   }
 }
 
-static void readBridges(const QJsonArray &arr, std::vector<Bridge> &out,
-                        const GridDefinition &grid, CoordSystem coordSys) {
+void readBridges(const QJsonArray &arr, std::vector<Bridge> &out,
+                 const GridDefinition &grid, CoordSystem coordSys) {
   out.clear();
   out.reserve(arr.size());
 
-  for (const auto &v : arr) {
-    auto o = v.toObject();
+  constexpr float bridge_y_offset = 0.2F;
+  constexpr float grid_center_offset = 0.5F;
+  constexpr float min_tile_size = 0.0001F;
+  constexpr double default_bridge_width = 3.0;
+  constexpr double default_bridge_height = 0.5;
+
+  for (const auto &bridge_val : arr) {
+    auto bridge_obj = bridge_val.toObject();
     Bridge bridge;
 
-    if (o.contains("start") && o.value("start").isArray()) {
-      auto startArr = o.value("start").toArray();
-      if (startArr.size() >= 2) {
-        float x = float(startArr[0].toDouble(0.0));
-        float z = float(startArr[1].toDouble(0.0));
+    if (bridge_obj.contains("start") && bridge_obj.value("start").isArray()) {
+      auto start_arr = bridge_obj.value("start").toArray();
+      if (start_arr.size() >= 2) {
+        const float start_x = float(start_arr[0].toDouble(0.0));
+        const float start_z = float(start_arr[1].toDouble(0.0));
 
         if (coordSys == CoordSystem::Grid) {
-          const float tile = std::max(0.0001f, grid.tileSize);
-          bridge.start.setX((x - (grid.width * 0.5f - 0.5f)) * tile);
-          bridge.start.setY(0.2f);
-          bridge.start.setZ((z - (grid.height * 0.5f - 0.5f)) * tile);
+          const float tile = std::max(min_tile_size, grid.tile_size);
+          bridge.start.setX((start_x - (grid.width * grid_center_offset -
+                                        grid_center_offset)) *
+                            tile);
+          bridge.start.setY(bridge_y_offset);
+          bridge.start.setZ((start_z - (grid.height * grid_center_offset -
+                                        grid_center_offset)) *
+                            tile);
         } else {
-          bridge.start = QVector3D(x, 0.2f, z);
+          bridge.start = QVector3D(start_x, bridge_y_offset, start_z);
         }
       }
     }
 
-    if (o.contains("end") && o.value("end").isArray()) {
-      auto endArr = o.value("end").toArray();
-      if (endArr.size() >= 2) {
-        float x = float(endArr[0].toDouble(0.0));
-        float z = float(endArr[1].toDouble(0.0));
+    if (bridge_obj.contains("end") && bridge_obj.value("end").isArray()) {
+      auto end_arr = bridge_obj.value("end").toArray();
+      if (end_arr.size() >= 2) {
+        const float end_x = float(end_arr[0].toDouble(0.0));
+        const float end_z = float(end_arr[1].toDouble(0.0));
 
         if (coordSys == CoordSystem::Grid) {
-          const float tile = std::max(0.0001f, grid.tileSize);
-          bridge.end.setX((x - (grid.width * 0.5f - 0.5f)) * tile);
-          bridge.end.setY(0.2f);
-          bridge.end.setZ((z - (grid.height * 0.5f - 0.5f)) * tile);
+          const float tile = std::max(min_tile_size, grid.tile_size);
+          bridge.end.setX(
+              (end_x - (grid.width * grid_center_offset - grid_center_offset)) *
+              tile);
+          bridge.end.setY(bridge_y_offset);
+          bridge.end.setZ((end_z - (grid.height * grid_center_offset -
+                                    grid_center_offset)) *
+                          tile);
         } else {
-          bridge.end = QVector3D(x, 0.2f, z);
+          bridge.end = QVector3D(end_x, bridge_y_offset, end_z);
         }
       }
     }
 
-    if (o.contains("width")) {
-      bridge.width = float(o.value("width").toDouble(3.0));
+    if (bridge_obj.contains("width")) {
+      bridge.width =
+          float(bridge_obj.value("width").toDouble(default_bridge_width));
     }
 
-    if (o.contains("height")) {
-      bridge.height = float(o.value("height").toDouble(0.5));
+    if (bridge_obj.contains("height")) {
+      bridge.height =
+          float(bridge_obj.value("height").toDouble(default_bridge_height));
     }
 
     out.push_back(bridge);
   }
 }
 
-bool MapLoader::loadFromJsonFile(const QString &path, MapDefinition &outMap,
-                                 QString *outError) {
-  QFile f(path);
-  if (!f.open(QIODevice::ReadOnly)) {
-    if (outError) {
-      *outError = QString("Failed to open map file: %1").arg(path);
+} // namespace
+
+auto MapLoader::loadFromJsonFile(const QString &path, MapDefinition &outMap,
+                                 QString *out_error) -> bool {
+  QFile map_file(path);
+  if (!map_file.open(QIODevice::ReadOnly)) {
+    if (out_error != nullptr) {
+      *out_error = QString("Failed to open map file: %1").arg(path);
     }
     return false;
   }
-  auto data = f.readAll();
-  f.close();
+  auto data = map_file.readAll();
+  map_file.close();
 
   QJsonParseError perr;
   auto doc = QJsonDocument::fromJson(data, &perr);
   if (perr.error != QJsonParseError::NoError) {
-    if (outError) {
-      *outError = QString("JSON parse error at %1: %2")
-                      .arg(perr.offset)
-                      .arg(perr.errorString());
+    if (out_error != nullptr) {
+      *out_error = QString("JSON parse error at %1: %2")
+                       .arg(perr.offset)
+                       .arg(perr.errorString());
     }
     return false;
   }
   if (!doc.isObject()) {
-    if (outError) {
-      *outError = "Map JSON root must be an object";
+    if (out_error != nullptr) {
+      *out_error = "Map JSON root must be an object";
     }
     return false;
   }
   auto root = doc.object();
 
-  outMap.name = root.value("name").toString("Unnamed Map");
+  outMap.name = root.value(NAME).toString("Unnamed Map");
 
-  if (root.contains("coordSystem")) {
-    const QString cs = root.value("coordSystem").toString().trimmed().toLower();
-    if (cs == "world") {
+  if (root.contains(COORD_SYSTEM)) {
+    const QString coord_system =
+        root.value(COORD_SYSTEM).toString().trimmed().toLower();
+    if (coord_system == "world") {
       outMap.coordSystem = CoordSystem::World;
     } else {
       outMap.coordSystem = CoordSystem::Grid;
     }
   }
 
-  if (root.contains("maxTroopsPerPlayer")) {
-    outMap.maxTroopsPerPlayer = root.value("maxTroopsPerPlayer").toInt(50);
+  constexpr int default_max_troops = 50;
+  if (root.contains(MAX_TROOPS_PER_PLAYER)) {
+    outMap.max_troops_per_player =
+        root.value(MAX_TROOPS_PER_PLAYER).toInt(default_max_troops);
   }
 
-  if (root.contains("grid") && root.value("grid").isObject()) {
-    if (!readGrid(root.value("grid").toObject(), outMap.grid)) {
-      if (outError) {
-        *outError = "Invalid grid definition";
+  if (root.contains(GRID) && root.value(GRID).isObject()) {
+    if (!readGrid(root.value(GRID).toObject(), outMap.grid)) {
+      if (out_error != nullptr) {
+        *out_error = "Invalid grid definition";
       }
       return false;
     }
   }
 
-  if (root.contains("camera") && root.value("camera").isObject()) {
-    readCamera(root.value("camera").toObject(), outMap.camera);
+  if (root.contains(CAMERA) && root.value(CAMERA).isObject()) {
+    readCamera(root.value(CAMERA).toObject(), outMap.camera);
   }
 
-  if (root.contains("spawns") && root.value("spawns").isArray()) {
-    readSpawns(root.value("spawns").toArray(), outMap.spawns);
+  if (root.contains(SPAWNS) && root.value(SPAWNS).isArray()) {
+    readSpawns(root.value(SPAWNS).toArray(), outMap.spawns);
   }
 
-  if (root.contains("firecamps") && root.value("firecamps").isArray()) {
-    readFireCamps(root.value("firecamps").toArray(), outMap.firecamps);
+  if (root.contains(FIRECAMPS) && root.value(FIRECAMPS).isArray()) {
+    readFireCamps(root.value(FIRECAMPS).toArray(), outMap.firecamps);
   }
 
-  if (root.contains("terrain") && root.value("terrain").isArray()) {
-    readTerrain(root.value("terrain").toArray(), outMap.terrain, outMap.grid,
+  if (root.contains(TERRAIN) && root.value(TERRAIN).isArray()) {
+    readTerrain(root.value(TERRAIN).toArray(), outMap.terrain, outMap.grid,
                 outMap.coordSystem);
   }
 
-  if (root.contains("rivers") && root.value("rivers").isArray()) {
-    readRivers(root.value("rivers").toArray(), outMap.rivers, outMap.grid,
+  if (root.contains(RIVERS) && root.value(RIVERS).isArray()) {
+    readRivers(root.value(RIVERS).toArray(), outMap.rivers, outMap.grid,
                outMap.coordSystem);
   }
 
-  if (root.contains("bridges") && root.value("bridges").isArray()) {
-    readBridges(root.value("bridges").toArray(), outMap.bridges, outMap.grid,
+  if (root.contains(BRIDGES) && root.value(BRIDGES).isArray()) {
+    readBridges(root.value(BRIDGES).toArray(), outMap.bridges, outMap.grid,
                 outMap.coordSystem);
   }
 
-  if (root.contains("biome") && root.value("biome").isObject()) {
-    readBiome(root.value("biome").toObject(), outMap.biome);
+  if (root.contains(BIOME) && root.value(BIOME).isObject()) {
+    readBiome(root.value(BIOME).toObject(), outMap.biome);
   }
 
-  if (root.contains("victory") && root.value("victory").isObject()) {
-    readVictoryConfig(root.value("victory").toObject(), outMap.victory);
+  if (root.contains(VICTORY) && root.value(VICTORY).isObject()) {
+    readVictoryConfig(root.value(VICTORY).toObject(), outMap.victory);
   }
 
   return true;

+ 2 - 2
game/map/map_loader.h

@@ -7,8 +7,8 @@ namespace Game::Map {
 
 class MapLoader {
 public:
-  static bool loadFromJsonFile(const QString &path, MapDefinition &outMap,
-                               QString *outError = nullptr);
+  static auto loadFromJsonFile(const QString &path, MapDefinition &outMap,
+                               QString *out_error = nullptr) -> bool;
 };
 
 } // namespace Game::Map

+ 75 - 66
game/map/map_transformer.cpp

@@ -6,130 +6,139 @@
 #include "../systems/owner_registry.h"
 #include "../units/factory.h"
 #include "../units/spawn_type.h"
-#include "../visuals/team_colors.h"
+#include "core/entity.h"
+#include "map/map_definition.h"
 #include "terrain_service.h"
+#include "units/unit.h"
+#include "visuals/visual_catalog.h"
 #include <QDebug>
 #include <QVector3D>
+#include <algorithm>
+#include <cstdlib>
+#include <memory>
+#include <qglobal.h>
 #include <set>
+#include <string>
 #include <unordered_map>
+#include <utility>
 
 namespace Game::Map {
 
 namespace {
 std::shared_ptr<Game::Units::UnitFactoryRegistry> s_registry;
-std::unordered_map<int, int> s_playerTeamOverrides;
+std::unordered_map<int, int> s_player_team_overrides;
 } // namespace
 
 void MapTransformer::setFactoryRegistry(
     std::shared_ptr<Game::Units::UnitFactoryRegistry> reg) {
   s_registry = std::move(reg);
 }
-std::shared_ptr<Game::Units::UnitFactoryRegistry>
-MapTransformer::getFactoryRegistry() {
+auto MapTransformer::getFactoryRegistry()
+    -> std::shared_ptr<Game::Units::UnitFactoryRegistry> {
   return s_registry;
 }
 
-void MapTransformer::setLocalOwnerId(int ownerId) {
+void MapTransformer::setLocalOwnerId(int owner_id) {
   auto &owners = Game::Systems::OwnerRegistry::instance();
-  owners.setLocalPlayerId(ownerId);
+  owners.setLocalPlayerId(owner_id);
 }
 
-int MapTransformer::localOwnerId() {
+auto MapTransformer::localOwnerId() -> int {
   auto &owners = Game::Systems::OwnerRegistry::instance();
   return owners.getLocalPlayerId();
 }
 
 void MapTransformer::setPlayerTeamOverrides(
     const std::unordered_map<int, int> &overrides) {
-  s_playerTeamOverrides = overrides;
+  s_player_team_overrides = overrides;
 }
 
 void MapTransformer::clearPlayerTeamOverrides() {
-  s_playerTeamOverrides.clear();
+  s_player_team_overrides.clear();
 }
 
-MapRuntime
-MapTransformer::applyToWorld(const MapDefinition &def,
-                             Engine::Core::World &world,
-                             const Game::Visuals::VisualCatalog *visuals) {
+auto MapTransformer::applyToWorld(
+    const MapDefinition &def, Engine::Core::World &world,
+    const Game::Visuals::VisualCatalog *visuals) -> MapRuntime {
   MapRuntime rt;
-  rt.unitIds.reserve(def.spawns.size());
+  rt.unit_ids.reserve(def.spawns.size());
 
-  auto &ownerRegistry = Game::Systems::OwnerRegistry::instance();
-  std::set<int> uniquePlayerIds;
-  std::unordered_map<int, int> playerIdToTeam;
+  auto &owner_registry = Game::Systems::OwnerRegistry::instance();
+  std::set<int> unique_player_ids;
+  std::unordered_map<int, int> player_idToTeam;
 
   for (const auto &spawn : def.spawns) {
-    if (spawn.playerId == Game::Core::NEUTRAL_OWNER_ID) {
+    if (spawn.player_id == Game::Core::NEUTRAL_OWNER_ID) {
       continue;
     }
-    uniquePlayerIds.insert(spawn.playerId);
+    unique_player_ids.insert(spawn.player_id);
 
-    if (spawn.teamId > 0) {
-      playerIdToTeam[spawn.playerId] = spawn.teamId;
+    if (spawn.team_id > 0) {
+      player_idToTeam[spawn.player_id] = spawn.team_id;
     }
   }
 
-  for (int playerId : uniquePlayerIds) {
+  for (int const player_id : unique_player_ids) {
 
-    if (ownerRegistry.getOwnerType(playerId) ==
+    if (owner_registry.getOwnerType(player_id) ==
         Game::Systems::OwnerType::Neutral) {
 
-      bool isLocalPlayer = (playerId == ownerRegistry.getLocalPlayerId());
-      Game::Systems::OwnerType ownerType =
-          isLocalPlayer ? Game::Systems::OwnerType::Player
-                        : Game::Systems::OwnerType::AI;
+      bool const is_local_player =
+          (player_id == owner_registry.getLocalPlayerId());
+      Game::Systems::OwnerType const owner_type =
+          is_local_player ? Game::Systems::OwnerType::Player
+                          : Game::Systems::OwnerType::AI;
 
-      std::string ownerName = isLocalPlayer
-                                  ? "Player " + std::to_string(playerId)
-                                  : "AI Player " + std::to_string(playerId);
+      std::string const owner_name =
+          is_local_player ? "Player " + std::to_string(player_id)
+                          : "AI Player " + std::to_string(player_id);
 
-      ownerRegistry.registerOwnerWithId(playerId, ownerType, ownerName);
+      owner_registry.registerOwnerWithId(player_id, owner_type, owner_name);
     }
 
-    int finalTeamId = 0;
-    auto overrideIt = s_playerTeamOverrides.find(playerId);
-    if (overrideIt != s_playerTeamOverrides.end()) {
+    int final_team_id = 0;
+    auto override_it = s_player_team_overrides.find(player_id);
+    if (override_it != s_player_team_overrides.end()) {
 
-      finalTeamId = overrideIt->second;
+      final_team_id = override_it->second;
     } else {
 
-      auto teamIt = playerIdToTeam.find(playerId);
-      if (teamIt != playerIdToTeam.end()) {
-        finalTeamId = teamIt->second;
+      auto team_it = player_idToTeam.find(player_id);
+      if (team_it != player_idToTeam.end()) {
+        final_team_id = team_it->second;
       } else {
       }
     }
-    ownerRegistry.setOwnerTeam(playerId, finalTeamId);
+    owner_registry.setOwnerTeam(player_id, final_team_id);
   }
 
   for (const auto &s : def.spawns) {
 
-    float worldX = s.x;
-    float worldZ = s.z;
+    float world_x = s.x;
+    float world_z = s.z;
     if (def.coordSystem == CoordSystem::Grid) {
-      const float tile = std::max(0.0001f, def.grid.tileSize);
-      worldX = (s.x - (def.grid.width * 0.5f - 0.5f)) * tile;
-      worldZ = (s.z - (def.grid.height * 0.5f - 0.5f)) * tile;
+      const float tile = std::max(0.0001F, def.grid.tile_size);
+      world_x = (s.x - (def.grid.width * 0.5F - 0.5F)) * tile;
+      world_z = (s.z - (def.grid.height * 0.5F - 0.5F)) * tile;
     }
 
     auto &terrain = Game::Map::TerrainService::instance();
-    if (terrain.isInitialized() && terrain.isForbiddenWorld(worldX, worldZ)) {
-      const float tile = std::max(0.0001f, def.grid.tileSize);
+    if (terrain.isInitialized() && terrain.isForbiddenWorld(world_x, world_z)) {
+      const float tile = std::max(0.0001F, def.grid.tile_size);
       bool found = false;
-      const int maxRadius = 12;
-      for (int r = 1; r <= maxRadius && !found; ++r) {
+      const int max_radius = 12;
+      for (int r = 1; r <= max_radius && !found; ++r) {
         for (int ox = -r; ox <= r && !found; ++ox) {
           for (int oz = -r; oz <= r && !found; ++oz) {
 
             if (std::abs(ox) != r && std::abs(oz) != r) {
               continue;
             }
-            float candX = worldX + float(ox) * tile;
-            float candZ = worldZ + float(oz) * tile;
-            if (!terrain.isForbiddenWorld(candX, candZ)) {
-              worldX = candX;
-              worldZ = candZ;
+            float const cand_x = world_x + float(ox) * tile;
+            float const cand_z = world_z + float(oz) * tile;
+            if (!terrain.isForbiddenWorld(cand_x, cand_z)) {
+              world_x = cand_x;
+              world_z = cand_z;
               found = true;
             }
           }
@@ -145,19 +154,19 @@ MapTransformer::applyToWorld(const MapDefinition &def,
     Engine::Core::Entity *e = nullptr;
     if (s_registry) {
       Game::Units::SpawnParams sp;
-      sp.position = QVector3D(worldX, 0.0f, worldZ);
-      sp.playerId = s.playerId;
-      sp.spawnType = s.type;
-      sp.aiControlled = !ownerRegistry.isPlayer(s.playerId);
+      sp.position = QVector3D(world_x, 0.0F, world_z);
+      sp.player_id = s.player_id;
+      sp.spawn_type = s.type;
+      sp.aiControlled = !owner_registry.isPlayer(s.player_id);
       sp.maxPopulation = s.maxPopulation;
       auto obj = s_registry->create(s.type, world, sp);
       if (obj) {
         e = world.getEntity(obj->id());
-        rt.unitIds.push_back(obj->id());
+        rt.unit_ids.push_back(obj->id());
       } else {
         qWarning() << "MapTransformer: no factory for spawn type"
-                   << Game::Units::spawnTypeToQString(s.type)
-                   << "- skipping spawn at" << worldX << worldZ;
+                   << Game::Units::spawn_typeToQString(s.type)
+                   << "- skipping spawn at" << world_x << world_z;
         continue;
       }
     } else {
@@ -165,24 +174,24 @@ MapTransformer::applyToWorld(const MapDefinition &def,
       continue;
     }
 
-    if (!e) {
+    if (e == nullptr) {
       continue;
     }
 
     if (auto *r = e->getComponent<Engine::Core::RenderableComponent>()) {
-      if (visuals) {
+      if (visuals != nullptr) {
         Game::Visuals::VisualDef defv;
-        if (visuals->lookup(Game::Units::spawnTypeToString(s.type), defv)) {
+        if (visuals->lookup(Game::Units::spawn_typeToString(s.type), defv)) {
           Game::Visuals::applyToRenderable(defv, *r);
         }
       }
-      if (r->color[0] == 0.0f && r->color[1] == 0.0f && r->color[2] == 0.0f) {
-        r->color[0] = r->color[1] = r->color[2] = 1.0f;
+      if (r->color[0] == 0.0F && r->color[1] == 0.0F && r->color[2] == 0.0F) {
+        r->color[0] = r->color[1] = r->color[2] = 1.0F;
       }
     }
 
     if (auto *t = e->getComponent<Engine::Core::TransformComponent>()) {
-      qInfo() << "Spawned" << Game::Units::spawnTypeToQString(s.type)
+      qInfo() << "Spawned" << Game::Units::spawn_typeToQString(s.type)
               << "id=" << e->getId() << "at"
               << QVector3D(t->position.x, t->position.y, t->position.z)
               << "(coordSystem="

+ 12 - 14
game/map/map_transformer.h

@@ -4,36 +4,34 @@
 #include "map_definition.h"
 #include <memory>
 
-namespace Engine {
-namespace Core {
+namespace Engine::Core {
 class World;
 using EntityID = unsigned int;
-} // namespace Core
-} // namespace Engine
-namespace Game {
-namespace Units {
+} // namespace Engine::Core
+
+namespace Game::Units {
 class UnitFactoryRegistry;
 }
-} // namespace Game
 
 namespace Game::Map {
 
 struct MapRuntime {
-  std::vector<Engine::Core::EntityID> unitIds;
+  std::vector<Engine::Core::EntityID> unit_ids;
 };
 
 class MapTransformer {
 public:
-  static MapRuntime
-  applyToWorld(const MapDefinition &def, Engine::Core::World &world,
-               const Game::Visuals::VisualCatalog *visuals = nullptr);
+  static auto applyToWorld(
+      const MapDefinition &def, Engine::Core::World &world,
+      const Game::Visuals::VisualCatalog *visuals = nullptr) -> MapRuntime;
 
   static void
   setFactoryRegistry(std::shared_ptr<Game::Units::UnitFactoryRegistry> reg);
-  static std::shared_ptr<Game::Units::UnitFactoryRegistry> getFactoryRegistry();
+  static auto
+  getFactoryRegistry() -> std::shared_ptr<Game::Units::UnitFactoryRegistry>;
 
-  static void setLocalOwnerId(int ownerId);
-  static int localOwnerId();
+  static void setLocalOwnerId(int owner_id);
+  static auto localOwnerId() -> int;
 
   static void
   setPlayerTeamOverrides(const std::unordered_map<int, int> &overrides);

+ 222 - 186
game/map/skirmish_loader.cpp

@@ -1,6 +1,7 @@
 #include "skirmish_loader.h"
 #include "game/core/component.h"
 #include "game/core/world.h"
+#include "game/map/json_keys.h"
 #include "game/map/level_loader.h"
 #include "game/map/map_transformer.h"
 #include "game/map/terrain_service.h"
@@ -24,18 +25,34 @@
 #include "render/ground/stone_renderer.h"
 #include "render/ground/terrain_renderer.h"
 #include "render/scene_renderer.h"
+#include "units/spawn_type.h"
+#include "units/troop_type.h"
 #include <QDebug>
 #include <QFile>
 #include <QJsonArray>
 #include <QJsonDocument>
 #include <QJsonObject>
+#include <QJsonParseError>
 #include <QSet>
 #include <algorithm>
+#include <qdir.h>
+#include <qfiledevice.h>
+#include <qglobal.h>
+#include <qjsonarray.h>
+#include <qjsondocument.h>
+#include <qjsonobject.h>
+#include <qlist.h>
+#include <qset.h>
+#include <qstringview.h>
+#include <qvariant.h>
+#include <qvectornd.h>
 #include <set>
 #include <unordered_map>
+#include <vector>
 
-namespace Game {
-namespace Map {
+namespace Game::Map {
+
+using namespace JsonKeys;
 
 SkirmishLoader::SkirmishLoader(Engine::Core::World &world,
                                Render::GL::Renderer &renderer,
@@ -43,9 +60,9 @@ SkirmishLoader::SkirmishLoader(Engine::Core::World &world,
     : m_world(world), m_renderer(renderer), m_camera(camera) {}
 
 void SkirmishLoader::resetGameState() {
-  if (auto *selectionSystem =
+  if (auto *selection_system =
           m_world.getSystem<Game::Systems::SelectionSystem>()) {
-    selectionSystem->clearSelection();
+    selection_system->clearSelection();
   }
 
   m_renderer.pause();
@@ -57,52 +74,52 @@ void SkirmishLoader::resetGameState() {
 
   Game::Systems::BuildingCollisionRegistry::instance().clear();
 
-  auto &ownerRegistry = Game::Systems::OwnerRegistry::instance();
-  ownerRegistry.clear();
+  auto &owner_registry = Game::Systems::OwnerRegistry::instance();
+  owner_registry.clear();
 
-  auto &visibilityService = Game::Map::VisibilityService::instance();
-  visibilityService.reset();
+  auto &visibility_service = Game::Map::VisibilityService::instance();
+  visibility_service.reset();
 
-  auto &terrainService = Game::Map::TerrainService::instance();
-  terrainService.clear();
+  auto &terrain_service = Game::Map::TerrainService::instance();
+  terrain_service.clear();
 
-  auto &statsRegistry = Game::Systems::GlobalStatsRegistry::instance();
-  statsRegistry.clear();
+  auto &stats_registry = Game::Systems::GlobalStatsRegistry::instance();
+  stats_registry.clear();
 
-  auto &troopRegistry = Game::Systems::TroopCountRegistry::instance();
-  troopRegistry.clear();
+  auto &troop_registry = Game::Systems::TroopCountRegistry::instance();
+  troop_registry.clear();
 
-  if (m_fog) {
-    m_fog->updateMask(0, 0, 1.0f, {});
+  if (m_fog != nullptr) {
+    m_fog->updateMask(0, 0, 1.0F, {});
   }
 }
 
-SkirmishLoadResult SkirmishLoader::start(const QString &mapPath,
-                                         const QVariantList &playerConfigs,
-                                         int selectedPlayerId,
-                                         int &outSelectedPlayerId) {
+auto SkirmishLoader::start(const QString &map_path,
+                           const QVariantList &playerConfigs,
+                           int selectedPlayerId,
+                           int &outSelectedPlayerId) -> SkirmishLoadResult {
   SkirmishLoadResult result;
 
   resetGameState();
 
-  QSet<int> mapPlayerIds;
-  QFile mapFile(mapPath);
-  if (mapFile.open(QIODevice::ReadOnly)) {
-    QByteArray data = mapFile.readAll();
-    mapFile.close();
+  QSet<int> map_player_ids;
+  QFile map_file(map_path);
+  if (map_file.open(QIODevice::ReadOnly)) {
+    const QByteArray data = map_file.readAll();
+    map_file.close();
     QJsonParseError err;
-    QJsonDocument doc = QJsonDocument::fromJson(data, &err);
+    const QJsonDocument doc = QJsonDocument::fromJson(data, &err);
     if (err.error == QJsonParseError::NoError && doc.isObject()) {
       QJsonObject obj = doc.object();
-      if (obj.contains("spawns") && obj["spawns"].isArray()) {
-        QJsonArray spawns = obj["spawns"].toArray();
-        for (const QJsonValue &spawnVal : spawns) {
-          if (spawnVal.isObject()) {
-            QJsonObject spawn = spawnVal.toObject();
-            if (spawn.contains("playerId")) {
-              int playerId = spawn["playerId"].toInt();
-              if (playerId > 0) {
-                mapPlayerIds.insert(playerId);
+      if (obj.contains(SPAWNS) && obj[SPAWNS].isArray()) {
+        const QJsonArray spawns = obj[SPAWNS].toArray();
+        for (const auto &spawn_val : spawns) {
+          if (spawn_val.isObject()) {
+            QJsonObject spawn = spawn_val.toObject();
+            if (spawn.contains(PLAYER_ID)) {
+              const int player_id = spawn[PLAYER_ID].toInt();
+              if (player_id > 0) {
+                map_player_ids.insert(player_id);
               }
             }
           }
@@ -110,69 +127,69 @@ SkirmishLoadResult SkirmishLoader::start(const QString &mapPath,
       }
     }
   } else {
-    qWarning() << "Could not open map file for reading player IDs:" << mapPath;
+    qWarning() << "Could not open map file for reading player IDs:" << map_path;
   }
 
-  auto &ownerRegistry = Game::Systems::OwnerRegistry::instance();
+  auto &owner_registry = Game::Systems::OwnerRegistry::instance();
 
-  int playerOwnerId = selectedPlayerId;
+  int player_owner_id = selectedPlayerId;
 
-  if (!mapPlayerIds.contains(playerOwnerId)) {
-    if (!mapPlayerIds.isEmpty()) {
-      QList<int> sortedIds = mapPlayerIds.values();
-      std::sort(sortedIds.begin(), sortedIds.end());
-      playerOwnerId = sortedIds.first();
+  if (!map_player_ids.contains(player_owner_id)) {
+    if (!map_player_ids.isEmpty()) {
+      QList<int> sorted_ids = map_player_ids.values();
+      std::sort(sorted_ids.begin(), sorted_ids.end());
+      player_owner_id = sorted_ids.first();
       qWarning() << "Selected player ID" << selectedPlayerId
-                 << "not found in map spawns. Using" << playerOwnerId
+                 << "not found in map spawns. Using" << player_owner_id
                  << "instead.";
-      outSelectedPlayerId = playerOwnerId;
+      outSelectedPlayerId = player_owner_id;
     } else {
       qWarning() << "No valid player spawns found in map. Using default "
                     "player ID"
-                 << playerOwnerId;
+                 << player_owner_id;
     }
   }
 
-  ownerRegistry.setLocalPlayerId(playerOwnerId);
+  owner_registry.setLocalPlayerId(player_owner_id);
 
-  std::unordered_map<int, int> teamOverrides;
-  QVariantList savedPlayerConfigs;
-  std::set<int> processedPlayerIds;
+  std::unordered_map<int, int> team_overrides;
+  QVariantList saved_player_configs;
+  std::set<int> processed_player_ids;
 
   if (!playerConfigs.isEmpty()) {
 
-    for (const QVariant &configVar : playerConfigs) {
-      QVariantMap config = configVar.toMap();
-      int playerId = config.value("playerId", -1).toInt();
-      int teamId = config.value("teamId", 0).toInt();
-      QString colorHex = config.value("colorHex", "#FFFFFF").toString();
-      bool isHuman = config.value("isHuman", false).toBool();
+    for (const QVariant &config_var : playerConfigs) {
+      const QVariantMap config = config_var.toMap();
+      int player_id = config.value("player_id", -1).toInt();
+      const int team_id = config.value("team_id", 0).toInt();
+      const QString color_hex = config.value("colorHex", "#FFFFFF").toString();
+      const bool is_human = config.value("isHuman", false).toBool();
 
-      if (isHuman && playerId != playerOwnerId) {
-        playerId = playerOwnerId;
+      if (is_human && player_id != player_owner_id) {
+        player_id = player_owner_id;
       }
 
-      if (processedPlayerIds.count(playerId) > 0) {
+      if (processed_player_ids.contains(player_id)) {
         continue;
       }
 
-      if (playerId >= 0) {
-        processedPlayerIds.insert(playerId);
-        teamOverrides[playerId] = teamId;
+      if (player_id >= 0) {
+        processed_player_ids.insert(player_id);
+        team_overrides[player_id] = team_id;
 
-        QVariantMap updatedConfig = config;
-        updatedConfig["playerId"] = playerId;
-        savedPlayerConfigs.append(updatedConfig);
+        QVariantMap updated_config = config;
+        updated_config["player_id"] = player_id;
+        saved_player_configs.append(updated_config);
       }
     }
   }
 
-  std::set<int> uniqueTeams;
-  for (const auto &[playerId, teamId] : teamOverrides) {
-    uniqueTeams.insert(teamId);
+  std::set<int> unique_teams;
+  for (const auto &[player_id, team_id] : team_overrides) {
+    unique_teams.insert(team_id);
   }
 
-  if (teamOverrides.size() >= 2 && uniqueTeams.size() < 2) {
+  if (team_overrides.size() >= 2 && unique_teams.size() < 2) {
     result.errorMessage = "Invalid team configuration: At least two teams must "
                           "be selected to start a match.";
     m_renderer.unlockWorldForModification();
@@ -181,47 +198,53 @@ SkirmishLoadResult SkirmishLoader::start(const QString &mapPath,
     return result;
   }
 
-  Game::Map::MapTransformer::setLocalOwnerId(playerOwnerId);
-  Game::Map::MapTransformer::setPlayerTeamOverrides(teamOverrides);
+  Game::Map::MapTransformer::setLocalOwnerId(player_owner_id);
+  Game::Map::MapTransformer::setPlayerTeamOverrides(team_overrides);
 
-  auto lr = Game::Map::LevelLoader::loadFromAssets(mapPath, m_world, m_renderer,
-                                                   m_camera);
+  auto level_result = Game::Map::LevelLoader::loadFromAssets(
+      map_path, m_world, m_renderer, m_camera);
 
-  if (!lr.ok && !lr.errorMessage.isEmpty()) {
-    result.errorMessage = lr.errorMessage;
+  if (!level_result.ok && !level_result.errorMessage.isEmpty()) {
+    result.errorMessage = level_result.errorMessage;
     m_renderer.unlockWorldForModification();
     m_renderer.resume();
     return result;
   }
 
-  if (!savedPlayerConfigs.isEmpty()) {
-    for (const QVariant &configVar : savedPlayerConfigs) {
-      QVariantMap config = configVar.toMap();
-      int playerId = config.value("playerId", -1).toInt();
-      QString colorHex = config.value("colorHex", "#FFFFFF").toString();
-
-      if (playerId >= 0 && colorHex.startsWith("#") && colorHex.length() == 7) {
-        bool ok;
-        int r = colorHex.mid(1, 2).toInt(&ok, 16);
-        int g = colorHex.mid(3, 2).toInt(&ok, 16);
-        int b = colorHex.mid(5, 2).toInt(&ok, 16);
-        ownerRegistry.setOwnerColor(playerId, r / 255.0f, g / 255.0f,
-                                    b / 255.0f);
+  constexpr float COLOR_SCALE = 255.0F;
+  constexpr int HEX_COLOR_LENGTH = 7;
+  constexpr int HEX_BASE = 16;
+
+  if (!saved_player_configs.isEmpty()) {
+    for (const QVariant &config_var : saved_player_configs) {
+      const QVariantMap config = config_var.toMap();
+      const int player_id = config.value("player_id", -1).toInt();
+      const QString color_hex = config.value("colorHex", "#FFFFFF").toString();
+
+      if (player_id >= 0 && color_hex.startsWith("#") &&
+          color_hex.length() == HEX_COLOR_LENGTH) {
+        bool conversion_ok = false;
+        const int red = color_hex.mid(1, 2).toInt(&conversion_ok, HEX_BASE);
+        const int green = color_hex.mid(3, 2).toInt(&conversion_ok, HEX_BASE);
+        const int blue = color_hex.mid(5, 2).toInt(&conversion_ok, HEX_BASE);
+        owner_registry.setOwnerColor(player_id, red / COLOR_SCALE,
+                                     green / COLOR_SCALE, blue / COLOR_SCALE);
       }
     }
 
     auto entities = m_world.getEntitiesWith<Engine::Core::UnitComponent>();
-    std::unordered_map<int, int> ownerEntityCount;
+    std::unordered_map<int, int> owner_entity_count;
     for (auto *entity : entities) {
       auto *unit = entity->getComponent<Engine::Core::UnitComponent>();
       auto *renderable =
           entity->getComponent<Engine::Core::RenderableComponent>();
-      if (unit && renderable) {
-        QVector3D tc = Game::Visuals::teamColorForOwner(unit->ownerId);
-        renderable->color[0] = tc.x();
-        renderable->color[1] = tc.y();
-        renderable->color[2] = tc.z();
-        ownerEntityCount[unit->ownerId]++;
+      if ((unit != nullptr) && (renderable != nullptr)) {
+        const QVector3D team_color =
+            Game::Visuals::team_colorForOwner(unit->owner_id);
+        renderable->color[0] = team_color.x();
+        renderable->color[1] = team_color.y();
+        renderable->color[2] = team_color.z();
+        owner_entity_count[unit->owner_id]++;
       }
     }
   }
@@ -230,100 +253,111 @@ SkirmishLoadResult SkirmishLoader::start(const QString &mapPath,
     m_onOwnersUpdated();
   }
 
-  auto &terrainService = Game::Map::TerrainService::instance();
+  auto &terrain_service = Game::Map::TerrainService::instance();
 
-  if (m_ground) {
-    if (lr.ok) {
-      m_ground->configure(lr.tileSize, lr.gridWidth, lr.gridHeight);
+  if (m_ground != nullptr) {
+    if (level_result.ok) {
+      m_ground->configure(level_result.tile_size, level_result.grid_width,
+                          level_result.grid_height);
     } else {
-      m_ground->configureExtent(50.0f);
+      m_ground->configureExtent(50.0F);
     }
-    if (terrainService.isInitialized()) {
-      m_ground->setBiome(terrainService.biomeSettings());
+    if (terrain_service.isInitialized()) {
+      m_ground->setBiome(terrain_service.biomeSettings());
     }
   }
 
-  if (m_terrain) {
-    if (terrainService.isInitialized() && terrainService.getHeightMap()) {
-      m_terrain->configure(*terrainService.getHeightMap(),
-                           terrainService.biomeSettings());
+  if (m_terrain != nullptr) {
+    if (terrain_service.isInitialized() &&
+        (terrain_service.getHeightMap() != nullptr)) {
+      m_terrain->configure(*terrain_service.getHeightMap(),
+                           terrain_service.biomeSettings());
     }
   }
 
-  if (m_biome) {
-    if (terrainService.isInitialized() && terrainService.getHeightMap()) {
-      m_biome->configure(*terrainService.getHeightMap(),
-                         terrainService.biomeSettings());
+  if (m_biome != nullptr) {
+    if (terrain_service.isInitialized() &&
+        (terrain_service.getHeightMap() != nullptr)) {
+      m_biome->configure(*terrain_service.getHeightMap(),
+                         terrain_service.biomeSettings());
     }
   }
 
-  if (m_river) {
-    if (terrainService.isInitialized() && terrainService.getHeightMap()) {
-      m_river->configure(terrainService.getHeightMap()->getRiverSegments(),
-                         terrainService.getHeightMap()->getTileSize());
+  if (m_river != nullptr) {
+    if (terrain_service.isInitialized() &&
+        (terrain_service.getHeightMap() != nullptr)) {
+      m_river->configure(terrain_service.getHeightMap()->getRiverSegments(),
+                         terrain_service.getHeightMap()->getTileSize());
     }
   }
 
-  if (m_riverbank) {
-    if (terrainService.isInitialized() && terrainService.getHeightMap()) {
-      m_riverbank->configure(terrainService.getHeightMap()->getRiverSegments(),
-                             *terrainService.getHeightMap());
+  if (m_riverbank != nullptr) {
+    if (terrain_service.isInitialized() &&
+        (terrain_service.getHeightMap() != nullptr)) {
+      m_riverbank->configure(terrain_service.getHeightMap()->getRiverSegments(),
+                             *terrain_service.getHeightMap());
     }
   }
 
-  if (m_bridge) {
-    if (terrainService.isInitialized() && terrainService.getHeightMap()) {
-      m_bridge->configure(terrainService.getHeightMap()->getBridges(),
-                          terrainService.getHeightMap()->getTileSize());
+  if (m_bridge != nullptr) {
+    if (terrain_service.isInitialized() &&
+        (terrain_service.getHeightMap() != nullptr)) {
+      m_bridge->configure(terrain_service.getHeightMap()->getBridges(),
+                          terrain_service.getHeightMap()->getTileSize());
     }
   }
 
-  if (m_stone) {
-    if (terrainService.isInitialized() && terrainService.getHeightMap()) {
-      m_stone->configure(*terrainService.getHeightMap(),
-                         terrainService.biomeSettings());
+  if (m_stone != nullptr) {
+    if (terrain_service.isInitialized() &&
+        (terrain_service.getHeightMap() != nullptr)) {
+      m_stone->configure(*terrain_service.getHeightMap(),
+                         terrain_service.biomeSettings());
     }
   }
 
-  if (m_plant) {
-    if (terrainService.isInitialized() && terrainService.getHeightMap()) {
-      m_plant->configure(*terrainService.getHeightMap(),
-                         terrainService.biomeSettings());
+  if (m_plant != nullptr) {
+    if (terrain_service.isInitialized() &&
+        (terrain_service.getHeightMap() != nullptr)) {
+      m_plant->configure(*terrain_service.getHeightMap(),
+                         terrain_service.biomeSettings());
     }
   }
 
-  if (m_pine) {
-    if (terrainService.isInitialized() && terrainService.getHeightMap()) {
-      m_pine->configure(*terrainService.getHeightMap(),
-                        terrainService.biomeSettings());
+  if (m_pine != nullptr) {
+    if (terrain_service.isInitialized() &&
+        (terrain_service.getHeightMap() != nullptr)) {
+      m_pine->configure(*terrain_service.getHeightMap(),
+                        terrain_service.biomeSettings());
     }
   }
 
-  if (m_firecamp) {
-    if (terrainService.isInitialized() && terrainService.getHeightMap()) {
-      m_firecamp->configure(*terrainService.getHeightMap(),
-                            terrainService.biomeSettings());
+  if (m_firecamp != nullptr) {
+    if (terrain_service.isInitialized() &&
+        (terrain_service.getHeightMap() != nullptr)) {
+      m_firecamp->configure(*terrain_service.getHeightMap(),
+                            terrain_service.biomeSettings());
 
-      const auto &fireCamps = terrainService.fireCamps();
-      if (!fireCamps.empty()) {
+      const auto &fire_camps = terrain_service.fire_camps();
+      if (!fire_camps.empty()) {
         std::vector<QVector3D> positions;
         std::vector<float> intensities;
         std::vector<float> radii;
 
-        const auto *heightMap = terrainService.getHeightMap();
-        const float tileSize = heightMap->getTileSize();
+        const auto *heightMap = terrain_service.getHeightMap();
+        const float tile_size = heightMap->getTileSize();
         const int width = heightMap->getWidth();
         const int height = heightMap->getHeight();
-        const float halfWidth = width * 0.5f;
-        const float halfHeight = height * 0.5f;
+        const float half_width = width * 0.5F;
+        const float half_height = height * 0.5F;
 
-        for (const auto &fc : fireCamps) {
+        for (const auto &fc : fire_camps) {
 
-          float worldX = (fc.x - halfWidth) * tileSize;
-          float worldZ = (fc.z - halfHeight) * tileSize;
-          float worldY = terrainService.getTerrainHeight(worldX, worldZ);
+          float const world_x = (fc.x - half_width) * tile_size;
+          float const world_z = (fc.z - half_height) * tile_size;
+          float const world_y =
+              terrain_service.getTerrainHeight(world_x, world_z);
 
-          positions.push_back(QVector3D(worldX, worldY, worldZ));
+          positions.emplace_back(world_x, world_y, world_z);
           intensities.push_back(fc.intensity);
           radii.push_back(fc.radius);
         }
@@ -333,76 +367,78 @@ SkirmishLoadResult SkirmishLoader::start(const QString &mapPath,
     }
   }
 
-  int mapWidth = lr.ok ? lr.gridWidth : 100;
-  int mapHeight = lr.ok ? lr.gridHeight : 100;
-  Game::Systems::CommandService::initialize(mapWidth, mapHeight);
+  constexpr int default_map_size = 100;
+  const int map_width =
+      level_result.ok ? level_result.grid_width : default_map_size;
+  const int map_height =
+      level_result.ok ? level_result.grid_height : default_map_size;
+  Game::Systems::CommandService::initialize(map_width, map_height);
 
-  auto &visibilityService = Game::Map::VisibilityService::instance();
-  visibilityService.initialize(mapWidth, mapHeight, lr.tileSize);
-  visibilityService.computeImmediate(m_world, playerOwnerId);
+  auto &visibility_service = Game::Map::VisibilityService::instance();
+  visibility_service.initialize(map_width, map_height, level_result.tile_size);
+  visibility_service.computeImmediate(m_world, player_owner_id);
 
-  if (m_fog && visibilityService.isInitialized()) {
+  if ((m_fog != nullptr) && visibility_service.isInitialized()) {
     m_fog->updateMask(
-        visibilityService.getWidth(), visibilityService.getHeight(),
-        visibilityService.getTileSize(), visibilityService.snapshotCells());
+        visibility_service.getWidth(), visibility_service.getHeight(),
+        visibility_service.getTileSize(), visibility_service.snapshotCells());
 
     if (m_onVisibilityMaskReady) {
       m_onVisibilityMaskReady();
     }
   }
 
-  if (m_biome) {
+  if (m_biome != nullptr) {
     m_biome->refreshGrass();
   }
 
   m_renderer.unlockWorldForModification();
   m_renderer.resume();
 
-  Engine::Core::Entity *focusEntity = nullptr;
+  Engine::Core::Entity *focus_entity = nullptr;
 
   auto candidates = m_world.getEntitiesWith<Engine::Core::UnitComponent>();
-  for (auto *e : candidates) {
-    if (!e) {
+  for (auto *entity : candidates) {
+    if (entity == nullptr) {
       continue;
     }
-    auto *u = e->getComponent<Engine::Core::UnitComponent>();
-    if (!u) {
+    auto *unit = entity->getComponent<Engine::Core::UnitComponent>();
+    if (unit == nullptr) {
       continue;
     }
-    if (u->spawnType == Game::Units::SpawnType::Barracks &&
-        u->ownerId == playerOwnerId && u->health > 0) {
-      focusEntity = e;
+    if (unit->spawn_type == Game::Units::SpawnType::Barracks &&
+        unit->owner_id == player_owner_id && unit->health > 0) {
+      focus_entity = entity;
       break;
     }
   }
 
-  if (!focusEntity && lr.playerUnitId != 0) {
-    focusEntity = m_world.getEntity(lr.playerUnitId);
+  if ((focus_entity == nullptr) && level_result.playerUnitId != 0) {
+    focus_entity = m_world.getEntity(level_result.playerUnitId);
   }
 
-  if (focusEntity) {
-    if (auto *t =
-            focusEntity->getComponent<Engine::Core::TransformComponent>()) {
-      result.focusPosition =
-          QVector3D(t->position.x, t->position.y, t->position.z);
+  if (focus_entity != nullptr) {
+    if (auto *transform =
+            focus_entity->getComponent<Engine::Core::TransformComponent>()) {
+      result.focusPosition = QVector3D(
+          transform->position.x, transform->position.y, transform->position.z);
       result.hasFocusPosition = true;
     }
   }
 
   result.ok = true;
-  result.mapName = lr.mapName;
-  result.playerUnitId = lr.playerUnitId;
-  result.camFov = lr.camFov;
-  result.camNear = lr.camNear;
-  result.camFar = lr.camFar;
-  result.gridWidth = lr.gridWidth;
-  result.gridHeight = lr.gridHeight;
-  result.tileSize = lr.tileSize;
-  result.maxTroopsPerPlayer = lr.maxTroopsPerPlayer;
-  result.victoryConfig = lr.victoryConfig;
+  result.map_name = level_result.map_name;
+  result.playerUnitId = level_result.playerUnitId;
+  result.camFov = level_result.camFov;
+  result.camNear = level_result.camNear;
+  result.camFar = level_result.camFar;
+  result.grid_width = level_result.grid_width;
+  result.grid_height = level_result.grid_height;
+  result.tile_size = level_result.tile_size;
+  result.max_troops_per_player = level_result.max_troops_per_player;
+  result.victoryConfig = level_result.victoryConfig;
 
   return result;
 }
 
-} // namespace Map
-} // namespace Game
+} // namespace Game::Map

+ 20 - 25
game/map/skirmish_loader.h

@@ -6,16 +6,14 @@
 #include <QVector3D>
 #include <functional>
 #include <memory>
+#include <utility>
 
-namespace Engine {
-namespace Core {
+namespace Engine::Core {
 class World;
 using EntityID = unsigned int;
-} // namespace Core
-} // namespace Engine
+} // namespace Engine::Core
 
-namespace Render {
-namespace GL {
+namespace Render::GL {
 class Renderer;
 class Camera;
 class GroundRenderer;
@@ -29,24 +27,22 @@ class FireCampRenderer;
 class RiverRenderer;
 class RiverbankRenderer;
 class BridgeRenderer;
-} // namespace GL
-} // namespace Render
+} // namespace Render::GL
 
-namespace Game {
-namespace Map {
+namespace Game::Map {
 
 struct SkirmishLoadResult {
   bool ok = false;
-  QString mapName;
+  QString map_name;
   QString errorMessage;
   Engine::Core::EntityID playerUnitId = 0;
-  float camFov = 45.0f;
-  float camNear = 0.1f;
-  float camFar = 1000.0f;
-  int gridWidth = 50;
-  int gridHeight = 50;
-  float tileSize = 1.0f;
-  int maxTroopsPerPlayer = 50;
+  float camFov = 45.0F;
+  float camNear = 0.1F;
+  float camFar = 1000.0F;
+  int grid_width = 50;
+  int grid_height = 50;
+  float tile_size = 1.0F;
+  int max_troops_per_player = 50;
   VictoryConfig victoryConfig;
   QVector3D focusPosition;
   bool hasFocusPosition = false;
@@ -83,16 +79,16 @@ public:
   }
 
   void setOnOwnersUpdated(OwnersUpdatedCallback callback) {
-    m_onOwnersUpdated = callback;
+    m_onOwnersUpdated = std::move(callback);
   }
 
   void setOnVisibilityMaskReady(VisibilityMaskReadyCallback callback) {
-    m_onVisibilityMaskReady = callback;
+    m_onVisibilityMaskReady = std::move(callback);
   }
 
-  SkirmishLoadResult start(const QString &mapPath,
-                           const QVariantList &playerConfigs,
-                           int selectedPlayerId, int &outSelectedPlayerId);
+  auto start(const QString &map_path, const QVariantList &playerConfigs,
+             int selectedPlayerId,
+             int &outSelectedPlayerId) -> SkirmishLoadResult;
 
 private:
   void resetGameState();
@@ -114,5 +110,4 @@ private:
   VisibilityMaskReadyCallback m_onVisibilityMaskReady;
 };
 
-} // namespace Map
-} // namespace Game
+} // namespace Game::Map

+ 321 - 303
game/map/terrain.cpp

@@ -1,55 +1,59 @@
 #include "terrain.h"
 #include <algorithm>
 #include <cmath>
+#include <cstddef>
 #include <cstdint>
+#include <math.h>
+#include <numbers>
+#include <vector>
 
 namespace {
-constexpr float kDegToRad = static_cast<float>(M_PI) / 180.0f;
-inline std::uint32_t hashCoords(int x, int z, std::uint32_t seed) {
-  std::uint32_t ux = static_cast<std::uint32_t>(x) * 73856093u;
-  std::uint32_t uz = static_cast<std::uint32_t>(z) * 19349663u;
-  std::uint32_t s = seed * 83492791u + 0x9e3779b9u;
+constexpr float k_deg_to_rad = std::numbers::pi_v<float> / 180.0F;
+inline auto hashCoords(int x, int z, std::uint32_t seed) -> std::uint32_t {
+  std::uint32_t const ux = static_cast<std::uint32_t>(x) * 73856093U;
+  std::uint32_t const uz = static_cast<std::uint32_t>(z) * 19349663U;
+  std::uint32_t const s = seed * 83492791U + 0x9e3779b9U;
   return ux ^ uz ^ s;
 }
 
-inline float hashToFloat01(std::uint32_t h) {
+inline auto hashToFloat01(std::uint32_t h) -> float {
   h ^= h >> 17;
-  h *= 0xed5ad4bbu;
+  h *= 0xed5ad4bbU;
   h ^= h >> 11;
-  h *= 0xac4c1b51u;
+  h *= 0xac4c1b51U;
   h ^= h >> 15;
-  h *= 0x31848babu;
+  h *= 0x31848babU;
   h ^= h >> 14;
-  return (h & 0x00FFFFFFu) / float(0x01000000);
+  return (h & 0x00FFFFFFU) / float(0x01000000);
 }
 
-inline float valueNoise2D(float x, float z, std::uint32_t seed) {
-  int ix0 = static_cast<int>(std::floor(x));
-  int iz0 = static_cast<int>(std::floor(z));
-  int ix1 = ix0 + 1;
-  int iz1 = iz0 + 1;
+inline auto valueNoise2D(float x, float z, std::uint32_t seed) -> float {
+  int const ix0 = static_cast<int>(std::floor(x));
+  int const iz0 = static_cast<int>(std::floor(z));
+  int const ix1 = ix0 + 1;
+  int const iz1 = iz0 + 1;
 
-  float tx = x - static_cast<float>(ix0);
-  float tz = z - static_cast<float>(iz0);
+  float const tx = x - static_cast<float>(ix0);
+  float const tz = z - static_cast<float>(iz0);
 
-  float n00 = hashToFloat01(hashCoords(ix0, iz0, seed));
-  float n10 = hashToFloat01(hashCoords(ix1, iz0, seed));
-  float n01 = hashToFloat01(hashCoords(ix0, iz1, seed));
-  float n11 = hashToFloat01(hashCoords(ix1, iz1, seed));
+  float const n00 = hashToFloat01(hashCoords(ix0, iz0, seed));
+  float const n10 = hashToFloat01(hashCoords(ix1, iz0, seed));
+  float const n01 = hashToFloat01(hashCoords(ix0, iz1, seed));
+  float const n11 = hashToFloat01(hashCoords(ix1, iz1, seed));
 
-  float nx0 = n00 * (1.0f - tx) + n10 * tx;
-  float nx1 = n01 * (1.0f - tx) + n11 * tx;
-  return nx0 * (1.0f - tz) + nx1 * tz;
+  float const nx0 = n00 * (1.0F - tx) + n10 * tx;
+  float const nx1 = n01 * (1.0F - tx) + n11 * tx;
+  return nx0 * (1.0F - tz) + nx1 * tz;
 }
 } // namespace
 
 namespace Game::Map {
 
-TerrainHeightMap::TerrainHeightMap(int width, int height, float tileSize)
-    : m_width(width), m_height(height), m_tileSize(tileSize) {
+TerrainHeightMap::TerrainHeightMap(int width, int height, float tile_size)
+    : m_width(width), m_height(height), m_tile_size(tile_size) {
   const int count = width * height;
-  m_heights.resize(count, 0.0f);
-  m_terrainTypes.resize(count, TerrainType::Flat);
+  m_heights.resize(count, 0.0F);
+  m_terrain_types.resize(count, TerrainType::Flat);
   m_hillEntrances.resize(count, false);
   m_hillWalkable.resize(count, false);
 }
@@ -57,60 +61,63 @@ TerrainHeightMap::TerrainHeightMap(int width, int height, float tileSize)
 void TerrainHeightMap::buildFromFeatures(
     const std::vector<TerrainFeature> &features) {
 
-  std::fill(m_heights.begin(), m_heights.end(), 0.0f);
-  std::fill(m_terrainTypes.begin(), m_terrainTypes.end(), TerrainType::Flat);
+  std::fill(m_heights.begin(), m_heights.end(), 0.0F);
+  std::fill(m_terrain_types.begin(), m_terrain_types.end(), TerrainType::Flat);
   std::fill(m_hillEntrances.begin(), m_hillEntrances.end(), false);
   std::fill(m_hillWalkable.begin(), m_hillWalkable.end(), false);
 
-  const float gridHalfWidth = m_width * 0.5f - 0.5f;
-  const float gridHalfHeight = m_height * 0.5f - 0.5f;
+  const float grid_half_width = m_width * 0.5F - 0.5F;
+  const float grid_half_height = m_height * 0.5F - 0.5F;
 
   for (const auto &feature : features) {
 
-    const float gridCenterX = (feature.centerX / m_tileSize) + gridHalfWidth;
-    const float gridCenterZ = (feature.centerZ / m_tileSize) + gridHalfHeight;
-    const float gridRadius = std::max(feature.radius / m_tileSize, 1.0f);
+    const float grid_center_x =
+        (feature.center_x / m_tile_size) + grid_half_width;
+    const float grid_center_z =
+        (feature.center_z / m_tile_size) + grid_half_height;
+    const float grid_radius = std::max(feature.radius / m_tile_size, 1.0F);
 
     if (feature.type == TerrainType::Mountain) {
-      const float majorRadius = std::max(gridRadius * 1.8f, gridRadius + 3.0f);
-      const float minorRadius = std::max(gridRadius * 0.22f, 0.8f);
-      const float bound = std::max(majorRadius, minorRadius) + 2.0f;
-      const int minX = std::max(0, int(std::floor(gridCenterX - bound)));
+      const float major_radius =
+          std::max(grid_radius * 1.8F, grid_radius + 3.0F);
+      const float minor_radius = std::max(grid_radius * 0.22F, 0.8F);
+      const float bound = std::max(major_radius, minor_radius) + 2.0F;
+      const int minX = std::max(0, int(std::floor(grid_center_x - bound)));
       const int maxX =
-          std::min(m_width - 1, int(std::ceil(gridCenterX + bound)));
-      const int minZ = std::max(0, int(std::floor(gridCenterZ - bound)));
+          std::min(m_width - 1, int(std::ceil(grid_center_x + bound)));
+      const int minZ = std::max(0, int(std::floor(grid_center_z - bound)));
       const int maxZ =
-          std::min(m_height - 1, int(std::ceil(gridCenterZ + bound)));
+          std::min(m_height - 1, int(std::ceil(grid_center_z + bound)));
 
-      const float angleRad = feature.rotationDeg * kDegToRad;
-      const float cosA = std::cos(angleRad);
-      const float sinA = std::sin(angleRad);
+      const float angle_rad = feature.rotationDeg * k_deg_to_rad;
+      const float cosA = std::cos(angle_rad);
+      const float sinA = std::sin(angle_rad);
 
       for (int z = minZ; z <= maxZ; ++z) {
         for (int x = minX; x <= maxX; ++x) {
-          const float localX = float(x) - gridCenterX;
-          const float localZ = float(z) - gridCenterZ;
+          const float local_x = float(x) - grid_center_x;
+          const float local_z = float(z) - grid_center_z;
 
-          const float rotatedX = localX * cosA + localZ * sinA;
-          const float rotatedZ = -localX * sinA + localZ * cosA;
+          const float rotated_x = local_x * cosA + local_z * sinA;
+          const float rotated_z = -local_x * sinA + local_z * cosA;
 
-          const float norm =
-              std::sqrt((rotatedX * rotatedX) / (majorRadius * majorRadius) +
-                        (rotatedZ * rotatedZ) / (minorRadius * minorRadius));
+          const float norm = std::sqrt(
+              (rotated_x * rotated_x) / (major_radius * major_radius) +
+              (rotated_z * rotated_z) / (minor_radius * minor_radius));
 
-          if (norm <= 1.0f) {
-            float blend = std::clamp(1.0f - norm, 0.0f, 1.0f);
+          if (norm <= 1.0F) {
+            float const blend = std::clamp(1.0F - norm, 0.0F, 1.0F);
 
-            float height = feature.height * std::pow(blend, 3.5f);
-            if (blend > 0.92f) {
+            float height = feature.height * std::pow(blend, 3.5F);
+            if (blend > 0.92F) {
               height = feature.height;
             }
 
-            if (height > 0.01f) {
-              int idx = indexAt(x, z);
+            if (height > 0.01F) {
+              int const idx = indexAt(x, z);
               if (height > m_heights[idx]) {
                 m_heights[idx] = height;
-                m_terrainTypes[idx] = TerrainType::Mountain;
+                m_terrain_types[idx] = TerrainType::Mountain;
               }
             }
           }
@@ -120,130 +127,131 @@ void TerrainHeightMap::buildFromFeatures(
     }
 
     if (feature.type == TerrainType::Hill) {
-      const float gridWidth = std::max(feature.width / m_tileSize, 1.0f);
-      const float gridDepth = std::max(feature.depth / m_tileSize, 1.0f);
+      const float grid_width = std::max(feature.width / m_tile_size, 1.0F);
+      const float grid_depth = std::max(feature.depth / m_tile_size, 1.0F);
 
-      const float plateauWidth = std::max(1.5f, gridWidth * 0.45f);
-      const float plateauDepth = std::max(1.5f, gridDepth * 0.45f);
-      const float slopeWidth = std::max(plateauWidth + 1.5f, gridWidth);
-      const float slopeDepth = std::max(plateauDepth + 1.5f, gridDepth);
+      const float plateau_width = std::max(1.5F, grid_width * 0.45F);
+      const float plateau_depth = std::max(1.5F, grid_depth * 0.45F);
+      const float slope_width = std::max(plateau_width + 1.5F, grid_width);
+      const float slope_depth = std::max(plateau_depth + 1.5F, grid_depth);
 
-      const float maxExtent = std::max(slopeWidth, slopeDepth);
+      const float max_extent = std::max(slope_width, slope_depth);
       const int minX =
-          std::max(0, int(std::floor(gridCenterX - maxExtent - 1.0f)));
-      const int maxX =
-          std::min(m_width - 1, int(std::ceil(gridCenterX + maxExtent + 1.0f)));
+          std::max(0, int(std::floor(grid_center_x - max_extent - 1.0F)));
+      const int maxX = std::min(
+          m_width - 1, int(std::ceil(grid_center_x + max_extent + 1.0F)));
       const int minZ =
-          std::max(0, int(std::floor(gridCenterZ - maxExtent - 1.0f)));
-      const int maxZ = std::min(m_height - 1,
-                                int(std::ceil(gridCenterZ + maxExtent + 1.0f)));
+          std::max(0, int(std::floor(grid_center_z - max_extent - 1.0F)));
+      const int maxZ = std::min(
+          m_height - 1, int(std::ceil(grid_center_z + max_extent + 1.0F)));
 
-      std::vector<int> plateauCells;
-      plateauCells.reserve(int(M_PI * plateauWidth * plateauDepth));
+      std::vector<int> plateau_cells;
+      plateau_cells.reserve(int(M_PI * plateau_width * plateau_depth));
 
-      const float angleRad = feature.rotationDeg * kDegToRad;
-      const float cosA = std::cos(angleRad);
-      const float sinA = std::sin(angleRad);
+      const float angle_rad = feature.rotationDeg * k_deg_to_rad;
+      const float cosA = std::cos(angle_rad);
+      const float sinA = std::sin(angle_rad);
 
       for (int z = minZ; z <= maxZ; ++z) {
         for (int x = minX; x <= maxX; ++x) {
-          const float dx = float(x) - gridCenterX;
-          const float dz = float(z) - gridCenterZ;
+          const float dx = float(x) - grid_center_x;
+          const float dz = float(z) - grid_center_z;
 
-          const float rotatedX = dx * cosA + dz * sinA;
-          const float rotatedZ = -dx * sinA + dz * cosA;
+          const float rotated_x = dx * cosA + dz * sinA;
+          const float rotated_z = -dx * sinA + dz * cosA;
 
-          const float normPlateauDist =
-              std::sqrt((rotatedX * rotatedX) / (plateauWidth * plateauWidth) +
-                        (rotatedZ * rotatedZ) / (plateauDepth * plateauDepth));
-          const float normSlopeDist =
-              std::sqrt((rotatedX * rotatedX) / (slopeWidth * slopeWidth) +
-                        (rotatedZ * rotatedZ) / (slopeDepth * slopeDepth));
+          const float norm_plateau_dist = std::sqrt(
+              (rotated_x * rotated_x) / (plateau_width * plateau_width) +
+              (rotated_z * rotated_z) / (plateau_depth * plateau_depth));
+          const float norm_slope_dist =
+              std::sqrt((rotated_x * rotated_x) / (slope_width * slope_width) +
+                        (rotated_z * rotated_z) / (slope_depth * slope_depth));
 
-          if (normSlopeDist > 1.0f) {
+          if (norm_slope_dist > 1.0F) {
             continue;
           }
 
           const int idx = indexAt(x, z);
 
-          float height = 0.0f;
-          if (normPlateauDist <= 1.0f) {
+          float height = 0.0F;
+          if (norm_plateau_dist <= 1.0F) {
             height = feature.height;
-            plateauCells.push_back(idx);
+            plateau_cells.push_back(idx);
           } else {
-            float t = std::clamp((normSlopeDist - normPlateauDist) /
-                                     (1.0f - normPlateauDist),
-                                 0.0f, 1.0f);
-            float smooth = 0.5f * (1.0f + std::cos(t * float(M_PI)));
+            float const t = std::clamp((norm_slope_dist - norm_plateau_dist) /
+                                           (1.0F - norm_plateau_dist),
+                                       0.0F, 1.0F);
+            float const smooth =
+                0.5F * (1.0F + std::cos(t * std::numbers::pi_v<float>));
             height = feature.height * smooth;
           }
 
           if (height > m_heights[idx]) {
             m_heights[idx] = height;
-            m_terrainTypes[idx] = TerrainType::Hill;
+            m_terrain_types[idx] = TerrainType::Hill;
           }
         }
       }
 
-      for (int idx : plateauCells) {
+      for (int const idx : plateau_cells) {
         m_hillWalkable[idx] = true;
       }
 
       for (const auto &entrance : feature.entrances) {
-        int ex = int(std::round(entrance.x()));
-        int ez = int(std::round(entrance.z()));
+        int const ex = int(std::round(entrance.x()));
+        int const ez = int(std::round(entrance.z()));
         if (!inBounds(ex, ez)) {
           continue;
         }
 
-        const int entranceIdx = indexAt(ex, ez);
-        m_hillEntrances[entranceIdx] = true;
-        m_hillWalkable[entranceIdx] = true;
+        const int entrance_idx = indexAt(ex, ez);
+        m_hillEntrances[entrance_idx] = true;
+        m_hillWalkable[entrance_idx] = true;
 
-        float dirX = gridCenterX - float(ex);
-        float dirZ = gridCenterZ - float(ez);
-        float length = std::sqrt(dirX * dirX + dirZ * dirZ);
-        if (length < 0.001f) {
+        float dirX = grid_center_x - float(ex);
+        float dirZ = grid_center_z - float(ez);
+        float const length = std::sqrt(dirX * dirX + dirZ * dirZ);
+        if (length < 0.001F) {
           continue;
         }
 
         dirX /= length;
         dirZ /= length;
 
-        float curX = float(ex);
-        float curZ = float(ez);
+        auto curX = float(ex);
+        auto curZ = float(ez);
         const int steps = int(length) + 3;
 
         for (int step = 0; step < steps; ++step) {
-          int ix = int(std::round(curX));
-          int iz = int(std::round(curZ));
+          int const ix = int(std::round(curX));
+          int const iz = int(std::round(curZ));
           if (!inBounds(ix, iz)) {
             break;
           }
 
           const int idx = indexAt(ix, iz);
 
-          const float cellDx = float(ix) - gridCenterX;
-          const float cellDz = float(iz) - gridCenterZ;
-          const float cellRotX = cellDx * cosA + cellDz * sinA;
-          const float cellRotZ = -cellDx * sinA + cellDz * cosA;
-          const float cellNormDist =
-              std::sqrt((cellRotX * cellRotX) / (slopeWidth * slopeWidth) +
-                        (cellRotZ * cellRotZ) / (slopeDepth * slopeDepth));
+          const float cell_dx = float(ix) - grid_center_x;
+          const float cell_dz = float(iz) - grid_center_z;
+          const float cell_rot_x = cell_dx * cosA + cell_dz * sinA;
+          const float cell_rot_z = -cell_dx * sinA + cell_dz * cosA;
+          const float cell_norm_dist = std::sqrt(
+              (cell_rot_x * cell_rot_x) / (slope_width * slope_width) +
+              (cell_rot_z * cell_rot_z) / (slope_depth * slope_depth));
 
-          if (cellNormDist > 1.1f) {
+          if (cell_norm_dist > 1.1F) {
             break;
           }
 
           m_hillWalkable[idx] = true;
-          if (m_terrainTypes[idx] != TerrainType::Mountain) {
-            m_terrainTypes[idx] = TerrainType::Hill;
+          if (m_terrain_types[idx] != TerrainType::Mountain) {
+            m_terrain_types[idx] = TerrainType::Hill;
           }
 
-          if (m_heights[idx] < feature.height * 0.25f) {
-            float t = std::clamp(cellNormDist, 0.0f, 1.0f);
-            float rampHeight = feature.height * (1.0f - t * 0.85f);
-            m_heights[idx] = std::max(m_heights[idx], rampHeight);
+          if (m_heights[idx] < feature.height * 0.25F) {
+            float const t = std::clamp(cell_norm_dist, 0.0F, 1.0F);
+            float const ramp_height = feature.height * (1.0F - t * 0.85F);
+            m_heights[idx] = std::max(m_heights[idx], ramp_height);
           }
 
           for (int oz = -1; oz <= 1; ++oz) {
@@ -251,40 +259,40 @@ void TerrainHeightMap::buildFromFeatures(
               if (ox == 0 && oz == 0) {
                 continue;
               }
-              int nx = ix + ox;
-              int nz = iz + oz;
+              int const nx = ix + ox;
+              int const nz = iz + oz;
               if (!inBounds(nx, nz)) {
                 continue;
               }
 
-              const float nDx = float(nx) - gridCenterX;
-              const float nDz = float(nz) - gridCenterZ;
-              const float nRotX = nDx * cosA + nDz * sinA;
-              const float nRotZ = -nDx * sinA + nDz * cosA;
-              const float neighborNormDist =
-                  std::sqrt((nRotX * nRotX) / (slopeWidth * slopeWidth) +
-                            (nRotZ * nRotZ) / (slopeDepth * slopeDepth));
-
-              if (neighborNormDist <= 1.05f) {
-                int nIdx = indexAt(nx, nz);
-                if (m_terrainTypes[nIdx] != TerrainType::Mountain) {
+              const float nDx = float(nx) - grid_center_x;
+              const float nDz = float(nz) - grid_center_z;
+              const float n_rot_x = nDx * cosA + nDz * sinA;
+              const float n_rot_z = -nDx * sinA + nDz * cosA;
+              const float neighbor_norm_dist =
+                  std::sqrt((n_rot_x * n_rot_x) / (slope_width * slope_width) +
+                            (n_rot_z * n_rot_z) / (slope_depth * slope_depth));
+
+              if (neighbor_norm_dist <= 1.05F) {
+                int const nIdx = indexAt(nx, nz);
+                if (m_terrain_types[nIdx] != TerrainType::Mountain) {
                   m_hillWalkable[nIdx] = true;
-                  if (m_terrainTypes[nIdx] == TerrainType::Flat) {
-                    m_terrainTypes[nIdx] = TerrainType::Hill;
+                  if (m_terrain_types[nIdx] == TerrainType::Flat) {
+                    m_terrain_types[nIdx] = TerrainType::Hill;
                   }
-                  if (m_heights[nIdx] < m_heights[idx] * 0.8f) {
+                  if (m_heights[nIdx] < m_heights[idx] * 0.8F) {
                     m_heights[nIdx] =
-                        std::max(m_heights[nIdx], m_heights[idx] * 0.7f);
+                        std::max(m_heights[nIdx], m_heights[idx] * 0.7F);
                   }
                 }
               }
             }
           }
 
-          const float plateauNormDist =
-              std::sqrt((cellRotX * cellRotX) / (plateauWidth * plateauWidth) +
-                        (cellRotZ * cellRotZ) / (plateauDepth * plateauDepth));
-          if (plateauNormDist <= 1.05f) {
+          const float plateau_norm_dist = std::sqrt(
+              (cell_rot_x * cell_rot_x) / (plateau_width * plateau_width) +
+              (cell_rot_z * cell_rot_z) / (plateau_depth * plateau_depth));
+          if (plateau_norm_dist <= 1.05F) {
             break;
           }
 
@@ -296,83 +304,84 @@ void TerrainHeightMap::buildFromFeatures(
       continue;
     }
 
-    const float flatRadius = gridRadius;
-    const int minX = std::max(0, int(std::floor(gridCenterX - flatRadius)));
+    const float flat_radius = grid_radius;
+    const int minX = std::max(0, int(std::floor(grid_center_x - flat_radius)));
     const int maxX =
-        std::min(m_width - 1, int(std::ceil(gridCenterX + flatRadius)));
-    const int minZ = std::max(0, int(std::floor(gridCenterZ - flatRadius)));
+        std::min(m_width - 1, int(std::ceil(grid_center_x + flat_radius)));
+    const int minZ = std::max(0, int(std::floor(grid_center_z - flat_radius)));
     const int maxZ =
-        std::min(m_height - 1, int(std::ceil(gridCenterZ + flatRadius)));
+        std::min(m_height - 1, int(std::ceil(grid_center_z + flat_radius)));
 
     for (int z = minZ; z <= maxZ; ++z) {
       for (int x = minX; x <= maxX; ++x) {
-        const float dx = float(x) - gridCenterX;
-        const float dz = float(z) - gridCenterZ;
+        const float dx = float(x) - grid_center_x;
+        const float dz = float(z) - grid_center_z;
         const float dist = std::sqrt(dx * dx + dz * dz);
-        if (dist > flatRadius) {
+        if (dist > flat_radius) {
           continue;
         }
 
-        float t = dist / std::max(flatRadius, 0.0001f);
-        float height = feature.height * (1.0f - t);
-        if (height <= 0.0f) {
+        float const t = dist / std::max(flat_radius, 0.0001F);
+        float const height = feature.height * (1.0F - t);
+        if (height <= 0.0F) {
           continue;
         }
 
-        int idx = indexAt(x, z);
+        int const idx = indexAt(x, z);
         if (height > m_heights[idx]) {
           m_heights[idx] = height;
-          m_terrainTypes[idx] = TerrainType::Flat;
+          m_terrain_types[idx] = TerrainType::Flat;
         }
       }
     }
   }
 }
 
-float TerrainHeightMap::getHeightAt(float worldX, float worldZ) const {
+auto TerrainHeightMap::getHeightAt(float world_x,
+                                   float world_z) const -> float {
 
-  const float gridHalfWidth = m_width * 0.5f - 0.5f;
-  const float gridHalfHeight = m_height * 0.5f - 0.5f;
+  const float grid_half_width = m_width * 0.5F - 0.5F;
+  const float grid_half_height = m_height * 0.5F - 0.5F;
 
-  float gx = worldX / m_tileSize + gridHalfWidth;
-  float gz = worldZ / m_tileSize + gridHalfHeight;
+  float const gx = world_x / m_tile_size + grid_half_width;
+  float const gz = world_z / m_tile_size + grid_half_height;
 
-  int x0 = int(std::floor(gx));
-  int z0 = int(std::floor(gz));
-  int x1 = x0 + 1;
-  int z1 = z0 + 1;
+  int const x0 = int(std::floor(gx));
+  int const z0 = int(std::floor(gz));
+  int const x1 = x0 + 1;
+  int const z1 = z0 + 1;
 
   if (!inBounds(x0, z0)) {
-    return 0.0f;
+    return 0.0F;
   }
 
-  float tx = gx - x0;
-  float tz = gz - z0;
+  float const tx = gx - x0;
+  float const tz = gz - z0;
 
-  float h00 = inBounds(x0, z0) ? m_heights[indexAt(x0, z0)] : 0.0f;
-  float h10 = inBounds(x1, z0) ? m_heights[indexAt(x1, z0)] : 0.0f;
-  float h01 = inBounds(x0, z1) ? m_heights[indexAt(x0, z1)] : 0.0f;
-  float h11 = inBounds(x1, z1) ? m_heights[indexAt(x1, z1)] : 0.0f;
+  float const h00 = inBounds(x0, z0) ? m_heights[indexAt(x0, z0)] : 0.0F;
+  float const h10 = inBounds(x1, z0) ? m_heights[indexAt(x1, z0)] : 0.0F;
+  float const h01 = inBounds(x0, z1) ? m_heights[indexAt(x0, z1)] : 0.0F;
+  float const h11 = inBounds(x1, z1) ? m_heights[indexAt(x1, z1)] : 0.0F;
 
-  float h0 = h00 * (1.0f - tx) + h10 * tx;
-  float h1 = h01 * (1.0f - tx) + h11 * tx;
+  float const h0 = h00 * (1.0F - tx) + h10 * tx;
+  float const h1 = h01 * (1.0F - tx) + h11 * tx;
 
-  return h0 * (1.0f - tz) + h1 * tz;
+  return h0 * (1.0F - tz) + h1 * tz;
 }
 
-float TerrainHeightMap::getHeightAtGrid(int gridX, int gridZ) const {
-  if (!inBounds(gridX, gridZ)) {
-    return 0.0f;
+auto TerrainHeightMap::getHeightAtGrid(int grid_x, int grid_z) const -> float {
+  if (!inBounds(grid_x, grid_z)) {
+    return 0.0F;
   }
-  return m_heights[indexAt(gridX, gridZ)];
+  return m_heights[indexAt(grid_x, grid_z)];
 }
 
-bool TerrainHeightMap::isWalkable(int gridX, int gridZ) const {
-  if (!inBounds(gridX, gridZ)) {
+auto TerrainHeightMap::isWalkable(int grid_x, int grid_z) const -> bool {
+  if (!inBounds(grid_x, grid_z)) {
     return false;
   }
 
-  TerrainType type = m_terrainTypes[indexAt(gridX, gridZ)];
+  TerrainType const type = m_terrain_types[indexAt(grid_x, grid_z)];
 
   if (type == TerrainType::Mountain) {
     return false;
@@ -383,32 +392,34 @@ bool TerrainHeightMap::isWalkable(int gridX, int gridZ) const {
   }
 
   if (type == TerrainType::Hill) {
-    return m_hillWalkable[indexAt(gridX, gridZ)];
+    return m_hillWalkable[indexAt(grid_x, grid_z)];
   }
 
   return true;
 }
 
-bool TerrainHeightMap::isHillEntrance(int gridX, int gridZ) const {
-  if (!inBounds(gridX, gridZ)) {
+auto TerrainHeightMap::isHillEntrance(int grid_x, int grid_z) const -> bool {
+  if (!inBounds(grid_x, grid_z)) {
     return false;
   }
-  return m_hillEntrances[indexAt(gridX, gridZ)];
+  return m_hillEntrances[indexAt(grid_x, grid_z)];
 }
 
-TerrainType TerrainHeightMap::getTerrainType(int gridX, int gridZ) const {
-  if (!inBounds(gridX, gridZ)) {
+auto TerrainHeightMap::getTerrainType(int grid_x,
+                                      int grid_z) const -> TerrainType {
+  if (!inBounds(grid_x, grid_z)) {
     return TerrainType::Flat;
   }
-  return m_terrainTypes[indexAt(gridX, gridZ)];
+  return m_terrain_types[indexAt(grid_x, grid_z)];
 }
 
-bool TerrainHeightMap::isRiverOrNearby(int gridX, int gridZ, int margin) const {
-  if (!inBounds(gridX, gridZ)) {
+auto TerrainHeightMap::isRiverOrNearby(int grid_x, int grid_z,
+                                       int margin) const -> bool {
+  if (!inBounds(grid_x, grid_z)) {
     return false;
   }
 
-  if (m_terrainTypes[indexAt(gridX, gridZ)] == TerrainType::River) {
+  if (m_terrain_types[indexAt(grid_x, grid_z)] == TerrainType::River) {
     return true;
   }
 
@@ -417,10 +428,10 @@ bool TerrainHeightMap::isRiverOrNearby(int gridX, int gridZ, int margin) const {
       if (dx == 0 && dz == 0) {
         continue;
       }
-      int nx = gridX + dx;
-      int nz = gridZ + dz;
+      int const nx = grid_x + dx;
+      int const nz = grid_z + dz;
       if (inBounds(nx, nz) &&
-          m_terrainTypes[indexAt(nx, nz)] == TerrainType::River) {
+          m_terrain_types[indexAt(nx, nz)] == TerrainType::River) {
         return true;
       }
     }
@@ -429,27 +440,28 @@ bool TerrainHeightMap::isRiverOrNearby(int gridX, int gridZ, int margin) const {
   return false;
 }
 
-int TerrainHeightMap::indexAt(int x, int z) const { return z * m_width + x; }
+auto TerrainHeightMap::indexAt(int x, int z) const -> int {
+  return z * m_width + x;
+}
 
-bool TerrainHeightMap::inBounds(int x, int z) const {
+auto TerrainHeightMap::inBounds(int x, int z) const -> bool {
   return x >= 0 && x < m_width && z >= 0 && z < m_height;
 }
 
 float TerrainHeightMap::calculateFeatureHeight(const TerrainFeature &feature,
-                                               float worldX,
-                                               float worldZ) const {
-  float dx = worldX - feature.centerX;
-  float dz = worldZ - feature.centerZ;
-  float dist = std::sqrt(dx * dx + dz * dz);
+                                               float world_x, float world_z) {
+  float const dx = world_x - feature.center_x;
+  float const dz = world_z - feature.center_z;
+  float const dist = std::sqrt(dx * dx + dz * dz);
 
   if (dist > feature.radius) {
-    return 0.0f;
+    return 0.0F;
   }
 
-  float t = dist / feature.radius;
-  float heightFactor = (std::cos(t * M_PI) + 1.0f) * 0.5f;
+  float const t = dist / feature.radius;
+  float const height_factor = (std::cos(t * M_PI) + 1.0F) * 0.5F;
 
-  return feature.height * heightFactor;
+  return feature.height * height_factor;
 }
 
 void TerrainHeightMap::applyBiomeVariation(const BiomeSettings &settings) {
@@ -457,40 +469,40 @@ void TerrainHeightMap::applyBiomeVariation(const BiomeSettings &settings) {
     return;
   }
 
-  const float amplitude = std::max(0.0f, settings.heightNoiseAmplitude);
-  if (amplitude <= 0.0001f) {
+  const float amplitude = std::max(0.0F, settings.heightNoiseAmplitude);
+  if (amplitude <= 0.0001F) {
     return;
   }
 
-  const float frequency = std::max(0.0001f, settings.heightNoiseFrequency);
-  const float halfWidth = m_width * 0.5f - 0.5f;
-  const float halfHeight = m_height * 0.5f - 0.5f;
+  const float frequency = std::max(0.0001F, settings.heightNoiseFrequency);
+  const float half_width = m_width * 0.5F - 0.5F;
+  const float half_height = m_height * 0.5F - 0.5F;
 
   for (int z = 0; z < m_height; ++z) {
     for (int x = 0; x < m_width; ++x) {
-      int idx = indexAt(x, z);
-      TerrainType type = m_terrainTypes[idx];
+      int const idx = indexAt(x, z);
+      TerrainType const type = m_terrain_types[idx];
       if (type == TerrainType::Mountain) {
         continue;
       }
 
-      float worldX = (static_cast<float>(x) - halfWidth) * m_tileSize;
-      float worldZ = (static_cast<float>(z) - halfHeight) * m_tileSize;
-      float sampleX = worldX * frequency;
-      float sampleZ = worldZ * frequency;
+      float const world_x = (static_cast<float>(x) - half_width) * m_tile_size;
+      float const world_z = (static_cast<float>(z) - half_height) * m_tile_size;
+      float const sample_x = world_x * frequency;
+      float const sample_z = world_z * frequency;
 
-      float baseNoise = valueNoise2D(sampleX, sampleZ, settings.seed);
-      float detailNoise = valueNoise2D(sampleX * 2.0f, sampleZ * 2.0f,
-                                       settings.seed ^ 0xA21C9E37u);
+      float const base_noise = valueNoise2D(sample_x, sample_z, settings.seed);
+      float const detail_noise = valueNoise2D(sample_x * 2.0F, sample_z * 2.0F,
+                                              settings.seed ^ 0xA21C9E37U);
 
-      float blended = 0.65f * baseNoise + 0.35f * detailNoise;
-      float perturb = (blended - 0.5f) * 2.0f * amplitude;
+      float const blended = 0.65F * base_noise + 0.35F * detail_noise;
+      float perturb = (blended - 0.5F) * 2.0F * amplitude;
 
       if (type == TerrainType::Hill) {
-        perturb *= 0.6f;
+        perturb *= 0.6F;
       }
 
-      m_heights[idx] = std::max(0.0f, m_heights[idx] + perturb);
+      m_heights[idx] = std::max(0.0F, m_heights[idx] + perturb);
     }
   }
 }
@@ -499,55 +511,57 @@ void TerrainHeightMap::addRiverSegments(
     const std::vector<RiverSegment> &riverSegments) {
   m_riverSegments = riverSegments;
 
-  const float gridHalfWidth = m_width * 0.5f - 0.5f;
-  const float gridHalfHeight = m_height * 0.5f - 0.5f;
+  const float grid_half_width = m_width * 0.5F - 0.5F;
+  const float grid_half_height = m_height * 0.5F - 0.5F;
 
   for (const auto &river : riverSegments) {
     QVector3D dir = river.end - river.start;
-    float length = dir.length();
-    if (length < 0.01f) {
+    float const length = dir.length();
+    if (length < 0.01F) {
       continue;
     }
 
     dir.normalize();
-    QVector3D perpendicular(-dir.z(), 0.0f, dir.x());
+    QVector3D const perpendicular(-dir.z(), 0.0F, dir.x());
 
-    int steps = static_cast<int>(std::ceil(length / m_tileSize)) + 1;
+    int const steps = static_cast<int>(std::ceil(length / m_tile_size)) + 1;
 
     for (int i = 0; i < steps; ++i) {
-      float t =
-          static_cast<float>(i) / std::max(1.0f, static_cast<float>(steps - 1));
-      QVector3D centerPos = river.start + dir * (length * t);
-
-      float gridCenterX = (centerPos.x() / m_tileSize) + gridHalfWidth;
-      float gridCenterZ = (centerPos.z() / m_tileSize) + gridHalfHeight;
-
-      float halfWidth = river.width * 0.5f / m_tileSize;
-
-      int minX = std::max(
-          0, static_cast<int>(std::floor(gridCenterX - halfWidth - 1.0f)));
-      int maxX =
-          std::min(m_width - 1,
-                   static_cast<int>(std::ceil(gridCenterX + halfWidth + 1.0f)));
-      int minZ = std::max(
-          0, static_cast<int>(std::floor(gridCenterZ - halfWidth - 1.0f)));
-      int maxZ =
-          std::min(m_height - 1,
-                   static_cast<int>(std::ceil(gridCenterZ + halfWidth + 1.0f)));
+      float const t =
+          static_cast<float>(i) / std::max(1.0F, static_cast<float>(steps - 1));
+      QVector3D const center_pos = river.start + dir * (length * t);
+
+      float const grid_center_x =
+          (center_pos.x() / m_tile_size) + grid_half_width;
+      float const grid_center_z =
+          (center_pos.z() / m_tile_size) + grid_half_height;
+
+      float const half_width = river.width * 0.5F / m_tile_size;
+
+      int const minX = std::max(
+          0, static_cast<int>(std::floor(grid_center_x - half_width - 1.0F)));
+      int const maxX = std::min(
+          m_width - 1,
+          static_cast<int>(std::ceil(grid_center_x + half_width + 1.0F)));
+      int const minZ = std::max(
+          0, static_cast<int>(std::floor(grid_center_z - half_width - 1.0F)));
+      int const maxZ = std::min(
+          m_height - 1,
+          static_cast<int>(std::ceil(grid_center_z + half_width + 1.0F)));
 
       for (int z = minZ; z <= maxZ; ++z) {
         for (int x = minX; x <= maxX; ++x) {
-          float dx = static_cast<float>(x) - gridCenterX;
-          float dz = static_cast<float>(z) - gridCenterZ;
+          float const dx = static_cast<float>(x) - grid_center_x;
+          float const dz = static_cast<float>(z) - grid_center_z;
 
-          float distAlongPerp =
+          float const dist_along_perp =
               std::abs(dx * perpendicular.x() + dz * perpendicular.z());
 
-          if (distAlongPerp <= halfWidth) {
-            int idx = indexAt(x, z);
-            if (m_terrainTypes[idx] != TerrainType::Mountain) {
-              m_terrainTypes[idx] = TerrainType::River;
-              m_heights[idx] = 0.0f;
+          if (dist_along_perp <= half_width) {
+            int const idx = indexAt(x, z);
+            if (m_terrain_types[idx] != TerrainType::Mountain) {
+              m_terrain_types[idx] = TerrainType::River;
+              m_heights[idx] = 0.0F;
             }
           }
         }
@@ -559,59 +573,63 @@ void TerrainHeightMap::addRiverSegments(
 void TerrainHeightMap::addBridges(const std::vector<Bridge> &bridges) {
   m_bridges = bridges;
 
-  const float gridHalfWidth = m_width * 0.5f - 0.5f;
-  const float gridHalfHeight = m_height * 0.5f - 0.5f;
+  const float grid_half_width = m_width * 0.5F - 0.5F;
+  const float grid_half_height = m_height * 0.5F - 0.5F;
 
   for (const auto &bridge : bridges) {
     QVector3D dir = bridge.end - bridge.start;
-    float length = dir.length();
-    if (length < 0.01f) {
+    float const length = dir.length();
+    if (length < 0.01F) {
       continue;
     }
 
     dir.normalize();
-    QVector3D perpendicular(-dir.z(), 0.0f, dir.x());
+    QVector3D const perpendicular(-dir.z(), 0.0F, dir.x());
 
-    int steps = static_cast<int>(std::ceil(length / m_tileSize)) + 1;
+    int const steps = static_cast<int>(std::ceil(length / m_tile_size)) + 1;
 
     for (int i = 0; i < steps; ++i) {
-      float t =
-          static_cast<float>(i) / std::max(1.0f, static_cast<float>(steps - 1));
-      QVector3D centerPos = bridge.start + dir * (length * t);
-
-      float archCurve = 4.0f * t * (1.0f - t);
-      float archHeight = bridge.height * archCurve * 0.8f;
-      float deckHeight = bridge.start.y() + bridge.height + archHeight * 0.5f;
-
-      float gridCenterX = (centerPos.x() / m_tileSize) + gridHalfWidth;
-      float gridCenterZ = (centerPos.z() / m_tileSize) + gridHalfHeight;
-
-      float halfWidth = bridge.width * 0.5f / m_tileSize;
-
-      int minX =
-          std::max(0, static_cast<int>(std::floor(gridCenterX - halfWidth)));
-      int maxX = std::min(m_width - 1,
-                          static_cast<int>(std::ceil(gridCenterX + halfWidth)));
-      int minZ =
-          std::max(0, static_cast<int>(std::floor(gridCenterZ - halfWidth)));
-      int maxZ = std::min(m_height - 1,
-                          static_cast<int>(std::ceil(gridCenterZ + halfWidth)));
+      float const t =
+          static_cast<float>(i) / std::max(1.0F, static_cast<float>(steps - 1));
+      QVector3D const center_pos = bridge.start + dir * (length * t);
+
+      float const arch_curve = 4.0F * t * (1.0F - t);
+      float const arch_height = bridge.height * arch_curve * 0.8F;
+      float const deck_height =
+          bridge.start.y() + bridge.height + arch_height * 0.5F;
+
+      float const grid_center_x =
+          (center_pos.x() / m_tile_size) + grid_half_width;
+      float const grid_center_z =
+          (center_pos.z() / m_tile_size) + grid_half_height;
+
+      float const half_width = bridge.width * 0.5F / m_tile_size;
+
+      int const minX =
+          std::max(0, static_cast<int>(std::floor(grid_center_x - half_width)));
+      int const maxX = std::min(
+          m_width - 1, static_cast<int>(std::ceil(grid_center_x + half_width)));
+      int const minZ =
+          std::max(0, static_cast<int>(std::floor(grid_center_z - half_width)));
+      int const maxZ =
+          std::min(m_height - 1,
+                   static_cast<int>(std::ceil(grid_center_z + half_width)));
 
       for (int z = minZ; z <= maxZ; ++z) {
         for (int x = minX; x <= maxX; ++x) {
-          float dx = static_cast<float>(x) - gridCenterX;
-          float dz = static_cast<float>(z) - gridCenterZ;
+          float const dx = static_cast<float>(x) - grid_center_x;
+          float const dz = static_cast<float>(z) - grid_center_z;
 
-          float distAlongPerp =
+          float const dist_along_perp =
               std::abs(dx * perpendicular.x() + dz * perpendicular.z());
 
-          if (distAlongPerp <= halfWidth) {
-            int idx = indexAt(x, z);
+          if (dist_along_perp <= half_width) {
+            int const idx = indexAt(x, z);
 
-            if (m_terrainTypes[idx] == TerrainType::River) {
-              m_terrainTypes[idx] = TerrainType::Flat;
+            if (m_terrain_types[idx] == TerrainType::River) {
+              m_terrain_types[idx] = TerrainType::Flat;
 
-              m_heights[idx] = deckHeight;
+              m_heights[idx] = deck_height;
             }
           }
         }
@@ -622,27 +640,27 @@ void TerrainHeightMap::addBridges(const std::vector<Bridge> &bridges) {
 
 void TerrainHeightMap::restoreFromData(
     const std::vector<float> &heights,
-    const std::vector<TerrainType> &terrainTypes,
+    const std::vector<TerrainType> &terrain_types,
     const std::vector<RiverSegment> &rivers,
     const std::vector<Bridge> &bridges) {
 
-  const size_t expectedSize = static_cast<size_t>(m_width * m_height);
+  const auto expected_size = static_cast<size_t>(m_width * m_height);
 
-  if (heights.size() == expectedSize) {
+  if (heights.size() == expected_size) {
     m_heights = heights;
   }
 
-  if (terrainTypes.size() == expectedSize) {
-    m_terrainTypes = terrainTypes;
+  if (terrain_types.size() == expected_size) {
+    m_terrain_types = terrain_types;
   }
 
   m_hillEntrances.clear();
-  m_hillEntrances.resize(expectedSize, false);
+  m_hillEntrances.resize(expected_size, false);
   m_hillWalkable.clear();
-  m_hillWalkable.resize(expectedSize, true);
+  m_hillWalkable.resize(expected_size, true);
 
-  for (size_t i = 0; i < m_terrainTypes.size(); ++i) {
-    if (m_terrainTypes[i] == TerrainType::Hill) {
+  for (size_t i = 0; i < m_terrain_types.size(); ++i) {
+    if (m_terrain_types[i] == TerrainType::Hill) {
       m_hillWalkable[i] = false;
     }
   }

+ 77 - 67
game/map/terrain.h

@@ -12,7 +12,7 @@ namespace Game::Map {
 
 enum class TerrainType { Flat, Hill, Mountain, River };
 
-inline QString terrainTypeToQString(TerrainType type) {
+inline auto terrainTypeToQString(TerrainType type) -> QString {
   switch (type) {
   case TerrainType::Flat:
     return QStringLiteral("flat");
@@ -26,11 +26,12 @@ inline QString terrainTypeToQString(TerrainType type) {
   return QStringLiteral("flat");
 }
 
-inline std::string terrainTypeToString(TerrainType type) {
+inline auto terrainTypeToString(TerrainType type) -> std::string {
   return terrainTypeToQString(type).toStdString();
 }
 
-inline bool tryParseTerrainType(const QString &value, TerrainType &out) {
+inline auto tryParseTerrainType(const QString &value,
+                                TerrainType &out) -> bool {
   const QString lowered = value.trimmed().toLower();
   if (lowered == QStringLiteral("flat")) {
     out = TerrainType::Flat;
@@ -51,8 +52,8 @@ inline bool tryParseTerrainType(const QString &value, TerrainType &out) {
   return false;
 }
 
-inline std::optional<TerrainType>
-terrainTypeFromString(const std::string &str) {
+inline auto
+terrainTypeFromString(const std::string &str) -> std::optional<TerrainType> {
   TerrainType result;
   if (tryParseTerrainType(QString::fromStdString(str), result)) {
     return result;
@@ -61,124 +62,133 @@ terrainTypeFromString(const std::string &str) {
 }
 
 struct BiomeSettings {
-  QVector3D grassPrimary{0.30f, 0.60f, 0.28f};
-  QVector3D grassSecondary{0.44f, 0.70f, 0.32f};
-  QVector3D grassDry{0.72f, 0.66f, 0.48f};
-  QVector3D soilColor{0.28f, 0.24f, 0.18f};
-  QVector3D rockLow{0.48f, 0.46f, 0.44f};
-  QVector3D rockHigh{0.68f, 0.69f, 0.73f};
-  float patchDensity = 4.5f;
-  float patchJitter = 0.95f;
-  float backgroundBladeDensity = 0.65f;
-  float bladeHeightMin = 0.55f;
-  float bladeHeightMax = 1.35f;
-  float bladeWidthMin = 0.025f;
-  float bladeWidthMax = 0.055f;
-  float swayStrength = 0.25f;
-  float swaySpeed = 1.4f;
-  float heightNoiseAmplitude = 0.16f;
-  float heightNoiseFrequency = 0.05f;
-  float terrainMacroNoiseScale = 0.035f;
-  float terrainDetailNoiseScale = 0.14f;
-  float terrainSoilHeight = 0.6f;
-  float terrainSoilSharpness = 3.8f;
-  float terrainRockThreshold = 0.42f;
-  float terrainRockSharpness = 3.1f;
-  float terrainAmbientBoost = 1.08f;
-  float terrainRockDetailStrength = 0.35f;
-  float backgroundSwayVariance = 0.2f;
-  float backgroundScatterRadius = 0.35f;
-  float plantDensity = 0.5f;
-  float spawnEdgePadding = 0.08f;
-  std::uint32_t seed = 1337u;
+  QVector3D grassPrimary{0.30F, 0.60F, 0.28F};
+  QVector3D grassSecondary{0.44F, 0.70F, 0.32F};
+  QVector3D grassDry{0.72F, 0.66F, 0.48F};
+  QVector3D soilColor{0.28F, 0.24F, 0.18F};
+  QVector3D rockLow{0.48F, 0.46F, 0.44F};
+  QVector3D rockHigh{0.68F, 0.69F, 0.73F};
+  float patchDensity = 4.5F;
+  float patchJitter = 0.95F;
+  float backgroundBladeDensity = 0.65F;
+  float bladeHeightMin = 0.55F;
+  float bladeHeightMax = 1.35F;
+  float bladeWidthMin = 0.025F;
+  float bladeWidthMax = 0.055F;
+  float sway_strength = 0.25F;
+  float sway_speed = 1.4F;
+  float heightNoiseAmplitude = 0.16F;
+  float heightNoiseFrequency = 0.05F;
+  float terrainMacroNoiseScale = 0.035F;
+  float terrainDetailNoiseScale = 0.14F;
+  float terrainSoilHeight = 0.6F;
+  float terrainSoilSharpness = 3.8F;
+  float terrainRockThreshold = 0.42F;
+  float terrainRockSharpness = 3.1F;
+  float terrainAmbientBoost = 1.08F;
+  float terrainRockDetailStrength = 0.35F;
+  float backgroundSwayVariance = 0.2F;
+  float backgroundScatterRadius = 0.35F;
+  float plant_density = 0.5F;
+  float spawnEdgePadding = 0.08F;
+  std::uint32_t seed = 1337U;
 };
 
 struct TerrainFeature {
   TerrainType type;
-  float centerX;
-  float centerZ;
-  float radius;
-  float width;
-  float depth;
-  float height;
+  float center_x{};
+  float center_z{};
+  float radius{};
+  float width{};
+  float depth{};
+  float height{};
 
   std::vector<QVector3D> entrances;
 
-  float rotationDeg = 0.0f;
+  float rotationDeg = 0.0F;
 };
 
 struct RiverSegment {
   QVector3D start;
   QVector3D end;
-  float width = 2.0f;
+  float width = 2.0F;
 };
 
 struct Bridge {
   QVector3D start;
   QVector3D end;
-  float width = 3.0f;
-  float height = 0.5f;
+  float width = 3.0F;
+  float height = 0.5F;
 };
 
 class TerrainHeightMap {
 public:
-  TerrainHeightMap(int width, int height, float tileSize);
+  TerrainHeightMap(int width, int height, float tile_size);
 
   void buildFromFeatures(const std::vector<TerrainFeature> &features);
 
   void addRiverSegments(const std::vector<RiverSegment> &riverSegments);
 
-  float getHeightAt(float worldX, float worldZ) const;
+  [[nodiscard]] auto getHeightAt(float world_x, float world_z) const -> float;
 
-  float getHeightAtGrid(int gridX, int gridZ) const;
+  [[nodiscard]] auto getHeightAtGrid(int grid_x, int grid_z) const -> float;
 
-  bool isWalkable(int gridX, int gridZ) const;
+  [[nodiscard]] auto isWalkable(int grid_x, int grid_z) const -> bool;
 
-  bool isHillEntrance(int gridX, int gridZ) const;
+  [[nodiscard]] auto isHillEntrance(int grid_x, int grid_z) const -> bool;
 
-  TerrainType getTerrainType(int gridX, int gridZ) const;
+  [[nodiscard]] auto getTerrainType(int grid_x,
+                                    int grid_z) const -> TerrainType;
 
-  bool isRiverOrNearby(int gridX, int gridZ, int margin = 1) const;
+  [[nodiscard]] auto isRiverOrNearby(int grid_x, int grid_z,
+                                     int margin = 1) const -> bool;
 
-  int getWidth() const { return m_width; }
-  int getHeight() const { return m_height; }
-  float getTileSize() const { return m_tileSize; }
+  [[nodiscard]] auto getWidth() const -> int { return m_width; }
+  [[nodiscard]] auto getHeight() const -> int { return m_height; }
+  [[nodiscard]] auto getTileSize() const -> float { return m_tile_size; }
 
-  const std::vector<float> &getHeightData() const { return m_heights; }
-  const std::vector<TerrainType> &getTerrainTypes() const {
-    return m_terrainTypes;
+  [[nodiscard]] auto getHeightData() const -> const std::vector<float> & {
+    return m_heights;
   }
-  const std::vector<RiverSegment> &getRiverSegments() const {
+  [[nodiscard]] auto
+  getTerrainTypes() const -> const std::vector<TerrainType> & {
+    return m_terrain_types;
+  }
+  [[nodiscard]] auto
+  getRiverSegments() const -> const std::vector<RiverSegment> & {
     return m_riverSegments;
   }
 
   void addBridges(const std::vector<Bridge> &bridges);
-  const std::vector<Bridge> &getBridges() const { return m_bridges; }
+  [[nodiscard]] auto getBridges() const -> const std::vector<Bridge> & {
+    return m_bridges;
+  }
 
   void applyBiomeVariation(const BiomeSettings &settings);
 
   void restoreFromData(const std::vector<float> &heights,
-                       const std::vector<TerrainType> &terrainTypes,
+                       const std::vector<TerrainType> &terrain_types,
                        const std::vector<RiverSegment> &rivers,
                        const std::vector<Bridge> &bridges);
 
 private:
   int m_width;
   int m_height;
-  float m_tileSize;
+  float m_tile_size;
 
   std::vector<float> m_heights;
-  std::vector<TerrainType> m_terrainTypes;
+  std::vector<TerrainType> m_terrain_types;
   std::vector<bool> m_hillEntrances;
   std::vector<bool> m_hillWalkable;
   std::vector<RiverSegment> m_riverSegments;
   std::vector<Bridge> m_bridges;
 
-  int indexAt(int x, int z) const;
-  bool inBounds(int x, int z) const;
+  [[nodiscard]] auto indexAt(int x, int z) const -> int;
+  [[nodiscard]] auto inBounds(int x, int z) const -> bool;
 
-  float calculateFeatureHeight(const TerrainFeature &feature, float worldX,
-                               float worldZ) const;
+  [[nodiscard]] static auto
+  calculateFeatureHeight(const TerrainFeature &feature, float world_x,
+                         float world_z) -> float;
 };
 
 } // namespace Game::Map

+ 72 - 53
game/map/terrain_service.cpp

@@ -1,114 +1,133 @@
 #include "terrain_service.h"
+
 #include "../systems/building_collision_registry.h"
 #include "map_definition.h"
+#include "terrain.h"
+
 #include <cmath>
+#include <memory>
+#include <vector>
 
 namespace Game::Map {
 
-TerrainService &TerrainService::instance() {
+auto TerrainService::instance() -> TerrainService & {
   static TerrainService s_instance;
   return s_instance;
 }
 
 void TerrainService::initialize(const MapDefinition &mapDef) {
-  m_heightMap = std::make_unique<TerrainHeightMap>(
-      mapDef.grid.width, mapDef.grid.height, mapDef.grid.tileSize);
+  m_height_map = std::make_unique<TerrainHeightMap>(
+      mapDef.grid.width, mapDef.grid.height, mapDef.grid.tile_size);
 
-  m_heightMap->buildFromFeatures(mapDef.terrain);
-  m_heightMap->addRiverSegments(mapDef.rivers);
-  m_heightMap->addBridges(mapDef.bridges);
+  m_height_map->buildFromFeatures(mapDef.terrain);
+  m_height_map->addRiverSegments(mapDef.rivers);
+  m_height_map->addBridges(mapDef.bridges);
   m_biomeSettings = mapDef.biome;
-  m_heightMap->applyBiomeVariation(m_biomeSettings);
-  m_fireCamps = mapDef.firecamps;
+  m_height_map->applyBiomeVariation(m_biomeSettings);
+  m_fire_camps = mapDef.firecamps;
 }
 
 void TerrainService::clear() {
-  m_heightMap.reset();
+  m_height_map.reset();
   m_biomeSettings = BiomeSettings();
-  m_fireCamps.clear();
+  m_fire_camps.clear();
 }
 
-float TerrainService::getTerrainHeight(float worldX, float worldZ) const {
-  if (!m_heightMap) {
-    return 0.0f;
+auto TerrainService::getTerrainHeight(float world_x,
+                                      float world_z) const -> float {
+  if (!m_height_map) {
+    return 0.0F;
   }
-  return m_heightMap->getHeightAt(worldX, worldZ);
+  return m_height_map->getHeightAt(world_x, world_z);
 }
 
-float TerrainService::getTerrainHeightGrid(int gridX, int gridZ) const {
-  if (!m_heightMap) {
-    return 0.0f;
+auto TerrainService::getTerrainHeightGrid(int grid_x,
+                                          int grid_z) const -> float {
+  if (!m_height_map) {
+    return 0.0F;
   }
-  return m_heightMap->getHeightAtGrid(gridX, gridZ);
+  return m_height_map->getHeightAtGrid(grid_x, grid_z);
 }
 
-bool TerrainService::isWalkable(int gridX, int gridZ) const {
-  if (!m_heightMap) {
+auto TerrainService::isWalkable(int grid_x, int grid_z) const -> bool {
+  if (!m_height_map) {
     return true;
   }
-  return m_heightMap->isWalkable(gridX, gridZ);
+  return m_height_map->isWalkable(grid_x, grid_z);
 }
 
-bool TerrainService::isForbidden(int gridX, int gridZ) const {
-  if (!m_heightMap) {
+auto TerrainService::isForbidden(int grid_x, int grid_z) const -> bool {
+  if (!m_height_map) {
     return false;
   }
 
-  if (!m_heightMap->isWalkable(gridX, gridZ)) {
+  if (!m_height_map->isWalkable(grid_x, grid_z)) {
     return true;
   }
 
-  float halfW = m_heightMap->getWidth() * 0.5f - 0.5f;
-  float halfH = m_heightMap->getHeight() * 0.5f - 0.5f;
-  const float tile = m_heightMap->getTileSize();
-  float worldX = (static_cast<float>(gridX) - halfW) * tile;
-  float worldZ = (static_cast<float>(gridZ) - halfH) * tile;
+  constexpr float k_half_cell_offset = 0.5F;
 
-  auto &registry = Game::Systems::BuildingCollisionRegistry::instance();
-  if (registry.isPointInBuilding(worldX, worldZ)) {
-    return true;
-  }
+  const float half_width =
+      static_cast<float>(m_height_map->getWidth()) * k_half_cell_offset -
+      k_half_cell_offset;
+  const float half_height =
+      static_cast<float>(m_height_map->getHeight()) * k_half_cell_offset -
+      k_half_cell_offset;
+  const float tile_size = m_height_map->getTileSize();
 
-  return false;
+  const float world_x = (static_cast<float>(grid_x) - half_width) * tile_size;
+  const float world_z = (static_cast<float>(grid_z) - half_height) * tile_size;
+
+  auto &registry = Game::Systems::BuildingCollisionRegistry::instance();
+  return registry.isPointInBuilding(world_x, world_z);
 }
 
-bool TerrainService::isForbiddenWorld(float worldX, float worldZ) const {
-  if (!m_heightMap) {
+auto TerrainService::isForbiddenWorld(float world_x,
+                                      float world_z) const -> bool {
+  if (!m_height_map) {
     return false;
   }
 
-  const float gridHalfWidth = m_heightMap->getWidth() * 0.5f - 0.5f;
-  const float gridHalfHeight = m_heightMap->getHeight() * 0.5f - 0.5f;
+  constexpr float k_half_cell_offset = 0.5F;
+
+  const float grid_half_width =
+      static_cast<float>(m_height_map->getWidth()) * k_half_cell_offset -
+      k_half_cell_offset;
+  const float grid_half_height =
+      static_cast<float>(m_height_map->getHeight()) * k_half_cell_offset -
+      k_half_cell_offset;
+
+  const float grid_x = world_x / m_height_map->getTileSize() + grid_half_width;
+  const float grid_z = world_z / m_height_map->getTileSize() + grid_half_height;
 
-  float gx = worldX / m_heightMap->getTileSize() + gridHalfWidth;
-  float gz = worldZ / m_heightMap->getTileSize() + gridHalfHeight;
+  const int grid_x_int = static_cast<int>(std::round(grid_x));
+  const int grid_z_int = static_cast<int>(std::round(grid_z));
 
-  int ix = static_cast<int>(std::round(gx));
-  int iz = static_cast<int>(std::round(gz));
-  return isForbidden(ix, iz);
+  return isForbidden(grid_x_int, grid_z_int);
 }
 
-bool TerrainService::isHillEntrance(int gridX, int gridZ) const {
-  if (!m_heightMap) {
+auto TerrainService::isHillEntrance(int grid_x, int grid_z) const -> bool {
+  if (!m_height_map) {
     return false;
   }
-  return m_heightMap->isHillEntrance(gridX, gridZ);
+  return m_height_map->isHillEntrance(grid_x, grid_z);
 }
 
-TerrainType TerrainService::getTerrainType(int gridX, int gridZ) const {
-  if (!m_heightMap) {
+auto TerrainService::getTerrainType(int grid_x,
+                                    int grid_z) const -> TerrainType {
+  if (!m_height_map) {
     return TerrainType::Flat;
   }
-  return m_heightMap->getTerrainType(gridX, gridZ);
+  return m_height_map->getTerrainType(grid_x, grid_z);
 }
 
 void TerrainService::restoreFromSerialized(
-    int width, int height, float tileSize, const std::vector<float> &heights,
-    const std::vector<TerrainType> &terrainTypes,
+    int width, int height, float tile_size, const std::vector<float> &heights,
+    const std::vector<TerrainType> &terrain_types,
     const std::vector<RiverSegment> &rivers, const std::vector<Bridge> &bridges,
     const BiomeSettings &biome) {
-  m_heightMap = std::make_unique<TerrainHeightMap>(width, height, tileSize);
-  m_heightMap->restoreFromData(heights, terrainTypes, rivers, bridges);
+  m_height_map = std::make_unique<TerrainHeightMap>(width, height, tile_size);
+  m_height_map->restoreFromData(heights, terrain_types, rivers, bridges);
   m_biomeSettings = biome;
 }
 

+ 29 - 17
game/map/terrain_service.h

@@ -11,37 +11,49 @@ struct FireCamp;
 
 class TerrainService {
 public:
-  static TerrainService &instance();
+  static auto instance() -> TerrainService &;
 
   void initialize(const MapDefinition &mapDef);
 
   void clear();
 
-  float getTerrainHeight(float worldX, float worldZ) const;
+  [[nodiscard]] auto getTerrainHeight(float world_x,
+                                      float world_z) const -> float;
 
-  float getTerrainHeightGrid(int gridX, int gridZ) const;
+  [[nodiscard]] auto getTerrainHeightGrid(int grid_x,
+                                          int grid_z) const -> float;
 
-  bool isWalkable(int gridX, int gridZ) const;
+  [[nodiscard]] auto isWalkable(int grid_x, int grid_z) const -> bool;
 
-  bool isHillEntrance(int gridX, int gridZ) const;
+  [[nodiscard]] auto isHillEntrance(int grid_x, int grid_z) const -> bool;
 
-  bool isForbidden(int gridX, int gridZ) const;
+  [[nodiscard]] auto isForbidden(int grid_x, int grid_z) const -> bool;
 
-  bool isForbiddenWorld(float worldX, float worldZ) const;
+  [[nodiscard]] auto isForbiddenWorld(float world_x,
+                                      float world_z) const -> bool;
 
-  TerrainType getTerrainType(int gridX, int gridZ) const;
+  [[nodiscard]] auto getTerrainType(int grid_x,
+                                    int grid_z) const -> TerrainType;
 
-  const TerrainHeightMap *getHeightMap() const { return m_heightMap.get(); }
+  [[nodiscard]] auto getHeightMap() const -> const TerrainHeightMap * {
+    return m_height_map.get();
+  }
 
-  const BiomeSettings &biomeSettings() const { return m_biomeSettings; }
+  [[nodiscard]] auto biomeSettings() const -> const BiomeSettings & {
+    return m_biomeSettings;
+  }
 
-  const std::vector<FireCamp> &fireCamps() const { return m_fireCamps; }
+  [[nodiscard]] auto fire_camps() const -> const std::vector<FireCamp> & {
+    return m_fire_camps;
+  }
 
-  bool isInitialized() const { return m_heightMap != nullptr; }
+  [[nodiscard]] auto isInitialized() const -> bool {
+    return m_height_map != nullptr;
+  }
 
-  void restoreFromSerialized(int width, int height, float tileSize,
+  void restoreFromSerialized(int width, int height, float tile_size,
                              const std::vector<float> &heights,
-                             const std::vector<TerrainType> &terrainTypes,
+                             const std::vector<TerrainType> &terrain_types,
                              const std::vector<RiverSegment> &rivers,
                              const std::vector<Bridge> &bridges,
                              const BiomeSettings &biome);
@@ -51,11 +63,11 @@ private:
   ~TerrainService() = default;
 
   TerrainService(const TerrainService &) = delete;
-  TerrainService &operator=(const TerrainService &) = delete;
+  auto operator=(const TerrainService &) -> TerrainService & = delete;
 
-  std::unique_ptr<TerrainHeightMap> m_heightMap;
+  std::unique_ptr<TerrainHeightMap> m_height_map;
   BiomeSettings m_biomeSettings;
-  std::vector<FireCamp> m_fireCamps;
+  std::vector<FireCamp> m_fire_camps;
 };
 
 } // namespace Game::Map

+ 131 - 105
game/map/visibility_service.cpp

@@ -4,38 +4,56 @@
 #include "../core/ownership_constants.h"
 #include "../core/world.h"
 #include "../systems/owner_registry.h"
+
 #include <algorithm>
+#include <atomic>
+#include <chrono>
 #include <cmath>
+#include <cstdint>
+#include <future>
+#include <mutex>
+#include <shared_mutex>
+#include <utility>
+#include <vector>
 
 namespace Game::Map {
 
 namespace {
-constexpr float kDefaultVisionRange = 12.0f;
 
-bool inBoundsStatic(int x, int z, int width, int height) {
-  return x >= 0 && x < width && z >= 0 && z < height;
+constexpr float k_default_vision_range = 12.0F;
+constexpr float k_half_cell_offset = 0.5F;
+constexpr float k_min_tile_size = 0.0001F;
+
+auto inBoundsStatic(int grid_x, int grid_z, int width, int height) -> bool {
+  return grid_x >= 0 && grid_x < width && grid_z >= 0 && grid_z < height;
 }
 
-int indexStatic(int x, int z, int width) { return z * width + x; }
+auto indexStatic(int grid_x, int grid_z, int width) -> int {
+  return grid_z * width + grid_x;
+}
 
-int worldToGridStatic(float worldCoord, float half, float tileSize) {
-  float gridCoord = worldCoord / tileSize + half;
-  return static_cast<int>(std::floor(gridCoord + 0.5f));
+auto worldToGridStatic(float world_coord, float half, float tile_size) -> int {
+  const float grid_coord = world_coord / tile_size + half;
+  return static_cast<int>(std::floor(grid_coord + k_half_cell_offset));
 }
+
 } // namespace
 
-VisibilityService &VisibilityService::instance() {
+auto VisibilityService::instance() -> VisibilityService & {
   static VisibilityService s_instance;
   return s_instance;
 }
 
-void VisibilityService::initialize(int width, int height, float tileSize) {
-  std::unique_lock lock(m_cellsMutex);
+void VisibilityService::initialize(int width, int height, float tile_size) {
+  std::unique_lock<std::shared_mutex> const lock(m_cellsMutex);
   m_width = std::max(1, width);
   m_height = std::max(1, height);
-  m_tileSize = std::max(0.0001f, tileSize);
-  m_halfWidth = m_width * 0.5f - 0.5f;
-  m_halfHeight = m_height * 0.5f - 0.5f;
+  m_tile_size = std::max(k_min_tile_size, tile_size);
+  m_half_width =
+      static_cast<float>(m_width) * k_half_cell_offset - k_half_cell_offset;
+  m_half_height =
+      static_cast<float>(m_height) * k_half_cell_offset - k_half_cell_offset;
+
   const int count = m_width * m_height;
   m_cells.assign(count, static_cast<std::uint8_t>(VisibilityState::Unseen));
   m_version.store(1, std::memory_order_release);
@@ -47,21 +65,22 @@ void VisibilityService::reset() {
   if (!m_initialized) {
     return;
   }
-  std::unique_lock lock(m_cellsMutex);
+  std::unique_lock<std::shared_mutex> const lock(m_cellsMutex);
   std::fill(m_cells.begin(), m_cells.end(),
             static_cast<std::uint8_t>(VisibilityState::Unseen));
   m_version.fetch_add(1, std::memory_order_release);
 }
 
-bool VisibilityService::update(Engine::Core::World &world, int playerId) {
+auto VisibilityService::update(Engine::Core::World &world,
+                               int player_id) -> bool {
   if (!m_initialized) {
     return false;
   }
 
-  bool integrated = integrateCompletedJob();
+  const bool integrated = integrateCompletedJob();
 
   if (!m_jobActive.load(std::memory_order_acquire)) {
-    auto sources = gatherVisionSources(world, playerId);
+    const auto sources = gatherVisionSources(world, player_id);
     auto payload = composeJobPayload(sources);
     startAsyncJob(std::move(payload));
   }
@@ -70,44 +89,45 @@ bool VisibilityService::update(Engine::Core::World &world, int playerId) {
 }
 
 void VisibilityService::computeImmediate(Engine::Core::World &world,
-                                         int playerId) {
+                                         int player_id) {
   if (!m_initialized) {
     return;
   }
 
-  auto sources = gatherVisionSources(world, playerId);
+  const auto sources = gatherVisionSources(world, player_id);
   auto payload = composeJobPayload(sources);
   auto result = executeJob(std::move(payload));
 
   if (result.changed) {
-    std::unique_lock lock(m_cellsMutex);
+    std::unique_lock<std::shared_mutex> const lock(m_cellsMutex);
     m_cells = std::move(result.cells);
     m_version.fetch_add(1, std::memory_order_release);
   }
 }
 
-std::vector<VisibilityService::VisionSource>
-VisibilityService::gatherVisionSources(Engine::Core::World &world,
-                                       int playerId) const {
+auto VisibilityService::gatherVisionSources(Engine::Core::World &world,
+                                            int player_id) const
+    -> std::vector<VisibilityService::VisionSource> {
   std::vector<VisionSource> sources;
-  auto entities = world.getEntitiesWith<Engine::Core::TransformComponent>();
-  const float rangePadding = m_tileSize * 0.5f;
+  const auto entities =
+      world.getEntitiesWith<Engine::Core::TransformComponent>();
+  const float range_padding = m_tile_size * k_half_cell_offset;
 
-  auto &ownerRegistry = Game::Systems::OwnerRegistry::instance();
+  auto &owner_registry = Game::Systems::OwnerRegistry::instance();
 
   for (auto *entity : entities) {
     auto *transform = entity->getComponent<Engine::Core::TransformComponent>();
     auto *unit = entity->getComponent<Engine::Core::UnitComponent>();
-    if (!transform || !unit) {
+    if (transform == nullptr || unit == nullptr) {
       continue;
     }
 
-    if (Game::Core::isNeutralOwner(unit->ownerId)) {
+    if (Game::Core::isNeutralOwner(unit->owner_id)) {
       continue;
     }
 
-    if (unit->ownerId != playerId &&
-        !ownerRegistry.areAllies(playerId, unit->ownerId)) {
+    if (unit->owner_id != player_id &&
+        !owner_registry.areAllies(player_id, unit->owner_id)) {
       continue;
     }
 
@@ -115,30 +135,33 @@ VisibilityService::gatherVisionSources(Engine::Core::World &world,
       continue;
     }
 
-    const float visionRange = std::max(unit->visionRange, kDefaultVisionRange);
-    const int centerX = worldToGrid(transform->position.x, m_halfWidth);
-    const int centerZ = worldToGrid(transform->position.z, m_halfHeight);
-    if (!inBounds(centerX, centerZ)) {
+    const float vision_range =
+        std::max(unit->vision_range, k_default_vision_range);
+    const int center_x = worldToGrid(transform->position.x, m_half_width);
+    const int center_z = worldToGrid(transform->position.z, m_half_height);
+    if (!inBounds(center_x, center_z)) {
       continue;
     }
 
-    const int cellRadius =
-        std::max(1, static_cast<int>(std::ceil(visionRange / m_tileSize)));
-    const float expandedRangeSq =
-        (visionRange + rangePadding) * (visionRange + rangePadding);
+    const int cell_radius =
+        std::max(1, static_cast<int>(std::ceil(vision_range / m_tile_size)));
+    const float expanded_range_sq =
+        (vision_range + range_padding) * (vision_range + range_padding);
 
-    sources.push_back({centerX, centerZ, cellRadius, expandedRangeSq});
+    sources.push_back({center_x, center_z, cell_radius, expanded_range_sq});
   }
 
   return sources;
 }
 
-VisibilityService::JobPayload VisibilityService::composeJobPayload(
-    const std::vector<VisionSource> &sources) const {
-  std::shared_lock lock(m_cellsMutex);
-  const auto gen = const_cast<std::atomic<std::uint64_t> &>(m_generation)
-                       .fetch_add(1, std::memory_order_relaxed);
-  return JobPayload{m_width, m_height, m_tileSize, m_cells, sources, gen};
+auto VisibilityService::composeJobPayload(
+    const std::vector<VisionSource> &sources) const
+    -> VisibilityService::JobPayload {
+  std::shared_lock<std::shared_mutex> const lock(m_cellsMutex);
+  const auto generation_value =
+      m_generation.fetch_add(1ULL, std::memory_order_relaxed);
+  return JobPayload{m_width, m_height, m_tile_size,
+                    m_cells, sources,  generation_value};
 }
 
 void VisibilityService::startAsyncJob(JobPayload &&payload) {
@@ -146,7 +169,7 @@ void VisibilityService::startAsyncJob(JobPayload &&payload) {
   m_pendingJob = std::async(std::launch::async, executeJob, std::move(payload));
 }
 
-bool VisibilityService::integrateCompletedJob() {
+auto VisibilityService::integrateCompletedJob() -> bool {
   if (!m_jobActive.load(std::memory_order_acquire)) {
     return false;
   }
@@ -160,7 +183,7 @@ bool VisibilityService::integrateCompletedJob() {
   m_jobActive.store(false, std::memory_order_release);
 
   if (result.changed) {
-    std::unique_lock lock(m_cellsMutex);
+    std::unique_lock<std::shared_mutex> const lock(m_cellsMutex);
     m_cells = std::move(result.cells);
     m_version.fetch_add(1, std::memory_order_release);
     return true;
@@ -169,110 +192,113 @@ bool VisibilityService::integrateCompletedJob() {
   return false;
 }
 
-VisibilityService::JobResult VisibilityService::executeJob(JobPayload payload) {
-  const int count = payload.width * payload.height;
-  std::vector<std::uint8_t> currentVisible(count, 0);
+auto VisibilityService::executeJob(JobPayload payload)
+    -> VisibilityService::JobResult {
+  const int cell_count = payload.width * payload.height;
+  std::vector<std::uint8_t> current_visible(cell_count, 0U);
 
-  const float halfWidth = payload.width * 0.5f - 0.5f;
-  const float halfHeight = payload.height * 0.5f - 0.5f;
-
-  for (const auto &src : payload.sources) {
-    for (int dz = -src.cellRadius; dz <= src.cellRadius; ++dz) {
-      const int gz = src.centerZ + dz;
-      if (!inBoundsStatic(src.centerX, gz, payload.width, payload.height)) {
+  for (const auto &source : payload.sources) {
+    for (int dz = -source.cell_radius; dz <= source.cell_radius; ++dz) {
+      const int grid_z = source.center_z + dz;
+      if (!inBoundsStatic(source.center_x, grid_z, payload.width,
+                          payload.height)) {
         continue;
       }
-      const float worldDz = dz * payload.tileSize;
-      for (int dx = -src.cellRadius; dx <= src.cellRadius; ++dx) {
-        const int gx = src.centerX + dx;
-        if (!inBoundsStatic(gx, gz, payload.width, payload.height)) {
+      const float world_dz = static_cast<float>(dz) * payload.tile_size;
+      for (int dx = -source.cell_radius; dx <= source.cell_radius; ++dx) {
+        const int grid_x = source.center_x + dx;
+        if (!inBoundsStatic(grid_x, grid_z, payload.width, payload.height)) {
           continue;
         }
-        const float worldDx = dx * payload.tileSize;
-        const float distSq = worldDx * worldDx + worldDz * worldDz;
-        if (distSq <= src.expandedRangeSq) {
-          const int idx = indexStatic(gx, gz, payload.width);
-          currentVisible[idx] = 1;
+        const float world_dx = static_cast<float>(dx) * payload.tile_size;
+        const float dist_sq = world_dx * world_dx + world_dz * world_dz;
+        if (dist_sq <= source.expanded_range_sq) {
+          const int idx = indexStatic(grid_x, grid_z, payload.width);
+          current_visible[idx] = 1U;
         }
       }
     }
   }
 
   bool changed = false;
-  for (int idx = 0; idx < count; ++idx) {
-    const std::uint8_t nowVisible = currentVisible[idx];
-
-    if (nowVisible) {
-      if (payload.cells[idx] !=
-          static_cast<std::uint8_t>(VisibilityState::Visible)) {
-        payload.cells[idx] =
-            static_cast<std::uint8_t>(VisibilityState::Visible);
-        changed = true;
-      }
-    } else {
-      if (payload.cells[idx] ==
-          static_cast<std::uint8_t>(VisibilityState::Visible)) {
-        payload.cells[idx] =
-            static_cast<std::uint8_t>(VisibilityState::Explored);
+  for (int idx = 0; idx < cell_count; ++idx) {
+    const std::uint8_t now_visible = current_visible[idx];
+    const auto visible_val =
+        static_cast<std::uint8_t>(VisibilityState::Visible);
+    const auto explored_val =
+        static_cast<std::uint8_t>(VisibilityState::Explored);
+
+    if (now_visible != 0U) {
+      if (payload.cells[idx] != visible_val) {
+        payload.cells[idx] = visible_val;
         changed = true;
       }
+    } else if (payload.cells[idx] == visible_val) {
+      payload.cells[idx] = explored_val;
+      changed = true;
     }
   }
 
   return JobResult{std::move(payload.cells), payload.generation, changed};
 }
 
-VisibilityState VisibilityService::stateAt(int gridX, int gridZ) const {
-  if (!m_initialized || !inBounds(gridX, gridZ)) {
+auto VisibilityService::stateAt(int grid_x,
+                                int grid_z) const -> VisibilityState {
+  if (!m_initialized || !inBounds(grid_x, grid_z)) {
     return VisibilityState::Visible;
   }
-  std::shared_lock lock(m_cellsMutex);
-  return static_cast<VisibilityState>(m_cells[index(gridX, gridZ)]);
+  std::shared_lock<std::shared_mutex> const lock(m_cellsMutex);
+  return static_cast<VisibilityState>(m_cells[index(grid_x, grid_z)]);
 }
 
-bool VisibilityService::isVisibleWorld(float worldX, float worldZ) const {
+auto VisibilityService::isVisibleWorld(float world_x,
+                                       float world_z) const -> bool {
   if (!m_initialized) {
     return true;
   }
-  const int gx = worldToGrid(worldX, m_halfWidth);
-  const int gz = worldToGrid(worldZ, m_halfHeight);
-  if (!inBounds(gx, gz)) {
+  const int grid_x = worldToGrid(world_x, m_half_width);
+  const int grid_z = worldToGrid(world_z, m_half_height);
+  if (!inBounds(grid_x, grid_z)) {
     return false;
   }
-  std::shared_lock lock(m_cellsMutex);
-  return m_cells[index(gx, gz)] ==
+  std::shared_lock<std::shared_mutex> const lock(m_cellsMutex);
+  return m_cells[index(grid_x, grid_z)] ==
          static_cast<std::uint8_t>(VisibilityState::Visible);
 }
 
-bool VisibilityService::isExploredWorld(float worldX, float worldZ) const {
+auto VisibilityService::isExploredWorld(float world_x,
+                                        float world_z) const -> bool {
   if (!m_initialized) {
     return true;
   }
-  const int gx = worldToGrid(worldX, m_halfWidth);
-  const int gz = worldToGrid(worldZ, m_halfHeight);
-  if (!inBounds(gx, gz)) {
+  const int grid_x = worldToGrid(world_x, m_half_width);
+  const int grid_z = worldToGrid(world_z, m_half_height);
+  if (!inBounds(grid_x, grid_z)) {
     return false;
   }
-  std::shared_lock lock(m_cellsMutex);
-  const auto state = m_cells[index(gx, gz)];
+  std::shared_lock<std::shared_mutex> const lock(m_cellsMutex);
+  const auto state = m_cells[index(grid_x, grid_z)];
   return state == static_cast<std::uint8_t>(VisibilityState::Visible) ||
          state == static_cast<std::uint8_t>(VisibilityState::Explored);
 }
 
-std::vector<std::uint8_t> VisibilityService::snapshotCells() const {
-  std::shared_lock lock(m_cellsMutex);
+auto VisibilityService::snapshotCells() const -> std::vector<std::uint8_t> {
+  std::shared_lock<std::shared_mutex> const lock(m_cellsMutex);
   return m_cells;
 }
 
-bool VisibilityService::inBounds(int x, int z) const {
-  return x >= 0 && x < m_width && z >= 0 && z < m_height;
+auto VisibilityService::inBounds(int grid_x, int grid_z) const -> bool {
+  return grid_x >= 0 && grid_x < m_width && grid_z >= 0 && grid_z < m_height;
 }
 
-int VisibilityService::index(int x, int z) const { return z * m_width + x; }
+auto VisibilityService::index(int grid_x, int grid_z) const -> int {
+  return grid_z * m_width + grid_x;
+}
 
-int VisibilityService::worldToGrid(float worldCoord, float half) const {
-  float gridCoord = worldCoord / m_tileSize + half;
-  return static_cast<int>(std::floor(gridCoord + 0.5f));
+auto VisibilityService::worldToGrid(float world_coord,
+                                    float half) const -> int {
+  const float grid_coord = world_coord / m_tile_size + half;
+  return static_cast<int>(std::floor(grid_coord + k_half_cell_offset));
 }
 
 } // namespace Game::Map

+ 34 - 37
game/map/visibility_service.h

@@ -7,14 +7,11 @@
 #include <shared_mutex>
 #include <vector>
 
-namespace Engine {
-namespace Core {
+namespace Engine::Core {
 class World;
 }
-} // namespace Engine
 
-namespace Game {
-namespace Map {
+namespace Game::Map {
 
 enum class VisibilityState : std::uint8_t {
   Unseen = 0,
@@ -24,44 +21,44 @@ enum class VisibilityState : std::uint8_t {
 
 class VisibilityService {
 public:
-  static VisibilityService &instance();
+  static auto instance() -> VisibilityService &;
 
-  void initialize(int width, int height, float tileSize);
+  void initialize(int width, int height, float tile_size);
   void reset();
-  bool update(Engine::Core::World &world, int playerId);
-  void computeImmediate(Engine::Core::World &world, int playerId);
+  auto update(Engine::Core::World &world, int player_id) -> bool;
+  void computeImmediate(Engine::Core::World &world, int player_id);
 
-  bool isInitialized() const { return m_initialized; }
+  auto isInitialized() const -> bool { return m_initialized; }
 
-  int getWidth() const { return m_width; }
-  int getHeight() const { return m_height; }
-  float getTileSize() const { return m_tileSize; }
+  auto getWidth() const -> int { return m_width; }
+  auto getHeight() const -> int { return m_height; }
+  auto getTileSize() const -> float { return m_tile_size; }
 
-  VisibilityState stateAt(int gridX, int gridZ) const;
-  bool isVisibleWorld(float worldX, float worldZ) const;
-  bool isExploredWorld(float worldX, float worldZ) const;
+  auto stateAt(int grid_x, int grid_z) const -> VisibilityState;
+  auto isVisibleWorld(float world_x, float world_z) const -> bool;
+  auto isExploredWorld(float world_x, float world_z) const -> bool;
 
-  std::vector<std::uint8_t> snapshotCells() const;
-  std::uint64_t version() const {
+  auto snapshotCells() const -> std::vector<std::uint8_t>;
+  auto version() const -> std::uint64_t {
     return m_version.load(std::memory_order_relaxed);
   }
 
 private:
-  bool inBounds(int x, int z) const;
-  int index(int x, int z) const;
-  int worldToGrid(float worldCoord, float half) const;
+  auto inBounds(int x, int z) const -> bool;
+  auto index(int x, int z) const -> int;
+  auto worldToGrid(float world_coord, float half) const -> int;
 
   struct VisionSource {
-    int centerX;
-    int centerZ;
-    int cellRadius;
-    float expandedRangeSq;
+    int center_x;
+    int center_z;
+    int cell_radius;
+    float expanded_range_sq;
   };
 
   struct JobPayload {
     int width;
     int height;
-    float tileSize;
+    float tile_size;
     std::vector<std::uint8_t> cells;
     std::vector<VisionSource> sources;
     std::uint64_t generation;
@@ -73,29 +70,29 @@ private:
     bool changed;
   };
 
-  std::vector<VisionSource> gatherVisionSources(Engine::Core::World &world,
-                                                int playerId) const;
-  JobPayload composeJobPayload(const std::vector<VisionSource> &sources) const;
+  auto gatherVisionSources(Engine::Core::World &world,
+                           int player_id) const -> std::vector<VisionSource>;
+  auto composeJobPayload(const std::vector<VisionSource> &sources) const
+      -> JobPayload;
   void startAsyncJob(JobPayload &&payload);
-  bool integrateCompletedJob();
-  static JobResult executeJob(JobPayload payload);
+  auto integrateCompletedJob() -> bool;
+  static auto executeJob(JobPayload payload) -> JobResult;
 
   VisibilityService() = default;
 
   bool m_initialized = false;
   int m_width = 0;
   int m_height = 0;
-  float m_tileSize = 1.0f;
-  float m_halfWidth = 0.0f;
-  float m_halfHeight = 0.0f;
+  float m_tile_size = 1.0F;
+  float m_half_width = 0.0F;
+  float m_half_height = 0.0F;
 
   mutable std::shared_mutex m_cellsMutex;
   std::vector<std::uint8_t> m_cells;
   std::atomic<std::uint64_t> m_version{0};
-  std::atomic<std::uint64_t> m_generation{0};
+  mutable std::atomic<std::uint64_t> m_generation{0};
   std::future<JobResult> m_pendingJob;
   std::atomic<bool> m_jobActive{false};
 };
 
-} // namespace Map
-} // namespace Game
+} // namespace Game::Map

+ 10 - 12
game/map/world_bootstrap.cpp

@@ -2,22 +2,21 @@
 #include "render/gl/bootstrap.h"
 #include "render/ground/ground_renderer.h"
 
-namespace Game {
-namespace Map {
+namespace Game::Map {
 
-bool WorldBootstrap::initialize(Render::GL::Renderer &renderer,
+auto WorldBootstrap::initialize(Render::GL::Renderer &renderer,
                                 Render::GL::Camera &camera,
                                 Render::GL::GroundRenderer *ground,
-                                QString *outError) {
+                                QString *out_error) -> bool {
   if (!Render::GL::RenderBootstrap::initialize(renderer, camera)) {
-    if (outError) {
-      *outError = "Failed to initialize OpenGL renderer";
+    if (out_error != nullptr) {
+      *out_error = "Failed to initialize OpenGL renderer";
     }
     return false;
   }
 
-  if (ground) {
-    ground->configureExtent(50.0f);
+  if (ground != nullptr) {
+    ground->configureExtent(50.0F);
   }
 
   return true;
@@ -27,11 +26,10 @@ void WorldBootstrap::ensureInitialized(bool &initialized,
                                        Render::GL::Renderer &renderer,
                                        Render::GL::Camera &camera,
                                        Render::GL::GroundRenderer *ground,
-                                       QString *outError) {
+                                       QString *out_error) {
   if (!initialized) {
-    initialized = initialize(renderer, camera, ground, outError);
+    initialized = initialize(renderer, camera, ground, out_error);
   }
 }
 
-} // namespace Map
-} // namespace Game
+} // namespace Game::Map

+ 7 - 11
game/map/world_bootstrap.h

@@ -2,30 +2,26 @@
 
 #include <QString>
 
-namespace Render {
-namespace GL {
+namespace Render::GL {
 class Renderer;
 class Camera;
 class GroundRenderer;
-} // namespace GL
-} // namespace Render
+} // namespace Render::GL
 
-namespace Game {
-namespace Map {
+namespace Game::Map {
 
 class WorldBootstrap {
 public:
-  static bool initialize(Render::GL::Renderer &renderer,
+  static auto initialize(Render::GL::Renderer &renderer,
                          Render::GL::Camera &camera,
                          Render::GL::GroundRenderer *ground = nullptr,
-                         QString *outError = nullptr);
+                         QString *out_error = nullptr) -> bool;
 
   static void ensureInitialized(bool &initialized,
                                 Render::GL::Renderer &renderer,
                                 Render::GL::Camera &camera,
                                 Render::GL::GroundRenderer *ground = nullptr,
-                                QString *outError = nullptr);
+                                QString *out_error = nullptr);
 };
 
-} // namespace Map
-} // namespace Game
+} // namespace Game::Map

+ 20 - 13
game/systems/ai_system.cpp

@@ -5,7 +5,14 @@
 #include "ai_system/behaviors/gather_behavior.h"
 #include "ai_system/behaviors/production_behavior.h"
 #include "ai_system/behaviors/retreat_behavior.h"
+#include "core/event_manager.h"
 #include "owner_registry.h"
+#include "systems/ai_system/ai_types.h"
+#include "systems/ai_system/ai_worker.h"
+#include <cstdint>
+#include <memory>
+#include <queue>
+#include <utility>
 
 namespace Game::Systems {
 
@@ -39,16 +46,16 @@ void AISystem::reinitialize() {
 
 void AISystem::initializeAIPlayers() {
   auto &registry = OwnerRegistry::instance();
-  const auto &aiOwnerIds = registry.getAIOwnerIds();
+  const auto &ai_owner_ids = registry.getAIOwnerIds();
 
-  if (aiOwnerIds.empty()) {
+  if (ai_owner_ids.empty()) {
     return;
   }
 
-  for (uint32_t playerId : aiOwnerIds) {
-    int teamId = registry.getOwnerTeam(playerId);
+  for (uint32_t const player_id : ai_owner_ids) {
+    int const team_id = registry.getOwnerTeam(player_id);
     AIInstance instance;
-    instance.context.playerId = playerId;
+    instance.context.player_id = player_id;
     instance.context.state = AI::AIState::Idle;
     instance.worker = std::make_unique<AI::AIWorker>(m_reasoner, m_executor,
                                                      m_behaviorRegistry);
@@ -57,10 +64,10 @@ void AISystem::initializeAIPlayers() {
   }
 }
 
-AISystem::~AISystem() {}
+AISystem::~AISystem() = default;
 
 void AISystem::update(Engine::Core::World *world, float deltaTime) {
-  if (!world) {
+  if (world == nullptr) {
     return;
   }
 
@@ -74,7 +81,7 @@ void AISystem::update(Engine::Core::World *world, float deltaTime) {
 
     ai.updateTimer += deltaTime;
 
-    if (ai.updateTimer < 0.3f) {
+    if (ai.updateTimer < 0.3F) {
       continue;
     }
 
@@ -83,7 +90,7 @@ void AISystem::update(Engine::Core::World *world, float deltaTime) {
     }
 
     AI::AISnapshot snapshot =
-        m_snapshotBuilder.build(*world, ai.context.playerId);
+        m_snapshotBuilder.build(*world, ai.context.player_id);
     snapshot.gameTime = m_totalGameTime;
 
     AI::AIJob job;
@@ -92,7 +99,7 @@ void AISystem::update(Engine::Core::World *world, float deltaTime) {
     job.deltaTime = ai.updateTimer;
 
     if (ai.worker->trySubmit(std::move(job))) {
-      ai.updateTimer = 0.0f;
+      ai.updateTimer = 0.0F;
     }
   }
 }
@@ -109,10 +116,10 @@ void AISystem::processResults(Engine::Core::World &world) {
 
       ai.context = result.context;
 
-      auto filteredCommands =
+      auto filtered_commands =
           m_commandFilter.filter(result.commands, m_totalGameTime);
 
-      m_applier.apply(world, ai.context.playerId, filteredCommands);
+      m_applier.apply(world, ai.context.player_id, filtered_commands);
 
       results.pop();
     }
@@ -122,7 +129,7 @@ void AISystem::processResults(Engine::Core::World &world) {
 void AISystem::onBuildingAttacked(
     const Engine::Core::BuildingAttackedEvent &event) {
   for (auto &ai : m_aiInstances) {
-    if (ai.context.playerId == event.ownerId) {
+    if (ai.context.player_id == event.owner_id) {
       ai.context.buildingsUnderAttack[event.buildingId] = m_totalGameTime;
 
       if (event.buildingId == ai.context.primaryBarracks) {

+ 2 - 2
game/systems/ai_system.h

@@ -33,7 +33,7 @@ private:
   struct AIInstance {
     AI::AIContext context;
     std::unique_ptr<AI::AIWorker> worker;
-    float updateTimer = 0.0f;
+    float updateTimer = 0.0F;
   };
 
   std::vector<AIInstance> m_aiInstances;
@@ -45,7 +45,7 @@ private:
   AI::AICommandApplier m_applier;
   AI::AICommandFilter m_commandFilter;
 
-  float m_totalGameTime = 0.0f;
+  float m_totalGameTime = 0.0F;
 
   Engine::Core::ScopedEventSubscription<Engine::Core::BuildingAttackedEvent>
       m_buildingAttackedSubscription;

+ 7 - 4
game/systems/ai_system/ai_behavior.h

@@ -14,12 +14,15 @@ public:
                        float deltaTime,
                        std::vector<AICommand> &outCommands) = 0;
 
-  virtual bool shouldExecute(const AISnapshot &snapshot,
-                             const AIContext &context) const = 0;
+  [[nodiscard]] virtual auto
+  should_execute(const AISnapshot &snapshot,
+                 const AIContext &context) const -> bool = 0;
 
-  virtual BehaviorPriority getPriority() const = 0;
+  [[nodiscard]] virtual auto getPriority() const -> BehaviorPriority = 0;
 
-  virtual bool canRunConcurrently() const { return false; }
+  [[nodiscard]] virtual auto canRunConcurrently() const -> bool {
+    return false;
+  }
 };
 
 } // namespace Game::Systems::AI

+ 5 - 5
game/systems/ai_system/ai_behavior_registry.h

@@ -14,7 +14,7 @@ public:
   ~AIBehaviorRegistry() = default;
 
   AIBehaviorRegistry(const AIBehaviorRegistry &) = delete;
-  AIBehaviorRegistry &operator=(const AIBehaviorRegistry &) = delete;
+  auto operator=(const AIBehaviorRegistry &) -> AIBehaviorRegistry & = delete;
 
   void registerBehavior(std::unique_ptr<AIBehavior> behavior) {
     m_behaviors.push_back(std::move(behavior));
@@ -26,21 +26,21 @@ public:
               });
   }
 
-  void forEach(std::function<void(AIBehavior &)> func) {
+  void forEach(const std::function<void(AIBehavior &)> &func) {
     for (auto &behavior : m_behaviors) {
       func(*behavior);
     }
   }
 
-  void forEach(std::function<void(const AIBehavior &)> func) const {
+  void forEach(const std::function<void(const AIBehavior &)> &func) const {
     for (const auto &behavior : m_behaviors) {
       func(*behavior);
     }
   }
 
-  size_t size() const { return m_behaviors.size(); }
+  [[nodiscard]] auto size() const -> size_t { return m_behaviors.size(); }
 
-  bool empty() const { return m_behaviors.empty(); }
+  [[nodiscard]] auto empty() const -> bool { return m_behaviors.empty(); }
 
   void clear() { m_behaviors.clear(); }
 

+ 50 - 41
game/systems/ai_system/ai_command_applier.cpp

@@ -5,8 +5,13 @@
 #include "../../units/troop_config.h"
 #include "../command_service.h"
 #include "ai_utils.h"
+#include "systems/ai_system/ai_types.h"
+#include "units/troop_type.h"
 
 #include <QVector3D>
+#include <cstddef>
+#include <qvectornd.h>
+#include <vector>
 
 namespace Game::Systems::AI {
 
@@ -21,96 +26,98 @@ void AICommandApplier::apply(Engine::Core::World &world, int aiOwnerId,
         break;
       }
 
-      std::vector<float> expandedX, expandedY, expandedZ;
+      std::vector<float> expanded_x;
+      std::vector<float> expanded_y;
+      std::vector<float> expanded_z;
 
       if (command.moveTargetX.size() != command.units.size()) {
         replicateLastTargetIfNeeded(command.moveTargetX, command.moveTargetY,
                                     command.moveTargetZ, command.units.size(),
-                                    expandedX, expandedY, expandedZ);
+                                    expanded_x, expanded_y, expanded_z);
       } else {
-        expandedX = command.moveTargetX;
-        expandedY = command.moveTargetY;
-        expandedZ = command.moveTargetZ;
+        expanded_x = command.moveTargetX;
+        expanded_y = command.moveTargetY;
+        expanded_z = command.moveTargetZ;
       }
 
-      if (expandedX.empty()) {
+      if (expanded_x.empty()) {
         break;
       }
 
-      std::vector<Engine::Core::EntityID> ownedUnits;
-      std::vector<QVector3D> ownedTargets;
-      ownedUnits.reserve(command.units.size());
-      ownedTargets.reserve(command.units.size());
+      std::vector<Engine::Core::EntityID> owned_units;
+      std::vector<QVector3D> owned_targets;
+      owned_units.reserve(command.units.size());
+      owned_targets.reserve(command.units.size());
 
       for (std::size_t idx = 0; idx < command.units.size(); ++idx) {
-        auto entityId = command.units[idx];
-        auto *entity = world.getEntity(entityId);
-        if (!entity) {
+        auto entity_id = command.units[idx];
+        auto *entity = world.getEntity(entity_id);
+        if (entity == nullptr) {
           continue;
         }
 
         auto *unit = entity->getComponent<Engine::Core::UnitComponent>();
-        if (!unit || unit->ownerId != aiOwnerId) {
+        if ((unit == nullptr) || unit->owner_id != aiOwnerId) {
           continue;
         }
 
-        ownedUnits.push_back(entityId);
-        ownedTargets.emplace_back(expandedX[idx], expandedY[idx],
-                                  expandedZ[idx]);
+        owned_units.push_back(entity_id);
+        owned_targets.emplace_back(expanded_x[idx], expanded_y[idx],
+                                   expanded_z[idx]);
       }
 
-      if (ownedUnits.empty()) {
+      if (owned_units.empty()) {
         break;
       }
 
       CommandService::MoveOptions opts;
       opts.allowDirectFallback = true;
       opts.clearAttackIntent = false;
-      opts.groupMove = ownedUnits.size() > 1;
-      CommandService::moveUnits(world, ownedUnits, ownedTargets, opts);
+      opts.groupMove = owned_units.size() > 1;
+      CommandService::moveUnits(world, owned_units, owned_targets, opts);
       break;
     }
 
     case AICommandType::AttackTarget: {
-      if (command.units.empty() || command.targetId == 0) {
+      if (command.units.empty() || command.target_id == 0) {
         break;
       }
 
-      std::vector<Engine::Core::EntityID> ownedUnits;
-      ownedUnits.reserve(command.units.size());
+      std::vector<Engine::Core::EntityID> owned_units;
+      owned_units.reserve(command.units.size());
 
-      for (auto entityId : command.units) {
-        auto *entity = world.getEntity(entityId);
-        if (!entity) {
+      for (auto entity_id : command.units) {
+        auto *entity = world.getEntity(entity_id);
+        if (entity == nullptr) {
           continue;
         }
 
         auto *unit = entity->getComponent<Engine::Core::UnitComponent>();
-        if (!unit || unit->ownerId != aiOwnerId) {
+        if ((unit == nullptr) || unit->owner_id != aiOwnerId) {
           continue;
         }
 
-        ownedUnits.push_back(entityId);
+        owned_units.push_back(entity_id);
       }
 
-      if (ownedUnits.empty()) {
+      if (owned_units.empty()) {
         break;
       }
 
-      CommandService::attackTarget(world, ownedUnits, command.targetId,
-                                   command.shouldChase);
+      CommandService::attack_target(world, owned_units, command.target_id,
+                                    command.shouldChase);
       break;
     }
 
     case AICommandType::StartProduction: {
       auto *entity = world.getEntity(command.buildingId);
-      if (!entity) {
+      if (entity == nullptr) {
         break;
       }
 
       auto *production =
           entity->getComponent<Engine::Core::ProductionComponent>();
-      if (!production) {
+      if (production == nullptr) {
         break;
       }
 
@@ -119,21 +126,23 @@ void AICommandApplier::apply(Engine::Core::World &world, int aiOwnerId,
       }
 
       auto *unit = entity->getComponent<Engine::Core::UnitComponent>();
-      if (unit && unit->ownerId != aiOwnerId) {
+      if ((unit != nullptr) && unit->owner_id != aiOwnerId) {
         break;
       }
 
-      int currentTroops = world.countTroopsForPlayer(aiOwnerId);
-      int maxTroops = Game::GameConfig::instance().getMaxTroopsPerPlayer();
-      Game::Units::TroopType productType = production->productType;
-      int individualsPerUnit =
+      int const current_troops =
+          Engine::Core::World::countTroopsForPlayer(aiOwnerId);
+      int const max_troops =
+          Game::GameConfig::instance().getMaxTroopsPerPlayer();
+      Game::Units::TroopType const product_type = production->product_type;
+      int const individuals_per_unit =
           Game::Units::TroopConfig::instance().getIndividualsPerUnit(
-              productType);
-      if (currentTroops + individualsPerUnit > maxTroops) {
+              product_type);
+      if (current_troops + individuals_per_unit > max_troops) {
         break;
       }
 
-      production->productType = command.productType;
+      production->product_type = command.product_type;
 
       production->timeRemaining = production->buildTime;
       production->inProgress = true;

+ 3 - 3
game/systems/ai_system/ai_command_applier.h

@@ -15,10 +15,10 @@ public:
   ~AICommandApplier() = default;
 
   AICommandApplier(const AICommandApplier &) = delete;
-  AICommandApplier &operator=(const AICommandApplier &) = delete;
+  auto operator=(const AICommandApplier &) -> AICommandApplier & = delete;
 
-  void apply(Engine::Core::World &world, int aiOwnerId,
-             const std::vector<AICommand> &commands);
+  static void apply(Engine::Core::World &world, int aiOwnerId,
+                    const std::vector<AICommand> &commands);
 };
 
 } // namespace Game::Systems::AI

+ 65 - 60
game/systems/ai_system/ai_command_filter.cpp

@@ -1,12 +1,15 @@
 #include "ai_command_filter.h"
+#include "systems/ai_system/ai_types.h"
 #include <algorithm>
 #include <cmath>
+#include <cstddef>
+#include <utility>
+#include <vector>
 
 namespace Game::Systems::AI {
 
-std::vector<AICommand>
-AICommandFilter::filter(const std::vector<AICommand> &commands,
-                        float currentTime) {
+auto AICommandFilter::filter(const std::vector<AICommand> &commands,
+                             float currentTime) -> std::vector<AICommand> {
   std::vector<AICommand> filtered;
   filtered.reserve(commands.size());
 
@@ -17,67 +20,71 @@ AICommandFilter::filter(const std::vector<AICommand> &commands,
       continue;
     }
 
-    std::vector<Engine::Core::EntityID> validUnits;
-    validUnits.reserve(cmd.units.size());
-    int blockedCount = 0;
+    std::vector<Engine::Core::EntityID> valid_units;
+    valid_units.reserve(cmd.units.size());
+    int blocked_count = 0;
 
     for (size_t i = 0; i < cmd.units.size(); ++i) {
-      Engine::Core::EntityID unitId = cmd.units[i];
+      Engine::Core::EntityID const unit_id = cmd.units[i];
 
-      Engine::Core::EntityID targetId = 0;
-      float moveX = 0.0f, moveY = 0.0f, moveZ = 0.0f;
+      Engine::Core::EntityID target_id = 0;
+      float move_x = 0.0F;
+      float move_y = 0.0F;
+      float move_z = 0.0F;
 
       if (cmd.type == AICommandType::AttackTarget) {
-        targetId = cmd.targetId;
+        target_id = cmd.target_id;
       } else if (cmd.type == AICommandType::MoveUnits) {
 
         if (i < cmd.moveTargetX.size()) {
-          moveX = cmd.moveTargetX[i];
-          moveY = cmd.moveTargetY[i];
-          moveZ = cmd.moveTargetZ[i];
+          move_x = cmd.moveTargetX[i];
+          move_y = cmd.moveTargetY[i];
+          move_z = cmd.moveTargetZ[i];
         }
       }
 
-      if (!isDuplicate(unitId, cmd.type, targetId, moveX, moveY, moveZ,
+      if (!isDuplicate(unit_id, cmd.type, target_id, move_x, move_y, move_z,
                        currentTime)) {
-        validUnits.push_back(unitId);
+        valid_units.push_back(unit_id);
       } else {
-        blockedCount++;
+        blocked_count++;
       }
     }
 
-    if (blockedCount > 0) {
+    if (blocked_count > 0) {
       continue;
     }
 
-    if (!validUnits.empty()) {
-      AICommand filteredCmd = cmd;
-      filteredCmd.units = validUnits;
+    if (!valid_units.empty()) {
+      AICommand filtered_cmd = cmd;
+      filtered_cmd.units = valid_units;
 
       if (cmd.type == AICommandType::MoveUnits) {
-        std::vector<float> newTargetX, newTargetY, newTargetZ;
-        newTargetX.reserve(validUnits.size());
-        newTargetY.reserve(validUnits.size());
-        newTargetZ.reserve(validUnits.size());
+        std::vector<float> new_target_x;
+        std::vector<float> new_target_y;
+        std::vector<float> new_target_z;
+        new_target_x.reserve(valid_units.size());
+        new_target_y.reserve(valid_units.size());
+        new_target_z.reserve(valid_units.size());
 
         for (size_t i = 0; i < cmd.units.size(); ++i) {
 
-          if (std::find(validUnits.begin(), validUnits.end(), cmd.units[i]) !=
-              validUnits.end()) {
+          if (std::find(valid_units.begin(), valid_units.end(), cmd.units[i]) !=
+              valid_units.end()) {
             if (i < cmd.moveTargetX.size()) {
-              newTargetX.push_back(cmd.moveTargetX[i]);
-              newTargetY.push_back(cmd.moveTargetY[i]);
-              newTargetZ.push_back(cmd.moveTargetZ[i]);
+              new_target_x.push_back(cmd.moveTargetX[i]);
+              new_target_y.push_back(cmd.moveTargetY[i]);
+              new_target_z.push_back(cmd.moveTargetZ[i]);
             }
           }
         }
 
-        filteredCmd.moveTargetX = std::move(newTargetX);
-        filteredCmd.moveTargetY = std::move(newTargetY);
-        filteredCmd.moveTargetZ = std::move(newTargetZ);
+        filtered_cmd.moveTargetX = std::move(new_target_x);
+        filtered_cmd.moveTargetY = std::move(new_target_y);
+        filtered_cmd.moveTargetZ = std::move(new_target_z);
       }
 
-      filtered.push_back(std::move(filteredCmd));
+      filtered.push_back(std::move(filtered_cmd));
 
       recordCommand(filtered.back(), currentTime);
     }
@@ -90,13 +97,13 @@ void AICommandFilter::update(float currentTime) { cleanupHistory(currentTime); }
 
 void AICommandFilter::reset() { m_history.clear(); }
 
-bool AICommandFilter::isDuplicate(Engine::Core::EntityID unitId,
+auto AICommandFilter::isDuplicate(Engine::Core::EntityID unit_id,
                                   AICommandType type,
-                                  Engine::Core::EntityID targetId, float moveX,
-                                  float moveY, float moveZ,
-                                  float currentTime) const {
+                                  Engine::Core::EntityID target_id,
+                                  float move_x, float move_y, float move_z,
+                                  float currentTime) const -> bool {
   for (const auto &entry : m_history) {
-    if (entry.isSimilarTo(type, unitId, targetId, moveX, moveY, moveZ,
+    if (entry.isSimilarTo(type, unit_id, target_id, move_x, move_y, move_z,
                           currentTime, m_cooldownPeriod)) {
       return true;
     }
@@ -106,18 +113,18 @@ bool AICommandFilter::isDuplicate(Engine::Core::EntityID unitId,
 
 void AICommandFilter::recordCommand(const AICommand &cmd, float currentTime) {
   for (size_t i = 0; i < cmd.units.size(); ++i) {
-    CommandHistory entry;
-    entry.unitId = cmd.units[i];
+    CommandHistory entry{};
+    entry.unit_id = cmd.units[i];
     entry.type = cmd.type;
     entry.issuedTime = currentTime;
 
     if (cmd.type == AICommandType::AttackTarget) {
-      entry.targetId = cmd.targetId;
-      entry.moveTargetX = 0.0f;
-      entry.moveTargetY = 0.0f;
-      entry.moveTargetZ = 0.0f;
+      entry.target_id = cmd.target_id;
+      entry.moveTargetX = 0.0F;
+      entry.moveTargetY = 0.0F;
+      entry.moveTargetZ = 0.0F;
     } else if (cmd.type == AICommandType::MoveUnits) {
-      entry.targetId = 0;
+      entry.target_id = 0;
       if (i < cmd.moveTargetX.size()) {
         entry.moveTargetX = cmd.moveTargetX[i];
         entry.moveTargetY = cmd.moveTargetY[i];
@@ -125,10 +132,10 @@ void AICommandFilter::recordCommand(const AICommand &cmd, float currentTime) {
       }
     } else {
 
-      entry.targetId = 0;
-      entry.moveTargetX = 0.0f;
-      entry.moveTargetY = 0.0f;
-      entry.moveTargetZ = 0.0f;
+      entry.target_id = 0;
+      entry.moveTargetX = 0.0F;
+      entry.moveTargetY = 0.0F;
+      entry.moveTargetZ = 0.0F;
     }
 
     m_history.push_back(entry);
@@ -145,14 +152,12 @@ void AICommandFilter::cleanupHistory(float currentTime) {
                   m_history.end());
 }
 
-bool AICommandFilter::CommandHistory::isSimilarTo(const AICommandType &cmdType,
-                                                  Engine::Core::EntityID unit,
-                                                  Engine::Core::EntityID target,
-                                                  float x, float y, float z,
-                                                  float currentTime,
-                                                  float cooldown) const {
+auto AICommandFilter::CommandHistory::isSimilarTo(
+    const AICommandType &cmdType, Engine::Core::EntityID unit,
+    Engine::Core::EntityID target, float x, float y, float z, float currentTime,
+    float cooldown) const -> bool {
 
-  if (unitId != unit) {
+  if (unit_id != unit) {
     return false;
   }
 
@@ -167,16 +172,16 @@ bool AICommandFilter::CommandHistory::isSimilarTo(const AICommandType &cmdType,
   switch (cmdType) {
   case AICommandType::AttackTarget:
 
-    return (targetId == target);
+    return (target_id == target);
 
   case AICommandType::MoveUnits: {
 
     const float dx = moveTargetX - x;
     const float dy = moveTargetY - y;
     const float dz = moveTargetZ - z;
-    const float distSq = dx * dx + dy * dy + dz * dz;
-    const float threshold = 3.0f * 3.0f;
-    return distSq < threshold;
+    const float dist_sq = dx * dx + dy * dy + dz * dz;
+    const float threshold = 3.0F * 3.0F;
+    return dist_sq < threshold;
   }
 
   case AICommandType::StartProduction:

+ 15 - 11
game/systems/ai_system/ai_command_filter.h

@@ -8,11 +8,11 @@ namespace Game::Systems::AI {
 
 class AICommandFilter {
 public:
-  explicit AICommandFilter(float cooldownPeriod = 5.0f)
+  explicit AICommandFilter(float cooldownPeriod = 5.0F)
       : m_cooldownPeriod(cooldownPeriod) {}
 
-  std::vector<AICommand> filter(const std::vector<AICommand> &commands,
-                                float currentTime);
+  auto filter(const std::vector<AICommand> &commands,
+              float currentTime) -> std::vector<AICommand>;
 
   void update(float currentTime);
 
@@ -20,10 +20,10 @@ public:
 
 private:
   struct CommandHistory {
-    Engine::Core::EntityID unitId;
+    Engine::Core::EntityID unit_id;
     AICommandType type;
 
-    Engine::Core::EntityID targetId;
+    Engine::Core::EntityID target_id;
 
     float moveTargetX;
     float moveTargetY;
@@ -31,17 +31,21 @@ private:
 
     float issuedTime;
 
-    bool isSimilarTo(const AICommandType &cmdType, Engine::Core::EntityID unit,
-                     Engine::Core::EntityID target, float x, float y, float z,
-                     float currentTime, float cooldown) const;
+    [[nodiscard]] auto isSimilarTo(const AICommandType &cmdType,
+                                   Engine::Core::EntityID unit,
+                                   Engine::Core::EntityID target, float x,
+                                   float y, float z, float currentTime,
+                                   float cooldown) const -> bool;
   };
 
   std::vector<CommandHistory> m_history;
   float m_cooldownPeriod;
 
-  bool isDuplicate(Engine::Core::EntityID unitId, AICommandType type,
-                   Engine::Core::EntityID targetId, float moveX, float moveY,
-                   float moveZ, float currentTime) const;
+  [[nodiscard]] auto isDuplicate(Engine::Core::EntityID unit_id,
+                                 AICommandType type,
+                                 Engine::Core::EntityID target_id, float move_x,
+                                 float move_y, float move_z,
+                                 float currentTime) const -> bool;
 
   void recordCommand(const AICommand &cmd, float currentTime);
 

+ 9 - 5
game/systems/ai_system/ai_executor.cpp

@@ -1,4 +1,8 @@
 #include "ai_executor.h"
+#include "systems/ai_system/ai_behavior.h"
+#include "systems/ai_system/ai_behavior_registry.h"
+#include "systems/ai_system/ai_types.h"
+#include <vector>
 
 namespace Game::Systems::AI {
 
@@ -6,20 +10,20 @@ void AIExecutor::run(const AISnapshot &snapshot, AIContext &context,
                      float deltaTime, AIBehaviorRegistry &registry,
                      std::vector<AICommand> &outCommands) {
 
-  bool exclusiveBehaviorExecuted = false;
+  bool exclusive_behavior_executed = false;
 
   registry.forEach([&](AIBehavior &behavior) {
-    if (exclusiveBehaviorExecuted && !behavior.canRunConcurrently()) {
+    if (exclusive_behavior_executed && !behavior.canRunConcurrently()) {
       return;
     }
 
-    bool shouldExec = behavior.shouldExecute(snapshot, context);
+    bool const should_exec = behavior.should_execute(snapshot, context);
 
-    if (shouldExec) {
+    if (should_exec) {
       behavior.execute(snapshot, context, deltaTime, outCommands);
 
       if (!behavior.canRunConcurrently()) {
-        exclusiveBehaviorExecuted = true;
+        exclusive_behavior_executed = true;
       }
     }
   });

+ 4 - 3
game/systems/ai_system/ai_executor.h

@@ -12,10 +12,11 @@ public:
   ~AIExecutor() = default;
 
   AIExecutor(const AIExecutor &) = delete;
-  AIExecutor &operator=(const AIExecutor &) = delete;
+  auto operator=(const AIExecutor &) -> AIExecutor & = delete;
 
-  void run(const AISnapshot &snapshot, AIContext &context, float deltaTime,
-           AIBehaviorRegistry &registry, std::vector<AICommand> &outCommands);
+  static void run(const AISnapshot &snapshot, AIContext &context,
+                  float deltaTime, AIBehaviorRegistry &registry,
+                  std::vector<AICommand> &outCommands);
 };
 
 } // namespace Game::Systems::AI

+ 81 - 77
game/systems/ai_system/ai_reasoner.cpp

@@ -1,8 +1,9 @@
 #include "ai_reasoner.h"
 #include "../../game_config.h"
-#include "../../units/troop_type.h"
 #include "../nation_registry.h"
 #include "ai_utils.h"
+#include "systems/ai_system/ai_types.h"
+#include "units/spawn_type.h"
 #include <algorithm>
 #include <cmath>
 #include <limits>
@@ -11,9 +12,9 @@ namespace Game::Systems::AI {
 
 void AIReasoner::updateContext(const AISnapshot &snapshot, AIContext &ctx) {
 
-  if (!ctx.nation) {
+  if (ctx.nation == nullptr) {
     ctx.nation = Game::Systems::NationRegistry::instance().getNationForPlayer(
-        ctx.playerId);
+        ctx.player_id);
   }
 
   cleanupDeadUnits(snapshot, ctx);
@@ -21,55 +22,56 @@ void AIReasoner::updateContext(const AISnapshot &snapshot, AIContext &ctx) {
   ctx.militaryUnits.clear();
   ctx.buildings.clear();
   ctx.primaryBarracks = 0;
-  ctx.totalUnits = 0;
+  ctx.total_units = 0;
   ctx.idleUnits = 0;
   ctx.combatUnits = 0;
   ctx.meleeCount = 0;
   ctx.rangedCount = 0;
   ctx.damagedUnitsCount = 0;
-  ctx.averageHealth = 1.0f;
-  ctx.rallyX = 0.0f;
-  ctx.rallyZ = 0.0f;
+  ctx.averageHealth = 1.0F;
+  ctx.rallyX = 0.0F;
+  ctx.rallyZ = 0.0F;
   ctx.barracksUnderThreat = false;
   ctx.nearbyThreatCount = 0;
-  ctx.closestThreatDistance = std::numeric_limits<float>::infinity();
-  ctx.basePosX = 0.0f;
-  ctx.basePosY = 0.0f;
-  ctx.basePosZ = 0.0f;
+  ctx.closest_threatDistance = std::numeric_limits<float>::infinity();
+  ctx.basePosX = 0.0F;
+  ctx.basePosY = 0.0F;
+  ctx.basePosZ = 0.0F;
   ctx.visibleEnemyCount = 0;
   ctx.enemyBuildingsCount = 0;
-  ctx.averageEnemyDistance = 0.0f;
-  ctx.maxTroopsPerPlayer = Game::GameConfig::instance().getMaxTroopsPerPlayer();
+  ctx.averageEnemyDistance = 0.0F;
+  ctx.max_troops_per_player =
+      Game::GameConfig::instance().getMaxTroopsPerPlayer();
 
-  constexpr float ATTACK_RECORD_TIMEOUT = 10.0f;
+  constexpr float attack_record_timeout = 10.0F;
   auto it = ctx.buildingsUnderAttack.begin();
   while (it != ctx.buildingsUnderAttack.end()) {
-    bool stillExists = false;
+    bool still_exists = false;
     for (const auto &entity : snapshot.friendlies) {
       if (entity.id == it->first && entity.isBuilding) {
-        stillExists = true;
+        still_exists = true;
         break;
       }
     }
 
-    if (!stillExists ||
-        (snapshot.gameTime - it->second) > ATTACK_RECORD_TIMEOUT) {
+    if (!still_exists ||
+        (snapshot.gameTime - it->second) > attack_record_timeout) {
       it = ctx.buildingsUnderAttack.erase(it);
     } else {
       ++it;
     }
   }
 
-  float totalHealthRatio = 0.0f;
+  float total_health_ratio = 0.0F;
 
   for (const auto &entity : snapshot.friendlies) {
     if (entity.isBuilding) {
       ctx.buildings.push_back(entity.id);
 
-      if (entity.spawnType == Game::Units::SpawnType::Barracks &&
+      if (entity.spawn_type == Game::Units::SpawnType::Barracks &&
           ctx.primaryBarracks == 0) {
         ctx.primaryBarracks = entity.id;
-        ctx.rallyX = entity.posX - 5.0f;
+        ctx.rallyX = entity.posX - 5.0F;
         ctx.rallyZ = entity.posZ;
         ctx.basePosX = entity.posX;
         ctx.basePosY = entity.posY;
@@ -79,15 +81,16 @@ void AIReasoner::updateContext(const AISnapshot &snapshot, AIContext &ctx) {
     }
 
     ctx.militaryUnits.push_back(entity.id);
-    ctx.totalUnits++;
-
-    if (ctx.nation) {
-      auto troopTypeOpt = Game::Units::spawnTypeToTroopType(entity.spawnType);
-      if (troopTypeOpt) {
-        auto troopType = *troopTypeOpt;
-        if (ctx.nation->isRangedUnit(troopType)) {
+    ctx.total_units++;
+
+    if (ctx.nation != nullptr) {
+      auto troop_type_opt =
+          Game::Units::spawn_typeToTroopType(entity.spawn_type);
+      if (troop_type_opt) {
+        auto troop_type = *troop_type_opt;
+        if (ctx.nation->is_ranged_unit(troop_type)) {
           ctx.rangedCount++;
-        } else if (ctx.nation->isMeleeUnit(troopType)) {
+        } else if (ctx.nation->isMeleeUnit(troop_type)) {
           ctx.meleeCount++;
         }
       }
@@ -99,24 +102,24 @@ void AIReasoner::updateContext(const AISnapshot &snapshot, AIContext &ctx) {
       ctx.combatUnits++;
     }
 
-    if (entity.maxHealth > 0) {
-      float healthRatio = static_cast<float>(entity.health) /
-                          static_cast<float>(entity.maxHealth);
-      totalHealthRatio += healthRatio;
+    if (entity.max_health > 0) {
+      float const health_ratio = static_cast<float>(entity.health) /
+                                 static_cast<float>(entity.max_health);
+      total_health_ratio += health_ratio;
 
-      if (healthRatio < 0.5f) {
+      if (health_ratio < 0.5F) {
         ctx.damagedUnitsCount++;
       }
     }
   }
 
   ctx.averageHealth =
-      (ctx.totalUnits > 0)
-          ? (totalHealthRatio / static_cast<float>(ctx.totalUnits))
-          : 1.0f;
+      (ctx.total_units > 0)
+          ? (total_health_ratio / static_cast<float>(ctx.total_units))
+          : 1.0F;
 
   ctx.visibleEnemyCount = static_cast<int>(snapshot.visibleEnemies.size());
-  float totalEnemyDist = 0.0f;
+  float total_enemy_dist = 0.0F;
 
   for (const auto &enemy : snapshot.visibleEnemies) {
     if (enemy.isBuilding) {
@@ -124,39 +127,40 @@ void AIReasoner::updateContext(const AISnapshot &snapshot, AIContext &ctx) {
     }
 
     if (ctx.primaryBarracks != 0) {
-      float dist = distance(enemy.posX, enemy.posY, enemy.posZ, ctx.basePosX,
-                            ctx.basePosY, ctx.basePosZ);
-      totalEnemyDist += dist;
+      float const dist = distance(enemy.posX, enemy.posY, enemy.posZ,
+                                  ctx.basePosX, ctx.basePosY, ctx.basePosZ);
+      total_enemy_dist += dist;
     }
   }
 
   ctx.averageEnemyDistance =
       (ctx.visibleEnemyCount > 0)
-          ? (totalEnemyDist / static_cast<float>(ctx.visibleEnemyCount))
-          : 1000.0f;
+          ? (total_enemy_dist / static_cast<float>(ctx.visibleEnemyCount))
+          : 1000.0F;
 
   if (ctx.primaryBarracks != 0) {
 
-    constexpr float DEFEND_RADIUS = 40.0f;
-    constexpr float CRITICAL_RADIUS = 20.0f;
-    const float defendRadiusSq = DEFEND_RADIUS * DEFEND_RADIUS;
-    const float criticalRadiusSq = CRITICAL_RADIUS * CRITICAL_RADIUS;
+    constexpr float defend_radius = 40.0F;
+    constexpr float critical_radius = 20.0F;
+    const float defend_radius_sq = defend_radius * defend_radius;
+    const float critical_radius_sq = critical_radius * critical_radius;
 
     for (const auto &enemy : snapshot.visibleEnemies) {
-      float distSq = distanceSquared(enemy.posX, enemy.posY, enemy.posZ,
-                                     ctx.basePosX, ctx.basePosY, ctx.basePosZ);
+      float const dist_sq =
+          distance_squared(enemy.posX, enemy.posY, enemy.posZ, ctx.basePosX,
+                           ctx.basePosY, ctx.basePosZ);
 
-      if (distSq <= defendRadiusSq) {
+      if (dist_sq <= defend_radius_sq) {
         ctx.barracksUnderThreat = true;
         ctx.nearbyThreatCount++;
 
-        float dist = std::sqrt(std::max(distSq, 0.0f));
-        ctx.closestThreatDistance = std::min(ctx.closestThreatDistance, dist);
+        float const dist = std::sqrt(std::max(dist_sq, 0.0F));
+        ctx.closest_threatDistance = std::min(ctx.closest_threatDistance, dist);
       }
     }
 
     if (!ctx.barracksUnderThreat) {
-      ctx.closestThreatDistance = std::numeric_limits<float>::infinity();
+      ctx.closest_threatDistance = std::numeric_limits<float>::infinity();
     }
   }
 }
@@ -165,33 +169,33 @@ void AIReasoner::updateStateMachine(AIContext &ctx, float deltaTime) {
   ctx.stateTimer += deltaTime;
   ctx.decisionTimer += deltaTime;
 
-  constexpr float MIN_STATE_DURATION = 3.0f;
+  constexpr float min_state_duration = 3.0F;
 
-  AIState previousState = ctx.state;
+  AIState previous_state = ctx.state;
   if ((ctx.barracksUnderThreat || !ctx.buildingsUnderAttack.empty()) &&
       ctx.state != AIState::Defending) {
 
     ctx.state = AIState::Defending;
   }
 
-  else if (ctx.visibleEnemyCount > 0 && ctx.averageEnemyDistance < 50.0f &&
+  else if (ctx.visibleEnemyCount > 0 && ctx.averageEnemyDistance < 50.0F &&
            (ctx.state == AIState::Gathering || ctx.state == AIState::Idle)) {
     ctx.state = AIState::Defending;
   }
 
-  if (ctx.decisionTimer < 2.0f) {
-    if (ctx.state != previousState) {
-      ctx.stateTimer = 0.0f;
+  if (ctx.decisionTimer < 2.0F) {
+    if (ctx.state != previous_state) {
+      ctx.stateTimer = 0.0F;
     }
     return;
   }
 
-  ctx.decisionTimer = 0.0f;
-  previousState = ctx.state;
+  ctx.decisionTimer = 0.0F;
+  previous_state = ctx.state;
 
-  if (ctx.stateTimer < MIN_STATE_DURATION &&
-      !((ctx.barracksUnderThreat || !ctx.buildingsUnderAttack.empty()) &&
-        ctx.state != AIState::Defending)) {
+  if (ctx.stateTimer < min_state_duration &&
+      ((!ctx.barracksUnderThreat && ctx.buildingsUnderAttack.empty()) ||
+       ctx.state == AIState::Defending)) {
     return;
   }
 
@@ -199,35 +203,35 @@ void AIReasoner::updateStateMachine(AIContext &ctx, float deltaTime) {
   case AIState::Idle:
     if (ctx.idleUnits >= 2) {
       ctx.state = AIState::Gathering;
-    } else if (ctx.averageHealth < 0.40f && ctx.totalUnits > 0) {
+    } else if (ctx.averageHealth < 0.40F && ctx.total_units > 0) {
 
       ctx.state = AIState::Defending;
-    } else if (ctx.totalUnits >= 1 && ctx.visibleEnemyCount > 0) {
+    } else if (ctx.total_units >= 1 && ctx.visibleEnemyCount > 0) {
 
       ctx.state = AIState::Attacking;
     }
     break;
 
   case AIState::Gathering:
-    if (ctx.totalUnits >= 3) {
+    if (ctx.total_units >= 3) {
 
       ctx.state = AIState::Attacking;
-    } else if (ctx.totalUnits < 2) {
+    } else if (ctx.total_units < 2) {
       ctx.state = AIState::Idle;
-    } else if (ctx.averageHealth < 0.40f) {
+    } else if (ctx.averageHealth < 0.40F) {
 
       ctx.state = AIState::Defending;
-    } else if (ctx.visibleEnemyCount > 0 && ctx.totalUnits >= 2) {
+    } else if (ctx.visibleEnemyCount > 0 && ctx.total_units >= 2) {
 
       ctx.state = AIState::Attacking;
     }
     break;
 
   case AIState::Attacking:
-    if (ctx.averageHealth < 0.25f) {
+    if (ctx.averageHealth < 0.25F) {
 
       ctx.state = AIState::Retreating;
-    } else if (ctx.totalUnits == 0) {
+    } else if (ctx.total_units == 0) {
 
       ctx.state = AIState::Idle;
     }
@@ -238,10 +242,10 @@ void AIReasoner::updateStateMachine(AIContext &ctx, float deltaTime) {
 
     if (ctx.barracksUnderThreat || !ctx.buildingsUnderAttack.empty()) {
 
-    } else if (ctx.totalUnits >= 4 && ctx.averageHealth > 0.65f) {
+    } else if (ctx.total_units >= 4 && ctx.averageHealth > 0.65F) {
 
       ctx.state = AIState::Attacking;
-    } else if (ctx.averageHealth > 0.80f) {
+    } else if (ctx.averageHealth > 0.80F) {
 
       ctx.state = AIState::Idle;
     }
@@ -249,7 +253,7 @@ void AIReasoner::updateStateMachine(AIContext &ctx, float deltaTime) {
 
   case AIState::Retreating:
 
-    if (ctx.stateTimer > 6.0f && ctx.averageHealth > 0.55f) {
+    if (ctx.stateTimer > 6.0F && ctx.averageHealth > 0.55F) {
 
       ctx.state = AIState::Defending;
     }
@@ -261,8 +265,8 @@ void AIReasoner::updateStateMachine(AIContext &ctx, float deltaTime) {
     break;
   }
 
-  if (ctx.state != previousState) {
-    ctx.stateTimer = 0.0f;
+  if (ctx.state != previous_state) {
+    ctx.stateTimer = 0.0F;
   }
 }
 

+ 3 - 3
game/systems/ai_system/ai_reasoner.h

@@ -10,11 +10,11 @@ public:
   ~AIReasoner() = default;
 
   AIReasoner(const AIReasoner &) = delete;
-  AIReasoner &operator=(const AIReasoner &) = delete;
+  auto operator=(const AIReasoner &) -> AIReasoner & = delete;
 
-  void updateContext(const AISnapshot &snapshot, AIContext &context);
+  static void updateContext(const AISnapshot &snapshot, AIContext &context);
 
-  void updateStateMachine(AIContext &context, float deltaTime);
+  static void updateStateMachine(AIContext &context, float deltaTime);
 };
 
 } // namespace Game::Systems::AI

+ 21 - 19
game/systems/ai_system/ai_snapshot_builder.cpp

@@ -1,51 +1,53 @@
 #include "ai_snapshot_builder.h"
 #include "../../core/component.h"
 #include "../../core/world.h"
+#include "systems/ai_system/ai_types.h"
+#include <utility>
 
 namespace Game::Systems::AI {
 
 AISnapshot AISnapshotBuilder::build(const Engine::Core::World &world,
-                                    int aiOwnerId) const {
+                                    int aiOwnerId) {
   AISnapshot snapshot;
-  snapshot.playerId = aiOwnerId;
+  snapshot.player_id = aiOwnerId;
 
   auto friendlies = world.getUnitsOwnedBy(aiOwnerId);
   snapshot.friendlies.reserve(friendlies.size());
 
-  int skippedNoAI = 0;
-  int skippedNoUnit = 0;
-  int skippedDead = 0;
+  int skipped_no_ai = 0;
+  int skipped_no_unit = 0;
+  int skipped_dead = 0;
   int added = 0;
 
   for (auto *entity : friendlies) {
     if (!entity->hasComponent<Engine::Core::AIControlledComponent>()) {
-      skippedNoAI++;
+      skipped_no_ai++;
       continue;
     }
 
     auto *unit = entity->getComponent<Engine::Core::UnitComponent>();
-    if (!unit) {
-      skippedNoUnit++;
+    if (unit == nullptr) {
+      skipped_no_unit++;
       continue;
     }
 
     if (unit->health <= 0) {
-      skippedDead++;
+      skipped_dead++;
       continue;
     }
 
     EntitySnapshot data;
     data.id = entity->getId();
-    data.spawnType = unit->spawnType;
-    data.ownerId = unit->ownerId;
+    data.spawn_type = unit->spawn_type;
+    data.owner_id = unit->owner_id;
     data.health = unit->health;
-    data.maxHealth = unit->maxHealth;
+    data.max_health = unit->max_health;
     data.isBuilding = entity->hasComponent<Engine::Core::BuildingComponent>();
 
     if (auto *transform =
             entity->getComponent<Engine::Core::TransformComponent>()) {
       data.posX = transform->position.x;
-      data.posY = 0.0f;
+      data.posY = 0.0F;
       data.posZ = transform->position.z;
     }
 
@@ -63,7 +65,7 @@ AISnapshot AISnapshotBuilder::build(const Engine::Core::World &world,
       data.production.timeRemaining = production->timeRemaining;
       data.production.producedCount = production->producedCount;
       data.production.maxUnits = production->maxUnits;
-      data.production.productType = production->productType;
+      data.production.product_type = production->product_type;
       data.production.rallySet = production->rallySet;
       data.production.rallyX = production->rallyX;
       data.production.rallyZ = production->rallyZ;
@@ -80,12 +82,12 @@ AISnapshot AISnapshotBuilder::build(const Engine::Core::World &world,
 
   for (auto *entity : enemies) {
     auto *unit = entity->getComponent<Engine::Core::UnitComponent>();
-    if (!unit || unit->health <= 0) {
+    if ((unit == nullptr) || unit->health <= 0) {
       continue;
     }
 
     auto *transform = entity->getComponent<Engine::Core::TransformComponent>();
-    if (!transform) {
+    if (transform == nullptr) {
       continue;
     }
 
@@ -94,12 +96,12 @@ AISnapshot AISnapshotBuilder::build(const Engine::Core::World &world,
     contact.isBuilding =
         entity->hasComponent<Engine::Core::BuildingComponent>();
     contact.posX = transform->position.x;
-    contact.posY = 0.0f;
+    contact.posY = 0.0F;
     contact.posZ = transform->position.z;
 
     contact.health = unit->health;
-    contact.maxHealth = unit->maxHealth;
-    contact.spawnType = unit->spawnType;
+    contact.max_health = unit->max_health;
+    contact.spawn_type = unit->spawn_type;
 
     snapshot.visibleEnemies.push_back(std::move(contact));
   }

+ 3 - 2
game/systems/ai_system/ai_snapshot_builder.h

@@ -14,9 +14,10 @@ public:
   ~AISnapshotBuilder() = default;
 
   AISnapshotBuilder(const AISnapshotBuilder &) = delete;
-  AISnapshotBuilder &operator=(const AISnapshotBuilder &) = delete;
+  auto operator=(const AISnapshotBuilder &) -> AISnapshotBuilder & = delete;
 
-  AISnapshot build(const Engine::Core::World &world, int aiOwnerId) const;
+  [[nodiscard]] static auto build(const Engine::Core::World &world,
+                                  int aiOwnerId) -> AISnapshot;
 };
 
 } // namespace Game::Systems::AI

+ 105 - 97
game/systems/ai_system/ai_tactical.cpp

@@ -2,14 +2,20 @@
 #include "../../units/troop_type.h"
 #include "../nation_registry.h"
 #include "ai_utils.h"
+#include "systems/ai_system/ai_types.h"
+#include "units/spawn_type.h"
 #include <algorithm>
 #include <cmath>
+#include <limits>
+#include <string>
+#include <vector>
 
 namespace Game::Systems::AI {
 
-TacticalUtils::EngagementAssessment TacticalUtils::assessEngagement(
+auto TacticalUtils::assessEngagement(
     const std::vector<const EntitySnapshot *> &friendlies,
-    const std::vector<const ContactSnapshot *> &enemies, float minForceRatio) {
+    const std::vector<const ContactSnapshot *> &enemies,
+    float minForceRatio) -> TacticalUtils::EngagementAssessment {
 
   EngagementAssessment result;
 
@@ -21,167 +27,167 @@ TacticalUtils::EngagementAssessment TacticalUtils::assessEngagement(
   result.friendlyCount = static_cast<int>(friendlies.size());
   result.enemyCount = static_cast<int>(enemies.size());
 
-  float totalFriendlyHealth = 0.0f;
-  float totalEnemyHealth = 0.0f;
-  int validFriendlies = 0;
-  int validEnemies = 0;
+  float total_friendly_health = 0.0F;
+  float total_enemy_health = 0.0F;
+  int valid_friendlies = 0;
+  int valid_enemies = 0;
 
   for (const auto *unit : friendlies) {
-    if (unit->maxHealth > 0) {
-      totalFriendlyHealth += static_cast<float>(unit->health) /
-                             static_cast<float>(unit->maxHealth);
-      ++validFriendlies;
+    if (unit->max_health > 0) {
+      total_friendly_health += static_cast<float>(unit->health) /
+                               static_cast<float>(unit->max_health);
+      ++valid_friendlies;
     }
   }
 
   for (const auto *enemy : enemies) {
-    if (enemy->maxHealth > 0) {
-      totalEnemyHealth += static_cast<float>(enemy->health) /
-                          static_cast<float>(enemy->maxHealth);
-      ++validEnemies;
+    if (enemy->max_health > 0) {
+      total_enemy_health += static_cast<float>(enemy->health) /
+                            static_cast<float>(enemy->max_health);
+      ++valid_enemies;
     }
   }
 
   result.avgFriendlyHealth =
-      validFriendlies > 0 ? (totalFriendlyHealth / validFriendlies) : 1.0f;
+      valid_friendlies > 0 ? (total_friendly_health / valid_friendlies) : 1.0F;
   result.avgEnemyHealth =
-      validEnemies > 0 ? (totalEnemyHealth / validEnemies) : 1.0f;
+      valid_enemies > 0 ? (total_enemy_health / valid_enemies) : 1.0F;
 
-  float friendlyStrength =
+  float const friendly_strength =
       static_cast<float>(result.friendlyCount) * result.avgFriendlyHealth;
-  float enemyStrength =
+  float const enemy_strength =
       static_cast<float>(result.enemyCount) * result.avgEnemyHealth;
 
-  if (enemyStrength < 0.01f) {
-    result.forceRatio = 10.0f;
+  if (enemy_strength < 0.01F) {
+    result.forceRatio = 10.0F;
   } else {
-    result.forceRatio = friendlyStrength / enemyStrength;
+    result.forceRatio = friendly_strength / enemy_strength;
   }
 
   result.confidenceLevel =
-      std::clamp((result.forceRatio - 0.5f) / 1.5f, 0.0f, 1.0f);
+      std::clamp((result.forceRatio - 0.5F) / 1.5F, 0.0F, 1.0F);
 
   result.shouldEngage = (result.forceRatio >= minForceRatio);
 
   return result;
 }
 
-TacticalUtils::TargetScore TacticalUtils::selectFocusFireTarget(
+auto TacticalUtils::selectFocusFireTarget(
     const std::vector<const EntitySnapshot *> &attackers,
-    const std::vector<const ContactSnapshot *> &enemies, float groupCenterX,
-    float groupCenterY, float groupCenterZ, const AIContext &context,
-    Engine::Core::EntityID currentTarget) {
+    const std::vector<const ContactSnapshot *> &enemies, float group_center_x,
+    float group_center_y, float group_center_z, const AIContext &context,
+    Engine::Core::EntityID currentTarget) -> TacticalUtils::TargetScore {
 
-  TargetScore bestTarget;
-  bestTarget.score = -std::numeric_limits<float>::infinity();
+  TargetScore best_target;
+  best_target.score = -std::numeric_limits<float>::infinity();
 
   if (enemies.empty()) {
-    return bestTarget;
+    return best_target;
   }
 
   for (const auto *enemy : enemies) {
-    float score = 0.0f;
+    float score = 0.0F;
 
-    float dist = distance(enemy->posX, enemy->posY, enemy->posZ, groupCenterX,
-                          groupCenterY, groupCenterZ);
-    score -= dist * 0.5f;
+    float const dist = distance(enemy->posX, enemy->posY, enemy->posZ,
+                                group_center_x, group_center_y, group_center_z);
+    score -= dist * 0.5F;
 
-    if (enemy->maxHealth > 0) {
-      float healthRatio = static_cast<float>(enemy->health) /
-                          static_cast<float>(enemy->maxHealth);
+    if (enemy->max_health > 0) {
+      float const health_ratio = static_cast<float>(enemy->health) /
+                                 static_cast<float>(enemy->max_health);
 
-      if (healthRatio < 0.5f) {
-        score += 8.0f * (1.0f - healthRatio);
+      if (health_ratio < 0.5F) {
+        score += 8.0F * (1.0F - health_ratio);
       }
 
-      if (healthRatio < 0.25f) {
-        score += 12.0f;
+      if (health_ratio < 0.25F) {
+        score += 12.0F;
       }
     }
 
-    float typePriority = getUnitTypePriority(
-        Game::Units::spawnTypeToString(enemy->spawnType), context.nation);
-    score += typePriority * 3.0f;
+    float const type_priority = getUnitTypePriority(
+        Game::Units::spawn_typeToString(enemy->spawn_type), context.nation);
+    score += type_priority * 3.0F;
 
     if (!enemy->isBuilding) {
-      score += 5.0f;
+      score += 5.0F;
     }
 
     if (currentTarget != 0 && enemy->id == currentTarget) {
-      score += 10.0f;
+      score += 10.0F;
     }
 
-    bool isolated = isTargetIsolated(*enemy, enemies, 8.0f);
+    bool const isolated = isTargetIsolated(*enemy, enemies, 8.0F);
     if (isolated) {
-      score += 6.0f;
+      score += 6.0F;
     }
 
     if (context.primaryBarracks != 0) {
-      float distToBase =
+      float const dist_to_base =
           distance(enemy->posX, enemy->posY, enemy->posZ, context.basePosX,
                    context.basePosY, context.basePosZ);
 
-      if (distToBase < 16.0f) {
-        score += (16.0f - distToBase) * 0.8f;
+      if (dist_to_base < 16.0F) {
+        score += (16.0F - dist_to_base) * 0.8F;
       }
     }
 
     if (context.state == AIState::Attacking && !enemy->isBuilding) {
-      score += 3.0f;
+      score += 3.0F;
     }
 
-    if (score > bestTarget.score) {
-      bestTarget.targetId = enemy->id;
-      bestTarget.score = score;
-      bestTarget.distanceToGroup = dist;
-      bestTarget.isLowHealth =
-          (enemy->maxHealth > 0 && enemy->health < enemy->maxHealth / 2);
-      bestTarget.isIsolated = isolated;
+    if (score > best_target.score) {
+      best_target.target_id = enemy->id;
+      best_target.score = score;
+      best_target.distanceToGroup = dist;
+      best_target.isLowHealth =
+          (enemy->max_health > 0 && enemy->health < enemy->max_health / 2);
+      best_target.isIsolated = isolated;
     }
   }
 
-  return bestTarget;
+  return best_target;
 }
 
-float TacticalUtils::calculateForceStrength(
-    const std::vector<const EntitySnapshot *> &units) {
+auto TacticalUtils::calculateForceStrength(
+    const std::vector<const EntitySnapshot *> &units) -> float {
 
-  float strength = 0.0f;
+  float strength = 0.0F;
   for (const auto *unit : units) {
-    if (unit->maxHealth > 0) {
-      float healthRatio = static_cast<float>(unit->health) /
-                          static_cast<float>(unit->maxHealth);
-      strength += healthRatio;
+    if (unit->max_health > 0) {
+      float const health_ratio = static_cast<float>(unit->health) /
+                                 static_cast<float>(unit->max_health);
+      strength += health_ratio;
     } else {
-      strength += 1.0f;
+      strength += 1.0F;
     }
   }
   return strength;
 }
 
-float TacticalUtils::calculateForceStrength(
-    const std::vector<const ContactSnapshot *> &units) {
+auto TacticalUtils::calculateForceStrength(
+    const std::vector<const ContactSnapshot *> &units) -> float {
 
-  float strength = 0.0f;
+  float strength = 0.0F;
   for (const auto *unit : units) {
-    if (unit->maxHealth > 0) {
-      float healthRatio = static_cast<float>(unit->health) /
-                          static_cast<float>(unit->maxHealth);
-      strength += healthRatio;
+    if (unit->max_health > 0) {
+      float const health_ratio = static_cast<float>(unit->health) /
+                                 static_cast<float>(unit->max_health);
+      strength += health_ratio;
     } else {
-      strength += 1.0f;
+      strength += 1.0F;
     }
   }
   return strength;
 }
 
-bool TacticalUtils::isTargetIsolated(
+auto TacticalUtils::isTargetIsolated(
     const ContactSnapshot &target,
     const std::vector<const ContactSnapshot *> &allEnemies,
-    float isolationRadius) {
+    float isolationRadius) -> bool {
 
-  const float isolationRadiusSq = isolationRadius * isolationRadius;
-  int nearbyAllies = 0;
+  const float isolation_radius_sq = isolationRadius * isolationRadius;
+  int nearby_allies = 0;
 
   for (const auto *enemy : allEnemies) {
 
@@ -189,39 +195,41 @@ bool TacticalUtils::isTargetIsolated(
       continue;
     }
 
-    float distSq = distanceSquared(target.posX, target.posY, target.posZ,
-                                   enemy->posX, enemy->posY, enemy->posZ);
+    float const dist_sq =
+        distance_squared(target.posX, target.posY, target.posZ, enemy->posX,
+                         enemy->posY, enemy->posZ);
 
-    if (distSq <= isolationRadiusSq) {
-      ++nearbyAllies;
+    if (dist_sq <= isolation_radius_sq) {
+      ++nearby_allies;
     }
   }
 
-  return (nearbyAllies <= 1);
+  return (nearby_allies <= 1);
 }
 
-float TacticalUtils::getUnitTypePriority(const std::string &unitType,
-                                         const Game::Systems::Nation *nation) {
+auto TacticalUtils::getUnitTypePriority(const std::string &unit_type,
+                                        const Game::Systems::Nation *nation)
+    -> float {
 
-  if (nation) {
-    auto troopType = Game::Units::troopTypeFromString(unitType);
-    if (nation->isRangedUnit(troopType)) {
-      return 3.0f;
+  if (nation != nullptr) {
+    auto troop_type = Game::Units::troop_typeFromString(unit_type);
+    if (nation->is_ranged_unit(troop_type)) {
+      return 3.0F;
     }
-    if (nation->isMeleeUnit(troopType)) {
-      return 2.0f;
+    if (nation->isMeleeUnit(troop_type)) {
+      return 2.0F;
     }
   }
 
-  if (unitType == "worker" || unitType == "villager") {
-    return 1.0f;
+  if (unit_type == "worker" || unit_type == "villager") {
+    return 1.0F;
   }
 
-  if (unitType == "barracks" || unitType == "base") {
-    return 0.5f;
+  if (unit_type == "barracks" || unit_type == "base") {
+    return 0.5F;
   }
 
-  return 1.5f;
+  return 1.5F;
 }
 
 } // namespace Game::Systems::AI

+ 23 - 24
game/systems/ai_system/ai_tactical.h

@@ -9,48 +9,47 @@ class TacticalUtils {
 public:
   struct EngagementAssessment {
     bool shouldEngage = false;
-    float forceRatio = 0.0f;
-    float confidenceLevel = 0.0f;
+    float forceRatio = 0.0F;
+    float confidenceLevel = 0.0F;
     int friendlyCount = 0;
     int enemyCount = 0;
-    float avgFriendlyHealth = 1.0f;
-    float avgEnemyHealth = 1.0f;
+    float avgFriendlyHealth = 1.0F;
+    float avgEnemyHealth = 1.0F;
   };
 
   struct TargetScore {
-    Engine::Core::EntityID targetId = 0;
-    float score = 0.0f;
-    float distanceToGroup = 0.0f;
+    Engine::Core::EntityID target_id = 0;
+    float score = 0.0F;
+    float distanceToGroup = 0.0F;
     bool isLowHealth = false;
     bool isIsolated = false;
   };
 
-  static EngagementAssessment
+  static auto
   assessEngagement(const std::vector<const EntitySnapshot *> &friendlies,
                    const std::vector<const ContactSnapshot *> &enemies,
-                   float minForceRatio = 0.8f);
+                   float minForceRatio = 0.8F) -> EngagementAssessment;
 
-  static TargetScore
-  selectFocusFireTarget(const std::vector<const EntitySnapshot *> &attackers,
-                        const std::vector<const ContactSnapshot *> &enemies,
-                        float groupCenterX, float groupCenterY,
-                        float groupCenterZ, const AIContext &context,
-                        Engine::Core::EntityID currentTarget = 0);
+  static auto selectFocusFireTarget(
+      const std::vector<const EntitySnapshot *> &attackers,
+      const std::vector<const ContactSnapshot *> &enemies, float group_center_x,
+      float group_center_y, float group_center_z, const AIContext &context,
+      Engine::Core::EntityID currentTarget = 0) -> TargetScore;
 
-  static float
-  calculateForceStrength(const std::vector<const EntitySnapshot *> &units);
+  static auto calculateForceStrength(
+      const std::vector<const EntitySnapshot *> &units) -> float;
 
-  static float
-  calculateForceStrength(const std::vector<const ContactSnapshot *> &units);
+  static auto calculateForceStrength(
+      const std::vector<const ContactSnapshot *> &units) -> float;
 
-  static bool
+  static auto
   isTargetIsolated(const ContactSnapshot &target,
                    const std::vector<const ContactSnapshot *> &allEnemies,
-                   float isolationRadius = 8.0f);
+                   float isolationRadius = 8.0F) -> bool;
 
-  static float
-  getUnitTypePriority(const std::string &unitType,
-                      const Game::Systems::Nation *nation = nullptr);
+  static auto
+  getUnitTypePriority(const std::string &unit_type,
+                      const Game::Systems::Nation *nation = nullptr) -> float;
 };
 
 } // namespace Game::Systems::AI

+ 35 - 35
game/systems/ai_system/ai_types.h

@@ -43,28 +43,28 @@ struct MovementSnapshot {
 struct ProductionSnapshot {
   bool hasComponent = false;
   bool inProgress = false;
-  float buildTime = 0.0f;
-  float timeRemaining = 0.0f;
+  float buildTime = 0.0F;
+  float timeRemaining = 0.0F;
   int producedCount = 0;
   int maxUnits = 0;
-  Game::Units::TroopType productType = Game::Units::TroopType::Archer;
+  Game::Units::TroopType product_type = Game::Units::TroopType::Archer;
   bool rallySet = false;
-  float rallyX = 0.0f;
-  float rallyZ = 0.0f;
+  float rallyX = 0.0F;
+  float rallyZ = 0.0F;
   int queueSize = 0;
 };
 
 struct EntitySnapshot {
   Engine::Core::EntityID id = 0;
-  Game::Units::SpawnType spawnType = Game::Units::SpawnType::Archer;
-  int ownerId = 0;
+  Game::Units::SpawnType spawn_type = Game::Units::SpawnType::Archer;
+  int owner_id = 0;
   int health = 0;
-  int maxHealth = 0;
+  int max_health = 0;
   bool isBuilding = false;
 
-  float posX = 0.0f;
-  float posY = 0.0f;
-  float posZ = 0.0f;
+  float posX = 0.0F;
+  float posY = 0.0F;
+  float posZ = 0.0F;
 
   MovementSnapshot movement;
   ProductionSnapshot production;
@@ -74,28 +74,28 @@ struct ContactSnapshot {
   Engine::Core::EntityID id = 0;
   bool isBuilding = false;
 
-  float posX = 0.0f;
-  float posY = 0.0f;
-  float posZ = 0.0f;
+  float posX = 0.0F;
+  float posY = 0.0F;
+  float posZ = 0.0F;
 
   int health = 0;
-  int maxHealth = 0;
-  Game::Units::SpawnType spawnType = Game::Units::SpawnType::Archer;
+  int max_health = 0;
+  Game::Units::SpawnType spawn_type = Game::Units::SpawnType::Archer;
 };
 
 struct AISnapshot {
-  int playerId = 0;
+  int player_id = 0;
   std::vector<EntitySnapshot> friendlies;
   std::vector<ContactSnapshot> visibleEnemies;
 
-  float gameTime = 0.0f;
+  float gameTime = 0.0F;
 };
 
 struct AIContext {
-  int playerId = 0;
+  int player_id = 0;
   AIState state = AIState::Idle;
-  float stateTimer = 0.0f;
-  float decisionTimer = 0.0f;
+  float stateTimer = 0.0F;
+  float decisionTimer = 0.0F;
 
   const Game::Systems::Nation *nation = nullptr;
 
@@ -103,25 +103,25 @@ struct AIContext {
   std::vector<Engine::Core::EntityID> buildings;
   Engine::Core::EntityID primaryBarracks = 0;
 
-  float rallyX = 0.0f;
-  float rallyZ = 0.0f;
+  float rallyX = 0.0F;
+  float rallyZ = 0.0F;
   int targetPriority = 0;
 
-  int totalUnits = 0;
+  int total_units = 0;
   int idleUnits = 0;
   int combatUnits = 0;
-  float averageHealth = 1.0f;
+  float averageHealth = 1.0F;
   bool barracksUnderThreat = false;
   int nearbyThreatCount = 0;
-  float closestThreatDistance = 0.0f;
+  float closest_threatDistance = 0.0F;
 
-  float basePosX = 0.0f;
-  float basePosY = 0.0f;
-  float basePosZ = 0.0f;
+  float basePosX = 0.0F;
+  float basePosY = 0.0F;
+  float basePosZ = 0.0F;
 
   struct UnitAssignment {
     BehaviorPriority ownerPriority = BehaviorPriority::Normal;
-    float assignmentTime = 0.0f;
+    float assignmentTime = 0.0F;
     std::string assignedTask;
   };
   std::unordered_map<Engine::Core::EntityID, UnitAssignment> assignedUnits;
@@ -132,9 +132,9 @@ struct AIContext {
 
   int visibleEnemyCount = 0;
   int enemyBuildingsCount = 0;
-  float averageEnemyDistance = 0.0f;
+  float averageEnemyDistance = 0.0F;
 
-  int maxTroopsPerPlayer = 50;
+  int max_troops_per_player = 50;
 
   std::unordered_map<Engine::Core::EntityID, float> buildingsUnderAttack;
 };
@@ -147,10 +147,10 @@ struct AICommand {
   std::vector<float> moveTargetY;
   std::vector<float> moveTargetZ;
 
-  Engine::Core::EntityID targetId = 0;
+  Engine::Core::EntityID target_id = 0;
   bool shouldChase = false;
   Engine::Core::EntityID buildingId = 0;
-  Game::Units::TroopType productType = Game::Units::TroopType::Archer;
+  Game::Units::TroopType product_type = Game::Units::TroopType::Archer;
 };
 
 struct AIResult {
@@ -161,7 +161,7 @@ struct AIResult {
 struct AIJob {
   AISnapshot snapshot;
   AIContext context;
-  float deltaTime = 0.0f;
+  float deltaTime = 0.0F;
 };
 
 } // namespace Game::Systems::AI

+ 40 - 36
game/systems/ai_system/ai_utils.h

@@ -20,69 +20,73 @@ inline void replicateLastTargetIfNeeded(const std::vector<float> &fromX,
   outY.clear();
   outZ.clear();
 
-  if (fromX.empty() || fromY.empty() || fromZ.empty())
+  if (fromX.empty() || fromY.empty() || fromZ.empty()) {
     return;
+  }
 
-  size_t srcSize = std::min({fromX.size(), fromY.size(), fromZ.size()});
+  size_t const srcSize = std::min({fromX.size(), fromY.size(), fromZ.size()});
 
   outX.reserve(wanted);
   outY.reserve(wanted);
   outZ.reserve(wanted);
 
   for (size_t i = 0; i < wanted; ++i) {
-    size_t idx = std::min(i, srcSize - 1);
+    size_t const idx = std::min(i, srcSize - 1);
     outX.push_back(fromX[idx]);
     outY.push_back(fromY[idx]);
     outZ.push_back(fromZ[idx]);
   }
 }
 
-inline bool isEntityEngaged(const EntitySnapshot &entity,
-                            const std::vector<ContactSnapshot> &enemies) {
+inline auto
+isEntityEngaged(const EntitySnapshot &entity,
+                const std::vector<ContactSnapshot> &enemies) -> bool {
 
-  if (entity.maxHealth > 0 && entity.health < entity.maxHealth)
+  if (entity.max_health > 0 && entity.health < entity.max_health) {
     return true;
+  }
 
-  constexpr float ENGAGED_RADIUS = 7.5f;
+  constexpr float ENGAGED_RADIUS = 7.5F;
   const float engagedSq = ENGAGED_RADIUS * ENGAGED_RADIUS;
 
   for (const auto &enemy : enemies) {
-    float dx = enemy.posX - entity.posX;
-    float dy = enemy.posY - entity.posY;
-    float dz = enemy.posZ - entity.posZ;
-    float distSq = dx * dx + dy * dy + dz * dz;
+    float const dx = enemy.posX - entity.posX;
+    float const dy = enemy.posY - entity.posY;
+    float const dz = enemy.posZ - entity.posZ;
+    float const dist_sq = dx * dx + dy * dy + dz * dz;
 
-    if (distSq <= engagedSq)
+    if (dist_sq <= engagedSq) {
       return true;
+    }
   }
 
   return false;
 }
 
-inline float distanceSquared(float x1, float y1, float z1, float x2, float y2,
-                             float z2) {
-  float dx = x2 - x1;
-  float dy = y2 - y1;
-  float dz = z2 - z1;
+inline auto distance_squared(float x1, float y1, float z1, float x2, float y2,
+                             float z2) -> float {
+  float const dx = x2 - x1;
+  float const dy = y2 - y1;
+  float const dz = z2 - z1;
   return dx * dx + dy * dy + dz * dz;
 }
 
-inline float distance(float x1, float y1, float z1, float x2, float y2,
-                      float z2) {
-  return std::sqrt(distanceSquared(x1, y1, z1, x2, y2, z2));
+inline auto distance(float x1, float y1, float z1, float x2, float y2,
+                     float z2) -> float {
+  return std::sqrt(distance_squared(x1, y1, z1, x2, y2, z2));
 }
 
-inline std::vector<Engine::Core::EntityID>
-claimUnits(const std::vector<Engine::Core::EntityID> &requestedUnits,
-           BehaviorPriority priority, const std::string &taskName,
-           AIContext &context, float currentTime,
-           float minLockDuration = 2.0f) {
+inline auto claimUnits(
+    const std::vector<Engine::Core::EntityID> &requestedUnits,
+    BehaviorPriority priority, const std::string &taskName, AIContext &context,
+    float currentTime,
+    float minLockDuration = 2.0F) -> std::vector<Engine::Core::EntityID> {
 
   std::vector<Engine::Core::EntityID> claimed;
   claimed.reserve(requestedUnits.size());
 
-  for (Engine::Core::EntityID unitId : requestedUnits) {
-    auto it = context.assignedUnits.find(unitId);
+  for (Engine::Core::EntityID const unit_id : requestedUnits) {
+    auto it = context.assignedUnits.find(unit_id);
 
     if (it == context.assignedUnits.end()) {
 
@@ -90,16 +94,16 @@ claimUnits(const std::vector<Engine::Core::EntityID> &requestedUnits,
       assignment.ownerPriority = priority;
       assignment.assignmentTime = currentTime;
       assignment.assignedTask = taskName;
-      context.assignedUnits[unitId] = assignment;
-      claimed.push_back(unitId);
+      context.assignedUnits[unit_id] = assignment;
+      claimed.push_back(unit_id);
 
     } else {
 
       const auto &existing = it->second;
-      float assignmentAge = currentTime - existing.assignmentTime;
+      float const assignmentAge = currentTime - existing.assignmentTime;
 
-      bool canSteal = (priority > existing.ownerPriority) &&
-                      (assignmentAge > minLockDuration);
+      bool const canSteal = (priority > existing.ownerPriority) &&
+                            (assignmentAge > minLockDuration);
 
       if (canSteal) {
 
@@ -107,8 +111,8 @@ claimUnits(const std::vector<Engine::Core::EntityID> &requestedUnits,
         assignment.ownerPriority = priority;
         assignment.assignmentTime = currentTime;
         assignment.assignedTask = taskName;
-        context.assignedUnits[unitId] = assignment;
-        claimed.push_back(unitId);
+        context.assignedUnits[unit_id] = assignment;
+        claimed.push_back(unit_id);
       }
     }
   }
@@ -118,8 +122,8 @@ claimUnits(const std::vector<Engine::Core::EntityID> &requestedUnits,
 
 inline void releaseUnits(const std::vector<Engine::Core::EntityID> &units,
                          AIContext &context) {
-  for (Engine::Core::EntityID unitId : units) {
-    context.assignedUnits.erase(unitId);
+  for (Engine::Core::EntityID const unit_id : units) {
+    context.assignedUnits.erase(unit_id);
   }
 }
 

+ 20 - 9
game/systems/ai_system/ai_worker.cpp

@@ -1,4 +1,12 @@
 #include "ai_worker.h"
+#include "systems/ai_system/ai_behavior_registry.h"
+#include "systems/ai_system/ai_executor.h"
+#include "systems/ai_system/ai_reasoner.h"
+#include "systems/ai_system/ai_types.h"
+#include <atomic>
+#include <mutex>
+#include <queue>
+#include <utility>
 
 namespace Game::Systems::AI {
 
@@ -12,7 +20,7 @@ AIWorker::AIWorker(AIReasoner &reasoner, AIExecutor &executor,
 AIWorker::~AIWorker() {
   stop();
 
-  { std::lock_guard<std::mutex> lock(m_jobMutex); }
+  { std::lock_guard<std::mutex> const lock(m_jobMutex); }
   m_jobCondition.notify_all();
 
   if (m_thread.joinable()) {
@@ -20,14 +28,14 @@ AIWorker::~AIWorker() {
   }
 }
 
-bool AIWorker::trySubmit(AIJob &&job) {
+auto AIWorker::trySubmit(AIJob &&job) -> bool {
 
   if (m_workerBusy.load(std::memory_order_acquire)) {
     return false;
   }
 
   {
-    std::lock_guard<std::mutex> lock(m_jobMutex);
+    std::lock_guard<std::mutex> const lock(m_jobMutex);
     m_pendingJob = std::move(job);
     m_hasPendingJob = true;
   }
@@ -39,7 +47,7 @@ bool AIWorker::trySubmit(AIJob &&job) {
 }
 
 void AIWorker::drainResults(std::queue<AIResult> &out) {
-  std::lock_guard<std::mutex> lock(m_resultMutex);
+  std::lock_guard<std::mutex> const lock(m_resultMutex);
 
   while (!m_results.empty()) {
     out.push(std::move(m_results.front()));
@@ -71,13 +79,16 @@ void AIWorker::workerLoop() {
       AIResult result;
       result.context = job.context;
 
-      m_reasoner.updateContext(job.snapshot, result.context);
-      m_reasoner.updateStateMachine(result.context, job.deltaTime);
-      m_executor.run(job.snapshot, result.context, job.deltaTime, m_registry,
-                     result.commands);
+      Game::Systems::AI::AIReasoner::updateContext(job.snapshot,
+                                                   result.context);
+      Game::Systems::AI::AIReasoner::updateStateMachine(result.context,
+                                                        job.deltaTime);
+      Game::Systems::AI::AIExecutor::run(job.snapshot, result.context,
+                                         job.deltaTime, m_registry,
+                                         result.commands);
 
       {
-        std::lock_guard<std::mutex> lock(m_resultMutex);
+        std::lock_guard<std::mutex> const lock(m_resultMutex);
         m_results.push(std::move(result));
       }
     } catch (...) {

+ 4 - 4
game/systems/ai_system/ai_worker.h

@@ -20,15 +20,15 @@ public:
   ~AIWorker();
 
   AIWorker(const AIWorker &) = delete;
-  AIWorker &operator=(const AIWorker &) = delete;
+  auto operator=(const AIWorker &) -> AIWorker & = delete;
   AIWorker(AIWorker &&) = delete;
-  AIWorker &operator=(AIWorker &&) = delete;
+  auto operator=(AIWorker &&) -> AIWorker & = delete;
 
-  bool trySubmit(AIJob &&job);
+  auto trySubmit(AIJob &&job) -> bool;
 
   void drainResults(std::queue<AIResult> &out);
 
-  bool busy() const noexcept {
+  auto busy() const noexcept -> bool {
     return m_workerBusy.load(std::memory_order_acquire);
   }
 

+ 127 - 122
game/systems/ai_system/behaviors/attack_behavior.cpp

@@ -1,10 +1,12 @@
 #include "attack_behavior.h"
 #include "../ai_tactical.h"
 #include "../ai_utils.h"
+#include "systems/ai_system/ai_types.h"
 
-#include <algorithm>
 #include <cmath>
 #include <limits>
+#include <utility>
+#include <vector>
 
 namespace Game::Systems::AI {
 
@@ -14,23 +16,23 @@ void AttackBehavior::execute(const AISnapshot &snapshot, AIContext &context,
   m_attackTimer += deltaTime;
   m_targetLockDuration += deltaTime;
 
-  if (m_attackTimer < 1.5f) {
+  if (m_attackTimer < 1.5F) {
     return;
   }
-  m_attackTimer = 0.0f;
+  m_attackTimer = 0.0F;
 
   if (snapshot.visibleEnemies.empty()) {
     return;
   }
 
-  std::vector<const EntitySnapshot *> engagedUnits;
-  std::vector<const EntitySnapshot *> readyUnits;
-  engagedUnits.reserve(snapshot.friendlies.size());
-  readyUnits.reserve(snapshot.friendlies.size());
+  std::vector<const EntitySnapshot *> engaged_units;
+  std::vector<const EntitySnapshot *> ready_units;
+  engaged_units.reserve(snapshot.friendlies.size());
+  ready_units.reserve(snapshot.friendlies.size());
 
-  float groupCenterX = 0.0f;
-  float groupCenterY = 0.0f;
-  float groupCenterZ = 0.0f;
+  float group_center_x = 0.0F;
+  float group_center_y = 0.0F;
+  float group_center_z = 0.0F;
 
   for (const auto &entity : snapshot.friendlies) {
     if (entity.isBuilding) {
@@ -38,223 +40,226 @@ void AttackBehavior::execute(const AISnapshot &snapshot, AIContext &context,
     }
 
     if (isEntityEngaged(entity, snapshot.visibleEnemies)) {
-      engagedUnits.push_back(&entity);
+      engaged_units.push_back(&entity);
       continue;
     }
 
-    readyUnits.push_back(&entity);
-    groupCenterX += entity.posX;
-    groupCenterY += entity.posY;
-    groupCenterZ += entity.posZ;
+    ready_units.push_back(&entity);
+    group_center_x += entity.posX;
+    group_center_y += entity.posY;
+    group_center_z += entity.posZ;
   }
 
-  if (readyUnits.empty()) {
+  if (ready_units.empty()) {
 
-    if (!engagedUnits.empty()) {
+    if (!engaged_units.empty()) {
     }
     return;
   }
 
-  float invCount = 1.0f / static_cast<float>(readyUnits.size());
-  groupCenterX *= invCount;
-  groupCenterY *= invCount;
-  groupCenterZ *= invCount;
+  float const inv_count = 1.0F / static_cast<float>(ready_units.size());
+  group_center_x *= inv_count;
+  group_center_y *= inv_count;
+  group_center_z *= inv_count;
 
-  std::vector<const ContactSnapshot *> nearbyEnemies;
-  nearbyEnemies.reserve(snapshot.visibleEnemies.size());
+  std::vector<const ContactSnapshot *> nearby_enemies;
+  nearby_enemies.reserve(snapshot.visibleEnemies.size());
 
-  const float ENGAGEMENT_RANGE =
-      (context.damagedUnitsCount > 0) ? 35.0f : 20.0f;
-  const float engageRangeSq = ENGAGEMENT_RANGE * ENGAGEMENT_RANGE;
+  const float engagement_range =
+      (context.damagedUnitsCount > 0) ? 35.0F : 20.0F;
+  const float engage_range_sq = engagement_range * engagement_range;
 
   for (const auto &enemy : snapshot.visibleEnemies) {
-    float distSq = distanceSquared(enemy.posX, enemy.posY, enemy.posZ,
-                                   groupCenterX, groupCenterY, groupCenterZ);
-    if (distSq <= engageRangeSq) {
-      nearbyEnemies.push_back(&enemy);
+    float const dist_sq =
+        distance_squared(enemy.posX, enemy.posY, enemy.posZ, group_center_x,
+                         group_center_y, group_center_z);
+    if (dist_sq <= engage_range_sq) {
+      nearby_enemies.push_back(&enemy);
     }
   }
 
-  if (nearbyEnemies.empty()) {
+  if (nearby_enemies.empty()) {
 
-    bool shouldAdvance =
+    bool const should_advance =
         (context.state == AIState::Attacking) ||
-        (context.state == AIState::Gathering && context.totalUnits >= 3);
+        (context.state == AIState::Gathering && context.total_units >= 3);
 
-    if (shouldAdvance && !snapshot.visibleEnemies.empty()) {
+    if (should_advance && !snapshot.visibleEnemies.empty()) {
 
-      const ContactSnapshot *targetBarracks = nullptr;
-      float closestBarracksDistSq = std::numeric_limits<float>::max();
+      const ContactSnapshot *target_barracks = nullptr;
+      float closest_barracks_dist_sq = std::numeric_limits<float>::max();
 
       for (const auto &enemy : snapshot.visibleEnemies) {
         if (enemy.isBuilding) {
-          float distSq =
-              distanceSquared(enemy.posX, enemy.posY, enemy.posZ, groupCenterX,
-                              groupCenterY, groupCenterZ);
-          if (distSq < closestBarracksDistSq) {
-            closestBarracksDistSq = distSq;
-            targetBarracks = &enemy;
+          float const dist_sq =
+              distance_squared(enemy.posX, enemy.posY, enemy.posZ,
+                               group_center_x, group_center_y, group_center_z);
+          if (dist_sq < closest_barracks_dist_sq) {
+            closest_barracks_dist_sq = dist_sq;
+            target_barracks = &enemy;
           }
         }
       }
 
-      const ContactSnapshot *closestEnemy = nullptr;
-      float closestDistSq = std::numeric_limits<float>::max();
+      const ContactSnapshot *closest_enemy = nullptr;
+      float closest_dist_sq = std::numeric_limits<float>::max();
 
-      if (!targetBarracks) {
+      if (target_barracks == nullptr) {
         for (const auto &enemy : snapshot.visibleEnemies) {
-          float distSq =
-              distanceSquared(enemy.posX, enemy.posY, enemy.posZ, groupCenterX,
-                              groupCenterY, groupCenterZ);
-          if (distSq < closestDistSq) {
-            closestDistSq = distSq;
-            closestEnemy = &enemy;
+          float const dist_sq =
+              distance_squared(enemy.posX, enemy.posY, enemy.posZ,
+                               group_center_x, group_center_y, group_center_z);
+          if (dist_sq < closest_dist_sq) {
+            closest_dist_sq = dist_sq;
+            closest_enemy = &enemy;
           }
         }
       }
 
       const ContactSnapshot *target =
-          targetBarracks ? targetBarracks : closestEnemy;
+          (target_barracks != nullptr) ? target_barracks : closest_enemy;
 
-      if (target && readyUnits.size() >= 1) {
+      if ((target != nullptr) && !ready_units.empty()) {
 
-        float attackPosX = target->posX;
-        float attackPosZ = target->posZ;
+        float attack_pos_x = target->posX;
+        float attack_pos_z = target->posZ;
 
-        if (targetBarracks) {
+        if (target_barracks != nullptr) {
 
-          float dx = groupCenterX - target->posX;
-          float dz = groupCenterZ - target->posZ;
-          float dist = std::sqrt(dx * dx + dz * dz);
-          if (dist > 0.1f) {
-            attackPosX += (dx / dist) * 3.0f;
-            attackPosZ += (dz / dist) * 3.0f;
+          float const dx = group_center_x - target->posX;
+          float const dz = group_center_z - target->posZ;
+          float const dist = std::sqrt(dx * dx + dz * dz);
+          if (dist > 0.1F) {
+            attack_pos_x += (dx / dist) * 3.0F;
+            attack_pos_z += (dz / dist) * 3.0F;
           } else {
-            attackPosX += 3.0f;
+            attack_pos_x += 3.0F;
           }
         }
 
-        bool needsNewCommand = false;
+        bool needs_new_command = false;
         if (m_lastTarget != target->id) {
-          needsNewCommand = true;
+          needs_new_command = true;
           m_lastTarget = target->id;
-          m_targetLockDuration = 0.0f;
+          m_targetLockDuration = 0.0F;
         } else {
 
-          for (const auto *unit : readyUnits) {
-            float dx = unit->posX - attackPosX;
-            float dz = unit->posZ - attackPosZ;
-            float distSq = dx * dx + dz * dz;
-            if (distSq > 15.0f * 15.0f) {
-              needsNewCommand = true;
+          for (const auto *unit : ready_units) {
+            float const dx = unit->posX - attack_pos_x;
+            float const dz = unit->posZ - attack_pos_z;
+            float const dist_sq = dx * dx + dz * dz;
+            if (dist_sq > 15.0F * 15.0F) {
+              needs_new_command = true;
               break;
             }
           }
         }
 
-        if (needsNewCommand) {
-          std::vector<Engine::Core::EntityID> unitIds;
-          std::vector<float> targetX, targetY, targetZ;
-
-          for (const auto *unit : readyUnits) {
-            unitIds.push_back(unit->id);
-            targetX.push_back(attackPosX);
-            targetY.push_back(0.0f);
-            targetZ.push_back(attackPosZ);
+        if (needs_new_command) {
+          std::vector<Engine::Core::EntityID> unit_ids;
+          std::vector<float> target_x;
+          std::vector<float> target_y;
+          std::vector<float> target_z;
+
+          for (const auto *unit : ready_units) {
+            unit_ids.push_back(unit->id);
+            target_x.push_back(attack_pos_x);
+            target_y.push_back(0.0F);
+            target_z.push_back(attack_pos_z);
           }
 
           AICommand cmd;
           cmd.type = AICommandType::MoveUnits;
-          cmd.units = std::move(unitIds);
-          cmd.moveTargetX = std::move(targetX);
-          cmd.moveTargetY = std::move(targetY);
-          cmd.moveTargetZ = std::move(targetZ);
+          cmd.units = std::move(unit_ids);
+          cmd.moveTargetX = std::move(target_x);
+          cmd.moveTargetY = std::move(target_y);
+          cmd.moveTargetZ = std::move(target_z);
           outCommands.push_back(cmd);
         }
       }
     }
 
     m_lastTarget = 0;
-    m_targetLockDuration = 0.0f;
+    m_targetLockDuration = 0.0F;
     return;
   }
 
   auto assessment = TacticalUtils::assessEngagement(
-      readyUnits, nearbyEnemies,
-      context.state == AIState::Attacking ? 0.7f : 0.9f);
+      ready_units, nearby_enemies,
+      context.state == AIState::Attacking ? 0.7F : 0.9F);
 
-  bool beingAttacked = context.damagedUnitsCount > 0;
+  bool const being_attacked = context.damagedUnitsCount > 0;
 
   if (!assessment.shouldEngage && !context.barracksUnderThreat &&
-      !beingAttacked) {
+      !being_attacked) {
 
     m_lastTarget = 0;
-    m_targetLockDuration = 0.0f;
+    m_targetLockDuration = 0.0F;
     return;
   }
 
-  bool lastTargetStillValid = false;
+  bool last_target_still_valid = false;
   if (m_lastTarget != 0) {
-    for (const auto *enemy : nearbyEnemies) {
+    for (const auto *enemy : nearby_enemies) {
       if (enemy->id == m_lastTarget) {
-        lastTargetStillValid = true;
+        last_target_still_valid = true;
         break;
       }
     }
   }
 
-  if (!lastTargetStillValid || m_targetLockDuration > 8.0f) {
+  if (!last_target_still_valid || m_targetLockDuration > 8.0F) {
     m_lastTarget = 0;
-    m_targetLockDuration = 0.0f;
+    m_targetLockDuration = 0.0F;
   }
 
-  auto targetInfo = TacticalUtils::selectFocusFireTarget(
-      readyUnits, nearbyEnemies, groupCenterX, groupCenterY, groupCenterZ,
-      context, m_lastTarget);
+  auto target_info = TacticalUtils::selectFocusFireTarget(
+      ready_units, nearby_enemies, group_center_x, group_center_y,
+      group_center_z, context, m_lastTarget);
 
-  if (targetInfo.targetId == 0) {
+  if (target_info.target_id == 0) {
     return;
   }
 
-  if (targetInfo.targetId != m_lastTarget) {
-    m_lastTarget = targetInfo.targetId;
-    m_targetLockDuration = 0.0f;
+  if (target_info.target_id != m_lastTarget) {
+    m_lastTarget = target_info.target_id;
+    m_targetLockDuration = 0.0F;
   }
 
-  std::vector<Engine::Core::EntityID> unitIds;
-  unitIds.reserve(readyUnits.size());
-  for (const auto *unit : readyUnits) {
-    unitIds.push_back(unit->id);
+  std::vector<Engine::Core::EntityID> unit_ids;
+  unit_ids.reserve(ready_units.size());
+  for (const auto *unit : ready_units) {
+    unit_ids.push_back(unit->id);
   }
 
-  auto claimedUnits = claimUnits(unitIds, getPriority(), "attacking", context,
-                                 m_attackTimer + deltaTime, 2.5f);
+  auto claimed_units = claimUnits(unit_ids, getPriority(), "attacking", context,
+                                  m_attackTimer + deltaTime, 2.5F);
 
-  if (claimedUnits.empty()) {
+  if (claimed_units.empty()) {
     return;
   }
 
   AICommand command;
   command.type = AICommandType::AttackTarget;
-  command.units = std::move(claimedUnits);
-  command.targetId = targetInfo.targetId;
+  command.units = std::move(claimed_units);
+  command.target_id = target_info.target_id;
 
-  bool shouldChaseAggressive =
+  bool const should_chase_aggressive =
       (context.state == AIState::Attacking || context.barracksUnderThreat) &&
-      assessment.forceRatio >= 0.8f;
+      assessment.forceRatio >= 0.8F;
 
-  command.shouldChase = shouldChaseAggressive;
+  command.shouldChase = should_chase_aggressive;
 
   outCommands.push_back(std::move(command));
 }
-bool AttackBehavior::shouldExecute(const AISnapshot &snapshot,
-                                   const AIContext &context) const {
+auto AttackBehavior::should_execute(const AISnapshot &snapshot,
+                                    const AIContext &context) const -> bool {
 
   if (context.state == AIState::Retreating) {
     return false;
   }
 
-  int readyUnits = 0;
+  int ready_units = 0;
   for (const auto &entity : snapshot.friendlies) {
     if (entity.isBuilding) {
       continue;
@@ -264,10 +269,10 @@ bool AttackBehavior::shouldExecute(const AISnapshot &snapshot,
       continue;
     }
 
-    ++readyUnits;
+    ++ready_units;
   }
 
-  if (readyUnits == 0) {
+  if (ready_units == 0) {
     return false;
   }
 
@@ -280,10 +285,10 @@ bool AttackBehavior::shouldExecute(const AISnapshot &snapshot,
   }
 
   if (context.state == AIState::Defending) {
-    return context.barracksUnderThreat && readyUnits >= 2;
+    return context.barracksUnderThreat && ready_units >= 2;
   }
 
-  return readyUnits >= 1;
+  return ready_units >= 1;
 }
 
 } // namespace Game::Systems::AI

+ 9 - 6
game/systems/ai_system/behaviors/attack_behavior.h

@@ -9,19 +9,22 @@ public:
   void execute(const AISnapshot &snapshot, AIContext &context, float deltaTime,
                std::vector<AICommand> &outCommands) override;
 
-  bool shouldExecute(const AISnapshot &snapshot,
-                     const AIContext &context) const override;
+  [[nodiscard]] auto
+  should_execute(const AISnapshot &snapshot,
+                 const AIContext &context) const -> bool override;
 
-  BehaviorPriority getPriority() const override {
+  [[nodiscard]] auto getPriority() const -> BehaviorPriority override {
     return BehaviorPriority::Normal;
   }
 
-  bool canRunConcurrently() const override { return false; }
+  [[nodiscard]] auto canRunConcurrently() const -> bool override {
+    return false;
+  }
 
 private:
-  float m_attackTimer = 0.0f;
+  float m_attackTimer = 0.0F;
   Engine::Core::EntityID m_lastTarget = 0;
-  float m_targetLockDuration = 0.0f;
+  float m_targetLockDuration = 0.0F;
 };
 
 } // namespace Game::Systems::AI

Some files were not shown because too many files changed in this diff