1
0
Fork 0
mirror of https://github.com/ninjamuffin99/Funkin.git synced 2024-11-15 19:33:36 +00:00

Make Freeplay use correct ranks, play the slam animation after Results, new Results music

This commit is contained in:
EliteMasterEric 2024-05-30 05:25:51 -04:00
parent d4cf18df00
commit b7a828e7d8
8 changed files with 389 additions and 241 deletions

2
assets

@ -1 +1 @@
Subproject commit 8fea0bf1fe07b6dd0efb8ecf46dc8091b0177007 Subproject commit 2719d3fc1d8f5d0cbafae8d27141d6c471148482

View file

@ -220,6 +220,8 @@ class InitState extends FlxState
{ {
storyMode: false, storyMode: false,
title: "CUM SONG", title: "CUM SONG",
songId: "cum",
difficultyId: "hard",
isNewHighscore: true, isNewHighscore: true,
scoreData: scoreData:
{ {
@ -227,7 +229,7 @@ class InitState extends FlxState
tallies: tallies:
{ {
sick: 130, sick: 130,
good: 25, good: 70,
bad: 69, bad: 69,
shit: 69, shit: 69,
missed: 69, missed: 69,

View file

@ -3123,9 +3123,10 @@ class PlayState extends MusicBeatSubState
var res:ResultState = new ResultState( var res:ResultState = new ResultState(
{ {
storyMode: PlayStatePlaylist.isStoryMode, storyMode: PlayStatePlaylist.isStoryMode,
songId: currentChart.song.id,
difficultyId: currentDifficulty,
title: PlayStatePlaylist.isStoryMode ? ('${PlayStatePlaylist.campaignTitle}') : ('${currentChart.songName} by ${currentChart.songArtist}'), title: PlayStatePlaylist.isStoryMode ? ('${PlayStatePlaylist.campaignTitle}') : ('${currentChart.songName} by ${currentChart.songArtist}'),
prevScoreData: prevScoreData, prevScoreData: prevScoreData,
difficultyId: currentDifficulty,
scoreData: scoreData:
{ {
score: PlayStatePlaylist.isStoryMode ? PlayStatePlaylist.campaignScore : songScore, score: PlayStatePlaylist.isStoryMode ? PlayStatePlaylist.campaignScore : songScore,

View file

@ -21,6 +21,7 @@ import funkin.audio.FunkinSound;
import flixel.util.FlxGradient; import flixel.util.FlxGradient;
import flixel.util.FlxTimer; import flixel.util.FlxTimer;
import funkin.save.Save; import funkin.save.Save;
import funkin.play.scoring.Scoring;
import funkin.save.Save.SaveScoreData; import funkin.save.Save.SaveScoreData;
import funkin.graphics.shaders.LeftMaskShader; import funkin.graphics.shaders.LeftMaskShader;
import funkin.play.components.TallyCounter; import funkin.play.components.TallyCounter;
@ -34,7 +35,7 @@ class ResultState extends MusicBeatSubState
{ {
final params:ResultsStateParams; final params:ResultsStateParams;
final rank:ResultRank; final rank:ScoringRank;
final songName:FlxBitmapText; final songName:FlxBitmapText;
final difficulty:FlxSprite; final difficulty:FlxSprite;
final clearPercentSmall:ClearPercentCounter; final clearPercentSmall:ClearPercentCounter;
@ -64,8 +65,7 @@ class ResultState extends MusicBeatSubState
this.params = params; this.params = params;
rank = calculateRank(params); rank = Scoring.calculateRank(params.scoreData) ?? SHIT;
// rank = SHIT;
// We build a lot of this stuff in the constructor, then place it in create(). // We build a lot of this stuff in the constructor, then place it in create().
// This prevents having to do `null` checks everywhere. // This prevents having to do `null` checks everywhere.
@ -99,6 +99,8 @@ class ResultState extends MusicBeatSubState
override function create():Void override function create():Void
{ {
if (FlxG.sound.music != null) FlxG.sound.music.stop();
// Reset the camera zoom on the results screen. // Reset the camera zoom on the results screen.
FlxG.camera.zoom = 1.0; 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(); refresh();
super.create(); super.create();
@ -376,7 +405,8 @@ class ResultState extends MusicBeatSubState
displayRankText(); displayRankText();
new FlxTimer().start(2.0, _ -> { // previously 2.0 seconds
new FlxTimer().start(0.25, _ -> {
FlxTween.tween(clearPercentCounter, {alpha: 0}, 0.5, FlxTween.tween(clearPercentCounter, {alpha: 0}, 0.5,
{ {
startDelay: 0.5, startDelay: 0.5,
@ -444,28 +474,6 @@ class ResultState extends MusicBeatSubState
{ {
showSmallClearPercent(); 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) switch (rank)
{ {
case PERFECT | PERFECT_GOLD: case PERFECT | PERFECT_GOLD:
@ -478,7 +486,6 @@ class ResultState extends MusicBeatSubState
bfPerfect.visible = true; bfPerfect.visible = true;
bfPerfect.playAnimation(''); bfPerfect.playAnimation('');
} }
case EXCELLENT: case EXCELLENT:
if (bfExcellent == null) if (bfExcellent == null)
{ {
@ -489,7 +496,6 @@ class ResultState extends MusicBeatSubState
bfExcellent.visible = true; bfExcellent.visible = true;
bfExcellent.playAnimation('Intro'); bfExcellent.playAnimation('Intro');
} }
case GREAT: case GREAT:
if (bfGreat == null) if (bfGreat == null)
{ {
@ -500,7 +506,6 @@ class ResultState extends MusicBeatSubState
bfGreat.visible = true; bfGreat.visible = true;
bfGreat.playAnimation('Intro'); bfGreat.playAnimation('Intro');
} }
case SHIT: case SHIT:
if (bfShit == null) if (bfShit == null)
{ {
@ -511,7 +516,6 @@ class ResultState extends MusicBeatSubState
bfShit.visible = true; bfShit.visible = true;
bfShit.playAnimation('Intro'); bfShit.playAnimation('Intro');
} }
case GOOD: case GOOD:
if (bfGood == null) if (bfGood == null)
{ {
@ -521,7 +525,6 @@ class ResultState extends MusicBeatSubState
{ {
bfGood.animation.play('fall'); bfGood.animation.play('fall');
bfGood.visible = true; bfGood.visible = true;
new FlxTimer().start((1 / 24) * 22, _ -> { new FlxTimer().start((1 / 24) * 22, _ -> {
// plays about 22 frames (at 24fps timing) after bf spawns in // plays about 22 frames (at 24fps timing) after bf spawns in
if (gfGood != null) if (gfGood != null)
@ -634,6 +637,8 @@ class ResultState extends MusicBeatSubState
} }
if (controls.PAUSE) if (controls.PAUSE)
{
if (FlxG.sound.music != null)
{ {
FlxTween.tween(FlxG.sound.music, {volume: 0}, 0.8); FlxTween.tween(FlxG.sound.music, {volume: 0}, 0.8);
FlxTween.tween(FlxG.sound.music, {pitch: 3}, 0.1, FlxTween.tween(FlxG.sound.music, {pitch: 3}, 0.1,
@ -642,147 +647,30 @@ class ResultState extends MusicBeatSubState
FlxTween.tween(FlxG.sound.music, {pitch: 0.5}, 0.4); FlxTween.tween(FlxG.sound.music, {pitch: 0.5}, 0.4);
} }
}); });
}
if (params.storyMode) if (params.storyMode)
{ {
openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new StoryMenuState(sticker))); openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new StoryMenuState(sticker)));
} }
else 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); 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 = typedef ResultsStateParams =
@ -797,6 +685,8 @@ typedef ResultsStateParams =
*/ */
var title:String; var title:String;
var songId:String;
/** /**
* Whether the displayed score is a new highscore * Whether the displayed score is a new highscore
*/ */

View file

@ -1,5 +1,7 @@
package funkin.play.scoring; package funkin.play.scoring;
import funkin.save.Save.SaveScoreData;
/** /**
* Which system to use when scoring and judging notes. * Which system to use when scoring and judging notes.
*/ */
@ -344,4 +346,178 @@ class Scoring
return 'miss'; 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';
}
}
} }

View file

@ -1,15 +1,17 @@
package funkin.save; package funkin.save;
import flixel.util.FlxSave; import flixel.util.FlxSave;
import funkin.save.migrator.SaveDataMigrator;
import thx.semver.Version;
import funkin.input.Controls.Device; 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.RawSaveData_v1_0_0;
import funkin.save.migrator.SaveDataMigrator; import funkin.save.migrator.SaveDataMigrator;
import funkin.save.migrator.SaveDataMigrator;
import funkin.ui.debug.charting.ChartEditorState.ChartEditorLiveInputStyle; import funkin.ui.debug.charting.ChartEditorState.ChartEditorLiveInputStyle;
import funkin.ui.debug.charting.ChartEditorState.ChartEditorTheme; import funkin.ui.debug.charting.ChartEditorState.ChartEditorTheme;
import thx.semver.Version;
import funkin.util.SerializerUtil; import funkin.util.SerializerUtil;
import thx.semver.Version;
import thx.semver.Version;
@:nullSafety @:nullSafety
class Save class Save
@ -492,6 +494,11 @@ class Save
return song.get(difficultyId); 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. * Apply the score the user achieved for a given song on a given difficulty.
*/ */

View file

@ -34,6 +34,8 @@ import funkin.play.song.Song;
import funkin.save.Save; import funkin.save.Save;
import funkin.save.Save.SaveScoreData; import funkin.save.Save.SaveScoreData;
import funkin.ui.AtlasText; import funkin.ui.AtlasText;
import funkin.play.scoring.Scoring;
import funkin.play.scoring.Scoring.ScoringRank;
import funkin.ui.mainmenu.MainMenuState; import funkin.ui.mainmenu.MainMenuState;
import funkin.ui.MusicBeatSubState; import funkin.ui.MusicBeatSubState;
import funkin.ui.transition.LoadingState; import funkin.ui.transition.LoadingState;
@ -49,6 +51,34 @@ import funkin.effects.IntervalShake;
typedef FreeplayStateParams = typedef FreeplayStateParams =
{ {
?character:String, ?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;
}; };
/** /**
@ -160,10 +190,14 @@ class FreeplayState extends MusicBeatSubState
var bgDad:FlxSprite; var bgDad:FlxSprite;
var cardGlow:FlxSprite; var cardGlow:FlxSprite;
var fromResultsParams:Null<FromResultsParams> = null;
public function new(?params:FreeplayStateParams, ?stickers:StickerSubState) public function new(?params:FreeplayStateParams, ?stickers:StickerSubState)
{ {
currentCharacter = params?.character ?? Constants.DEFAULT_CHARACTER; currentCharacter = params?.character ?? Constants.DEFAULT_CHARACTER;
fromResultsParams = params?.fromResults;
if (stickers != null) if (stickers != null)
{ {
stickerSubState = stickers; stickerSubState = stickers;
@ -587,6 +621,11 @@ class FreeplayState extends MusicBeatSubState
cardGlow.visible = true; cardGlow.visible = true;
FlxTween.tween(cardGlow, {alpha: 0, "scale.x": 1.2, "scale.y": 1.2}, 0.45, {ease: FlxEase.sineOut}); 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); generateSongList(null, false);
@ -657,6 +696,12 @@ class FreeplayState extends MusicBeatSubState
// If curSelected is 0, the result will be null and fall back to the rememberedSongId. // If curSelected is 0, the result will be null and fall back to the rememberedSongId.
rememberedSongId = grpCapsules.members[curSelected]?.songData?.songId ?? rememberedSongId; rememberedSongId = grpCapsules.members[curSelected]?.songData?.songId ?? rememberedSongId;
if (fromResultsParams != null)
{
rememberedSongId = fromResultsParams.songId;
rememberedDifficulty = fromResultsParams.difficultyId;
}
for (cap in grpCapsules.members) for (cap in grpCapsules.members)
{ {
cap.songText.resetText(); cap.songText.resetText();
@ -763,8 +808,10 @@ class FreeplayState extends MusicBeatSubState
return songsToFilter; return songsToFilter;
} }
function rankAnimStart() function rankAnimStart(fromResults:Null<FromResultsParams>):Void
{ {
busy = true;
dj.fistPump(); dj.fistPump();
// rankCamera.fade(FlxColor.BLACK, 0.5, true); // rankCamera.fade(FlxColor.BLACK, 0.5, true);
rankCamera.fade(0xFF000000, 0.5, true, null, true); rankCamera.fade(0xFF000000, 0.5, true, null, true);
@ -789,21 +836,21 @@ class FreeplayState extends MusicBeatSubState
new FlxTimer().start(0.5, _ -> { new FlxTimer().start(0.5, _ -> {
grpCapsules.members[curSelected].doLerp = false; 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].ranking.alpha = 1;
grpCapsules.members[curSelected].blurredRanking.alpha = 1; grpCapsules.members[curSelected].blurredRanking.alpha = 1;
grpCapsules.members[curSelected].ranking.scale.set(20, 20); grpCapsules.members[curSelected].ranking.scale.set(20, 20);
grpCapsules.members[curSelected].blurredRanking.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(fromResults.newRank.getFreeplayRankIconAsset(), true);
grpCapsules.members[curSelected].ranking.animation.play(grpCapsules.members[curSelected].ranking.animation.curAnim.name, true); // grpCapsules.members[curSelected].ranking.animation.curAnim.name, true);
FlxTween.tween(grpCapsules.members[curSelected].ranking, {"scale.x": 1, "scale.y": 1}, 0.1); 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); grpCapsules.members[curSelected].blurredRanking.animation.play(grpCapsules.members[curSelected].blurredRanking.animation.curAnim.name, true);
@ -811,13 +858,13 @@ class FreeplayState extends MusicBeatSubState
new FlxTimer().start(0.1, _ -> { new FlxTimer().start(0.1, _ -> {
trace(grpCapsules.members[curSelected].ranking.rank); trace(grpCapsules.members[curSelected].ranking.rank);
switch (grpCapsules.members[curSelected].tempr) switch (fromResultsParams?.newRank)
{ {
case 0: case SHIT:
FunkinSound.playOnce(Paths.sound('ranks/rankinbad')); FunkinSound.playOnce(Paths.sound('ranks/rankinbad'));
case 4: case PERFECT:
FunkinSound.playOnce(Paths.sound('ranks/rankinperfect')); FunkinSound.playOnce(Paths.sound('ranks/rankinperfect'));
case 5: case PERFECT_GOLD:
FunkinSound.playOnce(Paths.sound('ranks/rankinperfect')); FunkinSound.playOnce(Paths.sound('ranks/rankinperfect'));
default: default:
FunkinSound.playOnce(Paths.sound('ranks/rankinnormal')); FunkinSound.playOnce(Paths.sound('ranks/rankinnormal'));
@ -846,31 +893,31 @@ class FreeplayState extends MusicBeatSubState
}); });
new FlxTimer().start(0.6, _ -> { new FlxTimer().start(0.6, _ -> {
rankAnimSlam(); rankAnimSlam(fromResults);
// IntervalShake.shake(grpCapsules.members[curSelected].capsule, 0.3, 1 / 30, 0, 0.3, FlxEase.quartIn); // 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(rankCamera, {"zoom": 1.9}, 0.5, {ease: FlxEase.backOut});
FlxTween.tween(rankBg, {alpha: 0}, 0.5, {ease: FlxEase.expoIn}); FlxTween.tween(rankBg, {alpha: 0}, 0.5, {ease: FlxEase.expoIn});
// FlxTween.tween(grpCapsules.members[curSelected], {angle: 5}, 0.5, {ease: FlxEase.backIn}); // 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')); FunkinSound.playOnce(Paths.sound('ranks/loss'));
case 1: case GOOD:
FunkinSound.playOnce(Paths.sound('ranks/good')); FunkinSound.playOnce(Paths.sound('ranks/good'));
case 2: case GREAT:
FunkinSound.playOnce(Paths.sound('ranks/great')); FunkinSound.playOnce(Paths.sound('ranks/great'));
case 3: case EXCELLENT:
FunkinSound.playOnce(Paths.sound('ranks/excellent')); FunkinSound.playOnce(Paths.sound('ranks/excellent'));
case 4: case PERFECT:
FunkinSound.playOnce(Paths.sound('ranks/perfect')); FunkinSound.playOnce(Paths.sound('ranks/perfect'));
case 5: case PERFECT_GOLD:
FunkinSound.playOnce(Paths.sound('ranks/perfect')); FunkinSound.playOnce(Paths.sound('ranks/perfect'));
default: default:
FunkinSound.playOnce(Paths.sound('ranks/loss')); FunkinSound.playOnce(Paths.sound('ranks/loss'));
@ -880,7 +927,7 @@ class FreeplayState extends MusicBeatSubState
new FlxTimer().start(0.5, _ -> { new FlxTimer().start(0.5, _ -> {
funnyCam.shake(0.0045, 0.35); funnyCam.shake(0.0045, 0.35);
if (grpCapsules.members[curSelected].tempr == 0) if (fromResultsParams?.newRank == SHIT)
{ {
dj.pumpFistBad(); dj.pumpFistBad();
} }
@ -915,6 +962,9 @@ class FreeplayState extends MusicBeatSubState
IntervalShake.shake(capsule, 0.6, 1 / 24, 0.12, 0, FlxEase.quadOut, function(_) { IntervalShake.shake(capsule, 0.6, 1 / 24, 0.12, 0, FlxEase.quadOut, function(_) {
capsule.doLerp = true; capsule.doLerp = true;
capsule.cameras = [funnyCam]; capsule.cameras = [funnyCam];
// NOW we can interact with the menu
busy = false;
}, null); }, null);
// FlxTween.tween(capsule, {"targetPos.x": capsule.targetPos.x - 50}, 0.6, // FlxTween.tween(capsule, {"targetPos.x": capsule.targetPos.x - 50}, 0.6,
@ -981,7 +1031,10 @@ class FreeplayState extends MusicBeatSubState
var spamTimer:Float = 0; var spamTimer:Float = 0;
var spamming:Bool = false; 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(); var originalPos:FlxPoint = new FlxPoint();
@ -989,19 +1042,20 @@ class FreeplayState extends MusicBeatSubState
{ {
super.update(elapsed); super.update(elapsed);
#if debug
if (FlxG.keys.justPressed.T) if (FlxG.keys.justPressed.T)
{ {
rankAnimStart(); rankAnimStart(fromResultsParams);
} }
if (FlxG.keys.justPressed.H) if (FlxG.keys.justPressed.H)
{ {
rankDisplayNew(); rankDisplayNew(fromResultsParams);
} }
if (FlxG.keys.justPressed.G) if (FlxG.keys.justPressed.G)
{ {
rankAnimSlam(); rankAnimSlam(fromResultsParams);
} }
if (FlxG.keys.justPressed.I) if (FlxG.keys.justPressed.I)
@ -1024,6 +1078,7 @@ class FreeplayState extends MusicBeatSubState
confirmTextGlow.y += 1; confirmTextGlow.y += 1;
trace(confirmTextGlow.x, confirmTextGlow.y); trace(confirmTextGlow.x, confirmTextGlow.y);
} }
#end
if (FlxG.keys.justPressed.F) if (FlxG.keys.justPressed.F)
{ {
@ -1765,6 +1820,8 @@ class FreeplaySongData
public var currentDifficulty(default, set):String = Constants.DEFAULT_DIFFICULTY; public var currentDifficulty(default, set):String = Constants.DEFAULT_DIFFICULTY;
public var scoringRank:Null<ScoringRank> = null;
var displayedVariations:Array<String> = [Constants.DEFAULT_VARIATION]; var displayedVariations:Array<String> = [Constants.DEFAULT_VARIATION];
function set_currentDifficulty(value:String):String function set_currentDifficulty(value:String):String
@ -1827,6 +1884,8 @@ class FreeplaySongData
{ {
this.albumId = songDifficulty.album; this.albumId = songDifficulty.album;
} }
this.scoringRank = Save.instance.getSongRank(songId, currentDifficulty);
} }
} }

View file

@ -20,6 +20,7 @@ import funkin.graphics.FunkinSprite;
import flixel.tweens.FlxEase; import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween; import flixel.tweens.FlxTween;
import flixel.addons.effects.FlxTrail; import flixel.addons.effects.FlxTrail;
import funkin.play.scoring.Scoring.ScoringRank;
import flixel.util.FlxColor; import flixel.util.FlxColor;
class SongMenuItem extends FlxSpriteGroup class SongMenuItem extends FlxSpriteGroup
@ -70,8 +71,6 @@ class SongMenuItem extends FlxSpriteGroup
var impactThing:FunkinSprite; var impactThing:FunkinSprite;
public var tempr:Int;
public function new(x:Float, y:Float) public function new(x:Float, y:Float)
{ {
super(x, y); 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! // doesn't get added, simply is here to help with visibility of things for the pop in!
grpHide = new FlxGroup(); grpHide = new FlxGroup();
var rank:String = FlxG.random.getObject(ranks); ranking = new FreeplayRank(420, 41);
tempr = FlxG.random.int(0, 5);
ranking = new FreeplayRank(420, 41, tempr);
add(ranking); add(ranking);
blurredRanking = new FreeplayRank(ranking.x, ranking.y, tempr); blurredRanking = new FreeplayRank(ranking.x, ranking.y);
blurredRanking.shader = new GaussianBlurShader(1); blurredRanking.shader = new GaussianBlurShader(1);
add(blurredRanking); add(blurredRanking);
// ranking.loadGraphic(Paths.image('freeplay/ranks/' + rank)); // ranking.loadGraphic(Paths.image('freeplay/ranks/' + rank));
@ -344,19 +340,19 @@ class SongMenuItem extends FlxSpriteGroup
}); });
add(evilTrail); add(evilTrail);
switch (tempr) switch (ranking.rank)
{ {
case 0: case SHIT:
evilTrail.color = 0xFF6044FF; evilTrail.color = 0xFF6044FF;
case 1: case GOOD:
evilTrail.color = 0xFFEF8764; evilTrail.color = 0xFFEF8764;
case 2: case GREAT:
evilTrail.color = 0xFFEAF6FF; evilTrail.color = 0xFFEAF6FF;
case 3: case EXCELLENT:
evilTrail.color = 0xFFFDCB42; evilTrail.color = 0xFFFDCB42;
case 4: case PERFECT:
evilTrail.color = 0xFFFF58B4; evilTrail.color = 0xFFFF58B4;
case 5: case PERFECT_GOLD:
evilTrail.color = 0xFFFFB619; evilTrail.color = 0xFFFFB619;
} }
} }
@ -393,6 +389,12 @@ class SongMenuItem extends FlxSpriteGroup
// diffRatingSprite.visible = false; // diffRatingSprite.visible = false;
} }
function updateScoringRank(newRank:Null<ScoringRank>):Void
{
this.ranking.rank = newRank;
this.blurredRanking.rank = newRank;
}
function set_hsvShader(value:HSVShader):HSVShader function set_hsvShader(value:HSVShader):HSVShader
{ {
this.hsvShader = value; this.hsvShader = value;
@ -441,6 +443,7 @@ class SongMenuItem extends FlxSpriteGroup
if (songData?.songCharacter != null) setCharacter(songData.songCharacter); if (songData?.songCharacter != null) setCharacter(songData.songCharacter);
updateBPM(Std.int(songData?.songStartingBpm) ?? 0); updateBPM(Std.int(songData?.songStartingBpm) ?? 0);
updateDifficultyRating(songData?.difficultyRating ?? 0); updateDifficultyRating(songData?.difficultyRating ?? 0);
updateScoringRank(songData?.scoringRank);
// Update opacity, offsets, etc. // Update opacity, offsets, etc.
updateSelected(); updateSelected();
@ -668,41 +671,53 @@ class SongMenuItem extends FlxSpriteGroup
class FreeplayRank extends FlxSprite 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:Null<ScoringRank>):Null<ScoringRank>
function set_rank(val):Int
{ {
animation.play(numToRank[val], true, false); rank = val;
if (rank == null)
{
this.visible = false;
}
else
{
this.visible = true;
animation.play(val.getFreeplayRankIconAsset(), true, false);
centerOffsets(false); centerOffsets(false);
switch (val) switch (val)
{ {
case 0: case SHIT:
// offset.x -= 1; // offset.x -= 1;
case 1: case GOOD:
// offset.x -= 1; // offset.x -= 1;
offset.y -= 8; offset.y -= 8;
case 2: case GREAT:
// offset.x -= 1; // offset.x -= 1;
offset.y -= 8; offset.y -= 8;
case 3: case EXCELLENT:
// offset.y += 5; // offset.y += 5;
case 4: case PERFECT:
// offset.y += 5;
case PERFECT_GOLD:
// offset.y += 5; // offset.y += 5;
default: default:
centerOffsets(false); centerOffsets(false);
} }
updateHitbox(); updateHitbox();
return val;
} }
public var baseY:Float = 0; return rank = val;
public var baseX:Float = 0; }
public function new(x:Float, y:Float, ?initRank:Int = 0) public var baseX:Float = 0;
public var baseY:Float = 0;
public function new(x:Float, y:Float)
{ {
super(x, y); super(x, y);
@ -717,9 +732,7 @@ class FreeplayRank extends FlxSprite
blend = BlendMode.ADD; blend = BlendMode.ADD;
this.rank = initRank; this.rank = null;
animation.play(numToRank[initRank], true);
// setGraphicSize(Std.int(width * 0.9)); // setGraphicSize(Std.int(width * 0.9));
scale.set(0.9, 0.9); scale.set(0.9, 0.9);