Live: https://monsterrobot.games/games/policesquadquest/ web/index.html is our arcade page shell, matching the house style set by morpquest (boot splash, gold README tab, controls and the shelf explained). tools/webbuild.sh copies it over the engine's default after baking, so the cases/ shelf directory stays nothing but games. Hosting, established by reading the boxes rather than the docs: the deploy-map note pointing at /opt/dealgod/images/engine/ on the dealgod VPS is stale for this domain — that path now falls through to the arcade index. monsterrobot.games is actually served by forum-nginx on the GAMES VPS (humanjing@100.71.119.27) from a bind mount of /home/humanjing/monsterrobot.games, and games are plain directories under games/ picked up by try_files with no nginx change at all. Deployed exactly like /games/morpquest/, which is the same engine. Verified live: all four assets 200 with correct application/wasm content-type, our title (not the arcade fallback), the shelf renders, a case loads and plays, and the parser round-trips over the wire. Nothing existing was touched — fresh directory, no config edited, no cache purge needed for a new path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
151 lines
7.7 KiB
Markdown
151 lines
7.7 KiB
Markdown
# Police Squad Quest
|
|
|
|
A Sierra-style adventure game set in the *Police Squad!* / *Naked Gun* universe,
|
|
built on the [MRPGI](https://github.com/) engine (`~/Documents/MRPGI`) — which is
|
|
itself a reimplementation of AGI, the engine Sierra shipped *Police Quest* on.
|
|
|
|
> The game grades you on correct police procedure with a completely straight
|
|
> face. The reward for perfect procedure is catastrophe anyway.
|
|
|
|
- **[RESEARCH.md](RESEARCH.md)** — the source material: all six *Police Squad!*
|
|
episodes, all four films, the recurring cast, and the ZAZ comedy grammar.
|
|
- **[DESIGN.md](DESIGN.md)** — the game bible: the joke engine, the two Drebins,
|
|
the eleven-case campaign, and how it all maps onto MRPGI data.
|
|
|
|
**Sixteen cases, all playable, all verified end-to-end at 100/100** (Case One is
|
|
95 + 5 optional). `python3 tools/lint.py` checks all thirteen clean.
|
|
|
|
## Play
|
|
|
|
```bash
|
|
./play.sh
|
|
```
|
|
|
|
That opens the engine's **title screen** — the whole campaign on one shelf,
|
|
arrow keys to choose, Enter to play, Esc backs out of a case to the shelf.
|
|
`./play.sh 07` still jumps straight to one case. The shelf's big title comes
|
|
from [cases/collection.json](cases/collection.json).
|
|
|
|
Or directly:
|
|
|
|
```bash
|
|
cargo run -p mrpgi --manifest-path ~/Documents/MRPGI/Cargo.toml -- --game cases/case-01-substantial-gift
|
|
```
|
|
|
|
`Tab` switches between play and the room editor. Type `help` in play.
|
|
|
|
## What's here
|
|
|
|
| | |
|
|
|---|---|
|
|
| `cases/case-00-1958/` | **Act Zero — playable, 100 points.** Frank Drebin **Sr**, 1958, hard noir mono. Five rooms. Played completely straight; the score is the cover-up. |
|
|
| `cases/case-00b-the-quartet/` | **Act Zero crossover — playable, 100 points.** Drebin **Sr** vs. five Ealing-comedy incompetents. Five rooms. |
|
|
| `cases/case-00c-the-liaison/` | **Act Zero crossover — playable, 100 points.** 1965: the spy-spoof era arrives hunting a pattern that is Drebin **Sr**. Five rooms. |
|
|
| `cases/case-01-substantial-gift/` | **Case One — playable, 100 points.** Drebin (Nielsen), 1982, monochrome. Five rooms. |
|
|
| `cases/case-03-big-gulch/` | **Case Three — playable, 100 points.** Four rooms, the locksmith front. |
|
|
| `cases/case-04-revenge-remorse/` | **Case Four — playable, 100 points.** Four rooms, the wrong manual. |
|
|
| `cases/case-05-butler-did-it/` | **Case Five — playable, 100 points.** Four rooms, chain of custody on a cake. |
|
|
| `cases/case-06-testimony-of-evil/` | **Case Six — playable, 100 points.** Drebin (Nielsen), 1982, monochrome. Five rooms, the whiskey exploit, four deaths. |
|
|
| `cases/case-07-from-the-files/` | **Case Seven — playable, 100 points.** Drebin (Nielsen), 1988, full colour. Six rooms, the Anaheim Stadium finale. |
|
|
| `cases/case-02-ring-of-fear/` | **Case Two — playable, 100 points.** Drebin (Nielsen), 1982, monochrome. Five rooms, undercover, three deaths. |
|
|
| `cases/case-08b-the-heron/` | **Case 8½ — playable, 100 points.** Interpol team-up: Drebin and a Sûreté legend chase a gentleman jewel thief to London. Five rooms. |
|
|
| `cases/case-09-final-insult/` | **Case Nine — playable, 100 points.** Four rooms, prison undercover and the envelope. |
|
|
| `cases/case-10-plot-device/` | **Case Ten — playable, 100 points.** Drebin Jr (Neeson), 2025, cold palette. Six rooms, the arena finale and the owl. |
|
|
| `cases/case-08-smell-of-fear/` | **Case Eight — playable, 100 points.** Drebin (Nielsen), 1991, full colour. Five rooms, the memory test. |
|
|
| `cases/case-11-what-he-wrote/` | **Case Eleven — playable, 100 points.** Drebin **Jr** reads his grandfather's files. Five rooms; the palette drifts from 2025 back to 1958. |
|
|
| `cases/case-12-the-late-movie/` | **Case Twelve — playable, 100 points.** The finale: all three Drebins pulled into a demonic cable multiverse. Seven channels. |
|
|
| `tools/sprites.py` | Generates every sprite on the MODELBEAST farm (free, local). |
|
|
| `tools/lint.py` | Checks every case for the authoring traps that have bitten us. Run it before playtesting. |
|
|
| `tools/verify.sh` | Replays every case's win path headlessly and checks it reaches max_score. Scripts in `tests/scripts/`. |
|
|
| `RESEARCH.md` / `DESIGN.md` | Source research and the campaign bible. |
|
|
|
|
## Case One — A Substantial Gift
|
|
|
|
*Police Squad!* episode 1. A credit union manager is dead, the wrong man is in a
|
|
cell, and the teller has new braces.
|
|
|
|
Sign out your badge and sidearm (the door will not let you leave without them),
|
|
get briefed, tip Johnny, dust the counter, match the print, find the bill, and
|
|
Mirandize the suspect **in the correct order**. Get the order wrong and the
|
|
statement is suppressed, which is a Sierra death card, which is the joke.
|
|
|
|
## Case Seven — From the Files
|
|
|
|
*The Naked Gun* (1988). Nordberg is shot on Ludwig's freighter, you tackle a head
|
|
of state at a state reception, and you get fired — which is the only way forward,
|
|
because a private citizen can't walk onto a baseball field but **an umpire can
|
|
walk anywhere**.
|
|
|
|
The climax: you are the home plate umpire at Anaheim Stadium with no power to
|
|
search anyone, so every frisk needs an umpire-legitimate pretext — brush the
|
|
plate, inspect the mitt, check the bat for pine tar — until you reach Number 44.
|
|
Announce yourself as police instead and sixty thousand people come over the
|
|
railings.
|
|
|
|
## Case Ten — The P.L.O.T. Device
|
|
|
|
*The Naked Gun* (2025). Liam Neeson's Frank Drebin Jr. — played **sincere** where
|
|
his father was oblivious. He means everything he says, all the time, and that is
|
|
both the joke and, eventually, the thing that saves the city.
|
|
|
|
Bank cold open (you are the distraction and don't know it) → a suicide that
|
|
isn't → Richard Cane → a New Year's ball drop, a pair of lost trousers, and a
|
|
barn owl in a 1950s hat who is lit by a different decade than everything around
|
|
him.
|
|
|
|
## Play it online
|
|
|
|
**[monsterrobot.games/games/policesquadquest/](https://monsterrobot.games/games/policesquadquest/)**
|
|
|
|
## Web build
|
|
|
|
The whole campaign bakes into a single self-contained wasm — title screen,
|
|
all sixteen cases, ~2.1 MB:
|
|
|
|
```bash
|
|
./tools/webbuild.sh
|
|
```
|
|
|
|
Output lands in `MRPGI/web/dist/` (wasm + our page shell from
|
|
[web/index.html](web/index.html) + the macroquad JS shim). The shelf's title
|
|
comes from [cases/collection.json](cases/collection.json).
|
|
|
|
Deploy — monsterrobot.games is served by **forum-nginx on the games VPS**
|
|
(`humanjing@100.71.119.27`) from a bind mount of
|
|
`/home/humanjing/monsterrobot.games`. Games are plain directories under
|
|
`games/`; the server block's `try_files $uri $uri/ /index.html` picks them up
|
|
with no nginx change. Same pattern as `/games/morpquest/`:
|
|
|
|
```bash
|
|
./tools/webbuild.sh
|
|
rsync -az --delete ~/Documents/MRPGI/web/dist/ \
|
|
humanjing@100.71.119.27:/home/humanjing/monsterrobot.games/games/policesquadquest/
|
|
```
|
|
|
|
Then curl the live URL cache-busted to confirm. Note the deploy-map's older
|
|
note about `/opt/dealgod/images/engine/` on the dealgod VPS is stale for this
|
|
domain — that path no longer serves monsterrobot.games.
|
|
|
|
## Regenerating art
|
|
|
|
Sprites are generated locally on MODELBEAST (`flux_local` → `bg_remove_local` →
|
|
downscale). Prompts live in each case's `sprites.json`.
|
|
|
|
```bash
|
|
python3 tools/sprites.py cases/case-01-substantial-gift # fill gaps
|
|
python3 tools/sprites.py cases/case-01-substantial-gift --force # redo all
|
|
MB_POOL=1 python3 tools/sprites.py cases/... # if the farm 401s
|
|
```
|
|
|
|
Seeds derive from the sprite name, so reruns reproduce the same art.
|
|
|
|
## Engine changes
|
|
|
|
Two small, general-purpose additions were made upstream in MRPGI for this
|
|
project — both benefit any game:
|
|
|
|
- `sprites/ego.png` in a game folder replaces the default party robot as the
|
|
player avatar (`ego1.png` optional second walk cel).
|
|
- `death_text` in `game.json` overrides the death banner, which was previously
|
|
hardcoded to another game's flavour text.
|