diff --git a/.github/actions/setup-haxeshit/action.yml b/.github/actions/setup-haxeshit/action.yml index dcf5fd0a7..cb5e68f61 100644 --- a/.github/actions/setup-haxeshit/action.yml +++ b/.github/actions/setup-haxeshit/action.yml @@ -13,7 +13,7 @@ runs: - name: Installing Haxe lol run: | haxe -version - haxelib git haxelib https://github.com/HaxeFoundation/haxelib.git development + haxelib git haxelib https://github.com/HaxeFoundation/haxelib.git master haxelib version haxelib --global install hmm shell: bash diff --git a/source/funkin/FreeplayState.hx b/source/funkin/FreeplayState.hx index ae73524a8..918e7c725 100644 --- a/source/funkin/FreeplayState.hx +++ b/source/funkin/FreeplayState.hx @@ -535,16 +535,19 @@ class FreeplayState extends MusicBeatSubState // this creates a filter to return all the songs that start with a letter between those two var filterRegexp = new EReg("^[" + filterStuff.filterData + "].*", "i"); tempSongs = tempSongs.filter(str -> { + if (str == null) return true; // Random return filterRegexp.match(str.songName); }); case STARTSWITH: tempSongs = tempSongs.filter(str -> { + if (str == null) return true; // Random return str.songName.toLowerCase().startsWith(filterStuff.filterData); }); case ALL: // no filter! case FAVORITE: tempSongs = tempSongs.filter(str -> { + if (str == null) return true; // Random return str.isFav; }); default: @@ -555,7 +558,7 @@ class FreeplayState extends MusicBeatSubState var hsvShader:HSVShader = new HSVShader(); var randomCapsule:SongMenuItem = grpCapsules.recycle(SongMenuItem); - randomCapsule.init(FlxG.width, 0, "Random"); + randomCapsule.init(FlxG.width, 0, null); randomCapsule.onConfirm = function() { capsuleOnConfirmRandom(randomCapsule); }; @@ -574,8 +577,7 @@ class FreeplayState extends MusicBeatSubState var funnyMenu:SongMenuItem = grpCapsules.recycle(SongMenuItem); - funnyMenu.init(FlxG.width, 0, tempSongs[i].songName); - if (tempSongs[i].songCharacter != null) funnyMenu.setCharacter(tempSongs[i].songCharacter); + funnyMenu.init(FlxG.width, 0, tempSongs[i]); funnyMenu.onConfirm = function() { capsuleOnConfirmDefault(funnyMenu); }; @@ -946,11 +948,29 @@ class FreeplayState extends MusicBeatSubState } } - function capsuleOnConfirmRandom(cap:SongMenuItem):Void + function capsuleOnConfirmRandom(randomCapsule:SongMenuItem):Void { trace("RANDOM SELECTED"); busy = true; + + var availableSongCapsules:Array<SongMenuItem> = grpCapsules.members.filter(function(cap:SongMenuItem) { + // Dead capsules are ones which were removed from the list when changing filters. + return cap.alive && cap.songData != null; + }); + + trace('Available songs: ${availableSongCapsules.map(function(cap) { + return cap.songData.songName; + })}'); + + var targetSong:SongMenuItem = FlxG.random.getObject(availableSongCapsules); + + // Seeing if I can do an animation... + curSelected = grpCapsules.members.indexOf(targetSong); + changeSelection(0); // Trigger an update. + + // Act like we hit Confirm on that song. + capsuleOnConfirmDefault(targetSong); } function capsuleOnConfirmDefault(cap:SongMenuItem):Void @@ -959,8 +979,7 @@ class FreeplayState extends MusicBeatSubState PlayStatePlaylist.isStoryMode = false; - var songId:String = cap.songTitle.toLowerCase(); - var targetSong:Song = SongRegistry.instance.fetchEntry(songId); + var targetSong:Song = SongRegistry.instance.fetchEntry(cap.songData.songId); var targetDifficulty:String = currentDifficulty; // TODO: Implement Pico into the interface properly. @@ -970,7 +989,7 @@ class FreeplayState extends MusicBeatSubState targetCharacter = 'pico'; } - PlayStatePlaylist.campaignId = songs[curSelected].levelId; + PlayStatePlaylist.campaignId = cap.songData.levelId; // Visual and audio effects. FlxG.sound.play(Paths.sound('confirmMenu')); @@ -981,7 +1000,7 @@ class FreeplayState extends MusicBeatSubState targetSong.cacheCharts(true); new FlxTimer().start(1, function(tmr:FlxTimer) { - Paths.setCurrentLevel(songs[curSelected].levelId); + Paths.setCurrentLevel(cap.songData.levelId); LoadingState.loadAndSwitchState(new PlayState( { targetSong: targetSong, @@ -1013,16 +1032,21 @@ class FreeplayState extends MusicBeatSubState FlxG.sound.play(Paths.sound('scrollMenu'), 0.4); // FlxG.sound.playMusic(Paths.inst(songs[curSelected].songName)); + var prevSelected = curSelected; + curSelected += change; if (curSelected < 0) curSelected = grpCapsules.countLiving() - 1; if (curSelected >= grpCapsules.countLiving()) curSelected = 0; - var daSong = songs[curSelected]; - if (daSong != null) + var daSongCapsule = grpCapsules.members[curSelected]; + if (daSongCapsule.songData != null) { - diffIdsCurrent = daSong.songDifficulties; - rememberedSongId = daSong.songId; + var songScore:SaveScoreData = Save.get().getSongScore(daSongCapsule.songData.songId, currentDifficulty); + intendedScore = songScore?.score ?? 0; + intendedCompletion = songScore?.accuracy ?? 0.0; + diffIdsCurrent = daSongCapsule.songData.songDifficulties; + rememberedSongId = daSongCapsule.songData.songId; changeDiff(); } else @@ -1054,7 +1078,12 @@ class FreeplayState extends MusicBeatSubState } else { - // TODO: Try to stream the music? + // TODO: Stream the instrumental of the selected song? + if (prevSelected == 0) + { + FlxG.sound.playMusic(Paths.music('freakyMenu/freakyMenu')); + FlxG.sound.music.fadeIn(2, 0, 0.8); + } } grpCapsules.members[curSelected].selected = true; } diff --git a/source/funkin/freeplayStuff/SongMenuItem.hx b/source/funkin/freeplayStuff/SongMenuItem.hx index 5fd7eb576..06de92886 100644 --- a/source/funkin/freeplayStuff/SongMenuItem.hx +++ b/source/funkin/freeplayStuff/SongMenuItem.hx @@ -1,5 +1,6 @@ package funkin.freeplayStuff; +import funkin.FreeplayState.FreeplaySongData; import funkin.shaderslmfao.HSVShader; import funkin.shaderslmfao.GaussianBlurShader; import flixel.group.FlxGroup; @@ -19,9 +20,13 @@ class SongMenuItem extends FlxSpriteGroup var pixelIcon:FlxSprite; - public var selected(default, set):Bool; + /** + * Modify this by calling `init()` + * If `null`, assume this SongMenuItem is for the "Random Song" option. + */ + public var songData(default, null):Null<FreeplaySongData> = null; - public var songTitle:String = "Test"; + public var selected(default, set):Bool; public var songText:CapsuleText; public var favIcon:FlxSprite; @@ -45,12 +50,10 @@ class SongMenuItem extends FlxSpriteGroup public var hsvShader(default, set):HSVShader; - public function new(x:Float, y:Float, song:String, ?character:String) + public function new(x:Float, y:Float) { super(x, y); - this.songTitle = song; - capsule = new FlxSprite(); capsule.frames = Paths.getSparrowAtlas('freeplay/freeplayCapsule'); capsule.animation.addByPrefix('selected', 'mp3 capsule w backing0', 24); @@ -86,7 +89,7 @@ class SongMenuItem extends FlxSpriteGroup ranking.x -= 10; } - songText = new CapsuleText(capsule.width * 0.26, 45, songTitle, Std.int(40 * realScaled)); + songText = new CapsuleText(capsule.width * 0.26, 45, 'Random', Std.int(40 * realScaled)); add(songText); grpHide.add(songText); @@ -97,8 +100,6 @@ class SongMenuItem extends FlxSpriteGroup add(pixelIcon); grpHide.add(pixelIcon); - if (character != null) setCharacter(character); - favIcon = new FlxSprite(400, 40); favIcon.frames = Paths.getSparrowAtlas('freeplay/favHeart'); favIcon.animation.addByPrefix('fav', "favorite heart", 24, false); @@ -144,18 +145,21 @@ class SongMenuItem extends FlxSpriteGroup if (value) textAppear(); - selectedAlpha(); + updateSelected(); } - public function init(x:Float, y:Float, song:String, ?character:String) + public function init(x:Float, y:Float, songData:Null<FreeplaySongData>) { this.x = x; this.y = y; - this.songTitle = song; - songText.text = this.songTitle; - if (character != null) setCharacter(character); + this.songData = songData; - selected = selected; + // Update capsule text. + songText.text = songData?.songName ?? 'Random'; + // Update capsule character. + if (songData?.songCharacter != null) setCharacter(songData.songCharacter); + // Update opacity, offsets, etc. + updateSelected(); } /** @@ -169,6 +173,7 @@ class SongMenuItem extends FlxSpriteGroup trace(char); + // TODO: Put this in the character metadata where it belongs. switch (char) { case "monster-christmas": @@ -244,7 +249,7 @@ class SongMenuItem extends FlxSpriteGroup { visible = true; capsule.alpha = 1; - selectedAlpha(); + updateSelected(); doLerp = true; doJumpIn = false; doJumpOut = false; @@ -319,24 +324,22 @@ class SongMenuItem extends FlxSpriteGroup return (index * ((height * realScaled) + 10)) + 120; } - /** - * Merely a helper function to call set_selected, to make sure that the alpha is correct on the rankings/selections - */ - public function selectedAlpha():Void - { - selected = selected; - } - function set_selected(value:Bool):Bool { // cute one liners, lol! - diffGrayscale.setAmount(value ? 0 : 0.8); - songText.alpha = value ? 1 : 0.6; - songText.blurredText.visible = value ? true : false; - capsule.offset.x = value ? 0 : -5; - capsule.animation.play(value ? "selected" : "unselected"); - ranking.alpha = value ? 1 : 0.7; - ranking.color = value ? 0xFFFFFFFF : 0xFFAAAAAA; - return value; + selected = value; + updateSelected(); + return selected; + } + + function updateSelected():Void + { + diffGrayscale.setAmount(this.selected ? 0 : 0.8); + songText.alpha = this.selected ? 1 : 0.6; + songText.blurredText.visible = this.selected ? true : false; + capsule.offset.x = this.selected ? 0 : -5; + capsule.animation.play(this.selected ? "selected" : "unselected"); + ranking.alpha = this.selected ? 1 : 0.7; + ranking.color = this.selected ? 0xFFFFFFFF : 0xFFAAAAAA; } }