aboutsummaryrefslogtreecommitdiffstats
path: root/requirements/milestones.org
diff options
context:
space:
mode:
Diffstat (limited to 'requirements/milestones.org')
-rw-r--r--requirements/milestones.org186
1 files changed, 186 insertions, 0 deletions
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 <bx/...> 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/<name>/= 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