More bug fixes, modified wait methods to send modifiers too. Only show text nav instructions the first time desplay_text() is used.

This commit is contained in:
Storm Dragon 2025-02-23 14:51:49 -05:00
parent 99d26b7951
commit 576f4cc87a
3 changed files with 149 additions and 125 deletions

View File

@ -89,43 +89,44 @@ class pygstormgames:
self.speech.cleanup() self.speech.cleanup()
pyglet.app.exit() pyglet.app.exit()
def wait(self, valid_keys=None): def wait(self, validKeys=None):
"""Wait for key press(es). """Wait for key press(es).
Args: Args:
valid_keys (list, optional): List of pyglet.window.key values to wait for. validKeys (list, optional): List of pyglet.window.key values to wait for.
If None, accepts any key press. If None, accepts any key press.
Returns: Returns:
int: The key that was pressed tuple: (key, modifiers) that were pressed
""" """
result = [None] # Use list to allow modification in closure keyResult = [None, None] # Use list to allow modification in closure
def on_key_press(symbol, modifiers): def on_key_press(symbol, modifiers):
if valid_keys is None or symbol in valid_keys: if validKeys is None or symbol in validKeys:
result[0] = symbol keyResult[0] = symbol
keyResult[1] = modifiers
return pyglet.event.EVENT_HANDLED return pyglet.event.EVENT_HANDLED
# Register temporary handler # Register temporary handler
self.display.window.push_handlers(on_key_press=on_key_press) self.display.window.push_handlers(on_key_press=on_key_press)
# Wait for valid key press # Wait for valid key press
while result[0] is None: while keyResult[0] is None:
self.display.window.dispatch_events() self.display.window.dispatch_events()
pyglet.clock.tick() pyglet.clock.tick()
# Clean up # Clean up
self.display.window.remove_handlers() self.display.window.remove_handlers()
return result[0] return tuple(keyResult)
def wait_for_completion(self, condition, validKeys=None): def wait_for_completion(self, condition, validKeys=None):
"""Wait for either a condition to be met or valid keys to be pressed. """Wait for either a condition to be met or valid keys to be pressed.
Args: Args:
condition: Function that returns True when waiting should end condition: Function that returns True when waiting should end
validKeys (list, optional): List of pyglet.window.key values that can interrupt validKeys (list, optional): List of pyglet.window.key values that can interrupt
If None, uses ESCAPE, RETURN, and SPACE If None, uses ESCAPE, RETURN, and SPACE
Returns: Returns:
bool: True if interrupted by key press, False if condition was met bool: True if interrupted by key press, False if condition was met
""" """
@ -133,19 +134,19 @@ class pygstormgames:
validKeys = [pyglet.window.key.ESCAPE, validKeys = [pyglet.window.key.ESCAPE,
pyglet.window.key.RETURN, pyglet.window.key.RETURN,
pyglet.window.key.SPACE] pyglet.window.key.SPACE]
wasInterrupted = [False] # Use list to allow modification in closure interrupted = [False] # Use list to allow modification in closure
def on_key_press(symbol, modifiers): def on_key_press(symbol, modifiers):
if symbol in validKeys: if symbol in validKeys:
wasInterrupted[0] = True interrupted[0] = True
return pyglet.event.EVENT_HANDLED return pyglet.event.EVENT_HANDLED
self.display.window.push_handlers(on_key_press=on_key_press) self.display.window.push_handlers(on_key_press=on_key_press)
while not condition() and not wasInterrupted[0]: while not condition() and not interrupted[0]:
self.display.window.dispatch_events() self.display.window.dispatch_events()
pyglet.clock.tick() pyglet.clock.tick()
self.display.window.remove_handlers() self.display.window.remove_handlers()
return wasInterrupted[0] return interrupted[0]

View File

