Hold+Slide release scoring! Practically feature-complete!

This commit is contained in:
Luke Hubmayer-Werner 2019-12-11 23:55:25 +10:30
parent 2e02e279c4
commit 794e9dd4a0
5 changed files with 158 additions and 41 deletions

View File

@ -113,4 +113,20 @@ func load_folder(folder):
return result_json.error return result_json.error
var result = result_json.result var result = result_json.result
result.directory = folder result.directory = folder
return result return result
func load_ogg(filename) -> AudioStreamOGGVorbis:
var audiostream = AudioStreamOGGVorbis.new()
var oggfile = File.new()
oggfile.open(filename, File.READ)
audiostream.set_data(oggfile.get_buffer(oggfile.get_len()))
oggfile.close()
return audiostream
func load_image(filename) -> ImageTexture:
var tex = ImageTexture.new()
var img = Image.new()
img.load(filename)
tex.create_from_image(img)
return tex

50
Menu.gd
View File

@ -44,7 +44,7 @@ func scan_library():
if dir.file_exists(key + "/song.json"): if dir.file_exists(key + "/song.json"):
song_defs[key] = FileLoader.load_folder("%s/%s" % [rootdir, key]) song_defs[key] = FileLoader.load_folder("%s/%s" % [rootdir, key])
print("Loaded song directory: %s" % key) print("Loaded song directory: %s" % key)
song_images[key] = load("%s/%s/%s" % [rootdir, key, song_defs[key]["tile_filename"]]) song_images[key] = FileLoader.load_image("%s/%s/%s" % [rootdir, key, song_defs[key]["tile_filename"]])
if song_defs[key]["genre"] in genres: if song_defs[key]["genre"] in genres:
genres[song_defs[key]["genre"]].append(key) genres[song_defs[key]["genre"]].append(key)
else: else:
@ -67,7 +67,11 @@ func save_score():
data.song_key = scorescreen_song_key data.song_key = scorescreen_song_key
var json = JSON.print(data) var json = JSON.print(data)
var file = File.new() var file = File.new()
var err = file.open(rootdir + "/{year}{month}{day}T{hour}{minute}{second}.json".format(scorescreen_datetime), File.WRITE) # var filename = rootdir + "/{year}{month}{day}T{hour}{minute}{second}.json".format(scorescreen_datetime)
# So uh. Can't zero-pad using the string.format() method. This sucks.
var dt = scorescreen_datetime
var filename = rootdir + "/%04d%02d%02dT%02d%02d%02d.json"%[dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second]
var err = file.open(filename, File.WRITE)
if err != OK: if err != OK:
print(err) print(err)
return err return err
@ -109,7 +113,7 @@ func load_score(filename):
func _ready(): func _ready():
scan_library() scan_library()
$"/root/main/NoteHandler".connect("finished_song", self, "finished_song") $"/root/main/NoteHandler".connect("finished_song", self, "finished_song")
load_score("20191210T235010.json") load_score("20191211T234131.json") # For testing purposes
# Called every frame. 'delta' is the elapsed time since the previous frame. # Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta): func _process(delta):
@ -229,11 +233,11 @@ func _draw_score_screen(center: Vector2) -> Array:
var y = center.y - 200 var y = center.y - 200
var x_songtile = x - 120 var x_songtile = x - 120
var x_score = x + 120 var x_score = x + 120
var x2 = x - 360 var x2 = x - 370
var x_spacing = 116 var x_spacing = 124
var y_spacing = 48 var y_spacing = 42
var y1 = y var y1 = y
var y2 = y + size + y_spacing*2 var y2 = y + size + y_spacing*1.5
var tex_judgement_text = $"/root/main/NoteHandler".tex_judgement_text var tex_judgement_text = $"/root/main/NoteHandler".tex_judgement_text
var judgement_text_scale = 0.667 var judgement_text_scale = 0.667
@ -242,10 +246,12 @@ func _draw_score_screen(center: Vector2) -> Array:
draw_songtile(song_key, Vector2(x_songtile-size/2.0, y), size, false, selected_difficulty, 3) draw_songtile(song_key, Vector2(x_songtile-size/2.0, y), size, false, selected_difficulty, 3)
draw_string_centered(TitleFont, Vector2(x_songtile, y+size), song_defs[song_key]["title"], Color(0.95, 0.95, 1.0)) draw_string_centered(TitleFont, Vector2(x_songtile, y+size), song_defs[song_key]["title"], Color(0.95, 0.95, 1.0))
var notestrs = ["Tap", "Hold", "Slide"] var notestrs = ["Taps:", "Holds Hit:", "Released:", "Slides Hit:", "Slid:"]
var notetypes = [0, 1, -1, 2, -2]
var note_spacing = [0.0, 1.25, 2.25, 3.5, 4.5]
var judgestrs = Array(Rules.JUDGEMENT_STRINGS + ["Miss"]) var judgestrs = Array(Rules.JUDGEMENT_STRINGS + ["Miss"])
var judge_scores = [1.0, 0.9, 0.75, 0.5, 0.0] var judge_scores = [1.0, 0.9, 0.75, 0.5, 0.0]
var notetype_weights = [1.0, 2.0, 2.0] var notetype_weights = [1.0, 1.0, 1.0, 1.0, 1.0]
var notecount_total = 0 var notecount_total = 0
var notecount_early = 0 var notecount_early = 0
var notecount_late = 0 var notecount_late = 0
@ -260,24 +266,30 @@ func _draw_score_screen(center: Vector2) -> Array:
for i in len(notestrs): for i in len(notestrs):
# For each note type, make a row and print scores # For each note type, make a row and print scores
draw_string_centered(TitleFont, Vector2(x2, y2+y_spacing*(i+1)), notestrs[i]+"s:", Color(0.95, 0.95, 1.0)) var idx = notetypes[i]
var note_score = 0 var note_score = 0
var note_count = 0 var note_count = 0
# var y_row = y2+y_spacing*(i+1)
var y_row = y2 + y_spacing * (note_spacing[i]+1)
draw_string_centered(TitleFont, Vector2(x2, y_row), notestrs[i], Color(0.95, 0.95, 1.0))
for j in len(judgestrs): for j in len(judgestrs):
var score var score
if j == 0: if j == 0:
score = scorescreen_score_data[i][0] score = scorescreen_score_data[idx][0]
elif j >= len(judgestrs)-1: elif j >= len(judgestrs)-1:
score = scorescreen_score_data[i]["MISS"] score = scorescreen_score_data[idx]["MISS"]
else: else:
score = scorescreen_score_data[i][j] + scorescreen_score_data[i][-j] score = scorescreen_score_data[idx][j] + scorescreen_score_data[idx][-j]
notecount_early += scorescreen_score_data[i][-j] notecount_early += scorescreen_score_data[idx][-j]
notecount_late += scorescreen_score_data[i][j] notecount_late += scorescreen_score_data[idx][j]
draw_string_centered(TitleFont, Vector2(x2+x_spacing*(j+1), y2+y_spacing*(i+1)), str(score), Color(0.95, 0.95, 1.0)) if (j >= len(judgestrs)-1) and (idx == -1):
draw_string_centered(TitleFont, Vector2(x2+x_spacing*(j+1), y_row), "^", Color(0.95, 0.95, 1.0))
else:
draw_string_centered(TitleFont, Vector2(x2+x_spacing*(j+1), y_row), str(score), Color(0.95, 0.95, 1.0))
notecount_total += score # Kinda redundant, will probably refactor eventually notecount_total += score # Kinda redundant, will probably refactor eventually
note_count += score note_count += score
note_score += score * judge_scores[j] note_score += score * judge_scores[j]
draw_string_centered(TitleFont, Vector2(x2+x_spacing*(len(judgestrs)+1), y2+y_spacing*(i+1)), "%2.2f%%"%(note_score/note_count*100.0), Color(0.95, 0.95, 1.0)) draw_string_centered(TitleFont, Vector2(x2+x_spacing*(len(judgestrs)+1), y_row), "%2.2f%%"%(note_score/note_count*100.0), Color(0.95, 0.95, 1.0))
total_score += note_score * notetype_weights[i] total_score += note_score * notetype_weights[i]
total_scoremax += note_count * notetype_weights[i] total_scoremax += note_count * notetype_weights[i]
@ -295,8 +307,8 @@ func _draw_score_screen(center: Vector2) -> Array:
$ScoreText.score_sub = "%2.3f%%"%(overall_score*100.0) $ScoreText.score_sub = "%2.3f%%"%(overall_score*100.0)
$ScoreText.update() $ScoreText.update()
draw_string_centered(TitleFont, Vector2(x, y2+y_spacing*4), "Early : Late", Color(0.95, 0.95, 1.0)) draw_string_centered(TitleFont, Vector2(x, y2+y_spacing*7), "Early : Late", Color(0.95, 0.95, 1.0))
draw_string_centered(TitleFont, Vector2(x, y2+y_spacing*5), "%3d%% : %3d%%"%[notecount_early*100/notecount_total, notecount_late*100/notecount_total], Color(0.95, 0.95, 1.0)) draw_string_centered(TitleFont, Vector2(x, y2+y_spacing*8), "%3d%% : %3d%%"%[notecount_early*100/notecount_total, notecount_late*100/notecount_total], Color(0.95, 0.95, 1.0))
var rect_songselect := Rect2(-100.0, 300.0, 400.0, 100.0) var rect_songselect := Rect2(-100.0, 300.0, 400.0, 100.0)
draw_rect(rect_songselect, Color.red) draw_rect(rect_songselect, Color.red)

