浏览代码

apply format

djeada 1 月之前
父节点
当前提交
4bd1e66db8
共有 38 个文件被更改,包括 228 次插入202 次删除
  1. 9 15
      app/core/game_engine.cpp
  2. 3 3
      app/core/game_engine.h
  3. 33 42
      assets/shaders/archer_carthage.frag
  4. 3 3
      game/systems/save_load_service.cpp
  5. 2 2
      game/systems/save_load_service.h
  6. 23 23
      game/systems/save_storage.cpp
  7. 2 2
      game/systems/save_storage.h
  8. 1 2
      game/units/horse_archer.cpp
  9. 2 2
      game/units/horse_archer.h
  10. 1 1
      game/units/horse_spearman.cpp
  11. 8 1
      game/units/troop_type.h
  12. 12 7
      render/entity/arrow_vfx_renderer.cpp
  13. 3 3
      render/entity/horse_archer_renderer_base.cpp
  14. 2 3
      render/entity/horse_archer_renderer_base.h
  15. 2 1
      render/entity/horse_spearman_renderer_base.cpp
  16. 1 1
      render/entity/horse_spearman_renderer_base.h
  17. 3 4
      render/entity/mounted_knight_renderer_base.cpp
  18. 12 11
      render/entity/nations/carthage/archer_renderer.cpp
  19. 1 2
      render/entity/nations/carthage/horse_archer_renderer.cpp
  20. 1 2
      render/entity/nations/carthage/horse_spearman_renderer.cpp
  21. 2 1
      render/entity/nations/carthage/spearman_renderer.cpp
  22. 6 5
      render/entity/nations/kingdom/archer_renderer.cpp
  23. 1 2
      render/entity/nations/kingdom/horse_archer_renderer.cpp
  24. 1 2
      render/entity/nations/kingdom/horse_spearman_renderer.cpp
  25. 2 1
      render/entity/nations/kingdom/spearman_renderer.cpp
  26. 6 5
      render/entity/nations/roman/archer_renderer.cpp
  27. 2 4
      render/entity/nations/roman/horse_archer_renderer.cpp
  28. 1 2
      render/entity/nations/roman/horse_spearman_renderer.cpp
  29. 2 1
      render/entity/nations/roman/spearman_renderer.cpp
  30. 3 2
      render/equipment/weapons/spear_renderer.cpp
  31. 1 1
      render/gl/humanoid/animation/animation_inputs.cpp
  32. 1 1
      render/gl/humanoid/animation/gait.h
  33. 9 9
      render/humanoid/pose_controller.cpp
  34. 10 8
      render/humanoid/rig.cpp
  35. 6 6
      tests/render/pose_controller_compatibility_test.cpp
  36. 10 7
      tests/render/pose_controller_test.cpp
  37. 25 14
      ui/qml/CampaignMenu.qml
  38. 16 1
      ui/qml/ProductionPanel.qml

+ 9 - 15
app/core/game_engine.cpp

@@ -1102,7 +1102,6 @@ void GameEngine::start_campaign_mission(const QString &campaign_id) {
     return;
   }
 
