mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 11:40:13 +01:00
fix scrobbling
This commit is contained in:
@@ -113,16 +113,17 @@ class Background:
|
||||
if self.renda is not None:
|
||||
self.renda.add_renda()
|
||||
|
||||
def update(self, current_time_ms: float, bpm: float, gauge_1p, gauge_2p = None):
|
||||
def update(self, current_time_ms: float, bpm: float, gauge_1p = None, gauge_2p = None):
|
||||
"""
|
||||
Update the background.
|
||||
|
||||
Args:
|
||||
current_time_ms (float): The current time in milliseconds.
|
||||
bpm (float): The beats per minute.
|
||||
gauge (Gauge): The gauge object.
|
||||
gauge_1p (Gauge): The gauge object for player 1.
|
||||
gauge_2p (Gauge): The gauge object for player 2.
|
||||
"""
|
||||
if self.dancer is not None:
|
||||
if self.dancer is not None and gauge_1p is not None:
|
||||
clear_threshold = gauge_1p.clear_start[min(gauge_1p.difficulty, 3)]
|
||||
if gauge_1p.gauge_length < clear_threshold:
|
||||
current_milestone = min(self.max_dancers - 1, int(gauge_1p.gauge_length / (clear_threshold / self.max_dancers)))
|
||||
@@ -132,13 +133,14 @@ class Background:
|
||||
self.dancer.add_dancer()
|
||||
self.last_milestone = current_milestone
|
||||
logger.info(f"Dancer milestone reached: {current_milestone}/{self.max_dancers}")
|
||||
if self.bg_fever is not None:
|
||||
if self.bg_fever is not None and gauge_1p is not None:
|
||||
if not self.is_clear and gauge_1p.is_clear:
|
||||
self.bg_fever.start()
|
||||
logger.info("Fever started")
|
||||
if not self.is_rainbow and gauge_1p.is_rainbow and self.fever is not None:
|
||||
self.fever.start()
|
||||
logger.info("Rainbow fever started")
|
||||
if gauge_1p is not None:
|
||||
self.is_clear = gauge_1p.is_clear
|
||||
self.is_rainbow = gauge_1p.is_rainbow
|
||||
self.don_bg.update(current_time_ms, self.is_clear)
|
||||
|
||||
@@ -202,6 +202,19 @@ class GameScreen(Screen):
|
||||
self.movie.start(current_time)
|
||||
self.song_started = True
|
||||
|
||||
def pause_song(self):
|
||||
self.paused = not self.paused
|
||||
if self.paused:
|
||||
if self.song_music is not None:
|
||||
self.audio_time = audio.get_music_time_played(self.song_music)
|
||||
audio.stop_music_stream(self.song_music)
|
||||
self.pause_time = get_current_ms() - self.start_ms
|
||||
else:
|
||||
if self.song_music is not None:
|
||||
audio.play_music_stream(self.song_music, 'music')
|
||||
audio.seek_music_stream(self.song_music, self.audio_time)
|
||||
self.start_ms = get_current_ms() - self.pause_time
|
||||
|
||||
def global_keys(self):
|
||||
if ray.is_key_pressed(get_key_code(global_data.config["keys"]["restart_key"])):
|
||||
if self.song_music is not None:
|
||||
@@ -216,17 +229,7 @@ class GameScreen(Screen):
|
||||
return self.on_screen_end('SONG_SELECT')
|
||||
|
||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_SPACE):
|
||||
self.paused = not self.paused
|
||||
if self.paused:
|
||||
if self.song_music is not None:
|
||||
self.audio_time = audio.get_music_time_played(self.song_music)
|
||||
audio.stop_music_stream(self.song_music)
|
||||
self.pause_time = get_current_ms() - self.start_ms
|
||||
else:
|
||||
if self.song_music is not None:
|
||||
audio.play_music_stream(self.song_music, 'music')
|
||||
audio.seek_music_stream(self.song_music, self.audio_time)
|
||||
self.start_ms = get_current_ms() - self.pause_time
|
||||
self.pause_song()
|
||||
|
||||
def spawn_ending_anims(self):
|
||||
if global_data.session_data[global_data.player_num-1].result_data.bad == 0:
|
||||
@@ -266,6 +269,7 @@ class GameScreen(Screen):
|
||||
elif self.current_ms >= self.player_1.end_time:
|
||||
session_data = global_data.session_data[global_data.player_num-1]
|
||||
session_data.result_data.score, session_data.result_data.good, session_data.result_data.ok, session_data.result_data.bad, session_data.result_data.max_combo, session_data.result_data.total_drumroll = self.player_1.get_result_score()
|
||||
if self.player_1.gauge is not None:
|
||||
session_data.result_data.gauge_length = self.player_1.gauge.gauge_length
|
||||
if self.end_ms != 0:
|
||||
if current_time >= self.end_ms + 1000:
|
||||
@@ -524,6 +528,7 @@ class Player:
|
||||
else:
|
||||
background.add_chibi(True, 1)
|
||||
self.bad_count += 1
|
||||
if self.gauge is not None:
|
||||
self.gauge.add_bad()
|
||||
self.don_notes.popleft()
|
||||
if self.is_branch and self.branch_condition == 'p':
|
||||
@@ -537,6 +542,7 @@ class Player:
|
||||
else:
|
||||
background.add_chibi(True, 1)
|
||||
self.bad_count += 1
|
||||
if self.gauge is not None:
|
||||
self.gauge.add_bad()
|
||||
self.kat_notes.popleft()
|
||||
if self.is_branch and self.branch_condition == 'p':
|
||||
@@ -718,6 +724,7 @@ class Player:
|
||||
self.score += self.base_score
|
||||
self.base_score_list.append(ScoreCounterAnimation(self.player_number, self.base_score, self.is_2p))
|
||||
self.note_correct(curr_note, current_time)
|
||||
if self.gauge is not None:
|
||||
self.gauge.add_good()
|
||||
if self.is_branch and self.branch_condition == 'p':
|
||||
self.branch_condition_count += 1
|
||||
@@ -733,6 +740,7 @@ class Player:
|
||||
self.score += 10 * math.floor(self.base_score / 2 / 10)
|
||||
self.base_score_list.append(ScoreCounterAnimation(self.player_number, 10 * math.floor(self.base_score / 2 / 10), self.is_2p))
|
||||
self.note_correct(curr_note, current_time)
|
||||
if self.gauge is not None:
|
||||
self.gauge.add_ok()
|
||||
if self.is_branch and self.branch_condition == 'p':
|
||||
self.branch_condition_count += 0.5
|
||||
@@ -751,6 +759,7 @@ class Player:
|
||||
self.don_notes.popleft()
|
||||
else:
|
||||
self.kat_notes.popleft()
|
||||
if self.gauge is not None:
|
||||
self.gauge.add_bad()
|
||||
if background is not None:
|
||||
if self.is_2p:
|
||||
@@ -905,6 +914,7 @@ class Player:
|
||||
self.autoplay_manager(ms_from_start, current_time, background)
|
||||
self.handle_input(ms_from_start, current_time, background)
|
||||
self.nameplate.update(current_time)
|
||||
if self.gauge is not None:
|
||||
self.gauge.update(current_time)
|
||||
if self.judge_counter is not None:
|
||||
self.judge_counter.update(self.good_count, self.ok_count, self.bad_count, self.total_drumroll)
|
||||
@@ -939,6 +949,9 @@ class Player:
|
||||
self.is_gogo_time = False
|
||||
self.gogo_time = None
|
||||
self.chara.set_animation('gogo_stop')
|
||||
if self.gauge is None:
|
||||
self.chara.update(current_time, self.bpm, False, False)
|
||||
else:
|
||||
self.chara.update(current_time, self.bpm, self.gauge.is_clear, self.gauge.is_rainbow)
|
||||
|
||||
def draw_drumroll(self, current_ms: float, head: Drumroll, current_eighth: int):
|
||||
@@ -1058,11 +1071,16 @@ class Player:
|
||||
for modifier in modifiers_to_draw:
|
||||
tex.draw_texture('lane', modifier, index=self.is_2p)
|
||||
|
||||
def draw_note_types(self, ms_from_start: float, start_ms: float):
|
||||
self.draw_bars(ms_from_start)
|
||||
self.draw_notes(ms_from_start, start_ms)
|
||||
|
||||
def draw(self, ms_from_start: float, start_ms: float, mask_shader: ray.Shader, dan_transition = None):
|
||||
# Group 1: Background and lane elements
|
||||
tex.draw_texture('lane', 'lane_background', index=self.is_2p)
|
||||
if self.branch_indicator is not None:
|
||||
self.branch_indicator.draw()
|
||||
if self.gauge is not None:
|
||||
self.gauge.draw()
|
||||
if self.lane_hit_effect is not None:
|
||||
self.lane_hit_effect.draw()
|
||||
@@ -1075,8 +1093,7 @@ class Player:
|
||||
anim.draw()
|
||||
|
||||
# Group 3: Notes and bars (game content)
|
||||
self.draw_bars(ms_from_start)
|
||||
self.draw_notes(ms_from_start, start_ms)
|
||||
self.draw_note_types(ms_from_start, start_ms)
|
||||
if dan_transition is not None:
|
||||
dan_transition.draw()
|
||||
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
from collections import deque
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
import pyray as ray
|
||||
import copy
|
||||
|
||||
from libs.animation import Animation
|
||||
from libs.audio import audio
|
||||
from libs.background import Background
|
||||
from scenes.game import GameScreen, JudgeCounter
|
||||
from libs.global_data import Modifiers, global_data
|
||||
from libs.tja import Balloon, Drumroll, TJAParser, apply_modifiers
|
||||
from libs.utils import get_current_ms
|
||||
from libs.texture import tex
|
||||
from scenes.game import GameScreen, JudgeCounter, Player, SCREEN_WIDTH
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -12,5 +22,191 @@ class PracticeGameScreen(GameScreen):
|
||||
self.background = Background(1, self.bpm, scene_preset='PRACTICE')
|
||||
|
||||
def init_tja(self, song: Path):
|
||||
super().init_tja(song)
|
||||
self.player_1.judge_counter = JudgeCounter()
|
||||
"""Initialize the TJA file"""
|
||||
self.tja = TJAParser(song, start_delay=self.start_delay, distance=SCREEN_WIDTH - GameScreen.JUDGE_X)
|
||||
self.scrolling_tja = TJAParser(song, start_delay=self.start_delay, distance=SCREEN_WIDTH - GameScreen.JUDGE_X)
|
||||
global_data.session_data[0].song_title = self.tja.metadata.title.get(global_data.config['general']['language'].lower(), self.tja.metadata.title['en'])
|
||||
if self.tja.metadata.wave.exists() and self.tja.metadata.wave.is_file() and self.song_music is None:
|
||||
self.song_music = audio.load_music_stream(self.tja.metadata.wave, 'song')
|
||||
self.player_1 = PracticePlayer(self.tja, global_data.player_num, global_data.session_data[global_data.player_num-1].selected_difficulty, False, global_data.modifiers[0])
|
||||
notes, branch_m, branch_e, branch_n = self.tja.notes_to_position(self.player_1.difficulty)
|
||||
_, self.scroll_note_list, self.bars = apply_modifiers(notes, self.player_1.modifiers)
|
||||
self.start_ms = (get_current_ms() - self.tja.metadata.offset*1000)
|
||||
self.scrobble_index = 0
|
||||
self.scrobble_time = self.bars[self.scrobble_index].hit_ms
|
||||
self.scrobble_move = Animation.create_move(200, total_distance=0)
|
||||
|
||||
def pause_song(self):
|
||||
self.paused = not self.paused
|
||||
self.player_1.paused = self.paused
|
||||
if self.paused:
|
||||
if self.song_music is not None:
|
||||
audio.stop_music_stream(self.song_music)
|
||||
self.pause_time = get_current_ms() - self.start_ms
|
||||
first_bar_time = self.bars[0].hit_ms
|
||||
nearest_bar_index = 0
|
||||
min_distance = float('inf')
|
||||
for i, bar in enumerate(self.bars):
|
||||
bar_relative_time = bar.hit_ms - first_bar_time
|
||||
distance = abs(bar_relative_time - self.current_ms)
|
||||
if distance < min_distance:
|
||||
min_distance = distance
|
||||
nearest_bar_index = i
|
||||
self.scrobble_index = nearest_bar_index - 1
|
||||
self.scrobble_time = self.bars[self.scrobble_index].hit_ms
|
||||
else:
|
||||
resume_bar_index = max(0, self.scrobble_index)
|
||||
previous_bar_index = max(0, self.scrobble_index - 1)
|
||||
|
||||
first_bar_time = self.bars[0].hit_ms
|
||||
resume_time = self.bars[resume_bar_index].hit_ms - first_bar_time + self.start_delay
|
||||
start_time = self.bars[previous_bar_index].hit_ms - first_bar_time
|
||||
|
||||
tja_copy = copy.deepcopy(self.scrolling_tja)
|
||||
self.player_1.tja = tja_copy
|
||||
self.player_1.reset_chart()
|
||||
|
||||
self.player_1.don_notes = deque([note for note in self.player_1.don_notes if note.hit_ms >= resume_time])
|
||||
self.player_1.kat_notes = deque([note for note in self.player_1.kat_notes if note.hit_ms >= resume_time])
|
||||
self.player_1.other_notes = deque([note for note in self.player_1.other_notes if note.hit_ms >= resume_time])
|
||||
self.player_1.draw_note_list = deque([note for note in self.player_1.draw_note_list if note.hit_ms >= resume_time])
|
||||
self.player_1.draw_bar_list = deque([note for note in self.player_1.draw_bar_list if note.hit_ms >= resume_time])
|
||||
self.player_1.total_notes = len([note for note in self.player_1.play_notes if 0 < note.type < 5])
|
||||
|
||||
self.pause_time = start_time
|
||||
if self.song_music is not None:
|
||||
audio.play_music_stream(self.song_music, 'music')
|
||||
audio.seek_music_stream(self.song_music, (self.pause_time - self.start_delay)/1000 - self.tja.metadata.offset)
|
||||
self.start_ms = get_current_ms() - self.pause_time
|
||||
|
||||
def global_keys(self):
|
||||
super().global_keys()
|
||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_LEFT) or ray.is_key_pressed(ray.KeyboardKey.KEY_RIGHT):
|
||||
audio.play_sound('kat', 'sound')
|
||||
|
||||
old_index = self.scrobble_index
|
||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_LEFT):
|
||||
self.scrobble_index = (self.scrobble_index - 1) if self.scrobble_index > 0 else len(self.bars) - 1
|
||||
elif ray.is_key_pressed(ray.KeyboardKey.KEY_RIGHT):
|
||||
self.scrobble_index = (self.scrobble_index + 1) % len(self.bars)
|
||||
|
||||
time_difference = self.bars[self.scrobble_index].load_ms - self.bars[old_index].load_ms
|
||||
|
||||
self.scrobble_move = Animation.create_move(400, total_distance=time_difference, ease_out='quadratic')
|
||||
self.scrobble_move.start()
|
||||
|
||||
def update(self):
|
||||
super().update()
|
||||
self.scrobble_move.update(get_current_ms())
|
||||
if self.scrobble_move.is_finished:
|
||||
self.scrobble_time = self.bars[self.scrobble_index].hit_ms
|
||||
self.scrobble_move.reset()
|
||||
|
||||
def get_position_x(self, width: int, current_ms: float, load_ms: float, pixels_per_frame: float) -> int:
|
||||
"""Calculates the x-coordinate of a note based on its load time and current time"""
|
||||
if self.paused:
|
||||
time_diff = load_ms - self.scrobble_time - self.scrobble_move.attribute
|
||||
else:
|
||||
time_diff = load_ms - current_ms
|
||||
return int(width + pixels_per_frame * 0.06 * time_diff - 64)
|
||||
|
||||
def get_position_y(self, current_ms: float, load_ms: float, pixels_per_frame: float, pixels_per_frame_x) -> int:
|
||||
"""Calculates the y-coordinate of a note based on its load time and current time"""
|
||||
time_diff = load_ms - current_ms
|
||||
return int((pixels_per_frame * 0.06 * time_diff) + ((866 * pixels_per_frame) / pixels_per_frame_x))
|
||||
|
||||
def draw_drumroll(self, current_ms: float, head: Drumroll, current_eighth: int, index: int):
|
||||
"""Draws a drumroll in the player's lane"""
|
||||
start_position = self.get_position_x(SCREEN_WIDTH, current_ms, head.load_ms, head.pixels_per_frame_x)
|
||||
tail = self.scroll_note_list[index + 1]
|
||||
is_big = int(head.type == 6)
|
||||
end_position = self.get_position_x(SCREEN_WIDTH, current_ms, tail.load_ms, tail.pixels_per_frame_x)
|
||||
length = end_position - start_position
|
||||
color = ray.Color(255, head.color, head.color, 255)
|
||||
if head.display:
|
||||
if length > 0:
|
||||
tex.draw_texture('notes', "8", frame=is_big, x=start_position+64, y=192, x2=length-47, color=color)
|
||||
if is_big:
|
||||
tex.draw_texture('notes', "drumroll_big_tail", x=end_position+64, y=192, color=color)
|
||||
else:
|
||||
tex.draw_texture('notes', "drumroll_tail", x=end_position+64, 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', 'moji_drumroll_mid', x=start_position + 60, y=323, x2=length)
|
||||
tex.draw_texture('notes', 'moji', frame=head.moji, x=(start_position - (168//2)) + 64, y=323)
|
||||
tex.draw_texture('notes', 'moji', frame=tail.moji, x=(end_position - (168//2)) + 32, y=323)
|
||||
|
||||
def draw_balloon(self, current_ms: float, head: Balloon, current_eighth: int, index: int):
|
||||
"""Draws a balloon in the player's lane"""
|
||||
offset = 12
|
||||
start_position = self.get_position_x(SCREEN_WIDTH, current_ms, head.load_ms, head.pixels_per_frame_x)
|
||||
tail = self.scroll_note_list[index + 1]
|
||||
end_position = self.get_position_x(SCREEN_WIDTH, current_ms, tail.load_ms, tail.pixels_per_frame_x)
|
||||
pause_position = 349
|
||||
if current_ms >= tail.hit_ms:
|
||||
position = end_position
|
||||
elif current_ms >= head.hit_ms:
|
||||
position = pause_position
|
||||
else:
|
||||
position = start_position
|
||||
if head.display:
|
||||
tex.draw_texture('notes', str(head.type), frame=current_eighth % 2, x=position-offset, y=192)
|
||||
tex.draw_texture('notes', '10', frame=current_eighth % 2, x=position-offset+128, y=192)
|
||||
|
||||
def draw(self):
|
||||
super().draw()
|
||||
if self.paused:
|
||||
# Batch bar draws by pre-calculating positions
|
||||
bar_draws = []
|
||||
for bar in reversed(self.bars):
|
||||
if not bar.display:
|
||||
continue
|
||||
x_position = self.get_position_x(SCREEN_WIDTH, self.current_ms, bar.load_ms, bar.pixels_per_frame_x)
|
||||
y_position = self.get_position_y(self.current_ms, bar.load_ms, bar.pixels_per_frame_y, bar.pixels_per_frame_x)
|
||||
if x_position < 236 or x_position > SCREEN_WIDTH:
|
||||
continue
|
||||
if hasattr(bar, 'is_branch_start'):
|
||||
frame = 1
|
||||
else:
|
||||
frame = 0
|
||||
bar_draws.append((str(bar.type), frame, x_position+60, y_position+190))
|
||||
|
||||
# Draw all bars in one batch
|
||||
for bar_type, frame, x, y in bar_draws:
|
||||
tex.draw_texture('notes', bar_type, frame=frame, x=x, y=y)
|
||||
|
||||
for note in reversed(self.scroll_note_list):
|
||||
if note.type == 8:
|
||||
continue
|
||||
|
||||
if isinstance(note, Drumroll):
|
||||
self.draw_drumroll(self.current_ms, note, 0, note.index)
|
||||
elif isinstance(note, Balloon) and not note.is_kusudama:
|
||||
x_position = self.get_position_x(SCREEN_WIDTH, self.current_ms, note.load_ms, note.pixels_per_frame_x)
|
||||
y_position = self.get_position_y(self.current_ms, note.load_ms, note.pixels_per_frame_y, note.pixels_per_frame_x)
|
||||
if x_position < 236 or x_position > SCREEN_WIDTH:
|
||||
continue
|
||||
self.draw_balloon(self.current_ms, note, 0, note.index)
|
||||
tex.draw_texture('notes', 'moji', frame=note.moji, x=x_position - (168//2) + 64, y=323 + y_position)
|
||||
else:
|
||||
x_position = self.get_position_x(SCREEN_WIDTH, self.current_ms, note.load_ms, note.pixels_per_frame_x)
|
||||
y_position = self.get_position_y(self.current_ms, note.load_ms, note.pixels_per_frame_y, note.pixels_per_frame_x)
|
||||
if x_position < 236 or x_position > SCREEN_WIDTH:
|
||||
continue
|
||||
|
||||
if note.display:
|
||||
tex.draw_texture('notes', str(note.type), x=x_position, y=y_position+192, center=True)
|
||||
tex.draw_texture('notes', 'moji', frame=note.moji, x=x_position - (168//2) + 64, y=323 + y_position)
|
||||
|
||||
|
||||
class PracticePlayer(Player):
|
||||
def __init__(self, tja: TJAParser, player_number: int, difficulty: int, is_2p: bool, modifiers: Modifiers):
|
||||
super().__init__(tja, player_number, difficulty, is_2p, modifiers)
|
||||
self.judge_counter = JudgeCounter()
|
||||
self.gauge = None
|
||||
self.paused = False
|
||||
|
||||
def draw_note_types(self, ms_from_start: float, start_ms: float):
|
||||
if not self.paused:
|
||||
self.draw_bars(ms_from_start)
|
||||
self.draw_notes(ms_from_start, start_ms)
|
||||
|
||||
Reference in New Issue
Block a user