Browse Source

apply format

djeada 16 hours ago
parent
commit
80f81a2cd1

+ 8 - 26
app/controllers/command_controller.cpp

@@ -121,8 +121,6 @@ auto CommandController::on_hold_command() -> CommandResult {
     return result;
   }
 
-  // First, determine if all eligible units already have hold mode active
-  // If all do, we disable it; if any don't, we enable it for all
   int eligible_count = 0;
   int hold_active_count = 0;
 
@@ -137,7 +135,6 @@ auto CommandController::on_hold_command() -> CommandResult {
       continue;
     }
 
-    // Skip buildings
     if (unit->spawn_type == Game::Units::SpawnType::Barracks) {
       continue;
     }
@@ -154,7 +151,6 @@ auto CommandController::on_hold_command() -> CommandResult {
     return result;
   }
 
-  // Determine target state: if all have hold active, disable; otherwise enable
   const bool should_enable_hold = (hold_active_count < eligible_count);
 
   for (auto id : selected) {
@@ -168,7 +164,6 @@ auto CommandController::on_hold_command() -> CommandResult {
       continue;
     }
 
-    // Skip buildings
     if (unit->spawn_type == Game::Units::SpawnType::Barracks) {
       continue;
     }
@@ -176,7 +171,7 @@ auto CommandController::on_hold_command() -> CommandResult {
     auto *hold_mode = entity->get_component<Engine::Core::HoldModeComponent>();
 
     if (should_enable_hold) {
-      // Enable hold mode
+
       reset_movement(entity);
       entity->remove_component<Engine::Core::AttackTargetComponent>();
 
@@ -201,7 +196,7 @@ auto CommandController::on_hold_command() -> CommandResult {
         movement->vz = 0.0F;
       }
     } else {
-      // Disable hold mode
+
       if ((hold_mode != nullptr) && hold_mode->active) {
         hold_mode->active = false;
         hold_mode->exit_cooldown = hold_mode->stand_up_duration;
@@ -293,10 +288,9 @@ auto CommandController::on_patrol_click(qreal sx, qreal sy, int viewport_width,
   return result;
 }
 
-auto CommandController::set_rally_at_screen(qreal sx, qreal sy,
-                                            int viewport_width,
-                                            int viewport_height, void *camera,
-                                            int local_owner_id) -> CommandResult {
+auto CommandController::set_rally_at_screen(
+    qreal sx, qreal sy, int viewport_width, int viewport_height, void *camera,
+    int local_owner_id) -> CommandResult {
   CommandResult result;
   if ((m_world == nullptr) || (m_selection_system == nullptr) ||
       (m_picking_service == nullptr) || (camera == nullptr)) {
@@ -396,8 +390,6 @@ auto CommandController::on_guard_command() -> CommandResult {
     return result;
   }
 
-  // First, determine if all eligible units already have guard mode active
-  // If all do, we disable it; if any don't, we enable it for all
   int eligible_count = 0;
   int guard_active_count = 0;
 
@@ -412,7 +404,6 @@ auto CommandController::on_guard_command() -> CommandResult {
       continue;
     }
 
-    // Skip buildings
     if (unit->spawn_type == Game::Units::SpawnType::Barracks) {
       continue;
     }
@@ -430,7 +421,6 @@ auto CommandController::on_guard_command() -> CommandResult {
     return result;
   }
 
-  // Determine target state: if all have guard active, disable; otherwise enable
   const bool should_enable_guard = (guard_active_count < eligible_count);
 
   for (auto id : selected) {
@@ -444,7 +434,6 @@ auto CommandController::on_guard_command() -> CommandResult {
       continue;
     }
 
-    // Skip buildings
     if (unit->spawn_type == Game::Units::SpawnType::Barracks) {
       continue;
     }
@@ -453,14 +442,13 @@ auto CommandController::on_guard_command() -> CommandResult {
         entity->get_component<Engine::Core::GuardModeComponent>();
 
     if (should_enable_guard) {
-      // Enable guard mode at current position
+
       if (guard_mode == nullptr) {
         guard_mode = entity->add_component<Engine::Core::GuardModeComponent>();
       }
       guard_mode->active = true;
       guard_mode->returning_to_guard_position = false;
 
-      // Set guard position to current position
       auto *transform =
           entity->get_component<Engine::Core::TransformComponent>();
       if (transform != nullptr) {
@@ -470,21 +458,19 @@ auto CommandController::on_guard_command() -> CommandResult {
         guard_mode->guarded_entity_id = 0;
       }
 
-      // Disable hold mode if active
       auto *hold_mode =
           entity->get_component<Engine::Core::HoldModeComponent>();
       if ((hold_mode != nullptr) && hold_mode->active) {
         hold_mode->active = false;
       }
 
-      // Clear patrol
       if (auto *patrol =
               entity->get_component<Engine::Core::PatrolComponent>()) {
         patrol->patrolling = false;
         patrol->waypoints.clear();
       }
     } else {
-      // Disable guard mode
+
       if ((guard_mode != nullptr) && guard_mode->active) {
         guard_mode->active = false;
         guard_mode->guarded_entity_id = 0;
@@ -527,7 +513,6 @@ auto CommandController::on_guard_click(qreal sx, qreal sy, int viewport_width,
     return result;
   }
 
-  // Set guard position for all selected units
   for (auto id : selected) {
     auto *entity = m_world->get_entity(id);
     if (entity == nullptr) {
@@ -552,15 +537,12 @@ auto CommandController::on_guard_click(qreal sx, qreal sy, int viewport_width,
     guard_mode->returning_to_guard_position = false;
     guard_mode->has_guard_target = true;
 
-    // Disable hold mode if active
     auto *hold_mode = entity->get_component<Engine::Core::HoldModeComponent>();
     if ((hold_mode != nullptr) && hold_mode->active) {
       hold_mode->active = false;
     }
 
-    // Clear patrol
-    if (auto *patrol =
-            entity->get_component<Engine::Core::PatrolComponent>()) {
+    if (auto *patrol = entity->get_component<Engine::Core::PatrolComponent>()) {
       patrol->patrolling = false;
       patrol->waypoints.clear();
     }

+ 5 - 9
app/core/game_engine.cpp

@@ -259,7 +259,6 @@ GameEngine::GameEngine(QObject *parent)
   }
 
   connect(m_cursorManager.get(), &CursorManager::mode_changed, this, [this]() {
-    // Update the Qt cursor shape on the window when mode changes
     if (m_cursorManager && m_window) {
       m_cursorManager->update_cursor_shape(m_window);
     }
@@ -779,7 +778,8 @@ void GameEngine::render(int pixelWidth, int pixelHeight) {
 
   if (auto *res = m_renderer->resources()) {
     std::optional<QVector3D> preview_waypoint;
-    if (m_commandController && m_commandController->has_patrol_first_waypoint()) {
+    if (m_commandController &&
+        m_commandController->has_patrol_first_waypoint()) {
       preview_waypoint = m_commandController->get_patrol_first_waypoint();
     }
     Render::GL::renderPatrolFlags(m_renderer.get(), res, *m_world,
@@ -839,8 +839,6 @@ void GameEngine::sync_selection_flags() {
 
   App::Utils::sanitize_selection(m_world.get(), selection_system);
 
-  // Reset cursor mode to Normal when selection becomes empty
-  // This ensures the cursor mode doesn't persist without any units selected
   if (selection_system->get_selected_units().empty()) {
     if (m_cursorManager && m_cursorManager->mode() != CursorMode::Normal) {
       set_cursor_mode(CursorMode::Normal);
@@ -949,7 +947,8 @@ void GameEngine::recruit_near_selected(const QString &unit_type) {
   if (!m_commandController) {
     return;
   }
-  m_commandController->recruit_near_selected(unit_type, m_runtime.local_owner_id);
+  m_commandController->recruit_near_selected(unit_type,
+                                             m_runtime.local_owner_id);
 }
 
 auto GameEngine::get_selected_production_state() const -> QVariantMap {
@@ -1098,15 +1097,13 @@ auto GameEngine::get_selected_units_mode_availability() const -> QVariantMap {
     return result;
   }
 
-  // Check mode availability across all selected units
-  // If ANY unit cannot use a mode, that mode is disabled
   bool can_attack = true;
   bool can_guard = true;
   bool can_hold = true;
   bool can_patrol = true;
 
   for (auto id : sel) {
-    // Early exit if all modes are already disabled
+
     if (!can_attack && !can_guard && !can_hold && !can_patrol) {
       break;
     }
@@ -1121,7 +1118,6 @@ auto GameEngine::get_selected_units_mode_availability() const -> QVariantMap {
       continue;
     }
 
-    // Skip buildings
     if (u->spawn_type == Game::Units::SpawnType::Barracks) {
       continue;
     }

+ 2 - 2
app/core/game_engine.h

@@ -227,8 +227,8 @@ public:
   Q_INVOKABLE [[nodiscard]] QVariantMap
   get_unit_production_info(const QString &unit_type) const;
   Q_INVOKABLE [[nodiscard]] QString get_selected_units_command_mode() const;
-  Q_INVOKABLE [[nodiscard]] QVariantMap get_selected_units_mode_availability()
-      const;
+  Q_INVOKABLE [[nodiscard]] QVariantMap
+  get_selected_units_mode_availability() const;
   Q_INVOKABLE void set_rally_at_screen(qreal sx, qreal sy);
   Q_INVOKABLE [[nodiscard]] QVariantList available_maps() const;
   [[nodiscard]] QVariantList available_nations() const;

+ 4 - 4
app/core/input_command_handler.cpp

@@ -111,8 +111,8 @@ void InputCommandHandler::on_attack_click(qreal sx, qreal sy,
     return;
   }
 
-  auto result = m_command_controller->on_attack_click(sx, sy, viewport.width,
-                                                      viewport.height, m_camera);
+  auto result = m_command_controller->on_attack_click(
+      sx, sy, viewport.width, viewport.height, m_camera);
 
   auto *selection_system =
       m_world->get_system<Game::Systems::SelectionSystem>();
@@ -229,8 +229,8 @@ void InputCommandHandler::on_patrol_click(qreal sx, qreal sy,
     return;
   }
 
-  auto result = m_command_controller->on_patrol_click(sx, sy, viewport.width,
-                                                      viewport.height, m_camera);
+  auto result = m_command_controller->on_patrol_click(
+      sx, sy, viewport.width, viewport.height, m_camera);
   if (result.reset_cursor_to_normal) {
     m_cursor_manager->set_mode(CursorMode::Normal);
   }

+ 3 - 1
app/models/cursor_manager.cpp

@@ -68,4 +68,6 @@ void CursorManager::set_patrol_first_waypoint(const QVector3D &waypoint) {
   m_has_first_waypoint = true;
 }
 
-void CursorManager::clear_patrol_first_waypoint() { m_has_first_waypoint = false; }
+void CursorManager::clear_patrol_first_waypoint() {
+  m_has_first_waypoint = false;
+}

+ 3 - 5
game/systems/ai_system/behaviors/attack_behavior.cpp

@@ -149,18 +149,16 @@ void AttackBehavior::execute(const AISnapshot &snapshot, AIContext &context,
 
     if (should_advance && !snapshot.visible_enemies.empty()) {
 
-      // Don't auto-attack buildings - they should only be targeted explicitly
-      // Find closest enemy troop (not building) to advance toward
       const ContactSnapshot *closest_enemy = nullptr;
       float closest_dist_sq = std::numeric_limits<float>::max();
 
       for (const auto &enemy : snapshot.visible_enemies) {
         if (enemy.is_building) {
-          continue; // Skip buildings - only target troops
+          continue;
         }
         float const dist_sq =
-            distance_squared(enemy.posX, enemy.posY, enemy.posZ,
-                             group_center_x, group_center_y, group_center_z);
+            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;

+ 0 - 1
game/systems/patrol_system.cpp

@@ -54,7 +54,6 @@ void PatrolSystem::update(Engine::Core::World *world, float) {
         continue;
       }
 
-      // Don't auto-attack buildings - they should only be targeted explicitly
       if (other->has_component<Engine::Core::BuildingComponent>()) {
         continue;
       }

+ 0 - 8
game/units/spawn_type.h

@@ -141,27 +141,19 @@ inline auto is_building_spawn(SpawnType type) -> bool {
   return type == SpawnType::Barracks;
 }
 
-// Check if a unit type can use attack mode
-// Healers cannot attack
 inline auto can_use_attack_mode(SpawnType type) -> bool {
   return type != SpawnType::Healer && type != SpawnType::Barracks;
 }
 
-// Check if a unit type can use guard mode
-// All troops can guard
 inline auto can_use_guard_mode(SpawnType type) -> bool {
   return type != SpawnType::Barracks;
 }
 
-// Check if a unit type can use hold mode
-// Only swordsman (Knight), spearman, and archer can use hold mode
 inline auto can_use_hold_mode(SpawnType type) -> bool {
   return type == SpawnType::Archer || type == SpawnType::Knight ||
          type == SpawnType::Spearman;
 }
 
-// Check if a unit type can use patrol mode
-// All troops can patrol
 inline auto can_use_patrol_mode(SpawnType type) -> bool {
   return type != SpawnType::Barracks;
 }

+ 87 - 83
render/geom/mode_indicator.cpp

@@ -17,7 +17,6 @@ std::unique_ptr<Render::GL::Mesh> ModeIndicator::s_guard_mesh;
 std::unique_ptr<Render::GL::Mesh> ModeIndicator::s_hold_mesh;
 std::unique_ptr<Render::GL::Mesh> ModeIndicator::s_patrol_mesh;
 
-// Attack mode: crossed swords
 auto ModeIndicator::create_attack_mode_mesh()
     -> std::unique_ptr<Render::GL::Mesh> {
   using namespace Render::GL;
@@ -31,12 +30,12 @@ auto ModeIndicator::create_attack_mode_mesh()
   constexpr float cross_guard_width = 0.25F;
   constexpr float cross_guard_height = 0.06F;
   constexpr float blade_tip_width = 0.03F;
-  constexpr float handle_offset = 0.25F; // Offset handles so swords cross at top
+  constexpr float handle_offset = 0.25F;
   constexpr float guard_position_ratio = 0.15F;
   constexpr float handle_width_ratio = 0.3F;
 
-  const float angles[] = {0.785398F, -0.785398F}; // 45 degrees
-  const float x_offsets[] = {-handle_offset, handle_offset}; // Separate handles
+  const float angles[] = {0.785398F, -0.785398F};
+  const float x_offsets[] = {-handle_offset, handle_offset};
 
   for (int sword_idx = 0; sword_idx < 2; ++sword_idx) {
     float const angle = angles[sword_idx];
@@ -49,7 +48,6 @@ auto ModeIndicator::create_attack_mode_mesh()
     float const blade_half_width = sword_width * 0.5F;
     QVector3D const n(0, 0, 1);
 
-    // Blade starts at handle position and extends outward
     float blade_verts[4][2] = {{-blade_half_width, 0.0F},
                                {blade_half_width, 0.0F},
                                {blade_tip_width, blade_length},
@@ -59,7 +57,6 @@ auto ModeIndicator::create_attack_mode_mesh()
       float const local_x = blade_verts[i][0];
       float const local_y = blade_verts[i][1];
 
-      // Apply rotation and offset
       float const world_x = local_x * cos_a - local_y * sin_a + x_offset;
       float const world_y = local_x * sin_a + local_y * cos_a;
 
@@ -75,7 +72,6 @@ auto ModeIndicator::create_attack_mode_mesh()
     idx.push_back(base + 3);
     idx.push_back(base + 0);
 
-    // Cross-guard
     size_t const guard_base = verts.size();
     float const guard_half_width = cross_guard_width * 0.5F;
     float const guard_half_height = cross_guard_height * 0.5F;
@@ -105,16 +101,14 @@ auto ModeIndicator::create_attack_mode_mesh()
     idx.push_back(guard_base + 3);
     idx.push_back(guard_base + 0);
 
-    // Handle below guard
     size_t const handle_base = verts.size();
     float const handle_half_width = sword_width * handle_width_ratio;
     float const handle_start = -handle_length;
 
-    float handle_verts[4][2] = {
-        {-handle_half_width, handle_start},
-        {handle_half_width, handle_start},
-        {handle_half_width, 0.0F},
-        {-handle_half_width, 0.0F}};
+    float handle_verts[4][2] = {{-handle_half_width, handle_start},
+                                {handle_half_width, handle_start},
+                                {handle_half_width, 0.0F},
+                                {-handle_half_width, 0.0F}};
 
     for (int i = 0; i < 4; ++i) {
       float const local_x = handle_verts[i][0];
@@ -186,7 +180,6 @@ auto ModeIndicator::create_guard_mode_mesh()
   idx.push_back(bottom_idx);
   idx.push_back(rightmost_idx);
 
-  // Add center boss (raised decorative circle)
   constexpr int boss_segments = 12;
   size_t const boss_center = verts.size();
   verts.push_back({{0.0F, 0.0F, 0.0F}, {n.x(), n.y(), n.z()}, {0.5F, 0.5F}});
@@ -207,7 +200,6 @@ auto ModeIndicator::create_guard_mode_mesh()
   return std::make_unique<Mesh>(verts, idx);
 }
 
-// Hold mode: anchor shape
 auto ModeIndicator::create_hold_mode_mesh()
     -> std::unique_ptr<Render::GL::Mesh> {
   using namespace Render::GL;
@@ -225,31 +217,33 @@ auto ModeIndicator::create_hold_mode_mesh()
 
   QVector3D const n(0, 0, 1);
 
-  // Ring at top (hollow circle)
   constexpr int ring_segments = 16;
   float const ring_y = anchor_height * 0.65F;
-  
-  // Outer ring
+
   for (int i = 0; i < ring_segments; ++i) {
     float const angle1 = (i / float(ring_segments)) * 2.0F * k_pi;
     float const angle2 = ((i + 1) / float(ring_segments)) * 2.0F * k_pi;
-    
+
     float const x1_outer = ring_outer_radius * std::cos(angle1);
     float const y1_outer = ring_y + ring_outer_radius * std::sin(angle1);
     float const x2_outer = ring_outer_radius * std::cos(angle2);
     float const y2_outer = ring_y + ring_outer_radius * std::sin(angle2);
-    
+
     float const x1_inner = ring_inner_radius * std::cos(angle1);
     float const y1_inner = ring_y + ring_inner_radius * std::sin(angle1);
     float const x2_inner = ring_inner_radius * std::cos(angle2);
     float const y2_inner = ring_y + ring_inner_radius * std::sin(angle2);
-    
+
     size_t const base = verts.size();
-    verts.push_back({{x1_outer, y1_outer, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 1.0F}});
-    verts.push_back({{x2_outer, y2_outer, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 1.0F}});
-    verts.push_back({{x2_inner, y2_inner, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 0.0F}});
-    verts.push_back({{x1_inner, y1_inner, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 0.0F}});
-    
+    verts.push_back(
+        {{x1_outer, y1_outer, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 1.0F}});
+    verts.push_back(
+        {{x2_outer, y2_outer, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 1.0F}});
+    verts.push_back(
+        {{x2_inner, y2_inner, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 0.0F}});
+    verts.push_back(
+        {{x1_inner, y1_inner, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 0.0F}});
+
     idx.push_back(base + 0);
     idx.push_back(base + 1);
     idx.push_back(base + 2);
@@ -258,7 +252,6 @@ auto ModeIndicator::create_hold_mode_mesh()
     idx.push_back(base + 0);
   }
 
-  // Shank (vertical bar)
   float const shank_half = shank_width * 0.5F;
   size_t const shank_base = verts.size();
   verts.push_back({{-shank_half, ring_y - ring_inner_radius, 0.0F},
@@ -267,8 +260,9 @@ auto ModeIndicator::create_hold_mode_mesh()
   verts.push_back({{shank_half, ring_y - ring_inner_radius, 0.0F},
                    {n.x(), n.y(), n.z()},
                    {1.0F, 1.0F}});
-  verts.push_back(
-      {{shank_half, -anchor_height * 0.25F, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 0.0F}});
+  verts.push_back({{shank_half, -anchor_height * 0.25F, 0.0F},
+                   {n.x(), n.y(), n.z()},
+                   {1.0F, 0.0F}});
   verts.push_back({{-shank_half, -anchor_height * 0.25F, 0.0F},
                    {n.x(), n.y(), n.z()},
                    {0.0F, 0.0F}});
@@ -280,11 +274,10 @@ auto ModeIndicator::create_hold_mode_mesh()
   idx.push_back(shank_base + 3);
   idx.push_back(shank_base + 0);
 
-  // Stock (horizontal bar at bottom)
   float const stock_y = -anchor_height * 0.25F;
   float const stock_half = stock_width * 0.5F;
   float const stock_height = shank_width;
-  
+
   size_t const stock_base = verts.size();
   verts.push_back({{-stock_half, stock_y - stock_height * 0.5F, 0.0F},
                    {n.x(), n.y(), n.z()},
@@ -306,32 +299,33 @@ auto ModeIndicator::create_hold_mode_mesh()
   idx.push_back(stock_base + 3);
   idx.push_back(stock_base + 0);
 
-  // Flukes (curved arms at bottom) - more realistic shape
   float const fluke_y_start = stock_y;
   float const fluke_y_end = stock_y - fluke_height;
-  
-  // Left fluke - curved outward
+
   constexpr int fluke_segments = 8;
   for (int i = 0; i < fluke_segments; ++i) {
     float const t1 = i / float(fluke_segments);
     float const t2 = (i + 1) / float(fluke_segments);
-    
-    // Curve from center outward and downward
+
     float const x1_inner = -shank_half - (fluke_width - shank_half) * t1 * t1;
     float const y1 = fluke_y_start - fluke_height * t1;
     float const x2_inner = -shank_half - (fluke_width - shank_half) * t2 * t2;
     float const y2 = fluke_y_start - fluke_height * t2;
-    
+
     float const fluke_thickness = shank_width * (1.0F + t1 * 0.5F);
     float const x1_outer = x1_inner - fluke_thickness * 0.5F;
     float const x2_outer = x2_inner - fluke_thickness * 0.5F;
-    
+
     size_t const base = verts.size();
-    verts.push_back({{x1_inner, y1, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 1.0F}});
-    verts.push_back({{x2_inner, y2, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 1.0F}});
-    verts.push_back({{x2_outer, y2, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 0.0F}});
-    verts.push_back({{x1_outer, y1, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 0.0F}});
-    
+    verts.push_back(
+        {{x1_inner, y1, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 1.0F}});
+    verts.push_back(
+        {{x2_inner, y2, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 1.0F}});
+    verts.push_back(
+        {{x2_outer, y2, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 0.0F}});
+    verts.push_back(
+        {{x1_outer, y1, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 0.0F}});
+
     idx.push_back(base + 0);
     idx.push_back(base + 1);
     idx.push_back(base + 2);
@@ -339,27 +333,30 @@ auto ModeIndicator::create_hold_mode_mesh()
     idx.push_back(base + 3);
     idx.push_back(base + 0);
   }
-  
-  // Right fluke - curved outward (mirror of left)
+
   for (int i = 0; i < fluke_segments; ++i) {
     float const t1 = i / float(fluke_segments);
     float const t2 = (i + 1) / float(fluke_segments);
-    
+
     float const x1_inner = shank_half + (fluke_width - shank_half) * t1 * t1;
     float const y1 = fluke_y_start - fluke_height * t1;
     float const x2_inner = shank_half + (fluke_width - shank_half) * t2 * t2;
     float const y2 = fluke_y_start - fluke_height * t2;
-    
+
     float const fluke_thickness = shank_width * (1.0F + t1 * 0.5F);
     float const x1_outer = x1_inner + fluke_thickness * 0.5F;
     float const x2_outer = x2_inner + fluke_thickness * 0.5F;
-    
+
     size_t const base = verts.size();
-    verts.push_back({{x1_inner, y1, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 1.0F}});
-    verts.push_back({{x2_inner, y2, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 1.0F}});
-    verts.push_back({{x2_outer, y2, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 0.0F}});
-    verts.push_back({{x1_outer, y1, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 0.0F}});
-    
+    verts.push_back(
+        {{x1_inner, y1, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 1.0F}});
+    verts.push_back(
+        {{x2_inner, y2, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 1.0F}});
+    verts.push_back(
+        {{x2_outer, y2, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 0.0F}});
+    verts.push_back(
+        {{x1_outer, y1, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 0.0F}});
+
     idx.push_back(base + 0);
     idx.push_back(base + 1);
     idx.push_back(base + 2);
@@ -371,7 +368,6 @@ auto ModeIndicator::create_hold_mode_mesh()
   return std::make_unique<Mesh>(verts, idx);
 }
 
-// Patrol mode: circular arrows indicating patrol route
 auto ModeIndicator::create_patrol_mode_mesh()
     -> std::unique_ptr<Render::GL::Mesh> {
   using namespace Render::GL;
@@ -383,40 +379,50 @@ auto ModeIndicator::create_patrol_mode_mesh()
   constexpr float arrow_head_length = 0.15F;
   constexpr float arrow_head_width = 0.15F;
   constexpr int circle_segments = 24;
-  constexpr float arrow_end_ratio = 0.85F; // How far around the circle the arrow extends
+  constexpr float arrow_end_ratio = 0.85F;
 
   QVector3D const n(0, 0, 1);
 
-  // Create two circular arrow paths (top and bottom half of circle)
   for (int arrow = 0; arrow < 2; ++arrow) {
-    // Determine which half of the circle (top or bottom)
+
     float const start_angle = arrow == 0 ? 0.0F : k_pi;
-    float const end_angle = arrow == 0 ? k_pi * arrow_end_ratio : k_pi * (1.0F + arrow_end_ratio);
+    float const end_angle =
+        arrow == 0 ? k_pi * arrow_end_ratio : k_pi * (1.0F + arrow_end_ratio);
     int const segments = circle_segments / 2;
 
-    // Draw the curved path
     for (int i = 0; i < segments; ++i) {
       float const t1 = i / float(segments);
       float const t2 = (i + 1) / float(segments);
       float const angle1 = start_angle + (end_angle - start_angle) * t1;
       float const angle2 = start_angle + (end_angle - start_angle) * t2;
 
-      // Inner and outer points of the arrow path
-      float const x1_inner = (circle_radius - arrow_width * 0.5F) * std::cos(angle1);
-      float const y1_inner = (circle_radius - arrow_width * 0.5F) * std::sin(angle1);
-      float const x1_outer = (circle_radius + arrow_width * 0.5F) * std::cos(angle1);
-      float const y1_outer = (circle_radius + arrow_width * 0.5F) * std::sin(angle1);
-
-      float const x2_inner = (circle_radius - arrow_width * 0.5F) * std::cos(angle2);
-      float const y2_inner = (circle_radius - arrow_width * 0.5F) * std::sin(angle2);
-      float const x2_outer = (circle_radius + arrow_width * 0.5F) * std::cos(angle2);
-      float const y2_outer = (circle_radius + arrow_width * 0.5F) * std::sin(angle2);
+      float const x1_inner =
+          (circle_radius - arrow_width * 0.5F) * std::cos(angle1);
+      float const y1_inner =
+          (circle_radius - arrow_width * 0.5F) * std::sin(angle1);
+      float const x1_outer =
+          (circle_radius + arrow_width * 0.5F) * std::cos(angle1);
+      float const y1_outer =
+          (circle_radius + arrow_width * 0.5F) * std::sin(angle1);
+
+      float const x2_inner =
+          (circle_radius - arrow_width * 0.5F) * std::cos(angle2);
+      float const y2_inner =
+          (circle_radius - arrow_width * 0.5F) * std::sin(angle2);
+      float const x2_outer =
+          (circle_radius + arrow_width * 0.5F) * std::cos(angle2);
+      float const y2_outer =
+          (circle_radius + arrow_width * 0.5F) * std::sin(angle2);
 
       size_t const base = verts.size();
-      verts.push_back({{x1_inner, y1_inner, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 0.0F}});
-      verts.push_back({{x1_outer, y1_outer, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 0.0F}});
-      verts.push_back({{x2_outer, y2_outer, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 1.0F}});
-      verts.push_back({{x2_inner, y2_inner, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 1.0F}});
+      verts.push_back(
+          {{x1_inner, y1_inner, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 0.0F}});
+      verts.push_back(
+          {{x1_outer, y1_outer, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 0.0F}});
+      verts.push_back(
+          {{x2_outer, y2_outer, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 1.0F}});
+      verts.push_back(
+          {{x2_inner, y2_inner, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 1.0F}});
 
       idx.push_back(base + 0);
       idx.push_back(base + 1);
@@ -426,33 +432,31 @@ auto ModeIndicator::create_patrol_mode_mesh()
       idx.push_back(base + 0);
     }
 
-    // Add arrowhead at the end
     float const arrow_angle = end_angle;
     float const arrow_x = circle_radius * std::cos(arrow_angle);
     float const arrow_y = circle_radius * std::sin(arrow_angle);
-    
-    // Direction perpendicular to circle (tangent direction for arrow)
+
     float const tangent_x = -std::sin(arrow_angle);
     float const tangent_y = std::cos(arrow_angle);
-    
-    // Direction pointing outward from circle center
+
     float const normal_x = std::cos(arrow_angle);
     float const normal_y = std::sin(arrow_angle);
 
-    // Arrow head tip
     float const tip_x = arrow_x + tangent_x * arrow_head_length;
     float const tip_y = arrow_y + tangent_y * arrow_head_length;
 
-    // Arrow head base corners
     float const base1_x = arrow_x + normal_x * arrow_head_width * 0.5F;
     float const base1_y = arrow_y + normal_y * arrow_head_width * 0.5F;
     float const base2_x = arrow_x - normal_x * arrow_head_width * 0.5F;
     float const base2_y = arrow_y - normal_y * arrow_head_width * 0.5F;
 
     size_t const arrow_base = verts.size();
-    verts.push_back({{tip_x, tip_y, 0.0F}, {n.x(), n.y(), n.z()}, {0.5F, 1.0F}});
-    verts.push_back({{base1_x, base1_y, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 0.0F}});
-    verts.push_back({{base2_x, base2_y, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 0.0F}});
+    verts.push_back(
+        {{tip_x, tip_y, 0.0F}, {n.x(), n.y(), n.z()}, {0.5F, 1.0F}});
+    verts.push_back(
+        {{base1_x, base1_y, 0.0F}, {n.x(), n.y(), n.z()}, {1.0F, 0.0F}});
+    verts.push_back(
+        {{base2_x, base2_y, 0.0F}, {n.x(), n.y(), n.z()}, {0.0F, 0.0F}});
 
     idx.push_back(arrow_base + 0);
     idx.push_back(arrow_base + 1);

+ 4 - 6
render/geom/mode_indicator.h

@@ -6,7 +6,6 @@
 
 namespace Render::Geom {
 
-// Mode type constants
 constexpr int k_mode_type_attack = 0;
 constexpr int k_mode_type_guard = 1;
 constexpr int k_mode_type_hold = 2;
@@ -18,11 +17,10 @@ constexpr float k_indicator_alpha = 0.85F;
 constexpr float k_indicator_height_multiplier = 2.0F;
 constexpr float k_frustum_cull_margin = 1.5F;
 
-// Mode indicator colors
-const QVector3D k_attack_mode_color(1.0F, 0.3F, 0.3F);  // Red
-const QVector3D k_guard_mode_color(0.3F, 0.5F, 1.0F);   // Blue
-const QVector3D k_hold_mode_color(1.0F, 0.6F, 0.2F);    // Orange
-const QVector3D k_patrol_mode_color(0.5F, 0.5F, 0.5F);  // Gray
+const QVector3D k_attack_mode_color(1.0F, 0.3F, 0.3F);
+const QVector3D k_guard_mode_color(0.3F, 0.5F, 1.0F);
+const QVector3D k_hold_mode_color(1.0F, 0.6F, 0.2F);
+const QVector3D k_patrol_mode_color(0.5F, 0.5F, 0.5F);
 
 class ModeIndicator {
 public:

+ 2 - 8
render/ground/biome_renderer.cpp

@@ -138,24 +138,20 @@ void BiomeRenderer::generate_grass_instances() {
 
   const float tile_safe = std::max(0.001F, m_tile_size);
 
-  // Build terrain cache for spawn validation
   SpawnTerrainCache terrain_cache;
   terrain_cache.build_from_height_map(m_heightData, m_terrain_types, m_width,
                                       m_height, m_tile_size);
 
-  // Configure spawn validator for grass
   SpawnValidationConfig config = make_grass_spawn_config();
   config.grid_width = m_width;
   config.grid_height = m_height;
   config.tile_size = m_tile_size;
   config.edge_padding = m_biome_settings.spawn_edge_padding;
-  // Note: We handle river margin specially for grass (with reduced density
-  // near rivers) so we disable the strict river margin check in the validator
+
   config.check_river_margin = false;
 
   SpawnValidator validator(terrain_cache, config);
 
-  // Helper to check river margin with special riverbank density logic
   auto check_riverbank = [&](int ix, int iz, uint32_t &state) -> bool {
     constexpr int k_river_margin = 1;
     int near_river_count = 0;
@@ -176,7 +172,7 @@ void BiomeRenderer::generate_grass_instances() {
     }
 
     if (near_river_count > 0) {
-      // Allow some grass near riverbanks with reduced density
+
       float const riverbank_density = 0.15F;
       if (rand_01(state) > riverbank_density) {
         return false;
@@ -186,7 +182,6 @@ void BiomeRenderer::generate_grass_instances() {
   };
 
   auto add_grass_blade = [&](float gx, float gz, uint32_t &state) {
-    // Use unified spawn validator for most checks
     if (!validator.can_spawn_at_grid(gx, gz)) {
       return false;
     }
@@ -197,7 +192,6 @@ void BiomeRenderer::generate_grass_instances() {
     int const ix = std::clamp(int(std::floor(sgx + 0.5F)), 0, m_width - 1);
     int const iz = std::clamp(int(std::floor(sgz + 0.5F)), 0, m_height - 1);
 
-    // Special riverbank handling for grass
     if (!check_riverbank(ix, iz, state)) {
       return false;
     }

+ 2 - 7
render/ground/firecamp_renderer.cpp

@@ -221,8 +221,7 @@ void FireCampRenderer::setExplicitFireCamps(
   }
 }
 
-void FireCampRenderer::add_explicit_firecamps(
-    const SpawnValidator &validator) {
+void FireCampRenderer::add_explicit_firecamps(const SpawnValidator &validator) {
   if (m_explicitPositions.empty()) {
     return;
   }
@@ -230,9 +229,8 @@ void FireCampRenderer::add_explicit_firecamps(
   for (size_t i = 0; i < m_explicitPositions.size(); ++i) {
     const QVector3D &pos = m_explicitPositions[i];
 
-    // Validate explicit firecamp positions
     if (!validator.can_spawn_at_world(pos.x(), pos.z())) {
-      continue; // Skip invalid positions
+      continue;
     }
 
     float intensity = 1.0F;
@@ -263,12 +261,10 @@ void FireCampRenderer::generate_firecamp_instances() {
 
   const float tile_safe = std::max(0.1F, m_tile_size);
 
-  // Build terrain cache for spawn validation
   SpawnTerrainCache terrain_cache;
   terrain_cache.build_from_height_map(m_heightData, m_terrain_types, m_width,
                                       m_height, m_tile_size);
 
-  // Configure spawn validator for fire camps
   SpawnValidationConfig config = make_firecamp_spawn_config();
   config.grid_width = m_width;
   config.grid_height = m_height;
@@ -280,7 +276,6 @@ void FireCampRenderer::generate_firecamp_instances() {
   float const fire_camp_density = 0.02F;
 
   auto add_fire_camp = [&](float gx, float gz, uint32_t &state) -> bool {
-    // Use unified spawn validator for all checks
     if (!validator.can_spawn_at_grid(gx, gz)) {
       return false;
     }

+ 1 - 4
render/ground/olive_renderer.cpp

@@ -159,23 +159,20 @@ void OliveRenderer::generate_olive_instances() {
     olive_density = m_biome_settings.plant_density * density_mult;
   }
 
-  // Build terrain cache for spawn validation
   SpawnTerrainCache terrain_cache;
   terrain_cache.build_from_height_map(m_heightData, m_terrain_types, m_width,
                                       m_height, m_tile_size);
 
-  // Configure spawn validator for trees
   SpawnValidationConfig config = make_tree_spawn_config();
   config.grid_width = m_width;
   config.grid_height = m_height;
   config.tile_size = m_tile_size;
   config.edge_padding = m_biome_settings.spawn_edge_padding;
-  config.max_slope = 0.65F; // Olive trees can't grow on steep slopes
+  config.max_slope = 0.65F;
 
   SpawnValidator validator(terrain_cache, config);
 
   auto add_olive = [&](float gx, float gz, uint32_t &state) -> bool {
-    // Use unified spawn validator for all checks
     if (!validator.can_spawn_at_grid(gx, gz)) {
       return false;
     }

+ 0 - 3
render/ground/pine_renderer.cpp

@@ -152,12 +152,10 @@ void PineRenderer::generatePineInstances() {
     pine_density = m_biome_settings.plant_density * 0.3F;
   }
 
-  // Build terrain cache for spawn validation
   SpawnTerrainCache terrain_cache;
   terrain_cache.build_from_height_map(m_heightData, m_terrain_types, m_width,
                                       m_height, m_tile_size);
 
-  // Configure spawn validator for trees
   SpawnValidationConfig config = make_tree_spawn_config();
   config.grid_width = m_width;
   config.grid_height = m_height;
@@ -167,7 +165,6 @@ void PineRenderer::generatePineInstances() {
   SpawnValidator validator(terrain_cache, config);
 
   auto add_pine = [&](float gx, float gz, uint32_t &state) -> bool {
-    // Use unified spawn validator for all checks
     if (!validator.can_spawn_at_grid(gx, gz)) {
       return false;
     }

+ 0 - 3
render/ground/plant_renderer.cpp

@@ -156,12 +156,10 @@ void PlantRenderer::generatePlantInstances() {
 
   const float tile_safe = std::max(0.001F, m_tile_size);
 
-  // Build terrain cache for spawn validation
   SpawnTerrainCache terrain_cache;
   terrain_cache.build_from_height_map(m_heightData, m_terrain_types, m_width,
                                       m_height, m_tile_size);
 
-  // Configure spawn validator for plants
   SpawnValidationConfig config = make_plant_spawn_config();
   config.grid_width = m_width;
   config.grid_height = m_height;
@@ -171,7 +169,6 @@ void PlantRenderer::generatePlantInstances() {
   SpawnValidator validator(terrain_cache, config);
 
   auto add_plant = [&](float gx, float gz, uint32_t &state) -> bool {
-    // Use unified spawn validator for all checks
     if (!validator.can_spawn_at_grid(gx, gz)) {
       return false;
     }

+ 10 - 33
render/ground/spawn_validator.cpp

@@ -6,10 +6,6 @@
 
 namespace Render::Ground {
 
-// ============================================================================
-// SpawnTerrainCache implementation
-// ============================================================================
-
 void SpawnTerrainCache::build_from_height_map(
     const std::vector<float> &height_data,
     const std::vector<Game::Map::TerrainType> &types, int w, int h, float ts) {
@@ -19,7 +15,6 @@ void SpawnTerrainCache::build_from_height_map(
   heights = height_data;
   terrain_types = types;
 
-  // Build normals from height data
   normals.resize(static_cast<size_t>(width * height),
                  QVector3D(0.0F, 1.0F, 0.0F));
 
@@ -105,68 +100,54 @@ auto SpawnTerrainCache::get_terrain_type_at(int grid_x, int grid_z) const
   return terrain_types[static_cast<size_t>(idx)];
 }
 
-// ============================================================================
-// SpawnValidator implementation
-// ============================================================================
-
 SpawnValidator::SpawnValidator(const SpawnTerrainCache &cache,
                                const SpawnValidationConfig &config)
     : m_cache(cache), m_config(config) {
-  // Precompute edge margins
+
   float const edge_padding = std::clamp(m_config.edge_padding, 0.0F, 0.5F);
   m_edge_margin_x = static_cast<float>(m_config.grid_width) * edge_padding;
   m_edge_margin_z = static_cast<float>(m_config.grid_height) * edge_padding;
 
-  // Precompute coordinate conversion values
   m_half_width = static_cast<float>(m_config.grid_width) * 0.5F - 0.5F;
   m_half_height = static_cast<float>(m_config.grid_height) * 0.5F - 0.5F;
 }
 
 auto SpawnValidator::can_spawn_at_grid(float gx, float gz) const -> bool {
-  // Check edge padding
+
   if (!check_edge_padding(gx, gz)) {
     return false;
   }
 
-  // Get integer grid position for terrain lookups
   float const sgx =
       std::clamp(gx, 0.0F, static_cast<float>(m_config.grid_width - 1));
   float const sgz =
       std::clamp(gz, 0.0F, static_cast<float>(m_config.grid_height - 1));
 
-  int const grid_x =
-      std::clamp(static_cast<int>(std::floor(sgx + 0.5F)), 0,
-                 m_config.grid_width - 1);
-  int const grid_z =
-      std::clamp(static_cast<int>(std::floor(sgz + 0.5F)), 0,
-                 m_config.grid_height - 1);
+  int const grid_x = std::clamp(static_cast<int>(std::floor(sgx + 0.5F)), 0,
+                                m_config.grid_width - 1);
+  int const grid_z = std::clamp(static_cast<int>(std::floor(sgz + 0.5F)), 0,
+                                m_config.grid_height - 1);
 
-  // Check terrain type
   if (!check_terrain_type(grid_x, grid_z)) {
     return false;
   }
 
-  // Check river margin
   if (m_config.check_river_margin && !check_river_margin(grid_x, grid_z)) {
     return false;
   }
 
-  // Check slope
   if (m_config.check_slope && !check_slope(grid_x, grid_z)) {
     return false;
   }
 
-  // Convert to world coordinates for building and road checks
   float world_x = 0.0F;
   float world_z = 0.0F;
   grid_to_world(gx, gz, world_x, world_z);
 
-  // Check building collision
   if (m_config.check_buildings && !check_building_collision(world_x, world_z)) {
     return false;
   }
 
-  // Check road collision
   if (m_config.check_roads && !check_road_collision(world_x, world_z)) {
     return false;
   }
@@ -174,8 +155,8 @@ auto SpawnValidator::can_spawn_at_grid(float gx, float gz) const -> bool {
   return true;
 }
 
-auto SpawnValidator::can_spawn_at_world(float world_x, float world_z) const
-    -> bool {
+auto SpawnValidator::can_spawn_at_world(float world_x,
+                                        float world_z) const -> bool {
   float gx = 0.0F;
   float gz = 0.0F;
   world_to_grid(world_x, world_z, gx, gz);
@@ -257,16 +238,12 @@ auto SpawnValidator::check_building_collision(float world_x,
   return !building_registry.isPointInBuilding(world_x, world_z);
 }
 
-auto SpawnValidator::check_road_collision(float world_x, float world_z) const
-    -> bool {
+auto SpawnValidator::check_road_collision(float world_x,
+                                          float world_z) const -> bool {
   auto &terrain_service = Game::Map::TerrainService::instance();
   return !terrain_service.is_point_on_road(world_x, world_z);
 }
 
-// ============================================================================
-// Factory functions for common spawn configurations
-// ============================================================================
-
 auto make_plant_spawn_config() -> SpawnValidationConfig {
   SpawnValidationConfig config;
   config.edge_padding = 0.08F;

+ 3 - 140
render/ground/spawn_validator.h

@@ -7,49 +7,29 @@
 
 namespace Render::Ground {
 
-/**
- * @brief Configuration for spawn validation checks.
- *
- * This struct contains all the parameters needed to validate whether
- * a position is suitable for spawning objects (plants, stones, trees,
- * fire camps, etc.). Use this to configure which checks should be
- * performed and with what thresholds.
- */
 struct SpawnValidationConfig {
-  // Grid dimensions and tile size
+
   int grid_width = 0;
   int grid_height = 0;
   float tile_size = 1.0F;
 
-  // Edge padding (fraction of map size to exclude from edges)
   float edge_padding = 0.08F;
 
-  // Slope threshold (0-1, higher means steeper slopes are allowed)
   float max_slope = 0.65F;
 
-  // River margin (number of tiles around rivers to exclude)
   int river_margin = 1;
 
-  // Terrain type restrictions
   bool allow_flat = true;
   bool allow_hill = false;
   bool allow_mountain = false;
   bool allow_river = false;
 
-  // Check flags
   bool check_buildings = true;
   bool check_roads = true;
   bool check_slope = true;
   bool check_river_margin = true;
 };
 
-/**
- * @brief Cached terrain data for efficient spawn validation.
- *
- * This struct holds precomputed terrain data (normals, heights) to avoid
- * redundant calculations during spawn validation. The data should be
- * computed once and reused for all spawn checks in a renderer.
- */
 struct SpawnTerrainCache {
   std::vector<QVector3D> normals;
   std::vector<float> heights;
@@ -58,114 +38,31 @@ struct SpawnTerrainCache {
   int height = 0;
   float tile_size = 1.0F;
 
-  /**
-   * @brief Build the terrain cache from height map data.
-   *
-   * @param height_data The height data from TerrainHeightMap
-   * @param types The terrain types from TerrainHeightMap
-   * @param w Grid width
-   * @param h Grid height
-   * @param ts Tile size
-   */
   void build_from_height_map(const std::vector<float> &height_data,
                              const std::vector<Game::Map::TerrainType> &types,
                              int w, int h, float ts);
 
-  /**
-   * @brief Sample interpolated height at grid coordinates.
-   *
-   * @param gx Grid x coordinate (can be fractional)
-   * @param gz Grid z coordinate (can be fractional)
-   * @return Interpolated height value
-   */
   [[nodiscard]] auto sample_height_at(float gx, float gz) const -> float;
 
-  /**
-   * @brief Get the slope at a grid position (0 = flat, 1 = vertical).
-   *
-   * @param grid_x Grid x coordinate (integer)
-   * @param grid_z Grid z coordinate (integer)
-   * @return Slope value between 0 and 1
-   */
   [[nodiscard]] auto get_slope_at(int grid_x, int grid_z) const -> float;
 
-  /**
-   * @brief Get the terrain type at a grid position.
-   *
-   * @param grid_x Grid x coordinate
-   * @param grid_z Grid z coordinate
-   * @return Terrain type at the position
-   */
-  [[nodiscard]] auto get_terrain_type_at(int grid_x,
-                                         int grid_z) const -> Game::Map::TerrainType;
+  [[nodiscard]] auto
+  get_terrain_type_at(int grid_x, int grid_z) const -> Game::Map::TerrainType;
 };
 
-/**
- * @brief Unified spawn validator for random object placement.
- *
- * This class provides a centralized, efficient way to validate whether
- * a position is suitable for spawning objects. It consolidates all the
- * spawn validation logic that was previously duplicated across multiple
- * renderer files.
- *
- * Usage:
- * 1. Create a SpawnValidator with the terrain cache and configuration
- * 2. Call can_spawn_at_grid() or can_spawn_at_world() to check positions
- * 3. Reuse the same validator for all spawn checks in a renderer
- */
 class SpawnValidator {
 public:
-  /**
-   * @brief Construct a spawn validator.
-   *
-   * @param cache Reference to the terrain cache (must outlive the validator)
-   * @param config Validation configuration
-   */
   SpawnValidator(const SpawnTerrainCache &cache,
                  const SpawnValidationConfig &config);
 
-  /**
-   * @brief Check if an object can be spawned at grid coordinates.
-   *
-   * This method performs all configured checks to determine if a position
-   * is valid for spawning. It checks: edge padding, terrain type,
-   * river margin, slope, buildings, and roads.
-   *
-   * @param gx Grid x coordinate (can be fractional)
-   * @param gz Grid z coordinate (can be fractional)
-   * @return true if the position is valid for spawning
-   */
   [[nodiscard]] auto can_spawn_at_grid(float gx, float gz) const -> bool;
 
-  /**
-   * @brief Check if an object can be spawned at world coordinates.
-   *
-   * @param world_x World x coordinate
-   * @param world_z World z coordinate
-   * @return true if the position is valid for spawning
-   */
   [[nodiscard]] auto can_spawn_at_world(float world_x,
                                         float world_z) const -> bool;
 
-  /**
-   * @brief Convert grid coordinates to world coordinates.
-   *
-   * @param gx Grid x coordinate
-   * @param gz Grid z coordinate
-   * @param out_world_x Output world x coordinate
-   * @param out_world_z Output world z coordinate
-   */
   void grid_to_world(float gx, float gz, float &out_world_x,
                      float &out_world_z) const;
 
-  /**
-   * @brief Convert world coordinates to grid coordinates.
-   *
-   * @param world_x World x coordinate
-   * @param world_z World z coordinate
-   * @param out_gx Output grid x coordinate
-   * @param out_gz Output grid z coordinate
-   */
   void world_to_grid(float world_x, float world_z, float &out_gx,
                      float &out_gz) const;
 
@@ -173,68 +70,34 @@ private:
   const SpawnTerrainCache &m_cache;
   SpawnValidationConfig m_config;
 
-  // Precomputed edge margins
   float m_edge_margin_x = 0.0F;
   float m_edge_margin_z = 0.0F;
   float m_half_width = 0.0F;
   float m_half_height = 0.0F;
 
-  /**
-   * @brief Check if position is within edge padding bounds.
-   */
   [[nodiscard]] auto check_edge_padding(float gx, float gz) const -> bool;
 
-  /**
-   * @brief Check if terrain type is allowed at position.
-   */
   [[nodiscard]] auto check_terrain_type(int grid_x, int grid_z) const -> bool;
 
-  /**
-   * @brief Check if position is far enough from rivers.
-   */
   [[nodiscard]] auto check_river_margin(int grid_x, int grid_z) const -> bool;
 
-  /**
-   * @brief Check if slope is acceptable at position.
-   */
   [[nodiscard]] auto check_slope(int grid_x, int grid_z) const -> bool;
 
-  /**
-   * @brief Check if position collides with buildings.
-   */
   [[nodiscard]] auto check_building_collision(float world_x,
                                               float world_z) const -> bool;
 
-  /**
-   * @brief Check if position is on a road.
-   */
   [[nodiscard]] auto check_road_collision(float world_x,
                                           float world_z) const -> bool;
 };
 
-/**
- * @brief Create a default spawn config for plants/grass.
- */
 [[nodiscard]] auto make_plant_spawn_config() -> SpawnValidationConfig;
 
-/**
- * @brief Create a default spawn config for stones.
- */
 [[nodiscard]] auto make_stone_spawn_config() -> SpawnValidationConfig;
 
-/**
- * @brief Create a default spawn config for trees (pine, olive).
- */
 [[nodiscard]] auto make_tree_spawn_config() -> SpawnValidationConfig;
 
-/**
- * @brief Create a default spawn config for fire camps.
- */
 [[nodiscard]] auto make_firecamp_spawn_config() -> SpawnValidationConfig;
 
-/**
- * @brief Create a default spawn config for grass blades.
- */
 [[nodiscard]] auto make_grass_spawn_config() -> SpawnValidationConfig;
 
 } // namespace Render::Ground

+ 0 - 3
render/ground/stone_renderer.cpp

@@ -108,12 +108,10 @@ void StoneRenderer::generateStoneInstances() {
 
   const float tile_safe = std::max(0.001F, m_tile_size);
 
-  // Build terrain cache for spawn validation
   SpawnTerrainCache terrain_cache;
   terrain_cache.build_from_height_map(m_heightData, m_terrain_types, m_width,
                                       m_height, m_tile_size);
 
-  // Configure spawn validator for stones
   SpawnValidationConfig config = make_stone_spawn_config();
   config.grid_width = m_width;
   config.grid_height = m_height;
@@ -123,7 +121,6 @@ void StoneRenderer::generateStoneInstances() {
   SpawnValidator validator(terrain_cache, config);
 
   auto add_stone = [&](float gx, float gz, uint32_t &state) -> bool {
-    // Use unified spawn validator for all checks
     if (!validator.can_spawn_at_grid(gx, gz)) {
       return false;
     }

+ 2 - 4
render/scene_renderer.cpp

@@ -449,9 +449,9 @@ void Renderer::enqueue_mode_indicator(
     return;
   }
 
-  // Check for all mode types
   auto *attack_comp = entity->get_component<Engine::Core::AttackComponent>();
-  bool const has_attack = (attack_comp != nullptr) && attack_comp->in_melee_lock;
+  bool const has_attack =
+      (attack_comp != nullptr) && attack_comp->in_melee_lock;
 
   auto *guard_mode = entity->get_component<Engine::Core::GuardModeComponent>();
   bool const has_guard_mode = (guard_mode != nullptr) && guard_mode->active;
@@ -462,7 +462,6 @@ void Renderer::enqueue_mode_indicator(
   auto *patrol_comp = entity->get_component<Engine::Core::PatrolComponent>();
   bool const has_patrol = (patrol_comp != nullptr) && patrol_comp->patrolling;
 
-  // Only render if unit has an active mode
   if (!has_attack && !has_guard_mode && !has_hold_mode && !has_patrol) {
     return;
   }
@@ -526,7 +525,6 @@ void Renderer::enqueue_mode_indicator(
     indicator_model.rotate(yaw * 180.0F / k_pi, 0, 1, 0);
   }
 
-  // Determine mode type and color (priority: attack > guard > hold > patrol)
   int mode_type = Render::Geom::k_mode_type_patrol;
   QVector3D color = Render::Geom::k_patrol_mode_color;
 

+ 2 - 1
tests/render/spawn_validator_test.cpp

@@ -17,7 +17,8 @@ protected:
     height_data.resize(static_cast<size_t>(width * height), 0.0F);
 
     // Initialize terrain types (all flat by default)
-    terrain_types.resize(static_cast<size_t>(width * height), TerrainType::Flat);
+    terrain_types.resize(static_cast<size_t>(width * height),
+                         TerrainType::Flat);
   }
 
   void build_cache() {

+ 32 - 19
tests/systems/patrol_system_test.cpp

@@ -1,7 +1,7 @@
-#include "systems/patrol_system.h"
 #include "core/component.h"
 #include "core/entity.h"
 #include "core/world.h"
+#include "systems/patrol_system.h"
 #include <gtest/gtest.h>
 
 using namespace Engine::Core;
@@ -35,7 +35,7 @@ TEST_F(PatrolSystemTest, PatrollingUnitIgnoresEnemyBuildings) {
   unit_comp->owner_id = 1;
   auto *movement = unit->add_component<MovementComponent>();
   auto *patrol = unit->add_component<PatrolComponent>();
-  
+
   // Setup patrol waypoints
   patrol->waypoints.push_back({10.0F, 0.0F});
   patrol->waypoints.push_back({10.0F, 10.0F});
@@ -43,12 +43,15 @@ TEST_F(PatrolSystemTest, PatrollingUnitIgnoresEnemyBuildings) {
   patrol->current_waypoint = 0;
 
   // Create an enemy building nearby (within detection range of 25.0F dist_sq)
-  // Distance of 3.0F units from origin results in dist_sq = 9.0F, which is < 25.0F
+  // Distance of 3.0F units from origin results in dist_sq = 9.0F, which is
+  // < 25.0F
   auto *enemy_building = world->create_entity();
-  auto *enemy_transform = enemy_building->add_component<TransformComponent>(3.0F, 0.0F, 0.0F);
+  auto *enemy_transform =
+      enemy_building->add_component<TransformComponent>(3.0F, 0.0F, 0.0F);
   // UnitComponent(health, max_health, speed, vision_range)
-  auto *enemy_unit_comp = enemy_building->add_component<UnitComponent>(100, 100, 0.0F, 10.0F);
-  enemy_unit_comp->owner_id = 2; // Different owner
+  auto *enemy_unit_comp =
+      enemy_building->add_component<UnitComponent>(100, 100, 0.0F, 10.0F);
+  enemy_unit_comp->owner_id = 2;                      // Different owner
   enemy_building->add_component<BuildingComponent>(); // Mark as building
 
   // Run the patrol system
@@ -56,7 +59,8 @@ TEST_F(PatrolSystemTest, PatrollingUnitIgnoresEnemyBuildings) {
 
   // Verify that the unit did NOT auto-attack the building
   auto *attack_target = unit->get_component<AttackTargetComponent>();
-  EXPECT_EQ(attack_target, nullptr) << "Patrolling unit should not auto-attack enemy buildings";
+  EXPECT_EQ(attack_target, nullptr)
+      << "Patrolling unit should not auto-attack enemy buildings";
 }
 
 TEST_F(PatrolSystemTest, PatrollingUnitAttacksEnemyTroops) {
@@ -68,7 +72,7 @@ TEST_F(PatrolSystemTest, PatrollingUnitAttacksEnemyTroops) {
   unit_comp->owner_id = 1;
   auto *movement = unit->add_component<MovementComponent>();
   auto *patrol = unit->add_component<PatrolComponent>();
-  
+
   // Setup patrol waypoints
   patrol->waypoints.push_back({10.0F, 0.0F});
   patrol->waypoints.push_back({10.0F, 10.0F});
@@ -77,9 +81,11 @@ TEST_F(PatrolSystemTest, PatrollingUnitAttacksEnemyTroops) {
 
   // Create an enemy troop nearby (within detection range)
   auto *enemy_troop = world->create_entity();
-  auto *enemy_transform = enemy_troop->add_component<TransformComponent>(3.0F, 0.0F, 0.0F);
+  auto *enemy_transform =
+      enemy_troop->add_component<TransformComponent>(3.0F, 0.0F, 0.0F);
   // UnitComponent(health, max_health, speed, vision_range)
-  auto *enemy_unit_comp = enemy_troop->add_component<UnitComponent>(100, 100, 1.0F, 10.0F);
+  auto *enemy_unit_comp =
+      enemy_troop->add_component<UnitComponent>(100, 100, 1.0F, 10.0F);
   enemy_unit_comp->owner_id = 2; // Different owner
   // No BuildingComponent - this is a regular troop
 
@@ -88,7 +94,8 @@ TEST_F(PatrolSystemTest, PatrollingUnitAttacksEnemyTroops) {
 
   // Verify that the unit DID auto-attack the enemy troop
   auto *attack_target = unit->get_component<AttackTargetComponent>();
-  ASSERT_NE(attack_target, nullptr) << "Patrolling unit should auto-attack enemy troops";
+  ASSERT_NE(attack_target, nullptr)
+      << "Patrolling unit should auto-attack enemy troops";
   EXPECT_EQ(attack_target->target_id, enemy_troop->get_id());
   EXPECT_FALSE(attack_target->should_chase) << "Patrol attack should not chase";
 }
@@ -102,7 +109,7 @@ TEST_F(PatrolSystemTest, PatrollingUnitIgnoresFriendlyUnits) {
   unit_comp->owner_id = 1;
   auto *movement = unit->add_component<MovementComponent>();
   auto *patrol = unit->add_component<PatrolComponent>();
-  
+
   // Setup patrol waypoints
   patrol->waypoints.push_back({10.0F, 0.0F});
   patrol->waypoints.push_back({10.0F, 10.0F});
@@ -111,9 +118,11 @@ TEST_F(PatrolSystemTest, PatrollingUnitIgnoresFriendlyUnits) {
 
   // Create a friendly unit nearby
   auto *friendly_unit = world->create_entity();
-  auto *friendly_transform = friendly_unit->add_component<TransformComponent>(3.0F, 0.0F, 0.0F);
+  auto *friendly_transform =
+      friendly_unit->add_component<TransformComponent>(3.0F, 0.0F, 0.0F);
   // UnitComponent(health, max_health, speed, vision_range)
-  auto *friendly_unit_comp = friendly_unit->add_component<UnitComponent>(100, 100, 1.0F, 10.0F);
+  auto *friendly_unit_comp =
+      friendly_unit->add_component<UnitComponent>(100, 100, 1.0F, 10.0F);
   friendly_unit_comp->owner_id = 1; // Same owner
 
   // Run the patrol system
@@ -121,7 +130,8 @@ TEST_F(PatrolSystemTest, PatrollingUnitIgnoresFriendlyUnits) {
 
   // Verify that the unit did NOT attack the friendly unit
   auto *attack_target = unit->get_component<AttackTargetComponent>();
-  EXPECT_EQ(attack_target, nullptr) << "Patrolling unit should not attack friendly units";
+  EXPECT_EQ(attack_target, nullptr)
+      << "Patrolling unit should not attack friendly units";
 }
 
 TEST_F(PatrolSystemTest, PatrollingUnitIgnoresDeadEnemies) {
@@ -133,7 +143,7 @@ TEST_F(PatrolSystemTest, PatrollingUnitIgnoresDeadEnemies) {
   unit_comp->owner_id = 1;
   auto *movement = unit->add_component<MovementComponent>();
   auto *patrol = unit->add_component<PatrolComponent>();
-  
+
   // Setup patrol waypoints
   patrol->waypoints.push_back({10.0F, 0.0F});
   patrol->waypoints.push_back({10.0F, 10.0F});
@@ -142,9 +152,11 @@ TEST_F(PatrolSystemTest, PatrollingUnitIgnoresDeadEnemies) {
 
   // Create a dead enemy troop nearby
   auto *dead_enemy = world->create_entity();
-  auto *enemy_transform = dead_enemy->add_component<TransformComponent>(3.0F, 0.0F, 0.0F);
+  auto *enemy_transform =
+      dead_enemy->add_component<TransformComponent>(3.0F, 0.0F, 0.0F);
   // UnitComponent(health=0, max_health, speed, vision_range)
-  auto *enemy_unit_comp = dead_enemy->add_component<UnitComponent>(0, 100, 1.0F, 10.0F); // 0 health
+  auto *enemy_unit_comp =
+      dead_enemy->add_component<UnitComponent>(0, 100, 1.0F, 10.0F); // 0 health
   enemy_unit_comp->owner_id = 2; // Different owner
 
   // Run the patrol system
@@ -152,5 +164,6 @@ TEST_F(PatrolSystemTest, PatrollingUnitIgnoresDeadEnemies) {
 
   // Verify that the unit did NOT attack the dead enemy
   auto *attack_target = unit->get_component<AttackTargetComponent>();
-  EXPECT_EQ(attack_target, nullptr) << "Patrolling unit should not attack dead enemies";
+  EXPECT_EQ(attack_target, nullptr)
+      << "Patrolling unit should not attack dead enemies";
 }

+ 0 - 1
ui/qml/GameView.qml

@@ -312,7 +312,6 @@ Item {
 
                         return ;
                     }
-
                     if (gameView.cursorMode === "patrol") {
                         if (typeof game !== 'undefined' && game.on_patrol_click)
                             game.on_patrol_click(mouse.x, mouse.y);

+ 7 - 8
ui/qml/HUDBottom.qml

@@ -16,17 +16,14 @@ RowLayout {
         "canPatrol": true
     })
 
+    signal commandModeChanged(string mode)
+    signal recruit(string unitType)
+
     function updateModeAvailability() {
-        if (typeof game !== 'undefined' && game.get_selected_units_mode_availability) {
+        if (typeof game !== 'undefined' && game.get_selected_units_mode_availability)
             modeAvailability = game.get_selected_units_mode_availability();
-        }
-    }
 
-    Component.onCompleted: updateModeAvailability()
-    onSelectionTickChanged: updateModeAvailability()
-
-    signal commandModeChanged(string mode)
-    signal recruit(string unitType)
+    }
 
     function unitIconSource(unitType, nationKey) {
         if (typeof StyleGuide === "undefined" || !StyleGuide.unitIconSources || !unitType)
@@ -47,6 +44,8 @@ RowLayout {
         return "👤";
     }
 
+    Component.onCompleted: updateModeAvailability()
+    onSelectionTickChanged: updateModeAvailability()
     anchors.fill: parent
     anchors.margins: 10
     spacing: 12