diff --git a/PyTaiko.py b/PyTaiko.py index 44bb53b..a695ec2 100644 --- a/PyTaiko.py +++ b/PyTaiko.py @@ -14,6 +14,7 @@ from libs.utils import ( force_dedicated_gpu, get_config, global_data, + global_tex ) from scenes.devtest import DevScreen from scenes.entry import EntryScreen @@ -68,7 +69,7 @@ def main(): if global_data.config["video"]["target_fps"] != -1: ray.set_target_fps(global_data.config["video"]["target_fps"]) ray.set_config_flags(ray.ConfigFlags.FLAG_MSAA_4X_HINT) - ray.set_trace_log_level(ray.TraceLogLevel.LOG_INFO) + ray.set_trace_log_level(ray.TraceLogLevel.LOG_WARNING) camera = ray.Camera3D() camera.position = ray.Vector3(0.0, 0.0, 10.0) # Camera position @@ -78,9 +79,9 @@ def main(): camera.projection = CAMERA_ORTHOGRAPHIC ray.init_window(screen_width, screen_height, "PyTaiko") - global_data.tex.load_screen_textures('global') - global_data.tex.load_zip('chara', 'chara_0') - global_data.tex.load_zip('chara', 'chara_1') + global_tex.load_screen_textures('global') + global_tex.load_zip('chara', 'chara_0') + global_tex.load_zip('chara', 'chara_1') if global_data.config["video"]["borderless"]: ray.toggle_borderless_windowed() if global_data.config["video"]["fullscreen"]: diff --git a/libs/animation.py b/libs/animation.py index 61fd90c..c3917f3 100644 --- a/libs/animation.py +++ b/libs/animation.py @@ -1,6 +1,8 @@ import time from typing import Any, Optional +from libs.global_data import global_data + def rounded(num: float) -> int: sign = 1 if (num >= 0) else -1 @@ -15,7 +17,7 @@ def get_current_ms() -> int: class BaseAnimation(): - def __init__(self, duration: float, delay: float = 0.0, loop: bool = False) -> None: + def __init__(self, duration: float, delay: float = 0.0, loop: bool = False, lock_input: bool = False) -> None: """ Initialize a base animation. @@ -32,6 +34,7 @@ class BaseAnimation(): self.attribute = 0 self.is_started = False self.loop = loop + self.lock_input = lock_input def __repr__(self): return str(self.__dict__) @@ -43,11 +46,15 @@ class BaseAnimation(): """Update the animation based on the current time.""" if self.loop and self.is_finished: self.restart() + if self.lock_input and self.is_finished: + global_data.input_locked = False def restart(self) -> None: self.start_ms = get_current_ms() self.is_finished = False self.delay = self.delay_saved + if self.lock_input: + global_data.input_locked = True def start(self) -> None: self.is_started = True @@ -55,9 +62,13 @@ class BaseAnimation(): def pause(self): self.is_started = False + if self.lock_input: + global_data.input_locked = False def unpause(self): self.is_started = True + if self.lock_input: + global_data.input_locked = True def reset(self): self.restart() @@ -91,10 +102,10 @@ class BaseAnimation(): class FadeAnimation(BaseAnimation): def __init__(self, duration: float, initial_opacity: float = 1.0, loop: bool = False, - final_opacity: float = 0.0, delay: float = 0.0, + lock_input: bool = False, final_opacity: float = 0.0, delay: float = 0.0, ease_in: Optional[str] = None, ease_out: Optional[str] = None, reverse_delay: Optional[float] = None) -> None: - super().__init__(duration, delay=delay, loop=loop) + super().__init__(duration, delay=delay, loop=loop, lock_input=lock_input) self.initial_opacity = initial_opacity self.attribute = initial_opacity self.final_opacity = final_opacity @@ -139,10 +150,10 @@ class FadeAnimation(BaseAnimation): class MoveAnimation(BaseAnimation): def __init__(self, duration: float, total_distance: int = 0, loop: bool = False, - start_position: int = 0, delay: float = 0.0, + lock_input: bool = False, start_position: int = 0, delay: float = 0.0, reverse_delay: Optional[float] = None, ease_in: Optional[str] = None, ease_out: Optional[str] = None) -> None: - super().__init__(duration, delay=delay, loop=loop) + super().__init__(duration, delay=delay, loop=loop, lock_input=lock_input) self.reverse_delay = reverse_delay self.reverse_delay_saved = reverse_delay self.total_distance = total_distance @@ -184,8 +195,8 @@ class MoveAnimation(BaseAnimation): class TextureChangeAnimation(BaseAnimation): def __init__(self, duration: float, textures: list[tuple[float, float, int]], - loop: bool = False, delay: float = 0.0) -> None: - super().__init__(duration, loop=loop) + loop: bool = False, lock_input: bool = False, delay: float = 0.0) -> None: + super().__init__(duration, loop=loop, lock_input=lock_input) self.textures = textures self.delay = delay self.delay_saved = delay @@ -212,8 +223,8 @@ class TextureChangeAnimation(BaseAnimation): self.is_finished = True class TextStretchAnimation(BaseAnimation): - def __init__(self, duration: float, loop: bool = False,) -> None: - super().__init__(duration, loop=loop) + def __init__(self, duration: float, loop: bool = False, lock_input: bool = False) -> None: + super().__init__(duration, loop=loop, lock_input=lock_input) def update(self, current_time_ms: float) -> None: if not self.is_started: return @@ -230,11 +241,11 @@ class TextStretchAnimation(BaseAnimation): class TextureResizeAnimation(BaseAnimation): def __init__(self, duration: float, initial_size: float = 1.0, - loop: bool = False, + loop: bool = False, lock_input: bool = False, final_size: float = 0.0, delay: float = 0.0, reverse_delay: Optional[float] = None, ease_in: Optional[str] = None, ease_out: Optional[str] = None) -> None: - super().__init__(duration, delay=delay, loop=loop) + super().__init__(duration, delay=delay, loop=loop, lock_input=lock_input) self.initial_size = initial_size self.final_size = final_size self.reverse_delay = reverse_delay diff --git a/libs/chara_2d.py b/libs/chara_2d.py index 5be94a8..0a11b61 100644 --- a/libs/chara_2d.py +++ b/libs/chara_2d.py @@ -1,10 +1,10 @@ from libs.animation import Animation -from libs.utils import global_data +from libs.utils import global_tex class Chara2D: def __init__(self, index: int, bpm: float, path: str = 'chara'): self.name = "chara_" + str(index) - self.tex = global_data.tex + self.tex = global_tex self.anims = dict() self.bpm = bpm self.current_anim = 'normal' diff --git a/libs/global_data.py b/libs/global_data.py new file mode 100644 index 0000000..61900fc --- /dev/null +++ b/libs/global_data.py @@ -0,0 +1,26 @@ +from dataclasses import dataclass, field +from pathlib import Path + +@dataclass +class Modifiers: + auto: bool = False + speed: float = 1.0 + display: bool = False + inverse: bool = False + random: int = 0 + +@dataclass +class GlobalData: + selected_song: Path = Path() + songs_played: int = 0 + config: dict = field(default_factory=lambda: dict()) + song_hashes: dict[str, list[dict]] = field(default_factory=lambda: dict()) #Hash to path + song_paths: dict[Path, str] = field(default_factory=lambda: dict()) #path to hash + song_progress: float = 0.0 + total_songs: int = 0 + hit_sound: int = 0 + player_num: int = 1 + input_locked: bool = False + modifiers: Modifiers = field(default_factory=lambda: Modifiers()) + +global_data = GlobalData() diff --git a/libs/global_objects.py b/libs/global_objects.py index 6d8da28..bd69231 100644 --- a/libs/global_objects.py +++ b/libs/global_objects.py @@ -1,7 +1,7 @@ from enum import Enum import pyray as ray -from libs.utils import OutlinedText, global_data +from libs.utils import OutlinedText, global_tex class Nameplate: @@ -18,7 +18,7 @@ class Nameplate: self.name.unload() self.title.unload() def draw(self, x: int, y: int, fade: float = 1.0): - tex = global_data.tex + tex = global_tex tex.draw_texture('nameplate', 'shadow', x=x, y=y, fade=min(0.5, fade)) if self.player_num == -1: frame = 2 @@ -52,9 +52,9 @@ class Indicator: WAIT = 3 def __init__(self, state: State): self.state = state - self.don_fade = global_data.tex.get_animation(6) - self.blue_arrow_move = global_data.tex.get_animation(7) - self.blue_arrow_fade = global_data.tex.get_animation(8) + self.don_fade = global_tex.get_animation(6) + self.blue_arrow_move = global_tex.get_animation(7) + self.blue_arrow_fade = global_tex.get_animation(8) def update(self, current_time_ms: float): self.don_fade.update(current_time_ms) @@ -62,7 +62,7 @@ class Indicator: self.blue_arrow_fade.update(current_time_ms) def draw(self, x: int, y: int, fade=1.0): - tex = global_data.tex + tex = global_tex tex.draw_texture('indicator', 'background', x=x, y=y, fade=fade) tex.draw_texture('indicator', 'text', frame=self.state.value, x=x, y=y, fade=fade) tex.draw_texture('indicator', 'drum_face', index=self.state.value, x=x, y=y, fade=fade) diff --git a/libs/transition.py b/libs/transition.py index 89af806..3c6ae8f 100644 --- a/libs/transition.py +++ b/libs/transition.py @@ -1,16 +1,16 @@ import pyray as ray -from libs.utils import OutlinedText, global_data +from libs.utils import OutlinedText, global_tex class Transition: def __init__(self, title: str, subtitle: str, is_second: bool = False) -> None: self.is_finished = False - self.rainbow_up = global_data.tex.get_animation(0) - self.mini_up = global_data.tex.get_animation(1) - self.chara_down = global_data.tex.get_animation(2) - self.song_info_fade = global_data.tex.get_animation(3) - self.song_info_fade_out = global_data.tex.get_animation(4) + self.rainbow_up = global_tex.get_animation(0) + self.mini_up = global_tex.get_animation(1) + self.chara_down = global_tex.get_animation(2) + self.song_info_fade = global_tex.get_animation(3) + self.song_info_fade_out = global_tex.get_animation(4) self.title = OutlinedText(title, 40, ray.WHITE, ray.BLACK, outline_thickness=5) self.subtitle = OutlinedText(subtitle, 30, ray.WHITE, ray.BLACK, outline_thickness=5) self.is_second = is_second @@ -38,7 +38,7 @@ class Transition: color_1 = ray.fade(ray.WHITE, self.song_info_fade_out.attribute) color_2 = ray.fade(ray.WHITE, min(0.70, self.song_info_fade_out.attribute)) offset = 816 - self.rainbow_up.attribute - global_data.tex.draw_texture('rainbow_transition', 'text_bg', y=-self.rainbow_up.attribute - offset, color=color_2) + global_tex.draw_texture('rainbow_transition', 'text_bg', y=-self.rainbow_up.attribute - offset, color=color_2) texture = self.title.texture y = 1176 - texture.height//2 - int(self.rainbow_up.attribute) - offset @@ -53,16 +53,16 @@ class Transition: total_offset = 0 if self.is_second: total_offset = 816 - global_data.tex.draw_texture('rainbow_transition', 'rainbow_bg_bottom', y=-self.rainbow_up.attribute - total_offset) - global_data.tex.draw_texture('rainbow_transition', 'rainbow_bg_top', y=-self.rainbow_up.attribute - total_offset) - global_data.tex.draw_texture('rainbow_transition', 'rainbow_bg', y=-self.rainbow_up.attribute - total_offset) + global_tex.draw_texture('rainbow_transition', 'rainbow_bg_bottom', y=-self.rainbow_up.attribute - total_offset) + global_tex.draw_texture('rainbow_transition', 'rainbow_bg_top', y=-self.rainbow_up.attribute - total_offset) + global_tex.draw_texture('rainbow_transition', 'rainbow_bg', y=-self.rainbow_up.attribute - total_offset) offset = self.chara_down.attribute chara_offset = 0 if self.is_second: offset = self.chara_down.attribute - self.mini_up.attribute//3 chara_offset = 408 - global_data.tex.draw_texture('rainbow_transition', 'chara_left', x=-self.mini_up.attribute//2 - chara_offset, y=-self.mini_up.attribute + offset - total_offset) - global_data.tex.draw_texture('rainbow_transition', 'chara_right', x=self.mini_up.attribute//2 + chara_offset, y=-self.mini_up.attribute + offset - total_offset) - global_data.tex.draw_texture('rainbow_transition', 'chara_center', y=-self.rainbow_up.attribute + offset - total_offset) + global_tex.draw_texture('rainbow_transition', 'chara_left', x=-self.mini_up.attribute//2 - chara_offset, y=-self.mini_up.attribute + offset - total_offset) + global_tex.draw_texture('rainbow_transition', 'chara_right', x=self.mini_up.attribute//2 + chara_offset, y=-self.mini_up.attribute + offset - total_offset) + global_tex.draw_texture('rainbow_transition', 'chara_center', y=-self.rainbow_up.attribute + offset - total_offset) self.draw_song_info() diff --git a/libs/utils.py b/libs/utils.py index 3aaecae..bd3e38b 100644 --- a/libs/utils.py +++ b/libs/utils.py @@ -1,12 +1,10 @@ import ctypes import hashlib import math -import os import sys -import tempfile import time -import zipfile -from dataclasses import dataclass, field +from dataclasses import dataclass +from libs.global_data import global_data from functools import lru_cache from pathlib import Path from typing import Any, Optional @@ -89,6 +87,8 @@ def save_config(config: dict[str, Any]) -> None: tomlkit.dump(config, f) def is_l_don_pressed() -> bool: + if global_data.input_locked: + return False keys = global_data.config["keys"]["left_don"] gamepad_buttons = global_data.config["gamepad"]["left_don"] for key in keys: @@ -111,6 +111,8 @@ def is_l_don_pressed() -> bool: return False def is_r_don_pressed() -> bool: + if global_data.input_locked: + return False keys = global_data.config["keys"]["right_don"] gamepad_buttons = global_data.config["gamepad"]["right_don"] for key in keys: @@ -135,6 +137,8 @@ def is_r_don_pressed() -> bool: return False def is_l_kat_pressed() -> bool: + if global_data.input_locked: + return False keys = global_data.config["keys"]["left_kat"] gamepad_buttons = global_data.config["gamepad"]["left_kat"] for key in keys: @@ -159,6 +163,8 @@ def is_l_kat_pressed() -> bool: return False def is_r_kat_pressed() -> bool: + if global_data.input_locked: + return False keys = global_data.config["keys"]["right_kat"] gamepad_buttons = global_data.config["gamepad"]["right_kat"] for key in keys: @@ -182,14 +188,6 @@ def is_r_kat_pressed() -> bool: return False -@dataclass -class Modifiers: - auto: bool = False - speed: float = 1.0 - display: bool = False - inverse: bool = False - random: int = 0 - @dataclass class SessionData: selected_difficulty: int = 0 @@ -205,26 +203,11 @@ class SessionData: prev_score: int = 0 session_data = SessionData() +global_tex = TextureWrapper() def reset_session(): return SessionData() -@dataclass -class GlobalData: - selected_song: Path = Path() - tex: TextureWrapper = field(default_factory=lambda: TextureWrapper()) - songs_played: int = 0 - config: dict = field(default_factory=lambda: dict()) - song_hashes: dict[str, list[dict]] = field(default_factory=lambda: dict()) #Hash to path - song_paths: dict[Path, str] = field(default_factory=lambda: dict()) #path to hash - song_progress: float = 0.0 - total_songs: int = 0 - hit_sound: int = 0 - player_num: int = 1 - modifiers: Modifiers = field(default_factory=lambda: Modifiers()) - -global_data = GlobalData() - text_cache = set() if not Path('cache/image').exists(): if not Path('cache').exists(): diff --git a/scenes/game.py b/scenes/game.py index a50cedb..4870aa7 100644 --- a/scenes/game.py +++ b/scenes/game.py @@ -26,6 +26,7 @@ from libs.utils import ( OutlinedText, get_current_ms, global_data, + global_tex, is_l_don_pressed, is_l_kat_pressed, is_r_don_pressed, @@ -1412,7 +1413,7 @@ class SongInfo: class ResultTransition: def __init__(self, player_num: int): self.player_num = player_num - self.move = global_data.tex.get_animation(5) + self.move = global_tex.get_animation(5) self.move.reset() self.is_finished = False self.is_started = False @@ -1429,10 +1430,10 @@ class ResultTransition: x = 0 screen_width = 1280 while x < screen_width: - global_data.tex.draw_texture('result_transition', f'{str(self.player_num)}p_shutter', frame=0, x=x, y=-720 + self.move.attribute) - global_data.tex.draw_texture('result_transition', f'{str(self.player_num)}p_shutter', frame=0, x=x, y=720 - self.move.attribute) - global_data.tex.draw_texture('result_transition', f'{str(self.player_num)}p_shutter_footer', x=x, y=-432 + self.move.attribute) - global_data.tex.draw_texture('result_transition', f'{str(self.player_num)}p_shutter_footer', x=x, y=1008 - self.move.attribute) + global_tex.draw_texture('result_transition', f'{str(self.player_num)}p_shutter', frame=0, x=x, y=-720 + self.move.attribute) + global_tex.draw_texture('result_transition', f'{str(self.player_num)}p_shutter', frame=0, x=x, y=720 - self.move.attribute) + global_tex.draw_texture('result_transition', f'{str(self.player_num)}p_shutter_footer', x=x, y=-432 + self.move.attribute) + global_tex.draw_texture('result_transition', f'{str(self.player_num)}p_shutter_footer', x=x, y=1008 - self.move.attribute) x += 256 class Gauge: diff --git a/scenes/song_select.py b/scenes/song_select.py index c043cf2..daf1a51 100644 --- a/scenes/song_select.py +++ b/scenes/song_select.py @@ -10,12 +10,12 @@ import pyray as ray from libs.animation import Animation, MoveAnimation from libs.audio import audio from libs.chara_2d import Chara2D +from libs.global_data import Modifiers from libs.global_objects import Nameplate, Indicator from libs.texture import tex from libs.tja import TJAParser, test_encodings from libs.transition import Transition from libs.utils import ( - Modifiers, OutlinedText, get_current_ms, global_data, @@ -288,7 +288,7 @@ class SongSelectScreen: if len(diffs) == 1: self.selected_difficulty = -1 else: - self.selected_difficulty = diffs[-2] + self.selected_difficulty = diffs[-3] elif self.selected_difficulty == -1 or self.selected_difficulty == -2: self.diff_selector_move_2.start() self.prev_diff = self.selected_difficulty @@ -1208,6 +1208,8 @@ class NeiroSelector: self.curr_sound = audio.load_sound(Path("Sounds") / "hit_sounds" / str(self.selected_sound) / "don.ogg") def move_left(self): + if self.move.is_started and not self.move.is_finished: + return self.selected_sound = (self.selected_sound - 1) % len(self.sounds) audio.unload_sound(self.curr_sound) self.load_sound() @@ -1221,6 +1223,8 @@ class NeiroSelector: audio.play_sound(self.curr_sound) def move_right(self): + if self.move.is_started and not self.move.is_finished: + return self.selected_sound = (self.selected_sound + 1) % len(self.sounds) audio.unload_sound(self.curr_sound) self.load_sound() @@ -1234,6 +1238,8 @@ class NeiroSelector: audio.play_sound(self.curr_sound) def confirm(self): + if self.move.is_started and not self.move.is_finished: + return if self.selected_sound == len(self.sounds): global_data.hit_sound = -1 else: diff --git a/scenes/title.py b/scenes/title.py index 2b523fc..997ae5d 100644 --- a/scenes/title.py +++ b/scenes/title.py @@ -88,6 +88,7 @@ class TitleScreen: self.fade_out.update(get_current_ms()) if self.fade_out.is_finished: + self.fade_out.update(get_current_ms()) return self.on_screen_end() self.scene_manager()