""" Core initialization module for PygStormGames framework. Provides the main PygStormGames class that serves as the central hub for game functionality. """ import pyglet import time from .config import Config from .display import Display from .menu import Menu from .scoreboard import Scoreboard from .sound import Sound from .speech import Speech class pygstormgames: """Main class that coordinates all game systems.""" def __init__(self, gameTitle): """Initialize the game framework. Args: gameTitle (str): Title of the game """ self.gameTitle = gameTitle self._paused = False # Initialize core systems self.config = Config(gameTitle) self.display = Display(self) self.speech = Speech() self.sound = Sound(self) self.scoreboard = Scoreboard(self) self.menu = Menu(self) # Play intro sound if available try: player = self.sound.play_sound('game-intro') if player: startTime = time.time() duration = player.source.duration # Make sure to give pyglet enough cycles to start playing pyglet.clock.tick() interrupted = self.wait_for_completion( lambda: not player.playing or (time.time() - startTime) >= duration ) if interrupted: player.pause() except: pass # Set up window event handlers after intro is complete self.display.window.push_handlers(self.on_key_press) def on_key_press(self, symbol, modifiers): """Handle global keyboard events. Args: symbol: Pyglet key symbol modifiers: Key modifiers """ if self._paused: if symbol == pyglet.window.key.BACKSPACE: self._paused = False self.sound.resume() self.speech.speak("Game resumed") else: # Global exit handler if symbol == pyglet.window.key.ESCAPE: self.exit_game() # Global pause handler if symbol == pyglet.window.key.BACKSPACE: self.pause_game() def run(self): """Start the game loop.""" pyglet.app.run() def pause_game(self): """Pause all game systems and wait for resume.""" self._paused = True self.sound.pause() self.speech.speak("Game paused, press backspace to resume.") def exit_game(self): """Clean up and exit the game.""" self.sound.cleanup() self.speech.cleanup() pyglet.app.exit() def wait(self, validKeys=None, timeout=None): """Wait for key press(es) with optional timeout. Args: validKeys (list, optional): List of pyglet.window.key values to wait for. If None, accepts any key press. timeout (float, optional): Time in seconds to wait for input. If None, waits indefinitely. Returns: tuple: (key, modifiers) that were pressed. Returns (None, None) on timeout. """ keyResult = [None, None] # Use list to allow modification in closure start_time = time.time() def on_key_press(symbol, modifiers): if validKeys is None or symbol in validKeys: keyResult[0] = symbol keyResult[1] = modifiers return pyglet.event.EVENT_HANDLED # Register temporary handler self.display.window.push_handlers(on_key_press=on_key_press) # Wait for valid key press or timeout while keyResult[0] is None: self.display.window.dispatch_events() pyglet.clock.tick() # Check for timeout if timeout is not None and time.time() - start_time > timeout: break # Clean up self.display.window.remove_handlers() return tuple(keyResult) def wait_for_completion(self, condition, validKeys=None, timeout=None): """Wait for either a condition to be met, valid keys to be pressed, or timeout. Args: condition: Function that returns True when waiting should end validKeys (list, optional): List of pyglet.window.key values that can interrupt If None, uses ESCAPE, RETURN, and SPACE timeout (float, optional): Time in seconds to wait before timing out If None, waits indefinitely Returns: bool: True if interrupted by key press or timeout, False if condition was met """ if validKeys is None: validKeys = [pyglet.window.key.ESCAPE, pyglet.window.key.RETURN, pyglet.window.key.SPACE] interrupted = [False] # Use list to allow modification in closure start_time = time.time() def on_key_press(symbol, modifiers): if symbol in validKeys: interrupted[0] = True return pyglet.event.EVENT_HANDLED self.display.window.push_handlers(on_key_press=on_key_press) while not condition() and not interrupted[0]: self.display.window.dispatch_events() pyglet.clock.tick() # Check for timeout if timeout is not None and time.time() - start_time > timeout: interrupted[0] = True break self.display.window.remove_handlers() return interrupted[0] def exit_game(self): """Closes the game cleanly""" try: self.sound.cleanup() except Exception as e: print(f"Error with sound cleanup: {e}") pass try: self.display.window.remove_handlers() except Exception as e: print(f"Error with handler cleanup: {e}") pass try: self.speech.cleanup() except Exception as e: print(f"Error with speech cleanup: {e}") pass try: # Try to close the window explicitly if hasattr(self.display, 'window'): self.display.window.close() except Exception as e: print(f"Error closing window: {e}") pass try: pyglet.app.exit() except Exception as e: print(f"Error while exiting: {e}") pass # Force exit if pyglet.app.exit() didn't work import sys sys.exit(0)