From f8841bab35cf2bf26b70286bf723cb9739ecc735 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Mon, 2 Mar 2026 01:51:28 -0500 Subject: [PATCH] Use a float internally to hold the Score, ensuring hold notes get scored correctly relative to the current framerate. --- source/funkin/modding/events/ScriptEvent.hx | 12 +++---- source/funkin/play/PlayState.hx | 35 ++++++++++----------- source/funkin/util/Constants.hx | 5 +++ 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/source/funkin/modding/events/ScriptEvent.hx b/source/funkin/modding/events/ScriptEvent.hx index 46889032d..48094ce2e 100644 --- a/source/funkin/modding/events/ScriptEvent.hx +++ b/source/funkin/modding/events/ScriptEvent.hx @@ -140,7 +140,7 @@ class HitNoteScriptEvent extends NoteScriptEvent /** * The score the player received for hitting the note. */ - public var score:Int; + public var score:Float; /** * If the hit causes a combo break. @@ -158,7 +158,7 @@ class HitNoteScriptEvent extends NoteScriptEvent */ public var doesNotesplash:Bool = false; - public function new(note:NoteSprite, healthChange:Float, score:Int, judgement:String, isComboBreak:Bool, comboCount:Int = 0, hitDiff:Float = 0, + public function new(note:NoteSprite, healthChange:Float, score:Float, judgement:String, isComboBreak:Bool, comboCount:Int = 0, hitDiff:Float = 0, doesNotesplash:Bool = false):Void { super(NOTE_HIT, note, healthChange, comboCount, true); @@ -200,7 +200,7 @@ class GhostMissNoteScriptEvent extends ScriptEvent /** * How much score should be lost when this ghost note is pressed. */ - public var scoreChange(default, default):Int; + public var scoreChange(default, default):Float; /** * Whether to play the record scratch sound. @@ -212,7 +212,7 @@ class GhostMissNoteScriptEvent extends ScriptEvent */ public var playAnim(default, default):Bool; - public function new(dir:NoteDirection, hasPossibleNotes:Bool, healthChange:Float, scoreChange:Int):Void + public function new(dir:NoteDirection, hasPossibleNotes:Bool, healthChange:Float, scoreChange:Float):Void { super(NOTE_GHOST_MISS, true); this.dir = dir; @@ -239,7 +239,7 @@ class HoldNoteScriptEvent extends NoteScriptEvent /** * The score the player received for hitting the note. */ - public var score:Int; + public var score:Float; /** * If the hit causes a combo break. @@ -257,7 +257,7 @@ class HoldNoteScriptEvent extends NoteScriptEvent */ public var doesNotesplash:Bool = false; - public function new(type:ScriptEventType, holdNote:SustainTrail, healthChange:Float, score:Int, isComboBreak:Bool, comboCount:Int = 0, + public function new(type:ScriptEventType, holdNote:SustainTrail, healthChange:Float, score:Float, isComboBreak:Bool, comboCount:Int = 0, cancelable:Bool = false):Void { super(type, null, healthChange, comboCount, true); diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 4948e51a1..3e6ffc113 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -239,9 +239,10 @@ class PlayState extends MusicBeatSubState /** * The player's current score. - * TODO: Move this to its own class. + * This needs to be a float because you gain partial points as you hold a hold note, + * possibly less than one point each update depending on your framerate. */ - public var songScore:Int = 0; + public var songScore:Float = 0; /** * Start at this point in the song once the countdown is done. @@ -1119,7 +1120,7 @@ class PlayState extends MusicBeatSubState cameraZoomRate = Constants.DEFAULT_ZOOM_RATE; health = Constants.HEALTH_STARTING; - songScore = 0; + songScore = 0.0; Highscore.tallies.combo = 0; // so the song doesn't start too early :D @@ -1445,7 +1446,7 @@ class PlayState extends MusicBeatSubState vwooshTimer.cancel(); - songScore = 0; + songScore = 0.0; updateScoreText(); health = Constants.HEALTH_STARTING; @@ -2704,9 +2705,9 @@ class PlayState extends MusicBeatSubState } else { - // TODO: Add an option for this maybe? - var commaSeparated:Bool = true; - scoreText.text = 'Score: ${FlxStringUtil.formatMoney(songScore, false, commaSeparated)}'; + final SHOW_DECIMALS:Bool = false; + final COMMA_SEPARATED:Bool = true; + scoreText.text = 'Score: ${FlxStringUtil.formatMoney(songScore, SHOW_DECIMALS, COMMA_SEPARATED)}'; } } @@ -2872,7 +2873,7 @@ class PlayState extends MusicBeatSubState if (!isBotPlayMode && holdNote.scoreable) { health += Constants.HEALTH_HOLD_BONUS_PER_SECOND * elapsed; - songScore += Std.int(Constants.SCORE_HOLD_BONUS_PER_SECOND * elapsed); + songScore += Constants.SCORE_HOLD_BONUS_PER_SECOND * elapsed; } // Make sure the player keeps singing while the note is held by the bot. @@ -2905,7 +2906,7 @@ class PlayState extends MusicBeatSubState // If the base note of the hold was missed, don't penalize them more on top of that. var healthChangeMax = Constants.HEALTH_HOLD_DROP_PENALTY_MAX - (holdNote.hitNote ? -Constants.HEALTH_MISS_PENALTY : 0); var healthChange = healthChangeUncapped.clamp(healthChangeMax, 0); - var scoreChange = Std.int(Constants.SCORE_HOLD_DROP_PENALTY_PER_SECOND * remainingLengthSec); + var scoreChange:Float = Constants.SCORE_HOLD_DROP_PENALTY_PER_SECOND * remainingLengthSec; var event:HoldNoteScriptEvent = new HoldNoteScriptEvent(NOTE_HOLD_DROP, holdNote, healthChange, scoreChange, true, Highscore.tallies.combo); dispatchEvent(event); @@ -3021,9 +3022,7 @@ class PlayState extends MusicBeatSubState if (targetNote == null) continue; // Judge and hit the note. - // trace('Hit note! ${targetNote.noteData}'); goodNoteHit(targetNote, input); - // trace('Score: ${songScore}'); notesInDirection.remove(targetNote); @@ -3150,7 +3149,7 @@ class PlayState extends MusicBeatSubState var event:GhostMissNoteScriptEvent = new GhostMissNoteScriptEvent(direction, // Direction missed in. hasPossibleNotes, // Whether there was a note you could have hit. Constants.HEALTH_GHOST_MISS_PENALTY, // How much health to add (negative). - - 10 // Amount of score to add (negative). + Constants.SCORE_GHOST_MISS_PENALTY // Amount of score to add (negative). ); dispatchEvent(event); @@ -3269,7 +3268,7 @@ class PlayState extends MusicBeatSubState /** * Handles applying health, score, and ratings. */ - function applyScore(score:Int, daRating:String, healthChange:Float, isComboBreak:Bool) + function applyScore(score:Float, daRating:String, healthChange:Float, isComboBreak:Bool) { switch (daRating) { @@ -3426,7 +3425,7 @@ class PlayState extends MusicBeatSubState { // crackhead double thingie, sets whether was new highscore, AND saves the song! var data = { - score: songScore, + score: Std.int(songScore), tallies: { sick: Highscore.tallies.sick, good: Highscore.tallies.good, @@ -3444,7 +3443,7 @@ class PlayState extends MusicBeatSubState Highscore.talliesLevel = Highscore.combineTallies(Highscore.tallies, Highscore.talliesLevel); #if FEATURE_NEWGROUNDS - Leaderboards.submitSongScore(currentSong.id, suffixedDifficulty, songScore); + Leaderboards.submitSongScore(currentSong.id, suffixedDifficulty, Std.int(songScore)); #end if (!isPracticeMode && !isBotPlayMode) @@ -3475,7 +3474,7 @@ class PlayState extends MusicBeatSubState // Determine the score rank for this song we just finished. var scoreRank:Null = Scoring.calculateRank({ - score: songScore, + score: Std.int(songScore), tallies: { sick: Highscore.tallies.sick, good: Highscore.tallies.good, @@ -3510,7 +3509,7 @@ class PlayState extends MusicBeatSubState { isNewHighscore = false; - PlayStatePlaylist.campaignScore += songScore; + PlayStatePlaylist.campaignScore += Std.int(songScore); // Pop the next song ID from the list. // Returns null if the list is empty. @@ -3836,7 +3835,7 @@ class PlayState extends MusicBeatSubState title: PlayStatePlaylist.isStoryMode ? ('${PlayStatePlaylist.campaignTitle}') : ('${currentChart.songName} by ${currentChart.songArtist}'), prevScoreData: prevScoreData, scoreData: { - score: PlayStatePlaylist.isStoryMode ? PlayStatePlaylist.campaignScore : songScore, + score: PlayStatePlaylist.isStoryMode ? PlayStatePlaylist.campaignScore : Std.int(songScore), tallies: { sick: talliesToUse.sick, good: talliesToUse.good, diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index 80dcc6d58..39253a23f 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -487,6 +487,11 @@ class Constants */ // ============================== + /** + * The amount of score the player loses for pressing a key when no note is there. + */ + public static final SCORE_GHOST_MISS_PENALTY:Float = -10.0; + /** * The amount of score the player gains for every second they hold a hold note. * A fraction of this value is granted every frame.