View File

@ -6,6 +6,7 @@ extends Node
enum {NOTE_TAP, NOTE_HOLD, NOTE_SLIDE, NOTE_ARROW, NOTE_TOUCH, NOTE_TOUCH_HOLD} enum {NOTE_TAP, NOTE_HOLD, NOTE_SLIDE, NOTE_ARROW, NOTE_TOUCH, NOTE_TOUCH_HOLD}
enum SlideType {CHORD, ARC_CW, ARC_ACW} enum SlideType {CHORD, ARC_CW, ARC_ACW}
const DEATH_DELAY := 1.0 # This is touchy with the judgement windows and variable bpm. const DEATH_DELAY := 1.0 # This is touchy with the judgement windows and variable bpm.
const RELEASE_SCORE_TYPES := [NOTE_HOLD, NOTE_SLIDE, NOTE_TOUCH_HOLD]
class NoteBase: class NoteBase:
var time_hit: float var time_hit: float
@ -25,6 +26,7 @@ class NoteTap extends NoteBase:
class NoteHold extends NoteBase: class NoteHold extends NoteBase:
var type := NOTE_HOLD var type := NOTE_HOLD
var time_release: float var time_release: float
var time_released := INF
var duration: float var duration: float
var is_held: bool var is_held: bool
func _init(time_hit: float, duration: float, column: int): func _init(time_hit: float, duration: float, column: int):
@ -42,6 +44,8 @@ class NoteSlide extends NoteBase:
var column_release: int var column_release: int
var slide_type: int var slide_type: int
var slide_id: int var slide_id: int
var progress := INF
var missed_slide := false
var values: Dictionary var values: Dictionary
func _init(time_hit: float, duration: float, column: int, column_release: int, slide_type: int): func _init(time_hit: float, duration: float, column: int, column_release: int, slide_type: int):

