Commit Graph

132 Commits

Author SHA1 Message Date
863d58f6ec feat(io): bundle Cascadia Mono Nerd Font as the GUI font
Install the downloaded Cascadia Mono Nerd Font as src/main/resources/fonts/
game.ttf — the exact name SwingIO.loadFont() looks up on the classpath
(/fonts/game.ttf), so the GUI now uses a real monospaced Nerd Font (icon
glyphs included) instead of falling back to the logical monospaced font.
Include the font's SIL Open Font License as required for redistribution.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 09:27:25 +02:00
08d2dce10a feat(io): bundle background music as classpath resources
Switch OggMusicBackend from streaming an external, git-ignored music/ folder
(relative to the run directory) to streaming bundled classpath resources under
/music/, so the four manor tracks ship inside the JAR and play out of the box —
consistent with how fonts are bundled. The play loop reopens the resource each
iteration via a BufferedInputStream (the vorbisspi SPI needs mark/reset to read
the OGG header). Missing tracks still fall back to silence.

Add the four converted OGG Vorbis tracks (manor-theme/cellar-drone/musicbox/
lament) under src/main/resources/music/, un-ignore that path, and re-anchor the
gitignore so only the top-level MP3 source folder stays ignored. Update
docs/music.md for the bundled approach and conversion recipes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 09:21:11 +02:00
1ae464dfe4 feat(world): Haunted Manor content expansion (14 rooms, one world)
Replace the 5-room demo with a condensed 14-room manor on one spine
(restore power -> escape) that stacks all five mechanics, plus an optional
spirit thread feeding 3 prioritized endings (no hard-fail). Pure YAML on the
existing engines: 14 rooms across 3 levels, ~16 items, 5 combinations, the
old_man hint NPC, restore_power + lay_to_rest quests, and 3 endings.

