From dcd204e476aa06b0ed8d8ba8ba23b0d28f04e14c Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Sun, 7 Sep 2025 02:38:27 -0400 Subject: [PATCH] Added the ability to create submenus with instructions. --- __init__.py | 4 +-- menu.py | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/__init__.py b/__init__.py index 6b0afdb..99a3bf8 100755 --- a/__init__.py +++ b/__init__.py @@ -51,7 +51,7 @@ from .input import get_input, check_for_exit, pause_game from .display import display_text, initialize_gui # Import menu functions -from .menu import game_menu, learn_sounds, instructions, credits, donate, exit_game +from .menu import game_menu, instruction_menu, learn_sounds, instructions, credits, donate, exit_game # Update imports to reference Scoreboard methods high_scores = Scoreboard.display_high_scores @@ -113,7 +113,7 @@ __all__ = [ 'display_text', 'initialize_gui', # Menu - 'game_menu', 'learn_sounds', 'instructions', 'credits', 'donate', 'exit_game', 'high_scores', 'has_high_scores', + 'game_menu', 'instruction_menu', 'learn_sounds', 'instructions', 'credits', 'donate', 'exit_game', 'high_scores', 'has_high_scores', # Game class 'Game', diff --git a/menu.py b/menu.py index 8b18259..e6d5c58 100644 --- a/menu.py +++ b/menu.py @@ -25,6 +25,94 @@ from .display import display_text from .scoreboard import Scoreboard from .services import PathService, ConfigService +def instruction_menu(sounds, instruction_text, *options): + """Display a menu with an instruction announcement at the top. + + The instruction text is announced as item 0 but is not selectable. + The actual menu items start at index 1, and navigation skips the instruction. + + Args: + sounds (dict): Dictionary of sound objects + instruction_text (str): The instruction/context text to announce + *options: Menu options to display + + Returns: + str: Selected menu option or None if cancelled + """ + # Get speech instance + speech = Speech.get_instance() + + # Create combined list with instruction at index 0 + all_items = [instruction_text] + list(options) + + loop = True + pygame.mixer.stop() + current_index = 0 # Start at instruction + last_spoken = -1 + + # Clear any pending events + pygame.event.clear() + + while loop: + if current_index != last_spoken: + speech.speak(all_items[current_index]) + last_spoken = current_index + + event = pygame.event.wait() + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_ESCAPE: + return None + elif event.key in [pygame.K_DOWN, pygame.K_s]: + moved = False + if current_index == 0: # On instruction, go to first menu item + current_index = 1 + moved = True + elif current_index < len(all_items) - 1: # Normal navigation + current_index += 1 + moved = True + + if moved: + try: + sounds['menu-move'].play() + except: + pass + elif event.key in [pygame.K_UP, pygame.K_w]: + if current_index > 1: # Can move up from menu items (but not to instruction) + current_index -= 1 + try: + sounds['menu-move'].play() + except: + pass + elif event.key == pygame.K_HOME: + target_index = 1 if current_index != 1 else current_index # Go to first menu item + if target_index != current_index: + current_index = target_index + try: + sounds['menu-move'].play() + except: + pass + elif event.key == pygame.K_END and current_index != len(all_items) - 1: + current_index = len(all_items) - 1 + try: + sounds['menu-move'].play() + except: + pass + elif event.key == pygame.K_RETURN: + if current_index == 0: # Can't select the instruction + continue + try: + sounds['menu-select'].play() + time.sleep(sounds['menu-select'].get_length()) + except: + pass + return options[current_index - 1] # Adjust for instruction offset + elif event.type == pygame.QUIT: + return None + + pygame.event.pump() + pygame.event.clear() + time.sleep(0.001) + def game_menu(sounds, playCallback=None, *customOptions): """Display and handle the main game menu with standard and custom options.