diff --git a/assets b/assets index 371cce1fd..2719d3fc1 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 371cce1fdc44914ddc3a5327e996cece4e676715 +Subproject commit 2719d3fc1d8f5d0cbafae8d27141d6c471148482 diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index a945c10c5..d0009f95b 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -220,6 +220,8 @@ class InitState extends FlxState { storyMode: false, title: "CUM SONG", + songId: "cum", + difficultyId: "hard", isNewHighscore: true, scoreData: { @@ -227,7 +229,7 @@ class InitState extends FlxState tallies: { sick: 130, - good: 25, + good: 70, bad: 69, shit: 69, missed: 69, diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 0781e59b6..478a13269 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -3122,9 +3122,10 @@ class PlayState extends MusicBeatSubState var res:ResultState = new ResultState( { storyMode: PlayStatePlaylist.isStoryMode, + songId: currentChart.song.id, + difficultyId: currentDifficulty, title: PlayStatePlaylist.isStoryMode ? ('${PlayStatePlaylist.campaignTitle}') : ('${currentChart.songName} by ${currentChart.songArtist}'), prevScoreData: prevScoreData, - difficultyId: currentDifficulty, scoreData: { score: PlayStatePlaylist.isStoryMode ? PlayStatePlaylist.campaignScore : songScore, diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx index ee7c8eade..79880038d 100644 --- a/source/funkin/play/ResultState.hx +++ b/source/funkin/play/ResultState.hx @@ -21,6 +21,7 @@ import funkin.audio.FunkinSound; import flixel.util.FlxGradient; import flixel.util.FlxTimer; import funkin.save.Save; +import funkin.play.scoring.Scoring; import funkin.save.Save.SaveScoreData; import funkin.graphics.shaders.LeftMaskShader; import funkin.play.components.TallyCounter; @@ -34,7 +35,7 @@ class ResultState extends MusicBeatSubState { final params:ResultsStateParams; - final rank:ResultRank; + final rank:ScoringRank; final songName:FlxBitmapText; final difficulty:FlxSprite; final clearPercentSmall:ClearPercentCounter; @@ -64,8 +65,7 @@ class ResultState extends MusicBeatSubState this.params = params; - rank = calculateRank(params); - // rank = SHIT; + rank = Scoring.calculateRank(params.scoreData) ?? SHIT; // We build a lot of this stuff in the constructor, then place it in create(). // This prevents having to do `null` checks everywhere. @@ -99,6 +99,8 @@ class ResultState extends MusicBeatSubState override function create():Void { + if (FlxG.sound.music != null) FlxG.sound.music.stop(); + // Reset the camera zoom on the results screen. FlxG.camera.zoom = 1.0; @@ -327,6 +329,33 @@ class ResultState extends MusicBeatSubState } }; + new FlxTimer().start(rank.getMusicDelay(), _ -> { + if (rank.hasMusicIntro()) + { + // Play the intro music. + var introMusic:String = Paths.music(rank.getMusicPath() + '/' + rank.getMusicPath() + '-intro'); + FunkinSound.load(introMusic, 1.0, false, true, true, () -> { + FunkinSound.playMusic(rank.getMusicPath(), + { + startingVolume: 1.0, + overrideExisting: true, + restartTrack: true, + loop: rank.shouldMusicLoop() + }); + }); + } + else + { + FunkinSound.playMusic(rank.getMusicPath(), + { + startingVolume: 1.0, + overrideExisting: true, + restartTrack: true, + loop: rank.shouldMusicLoop() + }); + } + }); + refresh(); super.create(); @@ -376,7 +405,8 @@ class ResultState extends MusicBeatSubState displayRankText(); - new FlxTimer().start(2.0, _ -> { + // previously 2.0 seconds + new FlxTimer().start(0.25, _ -> { FlxTween.tween(clearPercentCounter, {alpha: 0}, 0.5, { startDelay: 0.5, @@ -444,28 +474,6 @@ class ResultState extends MusicBeatSubState { showSmallClearPercent(); - FunkinSound.playMusic(rank.getMusicPath(), - { - startingVolume: 1.0, - overrideExisting: true, - restartTrack: true, - loop: rank.shouldMusicLoop() - }); - - FlxG.sound.music.onComplete = () -> { - if (rank == SHIT) - { - FunkinSound.playMusic('bluu', - { - startingVolume: 0.0, - overrideExisting: true, - restartTrack: true, - loop: true - }); - FlxG.sound.music.fadeIn(10.0, 0.0, 1.0); - } - } - switch (rank) { case PERFECT | PERFECT_GOLD: @@ -478,7 +486,6 @@ class ResultState extends MusicBeatSubState bfPerfect.visible = true; bfPerfect.playAnimation(''); } - case EXCELLENT: if (bfExcellent == null) { @@ -489,7 +496,6 @@ class ResultState extends MusicBeatSubState bfExcellent.visible = true; bfExcellent.playAnimation('Intro'); } - case GREAT: if (bfGreat == null) { @@ -500,7 +506,6 @@ class ResultState extends MusicBeatSubState bfGreat.visible = true; bfGreat.playAnimation('Intro'); } - case SHIT: if (bfShit == null) { @@ -511,7 +516,6 @@ class ResultState extends MusicBeatSubState bfShit.visible = true; bfShit.playAnimation('Intro'); } - case GOOD: if (bfGood == null) { @@ -521,7 +525,6 @@ class ResultState extends MusicBeatSubState { bfGood.animation.play('fall'); bfGood.visible = true; - new FlxTimer().start((1 / 24) * 22, _ -> { // plays about 22 frames (at 24fps timing) after bf spawns in if (gfGood != null) @@ -635,154 +638,39 @@ class ResultState extends MusicBeatSubState if (controls.PAUSE) { - FlxTween.tween(FlxG.sound.music, {volume: 0}, 0.8); - FlxTween.tween(FlxG.sound.music, {pitch: 3}, 0.1, - { - onComplete: _ -> { - FlxTween.tween(FlxG.sound.music, {pitch: 0.5}, 0.4); - } - }); + if (FlxG.sound.music != null) + { + FlxTween.tween(FlxG.sound.music, {volume: 0}, 0.8); + FlxTween.tween(FlxG.sound.music, {pitch: 3}, 0.1, + { + onComplete: _ -> { + FlxTween.tween(FlxG.sound.music, {pitch: 0.5}, 0.4); + } + }); + } if (params.storyMode) { openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new StoryMenuState(sticker))); } else { - openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> FreeplayState.build(null, sticker))); + openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> FreeplayState.build( + { + { + fromResults: + { + oldRank: Scoring.calculateRank(params?.prevScoreData), + newRank: rank, + songId: params.songId, + difficultyId: params.difficultyId + } + } + }, sticker))); } } super.update(elapsed); } - - public static function calculateRank(params:ResultsStateParams):ResultRank - { - // Perfect (Platinum) is a Sick Full Clear - var isPerfectGold = params.scoreData.tallies.sick == params.scoreData.tallies.totalNotes; - if (isPerfectGold) return ResultRank.PERFECT_GOLD; - - // Else, use the standard grades - - // Grade % (only good and sick), 1.00 is a full combo - var grade = (params.scoreData.tallies.sick + params.scoreData.tallies.good) / params.scoreData.tallies.totalNotes; - // Clear % (including bad and shit). 1.00 is a full clear but not a full combo - var clear = (params.scoreData.tallies.totalNotesHit) / params.scoreData.tallies.totalNotes; - - if (grade == Constants.RANK_PERFECT_THRESHOLD) - { - return ResultRank.PERFECT; - } - else if (grade >= Constants.RANK_EXCELLENT_THRESHOLD) - { - return ResultRank.EXCELLENT; - } - else if (grade >= Constants.RANK_GREAT_THRESHOLD) - { - return ResultRank.GREAT; - } - else if (grade >= Constants.RANK_GOOD_THRESHOLD) - { - return ResultRank.GOOD; - } - else - { - return ResultRank.SHIT; - } - } -} - -enum abstract ResultRank(String) -{ - var PERFECT_GOLD; - var PERFECT; - var EXCELLENT; - var GREAT; - var GOOD; - var SHIT; - - public function getMusicPath():String - { - switch (abstract) - { - case PERFECT_GOLD: - return 'resultsPERFECT'; - case PERFECT: - return 'resultsPERFECT'; - case EXCELLENT: - return 'resultsNORMAL'; - case GREAT: - return 'resultsNORMAL'; - case GOOD: - return 'resultsNORMAL'; - case SHIT: - return 'resultsSHIT'; - default: - return 'resultsNORMAL'; - } - } - - public function shouldMusicLoop():Bool - { - switch (abstract) - { - case PERFECT_GOLD: - return true; - case PERFECT: - return true; - case EXCELLENT: - return true; - case GREAT: - return true; - case GOOD: - return true; - case SHIT: - return false; - default: - return false; - } - } - - public function getHorTextAsset() - { - switch (abstract) - { - case PERFECT_GOLD: - return 'resultScreen/rankText/rankScrollPERFECT'; - case PERFECT: - return 'resultScreen/rankText/rankScrollPERFECT'; - case EXCELLENT: - return 'resultScreen/rankText/rankScrollEXCELLENT'; - case GREAT: - return 'resultScreen/rankText/rankScrollGREAT'; - case GOOD: - return 'resultScreen/rankText/rankScrollGOOD'; - case SHIT: - return 'resultScreen/rankText/rankScrollLOSS'; - default: - return 'resultScreen/rankText/rankScrollGOOD'; - } - } - - public function getVerTextAsset() - { - switch (abstract) - { - case PERFECT_GOLD: - return 'resultScreen/rankText/rankTextPERFECT'; - case PERFECT: - return 'resultScreen/rankText/rankTextPERFECT'; - case EXCELLENT: - return 'resultScreen/rankText/rankTextEXCELLENT'; - case GREAT: - return 'resultScreen/rankText/rankTextGREAT'; - case GOOD: - return 'resultScreen/rankText/rankTextGOOD'; - case SHIT: - return 'resultScreen/rankText/rankTextLOSS'; - default: - return 'resultScreen/rankText/rankTextGOOD'; - } - } } typedef ResultsStateParams = @@ -797,6 +685,8 @@ typedef ResultsStateParams = */ var title:String; + var songId:String; + /** * Whether the displayed score is a new highscore */ diff --git a/source/funkin/play/scoring/Scoring.hx b/source/funkin/play/scoring/Scoring.hx index 744091b44..6155ec879 100644 --- a/source/funkin/play/scoring/Scoring.hx +++ b/source/funkin/play/scoring/Scoring.hx @@ -1,5 +1,7 @@ package funkin.play.scoring; +import funkin.save.Save.SaveScoreData; + /** * Which system to use when scoring and judging notes. */ @@ -344,4 +346,178 @@ class Scoring return 'miss'; } } + + public static function calculateRank(scoreData:Null<SaveScoreData>):Null<ScoringRank> + { + if (scoreData == null) return null; + + // Perfect (Platinum) is a Sick Full Clear + var isPerfectGold = scoreData.tallies.sick == scoreData.tallies.totalNotes; + if (isPerfectGold) return ScoringRank.PERFECT_GOLD; + + // Else, use the standard grades + + // Grade % (only good and sick), 1.00 is a full combo + var grade = (scoreData.tallies.sick + scoreData.tallies.good) / scoreData.tallies.totalNotes; + // Clear % (including bad and shit). 1.00 is a full clear but not a full combo + var clear = (scoreData.tallies.totalNotesHit) / scoreData.tallies.totalNotes; + + if (grade == Constants.RANK_PERFECT_THRESHOLD) + { + return ScoringRank.PERFECT; + } + else if (grade >= Constants.RANK_EXCELLENT_THRESHOLD) + { + return ScoringRank.EXCELLENT; + } + else if (grade >= Constants.RANK_GREAT_THRESHOLD) + { + return ScoringRank.GREAT; + } + else if (grade >= Constants.RANK_GOOD_THRESHOLD) + { + return ScoringRank.GOOD; + } + else + { + return ScoringRank.SHIT; + } + } +} + +enum abstract ScoringRank(String) +{ + var PERFECT_GOLD; + var PERFECT; + var EXCELLENT; + var GREAT; + var GOOD; + var SHIT; + + /** + * Delay in seconds + */ + public function getMusicDelay():Float + { + switch (abstract) + { + case PERFECT_GOLD | PERFECT: + // return 2.5; + return 5.0; + case EXCELLENT: + return 1.75; + default: + return 3.5; + } + } + + public function getMusicPath():String + { + switch (abstract) + { + case PERFECT_GOLD: + return 'resultsPERFECT'; + case PERFECT: + return 'resultsPERFECT'; + case EXCELLENT: + return 'resultsEXCELLENT'; + case GREAT: + return 'resultsNORMAL'; + case GOOD: + return 'resultsNORMAL'; + case SHIT: + return 'resultsSHIT'; + default: + return 'resultsNORMAL'; + } + } + + public function hasMusicIntro():Bool + { + switch (abstract) + { + case EXCELLENT: + return true; + case SHIT: + return true; + default: + return false; + } + } + + public function getFreeplayRankIconAsset():Null<String> + { + switch (abstract) + { + case PERFECT_GOLD: + return 'PERFECTSICK'; + case PERFECT: + return 'PERFECT'; + case EXCELLENT: + return 'EXCELLENT'; + case GREAT: + return 'GREAT'; + case GOOD: + return 'GOOD'; + case SHIT: + return 'LOSS'; + default: + return null; + } + } + + public function shouldMusicLoop():Bool + { + switch (abstract) + { + case PERFECT_GOLD | PERFECT | EXCELLENT | GREAT | GOOD: + return true; + case SHIT: + return false; + default: + return false; + } + } + + public function getHorTextAsset() + { + switch (abstract) + { + case PERFECT_GOLD: + return 'resultScreen/rankText/rankScrollPERFECT'; + case PERFECT: + return 'resultScreen/rankText/rankScrollPERFECT'; + case EXCELLENT: + return 'resultScreen/rankText/rankScrollEXCELLENT'; + case GREAT: + return 'resultScreen/rankText/rankScrollGREAT'; + case GOOD: + return 'resultScreen/rankText/rankScrollGOOD'; + case SHIT: + return 'resultScreen/rankText/rankScrollLOSS'; + default: + return 'resultScreen/rankText/rankScrollGOOD'; + } + } + + public function getVerTextAsset() + { + switch (abstract) + { + case PERFECT_GOLD: + return 'resultScreen/rankText/rankTextPERFECT'; + case PERFECT: + return 'resultScreen/rankText/rankTextPERFECT'; + case EXCELLENT: + return 'resultScreen/rankText/rankTextEXCELLENT'; + case GREAT: + return 'resultScreen/rankText/rankTextGREAT'; + case GOOD: + return 'resultScreen/rankText/rankTextGOOD'; + case SHIT: + return 'resultScreen/rankText/rankTextLOSS'; + default: + return 'resultScreen/rankText/rankTextGOOD'; + } + } } diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx index 934d6a4aa..7f25a8e01 100644 --- a/source/funkin/save/Save.hx +++ b/source/funkin/save/Save.hx @@ -1,15 +1,17 @@ package funkin.save; import flixel.util.FlxSave; -import funkin.save.migrator.SaveDataMigrator; -import thx.semver.Version; import funkin.input.Controls.Device; +import funkin.play.scoring.Scoring; +import funkin.play.scoring.Scoring.ScoringRank; import funkin.save.migrator.RawSaveData_v1_0_0; import funkin.save.migrator.SaveDataMigrator; +import funkin.save.migrator.SaveDataMigrator; import funkin.ui.debug.charting.ChartEditorState.ChartEditorLiveInputStyle; import funkin.ui.debug.charting.ChartEditorState.ChartEditorTheme; -import thx.semver.Version; import funkin.util.SerializerUtil; +import thx.semver.Version; +import thx.semver.Version; @:nullSafety class Save @@ -492,6 +494,11 @@ class Save return song.get(difficultyId); } + public function getSongRank(songId:String, difficultyId:String = 'normal'):Null<ScoringRank> + { + return Scoring.calculateRank(getSongScore(songId, difficultyId)); + } + /** * Apply the score the user achieved for a given song on a given difficulty. */ diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 61c53c7d7..192c6e3ce 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -35,6 +35,8 @@ import funkin.ui.story.Level; import funkin.save.Save; import funkin.save.Save.SaveScoreData; import funkin.ui.AtlasText; +import funkin.play.scoring.Scoring; +import funkin.play.scoring.Scoring.ScoringRank; import funkin.ui.mainmenu.MainMenuState; import funkin.ui.MusicBeatSubState; import funkin.ui.transition.LoadingState; @@ -50,6 +52,34 @@ import funkin.effects.IntervalShake; typedef FreeplayStateParams = { ?character:String, + + ?fromResults:FromResultsParams, +}; + +/** + * A set of parameters for transitioning to the FreeplayState from the ResultsState. + */ +typedef FromResultsParams = +{ + /** + * The previous rank the song hand, if any. Null if it had no score before. + */ + var ?oldRank:ScoringRank; + + /** + * The new rank the song has. + */ + var newRank:ScoringRank; + + /** + * The song ID to play the animation on. + */ + var songId:String; + + /** + * The difficulty ID to play the animation on. + */ + var difficultyId:String; }; /** @@ -161,10 +191,14 @@ class FreeplayState extends MusicBeatSubState var bgDad:FlxSprite; var cardGlow:FlxSprite; + var fromResultsParams:Null<FromResultsParams> = null; + public function new(?params:FreeplayStateParams, ?stickers:StickerSubState) { currentCharacter = params?.character ?? Constants.DEFAULT_CHARACTER; + fromResultsParams = params?.fromResults; + if (stickers != null) { stickerSubState = stickers; @@ -602,6 +636,11 @@ class FreeplayState extends MusicBeatSubState cardGlow.visible = true; FlxTween.tween(cardGlow, {alpha: 0, "scale.x": 1.2, "scale.y": 1.2}, 0.45, {ease: FlxEase.sineOut}); + + if (fromResultsParams != null) + { + rankAnimStart(fromResultsParams); + } }); generateSongList(null, false); @@ -672,6 +711,12 @@ class FreeplayState extends MusicBeatSubState // If curSelected is 0, the result will be null and fall back to the rememberedSongId. rememberedSongId = grpCapsules.members[curSelected]?.songData?.songId ?? rememberedSongId; + if (fromResultsParams != null) + { + rememberedSongId = fromResultsParams.songId; + rememberedDifficulty = fromResultsParams.difficultyId; + } + for (cap in grpCapsules.members) { cap.songText.resetText(); @@ -778,8 +823,10 @@ class FreeplayState extends MusicBeatSubState return songsToFilter; } - function rankAnimStart() + function rankAnimStart(fromResults:Null<FromResultsParams>):Void { + busy = true; + dj.fistPump(); // rankCamera.fade(FlxColor.BLACK, 0.5, true); rankCamera.fade(0xFF000000, 0.5, true, null, true); @@ -804,21 +851,21 @@ class FreeplayState extends MusicBeatSubState new FlxTimer().start(0.5, _ -> { grpCapsules.members[curSelected].doLerp = false; - rankDisplayNew(); + rankDisplayNew(fromResults); }); } - function rankDisplayNew() + function rankDisplayNew(fromResults:Null<FromResultsParams>):Void { grpCapsules.members[curSelected].ranking.alpha = 1; grpCapsules.members[curSelected].blurredRanking.alpha = 1; grpCapsules.members[curSelected].ranking.scale.set(20, 20); grpCapsules.members[curSelected].blurredRanking.scale.set(20, 20); - // var tempr:Int = FlxG.random.int(0, 4); - // grpCapsules.members[curSelected].ranking.rank = tempr; - grpCapsules.members[curSelected].ranking.animation.play(grpCapsules.members[curSelected].ranking.animation.curAnim.name, true); + grpCapsules.members[curSelected].ranking.animation.play(fromResults.newRank.getFreeplayRankIconAsset(), true); + // grpCapsules.members[curSelected].ranking.animation.curAnim.name, true); + FlxTween.tween(grpCapsules.members[curSelected].ranking, {"scale.x": 1, "scale.y": 1}, 0.1); grpCapsules.members[curSelected].blurredRanking.animation.play(grpCapsules.members[curSelected].blurredRanking.animation.curAnim.name, true); @@ -826,13 +873,13 @@ class FreeplayState extends MusicBeatSubState new FlxTimer().start(0.1, _ -> { trace(grpCapsules.members[curSelected].ranking.rank); - switch (grpCapsules.members[curSelected].tempr) + switch (fromResultsParams?.newRank) { - case 0: + case SHIT: FunkinSound.playOnce(Paths.sound('ranks/rankinbad')); - case 4: + case PERFECT: FunkinSound.playOnce(Paths.sound('ranks/rankinperfect')); - case 5: + case PERFECT_GOLD: FunkinSound.playOnce(Paths.sound('ranks/rankinperfect')); default: FunkinSound.playOnce(Paths.sound('ranks/rankinnormal')); @@ -861,31 +908,31 @@ class FreeplayState extends MusicBeatSubState }); new FlxTimer().start(0.6, _ -> { - rankAnimSlam(); + rankAnimSlam(fromResults); // IntervalShake.shake(grpCapsules.members[curSelected].capsule, 0.3, 1 / 30, 0, 0.3, FlxEase.quartIn); }); } - function rankAnimSlam() + function rankAnimSlam(fromResultsParams:Null<FromResultsParams>) { // FlxTween.tween(rankCamera, {"zoom": 1.9}, 0.5, {ease: FlxEase.backOut}); FlxTween.tween(rankBg, {alpha: 0}, 0.5, {ease: FlxEase.expoIn}); // FlxTween.tween(grpCapsules.members[curSelected], {angle: 5}, 0.5, {ease: FlxEase.backIn}); - switch (grpCapsules.members[curSelected].tempr) + switch (fromResultsParams?.newRank) { - case 0: + case SHIT: FunkinSound.playOnce(Paths.sound('ranks/loss')); - case 1: + case GOOD: FunkinSound.playOnce(Paths.sound('ranks/good')); - case 2: + case GREAT: FunkinSound.playOnce(Paths.sound('ranks/great')); - case 3: + case EXCELLENT: FunkinSound.playOnce(Paths.sound('ranks/excellent')); - case 4: + case PERFECT: FunkinSound.playOnce(Paths.sound('ranks/perfect')); - case 5: + case PERFECT_GOLD: FunkinSound.playOnce(Paths.sound('ranks/perfect')); default: FunkinSound.playOnce(Paths.sound('ranks/loss')); @@ -895,7 +942,7 @@ class FreeplayState extends MusicBeatSubState new FlxTimer().start(0.5, _ -> { funnyCam.shake(0.0045, 0.35); - if (grpCapsules.members[curSelected].tempr == 0) + if (fromResultsParams?.newRank == SHIT) { dj.pumpFistBad(); } @@ -930,6 +977,9 @@ class FreeplayState extends MusicBeatSubState IntervalShake.shake(capsule, 0.6, 1 / 24, 0.12, 0, FlxEase.quadOut, function(_) { capsule.doLerp = true; capsule.cameras = [funnyCam]; + + // NOW we can interact with the menu + busy = false; }, null); // FlxTween.tween(capsule, {"targetPos.x": capsule.targetPos.x - 50}, 0.6, @@ -996,7 +1046,10 @@ class FreeplayState extends MusicBeatSubState var spamTimer:Float = 0; var spamming:Bool = false; - var busy:Bool = false; // Set to true once the user has pressed enter to select a song. + /** + * If true, disable interaction with the interface. + */ + var busy:Bool = false; var originalPos:FlxPoint = new FlxPoint(); @@ -1004,19 +1057,20 @@ class FreeplayState extends MusicBeatSubState { super.update(elapsed); + #if debug if (FlxG.keys.justPressed.T) { - rankAnimStart(); + rankAnimStart(fromResultsParams); } if (FlxG.keys.justPressed.H) { - rankDisplayNew(); + rankDisplayNew(fromResultsParams); } if (FlxG.keys.justPressed.G) { - rankAnimSlam(); + rankAnimSlam(fromResultsParams); } if (FlxG.keys.justPressed.I) @@ -1039,6 +1093,7 @@ class FreeplayState extends MusicBeatSubState confirmTextGlow.y += 1; trace(confirmTextGlow.x, confirmTextGlow.y); } + #end if (FlxG.keys.justPressed.F) { @@ -1782,6 +1837,8 @@ class FreeplaySongData public var currentDifficulty(default, set):String = Constants.DEFAULT_DIFFICULTY; + public var scoringRank:Null<ScoringRank> = null; + var displayedVariations:Array<String> = [Constants.DEFAULT_VARIATION]; function set_currentDifficulty(value:String):String @@ -1844,6 +1901,8 @@ class FreeplaySongData { this.albumId = songDifficulty.album; } + + this.scoringRank = Save.instance.getSongRank(songId, currentDifficulty); } } diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index 536a9cfe6..ad6ea386e 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -20,6 +20,7 @@ import funkin.graphics.FunkinSprite; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; import flixel.addons.effects.FlxTrail; +import funkin.play.scoring.Scoring.ScoringRank; import flixel.util.FlxColor; class SongMenuItem extends FlxSpriteGroup @@ -70,8 +71,6 @@ class SongMenuItem extends FlxSpriteGroup var impactThing:FunkinSprite; - public var tempr:Int; - public function new(x:Float, y:Float) { super(x, y); @@ -132,13 +131,10 @@ class SongMenuItem extends FlxSpriteGroup // doesn't get added, simply is here to help with visibility of things for the pop in! grpHide = new FlxGroup(); - var rank:String = FlxG.random.getObject(ranks); - - tempr = FlxG.random.int(0, 5); - ranking = new FreeplayRank(420, 41, tempr); + ranking = new FreeplayRank(420, 41); add(ranking); - blurredRanking = new FreeplayRank(ranking.x, ranking.y, tempr); + blurredRanking = new FreeplayRank(ranking.x, ranking.y); blurredRanking.shader = new GaussianBlurShader(1); add(blurredRanking); // ranking.loadGraphic(Paths.image('freeplay/ranks/' + rank)); @@ -344,19 +340,19 @@ class SongMenuItem extends FlxSpriteGroup }); add(evilTrail); - switch (tempr) + switch (ranking.rank) { - case 0: + case SHIT: evilTrail.color = 0xFF6044FF; - case 1: + case GOOD: evilTrail.color = 0xFFEF8764; - case 2: + case GREAT: evilTrail.color = 0xFFEAF6FF; - case 3: + case EXCELLENT: evilTrail.color = 0xFFFDCB42; - case 4: + case PERFECT: evilTrail.color = 0xFFFF58B4; - case 5: + case PERFECT_GOLD: evilTrail.color = 0xFFFFB619; } } @@ -393,6 +389,12 @@ class SongMenuItem extends FlxSpriteGroup // diffRatingSprite.visible = false; } + function updateScoringRank(newRank:Null<ScoringRank>):Void + { + this.ranking.rank = newRank; + this.blurredRanking.rank = newRank; + } + function set_hsvShader(value:HSVShader):HSVShader { this.hsvShader = value; @@ -441,6 +443,7 @@ class SongMenuItem extends FlxSpriteGroup if (songData?.songCharacter != null) setCharacter(songData.songCharacter); updateBPM(Std.int(songData?.songStartingBpm) ?? 0); updateDifficultyRating(songData?.difficultyRating ?? 0); + updateScoringRank(songData?.scoringRank); // Update opacity, offsets, etc. updateSelected(); @@ -668,41 +671,53 @@ class SongMenuItem extends FlxSpriteGroup class FreeplayRank extends FlxSprite { - public var rank(default, set):Int = 0; + public var rank(default, set):Null<ScoringRank> = null; - var numToRank:Array<String> = ["LOSS", "GOOD", "GREAT", "EXCELLENT", "PERFECT", "PERFECTSICK"]; - - function set_rank(val):Int + function set_rank(val:Null<ScoringRank>):Null<ScoringRank> { - animation.play(numToRank[val], true, false); + rank = val; - centerOffsets(false); - - switch (val) + if (rank == null) { - case 0: - // offset.x -= 1; - case 1: - // offset.x -= 1; - offset.y -= 8; - case 2: - // offset.x -= 1; - offset.y -= 8; - case 3: - // offset.y += 5; - case 4: - // offset.y += 5; - default: - centerOffsets(false); + this.visible = false; } - updateHitbox(); - return val; + else + { + this.visible = true; + + animation.play(val.getFreeplayRankIconAsset(), true, false); + + centerOffsets(false); + + switch (val) + { + case SHIT: + // offset.x -= 1; + case GOOD: + // offset.x -= 1; + offset.y -= 8; + case GREAT: + // offset.x -= 1; + offset.y -= 8; + case EXCELLENT: + // offset.y += 5; + case PERFECT: + // offset.y += 5; + case PERFECT_GOLD: + // offset.y += 5; + default: + centerOffsets(false); + } + updateHitbox(); + } + + return rank = val; } - public var baseY:Float = 0; public var baseX:Float = 0; + public var baseY:Float = 0; - public function new(x:Float, y:Float, ?initRank:Int = 0) + public function new(x:Float, y:Float) { super(x, y); @@ -717,9 +732,7 @@ class FreeplayRank extends FlxSprite blend = BlendMode.ADD; - this.rank = initRank; - - animation.play(numToRank[initRank], true); + this.rank = null; // setGraphicSize(Std.int(width * 0.9)); scale.set(0.9, 0.9);