Compare commits
	
		
			10 Commits
		
	
	
		
			fe772cbb1e
			...
			27765e62bc
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 27765e62bc | ||
|  | 23aea6badf | ||
|  | af38d5af76 | ||
|  | 4d0436c5a9 | ||
|  | f51bd6dee4 | ||
|  | 3b2bcd928d | ||
|  | 91f39aad88 | ||
|  | 1dc0ac2a7f | ||
|  | 3f8385599b | ||
|  | 468c663cc1 | 
| @@ -53,6 +53,10 @@ from .display import display_text, initialize_gui | |||||||
| # Import menu functions | # Import menu functions | ||||||
| from .menu import game_menu, learn_sounds, instructions, credits, donate, exit_game | 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 | # Import utility functions and Game class | ||||||
| from .utils import ( | from .utils import ( | ||||||
|     Game, |     Game, | ||||||
| @@ -109,7 +113,7 @@ __all__ = [ | |||||||
|     'display_text', 'initialize_gui', |     'display_text', 'initialize_gui', | ||||||
|      |      | ||||||
|     # Menu |     # 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 class | ||||||
|     'Game', |     'Game', | ||||||
|   | |||||||
							
								
								
									
										26
									
								
								menu.py
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								menu.py
									
									
									
									
									
								
							| @@ -22,19 +22,21 @@ from inspect import isfunction | |||||||
| from .speech import messagebox, Speech | from .speech import messagebox, Speech | ||||||
| from .sound import adjust_master_volume, adjust_bgm_volume, adjust_sfx_volume, play_bgm | from .sound import adjust_master_volume, adjust_bgm_volume, adjust_sfx_volume, play_bgm | ||||||
| from .display import display_text | 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): | def game_menu(sounds, playCallback=None, *customOptions): | ||||||
|     """Display and handle the main game menu with standard and custom options. |     """Display and handle the main game menu with standard and custom options. | ||||||
|      |      | ||||||
|     Standard menu structure: |     Standard menu structure: | ||||||
|     1. Play (always first) |     1. Play (always first) | ||||||
|     2. Custom options (high scores, etc.) |     2. High Scores | ||||||
|     3. Learn Sounds |     3. Custom options (if provided) | ||||||
|     4. Instructions (if available) |     4. Learn Sounds | ||||||
|     5. Credits (if available) |     5. Instructions (if available) | ||||||
|     6. Donate |     6. Credits (if available) | ||||||
|     7. Exit |     7. Donate | ||||||
|  |     8. Exit | ||||||
|      |      | ||||||
|     Handles navigation with: |     Handles navigation with: | ||||||
|     - Up/Down arrows for selection |     - Up/Down arrows for selection | ||||||
| @@ -58,7 +60,11 @@ def game_menu(sounds, playCallback=None, *customOptions): | |||||||
|     # Start with Play option |     # Start with Play option | ||||||
|     allOptions = ["play"] |     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) |     allOptions.extend(customOptions) | ||||||
|      |      | ||||||
|     # Add standard options in preferred order |     # Add standard options in preferred order | ||||||
| @@ -183,7 +189,7 @@ def game_menu(sounds, playCallback=None, *customOptions): | |||||||
|                                 # Otherwise return "play" to the caller |                                 # Otherwise return "play" to the caller | ||||||
|                                 return "play" |                                 return "play" | ||||||
|                         # Handle standard options directly |                         # 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 |                             # Pause music before calling the selected function | ||||||
|                             try: |                             try: | ||||||
|                                 pygame.mixer.music.pause() |                                 pygame.mixer.music.pause() | ||||||
| @@ -197,6 +203,8 @@ def game_menu(sounds, playCallback=None, *customOptions): | |||||||
|                                 credits() |                                 credits() | ||||||
|                             elif selectedOption == "learn_sounds": |                             elif selectedOption == "learn_sounds": | ||||||
|                                 learn_sounds(sounds) |                                 learn_sounds(sounds) | ||||||
|  |                             elif selectedOption == "high_scores": | ||||||
|  |                                 Scoreboard.display_high_scores() | ||||||
|                             elif selectedOption == "donate": |                             elif selectedOption == "donate": | ||||||
|                                 donate() |                                 donate() | ||||||
|                              |                              | ||||||
|   | |||||||
							
								
								
									
										176
									
								
								scoreboard.py
									
									
									
									
									
								
							
							
						
						
									
										176
									
								
								scoreboard.py
									
									
									
									
									
								
							| @@ -1,15 +1,17 @@ | |||||||
| #!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||||
| # -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||||
| """Scoreboard handling for Storm Games. | """ | ||||||
|  | Modified Scoreboard class with integrated fixes. | ||||||
|  |  | ||||||
| Provides functionality for: | This code should replace the existing Scoreboard class in scoreboard.py. | ||||||
| - Tracking high scores with player names | The modifications ensure proper path handling and config operations. | ||||||
| - Saving/loading high scores from configuration |  | ||||||
| """ | """ | ||||||
|  |  | ||||||
| import time | import time | ||||||
| from .services import ConfigService | import os | ||||||
|  | from .services import ConfigService, PathService | ||||||
| from .speech import Speech | from .speech import Speech | ||||||
|  | from .display import display_text | ||||||
|  |  | ||||||
| # For backward compatibility | # For backward compatibility | ||||||
| from .config import localConfig, write_config, read_config | from .config import localConfig, write_config, read_config | ||||||
| @@ -25,6 +27,9 @@ class Scoreboard: | |||||||
|             configService (ConfigService): Config service (default: global instance) |             configService (ConfigService): Config service (default: global instance) | ||||||
|             speech (Speech): Speech system (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.configService = configService or ConfigService.get_instance() | ||||||
|         self.speech = speech or Speech.get_instance() |         self.speech = speech or Speech.get_instance() | ||||||
|         self.currentScore = score |         self.currentScore = score | ||||||
| @@ -35,7 +40,7 @@ class Scoreboard: | |||||||
|      |      | ||||||
|         try: |         try: | ||||||
|             # Try to use configService |             # Try to use configService | ||||||
|             self.configService.local_config.add_section("scoreboard") |             self.configService.localConfig.add_section("scoreboard") | ||||||
|         except: |         except: | ||||||
|             # Fallback to old method |             # Fallback to old method | ||||||
|             try: |             try: | ||||||
| @@ -47,8 +52,8 @@ class Scoreboard: | |||||||
|         for i in range(1, 11): |         for i in range(1, 11): | ||||||
|             try: |             try: | ||||||
|                 # Try to use configService |                 # Try to use configService | ||||||
|                 score = self.configService.local_config.getint("scoreboard", f"score_{i}") |                 score = self.configService.localConfig.getint("scoreboard", f"score_{i}") | ||||||
|                 name = self.configService.local_config.get("scoreboard", f"name_{i}") |                 name = self.configService.localConfig.get("scoreboard", f"name_{i}") | ||||||
|                 self.highScores.append({ |                 self.highScores.append({ | ||||||
|                     'name': name, |                     'name': name, | ||||||
|                     'score': score |                     'score': score | ||||||
| @@ -71,6 +76,37 @@ class Scoreboard: | |||||||
|         # Sort high scores by score value in descending order |         # Sort high scores by score value in descending order | ||||||
|         self.highScores.sort(key=lambda x: x['score'], reverse=True) |         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): |     def get_score(self): | ||||||
|         """Get current score.""" |         """Get current score.""" | ||||||
|         return self.currentScore |         return self.currentScore | ||||||
| @@ -119,6 +155,9 @@ class Scoreboard: | |||||||
|         Returns: |         Returns: | ||||||
|             bool: True if score was added, False if not |             bool: True if score was added, False if not | ||||||
|         """ |         """ | ||||||
|  |         # Ensure services are properly set up | ||||||
|  |         self._ensure_services() | ||||||
|  |          | ||||||
|         position = self.check_high_score() |         position = self.check_high_score() | ||||||
|         if position is None: |         if position is None: | ||||||
|             return False |             return False | ||||||
| @@ -144,13 +183,14 @@ class Scoreboard: | |||||||
|         try: |         try: | ||||||
|             # Try new method first |             # Try new method first | ||||||
|             for i, entry in enumerate(self.highScores): |             for i, entry in enumerate(self.highScores): | ||||||
|                 self.configService.local_config.set("scoreboard", f"score_{i+1}", str(entry['score'])) |                 self.configService.localConfig.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"name_{i+1}", entry['name']) | ||||||
|              |              | ||||||
|             # Try to write with configService |             # Try to write with configService | ||||||
|             try: |             try: | ||||||
|                 self.configService.write_local_config() |                 self.configService.write_local_config() | ||||||
|             except Exception as e: |             except Exception as e: | ||||||
|  |                 print(f"Error writing config with configService: {e}") | ||||||
|                 # Fallback to old method if configService fails |                 # Fallback to old method if configService fails | ||||||
|                 for i, entry in enumerate(self.highScores): |                 for i, entry in enumerate(self.highScores): | ||||||
|                     localConfig.set("scoreboard", f"score_{i+1}", str(entry['score'])) |                     localConfig.set("scoreboard", f"score_{i+1}", str(entry['score'])) | ||||||
| @@ -158,6 +198,7 @@ class Scoreboard: | |||||||
|                 write_config() |                 write_config() | ||||||
|                  |                  | ||||||
|         except Exception as e: |         except Exception as e: | ||||||
|  |             print(f"Error writing high scores: {e}") | ||||||
|             # If all else fails, try direct old method |             # If all else fails, try direct old method | ||||||
|             for i, entry in enumerate(self.highScores): |             for i, entry in enumerate(self.highScores): | ||||||
|                 localConfig.set("scoreboard", f"score_{i+1}", str(entry['score'])) |                 localConfig.set("scoreboard", f"score_{i+1}", str(entry['score'])) | ||||||
| @@ -174,3 +215,118 @@ class Scoreboard: | |||||||
|              |              | ||||||
|         time.sleep(1) |         time.sleep(1) | ||||||
|         return True |         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