Consolidate to one world: remove the toy "Test Manor" test fixture so the
loader tests exercise the real shipped world. Adapt WorldLoaderTest and
TutorialLoaderTest to form-invariants of the real world, and add
WorldSolvableTest, which walks the critical path (light/lock gating +
Combinations.tryUse + flags) to guarantee power_on, ghost_banished, and a
victory ending are reachable — an unsolvable world now fails the build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 09:06:28 +02:00
90311a7671 docs: spec for Haunted Manor content expansion (14 rooms)
Condensed 14-room manor on one spine (restore power -> escape) stacking all five
mechanics, plus an optional spirit thread feeding 3 priority endings (no
hard-fail). Pure YAML content on existing engines. Consolidates to one world
(removes the toy test fixture) + a WorldSolvableTest that walks the critical path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 08:48:52 +02:00
b5d603a7b1 docs: clarify music transition is a sequential fade, not cross-fade 2026-06-01 23:29:11 +02:00
08c92a57de docs: mark GUI background music implemented 2026-06-01 23:25:11 +02:00
2891553629 feat(io): OggMusicBackend + SwingIO wiring; music/ folder + docs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 23:20:14 +02:00
bcd2ae9ddd refactor(settings): guard all Settings fields vs null; tidy import + test
Guard colorMode and glyphMode against null in the Settings compact
constructor (alongside the existing musicLevel guard), so a hand-edited
settings.json with a missing field no longer NPEs in SettingsMenu.
Remove the unused MusicLevel import from SettingsMenu. Assert that the
defaulted musicLevel survives a round-trip in SettingsStoreTest.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 23:17:26 +02:00
2bad875df1 feat(settings): persisted Music level; SettingsMenu applies via GameIO
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 23:08:27 +02:00
d0d8648bd0 feat(io): GameIO music seams; push room track per turn, silence at menu
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 23:02:44 +02:00
35ad4e6f1a feat(loader): per-room music field + demo rooms.yaml entries
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 22:58:13 +02:00
a38bb6e4f3 fix(io): idempotent MusicController.level; assert gain forwarding + shutdown
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 22:55:27 +02:00
7f64c9f9e3 feat(io): MusicController + MusicBackend (testable music logic)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 22:50:58 +02:00
a1fd56b389 test(io): assert MEDIUM.isOn() too 2026-06-01 22:49:20 +02:00
d0e290c723 feat(io): MusicLevel enum (Off/Low/Med/High)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 22:47:40 +02:00
36f60863ad docs: implementation plan for GUI background music
7 TDD tasks: MusicLevel, MusicController+MusicBackend, Room music field,
GameIO seams + loop/app wiring, Settings music level + SettingsMenu->GameIO
refactor, OggMusicBackend + deps + SwingIO wiring + docs, backlog note.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 22:46:15 +02:00
a0e21a9baa docs: spec for GUI background music
OGG Vorbis (vorbisspi+jorbis) per-room music via rooms.yaml, external gitignored
music/ folder. Testable MusicController (idempotent track switch, null->silence,
OFF disables) over an isolated OggMusicBackend; GameIO.setMusic/setMusicLevel
no-op on console, played by SwingIO. Settings gains a Music level Off/Low/Med/High
(default Medium). Console stays silent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 22:21:10 +02:00
20d076832d fix(game): suppress endings while the tutorial is active
A command during the walkthrough (e.g. use front_door -> fled) no longer ends
the game mid-tutorial; a pending ending fires once the tutorial finishes or is
skipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 22:09:06 +02:00
1e980a80e2 docs: note interactive start-of-game tutorial 2026-06-01 21:59:44 +02:00
19ea7667b0 refactor: consistent isActive() guard on tutorial onCommand; tidy App imports 2026-06-01 21:59:07 +02:00
2ed6a71cea feat: wire TutorialGuide into the game loop; show on New Game only
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 21:53:27 +02:00
28871b4ddc fix(game): null-safe moved() + idempotent begin(); cover multi-step + go_to_room hint
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 21:49:47 +02:00
546a7672bf feat(game): TutorialGuide interactive walkthrough engine
Alias-aware, stateful engine with verb/minArgs matching, go_direction/go_to_room
room-change detection, skip, and closing-tips on completion. 7 tests, all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 21:42:30 +02:00
f47a3e7ca5 test(tutorial): cover malformed tutorial.yaml -> WorldLoadException 2026-06-01 21:40:06 +02:00
95098fbb09 feat(tutorial): Tutorial model + TutorialLoader + tutorial.yaml content
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 21:25:48 +02:00
5c9a8cb568 docs: implementation plan for interactive start tutorial
4 TDD tasks: Tutorial model+loader+tutorial.yaml, TutorialGuide engine,
Game+App wiring (New Game only), docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 21:23:06 +02:00
055a256b03 docs: spec for interactive start-of-game tutorial
Interactive walkthrough layered on the real game loop via a TutorialGuide
(optional in Game): core arc look->examine->take->inventory->use->go->go to,
verb-based alias-aware completion (movement steps require an actual room
change), closing tips, skippable via 'skip'. Data-driven tutorial.yaml +
separate TutorialLoader (not in World). Shown only on New Game.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 21:10:13 +02:00
930915da59 docs: sync spec unknown-target message with implemented wording 2026-06-01 20:27:19 +02:00
6d1b36f853 docs: mark go to <room> pathfinding implemented 2026-06-01 20:24:26 +02:00
c01c47a585 fix(command): combined unknown-target message; cover both go-to summary forms
- UX: unknown-target message now reads "don't know any direction or place
  called '...'" so direction typos (e.g. 'go nroth') make sense
- clarity: resolveVisited uses equalsIgnoreCase for id/name matching;
  add null-world guard comment pointing to CommandTestSupport
