from enum import Enum import pyray as ray from libs.utils import OutlinedText, get_config, global_tex from libs.audio import audio class Nameplate: """Nameplate for displaying player information.""" def __init__(self, name: str, title: str, player_num: int, dan: int, is_gold: bool, is_rainbow: bool, title_bg: int): """Initialize a Nameplate object. Args: name (str): The player's name. title (str): The player's title. player_num (int): The player's number. dan (int): The player's dan level. is_gold (bool): Whether the player's dan is gold. is_rainbow (bool): Whether the player's nameplate background is rainbow. title_bg (int): The player's non-rainbow nameplate background. """ self.name = OutlinedText(name, 22, ray.WHITE, outline_thickness=3.0) self.title = OutlinedText(title, 20, ray.BLACK, outline_thickness=0) self.dan_index = dan self.player_num = player_num self.is_gold = is_gold self.is_rainbow = is_rainbow self.title_bg = title_bg if self.is_rainbow: self.rainbow_animation = global_tex.get_animation(12) self.rainbow_animation.start() def update(self, current_time_ms: float): """Update the Nameplate object. Args: current_time_ms (float): The current time in milliseconds. """ if self.is_rainbow: self.rainbow_animation.update(current_time_ms) if self.rainbow_animation.is_finished: self.rainbow_animation.restart() def unload(self): """Unload the Nameplate object.""" self.name.unload() self.title.unload() def draw(self, x: int, y: int, fade: float = 1.0): """Draw the Nameplate object. Args: x (int): The x-coordinate of the Nameplate object. y (int): The y-coordinate of the Nameplate object. fade (float): The fade value of the Nameplate object. """ tex = global_tex tex.draw_texture('nameplate', 'shadow', x=x, y=y, fade=min(0.5, fade)) if self.player_num == -1: frame = 2 title_offset = 0 else: frame = self.title_bg title_offset = 14 if self.is_rainbow: if 0 < self.rainbow_animation.attribute < 6: tex.draw_texture('nameplate', 'frame_top_rainbow', frame=self.rainbow_animation.attribute-1, x=x, y=y, fade=fade) tex.draw_texture('nameplate', 'frame_top_rainbow', frame=self.rainbow_animation.attribute, x=x, y=y, fade=fade) else: tex.draw_texture('nameplate', 'frame_top', frame=frame, x=x, y=y, fade=fade) tex.draw_texture('nameplate', 'outline', x=x, y=y, fade=fade) offset = 0 if self.dan_index != -1: tex.draw_texture('nameplate', 'dan_emblem_bg', x=x, y=y, fade=fade) if self.is_gold: tex.draw_texture('nameplate', 'dan_emblem_gold', x=x, y=y, frame=self.dan_index, fade=fade) else: tex.draw_texture('nameplate', 'dan_emblem', x=x, y=y, frame=self.dan_index, fade=fade) offset = 34 if self.player_num != -1: tex.draw_texture('nameplate', f'{self.player_num}p', x=x, y=y, fade=fade) self.name.draw(outline_color=ray.BLACK, x=x+136 - (min(255 - offset*4, self.name.texture.width)//2) + offset, y=y+24, x2=min(255 - offset*4, self.name.texture.width)-self.name.texture.width, color=ray.fade(ray.WHITE, fade)) self.title.draw(x=x+136 - (min(255 - offset*2, self.title.texture.width)//2) + title_offset, y=y-3, x2=min(255 - offset*2, self.title.texture.width)-self.title.texture.width, color=ray.fade(ray.WHITE, fade)) class Indicator: """Indicator class for displaying drum navigation.""" class State(Enum): """Enum representing the different states of the indicator.""" SKIP = 0 SIDE = 1 SELECT = 2 WAIT = 3 def __init__(self, state: State): """Initialize the indicator with the given state.""" self.state = state 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): """Update the indicator's animations.""" self.don_fade.update(current_time_ms) self.blue_arrow_move.update(current_time_ms) self.blue_arrow_fade.update(current_time_ms) def draw(self, x: int, y: int, fade=1.0): """Draw the indicator at the given position with the given fade.""" 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) if self.state == Indicator.State.SELECT: tex.draw_texture('indicator', 'drum_kat', fade=min(fade, self.don_fade.attribute), x=x, y=y) tex.draw_texture('indicator', 'drum_kat', fade=min(fade, self.don_fade.attribute), x=x+23, y=y, mirror='horizontal') tex.draw_texture('indicator', 'drum_face', x=x+175, y=y, fade=fade) tex.draw_texture('indicator', 'drum_don', fade=min(fade, self.don_fade.attribute), index=self.state.value, x=x+214, y=y) tex.draw_texture('indicator', 'blue_arrow', x=x-self.blue_arrow_move.attribute, y=y, fade=min(fade, self.blue_arrow_fade.attribute)) tex.draw_texture('indicator', 'blue_arrow', index=1, x=x+self.blue_arrow_move.attribute, y=y, mirror='horizontal', fade=min(fade, self.blue_arrow_fade.attribute)) else: tex.draw_texture('indicator', 'drum_don', fade=min(fade, self.don_fade.attribute), index=self.state.value, x=x, y=y) class CoinOverlay: """Coin overlay for the game.""" def __init__(self): """Initialize the coin overlay.""" pass def update(self, current_time_ms: float): """Update the coin overlay. Unimplemented""" pass def draw(self, x: int = 0, y: int = 0): """Draw the coin overlay. Only draws free play for now.""" tex = global_tex tex.draw_texture('overlay', 'free_play', x=x, y=y) class AllNetIcon: """All.Net status icon for the game.""" def __init__(self): """Initialize the All.Net status icon.""" self.online = get_config()["general"]["fake_online"] def update(self, current_time_ms: float): """Update the All.Net status icon.""" pass def draw(self, x: int = 0, y: int = 0): """Draw the All.Net status icon. Only drawn offline for now""" tex = global_tex tex.draw_texture('overlay', 'allnet_indicator', x=x, y=y, frame=2 if self.online else 0) class EntryOverlay: """Banapass and Camera status icons""" def __init__(self): """Initialize the Banapass and Camera status icons.""" self.online = get_config()["general"]["fake_online"] def update(self, current_time_ms: float): """Update the Banapass and Camera status icons.""" pass def draw(self, x: int = 0, y: int = 0): """Draw the Banapass and Camera status icons.""" tex = global_tex tex.draw_texture('overlay', 'banapass_or', x=x, y=y, frame=self.online) tex.draw_texture('overlay', 'banapass_card', x=x, y=y, frame=self.online) tex.draw_texture('overlay', 'banapass_osaifu_keitai', x=x, y=y, frame=self.online) if not self.online: tex.draw_texture('overlay', 'banapass_no', x=x, y=y, frame=self.online) tex.draw_texture('overlay', 'camera', x=x, y=y, frame=self.online) class Timer: """Timer class for displaying countdown timers.""" def __init__(self, time: int, current_time_ms: float, confirm_func): """ Initialize a Timer object. Args: time (int): The value to start counting down from. current_time_ms (float): The current time in milliseconds. confirm_func (function): The function to call when the timer finishes. """ self.time = time self.last_time = current_time_ms self.counter = str(self.time) self.num_resize = global_tex.get_animation(9) self.highlight_resize = global_tex.get_animation(10) self.highlight_fade = global_tex.get_animation(11) self.confirm_func = confirm_func self.is_finished = False self.is_frozen = get_config()["general"]["timer_frozen"] def update(self, current_time_ms: float): """Update the timer's state.""" 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) self.highlight_resize.update(current_time_ms) self.highlight_fade.update(current_time_ms) if self.is_frozen: return if current_time_ms >= self.last_time + 1000 and self.time > 0: self.time -= 1 self.last_time = current_time_ms self.counter = str(self.time) if self.time < 10: audio.play_sound('timer_blip', 'sound') self.num_resize.start() self.highlight_fade.start() self.highlight_resize.start() if self.time == 10: audio.play_sound('voice_timer_10', 'voice') elif self.time == 5: audio.play_sound('voice_timer_5', 'voice') elif self.time == 0: audio.play_sound('voice_timer_0', 'voice') def draw(self, x: int = 0, y: int = 0): """Draw the timer on the screen.""" tex = global_tex if self.time < 10: tex.draw_texture('timer', 'bg_red') counter_name = 'counter_white' tex.draw_texture('timer', 'highlight', fade=self.highlight_fade.attribute, scale=self.highlight_resize.attribute, center=True) else: tex.draw_texture('timer', 'bg') counter_name = 'counter_black' margin = 40 total_width = len(self.counter) * margin for i, digit in enumerate(self.counter): tex.draw_texture('timer', counter_name, frame=int(digit), x=-(total_width//2)+(i*margin), scale=self.num_resize.attribute, center=True)