1
0
Fork 0
mirror of https://github.com/ninjamuffin99/Funkin.git synced 2024-09-12 05:07:06 +00:00

Remember difficulty when leaving story/freeplay menu.

This commit is contained in:
EliteMasterEric 2023-10-12 03:20:21 -04:00
parent 2e56fdb026
commit 996f7b275e
5 changed files with 172 additions and 87 deletions

2
assets

@ -1 +1 @@
Subproject commit d2b3dcab92f5cb4b11774a80cbe2e270972a9577
Subproject commit 486ea1cdc37a1f1907ba9231b0a1946ff4051f27

View file

@ -1,5 +1,6 @@
package funkin;
import funkin.play.song.Song;
import flash.text.TextField;
import flixel.addons.display.FlxGridOverlay;
import flixel.addons.transition.FlxTransitionableState;
@ -48,10 +49,13 @@ import lime.utils.Assets;
class FreeplayState extends MusicBeatSubState
{
var songs:Array<FreeplaySongData> = [];
var songs:Array<Null<FreeplaySongData>> = [];
var diffIdsCurrent:Array<String> = [];
var diffIdsTotal:Array<String> = [];
var curSelected:Int = 0;
var curDifficulty:Int = 1;
var currentDifficulty:String = Constants.DEFAULT_DIFFICULTY;
var fp:FreeplayScore;
var txtCompletion:FlxText;
@ -60,7 +64,7 @@ class FreeplayState extends MusicBeatSubState
var lerpScore:Float = 0;
var intendedScore:Int = 0;
var grpDifficulties:FlxSpriteGroup;
var grpDifficulties:FlxTypedSpriteGroup<DifficultySprite>;
var coolColors:Array<Int> = [
0xff9271fd,
@ -85,6 +89,10 @@ class FreeplayState extends MusicBeatSubState
var stickerSubState:StickerSubState;
//
static var rememberedDifficulty:Null<String> = "normal";
static var rememberedSongId:Null<String> = null;
public function new(?stickers:StickerSubState = null)
{
if (stickers != null)
@ -130,14 +138,23 @@ class FreeplayState extends MusicBeatSubState
songs.push(null);
// programmatically adds the songs via LevelRegistry and SongRegistry
for (coolWeek in LevelRegistry.instance.listBaseGameLevelIds())
for (levelId in LevelRegistry.instance.listBaseGameLevelIds())
{
for (songId in LevelRegistry.instance.parseEntryData(coolWeek).songs)
for (songId in LevelRegistry.instance.parseEntryData(levelId).songs)
{
var metadata = SongRegistry.instance.parseEntryMetadata(songId);
var char = metadata.playData.characters.opponent;
var songName = metadata.songName;
addSong(songId, songName, coolWeek, char);
var song:Song = SongRegistry.instance.fetchEntry(songId);
var songBaseDifficulty:SongDifficulty = song.getDifficulty(Constants.DEFAULT_DIFFICULTY);
var songName = songBaseDifficulty.songName;
var songOpponent = songBaseDifficulty.characters.opponent;
var songDifficulties = song.listDifficulties();
songs.push(new FreeplaySongData(songId, songName, levelId, songOpponent, songDifficulties));
for (difficulty in songDifficulties)
{
diffIdsTotal.pushUnique(difficulty);
}
}
}
@ -283,7 +300,7 @@ class FreeplayState extends MusicBeatSubState
grpCapsules = new FlxTypedGroup<SongMenuItem>();
add(grpCapsules);
grpDifficulties = new FlxSpriteGroup(-300, 80);
grpDifficulties = new FlxTypedSpriteGroup<DifficultySprite>(-300, 80);
add(grpDifficulties);
exitMovers.set([grpDifficulties],
@ -293,15 +310,22 @@ class FreeplayState extends MusicBeatSubState
wait: 0
});
grpDifficulties.add(new FlxSprite().loadGraphic(Paths.image('freeplay/freeplayEasy')));
grpDifficulties.add(new FlxSprite().loadGraphic(Paths.image('freeplay/freeplayNorm')));
grpDifficulties.add(new FlxSprite().loadGraphic(Paths.image('freeplay/freeplayHard')));
for (diffId in diffIdsTotal)
{
var diffSprite:DifficultySprite = new DifficultySprite(diffId);
diffSprite.difficultyId = diffId;
grpDifficulties.add(diffSprite);
}
grpDifficulties.group.forEach(function(spr) {
spr.visible = false;
});
grpDifficulties.group.members[curDifficulty].visible = true;
for (diffSprite in grpDifficulties.group.members)
{
if (diffSprite == null) continue;
if (diffSprite.difficultyId == currentDifficulty) diffSprite.visible = true;
}
var albumArt:FlxAtlasSprite = new FlxAtlasSprite(640, 360, Paths.animateAtlas("freeplay/albumRoll"));
albumArt.visible = false;
@ -572,15 +596,12 @@ class FreeplayState extends MusicBeatSubState
FlxG.console.registerFunction("changeSelection", changeSelection);
rememberSelection();
changeSelection();
changeDiff();
}
public function addSong(songId:String, songName:String, levelId:String, songCharacter:String)
{
songs.push(new FreeplaySongData(songId, songName, levelId, songCharacter));
}
var touchY:Float = 0;
var touchX:Float = 0;
var dxTouch:Float = 0;
@ -850,28 +871,24 @@ class FreeplayState extends MusicBeatSubState
{
touchTimer = 0;
curDifficulty += change;
var currentDifficultyIndex = diffIdsCurrent.indexOf(currentDifficulty);
if (curDifficulty < 0) curDifficulty = 2;
if (curDifficulty > 2) curDifficulty = 0;
if (currentDifficultyIndex == -1) currentDifficultyIndex = diffIdsCurrent.indexOf(Constants.DEFAULT_DIFFICULTY);
var targetDifficulty:String = switch (curDifficulty)
{
case 0:
'easy';
case 1:
'normal';
case 2:
'hard';
default: 'normal';
};
currentDifficultyIndex += change;
if (currentDifficultyIndex < 0) currentDifficultyIndex = diffIdsCurrent.length - 1;
if (currentDifficultyIndex >= diffIdsCurrent.length) currentDifficultyIndex = 0;
currentDifficulty = diffIdsCurrent[currentDifficultyIndex];
var daSong = songs[curSelected];
if (daSong != null)
{
var songScore:SaveScoreData = Save.get().getSongScore(songs[curSelected].songId, targetDifficulty);
var songScore:SaveScoreData = Save.get().getSongScore(songs[curSelected].songId, currentDifficulty);
intendedScore = songScore?.score ?? 0;
intendedCompletion = songScore?.accuracy ?? 0.0;
rememberedDifficulty = currentDifficulty;
}
else
{
@ -879,19 +896,31 @@ class FreeplayState extends MusicBeatSubState
intendedCompletion = 0.0;
}
grpDifficulties.group.forEach(function(spr) {
spr.visible = false;
grpDifficulties.group.forEach(function(diffSprite) {
diffSprite.visible = false;
});
var curShit:FlxSprite = grpDifficulties.group.members[curDifficulty];
curShit.visible = true;
curShit.offset.y += 5;
curShit.alpha = 0.5;
new FlxTimer().start(1 / 24, function(swag) {
curShit.alpha = 1;
curShit.updateHitbox();
});
for (diffSprite in grpDifficulties.group.members)
{
if (diffSprite == null) continue;
if (diffSprite.difficultyId == currentDifficulty)
{
if (change != 0)
{
diffSprite.visible = true;
diffSprite.offset.y += 5;
diffSprite.alpha = 0.5;
new FlxTimer().start(1 / 24, function(swag) {
diffSprite.alpha = 1;
diffSprite.updateHitbox();
});
}
else
{
diffSprite.visible = true;
}
}
}
}
// Clears the cache of songs, frees up memory, they' ll have to be loaded in later tho function clearDaCache(actualSongTho:String)
@ -899,6 +928,7 @@ class FreeplayState extends MusicBeatSubState
{
for (song in songs)
{
if (song == null) return;
if (song.songName != actualSongTho)
{
trace('trying to remove: ' + song.songName);
@ -913,22 +943,7 @@ class FreeplayState extends MusicBeatSubState
var songId:String = cap.songTitle.toLowerCase();
var targetSong:Song = SongRegistry.instance.fetchEntry(songId);
var targetDifficulty:String = switch (curDifficulty)
{
case 0:
'easy';
case 1:
'normal';
case 2:
'hard';
default: 'normal';
};
// TODO: Implement additional difficulties into the interface properly.
if (FlxG.keys.pressed.E)
{
targetDifficulty = 'erect';
}
var targetDifficulty:String = currentDifficulty;
// TODO: Implement Pico into the interface properly.
var targetCharacter:String = 'bf';
@ -957,6 +972,22 @@ class FreeplayState extends MusicBeatSubState
});
}
function rememberSelection():Void
{
if (rememberedSongId != null)
{
curSelected = songs.findIndex(function(song) {
if (song == null) return false;
return song.songId == rememberedSongId;
});
}
if (rememberedDifficulty != null)
{
currentDifficulty = rememberedDifficulty;
}
}
function changeSelection(change:Int = 0)
{
// NGio.logEvent('Fresh');
@ -968,28 +999,19 @@ class FreeplayState extends MusicBeatSubState
if (curSelected < 0) curSelected = grpCapsules.countLiving() - 1;
if (curSelected >= grpCapsules.countLiving()) curSelected = 0;
var targetDifficulty:String = switch (curDifficulty)
{
case 0:
'easy';
case 1:
'normal';
case 2:
'hard';
default: 'normal';
};
var daSong = songs[curSelected];
if (daSong != null)
{
var songScore:SaveScoreData = Save.get().getSongScore(daSong.songId, targetDifficulty);
intendedScore = songScore?.score ?? 0;
intendedCompletion = songScore?.accuracy ?? 0.0;
diffIdsCurrent = daSong.songDifficulties;
rememberedSongId = daSong.songId;
changeDiff();
}
else
{
intendedScore = 0;
intendedCompletion = 0.0;
rememberedSongId = null;
rememberedDifficulty = null;
}
for (index => capsule in grpCapsules.members)
@ -1011,6 +1033,10 @@ class FreeplayState extends MusicBeatSubState
FlxG.sound.playMusic(Paths.music('freeplay/freeplayRandom'), 0);
FlxG.sound.music.fadeIn(2, 0, 0.8);
}
else
{
// TODO: Try to stream the music?
}
grpCapsules.members[curSelected].selected = true;
}
}
@ -1078,19 +1104,21 @@ enum abstract FilterType(String)
class FreeplaySongData
{
public var isFav:Bool = false;
public var songId:String = "";
public var songName:String = "";
public var levelId:String = "";
public var songCharacter:String = "";
public var isFav:Bool = false;
public var songDifficulties:Array<String> = [];
public function new(songId:String, songName:String, levelId:String, songCharacter:String, isFav:Bool = false)
public function new(songId:String, songName:String, levelId:String, songCharacter:String, songDifficulties:Array<String>)
{
this.songId = songId;
this.songName = songName;
this.levelId = levelId;
this.songCharacter = songCharacter;
this.isFav = isFav;
this.songDifficulties = songDifficulties;
}
}
@ -1101,3 +1129,17 @@ typedef MoveData =
var ?speed:Float;
var ?wait:Float;
}
class DifficultySprite extends FlxSprite
{
public var difficultyId:String;
public function new(diffId:String)
{
super();
difficultyId = diffId;
loadGraphic(Paths.image('freeplay/freeplay' + diffId));
}
}

