diff --git a/PyTaiko.py b/PyTaiko.py index b72c2bd..9145e25 100644 --- a/PyTaiko.py +++ b/PyTaiko.py @@ -56,6 +56,13 @@ def create_song_db(): ''' cursor.execute(create_table_query) con.commit() + # Migrate existing records: set clear=2 for full combos (bad=0) + cursor.execute(""" + UPDATE Scores + SET clear = 2 + WHERE bad = 0 AND (clear IS NULL OR clear <> 2) + """) + con.commit() print("Scores database created successfully") def main(): diff --git a/libs/audio.py b/libs/audio.py index 207f8f9..1e1dda4 100644 --- a/libs/audio.py +++ b/libs/audio.py @@ -1,8 +1,6 @@ import cffi import platform from pathlib import Path -from typing import Optional -import numpy as np from libs.utils import get_config @@ -107,7 +105,7 @@ ffi.cdef(""" # gcc -shared -fPIC -o libaudio.so audio.c -lportaudio -lsndfile -lpthread try: if platform.system() == "Windows": - lib = ffi.dlopen("libaudio.dll") # or "libaudio.dll" if that's the compiled name + lib = ffi.dlopen("libaudio.dll") elif platform.system() == "Darwin": lib = ffi.dlopen("./libaudio.dylib") else: # Assume Linux/Unix @@ -134,12 +132,12 @@ class AudioEngine: sample_rate = 44100 self.target_sample_rate = sample_rate self.buffer_size = buffer_size - self.sounds = {} # sound_id -> sound struct - self.music_streams = {} # music_id -> music struct - self.sound_counter = 0 - self.music_counter = 0 + self.sounds = {} + self.music_streams = {} self.audio_device_ready = False + self.sounds_path = Path("Sounds") + def list_host_apis(self): lib.list_host_apis() # type: ignore @@ -148,6 +146,10 @@ class AudioEngine: try: lib.init_audio_device(self.device_type, self.target_sample_rate, self.buffer_size) # type: ignore self.audio_device_ready = lib.is_audio_device_ready() # type: ignore + file_path_str = str(self.sounds_path / 'don.wav').encode('utf-8') + self.don = lib.load_sound(file_path_str) # type: ignore + file_path_str = str(self.sounds_path / 'ka.wav').encode('utf-8') + self.kat = lib.load_sound(file_path_str) # type: ignore if self.audio_device_ready: print("Audio device initialized successfully") return self.audio_device_ready @@ -164,6 +166,8 @@ class AudioEngine: for music_id in list(self.music_streams.keys()): self.unload_music_stream(music_id) + lib.unload_sound(self.don) # type: ignore + lib.unload_sound(self.kat) # type: ignore lib.close_audio_device() # type: ignore self.audio_device_ready = False print("Audio device closed") @@ -183,18 +187,16 @@ class AudioEngine: return lib.get_master_volume() # type: ignore # Sound management - def load_sound(self, file_path: Path) -> str: + def load_sound(self, file_path: Path, name: str) -> str: """Load a sound file and return sound ID""" try: file_path_str = str(file_path).encode('utf-8') sound = lib.load_sound(file_path_str) # type: ignore if lib.is_sound_valid(sound): # type: ignore - sound_id = f"sound_{self.sound_counter}" - self.sounds[sound_id] = sound - self.sound_counter += 1 - print(f"Loaded sound from {file_path} as {sound_id}") - return sound_id + self.sounds[name] = sound + print(f"Loaded sound from {file_path} as {name}") + return name else: print(f"Failed to load sound: {file_path}") return "" @@ -202,164 +204,180 @@ class AudioEngine: print(f"Error loading sound {file_path}: {e}") return "" - def unload_sound(self, sound_id: str) -> None: - """Unload a sound""" - if sound_id in self.sounds: - lib.unload_sound(self.sounds[sound_id]) # type: ignore - del self.sounds[sound_id] + def unload_sound(self, name: str) -> None: + """Unload a sound by name""" + if name in self.sounds: + lib.unload_sound(self.sounds[name]) # type: ignore + del self.sounds[name] + print(f"Unloaded sound {name}") + else: + print(f"Sound {name} not found") - def unload_all_sounds(self) -> None: + def load_screen_sounds(self, screen_name: str) -> None: + """Load sounds for a given screen""" + path = self.sounds_path / screen_name + for sound in path.iterdir(): + if sound.is_dir(): + for file in sound.iterdir(): + self.load_sound(file, sound.stem + '_' + file.stem) + if sound.is_file(): + self.load_sound(sound, sound.stem) + + path = self.sounds_path / 'global' + for sound in path.iterdir(): + if sound.is_dir(): + for file in sound.iterdir(): + self.load_sound(file, sound.stem + '_' + file.stem) + if sound.is_file(): + self.load_sound(sound, sound.stem) + + def unload_all_sounds(self): """Unload all sounds""" - for sound_id in list(self.sounds.keys()): - self.unload_sound(sound_id) + for name in list(self.sounds.keys()): + self.unload_sound(name) - def play_sound(self, sound_id: str) -> None: + def play_sound(self, name: str) -> None: """Play a sound""" - if sound_id in self.sounds: - lib.play_sound(self.sounds[sound_id]) # type: ignore + if name == 'don': + lib.play_sound(self.don) # type: ignore + elif name == 'kat': + lib.play_sound(self.kat) # type: ignore + elif name in self.sounds: + sound = self.sounds[name] + lib.play_sound(sound) # type: ignore + else: + print(f"Sound {name} not found") - def stop_sound(self, sound_id: str) -> None: + def stop_sound(self, name: str) -> None: """Stop a sound""" - if sound_id in self.sounds: - lib.stop_sound(self.sounds[sound_id]) # type: ignore + if name == 'don': + lib.stop_sound(self.don) # type: ignore + elif name == 'kat': + lib.stop_sound(self.kat) # type: ignore + if name in self.sounds: + sound = self.sounds[name] + lib.stop_sound(sound) # type: ignore + else: + print(f"Sound {name} not found") - def pause_sound(self, sound_id: str) -> None: - """Pause a sound""" - if sound_id in self.sounds: - lib.pause_sound(self.sounds[sound_id]) # type: ignore + def is_sound_playing(self, name: str) -> bool: + if name == 'don': + return lib.is_sound_playing(self.don) # type: ignore + elif name == 'kat': + return lib.is_sound_playing(self.kat) # type: ignore + if name in self.sounds: + sound = self.sounds[name] + return lib.is_sound_playing(sound) # type: ignore + else: + print(f"Sound {name} not found") + return False - def resume_sound(self, sound_id: str) -> None: - """Resume a sound""" - if sound_id in self.sounds: - lib.resume_sound(self.sounds[sound_id]) # type: ignore - - def is_sound_valid(self, sound_id: str) -> bool: - """Check if sound is valid""" - if sound_id in self.sounds: - return lib.is_sound_valid(self.sounds[sound_id]) # type: ignore - return False - - def is_sound_playing(self, sound_id: str) -> bool: - """Check if sound is playing""" - if sound_id in self.sounds: - return lib.is_sound_playing(self.sounds[sound_id]) # type: ignore - return False - - def set_sound_volume(self, sound_id: str, volume: float) -> None: - """Set sound volume""" - if sound_id in self.sounds: - lib.set_sound_volume(self.sounds[sound_id], max(0.0, volume)) # type: ignore - - def set_sound_pan(self, sound_id: str, pan: float) -> None: - """Set sound pan (0.0 = left, 0.5 = center, 1.0 = right)""" - if sound_id in self.sounds: - lib.set_sound_pan(self.sounds[sound_id], max(0.0, min(1.0, pan))) # type: ignore - - def normalize_sound(self, sound_id: str, rms: float) -> None: - """Normalize sound - Note: This would need to be implemented in C""" - # The C implementation doesn't have normalize function yet - # You'd need to add this to your C code - print(f"Warning: normalize_sound not implemented in C backend") + def set_sound_volume(self, name: str, volume: float) -> None: + if name == 'don': + lib.set_sound_volume(self.don, volume) # type: ignore + elif name == 'kat': + lib.set_sound_volume(self.kat, volume) # type: ignore + elif name in self.sounds: + sound = self.sounds[name] + lib.set_sound_volume(sound, volume) # type: ignore + else: + print(f"Sound {name} not found") # Music management - def load_music_stream(self, file_path: Path, normalize: Optional[float] = None) -> str: + def load_music_stream(self, file_path: Path, name: str) -> str: """Load a music stream and return music ID""" - try: - file_path_str = str(file_path).encode('utf-8') - music = lib.load_music_stream(file_path_str) # type: ignore + file_path_str = str(file_path).encode('utf-8') + music = lib.load_music_stream(file_path_str) # type: ignore - if lib.is_music_valid(music): # type: ignore - music_id = f"music_{self.music_counter}" - self.music_streams[music_id] = music - self.music_counter += 1 - print(f"Loaded music stream from {file_path} as {music_id}") - return music_id - else: - print(f"Failed to load music: {file_path}") - return "" - except Exception as e: - print(f"Error loading music {file_path}: {e}") + if lib.is_music_valid(music): # type: ignore + self.music_streams[name] = music + print(f"Loaded music stream from {file_path} as {name}") + return name + else: + print(f"Failed to load music: {file_path}") return "" - def load_music_stream_from_data(self, audio_array: np.ndarray, sample_rate: int = 44100) -> str: - """Load music from numpy array - would need C implementation""" - print("Warning: load_music_stream_from_data not implemented in C backend") - return "" - - def unload_music_stream(self, music_id: str) -> None: - """Unload a music stream""" - if music_id in self.music_streams: - lib.unload_music_stream(self.music_streams[music_id]) # type: ignore - del self.music_streams[music_id] - - def is_music_valid(self, music_id: str) -> bool: - """Check if music is valid""" - if music_id in self.music_streams: - return lib.is_music_valid(self.music_streams[music_id]) # type: ignore - return False - - def play_music_stream(self, music_id: str) -> None: + def play_music_stream(self, name: str) -> None: """Play a music stream""" - if music_id in self.music_streams: - lib.seek_music_stream(self.music_streams[music_id], 0) # type: ignore - lib.play_music_stream(self.music_streams[music_id]) # type: ignore + if name in self.music_streams: + music = self.music_streams[name] + lib.seek_music_stream(music, 0) # type: ignore + lib.play_music_stream(music) # type: ignore + else: + print(f"Music stream {name} not found") - def stop_music_stream(self, music_id: str) -> None: + def update_music_stream(self, name: str) -> None: + """Update a music stream""" + if name in self.music_streams: + music = self.music_streams[name] + lib.update_music_stream(music) # type: ignore + else: + print(f"Music stream {name} not found") + + def get_music_time_length(self, name: str) -> float: + """Get the time length of a music stream""" + if name in self.music_streams: + music = self.music_streams[name] + return lib.get_music_time_length(music) # type: ignore + else: + print(f"Music stream {name} not found") + return 0.0 + + def get_music_time_played(self, name: str) -> float: + """Get the time played of a music stream""" + if name in self.music_streams: + music = self.music_streams[name] + return lib.get_music_time_played(music) # type: ignore + else: + print(f"Music stream {name} not found") + return 0.0 + + def set_music_volume(self, name: str, volume: float) -> None: + """Set the volume of a music stream""" + if name in self.music_streams: + music = self.music_streams[name] + lib.set_music_volume(music, volume) # type: ignore + else: + print(f"Music stream {name} not found") + + def is_music_stream_playing(self, name: str) -> bool: + """Check if a music stream is playing""" + if name in self.music_streams: + music = self.music_streams[name] + return lib.is_music_stream_playing(music) # type: ignore + else: + print(f"Music stream {name} not found") + return False + + def stop_music_stream(self, name: str) -> None: """Stop a music stream""" - if music_id in self.music_streams: - lib.stop_music_stream(self.music_streams[music_id]) # type: ignore + if name in self.music_streams: + music = self.music_streams[name] + lib.stop_music_stream(music) # type: ignore + else: + print(f"Music stream {name} not found") - def pause_music_stream(self, music_id: str) -> None: - """Pause a music stream""" - if music_id in self.music_streams: - lib.pause_music_stream(self.music_streams[music_id]) # type: ignore + def unload_music_stream(self, name: str) -> None: + """Unload a music stream""" + if name in self.music_streams: + music = self.music_streams[name] + lib.unload_music_stream(music) # type: ignore + del self.music_streams[name] + else: + print(f"Music stream {name} not found") - def resume_music_stream(self, music_id: str) -> None: - """Resume a music stream""" - if music_id in self.music_streams: - lib.resume_music_stream(self.music_streams[music_id]) # type: ignore + def unload_all_music(self) -> None: + """Unload all music streams""" + for music_id in list(self.music_streams.keys()): + self.unload_music_stream(music_id) - def is_music_stream_playing(self, music_id: str) -> bool: - """Check if music stream is playing""" - if music_id in self.music_streams: - return lib.is_music_stream_playing(self.music_streams[music_id]) # type: ignore - return False - - def seek_music_stream(self, music_id: str, position: float) -> None: - """Seek music stream to position in seconds""" - if music_id in self.music_streams: - lib.seek_music_stream(self.music_streams[music_id], position) # type: ignore - - def update_music_stream(self, music_id: str) -> None: - """Update music stream (fill buffers)""" - if music_id in self.music_streams: - lib.update_music_stream(self.music_streams[music_id]) # type: ignore - - def set_music_volume(self, music_id: str, volume: float) -> None: - """Set music volume""" - if music_id in self.music_streams: - lib.set_music_volume(self.music_streams[music_id], max(0.0, min(1.0, volume))) # type: ignore - - def set_music_pan(self, music_id: str, pan: float) -> None: - """Set music pan""" - if music_id in self.music_streams: - lib.set_music_pan(self.music_streams[music_id], max(0.0, min(1.0, pan))) # type: ignore - - def normalize_music_stream(self, music_id: str, rms: float) -> None: - """Normalize music stream - would need C implementation""" - print("Warning: normalize_music_stream not implemented in C backend") - - def get_music_time_length(self, music_id: str) -> float: - """Get total music length in seconds""" - if music_id in self.music_streams: - return lib.get_music_time_length(self.music_streams[music_id]) # type: ignore - return 0.0 - - def get_music_time_played(self, music_id: str) -> float: - """Get current music position in seconds""" - if music_id in self.music_streams: - return lib.get_music_time_played(self.music_streams[music_id]) # type: ignore - return 0.0 + def seek_music_stream(self, name: str, position: float) -> None: + """Seek a music stream to a specific position""" + if name in self.music_streams: + music = self.music_streams[name] + lib.seek_music_stream(music, position) # type: ignore + else: + print(f"Music stream {name} not found") # Create the global audio instance audio = AudioEngine(get_config()["audio"]["device_type"], get_config()["audio"]["sample_rate"], get_config()["audio"]["buffer_size"]) diff --git a/libs/global_objects.py b/libs/global_objects.py index 3e7f86e..2045b38 100644 --- a/libs/global_objects.py +++ b/libs/global_objects.py @@ -2,6 +2,7 @@ from enum import Enum import pyray as ray from libs.utils import OutlinedText, get_config, global_tex +from libs.audio import audio class Nameplate: @@ -123,7 +124,7 @@ class Timer: self.is_finished = False self.is_frozen = get_config()["general"]["timer_frozen"] def update(self, current_time_ms: float): - if self.time == 0 and not self.is_finished: + if self.time == 0 and not self.is_finished and not audio.is_sound_playing('voice_timer_0'): self.is_finished = True self.confirm_func() self.num_resize.update(current_time_ms) @@ -136,9 +137,16 @@ class Timer: self.last_time = current_time_ms self.counter = str(self.time) if self.time < 10: + audio.play_sound('timer_blip') self.num_resize.start() self.highlight_fade.start() self.highlight_resize.start() + if self.time == 10: + audio.play_sound('voice_timer_10') + elif self.time == 5: + audio.play_sound('voice_timer_5') + elif self.time == 0: + audio.play_sound('voice_timer_0') def draw(self, x: int = 0, y: int = 0): tex = global_tex if self.time < 10: diff --git a/libs/song_hash.py b/libs/song_hash.py index d2cfe8e..9214ed4 100644 --- a/libs/song_hash.py +++ b/libs/song_hash.py @@ -158,7 +158,7 @@ def build_song_hashes(output_dir=Path("cache")): continue if imported_clears[i] == 2: bads = 0 - clear = 1 + clear = 2 elif imported_clears[i] == 1: bads = None clear = 1 diff --git a/libs/video.py b/libs/video.py index a104f5d..5f388f8 100644 --- a/libs/video.py +++ b/libs/video.py @@ -14,7 +14,7 @@ class VideoPlayer: self.video = VideoFileClip(path) if self.video.audio is not None: self.video.audio.write_audiofile("cache/temp_audio.wav") - self.audio = audio.load_music_stream(Path("cache/temp_audio.wav")) + self.audio = audio.load_music_stream(Path("cache/temp_audio.wav"), 'video') self.buffer_size = 10 # Number of frames to keep in memory self.frame_buffer: dict[float, ray.Texture] = dict() # Dictionary to store frames {timestamp: texture} diff --git a/scenes/entry.py b/scenes/entry.py index d41f369..581d76e 100644 --- a/scenes/entry.py +++ b/scenes/entry.py @@ -1,5 +1,3 @@ -from pathlib import Path - import pyray as ray from libs.audio import audio @@ -25,19 +23,10 @@ class EntryScreen: def __init__(self): self.screen_init = False - def load_textures(self): - tex.load_screen_textures('entry') - - def load_sounds(self): - sounds_dir = Path("Sounds") - self.sound_don = audio.load_sound(sounds_dir / "hit_sounds" / "0" / "don.wav") - self.sound_kat = audio.load_sound(sounds_dir / "hit_sounds" / "0" / "ka.wav") - self.bgm = audio.load_sound(sounds_dir / "entry" / "JINGLE_ENTRY [1].ogg") - def on_screen_start(self): if not self.screen_init: - self.load_textures() - self.load_sounds() + tex.load_screen_textures('entry') + audio.load_screen_sounds('entry') self.side = 1 self.box_manager = BoxManager() self.state = State.SELECT_SIDE @@ -61,15 +50,16 @@ class EntryScreen: self.nameplate_fadein = tex.get_animation(12) self.side_select_fade.start() self.chara = Chara2D(0, 100) - audio.play_sound(self.bgm) + self.announce_played = False + audio.play_sound('bgm') def on_screen_end(self, next_screen: str): self.screen_init = False - global_data.player_num = round((self.side/3) + 1) - audio.stop_sound(self.bgm) + audio.stop_sound('bgm') self.nameplate.unload() tex.unload_textures() audio.unload_all_sounds() + audio.unload_all_music() return next_screen def handle_input(self): @@ -79,6 +69,7 @@ class EntryScreen: if is_l_don_pressed() or is_r_don_pressed(): if self.side == 1: return self.on_screen_end("TITLE") + global_data.player_num = round((self.side/3) + 1) self.drum_move_1.start() self.drum_move_2.start() self.drum_move_3.start() @@ -86,31 +77,33 @@ class EntryScreen: self.cloud_resize_loop.start() self.cloud_texture_change.start() self.cloud_fade.start() + audio.play_sound('cloud') + audio.play_sound(f'entry_start_{global_data.player_num}p') plate_info = global_data.config['nameplate'] self.nameplate.unload() - self.nameplate = Nameplate(plate_info['name'], plate_info['title'], round((self.side/3) + 1), plate_info['dan'], plate_info['gold']) + self.nameplate = Nameplate(plate_info['name'], plate_info['title'], global_data.player_num, plate_info['dan'], plate_info['gold']) self.nameplate_fadein.start() self.state = State.SELECT_MODE if self.side == 2: self.chara = Chara2D(1, 100) else: self.chara = Chara2D(0, 100) - audio.play_sound(self.sound_don) + audio.play_sound('don') if is_l_kat_pressed(): - audio.play_sound(self.sound_kat) + audio.play_sound('kat') self.side = max(0, self.side - 1) if is_r_kat_pressed(): - audio.play_sound(self.sound_kat) + audio.play_sound('kat') self.side = min(2, self.side + 1) elif self.state == State.SELECT_MODE: if is_l_don_pressed() or is_r_don_pressed(): - audio.play_sound(self.sound_don) + audio.play_sound('don') self.box_manager.select_box() if is_l_kat_pressed(): - audio.play_sound(self.sound_kat) + audio.play_sound('kat') self.box_manager.move_left() if is_r_kat_pressed(): - audio.play_sound(self.sound_kat) + audio.play_sound('kat') self.box_manager.move_right() def update(self): @@ -133,6 +126,9 @@ class EntryScreen: self.chara.update(current_time, 100, False, False) if self.box_manager.is_finished(): return self.on_screen_end(self.box_manager.selected_box()) + if self.cloud_fade.is_finished and not audio.is_sound_playing(f'entry_start_{global_data.player_num}p') and not self.announce_played: + audio.play_sound('select_mode') + self.announce_played = True return self.handle_input() def draw_background(self): diff --git a/scenes/game.py b/scenes/game.py index 00636b3..d2038b4 100644 --- a/scenes/game.py +++ b/scenes/game.py @@ -49,21 +49,17 @@ class GameScreen: self.song_started = False self.mask_shader = ray.load_shader("", "shader/mask.fs") - def load_sounds(self): + def load_hitsounds(self): sounds_dir = Path("Sounds") if global_data.hit_sound == -1: - self.sound_don = audio.load_sound(Path('none.wav')) - self.sound_kat = audio.load_sound(Path('none.wav')) + self.sound_don = audio.load_sound(Path('none.wav'), 'hitsound_don') + self.sound_kat = audio.load_sound(Path('none.wav'), 'hitsound_kat') if global_data.hit_sound == 0: - self.sound_don = audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "don.wav") - self.sound_kat = audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "ka.wav") + self.sound_don = audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "don.wav", 'hitsound_don') + self.sound_kat = audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "ka.wav", 'hitsound_kat') else: - self.sound_don = audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "don.ogg") - self.sound_kat = audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "ka.ogg") - self.sound_restart = audio.load_sound(sounds_dir / 'song_select' / 'Skip.ogg') - self.sound_balloon_pop = audio.load_sound(sounds_dir / "balloon_pop.wav") - self.sound_kusudama_pop = audio.load_sound(sounds_dir / "kusudama_pop.ogg") - self.sound_result_transition = audio.load_sound(sounds_dir / "result" / "VO_RESULT [1].ogg") + self.sound_don = audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "don.ogg", 'hitsound_don') + self.sound_kat = audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound) / "ka.ogg", 'hitsound_kat') def init_tja(self, song: Path, difficulty: int): if song == Path(''): @@ -78,8 +74,7 @@ class GameScreen: self.movie = None session_data.song_title = self.tja.metadata.title.get(global_data.config['general']['language'].lower(), self.tja.metadata.title['en']) if self.tja.metadata.wave.exists() and self.tja.metadata.wave.is_file() and self.song_music is None: - self.song_music = audio.load_music_stream(self.tja.metadata.wave) - audio.normalize_music_stream(self.song_music, 0.1935) + self.song_music = audio.load_music_stream(self.tja.metadata.wave, 'song') self.player_1 = Player(self.tja, global_data.player_num, difficulty) if self.tja is not None: @@ -91,9 +86,10 @@ class GameScreen: self.movie = None self.song_music = None tex.load_screen_textures('game') + audio.load_screen_sounds('game') + self.load_hitsounds() ray.set_shader_value_texture(self.mask_shader, ray.get_shader_location(self.mask_shader, "texture0"), tex.textures['balloon']['rainbow_mask'].texture) ray.set_shader_value_texture(self.mask_shader, ray.get_shader_location(self.mask_shader, "texture1"), tex.textures['balloon']['rainbow'].texture) - self.load_sounds() self.init_tja(global_data.selected_song, session_data.selected_difficulty) self.song_info = SongInfo(session_data.song_title, session_data.genre_index) self.result_transition = ResultTransition(global_data.player_num) @@ -113,8 +109,8 @@ class GameScreen: def on_screen_end(self, next_screen): self.screen_init = False tex.unload_textures() - if self.song_music is not None: - audio.unload_music_stream(self.song_music) + audio.unload_all_sounds() + audio.unload_all_music() self.song_started = False self.end_ms = 0 self.movie = None @@ -131,14 +127,24 @@ class GameScreen: cursor = con.cursor() notes, _, _, _ = TJAParser.notes_to_position(TJAParser(self.tja.file_path), self.player_1.difficulty) hash = self.tja.hash_note_data(notes) - check_query = "SELECT score FROM Scores WHERE hash = ? LIMIT 1" + check_query = "SELECT score, clear FROM Scores WHERE hash = ? LIMIT 1" cursor.execute(check_query, (hash,)) result = cursor.fetchone() - if result is None or session_data.result_score > result[0]: + existing_score = result[0] if result is not None else None + existing_clear = result[1] if result is not None and len(result) > 1 and result[1] is not None else 0 + + # Determine clear value for this run: 2 for full combo (no bads), 1 for clear gauge, 0 otherwise + run_clear = 2 if session_data.result_bad == 0 else (1 if self.player_1.gauge.is_clear else 0) + best_clear = max(existing_clear, run_clear) + + if result is None or (existing_score is not None and session_data.result_score > existing_score): if result is None: session_data.prev_score = 0 else: - session_data.prev_score = result[0] + if not isinstance(existing_score, int): + session_data.prev_score = 0 + else: + session_data.prev_score = existing_score insert_query = ''' INSERT OR REPLACE INTO Scores (hash, en_name, jp_name, diff, score, good, ok, bad, drumroll, combo, clear) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); @@ -147,9 +153,14 @@ class GameScreen: self.tja.metadata.title.get('ja', ''), self.player_1.difficulty, session_data.result_score, session_data.result_good, session_data.result_ok, session_data.result_bad, - session_data.result_total_drumroll, session_data.result_max_combo, int(self.player_1.gauge.is_clear)) + session_data.result_total_drumroll, session_data.result_max_combo, best_clear) cursor.execute(insert_query, data) con.commit() + else: + # Score didn't improve; if clear improved, update only the clear column to preserve best crown + if run_clear > existing_clear: + cursor.execute("UPDATE Scores SET clear = ? WHERE hash = ?", (run_clear, hash)) + con.commit() def update(self): self.on_screen_start() @@ -178,7 +189,7 @@ class GameScreen: self.player_1.update(self, current_time) self.song_info.update(current_time) self.result_transition.update(current_time) - if self.result_transition.is_finished: + if self.result_transition.is_finished and not audio.is_sound_playing('result_transition'): return self.on_screen_end('RESULT') elif self.current_ms >= self.player_1.end_time: session_data.result_score, session_data.result_good, session_data.result_ok, session_data.result_bad, session_data.result_max_combo, session_data.result_total_drumroll = self.player_1.get_result_score() @@ -195,7 +206,7 @@ class GameScreen: if current_time >= self.end_ms + 8533.34: if not self.result_transition.is_started: self.result_transition.start() - audio.play_sound(self.sound_result_transition) + audio.play_sound('result_transition') else: self.write_score() self.end_ms = current_time @@ -204,7 +215,7 @@ class GameScreen: if self.song_music is not None: audio.stop_music_stream(self.song_music) self.init_tja(global_data.selected_song, session_data.selected_difficulty) - audio.play_sound(self.sound_restart) + audio.play_sound('restart') self.song_started = False if ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE): @@ -570,7 +581,7 @@ class Player: self.is_balloon = False note.popped = True self.balloon_anim.update(current_time, self.curr_balloon_count, note.popped) - audio.play_sound(game_screen.sound_balloon_pop) + audio.play_sound('balloon_pop') self.note_correct(note, current_time) self.curr_balloon_count = 0 @@ -582,7 +593,7 @@ class Player: self.score += 100 self.base_score_list.append(ScoreCounterAnimation(self.player_number, 100)) if self.curr_balloon_count == note.count: - audio.play_sound(game_screen.sound_kusudama_pop) + audio.play_sound('kusudama_pop') self.is_balloon = False note.popped = True self.curr_balloon_count = 0 @@ -1696,6 +1707,7 @@ class ComboAnnounce: self.fade = Animation.create_fade(100) self.fade.start() self.is_finished = False + self.audio_played = False def update(self, current_time_ms: float): if current_time_ms >= self.wait + 1666.67 and not self.is_finished: @@ -1703,6 +1715,9 @@ class ComboAnnounce: self.is_finished = True self.fade.update(current_time_ms) + if not self.audio_played: + audio.play_sound(f'combo_{self.combo}_{global_data.player_num}p') + self.audio_played = True def draw(self): if self.combo == 0: @@ -1800,6 +1815,7 @@ class FailAnimation: self.text_fade_in.start() self.name = 'in' self.frame = self.bachio_texture_change.attribute + audio.play_sound('fail') def update(self, current_time_ms: float): self.bachio_fade_in.update(current_time_ms) self.bachio_texture_change.update(current_time_ms) @@ -1843,6 +1859,7 @@ class ClearAnimation: self.draw_clear_full = False self.name = 'in' self.frame = 0 + audio.play_sound('clear') def update(self, current_time_ms: float): self.bachio_fade_in.update(current_time_ms) @@ -1899,6 +1916,7 @@ class FCAnimation: self.draw_clear_full = False self.name = 'in' self.frame = 0 + audio.play_sound('full_combo') def update(self, current_time_ms: float): self.bachio_fade_in.update(current_time_ms) @@ -1918,6 +1936,7 @@ class FCAnimation: self.bachio_move_up.start() self.fan_fade_in.start() self.fan_texture_change.start() + audio.play_sound('full_combo_voice') if self.clear_highlight_fade_in.attribute == 1.0: self.draw_clear_full = True for fade in self.clear_separate_fade_in: diff --git a/scenes/result.py b/scenes/result.py index ae92ac2..6809e41 100644 --- a/scenes/result.py +++ b/scenes/result.py @@ -1,5 +1,3 @@ -from pathlib import Path - import pyray as ray from libs import utils @@ -28,23 +26,13 @@ class ResultScreen: self.height = 720 self.screen_init = False - def load_textures(self): - tex.load_screen_textures('result') - - def load_sounds(self): - sounds_dir = Path("Sounds") - self.sound_don = audio.load_sound(sounds_dir / "hit_sounds" / "0" / "don.wav") - self.sound_kat = audio.load_sound(sounds_dir / "hit_sounds" / "0" / "ka.wav") - self.sound_num_up = audio.load_sound(sounds_dir / "result" / "SE_RESULT [4].ogg") - self.bgm = audio.load_sound(sounds_dir / "result" / "JINGLE_SEISEKI [1].ogg") - def on_screen_start(self): if not self.screen_init: - self.load_textures() - self.load_sounds() + tex.load_screen_textures('result') + audio.load_screen_sounds('result') self.screen_init = True self.song_info = OutlinedText(session_data.song_title, 40, ray.WHITE, ray.BLACK, outline_thickness=5) - audio.play_sound(self.bgm) + audio.play_sound('bgm') self.fade_in = FadeIn() self.fade_out = tex.get_animation(0) self.fade_in_bottom = tex.get_animation(1) @@ -86,7 +74,9 @@ class ResultScreen: self.screen_init = False global_data.songs_played += 1 tex.unload_textures() - audio.stop_sound(self.bgm) + audio.stop_sound('bgm') + audio.unload_all_sounds() + audio.unload_all_music() utils.session_data = utils.reset_session() return "SONG_SELECT" @@ -102,9 +92,9 @@ class ResultScreen: curr_num = self.update_list[self.update_index][0] setattr(self, self.update_list[self.update_index][0], self.score_animator.next_score()) if self.update_list[self.update_index] != curr_num: - audio.play_sound(self.sound_num_up) + audio.play_sound('num_up') if self.score_animator.is_finished: - audio.play_sound(self.sound_don) + audio.play_sound('don') self.score_delay += 750 if self.update_index == len(self.update_list) - 1: self.is_skipped = True @@ -122,7 +112,7 @@ class ResultScreen: self.is_skipped = True else: self.fade_out.start() - audio.play_sound(self.sound_don) + audio.play_sound('don') def update(self): self.on_screen_start() @@ -281,7 +271,6 @@ class Crown: self.white_fadein.start() self.gleam.start() self.fadein.start() - self.sound = audio.load_sound(Path('Sounds/result/SE_RESULT [1].ogg')) self.sound_played = False def update(self, current_ms: float): @@ -291,7 +280,7 @@ class Crown: self.white_fadein.update(current_ms) self.gleam.update(current_ms) if self.resize_fix.is_finished and not self.sound_played: - audio.play_sound(self.sound) + audio.play_sound('crown') self.sound_played = True def draw(self, crown_name: str): diff --git a/scenes/song_select.py b/scenes/song_select.py index 835e2f1..e344177 100644 --- a/scenes/song_select.py +++ b/scenes/song_select.py @@ -43,21 +43,14 @@ class SongSelectScreen: def load_navigator(self): self.navigator = FileNavigator(self.root_dir) - def load_sounds(self): - sounds_dir = Path("Sounds") - self.sound_don = audio.load_sound(sounds_dir / "hit_sounds" / "0" / "don.wav") - self.sound_kat = audio.load_sound(sounds_dir / "hit_sounds" / "0" / "ka.wav") - self.sound_skip = audio.load_sound(sounds_dir / 'song_select' / 'Skip.ogg') - self.sound_ura_switch = audio.load_sound(sounds_dir / 'song_select' / 'SE_SELECT [4].ogg') - self.sound_add_favorite = audio.load_sound(sounds_dir / 'song_select' / 'add_favorite.ogg') - audio.set_sound_volume(self.sound_ura_switch, 0.25) - audio.set_sound_volume(self.sound_add_favorite, 3.0) - self.sound_bgm = audio.load_sound(sounds_dir / "song_select" / "JINGLE_GENRE [1].ogg") - def on_screen_start(self): if not self.screen_init: tex.load_screen_textures('song_select') - self.load_sounds() + audio.load_screen_sounds('song_select') + audio.set_sound_volume('ura_switch', 0.25) + audio.set_sound_volume('add_favorite', 3.0) + audio.play_sound('bgm') + audio.play_sound('voice_enter') self.background_move = tex.get_animation(0) self.move_away = tex.get_animation(1) self.diff_fade_out = tex.get_animation(2) @@ -120,6 +113,7 @@ class SongSelectScreen: self.reset_demo_music() self.navigator.reset_items() audio.unload_all_sounds() + audio.unload_all_music() tex.unload_textures() self.nameplate.unload() return next_screen @@ -128,7 +122,7 @@ class SongSelectScreen: if self.demo_song is not None: audio.stop_music_stream(self.demo_song) audio.unload_music_stream(self.demo_song) - audio.play_sound(self.sound_bgm) + audio.play_sound('bgm') self.demo_song = None self.navigator.get_current_item().box.wait = get_current_ms() @@ -137,24 +131,24 @@ class SongSelectScreen: self.reset_demo_music() for _ in range(10): self.navigator.navigate_left() - audio.play_sound(self.sound_skip) + audio.play_sound('skip') self.last_moved = get_current_ms() elif ray.is_key_pressed(ray.KeyboardKey.KEY_RIGHT_CONTROL) or (is_r_kat_pressed() and get_current_ms() <= self.last_moved + 50): self.reset_demo_music() for _ in range(10): self.navigator.navigate_right() - audio.play_sound(self.sound_skip) + audio.play_sound('skip') self.last_moved = get_current_ms() elif is_l_kat_pressed(): self.reset_demo_music() self.navigator.navigate_left() - audio.play_sound(self.sound_kat) + audio.play_sound('kat') self.last_moved = get_current_ms() elif is_r_kat_pressed(): self.reset_demo_music() self.navigator.navigate_right() - audio.play_sound(self.sound_kat) + audio.play_sound('kat') self.last_moved = get_current_ms() # Select/Enter @@ -162,7 +156,7 @@ class SongSelectScreen: selected_item = self.navigator.items[self.navigator.selected_index] if selected_item is not None and selected_item.box.is_back: self.navigator.go_back() - #audio.play_sound(self.sound_cancel) + audio.play_sound('cancel') elif isinstance(selected_item, Directory) and selected_item.collection == Directory.COLLECTIONS[3]: self.state = State.DIFF_SORTING self.diff_sort_selector = DiffSortSelect(self.navigator.diff_sort_statistics, self.navigator.diff_sort_diff, self.navigator.diff_sort_level) @@ -177,7 +171,8 @@ class SongSelectScreen: elif (4 in selected_song.tja.metadata.course_data and 3 not in selected_song.tja.metadata.course_data): self.is_ura = True - audio.play_sound(self.sound_don) + audio.play_sound('don') + audio.play_sound('voice_select_diff') self.move_away.start() self.diff_fade_out.start() self.text_fade_out.start() @@ -188,7 +183,7 @@ class SongSelectScreen: if ray.is_key_pressed(ray.KeyboardKey.KEY_SPACE): success = self.navigator.add_favorite() if success: - audio.play_sound(self.sound_add_favorite) + audio.play_sound('add_favorite') def handle_input_selected(self): # Handle song selection confirmation or cancel @@ -198,28 +193,28 @@ class SongSelectScreen: elif is_r_kat_pressed(): self.neiro_selector.move_right() if is_l_don_pressed() or is_r_don_pressed(): - audio.play_sound(self.sound_don) + audio.play_sound('don') self.neiro_selector.confirm() return if self.modifier_selector is not None: if is_l_kat_pressed(): - audio.play_sound(self.sound_kat) + audio.play_sound('kat') self.modifier_selector.left() elif is_r_kat_pressed(): - audio.play_sound(self.sound_kat) + audio.play_sound('kat') self.modifier_selector.right() if is_l_don_pressed() or is_r_don_pressed(): - audio.play_sound(self.sound_don) + audio.play_sound('don') self.modifier_selector.confirm() return if is_l_don_pressed() or is_r_don_pressed(): if self.selected_difficulty == -3: self._cancel_selection() elif self.selected_difficulty == -2: - audio.play_sound(self.sound_don) + audio.play_sound('don') self.modifier_selector = ModifierSelector() elif self.selected_difficulty == -1: - audio.play_sound(self.sound_don) + audio.play_sound('don') self.neiro_selector = NeiroSelector() else: self._confirm_selection() @@ -231,7 +226,7 @@ class SongSelectScreen: return selected_song if is_l_kat_pressed() or is_r_kat_pressed(): - audio.play_sound(self.sound_kat) + audio.play_sound('kat') selected_song = get_current_song() diffs = sorted(selected_song.tja.metadata.course_data) prev_diff = self.selected_difficulty @@ -254,13 +249,13 @@ class SongSelectScreen: raise Exception("Diff sort selector was not able to be created") if is_l_kat_pressed(): self.diff_sort_selector.input_left() - audio.play_sound(self.sound_kat) + audio.play_sound('kat') if is_r_kat_pressed(): self.diff_sort_selector.input_right() - audio.play_sound(self.sound_kat) + audio.play_sound('kat') if is_l_don_pressed() or is_r_don_pressed(): tuple = self.diff_sort_selector.input_select() - audio.play_sound(self.sound_don) + audio.play_sound('don') if tuple is None: return diff, level = tuple @@ -289,7 +284,8 @@ class SongSelectScreen: def _confirm_selection(self): """Confirm song selection and create game transition""" - audio.play_sound(self.sound_don) + audio.play_sound('don') + audio.play_sound(f'voice_start_song_{global_data.player_num}p') self.selected_diff_highlight_fade.start() self.selected_diff_text_resize.start() self.selected_diff_text_fadein.start() @@ -354,7 +350,7 @@ class SongSelectScreen: self.ura_toggle = 0 self.is_ura = not self.is_ura self.ura_switch_animation.start(not self.is_ura) - audio.play_sound(self.sound_ura_switch) + audio.play_sound('ura_switch') self.selected_difficulty = 7 - self.selected_difficulty def handle_input(self): @@ -431,7 +427,7 @@ class SongSelectScreen: if self.modifier_selector.is_finished: self.modifier_selector = None - if self.selected_diff_highlight_fade.is_finished and self.game_transition is None: + if self.selected_diff_highlight_fade.is_finished and not audio.is_sound_playing(f'voice_start_song_{global_data.player_num}p') and self.game_transition is None: selected_song = self.navigator.get_current_item() if not isinstance(selected_song, SongFile): raise Exception("picked directory") @@ -450,10 +446,10 @@ class SongSelectScreen: if self.demo_song is None and get_current_ms() >= song.box.wait + (83.33*3): song.box.get_scores() if song.tja.metadata.wave.exists() and song.tja.metadata.wave.is_file(): - self.demo_song = audio.load_music_stream(song.tja.metadata.wave) + self.demo_song = audio.load_music_stream(song.tja.metadata.wave, 'demo_song') audio.play_music_stream(self.demo_song) audio.seek_music_stream(self.demo_song, song.tja.metadata.demostart) - audio.stop_sound(self.sound_bgm) + audio.stop_sound('bgm') if song.box.is_open: current_box = song.box if not current_box.is_back and get_current_ms() >= song.box.wait + (83.33*3): @@ -623,6 +619,10 @@ class SongBox: self.target_position = -1 self.is_open = False self.is_back = self.texture_index == SongBox.BACK_INDEX + if self.is_back: + for i in range(1, 16): + if audio.is_sound_playing(f'genre_voice_{i}'): + audio.stop_sound(f'genre_voice_{i}') self.name = None self.black_name = None self.hori_name = None @@ -732,6 +732,10 @@ class SongBox: self.wait = get_current_ms() if get_current_ms() >= self.history_wait + 3000: self.history_wait = get_current_ms() + if self.tja is None and self.texture_index != 17 and not audio.is_sound_playing('voice_enter'): + audio.play_sound(f'genre_voice_{self.texture_index}') + elif not self.is_open and is_open_prev and audio.is_sound_playing(f'genre_voice_{self.texture_index}'): + audio.stop_sound(f'genre_voice_{self.texture_index}') if self.tja_count is not None and self.tja_count > 0 and self.tja_count_text is None: self.tja_count_text = OutlinedText(str(self.tja_count), 35, ray.WHITE, ray.BLACK, outline_thickness=5)#, horizontal_spacing=1.2) if self.box_texture is None and self.box_texture_path is not None: @@ -771,11 +775,11 @@ class SongBox: if valid_scores: highest_key = max(valid_scores.keys()) score = self.scores[highest_key] - if score and score[2] == 0 and score[3] == 0: + if score and ((score[4] == 2 and score[2] == 0) or (score[2] == 0 and score[3] == 0)): tex.draw_texture('yellow_box', 'crown_dfc', x=x, y=y, frame=min(4, highest_key)) - elif score and score[3] == 0: + elif score and ((score[4] == 2) or (score[3] == 0)): tex.draw_texture('yellow_box', 'crown_fc', x=x, y=y, frame=min(4, highest_key)) - elif score and score[4] == 1: + elif score and score[4] >= 1: tex.draw_texture('yellow_box', 'crown_clear', x=x, y=y, frame=min(4, highest_key)) if self.crown: #Folder lamp highest_crown = max(self.crown) @@ -934,11 +938,11 @@ class YellowBox: for diff in self.tja.metadata.course_data: if diff >= 4: continue - elif diff in song_box.scores and song_box.scores[diff] is not None and song_box.scores[diff][2] == 0 and song_box.scores[diff][3] == 0: + elif diff in song_box.scores and song_box.scores[diff] is not None and ((song_box.scores[diff][4] == 2 and song_box.scores[diff][2] == 0) or (song_box.scores[diff][2] == 0 and song_box.scores[diff][3] == 0)): tex.draw_texture('yellow_box', 's_crown_dfc', x=(diff*60), color=color) - elif diff in song_box.scores and song_box.scores[diff] is not None and song_box.scores[diff][3] == 0: + elif diff in song_box.scores and song_box.scores[diff] is not None and ((song_box.scores[diff][4] == 2) or (song_box.scores[diff][3] == 0)): tex.draw_texture('yellow_box', 's_crown_fc', x=(diff*60), color=color) - elif diff in song_box.scores and song_box.scores[diff] is not None and song_box.scores[diff][4] == 1: + elif diff in song_box.scores and song_box.scores[diff] is not None and song_box.scores[diff][4] >= 1: tex.draw_texture('yellow_box', 's_crown_clear', x=(diff*60), color=color) tex.draw_texture('yellow_box', 's_crown_outline', x=(diff*60), fade=min(fade, 0.25)) @@ -974,11 +978,11 @@ class YellowBox: for diff in self.tja.metadata.course_data: if diff >= 4: continue - elif diff in song_box.scores and song_box.scores[diff] is not None and song_box.scores[diff][2] == 0 and song_box.scores[diff][3] == 0: + elif diff in song_box.scores and song_box.scores[diff] is not None and ((song_box.scores[diff][4] == 2 and song_box.scores[diff][2] == 0) or (song_box.scores[diff][2] == 0 and song_box.scores[diff][3] == 0)): tex.draw_texture('yellow_box', 's_crown_dfc', x=(diff*115)+8, y=-120, fade=self.fade_in.attribute) - elif diff in song_box.scores and song_box.scores[diff] is not None and song_box.scores[diff][3] == 0: + elif diff in song_box.scores and song_box.scores[diff] is not None and ((song_box.scores[diff][4] == 2) or (song_box.scores[diff][3] == 0)): tex.draw_texture('yellow_box', 's_crown_fc', x=(diff*115)+8, y=-120, fade=self.fade_in.attribute) - elif diff in song_box.scores and song_box.scores[diff] is not None and song_box.scores[diff][4] == 1: + elif diff in song_box.scores and song_box.scores[diff] is not None and song_box.scores[diff][4] >= 1: tex.draw_texture('yellow_box', 's_crown_clear', x=(diff*115)+8, y=-120, fade=self.fade_in.attribute) tex.draw_texture('yellow_box', 's_crown_outline', x=(diff*115)+8, y=-120, fade=min(self.fade_in.attribute, 0.25)) @@ -1152,6 +1156,7 @@ class DiffSortSelect: ] for course, levels in self.diff_sort_statistics.items() } + audio.play_sound('voice_diff_sort_enter') def update(self, current_ms): self.bg_resize.update(current_ms) @@ -1194,6 +1199,7 @@ class DiffSortSelect: self.bounce_up_2.start() self.bounce_down_2.start() self.confirm_index = 1 + audio.play_sound('voice_diff_sort_confirm') return None if self.selected_box == -1: return (-1, -1) @@ -1201,6 +1207,7 @@ class DiffSortSelect: return (0, -1) elif self.selected_box == 4: return self.get_random_sort() + audio.play_sound('voice_diff_sort_level') self.in_level_select = True self.bg_resize.start() self.diff_fade_in.start() @@ -1356,6 +1363,7 @@ class NeiroSelector: self.sounds = neiro_list.readlines() self.sounds.append('無音') self.load_sound() + audio.play_sound(f'voice_hitsound_select_{global_data.player_num}p') self.is_finished = False self.is_confirmed = False self.move = tex.get_animation(28) @@ -1372,9 +1380,9 @@ class NeiroSelector: if self.selected_sound == len(self.sounds): return if self.selected_sound == 0: - self.curr_sound = audio.load_sound(Path("Sounds") / "hit_sounds" / str(self.selected_sound) / "don.wav") + self.curr_sound = audio.load_sound(Path("Sounds") / "hit_sounds" / str(self.selected_sound) / "don.wav", 'hit_sound') else: - self.curr_sound = audio.load_sound(Path("Sounds") / "hit_sounds" / str(self.selected_sound) / "don.ogg") + self.curr_sound = audio.load_sound(Path("Sounds") / "hit_sounds" / str(self.selected_sound) / "don.ogg", 'hit_sound') def move_left(self): if self.move.is_started and not self.move.is_finished: @@ -1484,6 +1492,7 @@ class ModifierSelector: self.move_sideways = tex.get_animation(31) self.fade_sideways = tex.get_animation(32) self.direction = -1 + audio.play_sound(f'voice_options_{global_data.player_num}p') self.text_name = [OutlinedText(ModifierSelector.NAME_MAP[mod.name], 30, ray.WHITE, ray.BLACK, outline_thickness=3.5) for mod in self.mods] self.text_true = OutlinedText('する', 30, ray.WHITE, ray.BLACK, outline_thickness=3.5) self.text_false = OutlinedText('しない', 30, ray.WHITE, ray.BLACK, outline_thickness=3.5) @@ -1921,8 +1930,8 @@ class FileNavigator: scores = song_obj.box.scores.get(course) if scores is not None: - is_cleared = scores[4] == 1 - is_full_combo = scores[3] == 0 + is_cleared = scores[4] >= 1 + is_full_combo = (scores[4] == 2) or (scores[3] == 0) else: is_cleared = False is_full_combo = False @@ -2181,11 +2190,11 @@ class FileNavigator: all_scores[diff].append(song_obj.box.scores[diff]) for diff in all_scores: - if all(score is not None and score[2] == 0 and score[3] == 0 for score in all_scores[diff]): + if all(score is not None and ((score[4] == 2 and score[2] == 0) or (score[2] == 0 and score[3] == 0)) for score in all_scores[diff]): crowns[diff] = 'DFC' - elif all(score is not None and score[3] == 0 for score in all_scores[diff]): + elif all(score is not None and ((score[4] == 2) or (score[3] == 0)) for score in all_scores[diff]): crowns[diff] = 'FC' - elif all(score is not None and score[4] == 1 for score in all_scores[diff]): + elif all(score is not None and score[4] >= 1 for score in all_scores[diff]): crowns[diff] = 'CLEAR' self.directory_crowns[dir_key] = crowns diff --git a/scenes/title.py b/scenes/title.py index 9a4fdf9..1919b74 100644 --- a/scenes/title.py +++ b/scenes/title.py @@ -30,20 +30,11 @@ class TitleScreen: self.allnet_indicator = AllNetIcon() self.entry_overlay = EntryOverlay() - def load_sounds(self): - sounds_dir = Path("Sounds") - title_dir = sounds_dir / "title" - self.sound_don = audio.load_sound(sounds_dir / "hit_sounds" / "0" / "don.wav") - self.sound_bachi_swipe = audio.load_sound(title_dir / "SE_ATTRACT_2.ogg") - self.sound_bachi_hit = audio.load_sound(title_dir / "SE_ATTRACT_3.ogg") - self.sound_warning_message = audio.load_sound(title_dir / "VO_ATTRACT_3.ogg") - self.sound_warning_error = audio.load_sound(title_dir / "SE_ATTRACT_1.ogg") - def on_screen_start(self): if not self.screen_init: self.screen_init = True tex.load_screen_textures('title') - self.load_sounds() + audio.load_screen_sounds('title') self.state = State.OP_VIDEO self.op_video = None self.attract_video = None @@ -57,15 +48,16 @@ class TitleScreen: if self.attract_video is not None: self.attract_video.stop() audio.unload_all_sounds() + audio.unload_all_music() tex.unload_textures() self.screen_init = False return "ENTRY" - def scene_manager(self): + def scene_manager(self, current_time): if self.state == State.OP_VIDEO: if self.op_video is None: self.op_video = VideoPlayer(random.choice(self.op_video_list)) - self.op_video.start(get_current_ms()) + self.op_video.start(current_time) self.op_video.update() if self.op_video.is_finished(): self.op_video.stop() @@ -73,15 +65,15 @@ class TitleScreen: self.state = State.WARNING elif self.state == State.WARNING: if self.warning_board is None: - self.warning_board = WarningScreen(get_current_ms()) - self.warning_board.update(get_current_ms(), self) + self.warning_board = WarningScreen(current_time) + self.warning_board.update(current_time) if self.warning_board.is_finished: self.state = State.ATTRACT_VIDEO self.warning_board = None elif self.state == State.ATTRACT_VIDEO: if self.attract_video is None: self.attract_video = VideoPlayer(random.choice(self.attract_video_list)) - self.attract_video.start(get_current_ms()) + self.attract_video.start(current_time) self.attract_video.update() if self.attract_video.is_finished(): self.attract_video.stop() @@ -91,17 +83,18 @@ class TitleScreen: def update(self): self.on_screen_start() + current_time = get_current_ms() - self.text_overlay_fade.update(get_current_ms()) - self.fade_out.update(get_current_ms()) + self.text_overlay_fade.update(current_time) + self.fade_out.update(current_time) if self.fade_out.is_finished: - self.fade_out.update(get_current_ms()) + self.fade_out.update(current_time) return self.on_screen_end() - self.scene_manager() + self.scene_manager(current_time) if is_l_don_pressed() or is_r_don_pressed(): self.fade_out.start() - audio.play_sound(self.sound_don) + audio.play_sound('don') def draw(self): if self.state == State.OP_VIDEO and self.op_video is not None: @@ -134,13 +127,13 @@ class WarningScreen: self.fadein_2.start() self.sound_played = False - def update(self, current_ms: float, sound): + def update(self, current_ms: float): self.resize.update(current_ms) self.fadein.update(current_ms) self.fadein_2.update(current_ms) if self.resize.attribute > 1 and not self.sound_played: - audio.play_sound(sound) + audio.play_sound('error') self.sound_played = True def draw_bg(self): @@ -156,9 +149,9 @@ class WarningScreen: self.sound_played = False - def update(self, current_ms: float, sound): + def update(self, current_ms: float): if not self.sound_played: - audio.play_sound(sound) + audio.play_sound('bachi_hit') self.sound_played = True self.fadein.start() self.resize.start() @@ -241,22 +234,22 @@ class WarningScreen: self.is_finished = False - def update(self, current_ms: float, title_screen: TitleScreen): + def update(self, current_ms: float): self.board.update(current_ms) self.fade_in.update(current_ms) self.fade_out.update(current_ms) delay = 566.67 elapsed_time = current_ms - self.start_ms - self.warning_x.update(current_ms, title_screen.sound_warning_error) + self.warning_x.update(current_ms) self.characters.update(current_ms) if self.characters.is_finished: - self.warning_bachi_hit.update(current_ms, title_screen.sound_bachi_hit) + self.warning_bachi_hit.update(current_ms) else: self.fade_out.delay = elapsed_time + 500 - if delay <= elapsed_time and not audio.is_sound_playing(title_screen.sound_bachi_swipe): - audio.play_sound(title_screen.sound_warning_message) - audio.play_sound(title_screen.sound_bachi_swipe) + if delay <= elapsed_time and not audio.is_sound_playing('bachi_swipe'): + audio.play_sound('warning_voiceover') + audio.play_sound('bachi_swipe') self.is_finished = self.fade_out.is_finished