Commit Graph

21 Commits

Author SHA1 Message Date
type-two
2bf19d983e Fix ego sprite and text wrap on the web build
ego_view() decided whether a game overrode the default party robot by
stat'ing sprites/ego.png on disk. A wasm build has no disk — the game is
baked into the binary with include_dir — so the check always failed and
every web player was a party robot regardless of what the game shipped.
Read the already-loaded sprite table instead, which both loaders populate
by file stem, so native and web now agree and native does one less read.

The transcript was drawn one draw_text per line with no wrapping, so any
line wider than the window ran off the right edge and was simply lost.
Room descriptions here are whole paragraphs, so this ate the end of most
of them. Greedy word-wrap on measured width, and the visible row count is
derived from the panel geometry rather than hardcoded at 5. Panel grows
150 -> 186 so a wrapped paragraph fits without pushing its own opening
line off the top.

Also: Game > Manual opened monsterrobot.games/engine/manual.html, which
has not served the manual since that domain moved hosts — it silently
returns the arcade index (200, so nothing looked wrong). Point native at
the repo's own web/manual.html, which always matches the build.

Verified: all 16 policesquadquest win paths still replay to max score,
and both fixes confirmed rendering in the native --shot and on the live
deploy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 21:30:14 +10:00
type-two
827797ad1f Web: bake any game into the wasm; never block first paint on audio
The title screen / world picker now works in the browser, not just natively.
`./web/build.sh <folder-of-game-folders>` stages every game inside it plus
collection.json and bakes the lot into one wasm; the engine boots into the
shelf exactly as it does on the desktop. Sixteen cases of Police Squad Quest
come to 2.1 MB total.

- embedded_world() becomes embedded_world_at(prefix), so one bundle can hold
  many games; embedded_games() / embedded_collection_name() are the browser
  twins of world::scan_collection / collection_name.
- The picker is now keyed by String on both platforms and resolved through one
  load_by_key() — a filesystem path natively, an embedded subdirectory in the
  browser — so Mode::Title has a single implementation.
- Esc is a no-op on the web when there is nowhere to back out to. Breaking the
  main loop in a browser just leaves a dead black canvas; found by pressing it.
- ascii_fold() on every game-text draw. macroquad's built-in font has no em
  dash, curly quote, star or dagger, so room names like "— Squad Room —" and
  every death card were drawing tofu boxes in both builds. Folding at the draw
  layer fixes the whole engine without making game authors type worse prose.
- web/build.sh uses the rustup toolchain explicitly: cargo/rustc on PATH may be
  Homebrew's, which ships no wasm32 std even though `rustup target list` shows
  the target installed, and the resulting "can't find crate for core" is a
  thoroughly misleading error.

Verified in a real browser: shelf renders, arrows move the selection and swap
the live room preview, Enter loads and plays the case, Esc returns to the shelf
with the selection preserved. Native --shot and all 13 core tests still pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 18:39:48 +10:00
type-two
fa7fa107d0 Title screen / world picker for game collections
Point --game at a directory that is not itself a game but contains game
folders, and the GUI boots into a title screen: the collection's name in
gold (optional collection.json {"name": ...}, else the folder name), a
shelf of games sorted by folder with display names from each game.json,
a dimmed live preview of the selected game's start room baked by the
headless renderer, arrow-key selection, Enter to play, and Esc from
inside a game returning to the shelf instead of the desktop.

Shelf names strip a shared "Series — " prefix when every game has one —
the collection title already names the series, and it also sidesteps the
em-dash glyph missing from macroquad's default font.

Core grows world::is_game_dir / scan_collection / collection_name with a
unit test; the GUI grows Mode::Title. --shot pointed at a collection
captures the title screen (that is how the screenshots in this commit's
review were taken). Sample/kit scaffolding is skipped for collection
dirs so a shelf never gets a stray sprites/ folder written into it.

