Weapon Damage + Upgrade Boost Implementation Plan
Weapon Damage + Upgrade Boost Implementation Plan
Section titled “Weapon Damage + Upgrade Boost Implementation Plan”For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Raise weapon damage output across the board per Chris’s direction — base_damage +30%
on every weapon that uses it, and the per-weapon “power” upgrade mod from ×1.25 (×1.20 for
scar_tissue) to ×1.5 for every weapon that has one, including the manual aim weapon.
Architecture: Two independent, purely numeric changes — a content-data edit
(data/bible.json) and a small constant-table edit (sim/upgrade_system.gd). No new code paths,
no logic changes. A determinism re-pin is expected and normal (see Global Constraints).
Tech Stack: Godot 4.6.3, typed GDScript, GUT 9.6.0.
Global Constraints
Section titled “Global Constraints”- Chronowell’s
base_damage(0) stays untouched — it’s an intentional zero-damage utility/CC weapon (sim/weapon_chronowell.gd:8: “Deals ZERO direct damage — it never touches sim.elemental_system.damage_enemy”), not an omission. - Scythe’s and Scar Tissue’s bespoke damage formulas (%-max-HP execute, stack-based reactive
burst) are untouched — only their table-driven
powermod magnitude changes; their own internal damage constants are a separate, unrequested change. - Determinism: this change will almost certainly shift the pinned baseline hash/checksum in
tests/test_determinism_survival.gd(enemies die faster on a fixed seed, shifting downstream spawn/kill timing). Re-pinning it is the normal, expected last step here — not a sign of a bug. sim.death_cause/soak death-cause tracking (merged earlier today) is unrelated and untouched.
Task 1: data/bible.json — +30% base_damage on the 12 weapons that use it
Section titled “Task 1: data/bible.json — +30% base_damage on the 12 weapons that use it”Files:
- Modify:
data/bible.json(12base_damagefields) - Modify:
tests/test_weapon_orbit.gd:59(pinned live-value test) - Modify:
tests/test_sweep_and_nova_stats.gd:40-41(pinned live-value test) - Modify:
tests/test_coop_integration.gd:14(stale comment only, value unchanged)
Interfaces: none (pure content-data change, no new function signatures).
- Step 1: Update the 12 base_damage values in
data/bible.json
Read the file first to confirm each weapon’s exact current line (line numbers below are from the most recent read of the file; verify before editing, since content data can drift). Apply exactly this ×1.30 table — every value below rounds to 2 decimal places where the multiply isn’t exact:
| Weapon | Old | New (×1.30) |
|---|---|---|
| blade | 3.0 | 3.9 |
| pulse | 3 | 3.9 |
| nova | 4 | 5.2 |
| orbit | 10.0 | 13.0 |
| beam | 0.8 | 1.04 |
| turret | 1.0 | 1.3 |
| scatter | 1.4 | 1.82 |
| blaster | 4 | 5.2 |
| chalice | 4.0 | 5.2 |
| thunder_wake | 20.0 | 26.0 |
| railgun | 6.0 | 7.8 |
| wildfire | 12.0 | 15.6 |
Do NOT touch scythe, scar_tissue, or chronowell’s base_damage (all 0) — leave them
exactly as-is, per this plan’s Global Constraints.
- Step 2: Update
tests/test_weapon_orbit.gd’s pinned live-value test
Find const BIBLE_BASE_DAMAGE := 10.0 (currently line 59) inside
test_orbit_full_contact_second_removes_exactly_base_damage_hp. Change to:
const BIBLE_BASE_DAMAGE := 13.0 # data/bible.json weapons/orbit base_damage (live value, boosted 2026-07-17: 10.0 * 1.30)The rest of the test (the assertion comparing final HP to 100.0 - BIBLE_BASE_DAMAGE) needs no
other change — it already derives its expected value FROM this constant, not a second hardcoded
number.
- Step 3: Update
tests/test_sweep_and_nova_stats.gd’s pinned live-value assertion
Find (currently lines 40-41):
# nova base_damage 4 * nova.damage_mult 2.0 = 8 ; no shock aura on a fresh enemy so unamplified assert_almost_eq(sim.enemies.data[e], 100.0 - 8.0, 0.001, "nova damage = base_damage * nova.damage_mult")Replace with:
# nova base_damage 5.2 (boosted 2026-07-17: bible.json 4 * 1.30) * nova.damage_mult 2.0 = 10.4 ; no shock aura on a fresh enemy so unamplified assert_almost_eq(sim.enemies.data[e], 100.0 - 10.4, 0.001, "nova damage = base_damage * nova.damage_mult")- Step 4: Update the stale comment in
tests/test_coop_integration.gd
Find (currently line 14):
const SPAWN_HP := 2.0 # one-shot by the blade's 3.0 base_damageThe numeric value 2.0 is CORRECT and unchanged — blade’s new 3.9 base_damage still one-shots
it (in fact more safely). Only the comment is stale. Replace with:
const SPAWN_HP := 2.0 # one-shot by the blade's 3.9 base_damage (boosted 2026-07-17, was 3.0)- Step 5: Run the affected tests to verify they pass
Run: godot --headless --path . -s res://addons/gut/gut_cmdln.gd -gselect=test_weapon_orbit -gexit
Run: godot --headless --path . -s res://addons/gut/gut_cmdln.gd -gselect=test_sweep_and_nova_stats -gexit
Run: godot --headless --path . -s res://addons/gut/gut_cmdln.gd -gselect=test_coop_integration -gexit
Expected: all PASS.
- Step 6: Commit
git add data/bible.json tests/test_weapon_orbit.gd tests/test_sweep_and_nova_stats.gd tests/test_coop_integration.gdgit commit -m "balance(weapons): +30% base_damage across the 12 weapons that use it"Task 2: sim/upgrade_system.gd — power mod magnitude 1.25/1.20 → 1.5
Section titled “Task 2: sim/upgrade_system.gd — power mod magnitude 1.25/1.20 → 1.5”Files:
- Modify:
sim/upgrade_system.gd:32-54(WEAPON_MODS,AIM_MODS)
Interfaces: none (constant-table value change only, no signature changes).
- Step 1: Update every
"power"entry inWEAPON_MODS
Read the current file first to confirm the table hasn’t drifted since this plan was written.
Change every ["power", 1.25] (14 occurrences: blade, pulse, nova, orbit, beam, turret, scatter,
blaster, scythe, chalice, thunder_wake, railgun, wildfire, momentum_core) to ["power", 1.5],
AND change scar_tissue’s ["power", 1.20] to ["power", 1.5] too (per Chris’s explicit
confirmation to bring it in line with the rest, not preserve the lower outlier value). Do NOT
add a "power" entry to chronowell — it has none today and this plan doesn’t add one (adding
damage to an intentionally-zero-damage weapon is a different, unrequested change).
The resulting table (verify your edit matches this exactly):
const WEAPON_MODS := { "blade": [["power", 1.5], ["arc", 1.30], ["reach", 1.25]], "pulse": [["power", 1.5], ["chain", 1.0], ["range", 1.30]], "nova": [["power", 1.5], ["radius", 1.30], ["rate", 0.82]], "orbit": [["power", 1.5], ["shard", 1.0], ["spin", 1.40], ["reach", 1.25]], "beam": [["power", 1.5], ["width", 1.40], ["reach", 1.25]], "turret": [["power", 1.5], ["count", 1.0], ["rate", 0.80]], "scatter": [["power", 1.5], ["pellets", 1.0], ["spread", 0.80]], "blaster": [["power", 1.5], ["rate", 0.80], ["multishot", 1.0]], "scythe": [["power", 1.5], ["arc", 1.30], ["reach", 1.25]], "chalice": [["power", 1.5], ["radius", 1.30], ["duration", 1.25]], "thunder_wake": [["power", 1.5], ["radius", 1.30], ["duration", 1.25], ["root", 1.0]], "railgun": [["power", 1.5], ["lances", 1.0], ["mark", 1.3]], "wildfire": [["power", 1.5], ["radius", 1.30], ["decal", 1.0]], "scar_tissue": [["power", 1.5], ["radius", 1.20], ["threshold", 0.85], ["lifesteal", 0.08]], "momentum_core": [["power", 1.5], ["rate", 0.85], ["charge_ease", 0.85], ["multishot", 1.0]], "chronowell": [["duration", 1.25], ["rate", 0.85], ["heal", 3.0]],}(Only the "power" entries change — every other mod kind/magnitude in this table is unchanged;
chronowell’s row is unchanged entirely, shown here only for context.)
- Step 2: Update
AIM_MODS’ power entry
Change (currently line 53):
const AIM_MODS := [["power", 1.25], ["pierce", 1.0], ["burst", 1.20], ["knockback", 1.30], ["firerate", 0.85], ["velocity", 1.20]]to:
const AIM_MODS := [["power", 1.5], ["pierce", 1.0], ["burst", 1.20], ["knockback", 1.30], ["firerate", 0.85], ["velocity", 1.20]]- Step 3: Run the upgrade-system test file to verify nothing broke
Run: godot --headless --path . -s res://addons/gut/gut_cmdln.gd -gselect=test_upgrade_system -gexit
Expected: PASS. (Per the pre-implementation audit, no test in this project asserts a damage
number derived from reading WEAPON_MODS/AIM_MODS’ magnitude through the live upgrade
pipeline — tests that call apply_mod("power", 1.25) pass their own literal magnitude directly
and are unaffected. If this run surfaces an assertion failure tied to the magnitude change
anyway, treat that as new information the pre-implementation audit missed — investigate and fix
the test’s expected value, don’t weaken the assertion.)
- Step 4: Commit
git add sim/upgrade_system.gdgit commit -m "balance(weapons): power upgrade mod 1.25/1.20 -> 1.5 across all weapons"Task 3: Verification, determinism re-pin, and push
Section titled “Task 3: Verification, determinism re-pin, and push”Files:
-
Modify:
tests/test_determinism_survival.gd(re-pinned hash/checksum, expected) -
Step 1: Full suite
Run: godot --headless --path . -s res://addons/gut/gut_cmdln.gd -gdir=res://tests -ginclude_subdirs -gexit
Expected: 0 unexpected failures outside test_determinism_survival (that one is EXPECTED to fail
here — its pinned hash/checksum literals are now stale). Same 4 pre-existing risky/pending.
- Step 2: Re-pin the determinism baseline
Run: godot --headless --path . -s res://addons/gut/gut_cmdln.gd -gselect=test_determinism_survival -gexit
Read the failure output — it prints the ACTUAL current snapshot_string().hash() and
state_checksum() values for the fixed seed. Update the two pinned literals in
tests/test_determinism_survival.gd to those actual values (find the existing
assert_eq(...).hash(), 4217109746-style literal and the state_checksum(),
3312602286-style literal — read the file to get their exact current form before editing).
Re-run the same command; expected: PASS with the new pinned values.
- Step 3: Count guard
Run: bash scripts/check-test-count.sh
Expected: test-count guard OK (241 scripts — this plan adds no new test files, only edits
existing ones).
- Step 4: Boot smoke
Run: godot --headless --path . --quit-after 90 2>&1 | grep "SCRIPT ERROR"
Expected: no output (clean).
- Step 5: Soak sanity check — confirm the bigger numbers don’t break anything
Run: bash scripts/soak.sh --runs=10 --ticks=36000 --player=skilled --seed0=11000
Expected: 0 invariant failures, 0 anomalies (specifically: no NaN/negative-HP flags from a much
larger hit landing in one tick, no early-end-without-game_over anomalies). Report the printed
death_tick_distribution/level_distribution — a real check on whether survival got
meaningfully easier with this change (informational for Chris, not a pass/fail gate, since a
requested damage buff naturally raising survival numbers is the expected and intended outcome,
not a regression).
- Step 6: Full re-pin commit
git add tests/test_determinism_survival.gdgit commit -m "test(determinism): re-pin baseline after weapon damage/upgrade boost"- Step 7: Push
git push origin main