Initial commit: ZIL source + Python game engine

Original ZIL source code for The Hitchhiker's Guide to the Galaxy (Infocom, 1984)
plus a native Python text adventure engine with the Earth opening sequence playable
(Bedroom → Front Porch → Front of House → Country Lane → Pub).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-03 20:46:54 +02:00
commit f55286db8e
49 changed files with 17531 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
__pycache__/
*.pyc
*.pyo
save.qzl
+1
View File
@@ -0,0 +1 @@
3.14
+56
View File
@@ -0,0 +1,56 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## What This Is
This is the original source code for **The Hitchhiker's Guide to the Galaxy** (1984), an interactive fiction game by Infocom (designed by Douglas Adams and Steve Meretzky). The code is written in **ZIL** (Zork Implementation Language), Infocom's proprietary Lisp-like language that compiles to Z-machine bytecode.
Release 60 (October 2, 1986) — the final release version. The compiled game runs as a `.z5` Z-machine story file (a copy is at `docs/The-Hitchhikers-Guide-to-the-Galaxy_DOS_EN_Z5-format/hitchhik.z5`).
## Building
ZIL source requires the **ZILF** compiler (open-source ZIL-to-Z-machine compiler) or Infocom's original toolchain. There is no build system or Makefile in this repo. To compile with ZILF:
```
zilf s4.zil
zapf s4.zap
```
This produces a `.z5` story file playable in any Z-machine interpreter (Frotz, Lectrote, etc.).
## Architecture
**Entry point:** `s4.zil` — includes all other source files via `<INSERT-FILE>`.
**Source files by function:**
| File | Purpose |
|------|---------|
| `s4.zil` | Main file; game title, file includes, property defaults |
| `globals.zil` | Global variables, directions, meta-objects (ROOMS, IT, NOT-HERE-OBJECT, LOCAL-GLOBALS) |
| `parser.zil` | Text parser — tokenizing input, resolving nouns/adjectives, disambiguation |
| `syntax.zil` | Vocabulary: BUZZ words, SYNONYMs, direction aliases, verb SYNTAX definitions |
| `verbs.zil` | Verb handler routines (`V-TAKE`, `V-DROP`, `V-EXAMINE`, etc.) and game commands |
| `misc.zil` | Utility routines, interrupt/clock system, macros |
| `earth.zil` | Earth locations — Arthur's bedroom, front of house, pub, country lane |
| `vogon.zil` | Vogon ship — hold, guard's room, airlock, poetry appreciation |
| `heart.zil` | Heart of Gold — bridge, engine room, corridors, Infinite Improbability Drive |
| `unearth.zil` | Off-Earth locations — Traal (Ravenous Bugblatter Beast), Damogran, Magrathea |
**Assembly files (`.xzap`):** `s4.xzap` is the assembly include order; `s4freq.xzap` defines frequently-used strings (Huffman-compressed). `s4.errors` is the assembler output log.
## ZIL Conventions
- **`<OBJECT ...>`** defines game objects with properties (DESC, SYNONYM, FLAGS, ACTION, etc.)
- **`<ROOM ...>`** defines locations (rooms are objects with directional exits)
- **`<ROUTINE ...>`** defines functions; `-F` suffix indicates an action handler (e.g., `HOME-F`)
- **`<GLOBAL ...>`** defines global variables; parser globals are prefixed `P-`
- **Flags on objects** control behavior: `TAKEBIT` (takeable), `OPENBIT` (open), `ONBIT` (lit/on), `TOUCHBIT` (seen), etc.
- **`PRSA` / `PRSO` / `PRSI`** — parsed action verb, direct object, indirect object
- **`<TELL ...>`** outputs text to the player; `CR` = carriage return
- Comments use `;"..."` syntax; `;<...>` comments out an entire form
## docs/
Contains the original MS-DOS executable, Z5 story file, game manuals (PDF), hint book, game maps, and photos of physical game "feelies" (props included with the boxed game).
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
+2454
View File
File diff suppressed because it is too large Load Diff
+2187
View File
File diff suppressed because it is too large Load Diff
View File
View File
+716
View File
@@ -0,0 +1,716 @@
"""Earth locations — Bedroom, Front Porch, Front of House, Country Lane, Pub."""
from h2g2.engine.game_object import GameObject, Room, Flag, Direction, DirectExit, ConditionalExit, BlockedExit
from h2g2.engine.world import World
from h2g2.engine.state import GameState
# ---- Object action handlers ----
def phone_action(state: GameState) -> bool:
out = state.output
phone = state.world.get("PHONE")
if state.prsa == "take":
if phone.fset_q(Flag.TOUCHBIT):
out.tell("You've already answered the phone.\n")
else:
phone.fset(Flag.TOUCHBIT)
out.tell("You pick up the receiver. A dialling tone.\n")
return True
if state.prsa == "answer":
phone.fset(Flag.TOUCHBIT)
out.tell("You pick up the receiver. A dialling tone.\n")
return True
if state.prsa == "hang up":
out.tell("You put down the receiver.\n")
return True
return False
def bed_action(state: GameState) -> bool:
out = state.output
bed = state.world.get("BED")
protagonist = state.protagonist
if state.prsa == "get out":
if state.headache:
protagonist.move_to(state.here)
state.lying_down = False
out.tell(
"Very difficult, but you manage it. The room is still "
"spinning. It dips and sways a little.\n"
)
return True
protagonist.move_to(state.here)
state.lying_down = False
out.tell("You get out of bed.\n")
return True
if state.prsa == "look under":
out.tell(
"There's nothing there. Well, there are a few soiled "
"handkerchiefs, a book you thought you'd lost, a couple of "
"foreign coins, and something else which can't be fully "
"described in a family game, but nothing you'd actually want.\n"
)
return True
if state.prsa == "examine":
out.tell("It's a bed. It's unmade and looks recently slept in.\n")
return True
return False
def gown_action(state: GameState) -> bool:
out = state.output
gown = state.world.get("GOWN")
if state.prsa == "take" and state.prso is gown:
if state.headache:
gown.fclear(Flag.TRYTAKEBIT)
gown.fclear(Flag.NDESCBIT)
gown.move_to(state.protagonist)
out.tell(
"Luckily, this is large enough for you to get hold of. "
"You notice something in the pocket.\n"
)
return True
return False # let default take handle it
if state.prsa == "put on" and state.prso is gown:
if not gown.is_held_by(state.protagonist):
# Auto-take it first
gown.move_to(state.protagonist)
gown.fset(Flag.WORNBIT)
out.tell("You are now wearing your gown.\n")
return True
if state.prsa == "examine":
out.tell(
"The dressing gown is faded and battered, and is clearly a "
"garment which has seen better decades. It has a pocket which "
"is "
)
if gown.fset_q(Flag.OPENBIT):
out.tell("open")
else:
out.tell("closed")
out.tell(", and a small loop at the back of the collar.\n")
return True
if state.prsa == "open":
gown.fset(Flag.OPENBIT)
visible = gown.contents_string()
if visible:
out.tell("Opening your gown reveals ")
descs = [obj.a_desc() for obj in visible]
out.tell(", ".join(descs[:-1]))
if len(descs) > 1:
out.tell(f", and {descs[-1]}")
else:
out.tell(descs[0])
out.tell(".\n")
else:
out.tell("You open the gown pocket. It's empty.\n")
return True
if state.prsa == "look in":
if not gown.fset_q(Flag.OPENBIT):
gown.fset(Flag.OPENBIT)
visible = gown.contents_string()
if visible:
out.tell("Opening your gown reveals ")
descs = [obj.a_desc() for obj in visible]
if len(descs) > 1:
out.tell(", ".join(descs[:-1]))
out.tell(f", and {descs[-1]}")
else:
out.tell(descs[0])
out.tell(".\n")
else:
out.tell("The pocket is empty.\n")
return True
return False
def tablet_action(state: GameState) -> bool:
out = state.output
tablet = state.world.get("TABLET")
if state.prsa in ("eat", "take", "drink", "swallow"):
tablet.move_to(state.world.local_globals) # consumed
state.headache = False
state.score += 10
out.tell(
"You swallow the tablet. After a few seconds the room begins "
"to calm down and behave in an orderly manner. Your terrible "
"headache goes.\n"
)
# Unset TRYTAKEBIT on screwdriver and toothbrush
screw = state.world.objects.get("SCREWDRIVER")
tooth = state.world.objects.get("TOOTHBRUSH")
if screw:
screw.fclear(Flag.TRYTAKEBIT)
if tooth:
tooth.fclear(Flag.TRYTAKEBIT)
return True
if state.prsa == "examine":
out.tell("It says \"Buffered Analgesic\" on the packet.\n")
return True
return False
def thing_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine":
out.tell(
'Apart from a label on the bottom saying "Made in Ibiza" it '
"furnishes you with no clue as to its purpose, if indeed it "
"has one. You are surprised to see it because you thought "
"you'd thrown it away. Like most gifts from your aunt, it is "
"extraordinarily dull.\n"
)
return True
return False
def curtains_action(state: GameState) -> bool:
out = state.output
bulldozer = state.world.get("BULLDOZER")
if state.prsa in ("open", "look in", "examine"):
bulldozer.fclear(Flag.INVISIBLE)
out.tell(
"As you part your curtains you see that it is a bright "
"morning, the sun is shining, the birds are singing, the "
"meadows are blooming, and a large yellow bulldozer is "
"advancing on your home.\n"
)
return True
return False
def screwdriver_action(state: GameState) -> bool:
out = state.output
if state.prsa == "take" and state.headache:
out.tell("It dances by you like a thing possessed.\n")
return True
if state.prsa == "examine":
out.tell("It's a flathead screwdriver.\n")
return True
return False
def toothbrush_action(state: GameState) -> bool:
out = state.output
if state.prsa == "take" and state.headache:
out.tell(
"You lunge for it, but the room spins nauseatingly away. "
"The floor gives you a light tap on the forehead.\n"
)
return True
if state.prsa == "examine":
out.tell("It's a perfectly normal toothbrush.\n")
return True
if state.prsa == "brush":
out.tell("Your teeth are fine. It's the rest of you that's a wreck.\n")
return True
return False
def bulldozer_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine":
if state.world.get("BULLDOZER").fset_q(Flag.INVISIBLE):
out.tell("You can't see any bulldozer.\n")
else:
out.tell(
"A large, My, a huge, My, a really huge yellow bulldozer.\n"
)
return True
return False
def prosser_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine":
if state.prosser_in_mud:
out.tell(
"Mr. Prosser is lying in the mud in front of the "
"bulldozer.\n"
)
else:
out.tell(
"Mr. Prosser is a rather fat man. He seems agitated.\n"
)
return True
if state.prsa in ("tell", "ask", "talk"):
if state.in_front_of_bulldozer:
out.tell(
'"Look, Mr. Dent, the plans have been available in the '
"planning office for the last nine months!\"\n"
)
else:
out.tell(
'"Come on, Mr. Dent, you can\'t win you know."\n'
)
return True
return False
def ford_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine":
out.tell(
"He is not the sort of man you'd want to get stuck in a "
"lift with, but at a pinch he'd do.\n"
)
return True
if state.prsa in ("tell", "ask", "talk"):
if state.here and state.here.id == "PUB":
out.tell('"Drink up," says Ford, "you\'ve got three pints to get through."\n')
elif state.here and state.here.id == "FRONT-OF-HOUSE":
out.tell('"Arthur! Come to the pub! I\'ve got to tell you something!"\n')
return True
return False
def beer_action(state: GameState) -> bool:
out = state.output
beer = state.world.get("BEER")
if state.prsa in ("drink", "eat"):
state.beer_counter += 1
state.score += 5
if state.beer_counter >= 3:
beer.move_to(state.world.local_globals)
out.tell(
"You finish the last of your beer. Ford then buys some "
"peanuts and hands you something small and yellow and "
"wriggly and shoves it in your ear.\n"
)
else:
out.tell(
f"You drink {'some' if state.beer_counter == 1 else 'more'} "
f"beer. {3 - state.beer_counter} pint"
f"{'s' if 3 - state.beer_counter != 1 else ''} left.\n"
)
return True
if state.prsa == "examine":
out.tell(f"There {'are' if state.beer_counter < 3 else 'is no'} beer"
f"{'s' if state.beer_counter == 0 else ''} here.\n")
return True
return False
# ---- Room action handlers ----
def bedroom_action(state: GameState, rarg: str) -> bool:
out = state.output
if rarg == "M-LOOK":
bed = state.world.get("BED")
gown = state.world.get("GOWN")
out.tell("The bedroom is a mess.\n")
out.tell(
"It is a small bedroom with a faded carpet and old wallpaper. "
"There is a washbasin, a chair"
)
if gown.fset_q(Flag.NDESCBIT):
out.tell(" with a tatty dressing gown slung over it")
out.tell(
", and a window with the curtains drawn. Near the exit "
"leading south is a phone.\n"
)
return True
if rarg == "M-BEG":
bed = state.world.get("BED")
protagonist = state.protagonist
# If player is in the bed, intercept certain actions
if protagonist and protagonist.parent is bed:
if state.prsa == "take" and state.prso:
# Can't reach things from bed
if state.prso.parent is not bed and not state.prso.is_held_by(protagonist):
out.tell("You can't reach it from the bed.")
if state.headache:
out.tell(" The effort almost kills you.")
out.tell("\n")
return True
return False
return False
def bedroom_exit(state: GameState) -> "Room | None":
out = state.output
door = state.world.get("BEDROOM-DOOR")
# Must be out of bed first
protagonist = state.protagonist
bed = state.world.get("BED")
if protagonist and protagonist.parent is bed:
out.tell("You'll have to get out of bed first.\n")
return None
if not door.fset_q(Flag.OPENBIT):
out.tell("The door is closed.\n")
return None
if state.headache:
out.tell(
"You miss the doorway by a good eighteen inches. The wall "
"jostles you rather rudely.\n"
)
return None
bulldozer = state.world.get("BULLDOZER")
if bulldozer.fset_q(Flag.INVISIBLE):
out.tell("You make your way down to the front porch.\n\n")
else:
out.tell("You rush down the stairs in panic.\n\n")
return state.world.get_room("FRONT-PORCH")
def front_porch_action(state: GameState, rarg: str) -> bool:
out = state.output
if rarg == "M-LOOK":
out.tell(
"This is the enclosed front porch of your home. Your front "
"garden lies to the south, and you can go back upstairs.\n"
)
return True
return False
def clothes_exit(state: GameState) -> "Room | None":
out = state.output
gown = state.world.get("GOWN")
if gown.fset_q(Flag.WORNBIT):
return state.world.get_room("FRONT-OF-HOUSE")
out.tell(
"You can't leave the house in your current state. You'd be "
"arrested for indecency.\n"
)
return None
def front_of_house_action(state: GameState, rarg: str) -> bool:
out = state.output
if rarg == "M-LOOK":
if state.house_demolished:
out.tell(
"Where your home used to be there is now a pile of "
"rubble, and through it runs a shiny new bypass.\n"
)
else:
out.tell(
"You can see your house from here. A large yellow "
"bulldozer is approaching it.\n"
)
if state.in_front_of_bulldozer:
out.tell("You are lying in the path of the bulldozer.\n")
return True
if rarg == "M-ENTER":
# Ford arrives after a few turns
pass
return False
def house_enter(state: GameState) -> "Room | None":
if state.house_demolished:
state.output.tell("Your home is now a pile of rubble.\n")
return None
return state.world.get_room("FRONT-PORCH")
def country_lane_action(state: GameState, rarg: str) -> bool:
out = state.output
if rarg == "M-LOOK":
out.tell(
"You are in a pleasant country lane winding between the "
"village and the pub. Your home lies to the north, and the "
"pub is south.\n"
)
return True
return False
def pub_action(state: GameState, rarg: str) -> bool:
out = state.output
if rarg == "M-LOOK":
out.tell(
"You are in the saloon bar of the Horse and Groom. "
"The pub is pleasant and cheerful. The exit is to the north.\n"
)
return True
if rarg == "M-ENTER":
ford = state.world.get("FORD")
beer = state.world.get("BEER")
if not state.ford_arrived:
state.ford_arrived = True
ford.move_to(state.here)
beer.move_to(state.here)
out.tell(
'\nFord Prefect bursts in. "Arthur! Thank God you\'re here! '
"I've got to tell you the most important thing you've ever "
'heard!"\n'
"He buys you three pints of beer.\n"
)
return False
# ---- Registration ----
def register(world: World) -> None:
"""Create all Earth rooms and objects."""
# ---- Objects (not in rooms yet) ----
bedroom_door = world.register(GameObject(
"BEDROOM-DOOR", desc="door",
synonyms=["door"],
flags={Flag.DOORBIT, Flag.OPENBIT, Flag.NDESCBIT},
))
bedroom_door.move_to(world.local_globals)
bulldozer = world.register(GameObject(
"BULLDOZER", desc="bulldozer",
synonyms=["bulldozer", "tractor"],
adjectives=["large", "yellow", "big"],
flags={Flag.INVISIBLE, Flag.NDESCBIT},
action=bulldozer_action,
))
bulldozer.move_to(world.local_globals)
prosser = world.register(GameObject(
"PROSSER", desc="Mr. Prosser",
synonyms=["prosser", "man"],
adjectives=["fat", "mr"],
flags={Flag.NARTICLEBIT, Flag.ACTORBIT, Flag.NDESCBIT},
action=prosser_action,
))
ford = world.register(GameObject(
"FORD", desc="Ford Prefect",
synonyms=["ford", "prefect"],
adjectives=["ford"],
flags={Flag.NARTICLEBIT, Flag.ACTORBIT, Flag.NDESCBIT},
action=ford_action,
))
window = world.register(GameObject(
"WINDOW", desc="window",
synonyms=["window"],
flags={Flag.NDESCBIT},
))
window.move_to(world.local_globals)
stairs = world.register(GameObject(
"STAIRS", desc="stairs",
synonyms=["stairs", "staircase", "stairway"],
flags={Flag.NDESCBIT},
))
stairs.move_to(world.local_globals)
# ---- BEDROOM ----
bedroom = world.register(Room(
"BEDROOM", desc="Bedroom",
flags={Flag.RLANDBIT},
action=bedroom_action,
global_objects=[
world.get("BEDROOM-DOOR"), bulldozer, window, stairs,
],
))
bed = world.register(GameObject(
"BED", desc="bed",
synonyms=["bed"],
flags={Flag.VEHBIT, Flag.CONTBIT, Flag.SURFACEBIT,
Flag.SEARCHBIT, Flag.OPENBIT, Flag.NDESCBIT},
action=bed_action,
))
bed.move_to(bedroom)
phone = world.register(GameObject(
"PHONE", desc="telephone",
synonyms=["phone", "telephone", "receiver"],
flags={Flag.NDESCBIT, Flag.TAKEBIT, Flag.TRYTAKEBIT},
action=phone_action,
))
phone.move_to(bedroom)
gown = world.register(GameObject(
"GOWN", desc="your gown",
ldesc="Your gown is here.",
synonyms=["gown", "pocket", "robe"],
adjectives=["my", "your", "dressing", "tatty", "faded", "battered"],
flags={Flag.WEARBIT, Flag.TRYTAKEBIT, Flag.TAKEBIT, Flag.CONTBIT,
Flag.NDESCBIT, Flag.NARTICLEBIT, Flag.SEARCHBIT},
size=15, capacity=14,
action=gown_action,
))
gown.move_to(bedroom)
curtains = world.register(GameObject(
"CURTAINS", desc="your curtains",
synonyms=["curtains", "curtain", "shade", "shades"],
adjectives=["your"],
flags={Flag.NDESCBIT, Flag.NARTICLEBIT},
action=curtains_action,
))
curtains.move_to(bedroom)
# Objects inside the gown
thing = world.register(GameObject(
"THING", desc="thing your aunt gave you which you don't know what it is",
synonyms=["thing", "gift"],
adjectives=["aunt's"],
flags={Flag.TAKEBIT, Flag.CONTBIT, Flag.SEARCHBIT, Flag.OPENBIT},
size=6, capacity=90,
action=thing_action,
))
thing.move_to(gown)
fluff = world.register(GameObject(
"POCKET-FLUFF", desc="pocket fluff",
synonyms=["fluff", "lint"],
adjectives=["pocket"],
flags={Flag.TAKEBIT, Flag.NARTICLEBIT},
size=1,
))
fluff.move_to(gown)
tablet = world.register(GameObject(
"TABLET", desc="buffered analgesic",
synonyms=["analgesic", "tablet", "aspirin", "pill"],
adjectives=["large", "buffered"],
flags={Flag.TAKEBIT},
size=2,
action=tablet_action,
))
tablet.move_to(gown)
screwdriver = world.register(GameObject(
"SCREWDRIVER", desc="flathead screwdriver",
synonyms=["screwdriver", "tool", "tools"],
adjectives=["flathead", "flat"],
flags={Flag.TAKEBIT, Flag.TRYTAKEBIT, Flag.TOOLBIT},
size=3,
action=screwdriver_action,
))
screwdriver.move_to(bedroom)
toothbrush = world.register(GameObject(
"TOOTHBRUSH", desc="toothbrush",
synonyms=["toothbrush", "brush"],
adjectives=["tooth", "my"],
flags={Flag.TAKEBIT, Flag.TRYTAKEBIT, Flag.TOOLBIT},
size=3,
action=toothbrush_action,
))
toothbrush.move_to(bedroom)
sink = world.register(GameObject(
"SINK", desc="washbasin",
synonyms=["basin", "washbasin", "sink"],
adjectives=["wash"],
flags={Flag.NDESCBIT, Flag.NARTICLEBIT},
))
sink.move_to(bedroom)
# Start player in bed
world.protagonist.move_to(bed)
# ---- FRONT PORCH ----
front_porch = world.register(Room(
"FRONT-PORCH", desc="Front Porch",
flags={Flag.RLANDBIT, Flag.ONBIT},
action=front_porch_action,
global_objects=[
world.get("BEDROOM-DOOR"), bulldozer, window, stairs,
],
))
mail = world.register(GameObject(
"MAIL", desc="some junk mail",
synonyms=["mail", "junk", "letter", "letters"],
flags={Flag.TAKEBIT, Flag.NARTICLEBIT},
text="Strewn among the usual junk mail is a notice from the local "
"council about a proposed demolition of your house.",
))
mail.move_to(front_porch)
# ---- FRONT OF HOUSE ----
front_of_house = world.register(Room(
"FRONT-OF-HOUSE", desc="Front of House",
flags={Flag.RLANDBIT, Flag.ONBIT, Flag.OUTSIDEBIT},
action=front_of_house_action,
global_objects=[bulldozer, prosser],
))
prosser.move_to(front_of_house)
# ---- COUNTRY LANE ----
country_lane = world.register(Room(
"COUNTRY-LANE", desc="Country Lane",
flags={Flag.RLANDBIT, Flag.ONBIT, Flag.OUTSIDEBIT},
action=country_lane_action,
))
# ---- PUB ----
pub = world.register(Room(
"PUB", desc="Pub",
flags={Flag.RLANDBIT, Flag.ONBIT},
action=pub_action,
))
beer = world.register(GameObject(
"BEER", desc="beer",
synonyms=["beer", "pint", "pints", "lager", "ale"],
adjectives=["three"],
flags={Flag.DRINKBIT, Flag.NDESCBIT},
action=beer_action,
))
# ---- Connect rooms ----
bedroom.exits = {
Direction.SOUTH: ConditionalExit(bedroom_exit),
Direction.OUT: ConditionalExit(bedroom_exit),
Direction.DOWN: ConditionalExit(bedroom_exit),
}
front_porch.exits = {
Direction.UP: DirectExit(bedroom),
Direction.NORTH: DirectExit(bedroom),
Direction.SOUTH: ConditionalExit(clothes_exit),
Direction.OUT: ConditionalExit(clothes_exit),
}
front_of_house.exits = {
Direction.NORTH: ConditionalExit(house_enter),
Direction.SOUTH: DirectExit(country_lane),
Direction.IN: ConditionalExit(house_enter),
}
country_lane.exits = {
Direction.NORTH: DirectExit(front_of_house),
Direction.SOUTH: DirectExit(pub),
}
pub.exits = {
Direction.NORTH: DirectExit(country_lane),
Direction.OUT: DirectExit(country_lane),
}
+143
View File
@@ -0,0 +1,143 @@
"""Global objects — always-visible entities and root containers."""
from h2g2.engine.game_object import GameObject, Flag
from h2g2.engine.world import World
from h2g2.engine.state import GameState
def hangover_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine" or state.prsa == "diagnose":
if state.headache:
out.tell("You have a big blinding throbber.\n")
else:
out.tell("You don't have a headache.\n")
return True
return False
def light_action(state: GameState) -> bool:
out = state.output
if state.prsa == "turn on":
if state.here and state.here.fset_q(Flag.ONBIT):
out.tell("It is.\n")
else:
if state.here:
state.here.fset(Flag.ONBIT)
state.update_lit()
out.tell("Good start to the day. Pity it's going to be the worst "
"one of your life. The light is now on.\n\n")
# Show room description now that light is on
from h2g2.engine.loop import GameLoop
GameLoop._describe_room_static(state)
return True
if state.prsa == "turn off":
if state.here:
state.here.fclear(Flag.ONBIT)
state.update_lit()
out.tell("It is now pitch dark in here. If you proceed you will "
"likely fall into a pit.\n")
return True
return False
def walls_action(state: GameState) -> bool:
if state.prsa == "examine":
state.output.tell("They look like walls.\n")
return True
return False
def me_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine":
if state.headache:
out.tell("You look about as ill as you feel.\n")
else:
out.tell("You look pretty normal.\n")
return True
return False
def ground_action(state: GameState) -> bool:
out = state.output
if state.prsa == "lie down":
state.lying_down = True
if state.here and state.here.id == "FRONT-OF-HOUSE":
state.in_front_of_bulldozer = True
out.tell("You lie down in the path of the advancing bulldozer.\n")
else:
out.tell("You lie down.\n")
return True
if state.prsa == "examine":
out.tell("It looks like ground.\n")
return True
return False
def register(world: World) -> None:
"""Create all global objects and root containers."""
# Root containers
global_objects = world.register(GameObject(
"GLOBAL-OBJECTS", desc="global objects",
flags={Flag.INVISIBLE},
))
world.global_objects = global_objects
local_globals = world.register(GameObject(
"LOCAL-GLOBALS", desc="local globals",
flags={Flag.INVISIBLE},
))
local_globals.move_to(global_objects)
world.local_globals = local_globals
protagonist = world.register(GameObject(
"PROTAGONIST", desc="you",
flags={Flag.INVISIBLE, Flag.ACTORBIT},
capacity=100,
))
world.protagonist = protagonist
# Globally visible objects
world.register(GameObject(
"LIGHT", desc="light",
synonyms=["light", "lights", "lamp"],
flags={Flag.LIGHTBIT},
action=light_action,
)).move_to(global_objects)
world.register(GameObject(
"WALLS", desc="wall",
synonyms=["wall", "walls", "ceiling", "floor"],
flags={Flag.NDESCBIT, Flag.TOUCHBIT},
action=walls_action,
)).move_to(global_objects)
world.register(GameObject(
"ME", desc="yourself",
synonyms=["me", "myself", "self", "yourself"],
flags={Flag.NDESCBIT, Flag.NARTICLEBIT, Flag.ACTORBIT},
action=me_action,
)).move_to(global_objects)
world.register(GameObject(
"HANGOVER", desc="splitting headache",
synonyms=["headache", "hangover", "throbber"],
adjectives=["splitting", "big", "blinding"],
action=hangover_action,
)).move_to(global_objects)
world.register(GameObject(
"GROUND", desc="ground",
synonyms=["ground", "mud", "dirt", "floor", "earth"],
flags={Flag.NDESCBIT},
action=ground_action,
)).move_to(global_objects)
world.register(GameObject(
"HANDS", desc="your hands",
synonyms=["hands", "hand"],
adjectives=["my", "your"],
flags={Flag.NDESCBIT, Flag.NARTICLEBIT},
)).move_to(global_objects)
+15
View File
@@ -0,0 +1,15 @@
from h2g2.engine.game_object import GameObject, Room, Flag, Direction, Exit
from h2g2.engine.world import World
from h2g2.engine.state import GameState
from h2g2.engine.output import Output
from h2g2.engine.clock import Clock, ClockEntry
from h2g2.engine.parser import Parser, ParseResult
from h2g2.engine.loop import GameLoop
__all__ = [
"GameObject", "Room", "Flag", "Direction", "Exit",
"World", "GameState", "Output",
"Clock", "ClockEntry",
"Parser", "ParseResult",
"GameLoop",
]
+66
View File
@@ -0,0 +1,66 @@
"""Clock/interrupt system — timed events that fire on game turns."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Callable, Any
@dataclass
class ClockEntry:
"""A scheduled interrupt."""
routine: Callable # (state) -> bool; True = handled/displayed
tick: int # Countdown; fires when reaches 0. -1 = every turn
enabled: bool = True
name: str = "" # For debugging
class Clock:
"""Manages timed game events, equivalent to ZIL's C-TABLE/CLOCKER."""
def __init__(self) -> None:
self.entries: list[ClockEntry] = []
def queue(self, routine: Callable, tick: int, name: str = "") -> ClockEntry:
"""Schedule an interrupt routine to fire after `tick` turns.
If an entry for the same routine already exists, update its tick.
"""
for entry in self.entries:
if entry.routine is routine:
entry.tick = tick
entry.enabled = True
return entry
entry = ClockEntry(routine=routine, tick=tick, name=name)
self.entries.append(entry)
return entry
def enable(self, entry: ClockEntry) -> None:
entry.enabled = True
def disable(self, entry: ClockEntry) -> None:
entry.enabled = False
def remove(self, entry: ClockEntry) -> None:
if entry in self.entries:
self.entries.remove(entry)
def tick_all(self, state: Any) -> bool:
"""Advance all clocks by one turn. Returns True if any event fired."""
any_fired = False
for entry in list(self.entries): # copy because handlers may modify
if not entry.enabled:
continue
if entry.tick > 0:
entry.tick -= 1
if entry.tick == 0:
result = entry.routine(state)
if result:
any_fired = True
entry.enabled = False # one-shot; re-enable manually
elif entry.tick < 0:
# Negative tick = fires every turn
result = entry.routine(state)
if result:
any_fired = True
return any_fired
+202
View File
@@ -0,0 +1,202 @@
"""Game object model — items, rooms, NPCs, and the flag/direction system."""
from __future__ import annotations
import enum
from dataclasses import dataclass, field
from typing import Callable, Any
class Flag(enum.Enum):
TAKEBIT = enum.auto()
OPENBIT = enum.auto()
TOUCHBIT = enum.auto()
ONBIT = enum.auto()
TRANSBIT = enum.auto()
WEARBIT = enum.auto()
WORNBIT = enum.auto()
RLANDBIT = enum.auto()
NDESCBIT = enum.auto()
INVISIBLE = enum.auto()
LIGHTBIT = enum.auto()
CONTBIT = enum.auto()
SURFACEBIT = enum.auto()
ACTORBIT = enum.auto()
VEHBIT = enum.auto()
DOORBIT = enum.auto()
READBIT = enum.auto()
DRINKBIT = enum.auto()
NARTICLEBIT = enum.auto()
VOWELBIT = enum.auto()
SEARCHBIT = enum.auto()
TRYTAKEBIT = enum.auto()
DARKBIT = enum.auto()
REVISITBIT = enum.auto()
MUNGEDBIT = enum.auto()
OUTSIDEBIT = enum.auto()
TOOLBIT = enum.auto()
INTEGRALBIT = enum.auto()
class Direction(enum.Enum):
NORTH = "north"
NE = "northeast"
EAST = "east"
SE = "southeast"
SOUTH = "south"
SW = "southwest"
WEST = "west"
NW = "northwest"
UP = "up"
DOWN = "down"
IN = "in"
OUT = "out"
@dataclass
class DirectExit:
"""Simple exit to a fixed room."""
destination: Room
@dataclass
class ConditionalExit:
"""Exit gated by a function that returns a Room or None."""
function: Callable # (state) -> Room | None; None means blocked
@dataclass
class GatedExit:
"""Exit that requires a door object to be open."""
destination: Room
door: GameObject
@dataclass
class BlockedExit:
"""Permanently blocked exit with a message."""
message: str
Exit = DirectExit | ConditionalExit | GatedExit | BlockedExit
class GameObject:
"""A game entity — item, NPC, abstract concept, or container."""
def __init__(
self,
id: str,
*,
desc: str = "",
ldesc: str | None = None,
fdesc: str | None = None,
synonyms: list[str] | None = None,
adjectives: list[str] | None = None,
flags: set[Flag] | None = None,
size: int = 5,
capacity: int = 0,
action: Callable | None = None,
text: str | None = None,
):
self.id = id
self.desc = desc
self.ldesc = ldesc
self.fdesc = fdesc
self.synonyms: list[str] = [s.lower() for s in (synonyms or [])]
self.adjectives: list[str] = [a.lower() for a in (adjectives or [])]
self.flags: set[Flag] = flags or set()
self.size = size
self.capacity = capacity
self.action = action
self.text = text
# Containment tree
self.parent: GameObject | None = None
self.children: list[GameObject] = []
def move_to(self, new_parent: GameObject | None) -> None:
"""Move this object into a new container."""
if self.parent:
self.parent.children.remove(self)
self.parent = new_parent
if new_parent:
new_parent.children.append(self)
def contains(self, obj: GameObject) -> bool:
"""Check if obj is a direct child."""
return obj in self.children
def is_held_by(self, holder: GameObject) -> bool:
"""Check if this object is carried by holder (direct or nested)."""
current = self.parent
while current:
if current is holder:
return True
current = current.parent
return False
def contents_string(self) -> list[GameObject]:
"""Return visible children (not INVISIBLE or NDESCBIT)."""
return [
c for c in self.children
if Flag.INVISIBLE not in c.flags and Flag.NDESCBIT not in c.flags
]
def fset(self, flag: Flag) -> None:
self.flags.add(flag)
def fclear(self, flag: Flag) -> None:
self.flags.discard(flag)
def fset_q(self, flag: Flag) -> bool:
return flag in self.flags
def article(self) -> str:
"""Return the appropriate article for this object."""
if Flag.NARTICLEBIT in self.flags:
return ""
if Flag.VOWELBIT in self.flags:
return "an "
return "a "
def the_desc(self) -> str:
"""Return 'the <desc>' or just desc for proper nouns."""
if Flag.NARTICLEBIT in self.flags:
return self.desc
return f"the {self.desc}"
def a_desc(self) -> str:
"""Return 'a/an <desc>' or just desc for proper nouns."""
if Flag.NARTICLEBIT in self.flags:
return self.desc
return f"{self.article()}{self.desc}"
def __repr__(self) -> str:
return f"<{self.__class__.__name__} {self.id!r}>"
class Room(GameObject):
"""A location in the game world."""
def __init__(
self,
id: str,
*,
desc: str = "",
ldesc: str | None = None,
synonyms: list[str] | None = None,
adjectives: list[str] | None = None,
flags: set[Flag] | None = None,
action: Callable | None = None,
exits: dict[Direction, Exit] | None = None,
global_objects: list[GameObject] | None = None,
pseudo: list[tuple[str, Callable]] | None = None,
):
super().__init__(
id, desc=desc, ldesc=ldesc, synonyms=synonyms,
adjectives=adjectives, flags=flags, action=action,
)
self.exits: dict[Direction, Exit] = exits or {}
self.global_objects: list[GameObject] = global_objects or []
self.pseudo: list[tuple[str, Callable]] = pseudo or []
+284
View File
@@ -0,0 +1,284 @@
"""Main game loop and PERFORM dispatch chain."""
from __future__ import annotations
from typing import Callable
from h2g2.engine.game_object import (
GameObject, Room, Flag, Direction,
DirectExit, ConditionalExit, GatedExit, BlockedExit,
)
from h2g2.engine.parser import Parser, ParseResult
from h2g2.engine.state import GameState
from h2g2.engine.output import Output
# Verb handlers: verb_name -> handler function
# Each handler receives (state, prso, prsi) -> bool (True = handled)
_verb_handlers: dict[str, Callable] = {}
_pre_handlers: dict[str, Callable] = {}
# Meta-verbs that don't advance the clock
META_VERBS = {
"save", "restore", "restart", "quit", "score",
"verbose", "brief", "superbrief", "again", "inventory",
"diagnose",
}
def verb_handler(verb: str) -> Callable:
"""Decorator to register a default verb handler."""
def decorator(fn: Callable) -> Callable:
_verb_handlers[verb] = fn
return fn
return decorator
def pre_handler(verb: str) -> Callable:
"""Decorator to register a pre-action handler."""
def decorator(fn: Callable) -> Callable:
_pre_handlers[verb] = fn
return fn
return decorator
class GameLoop:
"""The main game loop — parse, dispatch, clock."""
def __init__(self, state: GameState, parser: Parser) -> None:
self.state = state
self.parser = parser
def run(self) -> None:
"""Run the main game loop until the game ends."""
state = self.state
out = state.output
# Initial room description
self._describe_room()
print(out.flush(), end="")
while state.running:
try:
raw = input("\n> ")
except (EOFError, KeyboardInterrupt):
print("\nGoodbye!")
break
if not raw.strip():
continue
result = self.parser.parse(raw, state)
if result is None:
out.tell("I don't understand that.\n")
print(out.flush(), end="")
continue
self._execute(result)
# Print output
text = out.flush()
if text:
print(text, end="")
def _execute(self, result: ParseResult) -> None:
"""Execute a parsed command through the dispatch chain."""
state = self.state
# Set parser state
state.prsa = result.verb
state.prso = result.direct_obj
state.prsi = result.indirect_obj
state.dont_flag = result.is_negated
# Handle movement
if result.verb == "walk" and result.direction:
self._do_walk(result.direction)
else:
self._perform(result.verb, result.direct_obj, result.indirect_obj)
# Update IT pronoun
if result.direct_obj and result.verb not in META_VERBS:
state.p_it_object = result.direct_obj
# Store for AGAIN
if result.verb not in META_VERBS:
state.l_prsa = result.verb
state.l_prso = result.direct_obj
state.l_prsi = result.indirect_obj
# Advance clock (unless meta-verb)
if result.verb not in META_VERBS:
state.moves += 1
state.clock.tick_all(state)
def _perform(
self, verb: str,
prso: GameObject | None, prsi: GameObject | None,
) -> bool:
"""Execute the verb dispatch chain. Returns True if handled."""
state = self.state
out = state.output
# 1. Room M-BEG handler
if state.here and state.here.action:
result = state.here.action(state, "M-BEG")
if result:
return True
# 2. Pre-action handler
pre = _pre_handlers.get(verb)
if pre:
result = pre(state, prso, prsi)
if result:
return True
# 3. Indirect object handler
if prsi and prsi.action:
result = prsi.action(state)
if result:
return True
# 4. Direct object handler
if prso and prso.action:
result = prso.action(state)
if result:
return True
# 5. Default verb handler
handler = _verb_handlers.get(verb)
if handler:
return handler(state, prso, prsi)
out.tell("I don't know how to do that.\n")
return False
def _do_walk(self, direction_name: str) -> None:
"""Handle movement in a direction."""
state = self.state
out = state.output
# Check if in a vehicle/bed
if (state.protagonist and state.protagonist.parent
and state.protagonist.parent != state.here
and state.protagonist.parent.fset_q(Flag.VEHBIT)):
out.tell("You'll have to get out of "
f"{state.protagonist.parent.the_desc()} first.\n")
return
if state.lying_down:
out.tell("You'll have to get up first.\n")
return
direction = Direction[direction_name]
if state.here is None:
return
exit_def = state.here.exits.get(direction)
if exit_def is None:
out.tell("You can't go that way.\n")
return
if isinstance(exit_def, DirectExit):
self._enter_room(exit_def.destination)
elif isinstance(exit_def, ConditionalExit):
dest = exit_def.function(state)
if dest:
self._enter_room(dest)
# If function returns None, it should have printed a message
elif isinstance(exit_def, GatedExit):
if exit_def.door.fset_q(Flag.OPENBIT):
self._enter_room(exit_def.destination)
else:
out.tell(f"The {exit_def.door.desc} is closed.\n")
elif isinstance(exit_def, BlockedExit):
out.tell(exit_def.message + "\n")
def _enter_room(self, room: Room) -> None:
"""Move the player into a new room."""
state = self.state
state.here = room
state.update_lit()
# Mark as visited
if not room.fset_q(Flag.REVISITBIT):
room.fset(Flag.REVISITBIT)
# Room M-ENTER handler
if room.action:
room.action(state, "M-ENTER")
self._describe_room()
@staticmethod
def _describe_room_static(state: GameState) -> None:
"""Describe the current room (static version for external callers)."""
GameLoop._describe_room_impl(state)
def _describe_room(self) -> None:
"""Describe the current room."""
GameLoop._describe_room_impl(self.state)
@staticmethod
def _describe_room_impl(state: GameState) -> None:
"""Describe the current room (implementation)."""
out = state.output
if state.here is None:
return
state.update_lit()
if not state.lit:
out.tell("It is pitch black.\n")
return
# Room name
out.tell(state.here.desc)
# Show if player is in a vehicle/bed
if (state.protagonist and state.protagonist.parent
and state.protagonist.parent != state.here
and state.protagonist.parent.fset_q(Flag.VEHBIT)):
out.tell(f", in {state.protagonist.parent.the_desc()}")
elif state.lying_down:
out.tell(", lying down")
out.tell("\n")
# Room description
should_describe = (
state.verbosity == 2
or not state.here.fset_q(Flag.REVISITBIT)
or state.prsa == "look"
)
if should_describe:
# Room M-LOOK handler
if state.here.action:
result = state.here.action(state, "M-LOOK")
if result:
GameLoop._list_room_objects_impl(state)
return
if state.here.ldesc:
out.tell(state.here.ldesc + "\n")
GameLoop._list_room_objects_impl(state)
@staticmethod
def _list_room_objects_impl(state: GameState) -> None:
"""List visible objects in the current room."""
out = state.output
if state.here is None:
return
for obj in state.here.children:
if Flag.INVISIBLE in obj.flags or Flag.NDESCBIT in obj.flags:
continue
if obj is state.protagonist:
continue
if obj.fdesc and not obj.fset_q(Flag.TOUCHBIT):
out.tell(obj.fdesc + "\n")
elif obj.ldesc:
out.tell(obj.ldesc + "\n")
else:
out.tell(f"There is {obj.a_desc()} here.\n")
+53
View File
@@ -0,0 +1,53 @@
"""Text output buffer — clean, TTS-ready output."""
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from h2g2.engine.game_object import GameObject
class Output:
"""Accumulates game text for display and future TTS consumption.
No ANSI codes, no terminal escape sequences — just plain text.
"""
def __init__(self) -> None:
self._buffer: list[str] = []
def tell(self, *parts: str) -> None:
"""Append text fragments to the output buffer."""
self._buffer.append("".join(parts))
def newline(self) -> None:
self._buffer.append("\n")
def blank_line(self) -> None:
self._buffer.append("\n\n")
def describe(self, obj: "GameObject") -> None:
"""Output an object's description (equivalent to ZIL 'D')."""
self.tell(obj.desc)
def a_desc(self, obj: "GameObject") -> None:
"""Output 'a/an <desc>' or proper noun."""
self.tell(obj.a_desc())
def the_desc(self, obj: "GameObject") -> None:
"""Output 'the <desc>' or proper noun."""
self.tell(obj.the_desc())
def number(self, n: int) -> None:
"""Output a number."""
self.tell(str(n))
def flush(self) -> str:
"""Return accumulated text and clear the buffer."""
result = "".join(self._buffer)
self._buffer.clear()
return result
def has_content(self) -> bool:
return bool(self._buffer)
+331
View File
@@ -0,0 +1,331 @@
"""Input parser — tokenizes commands, matches verbs, resolves objects."""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from h2g2.engine.game_object import GameObject, Direction
from h2g2.engine.state import GameState
# Words stripped from input (articles, filler)
BUZZ_WORDS = {
"a", "an", "the", "is", "are", "am", "and", "of", "then",
"all", "but", "except", "please", "here", "some", "more",
}
# Direction word mappings
DIRECTION_WORDS: dict[str, str] = {
"north": "NORTH", "n": "NORTH", "fore": "NORTH", "f": "NORTH",
"south": "SOUTH", "s": "SOUTH", "aft": "SOUTH",
"east": "EAST", "e": "EAST", "starboard": "EAST", "sb": "EAST",
"west": "WEST", "w": "WEST", "port": "WEST", "p": "WEST",
"up": "UP", "u": "UP",
"down": "DOWN", "d": "DOWN",
"northeast": "NE", "ne": "NE",
"northwest": "NW", "nw": "NW",
"southeast": "SE", "se": "SE",
"southwest": "SW", "sw": "SW",
"in": "IN", "inside": "IN", "into": "IN", "enter": "IN",
"out": "OUT", "outside": "OUT", "exit": "OUT", "leave": "OUT",
}
# Prepositions that separate object clauses
PREPOSITIONS = {
"in", "into", "inside", "on", "onto", "with", "using",
"at", "to", "toward", "from", "off", "through", "thru",
"under", "below", "beneath", "behind", "before", "near",
"around", "about", "over", "across", "against",
}
# Verb synonyms
VERB_SYNONYMS: dict[str, str] = {
"grab": "take", "catch": "take", "get": "take", "hold": "take",
"carry": "take", "pick": "take",
"release": "drop", "discard": "drop",
"go": "walk", "move": "walk", "run": "walk",
"l": "look", "describe": "look",
"x": "examine", "inspect": "examine", "check": "examine",
"i": "inventory", "possessions": "inventory",
"q": "quit", "bye": "quit",
"g": "again",
"hit": "attack", "kill": "attack", "fight": "attack",
"yell": "shout", "scream": "shout",
"lie": "lie down",
"stand": "stand up", "rise": "stand up",
"wear": "put on",
"remove": "take off",
"drink": "drink",
"eat": "eat",
"read": "read",
"open": "open",
"close": "close", "shut": "close",
"push": "push", "press": "push",
"pull": "pull",
"turn": "turn",
"switch": "turn",
"give": "give",
"show": "show",
"tell": "tell",
"ask": "ask",
"wait": "wait", "z": "wait",
"save": "save",
"restore": "restore",
"score": "score",
"verbose": "verbose",
"brief": "brief",
"superbrief": "superbrief",
"diagnose": "diagnose",
"restart": "restart",
"swim": "swim",
"sleep": "sleep",
"wake": "wake",
"enjoy": "enjoy",
"listen": "listen",
"smell": "smell",
"taste": "taste",
"touch": "touch", "feel": "touch",
"pour": "pour",
"fill": "fill",
"empty": "empty",
"answer": "answer",
"call": "call",
"count": "count",
"drown": "drown",
"pray": "pray",
"brush": "brush",
"swallow": "swallow",
}
@dataclass
class ParseResult:
verb: str
direct_obj: GameObject | None = None
indirect_obj: GameObject | None = None
direction: str | None = None # For movement commands
prep: str | None = None # Preposition between objects
raw_input: str = ""
is_negated: bool = False
# Unresolved noun text (for disambiguation)
direct_noun: str | None = None
indirect_noun: str | None = None
direct_adj: str | None = None
indirect_adj: str | None = None
class Parser:
"""Parses player input into structured commands."""
def __init__(self) -> None:
self.last_result: ParseResult | None = None
def parse(self, raw: str, state: "GameState") -> ParseResult | None:
"""Parse a raw input string into a ParseResult, or None if unparseable."""
raw = raw.strip()
if not raw:
return None
tokens = raw.lower().split()
# Handle negation
is_negated = False
if tokens[0] in ("dont", "don't"):
is_negated = True
tokens = tokens[1:]
if not tokens:
return None
# Strip buzz words from beginning (but keep them between clauses)
while tokens and tokens[0] in BUZZ_WORDS:
tokens.pop(0)
if not tokens:
return None
# Check for bare direction command
if len(tokens) == 1 and tokens[0] in DIRECTION_WORDS:
return ParseResult(
verb="walk",
direction=DIRECTION_WORDS[tokens[0]],
raw_input=raw,
is_negated=is_negated,
)
# Check for "go <direction>"
if len(tokens) >= 2 and tokens[0] in ("go", "walk", "run", "move"):
if tokens[1] in DIRECTION_WORDS:
return ParseResult(
verb="walk",
direction=DIRECTION_WORDS[tokens[1]],
raw_input=raw,
is_negated=is_negated,
)
# Extract verb word (don't resolve synonyms yet — check compounds first)
verb_word = tokens.pop(0)
# Handle compound verbs using the RAW verb word
verb = verb_word # temporary, before synonym resolution
if verb_word == "get" and tokens:
if tokens[0] == "out":
verb = "get out"
tokens.pop(0)
if tokens and tokens[0] == "of":
tokens.pop(0)
elif tokens[0] == "in":
verb = "get in"
tokens.pop(0)
elif tokens[0] == "up":
verb = "stand up"
tokens.pop(0)
else:
verb = VERB_SYNONYMS.get(verb_word, verb_word)
elif verb_word == "turn" and tokens:
if tokens[0] == "on":
verb = "turn on"
tokens.pop(0)
elif tokens[0] == "off":
verb = "turn off"
tokens.pop(0)
else:
verb = VERB_SYNONYMS.get(verb_word, verb_word)
elif verb_word == "pick" and tokens and tokens[0] == "up":
verb = "take"
tokens.pop(0)
elif verb_word == "put" and tokens and tokens[0] == "on":
verb = "put on"
tokens.pop(0)
elif verb_word == "lie" and tokens and tokens[0] == "down":
verb = "lie down"
tokens.pop(0)
elif verb_word == "stand" and tokens and tokens[0] == "up":
verb = "stand up"
tokens.pop(0)
elif verb_word == "look" and tokens:
if tokens[0] == "at":
verb = "examine"
tokens.pop(0)
elif tokens[0] in ("in", "inside"):
verb = "look in"
tokens.pop(0)
elif tokens[0] == "under":
verb = "look under"
tokens.pop(0)
else:
verb = VERB_SYNONYMS.get(verb_word, verb_word)
elif verb_word == "hang" and tokens and tokens[0] == "up":
verb = "hang up"
tokens.pop(0)
else:
verb = VERB_SYNONYMS.get(verb_word, verb_word)
# Handle post-synonym compounds
if verb == "take" and tokens and tokens[0] == "off":
verb = "take off"
tokens.pop(0)
# Handle AGAIN
if verb == "again" and self.last_result:
return self.last_result
# Handle IT/THEM pronoun
for i, t in enumerate(tokens):
if t in ("it", "them", "him", "her") and state.p_it_object:
# Will resolve during object resolution
pass
# Strip remaining buzz words
tokens = [t for t in tokens if t not in BUZZ_WORDS]
# No object needed for some verbs
if not tokens:
result = ParseResult(
verb=verb, raw_input=raw, is_negated=is_negated,
)
self.last_result = result
return result
# Split on preposition to get direct/indirect object phrases
prep = None
direct_tokens: list[str] = []
indirect_tokens: list[str] = []
in_indirect = False
for token in tokens:
if token in PREPOSITIONS and not in_indirect and direct_tokens:
prep = token
in_indirect = True
elif in_indirect:
indirect_tokens.append(token)
else:
direct_tokens.append(token)
# Handle "in front of" as a special case
if prep == "in" and indirect_tokens and indirect_tokens[0] == "front":
indirect_tokens.pop(0)
if indirect_tokens and indirect_tokens[0] == "of":
indirect_tokens.pop(0)
prep = "in front of"
# Resolve nouns
d_adj, d_noun = self._extract_noun(direct_tokens)
i_adj, i_noun = self._extract_noun(indirect_tokens)
# Try to resolve objects
d_obj = self._resolve(d_noun, d_adj, state) if d_noun else None
i_obj = self._resolve(i_noun, i_adj, state) if i_noun else None
result = ParseResult(
verb=verb,
direct_obj=d_obj,
indirect_obj=i_obj,
prep=prep,
raw_input=raw,
is_negated=is_negated,
direct_noun=d_noun,
indirect_noun=i_noun,
direct_adj=d_adj,
indirect_adj=i_adj,
)
self.last_result = result
return result
def _extract_noun(self, tokens: list[str]) -> tuple[str | None, str | None]:
"""Extract adjective and noun from a token list.
Returns (adjective, noun). The last word is the noun,
preceding words are adjectives.
"""
if not tokens:
return None, None
if len(tokens) == 1:
return None, tokens[0]
# Last token is noun, rest are adjectives
return tokens[0], tokens[-1]
def _resolve(
self, noun: str | None, adj: str | None, state: "GameState"
) -> "GameObject | None":
"""Resolve a noun+adjective to a game object."""
if noun is None:
return None
# Handle pronouns
if noun in ("it", "them", "him", "her"):
return state.p_it_object
if state.here is None or state.protagonist is None:
return None
matches = state.world.find_by_name(
noun, adj, state.here, state.protagonist,
)
if len(matches) == 1:
return matches[0]
elif len(matches) > 1:
# Disambiguation — for now, return the first match
# TODO: Ask "Which one?" for true disambiguation
return matches[0]
return None
+97
View File
@@ -0,0 +1,97 @@
"""Game state — all mutable globals, score, turn counter, puzzle flags."""
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from h2g2.engine.game_object import GameObject, Room
from h2g2.engine.world import World
from h2g2.engine.output import Output
from h2g2.engine.clock import Clock
class GameState:
"""Central mutable state for the game."""
def __init__(self, world: "World", output: "Output", clock: "Clock") -> None:
self.world = world
self.output = output
self.clock = clock
# Core
self.here: Room | None = None
self.protagonist: GameObject | None = None
self.winner: GameObject | None = None # current actor
self.score: int = 0
self.moves: int = 0
self.lit: bool = False
self.running: bool = True
# Identity system (multi-character)
self.identity_flag: GameObject | None = None # ARTHUR, FORD, etc.
# Parser state
self.prsa: str | None = None # current verb
self.prso: GameObject | None = None # direct object
self.prsi: GameObject | None = None # indirect object
self.p_it_object: GameObject | None = None # last referenced object
self.dont_flag: bool = False
self.in_front_flag: bool = False
# Last action (for AGAIN)
self.l_prsa: str | None = None
self.l_prso: GameObject | None = None
self.l_prsi: GameObject | None = None
# Condition flags
self.lying_down: bool = False
self.headache: bool = True
self.groggy: bool = False
self.groggy_counter: int = 0
self.verbosity: int = 1 # 0=superbrief, 1=brief, 2=verbose
# Earth progression
self.house_demolished: bool = False
self.earth_demolished: bool = False
self.in_front_of_bulldozer: bool = False
self.ford_arrived: bool = False
self.ford_has_satchel: bool = True
self.prosser_in_mud: bool = False
self.beer_counter: int = 0
# Vogon
self.babel_fish_in_ear: bool = False
self.poem_enjoyed: bool = False
# Heart of Gold
self.holding_no_tea: bool = True
self.dreaming: bool = False
# Probability system (dream dispatch weights)
self.vogon_prob: int = 100
self.heart_prob: int = 0
self.traal_prob: int = 60
self.fleet_prob: int = 0
self.whale_prob: int = 0
# Deaths
self.dead_counter: int = 0
def update_lit(self) -> None:
"""Recalculate whether the current location is lit."""
if self.here is None:
self.lit = False
return
from h2g2.engine.game_object import Flag
# Room has ONBIT = lit
if self.here.fset_q(Flag.ONBIT):
self.lit = True
return
# Check if player carries a light source
if self.protagonist:
for obj in self.protagonist.children:
if obj.fset_q(Flag.LIGHTBIT) and obj.fset_q(Flag.ONBIT):
self.lit = True
return
self.lit = False
+473
View File
@@ -0,0 +1,473 @@
"""Default verb handler implementations."""
from __future__ import annotations
from h2g2.engine.game_object import GameObject, Flag
from h2g2.engine.state import GameState
from h2g2.engine.loop import verb_handler
@verb_handler("look")
def v_look(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
from h2g2.engine.loop import GameLoop
old_prsa = state.prsa
state.prsa = "look"
GameLoop._describe_room_impl(state)
state.prsa = old_prsa
return True
@verb_handler("examine")
def v_examine(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
out = state.output
if prso is None:
out.tell("What do you want to examine?\n")
return True
if prso.text:
out.tell(prso.text + "\n")
elif prso.ldesc:
out.tell(prso.ldesc + "\n")
else:
out.tell(f"There's nothing special about {prso.the_desc()}.\n")
# Show container contents
if prso.fset_q(Flag.CONTBIT) or prso.fset_q(Flag.SURFACEBIT):
if prso.fset_q(Flag.OPENBIT) or prso.fset_q(Flag.TRANSBIT):
visible = prso.contents_string()
if visible:
out.tell(f"{prso.the_desc().capitalize()} contains:\n")
for child in visible:
out.tell(f" {child.a_desc()}\n")
return True
@verb_handler("take")
def v_take(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
out = state.output
if prso is None:
out.tell("What do you want to take?\n")
return True
if not prso.fset_q(Flag.TAKEBIT):
out.tell(f"You can't take {prso.the_desc()}.\n")
return True
if prso.parent is state.protagonist:
out.tell("You already have that.\n")
return True
prso.fset(Flag.TOUCHBIT)
prso.move_to(state.protagonist)
out.tell("Taken.\n")
return True
@verb_handler("drop")
def v_drop(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
out = state.output
if prso is None:
out.tell("What do you want to drop?\n")
return True
if not prso.is_held_by(state.protagonist):
out.tell("You aren't carrying that.\n")
return True
prso.move_to(state.here)
out.tell("Dropped.\n")
return True
@verb_handler("inventory")
def v_inventory(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
out = state.output
if not state.protagonist or not state.protagonist.children:
out.tell("You are empty-handed.\n")
return True
out.tell("You have:\n")
if state.headache:
out.tell(" a splitting headache\n")
if state.holding_no_tea:
out.tell(" no tea\n")
for obj in state.protagonist.children:
desc = obj.a_desc()
if obj.fset_q(Flag.WORNBIT):
desc += " (being worn)"
out.tell(f" {desc}\n")
# Show contents of containers
if (obj.fset_q(Flag.CONTBIT) or obj.fset_q(Flag.SURFACEBIT)):
visible = obj.contents_string()
if visible and (obj.fset_q(Flag.OPENBIT) or obj.fset_q(Flag.TRANSBIT)):
out.tell(f" It looks like {obj.the_desc()} contains:\n")
for child in visible:
out.tell(f" {child.a_desc()}\n")
return True
@verb_handler("put on")
def v_wear(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
out = state.output
if prso is None:
out.tell("What do you want to wear?\n")
return True
if not prso.fset_q(Flag.WEARBIT):
out.tell(f"You can't wear {prso.the_desc()}.\n")
return True
if not prso.is_held_by(state.protagonist):
out.tell("You aren't carrying that.\n")
return True
prso.fset(Flag.WORNBIT)
prso.move_to(state.protagonist)
out.tell(f"You are now wearing {prso.the_desc()}.\n")
return True
@verb_handler("take off")
def v_take_off(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
out = state.output
if prso is None:
out.tell("What do you want to take off?\n")
return True
if not prso.fset_q(Flag.WORNBIT):
out.tell("You aren't wearing that.\n")
return True
prso.fclear(Flag.WORNBIT)
out.tell(f"You take off {prso.the_desc()}.\n")
return True
@verb_handler("open")
def v_open(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
out = state.output
if prso is None:
out.tell("What do you want to open?\n")
return True
if prso.fset_q(Flag.OPENBIT):
out.tell("It's already open.\n")
return True
if not prso.fset_q(Flag.CONTBIT) and not prso.fset_q(Flag.DOORBIT):
out.tell(f"You can't open {prso.the_desc()}.\n")
return True
prso.fset(Flag.OPENBIT)
out.tell("Opened.\n")
visible = prso.contents_string()
if visible:
for child in visible:
out.tell(f" {child.a_desc()}\n")
return True
@verb_handler("close")
def v_close(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
out = state.output
if prso is None:
out.tell("What do you want to close?\n")
return True
if not prso.fset_q(Flag.OPENBIT):
out.tell("It's already closed.\n")
return True
prso.fclear(Flag.OPENBIT)
out.tell("Closed.\n")
return True
@verb_handler("put")
def v_put(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
out = state.output
if prso is None or prsi is None:
out.tell("What do you want to put where?\n")
return True
if not prso.is_held_by(state.protagonist):
out.tell("You aren't carrying that.\n")
return True
if not prsi.fset_q(Flag.CONTBIT) and not prsi.fset_q(Flag.SURFACEBIT):
out.tell(f"You can't put things in {prsi.the_desc()}.\n")
return True
if not prsi.fset_q(Flag.OPENBIT) and prsi.fset_q(Flag.CONTBIT):
out.tell(f"{prsi.the_desc().capitalize()} isn't open.\n")
return True
prso.move_to(prsi)
out.tell("Done.\n")
return True
@verb_handler("look in")
def v_look_in(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
out = state.output
if prso is None:
out.tell("What do you want to look in?\n")
return True
if not prso.fset_q(Flag.CONTBIT) and not prso.fset_q(Flag.SURFACEBIT):
out.tell(f"You can't look inside {prso.the_desc()}.\n")
return True
if not prso.fset_q(Flag.OPENBIT) and not prso.fset_q(Flag.TRANSBIT):
out.tell(f"{prso.the_desc().capitalize()} is closed.\n")
return True
visible = prso.contents_string()
if visible:
for child in visible:
out.tell(f" {child.a_desc()}\n")
else:
out.tell(f"{prso.the_desc().capitalize()} is empty.\n")
return True
@verb_handler("look under")
def v_look_under(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell(f"There's nothing under {prso.the_desc() if prso else 'that'}.\n")
return True
@verb_handler("read")
def v_read(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
out = state.output
if prso is None:
out.tell("What do you want to read?\n")
return True
if prso.text:
out.tell(prso.text + "\n")
else:
out.tell(f"There's nothing written on {prso.the_desc()}.\n")
return True
@verb_handler("wait")
def v_wait(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("Time passes.\n")
return True
@verb_handler("turn on")
def v_turn_on(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
out = state.output
if prso is None:
# Default: turn on light in the room
out.tell("What do you want to turn on?\n")
return True
prso.fset(Flag.ONBIT)
out.tell(f"You turn on {prso.the_desc()}.\n")
state.update_lit()
return True
@verb_handler("turn off")
def v_turn_off(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
out = state.output
if prso is None:
out.tell("What do you want to turn off?\n")
return True
prso.fclear(Flag.ONBIT)
out.tell(f"You turn off {prso.the_desc()}.\n")
state.update_lit()
return True
@verb_handler("get out")
def v_get_out(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
# Getting out of bed, vehicle, etc.
# If prso is specified, delegate to its action handler
if prso and prso.action:
# Temporarily set the verb for the handler
old_prsa = state.prsa
state.prsa = "get out"
result = prso.action(state)
state.prsa = old_prsa
if result:
return True
# Check if protagonist is inside something (bed, vehicle)
if state.protagonist and state.protagonist.parent and state.protagonist.parent != state.here:
container = state.protagonist.parent
if container.action:
old_prsa = state.prsa
state.prsa = "get out"
result = container.action(state)
state.prsa = old_prsa
if result:
return True
# Default: move out of container
state.protagonist.move_to(state.here)
state.lying_down = False
state.output.tell("You get out.\n")
return True
state.output.tell("You're not in anything.\n")
return True
@verb_handler("get in")
def v_get_in(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("You get in.\n")
return True
@verb_handler("lie down")
def v_lie_down(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.lying_down = True
state.output.tell("You lie down.\n")
return True
@verb_handler("stand up")
def v_stand_up(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
if not state.lying_down:
state.output.tell("You're already standing.\n")
return True
state.lying_down = False
state.output.tell("You stand up.\n")
return True
@verb_handler("score")
def v_score(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
out = state.output
out.tell(f"Your score is {state.score} of a possible 400")
out.tell(f", in {state.moves} turn{'s' if state.moves != 1 else ''}.\n")
return True
@verb_handler("diagnose")
def v_diagnose(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
out = state.output
if state.headache:
out.tell("You have a big blinding throbber.\n")
elif state.groggy:
out.tell("You feel weak.\n")
else:
out.tell("You are in good health.\n")
return True
@verb_handler("verbose")
def v_verbose(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.verbosity = 2
state.output.tell("Maximum verbosity.\n")
# Re-describe room
state.prsa = "look"
return True
@verb_handler("brief")
def v_brief(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.verbosity = 1
state.output.tell("Brief descriptions.\n")
return True
@verb_handler("superbrief")
def v_superbrief(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.verbosity = 0
state.output.tell("Super-brief descriptions.\n")
return True
@verb_handler("quit")
def v_quit(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("Thanks for playing!\n")
state.running = False
return True
@verb_handler("eat")
def v_eat(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("That's not edible.\n")
return True
@verb_handler("drink")
def v_drink(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("You can't drink that.\n")
return True
@verb_handler("sleep")
def v_sleep(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("You don't feel sleepy.\n")
return True
@verb_handler("wake")
def v_wake(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("You are already awake.\n")
return True
@verb_handler("listen")
def v_listen(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("You hear nothing special.\n")
return True
@verb_handler("smell")
def v_smell(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("You smell nothing special.\n")
return True
@verb_handler("taste")
def v_taste(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("That doesn't taste like anything.\n")
return True
@verb_handler("touch")
def v_touch(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
if prso:
state.output.tell(f"You feel nothing unexpected about {prso.the_desc()}.\n")
else:
state.output.tell("You feel around in the dark.\n")
return True
@verb_handler("shout")
def v_shout(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("Shouting gets you nowhere.\n")
return True
@verb_handler("swim")
def v_swim(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("There's no water here.\n")
return True
@verb_handler("pray")
def v_pray(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("Nothing happens.\n")
return True
@verb_handler("attack")
def v_attack(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
if prso:
state.output.tell(f"Violence isn't the answer to this one.\n")
else:
state.output.tell("What do you want to attack?\n")
return True
@verb_handler("give")
def v_give(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("No one is interested.\n")
return True
@verb_handler("show")
def v_show(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("No one is interested.\n")
return True
@verb_handler("hang up")
def v_hang_up(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("You can't hang that up.\n")
return True
@verb_handler("answer")
def v_answer(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("Nobody asked you a question.\n")
return True
@verb_handler("call")
def v_call(state: GameState, prso: GameObject | None, prsi: GameObject | None) -> bool:
state.output.tell("There's no one to call.\n")
return True
+102
View File
@@ -0,0 +1,102 @@
"""World — object registry and containment tree management."""
from __future__ import annotations
from h2g2.engine.game_object import GameObject, Room, Flag
class World:
"""Registry of all game objects and rooms."""
def __init__(self) -> None:
self.objects: dict[str, GameObject] = {}
self.rooms: dict[str, Room] = {}
# Root containers (created during content registration)
self.global_objects: GameObject | None = None
self.local_globals: GameObject | None = None
self.protagonist: GameObject | None = None
def register(self, obj: GameObject) -> GameObject:
"""Add an object to the registry."""
self.objects[obj.id] = obj
if isinstance(obj, Room):
self.rooms[obj.id] = obj
return obj
def get(self, id: str) -> GameObject:
return self.objects[id]
def get_room(self, id: str) -> Room:
room = self.rooms.get(id)
if room is None:
raise KeyError(f"Room {id!r} not found")
return room
def visible_objects(self, here: Room, protagonist: GameObject) -> list[GameObject]:
"""Return all objects the player can currently see/interact with.
Search order matches ZIL: room contents, inventory, containers
with SEARCHBIT, local globals for the room, global objects.
"""
result: list[GameObject] = []
seen: set[int] = set()
def add(obj: GameObject) -> None:
if id(obj) not in seen:
seen.add(id(obj))
result.append(obj)
# 1. Room contents
for obj in here.children:
if Flag.INVISIBLE not in obj.flags:
add(obj)
# Search inside open/searchable containers
if obj.fset_q(Flag.SEARCHBIT) or obj.fset_q(Flag.OPENBIT):
for child in obj.children:
add(child)
# 2. Inventory
for obj in protagonist.children:
add(obj)
if obj.fset_q(Flag.SEARCHBIT) or obj.fset_q(Flag.OPENBIT):
for child in obj.children:
add(child)
# 3. Local globals for this room
for obj in here.global_objects:
add(obj)
# 4. Global objects
if self.global_objects:
for obj in self.global_objects.children:
if Flag.INVISIBLE not in obj.flags:
add(obj)
return result
def find_by_name(
self, name: str, adjective: str | None,
here: Room, protagonist: GameObject,
) -> list[GameObject]:
"""Find objects matching a noun (and optional adjective)."""
name = name.lower()
adj = adjective.lower() if adjective else None
candidates = self.visible_objects(here, protagonist)
matches = []
for obj in candidates:
if name in obj.synonyms or name == obj.id.lower():
if adj is None or adj in obj.adjectives:
matches.append(obj)
# Also check room pseudo-objects
for word, handler in here.pseudo:
if name == word.lower():
# Create a temporary pseudo-object
pseudo = GameObject(
f"pseudo_{word}", desc=word, action=handler,
)
matches.append(pseudo)
return matches
+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/env python3
"""The Hitchhiker's Guide to the Galaxy — Python text adventure engine."""
from h2g2.engine.game_object import Flag
from h2g2.engine.world import World
from h2g2.engine.state import GameState
from h2g2.engine.output import Output
from h2g2.engine.clock import Clock
from h2g2.engine.parser import Parser
from h2g2.engine.loop import GameLoop
# Import verb handlers (registers them via decorators)
import h2g2.engine.verbs # noqa: F401
# Import content modules
from h2g2.content import globals_content, earth
def main() -> None:
# Build the world
world = World()
globals_content.register(world)
earth.register(world)
# Initialize engine
output = Output()
clock = Clock()
state = GameState(world, output, clock)
# Set starting conditions
state.protagonist = world.protagonist
state.here = world.get_room("BEDROOM")
state.winner = world.protagonist
state.lying_down = True # start in bed
# Banner
output.tell(
"\n *** THE HITCHHIKER'S GUIDE TO THE GALAXY: "
"Interactive Science Fiction ***\n\n"
"Copyright (c) 1984 by Infocom, Inc. All Rights Reserved.\n"
"Python engine by Claude.\n\n"
)
# Opening text
output.tell(
"You wake up. The room is spinning very gently round your head. "
"Or at least it would be if you could see it which you can't.\n\n"
)
print(output.flush(), end="")
# Run the game loop
parser = Parser()
loop = GameLoop(state, parser)
loop.run()
if __name__ == "__main__":
main()
+1979
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -0,0 +1,6 @@
def main():
print("Hello from h2g2!")
if __name__ == "__main__":
main()
+611
View File
@@ -0,0 +1,611 @@
"MISC for
THE HITCHHIKER'S GUIDE TO THE GALAXY
(c) 1984 by Infocom, Inc. All Rights Reserved."
;"former MACROS.ZIL stuff"
<SETG C-ENABLED? 0>
<SETG C-ENABLED 1>
<SETG C-DISABLED 0>
;<ROUTINE ENABLED? (RTN "AUX" C E)
<SET E <REST ,C-TABLE ,C-TABLELEN>>
<SET C <REST ,C-TABLE ,C-INTS>>
<REPEAT ()
<COND (<==? .C .E> <RFALSE>)
(<EQUAL? <GET .C ,C-RTN> .RTN>
<COND (<0? <GET .C ,C-ENABLED?>>
<RFALSE>)
(T
<RTRUE>)>)>
<SET C <REST .C ,C-INTLEN>>>>
;<ROUTINE QUEUED? (RTN "AUX" C E)
<SET E <REST ,C-TABLE ,C-TABLELEN>>
<SET C <REST ,C-TABLE ,C-INTS>>
<REPEAT ()
<COND (<==? .C .E> <RFALSE>)
(<EQUAL? <GET .C ,C-RTN> .RTN>
<COND (<OR <0? <GET .C ,C-ENABLED?>>
<0? <GET .C ,C-TICK>>>
<RFALSE>)
(T <RTRUE>)>)>
<SET C <REST .C ,C-INTLEN>>>>
<ROUTINE RUNNING? (RTN "AUX" C E TICK)
<SET E <REST ,C-TABLE ,C-TABLELEN>>
<SET C <REST ,C-TABLE ,C-INTS>>
<REPEAT ()
<COND (<==? .C .E> <RFALSE>)
(<EQUAL? <GET .C ,C-RTN> .RTN>
<COND (<OR <0? <GET .C ,C-ENABLED?>>
<0? <SET TICK <GET .C ,C-TICK>>>
<G? .TICK 1>>
<RFALSE>)
(T <RTRUE>)>)>
<SET C <REST .C ,C-INTLEN>>>>
<DEFMAC TELL ("ARGS" A)
<FORM PROG ()
!<MAPF ,LIST
<FUNCTION ("AUX" E P O)
<COND (<EMPTY? .A> <MAPSTOP>)
(<SET E <NTH .A 1>>
<SET A <REST .A>>)>
<COND (<TYPE? .E ATOM>
<COND (<OR <=? <SET P <SPNAME .E>>
"CRLF">
<=? .P "CR">>
<MAPRET '<CRLF>>)
(<EMPTY? .A>
<ERROR INDICATOR-AT-END? .E>)
(ELSE
<SET O <NTH .A 1>>
<SET A <REST .A>>
<COND (<OR <=? <SET P <SPNAME .E>>
"DESC">
<=? .P "D">
<=? .P "OBJ">
<=? .P "O">>
<MAPRET <FORM PRINTD .O>>)
(<OR <=? .P "NUM">
<=? .P "N">>
<MAPRET <FORM PRINTN .O>>)
(<OR <=? .P "CHAR">
<=? .P "CHR">
<=? .P "C">>
<MAPRET <FORM PRINTC .O>>)
(ELSE
<MAPRET
<FORM PRINT
<FORM GETP .O .E>>>)>)>)
(<TYPE? .E STRING ZSTRING>
<MAPRET <FORM PRINTI .E>>)
(<TYPE? .E FORM LVAL GVAL>
<MAPRET <FORM PRINT .E>>)
(ELSE <ERROR UNKNOWN-TYPE .E>)>>>>>
<DEFMAC VERB? ("ARGS" ATMS)
<MULTIFROB PRSA .ATMS>>
<DEFMAC PRSO? ("ARGS" ATMS)
<MULTIFROB PRSO .ATMS>>
<DEFMAC PRSI? ("ARGS" ATMS)
<MULTIFROB PRSI .ATMS>>
<DEFMAC ROOM? ("ARGS" ATMS)
<MULTIFROB HERE .ATMS>>
<DEFINE MULTIFROB (X ATMS "AUX" (OO (OR)) (O .OO) (L ()) ATM)
<REPEAT ()
<COND (<EMPTY? .ATMS>
<RETURN!- <COND (<LENGTH? .OO 1> <ERROR .X>)
(<LENGTH? .OO 2> <NTH .OO 2>)
(ELSE <CHTYPE .OO FORM>)>>)>
<REPEAT ()
<COND (<EMPTY? .ATMS> <RETURN!->)>
<SET ATM <NTH .ATMS 1>>
<SET L
(<COND (<TYPE? .ATM ATOM>
<FORM GVAL
<COND (<==? .X PRSA>
<PARSE
<STRING "V?"
<SPNAME .ATM>>>)
(ELSE .ATM)>>)
(ELSE .ATM)>
!.L)>
<SET ATMS <REST .ATMS>>
<COND (<==? <LENGTH .L> 3> <RETURN!->)>>
<SET O <REST <PUTREST .O (<FORM EQUAL? <FORM GVAL .X> !.L>)>>>
<SET L ()>>>
<DEFMAC BSET ('OBJ "ARGS" BITS)
<MULTIBITS FSET .OBJ .BITS>>
<DEFMAC BCLEAR ('OBJ "ARGS" BITS)
<MULTIBITS FCLEAR .OBJ .BITS>>
<DEFMAC BSET? ('OBJ "ARGS" BITS)
<MULTIBITS FSET? .OBJ .BITS>>
<DEFINE MULTIBITS (X OBJ ATMS "AUX" (O ()) ATM)
<REPEAT ()
<COND (<EMPTY? .ATMS>
<RETURN!- <COND (<LENGTH? .O 1> <NTH .O 1>)
(<EQUAL? .X FSET?> <FORM OR !.O>)
(ELSE <FORM PROG () !.O>)>>)>
<SET ATM <NTH .ATMS 1>>
<SET ATMS <REST .ATMS>>
<SET O
(<FORM .X
.OBJ
<COND (<TYPE? .ATM FORM> .ATM)
(ELSE <FORM GVAL .ATM>)>>
!.O)>>>
<DEFMAC RFATAL ()
'<PROG () <PUSH 2> <RSTACK>>>
<DEFMAC PROB ('BASE?)
<FORM NOT <FORM L? .BASE? '<RANDOM 100>>>>
<ROUTINE PICK-ONE (FROB)
<GET .FROB <RANDOM <GET .FROB 0>>>>
<DEFMAC ENABLE ('INT)
<FORM PUT .INT ,C-ENABLED? 1>>
<DEFMAC DISABLE ('INT)
<FORM PUT .INT ,C-ENABLED? 0>>
;"former MAIN.ZIL stuff"
<GLOBAL PLAYER <>>
<GLOBAL P-WON <>>
<CONSTANT M-FATAL 2>
<CONSTANT M-BEG 1>
<CONSTANT M-END 6>
<CONSTANT M-ENTER 2>
<CONSTANT M-LOOK 3>
<CONSTANT M-FLASH 4>
<CONSTANT M-OBJDESC 5>
<ROUTINE GO ()
<PUTB ,P-LEXV 0 59>
;"put interrupts on clock chain"
<ENABLE <QUEUE I-HOUSEWRECK 20>>
<ENABLE <QUEUE I-THING 21>>
<ENABLE <QUEUE I-VOGONS 50>>
;"set up and go"
<SETG WINNER ,PROTAGONIST>
<SETG PLAYER ,PROTAGONIST>
<SETG HERE ,BEDROOM>
<SETG IDENTITY-FLAG ,ARTHUR>
<MOVE ,ARTHUR ,GLOBAL-OBJECTS>
<SETG LYING-DOWN T>
<MOVE ,PROTAGONIST ,BED>
<V-VERSION>
<CRLF>
<TELL
"You wake up. The room is spinning very gently round your head. Or at least
it would be if you could see it which you can't." CR CR>
<V-LOOK>
<MAIN-LOOP>
<AGAIN>>
<ROUTINE MAIN-LOOP ("AUX" ICNT OCNT NUM CNT OBJ TBL V PTBL OBJ1 TMP)
<REPEAT ()
<SET CNT 0>
<SET OBJ <>>
<SET PTBL T>
<COND (<SETG P-WON <PARSER>>
<SET ICNT <GET ,P-PRSI ,P-MATCHLEN>>
<SET OCNT <GET ,P-PRSO ,P-MATCHLEN>>
<COND (<AND ,P-IT-OBJECT <ACCESSIBLE? ,P-IT-OBJECT>>
<SET TMP <>>
<REPEAT ()
<COND (<G? <SET CNT <+ .CNT 1>> .ICNT>
<RETURN>)
(T
<COND (<EQUAL? <GET ,P-PRSI .CNT> ,IT>
<PUT ,P-PRSI .CNT ,P-IT-OBJECT>
<SET TMP T>
<RETURN>)>)>>
<COND (<NOT .TMP>
<SET CNT 0>
<REPEAT ()
<COND (<G? <SET CNT <+ .CNT 1>> .OCNT>
<RETURN>)
(T
<COND (<EQUAL? <GET ,P-PRSO .CNT> ,IT>
<PUT ,P-PRSO .CNT ,P-IT-OBJECT>
<RETURN>)>)>>)>
<SET CNT 0>)>
<SET NUM
<COND (<0? .OCNT> .OCNT)
(<G? .OCNT 1>
<SET TBL ,P-PRSO>
<COND (<0? .ICNT> <SET OBJ <>>)
(T <SET OBJ <GET ,P-PRSI 1>>)>
.OCNT)
(<G? .ICNT 1>
<SET PTBL <>>
<SET TBL ,P-PRSI>
<SET OBJ <GET ,P-PRSO 1>>
.ICNT)
(T 1)>>
<COND (<AND <NOT .OBJ>
<1? .ICNT>>
<SET OBJ <GET ,P-PRSI 1>>)>
<COND (<EQUAL? ,PRSA ,V?WALK> <SET V <PERFORM ,PRSA ,PRSO>>)
(<0? .NUM>
<COND (<0? <BAND <GETB ,P-SYNTAX ,P-SBITS> ,P-SONUMS>>
<SET V <PERFORM ,PRSA>>
<SETG PRSO <>>)
(<NOT ,LIT>
<TELL ,TOO-DARK CR>
<FUCKING-CLEAR>)
(T
<TELL "There isn't anything to ">
<SET TMP <GET ,P-ITBL ,P-VERBN>>
<COND (<VERB? TELL>
<TELL "talk to">)
(<OR ,P-OFLAG ,P-MERGED>
<PRINTB <GET .TMP 0>>)
(T
<WORD-PRINT <GETB .TMP 2>
<GETB .TMP 3>>)>
<TELL "!" CR>
<SET V <>>
<FUCKING-CLEAR>)>)
(T
<SETG P-NOT-HERE 0>
<SETG P-MULT <>>
<COND (<G? .NUM 1> <SETG P-MULT T>)>
<SET TMP <>>
<REPEAT ()
<COND (<G? <SET CNT <+ .CNT 1>> .NUM>
<COND (<G? ,P-NOT-HERE 0>
<TELL "The ">
<COND (<NOT <EQUAL? ,P-NOT-HERE .NUM>>
<TELL "other ">)>
<TELL "object">
<COND (<NOT <EQUAL? ,P-NOT-HERE 1>>
<TELL "s">)>
<TELL " that you mentioned ">
<COND (<NOT <EQUAL? ,P-NOT-HERE 1>>
<TELL "are">)
(T <TELL "is">)>
<TELL "n't here." CR>)
(<NOT .TMP>
<TELL ,REFERRING CR>)>
<RETURN>)
(T
<COND (.PTBL <SET OBJ1 <GET ,P-PRSO .CNT>>)
(T <SET OBJ1 <GET ,P-PRSI .CNT>>)>
<SETG PRSO <COND (.PTBL .OBJ1) (T .OBJ)>>
<SETG PRSI <COND (.PTBL .OBJ) (T .OBJ1)>>
<COND (<OR <G? .NUM 1>
<EQUAL? <GET <GET ,P-ITBL ,P-NC1>
0>
,W?ALL>>
<COND (<EQUAL? .OBJ1
,NOT-HERE-OBJECT>
<SETG P-NOT-HERE
<+ ,P-NOT-HERE 1>>
<AGAIN>)
(<AND <EQUAL? ,P-GETFLAGS
,P-ALL>
<VERB? TAKE PICK-UP>
<OR <AND <NOT <EQUAL?
<LOC .OBJ1>
,WINNER
,HERE
,PRSI>>
<NOT <FSET?
<LOC .OBJ1>
,SURFACEBIT>>>
<AND <NOT <FSET? .OBJ1
,TAKEBIT>>
<NOT <FSET? .OBJ1
,TRYTAKEBIT>>>>>
<AGAIN>)
(<AND <VERB? TAKE PICK-UP>
,PRSI
<NOT <IN? ,PRSO ,PRSI>>>
<AGAIN>)
(<AND <EQUAL? ,P-GETFLAGS
,P-ALL>
<VERB? DROP>
<NOT <IN? .OBJ1 ,WINNER>>
;"next frob semied by JW"
;<NOT <IN? ,P-IT-OBJECT
,WINNER>>>
<AGAIN>)
(<AND <EQUAL? ,P-GETFLAGS
,P-ALL>
,PRSI
<==? ,PRSO ,PRSI>>
<AGAIN>)
(<AND <EQUAL? ,P-GETFLAGS
,P-ALL>
<VERB? PUT>
<HELD? ,PRSO ,PRSI>>
<AGAIN>)
(<NOT <ACCESSIBLE? .OBJ1>>
<AGAIN>)
(T
<COND (<EQUAL? .OBJ1 ,IT>
<PRINTD ,P-IT-OBJECT>)
(<TEA-PRINT .OBJ1>
<PRINTD .OBJ1>)>
<COND (<TEA-PRINT .OBJ1>
<TELL ": ">)>)>)>
<SET TMP T>
<SET V <PERFORM ,PRSA ,PRSO ,PRSI>>
<COND (<EQUAL? .V ,M-FATAL> <RETURN>)>)>>)>
<COND (<NOT <EQUAL? .V ,M-FATAL>>
<COND (<VERB? TELL BRIEF SUPER-BRIEF VERBOSE
SAVE VERSION RESTORE SCRIPT UNSCRIPT>
T)
(T
<SET V <APPLY <GETP <LOC ,WINNER> ,P?ACTION>
,M-END>>)>)>
<COND (<VERB? AGAIN SAVE RESTORE SCRIPT UNSCRIPT
VERBOSE BRIEF SUPER-BRIEF>
T)
(,P-OFLAG T)
(T
<SETG L-PRSA ,PRSA>
<SETG L-PRSO ,PRSO>
<SETG L-PRSI ,PRSI>)>
<COND (,DONT-FLAG
<SETG L-DONT-FLAG T>)
(T
<SETG L-DONT-FLAG <>>)>
<COND (,IN-FRONT-FLAG
<SETG L-FRONT-FLAG T>)
(T
<SETG L-FRONT-FLAG <>>)>
<COND (<EQUAL? .V ,M-FATAL>
<SETG P-CONT <>>)>)
(T
<SETG P-CONT <>>)>
<COND (,P-WON
<COND (<VERB? TELL BRIEF SUPER-BRIEF VERBOSE VERSION QUIT SCORE
SAVE RESTORE SCRIPT UNSCRIPT FOOTNOTE HELP RESTART>
T)
(<AND <VERB? AGAIN>
<OR <EQUAL? ,L-PRSA ,V?FIND ,V?FOLLOW ,V?CALL>
<EQUAL? ,L-PRSA ,V?WHAT ,V?WHERE ,V?WAIT-FOR>
<EQUAL? ,L-PRSA ,V?WHO ,V?WALK-TO ,V?WHAT-ABOUT>
<EQUAL? ,L-PRSA ,V?ASK-ABOUT ,V?ASK-FOR ,V?I-AM>
<EQUAL? ,L-PRSA ,V?MY-NAME ,V?CARVE ,V?SCORE>
<EQUAL? ,L-PRSA ,V?VERSION ,V?FOOTNOTE ,V?HELP>>>
T)
(<AND <VERB? WAIT>
,DONT-FLAG>
T)
(<AND <VERB? AGAIN>
<EQUAL? ,L-PRSA ,V?WAIT>
,L-DONT-FLAG>
T)
(T
<SET V <CLOCKER>>)>
<SETG PRSA <>>
<SETG PRSO <>>
<SETG PRSI <>>)
(<AND <G? <GETB ,P-LEXV ,P-LEXWORDS> 3>
<NOT ,CARELESS-WORDS-FLAG>
,EARTH-DEMOLISHED
<SAVE-INPUT ,FIRST-BUFFER>>
<SETG CARELESS-WORDS-FLAG T>
<ENABLE <QUEUE I-CARELESS-WORDS 3>>)>>>
<GLOBAL FIRST-BUFFER <ITABLE BYTE 100>>
<ROUTINE SAVE-INPUT (TBL "AUX" (OFFS 0) CNT TMP)
<SET CNT <+ <GETB ,P-LEXV <SET TMP <* 4 ,P-INPUT-WORDS>>>
<GETB ,P-LEXV <+ .TMP 1>>>>
<COND (<EQUAL? .CNT 0> ;"failed"
<RFALSE>)>
<SET CNT <- .CNT 1>>
<REPEAT ()
<COND (<EQUAL? .OFFS .CNT>
<PUTB .TBL .OFFS 0>
<RETURN>)
(T
<PUTB .TBL .OFFS <GETB ,P-INBUF <+ .OFFS 1>>>)>
<SET OFFS <+ .OFFS 1>>>
<RTRUE>>
<ROUTINE RESTORE-INPUT (TBL "AUX" CHR)
<REPEAT ()
<COND (<EQUAL? <SET CHR <GETB .TBL 0>> 0>
<RETURN>)
(T
<PRINTC .CHR>
<SET TBL <REST .TBL>>)>>>
<GLOBAL L-PRSA <>>
<GLOBAL L-PRSO <>>
<GLOBAL L-PRSI <>>
<GLOBAL L-DONT-FLAG <>>
<GLOBAL L-FRONT-FLAG <>>
<GLOBAL P-MULT <>>
<GLOBAL P-NOT-HERE 0>
<ROUTINE FAKE-ORPHAN ("AUX" TMP)
<ORPHAN ,P-SYNTAX <>>
<TELL "Be specific: what object do">
<COND (,DONT-FLAG
<TELL "n't">)>
<TELL " you want to ">
<SET TMP <GET ,P-OTBL ,P-VERBN>>
<COND (<EQUAL? .TMP 0>
<TELL "tell">)
(<0? <GETB ,P-VTBL 2>>
<PRINTB <GET .TMP 0>>)
(T
<WORD-PRINT <GETB .TMP 2> <GETB .TMP 3>>
<PUTB ,P-VTBL 2 0>)>
<SETG P-OFLAG T>
<SETG P-WON <>>
<PREP-PRINT
<GETB ,P-SYNTAX ,P-SPREP1>>
<TELL "?" CR>>
<ROUTINE PERFORM (A "OPTIONAL" (O <>) (I <>) "AUX" V OA OO OI)
;<COND (,DEBUG
<TELL "[Perform: ">
%<COND (<GASSIGNED? PREDGEN> '<TELL N .A>)
(T '<PRINC <NTH ,ACTIONS <+ <* .A 2> 1>>>)>
<COND (<AND .O <NOT <EQUAL? .A ,V?WALK>>>
<TELL " / PRSO = " D .O>)>
<COND (.I <TELL " / PRSI = " D .I>)>
<TELL "]" CR>
<COND (,IN-FRONT-FLAG
<TELL "[IN-FRONT-FLAG is set]" CR>)>)>
<SET OA ,PRSA>
<SET OO ,PRSO>
<SET OI ,PRSI>
<SETG PRSA .A>
<COND (<EQUAL? ,IT .I .O>
<COND (<NOT .I>
<FAKE-ORPHAN>)
(T
<TELL ,REFERRING CR>)>
<RFATAL>)>
<SETG PRSO .O>
<COND (<AND ,PRSO
<NOT <VERB? WALK>>
<NOT <PRSO? ,NOT-HERE-OBJECT>>>
<SETG P-IT-OBJECT ,PRSO>)>
<SETG PRSI .I>
;<COND (<NOT <EQUAL? .A ,V?AGAIN>>
<SETG L-PRSA .A>
<COND (<EQUAL? .A ,V?WALK> <SETG L-PRSO <>>)
(T <SETG L-PRSO .O>)>
<SETG L-PRSI .I>)>
<COND (<AND <NOT <EQUAL? .A ,V?WALK>>
<EQUAL? ,NOT-HERE-OBJECT ,PRSO ,PRSI>
<SET V <D-APPLY "Not Here" ,NOT-HERE-OBJECT-F>>>
<SETG P-WON <>>
.V)
(T
<SET O ,PRSO>
<SET I ,PRSI>
<COND (<SET V <D-APPLY "Actor" <GETP ,WINNER ,P?ACTION>>>
.V)
(<AND ,DONT-FLAG <SET V <DONT-F>>>
.V)
(<SET V <D-APPLY "M-Beg" <GETP <LOC ,WINNER> ,P?ACTION>
,M-BEG>>
.V)
(<SET V <D-APPLY "Preaction" <GET ,PREACTIONS .A>>>
.V)
(<AND .I <SET V <D-APPLY "PRSI" <GETP .I ,P?ACTION>>>>
.V)
;(<AND .O
<NOT <EQUAL? .A ,V?WALK>>
<LOC .O>
<GETP <LOC .O> ,P?CONTFCN>
<SET V <D-APPLY "Cont" <GETP <LOC .O> ,P?CONTFCN>>>>
.V)
(<AND .O
<NOT <EQUAL? .A ,V?WALK>>
<SET V <D-APPLY "PRSO" <GETP .O ,P?ACTION>>>>
.V)
(<SET V <D-APPLY <> <GET ,ACTIONS .A>>>
.V)>)>
<SETG PRSA .OA>
<SETG PRSO .OO>
<SETG PRSI .OI>
.V>
<ROUTINE D-APPLY (STR FCN "OPTIONAL" (FOO <>) "AUX" RES)
<COND (<NOT .FCN> <>)
(T
;<COND (,DEBUG
<COND (<NOT .STR>
<TELL CR " Default ->" CR>)
(T <TELL CR " " .STR " -> ">)>)>
<SET RES
<COND (.FOO <APPLY .FCN .FOO>)
(T <APPLY .FCN>)>>
;<COND (<AND ,DEBUG .STR>
<COND (<EQUAL? .RES ,M-FATAL>
<TELL "Fatal" CR>)
(<NOT .RES>
<TELL "Not handled">)
(T <TELL "Handled" CR>)>)>
.RES)>>
;"former CLOCK.ZIL stuff"
<GLOBAL CLOCK-WAIT <>>
<GLOBAL C-TABLE %<COND (<GASSIGNED? PREDGEN>
'<ITABLE NONE 105>)
(T
'<ITABLE NONE 210>)>>
<CONSTANT C-TABLELEN 210>
<GLOBAL C-INTS 210>
<CONSTANT C-INTLEN 6>
<CONSTANT C-ENABLED? 0>
<CONSTANT C-TICK 1>
<CONSTANT C-RTN 2>
<ROUTINE QUEUE (RTN TICK "AUX" CINT)
<PUT <SET CINT <INT .RTN>> ,C-TICK .TICK>
.CINT>
<ROUTINE INT (RTN "OPTIONAL" E C INT)
<SET E <REST ,C-TABLE ,C-TABLELEN>>
<SET C <REST ,C-TABLE ,C-INTS>>
<REPEAT ()
<COND (<EQUAL? .C .E>
<SETG C-INTS <- ,C-INTS ,C-INTLEN>>
<SET INT <REST ,C-TABLE ,C-INTS>>
<PUT .INT ,C-RTN .RTN>
<RETURN .INT>)
(<EQUAL? <GET .C ,C-RTN> .RTN> <RETURN .C>)>
<SET C <REST .C ,C-INTLEN>>>>
<ROUTINE CLOCKER ("AUX" C E TICK (FLG <>))
<COND (,CLOCK-WAIT <SETG CLOCK-WAIT <>> <RFALSE>)>
<SET C <REST ,C-TABLE <COND (,P-WON ,C-INTS)>>>
<SET E <REST ,C-TABLE ,C-TABLELEN>>
<REPEAT ()
<COND (<EQUAL? .C .E>
<SETG MOVES <+ ,MOVES 1>>
<RETURN .FLG>)
(<NOT <0? <GET .C ,C-ENABLED?>>>
<SET TICK <GET .C ,C-TICK>>
<COND (<0? .TICK>)
(T
<PUT .C ,C-TICK <- .TICK 1>>
<COND (<AND <NOT <G? .TICK 1>>
<APPLY <GET .C ,C-RTN>>>
<SET FLG T>)>)>)>
<SET C <REST .C ,C-INTLEN>>>>
+1393
View File
File diff suppressed because it is too large Load Diff
+7
View File
@@ -0,0 +1,7 @@
[project]
name = "h2g2"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.14"
dependencies = []
+24
View File
@@ -0,0 +1,24 @@
Assembling S4.XZAP.1 on Thursday, October 2, 1986 22:03:54
Release: 60
64 Inserting S4FREQ.XZAP.2 (634 bytes)
698 Inserting S4DAT.ZAP.1 (19961 bytes)
20659 Inserting MISC.ZAP.1 (1826 bytes)
22485 Inserting PARSER.ZAP.1 (6083 bytes)
28568 Inserting SYNTAX.ZAP.1 (0 bytes)
28568 Inserting VERBS.ZAP.1 (15191 bytes)
43759 Inserting GLOBALS.ZAP.1 (14345 bytes)
58104 Inserting EARTH.ZAP.1 (19174 bytes)
77278 Inserting VOGON.ZAP.1 (5744 bytes)
83022 Inserting UNEARTH.ZAP.1 (9740 bytes)
92762 Inserting HEART.ZAP.1 (13513 bytes)
106275 Inserting S4STR.ZAP.1 (7055 bytes)
220 objects.
239 globals.
971 word vocabulary.
113330 bytes (111K).
20453 bytes of preload.
9736 bytes of impure.
Outputting symbol tables
+36
View File
@@ -0,0 +1,36 @@
.INSERT "S4FREQ"
.INSERT "S4DAT" ; DATA IS IN THIS FILE
.INSERT "MISC"
.INSERT "PARSER"
.INSERT "SYNTAX"
.INSERT "VERBS"
.INSERT "GLOBALS"
.INSERT "EARTH"
.INSERT "VOGON"
.INSERT "UNEARTH"
.INSERT "HEART"
.INSERT "S4STR"
.END
+28
View File
@@ -0,0 +1,28 @@
"S4 for
THE HITCHHIKER'S GUIDE TO THE GALAXY
(c) Copyright 1984 Infocom, Inc. All Rights Reserved."
<PRINC "
*** THE HITCHHIKER'S GUIDE TO THE GALAXY: Interactive Science Fiction ***
">
<SNAME "S4">
<SET REDEFINE T>
;<OR <GASSIGNED? INSERT-CRUFTY>
<DEFINE INSERT-CRUFTY (STR) <INSERT-FILE .STR T>>>
<INSERT-FILE "MISC" T>
<INSERT-FILE "HEART" T>
<INSERT-FILE "PARSER" T>
<INSERT-FILE "SYNTAX" T>
<INSERT-FILE "VERBS" T>
<INSERT-FILE "EARTH" T>
<INSERT-FILE "VOGON" T>
<INSERT-FILE "UNEARTH" T>
<INSERT-FILE "GLOBALS" T>
<PROPDEF SIZE 5>
<PROPDEF CAPACITY 0>
+200
View File
@@ -0,0 +1,200 @@
.FSTR FSTR?1,"the " ;1664 832
.FSTR FSTR?2,", " ;842 842
.FSTR FSTR?3,"You " ;810 270
.FSTR FSTR?4,"you " ;736 368
.FSTR FSTR?5,"and " ;736 368
.FSTR FSTR?6,"The " ;702 234
.FSTR FSTR?7,". " ;529 529
.FSTR FSTR?8,"your " ;513 171
.FSTR FSTR?9,"that " ;459 153
.FSTR FSTR?10,"of " ;406 406
.FSTR FSTR?11,"is " ;370 370
.FSTR FSTR?12,"to " ;368 368
.FSTR FSTR?13,"can't " ;350 70
.FSTR FSTR?14,"with " ;303 101
.FSTR FSTR?15,"have " ;246 82
.FSTR FSTR?16,"are " ;240 120
.FSTR FSTR?17,"from " ;237 79
.FSTR FSTR?18,"about " ;212 53
.FSTR FSTR?19,"in " ;209 209
.FSTR FSTR?20,"for " ;202 101
.FSTR FSTR?21,"There " ;190 38
.FSTR FSTR?22,"which " ;188 47
.FSTR FSTR?23,"already " ;180 30
.FSTR FSTR?24,"this " ;177 59
.FSTR FSTR?25,"something " ;168 21
.FSTR FSTR?26,"It " ;166 83
.FSTR FSTR?27,"through " ;162 27
.FSTR FSTR?28,"This " ;156 39
.FSTR FSTR?29,"nothing " ;150 25
.FSTR FSTR?30,"Prosser " ;147 21
.FSTR FSTR?31,"It's " ;145 29
.FSTR FSTR?32,"Ford " ;144 36
.FSTR FSTR?33,"don't " ;140 28
.FSTR FSTR?34,"Arthur " ;138 23
.FSTR FSTR?35,"There's " ;136 17
.FSTR FSTR?36,"around " ;135 27
.FSTR FSTR?37,"You're " ;133 19
.FSTR FSTR?38,"Beast " ;130 26
.FSTR FSTR?39,"into " ;126 42
.FSTR FSTR?40,"like " ;120 40
.FSTR FSTR?41,"it " ;113 113
.FSTR FSTR?42,"doesn't " ;112 16
.FSTR FSTR?43,"Footnote " ;112 14
.FSTR FSTR?44,"but " ;108 54
.FSTR FSTR?45,"you're " ;108 18
.FSTR FSTR?46,"small " ;104 26
.FSTR FSTR?47,"on " ;102 102
.FSTR FSTR?48,"will " ;102 34
.FSTR FSTR?49,"just " ;102 34
.FSTR FSTR?50,"because " ;102 17
.FSTR FSTR?51,"see " ;96 48
.FSTR FSTR?52,"has " ;96 48
.FSTR FSTR?53,"not " ;94 47
.FSTR FSTR?54,"seems " ;92 23
.FSTR FSTR?55,"it's " ;92 23
.FSTR FSTR?56,"Improbability " ;91 7
.FSTR FSTR?57,"toward " ;90 18
.FSTR FSTR?58,"you've " ;90 15
.FSTR FSTR?59,"what " ;87 29
.FSTR FSTR?60,"says " ;87 29
.FSTR FSTR?61,"at " ;86 86
.FSTR FSTR?62,"here" ;84 42
.FSTR FSTR?63,"very " ;84 28
.FSTR FSTR?64,"looks " ;84 21
.FSTR FSTR?65,"probably " ;84 12
.FSTR FSTR?66,"you" ;83 83
.FSTR FSTR?67,"can " ;82 41
.FSTR FSTR?68,"all " ;80 40
.FSTR FSTR?69,"out " ;78 39
.FSTR FSTR?70,"anything " ;77 11
.FSTR FSTR?71,"think " ;76 19
.FSTR FSTR?72,"closed" ;76 19
.FSTR FSTR?73,"isn't " ;75 15
.FSTR FSTR?74,"his " ;74 37
.FSTR FSTR?75,"I " ;72 72
.FSTR FSTR?76,"down " ;72 24
.FSTR FSTR?77,"would " ;72 18
.FSTR FSTR?78,"their " ;72 18
.FSTR FSTR?79,"large " ;72 18
.FSTR FSTR?80,"front " ;72 18
.FSTR FSTR?81,"I'm " ;72 18
.FSTR FSTR?82,"Unfortunately" ;72 6
.FSTR FSTR?83,"be " ;70 70
.FSTR FSTR?84,"little " ;70 14
.FSTR FSTR?85,"Arthur" ;70 14
.FSTR FSTR?86,"even " ;69 23
.FSTR FSTR?87,"He " ;66 33
.FSTR FSTR?88,"some " ;66 22
.FSTR FSTR?89,"Ford" ;66 22
.FSTR FSTR?90,"holding " ;66 11
.FSTR FSTR?91,"between " ;66 11
.FSTR FSTR?92,"anything" ;66 11
.FSTR FSTR?93,"across " ;65 13
.FSTR FSTR?94,"going " ;64 16
.FSTR FSTR?95,"currently " ;64 8
.FSTR FSTR?96,"something" ;63 9
;word frequency table of 96 most common words
WORDS:: .TABLE
FSTR?1
FSTR?2
FSTR?3
FSTR?4
FSTR?5
FSTR?6
FSTR?7
FSTR?8
FSTR?9
FSTR?10
FSTR?11
FSTR?12
FSTR?13
FSTR?14
FSTR?15
FSTR?16
FSTR?17
FSTR?18
FSTR?19
FSTR?20
FSTR?21
FSTR?22
FSTR?23
FSTR?24
FSTR?25
FSTR?26
FSTR?27
FSTR?28
FSTR?29
FSTR?30
FSTR?31
FSTR?32
FSTR?33
FSTR?34
FSTR?35
FSTR?36
FSTR?37
FSTR?38
FSTR?39
FSTR?40
FSTR?41
FSTR?42
FSTR?43
FSTR?44
FSTR?45
FSTR?46
FSTR?47
FSTR?48
FSTR?49
FSTR?50
FSTR?51
FSTR?52
FSTR?53
FSTR?54
FSTR?55
FSTR?56
FSTR?57
FSTR?58
FSTR?59
FSTR?60
FSTR?61
FSTR?62
FSTR?63
FSTR?64
FSTR?65
FSTR?66
FSTR?67
FSTR?68
FSTR?69
FSTR?70
FSTR?71
FSTR?72
FSTR?73
FSTR?74
FSTR?75
FSTR?76
FSTR?77
FSTR?78
FSTR?79
FSTR?80
FSTR?81
FSTR?82
FSTR?83
FSTR?84
FSTR?85
FSTR?86
FSTR?87
FSTR?88
FSTR?89
FSTR?90
FSTR?91
FSTR?92
FSTR?93
FSTR?94
FSTR?95
FSTR?96
.ENDT
.ENDI
+622
View File
@@ -0,0 +1,622 @@
"SYNTAX for
THE HITCHHIKER'S GUIDE TO THE GALAXY
(c) Copyright 1984 Infocom, Inc. All Rights Reserved."
<BUZZ A AN THE IS ARE AM AND OF THEN ALL BUT EXCEPT \. \, \"
DON\'T DONT PRY PLEASE HERE SOME MORE FRONT>
<SYNONYM TO TOWARD>
<SYNONYM WITH USING>
<SYNONYM THROUGH THRU>
<SYNONYM ON ONTO>
<SYNONYM OUT OUTSIDE>
<SYNONYM IN INSIDE INTO>
<SYNONYM UNDER BELOW BENEATH UNDERNEATH>
<SYNONYM AROUND ALONG>
<SYNONYM BEFORE NEAR NEXT AGAINST>
<SYNONYM ALL BOTH>
<SYNONYM DRUNK BOMBED SMASHE PLASTE>
<SYNONYM NORTH N FORE F FOREWA>
<SYNONYM SOUTH S AFT>
<SYNONYM EAST E STARBO SB>
<SYNONYM WEST W PORT P>
<SYNONYM DOWN D>
<SYNONYM UP U>
<SYNONYM NW NORTHWEST>
<SYNONYM NE NORTHE>
<SYNONYM SW SOUTHWEST>
<SYNONYM SE SOUTHE>
;"game commands"
<SYNTAX VERBOSE = V-VERBOSE>
<SYNTAX BRIEF = V-BRIEF>
<SYNTAX SUPER = V-SUPER-BRIEF>
<SYNONYM SUPER SUPERBRIEF>
<SYNTAX DIAGNOSE = V-DIAGNOSE>
<SYNTAX INVENT = V-INVENTORY>
<SYNTAX I = V-INVENTORY>
<SYNTAX I OBJECT = V-I-AM>
<SYNONYM I I\'M IM>
<SYNTAX QUIT = V-QUIT>
<SYNONYM QUIT Q>
<SYNTAX RESTAR = V-RESTART>
<SYNTAX RESTOR = V-RESTORE>
<SYNTAX SAVE = V-SAVE>
<SYNTAX SCORE = V-SCORE>
<SYNTAX SCRIPT = V-SCRIPT>
<SYNTAX UNSCRIPT = V-UNSCRIPT>
<SYNTAX VERSION = V-VERSION>
<SYNTAX $VERIFY = V-$VERIFY>
<SYNTAX $VERIFY OBJECT = V-$VERIFY>
;<SYNTAX $DEBUG = V-$DEBUG>
;<SYNTAX $CHEAT OBJECT = V-$CHEAT>
;<SYNTAX $PROB = V-$PROB>
;"subtitle real verbs"
<SYNTAX ADDRES OBJECT (FIND ACTORBIT) (IN-ROOM) = V-TELL>
<SYNTAX AGAIN = V-AGAIN>
<SYNONYM AGAIN G>
<SYNTAX ANSWER = V-ANSWER>
<SYNTAX ANSWER OBJECT = V-REPLY>
<SYNTAX ANSWER TO OBJECT = V-REPLY>
<SYNONYM ANSWER REPLY>
<SYNTAX APPLAU = V-APPLAUD>
<SYNONYM APPLAU CLAP CHEER>
<SYNTAX APPREC OBJECT = V-APPRECIATE>
<SYNTAX APPROA OBJECT = V-WALK-TO>
<SYNTAX ASK OBJECT (FIND ACTORBIT) ABOUT OBJECT = V-ASK-ABOUT>
<SYNTAX ASK OBJECT (FIND ACTORBIT) ON OBJECT = V-ASK-ABOUT>
<SYNTAX ASK OBJECT (FIND ACTORBIT) FOR OBJECT = V-ASK-FOR>
<SYNONYM ASK CONSUL QUERY>
<SYNTAX ATTACK OBJECT (FIND ACTORBIT) (ON-GROUND IN-ROOM) = V-KILL>
<SYNTAX ATTACK OBJECT (FIND ACTORBIT) (ON-GROUND IN-ROOM)
WITH OBJECT (HELD CARRIED HAVE) = V-KILL>
<SYNONYM ATTACK ASSAULT FIGHT HIT SLAP KILL MURDER STRIKE PUNCH>
<SYNTAX BITE OBJECT = V-BITE>
<SYNTAX BLOCK OBJECT = V-BLOCK>
<SYNTAX BLOCK OBJECT WITH OBJECT = V-BLOCK-WITH>
<SYNONYM BLOCK STOP>
<SYNTAX BOARD OBJECT (FIND VEHBIT) (ON-GROUND IN-ROOM) = V-BOARD PRE-BOARD>
<SYNONYM BOARD EMBARK>
<SYNTAX BRUSH OBJECT = V-BRUSH>
<SYNTAX BRUSH OBJECT WITH OBJECT (HAVE) = V-BRUSH>
<SYNONYM BRUSH>
<SYNTAX ORDER OBJECT = V-BUY>
<SYNONYM ORDER BUY PURCHASE>
<SYNTAX CARVE OBJECT ON OBJECT = V-CARVE PRE-CARVE>
<SYNTAX CARVE OBJECT IN OBJECT = V-CARVE PRE-CARVE>
<SYNTAX CARVE OBJECT WITH OBJECT (HAVE) = V-CARVE-WITH>
<SYNONYM CARVE INSCRI SCRATC WRITE>
<SYNTAX CLIMB OBJECT (ON-GROUND IN-ROOM) = V-CLIMB-FOO>
<SYNTAX CLIMB ON OBJECT (FIND VEHBIT) (ON-GROUND IN-ROOM) = V-CLIMB-ON>
<SYNTAX CLIMB UP OBJECT (FIND RLANDBIT) (ON-GROUND IN-ROOM) = V-CLIMB-UP>
<SYNTAX CLIMB DOWN OBJECT (FIND RLANDBIT) (ON-GROUND IN-ROOM) = V-CLIMB-DOWN>
<SYNTAX CLIMB OVER OBJECT (ON-GROUND IN-ROOM) = V-CLIMB-OVER>
<SYNTAX CLIMB IN OBJECT (FIND VEHBIT) (ON-GROUND IN-ROOM) = V-BOARD PRE-BOARD>
<SYNTAX CLIMB THROUGH OBJECT = V-THROUGH>
<SYNONYM CLIMB SCALE>
<SYNTAX CLOSE OBJECT (FIND DOORBIT) (HELD CARRIED ON-GROUND IN-ROOM) = V-CLOSE>
<SYNTAX CLOSE OFF OBJECT (FIND LIGHTBIT) (HELD CARRIED ON-GROUND IN-ROOM TAKE)
= V-LAMP-OFF>
<SYNONYM CLOSE SHUT>
<SYNTAX CONNECT OBJECT TO OBJECT = V-PLUG>
<SYNTAX COVER OBJECT WITH OBJECT (HELD MANY) = V-SPUT-ON>
<SYNTAX COUNT OBJECT = V-COUNT>
<SYNTAX CUT OBJECT WITH OBJECT (CARRIED HELD) = V-CUT>
<SYNTAX CUT THROUGH OBJECT WITH OBJECT (CARRIED HELD) = V-CUT>
<SYNONYM CUT SLICE>
<SYNTAX DEMOLI OBJECT (ON-GROUND IN-ROOM) = V-MUNG>
<SYNTAX DEMOLI OBJECT WITH OBJECT (HELD CARRIED TAKE) = V-MUNG>
<SYNTAX DEMOLI DOWN OBJECT = V-KILL>
<SYNONYM DEMOLI CRACK DESTRO DAMAGE BREAK SMASH WRECK>
<SYNTAX DANGLE OBJECT (HELD MANY) IN OBJECT = V-PUT PRE-PUT>
<SYNTAX DESCEN OBJECT (ON-GROUND IN-ROOM) = V-CLIMB-DOWN>
<SYNTAX DIG IN OBJECT = V-DIG>
<SYNTAX DIG WITH OBJECT = V-DIG>
<SYNTAX DIG THROUGH OBJECT = V-DIG>
<SYNTAX DISEMBARK OBJECT (FIND VEHBIT) (ON-GROUND IN-ROOM) = V-DISEMBARK>
<SYNONYM DISEMBARK DEBARK>
<SYNTAX DISROBE = V-GET-UNDRESSED>
<SYNTAX DOZE = V-DOZE>
<SYNONYM DOZE NAP SNOOZE>
<SYNTAX DRINK OBJECT (FIND DRINKBIT) (HELD CARRIED ON-GROUND IN-ROOM)
= V-DRINK>
<SYNTAX DRINK FROM OBJECT (HELD CARRIED) = V-DRINK-FROM>
<SYNONYM DRINK SIP SWALLOW IMBIBE QUAFF GUZZLE SWILL>
<SYNTAX DROP OBJECT (HELD MANY HAVE) = V-DROP PRE-DROP>
<SYNTAX DROP OBJECT (HELD MANY) BEFORE OBJECT = V-PUT-IN-FRONT PRE-GIVE>
<SYNTAX DROP OBJECT (HELD MANY) DOWN OBJECT = V-PUT PRE-PUT>
<SYNTAX DROP OBJECT (HELD MANY) IN OBJECT = V-PUT PRE-PUT>
<SYNTAX DROP OBJECT (HELD MANY) ON OBJECT = V-PUT-ON PRE-PUT>
<SYNTAX EAT OBJECT (FIND EATBIT) (HELD CARRIED ON-GROUND IN-ROOM) = V-EAT>
<SYNONYM EAT DEVOUR INGEST GOBBLE>
<SYNTAX ENJOY OBJECT = V-ENJOY>
<SYNTAX ENTER = V-ENTER>
<SYNTAX ENTER OBJECT = V-THROUGH>
<SYNTAX EXIT = V-EXIT>
<SYNTAX EXIT OBJECT = V-EXIT>
<SYNONYM EXIT DEPART WITHDR>
<SYNTAX ESCAPE = V-ESCAPE>
<SYNTAX ESCAPE OBJECT = V-ESCAPE>
<SYNTAX ESCAPE FROM OBJECT = V-ESCAPE>
<SYNONYM ESCAPE FLEE>
<SYNTAX EXAMINE OBJECT (HELD CARRIED ON-GROUND IN-ROOM) (FIND DARKBIT)
= V-EXAMINE PRE-READ>
<SYNTAX EXAMINE OBJECT THROUGH OBJECT = V-EXAMINE-THROUGH PRE-READ>
<SYNTAX EXAMINE IN OBJECT (HELD CARRIED IN-ROOM ON-GROUND)
= V-LOOK-INSIDE>
<SYNTAX EXAMINE ON OBJECT (HELD CARRIED IN-ROOM ON-GROUND)
= V-LOOK-INSIDE>
<SYNTAX EXAMINE FOR OBJECT = V-FIND>
<SYNONYM EXAMINE INSPECT DESCRIBE STUDY OBSERVE SEE SCOUR>
<SYNTAX EXTINGUISH OBJECT (FIND ONBIT) = V-LAMP-OFF>
<SYNTAX FEED OBJECT (FIND ACTORBIT) = V-FEED>
<SYNTAX FEED OBJECT (MANY HELD HAVE) TO OBJECT (FIND ACTORBIT) (ON-GROUND)
= V-GIVE PRE-GIVE>
<SYNTAX FEED OBJECT (FIND ACTORBIT) (ON-GROUND) OBJECT (MANY HELD HAVE)
= V-SGIVE>
<SYNTAX FILL OBJECT = V-FILL>
<SYNTAX FIND OBJECT = V-FIND>
<SYNONYM FIND SEEK>
<SYNTAX FOLLOW OBJECT = V-FOLLOW>
<SYNONYM FOLLOW PURSUE CHASE>
<SYNTAX FOOTNOTE = V-FOOTNOTE>
<SYNTAX FOOTNOTE OBJECT = V-FOOTNOTE>
<SYNTAX FRIPPI = V-FRIPPI>
<SYNONYM FRIPPI LYSHUS GASHEE MORPHO THOU BLEEM MISERA VENCHI WIMBGU>
<SYNTAX HAND OBJECT (MANY HELD HAVE) TO OBJECT (FIND ACTORBIT) (ON-GROUND)
= V-GIVE PRE-GIVE>
<SYNTAX HAND OBJECT (FIND ACTORBIT) (ON-GROUND) OBJECT (MANY HELD HAVE)
= V-SGIVE>
<SYNTAX HAND UP OBJECT (FIND RLANDBIT) = V-GIVE-UP>
<SYNONYM HAND GIVE SELL DONATE OFFER>
<SYNTAX HANG OBJECT ON OBJECT = V-HANG>
<SYNTAX HANG OBJECT FROM OBJECT = V-HANG>
<SYNTAX HANG OBJECT (HELD MANY) IN OBJECT = V-PUT PRE-PUT>
<SYNTAX HEAR OBJECT (FIND DARKBIT) = V-LISTEN>
<SYNTAX HELLO = V-HELLO>
<SYNTAX HELLO OBJECT = V-HELLO>
<SYNONYM HELLO HI>
<SYNTAX HELP = V-HELP>
<SYNTAX HELP OBJECT = V-SAVE-SOMETHING>
<SYNONYM HELP HINT HINTS>
<SYNTAX HIDE = V-HIDE>
<SYNTAX HIDE UNDER OBJECT = V-HIDE>
<SYNTAX HIDE BEHIND OBJECT = V-HIDE>
<SYNTAX HITCHH = V-HITCHHIKE>
<SYNONYM HITCHH HITCH>
<SYNTAX IDIOT = V-IDIOT>
<SYNONYM IDIOT>
<SYNTAX JUMP = V-LEAP>
<SYNTAX JUMP OVER OBJECT = V-LEAP>
<SYNTAX JUMP ACROSS OBJECT = V-LEAP>
<SYNTAX JUMP IN OBJECT = V-THROUGH>
<SYNTAX JUMP FROM OBJECT = V-LEAP>
<SYNTAX JUMP OFF OBJECT = V-LEAP>
<SYNTAX JUMP OUT OBJECT = V-THROUGH>
<SYNTAX JUMP THROUGH OBJECT = V-THROUGH>
<SYNONYM JUMP LEAP DIVE>
<SYNTAX KICK OBJECT = V-KICK>
<SYNTAX KISS OBJECT (FIND ACTORBIT) (ON-GROUND IN-ROOM) = V-KISS>
<SYNTAX KNEEL = V-KNEEL>
<SYNONYM KNEEL CRAWL PEEK>
<SYNTAX KNOCK AT OBJECT = V-KNOCK>
<SYNTAX KNOCK ON OBJECT = V-KNOCK>
<SYNTAX KNOCK DOWN OBJECT (FIND ACTORBIT) (ON-GROUND IN-ROOM) = V-KILL>
<SYNONYM KNOCK RAP>
<SYNTAX LEAVE = V-LEAVE>
<SYNTAX LEAVE OBJECT = V-LEAVE>
<SYNTAX LIE ON OBJECT (FIND VEHBIT) = V-LIE-DOWN>
<SYNTAX LIE IN OBJECT (FIND VEHBIT) = V-LIE-DOWN>
<SYNTAX LIE DOWN OBJECT (FIND RLANDBIT) = V-LIE-DOWN>
<SYNTAX LIE BEFORE OBJECT = V-BLOCK>
<SYNONYM LIE RECLIN>
<SYNTAX LIGHT OBJECT (FIND LIGHTBIT) (HELD CARRIED ON-GROUND IN-ROOM)
= V-LAMP-ON>
<SYNTAX LISTEN TO OBJECT (FIND DARKBIT) = V-LISTEN>
<SYNTAX LOCK OBJECT (ON-GROUND IN-ROOM) = V-LOCK>
<SYNTAX LOCK OBJECT (ON-GROUND IN-ROOM) WITH OBJECT (TAKE) = V-LOCK>
<SYNTAX LOOK = V-LOOK>
<SYNTAX LOOK AROUND OBJECT (FIND RLANDBIT) = V-LOOK>
<SYNTAX LOOK DOWN OBJECT (FIND RLANDBIT) = V-LOOK-DOWN>
<SYNTAX LOOK UP OBJECT (FIND RLANDBIT) = V-LOOK-UP>
<SYNTAX LOOK AT OBJECT (HELD CARRIED ON-GROUND IN-ROOM) (FIND DARKBIT)
= V-EXAMINE PRE-READ>
<SYNTAX LOOK AT OBJECT THROUGH OBJECT = V-EXAMINE-THROUGH PRE-READ>
<SYNTAX LOOK THROUGH OBJECT = V-LOOK-INSIDE>
<SYNTAX LOOK OUT OBJECT = V-LOOK-INSIDE>
<SYNTAX LOOK UNDER OBJECT = V-LOOK-UNDER PRE-READ>
<SYNTAX LOOK BEHIND OBJECT = V-LOOK-BEHIND PRE-READ>
<SYNTAX LOOK IN OBJECT (HELD CARRIED ON-GROUND IN-ROOM) = V-LOOK-INSIDE>
<SYNTAX LOOK ON OBJECT = V-EXAMINE PRE-READ>
<SYNTAX LOOK FOR OBJECT = V-FIND>
<SYNTAX LOOK OBJECT = V-CHASTISE>
<SYNONYM LOOK L STARE GAZE>
<SYNTAX LOWER OBJECT = V-LOWER>
<SYNTAX MAKE OBJECT = V-MAKE>
<SYNTAX MOVE OBJECT (ON-GROUND IN-ROOM) = V-MOVE>
<SYNTAX MOVE OBJECT OBJECT = V-FLIPSWITCH>
<SYNTAX MOVE TOGETHER OBJECT = V-PULL-TOGETHER> ;"pull myself together"
<SYNONYM MOVE PULL>
<SYNTAX MY OBJECT OBJECT = V-MY-NAME>
<SYNTAX NO = V-NO>
<SYNTAX OPEN OBJECT (FIND DOORBIT) (HELD CARRIED ON-GROUND IN-ROOM) = V-OPEN>
<SYNTAX OPEN UP OBJECT (FIND DOORBIT) (HELD CARRIED ON-GROUND IN-ROOM)
= V-OPEN>
<SYNTAX OPEN OBJECT (FIND DOORBIT) (HELD CARRIED ON-GROUND IN-ROOM)
WITH OBJECT (ON-GROUND IN-ROOM HELD CARRIED HAVE) = V-OPEN>
<SYNONYM OPEN PART DRAW>
<SYNTAX PANIC = V-PANIC>
<SYNTAX PAY FOR OBJECT = V-BUY>
<SYNTAX PHONE OBJECT = V-CALL>
<SYNTAX PHONE OBJECT WITH OBJECT = V-CALL-WITH>
<SYNTAX PHONE OBJECT ON OBJECT = V-CALL-WITH>
<SYNONYM PHONE CALL>
<SYNTAX PICK OBJECT = V-PICK>
<SYNTAX PICK OBJECT WITH OBJECT = V-PICK>
<SYNTAX PICK UP OBJECT (FIND TAKEBIT) (ON-GROUND MANY) = V-PICK-UP PRE-TAKE>
<SYNTAX PLANT OBJECT (HELD MANY) IN OBJECT = V-PLANT>
<SYNONYM PLANT BURY>
<SYNTAX PLUG OBJECT IN OBJECT = V-PLUG>
<SYNTAX PLUG OBJECT TO OBJECT = V-PLUG>
<SYNTAX PLUG IN OBJECT IN OBJECT = V-PLUG>
<SYNTAX PLUG IN OBJECT TO OBJECT = V-PLUG>
<SYNTAX POINT AT OBJECT = V-POINT>
<SYNTAX POINT TO OBJECT = V-POINT>
<SYNTAX POINT OBJECT AT OBJECT = V-STEER>
<SYNTAX POINT OBJECT TO OBJECT = V-STEER>
<SYNONYM POINT STEER>
<SYNTAX POUR OBJECT (HELD CARRIED) = V-POUR>
<SYNTAX POUR OBJECT (HELD CARRIED) IN OBJECT = V-POUR>
<SYNTAX POUR OBJECT (HELD CARRIED) ON OBJECT = V-POUR>
<SYNTAX POUR OBJECT (HELD CARRIED) OVER OBJECT = V-POUR>
<SYNONYM POUR SPILL SPRINK>
<SYNTAX PROTEST = V-PROTEST>
<SYNONYM PROTEST ARGUE>
<SYNTAX PUSH OBJECT = V-PUSH>
<SYNTAX PUSH OBJECT OBJECT = V-FLIPSWITCH>
<SYNTAX PUSH ON OBJECT (IN-ROOM ON-GROUND) = V-PUSH>
<SYNTAX PUSH OBJECT UNDER OBJECT = V-PUT-UNDER>
<SYNONYM PUSH PRESS>
<SYNTAX PUT OBJECT (HELD MANY) IN OBJECT = V-PUT PRE-PUT>
<SYNTAX PUT OBJECT (HELD MANY) AT OBJECT = V-PUT-IN-FRONT PRE-GIVE>
<SYNTAX PUT OBJECT (HELD MANY) BEFORE OBJECT = V-PUT-IN-FRONT PRE-GIVE>
<SYNTAX PUT OBJECT (HELD MANY) DOWN OBJECT = V-PUT-ON PRE-PUT>
<SYNTAX PUT OBJECT (HELD MANY) ON OBJECT = V-PUT-ON PRE-PUT>
<SYNTAX PUT OBJECT (HELD MANY) AROUND OBJECT = V-PUT-ON PRE-PUT>
<SYNTAX PUT OBJECT (HELD MANY) OVER OBJECT = V-PUT-ON PRE-PUT>
<SYNTAX PUT OBJECT (HELD MANY) ACROSS OBJECT = V-PUT-ON PRE-PUT>
<SYNTAX PUT DOWN OBJECT (HELD MANY HAVE) = V-DROP PRE-DROP>
<SYNTAX PUT OBJECT UNDER OBJECT = V-PUT-UNDER>
<SYNTAX PUT ON OBJECT (FIND WEARBIT) (HAVE) = V-WEAR>
<SYNTAX PUT OBJECT BEHIND OBJECT = V-PUT-BEHIND>
<SYNONYM PUT STUFF INSERT PLACE LAY>
<SYNTAX RAISE OBJECT = V-RAISE>
<SYNTAX RAISE UP OBJECT = V-RAISE>
<SYNONYM RAISE LIFT>
<SYNTAX RAPE OBJECT (FIND ACTORBIT) = V-RAPE>
;<SYNTAX REACH IN OBJECT (ON-GROUND IN-ROOM) = V-REACH-IN>
<SYNTAX READ OBJECT (FIND READBIT) (HELD CARRIED ON-GROUND IN-ROOM TAKE)
= V-READ PRE-READ>
<SYNTAX READ OBJECT (FIND READBIT) (HELD CARRIED ON-GROUND IN-ROOM TAKE)
THROUGH OBJECT = V-READ PRE-READ>
<SYNTAX READ OBJECT (FIND READBIT) (HELD CARRIED ON-GROUND IN-ROOM TAKE)
WITH OBJECT = V-READ PRE-READ>
<SYNONYM READ SKIM>
<SYNTAX REFUSE OBJECT (IN-ROOM) = V-REFUSE>
<SYNTAX RELAX = V-RELAX>
<SYNTAX REMOVE OBJECT (FIND WORNBIT) = V-REMOVE>
<SYNTAX REMOVE OBJECT (FIND TAKEBIT) (IN-ROOM CARRIED MANY)
FROM OBJECT = V-TAKE PRE-TAKE>
<SYNONYM REMOVE DOFF SHED>
<SYNTAX REPAIR OBJECT = V-REPAIR>
<SYNONYM REPAIR FIX UNJAM>
<SYNTAX REPLACE OBJECT = V-REPLACE>
<SYNTAX SAVE OBJECT = V-SAVE-SOMETHING>
<SYNTAX SAY TO OBJECT (FIND ACTORBIT) (IN-ROOM) = V-TELL>
<SYNTAX SAY OBJECT = V-SAY-NAME>
<SYNTAX SAY = V-SAY>
<SYNONYM SAY TALK SPEAK>
<SYNTAX SEARCH OBJECT = V-SEARCH>
<SYNTAX SEARCH IN OBJECT = V-SEARCH>
<SYNTAX SEARCH FOR OBJECT = V-FIND>
<SYNONYM SEARCH RUMMAG FRISK>
<SYNTAX SHAKE OBJECT = V-SHAKE>
<SYNTAX SHAKE OBJECT WITH OBJECT = V-SHAKE-WITH>
<SYNTAX SHOOT = V-SHOOT>
<SYNTAX SHOOT OBJECT = V-SHOOT>
<SYNTAX SHOOT OBJECT WITH OBJECT (HAVE) = V-SHOOT>
<SYNTAX SHOOT OBJECT (HAVE) AT OBJECT = V-SSHOOT>
<SYNONYM SHOOT FIRE BLAST>
<SYNTAX SHOW OBJECT (HELD MANY HAVE) TO OBJECT (FIND ACTORBIT) = V-SHOW>
<SYNTAX SHOW OBJECT (FIND ACTORBIT) OBJECT (HELD MANY HAVE) = V-SSHOW>
<SYNTAX SIT ON OBJECT (FIND VEHBIT) (ON-GROUND IN-ROOM) = V-CLIMB-ON>
<SYNTAX SIT DOWN OBJECT (FIND RLANDBIT) (ON-GROUND IN-ROOM) = V-SIT>
<SYNTAX SIT IN OBJECT (FIND VEHBIT) (ON-GROUND IN-ROOM) = V-BOARD PRE-BOARD>
<SYNONYM SIT REST SQUAT>
<SYNTAX SKIP = V-SKIP>
<SYNONYM SKIP HOP>
<SYNTAX SLEEP = V-SLEEP>
<SYNTAX SLEEP IN OBJECT (IN-ROOM ON-GROUND) = V-BOARD>
<SYNTAX SLEEP ON OBJECT (IN-ROOM ON-GROUND) = V-BOARD>
<SYNTAX SLIDE OBJECT = V-PUSH>
<SYNTAX SLIDE OBJECT UNDER OBJECT = V-PUT-UNDER>
<SYNTAX SMELL OBJECT (FIND DARKBIT) = V-SMELL>
<SYNONYM SMELL SNIFF WHIFF>
<SYNTAX SMILE = V-SMILE>
<SYNTAX SMILE AT OBJECT = V-SMILE>
<SYNTAX SPIN OBJECT = V-SPIN>
<SYNONYM SPIN WHIRL ROTATE>
<SYNTAX STAND = V-STAND>
<SYNTAX STAND UP OBJECT (FIND RLANDBIT) = V-STAND>
<SYNTAX STAND ON OBJECT = V-STAND-ON>
<SYNTAX STAND BEFORE OBJECT = V-STAND-BEFORE>
<SYNTAX STAND IN OBJECT = V-STAND-ON>
<SYNONYM STAND RISE>
<SYNTAX START OBJECT = V-LAMP-ON>
<SYNONYM START ACTIVA>
<SYNTAX SWITCH OBJECT = V-TURN>
<SYNTAX SWITCH OBJECT OBJECT = V-FLIPSWITCH>
<SYNTAX SWITCH AROUND OBJECT (FIND RLANDBIT) = V-TURN>
<SYNTAX SWITCH OBJECT TO OBJECT = V-TURN>
<SYNTAX SWITCH OBJECT WITH OBJECT (HAVE) = V-TURN>
<SYNTAX SWITCH ON OBJECT (FIND LIGHTBIT) = V-LAMP-ON>
<SYNTAX SWITCH ON OBJECT OBJECT = V-FLIPSWITCH>
<SYNTAX SWITCH OFF OBJECT (FIND LIGHTBIT) (TAKE) = V-LAMP-OFF>
<SYNTAX SWITCH OFF OBJECT OBJECT = V-FLIPSWITCH>
<SYNONYM SWITCH TURN FLIP FLICK TOGGLE>
<SYNTAX TAKE OBJECT (FIND TAKEBIT) (ON-GROUND IN-ROOM MANY) = V-TAKE PRE-TAKE>
<SYNTAX TAKE IN OBJECT (FIND VEHBIT) (ON-GROUND IN-ROOM) = V-BOARD PRE-BOARD>
<SYNTAX TAKE OUT OBJECT (FIND VEHBIT) (ON-GROUND) = V-DISEMBARK>
<SYNTAX TAKE ON OBJECT (FIND VEHBIT) (ON-GROUND IN-ROOM) = V-CLIMB-ON>
<SYNTAX TAKE UP OBJECT (FIND RLANDBIT) = V-STAND>
<SYNTAX TAKE DRESSE OBJECT (FIND RLANDBIT) = V-GET-DRESSED>
<SYNTAX TAKE UNDRES OBJECT (FIND RLANDBIT) = V-GET-UNDRESSED>
<SYNTAX TAKE DRUNK OBJECT (FIND RLANDBIT) = V-GET-DRUNK>
<SYNTAX TAKE OBJECT (FIND TAKEBIT) (CARRIED IN-ROOM MANY)
OUT OBJECT = V-TAKE PRE-TAKE>
<SYNTAX TAKE OBJECT (FIND TAKEBIT) (CARRIED IN-ROOM MANY)
OFF OBJECT = V-TAKE PRE-TAKE>
<SYNTAX TAKE OBJECT (FIND TAKEBIT) (IN-ROOM CARRIED MANY)
FROM OBJECT = V-TAKE PRE-TAKE>
<SYNTAX TAKE OBJECT (FIND TAKEBIT) (IN-ROOM CARRIED MANY)
IN OBJECT = V-TAKE PRE-TAKE>
<SYNTAX TAKE OFF OBJECT (FIND WORNBIT) (HAVE) = V-TAKE-OFF>
<SYNONYM TAKE GRAB CATCH GET HOLD CARRY>
<SYNTAX TASTE OBJECT (FIND DARKBIT) = V-TASTE>
<SYNONYM TASTE LICK>
<SYNTAX TELL OBJECT (FIND ACTORBIT) (IN-ROOM) = V-TELL>
<SYNTAX TELL OBJECT (FIND ACTORBIT) ABOUT OBJECT = V-TELL-ABOUT>
<SYNTAX TELL OBJECT OBJECT = V-TELL-TIME>
<SYNTAX TELL OBJECT TO OBJECT = V-TELL-NAME>
<SYNTAX THANK OBJECT = V-THANK>
<SYNONYM THANK THANKS>
<SYNTAX THROW OBJECT (HELD CARRIED) = V-THROW PRE-THROW>
<SYNTAX THROW OBJECT OBJECT = V-FLIPSWITCH>
<SYNTAX THROW OBJECT (HELD CARRIED) UP OBJECT (FIND RLANDBIT)
= V-THROW PRE-THROW>
<SYNTAX THROW OBJECT (HELD CARRIED) AT OBJECT (ON-GROUND IN-ROOM)
= V-THROW PRE-THROW>
<SYNTAX THROW OBJECT (HELD CARRIED) TO OBJECT (ON-GROUND IN-ROOM)
= V-THROW PRE-THROW>
<SYNTAX THROW OBJECT (HELD CARRIED) OFF OBJECT = V-THROW-OFF>
<SYNTAX THROW OBJECT (HELD CARRIED) OVER OBJECT = V-THROW-OFF>
<SYNTAX THROW OBJECT (HELD CARRIED) THROUGH OBJECT (ON-GROUND IN-ROOM)
= V-THROW PRE-THROW>
<SYNTAX THROW OBJECT (HELD CARRIED) IN OBJECT = V-THROW PRE-THROW>
<SYNTAX THROW IN OBJECT = V-THROW-IN-TOWEL>
<SYNONYM THROW HURL TOSS>
<SYNTAX TIE OBJECT = V-TIE>
<SYNTAX TIE TOGETHER OBJECT = V-TIE-TOGETHER>
<SYNTAX TIE OBJECT (HELD MANY) AROUND OBJECT = V-PUT-ON PRE-PUT>
<SYNTAX TIE OBJECT TO OBJECT = V-PLUG>
<SYNONYM TIE FASTEN SECURE ATTACH>
<SYNTAX TOUCH OBJECT (FIND DARKBIT) = V-RUB>
<SYNTAX TOUCH OBJECT WITH OBJECT = V-RUB>
<SYNONYM TOUCH FEEL PAT PET RUB>
<SYNTAX TYPE = V-TYPE>
<SYNTAX TYPE ON OBJECT = V-TYPE-ON>
<SYNTAX UNLOCK OBJECT = V-UNLOCK>
<SYNTAX UNLOCK OBJECT WITH OBJECT (HAVE) = V-UNLOCK>
<SYNTAX UNPLUG OBJECT = V-UNPLUG>
<SYNONYM UNPLUG DISCON>
<SYNTAX UNTIE OBJECT (ON-GROUND IN-ROOM HELD CARRIED) = V-UNTIE>
<SYNONYM UNTIE FREE UNFAST UNATTA UNKNOT>
<SYNTAX WAIT = V-WAIT>
<SYNTAX WAIT FOR OBJECT = V-WAIT-FOR>
<SYNONYM WAIT Z STAY>
<SYNTAX WAKE OBJECT (FIND RLANDBIT) = V-ALARM>
<SYNTAX WAKE UP OBJECT (FIND RLANDBIT) = V-ALARM>
<SYNONYM WAKE AWAKE ROUSE>
<SYNTAX WALK = V-WALK-AROUND>
<SYNTAX WALK OBJECT = V-WALK>
<SYNTAX WALK IN OBJECT = V-THROUGH>
<SYNTAX WALK OUT OBJECT = V-THROUGH>
<SYNTAX WALK ON OBJECT = V-WALK-AROUND>
<SYNTAX WALK OVER OBJECT = V-LEAP>
<SYNTAX WALK THROUGH OBJECT = V-THROUGH>
<SYNTAX WALK AROUND OBJECT = V-WALK-AROUND>
<SYNTAX WALK BEHIND OBJECT = V-WALK-AROUND>
<SYNTAX WALK UP OBJECT (ON-GROUND IN-ROOM) = V-CLIMB-UP>
<SYNTAX WALK DOWN OBJECT (ON-GROUND IN-ROOM) = V-CLIMB-DOWN>
<SYNTAX WALK TO OBJECT = V-WALK-TO>
<SYNTAX WALK AWAY OBJECT (FIND RLANDBIT) = V-LEAVE>
<SYNONYM WALK GO RUN PROCEE STEP>
<SYNTAX WASH OBJECT = V-CLEAN>
<SYNTAX WASH UP OBJECT (FIND RLANDBIT) = V-CLEAN>
<SYNONYM WASH CLEAN TIDY>
<SYNTAX WATER OBJECT WITH OBJECT (HAVE) = V-WATER>
<SYNTAX WAVE OBJECT (HELD CARRIED) = V-WAVE>
<SYNTAX WAVE = V-WAVE-AT>
<SYNTAX WAVE AT OBJECT = V-WAVE-AT>
<SYNTAX WAVE TO OBJECT = V-WAVE-AT>
<SYNTAX WEAR OBJECT (FIND WEARBIT) (HAVE) = V-WEAR>
<SYNONYM WEAR DON>
<SYNTAX WHAT OBJECT = V-WHAT>
<SYNTAX WHAT ABOUT OBJECT = V-WHAT-ABOUT>
<SYNTAX WHAT OBJECT OBJECT = V-WHAT-TIME>
<SYNONYM WHAT WHATS WHAT\'>
<SYNTAX WHERE OBJECT = V-WHERE>
<SYNONYM WHERE WHERES>
<SYNTAX WHO OBJECT = V-WHO>
<SYNONYM WHO WHOS>
<SYNTAX WHY = V-WHY>
<SYNTAX DRAPE OBJECT IN OBJECT (HELD MANY) = V-SPUT-ON>
<SYNTAX DRAPE OBJECT (HELD MANY) ON OBJECT = V-PUT-ON PRE-PUT>
<SYNTAX DRAPE OBJECT (HELD MANY) AROUND OBJECT = V-PUT-ON PRE-PUT>
<SYNTAX DRAPE OBJECT (HELD MANY) OVER OBJECT = V-PUT-ON PRE-PUT>
<SYNONYM DRAPE WRAP>
<SYNTAX YELL = V-YELL>
<SYNTAX YELL AT OBJECT = V-YELL>
<SYNTAX YELL TO OBJECT = V-YELL>
<SYNONYM YELL SCREAM SHOUT HOWL>
<SYNTAX YES = V-YES>
<SYNONYM YES Y OK OKAY SURE>
+1566
View File
File diff suppressed because it is too large Load Diff
+2930
View File
File diff suppressed because it is too large Load Diff
+886
View File
@@ -0,0 +1,886 @@
"VOGON for
THE HITCHHIKER'S GUIDE TO THE GALAXY
(c) Copyright 1984 Infocom, Inc. All Rights Reserved."
<OBJECT MINERAL-WATER
(IN SATCHEL)
(DESC "Santraginean Mineral Water")
(LDESC "There is a bottle of mineral water here.")
(SYNONYM BOTTLE WATER)
(ADJECTIVE SANTRA MINERA)
(FLAGS NARTICLEBIT DRINKBIT TAKEBIT)
(GENERIC MINERAL-WATER)
(ACTION MINERAL-WATER-F)>
<ROUTINE MINERAL-WATER-F ()
<COND (<VERB? DRINK DRINK-FROM>
<TELL
"Bad idea. Even Santraginus Five seawater is illegal on most planets. (You can
imagine what kind of beach communities they have.)" CR>)
(<VERB? LOOK-INSIDE>
<PERFORM ,V?EXAMINE ,PRSO>
<RTRUE>)
(<VERB? OPEN CLOSE>
<TELL
"This is one of those clever new always-open always-closed bottles." CR>)
(<VERB? POUR THROW>
<LIQUID-SPILL>)>>
<ROOM HOLD
(IN ROOMS)
(SYNONYM PROTEI)
(DESC "Vogon Hold")
(WEST "The door to the corridor is locked (from the outside).")
(EAST TO AIRLOCK IF VOGON-INNER-DOOR IS OPEN) ;"shouldn't happen"
(FLAGS RLANDBIT ONBIT)
(GLOBAL VOGON-INNER-DOOR AIRLOCK-OBJECT FLEET HOLD-FURNISHINGS)
(PSEUDO "WEAPON" WEAPON-PSEUDO)
(ACTION HOLD-F)>
<ROUTINE HOLD-F (RARG)
<COND (<AND <EQUAL? .RARG ,M-END>
<NOT <FSET? ,HOLD ,NDESCBIT>>>
<FSET ,HOLD ,NDESCBIT>
<FSET ,PEANUTS ,TAKEBIT>
<FCLEAR ,PEANUTS ,NDESCBIT>
<FCLEAR ,PEANUTS ,TRYTAKEBIT>
<FCLEAR ,TOWEL ,TRYTAKEBIT>
<MOVE ,PEANUTS ,PROTAGONIST>
<MOVE ,FORD ,HERE>
<MOVE ,MINERAL-WATER ,FORD>
<SETG GROGGY T>
<ENABLE <QUEUE I-GROGGY 3>>
<ENABLE <QUEUE I-FORD 6>>
<ENABLE <QUEUE I-ANNOUNCEMENT 18>>
<ENABLE <QUEUE I-GUARDS 36>>
<SETG LINE-NUMBER <RANDOM 6>>
<SETG WORD-NUMBER <RANDOM 3>>
<SETG SCORE <+ ,SCORE 8>>
<SETG P-IT-OBJECT ,PEANUTS>
<CRLF>
<TELL
"Ford removes the bottle of " D ,MINERAL-WATER " which he's been waving under
your nose. He tells you that you are aboard a Vogon spaceship, and gives you
some peanuts." CR>)
(<AND <EQUAL? .RARG ,M-END>
<FSET? ,HOLD ,REVISITBIT>>
<SETG DREAMING T>
<JIGS-UP
"A pair of Vogon guards stand nearby, waving acrid-smelling stun guns an inch
away from your face. Simultaneously, they fire.">
<RTRUE>)
(<EQUAL? .RARG ,M-LOOK>
<TELL
"This is a squalid room filled with grubby mattresses, unwashed cups, and
unidentifiable bits of smelly alien underwear. A door lies to port, and an
airlock lies to starboard.">
<COND (,GOWN-HUNG
<TELL " Your gown is hanging from a hook">
<COND (<NOT <FSET? ,TOWEL ,SURFACEBIT>>
<TELL ".">)>)>
<COND (<FSET? ,TOWEL ,SURFACEBIT>
<COND (,GOWN-HUNG
<TELL " and a ">)
(T
<TELL " A ">)>
<TELL "towel is draped over a drain on the floor.">)>
<COND (<AND ,PANEL-BLOCKER
<NOT <EQUAL? ,PANEL-BLOCKER ,SATCHEL>>>
<TELL
" Resting in front of a " D ,ROBOT-PANEL " at the base of one wall is">
<ARTICLE ,PANEL-BLOCKER>
<TELL ".">)>
<CRLF>)>>
<OBJECT HOLD-FURNISHINGS
(IN LOCAL-GLOBALS)
(DESC "it")
(SYNONYM MATTRE CUPS CUP UNDERW)
(ADJECTIVE GRUBBY UNWASH UNIDEN SMELLY ALIEN)
(FLAGS NDESCBIT NARTICLEBIT)
(ACTION UNIMPORTANT-THING-F)>
<ROUTINE I-GROGGY ()
<ENABLE <QUEUE I-GROGGY -1>>
<SETG GROGGY-COUNTER <+ ,GROGGY-COUNTER 1>>
<COND (<NOT ,GROGGY>
<DISABLE <INT I-GROGGY>>
<SETG GROGGY-COUNTER 0>
<RFALSE>)>
<CRLF>
<COND (<EQUAL? ,GROGGY-COUNTER 1 2>
<TELL "You begin to feel ">
<COND (<EQUAL? ,GROGGY-COUNTER 2>
<TELL "in">)>
<TELL "distinctly groggy." CR>)
(<EQUAL? ,GROGGY-COUNTER 3>
<TELL "You begin to feel very indistinct." CR>)
(T
<TELL
"Your serious allergic reaction to protein loss from" ,BEAM "s becomes a cause
celebre amongst various holistic pressure groups in the Galaxy and leads to a
total ban on dematerialisation. Within fifty years, space travel is replaced by
a keen interest in old furniture restoration and market gardening. In this new,
quieter Galaxy, the art of telepathy flourishes as never before, creating a new
universal harmony which brings all life together, converts all matter into
thought and brings about the rebirth of the entire Universe on a higher and
better plane of existence.|
|
However, none of this affects you, because you are dead." CR>
<FINISH>)>>
<GLOBAL GROGGY-COUNTER 0>
<GLOBAL GOWN-HUNG <>>
<GLOBAL PANEL-BLOCKER <>>
<GLOBAL ITEM-ON-SATCHEL <>>
<GLOBAL FISH-COUNTER 5>
<OBJECT DISPENSER
(IN HOLD)
(DESC "babel fish dispenser")
(LDESC "Along one wall is a tall dispensing machine.")
(SYNONYM DISPEN MACHIN SLOT)
(ADJECTIVE DISPEN BABEL FISH TALL VENDIN)
(ACTION DISPENSER-F)>
<ROUTINE DISPENSER-F ()
<COND (<VERB? EXAMINE>
<TELL
"The dispenser is tall, has a button at around eye-level, and says \"Babel
Fish\" in large letters. Anything dispensed would probably come out the slot
at around knee-level.">
<FINE-PRODUCT>
<CRLF>)
(<AND <VERB? PUT-IN-FRONT>
<PRSO? ,HEAD ,EARS>>
<SETG LYING-DOWN T>
<TELL
"You are now lying down with your ear near the " D ,DISPENSER " slot." CR>)
(<AND <VERB? LIE-DOWN>
,IN-FRONT-FLAG>
<PERFORM ,V?PUT-IN-FRONT ,HEAD ,DISPENSER>
<RTRUE>)>>
<OBJECT DISPENSER-BUTTON
(IN HOLD)
(DESC "dispenser button")
(SYNONYM BUTTON)
(ADJECTIVE DISPEN SINGLE BABEL FISH)
(FLAGS NDESCBIT)
(ACTION DISPENSER-BUTTON-F)>
<ROUTINE DISPENSER-BUTTON-F ()
<COND (<VERB? PUSH>
<COND (,LYING-DOWN
<TELL "You can't reach it from down here." CR>
<RTRUE>)
(<EQUAL? ,FISH-COUNTER 0>
<TELL "Click." CR>
<RTRUE>)>
<SETG FISH-COUNTER <- ,FISH-COUNTER 1>>
<TELL
"A single " D ,BABEL-FISH " shoots out of the slot. It sails across the
room and ">
<COND (<NOT ,GOWN-HUNG>
<TELL
"through a " D ,FISH-HOLE " in the wall, just under a " D ,HOOK "." CR>)
(T
<TELL "hits the dressing gown. The fish slides down the ">
<COND (,SLEEVE-TIED
<TELL "inside (nice try, though)">)
(T
<TELL "sleeve">)>
<TELL " of the gown and falls to the floor, ">
<COND (<NOT <FSET? ,TOWEL ,SURFACEBIT>>
<TELL
"vanishing through the grating of a hitherto unnoticed drain." CR>)
(T
<TELL
"landing on the towel. A split-second later, a tiny cleaning robot whizzes
across the floor, grabs the fish, and continues its breakneck pace toward
a " D ,ROBOT-PANEL " at the base of the wall. ">
<COND (<NOT ,PANEL-BLOCKER>
<TELL
"The robot zips through the panel, and is gone." CR>)
(<NOT <EQUAL? ,PANEL-BLOCKER ,SATCHEL>>
<TELL "The robot zips around">
<ARTICLE ,PANEL-BLOCKER>
<TELL ", through the panel, and is gone." CR>)
(T
<TELL
"The robot plows into the satchel, sending the " D ,BABEL-FISH>
<COND
(<AND <NOT <EQUAL? ,ITEM-ON-SATCHEL ,MAIL>>
,ITEM-ON-SATCHEL>
<TELL " and">
<ARTICLE ,ITEM-ON-SATCHEL T>)>
<TELL
" flying through the air in a graceful arc">
<COND
(<NOT <EQUAL? ,ITEM-ON-SATCHEL ,MAIL>>
<TELL
". " ,ROBOT-FLIES-IN "catches the " D ,BABEL-FISH " ">
<COND (,ITEM-ON-SATCHEL
<MOVE ,ITEM-ON-SATCHEL ,LOCAL-GLOBALS>
<TELL "and also manages to catch">
<ARTICLE ,ITEM-ON-SATCHEL T>
<SETG ITEM-ON-SATCHEL <>>)
(T
<TELL
"(which is all the flying junk it can find)">)>
<TELL ", and exits." CR>)
(<EQUAL? ,ITEM-ON-SATCHEL ,MAIL>
<MOVE ,MAIL ,LOCAL-GLOBALS>
<SETG SCORE <+ ,SCORE 12>>
<MOVE ,BABEL-FISH ,PROTAGONIST>
<COND (<RUNNING? ,I-ANNOUNCEMENT>
<ENABLE <QUEUE I-GUARDS 4>>)
(<NOT
<FSET? ,CAPTAINS-QUARTERS ,TOUCHBIT>>
<ENABLE <QUEUE I-ANNOUNCEMENT 4>>
<ENABLE <QUEUE I-GUARDS 7>>)>
<SETG FISH-COUNTER 0>
<SETG ITEM-ON-SATCHEL <>>
<TELL
" surrounded by a cloud of junk mail. Another robot flies in and begins madly
collecting the cluttered plume of mail. The " D ,BABEL-FISH " continues its
flight, landing with a loud \"squish\" in your ear." CR>)>)>)>)>)>>
<OBJECT FISH-HOLE
(IN HOLD)
(DESC "small hole")
(SYNONYM HOLE)
(ADJECTIVE SMALL)
(FLAGS NDESCBIT)
(ACTION FISH-HOLE-F)>
<ROUTINE FISH-HOLE-F ()
<COND (<VERB? LOOK-INSIDE>
<TELL "You see only " D ,DARK-OBJECT "." CR>)
(<AND <VERB? PUT>
<PRSI? ,FISH-HOLE>>
<COND (<FSET? ,PRSO ,INTEGRALBIT>
<PART-OF>)
(<L? <GETP ,PRSO ,P?SIZE> 5>
<MOVE ,PRSO ,LOCAL-GLOBALS>
<TELL "It falls through the hole and vanishes." CR>)
(T
<TELL "It doesn't fit through the hole." CR>)>)
(<AND <VERB? PUT-ON PUT-IN-FRONT>
<PRSI? ,FISH-HOLE>>
<COND (<PRSO? ,HANDS ,EARS ,ME ,HEAD>
<PERFORM ,V?STAND-BEFORE ,FISH-HOLE>
<RTRUE>)>
<PERFORM ,V?HANG ,PRSO ,HOOK>
<RTRUE>)
(<AND <VERB? BLOCK-WITH SPUT-ON>
<PRSO? ,FISH-HOLE>>
<PERFORM ,V?HANG ,PRSI ,HOOK>
<RTRUE>)
(<VERB? BLOCK>
<PERFORM ,V?STAND-BEFORE ,FISH-HOLE>
<RTRUE>)
(<AND <VERB? LIE-DOWN>
,IN-FRONT-FLAG>
<PERFORM ,V?STAND-BEFORE ,FISH-HOLE>
<RTRUE>)>>
<OBJECT HOOK
(IN HOLD)
(DESC "metal hook")
(SYNONYM HOOK)
(ADJECTIVE METAL)
(FLAGS NDESCBIT)
(ACTION HOOK-F)>
<ROUTINE HOOK-F ()
<COND (<VERB? EXAMINE>
<COND (,GOWN-HUNG
<TELL "Your gown is hanging from it." CR>)
(T
<TELL
"The hook is attached to the wall, inches above a tiny hole." CR>)>)
(<VERB? HANG PUT-ON>
<COND (,LYING-DOWN
<TELL ,WHILE-LYING CR>)
(<PRSO?,GOWN>
<COND (<FSET? ,GOWN ,WORNBIT>
<IDROP>
<RTRUE>)>
<SETG GOWN-HUNG T>
<MOVE ,GOWN ,HERE>
<FSET ,GOWN ,NDESCBIT>
<FSET ,GOWN ,TRYTAKEBIT>
<FCLEAR ,GOWN ,OPENBIT>
<TELL
"The gown is now hanging from the hook, covering a tiny hole." CR>)
(<PRSO? ,HANDS ,EARS ,HEAD>
<PERFORM ,V?STAND-BEFORE ,HOOK>
<RTRUE>)
(<FSET? ,PRSO ,TAKEBIT>
<COND (<FSET? ,PRSO ,TRYTAKEBIT>
<TELL ,NOT-HOLDING>
<ARTICLE ,PRSO T>
<TELL "." CR>)
(T
<MOVE ,PRSO ,HERE>
<TELL "It slips off the hook." CR>)>)
(T
<V-COUNT>)>)>>
<OBJECT DRAIN
(IN HOLD)
(DESC "drain")
(SYNONYM DRAIN GRATING GRATE)
(FLAGS NDESCBIT)
(ACTION DRAIN-F)>
<ROUTINE DRAIN-F ()
<COND (<VERB? PUT-ON>
<COND (<FSET? ,TOWEL ,SURFACEBIT>
<TELL "The drain is already covered by the towel." CR>)
(,LYING-DOWN
<TELL ,WHILE-LYING CR>)
(<PRSO?,TOWEL>
<FSET ,TOWEL ,CONTBIT>
<FSET ,TOWEL ,SURFACEBIT>
<FSET ,TOWEL ,OPENBIT>
<FSET ,TOWEL ,NDESCBIT>
<FSET ,TOWEL ,TRYTAKEBIT>
<MOVE ,TOWEL ,HERE>
<PERFORM ,V?EXAMINE ,DRAIN>
<RTRUE>)
(T
<TELL "The drain is too large to be covered by">
<ARTICLE ,PRSO T>
<TELL "." CR>)>)
(<VERB? LOOK-INSIDE>
<PERFORM ,V?LOOK-INSIDE ,FISH-HOLE>
<RTRUE>)
(<AND <VERB? EXAMINE>
<FSET? ,TOWEL ,SURFACEBIT>>
<TELL "The towel completely covers the drain." CR>)>>
<OBJECT ROBOT-PANEL
(IN HOLD)
(DESC "tiny robot panel")
(SYNONYM PANEL)
(ADJECTIVE ROBOT TINY)
(FLAGS NDESCBIT)
(ACTION ROBOT-PANEL-F)>
<ROUTINE ROBOT-PANEL-F ()
<COND (<VERB? EXAMINE CLOSE>
<TELL
"The panel, only a few inches high, is currently closed." CR>)
(<VERB? OPEN>
<TELL ,BUDGE CR>)
(<VERB? BLOCK>
<SETG AWAITING-REPLY 6>
<ENABLE <QUEUE I-REPLY 2>>
<TELL "With " D ,HANDS "s? By force of will?" CR>)
(<AND <VERB? LIE-DOWN>
,IN-FRONT-FLAG>
<PERFORM ,V?STAND-BEFORE ,ROBOT-PANEL>
<RTRUE>)
(<AND <VERB? PUT-IN-FRONT PUT-IN-FRONT PUT-ON>
<PRSI? ,ROBOT-PANEL>>
<PERFORM ,V?BLOCK-WITH ,ROBOT-PANEL ,PRSO>
<RTRUE>)
(<AND <VERB? BLOCK-WITH SPUT-ON>
<PRSO? ,ROBOT-PANEL>>
<COND (<PRSI? ,HEAD ,HANDS ,EARS ,EYES>
<V-COUNT>)
(<NOT <HELD? ,PRSI>>
<TELL ,NOT-HOLDING>
<ARTICLE ,PRSI T>
<TELL "." CR>)
(,PANEL-BLOCKER
<TELL "But">
<ARTICLE ,PANEL-BLOCKER T>
<TELL
" is already in front of the " D ,ROBOT-PANEL "." CR>)
(,LYING-DOWN
<TELL ,WHILE-LYING CR>)
(T
<MOVE ,PRSI ,HERE>
<SETG PANEL-BLOCKER ,PRSI>
<FSET ,PRSI ,TRYTAKEBIT>
<TELL "Okay,">
<COND (<PRSI? ,SATCHEL>
<TELL " the satchel is lying on its side">)
(T
<FSET ,PRSI ,NDESCBIT>
<ARTICLE ,PRSI T>
<TELL " is sitting">)>
<TELL " in front of the " D ,ROBOT-PANEL "." CR>)>)>>
<OBJECT BABEL-FISH
(IN LOCAL-GLOBALS) ;"just for the purpose of MOBY-FIND"
(DESC "babel fish")
(SYNONYM FISH)
(ADJECTIVE BABEL)
(FLAGS TAKEBIT)
(ACTION BABEL-FISH-F)>
<ROUTINE BABEL-FISH-F ()
<COND (<VERB? TAKE REMOVE>
<TELL
"That would be foolish. Having a " D ,BABEL-FISH " in your ear is terribly
useful." CR>)>>
<OBJECT GLASS-CASE
(IN HOLD)
(DESC "glass case")
(LDESC "In the corner is a glass case with a switch and a keyboard.")
(SYNONYM CASE LID GLASS)
(ADJECTIVE GLASS)
(SIZE 40)
(FLAGS CONTBIT TRANSBIT SEARCHBIT)
(ACTION GLASS-CASE-F)>
<GLOBAL GLASS-CASE-SCORE <>>
<ROUTINE GLASS-CASE-F ()
<COND (<VERB? EXAMINE>
<TELL "The " D ,GLASS-CASE " is ">
<COND (<FSET? ,GLASS-CASE ,OPENBIT>
<TELL "open">)
(T
<TELL "closed">)>
<TELL
". Attached to it are a " D ,KEYBOARD " and a switch." CR>)
(<AND <VERB? OPEN>
<NOT <FSET? ,GLASS-CASE ,OPENBIT>>>
<TELL ,BUDGE CR>)
(<VERB? MUNG>
<TELL
"The hold of the Vogon ship is virtually undamaged by the explosion
of the " D ,GLASS-CASE>
<JIGS-UP
". You, however, are blasted into tiny bits and smeared all over the room.
Several cleaning robots fly in and wipe you neatly off the walls.">
<RTRUE>)>>
<ROUTINE GLASS-CASE-OPENS () ;"see V-TYPE"
<COND (<FSET? ,GLASS-CASE ,OPENBIT>
<TELL "Nothing happens." CR>
<FUCKING-CLEAR>)
(T
<FSET ,GLASS-CASE ,OPENBIT>
<TELL "The " D ,GLASS-CASE " opens." CR>
<FCLEAR ,PLOTTER ,TRYTAKEBIT>
<COND (<NOT ,GLASS-CASE-SCORE>
<SETG GLASS-CASE-SCORE T>
<SETG SCORE <+ ,SCORE 25>>)>
<FUCKING-CLEAR>)>>
<OBJECT KEYBOARD
(IN HOLD)
(DESC "keyboard")
(SYNONYM KEYBOA)
(FLAGS NDESCBIT TRYTAKEBIT)>
<OBJECT CASE-SWITCH
(IN HOLD)
(DESC "switch")
(SYNONYM SWITCH)
(FLAGS NDESCBIT SWITCHBIT)
(ACTION CASE-SWITCH-F)>
<ROUTINE CASE-SWITCH-F ()
<COND (<VERB? LAMP-ON TURN PUSH MOVE THROW>
<COND (<HELD? ,BABEL-FISH>
<TELL
"A recording plays: \"To open the case, type in the ">
<COND (<EQUAL? ,WORD-NUMBER 1>
<TELL "first">)
(<EQUAL? ,WORD-NUMBER 2>
<TELL "second">)
(<EQUAL? ,WORD-NUMBER 3>
<TELL "third">)>
<TELL
" word from the second verse of the Captain's current favourite poem.
WARNING: An incorrect input will cause the case to explode.\"" CR>)
(T
<TELL "A recording plays: \"A">
<PRODUCE-GIBBERISH 5>
<CRLF>)>)>>
<ROUTINE PRODUCE-GIBBERISH (N "AUX" GIBBERISH-COUNTER SUPER-COUNTER)
<SET SUPER-COUNTER 0>
<REPEAT ()
<SET SUPER-COUNTER <+ .SUPER-COUNTER 1>>
<SET GIBBERISH-COUNTER 0>
<REPEAT ()
<SET GIBBERISH-COUNTER <+ .GIBBERISH-COUNTER 1>>
<TELL <PICK-ONE ,GIBBERISH>>
<COND (<EQUAL? .GIBBERISH-COUNTER 10>
<COND (<NOT <EQUAL? .SUPER-COUNTER .N>>
<TELL " o">)>
<RETURN>)>>
<COND (<EQUAL? .SUPER-COUNTER .N>
<TELL ".\"">
<RETURN>)>>>
<ROUTINE I-ANNOUNCEMENT ()
<ENABLE <QUEUE I-ANNOUNCEMENT -1>>
<TELL CR "An announcement is coming over the ship's intercom. \"">
<COND (<HELD? ,BABEL-FISH ,PROTAGONIST>
<TELL
"This is the Captain. My instruments show that we've picked up a couple of
hitchhikers. I hate freeloaders, and when my guards find you I'll have you
thrown into space. On second thought, maybe I'll read you some of my poetry
first. Repeating...\"" CR>)
(T
<TELL "E">
<PRODUCE-GIBBERISH 10>
<CRLF>)>>
<GLOBAL GIBBERISH
<PLTABLE
"toy" "r g" "irb" "kwa" "o s"
"fim" "p w" "osh" "flu" "a r"
"vup" "d t" "imb" "tha" "i l"
"cav" "s g" "ulp" "cho" "u n"
"zit" "z z" "eft" "qui" "e h"
"kon" "l m" "ork" "gry" "o t"
"huv" "x j" "erl" "tru" "a b"
"fud" "w c" "oll" "wro" "i s">>
<ROUTINE I-GUARDS ()
<COND (<EQUAL? ,HERE ,HOLD>
<DISABLE <INT I-ANNOUNCEMENT>>
<TELL CR
"Guards burst in and grab you and Ford, who comes slowly awake. They drag you
down the corridor to a large cabin, where they strap you into large, menacing
chairs..." CR CR>
<SETG HERE ,CAPTAINS-QUARTERS>
<MOVE ,NAME ,HERE>
<SETG LYING-DOWN <>>
<ENABLE <QUEUE I-CAPTAIN 2>>
<SETG FORD-SLEEPING <>>
<FSET ,FORD ,NDESCBIT>
<MOVE ,PROTAGONIST ,POETRY-APPRECIATION-CHAIR>
<V-LOOK>
<MOVE ,FORD ,HERE>
<MOVE ,GUARDS ,HERE>)
(<NOT <IN? ,RIFLES ,LOCAL-GLOBALS>>
<TELL CR ,GUARDS-REALIZE "They">
<GUARD-DEATH>
<RTRUE>)
(T
<RFALSE>)>>
<ROOM CAPTAINS-QUARTERS
(IN ROOMS)
(DESC "Captain's Quarters")
(FLAGS RLANDBIT ONBIT)
(PSEUDO "WEAPON" WEAPON-PSEUDO "STRAPS" UNIMPORTANT-THING-F)
(GLOBAL FLEET)
(ACTION CAPTAINS-QUARTERS-F)>
<ROUTINE CAPTAINS-QUARTERS-F (RARG)
<COND (<EQUAL? .RARG ,M-LOOK>
<TELL
"This is the cabin of the " D ,VOGON-CAPTAIN ". You and Ford are strapped
into " D ,POETRY-APPRECIATION-CHAIR "s." CR>)>>
<OBJECT POETRY-APPRECIATION-CHAIR
(IN CAPTAINS-QUARTERS)
(DESC "poetry appreciation chair")
(SYNONYM CHAIR CHAIRS SEAT)
(ADJECTIVE POETRY APPREC FORMID LARGE MENACI)
(FLAGS VEHBIT OPENBIT SEARCHBIT SURFACEBIT CONTBIT)
(ACTION POETRY-APPRECIATION-CHAIR-F)>
<ROUTINE POETRY-APPRECIATION-CHAIR-F ("OPTIONAL" (RARG <>))
<COND (.RARG
<RFALSE>)
(<VERB? DISEMBARK WALK LEAP WALK-AROUND>
<SETG AWAITING-REPLY 7>
<ENABLE <QUEUE I-REPLY 2>>
<TELL "You're strapped in, remember?" CR>)
(<AND <VERB? OPEN CLOSE>
<PRSO? ,POETRY-APPRECIATION-CHAIR>>
<TELL-ME-HOW>)>>
<OBJECT VOGON-CAPTAIN
(IN CAPTAINS-QUARTERS)
(DESC "Vogon Captain")
(LDESC
"The Captain is indescribably hideous, indescribably blubbery,
and indescribably mid-to-dark green. He is holding samples of his
favourite poetry.")
(SYNONYM CAPTAIN VOGONS)
(ADJECTIVE VOGON)
(FLAGS ACTORBIT)
(ACTION VOGON-CAPTAIN-F)>
<ROUTINE VOGON-CAPTAIN-F ()
<COND (<OR <VERB? TELL HELLO THANK>
<AND <VERB? ASK-ABOUT ASK-FOR>
<EQUAL? ,VOGON-CAPTAIN ,PRSO>>>
<TELL
"One of the guards lightly bashes your skull with the butt of his weapon">
<COND (<HELD? ,BABEL-FISH>
<TELL
". \"This is a poetry appreciation session, prisoner. No talking!\"" CR>)
(T
<TELL " and says, \"A">
<PRODUCE-GIBBERISH 2>
<CRLF>)>
<FUCKING-CLEAR>)
(<AND <IN? ,POETRY ,HERE>
<VERB? BLOCK>>
<PERFORM ,V?LISTEN ,POETRY>
<RTRUE>)>>
<GLOBAL CAPTAIN-COUNTER 0>
<ROUTINE I-CAPTAIN ()
<ENABLE <QUEUE I-CAPTAIN -1>>
<SETG CAPTAIN-COUNTER <+ ,CAPTAIN-COUNTER 1>>
<CRLF>
<COND (<EQUAL? ,CAPTAIN-COUNTER 1>
<TELL
"\"If he's going to read us his poetry,\" mutters Ford, sweating profusely,
\"just pray he softens us up with some cudgels first...\"" CR CR>)>
<COND (<NOT <HELD? ,BABEL-FISH ,PROTAGONIST>>
<TELL "The " D ,VOGON-CAPTAIN " says, \"O">
<PRODUCE-GIBBERISH 2>
<COND (<EQUAL? ,CAPTAIN-COUNTER 6>
<GUARDS-TO-AIRLOCK>)
(T
<CRLF>)>)
(<EQUAL? ,CAPTAIN-COUNTER 1>
<TELL
"\"Hello, hitchhikers!\" begins the " D ,VOGON-CAPTAIN ". \"I've decided to
read you a verse of my poetry!\"" CR>)
(<EQUAL? ,CAPTAIN-COUNTER 2>
<TELL
"\"Oh freddled gruntbuggly, thy nacturations are to me!\"" CR>)
(<EQUAL? ,CAPTAIN-COUNTER 3>
<TELL
"\"As plurdled gabbleblotchits on a lurgid bee.\"" CR>)
(<EQUAL? ,CAPTAIN-COUNTER 4>
<TELL
"\"Groop I implore thee, my foonting turlingdromes.\"" CR>)
(<EQUAL? ,CAPTAIN-COUNTER 5>
<TELL
"\"And hooptiously drangle me with crinkly bindlewurdles, or I will rend
thee in the gobberwarts with my blurglecruncheon, see if I don't!\"" CR>)
(<EQUAL? ,CAPTAIN-COUNTER 6>
<COND (,POEM-ENJOYED
<TELL
"\"You looked like you enjoyed my poem. I think...yes, I think I'll read
the NEXT verse, also!\"" CR>)
(T
<TELL
"\"You didn't seem to enjoy my poem at all! Guards, toss
them out the airlock!\"">
<GUARDS-TO-AIRLOCK>)>)
(<EQUAL? ,CAPTAIN-COUNTER 7>
<COND (<EQUAL? ,LINE-NUMBER 1 2>
<TELL ,LINE-A CR>)
(<EQUAL? ,LINE-NUMBER 3 4>
<TELL ,LINE-B CR>)
(T
<TELL ,LINE-C CR>)>)
(<EQUAL? ,CAPTAIN-COUNTER 8>
<COND (<EQUAL? ,LINE-NUMBER 3 5>
<TELL ,LINE-A CR>)
(<EQUAL? ,LINE-NUMBER 1 6>
<TELL ,LINE-B CR>)
(T
<TELL ,LINE-C CR>)>)
(<EQUAL? ,CAPTAIN-COUNTER 9>
<COND (<EQUAL? ,LINE-NUMBER 4 6>
<TELL ,LINE-A CR>)
(<EQUAL? ,LINE-NUMBER 2 5>
<TELL ,LINE-B CR>)
(T
<TELL ,LINE-C CR>)>)
(<EQUAL? ,CAPTAIN-COUNTER 10>
<TELL
"\"Gerond withoutitude form into formless bloit, why not then? Moose.\"" CR>)
(<EQUAL? ,CAPTAIN-COUNTER 11>
<TELL
"\"Since you have somehow managed to survive two verses of my poetry, I have
no choice but to space you. Guards!\"">
<GUARDS-TO-AIRLOCK>)>>
<GLOBAL LINE-A "\"Fripping lyshus wimbgunts, awhilst moongrovenly kormzibs.\"">
<GLOBAL LINE-B "\"Gashee morphousite, thou expungiest quoopisk!\"">
<GLOBAL LINE-C
"\"Bleem miserable venchit! Bleem forever mestinglish asunder frapt.\"">
<GLOBAL LINE-NUMBER 0>
;"The line order is set randomly from 1 to 6, with the following result:
1 Line A, Line B, Line C
2 Line A, Line C, Line B
3 Line B, Line A, Line C
4 Line B, Line C, Line A
5 Line C, Line A, Line B
6 Line C, Line B, Line A"
<GLOBAL WORD-NUMBER 0> ;"randomly set between one and three"
<ROUTINE GUARDS-TO-AIRLOCK ()
<DISABLE <INT I-CAPTAIN>>
<TELL
" A guard grabs you and Ford, and drags you toward the hold. Ford whispers,
\"Don't worry, I'll think of something!\"" CR CR>
<FCLEAR ,HOLD ,TOUCHBIT>
<GOTO ,HOLD>
<FCLEAR ,FORD ,NDESCBIT>
<MOVE ,GUARDS ,HERE>
<MOVE ,FORD ,HERE>
<ENABLE <QUEUE I-FORD 1>>>
<OBJECT POETRY
(IN CAPTAINS-QUARTERS)
(DESC "Vogon poetry")
(SYNONYM POETRY POEM SAMPLE VERSE)
(ADJECTIVE VOGON FIRST SECOND)
(FLAGS NDESCBIT NARTICLEBIT DARKBIT)
(ACTION POETRY-F)>
<GLOBAL POEM-ENJOYED <>>
<GLOBAL AIRLOCK-COUNTER 0>
<ROUTINE POETRY-F ()
<COND (<AND <VERB? ENJOY LISTEN>
<L? ,CAPTAIN-COUNTER 2>>
<TELL "The " D ,VOGON-CAPTAIN " hasn't begun yet!" CR>)
(<VERB? ENJOY>
<COND (<NOT <HELD? ,BABEL-FISH>>
<TELL
"You can't even understand it, let alone enjoy it!" CR>)
(,POEM-ENJOYED
<SETG AWAITING-REPLY 8>
<ENABLE <QUEUE I-REPLY 2>>
<TELL "Hey, let's not overdo it, okay?" CR>)
(T
<SETG POEM-ENJOYED T>
<SETG SCORE <+ ,SCORE 15>>
<TELL
"You realise that, although the " D ,POETRY " is indeed astoundingly bad,
worse things happen at sea, and in fact, at school. With an effort for which
Hercules himself would have patted you on the back, you grit your teeth and
enjoy the stuff." CR>)>)
(<VERB? LISTEN>
<TELL "You have no choice. Why not relax and enjoy it?" CR>)
(<AND <IN? ,POETRY ,HERE>
<VERB? BLOCK>>
<PERFORM ,V?LISTEN ,POETRY>
<RTRUE>)
(<VERB? READ EXAMINE>
<TELL "You can't see it from here." CR>)>>
<OBJECT VOGON-CORRIDOR-DOOR
(IN HOLD)
(DESC "corridor door")
(SYNONYM DOOR)
(ADJECTIVE CORRID)
(FLAGS DOORBIT NDESCBIT)
(ACTION VOGON-CORRIDOR-DOOR-F)>
<ROUTINE VOGON-CORRIDOR-DOOR-F ()
<COND (<VERB? OPEN UNLOCK THROUGH>
<DO-WALK ,P?WEST>)>>
<OBJECT VOGON-INNER-DOOR
(IN LOCAL-GLOBALS)
(DESC "inner door")
(SYNONYM DOOR)
(ADJECTIVE INNER AIRLOC MASSIV)
(FLAGS VOWELBIT NDESCBIT DOORBIT)
(ACTION VOGON-AIRLOCK-DOOR-F)>
<OBJECT VOGON-OUTER-DOOR
(IN LOCAL-GLOBALS)
(DESC "outer door")
(SYNONYM DOOR)
(ADJECTIVE OUTER AIRLOC MASSIV)
(FLAGS VOWELBIT NDESCBIT DOORBIT)
(ACTION VOGON-AIRLOCK-DOOR-F)>
<ROUTINE VOGON-AIRLOCK-DOOR-F ()
<COND (<VERB? OPEN THROUGH>
<TELL ,BUDGE CR>)>>
<OBJECT AIRLOCK-OBJECT
(IN LOCAL-GLOBALS)
(DESC "airlock")
(SYNONYM AIRLOC)
(FLAGS VOWELBIT)
(ACTION AIRLOCK-OBJECT-F)>
<ROUTINE AIRLOCK-OBJECT-F ()
<COND (<VERB? THROUGH WALK-TO>
<COND (<EQUAL? ,HERE ,AIRLOCK>
<TELL ,LOOK-AROUND CR>)
(<EQUAL? ,HERE ,HOLD>
<DO-WALK ,P?WEST>)>)
(<VERB? LEAVE EXIT DISEMBARK>
<COND (<EQUAL? ,HERE ,AIRLOCK>
<DO-WALK ,P?EAST>)
(T
<TELL ,LOOK-AROUND CR>)>)>>
<OBJECT EQUATIONS
(IN LOCAL-GLOBALS)
(DESC "it")
(SYNONYM EQUATI NUMBER PENCIL)
(FLAGS NDESCBIT NARTICLEBIT)
(ACTION UNIMPORTANT-THING-F)>
<ROOM AIRLOCK
(IN ROOMS)
(SYNONYM BETELG)
(DESC "Airlock")
(LDESC "This airlock has massive doors to port and starboard.")
(WEST TO HOLD IF VOGON-INNER-DOOR IS OPEN) ;"this should never happen"
(EAST TO HOLD IF VOGON-OUTER-DOOR IS OPEN) ;"ditto"
(FLAGS RLANDBIT ONBIT)
(GLOBAL VOGON-INNER-DOOR VOGON-OUTER-DOOR AIRLOCK-OBJECT FLEET EQUATIONS)
(ACTION AIRLOCK-F)>
<ROUTINE AIRLOCK-F (RARG)
<COND (<EQUAL? .RARG ,M-END>
<SETG AIRLOCK-COUNTER <+ ,AIRLOCK-COUNTER 1>>
<CRLF>
<COND (<EQUAL? ,AIRLOCK-COUNTER 1>
<TELL
"Ford points at the " D ,VOGON-OUTER-DOOR ". \"In about two minutes, it will
open and we'll be ejected into the vacuum of space. But don't panic, I'll
think of something.\"" CR>)
(<EQUAL? ,AIRLOCK-COUNTER 2>
<TELL "Ford is mumbling to himself." CR>)
(<EQUAL? ,AIRLOCK-COUNTER 3>
<TELL
"Ford produces a pencil and begins scribbling equations on the wall." CR>)
(<EQUAL? ,AIRLOCK-COUNTER 4>
<TELL
"Ford's eyes light up. \"Do you still have the Electronic Sub-Etha Auto
Hitching Thu...\" At that moment, the airlock door opens, and you and Ford
are blown out into space.||">
<COND (<HELD? ,GUIDE>
<TELL
"Your elbow must have struck some key on " D ,GUIDE " because it begins
droning out an entry, coincidentally enough the entry on SPACE. \""
,SPACE-TEXT "\" (Footnote 9)" CR CR>)>
<TELL
"Precisely twenty-nine seconds later, you and Ford are scooped up by a passing
ship. Gasping for air, you pass out..." CR CR>
<SETG HEART-PROB 100>
<GOTO ,DARK>)>)>>