679639df9f
Transitions: - Add I-HOUSEWRECK (tick 20) and I-VOGONS (tick 50) timed events to earth.py, queued at startup in main.py - I-VOGONS demolishes Earth and moves player to Vogon Hold - Fix airlock→Dark transition to call Dark room M-ENTER handler - Fix dream-restore to support multiple callbacks (list instead of single) - Add state.finish() call to RAMP for endgame victory Guide system: - Add 16-entry lookup database to GUIDE object (space, towel, vogons, poetry, beast, babel fish, earth, magrathea, marvin, etc.) - "consult guide about X" now returns relevant entry text Tests (79 passing): - test_engine.py (14): containment, flags, articles, clock mechanics - test_parser.py (20): directions, compound verbs, prepositions, synonyms - test_earth.py (21): full opening sequence, puzzles, navigation - test_vogon.py (4): room existence, Hold first-visit sequence - test_dark.py (7): inventory clearing, dream dispatch, probabilities - conftest.py: shared game fixture and send() helper Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
76 lines
2.3 KiB
Python
76 lines
2.3 KiB
Python
import pytest
|
|
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
|
|
from h2g2.content import globals_content, earth, vogon, heart, unearth, dark
|
|
import h2g2.engine.verbs # noqa: F401 — register handlers
|
|
|
|
|
|
@pytest.fixture
|
|
def game():
|
|
"""Create a fully initialized game world."""
|
|
world = World()
|
|
globals_content.register(world)
|
|
earth.register(world)
|
|
|
|
output = Output()
|
|
clock = Clock()
|
|
state = GameState(world, output, clock)
|
|
|
|
state.protagonist = world.protagonist
|
|
state.here = world.get_room("BEDROOM")
|
|
state.winner = world.protagonist
|
|
state.lying_down = True
|
|
|
|
# Initialize flags (same as main.py)
|
|
state.flags["headache"] = True
|
|
state.flags["groggy"] = False
|
|
state.flags["groggy_counter"] = 0
|
|
state.flags["house_demolished"] = False
|
|
state.flags["earth_demolished"] = False
|
|
state.flags["in_front_of_bulldozer"] = False
|
|
state.flags["ford_arrived"] = False
|
|
state.flags["ford_has_satchel"] = True
|
|
state.flags["prosser_in_mud"] = False
|
|
state.flags["beer_counter"] = 0
|
|
state.flags["babel_fish_in_ear"] = False
|
|
state.flags["poem_enjoyed"] = False
|
|
state.flags["holding_no_tea"] = True
|
|
state.flags["dead_counter"] = 0
|
|
state.flags["vogon_prob"] = 100
|
|
state.flags["heart_prob"] = 0
|
|
state.flags["traal_prob"] = 60
|
|
state.flags["fleet_prob"] = 0
|
|
state.flags["whale_prob"] = 0
|
|
|
|
state.inventory_extras.append(
|
|
lambda s: "a splitting headache" if s.flags.get("headache") else None
|
|
)
|
|
state.inventory_extras.append(
|
|
lambda s: "no tea" if s.flags.get("holding_no_tea") else None
|
|
)
|
|
|
|
# Register content that needs state
|
|
vogon.register(world, state)
|
|
heart.register(world, state)
|
|
unearth.register(world, state)
|
|
dark.register(world, state)
|
|
|
|
parser = Parser()
|
|
loop = GameLoop(state, parser)
|
|
|
|
return state, parser, loop
|
|
|
|
|
|
def send(game_tuple, command: str) -> str:
|
|
"""Send a command to the game and return the output text."""
|
|
state, parser, loop = game_tuple
|
|
result = parser.parse(command, state)
|
|
if result:
|
|
loop._execute(result)
|
|
text = state.output.flush()
|
|
return text
|