#!/usr/bin/env python3 import argparse import os import random import sys import time from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[1] if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) def parse_args(): parser = argparse.ArgumentParser(description="Render a real Mice menu screen to a PNG preview") parser.add_argument("--output", default="/tmp/mice_menu_preview.png", help="Output PNG path") parser.add_argument("--screen", choices=("start", "pause", "level_intro"), default="start") parser.add_argument("--difficulty", choices=("easy", "normal", "hard", "medium"), default="hard") parser.add_argument("--level", type=int, default=0, help="0-based level index") parser.add_argument("--resolution", default="1280x720", help="Preview resolution, for example 1280x720") parser.add_argument("--seed", type=int, default=1337, help="Random seed for deterministic previews") parser.add_argument("--animation-ms", type=int, default=1200, help="Start-menu GIF timestamp in milliseconds") return parser.parse_args() def configure_environment(args): os.environ.setdefault("MICE_PROJECT_ROOT", str(PROJECT_ROOT)) os.environ.setdefault("SDL_VIDEODRIVER", "dummy") os.environ.setdefault("SDL_AUDIODRIVER", "dummy") os.environ.setdefault("SDL_RENDER_DRIVER", "software") os.environ.setdefault("MICE_DISABLE_JOYSTICK", "1") os.environ["RESOLUTION"] = args.resolution def build_game(args): from engine import maze, sdl2 as engine from rats import MiceMaze original_show_intro = engine.GameWindow.show_intro original_load_joystick = engine.GameWindow.load_joystick original_start_game = MiceMaze.start_game def preview_start_game(self): self.start_menu_animation_started_at = time.monotonic() self.current_level_music = self._resolve_level_music(self.current_level) self._valid_positions = None self.run_recorded = False self.ammo = { "bomb": {"count": 2, "max": 8}, "nuclear": {"count": 1, "max": 1}, "mine": {"count": 2, "max": 4}, "gas": {"count": 2, "max": 4}, } self.blood_stains = {} self.background_texture = None self.blood_layer_sprites.clear() self.cave_foreground_tiles.clear() self.game_end = (False, None) self.game_status = "start_menu" self.menu_screen = "start" self.units.clear() self.unit_positions.clear() self.unit_positions_before.clear() self.points = 0 self.pointer = (self.map.width // 2, self.map.height // 2) self.scroll_cursor() engine.GameWindow.show_intro = lambda self, *a, **k: None engine.GameWindow.load_joystick = lambda self: None MiceMaze.start_game = preview_start_game try: game = MiceMaze(maze.get_default_map_source(), level_index=args.level) finally: engine.GameWindow.show_intro = original_show_intro engine.GameWindow.load_joystick = original_load_joystick MiceMaze.start_game = original_start_game game.render_engine.audio = False game._apply_difficulty(args.difficulty, persist=False) game.start_menu_animation_started_at = time.monotonic() - args.animation_ms / 1000 return game def render_screen(game, screen_name): renderer = game.render_engine.renderer renderer.clear() game.draw_maze() if screen_name == "start": game.game_status = "start_menu" game.menu_screen = "start" game.render_start_menu() elif screen_name == "pause": game.game_status = "paused" game.menu_screen = None game.render_pause_menu() else: game.game_status = "start_menu" game.menu_screen = "level_intro" game.render_engine.dialog( f"Level {game.current_level + 1}", subtitle=f"Points: {game.points}\nPress Return to begin", image=game.assets["BMP_WEWIN"], ) renderer.present() def main(): args = parse_args() configure_environment(args) random.seed(args.seed) game = build_game(args) output_path = Path(args.output).expanduser() try: render_screen(game, args.screen) saved_path = game.render_engine.save_frame(output_path) print(saved_path) finally: game.render_engine.close() if __name__ == "__main__": sys.exit(main())