-  // Get campaign details
   QString error;
   auto campaigns = m_saveLoadService->list_campaigns(&error);
   if (!error.isEmpty()) {
@@ -1110,7 +1109,6 @@ void GameEngine::start_campaign_mission(const QString &campaign_id) {
     return;
   }
 
-  // Find the campaign
   QVariantMap selectedCampaign;
   for (const auto &campaign : campaigns) {
     auto campaignMap = campaign.toMap();
@@ -1127,33 +1125,28 @@ void GameEngine::start_campaign_mission(const QString &campaign_id) {
 
   m_current_campaign_id = campaign_id;
 
-  // Get map path
   QString mapPath = selectedCampaign.value("mapPath").toString();
 
-  // For Carthage vs Rome mission, set up predefined players
   QVariantList playerConfigs;
 
-  // Player 1: Human (Carthage)
   QVariantMap player1;
   player1.insert("player_id", 1);
   player1.insert("playerName", "Carthage");
-  player1.insert("colorIndex", 0); // Blue
+  player1.insert("colorIndex", 0);
   player1.insert("team_id", 0);
   player1.insert("nationId", "carthage");
   player1.insert("isHuman", true);
   playerConfigs.append(player1);
 
-  // Player 2: AI (Rome)
   QVariantMap player2;
   player2.insert("player_id", 2);
   player2.insert("playerName", "Rome");
-  player2.insert("colorIndex", 1); // Red
+  player2.insert("colorIndex", 1);
   player2.insert("team_id", 1);
   player2.insert("nationId", "roman_republic");
   player2.insert("isHuman", false);
   playerConfigs.append(player2);
 
-  // Start the mission like a skirmish
   start_skirmish(mapPath, playerConfigs);
 }
 
@@ -1169,17 +1162,19 @@ void GameEngine::mark_current_mission_completed() {
   }
 
   QString error;
-  bool success = m_saveLoadService->mark_campaign_completed(m_current_campaign_id, &error);
+  bool success =
+      m_saveLoadService->mark_campaign_completed(m_current_campaign_id, &error);
   if (!success) {
     qWarning() << "Failed to mark campaign as completed:" << error;
   } else {
-    qInfo() << "Campaign mission" << m_current_campaign_id << "marked as completed";
-    load_campaigns(); // Refresh campaign list
+    qInfo() << "Campaign mission" << m_current_campaign_id
+            << "marked as completed";
+    load_campaigns();
   }
 }
 
 void GameEngine::start_skirmish(const QString &map_path,
-                               const QVariantList &playerConfigs) {
+                                const QVariantList &playerConfigs) {
 
   clearError();
 
@@ -1258,8 +1253,7 @@ void GameEngine::start_skirmish(const QString &map_path,
         if (m_runtime.victoryState != state) {
           m_runtime.victoryState = state;
           emit victoryStateChanged();
-          
-          // Mark campaign mission as completed if victory
+
           if (state == "victory" && !m_current_campaign_id.isEmpty()) {
             mark_current_mission_completed();
           }

+ 3 - 3
app/core/game_engine.h

@@ -97,8 +97,8 @@ public:
       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 available_maps READ available_maps NOTIFY available_maps_changed)
+  Q_PROPERTY(QVariantList available_maps READ available_maps NOTIFY
+                 available_maps_changed)
   Q_PROPERTY(bool maps_loading READ maps_loading NOTIFY maps_loading_changed)
   Q_PROPERTY(QVariantList available_nations READ available_nations CONSTANT)
   Q_PROPERTY(QVariantList available_campaigns READ available_campaigns NOTIFY
@@ -183,7 +183,7 @@ public:
   [[nodiscard]] bool maps_loading() const { return m_maps_loading; }
   Q_INVOKABLE void
   start_skirmish(const QString &map_path,
-                const QVariantList &playerConfigs = QVariantList());
+                 const QVariantList &playerConfigs = QVariantList());
   Q_INVOKABLE void start_campaign_mission(const QString &campaign_id);
   Q_INVOKABLE void mark_current_mission_completed();
   Q_INVOKABLE void open_settings();

+ 33 - 42
assets/shaders/archer_carthage.frag

@@ -204,9 +204,9 @@ vec3 computeAmbient(vec3 normal) {
   return sky * (0.25 + 0.55 * up) + ground * (0.10 + 0.35 * down);
 }
 
-MaterialSample makeLeatherSample(
-    vec3 baseColor, vec3 Nw, vec3 Tw, vec3 Bw, vec3 worldPos, float tension,
-    float bodyHeight, float layer, float wetMask, float curvature) {
+MaterialSample makeLeatherSample(vec3 baseColor, vec3 Nw, vec3 Tw, vec3 Bw,
+                                 vec3 worldPos, float tension, float bodyHeight,
+                                 float layer, float wetMask, float curvature) {
   MaterialSample mat;
   mat.metallic = 0.0;
 
@@ -280,8 +280,7 @@ MaterialSample makeLinenSample(vec3 baseColor, vec3 Nw, vec3 Tw, vec3 Bw,
   color -= vec3(fray * 0.12);
 
   float dust = clamp(1.0 - Nw.y, 0.0, 1.0) * fbm(worldPos * 1.1, Nw, 2.0);
-  float sweat =
-      smoothstep(0.6, 1.0, bodyHeight) * fbm(worldPos * 2.4, Nw, 3.1);
+  float sweat = smoothstep(0.6, 1.0, bodyHeight) * fbm(worldPos * 2.4, Nw, 3.1);
   color = mix(color, color * (1.0 - dust * 0.35), 0.7);
   color = mix(color, color * vec3(0.96, 0.93, 0.88),
               1.0 - clamp(sweat * 0.5, 0.0, 1.0));
@@ -291,10 +290,9 @@ MaterialSample makeLinenSample(vec3 baseColor, vec3 Nw, vec3 Tw, vec3 Bw,
   mat.albedo = color;
   mat.normal = perturbNormalLinen(Nw, Tw, Bw, worldPos);
   float roughNoise = fbm(worldPos * 5.0, Nw, 7.5);
-  mat.roughness =
-      clamp(0.82 + roughNoise * 0.12 - wetMask * 0.22, 0.55, 0.96);
-  mat.ao = clamp(0.85 - dust * 0.20 - sweat * 0.15 + curvature * 0.05, 0.4,
-                 1.0);
+  mat.roughness = clamp(0.82 + roughNoise * 0.12 - wetMask * 0.22, 0.55, 0.96);
+  mat.ao =
+      clamp(0.85 - dust * 0.20 - sweat * 0.15 + curvature * 0.05, 0.4, 1.0);
   mat.F0 = vec3(0.028);
   return mat;
 }
@@ -314,11 +312,10 @@ MaterialSample makeBronzeSample(vec3 baseColor, vec3 Nw, vec3 Tw, vec3 Bw,
                  (1.0 - clamp(Nw.y, 0.0, 1.0));
 
   vec3 bronzeBase = mix(bronzeWarm, baseColor, 0.35) + vec3(hammer);
-  vec3 withCuprite =
-      mix(bronzeBase, cuprite,
-          smoothstep(0.70, 0.95, fbm(worldPos * 9.0, Nw, 12.0)));
-  vec3 color = mix(withCuprite, malachite,
-                   clamp(patina * 0.5 + runOff * 0.6, 0.0, 1.0));
+  vec3 withCuprite = mix(bronzeBase, cuprite,
+                         smoothstep(0.70, 0.95, fbm(worldPos * 9.0, Nw, 12.0)));
+  vec3 color =
+      mix(withCuprite, malachite, clamp(patina * 0.5 + runOff * 0.6, 0.0, 1.0));
 
   color = mix(color, color * 0.65, wetMask * 0.6);
 
@@ -360,9 +357,8 @@ MaterialSample makeWoodSample(vec3 baseColor, vec3 Nw, vec3 Tw, vec3 Bw,
   mat.albedo = color;
   vec3 macroNormal = applyMicroNormal(Nw, Tw, Bw, worldPos, 0.18);
   mat.normal = normalize(macroNormal + Tw * (grain * 0.05));
-  mat.roughness =
-      clamp(0.62 + fbm(worldPos * 6.0, Nw, 6.0) * 0.15 - wetMask * 0.18, 0.35,
-            0.92);
+  mat.roughness = clamp(
+      0.62 + fbm(worldPos * 6.0, Nw, 6.0) * 0.15 - wetMask * 0.18, 0.35, 0.92);
   mat.ao = clamp(0.9 - burn * 0.15 + curvature * 0.08, 0.4, 1.0);
   mat.metallic = 0.0;
   mat.F0 = vec3(0.035);
@@ -490,9 +486,8 @@ void main() {
   bool likelyLinen = (Y > 0.65 && S < 0.22);
   bool likelyBronze = (baseColor.r > baseColor.g * 1.03 &&
                        baseColor.r > baseColor.b * 1.10 && Y > 0.42);
-  float leatherDist =
-      min(colorDistance(baseColor, REF_LEATHER),
-          colorDistance(baseColor, REF_LEATHER_DARK));
+  float leatherDist = min(colorDistance(baseColor, REF_LEATHER),
+                          colorDistance(baseColor, REF_LEATHER_DARK));
   bool paletteLeather = leatherDist < 0.18;
   bool looksWood =
       (blueRatio > 0.42 && blueRatio < 0.8 && Y < 0.55 && S < 0.55) ||
@@ -500,16 +495,14 @@ void main() {
   bool looksCloth =
       colorDistance(baseColor, REF_CLOTH) < 0.22 ||
       (baseColor.b > baseColor.g * 1.25 && baseColor.b > baseColor.r * 1.35);
-  bool looksSkin =
-      colorDistance(baseColor, REF_SKIN) < 0.2 ||
-      (S < 0.35 && baseColor.r > 0.55 && baseColor.g > 0.35 &&
-       baseColor.b > 0.28);
+  bool looksSkin = colorDistance(baseColor, REF_SKIN) < 0.2 ||
+                   (S < 0.35 && baseColor.r > 0.55 && baseColor.g > 0.35 &&
+                    baseColor.b > 0.28);
   bool looksBeard =
       (!looksSkin &&
        (colorDistance(baseColor, REF_BEARD) < 0.16 || (Y < 0.32 && S < 0.4)));
-  bool looksMetal =
-      colorDistance(baseColor, REF_METAL) < 0.18 ||
-      (S < 0.15 && Y > 0.4 && baseColor.b > baseColor.r * 0.9);
+  bool looksMetal = colorDistance(baseColor, REF_METAL) < 0.18 ||
+                    (S < 0.15 && Y > 0.4 && baseColor.b > baseColor.r * 0.9);
 
   bool preferLeather = (paletteLeather && blueRatio < 0.42) ||
                        (likelyLeather && !looksWood && blueRatio < 0.4);
@@ -539,8 +532,8 @@ void main() {
     material = makeMetalSample(CANON_HELMET, Nw, Tw, Bw, v_worldPos, wetMask,
                                curvature);
   } else if (looksSkin && isFaceRegion) {
-    material = makeSkinSample(CANON_SKIN, Nw, Tw, Bw, v_worldPos, wetMask,
-                              curvature);
+    material =
+        makeSkinSample(CANON_SKIN, Nw, Tw, Bw, v_worldPos, wetMask, curvature);
   } else if (looksBeard && isFaceRegion) {
     material = makeHairSample(CANON_BEARD, Nw, Tw, Bw, v_worldPos, wetMask);
   } else if (looksWood) {
@@ -551,14 +544,13 @@ void main() {
     material =
         makeClothSample(baseColor, Nw, Tw, Bw, v_worldPos, wetMask, curvature);
   } else if (preferLeather) {
-    material = makeLeatherSample(baseColor, Nw, Tw, Bw, v_worldPos,
-                                 clamp(v_leatherTension, 0.0, 1.0),
-                                 clamp(v_bodyHeight, 0.0, 1.0), v_armorLayer,
-                                 wetMask, curvature);
+    material = makeLeatherSample(
+        baseColor, Nw, Tw, Bw, v_worldPos, clamp(v_leatherTension, 0.0, 1.0),
+        clamp(v_bodyHeight, 0.0, 1.0), v_armorLayer, wetMask, curvature);
   } else if (likelyLinen) {
-    material = makeLinenSample(baseColor, Nw, Tw, Bw, v_worldPos,
-                               clamp(v_bodyHeight, 0.0, 1.0), wetMask,
-                               curvature);
+    material =
+        makeLinenSample(baseColor, Nw, Tw, Bw, v_worldPos,
+                        clamp(v_bodyHeight, 0.0, 1.0), wetMask, curvature);
   } else if (likelyBronze) {
     material =
         makeBronzeSample(baseColor, Nw, Tw, Bw, v_worldPos, wetMask, curvature);
@@ -577,17 +569,16 @@ void main() {
     vec3 contribution = evaluateLight(material, lights[i], V);
     if (wetMask > 0.001) {
       contribution += clearcoatSpec(material.normal, lights[i].dir, V,
-                                    wetMask * 0.8,
-                                    mix(0.10, 0.03, wetMask)) *
+                                    wetMask * 0.8, mix(0.10, 0.03, wetMask)) *
                       lights[i].color * lights[i].intensity;
     }
     lightAccum += contribution;
   }
 
-  vec3 ambient = computeAmbient(material.normal) * material.albedo *
-                 material.ao * 0.35;
-  vec3 bounce =
-      vec3(0.45, 0.34, 0.25) * (0.15 + 0.45 * clamp(-material.normal.y, 0.0, 1.0));
+  vec3 ambient =
+      computeAmbient(material.normal) * material.albedo * material.ao * 0.35;
+  vec3 bounce = vec3(0.45, 0.34, 0.25) *
+                (0.15 + 0.45 * clamp(-material.normal.y, 0.0, 1.0));
   vec3 color = lightAccum + ambient + bounce * (1.0 - material.metallic) * 0.25;
 
   color = mix(color, color * 0.85, wetMask * 0.2);

+ 3 - 3
game/systems/save_load_service.cpp

@@ -204,8 +204,8 @@ auto SaveLoadService::list_campaigns(QString *out_error) const -> QVariantList {
   return m_storage->list_campaigns(out_error);
 }
 
-auto SaveLoadService::get_campaign_progress(const QString &campaign_id,
-                                         QString *out_error) const -> QVariantMap {
+auto SaveLoadService::get_campaign_progress(
+    const QString &campaign_id, QString *out_error) const -> QVariantMap {
   if (!m_storage) {
     if (out_error != nullptr) {
       *out_error = "Storage not initialized";
@@ -216,7 +216,7 @@ auto SaveLoadService::get_campaign_progress(const QString &campaign_id,
 }
 
 auto SaveLoadService::mark_campaign_completed(const QString &campaign_id,
-                                           QString *out_error) -> bool {
+                                              QString *out_error) -> bool {
   if (!m_storage) {
     if (out_error != nullptr) {
       *out_error = "Storage not initialized";

+ 2 - 2
game/systems/save_load_service.h

@@ -42,9 +42,9 @@ public:
 
   auto list_campaigns(QString *out_error = nullptr) const -> QVariantList;
   auto get_campaign_progress(const QString &campaign_id,
-                          QString *out_error = nullptr) const -> QVariantMap;
+                             QString *out_error = nullptr) const -> QVariantMap;
   auto mark_campaign_completed(const QString &campaign_id,
-                            QString *out_error = nullptr) -> bool;
+                               QString *out_error = nullptr) -> bool;
 
   static void openSettings();
 

+ 23 - 23
game/systems/save_storage.cpp

@@ -285,7 +285,8 @@ auto SaveStorage::list_campaigns(QString *out_error) const -> QVariantList {
   QSqlQuery query(m_database);
   const QString sql = QStringLiteral(
       "SELECT c.id, c.title, c.description, c.map_path, c.order_index, "
-      "COALESCE(p.completed, 0) as completed, COALESCE(p.unlocked, 0) as unlocked, "
+      "COALESCE(p.completed, 0) as completed, COALESCE(p.unlocked, 0) as "
+      "unlocked, "
       "p.completed_at "
       "FROM campaigns c "
       "LEFT JOIN campaign_progress p ON c.id = p.campaign_id "
@@ -315,8 +316,8 @@ auto SaveStorage::list_campaigns(QString *out_error) const -> QVariantList {
   return result;
 }
 
-auto SaveStorage::get_campaign_progress(const QString &campaign_id,
-                                     QString *out_error) const -> QVariantMap {
+auto SaveStorage::get_campaign_progress(
+    const QString &campaign_id, QString *out_error) const -> QVariantMap {
   QVariantMap result;
   if (!const_cast<SaveStorage *>(this)->initialize(out_error)) {
     return result;
@@ -346,7 +347,7 @@ auto SaveStorage::get_campaign_progress(const QString &campaign_id,
 }
 
 auto SaveStorage::mark_campaign_completed(const QString &campaign_id,
-                                       QString *out_error) -> bool {
+                                          QString *out_error) -> bool {
   if (!initialize(out_error)) {
     return false;
   }
@@ -360,11 +361,12 @@ auto SaveStorage::mark_campaign_completed(const QString &campaign_id,
       QDateTime::currentDateTimeUtc().toString(Qt::ISODateWithMs);
 
   QSqlQuery query(m_database);
-  query.prepare(QStringLiteral(
-      "INSERT INTO campaign_progress (campaign_id, completed, unlocked, completed_at) "
-      "VALUES (:campaign_id, 1, 1, :completed_at) "
-      "ON CONFLICT(campaign_id) DO UPDATE SET "
-      "completed = 1, completed_at = excluded.completed_at"));
+  query.prepare(
+      QStringLiteral("INSERT INTO campaign_progress (campaign_id, completed, "
+                     "unlocked, completed_at) "
+                     "VALUES (:campaign_id, 1, 1, :completed_at) "
+                     "ON CONFLICT(campaign_id) DO UPDATE SET "
+                     "completed = 1, completed_at = excluded.completed_at"));
   query.bindValue(QStringLiteral(":campaign_id"), campaign_id);
   query.bindValue(QStringLiteral(":completed_at"), now_iso);
 
@@ -595,16 +597,16 @@ auto SaveStorage::migrateSchema(int fromVersion,
 }
 
 auto SaveStorage::migrate_to_2(QString *out_error) const -> bool {
-  // Create campaigns table
+
   QSqlQuery query(m_database);
-  const QString create_campaigns_sql = QStringLiteral(
-      "CREATE TABLE IF NOT EXISTS campaigns ("
-      "id TEXT PRIMARY KEY NOT NULL, "
-      "title TEXT NOT NULL, "
-      "description TEXT NOT NULL, "
-      "map_path TEXT NOT NULL, "
-      "order_index INTEGER NOT NULL DEFAULT 0"
-      ")");
+  const QString create_campaigns_sql =
+      QStringLiteral("CREATE TABLE IF NOT EXISTS campaigns ("
+                     "id TEXT PRIMARY KEY NOT NULL, "
+                     "title TEXT NOT NULL, "
+                     "description TEXT NOT NULL, "
+                     "map_path TEXT NOT NULL, "
+                     "order_index INTEGER NOT NULL DEFAULT 0"
+                     ")");
 
   if (!query.exec(create_campaigns_sql)) {
     if (out_error != nullptr) {
@@ -614,7 +616,6 @@ auto SaveStorage::migrate_to_2(QString *out_error) const -> bool {
     return false;
   }
 
-  // Create campaign_progress table
   QSqlQuery progress_query(m_database);
   const QString create_progress_sql = QStringLiteral(
       "CREATE TABLE IF NOT EXISTS campaign_progress ("
@@ -627,13 +628,13 @@ auto SaveStorage::migrate_to_2(QString *out_error) const -> bool {
 
   if (!progress_query.exec(create_progress_sql)) {
     if (out_error != nullptr) {
-      *out_error = QStringLiteral("Failed to create campaign_progress table: %1")
-                       .arg(lastErrorString(progress_query.lastError()));
+      *out_error =
+          QStringLiteral("Failed to create campaign_progress table: %1")
+              .arg(lastErrorString(progress_query.lastError()));
     }
     return false;
   }
 
-  // Insert initial mission: Carthage vs Rome
   QSqlQuery insert_query(m_database);
   const QString insert_campaign_sql = QStringLiteral(
       "INSERT INTO campaigns (id, title, description, map_path, order_index) "
@@ -650,7 +651,6 @@ auto SaveStorage::migrate_to_2(QString *out_error) const -> bool {
     return false;
   }
 
-  // Initialize progress for the mission (unlocked by default)
   QSqlQuery progress_insert_query(m_database);
   const QString insert_progress_sql = QStringLiteral(
       "INSERT INTO campaign_progress (campaign_id, completed, unlocked) "

+ 2 - 2
game/systems/save_storage.h

@@ -33,9 +33,9 @@ public:
 
   auto list_campaigns(QString *out_error = nullptr) const -> QVariantList;
   auto get_campaign_progress(const QString &campaign_id,
-                          QString *out_error = nullptr) const -> QVariantMap;
+                             QString *out_error = nullptr) const -> QVariantMap;
   auto mark_campaign_completed(const QString &campaign_id,
-                            QString *out_error = nullptr) -> bool;
+                               QString *out_error = nullptr) -> bool;
 
 private:
   auto open(QString *out_error = nullptr) const -> bool;

+ 1 - 2
game/units/horse_archer.cpp

@@ -28,8 +28,7 @@ namespace Game::Units {
 HorseArcher::HorseArcher(Engine::Core::World &world)
     : Unit(world, TroopType::HorseArcher) {}
 
-auto HorseArcher::Create(Engine::Core::World &world,
-                           const SpawnParams &params)
+auto HorseArcher::Create(Engine::Core::World &world, const SpawnParams &params)
     -> std::unique_ptr<HorseArcher> {
   auto unit = std::unique_ptr<HorseArcher>(new HorseArcher(world));
   unit->init(params);

+ 2 - 2
game/units/horse_archer.h

@@ -6,8 +6,8 @@ namespace Game::Units {
 
 class HorseArcher : public Unit {
 public:
-  static auto Create(Engine::Core::World &world, const SpawnParams &params)
-      -> std::unique_ptr<HorseArcher>;
+  static auto Create(Engine::Core::World &world,
+                     const SpawnParams &params) -> std::unique_ptr<HorseArcher>;
 
 private:
   HorseArcher(Engine::Core::World &world);

+ 1 - 1
game/units/horse_spearman.cpp

@@ -29,7 +29,7 @@ HorseSpearman::HorseSpearman(Engine::Core::World &world)
     : Unit(world, TroopType::HorseSpearman) {}
 
 auto HorseSpearman::Create(Engine::Core::World &world,
-                             const SpawnParams &params)
+                           const SpawnParams &params)
     -> std::unique_ptr<HorseSpearman> {
   auto unit = std::unique_ptr<HorseSpearman>(new HorseSpearman(world));
   unit->init(params);

+ 8 - 1
game/units/troop_type.h

@@ -9,7 +9,14 @@
 
 namespace Game::Units {
 
-enum class TroopType { Archer, Swordsman, Spearman, MountedKnight, HorseArcher, HorseSpearman };
+enum class TroopType {
+  Archer,
+  Swordsman,
+  Spearman,
+  MountedKnight,
+  HorseArcher,
+  HorseSpearman
+};
 
 inline auto troop_typeToQString(TroopType type) -> QString {
   switch (type) {

+ 12 - 7
render/entity/arrow_vfx_renderer.cpp

@@ -107,7 +107,7 @@ static inline ArcherPose makePose(uint32_t seed) {
   QVector3D perpL(-dirL.z(), 0.0F, dirL.x());
   float elbowOffsetL = 0.15F;
   P.elbow_l = P.shoulder_l + dirL * (distL * 0.45F) + perpL * elbowOffsetL +
-             QVector3D(0, -0.08F, 0);
+              QVector3D(0, -0.08F, 0);
 
   QVector3D shoulder_to_hand_r = P.hand_r - P.shoulder_r;
   float distR = shoulder_to_hand_r.length();
@@ -116,7 +116,7 @@ static inline ArcherPose makePose(uint32_t seed) {
   QVector3D perpR(-dirR.z(), 0.0F, dirR.x());
   float elbowOffsetR = 0.12F;
   P.elbow_r = P.shoulder_r + dirR * (distR * 0.48F) + perpR * elbowOffsetR +
-             QVector3D(0, 0.02F, 0);
+              QVector3D(0, 0.02F, 0);
 
   return P;
 }
@@ -190,16 +190,21 @@ static inline void drawHeadAndNeck(const DrawContext &p, ISubmitter &out,
   out.mesh(getUnitSphere(), sphereAt(p.model, domeC, domeR), C.metal, nullptr,
            1.0F);
 
-  QVector3D visorBase(0.0F, P.head_pos.y() + P.head_r * 0.10F, P.head_r * 0.80F);
+  QVector3D visorBase(0.0F, P.head_pos.y() + P.head_r * 0.10F,
+                      P.head_r * 0.80F);
   QVector3D visorTip = visorBase + QVector3D(0.0F, -0.015F, 0.06F);
   out.mesh(getUnitCone(),
            coneFromTo(p.model, visorBase, visorTip, P.head_r * 0.38F),
            C.metal * 0.92F, nullptr, 1.0F);
 
-  QVector3D cheekL0(-P.head_r * 0.85F, P.head_pos.y() + P.head_r * 0.05F, 0.02F);
-  QVector3D cheekL1(-P.head_r * 0.85F, P.head_pos.y() - P.head_r * 0.20F, 0.04F);
-  QVector3D cheekR0(P.head_r * 0.85F, P.head_pos.y() + P.head_r * 0.05F, -0.02F);
-  QVector3D cheekR1(P.head_r * 0.85F, P.head_pos.y() - P.head_r * 0.20F, -0.04F);
+  QVector3D cheekL0(-P.head_r * 0.85F, P.head_pos.y() + P.head_r * 0.05F,
+                    0.02F);
+  QVector3D cheekL1(-P.head_r * 0.85F, P.head_pos.y() - P.head_r * 0.20F,
+                    0.04F);
+  QVector3D cheekR0(P.head_r * 0.85F, P.head_pos.y() + P.head_r * 0.05F,
+                    -0.02F);
+  QVector3D cheekR1(P.head_r * 0.85F, P.head_pos.y() - P.head_r * 0.20F,
+                    -0.04F);
   out.mesh(getUnitCone(),
            coneFromTo(p.model, cheekL0, cheekL1, P.head_r * 0.24F),
            C.metal * 0.95F, nullptr, 1.0F);

+ 3 - 3
render/entity/horse_archer_renderer_base.cpp

@@ -65,8 +65,7 @@ void HorseArcherRendererBase::adjust_variation(
   variation.shoulder_tilt = 0.0F;
 }
 
-void HorseArcherRendererBase::get_variant(const DrawContext &ctx,
-                                          uint32_t seed,
+void HorseArcherRendererBase::get_variant(const DrawContext &ctx, uint32_t seed,
                                           HumanoidVariant &v) const {
   QVector3D const team_tint = resolveTeamTint(ctx);
   v.palette = makeHumanoidPalette(team_tint, seed);
@@ -197,7 +196,8 @@ void HorseArcherRendererBase::addAttachments(
       quiver_config.fletching_color = m_config.fletching_color;
       quiver_config.quiver_radius = HumanProportions::HEAD_RADIUS * 0.45F;
 
-      if (auto *quiver_renderer = dynamic_cast<QuiverRenderer *>(quiver.get())) {
+      if (auto *quiver_renderer =
+              dynamic_cast<QuiverRenderer *>(quiver.get())) {
         quiver_renderer->setConfig(quiver_config);
       }
       quiver->render(ctx, pose.body_frames, v.palette, anim_ctx, out);

+ 2 - 3
render/entity/horse_archer_renderer_base.h

@@ -31,8 +31,7 @@ class HorseArcherRendererBase : public HumanoidRendererBase {
 public:
   explicit HorseArcherRendererBase(HorseArcherRendererConfig config);
   HorseArcherRendererBase(const HorseArcherRendererBase &) = delete;
-  HorseArcherRendererBase &
-  operator=(const HorseArcherRendererBase &) = delete;
+  HorseArcherRendererBase &operator=(const HorseArcherRendererBase &) = delete;
   HorseArcherRendererBase(HorseArcherRendererBase &&) = delete;
   HorseArcherRendererBase &operator=(HorseArcherRendererBase &&) = delete;
   ~HorseArcherRendererBase() override = default;
@@ -70,7 +69,7 @@ private:
 
   auto get_scaled_horse_dimensions(uint32_t seed) const -> HorseDimensions;
   auto compute_horse_archer_extras(uint32_t seed, const HumanoidVariant &v,
-                                    const HorseDimensions &dims) const
+                                   const HorseDimensions &dims) const
       -> HorseArcherExtras;
 
   HorseArcherRendererConfig m_config;

+ 2 - 1
render/entity/horse_spearman_renderer_base.cpp

@@ -138,7 +138,8 @@ auto HorseSpearmanRendererBase::compute_horse_spearman_extras(
       makeHorseProfile(seed, v.palette.leather, v.palette.cloth);
   extras.horse_profile.dims = dims;
   extras.spear_length = 1.15F + (hash_01(seed ^ 0xABCDU) - 0.5F) * 0.10F;
-  extras.spear_shaft_radius = 0.018F + (hash_01(seed ^ 0x7777U) - 0.5F) * 0.003F;
+  extras.spear_shaft_radius =
+      0.018F + (hash_01(seed ^ 0x7777U) - 0.5F) * 0.003F;
 
   return extras;
 }

+ 1 - 1
render/entity/horse_spearman_renderer_base.h

@@ -70,7 +70,7 @@ private:
 
   auto get_scaled_horse_dimensions(uint32_t seed) const -> HorseDimensions;
   auto compute_horse_spearman_extras(uint32_t seed, const HumanoidVariant &v,
-                                      const HorseDimensions &dims) const
+                                     const HorseDimensions &dims) const
       -> HorseSpearmanExtras;
 
   HorseSpearmanRendererConfig m_config;

+ 3 - 4
render/entity/mounted_knight_renderer_base.cpp

@@ -129,10 +129,9 @@ void MountedKnightRendererBase::customize_pose(
   pose_request.seatPose = (speed_norm > 0.55F)
                               ? MountedPoseController::MountedSeatPose::Forward
                               : MountedPoseController::MountedSeatPose::Neutral;
-  pose_request.torsoCompression =
-      std::clamp(0.18F + speed_norm * 0.28F +
-                     anim_ctx.variation.posture_slump * 0.9F,
-                 0.0F, 0.55F);
+  pose_request.torsoCompression = std::clamp(
+      0.18F + speed_norm * 0.28F + anim_ctx.variation.posture_slump * 0.9F,
+      0.0F, 0.55F);
   pose_request.torsoTwist = anim_ctx.variation.shoulder_tilt * 3.0F;
   pose_request.shoulderDip =
       std::clamp(anim_ctx.variation.shoulder_tilt * 0.6F +

+ 12 - 11
render/entity/nations/carthage/archer_renderer.cpp

@@ -137,18 +137,18 @@ public:
       if (color_roll < 0.60F) {
 
         v.facial_hair.color = QVector3D(0.18F + nextRand(beard_seed) * 0.10F,
-                                       0.14F + nextRand(beard_seed) * 0.08F,
-                                       0.10F + nextRand(beard_seed) * 0.06F);
+                                        0.14F + nextRand(beard_seed) * 0.08F,
+                                        0.10F + nextRand(beard_seed) * 0.06F);
       } else if (color_roll < 0.85F) {
 
         v.facial_hair.color = QVector3D(0.30F + nextRand(beard_seed) * 0.12F,
-                                       0.24F + nextRand(beard_seed) * 0.10F,
-                                       0.16F + nextRand(beard_seed) * 0.08F);
+                                        0.24F + nextRand(beard_seed) * 0.10F,
+                                        0.16F + nextRand(beard_seed) * 0.08F);
       } else {
 
         v.facial_hair.color = QVector3D(0.35F + nextRand(beard_seed) * 0.10F,
-                                       0.20F + nextRand(beard_seed) * 0.08F,
-                                       0.12F + nextRand(beard_seed) * 0.06F);
+                                        0.20F + nextRand(beard_seed) * 0.08F,
+                                        0.12F + nextRand(beard_seed) * 0.06F);
       }
 
       v.facial_hair.thickness = 0.85F + nextRand(beard_seed) * 0.35F;
@@ -183,16 +183,17 @@ public:
     float const bow_x = 0.0F;
 
     if (anim.is_in_hold_mode || anim.is_exiting_hold) {
-      float const t = anim.is_in_hold_mode ? 1.0F : (1.0F - anim.hold_exit_progress);
+      float const t =
+          anim.is_in_hold_mode ? 1.0F : (1.0F - anim.hold_exit_progress);
 
       controller.kneel(t * k_kneel_depth_multiplier);
       controller.lean(QVector3D(0.0F, 0.0F, 1.0F),
                       t * k_lean_amount_multiplier);
 
-      QVector3D const hold_hand_l(bow_x - 0.15F, controller.get_shoulder_y(true) + 0.30F,
-                                  0.55F);
-      QVector3D const hold_hand_r(bow_x + 0.12F, controller.get_shoulder_y(false) + 0.15F,
-                                  0.10F);
+      QVector3D const hold_hand_l(
+          bow_x - 0.15F, controller.get_shoulder_y(true) + 0.30F, 0.55F);
+      QVector3D const hold_hand_r(
+          bow_x + 0.12F, controller.get_shoulder_y(false) + 0.15F, 0.10F);
       QVector3D const normal_hand_l(bow_x - 0.05F + arm_asymmetry,
                                     HP::SHOULDER_Y + 0.05F + arm_height_jitter,
                                     0.55F);

+ 1 - 2
render/entity/nations/carthage/horse_archer_renderer.cpp

@@ -44,8 +44,7 @@ void register_horse_archer_renderer(EntityRendererRegistry &registry) {
           }
         }
         auto *scene_renderer = dynamic_cast<Renderer *>(&out);
-        if ((scene_renderer != nullptr) &&
-            (horse_archer_shader != nullptr)) {
+        if ((scene_renderer != nullptr) && (horse_archer_shader != nullptr)) {
           scene_renderer->setCurrentShader(horse_archer_shader);
         }
         static_renderer.render(ctx, out);

+ 1 - 2
render/entity/nations/carthage/horse_spearman_renderer.cpp

@@ -42,8 +42,7 @@ void register_horse_spearman_renderer(EntityRendererRegistry &registry) {
           }
         }
         auto *scene_renderer = dynamic_cast<Renderer *>(&out);
-        if ((scene_renderer != nullptr) &&
-            (horse_spearman_shader != nullptr)) {
+        if ((scene_renderer != nullptr) && (horse_spearman_shader != nullptr)) {
           scene_renderer->setCurrentShader(horse_spearman_shader);
         }
         static_renderer.render(ctx, out);

+ 2 - 1
render/entity/nations/carthage/spearman_renderer.cpp

@@ -145,7 +145,8 @@ public:
     float const arm_asymmetry = (hash_01(seed ^ 0xDEF0U) - 0.5F) * 0.04F;
 
     if (anim.is_in_hold_mode || anim.is_exiting_hold) {
-      float const t = anim.is_in_hold_mode ? 1.0F : (1.0F - anim.hold_exit_progress);
+      float const t =
+          anim.is_in_hold_mode ? 1.0F : (1.0F - anim.hold_exit_progress);
 
       controller.kneel(t * k_kneel_depth_multiplier);
       controller.lean(QVector3D(0.0F, 0.0F, 1.0F),

+ 6 - 5
render/entity/nations/kingdom/archer_renderer.cpp

@@ -107,16 +107,17 @@ public:
     float const bow_x = 0.0F;
 
     if (anim.is_in_hold_mode || anim.is_exiting_hold) {
-      float const t = anim.is_in_hold_mode ? 1.0F : (1.0F - anim.hold_exit_progress);
+      float const t =
+          anim.is_in_hold_mode ? 1.0F : (1.0F - anim.hold_exit_progress);
 
       controller.kneel(t * k_kneel_depth_multiplier);
       controller.lean(QVector3D(0.0F, 0.0F, 1.0F),
                       t * k_lean_amount_multiplier);
 
-      QVector3D const hold_hand_l(bow_x - 0.15F, controller.get_shoulder_y(true) + 0.30F,
-                                  0.55F);
-      QVector3D const hold_hand_r(bow_x + 0.12F, controller.get_shoulder_y(false) + 0.15F,
-                                  0.10F);
+      QVector3D const hold_hand_l(
+          bow_x - 0.15F, controller.get_shoulder_y(true) + 0.30F, 0.55F);
+      QVector3D const hold_hand_r(
+          bow_x + 0.12F, controller.get_shoulder_y(false) + 0.15F, 0.10F);
       QVector3D const normal_hand_l(bow_x - 0.05F + arm_asymmetry,
                                     HP::SHOULDER_Y + 0.05F + arm_height_jitter,
                                     0.55F);

+ 1 - 2
render/entity/nations/kingdom/horse_archer_renderer.cpp

@@ -44,8 +44,7 @@ void register_horse_archer_renderer(EntityRendererRegistry &registry) {
           }
         }
         auto *scene_renderer = dynamic_cast<Renderer *>(&out);
-        if ((scene_renderer != nullptr) &&
-            (horse_archer_shader != nullptr)) {
+        if ((scene_renderer != nullptr) && (horse_archer_shader != nullptr)) {
           scene_renderer->setCurrentShader(horse_archer_shader);
         }
         static_renderer.render(ctx, out);

+ 1 - 2
render/entity/nations/kingdom/horse_spearman_renderer.cpp

@@ -42,8 +42,7 @@ void register_horse_spearman_renderer(EntityRendererRegistry &registry) {
           }
         }
         auto *scene_renderer = dynamic_cast<Renderer *>(&out);
-        if ((scene_renderer != nullptr) &&
-            (horse_spearman_shader != nullptr)) {
+        if ((scene_renderer != nullptr) && (horse_spearman_shader != nullptr)) {
           scene_renderer->setCurrentShader(horse_spearman_shader);
         }
         static_renderer.render(ctx, out);

+ 2 - 1
render/entity/nations/kingdom/spearman_renderer.cpp

@@ -138,7 +138,8 @@ public:
     float const arm_asymmetry = (hash_01(seed ^ 0xDEF0U) - 0.5F) * 0.04F;
 
     if (anim.is_in_hold_mode || anim.is_exiting_hold) {
-      float const t = anim.is_in_hold_mode ? 1.0F : (1.0F - anim.hold_exit_progress);
+      float const t =
+          anim.is_in_hold_mode ? 1.0F : (1.0F - anim.hold_exit_progress);
 
       controller.kneel(t * k_kneel_depth_multiplier);
       controller.lean(QVector3D(0.0F, 0.0F, 1.0F),

+ 6 - 5
render/entity/nations/roman/archer_renderer.cpp

@@ -107,16 +107,17 @@ public:
     float const bow_x = 0.0F;
 
     if (anim.is_in_hold_mode || anim.is_exiting_hold) {
-      float const t = anim.is_in_hold_mode ? 1.0F : (1.0F - anim.hold_exit_progress);
+      float const t =
+          anim.is_in_hold_mode ? 1.0F : (1.0F - anim.hold_exit_progress);
 
       controller.kneel(t * k_kneel_depth_multiplier);
       controller.lean(QVector3D(0.0F, 0.0F, 1.0F),
                       t * k_lean_amount_multiplier);
 
-      QVector3D const hold_hand_l(bow_x - 0.15F, controller.get_shoulder_y(true) + 0.30F,
-                                  0.55F);
-      QVector3D const hold_hand_r(bow_x + 0.12F, controller.get_shoulder_y(false) + 0.15F,
-                                  0.10F);
+      QVector3D const hold_hand_l(
+          bow_x - 0.15F, controller.get_shoulder_y(true) + 0.30F, 0.55F);
+      QVector3D const hold_hand_r(
+          bow_x + 0.12F, controller.get_shoulder_y(false) + 0.15F, 0.10F);
       QVector3D const normal_hand_l(bow_x - 0.05F + arm_asymmetry,
                                     HP::SHOULDER_Y + 0.05F + arm_height_jitter,
                                     0.55F);

+ 2 - 4
render/entity/nations/roman/horse_archer_renderer.cpp

@@ -30,8 +30,7 @@ auto make_horse_archer_config() -> HorseArcherRendererConfig {
 
 void register_horse_archer_renderer(EntityRendererRegistry &registry) {
   registry.register_renderer(
-      "troops/roman/horse_archer",
-      [](const DrawContext &ctx, ISubmitter &out) {
+      "troops/roman/horse_archer", [](const DrawContext &ctx, ISubmitter &out) {
         static HorseArcherRendererBase const static_renderer(
             make_horse_archer_config());
         Shader *horse_archer_shader = nullptr;
@@ -44,8 +43,7 @@ void register_horse_archer_renderer(EntityRendererRegistry &registry) {
           }
         }
         auto *scene_renderer = dynamic_cast<Renderer *>(&out);
-        if ((scene_renderer != nullptr) &&
-            (horse_archer_shader != nullptr)) {
+        if ((scene_renderer != nullptr) && (horse_archer_shader != nullptr)) {
           scene_renderer->setCurrentShader(horse_archer_shader);
         }
         static_renderer.render(ctx, out);

+ 1 - 2
render/entity/nations/roman/horse_spearman_renderer.cpp

@@ -42,8 +42,7 @@ void register_horse_spearman_renderer(EntityRendererRegistry &registry) {
           }
         }
         auto *scene_renderer = dynamic_cast<Renderer *>(&out);
-        if ((scene_renderer != nullptr) &&
-            (horse_spearman_shader != nullptr)) {
+        if ((scene_renderer != nullptr) && (horse_spearman_shader != nullptr)) {
           scene_renderer->setCurrentShader(horse_spearman_shader);
         }
         static_renderer.render(ctx, out);

+ 2 - 1
render/entity/nations/roman/spearman_renderer.cpp

@@ -138,7 +138,8 @@ public:
     float const arm_asymmetry = (hash_01(seed ^ 0xDEF0U) - 0.5F) * 0.04F;
 
     if (anim.is_in_hold_mode || anim.is_exiting_hold) {
-      float const t = anim.is_in_hold_mode ? 1.0F : (1.0F - anim.hold_exit_progress);
+      float const t =
+          anim.is_in_hold_mode ? 1.0F : (1.0F - anim.hold_exit_progress);
 
       controller.kneel(t * k_kneel_depth_multiplier);
       controller.lean(QVector3D(0.0F, 0.0F, 1.0F),

+ 3 - 2
render/equipment/weapons/spear_renderer.cpp

@@ -36,8 +36,9 @@ void SpearRenderer::render(const DrawContext &ctx, const BodyFrames &frames,
   }
 
   if (anim.inputs.is_in_hold_mode || anim.inputs.is_exiting_hold) {
-    float const t =
-        anim.inputs.is_in_hold_mode ? 1.0F : (1.0F - anim.inputs.hold_exit_progress);
+    float const t = anim.inputs.is_in_hold_mode
+                        ? 1.0F
+                        : (1.0F - anim.inputs.hold_exit_progress);
 
     QVector3D braced_dir = QVector3D(0.05F, 0.40F, 0.91F);
     if (braced_dir.lengthSquared() > 1e-6F) {

+ 1 - 1
render/gl/humanoid/animation/animation_inputs.cpp

@@ -47,7 +47,7 @@ auto sampleAnimState(const DrawContext &ctx) -> AnimationInputs {
   if ((attack != nullptr) && (attack_target != nullptr) &&
       attack_target->target_id > 0 && (transform != nullptr)) {
     anim.is_melee = (attack->currentMode ==
-                    Engine::Core::AttackComponent::CombatMode::Melee);
+                     Engine::Core::AttackComponent::CombatMode::Melee);
 
     bool const stationary = !anim.is_moving;
     float const current_cooldown =

+ 1 - 1
render/gl/humanoid/animation/gait.h

@@ -7,4 +7,4 @@ namespace Render::GL {
 auto classifyMotionState(const AnimationInputs &anim,
                          float move_speed) -> HumanoidMotionState;
 
-} // namespace Render::GL
+}

+ 9 - 9
render/humanoid/pose_controller.cpp

@@ -32,13 +32,13 @@ void HumanoidPoseController::kneel(float depth) {
   float const left_knee_z = -0.06F * depth;
   m_pose.knee_l = QVector3D(-stance_narrow, left_knee_y, left_knee_z);
   m_pose.foot_l = QVector3D(-stance_narrow - 0.025F, HP::GROUND_Y,
-                           left_knee_z - HP::LOWER_LEG_LEN * 0.93F * depth);
+                            left_knee_z - HP::LOWER_LEG_LEN * 0.93F * depth);
 
   float const right_knee_y = pelvis_y - 0.12F;
   float const right_foot_z = 0.28F * depth;
   m_pose.knee_r = QVector3D(stance_narrow, right_knee_y, right_foot_z - 0.05F);
-  m_pose.foot_r =
-      QVector3D(stance_narrow, HP::GROUND_Y + m_pose.foot_y_offset, right_foot_z);
+  m_pose.foot_r = QVector3D(stance_narrow, HP::GROUND_Y + m_pose.foot_y_offset,
+                            right_foot_z);
 
   float const upper_body_drop = kneel_offset;
   m_pose.shoulder_l.setY(m_pose.shoulder_l.y() - upper_body_drop);
@@ -444,21 +444,21 @@ void HumanoidPoseController::hold_sword_and_shield() {
 
 void HumanoidPoseController::look_at(const QVector3D &target) {
   QVector3D const head_to_target = target - m_pose.head_pos;
-  
+
   if (head_to_target.lengthSquared() < 1e-6F) {
     return;
   }
 
   QVector3D const direction = head_to_target.normalized();
-  
+
   float const max_head_turn = 0.03F;
   QVector3D const head_offset = direction * max_head_turn;
-  
+
   m_pose.head_pos += QVector3D(head_offset.x(), 0.0F, head_offset.z());
-  
+
   float const neck_follow = 0.5F;
-  m_pose.neck_base += QVector3D(head_offset.x() * neck_follow, 0.0F, 
-                                 head_offset.z() * neck_follow);
+  m_pose.neck_base += QVector3D(head_offset.x() * neck_follow, 0.0F,
+                                head_offset.z() * neck_follow);
 }
 
 } // namespace Render::GL

+ 10 - 8
render/humanoid/rig.cpp

@@ -289,9 +289,9 @@ void HumanoidRendererBase::computeLocomotionPose(
   QVector3D const outward_r = right_axis;
 
   pose.elbow_l = elbowBendTorso(pose.shoulder_l, pose.hand_l, outward_l, 0.45F,
-                               0.15F, -0.08F, +1.0F);
+                                0.15F, -0.08F, +1.0F);
   pose.elbow_r = elbowBendTorso(pose.shoulder_r, pose.hand_r, outward_r, 0.48F,
-                               0.12F, 0.02F, +1.0F);
+                                0.12F, 0.02F, +1.0F);
 }
 
 void HumanoidRendererBase::drawCommonBody(const DrawContext &ctx,
@@ -548,9 +548,10 @@ void HumanoidRendererBase::drawCommonBody(const DrawContext &ctx,
   out.mesh(getUnitSphere(), sphereAt(ctx.model, right_eye_world, eye_radius),
            iris, nullptr, 1.0F);
 
-  out.mesh(getUnitCylinder(),
-           cylinderBetween(ctx.model, pose.shoulder_l, pose.elbow_l, upper_arm_r),
-           v.palette.cloth, nullptr, 1.0F);
+  out.mesh(
+      getUnitCylinder(),
+      cylinderBetween(ctx.model, pose.shoulder_l, pose.elbow_l, upper_arm_r),
+      v.palette.cloth, nullptr, 1.0F);
   out.mesh(getUnitSphere(), sphereAt(ctx.model, pose.elbow_l, joint_r),
            v.palette.cloth * 0.95F, nullptr, 1.0F);
   out.mesh(getUnitCylinder(),
@@ -559,9 +560,10 @@ void HumanoidRendererBase::drawCommonBody(const DrawContext &ctx,
   out.mesh(getUnitSphere(), sphereAt(ctx.model, pose.hand_l, hand_r),
            v.palette.leatherDark * 0.92F, nullptr, 1.0F);
 
-  out.mesh(getUnitCylinder(),
-           cylinderBetween(ctx.model, pose.shoulder_r, pose.elbow_r, upper_arm_r),
-           v.palette.cloth, nullptr, 1.0F);
+  out.mesh(
+      getUnitCylinder(),
+      cylinderBetween(ctx.model, pose.shoulder_r, pose.elbow_r, upper_arm_r),
+      v.palette.cloth, nullptr, 1.0F);
   out.mesh(getUnitSphere(), sphereAt(ctx.model, pose.elbow_r, joint_r),
            v.palette.cloth * 0.95F, nullptr, 1.0F);
   out.mesh(getUnitCylinder(),

+ 6 - 6
tests/render/pose_controller_compatibility_test.cpp

@@ -93,7 +93,7 @@ TEST_F(PoseControllerCompatibilityTest, PlaceHandAtUsesCorrectElbowIK) {
   right_axis.normalize();
   QVector3D const outward_r = right_axis;
   legacy_pose.elbow_r = elbowBendTorso(legacy_pose.shoulder_r, target_hand,
-                                      outward_r, 0.48F, 0.12F, 0.02F, 1.0F);
+                                       outward_r, 0.48F, 0.12F, 0.02F, 1.0F);
 
   // New controller approach
   HumanoidPoseController controller(pose, anim_ctx);
@@ -146,7 +146,7 @@ TEST_F(PoseControllerCompatibilityTest,
   reference_pose.shoulder_r.setY(HP::SHOULDER_Y - kneel_depth);
   reference_pose.neck_base.setY(HP::NECK_BASE_Y - kneel_depth);
   reference_pose.head_pos.setY((HP::HEAD_TOP_Y + HP::CHIN_Y) * 0.5F -
-                              kneel_depth);
+                               kneel_depth);
 
   // Use controller to kneel
   HumanoidPoseController controller(pose, anim_ctx);
@@ -207,9 +207,9 @@ TEST_F(PoseControllerCompatibilityTest, CanRecreateBowAimingPose) {
                          QVector3D(0.12F, pose.shoulder_r.y() + 0.15F, 0.10F));
 
   // Verify pose is in a reasonable configuration
-  EXPECT_LT(pose.pelvis_pos.y(), HP::WAIST_Y);    // Kneeling
+  EXPECT_LT(pose.pelvis_pos.y(), HP::WAIST_Y);     // Kneeling
   EXPECT_GT(pose.hand_l.y(), pose.shoulder_l.y()); // Left hand raised
-  EXPECT_GT(pose.hand_l.z(), 0.0F);               // Left hand forward
+  EXPECT_GT(pose.hand_l.z(), 0.0F);                // Left hand forward
   EXPECT_LT(pose.hand_r.z(), pose.hand_l.z()); // Right hand back (drawing bow)
 }
 
@@ -231,7 +231,7 @@ TEST_F(PoseControllerCompatibilityTest, CanRecreateMeleeAttackPose) {
                          QVector3D(-0.05F, HP::SHOULDER_Y + 0.03F, 0.53F));
 
   // Verify thrust pose characteristics
-  EXPECT_GT(pose.hand_r.z(), 0.80F);              // Hand extended forward
-  EXPECT_GT(pose.shoulder_l.z(), 0.0F);            // Body leaning forward
+  EXPECT_GT(pose.hand_r.z(), 0.80F);                // Hand extended forward
+  EXPECT_GT(pose.shoulder_l.z(), 0.0F);             // Body leaning forward
   EXPECT_GT(pose.elbow_r.z(), pose.shoulder_r.z()); // Elbow extended
 }

+ 10 - 7
tests/render/pose_controller_test.cpp

@@ -57,7 +57,7 @@ TEST_F(HumanoidPoseControllerTest, ConstructorInitializesCorrectly) {
   HumanoidPoseController controller(pose, anim_ctx);
   // Constructor should not modify the pose
   EXPECT_FLOAT_EQ(pose.head_pos.y(), 0.5F * (HumanProportions::HEAD_TOP_Y +
-                                            HumanProportions::CHIN_Y));
+                                             HumanProportions::CHIN_Y));
   EXPECT_FLOAT_EQ(pose.pelvis_pos.y(), HumanProportions::WAIST_Y);
 }
 
@@ -162,7 +162,8 @@ TEST_F(HumanoidPoseControllerTest, PlaceHandAtComputesElbow) {
   EXPECT_FALSE(approxEqual(pose.elbow_r, original_elbow));
 
   // Elbow should be between shoulder and hand
-  float const shoulder_to_elbow_dist = (pose.elbow_r - pose.shoulder_r).length();
+  float const shoulder_to_elbow_dist =
+      (pose.elbow_r - pose.shoulder_r).length();
   float const elbow_to_hand_dist = (target_position - pose.elbow_r).length();
   EXPECT_GT(shoulder_to_elbow_dist, 0.0F);
   EXPECT_GT(elbow_to_hand_dist, 0.0F);
@@ -215,7 +216,8 @@ TEST_F(HumanoidPoseControllerTest, SolveKneeIKPreventsGroundPenetration) {
   QVector3D const knee = controller.solveKneeIK(true, hip, foot, height_scale);
 
   // Knee should be at or above the floor threshold
-  float const min_knee_y = HumanProportions::GROUND_Y + pose.foot_y_offset * 0.5F;
+  float const min_knee_y =
+      HumanProportions::GROUND_Y + pose.foot_y_offset * 0.5F;
   EXPECT_GE(knee.y(), min_knee_y - 0.001F); // Small epsilon for floating point
 }
 
@@ -293,7 +295,8 @@ TEST_F(HumanoidPoseControllerTest, LookAtMovesHeadTowardTarget) {
   HumanoidPoseController controller(pose, anim_ctx);
 
   QVector3D const original_head_pos = pose.head_pos;
-  QVector3D const target(0.5F, pose.head_pos.y(), 2.0F); // Target in front and to the right
+  QVector3D const target(0.5F, pose.head_pos.y(),
+                         2.0F); // Target in front and to the right
 
   controller.look_at(target);
 
@@ -306,7 +309,7 @@ TEST_F(HumanoidPoseControllerTest, LookAtWithSamePositionDoesNothing) {
   HumanoidPoseController controller(pose, anim_ctx);
 
   QVector3D const original_head_pos = pose.head_pos;
-  
+
   controller.look_at(pose.head_pos); // Look at current position
 
   // Head should remain unchanged
@@ -335,9 +338,9 @@ TEST_F(HumanoidPoseControllerTest, GetShoulderYReflectsKneeling) {
   HumanoidPoseController controller(pose, anim_ctx);
 
   float const original_shoulder_y = controller.get_shoulder_y(true);
-  
+
   controller.kneel(0.5F);
-  
+
   float const kneeling_shoulder_y = controller.get_shoulder_y(true);
 
   // After kneeling, shoulder should be lower

+ 25 - 14
ui/qml/CampaignMenu.qml

@@ -6,14 +6,13 @@ import StandardOfIron.UI 1.0
 Item {
     id: root
 
+    property var campaigns: (typeof game !== "undefined" && game.available_campaigns) ? game.available_campaigns : []
+
     signal missionSelected(string campaignId)
     signal cancelled()
 
-    property var campaigns: (typeof game !== "undefined" && game.available_campaigns) ? game.available_campaigns : []
-
     anchors.fill: parent
     focus: true
-
     Keys.onPressed: function(event) {
         if (event.key === Qt.Key_Escape) {
             root.cancelled();
@@ -43,7 +42,6 @@ Item {
             anchors.margins: Theme.spacingXLarge
             spacing: Theme.spacingLarge
 
-            // Header
             RowLayout {
                 Layout.fillWidth: true
                 spacing: Theme.spacingMedium
@@ -60,6 +58,7 @@ Item {
                     text: qsTr("← Back")
                     onClicked: root.cancelled()
                 }
+
             }
 
             Rectangle {
@@ -68,7 +67,6 @@ Item {
                 color: Theme.border
             }
 
-            // Mission list
             ScrollView {
                 Layout.fillWidth: true
                 Layout.fillHeight: true
@@ -137,6 +135,7 @@ Item {
                                             font.pointSize: Theme.fontSizeSmall
                                             font.bold: true
                                         }
+
                                     }
 
                                     Rectangle {
@@ -154,7 +153,9 @@ Item {
                                             color: Theme.textDim
                                             font.pointSize: Theme.fontSizeSmall
                                         }
+
                                     }
+
                                 }
 
                                 Label {
@@ -166,6 +167,7 @@ Item {
                                     Layout.fillWidth: true
                                     font.pointSize: Theme.fontSizeMedium
                                 }
+
                             }
 
                             Text {
@@ -173,24 +175,29 @@ Item {
                                 font.pointSize: Theme.fontSizeHero
                                 color: Theme.textHint
                             }
+
                         }
 
                         Behavior on color {
                             ColorAnimation {
                                 duration: Theme.animNormal
                             }
+
                         }
 
                         Behavior on border.color {
                             ColorAnimation {
                                 duration: Theme.animNormal
                             }
+
                         }
+
                     }
+
                 }
+
             }
 
-            // Empty state
             Label {
                 visible: root.campaigns.length === 0
                 text: qsTr("No campaign missions available")
@@ -200,10 +207,11 @@ Item {
                 Layout.fillWidth: true
                 Layout.fillHeight: true
             }
+
         }
+
     }
 
-    // Mission detail panel
     Rectangle {
         id: missionDetailPanel
 
@@ -230,7 +238,8 @@ Item {
 
             MouseArea {
                 anchors.fill: parent
-                onClicked: {} // Prevent click-through
+                onClicked: {
+                }
             }
 
             ColumnLayout {
@@ -238,7 +247,6 @@ Item {
                 anchors.margins: Theme.spacingXLarge
                 spacing: Theme.spacingLarge
 
-                // Title
                 Label {
                     text: missionDetailPanel.campaignData ? (missionDetailPanel.campaignData.title || "") : ""
                     color: Theme.textMain
@@ -247,7 +255,6 @@ Item {
                     Layout.fillWidth: true
                 }
 
-                // Description
                 Label {
                     text: missionDetailPanel.campaignData ? (missionDetailPanel.campaignData.description || "") : ""
                     color: Theme.textSubLite
@@ -256,7 +263,6 @@ Item {
                     font.pointSize: Theme.fontSizeMedium
                 }
 
-                // Black placeholder scene
                 Rectangle {
                     Layout.fillWidth: true
                     Layout.fillHeight: true
@@ -272,9 +278,9 @@ Item {
                         font.pointSize: Theme.fontSizeLarge
                         horizontalAlignment: Text.AlignHCenter
                     }
+
                 }
 
-                // Buttons
                 RowLayout {
                     Layout.fillWidth: true
                     spacing: Theme.spacingMedium
@@ -292,13 +298,18 @@ Item {
                         text: qsTr("Start Mission")
                         enabled: missionDetailPanel.campaignData ? (missionDetailPanel.campaignData.unlocked || false) : false
                         onClicked: {
-                            if (missionDetailPanel.campaignData) {
+                            if (missionDetailPanel.campaignData)
                                 root.missionSelected(missionDetailPanel.campaignData.id);
-                            }
+
                         }
                     }
+
                 }
+
             }
+
         }
+
     }
+
 }

+ 16 - 1
ui/qml/ProductionPanel.qml

@@ -38,18 +38,20 @@ Rectangle {
         if (typeof sources === "object" && sources !== null) {
             if (nationKey && sources[nationKey])
                 return sources[nationKey];
+
             if (sources["default"])
                 return sources["default"];
+
         } else if (typeof sources === "string") {
             return sources;
         }
-
         return "";
     }
 
     function unitIconEmoji(unitType) {
         if (typeof StyleGuide !== "undefined" && StyleGuide.unitIcons)
             return StyleGuide.unitIcons[unitType] || StyleGuide.unitIcons["default"] || "👤";
+
         return "👤";
     }
 
@@ -133,6 +135,7 @@ Rectangle {
 
                                 Image {
                                     id: queueIconImage
+
                                     anchors.centerIn: parent
                                     width: 28
                                     height: 28
@@ -321,6 +324,7 @@ Rectangle {
 
                                     Image {
                                         id: archerRecruitIcon
+
                                         anchors.fill: parent
                                         fillMode: Image.PreserveAspectFit
                                         smooth: true
@@ -336,6 +340,7 @@ Rectangle {
                                         color: parent.parent.parent.isEnabled ? "#ecf0f1" : "#5a5a5a"
                                         font.pointSize: 24
                                     }
+
                                 }
 
                                 Text {
@@ -412,6 +417,7 @@ Rectangle {
 
                                     Image {
                                         id: swordsmanRecruitIcon
+
                                         anchors.fill: parent
                                         fillMode: Image.PreserveAspectFit
                                         smooth: true
@@ -427,6 +433,7 @@ Rectangle {
                                         color: parent.parent.parent.isEnabled ? "#ecf0f1" : "#5a5a5a"
                                         font.pointSize: 24
                                     }
+
                                 }
 
                                 Text {
@@ -503,6 +510,7 @@ Rectangle {
 
                                     Image {
                                         id: spearmanRecruitIcon
+
                                         anchors.fill: parent
                                         fillMode: Image.PreserveAspectFit
                                         smooth: true
@@ -518,6 +526,7 @@ Rectangle {
                                         color: parent.parent.parent.isEnabled ? "#ecf0f1" : "#5a5a5a"
                                         font.pointSize: 24
                                     }
+
                                 }
 
                                 Text {
@@ -594,6 +603,7 @@ Rectangle {
 
                                     Image {
                                         id: horseKnightIcon
+
                                         anchors.fill: parent
                                         fillMode: Image.PreserveAspectFit
                                         smooth: true
@@ -609,6 +619,7 @@ Rectangle {
                                         color: parent.parent.parent.isEnabled ? "#ecf0f1" : "#5a5a5a"
                                         font.pointSize: 24
                                     }
+
                                 }
 
                                 Text {
@@ -685,6 +696,7 @@ Rectangle {
 
                                     Image {
                                         id: horseArcherIcon
+
                                         anchors.fill: parent
                                         fillMode: Image.PreserveAspectFit
                                         smooth: true
@@ -700,6 +712,7 @@ Rectangle {
                                         color: parent.parent.parent.isEnabled ? "#ecf0f1" : "#5a5a5a"
                                         font.pointSize: 20
                                     }
+
                                 }
 
                                 Text {
@@ -776,6 +789,7 @@ Rectangle {
 
                                     Image {
                                         id: horseSpearmanIcon
+
                                         anchors.fill: parent
                                         fillMode: Image.PreserveAspectFit
                                         smooth: true
@@ -791,6 +805,7 @@ Rectangle {
                                         color: parent.parent.parent.isEnabled ? "#ecf0f1" : "#5a5a5a"
                                         font.pointSize: 20
                                     }
+
                                 }
 
                                 Text {