diff --git a/PyTaiko.py b/PyTaiko.py index dbae0b0..57a98d6 100644 --- a/PyTaiko.py +++ b/PyTaiko.py @@ -145,7 +145,7 @@ def main(): current_screen = Screens.LOADING logger.info(f"Initial screen: {current_screen}") - audio.set_log_level(1) + audio.set_log_level((log_level-1)//10) old_stderr = os.dup(2) devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, 2) diff --git a/libs/video.py b/libs/video.py index 7184b47..a6b862a 100644 --- a/libs/video.py +++ b/libs/video.py @@ -14,6 +14,7 @@ class VideoPlayer: """Initialize a video player instance""" self.is_finished_list = [False, False] self.video = VideoFileClip(path) + self.audio = None if self.video.audio is not None: self.video.audio.write_audiofile("cache/temp_audio.wav", logger=None) self.audio = audio.load_music_stream(Path("cache/temp_audio.wav"), 'video') @@ -80,7 +81,8 @@ class VideoPlayer: def set_volume(self, volume: float) -> None: """Set video volume, takes float value from 0.0 to 1.0""" - audio.set_music_volume(self.audio, volume) + if self.audio is not None: + audio.set_music_volume(self.audio, volume) def update(self): """Updates video playback, advancing frames and audio""" diff --git a/scenes/game.py b/scenes/game.py index d4f63b9..d1e8960 100644 --- a/scenes/game.py +++ b/scenes/game.py @@ -36,6 +36,7 @@ from libs.utils import ( is_l_kat_pressed, is_r_don_pressed, is_r_kat_pressed, + rounded, ) from libs.video import VideoPlayer @@ -797,6 +798,10 @@ class Player: if self.kusudama_anim.is_finished: self.kusudama_anim = None + def spawn_hit_effects(self, note_type: str, side: str): + self.lane_hit_effect = LaneHitEffect(note_type, self.is_2p) + self.draw_drum_hit_list.append(DrumHitEffect(note_type, side, self.is_2p)) + def handle_input(self, ms_from_start: float, current_time: float, background: Optional[Background]): input_checks = [ (is_l_don_pressed, 'DON', 'L', f'hitsound_don_{self.player_number}p'), @@ -806,9 +811,7 @@ class Player: ] for check_func, note_type, side, sound in input_checks: if check_func(self.player_number): - self.lane_hit_effect = LaneHitEffect(note_type, self.is_2p) - self.draw_drum_hit_list.append(DrumHitEffect(note_type, side, self.is_2p)) - + self.spawn_hit_effects(note_type, side) audio.play_sound(sound, 'hitsound') drum_value = 1 if note_type == 'DON' else 2 @@ -832,9 +835,8 @@ class Player: if subdivision_in_ms > self.last_subdivision: self.last_subdivision = subdivision_in_ms hit_type = 'DON' - self.lane_hit_effect = LaneHitEffect(hit_type, self.is_2p) self.autoplay_hit_side = 'R' if self.autoplay_hit_side == 'L' else 'L' - self.draw_drum_hit_list.append(DrumHitEffect(hit_type, self.autoplay_hit_side, self.is_2p)) + self.spawn_hit_effects(hit_type, self.autoplay_hit_side) audio.play_sound(f'hitsound_don_{self.player_number}p', 'hitsound') note_type = 3 if note.type == 6 else 1 self.check_note(ms_from_start, note_type, current_time, background) @@ -843,9 +845,8 @@ class Player: while self.don_notes and ms_from_start >= self.don_notes[0].hit_ms: note = self.don_notes[0] hit_type = 'DON' - self.lane_hit_effect = LaneHitEffect(hit_type, self.is_2p) self.autoplay_hit_side = 'R' if self.autoplay_hit_side == 'L' else 'L' - self.draw_drum_hit_list.append(DrumHitEffect(hit_type, self.autoplay_hit_side, self.is_2p)) + self.spawn_hit_effects(hit_type, self.autoplay_hit_side) audio.play_sound(f'hitsound_don_{self.player_number}p', 'hitsound') self.check_note(ms_from_start, 1, current_time, background) @@ -853,9 +854,8 @@ class Player: while self.kat_notes and ms_from_start >= self.kat_notes[0].hit_ms: note = self.kat_notes[0] hit_type = 'KAT' - self.lane_hit_effect = LaneHitEffect(hit_type, self.is_2p) self.autoplay_hit_side = 'R' if self.autoplay_hit_side == 'L' else 'L' - self.draw_drum_hit_list.append(DrumHitEffect(hit_type, self.autoplay_hit_side, self.is_2p)) + self.spawn_hit_effects(hit_type, self.autoplay_hit_side) audio.play_sound(f'hitsound_kat_{self.player_number}p', 'hitsound') self.check_note(ms_from_start, 2, current_time, background) @@ -2148,7 +2148,7 @@ class JudgeCounter: self.bad = bad self.drumrolls = drumrolls def draw_counter(self, counter: float, x: int, y: int, margin: int, color: ray.Color): - counter_str = str(int(counter)) + counter_str = str(rounded(counter)) counter_len = len(counter_str) for i, digit in enumerate(counter_str): tex.draw_texture('judge_counter', 'counter', frame=int(digit), x=x - (counter_len - i) * margin, y=y, color=color) diff --git a/scenes/practice/game.py b/scenes/practice/game.py index c99a4ac..748dffc 100644 --- a/scenes/practice/game.py +++ b/scenes/practice/game.py @@ -12,7 +12,7 @@ from libs.global_data import Modifiers, global_data from libs.tja import Balloon, Drumroll, Note, TJAParser, apply_modifiers from libs.utils import get_current_ms, get_key_code from libs.texture import tex -from scenes.game import GameScreen, JudgeCounter, Player, SCREEN_WIDTH +from scenes.game import DrumHitEffect, GameScreen, JudgeCounter, LaneHitEffect, Player, SCREEN_WIDTH logger = logging.getLogger(__name__) @@ -249,7 +249,11 @@ class PracticeGameScreen(GameScreen): self.player_1.draw(self.current_ms, self.start_ms, self.mask_shader) if self.paused: self.draw_scrobble_list() + tex.draw_texture('practice', 'large_drum', index=0) + tex.draw_texture('practice', 'large_drum', index=1) self.player_1.draw_overlays(self.mask_shader) + if not self.paused: + tex.draw_texture('practice', 'playing', index=int(self.player_1.player_number)-1, fade=0.5) tex.draw_texture('practice', 'progress_bar_bg') if self.paused: progress = min((self.scrobble_time + self.scrobble_move.attribute - self.bars[0].hit_ms) / self.player_1.end_time, 1) @@ -268,6 +272,53 @@ class PracticePlayer(Player): self.gauge = None self.paused = False + def spawn_hit_effects(self, note_type: str, side: str): + self.lane_hit_effect = LaneHitEffect(note_type, self.is_2p) + self.draw_drum_hit_list.append(PracticeDrumHitEffect(note_type, side, self.is_2p, player_number=int(self.player_number)-1)) + + def draw_overlays(self, mask_shader: ray.Shader): + # Group 4: Lane covers and UI elements (batch similar textures) + tex.draw_texture('lane', f'{self.player_number}p_lane_cover', index=self.is_2p) + tex.draw_texture('lane', 'drum', index=self.is_2p) + if self.ending_anim is not None: + self.ending_anim.draw() + + # Group 5: Hit effects and animations + for anim in self.draw_drum_hit_list: + anim.draw() + for anim in self.draw_arc_list: + anim.draw(mask_shader) + for anim in self.gauge_hit_effect: + anim.draw() + + # Group 6: UI overlays + self.combo_display.draw() + self.combo_announce.draw() + tex.draw_texture('lane', f'{self.player_number}p_icon', index=self.is_2p) + tex.draw_texture('lane', 'lane_difficulty', frame=self.difficulty, index=self.is_2p) + if self.judge_counter is not None: + self.judge_counter.draw() + + # Group 7: Player-specific elements + if not self.modifiers.auto: + if self.is_2p: + self.nameplate.draw(-62, 371) + else: + self.nameplate.draw(-62, 285) + else: + tex.draw_texture('lane', 'auto_icon', index=self.is_2p) + self.draw_modifiers() + self.chara.draw(y=(self.is_2p*536)) + + # Group 8: Special animations and counters + if self.drumroll_counter is not None: + self.drumroll_counter.draw() + if self.balloon_anim is not None: + self.balloon_anim.draw() + if self.kusudama_anim is not None: + self.kusudama_anim.draw() + #ray.draw_circle(game_screen.width//2, game_screen.height, 300, ray.ORANGE) + def draw(self, ms_from_start: float, start_ms: float, mask_shader: ray.Shader, dan_transition = None): # Group 1: Background and lane elements tex.draw_texture('lane', 'lane_background', index=self.is_2p) @@ -289,3 +340,23 @@ class PracticePlayer(Player): if not self.paused: self.draw_bars(ms_from_start) self.draw_notes(ms_from_start, start_ms) + +class PracticeDrumHitEffect(DrumHitEffect): + def __init__(self, type, side, is_2p, player_number: int = 0): + super().__init__(type, side, is_2p) + self.player_number = player_number + + def draw(self): + if self.type == 'DON': + if self.side == 'L': + tex.draw_texture('lane', 'drum_don_l', index=self.is_2p, fade=self.fade.attribute) + elif self.side == 'R': + tex.draw_texture('lane', 'drum_don_r', index=self.is_2p, fade=self.fade.attribute) + tex.draw_texture('practice', 'large_drum_don', index=self.player_number, fade=self.fade.attribute) + elif self.type == 'KAT': + if self.side == 'L': + tex.draw_texture('lane', 'drum_kat_l', index=self.is_2p, fade=self.fade.attribute) + tex.draw_texture('practice', 'large_drum_kat_l', index=self.player_number, fade=self.fade.attribute) + elif self.side == 'R': + tex.draw_texture('lane', 'drum_kat_r', index=self.is_2p, fade=self.fade.attribute) + tex.draw_texture('practice', 'large_drum_kat_r', index=self.player_number, fade=self.fade.attribute)