mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 11:40:13 +01:00
fix audio engine, add difficulty sorting kind of
This commit is contained in:
@@ -6,9 +6,9 @@ from threading import Lock, Thread
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import soundfile as sf
|
import soundfile as sf
|
||||||
from numpy import abs as np_abs
|
|
||||||
from numpy import (
|
from numpy import (
|
||||||
arange,
|
arange,
|
||||||
|
clip,
|
||||||
column_stack,
|
column_stack,
|
||||||
float32,
|
float32,
|
||||||
frombuffer,
|
frombuffer,
|
||||||
@@ -16,13 +16,12 @@ from numpy import (
|
|||||||
int32,
|
int32,
|
||||||
interp,
|
interp,
|
||||||
mean,
|
mean,
|
||||||
|
multiply,
|
||||||
ndarray,
|
ndarray,
|
||||||
ones,
|
|
||||||
sqrt,
|
sqrt,
|
||||||
uint8,
|
uint8,
|
||||||
zeros,
|
zeros,
|
||||||
)
|
)
|
||||||
from numpy import max as np_max
|
|
||||||
|
|
||||||
os.environ["SD_ENABLE_ASIO"] = "1"
|
os.environ["SD_ENABLE_ASIO"] = "1"
|
||||||
import sounddevice as sd
|
import sounddevice as sd
|
||||||
@@ -514,7 +513,7 @@ class AudioEngine:
|
|||||||
self.running = False
|
self.running = False
|
||||||
self.sound_queue: queue.Queue[str] = queue.Queue()
|
self.sound_queue: queue.Queue[str] = queue.Queue()
|
||||||
self.music_queue = queue.Queue()
|
self.music_queue = queue.Queue()
|
||||||
self.master_volume = 1.0
|
self.master_volume = 0.70
|
||||||
self.output_channels = 2 # Default to stereo
|
self.output_channels = 2 # Default to stereo
|
||||||
self.audio_device_ready = False
|
self.audio_device_ready = False
|
||||||
|
|
||||||
@@ -523,6 +522,10 @@ class AudioEngine:
|
|||||||
self.update_thread_running = False
|
self.update_thread_running = False
|
||||||
self.type = type
|
self.type = type
|
||||||
|
|
||||||
|
self._output_buffer = None
|
||||||
|
self._channel_conversion_buffer = None
|
||||||
|
self._expected_frames = None
|
||||||
|
|
||||||
def _initialize_api(self) -> bool:
|
def _initialize_api(self) -> bool:
|
||||||
"""Set up API device"""
|
"""Set up API device"""
|
||||||
# Find API and use its default device
|
# Find API and use its default device
|
||||||
@@ -572,30 +575,25 @@ class AudioEngine:
|
|||||||
|
|
||||||
def _audio_callback(self, outdata: ndarray, frames: int, time: int, status: str) -> None:
|
def _audio_callback(self, outdata: ndarray, frames: int, time: int, status: str) -> None:
|
||||||
"""callback function for the sounddevice stream"""
|
"""callback function for the sounddevice stream"""
|
||||||
|
|
||||||
|
if self._output_buffer is None:
|
||||||
|
raise Exception("output buffer was not allocated")
|
||||||
if status:
|
if status:
|
||||||
print(f"Status: {status}")
|
print(f"Status: {status}")
|
||||||
|
|
||||||
self._process_sound_queue()
|
self._process_sound_queue()
|
||||||
self._process_music_queue()
|
self._process_music_queue()
|
||||||
|
|
||||||
# Pre-allocate output buffer (reuse if possible)
|
self._output_buffer.fill(0.0)
|
||||||
if not hasattr(self, '_output_buffer') or self._output_buffer.shape != (frames, self.output_channels):
|
|
||||||
self._output_buffer = zeros((frames, self.output_channels), dtype=float32)
|
|
||||||
else:
|
|
||||||
self._output_buffer.fill(0.0) # Clear previous data
|
|
||||||
|
|
||||||
self._mix_sounds(self._output_buffer, frames)
|
self._mix_sounds(self._output_buffer, frames)
|
||||||
|
|
||||||
self._mix_music(self._output_buffer, frames)
|
self._mix_music(self._output_buffer, frames)
|
||||||
|
|
||||||
# Apply master volume in-place
|
|
||||||
if self.master_volume != 1.0:
|
if self.master_volume != 1.0:
|
||||||
self._output_buffer *= self.master_volume
|
multiply(self._output_buffer, self.master_volume, out=self._output_buffer)
|
||||||
|
|
||||||
# Apply limiter only if needed
|
clip(self._output_buffer, -0.95, 0.95, out=self._output_buffer)
|
||||||
max_val = np_max(np_abs(self._output_buffer))
|
|
||||||
if max_val > 1.0:
|
|
||||||
self._output_buffer /= max_val
|
|
||||||
|
|
||||||
outdata[:] = self._output_buffer
|
outdata[:] = self._output_buffer
|
||||||
|
|
||||||
@@ -668,19 +666,36 @@ class AudioEngine:
|
|||||||
output += music_data
|
output += music_data
|
||||||
|
|
||||||
def _convert_channels(self, data: ndarray, input_channels: int) -> ndarray:
|
def _convert_channels(self, data: ndarray, input_channels: int) -> ndarray:
|
||||||
"""channel conversion with caching"""
|
"""Channel conversion using single pre-allocated buffer"""
|
||||||
|
if data.ndim == 1:
|
||||||
|
data = data.reshape(-1, 1)
|
||||||
|
input_channels = 1
|
||||||
|
|
||||||
|
frames = data.shape[0]
|
||||||
|
|
||||||
if input_channels == self.output_channels:
|
if input_channels == self.output_channels:
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
if self._channel_conversion_buffer is None:
|
||||||
|
raise Exception("channel conversion buffer was not allocated")
|
||||||
|
|
||||||
|
self._channel_conversion_buffer[:frames, :self.output_channels].fill(0.0)
|
||||||
|
|
||||||
if input_channels == 1 and self.output_channels > 1:
|
if input_channels == 1 and self.output_channels > 1:
|
||||||
return data[:, None] * ones((1, self.output_channels), dtype=float32)
|
# Mono to stereo/multi: broadcast to all channels
|
||||||
|
for ch in range(self.output_channels):
|
||||||
|
self._channel_conversion_buffer[:frames, ch] = data[:frames, 0]
|
||||||
|
|
||||||
elif input_channels > self.output_channels:
|
elif input_channels > self.output_channels:
|
||||||
if self.output_channels == 1:
|
if self.output_channels == 1:
|
||||||
return mean(data, axis=1, keepdims=True)
|
# Multi to mono: average channels
|
||||||
|
self._channel_conversion_buffer[:frames, 0] = mean(data[:frames, :input_channels], axis=1)
|
||||||
else:
|
else:
|
||||||
return data[:, :self.output_channels]
|
# Multi to fewer channels: take first N channels
|
||||||
|
self._channel_conversion_buffer[:frames, :self.output_channels] = data[:frames, :self.output_channels]
|
||||||
|
|
||||||
return data
|
# Return a view of the converted data
|
||||||
|
return self._channel_conversion_buffer[:frames, :self.output_channels]
|
||||||
|
|
||||||
def _start_update_thread(self) -> None:
|
def _start_update_thread(self) -> None:
|
||||||
"""Start a thread to update music streams"""
|
"""Start a thread to update music streams"""
|
||||||
@@ -710,6 +725,9 @@ class AudioEngine:
|
|||||||
try:
|
try:
|
||||||
self._initialize_api()
|
self._initialize_api()
|
||||||
|
|
||||||
|
self._expected_frames = self.buffer_size
|
||||||
|
self._output_buffer = zeros((self._expected_frames, self.output_channels), dtype=float32)
|
||||||
|
self._channel_conversion_buffer = zeros((self._expected_frames, max(8, self.output_channels)), dtype=float32)
|
||||||
# Set up and start the stream
|
# Set up and start the stream
|
||||||
extra_settings = None
|
extra_settings = None
|
||||||
buffer_size = self.buffer_size
|
buffer_size = self.buffer_size
|
||||||
@@ -752,6 +770,8 @@ class AudioEngine:
|
|||||||
self.music_streams = {}
|
self.music_streams = {}
|
||||||
self.sound_queue = queue.Queue()
|
self.sound_queue = queue.Queue()
|
||||||
self.music_queue = queue.Queue()
|
self.music_queue = queue.Queue()
|
||||||
|
self._output_buffer = None
|
||||||
|
self._channel_conversion_buffer = None
|
||||||
print("Audio device closed")
|
print("Audio device closed")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -62,29 +62,22 @@ def build_song_hashes(output_dir=Path("cache")):
|
|||||||
|
|
||||||
files_to_process = []
|
files_to_process = []
|
||||||
|
|
||||||
# O(n) pass to identify which files need processing
|
|
||||||
for tja_path in all_tja_files:
|
for tja_path in all_tja_files:
|
||||||
tja_path_str = str(tja_path)
|
tja_path_str = str(tja_path)
|
||||||
current_modified = tja_path.stat().st_mtime
|
current_modified = tja_path.stat().st_mtime
|
||||||
|
|
||||||
# Skip files that haven't been modified since last run
|
|
||||||
if current_modified <= saved_timestamp:
|
if current_modified <= saved_timestamp:
|
||||||
# File hasn't changed, just restore to global_data if we have it
|
|
||||||
current_hash = path_to_hash.get(tja_path_str)
|
current_hash = path_to_hash.get(tja_path_str)
|
||||||
if current_hash is not None:
|
if current_hash is not None:
|
||||||
global_data.song_paths[tja_path] = current_hash
|
global_data.song_paths[tja_path] = current_hash
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# O(1) lookup instead of nested loops
|
|
||||||
current_hash = path_to_hash.get(tja_path_str)
|
current_hash = path_to_hash.get(tja_path_str)
|
||||||
|
|
||||||
if current_hash is None:
|
if current_hash is None:
|
||||||
# New file (modified after saved_timestamp)
|
|
||||||
files_to_process.append(tja_path)
|
files_to_process.append(tja_path)
|
||||||
else:
|
else:
|
||||||
# File was modified after saved_timestamp, need to reprocess
|
|
||||||
files_to_process.append(tja_path)
|
files_to_process.append(tja_path)
|
||||||
# Clean up old hash
|
|
||||||
if current_hash in song_hashes:
|
if current_hash in song_hashes:
|
||||||
del song_hashes[current_hash]
|
del song_hashes[current_hash]
|
||||||
del path_to_hash[tja_path_str]
|
del path_to_hash[tja_path_str]
|
||||||
|
|||||||
@@ -208,6 +208,7 @@ class SessionData:
|
|||||||
result_max_combo: int = 0
|
result_max_combo: int = 0
|
||||||
result_total_drumroll: int = 0
|
result_total_drumroll: int = 0
|
||||||
result_gauge_length: int = 0
|
result_gauge_length: int = 0
|
||||||
|
prev_score: int = 0
|
||||||
|
|
||||||
session_data = SessionData()
|
session_data = SessionData()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
|
from libs.utils import session_data
|
||||||
|
|
||||||
|
|
||||||
class DevScreen:
|
class DevScreen:
|
||||||
def __init__(self, width: int, height: int):
|
def __init__(self, width: int, height: int):
|
||||||
@@ -13,12 +15,14 @@ class DevScreen:
|
|||||||
|
|
||||||
def on_screen_end(self, next_screen: str):
|
def on_screen_end(self, next_screen: str):
|
||||||
self.screen_init = False
|
self.screen_init = False
|
||||||
|
session_data.prev_score = 10000
|
||||||
|
session_data.result_score = 100000
|
||||||
return next_screen
|
return next_screen
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.on_screen_start()
|
self.on_screen_start()
|
||||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_ENTER):
|
if ray.is_key_pressed(ray.KeyboardKey.KEY_ENTER):
|
||||||
return self.on_screen_end('GAME')
|
return self.on_screen_end('RESULT')
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -274,6 +274,8 @@ class Box:
|
|||||||
|
|
||||||
def _draw_text(self, color):
|
def _draw_text(self, color):
|
||||||
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:
|
||||||
|
text_x += self.open.attribute
|
||||||
text_y = self.y + 20
|
text_y = self.y + 20
|
||||||
text_dest = ray.Rectangle(text_x, text_y, self.text.texture.width, self.text.texture.height)
|
text_dest = ray.Rectangle(text_x, text_y, self.text.texture.width, self.text.texture.height)
|
||||||
if self.is_selected:
|
if self.is_selected:
|
||||||
|
|||||||
@@ -109,6 +109,10 @@ class GameScreen:
|
|||||||
cursor.execute(check_query, (hash,))
|
cursor.execute(check_query, (hash,))
|
||||||
result = cursor.fetchone()
|
result = cursor.fetchone()
|
||||||
if result is None or session_data.result_score > result[0]:
|
if result is None or session_data.result_score > result[0]:
|
||||||
|
if result is None:
|
||||||
|
session_data.prev_score = 0
|
||||||
|
else:
|
||||||
|
session_data.prev_score = result[0]
|
||||||
insert_query = '''
|
insert_query = '''
|
||||||
INSERT OR REPLACE INTO Scores (hash, en_name, jp_name, diff, score, good, ok, bad, drumroll, combo, clear)
|
INSERT OR REPLACE INTO Scores (hash, en_name, jp_name, diff, score, good, ok, bad, drumroll, combo, clear)
|
||||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||||
@@ -542,11 +546,9 @@ class Player:
|
|||||||
tail = next((note for note in self.current_notes_draw[1:] if note.type == 8 and note.index > head.index), self.current_notes_draw[1])
|
tail = next((note for note in self.current_notes_draw[1:] if note.type == 8 and note.index > head.index), self.current_notes_draw[1])
|
||||||
is_big = int(head.type == 6)
|
is_big = int(head.type == 6)
|
||||||
end_position = self.get_position_x(game_screen.width, game_screen.current_ms, tail.load_ms, tail.pixels_per_frame_x)
|
end_position = self.get_position_x(game_screen.width, game_screen.current_ms, tail.load_ms, tail.pixels_per_frame_x)
|
||||||
length = (end_position - start_position - 50)
|
length = end_position - start_position
|
||||||
if length <= 0:
|
|
||||||
end_position += 50
|
|
||||||
color = ray.Color(255, head.color, head.color, 255)
|
color = ray.Color(255, head.color, head.color, 255)
|
||||||
tex.draw_texture('notes', "8", frame=is_big, x=start_position+64, y=192, x2=length, color=color)
|
tex.draw_texture('notes', "8", frame=is_big, x=start_position+64, y=192, x2=length-64-32, color=color)
|
||||||
tex.draw_texture('notes', "9", frame=is_big, x=end_position, y=192, color=color)
|
tex.draw_texture('notes', "9", frame=is_big, x=end_position, y=192, color=color)
|
||||||
tex.draw_texture('notes', str(head.type), frame=current_eighth % 2, x=start_position, y=192, color=color)
|
tex.draw_texture('notes', str(head.type), frame=current_eighth % 2, x=start_position, y=192, color=color)
|
||||||
|
|
||||||
|
|||||||
@@ -42,12 +42,8 @@ class LoadScreen:
|
|||||||
|
|
||||||
def _load_navigator(self):
|
def _load_navigator(self):
|
||||||
"""Background thread function to load navigator"""
|
"""Background thread function to load navigator"""
|
||||||
try:
|
|
||||||
self.song_select_screen.load_navigator()
|
self.song_select_screen.load_navigator()
|
||||||
self.loading_complete = True
|
self.loading_complete = True
|
||||||
except Exception as e:
|
|
||||||
print(f"Error loading navigator: {e}")
|
|
||||||
self.loading_complete = True
|
|
||||||
|
|
||||||
def on_screen_start(self):
|
def on_screen_start(self):
|
||||||
if not self.screen_init:
|
if not self.screen_init:
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
from raylib import SHADER_UNIFORM_FLOAT
|
from raylib import SHADER_UNIFORM_FLOAT
|
||||||
@@ -53,6 +54,7 @@ class ResultScreen:
|
|||||||
self.bottom_characters = BottomCharacters()
|
self.bottom_characters = BottomCharacters()
|
||||||
self.crown = None
|
self.crown = None
|
||||||
self.state = None
|
self.state = None
|
||||||
|
self.high_score_indicator = None
|
||||||
self.score_animator = ScoreAnimator(session_data.result_score)
|
self.score_animator = ScoreAnimator(session_data.result_score)
|
||||||
self.score = -1
|
self.score = -1
|
||||||
self.good = -1
|
self.good = -1
|
||||||
@@ -104,6 +106,9 @@ class ResultScreen:
|
|||||||
self.update_index += 1
|
self.update_index += 1
|
||||||
self.score_animator = ScoreAnimator(self.update_list[self.update_index][1])
|
self.score_animator = ScoreAnimator(self.update_list[self.update_index][1])
|
||||||
self.score_delay += 16.67 * 3
|
self.score_delay += 16.67 * 3
|
||||||
|
if self.update_index > 0 and self.high_score_indicator is None:
|
||||||
|
if session_data.result_score > session_data.prev_score:
|
||||||
|
self.high_score_indicator = HighScoreIndicator(session_data.prev_score, session_data.result_score)
|
||||||
|
|
||||||
def handle_input(self):
|
def handle_input(self):
|
||||||
if is_r_don_pressed() or is_l_don_pressed():
|
if is_r_don_pressed() or is_l_don_pressed():
|
||||||
@@ -138,6 +143,9 @@ class ResultScreen:
|
|||||||
if self.gauge is not None:
|
if self.gauge is not None:
|
||||||
self.state = self.gauge.state
|
self.state = self.gauge.state
|
||||||
|
|
||||||
|
if self.high_score_indicator is not None:
|
||||||
|
self.high_score_indicator.update(get_current_ms())
|
||||||
|
|
||||||
self.fade_in_bottom.update(get_current_ms())
|
self.fade_in_bottom.update(get_current_ms())
|
||||||
alpha_loc = ray.get_shader_location(self.alpha_shader, "ext_alpha")
|
alpha_loc = ray.get_shader_location(self.alpha_shader, "ext_alpha")
|
||||||
alpha_value = ray.ffi.new('float*', self.fade_in_bottom.attribute)
|
alpha_value = ray.ffi.new('float*', self.fade_in_bottom.attribute)
|
||||||
@@ -223,6 +231,9 @@ class ResultScreen:
|
|||||||
if self.crown is not None:
|
if self.crown is not None:
|
||||||
self.crown.draw(self.crown_type)
|
self.crown.draw(self.crown_type)
|
||||||
|
|
||||||
|
if self.high_score_indicator is not None:
|
||||||
|
self.high_score_indicator.draw()
|
||||||
|
|
||||||
self.fade_in.draw()
|
self.fade_in.draw()
|
||||||
ray.draw_rectangle(0, 0, self.width, self.height, ray.fade(ray.BLACK, self.fade_out.attribute))
|
ray.draw_rectangle(0, 0, self.width, self.height, ray.fade(ray.BLACK, self.fade_out.attribute))
|
||||||
|
|
||||||
@@ -379,6 +390,24 @@ class ScoreAnimator:
|
|||||||
self.digit_index -= 1
|
self.digit_index -= 1
|
||||||
return int(''.join([str(item[0]) for item in self.current_score_list]))
|
return int(''.join([str(item[0]) for item in self.current_score_list]))
|
||||||
|
|
||||||
|
class HighScoreIndicator:
|
||||||
|
def __init__(self, old_score: int, new_score: int):
|
||||||
|
self.score_diff = new_score - old_score
|
||||||
|
self.move = tex.get_animation(18)
|
||||||
|
self.fade = tex.get_animation(19)
|
||||||
|
self.move.start()
|
||||||
|
self.fade.start()
|
||||||
|
|
||||||
|
def update(self, current_ms):
|
||||||
|
self.move.update(current_ms)
|
||||||
|
self.fade.update(current_ms)
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
tex.draw_texture('score', 'high_score', y=self.move.attribute, fade=self.fade.attribute)
|
||||||
|
for i in range(len(str(self.score_diff))):
|
||||||
|
tex.draw_texture('score', 'high_score_num', x=-(i*14), frame=int(str(self.score_diff)[::-1][i]), y=self.move.attribute, fade=self.fade.attribute)
|
||||||
|
|
||||||
|
|
||||||
class Gauge:
|
class Gauge:
|
||||||
def __init__(self, player_num: str, gauge_length: int):
|
def __init__(self, player_num: str, gauge_length: int):
|
||||||
self.player_num = player_num
|
self.player_num = player_num
|
||||||
|
|||||||
@@ -334,7 +334,8 @@ class SongBox:
|
|||||||
5: ray.Color(60, 104, 0, 255),
|
5: ray.Color(60, 104, 0, 255),
|
||||||
6: ray.Color(134, 88, 0, 255),
|
6: ray.Color(134, 88, 0, 255),
|
||||||
7: ray.Color(79, 40, 134, 255),
|
7: ray.Color(79, 40, 134, 255),
|
||||||
8: ray.Color(148, 24, 0, 255)
|
8: ray.Color(148, 24, 0, 255),
|
||||||
|
14: ray.Color(157, 13, 31, 255)
|
||||||
}
|
}
|
||||||
def __init__(self, name: str, texture_index: int, is_dir: bool, tja: Optional[TJAParser] = None,
|
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):
|
tja_count: Optional[int] = None, box_texture: Optional[str] = None, name_texture_index: Optional[int] = None):
|
||||||
@@ -460,7 +461,7 @@ class SongBox:
|
|||||||
|
|
||||||
def _draw_closed(self, x: int, y: int):
|
def _draw_closed(self, x: int, y: int):
|
||||||
tex.draw_texture('box', 'folder_texture_left', frame=self.texture_index, x=x)
|
tex.draw_texture('box', 'folder_texture_left', frame=self.texture_index, x=x)
|
||||||
offset = 1 if self.texture_index in {3, 9, 17} else 0
|
offset = 1 if self.texture_index == 3 or self.texture_index >= 9 else 0
|
||||||
tex.draw_texture('box', 'folder_texture', frame=self.texture_index, x=x, x2=32, y=offset)
|
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)
|
tex.draw_texture('box', 'folder_texture_right', frame=self.texture_index, x=x)
|
||||||
if self.texture_index == 9:
|
if self.texture_index == 9:
|
||||||
@@ -476,8 +477,9 @@ class SongBox:
|
|||||||
|
|
||||||
if self.tja is not None and self.tja.ex_data.new:
|
if self.tja is not None and 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)
|
||||||
if self.scores:
|
valid_scores = {k: v for k, v in self.scores.items() if v is not None}
|
||||||
highest_key = max(self.scores.keys())
|
if valid_scores:
|
||||||
|
highest_key = max(valid_scores.keys())
|
||||||
score = self.scores[highest_key]
|
score = self.scores[highest_key]
|
||||||
if score and score[3] == 0:
|
if score and score[3] == 0:
|
||||||
tex.draw_texture('yellow_box', 'crown_fc', x=x, y=y, frame=highest_key)
|
tex.draw_texture('yellow_box', 'crown_fc', x=x, y=y, frame=highest_key)
|
||||||
@@ -503,7 +505,7 @@ class SongBox:
|
|||||||
self.hori_name.draw(self.hori_name.default_src, dest, ray.Vector2(0, 0), 0, color)
|
self.hori_name.draw(self.hori_name.default_src, dest, ray.Vector2(0, 0), 0, color)
|
||||||
|
|
||||||
tex.draw_texture('box', 'folder_texture_left', frame=self.texture_index, x=x - self.open_anim.attribute)
|
tex.draw_texture('box', 'folder_texture_left', frame=self.texture_index, x=x - self.open_anim.attribute)
|
||||||
offset = 1 if self.texture_index in {3, 9, 17} else 0
|
offset = 1 if self.texture_index == 3 or self.texture_index >= 9 else 0
|
||||||
tex.draw_texture('box', 'folder_texture', frame=self.texture_index, x=x - self.open_anim.attribute, y=offset, x2=324)
|
tex.draw_texture('box', 'folder_texture', frame=self.texture_index, x=x - self.open_anim.attribute, y=offset, x2=324)
|
||||||
tex.draw_texture('box', 'folder_texture_right', frame=self.texture_index, x=x + self.open_anim.attribute)
|
tex.draw_texture('box', 'folder_texture_right', frame=self.texture_index, x=x + self.open_anim.attribute)
|
||||||
|
|
||||||
@@ -788,6 +790,7 @@ class FileSystemItem:
|
|||||||
'クラシック': 6,
|
'クラシック': 6,
|
||||||
'ゲームミュージック': 7,
|
'ゲームミュージック': 7,
|
||||||
'ナムコオリジナル': 8,
|
'ナムコオリジナル': 8,
|
||||||
|
'DIFFICULTY': 14
|
||||||
}
|
}
|
||||||
"""Base class for files and directories in the navigation system"""
|
"""Base class for files and directories in the navigation system"""
|
||||||
def __init__(self, path: Path, name: str):
|
def __init__(self, path: Path, name: str):
|
||||||
@@ -811,8 +814,9 @@ class Directory(FileSystemItem):
|
|||||||
self.collection = None
|
self.collection = None
|
||||||
if collection in Directory.COLLECTIONS:
|
if collection in Directory.COLLECTIONS:
|
||||||
self.collection = collection
|
self.collection = collection
|
||||||
|
if collection in FileSystemItem.GENRE_MAP:
|
||||||
if self.to_root or self.back:
|
texture_index = FileSystemItem.GENRE_MAP[collection]
|
||||||
|
elif self.to_root or self.back:
|
||||||
texture_index = 17
|
texture_index = 17
|
||||||
|
|
||||||
self.box = SongBox(name, texture_index, True, tja_count=tja_count, box_texture=box_texture)
|
self.box = SongBox(name, texture_index, True, tja_count=tja_count, box_texture=box_texture)
|
||||||
@@ -1215,8 +1219,21 @@ class FileNavigator:
|
|||||||
# Add pre-generated content for this directory
|
# Add pre-generated content for this directory
|
||||||
if dir_key in self.directory_contents:
|
if dir_key in self.directory_contents:
|
||||||
content_items = self.directory_contents[dir_key]
|
content_items = self.directory_contents[dir_key]
|
||||||
if isinstance(selected_item, Directory) and selected_item.collection == Directory.COLLECTIONS[0]:
|
if isinstance(selected_item, Directory):
|
||||||
|
if selected_item.collection == Directory.COLLECTIONS[0]:
|
||||||
content_items = self.new_items
|
content_items = self.new_items
|
||||||
|
elif selected_item.collection == Directory.COLLECTIONS[3]:
|
||||||
|
content_items = []
|
||||||
|
parent_dir = selected_item.path.parent
|
||||||
|
for sibling_path in parent_dir.iterdir():
|
||||||
|
if sibling_path.is_dir() and sibling_path != selected_item.path:
|
||||||
|
sibling_key = str(sibling_path)
|
||||||
|
if sibling_key in self.directory_contents:
|
||||||
|
for item in self.directory_contents[sibling_key]:
|
||||||
|
if isinstance(item, SongFile):
|
||||||
|
if 3 in item.tja.metadata.course_data and item.tja.metadata.course_data[3].level == 10:
|
||||||
|
item.box.texture_index = 14
|
||||||
|
content_items.append(item)
|
||||||
|
|
||||||
i = 1
|
i = 1
|
||||||
for item in content_items:
|
for item in content_items:
|
||||||
|
|||||||
Reference in New Issue
Block a user