This commit is contained in:
Anthony Samms
2025-10-29 21:55:45 -04:00
parent 8c2447c912
commit 9cc02741bc
8 changed files with 441 additions and 86 deletions

170
scenes/dan_select.py Normal file
View File

@@ -0,0 +1,170 @@
import pyray as ray
from libs.audio import audio
from libs.global_data import global_data
from libs.texture import tex
from libs.chara_2d import Chara2D
from libs.global_objects import AllNetIcon, CoinOverlay, Indicator, Nameplate, Timer
from libs.screen import Screen
from libs.file_navigator import navigator
from libs.utils import get_current_ms, is_l_don_pressed, is_l_kat_pressed, is_r_don_pressed, is_r_kat_pressed
from scenes.song_select import SongSelectScreen, State
class DanSelectScreen(Screen):
def on_screen_start(self):
super().on_screen_start()
self.navigator = navigator
self.navigator.in_dan_select = True
self.navigator.select_current_item()
self.coin_overlay = CoinOverlay()
self.allnet_indicator = AllNetIcon()
self.timer = Timer(60, get_current_ms(), self.navigator.select_current_item)
self.indicator = Indicator(Indicator.State.SELECT)
self.player = DanSelectPlayer(str(global_data.player_num))
self.state = State.BROWSING
self.last_moved = 0
def on_screen_end(self, next_screen: str):
return super().on_screen_end(next_screen)
def handle_input_browsing(self):
"""Handle input for browsing songs."""
action = self.player.handle_input_browsing(self.last_moved, self.navigator.items[self.navigator.selected_index] if self.navigator.items else None)
current_time = get_current_ms()
if action == "skip_left":
for _ in range(10):
self.navigator.navigate_left()
self.last_moved = current_time
elif action == "skip_right":
for _ in range(10):
self.navigator.navigate_right()
self.last_moved = current_time
elif action == "navigate_left":
self.navigator.navigate_left()
self.last_moved = current_time
elif action == "navigate_right":
self.navigator.navigate_right()
self.last_moved = current_time
elif action == "go_back":
self.navigator.go_back()
elif action == "select_song":
pass
def handle_input(self, state, screen):
"""Main input dispatcher. Delegates to state-specific handlers."""
if state == State.BROWSING:
screen.handle_input_browsing()
elif state == State.SONG_SELECTED:
screen.handle_input_selected()
def update(self):
super().update()
current_time = get_current_ms()
self.indicator.update(current_time)
self.timer.update(current_time)
for song in self.navigator.items:
song.box.update(False)
song.box.is_open = song.box.position == SongSelectScreen.BOX_CENTER + 150
self.player.update(current_time)
self.handle_input(self.state, self)
def draw(self):
tex.draw_texture('global', 'bg')
tex.draw_texture('global', 'bg_header')
tex.draw_texture('global', 'bg_footer')
tex.draw_texture('global', 'footer')
for item in self.navigator.items:
box = item.box
if -156 <= box.position <= 1280 + 144:
if box.position <= 500:
box.draw(box.position, 95, False)
else:
box.draw(box.position, 95, False)
self.player.draw()
self.indicator.draw(410, 575)
self.timer.draw()
self.coin_overlay.draw()
tex.draw_texture('global', 'dan_select')
self.allnet_indicator.draw()
class DanSelectPlayer:
def __init__(self, player_num: str):
self.player_num = player_num
self.selected_difficulty = -3
self.prev_diff = -3
self.selected_song = False
self.is_ura = False
self.ura_toggle = 0
self.diff_select_move_right = False
self.neiro_selector = None
self.modifier_selector = None
# Player-specific objects
self.chara = Chara2D(int(self.player_num) - 1, 100)
plate_info = global_data.config[f'nameplate_{self.player_num}p']
self.nameplate = Nameplate(plate_info['name'], plate_info['title'],
int(self.player_num), plate_info['dan'], plate_info['gold'])
def update(self, current_time):
"""Update player state"""
self.nameplate.update(current_time)
self.chara.update(current_time, 100, False, False)
def handle_input_browsing(self, last_moved, selected_item):
"""Handle input for browsing songs. Returns action string or None."""
current_time = get_current_ms()
# Skip left (fast navigate)
if ray.is_key_pressed(ray.KeyboardKey.KEY_LEFT_CONTROL) or (is_l_kat_pressed(self.player_num) and current_time <= last_moved + 50):
audio.play_sound('skip', 'sound')
return "skip_left"
# Skip right (fast navigate)
if ray.is_key_pressed(ray.KeyboardKey.KEY_RIGHT_CONTROL) or (is_r_kat_pressed(self.player_num) and current_time <= last_moved + 50):
audio.play_sound('skip', 'sound')
return "skip_right"
# Navigate left
if is_l_kat_pressed(self.player_num):
audio.play_sound('kat', 'sound')
return "navigate_left"
# Navigate right
if is_r_kat_pressed(self.player_num):
audio.play_sound('kat', 'sound')
return "navigate_right"
# Select/Enter
if is_l_don_pressed(self.player_num) or is_r_don_pressed(self.player_num):
if selected_item is not None and selected_item.box.is_back:
audio.play_sound('cancel', 'sound')
return "go_back"
else:
return "select_song"
return None
def handle_input(self, state, screen):
"""Main input dispatcher. Delegates to state-specific handlers."""
if self.is_voice_playing():
return
if state == State.BROWSING:
screen.handle_input_browsing()
elif state == State.SONG_SELECTED:
screen.handle_input_selected()
def handle_input_selected(self, current_item):
"""Handle input for selecting difficulty. Returns 'cancel', 'confirm', or None"""
if is_l_don_pressed(self.player_num) or is_r_don_pressed(self.player_num):
return "confirm"
return None
def draw(self):
if self.player_num == '1':
self.nameplate.draw(30, 640)
self.chara.draw(x=-50, y=410)
else:
self.nameplate.draw(950, 640)
self.chara.draw(mirror=True, x=950, y=410)

