# game_manager.py import pygame import json import importlib import random from engine.scene import Scene from engine.menu import Menu from engine.transitions import Transition from settings import * from engine.sound import init_mixer, load_music, play_music, stop_music from engine.prompt_scene import PromptScene from engine.result_scene import ResultScene import pygame import random import json from engine.sound import play_music, stop_music, fadeout_music from settings import FONT_MD, FONT_LG, WHITE, BLACK, SCREEN_WIDTH, SCREEN_HEIGHT, resource_path # Import all microgame classes from microgames.wario.spot_the_bright_one import SpotTheBrightOne from microgames.wario.light_it_up import LightItUp from microgames.wario.match_the_mood import MatchTheMood from microgames.wario.hot_or_cold import HotOrCold from microgames.wario.truth_or_lie import TruthOrLie from microgames.ninevolt.insert_cartridge import InsertCartridge from microgames.ninevolt.jump_plumber import JumpPlumber from microgames.ninevolt.catch_the_disk import CatchTheDisk from microgames.ninevolt.pixel_paint import PixelPaint from microgames.ninevolt.retro_or_modern import RetroOrModern MICROGAME_CLASSES = { 'microgames.wario.spot_the_bright_one': SpotTheBrightOne, 'microgames.wario.light_it_up': LightItUp, 'microgames.wario.match_the_mood': MatchTheMood, 'microgames.wario.hot_or_cold': HotOrCold, 'microgames.wario.truth_or_lie': TruthOrLie, 'microgames.ninevolt.insert_cartridge': InsertCartridge, 'microgames.ninevolt.jump_plumber': JumpPlumber, 'microgames.ninevolt.catch_the_disk': CatchTheDisk, 'microgames.ninevolt.pixel_paint': PixelPaint, 'microgames.ninevolt.retro_or_modern': RetroOrModern, } class GameManager: def __init__(self, screen, game_type=None): self.screen = screen self.game_type = game_type # 'wario' or 'ninevolt' self.current_microgame = None self.microgame_start_time = 0 self.score = 0 self.lives = 3 self.game_over = False self.speed_level = 0 # 0, 1, 2 for normal, speedup 1, speedup 2 self.max_speed_levels = 2 self.initial_microgame_time_limit = 4000 # 4 seconds self.current_microgame_time_limit = self.initial_microgame_time_limit self.current_music_type = None # Track currently playing music type self.load_microgame_list() self.load_next_microgame() @property def speed(self): return 1 + (self.speed_level * 0.2) # Increase speed by 20% per level def load_microgame_list(self): with open(resource_path('data/microgame_list.json'), 'r') as f: self.microgame_list = json.load(f) def load_next_microgame(self): if self.current_microgame: # self.current_microgame.unload() # No unload method in Scene class pass available_microgames = [] for module_name in MICROGAME_CLASSES.keys(): if self.game_type == 'wario' and 'wario' in module_name: available_microgames.append(module_name) elif self.game_type == 'ninevolt' and 'ninevolt' in module_name: available_microgames.append(module_name) elif self.game_type is None: # If no specific game_type, allow all available_microgames.append(module_name) if not available_microgames: print(f"No microgames found for game_type: {self.game_type}. Loading all microgames.") available_microgames = list(MICROGAME_CLASSES.keys()) microgame_module_name = random.choice(available_microgames) MicrogameClass = MICROGAME_CLASSES[microgame_module_name] self.current_microgame = MicrogameClass(self) self.current_microgame.start() self.microgame_start_time = pygame.time.get_ticks() # Dynamically set time limit based on microgame's timer and end_timer # Add a small buffer (e.g., 500ms) to ensure GameManager doesn't time out prematurely self.current_microgame_time_limit = int((self.current_microgame.timer + 0.5) * 1000) # Load and play music based on microgame type current_microgame_type = 'wario' if 'wario' in microgame_module_name else 'ninevolt' if current_microgame_type != self.current_music_type: if current_microgame_type == 'wario': load_music(resource_path("Assets/music/wario.ogg")) elif current_microgame_type == 'ninevolt': load_music(resource_path("Assets/music/9volt.ogg")) play_music() self.current_music_type = current_microgame_type def update(self, dt): if self.game_over: return current_time = pygame.time.get_ticks() time_left = max(0, self.current_microgame_time_limit - (current_time - self.microgame_start_time)) self.current_microgame.update(dt, time_left) def draw(self, screen): if self.game_over: self._draw_game_over() else: self.current_microgame.draw(self.screen) self._draw_ui(screen) def handle_event(self, event): if self.game_over: return self.current_microgame.handle_event(event) def microgame_finished(self, success, game_type=None): if self.game_over: return if success: self.score += 1 if self.score % 5 == 0 and self.speed_level < self.max_speed_levels: self._update_game_speed() else: self.lives -= 1 self._check_game_over() if not self.game_over: self.current_microgame = ResultScene(self, success, game_type=game_type) def _update_game_speed(self): self.speed_level += 1 # The time limit is recalculated in load_next_microgame def _check_game_over(self): if self.lives <= 0: self.game_over = True fadeout_music(2000) # Fade out music over 2 seconds def _draw_ui(self, screen): score_text = FONT_MD.render(f"Score: {self.score}", True, WHITE) lives_text = FONT_MD.render(f"Lives: {self.lives}", True, WHITE) screen.blit(score_text, (10, 10)) screen.blit(lives_text, (SCREEN_WIDTH - lives_text.get_width() - 10, 10)) # Draw microgame prompt if self.current_microgame and hasattr(self.current_microgame, 'prompt'): prompt_text = FONT_LG.render(self.current_microgame.prompt, True, WHITE) prompt_rect = prompt_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 8)) screen.blit(prompt_text, prompt_rect) # Draw time bar time_left = max(0, self.current_microgame_time_limit - (pygame.time.get_ticks() - self.microgame_start_time)) bar_width = int((time_left / self.current_microgame_time_limit) * SCREEN_WIDTH) pygame.draw.rect(screen, WHITE, (0, SCREEN_HEIGHT - 20, bar_width, 10)) def _draw_game_over(self): game_over_text = FONT_LG.render("GAME OVER", True, WHITE) restart_text = FONT_MD.render("Press R to Restart", True, WHITE) self.screen.blit(game_over_text, (SCREEN_WIDTH // 2 - game_over_text.get_width() // 2, SCREEN_HEIGHT // 2 - game_over_text.get_height() // 2)) self.screen.blit(restart_text, (SCREEN_WIDTH // 2 - restart_text.get_width() // 2, SCREEN_HEIGHT // 2 + restart_text.get_height())) class GameOverScene(Scene): def __init__(self, manager): super().__init__(manager) def update(self, dt): pass # No continuous update needed for game over screen def handle_event(self, event): if event.type == pygame.MOUSEBUTTONDOWN: if event.button == 1: # Left click stop_music() # Stop music when returning to menu self.manager.game_state = "menu" self.manager.current_scene = Menu(self.manager) elif event.type == pygame.KEYDOWN: if event.key == pygame.K_r: stop_music() # Stop music when returning to menu self.manager.game_state = "menu" self.manager.current_scene = Menu(self.manager) def draw(self, screen): screen.fill(BLACK) font = pygame.font.Font(None, 100) text = font.render("Game Over", True, RED) text_rect = text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 3)) screen.blit(text, text_rect) font = pygame.font.Font(None, 50) score_text = font.render(f"Score: {self.manager.score}", True, WHITE) score_rect = score_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2)) screen.blit(score_text, score_rect) font = pygame.font.Font(None, 30) continue_text = font.render("Press R to Restart or Click to continue", True, WHITE) continue_rect = continue_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT * 2 // 3)) screen.blit(continue_text, continue_rect) ""