View File

@ -62,6 +62,7 @@ var next_note_to_load := 0
var active_judgement_texts := [] var active_judgement_texts := []
var scores := {} var scores := {}
var active_slide_trails := []
var slide_trail_meshes := {} var slide_trail_meshes := {}
var slide_trail_mesh_instances := {} var slide_trail_mesh_instances := {}
@ -116,6 +117,11 @@ func initialise_scores():
scores[type] = {} scores[type] = {}
for key in TextJudgement: for key in TextJudgement:
scores[type][key] = 0 scores[type][key] = 0
# Release types
for type in [Note.NOTE_HOLD, Note.NOTE_SLIDE]:
scores[-type] = {}
for key in TextJudgement:
scores[-type][key] = 0
func make_text_mesh(mesh: ArrayMesh, text_id: int, pos: Vector2, angle: float, alpha:=1.0, scale:=1.0): func make_text_mesh(mesh: ArrayMesh, text_id: int, pos: Vector2, angle: float, alpha:=1.0, scale:=1.0):
var r := GameTheme.judge_text_size2 * scale var r := GameTheme.judge_text_size2 * scale
@ -270,8 +276,24 @@ func activate_note(note, judgement):
Note.NOTE_HOLD: Note.NOTE_HOLD:
note.is_held = true note.is_held = true
Note.NOTE_SLIDE: Note.NOTE_SLIDE:
pass # Set up slide trail? # Set up slide trail?
return active_slide_trails.append(note)
note.progress = 0.0
func activate_note_release(note, judgement):
# Only for Hold, Slide
SFXPlayer.play(SFXPlayer.Type.NON_POSITIONAL, self, snd_judgement[judgement], db_judgement[judgement], pitch_judgement[judgement])
scores[-note.type][judgement] += 1
match note.type:
Note.NOTE_HOLD:
note.is_held = false
note.time_released = t
active_judgement_texts.append({col=note.column, judgement=judgement, time=t})
Note.NOTE_SLIDE:
active_judgement_texts.append({col=note.column_release, judgement=judgement, time=t})
Note.NOTE_TOUCH_HOLD:
pass
func button_pressed(col): func button_pressed(col):
for note in active_notes: for note in active_notes:
@ -283,37 +305,65 @@ func button_pressed(col):
var hit_delta = get_realtime_precise() - real_time(note.time_hit) # Judgement times are in seconds not gametime var hit_delta = get_realtime_precise() - real_time(note.time_hit) # Judgement times are in seconds not gametime
if hit_delta >= 0.0: if hit_delta >= 0.0:
if hit_delta > Rules.JUDGEMENT_TIMES_POST[-1]: if hit_delta > Rules.JUDGEMENT_TIMES_POST[-1]:
continue # missed continue # missed, don't consume input
for i in Rules.JUDGEMENT_TIERS: for i in Rules.JUDGEMENT_TIERS:
if hit_delta <= Rules.JUDGEMENT_TIMES_POST[i]: if hit_delta <= Rules.JUDGEMENT_TIMES_POST[i]:
activate_note(note, i) activate_note(note, i)
return return # Consume input because one press shouldn't trigger two notes
else: else:
if -hit_delta > Rules.JUDGEMENT_TIMES_PRE[-1]: if -hit_delta > Rules.JUDGEMENT_TIMES_PRE[-1]:
continue # too far away continue # too far away, don't consume input
for i in Rules.JUDGEMENT_TIERS: for i in Rules.JUDGEMENT_TIERS:
if -hit_delta <= Rules.JUDGEMENT_TIMES_POST[i]: if -hit_delta <= Rules.JUDGEMENT_TIMES_PRE[i]:
activate_note(note, -i) activate_note(note, -i)
return return
func touchbutton_pressed(col): func touchbutton_pressed(col):
button_pressed(col) button_pressed(col)
func do_hold_release(note):
var hit_delta = get_realtime_precise() - real_time(note.time_release) # Judgement times are in seconds not gametime
if hit_delta >= 0.0:
for i in Rules.JUDGEMENT_TIERS-1:
if hit_delta <= Rules.JUDGEMENT_TIMES_RELEASE_POST[i]:
activate_note_release(note, i)
return
activate_note_release(note, Rules.JUDGEMENT_TIERS-1) # No "miss" for releasing, only worst judgement.
return
else:
for i in Rules.JUDGEMENT_TIERS-1:
if -hit_delta <= Rules.JUDGEMENT_TIMES_RELEASE_PRE[i]:
activate_note_release(note, -i)
return
activate_note_release(note, Rules.JUDGEMENT_TIERS-1) # No "miss" for releasing, only worst judgement.
return
func do_slide_release(note):
var hit_delta = get_realtime_precise() - real_time(note.time_release) # Judgement times are in seconds not gametime
if hit_delta >= 0.0:
for i in Rules.JUDGEMENT_TIERS:
if hit_delta <= Rules.JUDGEMENT_TIMES_SLIDE_POST[i]:
activate_note_release(note, i)
return
else:
for i in Rules.JUDGEMENT_TIERS:
if -hit_delta <= Rules.JUDGEMENT_TIMES_SLIDE_PRE[i]:
activate_note_release(note, -i)
return
func check_hold_release(col): func check_hold_release(col):
for note in active_notes: for note in active_notes:
if note.column != col: if note.column != col:
continue continue
if note.type == Note.NOTE_HOLD: if note.type == Note.NOTE_HOLD:
if note.is_held == true: if note.is_held == true:
note.is_held = false do_hold_release(note) # Separate function since there's no need to "consume" releases
pass
func button_released(col): func button_released(col):
# We only care about hold release. # We only care about hold release.
# For that particular case, we want both to be unheld. # For that particular case, we want both to be unheld.
if $"/root/main/InputHandler".touchbuttons_pressed[col] == 0: if $"/root/main/InputHandler".touchbuttons_pressed[col] == 0:
check_hold_release(col) check_hold_release(col)
func touchbutton_released(col): func touchbutton_released(col):
if $"/root/main/InputHandler".buttons_pressed[col] == 0: if $"/root/main/InputHandler".buttons_pressed[col] == 0:
check_hold_release(col) check_hold_release(col)
@ -345,10 +395,14 @@ func _draw():
make_tap_mesh(mesh, note_center, scale, color) make_tap_mesh(mesh, note_center, scale, color)
Note.NOTE_HOLD: Note.NOTE_HOLD:
if note.is_held: if note.is_held:
position = (t+GameTheme.note_forecast_beats-note.time_release)/GameTheme.note_forecast_beats
color = GameTheme.COLOR_ARRAY_HOLD_HELD color = GameTheme.COLOR_ARRAY_HOLD_HELD
note_center = GameTheme.RADIAL_UNIT_VECTORS[note.column] * GameTheme.receptor_ring_radius note_center = GameTheme.RADIAL_UNIT_VECTORS[note.column] * GameTheme.receptor_ring_radius * max(position, 1.0)
elif position > 1.0: elif position > 1.0:
color = GameTheme.COLOR_ARRAY_DOUBLE_MISS_8 if note.double_hit else GameTheme.COLOR_ARRAY_HOLD_MISS color = GameTheme.COLOR_ARRAY_DOUBLE_MISS_8 if note.double_hit else GameTheme.COLOR_ARRAY_HOLD_MISS
if note.time_released != INF:
position = (t+GameTheme.note_forecast_beats-note.time_released)/GameTheme.note_forecast_beats
note_center = GameTheme.RADIAL_UNIT_VECTORS[note.column] * GameTheme.receptor_ring_radius * position
else: else:
color = GameTheme.COLOR_ARRAY_DOUBLE_8 if note.double_hit else GameTheme.COLOR_ARRAY_HOLD color = GameTheme.COLOR_ARRAY_DOUBLE_8 if note.double_hit else GameTheme.COLOR_ARRAY_HOLD
var position_rel : float = (t+GameTheme.note_forecast_beats-note.time_release)/GameTheme.note_forecast_beats var position_rel : float = (t+GameTheme.note_forecast_beats-note.time_release)/GameTheme.note_forecast_beats
@ -374,7 +428,8 @@ func _draw():
var star_pos : Vector2 = note.get_position(trail_progress) var star_pos : Vector2 = note.get_position(trail_progress)
var star_angle : float = note.get_angle(trail_progress) var star_angle : float = note.get_angle(trail_progress)
make_star_mesh(mesh, star_pos, 1.33, star_angle, color) make_star_mesh(mesh, star_pos, 1.33, star_angle, color)
# slide_trail_mesh_instances[note.slide_id].material.set_shader_param("trail_progress", trail_progress) if note.progress != INF:
slide_trail_mesh_instances[note.slide_id].material.set_shader_param("trail_progress", note.progress)
if t > note.time_release: if t > note.time_release:
trail_alpha = max(1 - (t - note.time_release)/Note.DEATH_DELAY, 0.0) trail_alpha = max(1 - (t - note.time_release)/Note.DEATH_DELAY, 0.0)
slide_trail_mesh_instances[note.slide_id].material.set_shader_param("base_alpha", trail_alpha*0.88) slide_trail_mesh_instances[note.slide_id].material.set_shader_param("base_alpha", trail_alpha*0.88)
@ -392,6 +447,29 @@ func _draw():
make_judgement_text(textmesh, TextJudgement[text.judgement], text.col, (t-text.time)/GameTheme.judge_text_duration) make_judgement_text(textmesh, TextJudgement[text.judgement], text.col, (t-text.time)/GameTheme.judge_text_duration)
$JudgeText.set_mesh(textmesh) $JudgeText.set_mesh(textmesh)
func _input(event):
var pos
if event is InputEventScreenTouch:
if event.pressed:
pos = event.position - get_global_transform_with_canvas().get_origin()
else:
return
elif event is InputEventScreenDrag:
pos = event.position - get_global_transform_with_canvas().get_origin()
else:
return
for i in range(len(active_slide_trails)-1, -1, -1):
var note = active_slide_trails[i]
var center = note.get_position(note.progress)
if (pos - center).length_squared() < 10000.0:
note.progress += 0.09
if note.progress >= 1.0:
do_slide_release(note)
active_slide_trails.remove(i)
func _init(): func _init():
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN) Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
GameTheme.init_radial_values() GameTheme.init_radial_values()
@ -440,14 +518,7 @@ func load_track(data: Dictionary, difficulty_idx: int):
bpm = data.bpm_values[0] bpm = data.bpm_values[0]
sync_offset_audio = data.audio_offsets[0] sync_offset_audio = data.audio_offsets[0]
sync_offset_video = data.video_offsets[0] sync_offset_video = data.video_offsets[0]
var audiostream = AudioStreamOGGVorbis.new() var audiostream = FileLoader.load_ogg(data.directory + "/" + data.audio_filelist[0])
# var asb = load(data.directory + "/" + data.audio_filelist[0])
# audiostream.set_data(asb.get_data())
# Unbelievably stupid bug, infuriating workaround
var oggfile = File.new()
oggfile.open(data.directory + "/" + data.audio_filelist[0], File.READ)
audiostream.set_data(oggfile.get_buffer(oggfile.get_len()))
oggfile.close()
var videostream = load(data.directory + "/" + data.video_filelist[0]) var videostream = load(data.directory + "/" + data.video_filelist[0])
$"/root/main/music".set_stream(audiostream) $"/root/main/music".set_stream(audiostream)
@ -533,13 +604,26 @@ func _process(delta):
if note.type == Note.NOTE_SLIDE: if note.type == Note.NOTE_SLIDE:
$SlideTrailHandler.remove_child(slide_trail_mesh_instances[note.slide_id]) $SlideTrailHandler.remove_child(slide_trail_mesh_instances[note.slide_id])
slide_trail_mesh_instances.erase(note.slide_id) slide_trail_mesh_instances.erase(note.slide_id)
var idx = active_slide_trails.find(note)
if idx >= 0:
active_slide_trails.remove(idx)
active_judgement_texts.append({col=note.column_release, judgement="MISS", time=t})
scores[-Note.NOTE_SLIDE]["MISS"] += 1
note.missed_slide = true
SFXPlayer.play(SFXPlayer.Type.NON_POSITIONAL, self, snd_judgement["MISS"], db_judgement["MISS"])
active_notes.remove(i) active_notes.remove(i)
elif note.time_activated == INF: elif note.time_activated == INF:
if ((t-note.time_hit) > miss_time) and not note.missed: if ((t-note.time_hit) > miss_time) and not note.missed:
active_judgement_texts.append({col=note.column, judgement="MISS", time=t}) active_judgement_texts.append({col=note.column, judgement="MISS", time=t})
scores[note.type]["MISS"] += 1 scores[note.type]["MISS"] += 1
if Note.RELEASE_SCORE_TYPES.has(note.type):
scores[-note.type]["MISS"] += 1
note.missed = true note.missed = true
SFXPlayer.play(SFXPlayer.Type.NON_POSITIONAL, self, snd_judgement["MISS"], db_judgement["MISS"]) SFXPlayer.play(SFXPlayer.Type.NON_POSITIONAL, self, snd_judgement["MISS"], db_judgement["MISS"])
if note.type == Note.NOTE_SLIDE:
# Even if you miss the hit you can still slide, we're so nice
active_slide_trails.append(note)
note.progress = 0.0
# Clean out expired judgement texts # Clean out expired judgement texts
# By design they will always be in order so we can ignore anything past the first index # By design they will always be in order so we can ignore anything past the first index
@ -574,6 +658,7 @@ func _process(delta):
# next_note_to_load = 0 # next_note_to_load = 0
if (len(active_notes) < 1) and (next_note_to_load >= len(all_notes)) and not get_node("/root/main/music").is_playing(): if (len(active_notes) < 1) and (next_note_to_load >= len(all_notes)) and not get_node("/root/main/music").is_playing():
self.running = false self.running = false
self.timers_set = false
emit_signal("finished_song", song_key, scores) emit_signal("finished_song", song_key, scores)
# Redraw # Redraw