View File

@@ -2159,7 +2159,6 @@ class Gauge:
self.is_rainbow = False
self.table = [
[
None,
{"clear_rate": 36.0, "ok_multiplier": 0.75, "bad_multiplier": -0.5},
{"clear_rate": 38.0, "ok_multiplier": 0.75, "bad_multiplier": -0.5},
{"clear_rate": 38.0, "ok_multiplier": 0.75, "bad_multiplier": -0.5},
@@ -2167,7 +2166,6 @@ class Gauge:
{"clear_rate": 44.0, "ok_multiplier": 0.75, "bad_multiplier": -0.5},
],
[
None,
{"clear_rate": 45.939, "ok_multiplier": 0.75, "bad_multiplier": -0.5},
{"clear_rate": 45.939, "ok_multiplier": 0.75, "bad_multiplier": -0.5},
{"clear_rate": 48.676, "ok_multiplier": 0.75, "bad_multiplier": -0.5},
@@ -2177,7 +2175,6 @@ class Gauge:
{"clear_rate": 52.5, "ok_multiplier": 0.75, "bad_multiplier": -1.0},
],
[
None,
{"clear_rate": 54.325, "ok_multiplier": 0.75, "bad_multiplier": -0.75},
{"clear_rate": 54.325, "ok_multiplier": 0.75, "bad_multiplier": -0.75},
{"clear_rate": 50.774, "ok_multiplier": 0.75, "bad_multiplier": -1.0},
@@ -2188,7 +2185,6 @@ class Gauge:
{"clear_rate": 48.120, "ok_multiplier": 0.75, "bad_multiplier": -1.25},
],
[
None,
{"clear_rate": 56.603, "ok_multiplier": 0.5, "bad_multiplier": -1.6},
{"clear_rate": 56.603, "ok_multiplier": 0.5, "bad_multiplier": -1.6},
{"clear_rate": 56.603, "ok_multiplier": 0.5, "bad_multiplier": -1.6},
@@ -2209,7 +2205,7 @@ class Gauge:
"""Adds a good note to the gauge"""
self.gauge_update_anim.start()
self.previous_length = int(self.gauge_length)
self.gauge_length += (1 / self.total_notes) * (100 * (self.clear_start[self.difficulty] / self.table[self.difficulty][self.level]["clear_rate"]))
self.gauge_length += (1 / self.total_notes) * (100 * (self.clear_start[self.difficulty] / self.table[self.difficulty][self.level-1]["clear_rate"]))
if self.gauge_length > self.gauge_max:
self.gauge_length = self.gauge_max
@@ -2217,14 +2213,14 @@ class Gauge:
"""Adds an ok note to the gauge"""
self.gauge_update_anim.start()
self.previous_length = int(self.gauge_length)
self.gauge_length += ((1 * self.table[self.difficulty][self.level]["ok_multiplier"]) / self.total_notes) * (100 * (self.clear_start[self.difficulty] / self.table[self.difficulty][self.level]["clear_rate"]))
self.gauge_length += ((1 * self.table[self.difficulty][self.level-1]["ok_multiplier"]) / self.total_notes) * (100 * (self.clear_start[self.difficulty] / self.table[self.difficulty][self.level-1]["clear_rate"]))
if self.gauge_length > self.gauge_max:
self.gauge_length = self.gauge_max
def add_bad(self):
"""Adds a bad note to the gauge"""
self.previous_length = int(self.gauge_length)
self.gauge_length += ((1 * self.table[self.difficulty][self.level]["bad_multiplier"]) / self.total_notes) * (100 * (self.clear_start[self.difficulty] / self.table[self.difficulty][self.level]["clear_rate"]))
self.gauge_length += ((1 * self.table[self.difficulty][self.level-1]["bad_multiplier"]) / self.total_notes) * (100 * (self.clear_start[self.difficulty] / self.table[self.difficulty][self.level-1]["clear_rate"]))
if self.gauge_length < 0:
self.gauge_length = 0

View File

@@ -121,8 +121,8 @@ class ResultPlayer:
self.score_animator = ScoreAnimator(session_data.result_score)
plate_info = global_data.config[f'nameplate_{self.player_num}p']
self.nameplate = Nameplate(plate_info['name'], plate_info['title'], int(self.player_num), plate_info['dan'], plate_info['gold'])
self.score, self.good, self.ok, self.bad, self.max_combo, self.total_drumroll= '', '', '', '', '', ''
self.update_list = [['score', session_data.result_score],
self.score, self.good, self.ok, self.bad, self.max_combo, self.total_drumroll = '', '', '', '', '', ''
self.update_list: list[tuple[str, int]] = [['score', session_data.result_score],
['good', session_data.result_good],
['ok', session_data.result_ok],
['bad', session_data.result_bad],

View File

@@ -64,6 +64,7 @@ class SongSelectScreen(Screen):
self.timer_selected = Timer(40, get_current_ms(), self._confirm_selection_wrapper)
self.screen_init = True
self.ura_switch_animation = UraSwitchAnimation()
self.dan_transition = DanTransition()
self.player_1 = SongSelectPlayer(str(global_data.player_num), self.text_fade_in)
@@ -88,7 +89,9 @@ class SongSelectScreen(Screen):
self.reset_demo_music()
self.finalize_song()
self.player_1.nameplate.unload()
self.navigator.get_current_item().box.yellow_box.create_anim()
current_item = self.navigator.get_current_item()
if current_item.box.yellow_box is not None:
current_item.box.yellow_box.create_anim()
return super().on_screen_end(next_screen)
def reset_demo_music(self):
@@ -130,8 +133,13 @@ class SongSelectScreen(Screen):
self.text_fade_in.start()
self.text_fade_out.start()
elif action == "select_song":
current_song = self.navigator.get_current_item()
if isinstance(current_song, Directory) and current_song.box.texture_index == 13:
self.dan_transition.start()
audio.stop_sound('bgm')
return
selected_song = self.navigator.select_current_item()
if selected_song:
if isinstance(selected_song, SongFile):
self.state = State.SONG_SELECTED
self.player_1.on_song_selected(selected_song)
audio.play_sound('don', 'sound')
@@ -240,6 +248,9 @@ class SongSelectScreen(Screen):
self.indicator.update(current_time)
self.blue_arrow_fade.update(current_time)
self.blue_arrow_move.update(current_time)
self.dan_transition.update(current_time)
if self.dan_transition.is_finished:
return self.on_screen_end('DAN_SELECT')
next_screen = self.update_players(current_time)
@@ -353,6 +364,8 @@ class SongSelectScreen(Screen):
if self.game_transition is not None:
self.game_transition.draw()
if self.dan_transition.is_started:
self.dan_transition.draw()
self.allnet_indicator.draw()
class SongSelectPlayer:
@@ -998,7 +1011,7 @@ class NeiroSelector:
self.move_sideways.start()
self.fade_sideways.start()
self.text_2.unload()
self.text_2 = OutlinedText(self.sounds[self.selected_sound], 50, ray.WHITE, ray.BLACK)
self.text_2 = OutlinedText(self.sounds[self.selected_sound], 50, ray.WHITE)
self.direction = -1
if self.selected_sound == len(self.sounds):
return
@@ -1013,7 +1026,7 @@ class NeiroSelector:
self.move_sideways.start()
self.fade_sideways.start()
self.text_2.unload()
self.text_2 = OutlinedText(self.sounds[self.selected_sound], 50, ray.WHITE, ray.BLACK)
self.text_2 = OutlinedText(self.sounds[self.selected_sound], 50, ray.WHITE)
self.direction = 1
if self.selected_sound == len(self.sounds):
return
@@ -1037,7 +1050,7 @@ class NeiroSelector:
self.fade_sideways.update(current_ms)
if self.move_sideways.is_finished:
self.text.unload()
self.text = OutlinedText(self.sounds[self.selected_sound], 50, ray.WHITE, ray.BLACK)
self.text = OutlinedText(self.sounds[self.selected_sound], 50, ray.WHITE)
self.is_finished = self.move.is_finished and self.is_confirmed
def draw(self):
@@ -1208,8 +1221,7 @@ class ModifierSelector:
else:
tex.draw_texture('modifier', 'mod_bg', y=move + (i*50), x=x)
tex.draw_texture('modifier', 'mod_box', y=move + (i*50), x=x)
dest = ray.Rectangle(92 + x, 819 + move + (i*50), self.text_name[i].texture.width, self.text_name[i].texture.height)
self.text_name[i].draw(self.text_name[i].default_src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
self.text_name[i].draw(outline_color=ray.BLACK, x=92 + x, y=819 + move + (i*50))
current_mod = self.mods[i]
current_value = getattr(global_data.modifiers[int(self.player_num)-1], current_mod.name)
@@ -1255,3 +1267,21 @@ class ModifierSelector:
if i == self.current_mod_index:
tex.draw_texture('modifier', 'blue_arrow', y=move + (i*50), x=x-self.blue_arrow_move.attribute, fade=self.blue_arrow_fade.attribute)
tex.draw_texture('modifier', 'blue_arrow', y=move + (i*50), x=x+110 + self.blue_arrow_move.attribute, mirror='horizontal', fade=self.blue_arrow_fade.attribute)
class DanTransition:
def __init__(self):
self.slide_in = tex.get_animation(38)
self.is_finished = False
self.is_started = False
def start(self):
self.slide_in.start()
self.is_started = True
def update(self, current_time_ms: float):
self.slide_in.update(current_time_ms)
if self.slide_in.is_finished:
self.is_finished = True
def draw(self):
tex.draw_texture('dan_transition', 'background', x2=self.slide_in.attribute)