Fixed an issue with Game Over states not being correctly detected/handled.

This commit is contained in:
Jonathan Hite 2025-02-07 13:25:27 -05:00
parent 34704013bd
commit dfeea2d36f
3 changed files with 53 additions and 51 deletions

View file

@ -701,40 +701,34 @@ def get_games_available(game_files):
def handle_games_command(sender_id, interface): def handle_games_command(sender_id, interface):
"""Handles the Games Menu and lists available text-based games.""" """Handles the Games Menu and lists available text-based games."""
# Find files in ./games that:
# - Have a .txt or .csv extension
# - OR have no extension
game_files = [ game_files = [
f for f in os.listdir('./games') f for f in os.listdir('./games')
if os.path.isfile(os.path.join('./games', f)) and (f.endswith('.txt') or f.endswith('.csv') or '.' not in f) if os.path.isfile(os.path.join('./games', f)) and (f.endswith('.txt') or f.endswith('.csv') or '.' not in f)
] ]
games_available = get_games_available(game_files) games_available = get_games_available(game_files)
if not games_available: if not games_available:
send_message("No games available yet. Come back soon.", sender_id, interface) send_message("No games available yet. Come back soon.", sender_id, interface)
update_user_state(sender_id, {'command': 'UTILITIES', 'step': 1}) update_user_state(sender_id, {'command': 'UTILITIES', 'step': 1})
return None return None
# Store game filenames in state to avoid title-related issues
game_titles = list(games_available.keys()) # Display titles game_titles = list(games_available.keys()) # Display titles
game_filenames = list(games_available.values()) # Actual filenames game_filenames = list(games_available.values()) # Actual filenames
# Include exit option
numbered_games = "\n".join(f"{i+1}. {title}" for i, title in enumerate(game_titles)) numbered_games = "\n".join(f"{i+1}. {title}" for i, title in enumerate(game_titles))
numbered_games += "\n[X] Exit" numbered_games += "\n[X] Exit"
response = f"🎮 Games Menu 🎮\nWhich game would you like to play?\n{numbered_games}" response = f"🎮 Games Menu 🎮\nWhich game would you like to play?\n{numbered_games}"
send_message(response, sender_id, interface) send_message(response, sender_id, interface)
# ✅ Ensure `games` state is always reset when displaying the menu
update_user_state(sender_id, {'command': 'GAMES', 'step': 1, 'games': game_filenames, 'titles': game_titles}) update_user_state(sender_id, {'command': 'GAMES', 'step': 1, 'games': game_filenames, 'titles': game_titles})
return response return response
def handle_game_menu_selection(sender_id, message, step, interface, state): def handle_game_menu_selection(sender_id, message, step, interface, state):
"""Handles the user's selection of a game from the Games Menu, allowing exit with 'X' and starting immediately.""" """Handles the user's selection of a game from the Games Menu, allowing exit with 'X' and starting immediately."""
@ -750,6 +744,9 @@ def handle_game_menu_selection(sender_id, message, step, interface, state):
if 0 <= game_index < len(games_available): if 0 <= game_index < len(games_available):
selected_game = games_available[game_index] selected_game = games_available[game_index]
# Reset user state to ensure a clean start
update_user_state(sender_id, None)
# Update state to indicate the user is now in-game # Update state to indicate the user is now in-game
update_user_state(sender_id, {'command': 'IN_GAME', 'step': 3, 'game': selected_game}) update_user_state(sender_id, {'command': 'IN_GAME', 'step': 3, 'game': selected_game})
@ -761,6 +758,7 @@ def handle_game_menu_selection(sender_id, message, step, interface, state):
except ValueError: except ValueError:
send_message("Invalid input. Please enter a number corresponding to a game or 'X' to exit.", sender_id, interface) send_message("Invalid input. Please enter a number corresponding to a game or 'X' to exit.", sender_id, interface)
def start_selected_game(sender_id, interface, state): def start_selected_game(sender_id, interface, state):
"""Starts the game selected by the user and ensures title detection.""" """Starts the game selected by the user and ensures title detection."""
@ -844,24 +842,37 @@ def load_game_map(file_path):
print(f"❌ ERROR inside load_game_map(): {e}") print(f"❌ ERROR inside load_game_map(): {e}")
return None return None
def present_story_segment(sender_id, interface, state): def present_story_segment(sender_id, interface, state):
"""Presents the current segment of the game and available choices.""" """Presents the current segment of the game and available choices."""
game_name = state.get('game') game_name = state.get('game')
game_title = state.get('game_title', "Unknown Game") # ✅ Prevent KeyError game_title = state.get('game_title', "Unknown Game")
game_map = state.get('game_map', {}) game_map = state.get('game_map', {})
game_position = state.get('game_position', 1) game_position = state.get('game_position', 1)
if game_position not in game_map: if game_position not in game_map:
send_message("Error: Invalid game state.", sender_id, interface) send_message("Error: Invalid game state.", sender_id, interface)
update_user_state(sender_id, {'command': 'GAMES', 'step': 1}) update_user_state(sender_id, {'command': 'GAMES', 'step': 1})
handle_games_command(sender_id, interface)
return return
# Retrieve the current story segment # Retrieve the current story segment
segment = game_map[game_position] segment = game_map[game_position]
storyline = segment[0] storyline = segment[0]
choices = segment[1:] choices = segment[1:] # Extract choices
# 🛠️ **Check if this is a game-over state (no choices)**
if not choices:
send_message(f"🎮 {game_title} 🎮\n\n{storyline}\n\n💀 GAME OVER! Returning to the game menu...", sender_id, interface)
# Reset user state before returning to menu
update_user_state(sender_id, {'command': 'GAMES', 'step': 1})
import time
time.sleep(1) # Ensure the message is processed before switching menus
handle_games_command(sender_id, interface)
return
# Build response message # Build response message
response = f"🎮 {game_title} 🎮\n\n{storyline}\n\n" response = f"🎮 {game_title} 🎮\n\n{storyline}\n\n"
@ -872,16 +883,17 @@ def present_story_segment(sender_id, interface, state):
send_message(response, sender_id, interface) send_message(response, sender_id, interface)
# Update user state to track the current game progress # Ensure user state is properly tracked
update_user_state(sender_id, { update_user_state(sender_id, {
'command': 'IN_GAME', 'command': 'IN_GAME',
'step': 3, 'step': 3,
'game': game_name, 'game': game_name,
'game_title': game_title, # ✅ Ensure it stays in state 'game_title': game_title,
'game_map': game_map, 'game_map': game_map,
'game_position': game_position 'game_position': game_position
}) })
def process_game_choice(sender_id, message, interface, state): def process_game_choice(sender_id, message, interface, state):
"""Processes the player's choice and advances the game.""" """Processes the player's choice and advances the game."""
@ -891,65 +903,50 @@ def process_game_choice(sender_id, message, interface, state):
if game_position not in game_map: if game_position not in game_map:
send_message("Error: Invalid game state.", sender_id, interface) send_message("Error: Invalid game state.", sender_id, interface)
update_user_state(sender_id, {'command': 'GAMES', 'step': 1}) update_user_state(sender_id, {'command': 'GAMES', 'step': 1})
handle_games_command(sender_id, interface)
return return
segment = game_map[game_position] segment = game_map[game_position]
# Extract the storyline and choices # Extract the storyline and choices
storyline = segment[0] # First element is the story text storyline = segment[0]
choices = segment[1:] # Remaining elements are choices choices = segment[1:]
# Ensure choices are properly formatted (must be in pairs) # Ensure choices are properly formatted
if len(choices) % 2 != 0: if len(choices) % 2 != 0:
send_message("Error: Game data is corrupted.", sender_id, interface) send_message("Error: Game data is corrupted.", sender_id, interface)
update_user_state(sender_id, {'command': 'GAMES', 'step': 1}) update_user_state(sender_id, {'command': 'GAMES', 'step': 1})
handle_games_command(sender_id, interface)
return return
# Handle Exit # Handle Exit
if message.lower() == "x": if message.lower() == "x":
send_message(f"Exiting '{state['game_title']}'... Returning to Games Menu.", sender_id, interface) send_message(f"Exiting '{state['game_title']}'... Returning to Games Menu.", sender_id, interface)
update_user_state(sender_id, {'command': 'GAMES', 'step': 1}) update_user_state(sender_id, {'command': 'GAMES', 'step': 1})
handle_games_command(sender_id, interface) # Immediately display the game menu handle_games_command(sender_id, interface)
return return
try: try:
# Convert user input to index (1-based to 0-based)
choice_index = int(message) - 1 choice_index = int(message) - 1
# Validate choice selection
if choice_index < 0 or choice_index * 2 + 1 >= len(choices): if choice_index < 0 or choice_index * 2 + 1 >= len(choices):
send_message("Invalid selection. Please enter a valid number.", sender_id, interface) send_message("Invalid selection. Please enter a valid number.", sender_id, interface)
return return
# Retrieve the target position for the chosen option
target_position = int(choices[choice_index * 2 + 1]) target_position = int(choices[choice_index * 2 + 1])
# Check if the target position exists
if target_position not in game_map: if target_position not in game_map:
send_message("💀 Game Over! You fell into an abyss. 💀", sender_id, interface) send_message("💀 GAME OVER! No further choices available. 💀 Returning to the game menu...", sender_id, interface)
update_user_state(sender_id, {'command': 'GAMES', 'step': 1}) update_user_state(sender_id, {'command': 'GAMES', 'step': 1})
handle_games_command(sender_id, interface) # Return to game menu handle_games_command(sender_id, interface)
return return
# Update state with the new game position # ✅ FIX: Pass `state` instead of `update_user_state`
update_user_state(sender_id, { state['game_position'] = target_position
'command': 'IN_GAME', update_user_state(sender_id, state)
'step': 3,
'game': state['game'],
'game_title': state['game_title'],
'game_map': game_map,
'game_position': target_position
})
# Present the new story segment # ✅ FIX: Pass the correct `state` variable, NOT `update_user_state`
present_story_segment(sender_id, interface, { present_story_segment(sender_id, interface, state)
'command': 'IN_GAME',
'step': 3,
'game': state['game'],
'game_title': state['game_title'],
'game_map': game_map,
'game_position': target_position
})
except (ValueError, IndexError): except ValueError:
send_message("Invalid selection. Please enter a valid number.", sender_id, interface) send_message("Invalid input. Please enter a valid number.", sender_id, interface)

