finally refactor the song select boxes

This commit is contained in:
Anthony Samms
2025-11-19 18:35:26 -05:00
parent 24e0c8d980
commit 802d9c5b37
14 changed files with 401 additions and 387 deletions

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@ cache
dev-config.toml
libaudio.so
latest.log
Graphics1080

View File

@@ -1,86 +1,86 @@
Command/Header,Support Status,Initial Sim Release
TITLE,Supported,TaikoJiro v0.80 (initial release)
SUBTITLE,Supported,TaikoJiro v2.64
WAVE,Supported,TaikoJiro v0.80 (initial release)
DEMOSTART,Supported,TaikoJiro v2.37
OFFSET,Supported,TaikoJiro v0.80 (initial release)
BPM,Supported,TaikoJiro v0.80 (initial release)
SCENEPRESET,Supported,OpenTaiko (0auBSQ) v0.6.0
BGMOVIE,Supported,TJAPlayer2 for.PC ver.2016021300
COURSE,Supported,TaikoJiro v1.76
LEVEL,Supported,TaikoJiro v0.80 (initial release)
BALLOON,Supported,TaikoJiro
COURSE,Supported,TaikoJiro v1.76
DEMOSTART,Supported,TaikoJiro v2.37
SUBTITLE,Supported,TaikoJiro v2.64
BGMOVIE,Supported,TJAPlayer2 for.PC ver.2016021300
SCENEPRESET,Supported,OpenTaiko (0auBSQ) v0.6.0
#START / #END,Supported,TaikoJiro v0.80 (initial release)
#BPMCHANGE,Supported,TaikoJiro v0.80 (initial release)
#MEASURE,Supported,TaikoJiro
#GOGOSTART / #GOGOEND,Supported,TaikoJiro
#SCROLL,Supported,TaikoJiro
#BARLINEOFF / #BARLINEON,Supported,TaikoJiro v2.69
#LYRIC,Supported,TJAPlayer2 for.PC
#DELAY,Supported,TaikoJiro v1.60
#SECTION,Supported,TaikoJiro v1.63
#BRANCHSTART / #BRANCHEND,Supported,TaikoJiro v1.63
#N / #E / #M,Supported,TaikoJiro v1.63
#DELAY,Supported,TaikoJiro v1.60
#BARLINEOFF / #BARLINEON,Supported,TaikoJiro v2.69
#LYRIC,Supported,TJAPlayer2 for.PC
#SUDDEN,Supported,TJAPlayer2 for.PC
#JPOSSCROLL,Supported,TJAPlayer2 for.PC
ARTIST,Unsupported,Malody
MAKER,Unsupported,taiko-web ver.19.11.25
NOTESDESIGNER,Unsupported,(Better)TaikoCatsCaffe
AUTHOR,Unsupported,Malody
GENRE,Unsupported,TJAPlayer2 for.PC
SIDE,Unsupported,TaikoJiro v2.49
SIDEREV,Unsupported,TaikoJiro 2 v0.70
SONGVOL,Unsupported,TaikoJiro v1.66
SEVOL,Unsupported,TaikoJiro v1.66
SCOREINIT,Unsupported,TaikoJiro v1.67
SCOREDIFF,Unsupported,TaikoJiro v1.67
STYLE,Unsupported,TaikoJiro v1.99
GAME,Unsupported,TaikoJiro v2.13
LIFE,Unsupported,TaikoJiro v2.19
SIDE,Unsupported,TaikoJiro v2.49
SCOREMODE,Unsupported,TaikoJiro v2.85
SIDEREV,Unsupported,TaikoJiro 2 v0.70
TOTAL,Unsupported,TaikoJiro v2.92 & TaikoJiro 2 v0.93
GENRE,Unsupported,TJAPlayer2 for.PC
HIDDENBRANCH,Unsupported,TJAPlayer2 for.PC
HEADSCROLL,Unsupported,TJAPlayer2 for.PC
PREIMAGE,Unsupported,OpenTaiko (0auBSQ) v0.5.4
COVER,Unsupported,Malody
MOVIEOFFSET,Unsupported,TJAPlayer2 for.PC ver.2015081100
BGIMAGE,Unsupported,TJAPlayer2 for.PC ver.2016021300
EXAM,Unsupported,TJAPlayer3 v1.5.0
GAUGEINCR,Unsupported,TJAPlayer3 v1.5.4
TAIKOWEBSKIN,Unsupported,taiko-web ver.19.02.03
MAKER,Unsupported,taiko-web ver.19.11.25
LYRICS: / LYRICFILE,Unsupported,taiko-web ver.20.03.31
NOTESDESIGNER,Unsupported,(Better)TaikoCatsCaffe
TOWERTYPE,Unsupported,OpenTaiko (0auBSQ) v0.5.0
DANTICK,Unsupported,OpenTaiko (0auBSQ) v0.5.1
DANTICKCOLOR,Unsupported,OpenTaiko (0auBSQ) v0.5.1
PREIMAGE,Unsupported,OpenTaiko (0auBSQ) v0.5.4
SELECTBG,Unsupported,OpenTaiko (0auBSQ) v0.6.0
BGIMAGE,Unsupported,TJAPlayer2 for.PC ver.2016021300
BGOFFSET,Unsupported,Unknown
MOVIEOFFSET,Unsupported,TJAPlayer2 for.PC ver.2015081100
BGA Headers,Unsupported,C-Taiko
LYRICS: / LYRICFILE,Unsupported,taiko-web ver.20.03.31
EXPLICIT,Unsupported,OpenTaiko (0auBSQ) v0.6.0
GAME,Unsupported,TaikoJiro v2.13
STYLE,Unsupported,TaikoJiro v1.99
LIFE,Unsupported,TaikoJiro v2.19
TOTAL,Unsupported,TaikoJiro v2.92 & TaikoJiro 2 v0.93
GAUGEINCR,Unsupported,TJAPlayer3 v1.5.4
EXAM,Unsupported,TJAPlayer3 v1.5.0
SCOREMODE,Unsupported,TaikoJiro v2.85
SCOREINIT,Unsupported,TaikoJiro v1.67
SCOREDIFF,Unsupported,TaikoJiro v1.67
HIDDENBRANCH,Unsupported,TJAPlayer2 for.PC
BGA Headers,Unsupported,C-Taiko
ARTIST,Unsupported,Malody
COVER,Unsupported,Malody
AUTHOR,Unsupported,Malody
BGOFFSET,Unsupported,Unknown
#BMSCROLL / #HBSCROLL / #NMSCROLL,Unsupported,TaikoJiro v1.91
#PAPAMAMA,Unsupported,TJAPlayer3-f v1.7.2.0
#DUMMYSTART / #DUMMYEND,Unsupported,TaikoManyGimmicks
#BARLINESCROLL,Unsupported,taiko-web (plugin Custom Barlines)
#HISPEED,Unsupported,TaikoManyGimmicks v0.6.1α
#DIRECTION,Unsupported,TJAPlayer2 for.PC
#BARLINE,Unsupported,taiko-web (plugin Custom Barlines)
#JUDGEDELAY,Unsupported,TaikoManyGimmicks
#NOTESPAWN,Unsupported,TaikoManyGimmicks
#ENABLEDORON / #DISABLEDORON,Unsupported,TJAPlayer3-Extended
#SENOTECHANGE,Unsupported,TJAPlayer3 v1.4.0
#NOTESCHANGE,Unsupported,C-Taiko
#LEVELHOLD,Unsupported,TaikoJiro v1.63
#NEXTSONG,Unsupported,TJAPlayer3 v1.5.0
#GAMETYPE,Unsupported,OpenTaiko (0auBSQ) v0.6.0
#BMSCROLL / #HBSCROLL / #NMSCROLL,Unsupported,TaikoJiro v1.91
#DIRECTION,Unsupported,TJAPlayer2 for.PC
#HIDDEN,Unsupported,TJAPlayer2 for.PC
NOTE / BARLINE,Unsupported,TaikoManyGimmicks
#GRADATION,Unsupported,TaikoManyGimmicks v0.6α
#INCLUDE,Unsupported,TaikoManyGimmicks v0.6.1α
#SPLITLANE / #MERGELANE,Unsupported,OpenTaiko (0auBSQ) v0.6.0
#SENOTECHANGE,Unsupported,TJAPlayer3 v1.4.0
#NEXTSONG,Unsupported,TJAPlayer3 v1.5.0
#PAPAMAMA,Unsupported,TJAPlayer3-f v1.7.2.0
#ENABLEDORON / #DISABLEDORON,Unsupported,TJAPlayer3-Extended
#OBJ / #CAM,Unsupported,TJAPlayer3-Extended
#BORDERCOLOR,Unsupported,TJAPlayer3-Extended
#CHANGETEXTURE / #RESETTEXTURE,Unsupported,TJAPlayer3-Extended
#SETCONFIG,Unsupported,TJAPlayer3-Extended
#BARLINE,Unsupported,taiko-web (plugin Custom Barlines)
#BARLINESCROLL,Unsupported,taiko-web (plugin Custom Barlines)
#GAMETYPE,Unsupported,OpenTaiko (0auBSQ) v0.6.0
#SPLITLANE / #MERGELANE,Unsupported,OpenTaiko (0auBSQ) v0.6.0
#BGAON / #BGAOFF,Unsupported,OpenTaiko (0auBSQ) v0.6.0
#JUDGEDELAY,Unsupported,TaikoManyGimmicks
#NOTESPAWN,Unsupported,TaikoManyGimmicks
NOTE / BARLINE,Unsupported,TaikoManyGimmicks
#DUMMYSTART / #DUMMYEND,Unsupported,TaikoManyGimmicks
#GRADATION,Unsupported,TaikoManyGimmicks v0.6α
#INCLUDE,Unsupported,TaikoManyGimmicks v0.6.1α
#HISPEED,Unsupported,TaikoManyGimmicks v0.6.1α
#NOTESCHANGE,Unsupported,C-Taiko
1 Command/Header Support Status Initial Sim Release
2 TITLE Supported TaikoJiro v0.80 (initial release)
SUBTITLE Supported TaikoJiro v2.64
3 WAVE Supported TaikoJiro v0.80 (initial release)
DEMOSTART Supported TaikoJiro v2.37
4 OFFSET Supported TaikoJiro v0.80 (initial release)
5 BPM Supported TaikoJiro v0.80 (initial release)
SCENEPRESET Supported OpenTaiko (0auBSQ) v0.6.0
BGMOVIE Supported TJAPlayer2 for.PC ver.2016021300
COURSE Supported TaikoJiro v1.76
6 LEVEL Supported TaikoJiro v0.80 (initial release)
7 BALLOON Supported TaikoJiro
8 COURSE Supported TaikoJiro v1.76
9 DEMOSTART Supported TaikoJiro v2.37
10 SUBTITLE Supported TaikoJiro v2.64
11 BGMOVIE Supported TJAPlayer2 for.PC ver.2016021300
12 SCENEPRESET Supported OpenTaiko (0auBSQ) v0.6.0
13 #START / #END Supported TaikoJiro v0.80 (initial release)
14 #BPMCHANGE Supported TaikoJiro v0.80 (initial release)
15 #MEASURE Supported TaikoJiro
16 #GOGOSTART / #GOGOEND Supported TaikoJiro
17 #SCROLL Supported TaikoJiro
18 #BARLINEOFF / #BARLINEON #DELAY Supported TaikoJiro v2.69 TaikoJiro v1.60
19 #LYRIC #SECTION Supported TJAPlayer2 for.PC TaikoJiro v1.63
#SECTION Supported TaikoJiro v1.63
20 #BRANCHSTART / #BRANCHEND Supported TaikoJiro v1.63
21 #N / #E / #M Supported TaikoJiro v1.63
22 #DELAY #BARLINEOFF / #BARLINEON Supported TaikoJiro v1.60 TaikoJiro v2.69
23 #SUDDEN #LYRIC Supported TJAPlayer2 for.PC
24 #SUDDEN Supported TJAPlayer2 for.PC
25 #JPOSSCROLL Supported TJAPlayer2 for.PC
26 ARTIST SONGVOL Unsupported Malody TaikoJiro v1.66
27 MAKER SEVOL Unsupported taiko-web ver.19.11.25 TaikoJiro v1.66
NOTESDESIGNER Unsupported (Better)TaikoCatsCaffe
AUTHOR Unsupported Malody
GENRE Unsupported TJAPlayer2 for.PC
SIDE Unsupported TaikoJiro v2.49
SIDEREV Unsupported TaikoJiro 2 v0.70
SONGVOL Unsupported TaikoJiro v1.66
SEVOL Unsupported TaikoJiro v1.66
28 HEADSCROLL SCOREINIT Unsupported TJAPlayer2 for.PC TaikoJiro v1.67
29 PREIMAGE SCOREDIFF Unsupported OpenTaiko (0auBSQ) v0.5.4 TaikoJiro v1.67
30 STYLE Unsupported TaikoJiro v1.99
31 GAME Unsupported TaikoJiro v2.13
32 LIFE Unsupported TaikoJiro v2.19
33 SIDE Unsupported TaikoJiro v2.49
34 SCOREMODE Unsupported TaikoJiro v2.85
35 SIDEREV Unsupported TaikoJiro 2 v0.70
36 TOTAL Unsupported TaikoJiro v2.92 & TaikoJiro 2 v0.93
37 GENRE Unsupported TJAPlayer2 for.PC
38 HIDDENBRANCH Unsupported TJAPlayer2 for.PC
39 HEADSCROLL Unsupported TJAPlayer2 for.PC
40 MOVIEOFFSET Unsupported TJAPlayer2 for.PC ver.2015081100
41 COVER BGIMAGE Unsupported Malody TJAPlayer2 for.PC ver.2016021300
42 TAIKOWEBSKIN EXAM Unsupported taiko-web ver.19.02.03 TJAPlayer3 v1.5.0
43 TOWERTYPE GAUGEINCR Unsupported OpenTaiko (0auBSQ) v0.5.0 TJAPlayer3 v1.5.4
44 TAIKOWEBSKIN Unsupported taiko-web ver.19.02.03
45 MAKER Unsupported taiko-web ver.19.11.25
46 DANTICK LYRICS: / LYRICFILE Unsupported OpenTaiko (0auBSQ) v0.5.1 taiko-web ver.20.03.31
47 NOTESDESIGNER Unsupported (Better)TaikoCatsCaffe
48 TOWERTYPE Unsupported OpenTaiko (0auBSQ) v0.5.0
49 DANTICK Unsupported OpenTaiko (0auBSQ) v0.5.1
50 DANTICKCOLOR Unsupported OpenTaiko (0auBSQ) v0.5.1
51 SELECTBG PREIMAGE Unsupported OpenTaiko (0auBSQ) v0.6.0 OpenTaiko (0auBSQ) v0.5.4
52 BGIMAGE SELECTBG Unsupported TJAPlayer2 for.PC ver.2016021300 OpenTaiko (0auBSQ) v0.6.0
53 EXPLICIT Unsupported OpenTaiko (0auBSQ) v0.6.0
54 BGOFFSET BGA Headers Unsupported Unknown C-Taiko
MOVIEOFFSET Unsupported TJAPlayer2 for.PC ver.2015081100
BGA Headers Unsupported C-Taiko
LYRICS: / LYRICFILE Unsupported taiko-web ver.20.03.31
EXPLICIT Unsupported OpenTaiko (0auBSQ) v0.6.0
GAME Unsupported TaikoJiro v2.13
55 STYLE ARTIST Unsupported TaikoJiro v1.99 Malody
56 LIFE COVER Unsupported TaikoJiro v2.19 Malody
57 TOTAL AUTHOR Unsupported TaikoJiro v2.92 & TaikoJiro 2 v0.93 Malody
58 GAUGEINCR BGOFFSET Unsupported TJAPlayer3 v1.5.4 Unknown
59 EXAM #LEVELHOLD Unsupported TJAPlayer3 v1.5.0 TaikoJiro v1.63
60 SCOREMODE #BMSCROLL / #HBSCROLL / #NMSCROLL Unsupported TaikoJiro v2.85 TaikoJiro v1.91
SCOREINIT Unsupported TaikoJiro v1.67
SCOREDIFF Unsupported TaikoJiro v1.67
HIDDENBRANCH Unsupported TJAPlayer2 for.PC
#BMSCROLL / #HBSCROLL / #NMSCROLL Unsupported TaikoJiro v1.91
#PAPAMAMA Unsupported TJAPlayer3-f v1.7.2.0
61 #DUMMYSTART / #DUMMYEND #DIRECTION Unsupported TaikoManyGimmicks TJAPlayer2 for.PC
#BARLINESCROLL Unsupported taiko-web (plugin Custom Barlines)
#HISPEED Unsupported TaikoManyGimmicks v0.6.1α
#DIRECTION Unsupported TJAPlayer2 for.PC
#BARLINE Unsupported taiko-web (plugin Custom Barlines)
#JUDGEDELAY Unsupported TaikoManyGimmicks
#NOTESPAWN Unsupported TaikoManyGimmicks
#ENABLEDORON / #DISABLEDORON Unsupported TJAPlayer3-Extended
#SENOTECHANGE Unsupported TJAPlayer3 v1.4.0
#NOTESCHANGE Unsupported C-Taiko
#LEVELHOLD Unsupported TaikoJiro v1.63
#NEXTSONG Unsupported TJAPlayer3 v1.5.0
#GAMETYPE Unsupported OpenTaiko (0auBSQ) v0.6.0
62 #HIDDEN Unsupported TJAPlayer2 for.PC
63 NOTE / BARLINE #SENOTECHANGE Unsupported TaikoManyGimmicks TJAPlayer3 v1.4.0
64 #GRADATION #NEXTSONG Unsupported TaikoManyGimmicks v0.6α TJAPlayer3 v1.5.0
65 #INCLUDE #PAPAMAMA Unsupported TaikoManyGimmicks v0.6.1α TJAPlayer3-f v1.7.2.0
66 #SPLITLANE / #MERGELANE #ENABLEDORON / #DISABLEDORON Unsupported OpenTaiko (0auBSQ) v0.6.0 TJAPlayer3-Extended
67 #OBJ / #CAM Unsupported TJAPlayer3-Extended
68 #BORDERCOLOR Unsupported TJAPlayer3-Extended
69 #CHANGETEXTURE / #RESETTEXTURE Unsupported TJAPlayer3-Extended
70 #SETCONFIG Unsupported TJAPlayer3-Extended
71 #BGAON / #BGAOFF #BARLINE Unsupported OpenTaiko (0auBSQ) v0.6.0 taiko-web (plugin Custom Barlines)
72 #BARLINESCROLL Unsupported taiko-web (plugin Custom Barlines)
73 #GAMETYPE Unsupported OpenTaiko (0auBSQ) v0.6.0
74 #SPLITLANE / #MERGELANE Unsupported OpenTaiko (0auBSQ) v0.6.0
75 #BGAON / #BGAOFF Unsupported OpenTaiko (0auBSQ) v0.6.0
76 #JUDGEDELAY Unsupported TaikoManyGimmicks
77 #NOTESPAWN Unsupported TaikoManyGimmicks
78 NOTE / BARLINE Unsupported TaikoManyGimmicks
79 #DUMMYSTART / #DUMMYEND Unsupported TaikoManyGimmicks
80 #GRADATION Unsupported TaikoManyGimmicks v0.6α
81 #INCLUDE Unsupported TaikoManyGimmicks v0.6.1α
82 #HISPEED Unsupported TaikoManyGimmicks v0.6.1α
83 #NOTESCHANGE Unsupported C-Taiko
84
85
86