@ -25,6 +25,7 @@ class Display:
""" """
self.game = game self.game = game
self.window = pyglet.window.Window(800, 600, caption=game.gameTitle) self.window = pyglet.window.Window(800, 600, caption=game.gameTitle)
self.displayedInstructions = False
self.currentText = [] self.currentText = []
self.currentIndex = 0 self.currentIndex = 0
self.gameTitle = game.gameTitle self.gameTitle = game.gameTitle
@ -43,10 +44,12 @@ class Display:
self.navText = [line for line in text if line.strip()] self.navText = [line for line in text if line.strip()]
# Add instructions at start # Add instructions at start
instructions = ("Press space to read the whole text. Use up and down arrows to navigate " if not self.displayedInstructions:
"the text line by line. Press c to copy the current line to the clipboard " instructions = ("Press space to read the whole text. Use up and down arrows to navigate "
"or t to copy the entire text. Press enter or escape when you are done reading.") "the text line by line. Press c to copy the current line to the clipboard "
self.navText.insert(0, instructions) "or t to copy the entire text. Press enter or escape when you are done reading.")
self.navText.insert(0, instructions)
self.displayedInstructions = True
# Add end marker # Add end marker
self.navText.append("End of text.") self.navText.append("End of text.")
@ -68,7 +71,7 @@ class Display:
] ]
while True: while True:
key = self.game.wait(validKeys) key, _ = self.game.wait(validKeys)
if key in (pyglet.window.key.ESCAPE, pyglet.window.key.RETURN): if key in (pyglet.window.key.ESCAPE, pyglet.window.key.RETURN):
break break
@ -142,7 +145,7 @@ def messagebox(self, text):
self.game.speech.speak(text) self.game.speech.speak(text)
# Wait for any key # Wait for any key
key = self.game.wait() key, _ = self.game.wait()
# Exit if enter/escape pressed # Exit if enter/escape pressed
if key in (pyglet.window.key.RETURN, pyglet.window.key.ESCAPE): if key in (pyglet.window.key.RETURN, pyglet.window.key.ESCAPE):

208
menu.py
View File

