# Forts Clone — developer guide An open-source, from-scratch clone of **Forts** (2D physics-based artillery RTS): build a fort out of struts, place weapons, and blast the enemy reactor to bits. C++20, custom engine, data-driven (Lua), no game engine. This file is the orientation for anyone (human or agent) picking up the project. Read `research/` and `requirements/` for the deep dives; this is the map. --- ## 1. Build & run **Everything builds inside a Podman container** (Fedora 41 with all deps pre-built in `/usr/local`, defined by `Containerfile`). The **binary runs on the host** (needs the host's SDL3 + a display). ```bash # one-time (and after editing Containerfile): build the dev image podman build -t forts-clone-dev . # configure + compile (from repo root) podman run --rm -v "$PWD":/src:Z --userns=keep-id localhost/forts-clone-dev:latest \ bash -c "cd /src && meson setup builddir && meson compile -C builddir" # run ON THE HOST, from the repo root (data/ is resolved relative to CWD) ./builddir/forts-clone ``` - `scripts/build.sh` wraps the container build/compile. - Lua is **statically linked** (Containerfile builds `liblua.a`) so the container-built binary runs on any host regardless of its lua soname. - If you add a dependency: add it to `Containerfile` **at the end** (so cached layers don't rebuild) unless it must come earlier. **Verify without a display:** you can't run the GUI in the container, so validate by (a) compiling clean, and (b) running Lua data files through a standalone `lua` to check they parse. Do both after changes. --- ## 2. Architecture Two layers under `src/`: - **`src/engine/`** — reusable: windowing/input (SDL3), 2D renderer (SDL_Renderer + textures + ImGui), camera, Lua host (sol2), Box2D wrapper (idle, kept for future projectiles). - **`src/game/`** — the game: the building graph + solver, and the data loaders. ### Key files | File | Role | |---|---| | `game/build_graph.{hpp,cpp}` | **The heart.** Node/strut graph + stiff mass-spring solver, stress/fire/breaking, splash & beam damage, materials table. | | `game/data.{hpp,cpp}` | Lua loaders: materials, weapons, devices, prebuilt structures, map. Layered mod loading. | | `engine/script.{hpp,cpp}` | sol2 wrapper (`ScriptEngine`); runs Lua files with errors caught. | | `engine/renderer.{hpp,cpp}` | Draw boxes/sprites/arcs/HUD, texture cache (+ `forts:` BYO paths), ImGui lifecycle. | | `engine/app.cpp` | The whole game loop: input, build/fire/place, fixed-step sim, rendering, dev UI. Big; most gameplay glue lives here. | | `engine/physics.*` | Box2D wrapper — currently **idle**, reserved for M4+ projectiles/terrain. | > `src/game/build_system.hpp` and `src/engine/verlet.*` are legacy/removed — the > solver is now the mass-spring in `build_graph`. If you see references, they're stale. --- ## 3. The physics model (this is what makes it Forts) Canon Forts is a **stiff damped mass-spring system**, and so is ours (see `research/forts-data-reference.org` for the extracted numbers). - **Node** = point mass with velocity; foundation nodes are pinned to the ground. - **Strut** = a damped Hookean spring (`F = k·Δx + c·v`), integrated semi-implicit with `OVERSAMPLES` (14) substeps for stiff-spring stability, inside a fixed 60 Hz timestep. - **Rigidity is geometric** — from triangulation, not a per-strut property. A lone strut is a free-hinging pin joint. You can only *start* a build from an existing node or the ground (no floating structure). - **Breaking:** (a) axial deformation past per-material `max_compression` / `max_expansion` (wood ±10%), and (b) the **30° angle-stress** rule on un-triangulated struts. Both from the shipped game data. - **Build grace:** a fresh strut is held rigid briefly (`SETTLE_TIME`, Forts' "TempBracing") so you can triangulate it before it hinges. - **Fire:** per-strut HP-over-time that **spreads along the graph** to flammable neighbours; bg-brace burns ~3× faster (the counter to the "hide supports as bg-brace" trick). - **Ground destroys** any debris that falls below the surface (our choice; Forts bounces it). Collapse is emergent: cut supports → chunk falls → ground kills it. - **Damage model:** splash = pure radius falloff (ignores structure, like Forts AoE); cannon shells **pass through bg-brace/rope** and detonate on wood; the laser beam passes through bg-brace/rope, damages+ignites everything it crosses, and **stops at wood**. **Tunables** live at the top of `build_graph.hpp` (`OVERSAMPLES`, `SETTLE_TIME`, `gravity`, `air_drag`, strengths) and in the Lua data. Most are exposed **live in the ImGui Dev panel** — use it; the constants were tuned by eye, not proven. ### Gotchas - Removing a node/edge **shifts indices**. Never cache node/edge indices across a frame where destruction can happen — re-query (see the `hover_node` re-validation in `app.cpp`). Use `break_edge`/`break_node`/`apply_splash` which keep everything consistent. - **Determinism:** the solver is order-deterministic but uses `sin/cos/sqrt`, so it is **not** cross-platform deterministic. Revisit before any lockstep netcode. - The **data path is relative to CWD** — run from the repo root. --- ## 4. Data-driven + modding (Lua / sol2) Game content is **Lua data**, loaded at startup. This is the seam mods hook into. Base files in `data/`: `materials.lua`, `weapons.lua`, `devices.lua`, `structures.lua`, `map.lua`. Each defines a global table (`Materials`, `Weapons`, `DeviceDefs`, `Structures`, `Deposits`/`MapDevices`) plus `Find*`/`IndexOf*` helpers. **Layered loader** (`data.cpp::run_layered`): base file runs first, then every `data/mods//.lua` runs on top in **(priority, name)** order, mutating or extending the global tables — exactly like Forts. A mod's `mod.lua` sets `Priority`. Example: `data/mods/enemy-fort/` adds the target fort + enemy reactor. To add content, prefer **editing Lua data** over hard-coding C++. When you must add a field, add it to the `*Def` struct, read it in `data.cpp` (`get_or` with a default), and document it in the Lua file. --- ## 5. Assets policy — IMPORTANT **Never commit Forts' proprietary art/audio/Lua to this repo.** It's EarthWork Games' copyrighted work. - The repo ships **CC0 placeholder art** only (Kenney — see `data/textures/CREDITS.md`) plus public-domain code (`third_party/stb`, MIT `third_party/imgui`). - To debug with the *real* game art, we use **bring-your-own game files** (like a Doom source port + WAD): a texture path `forts:REL` resolves at runtime to `$FORTS_DATA/REL` (auto-detected Steam path if unset). Missing game → graceful fallback to CC0 / colored boxes. Nothing copyrighted ever enters the repo. - Keep personal/BYO override mods under `data/mods/local-*/` (git-ignored). --- ## 6. Status (milestones) See `requirements/milestones.org` for the live checklist. Roughly: - **M0–M3 done:** scaffolding, rendering/physics, building system, structural destruction (stress/collapse/fire). - **M4 in progress:** cannon (ballistic) + laser (beam/fire) with the Forts select-a-weapon-and-aim-in-its-arc UX. Missing: mortar, flak/point-defence, machinegun/sniper (hitscan), guided missiles, EMP, per-shot recoil. - **M5 in progress:** reactors + win/loss + restart (R), real resource economy (mines on deposits, turbines by height, storage caps, firing costs energy), device framework + placement. - **Not started / later:** repair & recycle (M7), armour/door/shield materials, tech tree + upgrades, commanders, real map/terrain, AI, netcode. `research/gameplay-gaps.org` is the **sourced** list of what's missing and why — consult it before deciding what to build; don't guess from vibes. --- ## 7. Working conventions - **Branch for work.** `main` is the baseline. Do features and fixes on their own branches: `feat/`, `fix/` (e.g. `feat/mortar`, `fix/beam-passthru`). Don't commit feature work straight to `main`; open a branch, then merge. - **Commit/push only when asked.** End commit messages with the `Co-Authored-By: Claude ...` trailer. - **Build before you claim done** (compile in the container) and validate any Lua you touched with a standalone `lua` run. Be honest about what you couldn't verify (the GUI can't run headless here). - **Don't commit game assets** (§5), `builddir/`, or `imgui.ini`. - Match surrounding code style; keep the engine/game split; prefer data (Lua) over hard-coded constants. --- ## 8. Reference docs - `requirements/v0.1-core.org` — the v0.1 design spec. - `requirements/milestones.org` — milestone checklist + architecture notes. - `research/forts-gameplay.org` — gameplay research. - `research/forts-data-reference.org` — **exact numbers** extracted from the game data (physics constants, material/weapon/fire values, modding API). - `research/forts-data-map.org` — index of the shipped Forts data directory (layout, file inventory, what each area holds). Use it to find where a reference value or mechanic lives before diving into the game's Lua. - `research/gameplay-gaps.org` — sourced list of missing systems, prioritized. - `research/tech-stack.org` — locked tech choices and rationale.