Closes the "title screen / world picker" roadmap item in MANUAL §20.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 21:50:13 +10:00
type-two
b6c9c5eb23 Untrack mrpgi-vault build artifacts (254 compiled files; also carried stray game-name strings)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 10:44:35 +10:00
type-two
2de9d10146 CLAUDE.md: this repo is the engine; games (morpquest, policesquadquest) are separate repos
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 10:39:13 +10:00
type-two
f9c3fbd5ce Add CLAUDE.md project context (with the correct Gitea remote)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 10:30:38 +10:00
type-two
a30d8a25d3 GUI: enable macroquad audio feature (cues and music were silently disabled)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 10:30:38 +10:00
type-two
0b8fe85ccd Let a game supply its own ego sprite and death text
Two general-purpose additions, both needed by an external game folder and
useful to any other:

- World::ego_view() — a game folder with sprites/ego.png uses it as the
  player avatar instead of the hardcoded party robot (optional ego1.png
  gives the walk bob a second cel). Refreshed on LoadGame and ReloadSprites.
- GameManifest.death_text — the death banner was hardcoded to morp2's
  "Morp is not cruel; Morp is accurate", which leaked that game's flavour
  into every other one. Now a manifest field; the default keeps the old
  wording minus the morp2 reference, so existing games are unaffected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 22:11:16 +10:00
type-two
23865f1483 Web: bake any game into the wasm; never block first paint on audio
- MRPGI_WEB_GAME env (default games/lost-fuse via .cargo/config.toml)
  selects the game include_dir! embeds; web/build.sh <game-dir> stages
  just game.json+rooms+sprites (a repo's raw art was ballooning the wasm
  to 41MB; now 1.9MB) and ships the game's web/index.html and music/.
- sound.rs: file overrides load through macroquad's loader (fs on native,
  HTTP fetch on web), and AudioOut now loads inside a coroutine behind
  LazyAudio — browsers gate audio decoding behind a user gesture, and
  blocking boot on it was a black screen. First frame draws immediately;
  music starts when ready, remembering the requested mood/mute.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 15:53:22 +10:00
type-two
755168a969 Sierra soul for game authors: scoring, deaths, gated exits, room prose, visibility flags
New authoring surface (all serde-defaulted; old games load unchanged):
- RoomDoc: name + enter_text (announced on entry), exit_flags/exit_blocked
  (per-direction flag gates with authored refusal lines, latched per attempt)