@ -32,73 +32,81 @@ class Menu:
self.currentIndex = 0 self.currentIndex = 0
lastSpoken = -1 lastSpoken = -1
selection = None # Add this to store the selection
if title: if title:
self.game.speech.speak(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 validKeys = [
self.game.display.window.push_handlers(on_key_press=key_handler) pyglet.window.key.ESCAPE,
pyglet.window.key.RETURN,
# Main menu loop pyglet.window.key.UP,
while selection is None: pyglet.window.key.DOWN,
pyglet.window.key.W,
pyglet.window.key.S,
pyglet.window.key.HOME,
pyglet.window.key.END,
pyglet.window.key.PAGEUP,
pyglet.window.key.PAGEDOWN,
pyglet.window.key.INSERT,
pyglet.window.key.DELETE
]
while True:
# Speak current option if changed
if self.currentIndex != lastSpoken: if self.currentIndex != lastSpoken:
self.game.speech.speak(options[self.currentIndex]) self.game.speech.speak(options[self.currentIndex])
lastSpoken = self.currentIndex lastSpoken = self.currentIndex
self.game.display.window.dispatch_events()
key, keyModifiers = self.game.wait(validKeys)
# Clean up
self.game.display.window.remove_handlers() # Handle Alt+volume controls
return selection if keyModifiers & pyglet.window.key.MOD_ALT:
if key == pyglet.window.key.PAGEUP:
self.game.sound.adjust_master_volume(0.1)
elif key == pyglet.window.key.PAGEDOWN:
self.game.sound.adjust_master_volume(-0.1)
elif key == pyglet.window.key.HOME:
self.game.sound.adjust_bgm_volume(0.1)
elif key == pyglet.window.key.END:
self.game.sound.adjust_bgm_volume(-0.1)
elif key == pyglet.window.key.INSERT:
self.game.sound.adjust_sfx_volume(0.1)
elif key == pyglet.window.key.DELETE:
self.game.sound.adjust_sfx_volume(-0.1)
continue
if key == pyglet.window.key.ESCAPE:
if "exit" in options:
# Handle exit cleanup immediately
self.game.sound.cleanup()
self.game.display.window.remove_handlers()
self.game.speech.cleanup()
pyglet.app.exit()
return "exit"
if key == pyglet.window.key.HOME and self.currentIndex != 0:
self.currentIndex = 0
self.game.sound.play_sound('menu-move')
lastSpoken = -1 # Force speech
elif key == pyglet.window.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 key in (pyglet.window.key.DOWN, pyglet.window.key.S) and self.currentIndex < len(options) - 1:
self.currentIndex += 1
self.game.sound.play_sound('menu-move')
lastSpoken = -1 # Force speech
elif key in (pyglet.window.key.UP, pyglet.window.key.W) and self.currentIndex > 0:
self.currentIndex -= 1
self.game.sound.play_sound('menu-move')
lastSpoken = -1 # Force speech
elif key == pyglet.window.key.RETURN:
self.game.sound.play_sound('menu-select')
return options[self.currentIndex]
def game_menu(self): def game_menu(self):
"""Show main game menu.""" """Show main game menu."""
@ -153,14 +161,20 @@ class Menu:
if self.game.sound.currentBgm: if self.game.sound.currentBgm:
self.game.sound.currentBgm.play() self.game.sound.currentBgm.play()
elif selection == "exit":
self.game.sound.cleanup() # Stop all sounds first
self.game.display.window.remove_handlers() # Remove handlers before closing speech
self.game.speech.cleanup() # Clean up speech last
self.game.exit_game()
def learn_sounds(self): def learn_sounds(self):
"""Interactive menu for learning game sounds. """Interactive menu for learning game sounds.
Allows users to: Allows users to:
- Navigate through available sounds - Navigate through available sounds
- Play selected sounds - Play selected sounds
- Return to menu with escape key - Return to menu with escape key
Returns: Returns:
str: "menu" if user exits with escape str: "menu" if user exits with escape
""" """
@ -177,40 +191,46 @@ class Menu:
and (f.split('.')[1].lower() in ["ogg", "wav"]) and (f.split('.')[1].lower() in ["ogg", "wav"])
and (f.split('.')[0].lower() not in ["game-intro", "music_menu"]) and (f.split('.')[0].lower() not in ["game-intro", "music_menu"])
and (not f.lower().startswith("_"))] 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 if not soundFiles:
def on_key_press(symbol, modifiers): self.game.speech.speak("No sounds available to learn.")
if symbol == key.ESCAPE: return "menu"
validKeys = [
pyglet.window.key.ESCAPE,
pyglet.window.key.RETURN,
pyglet.window.key.UP,
pyglet.window.key.DOWN,
pyglet.window.key.W,
pyglet.window.key.S
]
# Speak initial sound name
self.game.speech.speak(soundFiles[self.currentIndex][:-4])
while True:
key, _ = self.game.wait(validKeys)
if key == pyglet.window.key.ESCAPE:
try: try:
self.game.sound.currentBgm.unpause() self.game.sound.currentBgm.play()
except: except:
pass pass
self.game.display.window.remove_handler('on_key_press', on_key_press)
return "menu" return "menu"
if symbol in [key.DOWN, key.S] and self.currentIndex < len(soundFiles) - 1: if key in [pyglet.window.key.DOWN, pyglet.window.key.S]:
self.game.sound.stop_all_sounds() if self.currentIndex < len(soundFiles) - 1:
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.stop_all_sounds()
self.game.sound.play_sound(soundName) self.currentIndex += 1
except: self.game.speech.speak(soundFiles[self.currentIndex][:-4])
lastSpoken = -1
self.game.speech.speak("Could not play sound.") if key in [pyglet.window.key.UP, pyglet.window.key.W]:
if self.currentIndex > 0:
self.game.sound.stop_all_sounds()
self.currentIndex -= 1
self.game.speech.speak(soundFiles[self.currentIndex][:-4])
if key == pyglet.window.key.RETURN:
soundName = soundFiles[self.currentIndex][:-4]
self.game.sound.stop_all_sounds()
self.game.sound.play_sound(soundName)