View file

@ -162,7 +162,7 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
// but all the difficulties in the metadata must be in the chart file.
for (diffId in metadata.playData.difficulties)
{
difficultyIds.push(diffId);
difficultyIds.pushUnique(diffId);
var difficulty:SongDifficulty = new SongDifficulty(this, diffId, metadata.variation);

View file

@ -99,6 +99,9 @@ class StoryMenuState extends MusicBeatState
var stickerSubState:StickerSubState;
static var rememberedLevelId:Null<String> = null;
static var rememberedDifficulty:Null<String> = "normal";
public function new(?stickers:StickerSubState = null)
{
super();
@ -133,6 +136,8 @@ class StoryMenuState extends MusicBeatState
updateData();
rememberSelection();
// Explicitly define the background color.
this.bgColor = FlxColor.BLACK;
@ -185,6 +190,7 @@ class StoryMenuState extends MusicBeatState
leftDifficultyArrow.animation.play('idle');
add(leftDifficultyArrow);
buildDifficultySprite(Constants.DEFAULT_DIFFICULTY);
buildDifficultySprite();
rightDifficultyArrow = new FlxSprite(difficultySprite.x + difficultySprite.width + 10, leftDifficultyArrow.y);
@ -207,6 +213,18 @@ class StoryMenuState extends MusicBeatState
#end
}
function rememberSelection():Void
{
if (rememberedLevelId != null)
{
currentLevelId = rememberedLevelId;
}
if (rememberedDifficulty != null)
{
currentDifficultyId = rememberedDifficulty;
}
}
function playMenuMusic():Void
{
if (FlxG.sound.music == null || !FlxG.sound.music.playing)
@ -228,34 +246,35 @@ class StoryMenuState extends MusicBeatState
isLevelUnlocked = currentLevel == null ? false : currentLevel.isUnlocked();
}
function buildDifficultySprite():Void
function buildDifficultySprite(?diff:String):Void
{
if (diff == null) diff = currentDifficultyId;
remove(difficultySprite);
difficultySprite = difficultySprites.get(currentDifficultyId);
difficultySprite = difficultySprites.get(diff);
if (difficultySprite == null)
{
difficultySprite = new FlxSprite(leftDifficultyArrow.x + leftDifficultyArrow.width + 10, leftDifficultyArrow.y);
if (Assets.exists(Paths.file('images/storymenu/difficulties/${currentDifficultyId}.xml')))
if (Assets.exists(Paths.file('images/storymenu/difficulties/${diff}.xml')))
{
difficultySprite.frames = Paths.getSparrowAtlas('storymenu/difficulties/${currentDifficultyId}');
difficultySprite.frames = Paths.getSparrowAtlas('storymenu/difficulties/${diff}');
difficultySprite.animation.addByPrefix('idle', 'idle0', 24, true);
difficultySprite.animation.play('idle');
}
else
{
difficultySprite.loadGraphic(Paths.image('storymenu/difficulties/${currentDifficultyId}'));
difficultySprite.loadGraphic(Paths.image('storymenu/difficulties/${diff}'));
}
difficultySprites.set(currentDifficultyId, difficultySprite);
difficultySprites.set(diff, difficultySprite);
difficultySprite.x += (difficultySprites.get('normal').width - difficultySprite.width) / 2;
difficultySprite.x += (difficultySprites.get(Constants.DEFAULT_DIFFICULTY).width - difficultySprite.width) / 2;
}
difficultySprite.alpha = 0;
difficultySprite.y = leftDifficultyArrow.y - 15;
var targetY:Float = leftDifficultyArrow.y + 10;
targetY -= (difficultySprite.height - difficultySprites.get('normal').height) / 2;
targetY -= (difficultySprite.height - difficultySprites.get(Constants.DEFAULT_DIFFICULTY).height) / 2;
FlxTween.tween(difficultySprite, {y: targetY, alpha: 1}, 0.07);
add(difficultySprite);
@ -399,6 +418,7 @@ class StoryMenuState extends MusicBeatState
var previousLevelId:String = currentLevelId;
currentLevelId = levelList[currentIndex];
rememberedLevelId = currentLevelId;
updateData();
@ -442,6 +462,7 @@ class StoryMenuState extends MusicBeatState
var hasChanged:Bool = currentDifficultyId != difficultyList[currentIndex];
currentDifficultyId = difficultyList[currentIndex];
rememberedDifficulty = currentDifficultyId;
if (difficultyList.length <= 1)
{

View file

@ -23,6 +23,13 @@ class ArrayTools
return result;
}
public static function pushUnique<T>(array:Array<T>, element:T):Bool
{
if (array.contains(element)) return false;
array.push(element);
return true;
}
/**
* Return the first element of the array that satisfies the predicate, or null if none do.
* @param input The array to search
@ -38,6 +45,21 @@ class ArrayTools
return null;
}
/**
* Return the index of the first element of the array that satisfies the predicate, or `-1` if none do.
* @param input The array to search
* @param predicate The predicate to call
* @return The index of the result
*/
public static function findIndex<T>(input:Array<T>, predicate:T->Bool):Int
{
for (index in 0...input.length)
{
if (predicate(input[index])) return index;
}
return -1;
}
/**
* Remove all elements from the array, without creating a new array.
* @param array The array to clear.