Add #SUDDEN, #DELAY

This commit is contained in:
Anthony Samms
2025-11-14 19:13:54 -05:00
parent 540df313db
commit 9ed4ea6c59
4 changed files with 143 additions and 15 deletions

83
docs/tja_compat.csv Normal file
View 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
1 TITLE Supported
2 SUBTITLE Supported
3 WAVE Supported
4 DEMOSTART Supported
5 OFFSET Supported
6 BPM Supported
7 SCENEPRESET Supported
8 BGMOVIE Supported
9 COURSE Supported
10 LEVEL Supported
11 BALLOON Supported
12 TOTAL Supported
13 #START / #END Supported
14 #BPMCHANGE Supported
15 #MEASURE Supported
16 #GOGOSTART / #GOGOEND Supported
17 #SCROLL Supported
18 #BARLINEOFF / #BARLINEON Supported
19 #LYRIC Supported
20 #SECTION Supported
21 #BRANCHSTART / #BRANCHEND Supported
22 #N / #E / #M Supported
23 #DELAY Supported
24 #SUDDEN Supported
25 ARTIST Unsupported
26 MAKER Unsupported
27 NOTESDESIGNER Unsupported
28 AUTHOR Unsupported
29 GENRE Unsupported
30 SIDE Unsupported
31 SIDEREV Unsupported
32 SONGVOL Unsupported
33 SEVOL Unsupported
34 HEADSCROLL Unsupported
35 PREIMAGE Unsupported
36 TAIKOWEBSKIN Unsupported
37 TOWERTYPE Unsupported
38 DANTICK Unsupported
39 DANTICKCOLOR Unsupported
40 SELECTBG Unsupported
41 BGIMAGE Unsupported
42 BGOFFSET Unsupported
43 MOVIEOFFSET Unsupported
44 BGA Headers Unsupported
45 LYRICS: / LYRICFILE Unsupported
46 EXPLICIT Unsupported
47 GAME Unsupported
48 STYLE Unsupported
49 LIFE Unsupported
50 GAUGEINCR Unsupported
51 EXAM Unsupported
52 SCOREMODE Unsupported
53 SCOREINIT Unsupported
54 SCOREDIFF Unsupported
55 HIDDENBRANCH Unsupported
56 #BMSCROLL / #HBSCROLL / #NMSCROLL Unsupported
57 #PAPAMAMA Unsupported
58 #DUMMYSTART / #DUMMYEND Unsupported
59 #BARLINESCROLL Unsupported
60 #HISPEED Unsupported
61 #DIRECTION Unsupported
62 #BARLINE Unsupported
63 #JPOSSCROLL Unsupported
64 #JUDGEDELAY Unsupported
65 #NOTESPAWN Unsupported
66 #SENOTECHANGE Unsupported
67 #NOTESCHANGE Unsupported
68 #LEVELHOLD Unsupported
69 #NEXTSONG Unsupported
70 #GAMETYPE Unsupported
71 #HIDDEN Unsupported
72 #NOTE / #BARLINE Unsupported
73 #GRADATION Unsupported
74 #INCLUDE Unsupported
75 #SPLITLANE / #MERGELANE Unsupported
76 #OBJ / #CAM Unsupported
77 #BORDERCOLOR Unsupported
78 #CHANGETEXTURE / #RESETTEXTURE Unsupported
79 #SETCONFIG Unsupported
80 #BGAON / #BGAOFF Unsupported

View File

@@ -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

View File

@@ -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)

View File

@@ -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: