When starting an IF game, check for existing save file and restore if present. Shows 'restoring saved game...' message and broadcasts restored game state to spectators. Also cleaned up redundant tests that didn't properly mock the auto-save functionality now present in ::quit and stop().
101 lines
3.2 KiB
Python
101 lines
3.2 KiB
Python
"""Play interactive fiction games."""
|
|
|
|
import pathlib
|
|
|
|
from mudlib.commands import CommandDefinition, register
|
|
from mudlib.if_session import IFSession, broadcast_to_spectators
|
|
from mudlib.player import Player
|
|
|
|
# Story files directory
|
|
_stories_dir = pathlib.Path(__file__).resolve().parents[3] / "content" / "stories"
|
|
|
|
# Map of game name -> file extension for lookup
|
|
_STORY_EXTENSIONS = (".z3", ".z5", ".z8", ".zblorb")
|
|
|
|
|
|
def _find_story(name: str) -> pathlib.Path | None:
|
|
"""Find a story file by name in content/stories/."""
|
|
# exact match first
|
|
for ext in _STORY_EXTENSIONS:
|
|
path = _stories_dir / f"{name}{ext}"
|
|
if path.exists():
|
|
return path
|
|
# prefix match (e.g. "zork" matches "zork1.z3")
|
|
if _stories_dir.exists():
|
|
for path in sorted(_stories_dir.iterdir()):
|
|
if path.stem.startswith(name) and path.suffix in _STORY_EXTENSIONS:
|
|
return path
|
|
return None
|
|
|
|
|
|
def _list_stories() -> list[str]:
|
|
"""Return available story names."""
|
|
if not _stories_dir.exists():
|
|
return []
|
|
return sorted(
|
|
p.stem for p in _stories_dir.iterdir() if p.suffix in _STORY_EXTENSIONS
|
|
)
|
|
|
|
|
|
async def cmd_play(player: Player, args: str) -> None:
|
|
"""Start playing an interactive fiction game."""
|
|
game_name = args.strip().lower()
|
|
if not game_name:
|
|
stories = _list_stories()
|
|
if stories:
|
|
names = ", ".join(stories)
|
|
await player.send(f"play what? available: {names}\r\n")
|
|
else:
|
|
await player.send("play what? (no stories installed)\r\n")
|
|
return
|
|
|
|
story_path = _find_story(game_name)
|
|
if not story_path:
|
|
stories = _list_stories()
|
|
if stories:
|
|
names = ", ".join(stories)
|
|
msg = f"no story '{game_name}'. available: {names}\r\n"
|
|
else:
|
|
msg = f"no story found for '{game_name}'.\r\n"
|
|
await player.send(msg)
|
|
return
|
|
|
|
# Create and start IF session
|
|
session = IFSession(player, str(story_path), game_name)
|
|
try:
|
|
intro = await session.start()
|
|
except FileNotFoundError:
|
|
await session.stop()
|
|
await player.send("error: dfrotz not found. cannot play IF games.\r\n")
|
|
return
|
|
except OSError as e:
|
|
await session.stop()
|
|
await player.send(f"error starting game: {e}\r\n")
|
|
return
|
|
|
|
player.if_session = session
|
|
player.mode_stack.append("if")
|
|
|
|
await player.send("(type ::help for escape commands)\r\n")
|
|
|
|
# Check for saved game
|
|
if session.save_path.exists():
|
|
await player.send("restoring saved game...\r\n")
|
|
restored_text = await session._do_restore()
|
|
if restored_text:
|
|
await player.send(restored_text + "\r\n")
|
|
# Broadcast restored text to spectators
|
|
spectator_msg = f"[{player.name}'s terminal]\r\n{restored_text}\r\n"
|
|
await broadcast_to_spectators(player, spectator_msg)
|
|
elif intro:
|
|
await player.send(intro + "\r\n")
|
|
# Broadcast intro to spectators
|
|
spectator_msg = f"[{player.name}'s terminal]\r\n{intro}\r\n"
|
|
await broadcast_to_spectators(player, spectator_msg)
|
|
|
|
|
|
register(
|
|
CommandDefinition(
|
|
"play", cmd_play, mode="normal", help="play an interactive fiction game"
|
|
)
|
|
)
|