Compare commits
10 Commits
fe772cbb1e
...
27765e62bc
Author | SHA1 | Date | |
---|---|---|---|
|
27765e62bc | ||
|
23aea6badf | ||
|
af38d5af76 | ||
|
4d0436c5a9 | ||
|
f51bd6dee4 | ||
|
3b2bcd928d | ||
|
91f39aad88 | ||
|
1dc0ac2a7f | ||
|
3f8385599b | ||
|
468c663cc1 |
12
__init__.py
12
__init__.py
@@ -53,6 +53,10 @@ from .display import display_text, initialize_gui
|
||||
# Import menu functions
|
||||
from .menu import game_menu, learn_sounds, instructions, credits, donate, exit_game
|
||||
|
||||
# Update imports to reference Scoreboard methods
|
||||
high_scores = Scoreboard.display_high_scores
|
||||
has_high_scores = Scoreboard.has_high_scores
|
||||
|
||||
# Import utility functions and Game class
|
||||
from .utils import (
|
||||
Game,
|
||||
@@ -109,15 +113,15 @@ __all__ = [
|
||||
'display_text', 'initialize_gui',
|
||||
|
||||
# Menu
|
||||
'game_menu', 'learn_sounds', 'instructions', 'credits', 'donate', 'exit_game',
|
||||
'game_menu', 'learn_sounds', 'instructions', 'credits', 'donate', 'exit_game', 'high_scores', 'has_high_scores',
|
||||
|
||||
# Game class
|
||||
'Game',
|
||||
|
||||
# Utils
|
||||
'check_for_updates', 'get_version_tuple', 'check_compatibility',
|
||||
'sanitize_filename', 'lerp', 'smooth_step', 'distance_2d',
|
||||
'x_powerbar', 'y_powerbar', 'generate_tone',
|
||||
'check_for_updates', 'get_version_tuple', 'check_compatibility',
|
||||
'sanitize_filename', 'lerp', 'smooth_step', 'distance_2d',
|
||||
'x_powerbar', 'y_powerbar', 'generate_tone',
|
||||
|
||||
# Re-exported functions from pygame, math, random
|
||||
'get_ticks', 'delay', 'wait',
|
||||
|
26
menu.py
26
menu.py
@@ -22,19 +22,21 @@ from inspect import isfunction
|
||||
from .speech import messagebox, Speech
|
||||
from .sound import adjust_master_volume, adjust_bgm_volume, adjust_sfx_volume, play_bgm
|
||||
from .display import display_text
|
||||
from .services import PathService
|
||||
from .scoreboard import Scoreboard
|
||||
from .services import PathService, ConfigService
|
||||
|
||||
def game_menu(sounds, playCallback=None, *customOptions):
|
||||
"""Display and handle the main game menu with standard and custom options.
|
||||
|
||||
Standard menu structure:
|
||||
1. Play (always first)
|
||||
2. Custom options (high scores, etc.)
|
||||
3. Learn Sounds
|
||||
4. Instructions (if available)
|
||||
5. Credits (if available)
|
||||
6. Donate
|
||||
7. Exit
|
||||
2. High Scores
|
||||
3. Custom options (if provided)
|
||||
4. Learn Sounds
|
||||
5. Instructions (if available)
|
||||
6. Credits (if available)
|
||||
7. Donate
|
||||
8. Exit
|
||||
|
||||
Handles navigation with:
|
||||
- Up/Down arrows for selection
|
||||
@@ -58,7 +60,11 @@ def game_menu(sounds, playCallback=None, *customOptions):
|
||||
# Start with Play option
|
||||
allOptions = ["play"]
|
||||
|
||||
# Add custom options (high scores, etc.)
|
||||
# Add high scores option if scores exist
|
||||
if Scoreboard.has_high_scores():
|
||||
allOptions.append("high_scores")
|
||||
|
||||
# Add custom options (other menu items, etc.)
|
||||
allOptions.extend(customOptions)
|
||||
|
||||
# Add standard options in preferred order
|
||||
@@ -183,7 +189,7 @@ def game_menu(sounds, playCallback=None, *customOptions):
|
||||
# Otherwise return "play" to the caller
|
||||
return "play"
|
||||
# Handle standard options directly
|
||||
elif selectedOption in ["instructions", "credits", "learn_sounds", "donate"]:
|
||||
elif selectedOption in ["instructions", "credits", "learn_sounds", "high_scores", "donate"]:
|
||||
# Pause music before calling the selected function
|
||||
try:
|
||||
pygame.mixer.music.pause()
|
||||
@@ -197,6 +203,8 @@ def game_menu(sounds, playCallback=None, *customOptions):
|
||||
credits()
|
||||
elif selectedOption == "learn_sounds":
|
||||
learn_sounds(sounds)
|
||||
elif selectedOption == "high_scores":
|
||||
Scoreboard.display_high_scores()
|
||||
elif selectedOption == "donate":
|
||||
donate()
|
||||
|
||||
|
176
scoreboard.py
176
scoreboard.py
@@ -1,15 +1,17 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Scoreboard handling for Storm Games.
|
||||
"""
|
||||
Modified Scoreboard class with integrated fixes.
|
||||
|
||||
Provides functionality for:
|
||||
- Tracking high scores with player names
|
||||
- Saving/loading high scores from configuration
|
||||
This code should replace the existing Scoreboard class in scoreboard.py.
|
||||
The modifications ensure proper path handling and config operations.
|
||||
"""
|
||||
|
||||
import time
|
||||
from .services import ConfigService
|
||||
import os
|
||||
from .services import ConfigService, PathService
|
||||
from .speech import Speech
|
||||
from .display import display_text
|
||||
|
||||
# For backward compatibility
|
||||
from .config import localConfig, write_config, read_config
|
||||
@@ -25,6 +27,9 @@ class Scoreboard:
|
||||
configService (ConfigService): Config service (default: global instance)
|
||||
speech (Speech): Speech system (default: global instance)
|
||||
"""
|
||||
# Ensure services are properly initialized
|
||||
self._ensure_services()
|
||||
|
||||
self.configService = configService or ConfigService.get_instance()
|
||||
self.speech = speech or Speech.get_instance()
|
||||
self.currentScore = score
|
||||
@@ -35,7 +40,7 @@ class Scoreboard:
|
||||
|
||||
try:
|
||||
# Try to use configService
|
||||
self.configService.local_config.add_section("scoreboard")
|
||||
self.configService.localConfig.add_section("scoreboard")
|
||||
except:
|
||||
# Fallback to old method
|
||||
try:
|
||||
@@ -47,8 +52,8 @@ class Scoreboard:
|
||||
for i in range(1, 11):
|
||||
try:
|
||||
# Try to use configService
|
||||
score = self.configService.local_config.getint("scoreboard", f"score_{i}")
|
||||
name = self.configService.local_config.get("scoreboard", f"name_{i}")
|
||||
score = self.configService.localConfig.getint("scoreboard", f"score_{i}")
|
||||
name = self.configService.localConfig.get("scoreboard", f"name_{i}")
|
||||
self.highScores.append({
|
||||
'name': name,
|
||||
'score': score
|
||||
@@ -70,6 +75,37 @@ class Scoreboard:
|
||||
|
||||
# Sort high scores by score value in descending order
|
||||
self.highScores.sort(key=lambda x: x['score'], reverse=True)
|
||||
|
||||
def _ensure_services(self):
|
||||
"""Ensure PathService and ConfigService are properly initialized."""
|
||||
# Get PathService and make sure it has a game name
|
||||
pathService = PathService.get_instance()
|
||||
|
||||
# If no game name yet, try to get from pygame window title
|
||||
if not pathService.gameName:
|
||||
try:
|
||||
import pygame
|
||||
if pygame.display.get_caption()[0]:
|
||||
pathService.gameName = pygame.display.get_caption()[0]
|
||||
except:
|
||||
pass
|
||||
|
||||
# Initialize path service if we have a game name but no paths set up
|
||||
if pathService.gameName and not pathService.gamePath:
|
||||
pathService.initialize(pathService.gameName)
|
||||
|
||||
# Get ConfigService and connect to PathService
|
||||
configService = ConfigService.get_instance()
|
||||
if not hasattr(configService, 'pathService') or not configService.pathService:
|
||||
if pathService.gameName:
|
||||
configService.set_game_info(pathService.gameName, pathService)
|
||||
|
||||
# Ensure the game directory exists
|
||||
if pathService.gamePath and not os.path.exists(pathService.gamePath):
|
||||
try:
|
||||
os.makedirs(pathService.gamePath)
|
||||
except Exception as e:
|
||||
print(f"Error creating game directory: {e}")
|
||||
|
||||
def get_score(self):
|
||||
"""Get current score."""
|
||||
@@ -119,6 +155,9 @@ class Scoreboard:
|
||||
Returns:
|
||||
bool: True if score was added, False if not
|
||||
"""
|
||||
# Ensure services are properly set up
|
||||
self._ensure_services()
|
||||
|
||||
position = self.check_high_score()
|
||||
if position is None:
|
||||
return False
|
||||
@@ -144,13 +183,14 @@ class Scoreboard:
|
||||
try:
|
||||
# Try new method first
|
||||
for i, entry in enumerate(self.highScores):
|
||||
self.configService.local_config.set("scoreboard", f"score_{i+1}", str(entry['score']))
|
||||
self.configService.local_config.set("scoreboard", f"name_{i+1}", entry['name'])
|
||||
self.configService.localConfig.set("scoreboard", f"score_{i+1}", str(entry['score']))
|
||||
self.configService.localConfig.set("scoreboard", f"name_{i+1}", entry['name'])
|
||||
|
||||
# Try to write with configService
|
||||
try:
|
||||
self.configService.write_local_config()
|
||||
except Exception as e:
|
||||
print(f"Error writing config with configService: {e}")
|
||||
# Fallback to old method if configService fails
|
||||
for i, entry in enumerate(self.highScores):
|
||||
localConfig.set("scoreboard", f"score_{i+1}", str(entry['score']))
|
||||
@@ -158,6 +198,7 @@ class Scoreboard:
|
||||
write_config()
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error writing high scores: {e}")
|
||||
# If all else fails, try direct old method
|
||||
for i, entry in enumerate(self.highScores):
|
||||
localConfig.set("scoreboard", f"score_{i+1}", str(entry['score']))
|
||||
@@ -174,3 +215,118 @@ class Scoreboard:
|
||||
|
||||
time.sleep(1)
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def has_high_scores():
|
||||
"""Check if the current game has any high scores.
|
||||
|
||||
Returns:
|
||||
bool: True if at least one high score exists, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Get PathService to access game name
|
||||
pathService = PathService.get_instance()
|
||||
gameName = pathService.gameName
|
||||
|
||||
# If no game name, try to get from window title
|
||||
if not gameName:
|
||||
try:
|
||||
import pygame
|
||||
if pygame.display.get_caption()[0]:
|
||||
gameName = pygame.display.get_caption()[0]
|
||||
pathService.gameName = gameName
|
||||
except:
|
||||
pass
|
||||
|
||||
# Ensure path service is properly initialized
|
||||
if gameName and not pathService.gamePath:
|
||||
pathService.initialize(gameName)
|
||||
|
||||
# Get the config file path
|
||||
configPath = os.path.join(pathService.gamePath, "config.ini")
|
||||
|
||||
# If config file doesn't exist, there are no scores
|
||||
if not os.path.exists(configPath):
|
||||
return False
|
||||
|
||||
# Ensure config service is properly connected to path service
|
||||
configService = ConfigService.get_instance()
|
||||
configService.set_game_info(gameName, pathService)
|
||||
|
||||
# Create scoreboard using the properly initialized services
|
||||
board = Scoreboard(0, configService)
|
||||
|
||||
# Force a read of local config to ensure fresh data
|
||||
configService.read_local_config()
|
||||
|
||||
# Get high scores
|
||||
scores = board.get_high_scores()
|
||||
|
||||
# Check if any score is greater than zero
|
||||
return any(score['score'] > 0 for score in scores)
|
||||
except Exception as e:
|
||||
print(f"Error checking high scores: {e}")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def display_high_scores():
|
||||
"""Display high scores for the current game.
|
||||
|
||||
Reads the high scores from Scoreboard class.
|
||||
Shows the game name at the top followed by the available scores.
|
||||
"""
|
||||
try:
|
||||
# Get PathService to access game name
|
||||
pathService = PathService.get_instance()
|
||||
gameName = pathService.gameName
|
||||
|
||||
# If no game name, try to get from window title
|
||||
if not gameName:
|
||||
try:
|
||||
import pygame
|
||||
if pygame.display.get_caption()[0]:
|
||||
gameName = pygame.display.get_caption()[0]
|
||||
pathService.gameName = gameName
|
||||
except:
|
||||
pass
|
||||
|
||||
# Ensure path service is properly initialized
|
||||
if gameName and not pathService.gamePath:
|
||||
pathService.initialize(gameName)
|
||||
|
||||
# Ensure config service is properly connected to path service
|
||||
configService = ConfigService.get_instance()
|
||||
configService.set_game_info(gameName, pathService)
|
||||
|
||||
# Create scoreboard using the properly initialized services
|
||||
board = Scoreboard(0, configService)
|
||||
|
||||
# Force a read of local config to ensure fresh data
|
||||
configService.read_local_config()
|
||||
|
||||
# Get high scores
|
||||
scores = board.get_high_scores()
|
||||
|
||||
# Filter out scores with zero points
|
||||
validScores = [score for score in scores if score['score'] > 0]
|
||||
|
||||
# Prepare the lines to display
|
||||
lines = [f"High Scores for {gameName}:"]
|
||||
|
||||
# Add scores to the display list
|
||||
if validScores:
|
||||
for i, entry in enumerate(validScores, 1):
|
||||
scoreStr = f"{i}. {entry['name']}: {entry['score']}"
|
||||
lines.append(scoreStr)
|
||||
else:
|
||||
lines.append("No high scores yet.")
|
||||
|
||||
# Display the high scores
|
||||
display_text(lines)
|
||||
except Exception as e:
|
||||
print(f"Error displaying high scores: {e}")
|
||||
info = ["Could not display high scores."]
|
||||
display_text(info)
|
||||
|
||||
# For backward compatibility with older code that might call displayHigh_scores
|
||||
displayHigh_scores = display_high_scores
|
||||
|
Reference in New Issue
Block a user