From cd0c08dc7ce754473178ad3f32f7740a1dddc1eb Mon Sep 17 00:00:00 2001 From: Vaino Kauppila Date: Thu, 2 Jul 2026 22:58:25 +0300 Subject: Initial import: LibreForts (M0-M5 in progress) Open-source Forts clone: custom C++20 engine + data-driven (Lua) 2D physics artillery RTS. - Building: node/strut graph on a stiff mass-spring solver (canon Forts model), triangulation rigidity, axial + 30-degree angle-stress breaking, cascading collapse, fire (DoT + spread), ground destroys debris. - Weapons (M4): cannon (ballistic) + laser (beam/ignite) with select-and-aim-in- arc UX; splash / beam damage; bg-brace passthrough. - Devices + economy (M5): reactors + win/loss + restart, mines/turbines/battery, metal deposits, storage caps, per-shot energy cost. - Data-driven via Lua/sol2 with a layered mod loader; enemy-fort scenario mod. - Renderer: SDL3 + textures + ImGui dev UI. stb_image + ImGui vendored. - Assets: CC0 placeholders only; real game art loaded at runtime from the user's own install via forts: paths (bring-your-own; nothing copyrighted committed). See README.md / CLAUDE.md and research/ + requirements/ for detail. --- requirements/milestones.org | 186 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 requirements/milestones.org (limited to 'requirements/milestones.org') diff --git a/requirements/milestones.org b/requirements/milestones.org new file mode 100644 index 0000000..9aa5a5a --- /dev/null +++ b/requirements/milestones.org @@ -0,0 +1,186 @@ +#+TITLE: Forts Clone v0.1 -- Milestones +#+AUTHOR: Forts Clone Project +#+DATE: 2025-06-19 +#+OPTIONS: toc:3 num:t + +* Overview + +v0.1 is split into 7 milestones. Each milestone delivers something you can +run and test. Milestones are sequential -- each builds on the previous. + +* M0: Scaffolding & Build Environment [DONE] +SCHEDULED: <2025-06-19> +CLOSED: <2025-06-19> + +Goal: Container builds, SDL3 window opens, clears to a color. + +- [X] Containerfile with all dependencies pre-built +- [X] meson.build at project root, compiles and links SDL3 + Box2D + all deps +- [X] =src/main.cpp= -- SDL3 creates a window, clears to dark blue-gray +- [X] Camera: 2D orthographic, pan (arrows/middle-drag), zoom (scroll) +- [X] Input system: polling keyboard/mouse state +- [X] Podman build + run workflow + +Notes: +- Pivoted from bgfx to SDL3 renderer for M0. bgfx init fails silently on this + system (EGL-only Linux backend, GLX removed upstream). SDL3 OpenGL renderer + works perfectly. Revisit bgfx later in the project. +- Header collision: -I/usr/local/include/bx caused sys/types.h to find + bx/endian.h instead of glibc endian.h. Fixed by using single + -I/usr/local/include with qualified includes. + +* M1: Rendering & Physics Foundations [DONE] +SCHEDULED: <2025-06-19> +CLOSED: <2025-06-19> + +Goal: See physics bodies rendered as colored rectangles against terrain. + +- [X] Box2D v3 integration -- world, gravity, fixed timestep at 60Hz +- [X] Static terrain body (ground plane + platform) +- [X] Dynamic bodies falling and landing (proof of physics->render) +- [X] SDL3 sprite rendering (colored quads, world-to-screen transform) +- [X] Fixed-timestep accumulator pattern (physics at 60Hz, render at display rate) +- [X] Camera pan/zoom with proper defaults (zoom 10, centered on action) + +Notes: +- Box2D v3.0.0 has broken CMake (FetchContent pulls GLFW unconditionally). + Built from v3.1.1 directly (gcc -c src/*.c + ar rcs). +- b2ShapeDef.friction moved to b2ShapeDef.material.friction in v3. +- b2Rot is { float c, s; } (cos/sin), angle via std::atan2(rot.s, rot.c). + +* ARCHITECTURE NOTE: Building physics is a mass-spring system (the canon Forts model) + +The locked stack specified Box2D (weld/distance joints, b2DestructionListener) +for the building structure. Instead the building system is a custom *stiff +damped mass-spring solver* (=src/game/build_graph.*=) — the same model the +shipped game uses (see =research/forts-data-reference.org=). It maps directly +onto Forts' node/edge graph and onto its data. + +- Node = point mass with velocity; foundation nodes are pinned at the ground. +- Strut = a damped Hookean spring (F = k.dx + c.v), per-material stiffness. + Integrated semi-implicit with OVERSAMPLES (14) substeps for stiff-spring + stability (Forts uses the same oversampling). +- Rigidity is GEOMETRIC (triangulation); a lone strut is a free-hinging pin + joint. It SNAPS on (a) axial deformation past per-material MaxCompression/ + MaxExpansion, or (b) the 30-degree angle-stress rule for un-triangulated + struts — both taken from the shipped game's constants. +- Box2D is retained (=src/engine/physics.*=) but idle; foundation for M4 + projectiles / terrain collision. + +Consequence: multiplayer determinism now rests on our own solver, not Box2D's +cross-platform guarantees (revisit before netcode work). + +* LUA / MODDING: materials are now data-driven (sol2) [DONE for materials] + +Lua (sol2 3.5) is up. Materials are no longer hard-coded — they load at startup +from =data/materials.lua= via =load_materials()= (=src/game/data.*=), into a +runtime =BuildGraph::materials= vector. The layered loader works: + +1. =ScriptEngine= (=src/engine/script.*=) wraps a sol2 state, runs files with + errors caught (a bad mod can't crash the game). +2. Base =data/materials.lua= defines the global =Materials= array + helpers + (=FindMaterial=, =IndexOfMaterial=). +3. Every mod under =data/mods//= with a =materials.lua= is applied on top + in (Priority, name) order; mods mutate the shared =Materials= table. + (=data/mods/example-recolour-wood/= ships as a live demo.) + +Runtime data path is relative to CWD (run from the repo root). NEXT for Lua: +extend the same loader to weapons/devices/projectiles tables (lands with M4), +and a mod-selection step instead of "apply everything in data/mods/". + +* M2: Building System [MOSTLY DONE] + +Goal: Click to place struts on the map. They have physics, connect into a +graph, and form structures. + +- [X] Build mode: number keys 1-3 select material (wood / bg-brace / rope) +- [X] Strut placed as a mass-spring node/edge + colored quad, stress-tinted + (red under compression, blue under tension) +- [X] Anchored building only: a drag must START from an existing node or the + ground (foundation) — no growing structure out of thin air +- [X] Click-drag single strut; endpoints snap onto existing nodes +- [X] Drag-build (extrude): sweep an edge into a box with node-merging and an + auto diagonal brace; free (non-perpendicular) drag angle +- [X] Build-grace radial timer on un-triangulated struts (temporary rigid hold) +- [X] Building costs: placing a piece deducts metal + energy +- [X] Simple HUD: resource bars + current-material indicator +- [ ] Resource system: Metal (mines on deposits) + Energy (wind turbines) + -- DEFERRED to M5 (needs the reactor / game-loop context). For now metal + and energy are fixed starting pools that only deplete. + +* M3: Structural Destruction [MOSTLY DONE] + (swapped with weapons -- destruction goes hand-in-hand with M2 building) + +Goal: Overloaded structures snap and collapse; debris that falls is destroyed. +This is the purely-structural half of Forts destruction (no weapons yet). + +- [X] Axial failure: deformation past per-material MaxCompression/MaxExpansion + (wood +/-10%, asymmetric per material) — canon, read straight off the + spring length (not a reconstructed force) +- [X] Angle-stress failure: an un-triangulated strut snaps once it rotates past + ~30 deg from its built angle (Forts' rule; replaces the old dangle timer) +- [X] Cascading collapse: a snapped support redistributes load and overloads + neighbours, which snap in turn (emergent, not a scripted event) +- [X] Ground destroys falling debris: any non-foundation node that sinks below + the ground surface is removed (+ explosion puff), taking its edges with it +- [X] Disconnection -> fall -> destroy: a chunk that loses its path to a + foundation simply falls under gravity and dies on the ground +- [X] Materials: wood, background bracing, ropes (tension-only) +- [ ] Per-strut HP pool (separate from stress) -- belongs with M4 weapon damage +- [ ] Fire (damage-over-time, strut-to-strut spread) -- M4 + +* M4: Weapons & Damage + (swapped with destruction) + +Goal: Place and fire all three weapons. They feed the M3 graph via two damage +models (per-strut HP and radius splash) plus fire. + +- [ ] Per-strut HP pool, depleted by weapon hits (independent of stress) +- [ ] Cannon: click-drag angle/power, Box2D ballistic projectile, splash + damage with linear radius falloff, knockback impulse, ~25% fire chance +- [ ] Laser: click-drag beam; stops at wood, passes bg-brace/ropes; 100% ignite +- [ ] Flak: auto-target incoming shells within an arc; hitscan/fast projectile +- [ ] Direct vs splash delivery: foreground struts block direct fire; + background bracing is passed through by direct hits but takes splash + fire +- [ ] Fire system: ignition flag, damage-over-time, spread along the graph, + burns background bracing faster (the counter to the bg-brace trick) + +* M5: Reactor, Resources & Game Loop + +Goal: There's a reactor to destroy, and a real economy to build it with. + +- [ ] Reactor entity -- large block, HP bar +- [ ] Player reactor on left, dummy reactor on right +- [ ] Reactor takes damage from direct hits, fire, falling/collision +- [ ] Win condition: destroy reactor HP OR disconnect it from its foundation + (collapse) -- two distinct victory paths +- [ ] Resource system (deferred from M2): mines on metal deposits, wind + turbines for energy, generation rates, "can't build when broke" +- [ ] Win/lose condition + restart (R key) + +* M6: Dummy Fort & Map + +Goal: The dummy fort on the right is a hand-crafted target. The map has metal +deposits and a complete layout. + +- [ ] Dummy fort pre-built structure (reactor, wood walls, bg-brace, ropes) +- [ ] Map layout: terrain with metal deposits on both sides +- [ ] Player starting area: reactor + small starter shell + nearby deposits +- [ ] Visual polish: distinct colors for materials, simple sky backdrop + +* M7: Polish & Controls + +Goal: Everything feels good. Controls are responsive. Visuals are clear. + +- [ ] Repair tool: right-click damaged piece, pay resources to restore HP +- [ ] Recycle: shift+click to remove piece, recover partial resources +- [X] Camera feel: pan (arrows / middle-drag), scroll zoom (basic; edge-scroll TBD) +- [ ] Visual feedback: damage states, fire glow +- [X] Build UX: ghost/extrusion previews, hover highlights, build-grace timers +- [ ] Edge cases: zero resources enforcement, etc. + +* Dependency Graph + +#+begin_src text +M0 -- M1 -- M2 -- M3 -- M4 -- M5 -- M6 -- M7 +#+end_src -- cgit v1.3