You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Merge pull request #6 from ShemJM/claude/agent-game-creation-plan-09a1jz
Phase D: adventure_demo — the full RPG loop end-to-end + docs pass
games/adventure_demo.rpgc chains every v5 system in one game: quest NPC
grants gold -> shop (buy potion + sword) -> armory equips it (has_item
branch, +6 atk) -> unwinnable-without-gear Ogre fight using battle_item
mid-battle (HP totals chosen so the outcome is variance-proof) -> win
branch breaks the gate seal -> transfer to the sanctum -> claim the
crystal. The scenario asserts gold/stock/stats/HP bounds/battle result/
switches/transfer position at every step.
Docs: CLAUDE.md points to it as the canonical full-loop example;
CURRENT_STATE.md moves party/shops/battle to "what works" with the
remaining gaps listed; ROADMAP.md marks the Phase 7 v1 subset done.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012y1ompK7McTvuvy5jmVcio
Copy file name to clipboardExpand all lines: CLAUDE.md
+43-6Lines changed: 43 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,7 +12,7 @@ rpg-creator is an RPG Maker-style tool built in **Godot 4.6 / GDScript**. Humans
12
12
13
13
Setup: `make setup` resolves or downloads a Godot 4.6 binary into `bin/godot` (a SessionStart hook does this automatically in Claude Code web sessions; it needs network access to `github.com/godotengine`, or set `$GODOT` to an existing binary). There is no build step — GDScript is interpreted.
14
14
15
-
Canonical worked example: `games/lost_crystal.rpgm`+ `games/lost_crystal_scenario.json`.
15
+
Canonical worked examples: `games/lost_crystal.rpgm`(dialogue/switch adventure) and `games/adventure_demo.rpgc` (full RPG loop: quest → shop → equip → boss battle with a mid-fight item → transfer), each with a passing `*_scenario.json`.
16
16
17
17
## Headless CLI
18
18
@@ -36,10 +36,11 @@ Written/read by `ProjectState.serialize()/deserialize()` (`scripts/autoloads/pro
36
36
37
37
```json
38
38
{
39
-
"version": 4,
39
+
"version": 5,
40
40
"maps": [ ... ],
41
41
"tileset": [ ... ], // optional — omit to get the default 5-tile set
42
42
"player_graphic": null, // optional charset; null = colored-block player
| 4 | CONDITIONAL_BRANCH |`{ "condition_type": "switch"\|"variable_gte"\|"self_switch", "id": 1, "value": true, "commands_if": [...], "commands_else": [...] }` — for `switch`,`value`is bool; for `variable_gte`, condition is variable[id] ≥ value; for `self_switch`,`value` is the letter (`"A"`)|
| 18 | CHANGE_HP |`{ "actor_id": -1 (whole party) \| id, "op": "add"\|"sub"\|"set", "value": 20, "allow_ko": false }` — without `allow_ko` HP floors at 1; with it, a full party wipe triggers game over |
111
+
| 19 | CHANGE_EQUIPMENT |`{ "actor_id": 0, "slot": "weapon"\|"head"\|"body"\|"accessory", "equip_id": 3 }` — `-1` unequips; equipping consumes the piece from equip stock (grant it with CHANGE_ITEMS `kind:"equip"` first), unequipping returns it |
112
+
| 20 | USE_ITEM |`{ "item_id": 0, "actor_id": 0 }` — applies the item's `effect``{"hp": n, "mp": n}` restore; consumables decrement; no-op (traced `ok:false`) if out of stock |
113
+
| 21 | SHOP_PROCESSING |`{ "entries": [ { "kind": "item"\|"equip", "id": 0, "price": 30 } ] }` — `price` optional (defaults to database price); sell price = floor(db price / 2); **blocks the event until the shop closes** — drive it with the `shop_buy`/`shop_sell`/`shop_close` scenario actions |
114
+
| 22 | BATTLE_PROCESSING |`{ "enemies": [enemy_id, ...], "can_flee": true, "commands_win": [...], "commands_lose": [...] }` — blocks until the battle ends; `win` splices `commands_win`, `lose` splices `commands_lose` (**empty `commands_lose` = game over**), `flee` continues past the command |
107
115
108
116
Follow-up branching after SHOW_CHOICES: the chosen index is written to **variable 0** — branch with CONDITIONAL_BRANCH on `condition_type: "variable"`. There are **100 switches and 100 variables** (ids 0–99), reset each play-test. Self-switches are per-event letters A–D.
109
117
110
-
### Database (authoring-only for now — not consumed at runtime)
- Play-test start builds the party from `system.starting_party` (default: the lowest actor id) with `system.starting_gold` (default 0). Party membership is fixed during play (no add/remove command yet).
125
+
-**Effective stats = actor base `stats` + Σ equipped `stat_mods`** (class stats are authoring-only; no level growth yet). HP/MP start at computed max.
126
+
- Items and equipment have **separate id spaces and stock pools** (`kind: "item"` vs `"equip"`).
127
+
- All changes are traced (`gold_changed`, `item_changed`, `hp_changed`, `equip_changed`, `item_used`) and visible in the snapshot: `gold`, `inventory`, `equip_inventory`, `party: [{actor_id, name, hp, max_hp, mp, max_mp, stats, equipment}]`.
113
128
114
129
## Scenario format (`games/*_scenario.json`)
115
130
@@ -132,11 +147,33 @@ Follow-up branching after SHOW_CHOICES: the chosen index is written to **variabl
Shop flow: `interact` with the shop event → `advance_dialogue` past any greeting → the shop opens (`expect_shop_open`) → `shop_buy` (index into the SHOP_PROCESSING entries) / `shop_sell` (any stocked item, half price) → `shop_close` resumes the event. A rejected buy (not enough gold) changes nothing and is traced with `ok: false`.
165
+
166
+
### Battle (deterministic — design scenarios around these exact rules)
167
+
168
+
- Party fights with **live HP** (battle damage persists after the battle). Each round waits for one command per living party member in party order — supply them with `battle_attack {"target": enemy_index}`, `battle_item {"item_id", "target_actor_id"?}` (consumes the turn), or `battle_flee` — then resolves synchronously.
169
+
- Turn order: `agi` descending; ties → party before enemies, then lower index. Enemy AI: basic attack on the lowest-index living party member. A dead attack target retargets to the first living one.
170
+
-**Damage** = `max(1, base * rng(90..110) / 100)` where `base = max(1, atk - def / 2)` (integer division). That rng roll is the only randomness (seed 0 unless the scenario sets `rng_seed`), so damage varies ±10% — bound assertions with `expect_enemy_hp {"index", "lte"}` / `expect_actor_hp {"gte"}`, or design HP totals so the outcome is variance-proof (e.g. 20 HP enemy vs 10–13 damage = always exactly 2 hits).
171
+
-`battle_flee` succeeds iff `can_flee` (a failed attempt wastes the turn). Win grants every enemy's `gold_reward` + `item_rewards`.
172
+
- Assertions: `expect_battle_active {value}`, `expect_battle_result {value: "win"|"lose"|"flee"}` (persists after the battle), `expect_enemy_hp {index, value|lte}`. Snapshot carries `battle: {active, round, pending_actor_id, enemies, last_result}`; the trace logs `battle_started/round/action/ended` with per-action damage.
173
+
- Worked examples: `games/battle_demo.rpgc` with `battle_demo_scenario.json` (flee, then a 2-round win) and `battle_lose_scenario.json` (unwinnable → game over).
174
+
175
+
Optional top-level `"rng_seed"` (int): gameplay randomness flows through one seeded RNG (`GameState.rng`, default seed 0), so runs are always reproducible — set `rng_seed` only to explore alternate outcomes. `expect_actor_hp` also accepts `"gte"` instead of `"value"`.
176
+
140
177
An optional top-level `"timeout_frames"` (default 6000) fails the run with a `timeout` assertion if it doesn't finish in time. `expect_dialogue` matches against **all** dialogue seen so far (lines of one box are joined with `\n`).
141
178
142
179
Timing conventions that make scenarios deterministic:
@@ -146,7 +183,7 @@ Timing conventions that make scenarios deterministic:
146
183
- One `advance_dialogue` per SHOW_TEXT box; dialogue must be advanced before the event continues.
147
184
- Facing vectors: right `(1,0)`, left `(-1,0)`, up `(0,-1)`, down `(0,1)`.
148
185
149
-
Results JSON: `{ passed, failed, total, assertions: [{pass, message}], trace: [...], snapshot }`. The `trace` array logs every event start/finish, command, switch/variable/self-switch change, transfer, dialogue line, choice, game over, and player move— read it to debug why an assertion failed. Final `snapshot`: `{ map_id, map_name, player_grid, player_facing, event_facing, event_running, events_erased, switches_on, variables}` (only non-false switches / non-zero variables listed).
186
+
Results JSON: `{ passed, failed, total, assertions: [{pass, message}], trace: [...], snapshot }`. The `trace` array logs every event start/finish, command, switch/variable/self-switch change, transfer, dialogue line, choice, game over, player move, and every gold/item/HP/MP/equipment change — read it to debug why an assertion failed. Final `snapshot`: `{ map_id, map_name, player_grid, player_facing, event_facing, event_running, events_erased, switches_on, variables, gold, inventory, equip_inventory, party }` (only non-false switches / non-zero variables/stock listed).
150
187
151
188
`make test-scenarios` runs every scenario in `games/` inside **one** engine boot (`--test-all games`), so the suite stays fast as games accumulate.
Copy file name to clipboardExpand all lines: CURRENT_STATE.md
+5-2Lines changed: 5 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -37,6 +37,9 @@
37
37
-**Game over** — `GAME_OVER` ends the play-test immediately.
38
38
-**Parallel events** — pages with the Parallel trigger run in their own runner without blocking the player, looping while their conditions hold.
39
39
-**Page re-evaluation** — event pages re-evaluate when switches, variables, or self-switches change; visuals update, parallel runners start/stop, and autorun pages fire when they *become* active (edge-triggered).
40
+
-**Party & resources** — starting party from the `system` block, live HP/MP, gold, item/equipment stock, equipment slots that modify effective stats; commands `CHANGE_GOLD`, `CHANGE_ITEMS`, `CHANGE_HP`, `CHANGE_EQUIPMENT`, `USE_ITEM`; branch conditions `gold_gte` / `has_item`.
41
+
-**Shops** — `SHOP_PROCESSING` opens a buy/sell session (database or override prices, half-price sells) that blocks the event until closed; fully scriptable headlessly.
42
+
-**Battle v1** — `BATTLE_PROCESSING` runs a deterministic turn-based fight (agi order, ±10% seeded damage variance, enemy AI, items and fleeing, win/lose command branches, gold + item rewards). Managed by `BattleManager` with a minimal reactive `BattleUI`.
40
43
41
44
### Infrastructure
42
45
@@ -55,8 +58,8 @@
55
58
## Known gaps / rough edges
56
59
57
60
-**`PLAY_SE` is a stub** — advances immediately with no audio playback (no BGM/SE yet).
58
-
-**Database is authoring-only** — actors/classes/items/weapons/armor are stored but not yet consumed at runtime (party, inventory, shops, and combat come in later phases). No skills/enemies/troops yet.
59
-
-**No party / inventory / combat** — `GameState` still holds only switches/variables; no party, gold, inventory, or battle system yet.
61
+
-**Party is fixed at play-test start** — no CHANGE_PARTY command yet; class stats are authoring-only (no level growth); no skills, no random encounter zones, no troops table (BATTLE_PROCESSING takes inline enemy ids); item effects are HP/MP restore only.
62
+
-**No editor UI yet for the v5 systems** — the party/shop/battle commands and enemies table are authorable via JSON (agents) but not yet in the event editor panel / database panel.
60
63
-**Map transfer UX** — Transfer Player command works at runtime but there is no editor UI for picking the target map by name.
61
64
-**Parallel events + dialogue** — a parallel event showing text while a blocking event also waits on dialogue can cross-talk; parallel pages are best used for switch/variable/wait/move logic.
0 commit comments