Browse Source

Add nation field to map JSON parsing and barracks rendering

Co-authored-by: djeada <[email protected]>
copilot-swe-agent[bot] 1 month ago
parent
commit
37c8e67530

+ 70 - 0
assets/maps/map_nation_test.json

@@ -0,0 +1,70 @@
+{
+  "name": "Nation Barracks Test",
+  "description": "Test map for Roman and Carthaginian barracks",
+  "coordSystem": "grid",
+  "maxTroopsPerPlayer": 100,
+  "grid": {
+    "width": 60,
+    "height": 60,
+    "tileSize": 1.0
+  },
+  "biome": {
+    "seed": 123,
+    "patchDensity": 3.0,
+    "patchJitter": 0.8,
+    "bladeHeight": [0.5, 1.2],
+    "bladeWidth": [0.03, 0.06],
+    "swayStrength": 0.3,
+    "swaySpeed": 1.2,
+    "heightNoise": [0.2, 0.06],
+    "grassPrimary": [0.3, 0.6, 0.28],
+    "grassSecondary": [0.44, 0.7, 0.32],
+    "grassDry": [0.6, 0.52, 0.38],
+    "soilColor": [0.28, 0.24, 0.18],
+    "rockLow": [0.5, 0.48, 0.46],
+    "rockHigh": [0.68, 0.69, 0.73],
+    "plantDensity": 0.5
+  },
+  "camera": {
+    "center": [30, 0, 30],
+    "distance": 25.0,
+    "tiltDeg": 45.0,
+    "yaw": 225.0,
+    "fovY": 45.0,
+    "near": 1.0,
+    "far": 300.0
+  },
+  "spawns": [
+    {
+      "type": "barracks",
+      "x": 20,
+      "z": 30,
+      "playerId": 1,
+      "maxPopulation": 100,
+      "nation": "roman_republic"
+    },
+    {
+      "type": "barracks",
+      "x": 40,
+      "z": 30,
+      "playerId": 2,
+      "maxPopulation": 100,
+      "nation": "carthage"
+    },
+    {
+      "type": "barracks",
+      "x": 30,
+      "z": 45,
+      "maxPopulation": 100
+    }
+  ],
+  "firecamps": [
+    { "x": 18, "z": 28, "intensity": 1.0, "radius": 3.0 },
+    { "x": 42, "z": 28, "intensity": 1.0, "radius": 3.0 }
+  ],
+  "victory": {
+    "type": "elimination",
+    "key_structures": ["barracks"],
+    "defeat_conditions": ["no_key_structures"]
+  }
+}

+ 1 - 0
game/map/json_keys.h

@@ -68,6 +68,7 @@ inline constexpr const char *Z = "z";
 inline constexpr const char *PLAYER_ID = "playerId";
 inline constexpr const char *TEAM_ID = "teamId";
 inline constexpr const char *MAX_POPULATION = "maxPopulation";
+inline constexpr const char *NATION = "nation";
 
 inline constexpr const char *VICTORY_TYPE = "type";
 inline constexpr const char *KEY_STRUCTURES = "key_structures";

+ 3 - 0
game/map/map_definition.h

@@ -1,9 +1,11 @@
 #pragma once
 
+#include "../systems/nation_id.h"
 #include "../units/spawn_type.h"
 #include "terrain.h"
 #include <QString>
 #include <QVector3D>
