Act I, monochrome. Five rooms, 100 points, verified at 100/100 with four verified deaths. Built out of John's Police Quest material. PQ1's famous 8-bit integer underflow is not an easter egg here, it is the central puzzle: Frank signs for a $40 operational float clipped to a note reading DO NOT EXCEED YOUR FLOAT, the back room costs $2,500, and exceeding the float by one dollar wraps the department ledger's eight-bit field to 255 — the terminal appends the cents column and authorises $2,550.00. He keeps drinking to 132 because it will not do to stop suddenly. Accounts raise it in March; it goes to a hearing. PQ1's Gremlin runs through the whole case and is never resolved: chickens on the Captain's desk, on Al's shoulder, on the murdered guest star, and one in the winning freeze-frame. Nobody has said the word "chicken" out loud in eleven years. No file was ever opened. Then the stage: six memorised jokes, in order, and every "improvise" option is fatal — plus a full glass on a stool three feet from the microphone, which is how Danny Cavanaugh died and which you must not touch. Linter gained the rule that actually caused this session's bug: MRPGI's obj_matches is a BIDIRECTIONAL substring test over name AND synonyms, and match_obj takes the first hit in array order, so an earlier object can make a later one unreachable by its own name. `talk barman` was addressing `clubbar`. It found two more: `sideboard` swallowing `cardtable`, and `bouncer` swallowing `bunkerdoor` — the last of which shipped broken in Case Ten. All six cases lint clean and all six still win. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
101 lines
4.6 KiB
Markdown
101 lines
4.6 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.
|
|
|
|
## Play
|
|
|
|
```bash
|
|
./play.sh
|
|
```
|
|
|
|
That lists the cases and asks which one. `./play.sh 07` jumps straight to one.
|
|
|
|
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-01-substantial-gift/` | **Case One — playable, 100 points.** Drebin Sr, 1982, monochrome. Five rooms. |
|
|
| `cases/case-06-testimony-of-evil/` | **Case Six — playable, 100 points.** Drebin Sr, 1982, monochrome. Five rooms, the whiskey exploit, four deaths. |
|
|
| `cases/case-07-from-the-files/` | **Case Seven — playable, 100 points.** Drebin Sr, 1988, full colour. Six rooms, the Anaheim Stadium finale. |
|
|
| `cases/case-02-ring-of-fear/` | **Case Two — playable, 100 points.** Drebin Sr, 1982, monochrome. Five rooms, undercover, three deaths. |
|
|
| `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 Sr, 1991, full colour. Five rooms, the memory test. |
|
|
| `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. |
|
|
| `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.
|
|
|
|
## 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.
|