tallyCompletion() function for cleanup + constency

This commit is contained in:
Cameron Taylor
2025-08-01 13:15:56 +07:00
committed by MoonDroid
parent 065ee74aea
commit 542f59ef72
4 changed files with 39 additions and 35 deletions
+1 -2
View File
@@ -527,8 +527,7 @@ class ResultState extends MusicBeatSubState
bgFlash.visible = true;
FlxTween.tween(bgFlash, {alpha: 0}, 5 / 24);
// NOTE: Only divide if totalNotes > 0 to prevent divide-by-zero errors.
var clearPercentFloat = params.scoreData.tallies.totalNotes == 0 ? 0.0 : (params.scoreData.tallies.sick + params.scoreData.tallies.good
- params.scoreData.tallies.missed) / params.scoreData.tallies.totalNotes * 100;
var clearPercentFloat = params.scoreData.tallies.totalNotes == 0 ? 0.0 : Scoring.tallyCompletion(params.scoreData.tallies) * 100;
clearPercentTarget = Math.floor(clearPercentFloat);
// Prevent off-by-one errors.
+20 -5
View File
@@ -384,21 +384,21 @@ class Scoring
// Final Grade = (Sick + Good - Miss) / (Total Notes)
var grade = (scoreData.tallies.sick + scoreData.tallies.good - scoreData.tallies.missed) / scoreData.tallies.totalNotes;
var completionAmount:Float = Scoring.tallyCompletion(scoreData.tallies);
if (grade == Constants.RANK_PERFECT_THRESHOLD)
if (completionAmount == Constants.RANK_PERFECT_THRESHOLD)
{
return ScoringRank.PERFECT;
}
else if (grade >= Constants.RANK_EXCELLENT_THRESHOLD)
else if (completionAmount >= Constants.RANK_EXCELLENT_THRESHOLD)
{
return ScoringRank.EXCELLENT;
}
else if (grade >= Constants.RANK_GREAT_THRESHOLD)
else if (completionAmount >= Constants.RANK_GREAT_THRESHOLD)
{
return ScoringRank.GREAT;
}
else if (grade >= Constants.RANK_GOOD_THRESHOLD)
else if (completionAmount >= Constants.RANK_GOOD_THRESHOLD)
{
return ScoringRank.GOOD;
}
@@ -407,6 +407,21 @@ class Scoring
return ScoringRank.SHIT;
}
}
/**
* Calculates the "completion" of a song, based on how many GOOD and SICK notes were hit, minus how many were missed
* Top secret funkin crew patented algorithm
* TODO: Could possibly move more of the "tallying" related handling here.
* In FreeplayState we make sure it's clamped between 0 and 1, and we probably always want to assume that?
*
* @param tallies
* @return Float Completion, as a float value between 0 and 1. If `tallies` is `null`, we return 0;
*/
public static function tallyCompletion(?tallies:SaveScoreTallyData):Float
{
if (tallies == null) return 0.0;
return (tallies.sick + tallies.good - tallies.missed) / tallies.totalNotes;
}
}
enum abstract ScoringRank(String)
+2 -4
View File
@@ -882,14 +882,12 @@ class Save
return;
}
var newCompletion = (newScoreData.tallies.sick + newScoreData.tallies.good) / newScoreData.tallies.totalNotes;
var previousCompletion = (previousScoreData.tallies.sick + previousScoreData.tallies.good) / previousScoreData.tallies.totalNotes;
// Set the high score and the high rank separately.
var newScore:SaveScoreData =
{
score: (previousScoreData.score > newScoreData.score) ? previousScoreData.score : newScoreData.score,
tallies: (previousRank > newRank || previousCompletion > newCompletion) ? previousScoreData.tallies : newScoreData.tallies
tallies: (previousRank > newRank
|| Scoring.tallyCompletion(previousScoreData.tallies) > Scoring.tallyCompletion(newScoreData.tallies)) ? previousScoreData.tallies : newScoreData.tallies
};
song.set(difficultyId, newScore);
+16 -24
View File
@@ -31,6 +31,7 @@ import funkin.input.Controls;
import funkin.modding.events.ScriptEvent;
import funkin.modding.events.ScriptEventDispatcher;
import funkin.play.PlayStatePlaylist;
import funkin.play.scoring.Scoring;
import funkin.play.scoring.Scoring.ScoringRank;
import funkin.play.song.Song;
import funkin.save.Save;
@@ -2300,11 +2301,10 @@ class FreeplayState extends MusicBeatSubState
var songScore:Null<SaveScoreData> = Save.instance.getSongScore(daSong.data.id, currentDifficulty, currentVariation);
intendedScore = songScore?.score ?? 0;
intendedCompletion = songScore == null ? 0.0 : Math.max(0,
((songScore.tallies.sick + songScore.tallies.good - songScore.tallies.missed) / songScore.tallies.totalNotes));
intendedCompletion = Math.max(0, Scoring.tallyCompletion(songScore?.tallies));
rememberedDifficulty = currentDifficulty;
if (!capsuleAnim) generateSongList(currentFilter, false, true, true);
currentCapsule.refreshDisplay((prepForNewRank == true) ? false : true);
currentCapsule.refreshDisplay(!prepForNewRank);
}
else
{
@@ -2719,26 +2719,18 @@ class FreeplayState extends MusicBeatSubState
if (!prepForNewRank && curSelected != prevSelected) FunkinSound.playOnce(Paths.sound('scrollMenu'), 0.4);
var daSongCapsule:SongMenuItem = currentCapsule;
if (daSongCapsule.freeplayData != null)
{
var songScore:Null<SaveScoreData> = Save.instance.getSongScore(daSongCapsule.freeplayData.data.id, currentDifficulty, currentVariation);
intendedScore = songScore?.score ?? 0;
intendedCompletion = songScore == null ? 0.0 : ((songScore.tallies.sick +
songScore.tallies.good - songScore.tallies.missed) / songScore.tallies.totalNotes);
rememberedSongId = daSongCapsule.freeplayData.data.id;
changeDiff();
daSongCapsule.refreshDisplay((prepForNewRank == true) ? false : true);
}
var songScore:Null<SaveScoreData> = Save.instance.getSongScore(currentCapsule.freeplayData?.data.id ?? "", currentDifficulty, currentVariation);
intendedScore = songScore?.score ?? 0;
intendedCompletion = Scoring.tallyCompletion(songScore?.tallies);
rememberedSongId = currentCapsule.freeplayData?.data.id;
if (currentCapsule.freeplayData == null) albumRoll.albumId = null;
changeDiff();
if (currentCapsule.freeplayData == null) currentCapsule.refreshDisplay();
else
{
intendedScore = 0;
intendedCompletion = 0.0;
rememberedSongId = null;
albumRoll.albumId = null;
changeDiff();
daSongCapsule.refreshDisplay();
}
currentCapsule.refreshDisplay(!prepForNewRank);
for (index => capsule in grpCapsules.members)
{
@@ -2756,10 +2748,10 @@ class FreeplayState extends MusicBeatSubState
if (grpCapsules.countLiving() > 0 && !prepForNewRank && controls.active)
{
playCurSongPreview(daSongCapsule);
playCurSongPreview(currentCapsule);
currentCapsule.selected = true;
// switchBackingImage(daSongCapsule.freeplayData);
// switchBackingImage(currentCapsule.freeplayData);
}
// Small vibrations every selection change.