+#include <optional>
 #include <vector>
 
 namespace Game::Map {
@@ -33,6 +35,7 @@ struct UnitSpawn {
   int player_id = 0;
   int team_id = 0;
   int maxPopulation = 100;
+  std::optional<Game::Systems::NationID> nation;
 };
 
 struct FireCamp {

+ 13 - 0
game/map/map_loader.cpp

@@ -254,6 +254,19 @@ void readSpawns(const QJsonArray &arr, std::vector<UnitSpawn> &out) {
     constexpr int default_max_population = 100;
     spawn.maxPopulation =
         spawn_obj.value(MAX_POPULATION).toInt(default_max_population);
+    
+    // Parse nation field if present (for backward compatibility, it's optional)
+    if (spawn_obj.contains(NATION)) {
+      const QString nation_str = spawn_obj.value(NATION).toString();
+      Game::Systems::NationID nation_id;
+      if (Game::Systems::tryParseNationID(nation_str, nation_id)) {
+        spawn.nation = nation_id;
+      } else {
+        qWarning() << "MapLoader: unknown nation" << nation_str 
+                   << "- will use default";
+      }
+    }
+    
     out.push_back(spawn);
   }
 }

+ 6 - 1
game/map/map_transformer.cpp

@@ -177,7 +177,11 @@ auto MapTransformer::applyToWorld(
       sp.spawn_type = s.type;
       sp.aiControlled = !owner_registry.isPlayer(effective_player_id);
       sp.maxPopulation = s.maxPopulation;
-      if (const auto *nation =
+      
+      // Use nation from spawn definition if present, otherwise use player's nation
+      if (s.nation.has_value()) {
+        sp.nation_id = s.nation.value();
+      } else if (const auto *nation =
               Game::Systems::NationRegistry::instance().getNationForPlayer(
                   effective_player_id)) {
         sp.nation_id = nation->id;
@@ -185,6 +189,7 @@ auto MapTransformer::applyToWorld(
         sp.nation_id =
             Game::Systems::NationRegistry::instance().default_nation_id();
       }
+      
       auto obj = s_registry->create(s.type, world, sp);
       if (obj) {
         e = world.getEntity(obj->id());

+ 34 - 1
render/entity/barracks_renderer.cpp

@@ -1,5 +1,6 @@
 #include "barracks_renderer.h"
 #include "../../game/core/component.h"
+#include "../../game/systems/nation_id.h"
 #include "../../game/visuals/team_colors.h"
 #include "../geom/flag.h"
 #include "../geom/math_utils.h"
@@ -77,6 +78,28 @@ inline auto makePalette(const QVector3D &team) -> BarracksPalette {
   return p;
 }
 
+inline auto makeCarthaginianPalette(const QVector3D &team) -> BarracksPalette {
+  BarracksPalette p;
+  // Carthaginian style: warmer tones, white plaster, darker timber
+  p.plaster = QVector3D(0.95F, 0.93F, 0.85F);  // Bright white plaster
+  p.plasterShade = QVector3D(0.85F, 0.83F, 0.75F);
+  p.timber = QVector3D(0.28F, 0.18F, 0.10F);  // Darker, richer timber
+  p.timberLight = QVector3D(0.42F, 0.30F, 0.18F);
+  p.woodDark = QVector3D(0.22F, 0.14F, 0.08F);
+  p.thatch = QVector3D(0.75F, 0.62F, 0.30F);  // Slightly different thatch color
+  p.thatchDark = QVector3D(0.62F, 0.50F, 0.24F);
+  p.stone = QVector3D(0.65F, 0.62F, 0.58F);  // Lighter stone
+  p.stoneDark = QVector3D(0.50F, 0.48F, 0.45F);
+  p.door = QVector3D(0.32F, 0.24F, 0.16F);
+  p.window = QVector3D(0.30F, 0.38F, 0.45F);
+  p.path = QVector3D(0.68F, 0.65F, 0.58F);
+  p.crate = QVector3D(0.52F, 0.38F, 0.22F);
+  p.team = clampVec01(team);
+  p.teamTrim =
+      clampVec01(QVector3D(team.x() * 0.6F, team.y() * 0.6F, team.z() * 0.6F));
+  return p;
+}
+
 inline void drawCylinder(ISubmitter &out, const QMatrix4x4 &model,
                          const QVector3D &a, const QVector3D &b, float radius,
                          const QVector3D &color, Texture *white) {
@@ -680,6 +703,7 @@ void drawBarracks(const DrawContext &p, ISubmitter &out) {
 
   auto *t = p.entity->getComponent<Engine::Core::TransformComponent>();
   auto *r = p.entity->getComponent<Engine::Core::RenderableComponent>();
+  auto *u = p.entity->getComponent<Engine::Core::UnitComponent>();
   if ((t == nullptr) || (r == nullptr)) {
     return;
   }
@@ -688,7 +712,16 @@ void drawBarracks(const DrawContext &p, ISubmitter &out) {
   Texture *white = p.resources->white();
 
   QVector3D const team(r->color[0], r->color[1], r->color[2]);
-  BarracksPalette const c = makePalette(team);
+  
+  // Determine nation and select appropriate palette
+  // Default to Roman if nation is not specified
+  BarracksPalette c;
+  if (u != nullptr && u->nation_id == Game::Systems::NationID::Carthage) {
+    c = makeCarthaginianPalette(team);
+  } else {
+    // Roman (default)
+    c = makePalette(team);
+  }
 
   drawFoundation(p, out, unit, white, c);
   drawAnnex(p, out, unit, white, c);