Add menu audio controls and menu music
This commit is contained in:
Binary file not shown.
@@ -20,12 +20,20 @@
|
|||||||
"keybinding_start_menu": {
|
"keybinding_start_menu": {
|
||||||
"keydown_Return": "reset_game",
|
"keydown_Return": "reset_game",
|
||||||
"keydown_Escape": "quit_game",
|
"keydown_Escape": "quit_game",
|
||||||
|
"keydown_Up": "menu_up",
|
||||||
|
"keydown_Down": "menu_down",
|
||||||
|
"keydown_Left": "menu_left",
|
||||||
|
"keydown_Right": "menu_right",
|
||||||
"keydown_M": "toggle_audio",
|
"keydown_M": "toggle_audio",
|
||||||
"keydown_F": "toggle_full_screen"
|
"keydown_F": "toggle_full_screen"
|
||||||
},
|
},
|
||||||
"keybinding_paused": {
|
"keybinding_paused": {
|
||||||
"keydown_Return": "reset_game",
|
"keydown_Return": "reset_game",
|
||||||
"keydown_Escape": "quit_game",
|
"keydown_Escape": "quit_game",
|
||||||
|
"keydown_Up": "menu_up",
|
||||||
|
"keydown_Down": "menu_down",
|
||||||
|
"keydown_Left": "menu_left",
|
||||||
|
"keydown_Right": "menu_right",
|
||||||
"keydown_M": "toggle_audio",
|
"keydown_M": "toggle_audio",
|
||||||
"keydown_F": "toggle_full_screen"
|
"keydown_F": "toggle_full_screen"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,19 @@ keybinding_game:
|
|||||||
keybinding_start_menu:
|
keybinding_start_menu:
|
||||||
controllerbuttondown_a: reset_game
|
controllerbuttondown_a: reset_game
|
||||||
controllerbuttondown_start: reset_game
|
controllerbuttondown_start: reset_game
|
||||||
|
controllerbuttondown_dpad_up: menu_up
|
||||||
|
controllerbuttondown_dpad_down: menu_down
|
||||||
|
controllerbuttondown_dpad_left: menu_left
|
||||||
|
controllerbuttondown_dpad_right: menu_right
|
||||||
controllerbuttondown_b: quit_game
|
controllerbuttondown_b: quit_game
|
||||||
controllerbuttondown_back: quit_game
|
controllerbuttondown_back: quit_game
|
||||||
|
|
||||||
keybinding_paused:
|
keybinding_paused:
|
||||||
controllerbuttondown_a: reset_game
|
controllerbuttondown_a: reset_game
|
||||||
controllerbuttondown_start: toggle_pause
|
controllerbuttondown_start: toggle_pause
|
||||||
|
controllerbuttondown_dpad_up: menu_up
|
||||||
|
controllerbuttondown_dpad_down: menu_down
|
||||||
|
controllerbuttondown_dpad_left: menu_left
|
||||||
|
controllerbuttondown_dpad_right: menu_right
|
||||||
controllerbuttondown_b: quit_game
|
controllerbuttondown_b: quit_game
|
||||||
controllerbuttondown_back: quit_game
|
controllerbuttondown_back: quit_game
|
||||||
@@ -18,11 +18,19 @@ keybinding_game:
|
|||||||
keybinding_start_menu:
|
keybinding_start_menu:
|
||||||
keydown_Return: reset_game
|
keydown_Return: reset_game
|
||||||
keydown_Escape: quit_game
|
keydown_Escape: quit_game
|
||||||
|
keydown_Up: menu_up
|
||||||
|
keydown_Down: menu_down
|
||||||
|
keydown_Left: menu_left
|
||||||
|
keydown_Right: menu_right
|
||||||
keydown_M: toggle_audio
|
keydown_M: toggle_audio
|
||||||
keydown_F: toggle_full_screen
|
keydown_F: toggle_full_screen
|
||||||
|
|
||||||
keybinding_paused:
|
keybinding_paused:
|
||||||
keydown_Return: reset_game
|
keydown_Return: reset_game
|
||||||
keydown_Escape: quit_game
|
keydown_Escape: quit_game
|
||||||
|
keydown_Up: menu_up
|
||||||
|
keydown_Down: menu_down
|
||||||
|
keydown_Left: menu_left
|
||||||
|
keydown_Right: menu_right
|
||||||
keydown_M: toggle_audio
|
keydown_M: toggle_audio
|
||||||
keydown_F: toggle_full_screen
|
keydown_F: toggle_full_screen
|
||||||
@@ -17,8 +17,16 @@ keybinding_start_menu:
|
|||||||
joybuttondown_13: reset_game
|
joybuttondown_13: reset_game
|
||||||
joybuttondown_16: toggle_pause
|
joybuttondown_16: toggle_pause
|
||||||
joybuttondown_12: quit_game
|
joybuttondown_12: quit_game
|
||||||
|
joybuttondown_8: menu_up
|
||||||
|
joybuttondown_9: menu_down
|
||||||
|
joybuttondown_10: menu_left
|
||||||
|
joybuttondown_11: menu_right
|
||||||
|
|
||||||
keybinding_paused:
|
keybinding_paused:
|
||||||
joybuttondown_13: reset_game
|
joybuttondown_13: reset_game
|
||||||
joybuttondown_16: toggle_pause
|
joybuttondown_16: toggle_pause
|
||||||
joybuttondown_12: quit_game
|
joybuttondown_12: quit_game
|
||||||
|
joybuttondown_8: menu_up
|
||||||
|
joybuttondown_9: menu_down
|
||||||
|
joybuttondown_10: menu_left
|
||||||
|
joybuttondown_11: menu_right
|
||||||
|
|||||||
@@ -15,8 +15,16 @@ keybinding_start_menu:
|
|||||||
joybuttondown_9: reset_game
|
joybuttondown_9: reset_game
|
||||||
joybuttondown_10: toggle_pause
|
joybuttondown_10: toggle_pause
|
||||||
joybuttondown_11: quit_game
|
joybuttondown_11: quit_game
|
||||||
|
joyhatmotion_0_1: menu_up
|
||||||
|
joyhatmotion_0_4: menu_down
|
||||||
|
joyhatmotion_0_8: menu_left
|
||||||
|
joyhatmotion_0_2: menu_right
|
||||||
|
|
||||||
keybinding_paused:
|
keybinding_paused:
|
||||||
joybuttondown_9: reset_game
|
joybuttondown_9: reset_game
|
||||||
joybuttondown_10: toggle_pause
|
joybuttondown_10: toggle_pause
|
||||||
joybuttondown_11: quit_game
|
joybuttondown_11: quit_game
|
||||||
|
joyhatmotion_0_1: menu_up
|
||||||
|
joyhatmotion_0_4: menu_down
|
||||||
|
joyhatmotion_0_8: menu_left
|
||||||
|
joyhatmotion_0_2: menu_right
|
||||||
|
|||||||
@@ -279,6 +279,8 @@ class KeyBindings:
|
|||||||
def toggle_audio(self):
|
def toggle_audio(self):
|
||||||
self.render_engine.audio = not self.render_engine.audio
|
self.render_engine.audio = not self.render_engine.audio
|
||||||
self.audio = self.render_engine.audio
|
self.audio = self.render_engine.audio
|
||||||
|
if hasattr(self, "profile_integration") and self.profile_integration:
|
||||||
|
self.profile_integration.set_setting("sound_enabled", self.audio)
|
||||||
if not self.render_engine.audio:
|
if not self.render_engine.audio:
|
||||||
self.render_engine.stop_sound()
|
self.render_engine.stop_sound()
|
||||||
|
|
||||||
|
|||||||
+30
-2
@@ -128,6 +128,7 @@ class GameWindow:
|
|||||||
self.audio_devs["base"] = sdl2.SDL_OpenAudioDevice(None, 0, audio_spec, None, 0)
|
self.audio_devs["base"] = sdl2.SDL_OpenAudioDevice(None, 0, audio_spec, None, 0)
|
||||||
self.audio_devs["effects"] = sdl2.SDL_OpenAudioDevice(None, 0, audio_spec, None, 0)
|
self.audio_devs["effects"] = sdl2.SDL_OpenAudioDevice(None, 0, audio_spec, None, 0)
|
||||||
self.audio_devs["music"] = sdl2.SDL_OpenAudioDevice(None, 0, audio_spec, None, 0)
|
self.audio_devs["music"] = sdl2.SDL_OpenAudioDevice(None, 0, audio_spec, None, 0)
|
||||||
|
self.sound_volume = sdl2.SDL_MIX_MAXVOLUME
|
||||||
self.music_enabled = False
|
self.music_enabled = False
|
||||||
self.music_volume = 128
|
self.music_volume = 128
|
||||||
self.music_track = None
|
self.music_track = None
|
||||||
@@ -149,12 +150,20 @@ class GameWindow:
|
|||||||
self.music_enabled = True
|
self.music_enabled = True
|
||||||
sdlmixer.Mix_VolumeMusic(self.music_volume)
|
sdlmixer.Mix_VolumeMusic(self.music_volume)
|
||||||
|
|
||||||
def set_volume(self, volume_percent):
|
def set_sound_volume(self, volume_percent):
|
||||||
|
clamped = max(0, min(int(volume_percent), 100))
|
||||||
|
self.sound_volume = int(round(clamped * sdl2.SDL_MIX_MAXVOLUME / 100))
|
||||||
|
|
||||||
|
def set_music_volume(self, volume_percent):
|
||||||
clamped = max(0, min(int(volume_percent), 100))
|
clamped = max(0, min(int(volume_percent), 100))
|
||||||
self.music_volume = int(round(clamped * 128 / 100))
|
self.music_volume = int(round(clamped * 128 / 100))
|
||||||
if self.music_enabled and sdlmixer is not None:
|
if self.music_enabled and sdlmixer is not None:
|
||||||
sdlmixer.Mix_VolumeMusic(self.music_volume)
|
sdlmixer.Mix_VolumeMusic(self.music_volume)
|
||||||
|
|
||||||
|
def set_volume(self, volume_percent):
|
||||||
|
self.set_sound_volume(volume_percent)
|
||||||
|
self.set_music_volume(volume_percent)
|
||||||
|
|
||||||
def play_music(self, music_file, loop=True):
|
def play_music(self, music_file, loop=True):
|
||||||
if not self.audio or not self.music_enabled or sdlmixer is None:
|
if not self.audio or not self.music_enabled or sdlmixer is None:
|
||||||
return False
|
return False
|
||||||
@@ -498,12 +507,31 @@ class GameWindow:
|
|||||||
spec = SDL_AudioSpec(freq=22050, aformat=sdl2.AUDIO_U8, channels=1, samples=2048)
|
spec = SDL_AudioSpec(freq=22050, aformat=sdl2.AUDIO_U8, channels=1, samples=2048)
|
||||||
if sdl2.SDL_LoadWAV_RW(rw, 1, byref(spec), byref(_buf), byref(_length)) == None:
|
if sdl2.SDL_LoadWAV_RW(rw, 1, byref(spec), byref(_buf), byref(_length)) == None:
|
||||||
raise RuntimeError("Failed to load WAV")
|
raise RuntimeError("Failed to load WAV")
|
||||||
|
|
||||||
|
if self.sound_volume <= 0:
|
||||||
|
sdl2.SDL_FreeWAV(_buf)
|
||||||
|
return
|
||||||
|
|
||||||
devid = self.audio_devs[tag]
|
devid = self.audio_devs[tag]
|
||||||
# Clear any queued audio
|
# Clear any queued audio
|
||||||
sdl2.SDL_ClearQueuedAudio(devid)
|
sdl2.SDL_ClearQueuedAudio(devid)
|
||||||
|
buffer_length = int(_length.value)
|
||||||
|
|
||||||
|
if self.sound_volume < sdl2.SDL_MIX_MAXVOLUME:
|
||||||
|
scaled_buffer = create_string_buffer(buffer_length)
|
||||||
|
sdl2.SDL_MixAudioFormat(
|
||||||
|
cast(scaled_buffer, POINTER(sdl2.Uint8)),
|
||||||
|
_buf,
|
||||||
|
spec.format,
|
||||||
|
buffer_length,
|
||||||
|
self.sound_volume,
|
||||||
|
)
|
||||||
|
sdl2.SDL_QueueAudio(devid, cast(scaled_buffer, POINTER(sdl2.Uint8)), buffer_length)
|
||||||
|
else:
|
||||||
|
sdl2.SDL_QueueAudio(devid, _buf, buffer_length)
|
||||||
|
|
||||||
|
sdl2.SDL_FreeWAV(_buf)
|
||||||
# Start playing audio
|
# Start playing audio
|
||||||
sdl2.SDL_QueueAudio(devid, _buf, _length)
|
|
||||||
sdl2.SDL_PauseAudioDevice(devid, 0)
|
sdl2.SDL_PauseAudioDevice(devid, 0)
|
||||||
|
|
||||||
def stop_sound(self):
|
def stop_sound(self):
|
||||||
|
|||||||
@@ -72,6 +72,32 @@ class UserProfileIntegration:
|
|||||||
if self.current_profile and 'settings' in self.current_profile:
|
if self.current_profile and 'settings' in self.current_profile:
|
||||||
return self.current_profile['settings'].get(setting_name, default_value)
|
return self.current_profile['settings'].get(setting_name, default_value)
|
||||||
return default_value
|
return default_value
|
||||||
|
|
||||||
|
def set_setting(self, setting_name, value):
|
||||||
|
"""Persist a setting on the active local profile."""
|
||||||
|
if not self.current_profile:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
with self.profiles_file.open('r', encoding='utf-8') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
profile_name = self.current_profile['name']
|
||||||
|
if profile_name not in data.get('profiles', {}):
|
||||||
|
return False
|
||||||
|
|
||||||
|
profile = data['profiles'][profile_name]
|
||||||
|
profile.setdefault('settings', {})
|
||||||
|
profile['settings'][setting_name] = value
|
||||||
|
self.current_profile = profile
|
||||||
|
|
||||||
|
with self.profiles_file.open('w', encoding='utf-8') as f:
|
||||||
|
json.dump(data, f, indent=2)
|
||||||
|
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error updating setting {setting_name}: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
def register_new_user(self, user_id):
|
def register_new_user(self, user_id):
|
||||||
"""Registration is handled locally via the profile manager."""
|
"""Registration is handled locally via the profile manager."""
|
||||||
|
|||||||
@@ -13,6 +13,32 @@ from runtime_paths import bundle_path
|
|||||||
|
|
||||||
|
|
||||||
GAMEPLAY_MUSIC = "Clockwork_Thicket.mp3"
|
GAMEPLAY_MUSIC = "Clockwork_Thicket.mp3"
|
||||||
|
START_MENU_MUSIC = "High_Score_Garden.mp3"
|
||||||
|
START_MENU_AUDIO_OPTIONS = (
|
||||||
|
("sound_volume", "Suono"),
|
||||||
|
("music_volume", "Musica"),
|
||||||
|
)
|
||||||
|
VOLUME_STEP = 5
|
||||||
|
START_MENU_COLORS = {
|
||||||
|
"panel_fill": (248, 248, 244),
|
||||||
|
"panel_border": (52, 52, 52),
|
||||||
|
"header_fill": (230, 236, 231),
|
||||||
|
"text": (24, 24, 24),
|
||||||
|
"muted": (82, 82, 82),
|
||||||
|
"hint_fill": (236, 238, 232),
|
||||||
|
"track_fill": (212, 215, 216),
|
||||||
|
"card_fill": (242, 242, 239),
|
||||||
|
}
|
||||||
|
START_MENU_AUDIO_STYLES = {
|
||||||
|
"sound_volume": {
|
||||||
|
"accent": (214, 146, 62),
|
||||||
|
"fill": (251, 241, 225),
|
||||||
|
},
|
||||||
|
"music_volume": {
|
||||||
|
"accent": (91, 122, 208),
|
||||||
|
"fill": (230, 235, 248),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class MiceMaze(
|
class MiceMaze(
|
||||||
@@ -34,11 +60,13 @@ class MiceMaze(
|
|||||||
|
|
||||||
# Load profile-specific settings
|
# Load profile-specific settings
|
||||||
self.audio = self.profile_integration.get_setting('sound_enabled', True)
|
self.audio = self.profile_integration.get_setting('sound_enabled', True)
|
||||||
sound_volume = self.profile_integration.get_setting('sound_volume', 50)
|
self.sound_volume = self.profile_integration.get_setting('sound_volume', 50)
|
||||||
|
self.music_volume = self.profile_integration.get_setting('music_volume', self.sound_volume)
|
||||||
|
|
||||||
self.cell_size = 40
|
self.cell_size = 40
|
||||||
self.full_screen = False
|
self.full_screen = False
|
||||||
self.loaded_theme_index = None
|
self.loaded_theme_index = None
|
||||||
|
self.start_menu_selection = 0
|
||||||
|
|
||||||
# Initialize render engine with profile-aware title
|
# Initialize render engine with profile-aware title
|
||||||
player_name = self.profile_integration.get_profile_name()
|
player_name = self.profile_integration.get_profile_name()
|
||||||
@@ -50,8 +78,12 @@ class MiceMaze(
|
|||||||
self.render_engine.audio = self.audio
|
self.render_engine.audio = self.audio
|
||||||
|
|
||||||
# Apply profile settings
|
# Apply profile settings
|
||||||
if hasattr(self.render_engine, 'set_volume'):
|
if hasattr(self.render_engine, 'set_sound_volume'):
|
||||||
self.render_engine.set_volume(sound_volume)
|
self.render_engine.set_sound_volume(self.sound_volume)
|
||||||
|
if hasattr(self.render_engine, 'set_music_volume'):
|
||||||
|
self.render_engine.set_music_volume(self.music_volume)
|
||||||
|
elif hasattr(self.render_engine, 'set_volume'):
|
||||||
|
self.render_engine.set_volume(self.music_volume)
|
||||||
self.initialize_keybindings()
|
self.initialize_keybindings()
|
||||||
|
|
||||||
self.load_assets()
|
self.load_assets()
|
||||||
@@ -249,10 +281,223 @@ class MiceMaze(
|
|||||||
if random.random() < 0.01:
|
if random.random() < 0.01:
|
||||||
data["count"] = min(data["count"] + 1, data["max"])
|
data["count"] = min(data["count"] + 1, data["max"])
|
||||||
|
|
||||||
|
def _can_adjust_audio_menu(self):
|
||||||
|
if self.game_end[0]:
|
||||||
|
return False
|
||||||
|
return (
|
||||||
|
self.game_status == "paused"
|
||||||
|
or (self.game_status == "start_menu" and self.menu_screen == "start")
|
||||||
|
)
|
||||||
|
|
||||||
|
def _menu_font(self, size):
|
||||||
|
clamped = max(10, min(69, int(size)))
|
||||||
|
return self.render_engine.fonts[clamped]
|
||||||
|
|
||||||
|
def _draw_start_menu_slider(self, x, y, width, height, setting_name, label, value, selected):
|
||||||
|
colors = START_MENU_COLORS
|
||||||
|
style = START_MENU_AUDIO_STYLES[setting_name]
|
||||||
|
accent = style["accent"]
|
||||||
|
fill_color = style["fill"] if selected else colors["card_fill"]
|
||||||
|
border_color = accent if selected else (156, 156, 156)
|
||||||
|
text_color = colors["text"]
|
||||||
|
render_engine = self.render_engine
|
||||||
|
|
||||||
|
render_engine.draw_rectangle(x, y, width, height, "start_menu_slider", filling=fill_color)
|
||||||
|
render_engine.draw_rectangle(x, y, width, height, "start_menu_slider", outline=border_color)
|
||||||
|
|
||||||
|
if selected:
|
||||||
|
render_engine.draw_rectangle(x + 12, y + 10, 8, height - 20, "start_menu_slider", filling=accent)
|
||||||
|
|
||||||
|
title_y = y + 10
|
||||||
|
render_engine.draw_text(label, self._menu_font(render_engine.target_size[1] // 32), (x + 34, title_y), text_color)
|
||||||
|
render_engine.draw_text(f"{value}%", self._menu_font(render_engine.target_size[1] // 34), (x + width - 84, title_y + 2), text_color)
|
||||||
|
|
||||||
|
track_x = x + 34
|
||||||
|
track_y = y + height - 26
|
||||||
|
track_width = width - 68
|
||||||
|
track_height = 14
|
||||||
|
filled_width = int(track_width * value / 100)
|
||||||
|
knob_width = 14
|
||||||
|
knob_x = track_x + int((track_width - knob_width) * value / 100)
|
||||||
|
|
||||||
|
render_engine.draw_rectangle(track_x, track_y, track_width, track_height, "start_menu_slider", filling=colors["track_fill"])
|
||||||
|
render_engine.draw_rectangle(track_x, track_y, track_width, track_height, "start_menu_slider", outline=(128, 128, 128))
|
||||||
|
if filled_width > 0:
|
||||||
|
render_engine.draw_rectangle(track_x, track_y, filled_width, track_height, "start_menu_slider", filling=accent)
|
||||||
|
render_engine.draw_rectangle(knob_x, track_y - 4, knob_width, track_height + 8, "start_menu_slider", filling=(255, 255, 255))
|
||||||
|
render_engine.draw_rectangle(knob_x, track_y - 4, knob_width, track_height + 8, "start_menu_slider", outline=accent)
|
||||||
|
|
||||||
|
def _render_audio_menu(self, title, subtitle_lines, primary_action_text, hint_text, image_name="BMP_WEWIN"):
|
||||||
|
colors = START_MENU_COLORS
|
||||||
|
render_engine = self.render_engine
|
||||||
|
target_width, target_height = render_engine.target_size
|
||||||
|
compact_menu = target_height <= 540
|
||||||
|
panel_x = max(48, target_width // 12)
|
||||||
|
panel_y = max(34, target_height // 18)
|
||||||
|
panel_width = target_width - panel_x * 2
|
||||||
|
panel_height = target_height - panel_y * 2
|
||||||
|
header_height = max(44, target_height // 13)
|
||||||
|
|
||||||
|
render_engine.draw_rectangle(panel_x, panel_y, panel_width, panel_height, "start_menu", filling=colors["panel_fill"])
|
||||||
|
render_engine.draw_rectangle(panel_x, panel_y, panel_width, panel_height, "start_menu", outline=colors["panel_border"])
|
||||||
|
render_engine.draw_rectangle(panel_x, panel_y, panel_width, header_height, "start_menu", filling=colors["header_fill"])
|
||||||
|
render_engine.draw_text(
|
||||||
|
title,
|
||||||
|
self._menu_font(target_height // 20),
|
||||||
|
("center", panel_y + 16),
|
||||||
|
colors["text"],
|
||||||
|
)
|
||||||
|
|
||||||
|
image = self.assets[image_name]
|
||||||
|
image_width, image_height = render_engine.get_image_size(image)
|
||||||
|
image_y = panel_y + header_height + (14 if compact_menu else 18)
|
||||||
|
render_engine.draw_image(
|
||||||
|
target_width // 2 - image_width // 2 - render_engine.w_offset,
|
||||||
|
image_y - render_engine.h_offset,
|
||||||
|
image,
|
||||||
|
"start_menu",
|
||||||
|
)
|
||||||
|
|
||||||
|
info_y = image_y + image_height + 18
|
||||||
|
line_gap = 18 if compact_menu else max(20, target_height // 34)
|
||||||
|
for index, line in enumerate(subtitle_lines):
|
||||||
|
render_engine.draw_text(
|
||||||
|
line,
|
||||||
|
self._menu_font(target_height // (34 if index == 0 else 36)),
|
||||||
|
("center", info_y + line_gap * index),
|
||||||
|
colors["text"] if index == 0 else colors["muted"],
|
||||||
|
)
|
||||||
|
|
||||||
|
cta_y = info_y + line_gap * len(subtitle_lines) + 8
|
||||||
|
render_engine.draw_text(
|
||||||
|
primary_action_text,
|
||||||
|
self._menu_font(target_height // 31),
|
||||||
|
("center", cta_y),
|
||||||
|
colors["text"],
|
||||||
|
)
|
||||||
|
|
||||||
|
card_width = max(320, min(panel_width - 160, 720))
|
||||||
|
card_height = 60 if compact_menu else max(68, target_height // 10)
|
||||||
|
card_x = target_width // 2 - card_width // 2
|
||||||
|
cards_y = cta_y + (16 if compact_menu else 26)
|
||||||
|
card_gap = 12 if compact_menu else 16
|
||||||
|
for index, (setting_name, label) in enumerate(START_MENU_AUDIO_OPTIONS):
|
||||||
|
card_y = cards_y + index * (card_height + card_gap)
|
||||||
|
self._draw_start_menu_slider(
|
||||||
|
card_x,
|
||||||
|
card_y,
|
||||||
|
card_width,
|
||||||
|
card_height,
|
||||||
|
setting_name,
|
||||||
|
label,
|
||||||
|
getattr(self, setting_name),
|
||||||
|
index == self.start_menu_selection,
|
||||||
|
)
|
||||||
|
|
||||||
|
cards_bottom = cards_y + len(START_MENU_AUDIO_OPTIONS) * card_height + (len(START_MENU_AUDIO_OPTIONS) - 1) * card_gap
|
||||||
|
if compact_menu:
|
||||||
|
hint_y = min(cards_bottom + 8, panel_y + panel_height - 28)
|
||||||
|
render_engine.draw_text(
|
||||||
|
hint_text,
|
||||||
|
self._menu_font(target_height // 42),
|
||||||
|
("center", hint_y),
|
||||||
|
colors["muted"],
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
hint_y = cards_bottom + 10
|
||||||
|
hint_height = max(34, target_height // 18)
|
||||||
|
hint_width = card_width
|
||||||
|
hint_x = card_x
|
||||||
|
render_engine.draw_rectangle(hint_x, hint_y, hint_width, hint_height, "start_menu", filling=colors["hint_fill"])
|
||||||
|
render_engine.draw_rectangle(hint_x, hint_y, hint_width, hint_height, "start_menu", outline=(170, 170, 170))
|
||||||
|
render_engine.draw_text(
|
||||||
|
hint_text,
|
||||||
|
self._menu_font(target_height // 40),
|
||||||
|
("center", hint_y + 10),
|
||||||
|
colors["muted"],
|
||||||
|
)
|
||||||
|
|
||||||
|
def render_start_menu(self):
|
||||||
|
player_profile = self.profile_integration.current_profile
|
||||||
|
device_id = self.profile_integration.get_device_id()
|
||||||
|
subtitle_lines = ["A game by Matteo, because he was bored."]
|
||||||
|
if player_profile:
|
||||||
|
if self.render_engine.target_size[1] <= 540:
|
||||||
|
subtitle_lines.append(
|
||||||
|
f"Best: {player_profile['best_score']} | Games: {player_profile['games_played']} | {device_id}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
subtitle_lines.append(f"Device: {device_id}")
|
||||||
|
subtitle_lines.append(
|
||||||
|
f"Best Score: {player_profile['best_score']} | Games: {player_profile['games_played']}"
|
||||||
|
)
|
||||||
|
elif self.render_engine.target_size[1] <= 540:
|
||||||
|
subtitle_lines.append(f"Guest profile | {device_id}")
|
||||||
|
else:
|
||||||
|
subtitle_lines.append(f"Device: {device_id}")
|
||||||
|
subtitle_lines.append("No profile loaded - playing as guest")
|
||||||
|
|
||||||
|
self._render_audio_menu(
|
||||||
|
title=f"Welcome to Mice, {self.profile_integration.get_profile_name()}!",
|
||||||
|
subtitle_lines=subtitle_lines,
|
||||||
|
primary_action_text="Press Return to start",
|
||||||
|
hint_text="Up/Down select Left/Right adjust M toggle audio",
|
||||||
|
)
|
||||||
|
|
||||||
|
def render_pause_menu(self):
|
||||||
|
subtitle_lines = [
|
||||||
|
f"Level {self.current_level + 1} | Points: {self.points}",
|
||||||
|
f"Rats in maze: {self.count_rats()}",
|
||||||
|
]
|
||||||
|
self._render_audio_menu(
|
||||||
|
title="Pause",
|
||||||
|
subtitle_lines=subtitle_lines,
|
||||||
|
primary_action_text="Press Return to resume",
|
||||||
|
hint_text="Up/Down select Left/Right adjust Esc quits",
|
||||||
|
image_name="BMP_PAUSE" if "BMP_PAUSE" in self.assets else "BMP_WEWIN",
|
||||||
|
)
|
||||||
|
|
||||||
|
def _apply_volume_setting(self, setting_name, value):
|
||||||
|
clamped = max(0, min(100, int(value)))
|
||||||
|
setattr(self, setting_name, clamped)
|
||||||
|
|
||||||
|
if setting_name == "sound_volume":
|
||||||
|
self.render_engine.set_sound_volume(clamped)
|
||||||
|
else:
|
||||||
|
self.render_engine.set_music_volume(clamped)
|
||||||
|
|
||||||
|
self.profile_integration.set_setting(setting_name, clamped)
|
||||||
|
|
||||||
|
def menu_up(self):
|
||||||
|
if not self._can_adjust_audio_menu():
|
||||||
|
return
|
||||||
|
self.start_menu_selection = (self.start_menu_selection - 1) % len(START_MENU_AUDIO_OPTIONS)
|
||||||
|
|
||||||
|
def menu_down(self):
|
||||||
|
if not self._can_adjust_audio_menu():
|
||||||
|
return
|
||||||
|
self.start_menu_selection = (self.start_menu_selection + 1) % len(START_MENU_AUDIO_OPTIONS)
|
||||||
|
|
||||||
|
def _adjust_selected_volume(self, delta):
|
||||||
|
if not self._can_adjust_audio_menu():
|
||||||
|
return
|
||||||
|
setting_name, _ = START_MENU_AUDIO_OPTIONS[self.start_menu_selection]
|
||||||
|
current_value = getattr(self, setting_name)
|
||||||
|
self._apply_volume_setting(setting_name, current_value + delta)
|
||||||
|
|
||||||
|
def menu_left(self):
|
||||||
|
self._adjust_selected_volume(-VOLUME_STEP)
|
||||||
|
|
||||||
|
def menu_right(self):
|
||||||
|
self._adjust_selected_volume(VOLUME_STEP)
|
||||||
|
|
||||||
def update_background_music(self):
|
def update_background_music(self):
|
||||||
if self.game_status == "game" and not self.game_end[0]:
|
if self.game_status == "game" and not self.game_end[0]:
|
||||||
self.render_engine.play_music(GAMEPLAY_MUSIC, loop=True)
|
self.render_engine.play_music(GAMEPLAY_MUSIC, loop=True)
|
||||||
return
|
return
|
||||||
|
if self.game_status == "start_menu" and self.menu_screen == "start" and not self.game_end[0]:
|
||||||
|
self.render_engine.play_music(START_MENU_MUSIC, loop=True)
|
||||||
|
return
|
||||||
self.render_engine.pause_music()
|
self.render_engine.pause_music()
|
||||||
|
|
||||||
def update_maze(self):
|
def update_maze(self):
|
||||||
@@ -260,7 +505,7 @@ class MiceMaze(
|
|||||||
if self.game_over():
|
if self.game_over():
|
||||||
return
|
return
|
||||||
if self.game_status == "paused":
|
if self.game_status == "paused":
|
||||||
self.render_engine.dialog("Pause")
|
self.render_pause_menu()
|
||||||
return
|
return
|
||||||
if self.game_status == "start_menu":
|
if self.game_status == "start_menu":
|
||||||
if self.menu_screen == "level_intro":
|
if self.menu_screen == "level_intro":
|
||||||
@@ -270,25 +515,7 @@ class MiceMaze(
|
|||||||
image=self.assets["BMP_WEWIN"],
|
image=self.assets["BMP_WEWIN"],
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
player_name = self.profile_integration.get_profile_name()
|
self.render_start_menu()
|
||||||
device_id = self.profile_integration.get_device_id()
|
|
||||||
|
|
||||||
greeting_title = f"Welcome to Mice, {player_name}!"
|
|
||||||
subtitle = "A game by Matteo, because he was bored."
|
|
||||||
device_line = f"Device: {device_id}"
|
|
||||||
|
|
||||||
if self.profile_integration.current_profile:
|
|
||||||
profile = self.profile_integration.current_profile
|
|
||||||
stats_line = f"Best Score: {profile['best_score']} | Games: {profile['games_played']}"
|
|
||||||
full_subtitle = f"{subtitle}\n{device_line}\n{stats_line}\nPress Return to start"
|
|
||||||
else:
|
|
||||||
full_subtitle = f"{device_line}\nNo profile loaded - playing as guest\nPress Return to start"
|
|
||||||
|
|
||||||
self.render_engine.dialog(
|
|
||||||
greeting_title,
|
|
||||||
subtitle=full_subtitle,
|
|
||||||
image=self.assets["BMP_WEWIN"],
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
self.render_engine.delete_tag("unit")
|
self.render_engine.delete_tag("unit")
|
||||||
self.render_engine.delete_tag("effect")
|
self.render_engine.delete_tag("effect")
|
||||||
|
|||||||
Reference in New Issue
Block a user