aboutsummaryrefslogtreecommitdiffstats
path: root/CLAUDE.md
diff options
context:
space:
mode:
Diffstat (limited to 'CLAUDE.md')
-rw-r--r--CLAUDE.md186
1 files changed, 186 insertions, 0 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..5e54edd
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,186 @@
+# 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/<name>/<file>.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/<thing>`, `fix/<thing>` (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/gameplay-gaps.org` — sourced list of missing systems, prioritized.
+- `research/tech-stack.org` — locked tech choices and rationale.