Fights were ~3-5s; the user wanted 20-30s. Tuned the table (and added one mechanic) so they land there, re-validated against the sim throughout. - Engine: a `global_cooldown` (the genre swing timer, §10 "attack delay") — an actor can't start a new action until it elapses, so no button-masher can out-DPS the intended tempo. Config-driven (`global_cooldown` ticks; 0 = off). Actor gains `next_action_at`; engine gates decisions on it. - Controller: ScriptedPlayer now pressures with its heavy proactively when healthy (not only on the exact overrun frame), so the sim measures what a real player experiences instead of an unrealistically patient bound. - Config rebalance: damage cut + flattened, fatigue/regen/recovery co-tuned, and the kit made roughly **DPS-neutral** with auto-attack (each ability's cooldown matched to auto's damage-per-second). Under the global cooldown that's the key insight: abilities win through stagger leverage + timing, not raw throughput — otherwise strong abilities trivialize the pace and flat ones aren't worth their fill (the guardrail kept inverting until this landed). Auto-attacks (difficulty 0) also no longer fizzle. - Front-end: cache-bust the config fetch so edits are always picked up; widened the sim's archetype sweep to all six monsters. Result (sim, skilled play ≈ real play): monster fights 16-38s (centered ~24s); guardrail steep and green (even-con auto 0% → skill20 2% → skill50 12% → skill80 44% → skill100 78%); all six monsters winnable. Verified live in-browser: realistic play lands ~15-30s and a clean mid-fight reads perfectly on the dual bar. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| portraits | ||
| game.js | ||
| index.html | ||
| README.md | ||
| style.css | ||
Vigor — playable combat front-end
A browser battler that drives combat-core (via combat-wasm) in real time: pick
a foe, manage your single Vigor pool, and try not to spend your survival. The
engine is authoritative and unchanged — this is just a presentation layer and a
[HumanController] pushing your intent between ticks.
What's here
index.html/style.css/game.js— the UI (torch-lit dark fantasy).portraits/— AI-generated monster art (Z-Image on the LAN workstation; see../tools/portraits.py). Committed so the game runs offline.pkg/— the wasm-bindgen output (gitignored; rebuild with the command below).
Build & play
# 1. Build the wasm bridge into ./pkg (cargo on PATH; from combat/)
export PATH="$HOME/.cargo/bin:$PATH"
wasm-pack build combat-wasm --dev --target web \
--out-dir ../combat-web/pkg --out-name combat_wasm
# 2. Serve combat/ as the web root (so the page AND configs/ resolve)
python3 -m http.server 8013 --directory .
# 3. Open the game
open http://127.0.0.1:8013/combat-web/
(Re)generate portraits — needs the LAN ComfyUI / Z-Image server up:
python3 tools/portraits.py --url http://192.168.1.26:8188 --size 768
How to play
- Click a foe to start. The fight runs in real time (10 ticks/second).
- Auto-attack is on by default (toggle with the AUTO button or
space). - Abilities: click a card or press
1–5. Each shows its fill cost — spending fill lowers your capacity, so a big hit leaves you fragile. - Watch the dual bar: bright = current fill, dim = regen headroom, the gold
line is your ceiling (
cap), and the dark cracked zone on the right is fatigue — ceiling lost for the rest of the fight. When the ceiling collapses to your fill, the next hit overruns you (daze → KO). - Second Wind restores ceiling; Guard opens a brief block window. Passive auto-attacking beats the weak foes (Dire Rat, Skeleton); the Golem, Troll, and Wraith want real play — recover, punish when they're spent, don't over-commit.
Difficulty is a table: edit ../configs/default.json (monster stats, ability
numbers, the con curve) to taste — the same file the sim tunes against.