Files
2026-11-10 20:31:33 +01:00

17 KiB

AGENTS.md — RTS Civilization Game Engine Architecture & Roadmap

This document serves as the primary technical specification, architecture reference, and development guide for AI agents and developers implementing an RTS Civilization game (Real-Time Strategy / 4X hybrid) on top of this hexagonal 3D terrain engine.


0. Mandatory Agent Rules

0.1 All Values Must Be Configurable via YAML

Important

Strict Agent Directive: All gameplay values, numeric parameters, costs, multipliers, initial statistics, thresholds, ratios, yields, and game limits mentioned by the user MUST be implemented as configurable parameters loaded from YAML files (in the config/ directory) rather than being hardcoded in C++ code.

  • Whenever a new value, parameter, or mechanic is introduced, create or update a corresponding YAML configuration file and load it at startup.
  • Default values in C++ must only serve as fallbacks if the YAML key is absent.
  • Keep configurations modular (e.g. config/city.yaml, config/terrain_yields.yaml, config/game.yaml, config/units/*.yaml).

0.2 English Language & Externalized UI Text (Localization)

Important

Strict Agent Directive: Everything in the application must be in English.

  • Language Requirement: All source code, identifiers, variable and class names, comments, documentation, and user-facing text MUST be written in English.
  • External UI String Catalog: Any text, label, prompt, message, tooltip, menu item, dialog, or UI notification displayed on the screen MUST NOT be hardcoded in C++ source files.
  • File-based Translations: Screen texts must be loaded dynamically from a designated external string/localization file (e.g. config/strings_en.yaml or config/localization/en.yaml) containing the English translations/texts.
  • Key-Based Lookup: Code must reference screen texts exclusively by localization keys (e.g. localization.get("ui.button.found_city") or equivalent lookup) resolving to the external file.
  • Whenever new on-screen text is introduced, add its English translation entry to the external string file first before referencing its key in code.

1. Project Vision & Core Concept

Goal: Transform this 3D hexagonal terrain engine into a seamless Real-Time Strategy Civilization game.

Gameplay Formula:

  • Civilization Depth (4X): Hex-based empire building, city founding, tile improvements (farms, mines, lumber mills), territory border expansion, technology tree, and resource economy (Food, Production, Gold, Science, Culture).
  • RTS Dynamics: Continuous real-time simulation (with pause/speed controls) rather than strict turn-waiting. Units move, scout, build, and fight in real time with tactical unit control, responsive pathfinding, and dynamic skirmishes.
  • Visual Realism: Modern OpenGL 4.0 rendering with realistic heightmaps, animated procedural water, smooth multi-biome blending (grassland, forest, desert, tundra, red rock canyon, snow-capped mountains), and hex-edge river networks.

2. Existing Codebase Architecture

The project is built on C++, Qt (Widgets & OpenGL), and OpenGL 4.0 Core Profile.

Key Source Files & Responsibilities:

  • terrain.h:
    • Map dimensions: MAP_WIDTH = 300, MAP_HEIGHT = 125 (total 37,500 hexagons).
    • Hex geometry constants: LOD_0_SIZE = 1.0f, LOD_0_SIZE_Y = 0.4328799f.
    • Staggered column neighbor resolution: getHexNeighbor(x, y, edge, &nx, &ny).
    • Edge midpoints: getHexEdgeMidpoint(edge) for river routing.
    • Data structure TerrainPoint: height, biome type, river flags.
  • tile.h & tile.cpp:
    • Hexagon subdivision into triangles (LOD system: 6 base triangles subdivided \times 4 \times 4 = 96 triangles per hex).
    • Per-vertex elevation sampling from heightmap.jpg (scaled to 3.5\text{ km} peak height) with riverbed depression carving.
    • Smooth neighbor-aware normal generation across hex seams.
    • Triplanar texture binding: grass, rock cliff, sand beach, animated water, snow, sahara, tundra, red sand, red rock canyon, and woodland forest.
  • qscenerenderer.h & qscenerenderer.cpp:
    • QOpenGLWidget subclass managing camera view, rotation, and mouse interaction.
    • Interactive orthographic hex-tile minimap with camera viewport outline, drag-to-pan, and zoom controls.
  • shaders/simple.vert & shaders/simple.frag:
    • GLSL 400 shaders.
    • Biome typemap sampling and altitude/latitude-based snowline (2.5\text{ km} temperate, down to sea-level at polar caps).
    • Procedural dynamic dual-wave ocean and riverbed water rendering.
  • generate_rivers.py:
    • Python map preprocessor for strict hex-edge river connectivity and orthographic minimap generation.

Coordinate Systems:

  • Grid Coordinates: (tx, ty) with 0 \le tx < 300 and 0 \le ty < 125.
  • World Coordinates: \text{worldX} = tx \times 0.75 \text{worldY} = ty \times (2.0 \times \text{LOD\_0\_SIZE\_Y}) + (tx \% 2 == 0 \; ? \; 0.0 : \text{LOD\_0\_SIZE\_Y})
  • Elevation (Z): 0.0 at sea level; land rises up to \approx 3.5\text{ km}.

3. Game Systems Architecture

To implement the RTS Civilization game, develop modular subsystems decoupled from the raw rendering loop:

                      +-------------------+
                      |    GameManager    |
                      +---------+---------+
                                |
     +-----------------+--------+--------+-----------------+
     |                 |                 |                 |
+----+----+      +-----+-----+     +-----+-----+     +-----+-----+
| Faction |      |   Unit    |     |   City    |     | Economy & |
| Manager |      |  Manager  |     |  Manager  |     | Tech Tree |
+----+----+      +-----+-----+     +-----+-----+     +-----+-----+
     |                 |                 |                 |
     |         +-------+-------+         |                 |
     |         |  Pathfinding  |         |                 |
     |         |   (Hex A*)    |         |                 |
     |         +---------------+         |                 |
     +-----------------+-----------------+                 |
                       |                                   |
              +--------+--------+                          |
              | Fog of War /    |                          |
              | Visibility      |<-------------------------+
              +--------+--------+
                       |
              +--------+--------+
              | QSceneRenderer  | (OpenGL Viewport + UI Overlays)
              +-----------------+

3.1 Simulation Time & Tick System

The game combines continuous real-time rendering and interpolation (deltaTime) with a configurable Simulation Tick (movement_tick_duration in config/game.yaml, defaulting to 30.0 seconds at 1\times simulation speed):

  1. Tick Timer & Speed Multiplier:
    • GameManager::update advances an internal tick timer by deltaTime * simSpeedMultiplier.
    • When the timer reaches movement_tick_duration, a simulation tick fires (processTickYields).
  2. Discrete Per-Tick Economy & Progression (processTickYields):
    • Food & Population: City food yield is converted into inhabitants (food * foodToInhabitantsRatio).
    • Labor (Production): City labor yield is added to the active construction project (currentLabor), completing units or buildings when laborCost is reached, or accumulating locally if idle.
    • National Stockpiles: Culture, Faith, and Gold yields from all owned cities are added to the player's national treasury.
    • Science & Research: Total science generated per tick across a player's cities is applied directly to the active technology in the player's researchQueue.
  3. Continuous Real-Time Unit Movement (movement_speed, Scaled by Tick Duration):
    • Units move smoothly every frame, and their movement rate is defined in movement points (base hexes) per tick (movement_speed in config/units/*.yaml, stored in UnitConfig::movementSpeed — higher values mean faster movement, e.g., 2.0 for infantry/civilian, 3.0 for galley, 4.0 for cavalry).
    • Effective speed in hexes per second is calculated dynamically per hex segment as: \text{hexesPerSec} = \frac{\text{movementSpeed}}{\text{tickDuration} \times \text{stepCost}} \times \text{simSpeedMultiplier}
    • On flat terrain (stepCost = 1.0), a unit with movementSpeed = 2.0 traverses 2.0 hexes during one full simulation tick (0.5 ticks per hex).
  4. Unit Construction & Action Durations (action_durations):
    • Unlike movement_speed (which is a rate per tick), unit build actions (such as boerderij_bouwen and build_road under action_durations in config/units/builder.yaml) are configured as durations in simulation ticks (ticks per action, accessed via UnitConfig::getActionDuration).
    • Total real-time build duration in seconds is calculated as: \text{duration} = \text{ticks} \times \text{movement\_tick\_duration}
    • While building, buildProgress interpolates continuously from 0.0 to 1.0 over duration seconds (scaled by simSpeedMultiplier).
    • Similarly, city production (labor_cost in config/units/*.yaml and config/buildings.yaml) and technology research (science_cost in config/technologies.yaml) progress discretely each tick based on the city/empire's per-tick yield.

4. Agents & Unit Specifications

Units are autonomous or player-directed entities traversing the hex map in real time.

4.1 Unit Types

  1. Civilian Units:

    • Settler: Consumed to found a new City Center on valid land tiles (cannot settle on water or mountains).
    • Worker / Builder: Constructs tile improvements (Farms, Mines, Lumber Mills, Quarries, Roads) and repairs pillaged tiles. Can be automated via worker AI.
    • Trader / Caravan: Establishes land or sea trade routes between cities, providing continuous Gold, Food, and Production.
  2. Military Units (RTS Combat):

    • Melee: Scout \rightarrow Warrior \rightarrow Swordsman \rightarrow Musketman \rightarrow Infantry.
    • Ranged: Archer \rightarrow Crossbowman \rightarrow Field Cannon \rightarrow Artillery.
    • Cavalry: Horseman \rightarrow Knight \rightarrow Cavalry \rightarrow Tank (high movement speed, flanking bonuses).
    • Siege: Catapult \rightarrow Trebuchet \rightarrow Bombard (high bonus damage against city walls).
    • Naval: Galley \rightarrow Caravel \rightarrow Frigate \rightarrow Battleship (operates only on water hexes).

4.2 Unit Data Model (unit.h / unitconfig.h)

enum class UnitType { Settler, Worker, Warrior, Archer, Horseman, Galley };
enum class UnitState { Idle, Moving, Attacking, Harvesting, Building, Fortified };

class Unit {
public:
    int id;
    int factionId;
    UnitType type;
    UnitState state;
    
    // Grid Position & Smooth Real-time World Position
    int tileX, tileY;
    QVector3D worldPosition;
    QVector3D targetPosition;
    float moveProgress; // 0.0 to 1.0 between hexes
    
    // Attributes
    float health, maxHealth;
    float attackDamage;
    float defense;
    float movementSpeed; // movement points (base hexes) per simulation tick
    float visionRange;   // in hex radius
    
    // Path & Target
    std::vector<std::pair<int, int>> currentPath;
    int targetEntityId; // target unit or city
    
    void update(float deltaTime, float tickDuration, float simSpeedMultiplier);
    void commandMoveTo(int destX, int destY);
    void commandAttack(int targetId);
    void commandBuildImprovement(int improvementType);
};

4.3 Real-time Hex Pathfinding (Pathfinder.h)

  • Implement A* over the hexagonal grid with cost functions:
    • Flatland (Grassland/Plains): Base cost 1.0.
    • Forest / Jungle: Cost 2.0.
    • Hills: Cost 2.0.
    • River Crossing: Penalty +1.5 (unless road/bridge is present).
    • Mountain / Deep Water: Impassable for land units.
    • Friendly vs Enemy Hexes: ZOC (Zone of Control) penalties near hostile military units.

5. Cities, Territory & Improvements

5.1 City Architecture

  • City Founding: Consumes a Settler. Claims the center hex and immediate ring of 6 adjacent hexes.
  • Borders: Expanding territory based on accumulated Culture.
  • Hex Yields:
    • Food: Drives city population growth (Pop = 1, 2, 3 \dots).
    • Production (Hammers): Contributes to the active construction queue (units, buildings, wonders).
    • Gold: Empire treasury for unit upkeep, tile purchasing, and rush production.
    • Science: Advances active technology research in real time.
    • Culture: Expands borders and advances civics/policies.

5.2 Tile Improvements

  • Farm: Built on Grassland/Plains/Floodplains (+2\text{ Food}, river adjacency bonus).
  • Mine: Built on Hills (+2\text{ Production}).
  • Lumber Mill: Built on Forest (+1\text{ Production}, preserves forest defense).
  • Road: Built along hex edges/centers to reduce movement cost to 0.33.

6. AI Agent Behavior (Civilization Empire AI)

AI opponents must operate through a hierarchical decision architecture:

  1. Strategic Commander (Empire Level):
    • Assesses empire needs: expansion, military defense, economic development, or technology rush.
    • Queues city construction and manages empire-wide resource allocation.
  2. Operational Commander (Theater Level):
    • Coordinates multi-unit formations (e.g. Settler with Warrior escort; army squads containing front-line melee and rear-line archers).
    • Manages tactical skirmishes, city sieges, and territorial defense.
  3. Tactical Agent (Unit Level):
    • Implements Utility AI or Behavior Trees:
      • Worker AI: evaluates unworked tiles in city radius and constructs optimal improvements.
      • Scout AI: moves toward unrevealed fog of war while avoiding hostile barbarians.
      • Military AI: attacks vulnerable targets, retreats when health drops below 30\%, uses terrain defense bonuses.

7. Fog of War & Vision System

  1. Three Visibility States:
    • Unexplored (Black): Never seen. No terrain, no entities.
    • Explored / Fog of War (Grayscale/Dimmed): Previously discovered terrain and static cities visible; enemy units hidden.
    • Visible (Full Color): Currently within line-of-sight of any friendly unit or city.
  2. GPU Texture Mask:
    • Maintain a 300 \times 125 texture updated on the CPU / compute shader representing visibility (0 = \text{black}, 128 = \text{fog}, 255 = \text{visible}).
    • Sample this mask in simple.frag to dim or mask terrain and hide out-of-vision units.

8. Implementation Roadmap

Phase 1: Core Simulation Loop & Pathfinding

  • Create GameSimulation class with fixed-tick update (e.g., 20 ticks/sec).
  • Implement hex A* pathfinding (Pathfinder.h/.cpp) using getHexNeighbor.
  • Add basic Unit class with real-time waypoint interpolation across hex centers.
  • Implement mouse raycasting / hex picking from screen click to (tx, ty).

Phase 2: Unit Rendering & RTS Controls

  • Render 3D unit meshes / billboards on tile surfaces at correct elevation Z.
  • Implement standard RTS controls: Left-click select, box-select, right-click move/attack.
  • Add unit health bars, selection rings, and minimap unit dots.

Phase 3: Cities & Tile Improvements

  • Implement City class, city founding with Settler, and territory border rendering.
  • Add Worker unit improvement actions (Farm, Mine, Road).
  • Implement resource yield accumulation (Food, Production, Gold, Science).

Phase 4: Combat, Technology & Opponent AI

  • Implement real-time combat calculation, ranged attack trajectories, and damage resolution.
  • Add Technology Tree interface and research progression.
  • Implement AI Factions and Barbarian encampments.

9. Coding Guidelines for Agents & Developers

  • Language Standard: C++17 with Qt 5/6 framework.
  • Rendering Thread Safety: Game logic and pathfinding must run synchronously or safely decoupled from paintGL(). Never call OpenGL functions outside the OpenGL context thread.
  • Memory Management: Use RAII and smart pointers (std::unique_ptr, std::shared_ptr) for entities. Avoid raw manual array allocations in game loop updates.
  • Performance:
    • With 37,500 hexes, avoid iterating all hexes every frame. Use spatial partitioning or chunking for unit queries.
    • Batch unit rendering using instanced OpenGL draw calls (glDrawArraysInstanced or glDrawElementsInstanced).
  • Math Consistency: Always use terrain.h helper functions (getHexNeighbor, getHexEdgeMidpoint, LOD_0_SIZE_Y) to maintain consistent geometry and alignment with the terrain mesh.
  • Language & Localization: English only across the entire codebase and UI. Never hardcode screen display text in C++; always retrieve English strings from the external localization file (config/strings_en.yaml).