Wire game transitions end-to-end, add Guide lookup, add 79 tests
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>
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
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
|
||||
Reference in New Issue
Block a user