Files
h2g2/h2g2/content/vogon.py
T
seppedl a1bb4cbf02 Add complete game content: Vogon ship, Heart of Gold, off-Earth, dream system
Engine refactoring:
- Replace hardcoded state attributes with generic state.flags dict
- Add death system (jigs_up/finish) with dream-restore callbacks
- Add inventory extras hook system (removes hardcoded headache/tea lines)
- Add 16 new verb handlers (consult, say, carve, plug, repair, kick, etc.)
- Add verb synonyms to parser

New content modules (25 rooms, 107 objects total):
- vogon.py: Hold, Captain's Quarters, Airlock; babel fish puzzle, poetry
  scene, airlock ejection sequence with timed events
- heart.py: 10 Heart of Gold rooms; Marvin tool quest, tea/no-tea paradox,
  Nutrimat overload, Infinite Improbability Drive puzzle, victory sequence
- unearth.py: Traal (Beast lair with towel/name/carve puzzle), War Chamber,
  Inside Whale, Maze with random exits and particle
- dark.py: Dream dispatch room with probabilistic destination selection,
  sensory discovery mechanic, dream-restore callback

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 21:52:57 +02:00

1154 lines
35 KiB
Python

"""Vogon ship locations -- Hold, Captain's Quarters, Airlock."""
import random
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
# ---- Gibberish generator ----
_VOGON_SYLLABLES = [
"blurp", "grun", "flib", "morgh", "splut", "vrunt", "glub", "snarg",
"plod", "quork", "bleg", "frot", "nargh", "sklurb", "thrip", "zunt",
"drob", "munt", "flob", "grak", "prunt", "vlib", "skrog", "blort",
]
_VOGON_SUFFIXES = [
"ulous", "ting", "ment", "ish", "wards", "oid", "esque", "ble",
"ness", "ling", "osity", "ated", "ingly", "ation",
]
def _gibberish_word() -> str:
"""Generate a random Vogon-sounding gibberish word."""
base = random.choice(_VOGON_SYLLABLES)
if random.random() > 0.5:
base += random.choice(_VOGON_SYLLABLES)[:3]
base += random.choice(_VOGON_SUFFIXES)
return base
def _gibberish_line() -> str:
"""Generate a full line of Vogon gibberish."""
words = [_gibberish_word() for _ in range(random.randint(4, 8))]
line = " ".join(words)
return f'"{line.capitalize()}!"'
# ---- Poetry text ----
POETRY_LINES = [
'"Oh freddled gruntbuggly, thy nacturations are to me!"',
'"As plurdled gabbleblotchits on a lurgid bee."',
'"Groop I implore thee, my foonting turlingdromes."',
'"And hooptiously drangle me with crinkly bindlewurdles,"',
'"or I will rend thee in the gobberwarts with my blurglecruncheon, see if I don\'t!"',
]
POETRY_VERSE_2 = [
'"Fripping lyshus wimbgunts, awhilst moongrovenly kormzibs."',
'"Gashee morphousite, thou expungiest quoopisk!"',
'"Bleem miserable venchit! Bleem forever mestinglish asunder frapt."',
]
# ---- Object action handlers ----
def _inner_door_action(state: GameState) -> bool:
out = state.output
door = state.world.get("INNER-DOOR")
if state.prsa == "open":
if door.fset_q(Flag.OPENBIT):
out.tell("The inner airlock door is already open.\n")
else:
door.fset(Flag.OPENBIT)
out.tell("You open the inner airlock door.\n")
return True
if state.prsa == "close":
if not door.fset_q(Flag.OPENBIT):
out.tell("It's already closed.\n")
else:
door.fclear(Flag.OPENBIT)
out.tell("You close the inner airlock door.\n")
return True
if state.prsa == "examine":
status = "open" if door.fset_q(Flag.OPENBIT) else "closed"
out.tell(f"A heavy inner airlock door. It is {status}.\n")
return True
return False
def _airlock_obj_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine":
out.tell(
"The airlock is a standard Vogon design: built to eject "
"unwanted hitchhikers into the vacuum of space.\n"
)
return True
return False
def _dispenser_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine":
out.tell(
"The dispenser has a button, and a small sign that reads "
'"Babel Fish." A small hole at the bottom dispenses the fish.\n'
)
return True
return False
def _dispenser_button_action(state: GameState) -> bool:
out = state.output
if state.prsa not in ("push", "press"):
return False
fish_counter = state.flags.get("fish_counter", 5)
if state.flags.get("babel_fish_in_ear"):
out.tell("You already have a babel fish in your ear.\n")
return True
if fish_counter <= 0:
out.tell(
"The dispenser makes a grinding noise, but nothing comes "
"out. It appears to be empty.\n"
)
return True
state.flags["fish_counter"] = fish_counter - 1
# Check puzzle conditions
gown_hung = state.flags.get("gown_hung", False)
towel_on_drain = state.flags.get("towel_on_drain", False)
panel_blocker = state.flags.get("panel_blocker")
item_on_satchel = state.flags.get("item_on_satchel")
if not gown_hung:
out.tell(
"A small babel fish shoots out of the dispenser, arcs through "
"the air, and vanishes down a drain in the floor.\n"
)
return True
if not towel_on_drain:
out.tell(
"A small babel fish shoots out of the dispenser, bounces off "
"the dressing gown hanging on the hook, and vanishes down a "
"drain in the floor.\n"
)
return True
if panel_blocker is None:
out.tell(
"A small babel fish shoots out of the dispenser, bounces off "
"the dressing gown, slides across the towel covering the "
"drain, and is scooped up by a small cleaning robot that "
"emerges from a panel in the wall. The robot disappears back "
"into the wall.\n"
)
return True
if item_on_satchel is None:
out.tell(
"A small babel fish shoots out of the dispenser, bounces off "
"the dressing gown, slides across the towel, hits the satchel "
"blocking the robot panel, and flies upward -- straight into "
"the upper reaches of the room and out of sight.\n"
)
return True
# Success!
out.tell(
"A small babel fish shoots out of the dispenser, bounces off "
"the dressing gown, slides across the towel, hits the satchel "
"blocking the robot panel, flies upward, bounces off the junk "
"mail balanced on the satchel, and lands neatly in your ear.\n\n"
"You can suddenly understand everything around you. The babel "
"fish is now happily nestled in your ear.\n"
)
state.flags["babel_fish_in_ear"] = True
state.score += 12
return True
def _hook_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine":
if state.flags.get("gown_hung"):
out.tell("Your gown is hanging on the hook.\n")
else:
out.tell("A small hook on the wall opposite the dispenser.\n")
return True
if state.prsa in ("hang", "put"):
gown = state.world.objects.get("GOWN")
if state.prso is gown:
if not gown.is_held_by(state.protagonist):
out.tell("You're not carrying the gown.\n")
return True
state.flags["gown_hung"] = True
gown.move_to(state.world.local_globals)
out.tell("You hang the gown on the hook.\n")
return True
return False
def _drain_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine":
if state.flags.get("towel_on_drain"):
out.tell("The drain is covered by a towel.\n")
else:
out.tell("A small drain grate in the floor.\n")
return True
if state.prsa in ("cover", "put", "block"):
towel = state.world.objects.get("TOWEL")
if state.prso is towel:
if not towel.is_held_by(state.protagonist):
out.tell("You're not carrying the towel.\n")
return True
state.flags["towel_on_drain"] = True
towel.move_to(state.world.local_globals)
out.tell("You cover the drain with the towel.\n")
return True
return False
def _robot_panel_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine":
blocker = state.flags.get("panel_blocker")
if blocker:
out.tell(f"The robot panel is blocked by {blocker.the_desc()}.\n")
else:
out.tell("A small panel in the wall from which a cleaning robot emerges.\n")
return True
if state.prsa in ("put", "block", "cover"):
satchel = state.world.objects.get("SATCHEL")
if state.prso is satchel:
if not satchel.is_held_by(state.protagonist):
out.tell("You're not carrying the satchel.\n")
return True
state.flags["panel_blocker"] = satchel
satchel.move_to(state.world.local_globals)
out.tell("You put the satchel in front of the robot panel.\n")
return True
return False
def _babel_fish_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine":
if state.flags.get("babel_fish_in_ear"):
out.tell(
"The babel fish is snugly lodged in your ear, translating "
"all alien languages into English for you.\n"
)
else:
out.tell("A small, yellow, leech-like fish.\n")
return True
if state.prsa == "take":
if state.flags.get("babel_fish_in_ear"):
out.tell("It's far too comfortable in your ear to remove.\n")
return True
return False
def _vogon_captain_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine":
out.tell(
"The Vogon Captain is a large, slug-like creature with a "
"foul temper and a passion for bureaucratic paperwork. And "
"poetry. Especially poetry.\n"
)
return True
if state.prsa in ("tell", "ask", "talk"):
out.tell(
'The Captain grunts. "Resistance is useless!" he bellows.\n'
)
return True
return False
def _poetry_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine":
if state.flags.get("babel_fish_in_ear"):
out.tell(
"It's Vogon poetry. The third worst in the known galaxy.\n"
)
else:
out.tell(
"It sounds like someone gargling with a throat full of "
"live weasels.\n"
)
return True
if state.prsa in ("enjoy", "appreciate", "like", "listen"):
if not state.flags.get("babel_fish_in_ear"):
out.tell(
"You can't even understand it. How could you enjoy it?\n"
)
return True
if state.flags.get("poem_enjoyed"):
out.tell("You've already expressed your enjoyment.\n")
return True
state.flags["poem_enjoyed"] = True
state.score += 15
out.tell(
'You nod your head approvingly. "Oh, very good," you say.\n'
"The Captain beams with delight and continues reading.\n"
)
return True
return False
def _chair_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine":
out.tell(
"The Poetry Appreciation Chair is a fiendish Vogon device "
"that clamps you in place and forces you to listen. Steel "
"bands hold your arms, legs, and head firmly in position.\n"
)
return True
if state.prsa in ("get out", "leave", "escape", "stand"):
out.tell(
"The steel bands hold you firmly in the chair. You're not "
"going anywhere until the Captain decides otherwise.\n"
)
return True
return False
def _glass_case_action(state: GameState) -> bool:
out = state.output
case = state.world.get("GLASS-CASE")
if state.prsa == "examine":
if case.fset_q(Flag.OPENBIT):
out.tell("The glass case is open.\n")
else:
out.tell(
"A sealed glass case on the wall. Inside you can see a "
"device of some sort. There is a keyboard and a small "
"switch on the front.\n"
)
return True
if state.prsa == "open":
if case.fset_q(Flag.OPENBIT):
out.tell("It's already open.\n")
else:
out.tell("It won't open by force. Try the keyboard.\n")
return True
return False
def _keyboard_action(state: GameState) -> bool:
out = state.output
if state.prsa in ("type", "use", "push"):
case = state.world.get("GLASS-CASE")
if case.fset_q(Flag.OPENBIT):
out.tell("The case is already open.\n")
return True
# Accept any typing action -- the correct answer is typing a
# word from the poem while you understand it
if state.flags.get("babel_fish_in_ear") and state.flags.get("poem_enjoyed"):
case.fset(Flag.OPENBIT)
state.score += 25
out.tell(
"You type a word from the poem on the keyboard. The case "
"makes a satisfying click and swings open, revealing an "
"atomic vector plotter.\n"
)
return True
out.tell(
"You type something on the keyboard. Nothing happens. "
"Perhaps you need to type the right thing.\n"
)
return True
if state.prsa == "examine":
out.tell("A small keyboard attached to the glass case.\n")
return True
return False
def _switch_action(state: GameState) -> bool:
out = state.output
if state.prsa in ("push", "press", "flip", "turn on", "turn off"):
out.tell("Click. Nothing obvious happens.\n")
return True
if state.prsa == "examine":
out.tell("A small switch on the front of the glass case.\n")
return True
return False
def _plotter_action(state: GameState) -> bool:
out = state.output
case = state.world.get("GLASS-CASE")
if state.prsa == "take":
if not case.fset_q(Flag.OPENBIT):
out.tell("The plotter is sealed inside the glass case.\n")
return True
plotter = state.world.get("PLOTTER")
plotter.move_to(state.protagonist)
out.tell("You take the atomic vector plotter.\n")
return True
if state.prsa == "examine":
out.tell(
"It's an atomic vector plotter -- a small, sleek device "
"of obviously advanced technology.\n"
)
return True
return False
def _satchel_action(state: GameState) -> bool:
out = state.output
satchel = state.world.get("SATCHEL")
if state.prsa == "examine":
out.tell("It's Ford's battered leather satchel.\n")
return True
if state.prsa in ("open", "look in"):
visible = satchel.contents_string()
if visible:
descs = [obj.a_desc() for obj in visible]
out.tell("The satchel contains " + ", ".join(descs) + ".\n")
else:
out.tell("The satchel is empty.\n")
return True
return False
def _towel_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine":
out.tell(
"It's a large, fluffy towel. About the most massively "
"useful thing an interstellar hitchhiker can have.\n"
)
return True
return False
def _guide_action(state: GameState) -> bool:
out = state.output
if state.prsa in ("read", "examine", "consult"):
out.tell(
"The cover of the Guide reads, in large friendly letters: "
'"DON\'T PANIC"\n\n'
"The Guide has a lot to say on many subjects. It is the "
"standard repository of all knowledge and wisdom.\n"
)
return True
return False
def _peanuts_action(state: GameState) -> bool:
out = state.output
if state.prsa in ("eat", "open"):
out.tell(
"You eat the peanuts. They were rather good, as peanuts go.\n"
)
state.world.get("PEANUTS").move_to(state.world.local_globals)
return True
if state.prsa == "examine":
out.tell("A small packet of salted peanuts.\n")
return True
return False
def _ford_vogon_action(state: GameState) -> bool:
out = state.output
if state.prsa == "examine":
if state.flags.get("ford_sleeping"):
out.tell("Ford is slumped against the wall, fast asleep.\n")
else:
out.tell(
"Ford looks somewhat the worse for wear, but his eyes "
"are sharp and alert.\n"
)
return True
if state.prsa in ("tell", "ask", "talk"):
if state.flags.get("ford_sleeping"):
out.tell("Ford is asleep and doesn't respond.\n")
else:
out.tell('"Don\'t panic," says Ford.\n')
return True
if state.prsa == "wake":
if state.flags.get("ford_sleeping"):
out.tell("Ford grunts and rolls over but doesn't wake.\n")
else:
out.tell("Ford is already awake.\n")
return True
return False
# ---- Timed event handlers ----
def _i_groggy(state: GameState) -> bool:
"""Groggy countdown -- player must act before passing out."""
out = state.output
counter = state.flags.get("groggy_counter", 0)
if not state.flags.get("groggy"):
return False
if state.here and state.here.id != "HOLD":
return False
counter += 1
state.flags["groggy_counter"] = counter
if counter == 1:
out.tell(
"\nYour head is spinning. You feel very groggy and confused.\n"
)
return True
if counter == 2:
out.tell(
"\nThe room lurches sickeningly. You really don't feel well.\n"
)
return True
if counter >= 3:
state.jigs_up(
"The room spins wildly and you pass out on the filthy floor. "
"You are woken some time later by a Vogon guard who drags "
"you off and throws you out of an airlock."
)
return True
return False
def _i_ford(state: GameState) -> bool:
"""Ford gives the player the Guide and goes to sleep."""
out = state.output
if state.here and state.here.id != "HOLD":
return False
ford = state.world.get("FORD-VOGON")
guide = state.world.get("GUIDE")
satchel = state.world.get("SATCHEL")
towel = state.world.get("TOWEL")
out.tell(
'\nFord rummages through his satchel. "Here," he says, handing '
'you a battered book. "The Hitchhiker\'s Guide to the Galaxy. '
"It's the most remarkable book ever to come out of the great "
'publishing corporations of Ursa Minor."\n\n'
"He also hands you a towel.\n\n"
'"A towel," says Ford, "is about the most massively useful thing '
'an interstellar hitchhiker can have."\n\n'
"With that, Ford slumps against the wall and falls asleep.\n"
)
guide.move_to(state.protagonist)
towel.move_to(state.protagonist)
satchel.move_to(state.here)
state.flags["ford_sleeping"] = True
return True
def _i_announcement(state: GameState) -> bool:
"""Intercom announcement."""
out = state.output
if state.here and state.here.id != "HOLD":
return False
out.tell(
"\nThere is a crackle from the intercom. A Vogon voice "
'announces: "Attention. This is your Captain speaking. We will '
"shortly be arriving at our destination. Passengers are reminded "
'that the airlock is NOT an emergency exit."\n'
)
return True
def _i_guards(state: GameState) -> bool:
"""Guards arrive to take you to the Captain."""
out = state.output
if state.here and state.here.id != "HOLD":
return False
out.tell(
"\nThe door bursts open. Two Vogon guards stomp in, grab you "
"and Ford by your collars, and drag you down the corridor to "
"the Captain's quarters.\n"
)
# Move player and Ford to the Captain's quarters
captains_quarters = state.world.get_room("CAPTAINS-QUARTERS")
state.here = captains_quarters
state.protagonist.move_to(captains_quarters)
ford = state.world.get("FORD-VOGON")
ford.move_to(captains_quarters)
state.flags["ford_sleeping"] = False
# Start the captain sequence
state.flags["captain_counter"] = 0
state.clock.queue(_i_captain, -1, name="I-CAPTAIN")
return True
def _i_captain(state: GameState) -> bool:
"""Poetry reading sequence in the Captain's quarters."""
out = state.output
if state.here and state.here.id != "CAPTAINS-QUARTERS":
return False
counter = state.flags.get("captain_counter", 0)
state.flags["captain_counter"] = counter + 1
has_fish = state.flags.get("babel_fish_in_ear", False)
if counter == 0:
out.tell(
'\nThe Vogon Captain clears his throat. "I\'m now going to '
"read you some of my poetry,\" he announces.\n"
)
return True
# Read poetry lines (counter 1-5)
if 1 <= counter <= 5:
line_idx = counter - 1
if has_fish:
line = POETRY_LINES[line_idx]
else:
line = _gibberish_line()
out.tell(f"\nThe Captain reads: {line}\n")
if counter == 5:
if has_fish:
out.tell(
"\nThe Captain pauses and looks at you expectantly.\n"
)
else:
out.tell(
"\nThe Captain finishes. It sounded like someone "
"gargling with quicksand.\n"
)
return True
# After the first verse
if counter == 6:
enjoyed = state.flags.get("poem_enjoyed", False)
if enjoyed and has_fish:
out.tell(
'\nThe Captain is delighted. "You liked it! Oh how '
"wonderful! Let me read you another!\"\n"
)
state.flags["captain_counter"] = 100 # jump to second verse
return True
else:
_eject_to_airlock(state)
return True
# Second verse (counters 101-103)
if 101 <= counter <= 103:
line_idx = counter - 101
if line_idx < len(POETRY_VERSE_2):
line = POETRY_VERSE_2[line_idx]
out.tell(f"\nThe Captain reads: {line}\n")
if line_idx == len(POETRY_VERSE_2) - 1:
# After second verse, eject
out.tell(
'\n"Now," says the Captain, "did you enjoy that?"\n'
"Before you can answer, the guards grab you.\n"
)
return True
if counter == 104:
_eject_to_airlock(state)
return True
return False
def _eject_to_airlock(state: GameState) -> None:
"""Guards drag you from the Captain's quarters to the hold, then airlock."""
out = state.output
out.tell(
"\nThe Vogon guards grab you and Ford, drag you struggling "
"down the corridor, through the hold, and hurl you into the "
"airlock.\n"
)
# Disable the captain timer
state.clock.queue(_i_captain, 0, name="I-CAPTAIN")
for entry in state.clock.entries:
if entry.routine is _i_captain:
entry.enabled = False
# Move to airlock
airlock = state.world.get_room("AIRLOCK")
state.here = airlock
state.protagonist.move_to(airlock)
ford = state.world.get("FORD-VOGON")
ford.move_to(airlock)
state.flags["airlock_counter"] = 0
state.clock.queue(_i_airlock, -1, name="I-AIRLOCK")
def _i_airlock(state: GameState) -> bool:
"""Airlock countdown -- Ford's dialogue then ejection into space."""
out = state.output
if state.here and state.here.id != "AIRLOCK":
return False
counter = state.flags.get("airlock_counter", 0)
counter += 1
state.flags["airlock_counter"] = counter
if counter == 1:
out.tell(
'\nFord says: "I wonder if we\'ll be picked up by another '
"ship. The chances are pretty remote, of course, but it's "
'our only hope."\n'
)
return True
if counter == 2:
out.tell(
"\nFord is rummaging in his pockets for something. "
'"I had a Sub-Etha Sens-O-Matic somewhere..." he mutters.\n'
)
return True
if counter == 3:
out.tell(
'\nFord says: "If we hold our breath, we might survive for '
"about thirty seconds in the vacuum of space. It's not "
'long, but it might just be enough."\n'
)
return True
if counter >= 4:
out.tell(
"\nWith a great hiss, the outer airlock door opens. The "
"air rushes out. You and Ford are sucked into the cold "
"vacuum of space.\n\n"
"You gasp. Stars wheel around you. The cold is incredible.\n"
)
# Disable airlock timer
for entry in state.clock.entries:
if entry.routine is _i_airlock:
entry.enabled = False
# Set heart probability for Heart of Gold sequence
state.flags["heart_prob"] = 100
# Transition to DARK room
dark = state.world.rooms.get("DARK")
if dark:
state.here = dark
state.protagonist.move_to(dark)
else:
# If DARK room doesn't exist yet, end the sequence
out.tell(
"\nYou drift in the void of space...\n"
"Everything goes dark.\n"
)
return True
return False
# ---- Room action handlers ----
def _hold_action(state: GameState, rarg: str) -> bool:
out = state.output
if rarg == "M-LOOK":
out.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.\n"
)
return True
if rarg == "M-END":
hold = state.world.get_room("HOLD")
if hold.fset_q(Flag.REVISITBIT):
# Revisit -- guards stun you
state.jigs_up(
"A Vogon guard spots you wandering around and stuns you "
"with a blast from his kill-o-zap gun."
)
return True
if not hold.fset_q(Flag.TOUCHBIT):
# First visit
hold.fset(Flag.TOUCHBIT)
hold.fset(Flag.REVISITBIT)
# Give player peanuts
peanuts = state.world.get("PEANUTS")
peanuts.move_to(state.protagonist)
# Move Ford here
ford = state.world.get("FORD-VOGON")
ford.move_to(hold)
# Set groggy state
state.flags["groggy"] = True
state.flags["groggy_counter"] = 0
# Add score
state.score += 8
out.tell(
"\nYou 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"
"You are lying on what feels like a pile of old mattresses "
"in a room that smells like the inside of a pair of "
"Vogon-ripper trainers.\n\n"
'Ford Prefect is here. "It\'s OK," he says, "we\'re safe '
'now. We\'re on a Vogon ship."\n\n'
"He hands you a small packet of peanuts.\n"
)
# Queue timed events
state.clock.queue(_i_groggy, 3, name="I-GROGGY")
state.clock.queue(_i_ford, 6, name="I-FORD")
state.clock.queue(_i_announcement, 18, name="I-ANNOUNCEMENT")
state.clock.queue(_i_guards, 36, name="I-GUARDS")
return True
return False
def _hold_east_exit(state: GameState) -> "Room | None":
"""Exit from hold east to airlock -- requires inner door open."""
out = state.output
door = state.world.get("INNER-DOOR")
if not door.fset_q(Flag.OPENBIT):
out.tell("The inner airlock door is closed.\n")
return None
return state.world.get_room("AIRLOCK")
def _captains_quarters_action(state: GameState, rarg: str) -> bool:
out = state.output
if rarg == "M-LOOK":
out.tell(
"This is the cabin of the Vogon Captain. You and Ford are "
"strapped into poetry appreciation chairs.\n"
)
return True
return False
def _airlock_action(state: GameState, rarg: str) -> bool:
out = state.output
if rarg == "M-LOOK":
out.tell(
"This airlock has massive doors to port and starboard.\n"
)
return True
return False
# ---- Registration ----
def register(world: World, state: GameState) -> None:
"""Create all Vogon ship rooms and objects."""
# ---- Initialize state flags ----
state.flags.setdefault("groggy", False)
state.flags.setdefault("groggy_counter", 0)
state.flags.setdefault("gown_hung", False)
state.flags.setdefault("panel_blocker", None)
state.flags.setdefault("item_on_satchel", None)
state.flags.setdefault("fish_counter", 5)
state.flags.setdefault("babel_fish_in_ear", False)
state.flags.setdefault("captain_counter", 0)
state.flags.setdefault("poem_enjoyed", False)
state.flags.setdefault("airlock_counter", 0)
state.flags.setdefault("guards_counter", 0)
state.flags.setdefault("ford_sleeping", False)
# ---- Global objects for the ship ----
inner_door = world.register(GameObject(
"INNER-DOOR", desc="inner door",
synonyms=["door", "inner"],
adjectives=["inner", "airlock"],
flags={Flag.DOORBIT, Flag.NDESCBIT},
action=_inner_door_action,
))
inner_door.move_to(world.local_globals)
airlock_obj = world.register(GameObject(
"AIRLOCK-OBJ", desc="airlock",
synonyms=["airlock"],
flags={Flag.NDESCBIT},
action=_airlock_obj_action,
))
airlock_obj.move_to(world.local_globals)
# ---- HOLD ----
hold = world.register(Room(
"HOLD", desc="Vogon Hold",
flags={Flag.RLANDBIT, Flag.ONBIT},
action=_hold_action,
global_objects=[inner_door, airlock_obj],
))
# Babel fish dispenser and puzzle objects
dispenser = world.register(GameObject(
"DISPENSER", desc="babel fish dispenser",
synonyms=["dispenser", "machine"],
adjectives=["babel", "fish"],
flags={Flag.NDESCBIT},
action=_dispenser_action,
))
dispenser.move_to(hold)
dispenser_button = world.register(GameObject(
"DISPENSER-BUTTON", desc="dispenser button",
synonyms=["button"],
adjectives=["dispenser"],
flags={Flag.NDESCBIT},
action=_dispenser_button_action,
))
dispenser_button.move_to(hold)
hook = world.register(GameObject(
"HOOK", desc="hook",
synonyms=["hook", "peg"],
adjectives=["small", "wall"],
flags={Flag.NDESCBIT},
action=_hook_action,
))
hook.move_to(hold)
drain = world.register(GameObject(
"DRAIN", desc="drain",
synonyms=["drain", "grate"],
adjectives=["small", "floor"],
flags={Flag.NDESCBIT},
action=_drain_action,
))
drain.move_to(hold)
robot_panel = world.register(GameObject(
"ROBOT-PANEL", desc="robot panel",
synonyms=["panel"],
adjectives=["robot", "small", "wall"],
flags={Flag.NDESCBIT},
action=_robot_panel_action,
))
robot_panel.move_to(hold)
babel_fish = world.register(GameObject(
"BABEL-FISH", desc="babel fish",
synonyms=["fish"],
adjectives=["babel", "small", "yellow"],
flags={Flag.NDESCBIT, Flag.INVISIBLE},
action=_babel_fish_action,
))
babel_fish.move_to(world.local_globals)
# Glass case with plotter
glass_case = world.register(GameObject(
"GLASS-CASE", desc="glass case",
synonyms=["case"],
adjectives=["glass", "sealed"],
flags={Flag.CONTBIT, Flag.NDESCBIT, Flag.SEARCHBIT},
action=_glass_case_action,
))
glass_case.move_to(hold)
keyboard = world.register(GameObject(
"KEYBOARD", desc="keyboard",
synonyms=["keyboard", "keys"],
adjectives=["small"],
flags={Flag.NDESCBIT},
action=_keyboard_action,
))
keyboard.move_to(hold)
switch = world.register(GameObject(
"SWITCH", desc="small switch",
synonyms=["switch"],
adjectives=["small"],
flags={Flag.NDESCBIT},
action=_switch_action,
))
switch.move_to(hold)
plotter = world.register(GameObject(
"PLOTTER", desc="atomic vector plotter",
synonyms=["plotter", "device"],
adjectives=["atomic", "vector"],
flags={Flag.TAKEBIT, Flag.NDESCBIT},
size=4,
action=_plotter_action,
))
plotter.move_to(glass_case)
# Ford (Vogon ship version -- separate from earth Ford)
ford = world.register(GameObject(
"FORD-VOGON", desc="Ford Prefect",
synonyms=["ford", "prefect"],
adjectives=["ford"],
flags={Flag.NARTICLEBIT, Flag.ACTORBIT, Flag.NDESCBIT},
action=_ford_vogon_action,
))
# Items Ford gives or that appear on the ship
peanuts = world.register(GameObject(
"PEANUTS", desc="small packet of peanuts",
synonyms=["peanuts", "packet", "nuts"],
adjectives=["small"],
flags={Flag.TAKEBIT},
size=2,
action=_peanuts_action,
))
satchel = world.register(GameObject(
"SATCHEL", desc="satchel",
synonyms=["satchel", "bag"],
adjectives=["ford's", "leather", "battered"],
flags={Flag.TAKEBIT, Flag.CONTBIT, Flag.SEARCHBIT, Flag.OPENBIT},
size=10, capacity=20,
action=_satchel_action,
))
towel = world.register(GameObject(
"TOWEL", desc="towel",
synonyms=["towel"],
adjectives=["large", "fluffy"],
flags={Flag.TAKEBIT},
size=4,
action=_towel_action,
))
guide = world.register(GameObject(
"GUIDE", desc="Hitchhiker's Guide",
synonyms=["guide", "book"],
adjectives=["hitchhiker's", "electronic"],
flags={Flag.TAKEBIT, Flag.READBIT, Flag.NARTICLEBIT},
size=3,
text='The cover reads: "DON\'T PANIC"',
action=_guide_action,
))
# ---- CAPTAIN'S QUARTERS ----
captains_quarters = world.register(Room(
"CAPTAINS-QUARTERS", desc="Captain's Quarters",
flags={Flag.RLANDBIT, Flag.ONBIT},
action=_captains_quarters_action,
))
vogon_captain = world.register(GameObject(
"VOGON-CAPTAIN", desc="Vogon Captain",
synonyms=["captain", "vogon"],
adjectives=["vogon"],
flags={Flag.NARTICLEBIT, Flag.ACTORBIT, Flag.NDESCBIT},
action=_vogon_captain_action,
))
vogon_captain.move_to(captains_quarters)
poetry = world.register(GameObject(
"POETRY", desc="poetry",
synonyms=["poetry", "poem", "verse"],
adjectives=["vogon"],
flags={Flag.NDESCBIT, Flag.NARTICLEBIT},
action=_poetry_action,
))
poetry.move_to(captains_quarters)
chair = world.register(GameObject(
"POETRY-APPRECIATION-CHAIR", desc="poetry appreciation chair",
synonyms=["chair", "chairs"],
adjectives=["poetry", "appreciation"],
flags={Flag.VEHBIT, Flag.NDESCBIT},
action=_chair_action,
))
chair.move_to(captains_quarters)
# ---- AIRLOCK ----
airlock = world.register(Room(
"AIRLOCK", desc="Airlock",
flags={Flag.RLANDBIT, Flag.ONBIT},
action=_airlock_action,
global_objects=[inner_door, airlock_obj],
))
# ---- Connect rooms ----
hold.exits = {
Direction.WEST: BlockedExit(
"The door to the corridor is locked (from the outside)."
),
Direction.EAST: ConditionalExit(_hold_east_exit),
}
# Captain's quarters has no exits -- you arrive via guards
captains_quarters.exits = {}
# Airlock exits are blocked
airlock.exits = {
Direction.WEST: BlockedExit(
"The inner door has sealed behind you."
),
Direction.EAST: BlockedExit(
"The outer door is massive and immovable. Not that you'd "
"want to open it."
),
}