View File

@ -13,7 +13,7 @@ const JUDGEMENT_TIMES_PRE := [0.040, 0.090, 0.125, 0.150]
const JUDGEMENT_TIMES_POST := [0.040, 0.090, 0.125, 0.150] const JUDGEMENT_TIMES_POST := [0.040, 0.090, 0.125, 0.150]
const JUDGEMENT_TIMES_RELEASE_PRE := [0.040, 0.090, 0.125, 0.150] const JUDGEMENT_TIMES_RELEASE_PRE := [0.040, 0.090, 0.125, 0.150]
const JUDGEMENT_TIMES_RELEASE_POST := [0.090, 0.140, 0.175, 0.200] # Small grace period const JUDGEMENT_TIMES_RELEASE_POST := [0.090, 0.140, 0.175, 0.200] # Small grace period
const JUDGEMENT_TIMES_SLIDE_PRE := [0.090, 0.140, 0.175, 0.200] # Small grace period, sort-of const JUDGEMENT_TIMES_SLIDE_PRE := [0.090, 0.240, 0.375, 60.000] # Small grace period, sort-of. Just be generous, really.
const JUDGEMENT_TIMES_SLIDE_POST := [0.090, 0.140, 0.175, 0.200] const JUDGEMENT_TIMES_SLIDE_POST := [0.090, 0.140, 0.175, 0.200]
const SCORE_STRINGS = ["SSS", "SS", "S", "A⁺", "A", "B⁺", "B", "C⁺", "C", "F"] const SCORE_STRINGS = ["SSS", "SS", "S", "A⁺", "A", "B⁺", "B", "C⁺", "C", "F"]