Part II — Systems
The world & how it's stored
What it is. The battlefield is a 3D grid of small cells called voxels. A voxel is either empty or holds one block: a material (grass, lava, water, wall…), a shape (full cube, half block, slab, slope, wedge…), a rotation, and later a fractional height. Terrain is just columns of blocks rising from the ground; a building is blocks stacked on top. There is no separate "terrain" structure — one grid holds everything.
The facts rule. The map stores only facts: what material is where, in what shape and orientation. It never stores judgments like "walkable" or "costs 5." Those live in the rules layer (below). This is the single most important idea in the project: the map is what is; rules are how it behaves.
How it's stored.
- The grid is split into 16×16×16 chunks, so a map can be small (a demo) or effectively endless (an open world) with the same code.
- Files are saved by a codec that packs the grid into a compact binary format (.vmap), versioned so old files fail loudly rather than load wrong.
- Materials are catalogued in a registry (currently built in code, one day an on-disk catalog). Maps reference materials by index, so the catalog is append-only — entries are never reordered or removed.
Where it lives. src/map/ (voxel_map.gd, voxel_codec.gd, tile_type.gd, tile_type_registry.gd, the demo/test registries), assets/maps/ for map files, tools/ for the builders that create them.
Status: [built] — storage, codec, catalog, and demo/hills/test maps. The per-voxel fractional height byte is [planned] (schema 4).
The rules layer
What it is. A separate area of the code that decides how the world treats each material. It turns map facts into gameplay answers: can a unit stand here, what does it cost to move here, does standing here hurt, what statuses does it apply?
How it works. Three rule modules compose together:
- Material rules — one entry per material: passable or not, movement cost, hazard (lava, water, poison, fire, spikes) and its damage, status effects applied on contact, and behavioral flags.
- Movement rules — the tunable thresholds for climbing: how high a step is free (0.25), the ceiling a normal unit can climb (1.0), how much extra a climb costs, and the surcharge for wading without swim.
- Unit mobility — each unit's move budget, plus traits (float, fly, swim) and status effects (slow, stop, immobilize) that change how the rules apply to that unit.
Rules are data (editor-editable Godot resources) — the intent is that they can be tuned later from a debug/config screen without touching code.
Where it lives. src/rules/ (material_rules.gd, terrain_rule.gd, movement_rules.gd, unit_profile.gd).
Status: [built].
The pathfinding pipeline
What it is. The engine that answers "how does this unit get there?" — and, for the player, "where can this unit go?" It is called every time a player (or an NPC) wants to move.
How it works. Four steps:
- Read the field. From the map it computes a surface for every column — the exact height a unit would stand on. The map supplies only facts: heights, materials, shapes.
- Compose the verdict. For every candidate step, it asks the rules layer: is this step passable, what does it cost, is there a hazard? The rules consider the material, the height difference (a rise costs extra; one above the ceiling is blocked), and the unit's traits/statuses (fly ignores terrain, float ignores height and ground effects, swim skips the wading surcharge).
- Search. A budgeted search fans out from the unit's position, tracking how many move points each tile costs. It stops when it has spent the unit's entire move budget. This single pass produces the movement bubble (every reachable tile) — and, given a destination, the lowest-cost path to it.
- Report. The result is the ordered list of tiles to walk, the total cost, and every hazardous tile crossed — so the movement system can apply the damage and status effects as the unit actually walks through them.
The same search serves the player (bubble + path) and the AI (which uses the bubble to pick where to move). It is fully deterministic and runs headless — the whole pipeline is unit-tested.
Where it lives. src/pathfinding/ (path_evaluator.gd, pathfinder.gd, path_result.gd).
Status: [built] — flat steps, climbing, walls, water, hazards, flight/float/swim, status effects, movement bubble, hazard report. Jumping is [planned] (the rule supports a ceiling extension).
Movement & turn flow (planned)
Once a path is chosen, the movement phase walks the unit along it, applying the reported hazards as it goes, then consumes the turn. The exact order — move → act → end turn — and the rules for facing, disengage, and counterplay are still being designed. The pathfinding pipeline is the substrate this is built on.
Combat (planned)
Combat will compute, from the unit's final position: attack range (reusing the reachability machinery), line-of-sight (a voxel raycast sharing the rules' BLOCKS_LOS flags), damage from the attacker's ability and the defender's defense, and status effects. Damage/healing from terrain (the hazard reports) will be applied here, not in the pathfinder.
Units, jobs & abilities (planned)
Units have stats and a move budget. Jobs/classes unlock abilities learned by doing. The mobility traits and statuses already exist in UnitProfile and will be joined by combat stats and an ability catalog.
Items & economy (planned)
Equipment, consumables (including the statuses like float/swim that the rules already understand), shops, and job-point progression between battles.
AI (planned)
Enemy AI will consume the same reachability and cost model the player uses — evaluating its movement bubble, scoring candidate tiles (threat, hazards, height advantage), then pathfinding. Because everything reads the same rules, the AI cannot "cheat" the terrain in ways the player can't.
Rendering & presentation
What it is. Everything visual. It is strictly a consumer: it reads map data and rules and never feeds back into them.
How it works. - The voxel mesh builds each block's shape as triangles and drops interior faces hidden by neighbors (so a solid hill doesn't render its inner walls). - The smooth terrain view draws continuous ground across columns; the cosmetic layer adds per-tile tint, subtle surface jitter, and scattered props — all a pure function of the map's seed, so the same map always looks the same. - The theme maps each material to a color (later, scenes/textures), keeping visuals fully separate from logic. - The top grid is a shader overlay drawn on the terrain: grid lines, hover highlight, and selection — used by the player and by debugging. - Day/night runs on a timer for atmosphere (currently purely visual).
Where it lives. src/render/ (voxel_mesh.gd, terrain_mesh.gd, shape_geometry.gd, map_theme.gd, map_details.gd, map_view.gd, day_night.gd, top_grid.gdshader).
Status: [built] — box + smooth views, cosmetic layer, theme, top grid, day/night, F1 toggle. Voxel-side picking/hover is [partial].