pygstormgames/menu.py

217 lines
7.6 KiB
Python

"""Menu system module for PygStormGames.
Handles main menu and submenu functionality for games.
"""
import os
import pyglet
from os.path import isfile, join
from pyglet.window import key
class Menu:
"""Handles menu systems."""
def __init__(self, game):
"""Initialize menu system.
Args:
game (PygStormGames): Reference to main game object
"""
self.game = game
self.currentIndex = 0
def show_menu(self, options, title=None, with_music=False):
"""Display a menu and return selected option."""
if with_music:
try:
if self.game.sound.currentBgm:
self.game.sound.currentBgm.pause()
self.game.sound.play_bgm("sounds/music_menu.ogg")
except:
pass
self.currentIndex = 0
lastSpoken = -1
selection = None # Add this to store the selection
if title:
self.game.speech.speak(title)
def key_handler(symbol, modifiers): # Define handler outside event
nonlocal selection, lastSpoken
# Handle Alt+volume controls
if modifiers & key.MOD_ALT:
if symbol == key.PAGEUP:
self.game.sound.adjust_master_volume(0.1)
elif symbol == key.PAGEDOWN:
self.game.sound.adjust_master_volume(-0.1)
elif symbol == key.HOME:
self.game.sound.adjust_bgm_volume(0.1)
elif symbol == key.END:
self.game.sound.adjust_bgm_volume(-0.1)
elif symbol == key.INSERT:
self.game.sound.adjust_sfx_volume(0.1)
elif symbol == key.DELETE:
self.game.sound.adjust_sfx_volume(-0.1)
return
if symbol == key.ESCAPE:
selection = "exit"
return pyglet.event.EVENT_HANDLED
if symbol == key.HOME and self.currentIndex != 0:
self.currentIndex = 0
self.game.sound.play_sound('menu-move')
lastSpoken = -1 # Force speech
elif symbol == key.END and self.currentIndex != len(options) - 1:
self.currentIndex = len(options) - 1
self.game.sound.play_sound('menu-move')
lastSpoken = -1 # Force speech
elif symbol in (key.DOWN, key.S) and self.currentIndex < len(options) - 1:
self.currentIndex += 1
self.game.sound.play_sound('menu-move')
lastSpoken = -1 # Force speech
elif symbol in (key.UP, key.W) and self.currentIndex > 0:
self.currentIndex -= 1
self.game.sound.play_sound('menu-move')
lastSpoken = -1 # Force speech
elif symbol == key.RETURN:
self.game.sound.play_sound('menu-select')
selection = options[self.currentIndex]
return pyglet.event.EVENT_HANDLED
return pyglet.event.EVENT_HANDLED
# Register the handler
self.game.display.window.push_handlers(on_key_press=key_handler)
# Main menu loop
while selection is None:
if self.currentIndex != lastSpoken:
self.game.speech.speak(options[self.currentIndex])
lastSpoken = self.currentIndex
self.game.display.window.dispatch_events()
# Clean up
self.game.display.window.remove_handlers()
return selection
def game_menu(self):
"""Show main game menu."""
options = [
"play",
"instructions",
"learn_sounds",
"credits",
"donate",
"exit"
]
while True:
selection = self.show_menu(options, with_music=True)
if selection == "play":
return selection
elif selection == "instructions":
# Pause menu music
if self.game.sound.currentBgm:
self.game.sound.currentBgm.pause()
self.game.display.instructions(self.game.speech)
# Resume menu music
if self.game.sound.currentBgm:
self.game.sound.currentBgm.play()
elif selection == "learn_sounds":
if self.learn_sounds() == "menu":
continue
elif selection == "credits":
# Pause menu music
if self.game.sound.currentBgm:
self.game.sound.currentBgm.pause()
self.game.display.credits(self.game.speech)
# Resume menu music
if self.game.sound.currentBgm:
self.game.sound.currentBgm.play()
elif selection == "donate":
# Pause menu music
if self.game.sound.currentBgm:
self.game.sound.currentBgm.pause()
self.game.display.donate(self.game.speech)
# Resume menu music
if self.game.sound.currentBgm:
self.game.sound.currentBgm.play()
def learn_sounds(self):
"""Interactive menu for learning game sounds.
Allows users to:
- Navigate through available sounds
- Play selected sounds
- Return to menu with escape key
Returns:
str: "menu" if user exits with escape
"""
try:
self.game.sound.currentBgm.pause()
except:
pass
self.currentIndex = 0
# Get list of available sounds, excluding special sounds
soundFiles = [f for f in os.listdir("sounds/")
if isfile(join("sounds/", f))
and (f.split('.')[1].lower() in ["ogg", "wav"])
and (f.split('.')[0].lower() not in ["game-intro", "music_menu"])
and (not f.lower().startswith("_"))]
# Track last spoken index to avoid repetition
lastSpoken = -1
while True:
if self.currentIndex != lastSpoken:
self.game.speech.speak(soundFiles[self.currentIndex][:-4])
lastSpoken = self.currentIndex
event = self.game.display.window.dispatch_events()
@self.game.display.window.event
def on_key_press(symbol, modifiers):
if symbol == key.ESCAPE:
try:
self.game.sound.currentBgm.unpause()
except:
pass
self.game.display.window.remove_handler('on_key_press', on_key_press)
return "menu"
if symbol in [key.DOWN, key.S] and self.currentIndex < len(soundFiles) - 1:
self.game.sound.stop_all_sounds()
self.currentIndex += 1
if symbol in [key.UP, key.W] and self.currentIndex > 0:
self.game.sound.stop_all_sounds()
self.currentIndex -= 1
if symbol == key.RETURN:
try:
soundName = soundFiles[self.currentIndex][:-4]
self.game.sound.stop_all_sounds()
self.game.sound.play_sound(soundName)
except:
lastSpoken = -1
self.game.speech.speak("Could not play sound.")