mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 03:30:13 +01:00
finally refactor the song select boxes
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@ cache
|
||||
dev-config.toml
|
||||
libaudio.so
|
||||
latest.log
|
||||
Graphics1080
|
||||
|
||||
@@ -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
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
@@ -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"""
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"""
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]:
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user