mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 11:40:13 +01:00
fix bugs
This commit is contained in:
@@ -29,6 +29,7 @@ from scenes.settings import SettingsScreen
|
|||||||
from scenes.song_select import SongSelectScreen
|
from scenes.song_select import SongSelectScreen
|
||||||
from scenes.title import TitleScreen
|
from scenes.title import TitleScreen
|
||||||
from scenes.two_player.song_select import TwoPlayerSongSelectScreen
|
from scenes.two_player.song_select import TwoPlayerSongSelectScreen
|
||||||
|
from scenes.dan_select import DanSelectScreen
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -42,6 +43,7 @@ class Screens:
|
|||||||
RESULT = "RESULT"
|
RESULT = "RESULT"
|
||||||
RESULT_2P = "RESULT_2P"
|
RESULT_2P = "RESULT_2P"
|
||||||
SONG_SELECT_2P = "SONG_SELECT_2P"
|
SONG_SELECT_2P = "SONG_SELECT_2P"
|
||||||
|
DAN_SELECT = "DAN_SELECT"
|
||||||
SETTINGS = "SETTINGS"
|
SETTINGS = "SETTINGS"
|
||||||
DEV_MENU = "DEV_MENU"
|
DEV_MENU = "DEV_MENU"
|
||||||
LOADING = "LOADING"
|
LOADING = "LOADING"
|
||||||
@@ -156,6 +158,7 @@ def main():
|
|||||||
result_screen_2p = TwoPlayerResultScreen('result')
|
result_screen_2p = TwoPlayerResultScreen('result')
|
||||||
settings_screen = SettingsScreen('settings')
|
settings_screen = SettingsScreen('settings')
|
||||||
dev_screen = DevScreen('dev')
|
dev_screen = DevScreen('dev')
|
||||||
|
dan_select_screen = DanSelectScreen('dan_select')
|
||||||
|
|
||||||
screen_mapping = {
|
screen_mapping = {
|
||||||
Screens.ENTRY: entry_screen,
|
Screens.ENTRY: entry_screen,
|
||||||
@@ -168,6 +171,7 @@ def main():
|
|||||||
Screens.RESULT_2P: result_screen_2p,
|
Screens.RESULT_2P: result_screen_2p,
|
||||||
Screens.SETTINGS: settings_screen,
|
Screens.SETTINGS: settings_screen,
|
||||||
Screens.DEV_MENU: dev_screen,
|
Screens.DEV_MENU: dev_screen,
|
||||||
|
Screens.DAN_SELECT: dan_select_screen,
|
||||||
Screens.LOADING: load_screen
|
Screens.LOADING: load_screen
|
||||||
}
|
}
|
||||||
target = ray.load_render_texture(screen_width, screen_height)
|
target = ray.load_render_texture(screen_width, screen_height)
|
||||||
@@ -195,7 +199,7 @@ def main():
|
|||||||
next_screen = screen.update()
|
next_screen = screen.update()
|
||||||
if screen.screen_init:
|
if screen.screen_init:
|
||||||
ray.clear_background(ray.BLACK)
|
ray.clear_background(ray.BLACK)
|
||||||
screen.draw()
|
screen._do_draw()
|
||||||
|
|
||||||
if next_screen is not None:
|
if next_screen is not None:
|
||||||
logger.info(f"Screen changed from {current_screen} to {next_screen}")
|
logger.info(f"Screen changed from {current_screen} to {next_screen}")
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import random
|
import random
|
||||||
@@ -134,7 +136,8 @@ class SongBox:
|
|||||||
if not (-56 <= self.position <= 1280):
|
if not (-56 <= self.position <= 1280):
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
def update(self, is_diff_select):
|
def update(self, is_diff_select: bool):
|
||||||
|
current_time = get_current_ms()
|
||||||
self.is_diff_select = is_diff_select
|
self.is_diff_select = is_diff_select
|
||||||
is_open_prev = self.is_open
|
is_open_prev = self.is_open
|
||||||
self.move_box()
|
self.move_box()
|
||||||
@@ -146,10 +149,10 @@ class SongBox:
|
|||||||
self.yellow_box.update(is_diff_select)
|
self.yellow_box.update(is_diff_select)
|
||||||
|
|
||||||
if self.history_wait == 0:
|
if self.history_wait == 0:
|
||||||
self.history_wait = get_current_ms()
|
self.history_wait = current_time
|
||||||
|
|
||||||
if self.score_history is None and {k: v for k, v in self.scores.items() if v is not None}:
|
if self.score_history is None and {k: v for k, v in self.scores.items() if v is not None}:
|
||||||
self.score_history = ScoreHistory(self.scores, get_current_ms())
|
self.score_history = ScoreHistory(self.scores, current_time)
|
||||||
|
|
||||||
if not is_open_prev and self.is_open:
|
if not is_open_prev and self.is_open:
|
||||||
if self.tja is not None or self.is_back:
|
if self.tja is not None or self.is_back:
|
||||||
@@ -159,9 +162,9 @@ class SongBox:
|
|||||||
self.hori_name = OutlinedText(self.text_name, 40, ray.WHITE, outline_thickness=5)
|
self.hori_name = OutlinedText(self.text_name, 40, ray.WHITE, outline_thickness=5)
|
||||||
self.open_anim.start()
|
self.open_anim.start()
|
||||||
self.open_fade.start()
|
self.open_fade.start()
|
||||||
self.wait = get_current_ms()
|
self.wait = current_time
|
||||||
if get_current_ms() >= self.history_wait + 3000:
|
if current_time >= self.history_wait + 3000:
|
||||||
self.history_wait = get_current_ms()
|
self.history_wait = current_time
|
||||||
if self.tja is None and self.texture_index != 17 and not audio.is_sound_playing('voice_enter'):
|
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}', 'voice')
|
audio.play_sound(f'genre_voice_{self.texture_index}', 'voice')
|
||||||
elif not self.is_open and is_open_prev and audio.is_sound_playing(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}'):
|
||||||
@@ -171,14 +174,14 @@ class SongBox:
|
|||||||
if self.box_texture is None and self.box_texture_path is not None:
|
if self.box_texture is None and self.box_texture_path is not None:
|
||||||
self.box_texture = ray.load_texture(self.box_texture_path)
|
self.box_texture = ray.load_texture(self.box_texture_path)
|
||||||
|
|
||||||
self.open_anim.update(get_current_ms())
|
self.open_anim.update(current_time)
|
||||||
self.open_fade.update(get_current_ms())
|
self.open_fade.update(current_time)
|
||||||
|
|
||||||
if self.name is None:
|
if self.name is None:
|
||||||
self.name = OutlinedText(self.text_name, 40, ray.WHITE, outline_thickness=5, vertical=True)
|
self.name = OutlinedText(self.text_name, 40, ray.WHITE, outline_thickness=5, vertical=True)
|
||||||
|
|
||||||
if self.score_history is not None:
|
if self.score_history is not None:
|
||||||
self.score_history.update(get_current_ms())
|
self.score_history.update(current_time)
|
||||||
|
|
||||||
|
|
||||||
def _draw_closed(self, x: int, y: int):
|
def _draw_closed(self, x: int, y: int):
|
||||||
@@ -195,6 +198,7 @@ class SongBox:
|
|||||||
|
|
||||||
if self.is_back:
|
if self.is_back:
|
||||||
tex.draw_texture('box', 'back_text', x=x, y=y)
|
tex.draw_texture('box', 'back_text', x=x, y=y)
|
||||||
|
return
|
||||||
elif self.name is not None:
|
elif self.name is not None:
|
||||||
self.name.draw(outline_color=SongBox.OUTLINE_MAP.get(self.name_texture_index, ray.Color(101, 0, 82, 255)), x=x + 47 - int(self.name.texture.width / 2), y=y+35, y2=min(self.name.texture.height, 417)-self.name.texture.height)
|
self.name.draw(outline_color=SongBox.OUTLINE_MAP.get(self.name_texture_index, ray.Color(101, 0, 82, 255)), x=x + 47 - int(self.name.texture.width / 2), y=y+35, y2=min(self.name.texture.height, 417)-self.name.texture.height)
|
||||||
|
|
||||||
@@ -271,11 +275,12 @@ class SongBox:
|
|||||||
|
|
||||||
class YellowBox:
|
class YellowBox:
|
||||||
"""A song box when it is opened."""
|
"""A song box when it is opened."""
|
||||||
def __init__(self, name: OutlinedText, is_back: bool, tja: Optional[TJAParser] = None):
|
def __init__(self, name: Optional[OutlinedText], is_back: bool, tja: Optional[TJAParser] = None, is_dan: bool = False):
|
||||||
self.is_diff_select = False
|
self.is_diff_select = False
|
||||||
self.name = name
|
self.name = name
|
||||||
self.is_back = is_back
|
self.is_back = is_back
|
||||||
self.tja = tja
|
self.tja = tja
|
||||||
|
self.is_dan = is_dan
|
||||||
self.subtitle = None
|
self.subtitle = None
|
||||||
if self.tja is not None:
|
if self.tja is not None:
|
||||||
subtitle_text = self.tja.metadata.subtitle.get(global_data.config['general']['language'], '')
|
subtitle_text = self.tja.metadata.subtitle.get(global_data.config['general']['language'], '')
|
||||||
@@ -469,6 +474,8 @@ class YellowBox:
|
|||||||
|
|
||||||
def draw(self, song_box: SongBox, fade_override: Optional[float], is_ura: bool):
|
def draw(self, song_box: SongBox, fade_override: Optional[float], is_ura: bool):
|
||||||
self._draw_yellow_box()
|
self._draw_yellow_box()
|
||||||
|
if self.is_dan:
|
||||||
|
return
|
||||||
if self.is_diff_select and self.tja is not None:
|
if self.is_diff_select and self.tja is not None:
|
||||||
self._draw_tja_data_diff(is_ura, song_box)
|
self._draw_tja_data_diff(is_ura, song_box)
|
||||||
else:
|
else:
|
||||||
@@ -481,6 +488,103 @@ class YellowBox:
|
|||||||
|
|
||||||
self._draw_text(song_box)
|
self._draw_text(song_box)
|
||||||
|
|
||||||
|
class DanBox:
|
||||||
|
def __init__(self, title: str, color: int, songs: list[tuple[TJAParser, int, int]], exams: list['Exam']):
|
||||||
|
self.position = -11111
|
||||||
|
self.start_position = -1
|
||||||
|
self.target_position = -1
|
||||||
|
self.move = None
|
||||||
|
self.is_open = False
|
||||||
|
self.is_back = False
|
||||||
|
self.title = title
|
||||||
|
self.color = color
|
||||||
|
self.songs = songs
|
||||||
|
self.exams = exams
|
||||||
|
self.song_text: list[tuple[OutlinedText, OutlinedText]] = []
|
||||||
|
self.name = None
|
||||||
|
self.yellow_box = None
|
||||||
|
|
||||||
|
def move_box(self):
|
||||||
|
if self.position != self.target_position and self.move is None:
|
||||||
|
if self.position < self.target_position:
|
||||||
|
direction = 1
|
||||||
|
else:
|
||||||
|
direction = -1
|
||||||
|
if abs(self.target_position - self.position) > 250:
|
||||||
|
direction *= -1
|
||||||
|
self.move = Animation.create_move(83.3*2, start_position=0, total_distance=300 * direction, ease_out='cubic')
|
||||||
|
self.move.start()
|
||||||
|
if self.is_open or self.target_position == BOX_CENTER + 150:
|
||||||
|
self.move.total_distance = 450 * direction
|
||||||
|
self.start_position = self.position
|
||||||
|
if self.move is not None:
|
||||||
|
self.move.update(get_current_ms())
|
||||||
|
self.position = self.start_position + int(self.move.attribute)
|
||||||
|
if self.move.is_finished:
|
||||||
|
self.position = self.target_position
|
||||||
|
self.move = None
|
||||||
|
if not (-56 <= self.position <= 1280):
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
if self.name is None:
|
||||||
|
self.name.unload()
|
||||||
|
self.name = None
|
||||||
|
|
||||||
|
def get_text(self):
|
||||||
|
if self.name is None:
|
||||||
|
self.name = OutlinedText(self.title, 40, ray.WHITE, outline_thickness=5, vertical=True)
|
||||||
|
if self.is_open and not self.song_text:
|
||||||
|
for song, genre, difficulty in self.songs:
|
||||||
|
title = song.metadata.title.get(global_data.config["general"]["language"], song.metadata.title["en"])
|
||||||
|
subtitle = song.metadata.subtitle.get(global_data.config["general"]["language"], "")
|
||||||
|
title_text = OutlinedText(title, 40, ray.WHITE, outline_thickness=5, vertical=True)
|
||||||
|
font_size = 30 if len(subtitle) < 30 else 20
|
||||||
|
subtitle_text = OutlinedText(subtitle, font_size, ray.WHITE, outline_thickness=5, vertical=True)
|
||||||
|
self.song_text.append((title_text, subtitle_text))
|
||||||
|
|
||||||
|
def update(self, is_diff_select: bool):
|
||||||
|
self.move_box()
|
||||||
|
self.get_text()
|
||||||
|
is_open_prev = self.is_open
|
||||||
|
self.is_open = self.position == BOX_CENTER + 150
|
||||||
|
if not is_open_prev and self.is_open:
|
||||||
|
self.yellow_box = YellowBox(self.name, self.is_back, is_dan=True)
|
||||||
|
self.yellow_box.create_anim()
|
||||||
|
|
||||||
|
if self.yellow_box is not None:
|
||||||
|
self.yellow_box.update(True)
|
||||||
|
|
||||||
|
def _draw_closed(self, x: int, y: int):
|
||||||
|
tex.draw_texture('box', 'folder', frame=self.color, x=x)
|
||||||
|
if self.name is not None:
|
||||||
|
self.name.draw(outline_color=ray.BLACK, x=x + 47 - int(self.name.texture.width / 2), y=y+35, y2=min(self.name.texture.height, 417)-self.name.texture.height)
|
||||||
|
|
||||||
|
def _draw_open(self, x: int, y: int, is_ura: bool):
|
||||||
|
if self.yellow_box is not None:
|
||||||
|
self.yellow_box.draw(x, y, False)
|
||||||
|
for i, song in enumerate(self.song_text):
|
||||||
|
title, subtitle = song
|
||||||
|
x = i * 140
|
||||||
|
tex.draw_texture('yellow_box', 'genre_banner', x=x, frame=self.songs[i][1])
|
||||||
|
tex.draw_texture('yellow_box', 'difficulty', x=x, frame=self.songs[i][2])
|
||||||
|
tex.draw_texture('yellow_box', 'difficulty_x', x=x)
|
||||||
|
tex.draw_texture('yellow_box', 'difficulty_star', x=x)
|
||||||
|
level = self.songs[i][0].metadata.course_data[self.songs[i][2]].level
|
||||||
|
counter = str(level)
|
||||||
|
total_width = len(counter) * 10
|
||||||
|
for i in range(len(counter)):
|
||||||
|
tex.draw_texture('yellow_box', 'difficulty_num', frame=int(counter[i]), x=x-(total_width // 2) + (i * 10))
|
||||||
|
|
||||||
|
title.draw(outline_color=ray.BLACK, x=665+x, y=127, y2=min(title.texture.height, 400)-title.texture.height)
|
||||||
|
subtitle.draw(outline_color=ray.BLACK, x=620+x, y=525-min(subtitle.texture.height, 400), y2=min(subtitle.texture.height, 400)-subtitle.texture.height)
|
||||||
|
|
||||||
|
def draw(self, x: int, y: int, is_ura: bool):
|
||||||
|
if self.is_open:
|
||||||
|
self._draw_open(x, y, is_ura)
|
||||||
|
else:
|
||||||
|
self._draw_closed(x, y)
|
||||||
|
|
||||||
class GenreBG:
|
class GenreBG:
|
||||||
"""The background for a genre box."""
|
"""The background for a genre box."""
|
||||||
def __init__(self, start_box: SongBox, end_box: SongBox, title: OutlinedText, diff_sort: Optional[int]):
|
def __init__(self, start_box: SongBox, end_box: SongBox, title: OutlinedText, diff_sort: Optional[int]):
|
||||||
@@ -651,6 +755,34 @@ class FileSystemItem:
|
|||||||
self.path = path
|
self.path = path
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
|
def parse_box_def(path: Path):
|
||||||
|
"""Parse box.def file for directory metadata"""
|
||||||
|
texture_index = SongBox.DEFAULT_INDEX
|
||||||
|
name = path.name
|
||||||
|
collection = None
|
||||||
|
encoding = test_encodings(path / "box.def")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(path / "box.def", 'r', encoding=encoding) as box_def:
|
||||||
|
for line in box_def:
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith("#GENRE:"):
|
||||||
|
genre = line.split(":", 1)[1].strip()
|
||||||
|
texture_index = FileSystemItem.GENRE_MAP.get(genre, SongBox.DEFAULT_INDEX)
|
||||||
|
if texture_index == SongBox.DEFAULT_INDEX:
|
||||||
|
texture_index = FileSystemItem.GENRE_MAP_2.get(genre, SongBox.DEFAULT_INDEX)
|
||||||
|
elif line.startswith("#TITLE:"):
|
||||||
|
name = line.split(":", 1)[1].strip()
|
||||||
|
elif line.startswith("#TITLEJA:"):
|
||||||
|
if global_data.config['general']['language'] == 'ja':
|
||||||
|
name = line.split(":", 1)[1].strip()
|
||||||
|
elif line.startswith("#COLLECTION"):
|
||||||
|
collection = line.split(":", 1)[1].strip()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error parsing box.def in {path}: {e}")
|
||||||
|
|
||||||
|
return name, texture_index, collection
|
||||||
|
|
||||||
class Directory(FileSystemItem):
|
class Directory(FileSystemItem):
|
||||||
"""Represents a directory in the navigation system"""
|
"""Represents a directory in the navigation system"""
|
||||||
COLLECTIONS = [
|
COLLECTIONS = [
|
||||||
@@ -690,6 +822,42 @@ class SongFile(FileSystemItem):
|
|||||||
self.box.hash = global_data.song_hashes[self.hash][0]["diff_hashes"]
|
self.box.hash = global_data.song_hashes[self.hash][0]["diff_hashes"]
|
||||||
self.box.get_scores()
|
self.box.get_scores()
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Exam:
|
||||||
|
type: str
|
||||||
|
red: int
|
||||||
|
gold: int
|
||||||
|
range: str
|
||||||
|
|
||||||
|
class DanCourse(FileSystemItem):
|
||||||
|
def __init__(self, path: Path, name: str):
|
||||||
|
super().__init__(path, name)
|
||||||
|
if name != "dan.json":
|
||||||
|
self.logging.error(f"Invalid dan course file: {path}")
|
||||||
|
with open(path, 'r') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
title = data["title"]
|
||||||
|
color = data["color"]
|
||||||
|
songs = []
|
||||||
|
for song in data["songs"]:
|
||||||
|
hash = song["hash"]
|
||||||
|
song_title = song["title"]
|
||||||
|
song_subtitle = song["subtitle"]
|
||||||
|
difficulty = song["difficulty"]
|
||||||
|
if hash in global_data.song_hashes:
|
||||||
|
path = Path(global_data.song_hashes[hash][0]["file_path"])
|
||||||
|
if (path.parent.parent / "box.def").exists():
|
||||||
|
_, genre_index, _ = parse_box_def(path.parent.parent)
|
||||||
|
songs.append((TJAParser(path), genre_index, difficulty))
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
#do something with song_title, song_subtitle
|
||||||
|
exams = []
|
||||||
|
for exam in data["exams"]:
|
||||||
|
exams.append(Exam(exam["type"], exam["red"], exam["gold"], exam["range"]))
|
||||||
|
|
||||||
|
self.box = DanBox(title, color, songs, exams)
|
||||||
|
|
||||||
class FileNavigator:
|
class FileNavigator:
|
||||||
"""Manages navigation through pre-generated Directory and SongFile objects"""
|
"""Manages navigation through pre-generated Directory and SongFile objects"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -717,6 +885,7 @@ class FileNavigator:
|
|||||||
self.box_open = False
|
self.box_open = False
|
||||||
self.genre_bg = None
|
self.genre_bg = None
|
||||||
self.song_count = 0
|
self.song_count = 0
|
||||||
|
self.in_dan_select = False
|
||||||
logger.info("FileNavigator initialized")
|
logger.info("FileNavigator initialized")
|
||||||
|
|
||||||
def initialize(self, root_dirs: list[Path]):
|
def initialize(self, root_dirs: list[Path]):
|
||||||
@@ -796,7 +965,7 @@ class FileNavigator:
|
|||||||
box_texture = None
|
box_texture = None
|
||||||
collection = None
|
collection = None
|
||||||
|
|
||||||
name, texture_index, collection = self._parse_box_def(dir_path)
|
name, texture_index, collection = parse_box_def(dir_path)
|
||||||
box_png_path = dir_path / "box.png"
|
box_png_path = dir_path / "box.png"
|
||||||
if box_png_path.exists():
|
if box_png_path.exists():
|
||||||
box_texture = str(box_png_path)
|
box_texture = str(box_png_path)
|
||||||
@@ -847,7 +1016,10 @@ class FileNavigator:
|
|||||||
# Create SongFile objects
|
# Create SongFile objects
|
||||||
for tja_path in sorted(tja_files):
|
for tja_path in sorted(tja_files):
|
||||||
song_key = str(tja_path)
|
song_key = str(tja_path)
|
||||||
if song_key not in self.all_song_files and tja_path in global_data.song_paths:
|
if song_key not in self.all_song_files and tja_path.name == "dan.json":
|
||||||
|
song_obj = DanCourse(tja_path, tja_path.name)
|
||||||
|
self.all_song_files[song_key] = song_obj
|
||||||
|
elif song_key not in self.all_song_files and tja_path in global_data.song_paths:
|
||||||
song_obj = SongFile(tja_path, tja_path.name, texture_index)
|
song_obj = SongFile(tja_path, tja_path.name, texture_index)
|
||||||
song_obj.box.get_scores()
|
song_obj.box.get_scores()
|
||||||
for course in song_obj.tja.metadata.course_data:
|
for course in song_obj.tja.metadata.course_data:
|
||||||
@@ -872,10 +1044,10 @@ class FileNavigator:
|
|||||||
self.diff_sort_statistics[course][level][1] += 1
|
self.diff_sort_statistics[course][level][1] += 1
|
||||||
elif is_cleared:
|
elif is_cleared:
|
||||||
self.diff_sort_statistics[course][level][2] += 1
|
self.diff_sort_statistics[course][level][2] += 1
|
||||||
self.song_count += 1
|
|
||||||
global_data.song_progress = self.song_count / global_data.total_songs
|
|
||||||
if song_obj.is_recent:
|
if song_obj.is_recent:
|
||||||
self.new_items.append(SongFile(tja_path, tja_path.name, SongBox.DEFAULT_INDEX, name_texture_index=texture_index))
|
self.new_items.append(SongFile(tja_path, tja_path.name, SongBox.DEFAULT_INDEX, name_texture_index=texture_index))
|
||||||
|
self.song_count += 1
|
||||||
|
global_data.song_progress = self.song_count / global_data.total_songs
|
||||||
self.all_song_files[song_key] = song_obj
|
self.all_song_files[song_key] = song_obj
|
||||||
|
|
||||||
if song_key in self.all_song_files:
|
if song_key in self.all_song_files:
|
||||||
@@ -914,7 +1086,7 @@ class FileNavigator:
|
|||||||
|
|
||||||
# Determine if current directory has child directories with box.def
|
# Determine if current directory has child directories with box.def
|
||||||
has_children = False
|
has_children = False
|
||||||
if self.is_at_root():
|
if self.is_at_root() or selected_item and selected_item.box.texture_index == 13:
|
||||||
has_children = True # Root always has "children" (the root directories)
|
has_children = True # Root always has "children" (the root directories)
|
||||||
else:
|
else:
|
||||||
has_children = any(item.is_dir() and (item / "box.def").exists()
|
has_children = any(item.is_dir() and (item / "box.def").exists()
|
||||||
@@ -987,7 +1159,7 @@ class FileNavigator:
|
|||||||
temp_items.append(item)
|
temp_items.append(item)
|
||||||
content_items = random.sample(temp_items, 10)
|
content_items = random.sample(temp_items, 10)
|
||||||
|
|
||||||
if content_items == [] or (selected_item is not None and selected_item.box.texture_index == 13):
|
if content_items == []:
|
||||||
self.go_back()
|
self.go_back()
|
||||||
return
|
return
|
||||||
i = 1
|
i = 1
|
||||||
@@ -1060,7 +1232,6 @@ class FileNavigator:
|
|||||||
|
|
||||||
self.load_current_directory(selected_item=selected_item)
|
self.load_current_directory(selected_item=selected_item)
|
||||||
|
|
||||||
elif isinstance(selected_item, SongFile):
|
|
||||||
return selected_item
|
return selected_item
|
||||||
|
|
||||||
def go_back(self):
|
def go_back(self):
|
||||||
@@ -1109,6 +1280,8 @@ class FileNavigator:
|
|||||||
song_key = str(tja_path)
|
song_key = str(tja_path)
|
||||||
if song_key in self.all_song_files:
|
if song_key in self.all_song_files:
|
||||||
song_obj = self.all_song_files[song_key]
|
song_obj = self.all_song_files[song_key]
|
||||||
|
if not isinstance(song_obj, SongFile):
|
||||||
|
continue
|
||||||
for diff in song_obj.box.scores:
|
for diff in song_obj.box.scores:
|
||||||
if diff not in all_scores:
|
if diff not in all_scores:
|
||||||
all_scores[diff] = []
|
all_scores[diff] = []
|
||||||
@@ -1136,7 +1309,7 @@ class FileNavigator:
|
|||||||
tja_files: list[Path] = []
|
tja_files: list[Path] = []
|
||||||
|
|
||||||
for path in directory.iterdir():
|
for path in directory.iterdir():
|
||||||
if path.is_file() and path.suffix.lower() == ".tja":
|
if (path.is_file() and path.suffix.lower() == ".tja") or path.name == "dan.json":
|
||||||
tja_files.append(path)
|
tja_files.append(path)
|
||||||
elif path.is_dir():
|
elif path.is_dir():
|
||||||
# Only recurse into subdirectories that don't have box.def
|
# Only recurse into subdirectories that don't have box.def
|
||||||
@@ -1163,34 +1336,6 @@ class FileNavigator:
|
|||||||
|
|
||||||
return tja_files
|
return tja_files
|
||||||
|
|
||||||
def _parse_box_def(self, path: Path):
|
|
||||||
"""Parse box.def file for directory metadata"""
|
|
||||||
texture_index = SongBox.DEFAULT_INDEX
|
|
||||||
name = path.name
|
|
||||||
collection = None
|
|
||||||
encoding = test_encodings(path / "box.def")
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(path / "box.def", 'r', encoding=encoding) as box_def:
|
|
||||||
for line in box_def:
|
|
||||||
line = line.strip()
|
|
||||||
if line.startswith("#GENRE:"):
|
|
||||||
genre = line.split(":", 1)[1].strip()
|
|
||||||
texture_index = FileSystemItem.GENRE_MAP.get(genre, SongBox.DEFAULT_INDEX)
|
|
||||||
if texture_index == SongBox.DEFAULT_INDEX:
|
|
||||||
texture_index = FileSystemItem.GENRE_MAP_2.get(genre, SongBox.DEFAULT_INDEX)
|
|
||||||
elif line.startswith("#TITLE:"):
|
|
||||||
name = line.split(":", 1)[1].strip()
|
|
||||||
elif line.startswith("#TITLEJA:"):
|
|
||||||
if global_data.config['general']['language'] == 'ja':
|
|
||||||
name = line.split(":", 1)[1].strip()
|
|
||||||
elif line.startswith("#COLLECTION"):
|
|
||||||
collection = line.split(":", 1)[1].strip()
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Error parsing box.def in {path}: {e}")
|
|
||||||
|
|
||||||
return name, texture_index, collection
|
|
||||||
|
|
||||||
def _read_song_list(self, path: Path):
|
def _read_song_list(self, path: Path):
|
||||||
"""Read and process song_list.txt file"""
|
"""Read and process song_list.txt file"""
|
||||||
tja_files: list[Path] = []
|
tja_files: list[Path] = []
|
||||||
@@ -1251,13 +1396,24 @@ class FileNavigator:
|
|||||||
elif offset < -len(self.items) // 2:
|
elif offset < -len(self.items) // 2:
|
||||||
offset += len(self.items)
|
offset += len(self.items)
|
||||||
|
|
||||||
position = BOX_CENTER + (100 * offset)
|
# Adjust spacing based on dan select mode
|
||||||
|
base_spacing = 100
|
||||||
|
center_offset = 150
|
||||||
|
side_offset_l = 0
|
||||||
|
side_offset_r = 300
|
||||||
|
|
||||||
|
if self.in_dan_select:
|
||||||
|
base_spacing = 150
|
||||||
|
side_offset_l = 200
|
||||||
|
side_offset_r = 500
|
||||||
|
|
||||||
|
position = BOX_CENTER + (base_spacing * offset)
|
||||||
if position == BOX_CENTER:
|
if position == BOX_CENTER:
|
||||||
position += 150
|
position += center_offset
|
||||||
elif position > BOX_CENTER:
|
elif position > BOX_CENTER:
|
||||||
position += 300
|
position += side_offset_r
|
||||||
else:
|
else:
|
||||||
position -= 0
|
position -= side_offset_l
|
||||||
|
|
||||||
if item.box.position == -11111:
|
if item.box.position == -11111:
|
||||||
item.box.position = position
|
item.box.position = position
|
||||||
|
|||||||
@@ -39,3 +39,7 @@ class Screen:
|
|||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _do_draw(self):
|
||||||
|
if self.screen_init:
|
||||||
|
self.draw()
|
||||||
|
|||||||
31
libs/tja.py
31
libs/tja.py
@@ -495,17 +495,15 @@ class TJAParser:
|
|||||||
def get_moji(self, play_note_list: list[Note], ms_per_measure: float) -> None:
|
def get_moji(self, play_note_list: list[Note], ms_per_measure: float) -> None:
|
||||||
"""
|
"""
|
||||||
Assign 口唱歌 (note phoneticization) to notes.
|
Assign 口唱歌 (note phoneticization) to notes.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
play_note_list (list[Note]): The list of notes to process.
|
play_note_list (list[Note]): The list of notes to process.
|
||||||
ms_per_measure (float): The duration of a measure in milliseconds.
|
ms_per_measure (float): The duration of a measure in milliseconds.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
None
|
None
|
||||||
"""
|
"""
|
||||||
se_notes = {
|
se_notes = {
|
||||||
1: [0, 1, 2], # Note '1' has three possible sound effects
|
1: 0,
|
||||||
2: [3, 4], # Note '2' has two possible sound effects
|
2: 3,
|
||||||
3: 5,
|
3: 5,
|
||||||
4: 6,
|
4: 6,
|
||||||
5: 7,
|
5: 7,
|
||||||
@@ -514,10 +512,8 @@ class TJAParser:
|
|||||||
8: 10,
|
8: 10,
|
||||||
9: 11
|
9: 11
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(play_note_list) <= 1:
|
if len(play_note_list) <= 1:
|
||||||
return
|
return
|
||||||
|
|
||||||
current_note = play_note_list[-1]
|
current_note = play_note_list[-1]
|
||||||
if current_note.type == 1:
|
if current_note.type == 1:
|
||||||
current_note.moji = 0
|
current_note.moji = 0
|
||||||
@@ -525,44 +521,43 @@ class TJAParser:
|
|||||||
current_note.moji = 3
|
current_note.moji = 3
|
||||||
else:
|
else:
|
||||||
current_note.moji = se_notes[current_note.type]
|
current_note.moji = se_notes[current_note.type]
|
||||||
|
|
||||||
prev_note = play_note_list[-2]
|
prev_note = play_note_list[-2]
|
||||||
|
if prev_note.type == 1:
|
||||||
if prev_note.type in {1, 2}:
|
|
||||||
timing_threshold = ms_per_measure / 8 - 1
|
timing_threshold = ms_per_measure / 8 - 1
|
||||||
if current_note.hit_ms - prev_note.hit_ms <= timing_threshold:
|
if current_note.hit_ms - prev_note.hit_ms <= timing_threshold:
|
||||||
prev_note.moji = se_notes[prev_note.type][1]
|
prev_note.moji = 1
|
||||||
else:
|
else:
|
||||||
prev_note.moji = se_notes[prev_note.type][0]
|
prev_note.moji = 0
|
||||||
|
elif prev_note.type == 2:
|
||||||
|
timing_threshold = ms_per_measure / 8 - 1
|
||||||
|
if current_note.hit_ms - prev_note.hit_ms <= timing_threshold:
|
||||||
|
prev_note.moji = 4
|
||||||
|
else:
|
||||||
|
prev_note.moji = 3
|
||||||
else:
|
else:
|
||||||
prev_note.moji = se_notes[prev_note.type]
|
prev_note.moji = se_notes[prev_note.type]
|
||||||
|
|
||||||
if len(play_note_list) > 3:
|
if len(play_note_list) > 3:
|
||||||
notes_minus_4 = play_note_list[-4]
|
notes_minus_4 = play_note_list[-4]
|
||||||
notes_minus_3 = play_note_list[-3]
|
notes_minus_3 = play_note_list[-3]
|
||||||
notes_minus_2 = play_note_list[-2]
|
notes_minus_2 = play_note_list[-2]
|
||||||
|
|
||||||
consecutive_ones = (
|
consecutive_ones = (
|
||||||
notes_minus_4.type == 1 and
|
notes_minus_4.type == 1 and
|
||||||
notes_minus_3.type == 1 and
|
notes_minus_3.type == 1 and
|
||||||
notes_minus_2.type == 1
|
notes_minus_2.type == 1
|
||||||
)
|
)
|
||||||
|
|
||||||
if consecutive_ones:
|
if consecutive_ones:
|
||||||
rapid_timing = (
|
rapid_timing = (
|
||||||
notes_minus_3.hit_ms - notes_minus_4.hit_ms < (ms_per_measure / 8) and
|
notes_minus_3.hit_ms - notes_minus_4.hit_ms < (ms_per_measure / 8) and
|
||||||
notes_minus_2.hit_ms - notes_minus_3.hit_ms < (ms_per_measure / 8)
|
notes_minus_2.hit_ms - notes_minus_3.hit_ms < (ms_per_measure / 8)
|
||||||
)
|
)
|
||||||
|
|
||||||
if rapid_timing:
|
if rapid_timing:
|
||||||
if len(play_note_list) > 5:
|
if len(play_note_list) > 5:
|
||||||
spacing_before = play_note_list[-4].hit_ms - play_note_list[-5].hit_ms >= (ms_per_measure / 8)
|
spacing_before = play_note_list[-4].hit_ms - play_note_list[-5].hit_ms >= (ms_per_measure / 8)
|
||||||
spacing_after = play_note_list[-1].hit_ms - play_note_list[-2].hit_ms >= (ms_per_measure / 8)
|
spacing_after = play_note_list[-1].hit_ms - play_note_list[-2].hit_ms >= (ms_per_measure / 8)
|
||||||
|
|
||||||
if spacing_before and spacing_after:
|
if spacing_before and spacing_after:
|
||||||
play_note_list[-3].moji = se_notes[1][2]
|
play_note_list[-3].moji = 2
|
||||||
else:
|
else:
|
||||||
play_note_list[-3].moji = se_notes[1][2]
|
play_note_list[-3].moji = 2
|
||||||
|
|
||||||
def notes_to_position(self, diff: int):
|
def notes_to_position(self, diff: int):
|
||||||
"""Parse a TJA's notes into a NoteList."""
|
"""Parse a TJA's notes into a NoteList."""
|
||||||
|
|||||||
170
scenes/dan_select.py
Normal file
170
scenes/dan_select.py
Normal 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)
|
||||||
@@ -2159,7 +2159,6 @@ class Gauge:
|
|||||||
self.is_rainbow = False
|
self.is_rainbow = False
|
||||||
self.table = [
|
self.table = [
|
||||||
[
|
[
|
||||||
None,
|
|
||||||
{"clear_rate": 36.0, "ok_multiplier": 0.75, "bad_multiplier": -0.5},
|
{"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},
|
||||||
{"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},
|
{"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": 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},
|
{"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},
|
{"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": 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},
|
{"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},
|
{"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},
|
{"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"""
|
"""Adds a good note to the gauge"""
|
||||||
self.gauge_update_anim.start()
|
self.gauge_update_anim.start()
|
||||||
self.previous_length = int(self.gauge_length)
|
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:
|
if self.gauge_length > self.gauge_max:
|
||||||
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"""
|
"""Adds an ok note to the gauge"""
|
||||||
self.gauge_update_anim.start()
|
self.gauge_update_anim.start()
|
||||||
self.previous_length = int(self.gauge_length)
|
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:
|
if self.gauge_length > self.gauge_max:
|
||||||
self.gauge_length = self.gauge_max
|
self.gauge_length = self.gauge_max
|
||||||
|
|
||||||
def add_bad(self):
|
def add_bad(self):
|
||||||
"""Adds a bad note to the gauge"""
|
"""Adds a bad note to the gauge"""
|
||||||
self.previous_length = int(self.gauge_length)
|
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:
|
if self.gauge_length < 0:
|
||||||
self.gauge_length = 0
|
self.gauge_length = 0
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ class ResultPlayer:
|
|||||||
plate_info = global_data.config[f'nameplate_{self.player_num}p']
|
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.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.score, self.good, self.ok, self.bad, self.max_combo, self.total_drumroll = '', '', '', '', '', ''
|
||||||
self.update_list = [['score', session_data.result_score],
|
self.update_list: list[tuple[str, int]] = [['score', session_data.result_score],
|
||||||
['good', session_data.result_good],
|
['good', session_data.result_good],
|
||||||
['ok', session_data.result_ok],
|
['ok', session_data.result_ok],
|
||||||
['bad', session_data.result_bad],
|
['bad', session_data.result_bad],
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ class SongSelectScreen(Screen):
|
|||||||
self.timer_selected = Timer(40, get_current_ms(), self._confirm_selection_wrapper)
|
self.timer_selected = Timer(40, get_current_ms(), self._confirm_selection_wrapper)
|
||||||
self.screen_init = True
|
self.screen_init = True
|
||||||
self.ura_switch_animation = UraSwitchAnimation()
|
self.ura_switch_animation = UraSwitchAnimation()
|
||||||
|
self.dan_transition = DanTransition()
|
||||||
|
|
||||||
self.player_1 = SongSelectPlayer(str(global_data.player_num), self.text_fade_in)
|
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.reset_demo_music()
|
||||||
self.finalize_song()
|
self.finalize_song()
|
||||||
self.player_1.nameplate.unload()
|
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)
|
return super().on_screen_end(next_screen)
|
||||||
|
|
||||||
def reset_demo_music(self):
|
def reset_demo_music(self):
|
||||||
@@ -130,8 +133,13 @@ class SongSelectScreen(Screen):
|
|||||||
self.text_fade_in.start()
|
self.text_fade_in.start()
|
||||||
self.text_fade_out.start()
|
self.text_fade_out.start()
|
||||||
elif action == "select_song":
|
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()
|
selected_song = self.navigator.select_current_item()
|
||||||
if selected_song:
|
if isinstance(selected_song, SongFile):
|
||||||
self.state = State.SONG_SELECTED
|
self.state = State.SONG_SELECTED
|
||||||
self.player_1.on_song_selected(selected_song)
|
self.player_1.on_song_selected(selected_song)
|
||||||
audio.play_sound('don', 'sound')
|
audio.play_sound('don', 'sound')
|
||||||
@@ -240,6 +248,9 @@ class SongSelectScreen(Screen):
|
|||||||
self.indicator.update(current_time)
|
self.indicator.update(current_time)
|
||||||
self.blue_arrow_fade.update(current_time)
|
self.blue_arrow_fade.update(current_time)
|
||||||
self.blue_arrow_move.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)
|
next_screen = self.update_players(current_time)
|
||||||
|
|
||||||
@@ -353,6 +364,8 @@ class SongSelectScreen(Screen):
|
|||||||
if self.game_transition is not None:
|
if self.game_transition is not None:
|
||||||
self.game_transition.draw()
|
self.game_transition.draw()
|
||||||
|
|
||||||
|
if self.dan_transition.is_started:
|
||||||
|
self.dan_transition.draw()
|
||||||
self.allnet_indicator.draw()
|
self.allnet_indicator.draw()
|
||||||
|
|
||||||
class SongSelectPlayer:
|
class SongSelectPlayer:
|
||||||
@@ -998,7 +1011,7 @@ class NeiroSelector:
|
|||||||
self.move_sideways.start()
|
self.move_sideways.start()
|
||||||
self.fade_sideways.start()
|
self.fade_sideways.start()
|
||||||
self.text_2.unload()
|
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
|
self.direction = -1
|
||||||
if self.selected_sound == len(self.sounds):
|
if self.selected_sound == len(self.sounds):
|
||||||
return
|
return
|
||||||
@@ -1013,7 +1026,7 @@ class NeiroSelector:
|
|||||||
self.move_sideways.start()
|
self.move_sideways.start()
|
||||||
self.fade_sideways.start()
|
self.fade_sideways.start()
|
||||||
self.text_2.unload()
|
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
|
self.direction = 1
|
||||||
if self.selected_sound == len(self.sounds):
|
if self.selected_sound == len(self.sounds):
|
||||||
return
|
return
|
||||||
@@ -1037,7 +1050,7 @@ class NeiroSelector:
|
|||||||
self.fade_sideways.update(current_ms)
|
self.fade_sideways.update(current_ms)
|
||||||
if self.move_sideways.is_finished:
|
if self.move_sideways.is_finished:
|
||||||
self.text.unload()
|
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
|
self.is_finished = self.move.is_finished and self.is_confirmed
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
@@ -1208,8 +1221,7 @@ class ModifierSelector:
|
|||||||
else:
|
else:
|
||||||
tex.draw_texture('modifier', 'mod_bg', y=move + (i*50), x=x)
|
tex.draw_texture('modifier', 'mod_bg', y=move + (i*50), x=x)
|
||||||
tex.draw_texture('modifier', 'mod_box', 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(outline_color=ray.BLACK, x=92 + x, y=819 + move + (i*50))
|
||||||
self.text_name[i].draw(self.text_name[i].default_src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
|
|
||||||
|
|
||||||
current_mod = self.mods[i]
|
current_mod = self.mods[i]
|
||||||
current_value = getattr(global_data.modifiers[int(self.player_num)-1], current_mod.name)
|
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:
|
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-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)
|
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)
|
||||||
|
|||||||
Reference in New Issue
Block a user