- Javadoc: note that 'to' filler word is stripped, making go-to forms equivalent
- tests: assert 'through the Hallway' in 3-node route; update unknown message
  assertion; add adjacentWalkUsesShortSummary covering the n==2 short-form path

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 20:23:41 +02:00
a30c153de1 feat(command): go to <room> auto-walk (BFS path, animated map, summary)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 20:13:25 +02:00
663a78ed9e feat(game): Pathfinder BFS over visited rooms (locks + light aware)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 20:08:11 +02:00
7c1cdc545e feat(io): travelStep hook for animated auto-walk (console no-op, Swing override)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 20:04:17 +02:00
7b60230f1e docs: implementation plan for go to <room> pathfinding
4 TDD tasks: GameIO.travelStep hook (+SwingIO animation), Pathfinder BFS over
visited rooms (locks+light), GoCommand routing/resolve/walk/summary, docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 20:02:11 +02:00
d10632b800 docs: spec for go to <room> pathfinding
BFS over visited rooms (respecting locks + light), routed via GoCommand
(go to <room> vs go <direction>); silent console traversal + summary naming
start/middle/destination; GUI minimap animates per step via a new
GameIO.travelStep hook (SwingIO override, ~300ms). Trie autocomplete deferred.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 19:03:26 +02:00
966762fff9 docs: mark use X on Y item combination implemented 2026-06-01 17:45:16 +02:00
1bdae4f295 test(loader): assert exact item set incl. demo items (restore completeness check) 2026-06-01 17:44:32 +02:00
8d88157573 feat(loader): load combinations.yaml; demo matches+torch -> lit_torch
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 17:38:17 +02:00
63af4c7641 docs(command): update UseCommand javadoc for the combination form 2026-06-01 17:32:58 +02:00
a89684807b feat(command): route use X on Y to the combination engine
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 17:31:07 +02:00
e7b9891771 fix(combinations): guard null response; reject self-combination at load
- Combinations.tryUse: only write response when non-null and non-blank,
  preventing NPE/IllegalArgument for effects-only recipes.
- CombinationFactory.fromDto: throw WorldLoadException when a == b,
  since item singletons make a self-combination impossible at runtime.
- Tests: +effectsOnlyRecipeAppliesEffectsWithoutProduceOrResponse
  (CombinationsTest 7→8), +rejectsSelfCombination
  (CombinationFactoryTest 4→5).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 17:28:32 +02:00
89962b4b60 feat(game): Combinations engine for use X on Y
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 17:22:16 +02:00
667991df26 test(loader): cover unknown consume id rejection 2026-06-01 17:19:41 +02:00
3d183ad162 feat(loader): CombinationDto + CombinationFactory with id validation 2026-06-01 17:17:25 +02:00
9f9b0c0808 feat(model): World.combinations field + backward-compatible constructors 2026-06-01 17:13:05 +02:00
bbc4fc37f8 style(test): drop unused import in CombinationTest 2026-06-01 17:11:37 +02:00
b7094bf152 feat(model): Combination recipe record + order-independent key 2026-06-01 17:08:14 +02:00
2e48ec7221 docs: implementation plan for use X on Y combinations
7 TDD tasks: Combination model+key, World.combinations, CombinationDto+Factory
(id validation), Combinations engine, UseCommand routing, loader wiring + demo
(matches+torch -> lit_torch), docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 17:06:35 +02:00
34cbb7f158 docs: spec for use X on Y item combinations
Data-driven combination recipes (requires/consume/produce/effects/response/
failText), operands from inventory or current room, order-independent lookup,
generic-or-failText feedback. No parser change (on/with already fillers).
Minimal matches+torch -> lit_torch demo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 16:58:39 +02:00
6887102d19 feat(io): themed full-window menu overlay in the GUI
Replace the plain Swing JDialog menu with a glass-pane overlay that fills
the whole window: dark background matching the game palette, bundled font,
lavender heading, flat hover-highlighted buttons, Escape = last option. The
overlay hides the game chrome (HUD/map/quest panels) while in the menu and
rebuilds at the current frameScale*zoom on window resize, so it scales
correctly from startup.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 16:21:46 +02:00