View file

@ -1,7 +0,0 @@
What is your first choice?, East, 2, West, 3, North, 4, South, 5
You chose East. A dense forest appears., Run forward, 6, Look around, 7
You chose West. A river blocks your path., Try to swim, 8, Walk along the bank, 9
You chose North. The path is blocked by rocks.
You chose South. A cave entrance looms ahead., Enter the cave, 10, Turn back, 11
You went East and chose to run. The ground gives way and you fall. GAME OVER.
You went East and looked around. You see a hidden path., Follow it, 12, Stay put, 13

View file

@ -0,0 +1,12 @@
title="The Shortest Game"
You awaken at a crossroads. Which way will you go?, North, 2, East, 3, South, 4, West, 5
You chose north. There was a cottage. Will you:, Explore it, 6, Keep going, 7
You chose East. The way is dark. What will you do?, Keep going, 8, Light a fire, 9
You chose South. You walked for a mile and found nothing.
You chose West. There is a man on the path., Ignore him, 10, Talk to him, 11
You fell through the floor of the cottage.
Just beyond the cottage you see a village full of people. They seem to recognize you. You make this your new home.
You are brave. After a short walk through the dark forest you find a clearing you recognize. You know the way home.
Marauders spot your fire in the night. You don't wake again.
The man snickers as you pass. Later down the trail you are robbed.
The man tells you where you are and how to get back home.
Can't render this file because it contains an unexpected character in line 1 and column 7.