- ObjDef: points (once per room+name), consumes, kills, visible_flag,
  hidden_by_flag; DlgChoice: points (latched on sets_flag flip), kills
  (goto node's says = death text)
- GameManifest: max_score enables scoring; GUI shows the classic
  'Score: X of Y' in the menu bar; score_changed + died on the bus
- Death restarts the day, keeping the cause at the top of the fresh transcript

Reviewed by an adversarial multi-agent pass; confirmed findings fixed:
corner push-back no longer slingshots through a perpendicular open exit
(and checks the landing pixel), blocked messages latch per attempt,
kill choices pay no points/flags, new_game re-zeroes the score on the bus,
AI-lane prompts respect object visibility. Deliberate behavior change:
drop/consumes now emit inventory_changed (was a silent client desync).

Built for MORPQUEST (games/… ssh://…/monster/mrpquest.git), which uses all
of it: 250-point budget, four gated exits, two deaths, vanishing Beckies.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 15:30:32 +10:00
type-two
eb4a21491e vault backup: document the daily launchd schedule + macOS TCC gotcha
Scheduled daily at 4am on the ultra. launchd can't exec scripts inside
~/Documents (TCC), so the job runs a copy under Application Support;
header documents the sync/manage/remove commands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 12:32:10 +10:00
type-two
24f812dbfd vault: offline backup script (pull accounts + worlds to local snapshots)
The vault's user data (argon2 hashes + saved worlds) only lives on the
VPS and isn't in git. backup.sh pulls /opt/mrpgi-vault/data down as a
timestamped tarball, keeps the 30 newest, and documents the restore
path in its header.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 12:22:44 +10:00
type-two
e9cf00e686 THE MRPGI BOOK: deep combined user/dev manual, linked from the live menus
- web/manual.html — 17 chapters: playing, the editor deeply, the
  authoring cookbook (full JSON reference + the five load-bearing
  puzzle patterns), dialogue trees, flags, the art pipeline with
  sprite-generation prompts, sound, driving the engine with code
  (real JSONL transcripts), AIs + MCP, prompt patterns with actual
  outputs (the roof room is the real shipped expansion), the web
  build & cloud saves, engine internals, extension recipes,
  troubleshooting, and full command/event/palette reference.
- Game menu gains "Manual": window.open on the web (via a JS plugin
  import), the default browser natively.
- README tab links the Book; repo README points at it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 11:49:24 +10:00
type-two
cd7f658444 Accounts + cloud saves: the front door for the web engine
- mrpgi-vault (standalone crate): tiny signup/login/world-save service.
  Argon2 password hashes, random session cookies, JSON-file storage,
  naive per-IP rate limit, 4MB body cap. tiny_http, no framework, no db.
  Runs as a container on the dealgod network; nginx proxies
  /engine/api/ to it.
- core: WorldBundle — a whole world (manifest + every room) as one JSON
  document, with World::to_bundle/apply_bundle.
- web bridge: mrpgi_request_save / mrpgi_alloc / mrpgi_world_in exports
  + an mrpgi_world_saved JS plugin import; the page's SAVE button pulls
  the live world out of the running engine, LOAD swaps it back in.
  SAVE_REQUESTED is an AtomicBool on purpose — wasm's thread-less
  Mutex<bool> is a plain static to LLVM and release builds const-folded
  the read (the only writer is JS-visible, not IR-visible).
- web UI: SIGN IN tab → create account (own username + password) /
  sign in / Save world / Load world / sign out. Session restores on
  revisit.

Verified live end-to-end through Cloudflare: signup → save → reload →
anonymous rejected; throwaway account removed after.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 11:38:27 +10:00
type-two
584424c939 Sierra menu bar + web README tab (thanks Matt)
- The classic dropdown menus across the top of the play screen: Game
  (New Game / Edit Mode / CRT / Sound / About) and Action (Look Around /
  Inventory / Help). Pure bus consumers — menu items inject the same
  Commands every other surface uses. Sliding along the bar switches
  menus, clicks outside close, clicks never leak into click-to-walk.
- web: README tab pinned top-right with the short guide — controls,
  editor shortcuts (undo is just Z, no Ctrl), the two-layer paint model,
  and why the lake is scenery for now.
- --shot out.png: render a few Play frames and save the real backbuffer
  to PNG — ground-truth GPU screenshots for debugging and CI. (Used to
  prove the menu colors were right when a preview browser's auto-dark
  filter was inverting light neutrals on canvas.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 11:14:48 +10:00
type-two
fb7524e847 web: document the live deploy path + nginx bind-mount gotcha
Live at https://monsterrobot.games/engine/ (dealgod VPS, dealgod-nginx
/engine alias over /opt/dealgod/images/engine/).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 10:31:55 +10:00
type-two
11d25f5c52 Browser build: the engine compiles to WASM and runs at a URL
- mrpgi-core: ureq/tiny_http/threads are native-only deps; the AI lane
  compiles to an always-off stub on wasm32 (deterministic parser stays).
- World::from_memory + assets::cel_from_bytes — boot a game with no
  filesystem.
- mrpgi GUI on wasm: embeds games/lost-fuse via include_dir, boots
  straight into Play (Tab still opens the editor; saving needs a disk,
  so web is play + paint-only for now).
- web/: index.html shell + macroquad JS loader + build.sh producing a
  self-contained static web/dist (1.1 MB total, game included).
- .cargo/config.toml: --allow-undefined for miniquad's JS imports.

Verified in-browser: renders, typed commands reach the parser,
click-to-walk works, zero console errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 09:35:45 +10:00
type-two
2fdd730cde Add the updated manual and a teaching game: The DJ's Lost Fuse
- MANUAL.md brought up to the workspace era: game folders + manifest,
  flags & gated puzzles, hidden dialogue choices, audio file
  overrides, a Programmatic control section (CLI/HTTP/MCP/Python),
  and the new two-crate architecture map.
- games/lost-fuse: three rooms that demonstrate every mechanic in one
  chain — item, needs-lock, object sets_flag, a dialogue choice hidden
  behind requires_flag, dialogue sets_flag, and a flag-locked wins
  finale. Verified winnable headlessly, gate included.
- games/lost-fuse/expansion/roof.jsonl: a live lore drop that upserts
  a fourth room into a running game and rewires an exit — the "drop
  JSON lore in" workflow, runnable as a one-liner.
- games/README.md: the guided tour — mechanic-to-JSON map, the live
  expansion demo, and how to prompt an LLM (or point Claude's MCP at
  the engine) to write valid lore.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 09:18:50 +10:00
type-two
96b45561d0 Carve the engine into a headless core behind a command/event bus
The handover plan (docs/HANDOVER.md), P0-P6, in one pass. One insight
powers it: CLI/HTTP/MCP/Python is one feature, not four — a headless
core driven by Commands in, Events out, with every surface a thin
adapter.

- mrpgi-core: the whole sim as a library with zero macroquad (the
  workspace boundary is the guardrail). GameState::apply/tick, fixed
  1/20s cycles, deterministic replays, headless RGBA/PNG rendering.
- mrpgi-headless: JSONL stdio REPL, --script replay (AI lane off =
  byte-identical), --render-room PNG, --serve HTTP (state/command/
  events cursor/frame.png), --mcp JSON-RPC stdio server whose
  render_frame returns a real PNG so a model sees its own moves.
- Games are folders: game.json manifest (all fields default — legacy
  dirs still load), data-driven verb table feeding both the parser and
  the AI whitelist, flags with requires_flag/sets_flag gating on
  objects and dialogue choices, live UpsertRoom lore ingestion with
  validation.
- mrpgi (GUI): now one consumer of the bus; editor commits through the
  same commands MCP uses; audio became core events with per-game
  sfx/ music/ file overrides beating the chiptune synth.
- Tests: parser goldens + a full win-path playthrough asserting
  byte-identical transcripts across runs.

Deleted: the old fused src/ (root is now a virtual workspace), the
dead demo Scene/Assets path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 09:18:33 +10:00
m3ultra
d0728e121c docs: add architecture handover — headless core + command bus plan
Captures the 2026-07-05 design session: making MRPGI fully
programmatically controllable (MCP + CLI/stdio + HTTP/WebSocket) via a
headless mrpgi-core engine behind a typed command/event bus, with the
macroquad GUI as one optional front-end.

Includes: current-state analysis, the core refactor (GameState with
apply/tick), games-as-folders + JSON lore ingestion, an "always want
options" audio design (SynthSink / FileSink mp3-ogg-wav / StrudelSink,
all toggleable), a P0-P6 roadmap, quick wins, risks, and a source map.

Adds docs/architecture.svg (self-contained) plus an inline Mermaid
diagram in the handover.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 02:16:40 +10:00
type-two
d0caf983a0 Initial commit: MRPGI — Apple-Silicon AGI adventure engine
A new-school reimagining of Sierra's 1980s AGI interpreter in Rust + macroquad:

- Dual-buffer (visual + priority) room model with hand-painted walkability
- In-engine room editor: brush/line/rect/fill/pick/erase/oval/image/spawn/object tools
- Sprite pipeline (PNG -> EGA quantize), multi-room worlds with edge exits
- Objects with look/use/needs/keys/win conditions (no code)
- Forgiving text parser + optional local-LLM lane (Ollama / OpenRouter)
- Branching NPC dialogue trees, chiptune SFX, per-room ambient music
- Content kit: 61 archetypes across fantasy/scifi/monsters/saucy/horror
- Full docs: README, EDITOR_GUIDE, MANUAL, art manifesto + Gemini prompts

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 17:26:55 +10:00