View File

@@ -213,10 +213,8 @@ static int port_audio_callback(const void *inputBuffer, void *outputBuffer,
}
struct audio_buffer *audio_buffer = AUDIO.Buffer.first;
int active_buffers = 0;
while (audio_buffer != NULL) {
if (audio_buffer->playing && !audio_buffer->paused && audio_buffer->data != NULL) {
active_buffers++;
unsigned int subBufferSizeFrames = audio_buffer->sizeInFrames / 2;
unsigned long framesToMix = framesPerBuffer;
float *buffer_data = (float *)audio_buffer->data;

View File

@@ -8,18 +8,17 @@ from libs.audio import audio
from libs.animation import Animation, MoveAnimation
from libs.global_data import Crown, Difficulty
from libs.tja import TJAParser, test_encodings
from libs.texture import tex
from libs.texture import SCREEN_SCALE, SCREEN_WIDTH, tex
from libs.utils import OutlinedText, get_current_ms, global_data
from datetime import datetime, timedelta
import sqlite3
import pyray as ray
BOX_CENTER = 444
BOX_CENTER = 594 * SCREEN_SCALE
logger = logging.getLogger(__name__)
class SongBox:
"""A box for the song select screen."""
class BaseBox():
OUTLINE_MAP = {
1: ray.Color(0, 77, 104, 255),
2: ray.Color(156, 64, 2, 255),
@@ -38,61 +37,118 @@ class SongBox:
}
BACK_INDEX = 17
DEFAULT_INDEX = 9
def __init__(self, name: str, texture_index: int, is_dir: bool, tja: Optional[TJAParser] = None,
tja_count: Optional[int] = None, box_texture: Optional[str] = None, name_texture_index: Optional[int] = None):
"""Base class for all box types in the song select screen."""
def __init__(self, name: str, texture_index: int):
self.text_name = name
self.texture_index = texture_index
self.position = float('inf')
self.start_position: float = -1
self.target_position: float = -1
self.open_anim = Animation.create_move(133, total_distance=150*SCREEN_SCALE, delay=83.33)
self.open_fade = Animation.create_fade(200, initial_opacity=0, final_opacity=1.0)
self.move = None
self.is_open = False
self.text_loaded = False
self.wait = 0
def load_text(self):
self.name = OutlinedText(self.text_name, 40, ray.WHITE, outline_thickness=5, vertical=True)
def move_box(self, current_time: float):
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, total_distance=100 * direction * SCREEN_SCALE, ease_out='cubic')
self.move.start()
if self.is_open or self.target_position == BOX_CENTER:
self.move.total_distance = 250 * direction
self.start_position = self.position
if self.move is not None:
self.move.update(current_time)
self.position = self.start_position + int(self.move.attribute)
if self.move.is_finished:
self.position = self.target_position
self.move = None
def update(self, current_time: float, is_diff_select: bool):
self.is_diff_select = is_diff_select
self.open_anim.update(current_time)
self.open_fade.update(current_time)
def _draw_closed(self, x: float, y: float):
tex.draw_texture('box', 'folder_texture_left', frame=self.texture_index, x=x)
offset = 1 if self.texture_index == 3 or self.texture_index >= 9 and self.texture_index not in {10,11,12} else 0
tex.draw_texture('box', 'folder_texture', frame=self.texture_index, x=x, x2=32, y=offset)
tex.draw_texture('box', 'folder_texture_right', frame=self.texture_index, x=x)
if self.texture_index == SongBox.DEFAULT_INDEX:
tex.draw_texture('box', 'genre_overlay', x=x, y=y)
elif self.texture_index == 14:
tex.draw_texture('box', 'diff_overlay', x=x, y=y)
def _draw_open(self, x: float, y: float, fade_override: Optional[float], is_ura: bool):
pass
def draw(self, x: float, y: float, is_ura: bool, fade_override: Optional[float] = None):
if self.is_open and get_current_ms() >= self.wait + 83.33:
self._draw_open(x, y, fade_override, is_ura)
else:
self._draw_closed(x, y)
class BackBox(BaseBox):
def __init__(self, name: str, texture_index: int):
super().__init__(name, texture_index)
self.yellow_box = None
def load_text(self):
super().load_text()
self.text_loaded = True
def update(self, current_time: float, is_diff_select: bool):
super().update(current_time, is_diff_select)
is_open_prev = self.is_open
self.move_box(current_time)
self.is_open = self.position == BOX_CENTER
if self.yellow_box is not None:
self.yellow_box.update(is_diff_select)
if not is_open_prev and self.is_open:
self.yellow_box = YellowBox(True)
self.yellow_box.create_anim()
self.wait = current_time
def _draw_closed(self, x: float, y: float):
super()._draw_closed(x, y)
tex.draw_texture('box', 'back_text', x=x, y=y)
def _draw_open(self, x: float, y: float, fade_override: Optional[float] = None, is_ura: bool = False):
if self.yellow_box is not None:
self.yellow_box.draw(self, fade_override, is_ura, self.name)
class SongBox(BaseBox):
def __init__(self, name: str, texture_index: int, tja: TJAParser, name_texture_index: Optional[int] = None):
super().__init__(name, texture_index)
if name_texture_index is None:
self.name_texture_index = texture_index
else:
self.name_texture_index = name_texture_index
self.box_texture_path = box_texture
self.box_texture = None
self.scores = dict()
self.crown = dict()
self.position = -11111
self.start_position = -1
self.target_position = -1
self.is_open = False
self.is_back = self.texture_index == SongBox.BACK_INDEX
if self.is_back:
for i in range(1, SongBox.BACK_INDEX-1):
if audio.is_sound_playing(f'genre_voice_{i}'):
audio.stop_sound(f'genre_voice_{i}')
self.name = None
self.hori_name = None
self.yellow_box = None
self.open_anim = Animation.create_move(133, start_position=0, total_distance=150, delay=83.33)
self.open_fade = Animation.create_fade(200, initial_opacity=0, final_opacity=1.0)
self.move = None
self.wait = 0
self.is_dir = is_dir
self.tja_count = tja_count
self.tja_count_text = None
self.hash = dict()
self.score_history = None
self.history_wait = 0
self.tja = tja
self.hash = dict()
self.is_favorite = False
self.yellow_box = None
def reset(self):
if self.yellow_box is not None:
self.yellow_box.reset()
self.yellow_box.create_anim()
if self.name is not None:
self.name.unload()
self.name = None
if self.box_texture is not None:
ray.unload_texture(self.box_texture)
self.box_texture = None
if self.hori_name is not None:
self.hori_name.unload()
self.hori_name = None
self.is_open = False
def load_text(self):
super().load_text()
self.text_loaded = True
def get_scores(self):
if self.tja is None:
return
with sqlite3.connect('scores.db') as con:
cursor = con.cursor()
# Batch database query for all diffs at once
@@ -116,37 +172,12 @@ class SongBox:
self.scores[diff] = hash_to_score.get(diff_hash)
self.score_history = 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, start_position=0, total_distance=100 * direction, ease_out='cubic')
self.move.start()
if self.is_open or self.target_position == BOX_CENTER + 150:
self.move.total_distance = 250 * 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 update(self, is_diff_select: bool):
current_time = get_current_ms()
self.is_diff_select = is_diff_select
def update(self, current_time: float, is_diff_select: bool):
super().update(current_time, is_diff_select)
is_open_prev = self.is_open
self.move_box()
self.is_open = self.position == BOX_CENTER + 150
self.move_box(current_time)
self.is_open = self.position == BOX_CENTER
if not (-56 <= self.position <= 1280):
return
if self.yellow_box is not None:
self.yellow_box.update(is_diff_select)
@@ -157,54 +188,21 @@ class SongBox:
self.score_history = ScoreHistory(self.scores, current_time)
if not is_open_prev and self.is_open:
if self.tja is not None or self.is_back:
self.yellow_box = YellowBox(self.name, self.is_back, tja=self.tja)
self.yellow_box.create_anim()
else:
self.hori_name = OutlinedText(self.text_name, 40, ray.WHITE, outline_thickness=5)
self.open_anim.start()
self.open_fade.start()
self.yellow_box = YellowBox(False, tja=self.tja)
self.yellow_box.create_anim()
self.wait = current_time
if current_time >= self.history_wait + 3000:
self.history_wait = current_time
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')
elif not self.is_open and is_open_prev and self.texture_index != 17 and audio.is_sound_playing(f'genre_voice_{self.texture_index}'):
audio.stop_sound(f'genre_voice_{self.texture_index}')
if self.tja_count is not None and self.tja_count > 0 and self.tja_count_text is None:
self.tja_count_text = OutlinedText(str(self.tja_count), 35, ray.WHITE, outline_thickness=5)#, horizontal_spacing=1.2)
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.open_anim.update(current_time)
self.open_fade.update(current_time)
if self.name is None:
self.name = OutlinedText(self.text_name, 40, ray.WHITE, outline_thickness=5, vertical=True)
if self.score_history is not None:
self.score_history.update(current_time)
def _draw_closed(self, x: float, y: float):
super()._draw_closed(x, y)
def _draw_closed(self, x: int, y: int):
tex.draw_texture('box', 'folder_texture_left', frame=self.texture_index, x=x)
offset = 1 if self.texture_index == 3 or self.texture_index >= 9 and self.texture_index not in {10,11,12} else 0
tex.draw_texture('box', 'folder_texture', frame=self.texture_index, x=x, x2=32, y=offset)
tex.draw_texture('box', 'folder_texture_right', frame=self.texture_index, x=x)
if self.texture_index == SongBox.DEFAULT_INDEX:
tex.draw_texture('box', 'genre_overlay', x=x, y=y)
elif self.texture_index == 14:
tex.draw_texture('box', 'diff_overlay', x=x, y=y)
if not self.is_back and self.is_dir:
tex.draw_texture('box', 'folder_clip', frame=self.texture_index, x=x - (1 - offset), y=y)
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)
if self.is_back:
tex.draw_texture('box', 'back_text', x=x, y=y)
return
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)
if self.tja is not None and self.tja.ex_data.new:
if self.tja.ex_data.new:
tex.draw_texture('yellow_box', 'ex_data_new_song_balloon', x=x, y=y)
valid_scores = {k: v for k, v in self.scores.items() if v is not None}
if valid_scores:
@@ -216,6 +214,58 @@ class SongBox:
tex.draw_texture('yellow_box', 'crown_fc', x=x, y=y, frame=min(Difficulty.URA, highest_key))
elif score and score[5] >= Crown.CLEAR:
tex.draw_texture('yellow_box', 'crown_clear', x=x, y=y, frame=min(Difficulty.URA, highest_key))
def _draw_open(self, x: float, y: float, fade_override=None, is_ura=False):
if self.yellow_box is not None:
self.yellow_box.draw(self, fade_override, is_ura, self.name)
def draw_score_history(self):
if self.is_open and get_current_ms() >= self.wait + 83.33:
if self.score_history is not None and get_current_ms() >= self.history_wait + 3000:
self.score_history.draw()
class FolderBox(BaseBox):
def __init__(self, name: str, texture_index: int, tja_count: int = 0,
box_texture: Optional[str] = None):
super().__init__(name, texture_index)
self.box_texture_path = Path(box_texture) if box_texture else None
self.is_back = self.texture_index == SongBox.BACK_INDEX
if self.is_back:
for i in range(1, SongBox.BACK_INDEX-1):
if audio.is_sound_playing(f'genre_voice_{i}'):
audio.stop_sound(f'genre_voice_{i}')
self.tja_count = tja_count
self.crown = dict()
def load_text(self):
super().load_text()
self.hori_name = OutlinedText(self.text_name, 40, ray.WHITE, outline_thickness=5)
self.box_texture = ray.load_texture(str(self.box_texture_path)) if self.box_texture_path and self.box_texture_path.exists() else None
self.tja_count_text = OutlinedText(str(self.tja_count), 35, ray.WHITE, outline_thickness=5)
self.text_loaded = True
def update(self, current_time: float, is_diff_select: bool):
super().update(current_time, is_diff_select)
is_open_prev = self.is_open
self.move_box(current_time)
self.is_open = self.position == BOX_CENTER
if not is_open_prev and self.is_open:
self.open_anim.start()
self.open_fade.start()
self.wait = current_time
if self.texture_index != SongBox.BACK_INDEX and not audio.is_sound_playing('voice_enter'):
audio.play_sound(f'genre_voice_{self.texture_index}', 'voice')
elif not self.is_open and is_open_prev and self.texture_index != 17 and audio.is_sound_playing(f'genre_voice_{self.texture_index}'):
audio.stop_sound(f'genre_voice_{self.texture_index}')
def _draw_closed(self, x: float, y: float):
super()._draw_closed(x, y)
offset = 1 if self.texture_index == 3 or self.texture_index >= 9 and self.texture_index not in {10,11,12} else 0
tex.draw_texture('box', 'folder_clip', frame=self.texture_index, x=x - (1 - offset), y=y)
self.name.draw(outline_color=SongBox.OUTLINE_MAP.get(self.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)
if self.crown: #Folder lamp
highest_crown = max(self.crown)
if self.crown[highest_crown] == 'DFC':
@@ -225,11 +275,11 @@ class SongBox:
else:
tex.draw_texture('yellow_box', 'crown_clear', x=x, y=y, frame=min(Difficulty.URA, highest_crown))
def _draw_open(self, x: int, y: int, fade_override: Optional[float]):
def _draw_open(self, x: float, y: float, fade_override: Optional[float], is_ura: bool):
color = ray.WHITE
if fade_override is not None:
color = ray.fade(ray.WHITE, fade_override)
if self.hori_name is not None and self.open_anim.attribute >= 100:
if not self.is_back and self.open_anim.attribute >= 100:
tex.draw_texture('box', 'folder_top_edge', x=x, y=y - self.open_anim.attribute, color=color, mirror='horizontal', frame=self.texture_index)
tex.draw_texture('box', 'folder_top', x=x, y=y - self.open_anim.attribute, color=color, frame=self.texture_index)
tex.draw_texture('box', 'folder_top_edge', x=x+268, y=y - self.open_anim.attribute, color=color, frame=self.texture_index)
@@ -249,45 +299,30 @@ class SongBox:
color = ray.WHITE
if fade_override is not None:
color = ray.fade(ray.WHITE, fade_override)
if self.tja_count_text is not None and self.texture_index != 14:
if self.texture_index != 14:
tex.draw_texture('yellow_box', 'song_count_back', color=color, fade=0.5)
tex.draw_texture('yellow_box', 'song_count_num', color=color)
tex.draw_texture('yellow_box', 'song_count_songs', color=color)
dest_width = min(124, self.tja_count_text.texture.width)
self.tja_count_text.draw(outline_color=ray.BLACK, x=560 - (dest_width//2), y=126, x2=dest_width-self.tja_count_text.texture.width, color=color)
if self.texture_index != 9:
if self.texture_index != SongBox.DEFAULT_INDEX:
tex.draw_texture('box', 'folder_graphic', color=color, frame=self.texture_index)
tex.draw_texture('box', 'folder_text', color=color, frame=self.texture_index)
elif self.box_texture is not None:
ray.draw_texture(self.box_texture, (x+48) - (self.box_texture.width//2), (y+240) - (self.box_texture.height//2), color)
def draw_score_history(self):
if self.is_open and get_current_ms() >= self.wait + 83.33:
if self.score_history is not None and get_current_ms() >= self.history_wait + 3000:
self.score_history.draw()
def draw(self, x: int, y: int, is_ura: bool, fade_override=None):
if self.is_open and get_current_ms() >= self.wait + 83.33:
if self.yellow_box is not None:
self.yellow_box.draw(self, fade_override, is_ura)
else:
self._draw_open(x, y, self.open_fade.attribute)
else:
self._draw_closed(x, y)
ray.draw_texture(self.box_texture, int((x+48) - (self.box_texture.width//2)), int((y+240) - (self.box_texture.height//2)), color)
class YellowBox:
"""A song box when it is opened."""
def __init__(self, name: Optional[OutlinedText], is_back: bool, tja: Optional[TJAParser] = None, is_dan: bool = False):
def __init__(self, is_back: bool, tja: Optional[TJAParser] = None, is_dan: bool = False):
self.is_diff_select = False
self.name = name
self.is_back = is_back
self.tja = tja
self.is_dan = is_dan
self.subtitle = None
if self.tja is not None:
subtitle_text = self.tja.metadata.subtitle.get(global_data.config['general']['language'], '')
font_size = 30 if len(subtitle_text) < 30 else 20
self.subtitle = OutlinedText(subtitle_text, font_size, ray.WHITE, outline_thickness=5, vertical=True)
self.is_dan = is_dan
self.subtitle = None
self.left_out = tex.get_animation(9)
self.right_out = tex.get_animation(10)
@@ -318,11 +353,6 @@ class YellowBox:
self.bottom_y = tex.textures['yellow_box']['yellow_box_bottom_right'].y[0]
self.edge_height = tex.textures['yellow_box']['yellow_box_bottom_right'].height
def reset(self):
if self.subtitle is not None:
self.subtitle.unload()
self.subtitle = None
def create_anim(self):
self.right_out_2.reset()
self.top_y_out.reset()
@@ -368,8 +398,8 @@ class YellowBox:
self.center_height = self.center_h_out.attribute
self.is_diff_select = is_diff_select
def _draw_tja_data(self, song_box, color, fade):
if self.tja is None:
def _draw_tja_data(self, song_box: SongBox, color: ray.Color, fade: float):
if not self.tja:
return
for diff in self.tja.metadata.course_data:
if diff >= Difficulty.URA:
@@ -406,16 +436,14 @@ class YellowBox:
if self.tja.metadata.course_data[diff].is_branching and (get_current_ms() // 1000) % 2 == 0:
tex.draw_texture('yellow_box', 'branch_indicator', x=(diff*60), color=color)
def _draw_tja_data_diff(self, is_ura: bool, song_box: Optional[SongBox] = None):
if self.tja is None:
def _draw_tja_data_diff(self, is_ura: bool, song_box: SongBox):
if not self.tja:
return
tex.draw_texture('diff_select', 'back', fade=self.fade_in.attribute)
tex.draw_texture('diff_select', 'option', fade=self.fade_in.attribute)
tex.draw_texture('diff_select', 'neiro', fade=self.fade_in.attribute)
for diff in self.tja.metadata.course_data:
if song_box is None:
continue
if diff >= Difficulty.URA:
continue
elif diff in song_box.scores and song_box.scores[diff] is not None and ((song_box.scores[diff][4] is not None and song_box.scores[diff][4] == 2 and song_box.scores[diff][2] == 0) or (song_box.scores[diff][2] == 0 and song_box.scores[diff][3] == 0)):
@@ -447,7 +475,7 @@ class YellowBox:
name = 'branch_indicator_diff'
tex.draw_texture('yellow_box', name, x=min(course, Difficulty.ONI)*115, fade=self.fade_in.attribute)
def _draw_text(self, song_box):
def _draw_text(self, song_box, name: OutlinedText):
if not isinstance(self.right_out, MoveAnimation):
return
if not isinstance(self.right_out_2, MoveAnimation):
@@ -457,9 +485,9 @@ class YellowBox:
x = song_box.position + (self.right_out.attribute*0.85 - (self.right_out.start_position*0.85)) + self.right_out_2.attribute - self.right_out_2.start_position
if self.is_back:
tex.draw_texture('box', 'back_text_highlight', x=x)
elif self.name is not None:
texture = self.name.texture
self.name.draw(outline_color=ray.BLACK, x=x + 30, y=35 + self.top_y_out.attribute, y2=min(texture.height, 417)-texture.height, color=ray.WHITE)
else:
texture = name.texture
name.draw(outline_color=ray.BLACK, x=x + 30, y=35 + self.top_y_out.attribute, y2=min(texture.height, 417)-texture.height, color=ray.WHITE)
if self.subtitle is not None:
texture = self.subtitle.texture
y = self.bottom_y - min(texture.height, 410) + 10 + self.top_y_out.attribute - self.top_y_out.start_position
@@ -476,36 +504,31 @@ class YellowBox:
tex.draw_texture('yellow_box', 'yellow_box_top', x=self.left_x + self.edge_height, y=self.top_y, x2=self.center_width)
tex.draw_texture('yellow_box', 'yellow_box_center', x=self.left_x + self.edge_height, y=self.top_y + self.edge_height, x2=self.center_width, y2=self.center_height)
def draw(self, song_box: Optional[SongBox], fade_override: Optional[float], is_ura: bool):
def draw(self, song_box: Optional[SongBox | BackBox], fade_override: Optional[float], is_ura: bool, name: OutlinedText):
self._draw_yellow_box()
fade = self.fade.attribute
if fade_override is not None:
fade = min(self.fade.attribute, fade_override)
if self.is_dan:
return
if self.is_diff_select and self.tja is not None:
if self.is_back:
tex.draw_texture('box', 'back_graphic', fade=fade)
return
if self.is_diff_select and isinstance(song_box, SongBox):
self._draw_tja_data_diff(is_ura, song_box)
else:
fade = self.fade.attribute
if fade_override is not None:
fade = min(self.fade.attribute, fade_override)
if self.is_back:
tex.draw_texture('box', 'back_graphic', fade=fade)
elif isinstance(song_box, SongBox):
self._draw_tja_data(song_box, ray.fade(ray.WHITE, fade), fade)
self._draw_text(song_box)
self._draw_text(song_box, name)
class DanBox:
def __init__(self, title: str, color: int, songs: list[tuple[TJAParser, int, 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
class DanBox(BaseBox):
def __init__(self, name, color: int, songs: list[tuple[TJAParser, int, int, int]], exams: list['Exam']):
super().__init__(name, color)
self.songs = songs
self.exams = exams
self.song_text: list[tuple[OutlinedText, OutlinedText]] = []
self.total_notes = 0
self.yellow_box = None
for song, genre_index, difficulty, level in self.songs:
notes, branch_m, branch_e, branch_n = song.notes_to_position(difficulty)
self.total_notes += sum(1 for note in notes.play_notes if note.type < 5)
@@ -515,57 +538,26 @@ class DanBox:
self.total_notes += sum(1 for note in branch.play_notes if note.type < 5)
for branch in branch_n:
self.total_notes += sum(1 for note in branch.play_notes if note.type < 5)
self.name = None
self.hori_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 * -1
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 load_text(self):
super().load_text()
self.hori_name = OutlinedText(self.text_name, 40, ray.WHITE)
for song, genre, difficulty, level 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, vertical=True)
font_size = 30 if len(subtitle) < 30 else 20
subtitle_text = OutlinedText(subtitle, font_size, ray.WHITE, vertical=True)
self.song_text.append((title_text, subtitle_text))
self.text_loaded = True
def reset(self):
if self.name is not None:
self.name.unload()
self.name = None
def get_text(self):
if self.name is None:
self.name = OutlinedText(self.title, 40, ray.WHITE, vertical=True)
self.hori_name = OutlinedText(self.title, 40, ray.WHITE)
if self.is_open and not self.song_text:
for song, genre, difficulty, level 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, vertical=True)
font_size = 30 if len(subtitle) < 30 else 20
subtitle_text = OutlinedText(subtitle, font_size, ray.WHITE, vertical=True)
self.song_text.append((title_text, subtitle_text))
def update(self, is_diff_select: bool):
self.move_box()
self.get_text()
def update(self, current_time: float, is_diff_select: bool):
super().update(current_time, is_diff_select)
is_open_prev = self.is_open
self.is_open = self.position == BOX_CENTER + 150
self.move_box(current_time)
self.is_open = self.position == BOX_CENTER
if not is_open_prev and self.is_open:
self.yellow_box = YellowBox(self.name, self.is_back, is_dan=True)
self.yellow_box = YellowBox(False, is_dan=True)
self.yellow_box.create_anim()
if self.yellow_box is not None:
@@ -601,51 +593,49 @@ class DanBox:
elif self.exams[i].range == 'less':
tex.draw_texture('yellow_box', 'exam_less', x=(offset*-1.7), y=(i*83))
def _draw_closed(self, x: int, y: int):
tex.draw_texture('box', 'folder', frame=self.color, x=x)
def _draw_closed(self, x: float, y: float):
tex.draw_texture('box', 'folder', frame=self.texture_index, 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):
def _draw_open(self, x: float, y: float, fade_override: Optional[float], is_ura: bool):
if fade_override is not None:
fade = fade_override
else:
fade = 1.0
if self.yellow_box is not None:
self.yellow_box.draw(None, None, False)
self.yellow_box.draw(None, None, False, self.name)
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)
tex.draw_texture('yellow_box', 'genre_banner', x=x, frame=self.songs[i][1], fade=fade)
tex.draw_texture('yellow_box', 'difficulty', x=x, frame=self.songs[i][2], fade=fade)
tex.draw_texture('yellow_box', 'difficulty_x', x=x, fade=fade)
tex.draw_texture('yellow_box', 'difficulty_star', x=x, fade=fade)
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))
tex.draw_texture('yellow_box', 'difficulty_num', frame=int(counter[i]), x=x-(total_width // 2) + (i * 10), fade=fade)
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)
title.draw(outline_color=ray.BLACK, x=665+x, y=127, y2=min(title.texture.height, 400)-title.texture.height, fade=fade)
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, fade=fade)
tex.draw_texture('yellow_box', 'total_notes_bg')
tex.draw_texture('yellow_box', 'total_notes')
tex.draw_texture('yellow_box', 'total_notes_bg', fade=fade)
tex.draw_texture('yellow_box', 'total_notes', fade=fade)
counter = str(self.total_notes)
for i in range(len(counter)):
tex.draw_texture('yellow_box', 'total_notes_counter', frame=int(counter[i]), x=(i * 25))
tex.draw_texture('yellow_box', 'total_notes_counter', frame=int(counter[i]), x=(i * 25), fade=fade)
tex.draw_texture('yellow_box', 'frame', frame=self.color)
tex.draw_texture('yellow_box', 'frame', frame=self.texture_index, fade=fade)
if self.hori_name is not None:
self.hori_name.draw(outline_color=ray.BLACK, x=434 - (self.hori_name.texture.width//2), y=84, x2=min(self.hori_name.texture.width, 275)-self.hori_name.texture.width)
self.hori_name.draw(outline_color=ray.BLACK, x=434 - (self.hori_name.texture.width//2), y=84, x2=min(self.hori_name.texture.width, 275)-self.hori_name.texture.width, fade=fade)
self._draw_exam_box()
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:
"""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: BaseBox, end_box: BaseBox, title: OutlinedText, diff_sort: Optional[int]):
self.start_box = start_box
self.end_box = end_box
self.start_position = start_box.position
@@ -694,7 +684,7 @@ class GenreBG:
tex.draw_texture('box', 'folder_background_folder_edge', x=((offset+dest_width)//2)+20, y=y-2, fade=self.fade_in.attribute, frame=self.end_box.texture_index)
if self.diff_num is not None:
tex.draw_texture('diff_sort', 'star_num', frame=self.diff_num, x=-150 + (dest_width//2), y=-143)
self.title.draw(outline_color=ray.BLACK, x=(1280//2) - (dest_width//2)-(offset//2), y=y-60, x2=dest_width - self.title.texture.width, color=ray.fade(ray.WHITE, self.fade_in.attribute))
self.title.draw(outline_color=ray.BLACK, x=(SCREEN_WIDTH//2) - (dest_width//2)-(offset//2), y=y-60, x2=dest_width - self.title.texture.width, color=ray.fade(ray.WHITE, self.fade_in.attribute))
class ScoreHistory:
"""The score information that appears while hovering over a song"""
@@ -872,7 +862,10 @@ class Directory(FileSystemItem):
elif self.to_root or self.back:
texture_index = SongBox.BACK_INDEX
self.box = SongBox(name, texture_index, True, tja_count=tja_count, box_texture=box_texture)
if self.back:
self.box = BackBox(name, texture_index)
else:
self.box = FolderBox(name, texture_index, tja_count=tja_count, box_texture=box_texture)
class SongFile(FileSystemItem):
"""Represents a song file (TJA) in the navigation system"""
@@ -884,7 +877,7 @@ class SongFile(FileSystemItem):
self.tja.ex_data.new = True
title = self.tja.metadata.title.get(global_data.config['general']['language'].lower(), self.tja.metadata.title['en'])
self.hash = global_data.song_paths[path]
self.box = SongBox(title, texture_index, False, tja=self.tja, name_texture_index=name_texture_index if name_texture_index is not None else texture_index)
self.box = SongBox(title, texture_index, self.tja, name_texture_index=name_texture_index if name_texture_index is not None else texture_index)
self.box.hash = global_data.song_hashes[self.hash][0]["diff_hashes"]
self.box.get_scores()
@@ -904,7 +897,7 @@ class DanCourse(FileSystemItem):
data = json.load(f)
self.title = data["title"]
self.color = data["color"]
self.charts = []
self.charts: list[tuple[TJAParser, int, int, int]] = []
for chart in data["charts"]:
hash = chart["hash"]
#chart_title = chart["title"]
@@ -1203,8 +1196,8 @@ class FileNavigator:
if self.recent_folder is None:
raise Exception("tried to enter recent folder without recents")
self._generate_objects_recursive(self.recent_folder.path)
selected_item.box.tja_count_text = None
selected_item.box.tja_count = self._count_tja_files(self.recent_folder.path)
if not isinstance(selected_item.box, BackBox):
selected_item.box.tja_count = self._count_tja_files(self.recent_folder.path)
content_items = self.directory_contents[dir_key]
elif selected_item.collection == Directory.COLLECTIONS[2]:
if self.favorite_folder is None:
@@ -1212,8 +1205,8 @@ class FileNavigator:
self._generate_objects_recursive(self.favorite_folder.path)
tja_files = self._get_tja_files_for_directory(self.favorite_folder.path)
self._calculate_directory_crowns(dir_key, tja_files)
selected_item.box.tja_count_text = None
selected_item.box.tja_count = self._count_tja_files(self.favorite_folder.path)
if not isinstance(selected_item.box, BackBox):
selected_item.box.tja_count = self._count_tja_files(self.favorite_folder.path)
content_items = self.directory_contents[dir_key]
self.in_favorites = True
elif selected_item.collection == Directory.COLLECTIONS[3]:
@@ -1245,7 +1238,7 @@ class FileNavigator:
return
i = 1
for item in content_items:
if isinstance(item, SongFile):
if isinstance(item, SongFile) and not has_children:
if i % 10 == 0 and i != 0:
back_dir = Directory(self.current_dir.parent, "", SongBox.BACK_INDEX, back=True)
self.items.insert(self.selected_index+i, back_dir)
@@ -1268,24 +1261,22 @@ class FileNavigator:
for item in self.items:
if isinstance(item, Directory):
item_key = str(item.path)
if item_key in self.directory_contents: # Only for real directories
if isinstance(item.box, FolderBox):
item.box.crown = self._get_directory_crowns_cached(item_key)
else:
# Navigation items (back/to_root)
item.box.crown = dict()
self.calculate_box_positions()
if (not has_children and start_box is not None
and end_box is not None and selected_item is not None
and selected_item.box.hori_name is not None):
hori_name = selected_item.box.hori_name
diff_sort = None
if selected_item.collection == Directory.COLLECTIONS[3]:
diff_sort = self.diff_sort_level
diffs = ['かんたん', 'ふつう', 'むずかしい', 'おに']
hori_name = OutlinedText(diffs[min(Difficulty.ONI, self.diff_sort_diff)], 40, ray.WHITE, outline_thickness=5)
self.genre_bg = GenreBG(start_box, end_box, hori_name, diff_sort)
if selected_item and isinstance(selected_item.box, FolderBox):
if (not has_children and start_box is not None
and end_box is not None and selected_item is not None
and selected_item.box.hori_name is not None):
hori_name = selected_item.box.hori_name
diff_sort = None
if selected_item.collection == Directory.COLLECTIONS[3]:
diff_sort = self.diff_sort_level
diffs = ['かんたん', 'ふつう', 'むずかしい', 'おに']
hori_name = OutlinedText(diffs[min(Difficulty.ONI, self.diff_sort_diff)], 40, ray.WHITE, outline_thickness=5)
self.genre_bg = GenreBG(start_box, end_box, hori_name, diff_sort)
def select_current_item(self):
"""Select the currently highlighted item"""
@@ -1488,15 +1479,18 @@ class FileNavigator:
side_offset_l = 200
side_offset_r = 500
position = BOX_CENTER + (base_spacing * offset)
if position == BOX_CENTER:
position = (BOX_CENTER - 150) + (base_spacing * offset)
if position == BOX_CENTER - 150:
#item.box.is_open = True
position += center_offset
elif position > BOX_CENTER:
elif position > BOX_CENTER - 150:
#item.box.is_open = False
position += side_offset_r
else:
position -= side_offset_l
#item.box.is_open = False
if item.box.position == -11111:
if item.box.position == float('inf'):
item.box.position = position
item.box.target_position = position
else:
@@ -1535,8 +1529,10 @@ class FileNavigator:
def reset_items(self):
"""Reset the items in the song select scene"""
for item in self.items:
item.box.reset()
song = self.get_current_item()
if isinstance(song.box, SongBox):
if song.box.yellow_box is not None:
song.box.yellow_box.create_anim()
def add_recent(self):
"""Add the current song to the recent list"""

View File

@@ -1,4 +1,5 @@
from enum import Enum
from typing import Callable
import pyray as ray
from libs.global_data import PlayerNum
@@ -20,8 +21,8 @@ class Nameplate:
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.name = OutlinedText(name, global_tex.skin_config["nameplate_text_name"].font_size, ray.WHITE, outline_thickness=3.0)
self.title = OutlinedText(title, global_tex.skin_config["nameplate_text_title"].font_size, ray.BLACK, outline_thickness=0)
self.dan_index = dan
self.player_num = player_num
self.is_gold = is_gold
@@ -60,7 +61,7 @@ class Nameplate:
title_offset = 0
else:
frame = self.title_bg
title_offset = 14
title_offset = tex.skin_config["nameplate_title_offset"].x
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)
@@ -75,12 +76,12 @@ class Nameplate:
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
offset = tex.skin_config["nameplate_dan_offset"].x
if self.player_num != 0:
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))
self.name.draw(outline_color=ray.BLACK, x=x+tex.skin_config["nameplate_text_name"].x - (min(tex.skin_config["nameplate_text_name"].width - offset*4, self.name.texture.width)//2) + offset, y=y+tex.skin_config["nameplate_text_name"].y, x2=min(tex.skin_config["nameplate_text_name"].width - offset*4, self.name.texture.width)-self.name.texture.width, color=ray.fade(ray.WHITE, fade))
self.title.draw(x=x+tex.skin_config["nameplate_text_title"].x - (min(tex.skin_config["nameplate_text_title"].width - offset*2, self.title.texture.width)//2) + title_offset, y=y+tex.skin_config["nameplate_text_title"].y, x2=min(tex.skin_config["nameplate_text_title"].width - offset*2, self.title.texture.width)-self.title.texture.width, color=ray.fade(ray.WHITE, fade))
class Indicator:
"""Indicator class for displaying drum navigation."""
@@ -112,10 +113,10 @@ class Indicator:
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_kat', fade=min(fade, self.don_fade.attribute), x=x+tex.skin_config["indicator_kat_offset"].x, y=y, mirror='horizontal')
tex.draw_texture('indicator', 'drum_face', x=x+tex.skin_config["indicator_face_offset"].x, 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', 'drum_don', fade=min(fade, self.don_fade.attribute), index=self.state.value, x=x+tex.skin_config["indicator_don_offset"].x, 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:
@@ -169,7 +170,7 @@ class EntryOverlay:
class Timer:
"""Timer class for displaying countdown timers."""
def __init__(self, time: int, current_time_ms: float, confirm_func):
def __init__(self, time: int, current_time_ms: float, confirm_func: Callable):
"""
Initialize a Timer object.
@@ -222,7 +223,7 @@ class Timer:
else:
tex.draw_texture('timer', 'bg')
counter_name = 'counter_black'
margin = 40
margin = tex.skin_config["timer_text_margin"].x
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)

View File

@@ -14,13 +14,17 @@ from libs.animation import BaseAnimation, parse_animations
SCREEN_WIDTH = 1280
SCREEN_HEIGHT = 720
SCREEN_SCALE = SCREEN_WIDTH / 1280
logger = logging.getLogger(__name__)
class Coordinates:
def __init__(self, x: float, y: float):
class SkinInfo:
def __init__(self, x: float, y: float, font_size: int, width: float, height: float):
self.x = x
self.y = y
self.width = width
self.height = height
self.font_size = font_size
class Texture:
"""Texture class for managing textures and animations."""
@@ -47,12 +51,12 @@ class TextureWrapper:
def __init__(self):
self.textures: dict[str, dict[str, Texture]] = dict()
self.animations: dict[int, BaseAnimation] = dict()
self.skin_config: dict[str, Coordinates] = dict()
self.skin_config: dict[str, SkinInfo] = dict()
self.graphics_path = Path("Graphics")
if (self.graphics_path / "skin_config.json").exists():
data = json.loads((self.graphics_path / "skin_config.json").read_text())
self.skin_config: dict[str, Coordinates] = {
k: Coordinates(v['x'], v['y']) for k, v in data.items()
self.skin_config: dict[str, SkinInfo] = {
k: SkinInfo(v.get('x', 0), v.get('y', 0), v.get('font_size', 0), v.get('width', 0), v.get('height', 0)) for k, v in data.items()
}
def unload_textures(self):

View File

@@ -18,7 +18,7 @@ from raylib import (
SHADER_UNIFORM_VEC4,
)
from libs.texture import TextureWrapper
from libs.texture import SCREEN_WIDTH, TextureWrapper
logger = logging.getLogger(__name__)
@@ -230,7 +230,7 @@ class OutlinedText:
"""
self.text = text
self.hash = self._hash_text(text, font_size, color, vertical)
self.outline_thickness = outline_thickness
self.outline_thickness = outline_thickness * (SCREEN_WIDTH/1280)
if self.hash in text_cache:
self.texture = ray.load_texture(f'cache/image/{self.hash}.png')
else:

View File

@@ -6,6 +6,7 @@ from moviepy import VideoFileClip
from libs.audio import audio
from libs.utils import get_current_ms
from libs.texture import SCREEN_WIDTH, SCREEN_HEIGHT
logger = logging.getLogger(__name__)
@@ -119,7 +120,7 @@ class VideoPlayer:
def draw(self):
"""Draw video frames to the raylib canvas"""
if self.texture is not None:
ray.DrawTexture(self.texture, 0, 0, ray.WHITE)
ray.DrawTexturePro(self.texture, (0, 0, self.texture.width, self.texture.height), (0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), (0, 0), 0, ray.WHITE)
def stop(self):
"""Stops the video, audio, and clears its buffer"""

View File

@@ -4,14 +4,14 @@ import pyray as ray
from libs.audio import audio
from libs.global_data import PlayerNum, global_data
from libs.texture import tex
from libs.texture import SCREEN_HEIGHT, SCREEN_WIDTH, 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 DanCourse, navigator
from libs.file_navigator import BackBox, DanCourse, navigator
from libs.transition import Transition
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
from scenes.song_select import State
logger = logging.getLogger(__name__)
@@ -35,7 +35,7 @@ class DanSelectScreen(Screen):
session_data = global_data.session_data[global_data.player_num]
current_item = self.navigator.get_current_item()
if isinstance(current_item, DanCourse):
session_data.selected_song = current_item.charts[0]
session_data.selected_song = current_item.charts[0][0].file_path
session_data.selected_dan = current_item.charts
session_data.selected_dan_exam = current_item.exams
session_data.song_title = current_item.title
@@ -88,8 +88,9 @@ class DanSelectScreen(Screen):
if self.transition.is_finished:
return self.on_screen_end("GAME_DAN")
for song in self.navigator.items:
song.box.update(False)
song.box.is_open = song.box.position == SongSelectScreen.BOX_CENTER + 150
if not song.box.text_loaded:
song.box.load_text()
song.box.update(current_time, False)
self.player.update(current_time)
res = self.handle_input(self.state, self)
if res == 'go_back':
@@ -102,13 +103,13 @@ class DanSelectScreen(Screen):
tex.draw_texture('global', 'footer')
for item in self.navigator.items:
box = item.box
if -156 <= box.position <= 1280 + 144:
if -156 <= box.position <= SCREEN_WIDTH + 144:
if box.position <= 500:
box.draw(box.position, 95, False)
else:
box.draw(box.position, 95, False)
if self.state == State.SONG_SELECTED:
ray.draw_rectangle(0, 0, 1280, 720, ray.fade(ray.BLACK, min(0.5, self.player.confirmation_window.fade_in.attribute)))
ray.draw_rectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ray.fade(ray.BLACK, min(0.5, self.player.confirmation_window.fade_in.attribute)))
self.player.draw()
self.indicator.draw(410, 575)
self.timer.draw()
@@ -169,7 +170,7 @@ class DanSelectPlayer:
# 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:
if selected_item is not None and isinstance(selected_item.box, BackBox):
audio.play_sound('cancel', 'sound')
return "go_back"
else:

View File

@@ -185,7 +185,10 @@ class DanGameScreen(GameScreen):
self.transition.update(current_time)
self.current_ms = current_time - self.start_ms
self.dan_transition.update(current_time)
self.start_song(current_time)
if self.transition.is_finished and self.dan_transition.is_finished:
self.start_song(self.current_ms)
else:
self.start_ms = current_time - self.tja.metadata.offset*1000
self.update_background(current_time)
if self.song_music is not None:

View File

@@ -104,7 +104,7 @@ class EntryScreen(Screen):
self.state = State.SELECT_SIDE
plate_info = global_data.config['nameplate_2p']
self.nameplate = Nameplate(plate_info['name'], plate_info['title'], PlayerNum.ALL, -1, False, False, 1)
self.chara = Chara2D(1, 100)
self.chara = Chara2D(1)
self.side_select_fade.restart()
self.side = 1
elif self.players[0] and self.players[0].player_num == PlayerNum.P2 and is_l_don_pressed(PlayerNum.P1) or is_r_don_pressed(PlayerNum.P1):
@@ -291,19 +291,19 @@ class EntryPlayer:
move_y = self.drum_move_1.attribute + self.drum_move_2.attribute
if self.side == 0: # Left side (1P/red)
offset = 0
offset = tex.skin_config["entry_drum_offset"].x
tex.draw_texture('side_select', 'red_drum', x=move_x, y=move_y)
chara_x = move_x + offset + 170
chara_x = move_x + offset + tex.skin_config["entry_chara_offset_l"].x
chara_mirror = False
else: # Right side (2P/blue)
move_x *= -1
offset = 620
offset = tex.skin_config["entry_drum_offset"].y # bad practice to use y value as x value
tex.draw_texture('side_select', 'blue_drum', x=move_x, y=move_y)
chara_x = move_x + offset + 130
chara_x = move_x + offset + tex.skin_config["entry_chara_offset_r"].x
chara_mirror = True
# Draw character
chara_y = 570 + move_y
chara_y = tex.skin_config["entry_chara_offset_r"].y + move_y
self.chara.draw(chara_x, chara_y, mirror=chara_mirror)
# Draw cloud
@@ -414,7 +414,7 @@ class Box:
texture_left = tex.textures['mode_select']['box_highlight_left'].texture
if isinstance(texture_left, list):
raise Exception("highlight textures cannot be iterable")
tex.draw_texture('mode_select', 'box_highlight_center', x=self.left_x + texture_left.width, y=self.y, x2=self.right_x - self.left_x -15, color=color)
tex.draw_texture('mode_select', 'box_highlight_center', x=self.left_x + texture_left.width, y=self.y, x2=self.right_x - self.left_x + tex.skin_config["entry_box_highlight_offset"].x, color=color)
tex.draw_texture('mode_select', 'box_highlight_left', x=self.left_x, y=self.y, color=color)
tex.draw_texture('mode_select', 'box_highlight_right', x=self.right_x, y=self.y, color=color)
@@ -422,7 +422,7 @@ class Box:
text_x = self.x + (self.texture.width//2) - (self.text.texture.width//2)
if self.is_selected:
text_x += self.open.attribute
text_y = self.y + 20
text_y = self.y + tex.skin_config["entry_box_text_offset"].y
if self.is_selected:
self.text.draw(outline_color=ray.BLACK, x=text_x, y=text_y, color=color)
else:
@@ -430,7 +430,7 @@ class Box:
def draw(self, fade: float):
color = ray.fade(ray.WHITE, fade)
ray.draw_texture(self.texture, self.x, self.y, color)
ray.draw_texture(self.texture, int(self.x), int(self.y), color)
if self.is_selected and self.move.is_finished:
self._draw_highlighted(color)
self._draw_text(color)
@@ -439,9 +439,9 @@ class BoxManager:
"""BoxManager class for the entry screen"""
def __init__(self):
self.box_titles: list[OutlinedText] = [
OutlinedText('演奏ゲーム', 50, ray.WHITE, outline_thickness=5, vertical=True),
OutlinedText('特訓モード', 50, ray.WHITE, outline_thickness=5, vertical=True),
OutlinedText('ゲーム設定', 50, ray.WHITE, outline_thickness=5, vertical=True)]
OutlinedText('演奏ゲーム', tex.skin_config["entry_box_text"].font_size, ray.WHITE, outline_thickness=5, vertical=True),
OutlinedText('特訓モード', tex.skin_config["entry_box_text"].font_size, ray.WHITE, outline_thickness=5, vertical=True),
OutlinedText('ゲーム設定', tex.skin_config["entry_box_text"].font_size, ray.WHITE, outline_thickness=5, vertical=True)]
self.box_locations = ["SONG_SELECT", "PRACTICE_SELECT", "SETTINGS"]
self.num_boxes = len(self.box_titles)
self.boxes = [Box(self.box_titles[i], self.box_locations[i]) for i in range(len(self.box_titles))]
@@ -449,7 +449,7 @@ class BoxManager:
self.fade_out = tex.get_animation(9)
self.is_2p = False
spacing = 80
spacing = tex.skin_config["entry_box_spacing"].x
box_width = self.boxes[0].texture.width
total_width = self.num_boxes * box_width + (self.num_boxes - 1) * spacing
start_x = SCREEN_WIDTH//2 - total_width//2

View File

@@ -7,7 +7,7 @@ from libs.animation import Animation
from libs.global_objects import AllNetIcon
from libs.screen import Screen
from libs.song_hash import build_song_hashes
from libs.texture import tex
from libs.texture import SCREEN_HEIGHT, SCREEN_WIDTH, tex
from libs.utils import get_current_ms, global_data
from libs.file_navigator import navigator
@@ -17,8 +17,8 @@ logger = logging.getLogger(__name__)
class LoadScreen(Screen):
def __init__(self, name: str):
super().__init__(name)
self.width = 1280
self.height = 720
self.width = SCREEN_WIDTH
self.height = SCREEN_HEIGHT
self.songs_loaded = False
self.navigator_started = False
self.loading_complete = False

View File

@@ -5,7 +5,7 @@ from pathlib import Path
import pyray as ray
import logging
from libs.file_navigator import DanCourse, navigator
from libs.file_navigator import BackBox, DanCourse, navigator
from libs.audio import audio
from libs.chara_2d import Chara2D
from libs.file_navigator import Directory, SongBox, SongFile
@@ -79,21 +79,23 @@ class SongSelectScreen(Screen):
self.navigator.mark_crowns_dirty_for_song(selected_song)
curr_item = self.navigator.get_current_item()
curr_item.box.get_scores()
if isinstance(curr_item, SongFile):
curr_item.box.get_scores()
self.navigator.add_recent()
def finalize_song(self):
global_data.session_data[global_data.player_num].selected_song = self.navigator.get_current_item().path
def finalize_song(self, current_item: SongFile):
global_data.session_data[global_data.player_num].selected_song = current_item.path
global_data.session_data[global_data.player_num].selected_difficulty = self.player_1.selected_difficulty
global_data.session_data[global_data.player_num].genre_index = self.navigator.get_current_item().box.name_texture_index
global_data.session_data[global_data.player_num].genre_index = current_item.box.name_texture_index
def on_screen_end(self, next_screen):
self.screen_init = False
self.reset_demo_music()
self.finalize_song()
self.player_1.nameplate.unload()
current_item = self.navigator.get_current_item()
if current_item.box.yellow_box is not None:
if isinstance(current_item, SongFile):
self.finalize_song(current_item)
self.player_1.nameplate.unload()
if isinstance(current_item.box, SongBox) and current_item.box.yellow_box is not None:
current_item.box.yellow_box.create_anim()
return super().on_screen_end(next_screen)
@@ -156,6 +158,8 @@ class SongSelectScreen(Screen):
elif action == "add_favorite":
self.navigator.add_favorite()
current_box = self.navigator.get_current_item().box
if not isinstance(current_box, SongBox):
return
current_box.is_favorite = not current_box.is_favorite
def handle_input_selected(self):
@@ -281,18 +285,19 @@ class SongSelectScreen(Screen):
audio.update_music_stream(self.demo_song)
if self.navigator.genre_bg is not None:
self.navigator.genre_bg.update(get_current_ms())
self.navigator.genre_bg.update(current_time)
if self.diff_sort_selector is not None:
self.diff_sort_selector.update(get_current_ms())
self.diff_sort_selector.update(current_time)
self.check_for_selection()
for song in self.navigator.items:
song.box.update(self.state == State.SONG_SELECTED)
song.box.is_open = song.box.position == SongSelectScreen.BOX_CENTER + 150
song.box.update(current_time, self.state == State.SONG_SELECTED)
if not song.box.text_loaded:
song.box.load_text()
if not isinstance(song, Directory) and song.box.is_open:
if self.demo_song is None and get_current_ms() >= song.box.wait + (83.33*3):
if self.demo_song is None and current_time >= song.box.wait + (83.33*3):
song.box.get_scores()
if song.tja.metadata.wave.exists() and song.tja.metadata.wave.is_file():
self.demo_song = audio.load_music_stream(song.tja.metadata.wave, 'demo_song')
@@ -302,7 +307,7 @@ class SongSelectScreen(Screen):
logger.info(f"Demo song loaded and playing for {song.tja.metadata.title}")
if song.box.is_open:
current_box = song.box
if not current_box.is_back and get_current_ms() >= song.box.wait + (83.33*3):
if not isinstance(current_box, BackBox) and current_time >= song.box.wait + (83.33*3):
self.texture_index = current_box.texture_index
if ray.is_key_pressed(global_data.config["keys"]["back_key"]):
@@ -326,7 +331,7 @@ class SongSelectScreen(Screen):
if self.navigator.genre_bg is not None and self.state == State.BROWSING:
self.navigator.genre_bg.draw(95)
for item in self.navigator.items:
for i, item in enumerate(self.navigator.items):
box = item.box
if -156 <= box.position <= SCREEN_WIDTH + 144:
if box.position <= 500:
@@ -354,7 +359,9 @@ class SongSelectScreen(Screen):
self.draw_players()
if self.state == State.BROWSING and self.navigator.items != []:
self.navigator.get_current_item().box.draw_score_history()
curr_item = self.navigator.get_current_item()
if isinstance(curr_item, SongFile):
curr_item.box.draw_score_history()
self.indicator.draw(410, 575)
@@ -461,7 +468,7 @@ class SongSelectPlayer:
# 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:
if selected_item is not None and isinstance(selected_item.box, BackBox):
audio.play_sound('cancel', 'sound')
return "go_back"
elif isinstance(selected_item, Directory) and selected_item.collection == Directory.COLLECTIONS[3]:

View File

@@ -1,5 +1,5 @@
import logging
from libs.file_navigator import SongFile
from libs.file_navigator import SongBox, SongFile
from libs.global_data import PlayerNum
from libs.transition import Transition
from scenes.song_select import DiffSortSelect, SongSelectPlayer, SongSelectScreen, State
@@ -14,9 +14,9 @@ class TwoPlayerSongSelectScreen(SongSelectScreen):
self.player_1 = SongSelectPlayer(PlayerNum.P1, self.text_fade_in)
self.player_2 = SongSelectPlayer(PlayerNum.P2, self.text_fade_in)
def finalize_song(self):
global_data.session_data[PlayerNum.P1].selected_song = self.navigator.get_current_item().path
global_data.session_data[PlayerNum.P1].genre_index = self.navigator.get_current_item().box.name_texture_index
def finalize_song(self, current_item):
global_data.session_data[PlayerNum.P1].selected_song = current_item.path
global_data.session_data[PlayerNum.P1].genre_index = current_item.box.name_texture_index
logger.info(f"Finalized song selection: {global_data.session_data[PlayerNum.P1].selected_song}")
def handle_input(self):
@@ -81,6 +81,8 @@ class TwoPlayerSongSelectScreen(SongSelectScreen):
elif action == "add_favorite":
self.navigator.add_favorite()
current_box = self.navigator.get_current_item().box
if not isinstance(current_box, SongBox):
return
current_box.is_favorite = not current_box.is_favorite
def handle_input_selected(self):