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 dev-config.toml
libaudio.so libaudio.so
latest.log latest.log
Graphics1080

View File

@@ -1,86 +1,86 @@
Command/Header,Support Status,Initial Sim Release Command/Header,Support Status,Initial Sim Release
TITLE,Supported,TaikoJiro v0.80 (initial release) TITLE,Supported,TaikoJiro v0.80 (initial release)
SUBTITLE,Supported,TaikoJiro v2.64
WAVE,Supported,TaikoJiro v0.80 (initial release) WAVE,Supported,TaikoJiro v0.80 (initial release)
DEMOSTART,Supported,TaikoJiro v2.37
OFFSET,Supported,TaikoJiro v0.80 (initial release) OFFSET,Supported,TaikoJiro v0.80 (initial release)
BPM,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) LEVEL,Supported,TaikoJiro v0.80 (initial release)
BALLOON,Supported,TaikoJiro 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) #START / #END,Supported,TaikoJiro v0.80 (initial release)
#BPMCHANGE,Supported,TaikoJiro v0.80 (initial release) #BPMCHANGE,Supported,TaikoJiro v0.80 (initial release)
#MEASURE,Supported,TaikoJiro #MEASURE,Supported,TaikoJiro
#GOGOSTART / #GOGOEND,Supported,TaikoJiro #GOGOSTART / #GOGOEND,Supported,TaikoJiro
#SCROLL,Supported,TaikoJiro #SCROLL,Supported,TaikoJiro
#BARLINEOFF / #BARLINEON,Supported,TaikoJiro v2.69 #DELAY,Supported,TaikoJiro v1.60
#LYRIC,Supported,TJAPlayer2 for.PC
#SECTION,Supported,TaikoJiro v1.63 #SECTION,Supported,TaikoJiro v1.63
#BRANCHSTART / #BRANCHEND,Supported,TaikoJiro v1.63 #BRANCHSTART / #BRANCHEND,Supported,TaikoJiro v1.63
#N / #E / #M,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 #SUDDEN,Supported,TJAPlayer2 for.PC
#JPOSSCROLL,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 SONGVOL,Unsupported,TaikoJiro v1.66
SEVOL,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 HEADSCROLL,Unsupported,TJAPlayer2 for.PC
PREIMAGE,Unsupported,OpenTaiko (0auBSQ) v0.5.4 MOVIEOFFSET,Unsupported,TJAPlayer2 for.PC ver.2015081100
COVER,Unsupported,Malody 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 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 TOWERTYPE,Unsupported,OpenTaiko (0auBSQ) v0.5.0
DANTICK,Unsupported,OpenTaiko (0auBSQ) v0.5.1 DANTICK,Unsupported,OpenTaiko (0auBSQ) v0.5.1
DANTICKCOLOR,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 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 EXPLICIT,Unsupported,OpenTaiko (0auBSQ) v0.6.0
GAME,Unsupported,TaikoJiro v2.13 BGA Headers,Unsupported,C-Taiko
STYLE,Unsupported,TaikoJiro v1.99 ARTIST,Unsupported,Malody
LIFE,Unsupported,TaikoJiro v2.19 COVER,Unsupported,Malody
TOTAL,Unsupported,TaikoJiro v2.92 & TaikoJiro 2 v0.93 AUTHOR,Unsupported,Malody
GAUGEINCR,Unsupported,TJAPlayer3 v1.5.4 BGOFFSET,Unsupported,Unknown
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
#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 #LEVELHOLD,Unsupported,TaikoJiro v1.63
#NEXTSONG,Unsupported,TJAPlayer3 v1.5.0 #BMSCROLL / #HBSCROLL / #NMSCROLL,Unsupported,TaikoJiro v1.91
#GAMETYPE,Unsupported,OpenTaiko (0auBSQ) v0.6.0 #DIRECTION,Unsupported,TJAPlayer2 for.PC
#HIDDEN,Unsupported,TJAPlayer2 for.PC #HIDDEN,Unsupported,TJAPlayer2 for.PC
NOTE / BARLINE,Unsupported,TaikoManyGimmicks #SENOTECHANGE,Unsupported,TJAPlayer3 v1.4.0
#GRADATION,Unsupported,TaikoManyGimmicks v0.6α #NEXTSONG,Unsupported,TJAPlayer3 v1.5.0
#INCLUDE,Unsupported,TaikoManyGimmicks v0.6.1α #PAPAMAMA,Unsupported,TJAPlayer3-f v1.7.2.0
#SPLITLANE / #MERGELANE,Unsupported,OpenTaiko (0auBSQ) v0.6.0 #ENABLEDORON / #DISABLEDORON,Unsupported,TJAPlayer3-Extended
#OBJ / #CAM,Unsupported,TJAPlayer3-Extended #OBJ / #CAM,Unsupported,TJAPlayer3-Extended
#BORDERCOLOR,Unsupported,TJAPlayer3-Extended #BORDERCOLOR,Unsupported,TJAPlayer3-Extended
#CHANGETEXTURE / #RESETTEXTURE,Unsupported,TJAPlayer3-Extended #CHANGETEXTURE / #RESETTEXTURE,Unsupported,TJAPlayer3-Extended
#SETCONFIG,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 #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; struct audio_buffer *audio_buffer = AUDIO.Buffer.first;
int active_buffers = 0;
while (audio_buffer != NULL) { while (audio_buffer != NULL) {
if (audio_buffer->playing && !audio_buffer->paused && audio_buffer->data != NULL) { if (audio_buffer->playing && !audio_buffer->paused && audio_buffer->data != NULL) {
active_buffers++;
unsigned int subBufferSizeFrames = audio_buffer->sizeInFrames / 2; unsigned int subBufferSizeFrames = audio_buffer->sizeInFrames / 2;
unsigned long framesToMix = framesPerBuffer; unsigned long framesToMix = framesPerBuffer;
float *buffer_data = (float *)audio_buffer->data; 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.animation import Animation, MoveAnimation
from libs.global_data import Crown, Difficulty from libs.global_data import Crown, Difficulty
from libs.tja import TJAParser, test_encodings 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 libs.utils import OutlinedText, get_current_ms, global_data
from datetime import datetime, timedelta from datetime import datetime, timedelta
import sqlite3 import sqlite3
import pyray as ray import pyray as ray
BOX_CENTER = 444 BOX_CENTER = 594 * SCREEN_SCALE
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class SongBox: class BaseBox():
"""A box for the song select screen."""
OUTLINE_MAP = { OUTLINE_MAP = {
1: ray.Color(0, 77, 104, 255), 1: ray.Color(0, 77, 104, 255),
2: ray.Color(156, 64, 2, 255), 2: ray.Color(156, 64, 2, 255),
@@ -38,61 +37,118 @@ class SongBox:
} }
BACK_INDEX = 17 BACK_INDEX = 17
DEFAULT_INDEX = 9 DEFAULT_INDEX = 9
def __init__(self, name: str, texture_index: int, is_dir: bool, tja: Optional[TJAParser] = None, """Base class for all box types in the song select screen."""
tja_count: Optional[int] = None, box_texture: Optional[str] = None, name_texture_index: Optional[int] = None): def __init__(self, name: str, texture_index: int):
self.text_name = name self.text_name = name
self.texture_index = texture_index 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: if name_texture_index is None:
self.name_texture_index = texture_index self.name_texture_index = texture_index
else: else:
self.name_texture_index = name_texture_index self.name_texture_index = name_texture_index
self.box_texture_path = box_texture
self.box_texture = None
self.scores = dict() self.scores = dict()
self.crown = dict() self.hash = 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.score_history = None self.score_history = None
self.history_wait = 0 self.history_wait = 0
self.tja = tja self.tja = tja
self.hash = dict()
self.is_favorite = False self.is_favorite = False
self.yellow_box = None
def reset(self): def load_text(self):
if self.yellow_box is not None: super().load_text()
self.yellow_box.reset() self.text_loaded = True
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 get_scores(self): def get_scores(self):
if self.tja is None:
return
with sqlite3.connect('scores.db') as con: with sqlite3.connect('scores.db') as con:
cursor = con.cursor() cursor = con.cursor()
# Batch database query for all diffs at once # Batch database query for all diffs at once
@@ -116,37 +172,12 @@ class SongBox:
self.scores[diff] = hash_to_score.get(diff_hash) self.scores[diff] = hash_to_score.get(diff_hash)
self.score_history = None self.score_history = None
def move_box(self): def update(self, current_time: float, is_diff_select: bool):
if self.position != self.target_position and self.move is None: super().update(current_time, is_diff_select)
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
is_open_prev = self.is_open is_open_prev = self.is_open
self.move_box() self.move_box(current_time)
self.is_open = self.position == BOX_CENTER + 150 self.is_open = self.position == BOX_CENTER
if not (-56 <= self.position <= 1280):
return
if self.yellow_box is not None: if self.yellow_box is not None:
self.yellow_box.update(is_diff_select) self.yellow_box.update(is_diff_select)
@@ -157,54 +188,21 @@ class SongBox:
self.score_history = ScoreHistory(self.scores, current_time) 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: self.yellow_box = YellowBox(False, tja=self.tja)
self.yellow_box = YellowBox(self.name, self.is_back, tja=self.tja)
self.yellow_box.create_anim() 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.wait = current_time self.wait = current_time
if current_time >= self.history_wait + 3000: if current_time >= self.history_wait + 3000:
self.history_wait = current_time 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: if self.score_history is not None:
self.score_history.update(current_time) 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)
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) 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) 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} valid_scores = {k: v for k, v in self.scores.items() if v is not None}
if valid_scores: 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)) tex.draw_texture('yellow_box', 'crown_fc', x=x, y=y, frame=min(Difficulty.URA, highest_key))
elif score and score[5] >= Crown.CLEAR: elif score and score[5] >= Crown.CLEAR:
tex.draw_texture('yellow_box', 'crown_clear', x=x, y=y, frame=min(Difficulty.URA, highest_key)) 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 if self.crown: #Folder lamp
highest_crown = max(self.crown) highest_crown = max(self.crown)
if self.crown[highest_crown] == 'DFC': if self.crown[highest_crown] == 'DFC':
@@ -225,11 +275,11 @@ class SongBox:
else: else:
tex.draw_texture('yellow_box', 'crown_clear', x=x, y=y, frame=min(Difficulty.URA, highest_crown)) 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 color = ray.WHITE
if fade_override is not None: if fade_override is not None:
color = ray.fade(ray.WHITE, fade_override) 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_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', 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) 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 color = ray.WHITE
if fade_override is not None: if fade_override is not None:
color = ray.fade(ray.WHITE, fade_override) 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_back', color=color, fade=0.5)
tex.draw_texture('yellow_box', 'song_count_num', color=color) tex.draw_texture('yellow_box', 'song_count_num', color=color)
tex.draw_texture('yellow_box', 'song_count_songs', color=color) tex.draw_texture('yellow_box', 'song_count_songs', color=color)
dest_width = min(124, self.tja_count_text.texture.width) 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) 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_graphic', color=color, frame=self.texture_index)
tex.draw_texture('box', 'folder_text', 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: 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) ray.draw_texture(self.box_texture, int((x+48) - (self.box_texture.width//2)), int((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)
class YellowBox: class YellowBox:
"""A song box when it is opened.""" """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.is_diff_select = False
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
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'], '')
font_size = 30 if len(subtitle_text) < 30 else 20 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.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.left_out = tex.get_animation(9)
self.right_out = tex.get_animation(10) 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.bottom_y = tex.textures['yellow_box']['yellow_box_bottom_right'].y[0]
self.edge_height = tex.textures['yellow_box']['yellow_box_bottom_right'].height 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): def create_anim(self):
self.right_out_2.reset() self.right_out_2.reset()
self.top_y_out.reset() self.top_y_out.reset()
@@ -368,8 +398,8 @@ class YellowBox:
self.center_height = self.center_h_out.attribute self.center_height = self.center_h_out.attribute
self.is_diff_select = is_diff_select self.is_diff_select = is_diff_select
def _draw_tja_data(self, song_box, color, fade): def _draw_tja_data(self, song_box: SongBox, color: ray.Color, fade: float):
if self.tja is None: if not self.tja:
return return
for diff in self.tja.metadata.course_data: for diff in self.tja.metadata.course_data:
if diff >= Difficulty.URA: 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: 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) 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): def _draw_tja_data_diff(self, is_ura: bool, song_box: SongBox):
if self.tja is None: if not self.tja:
return return
tex.draw_texture('diff_select', 'back', fade=self.fade_in.attribute) 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', 'option', fade=self.fade_in.attribute)
tex.draw_texture('diff_select', 'neiro', fade=self.fade_in.attribute) tex.draw_texture('diff_select', 'neiro', fade=self.fade_in.attribute)
for diff in self.tja.metadata.course_data: for diff in self.tja.metadata.course_data:
if song_box is None:
continue
if diff >= Difficulty.URA: if diff >= Difficulty.URA:
continue 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)): 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' name = 'branch_indicator_diff'
tex.draw_texture('yellow_box', name, x=min(course, Difficulty.ONI)*115, fade=self.fade_in.attribute) 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): if not isinstance(self.right_out, MoveAnimation):
return return
if not isinstance(self.right_out_2, MoveAnimation): 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 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: if self.is_back:
tex.draw_texture('box', 'back_text_highlight', x=x) tex.draw_texture('box', 'back_text_highlight', x=x)
elif self.name is not None: else:
texture = self.name.texture texture = 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) 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: if self.subtitle is not None:
texture = self.subtitle.texture texture = self.subtitle.texture
y = self.bottom_y - min(texture.height, 410) + 10 + self.top_y_out.attribute - self.top_y_out.start_position 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_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) 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() self._draw_yellow_box()
if self.is_dan:
return
if self.is_diff_select and self.tja is not None:
self._draw_tja_data_diff(is_ura, song_box)
else:
fade = self.fade.attribute fade = self.fade.attribute
if fade_override is not None: if fade_override is not None:
fade = min(self.fade.attribute, fade_override) fade = min(self.fade.attribute, fade_override)
if self.is_dan:
return
if self.is_back: if self.is_back:
tex.draw_texture('box', 'back_graphic', fade=fade) 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)
elif isinstance(song_box, SongBox):
self._draw_tja_data(song_box, ray.fade(ray.WHITE, fade), fade) 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: class DanBox(BaseBox):
def __init__(self, title: str, color: int, songs: list[tuple[TJAParser, int, int, int]], exams: list['Exam']): def __init__(self, name, color: int, songs: list[tuple[TJAParser, int, int, int]], exams: list['Exam']):
self.position = -11111 super().__init__(name, color)
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.songs = songs
self.exams = exams self.exams = exams
self.song_text: list[tuple[OutlinedText, OutlinedText]] = [] self.song_text: list[tuple[OutlinedText, OutlinedText]] = []
self.total_notes = 0 self.total_notes = 0
self.yellow_box = None
for song, genre_index, difficulty, level in self.songs: for song, genre_index, difficulty, level in self.songs:
notes, branch_m, branch_e, branch_n = song.notes_to_position(difficulty) 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) self.total_notes += sum(1 for note in notes.play_notes if note.type < 5)
@@ -515,42 +538,10 @@ class DanBox:
self.total_notes += sum(1 for note in branch.play_notes if note.type < 5) self.total_notes += sum(1 for note in branch.play_notes if note.type < 5)
for branch in branch_n: for branch in branch_n:
self.total_notes += sum(1 for note in branch.play_notes if note.type < 5) 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): def load_text(self):
if self.position != self.target_position and self.move is None: super().load_text()
if self.position < self.target_position: self.hori_name = OutlinedText(self.text_name, 40, ray.WHITE)
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 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: for song, genre, difficulty, level in self.songs:
title = song.metadata.title.get(global_data.config["general"]["language"], song.metadata.title["en"]) title = song.metadata.title.get(global_data.config["general"]["language"], song.metadata.title["en"])
subtitle = song.metadata.subtitle.get(global_data.config["general"]["language"], "") subtitle = song.metadata.subtitle.get(global_data.config["general"]["language"], "")
@@ -558,14 +549,15 @@ class DanBox:
font_size = 30 if len(subtitle) < 30 else 20 font_size = 30 if len(subtitle) < 30 else 20
subtitle_text = OutlinedText(subtitle, font_size, ray.WHITE, vertical=True) subtitle_text = OutlinedText(subtitle, font_size, ray.WHITE, vertical=True)
self.song_text.append((title_text, subtitle_text)) self.song_text.append((title_text, subtitle_text))
self.text_loaded = True
def update(self, is_diff_select: bool): def update(self, current_time: float, is_diff_select: bool):
self.move_box() super().update(current_time, is_diff_select)
self.get_text()
is_open_prev = self.is_open 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: 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() self.yellow_box.create_anim()
if self.yellow_box is not None: if self.yellow_box is not None:
@@ -601,51 +593,49 @@ class DanBox:
elif self.exams[i].range == 'less': elif self.exams[i].range == 'less':
tex.draw_texture('yellow_box', 'exam_less', x=(offset*-1.7), y=(i*83)) tex.draw_texture('yellow_box', 'exam_less', x=(offset*-1.7), y=(i*83))
def _draw_closed(self, x: int, y: int): def _draw_closed(self, x: float, y: float):
tex.draw_texture('box', 'folder', frame=self.color, x=x) tex.draw_texture('box', 'folder', frame=self.texture_index, x=x)
if self.name is not None: 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) 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: 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): for i, song in enumerate(self.song_text):
title, subtitle = song title, subtitle = song
x = i * 140 x = i * 140
tex.draw_texture('yellow_box', 'genre_banner', x=x, frame=self.songs[i][1]) 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]) tex.draw_texture('yellow_box', 'difficulty', x=x, frame=self.songs[i][2], fade=fade)
tex.draw_texture('yellow_box', 'difficulty_x', x=x) tex.draw_texture('yellow_box', 'difficulty_x', x=x, fade=fade)
tex.draw_texture('yellow_box', 'difficulty_star', x=x) tex.draw_texture('yellow_box', 'difficulty_star', x=x, fade=fade)
level = self.songs[i][0].metadata.course_data[self.songs[i][2]].level level = self.songs[i][0].metadata.course_data[self.songs[i][2]].level
counter = str(level) counter = str(level)
total_width = len(counter) * 10 total_width = len(counter) * 10
for i in range(len(counter)): 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) 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) 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_bg', fade=fade)
tex.draw_texture('yellow_box', 'total_notes') tex.draw_texture('yellow_box', 'total_notes', fade=fade)
counter = str(self.total_notes) counter = str(self.total_notes)
for i in range(len(counter)): 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: 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() 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: 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: BaseBox, end_box: BaseBox, title: OutlinedText, diff_sort: Optional[int]):
self.start_box = start_box self.start_box = start_box
self.end_box = end_box self.end_box = end_box
self.start_position = start_box.position 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) 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: 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) 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: class ScoreHistory:
"""The score information that appears while hovering over a song""" """The score information that appears while hovering over a song"""
@@ -872,7 +862,10 @@ class Directory(FileSystemItem):
elif self.to_root or self.back: elif self.to_root or self.back:
texture_index = SongBox.BACK_INDEX 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): class SongFile(FileSystemItem):
"""Represents a song file (TJA) in the navigation system""" """Represents a song file (TJA) in the navigation system"""
@@ -884,7 +877,7 @@ class SongFile(FileSystemItem):
self.tja.ex_data.new = True self.tja.ex_data.new = True
title = self.tja.metadata.title.get(global_data.config['general']['language'].lower(), self.tja.metadata.title['en']) 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.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.hash = global_data.song_hashes[self.hash][0]["diff_hashes"]
self.box.get_scores() self.box.get_scores()
@@ -904,7 +897,7 @@ class DanCourse(FileSystemItem):
data = json.load(f) data = json.load(f)
self.title = data["title"] self.title = data["title"]
self.color = data["color"] self.color = data["color"]
self.charts = [] self.charts: list[tuple[TJAParser, int, int, int]] = []
for chart in data["charts"]: for chart in data["charts"]:
hash = chart["hash"] hash = chart["hash"]
#chart_title = chart["title"] #chart_title = chart["title"]
@@ -1203,7 +1196,7 @@ class FileNavigator:
if self.recent_folder is None: if self.recent_folder is None:
raise Exception("tried to enter recent folder without recents") raise Exception("tried to enter recent folder without recents")
self._generate_objects_recursive(self.recent_folder.path) self._generate_objects_recursive(self.recent_folder.path)
selected_item.box.tja_count_text = None if not isinstance(selected_item.box, BackBox):
selected_item.box.tja_count = self._count_tja_files(self.recent_folder.path) selected_item.box.tja_count = self._count_tja_files(self.recent_folder.path)
content_items = self.directory_contents[dir_key] content_items = self.directory_contents[dir_key]
elif selected_item.collection == Directory.COLLECTIONS[2]: elif selected_item.collection == Directory.COLLECTIONS[2]:
@@ -1212,7 +1205,7 @@ class FileNavigator:
self._generate_objects_recursive(self.favorite_folder.path) self._generate_objects_recursive(self.favorite_folder.path)
tja_files = self._get_tja_files_for_directory(self.favorite_folder.path) tja_files = self._get_tja_files_for_directory(self.favorite_folder.path)
self._calculate_directory_crowns(dir_key, tja_files) self._calculate_directory_crowns(dir_key, tja_files)
selected_item.box.tja_count_text = None if not isinstance(selected_item.box, BackBox):
selected_item.box.tja_count = self._count_tja_files(self.favorite_folder.path) selected_item.box.tja_count = self._count_tja_files(self.favorite_folder.path)
content_items = self.directory_contents[dir_key] content_items = self.directory_contents[dir_key]
self.in_favorites = True self.in_favorites = True
@@ -1245,7 +1238,7 @@ class FileNavigator:
return return
i = 1 i = 1
for item in content_items: for item in content_items:
if isinstance(item, SongFile): if isinstance(item, SongFile) and not has_children:
if i % 10 == 0 and i != 0: if i % 10 == 0 and i != 0:
back_dir = Directory(self.current_dir.parent, "", SongBox.BACK_INDEX, back=True) back_dir = Directory(self.current_dir.parent, "", SongBox.BACK_INDEX, back=True)
self.items.insert(self.selected_index+i, back_dir) self.items.insert(self.selected_index+i, back_dir)
@@ -1268,14 +1261,12 @@ class FileNavigator:
for item in self.items: for item in self.items:
if isinstance(item, Directory): if isinstance(item, Directory):
item_key = str(item.path) 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) item.box.crown = self._get_directory_crowns_cached(item_key)
else:
# Navigation items (back/to_root)
item.box.crown = dict()
self.calculate_box_positions() self.calculate_box_positions()
if selected_item and isinstance(selected_item.box, FolderBox):
if (not has_children and start_box is not None if (not has_children and start_box is not None
and end_box is not None and selected_item is not None and end_box is not None and selected_item is not None
and selected_item.box.hori_name is not None): and selected_item.box.hori_name is not None):
@@ -1488,15 +1479,18 @@ class FileNavigator:
side_offset_l = 200 side_offset_l = 200
side_offset_r = 500 side_offset_r = 500
position = BOX_CENTER + (base_spacing * offset) position = (BOX_CENTER - 150) + (base_spacing * offset)
if position == BOX_CENTER: if position == BOX_CENTER - 150:
#item.box.is_open = True
position += center_offset position += center_offset
elif position > BOX_CENTER: elif position > BOX_CENTER - 150:
#item.box.is_open = False
position += side_offset_r position += side_offset_r
else: else:
position -= side_offset_l 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.position = position
item.box.target_position = position item.box.target_position = position
else: else:
@@ -1535,8 +1529,10 @@ class FileNavigator:
def reset_items(self): def reset_items(self):
"""Reset the items in the song select scene""" """Reset the items in the song select scene"""
for item in self.items: song = self.get_current_item()
item.box.reset() if isinstance(song.box, SongBox):
if song.box.yellow_box is not None:
song.box.yellow_box.create_anim()
def add_recent(self): def add_recent(self):
"""Add the current song to the recent list""" """Add the current song to the recent list"""

View File

@@ -1,4 +1,5 @@
from enum import Enum from enum import Enum
from typing import Callable
import pyray as ray import pyray as ray
from libs.global_data import PlayerNum from libs.global_data import PlayerNum
@@ -20,8 +21,8 @@ class Nameplate:
is_rainbow (bool): Whether the player's nameplate background is rainbow. is_rainbow (bool): Whether the player's nameplate background is rainbow.
title_bg (int): The player's non-rainbow nameplate background. title_bg (int): The player's non-rainbow nameplate background.
""" """
self.name = OutlinedText(name, 22, ray.WHITE, outline_thickness=3.0) self.name = OutlinedText(name, global_tex.skin_config["nameplate_text_name"].font_size, ray.WHITE, outline_thickness=3.0)
self.title = OutlinedText(title, 20, ray.BLACK, outline_thickness=0) self.title = OutlinedText(title, global_tex.skin_config["nameplate_text_title"].font_size, ray.BLACK, outline_thickness=0)
self.dan_index = dan self.dan_index = dan
self.player_num = player_num self.player_num = player_num
self.is_gold = is_gold self.is_gold = is_gold
@@ -60,7 +61,7 @@ class Nameplate:
title_offset = 0 title_offset = 0
else: else:
frame = self.title_bg frame = self.title_bg
title_offset = 14 title_offset = tex.skin_config["nameplate_title_offset"].x
if self.is_rainbow: if self.is_rainbow:
if 0 < self.rainbow_animation.attribute < 6: if 0 < self.rainbow_animation.attribute < 6:
tex.draw_texture('nameplate', 'frame_top_rainbow', frame=self.rainbow_animation.attribute-1, x=x, y=y, fade=fade) tex.draw_texture('nameplate', 'frame_top_rainbow', frame=self.rainbow_animation.attribute-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) tex.draw_texture('nameplate', 'dan_emblem_gold', x=x, y=y, frame=self.dan_index, fade=fade)
else: else:
tex.draw_texture('nameplate', 'dan_emblem', x=x, y=y, frame=self.dan_index, fade=fade) 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: if self.player_num != 0:
tex.draw_texture('nameplate', f'{self.player_num}p', x=x, y=y, fade=fade) 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.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+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.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: class Indicator:
"""Indicator class for displaying drum navigation.""" """Indicator class for displaying drum navigation."""
@@ -112,10 +113,10 @@ class Indicator:
if self.state == Indicator.State.SELECT: 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, 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_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+175, y=y, fade=fade) 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', 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)) 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: else:
@@ -169,7 +170,7 @@ class EntryOverlay:
class Timer: class Timer:
"""Timer class for displaying countdown timers.""" """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. Initialize a Timer object.
@@ -222,7 +223,7 @@ class Timer:
else: else:
tex.draw_texture('timer', 'bg') tex.draw_texture('timer', 'bg')
counter_name = 'counter_black' counter_name = 'counter_black'
margin = 40 margin = tex.skin_config["timer_text_margin"].x
total_width = len(self.counter) * margin total_width = len(self.counter) * margin
for i, digit in enumerate(self.counter): 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) 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_WIDTH = 1280
SCREEN_HEIGHT = 720 SCREEN_HEIGHT = 720
SCREEN_SCALE = SCREEN_WIDTH / 1280
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class Coordinates: class SkinInfo:
def __init__(self, x: float, y: float): def __init__(self, x: float, y: float, font_size: int, width: float, height: float):
self.x = x self.x = x
self.y = y self.y = y
self.width = width
self.height = height
self.font_size = font_size
class Texture: class Texture:
"""Texture class for managing textures and animations.""" """Texture class for managing textures and animations."""
@@ -47,12 +51,12 @@ class TextureWrapper:
def __init__(self): def __init__(self):
self.textures: dict[str, dict[str, Texture]] = dict() self.textures: dict[str, dict[str, Texture]] = dict()
self.animations: dict[int, BaseAnimation] = 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") self.graphics_path = Path("Graphics")
if (self.graphics_path / "skin_config.json").exists(): if (self.graphics_path / "skin_config.json").exists():
data = json.loads((self.graphics_path / "skin_config.json").read_text()) data = json.loads((self.graphics_path / "skin_config.json").read_text())
self.skin_config: dict[str, Coordinates] = { self.skin_config: dict[str, SkinInfo] = {
k: Coordinates(v['x'], v['y']) for k, v in data.items() 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): def unload_textures(self):

View File

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

View File

@@ -6,6 +6,7 @@ from moviepy import VideoFileClip
from libs.audio import audio from libs.audio import audio
from libs.utils import get_current_ms from libs.utils import get_current_ms
from libs.texture import SCREEN_WIDTH, SCREEN_HEIGHT
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -119,7 +120,7 @@ class VideoPlayer:
def draw(self): def draw(self):
"""Draw video frames to the raylib canvas""" """Draw video frames to the raylib canvas"""
if self.texture is not None: 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): def stop(self):
"""Stops the video, audio, and clears its buffer""" """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.audio import audio
from libs.global_data import PlayerNum, global_data 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.chara_2d import Chara2D
from libs.global_objects import AllNetIcon, CoinOverlay, Indicator, Nameplate, Timer from libs.global_objects import AllNetIcon, CoinOverlay, Indicator, Nameplate, Timer
from libs.screen import Screen 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.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 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__) logger = logging.getLogger(__name__)
@@ -35,7 +35,7 @@ class DanSelectScreen(Screen):
session_data = global_data.session_data[global_data.player_num] session_data = global_data.session_data[global_data.player_num]
current_item = self.navigator.get_current_item() current_item = self.navigator.get_current_item()
if isinstance(current_item, DanCourse): 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 = current_item.charts
session_data.selected_dan_exam = current_item.exams session_data.selected_dan_exam = current_item.exams
session_data.song_title = current_item.title session_data.song_title = current_item.title
@@ -88,8 +88,9 @@ class DanSelectScreen(Screen):
if self.transition.is_finished: if self.transition.is_finished:
return self.on_screen_end("GAME_DAN") return self.on_screen_end("GAME_DAN")
for song in self.navigator.items: for song in self.navigator.items:
song.box.update(False) if not song.box.text_loaded:
song.box.is_open = song.box.position == SongSelectScreen.BOX_CENTER + 150 song.box.load_text()
song.box.update(current_time, False)
self.player.update(current_time) self.player.update(current_time)
res = self.handle_input(self.state, self) res = self.handle_input(self.state, self)
if res == 'go_back': if res == 'go_back':
@@ -102,13 +103,13 @@ class DanSelectScreen(Screen):
tex.draw_texture('global', 'footer') tex.draw_texture('global', 'footer')
for item in self.navigator.items: for item in self.navigator.items:
box = item.box box = item.box
if -156 <= box.position <= 1280 + 144: if -156 <= box.position <= SCREEN_WIDTH + 144:
if box.position <= 500: if box.position <= 500:
box.draw(box.position, 95, False) box.draw(box.position, 95, False)
else: else:
box.draw(box.position, 95, False) box.draw(box.position, 95, False)
if self.state == State.SONG_SELECTED: 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.player.draw()
self.indicator.draw(410, 575) self.indicator.draw(410, 575)
self.timer.draw() self.timer.draw()
@@ -169,7 +170,7 @@ class DanSelectPlayer:
# Select/Enter # Select/Enter
if is_l_don_pressed(self.player_num) or is_r_don_pressed(self.player_num): 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') audio.play_sound('cancel', 'sound')
return "go_back" return "go_back"
else: else:

View File

@@ -185,7 +185,10 @@ class DanGameScreen(GameScreen):
self.transition.update(current_time) self.transition.update(current_time)
self.current_ms = current_time - self.start_ms self.current_ms = current_time - self.start_ms
self.dan_transition.update(current_time) 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) self.update_background(current_time)
if self.song_music is not None: if self.song_music is not None:

View File

@@ -104,7 +104,7 @@ class EntryScreen(Screen):
self.state = State.SELECT_SIDE self.state = State.SELECT_SIDE
plate_info = global_data.config['nameplate_2p'] plate_info = global_data.config['nameplate_2p']
self.nameplate = Nameplate(plate_info['name'], plate_info['title'], PlayerNum.ALL, -1, False, False, 1) 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_select_fade.restart()
self.side = 1 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): 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 move_y = self.drum_move_1.attribute + self.drum_move_2.attribute
if self.side == 0: # Left side (1P/red) 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) 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 chara_mirror = False
else: # Right side (2P/blue) else: # Right side (2P/blue)
move_x *= -1 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) 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 chara_mirror = True
# Draw character # 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) self.chara.draw(chara_x, chara_y, mirror=chara_mirror)
# Draw cloud # Draw cloud
@@ -414,7 +414,7 @@ class Box:
texture_left = tex.textures['mode_select']['box_highlight_left'].texture texture_left = tex.textures['mode_select']['box_highlight_left'].texture
if isinstance(texture_left, list): if isinstance(texture_left, list):
raise Exception("highlight textures cannot be iterable") 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_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) 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) text_x = self.x + (self.texture.width//2) - (self.text.texture.width//2)
if self.is_selected: if self.is_selected:
text_x += self.open.attribute 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: if self.is_selected:
self.text.draw(outline_color=ray.BLACK, x=text_x, y=text_y, color=color) self.text.draw(outline_color=ray.BLACK, x=text_x, y=text_y, color=color)
else: else:
@@ -430,7 +430,7 @@ class Box:
def draw(self, fade: float): def draw(self, fade: float):
color = ray.fade(ray.WHITE, fade) 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: if self.is_selected and self.move.is_finished:
self._draw_highlighted(color) self._draw_highlighted(color)
self._draw_text(color) self._draw_text(color)
@@ -439,9 +439,9 @@ class BoxManager:
"""BoxManager class for the entry screen""" """BoxManager class for the entry screen"""
def __init__(self): def __init__(self):
self.box_titles: list[OutlinedText] = [ self.box_titles: list[OutlinedText] = [
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('特訓モード', 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('ゲーム設定', 50, 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.box_locations = ["SONG_SELECT", "PRACTICE_SELECT", "SETTINGS"]
self.num_boxes = len(self.box_titles) 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))] 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.fade_out = tex.get_animation(9)
self.is_2p = False self.is_2p = False
spacing = 80 spacing = tex.skin_config["entry_box_spacing"].x
box_width = self.boxes[0].texture.width box_width = self.boxes[0].texture.width
total_width = self.num_boxes * box_width + (self.num_boxes - 1) * spacing total_width = self.num_boxes * box_width + (self.num_boxes - 1) * spacing
start_x = SCREEN_WIDTH//2 - total_width//2 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.global_objects import AllNetIcon
from libs.screen import Screen from libs.screen import Screen
from libs.song_hash import build_song_hashes 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.utils import get_current_ms, global_data
from libs.file_navigator import navigator from libs.file_navigator import navigator
@@ -17,8 +17,8 @@ logger = logging.getLogger(__name__)
class LoadScreen(Screen): class LoadScreen(Screen):
def __init__(self, name: str): def __init__(self, name: str):
super().__init__(name) super().__init__(name)
self.width = 1280 self.width = SCREEN_WIDTH
self.height = 720 self.height = SCREEN_HEIGHT
self.songs_loaded = False self.songs_loaded = False
self.navigator_started = False self.navigator_started = False
self.loading_complete = False self.loading_complete = False

View File

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

View File

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