mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 11:40:13 +01:00
Add #SUDDEN, #DELAY
This commit is contained in:
83
docs/tja_compat.csv
Normal file
83
docs/tja_compat.csv
Normal file
@@ -0,0 +1,83 @@
|
||||
TITLE,Supported
|
||||
SUBTITLE,Supported
|
||||
WAVE,Supported
|
||||
DEMOSTART,Supported
|
||||
OFFSET,Supported
|
||||
BPM,Supported
|
||||
SCENEPRESET,Supported
|
||||
BGMOVIE,Supported
|
||||
COURSE,Supported
|
||||
LEVEL,Supported
|
||||
BALLOON,Supported
|
||||
TOTAL,Supported
|
||||
|
||||
#START / #END,Supported
|
||||
#BPMCHANGE,Supported
|
||||
#MEASURE,Supported
|
||||
#GOGOSTART / #GOGOEND,Supported
|
||||
#SCROLL,Supported
|
||||
#BARLINEOFF / #BARLINEON,Supported
|
||||
#LYRIC,Supported
|
||||
#SECTION,Supported
|
||||
#BRANCHSTART / #BRANCHEND,Supported
|
||||
#N / #E / #M,Supported
|
||||
#DELAY,Supported
|
||||
#SUDDEN,Supported
|
||||
|
||||
ARTIST,Unsupported
|
||||
MAKER,Unsupported
|
||||
NOTESDESIGNER,Unsupported
|
||||
AUTHOR,Unsupported
|
||||
GENRE,Unsupported
|
||||
SIDE,Unsupported
|
||||
SIDEREV,Unsupported
|
||||
SONGVOL,Unsupported
|
||||
SEVOL,Unsupported
|
||||
HEADSCROLL,Unsupported
|
||||
PREIMAGE,Unsupported
|
||||
TAIKOWEBSKIN,Unsupported
|
||||
TOWERTYPE,Unsupported
|
||||
DANTICK,Unsupported
|
||||
DANTICKCOLOR,Unsupported
|
||||
SELECTBG,Unsupported
|
||||
BGIMAGE,Unsupported
|
||||
BGOFFSET,Unsupported
|
||||
MOVIEOFFSET,Unsupported
|
||||
BGA Headers,Unsupported
|
||||
LYRICS: / LYRICFILE,Unsupported
|
||||
EXPLICIT,Unsupported
|
||||
GAME,Unsupported
|
||||
STYLE,Unsupported
|
||||
LIFE,Unsupported
|
||||
GAUGEINCR,Unsupported
|
||||
EXAM,Unsupported
|
||||
SCOREMODE,Unsupported
|
||||
SCOREINIT,Unsupported
|
||||
SCOREDIFF,Unsupported
|
||||
HIDDENBRANCH,Unsupported
|
||||
|
||||
#BMSCROLL / #HBSCROLL / #NMSCROLL,Unsupported
|
||||
#PAPAMAMA,Unsupported
|
||||
#DUMMYSTART / #DUMMYEND,Unsupported
|
||||
#BARLINESCROLL,Unsupported
|
||||
#HISPEED,Unsupported
|
||||
#DIRECTION,Unsupported
|
||||
#BARLINE,Unsupported
|
||||
#JPOSSCROLL,Unsupported
|
||||
#JUDGEDELAY,Unsupported
|
||||
#NOTESPAWN,Unsupported
|
||||
#SENOTECHANGE,Unsupported
|
||||
#NOTESCHANGE,Unsupported
|
||||
#LEVELHOLD,Unsupported
|
||||
#NEXTSONG,Unsupported
|
||||
#GAMETYPE,Unsupported
|
||||
#HIDDEN,Unsupported
|
||||
#NOTE / #BARLINE,Unsupported
|
||||
#GRADATION,Unsupported
|
||||
#INCLUDE,Unsupported
|
||||
#SPLITLANE / #MERGELANE,Unsupported
|
||||
#OBJ / #CAM,Unsupported
|
||||
#BORDERCOLOR,Unsupported
|
||||
#CHANGETEXTURE / #RESETTEXTURE,Unsupported
|
||||
#SETCONFIG,Unsupported
|
||||
#BGAON / #BGAOFF,Unsupported
|
||||
|
29
libs/tja.py
29
libs/tja.py
@@ -70,6 +70,8 @@ class Note:
|
||||
is_branch_start: bool = field(init=False)
|
||||
branch_params: str = field(init=False)
|
||||
lyric: str = field(init=False)
|
||||
sudden_appear_ms: float = field(init=False)
|
||||
sudden_moving_ms: float = field(init=False)
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.hit_ms < other.hit_ms
|
||||
@@ -623,6 +625,8 @@ class TJAParser:
|
||||
balloon = self.metadata.course_data[diff].balloon.copy()
|
||||
count = 0
|
||||
index = 0
|
||||
sudden_appear = 0
|
||||
sudden_moving = 0
|
||||
time_signature = 4/4
|
||||
bpm = self.metadata.bpm
|
||||
x_scroll_modifier = 1
|
||||
@@ -788,6 +792,26 @@ class TJAParser:
|
||||
elif '#GOGOEND' in part:
|
||||
gogo_time = False
|
||||
continue
|
||||
elif part.startswith("#DELAY"):
|
||||
self.current_ms += float(part[6:]) * 1000
|
||||
continue
|
||||
elif part.startswith("#SUDDEN"):
|
||||
# Parse #SUDDEN command
|
||||
parts = part.split()
|
||||
if len(parts) >= 3:
|
||||
appear_duration = float(parts[1])
|
||||
moving_duration = float(parts[2])
|
||||
|
||||
# Convert to milliseconds
|
||||
sudden_appear = appear_duration * 1000
|
||||
sudden_moving = moving_duration * 1000
|
||||
|
||||
# Handle special case: if value is 0, treat as infinity
|
||||
if sudden_appear == 0:
|
||||
sudden_appear = float('inf')
|
||||
if sudden_moving == 0:
|
||||
sudden_moving = float('inf')
|
||||
continue
|
||||
#Unrecognized commands will be skipped for now
|
||||
elif len(part) > 0 and not part[0].isdigit():
|
||||
logger.warning(f"Unrecognized command: {part}")
|
||||
@@ -856,6 +880,11 @@ class TJAParser:
|
||||
note.gogo_time = gogo_time
|
||||
note.moji = -1
|
||||
note.lyric = lyric
|
||||
|
||||
if sudden_appear > 0 or sudden_moving > 0:
|
||||
note.sudden_appear_ms = sudden_appear
|
||||
note.sudden_moving_ms = sudden_moving
|
||||
|
||||
if item in {'5', '6'}:
|
||||
note = Drumroll(note)
|
||||
note.color = 255
|
||||
|
||||
@@ -1015,8 +1015,6 @@ class Player:
|
||||
if not self.current_bars:
|
||||
return
|
||||
|
||||
# Batch bar draws by pre-calculating positions
|
||||
bar_draws = []
|
||||
for bar in reversed(self.current_bars):
|
||||
if not bar.display:
|
||||
continue
|
||||
@@ -1026,17 +1024,17 @@ class Player:
|
||||
frame = 1
|
||||
else:
|
||||
frame = 0
|
||||
bar_draws.append((str(bar.type), frame, x_position+60, y_position+190+(self.is_2p*176)))
|
||||
if y_position != 0:
|
||||
angle = math.degrees(math.atan2(bar.pixels_per_frame_y, bar.pixels_per_frame_x))
|
||||
else:
|
||||
angle = 0
|
||||
tex.draw_texture('notes', str(bar.type), frame=frame, x=x_position+60, y=y_position+190+(self.is_2p*176), rotation=angle)
|
||||
|
||||
# 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)
|
||||
|
||||
def draw_notes(self, current_ms: float, start_ms: float):
|
||||
"""Draw notes in the player's lane"""
|
||||
if not self.current_notes_draw:
|
||||
return
|
||||
|
||||
eighth_in_ms = 0 if self.bpm == 0 else (60000 * 4 / self.bpm) / 8
|
||||
current_eighth = 0
|
||||
if self.combo >= 50 and eighth_in_ms != 0:
|
||||
@@ -1048,19 +1046,34 @@ class Player:
|
||||
if note.type == NoteType.TAIL:
|
||||
continue
|
||||
|
||||
if isinstance(note, Drumroll):
|
||||
self.draw_drumroll(current_ms, note, current_eighth)
|
||||
elif isinstance(note, Balloon) and not note.is_kusudama:
|
||||
x_position = self.get_position_x(SCREEN_WIDTH, current_ms, note.load_ms, note.pixels_per_frame_x)
|
||||
y_position = self.get_position_y(current_ms, note.load_ms, note.pixels_per_frame_y, note.pixels_per_frame_x)
|
||||
self.draw_balloon(current_ms, note, current_eighth)
|
||||
tex.draw_texture('notes', 'moji', frame=note.moji, x=x_position - (168//2) + 64, y=323 + y_position+(self.is_2p*176))
|
||||
if hasattr(note, 'sudden_appear_ms') and hasattr(note, 'sudden_moving_ms'):
|
||||
appear_ms = note.hit_ms - note.sudden_appear_ms
|
||||
moving_start_ms = note.hit_ms - note.sudden_moving_ms
|
||||
|
||||
if current_ms < appear_ms:
|
||||
continue
|
||||
|
||||
if current_ms < moving_start_ms:
|
||||
effective_ms = moving_start_ms
|
||||
else:
|
||||
effective_ms = current_ms
|
||||
|
||||
x_position = self.get_position_x(SCREEN_WIDTH, effective_ms, note.load_ms, note.pixels_per_frame_x)
|
||||
y_position = self.get_position_y(effective_ms, note.load_ms, note.pixels_per_frame_y, note.pixels_per_frame_x)
|
||||
else:
|
||||
x_position = self.get_position_x(SCREEN_WIDTH, current_ms, note.load_ms, note.pixels_per_frame_x)
|
||||
y_position = self.get_position_y(current_ms, note.load_ms, note.pixels_per_frame_y, note.pixels_per_frame_x)
|
||||
|
||||
if isinstance(note, Drumroll):
|
||||
self.draw_drumroll(current_ms, note, current_eighth)
|
||||
elif isinstance(note, Balloon) and not note.is_kusudama:
|
||||
self.draw_balloon(current_ms, note, current_eighth)
|
||||
tex.draw_texture('notes', 'moji', frame=note.moji, x=x_position - (168//2) + 64, y=323 + y_position+(self.is_2p*176))
|
||||
else:
|
||||
if note.display:
|
||||
tex.draw_texture('notes', str(note.type), frame=current_eighth % 2, x=x_position, y=y_position+192+(self.is_2p*176), center=True)
|
||||
tex.draw_texture('notes', 'moji', frame=note.moji, x=x_position - (168//2) + 64, y=323 + y_position+(self.is_2p*176))
|
||||
|
||||
ray.draw_text(self.current_notes_draw[0].lyric, SCREEN_WIDTH//2 - (ray.measure_text(self.current_notes_draw[0].lyric, 40)//2), SCREEN_HEIGHT - 50, 40, ray.BLUE)
|
||||
|
||||
|
||||
|
||||
@@ -131,7 +131,10 @@ class PracticeGameScreen(GameScreen):
|
||||
self.transition.update(current_time)
|
||||
if not self.paused:
|
||||
self.current_ms = current_time - self.start_ms
|
||||
self.start_song(current_time)
|
||||
if self.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:
|
||||
|
||||
Reference in New Issue
Block a user