Drone System — Phase 4 (Drone HP + Shop Trees) Implementation Plan
Drone System — Phase 4 (Drone HP + Shop Trees) Implementation Plan
Section titled “Drone System — Phase 4 (Drone HP + Shop Trees) Implementation Plan”For agentic workers: REQUIRED SUB-SKILL: superpowers:subagent-driven-development or executing-plans. Each task = one
bh-dev-chunkcycle (TDD →--import→ boot-check → full GUT suite →scripts/check-test-count.sh→ determinism). Steps use- [ ].
Goal: Give drones real HP (destroyable) and a per-class upgrade economy in the shop, so spending gold on drones is a strategic axis beside weapons + the pilot.
Decisions (locked by Chris 2026-06-28): (1) Full HP — drones take damage and can die; Durability is an HP upgrade. (2) Full spec trees — every attribute incl. the novel class mechanics (so Phase 4 is multi-cycle: 4A HP → 4B scaling trees + shop → 4C novel mechanics → 4D review).
Architecture: DroneState gains hp/max_hp; an enemy-contact pass damages drones (Sentinel taunt
ties in — it soaks). Drone upgrades reuse the existing shop: meta_upgrades with category: "Drones"
and ids like unlock-drone-bomber / drone-bomber-power. apply_to skips them (unknown StatEffect);
build_drone_loadout reads their levels to scale each class’s cfg; owns_class gates on the unlocks. The
class behaviours read the cfg scales (durability/speed/range/recharge/power/area). All drone state is
opt-in → the no-drone determinism baseline stays byte-identical.
Tech Stack: Godot 4.6 typed GDScript; /sim; GUT 9.6. Branch: feat/drone-system.
Global Constraints
Section titled “Global Constraints”- Determinism byte-identical — survival
1405185210/3122397125, crystals91572468/1173256610. Every new pass iteratesdrones(empty in baseline) or reads default-0 levels → no-op. Re-check each task. /simpure; upgrades are data + the build_drone_loadout seam (render-side). Numbers tunable (playtest).- Don’t touch
CLAUDE.md/git add -A; coordinate merges with the UI agent at the boundary.
Sub-cycle 4A — Drone HP (destroyable drones)
Section titled “Sub-cycle 4A — Drone HP (destroyable drones)”Task 4A.1: DroneState HP + deploy + a contact-damage pass + death
Section titled “Task 4A.1: DroneState HP + deploy + a contact-damage pass + death”Files: sim/drone_state.gd (hp/max_hp), sim/sim.gd (DRONE_BASE_HP, DRONE_RADIUS; set hp in
deploy_drones from cfg.durability; _damage_drones_from_enemies(dt) called each tick after
_update_drones; remove drones at hp<=0 with a death fx), tests/test_drone_hp.gd (new).
Mechanics: deploy_drones sets d.max_hp = DRONE_BASE_HP * cfg.get("durability", 1.0), d.hp = max_hp.
_damage_drones_from_enemies: for each drone, hash.query_circle(d.pos, DRONE_RADIUS, enemies) → sum
enemies.contact_dmg[ei] * dt → d.hp -= sum; if d.hp <= 0 remove the drone (emit death fx at d.pos).
Tie-in: the Sentinel taunt already pulls enemies onto the drone → they now chip its HP.
- Determinism: the pass iterates
drones(empty in baseline) → no-op → byte-identical. Verify. - Test: a deployed drone surrounded by enemies loses HP and is removed when it hits 0; a drone with no
enemies nearby keeps full HP;
deployscales max_hp bycfg.durability. Determinism unchanged. Commit.
Task 4A.2: HP in render-info + Bay/HUD readout (light)
Section titled “Task 4A.2: HP in render-info + Bay/HUD readout (light)”Files: sim/sim.gd (drones_render_info/decoy_render_info include hp/max_hp), render/decoy_renderer.gd
(optional thin HP ring on a drone). Render-only.
- Render-only (boot-verify). Determinism untouched. Commit.
Sub-cycle 4B — Drone upgrade shop trees (scaling attributes)
Section titled “Sub-cycle 4B — Drone upgrade shop trees (scaling attributes)”Task 4B.1: bible Drones meta_upgrades (unlocks + scaling attrs)
Section titled “Task 4B.1: bible Drones meta_upgrades (unlocks + scaling attrs)”Files: data/bible.json (meta_upgrades += Drones-category entries), tests/test_drone_shop.gd (new).
Entries (category “Drones”):
- Unlocks:
unlock-drone-bomber/interceptor/disruptor/logistics(type unlock, targetclass:<id>). - Global:
drone-slots(the +1 slot, already referenced byMetaState.drone_slots()). - Per class (id
drone-<class>-<attr>), the SCALING attrs:power(dmg),area(radius),endurance(life),durability(hp),speed,recharge. (Novel class-specific attrs land in 4C.) - Test: every Drones-category entry has a valid shape (id/category/base_cost/max_level/…); the unlocks
target a known class;
ContentDB.meta_upgrades()returns them; they group underShopCategories.present. - Add via the tab-indented python round-trip. Commit (data only — determinism untouched).
Task 4B.2: build_drone_loadout applies upgrade levels + owns_class gates on unlocks
Section titled “Task 4B.2: build_drone_loadout applies upgrade levels + owns_class gates on unlocks”Files: sim/meta_state.gd (owns_class reads unlock-drone-<klass> levels — sentinel always;
build_drone_loadout(sentinel_cfg, defs) folds each class’s drone-<class>-<attr> levels into the cfg
scales: dmg = 1 + power*STEP, radius = 1 + area*STEP, life, durability, speed, etc.),
sim/sim.gd (the apply path / steps as consts), tests/test_drone_loadout.gd (extend).
- Test: with
levels["drone-bomber-power"]=2, the built bomber spec’sdmgscale rises;owns_class ("bomber")false untilunlock-drone-bomberbought, true after.apply_todoes NOT mutate PlayerState for drone ids (unknown StatEffect → no-op). Determinism untouched (meta-side). Commit.
Task 4B.3: class behaviours read the cfg scales
Section titled “Task 4B.3: class behaviours read the cfg scales”Files: sim/sim.gd (thread cfg.speed/cfg.durability/cfg.range into _drone_bomber/_interceptor/
_disruptor/_logistics/_sentinel: e.g. BOMBER_SPEED * cfg.get("speed",1.0), targeting range from
cfg.range, deploy max_hp from cfg.durability (done in 4A)), tests.
- Test: a speed-upgraded interceptor moves faster; a range-upgraded drone targets farther. Determinism byte-identical (cfg defaults 1.0 → unchanged; opt-in). Commit.
Task 4B.4: main passes defs to build_drone_loadout
Section titled “Task 4B.4: main passes defs to build_drone_loadout”Files: main.gd (build_drone_loadout(sim.sentinel_cfg(), defs) at run start + on Bay deploy, where
defs = sim.content.meta_upgrades()). Boot + (playtest) the shop Drones tab → buy → drones scale up.
- Boot + suite + determinism. Commit. 4B boundary: fetch+merge origin; flag the scaling trees + HP as deploy-ready for Chris to playtest.
Sub-cycle 4C — Per-class novel mechanics (separate plan)
Section titled “Sub-cycle 4C — Per-class novel mechanics (separate plan)”Written after 4A+4B land. Each is a chunk with its own sim work + determinism check (all opt-in):
- Sentinel: taunt strength/radius, damage-reflect (return a fraction of contact damage to attackers), shield-pulse on expire (AoE on death).
- Bomber: multi-bomb payload (N blasts/cycle), armor-pen scaling.
- Interceptor: target-chaining (strike hits N nearby), crit.
- Disruptor: effect-unlocks (slow → fire-suppress [enemies in field don’t fire] → weaken [+dmg taken]).
- Logistics: repair rate/radius, also-repairs-drones, overcharge burst.
Sub-cycle 4D — Review + merge prep
Section titled “Sub-cycle 4D — Review + merge prep”- Whole-branch review (determinism parity, drone-HP lockstep, shop-category integrity,
/simpurity). fetch+merge origin; flag Phase 4 ready for Chris to merge + deploy. Then Phase 5 (counter-tuning vs the biomass enemy taxonomy, with playtest data).
Sequencing notes
Section titled “Sequencing notes”- 4A (HP) is the new system; 4B (shop trees) reuses the existing meta/shop infra (drone upgrades = Drones- category meta_upgrades whose levels build_drone_loadout reads — apply_to skips them). 4C (novel mechanics) is the big varied one → its own plan. Every task is determinism-neutral (drones + drone-upgrade levels are opt-in / default-0). Re-pin NEVER expected — a move = a leak into the no-drone baseline → STOP.