1
0
Fork 0
mirror of https://github.com/ninjamuffin99/Funkin.git synced 2024-11-15 11:22:55 +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,
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,

View file

@ -3123,9 +3123,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,

View file

@ -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
*/

View file

@ -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';
}
}
}

View file

@ -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.
*/

View file

@ -34,6 +34,8 @@ import funkin.play.song.Song;
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;
@ -49,6 +51,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;
};
/**
@ -160,10 +190,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;
@ -587,6 +621,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);
@ -657,6 +696,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();
@ -763,8 +808,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);
@ -789,21 +836,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);
@ -811,13 +858,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'));
@ -846,31 +893,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'));
@ -880,7 +927,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();
}
@ -915,6 +962,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,
@ -981,7 +1031,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();
@ -989,19 +1042,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)
@ -1024,6 +1078,7 @@ class FreeplayState extends MusicBeatSubState
confirmTextGlow.y += 1;
trace(confirmTextGlow.x, confirmTextGlow.y);
}
#end
if (FlxG.keys.justPressed.F)
{
@ -1765,6 +1820,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
@ -1827,6 +1884,8 @@ class FreeplaySongData
{
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.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);