From 36a9c29720f5a9c76316d2ab24461b8f54063aa7 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Wed, 20 Mar 2024 14:37:24 -0400 Subject: [PATCH] Work in progress on custom album art for freeplay --- assets | 2 +- source/funkin/InitState.hx | 2 + source/funkin/data/freeplay/AlbumData.hx | 36 ++ source/funkin/data/freeplay/AlbumRegistry.hx | 84 +++++ .../graphics/adobeanimate/FlxAtlasSprite.hx | 7 +- source/funkin/modding/PolymodHandler.hx | 2 + source/funkin/play/song/Song.hx | 20 ++ .../debug/dialogue/ConversationDebugState.hx | 1 + source/funkin/ui/freeplay/Album.hx | 89 +++++ source/funkin/ui/freeplay/AlbumRoll.hx | 173 ++++++++++ source/funkin/ui/freeplay/FreeplayState.hx | 314 +++++++++--------- source/funkin/ui/freeplay/ScriptedAlbum.hx | 9 + source/funkin/ui/freeplay/SongMenuItem.hx | 54 +-- source/funkin/util/Constants.hx | 11 +- 14 files changed, 619 insertions(+), 185 deletions(-) create mode 100644 source/funkin/data/freeplay/AlbumData.hx create mode 100644 source/funkin/data/freeplay/AlbumRegistry.hx create mode 100644 source/funkin/ui/freeplay/Album.hx create mode 100644 source/funkin/ui/freeplay/AlbumRoll.hx create mode 100644 source/funkin/ui/freeplay/ScriptedAlbum.hx diff --git a/assets b/assets index 0e2c5bf21..4e88fb2a5 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 0e2c5bf2134c7e517b70cf74afd58abe5c7b5e50 +Subproject commit 4e88fb2a50b284d92404af6afc95b9840d3cda8d diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx index a9e8dbffa..8837b578d 100644 --- a/source/funkin/InitState.hx +++ b/source/funkin/InitState.hx @@ -24,6 +24,7 @@ import funkin.data.stage.StageRegistry; import funkin.data.dialogue.ConversationRegistry; import funkin.data.dialogue.DialogueBoxRegistry; import funkin.data.dialogue.SpeakerRegistry; +import funkin.data.freeplay.AlbumRegistry; import funkin.data.song.SongRegistry; import funkin.play.character.CharacterData.CharacterDataParser; import funkin.modding.module.ModuleHandler; @@ -167,6 +168,7 @@ class InitState extends FlxState ConversationRegistry.instance.loadEntries(); DialogueBoxRegistry.instance.loadEntries(); SpeakerRegistry.instance.loadEntries(); + AlbumRegistry.instance.loadEntries(); StageRegistry.instance.loadEntries(); // TODO: CharacterDataParser doesn't use json2object, so it's way slower than the other parsers. diff --git a/source/funkin/data/freeplay/AlbumData.hx b/source/funkin/data/freeplay/AlbumData.hx new file mode 100644 index 000000000..265a01fce --- /dev/null +++ b/source/funkin/data/freeplay/AlbumData.hx @@ -0,0 +1,36 @@ +package funkin.data.freeplay; + +/** + * A type definition for the data for an album of songs. + * It includes things like what graphics to display in Freeplay. + * @see https://lib.haxe.org/p/json2object/ + */ +typedef AlbumData = +{ + /** + * Semantic version for album data. + */ + public var version:String; + + /** + * Readable name of the album. + */ + public var name:String; + + /** + * Readable name of the artist(s) of the album. + */ + public var artists:Array; + + /** + * Asset key for the album art. + * The album art will be displayed in Freeplay. + */ + public var albumArtAsset:String; + + /** + * Asset key for the album title. + * The album title will be displayed below the album art in Freeplay. + */ + public var albumTitleAsset:String; +} diff --git a/source/funkin/data/freeplay/AlbumRegistry.hx b/source/funkin/data/freeplay/AlbumRegistry.hx new file mode 100644 index 000000000..78fba451b --- /dev/null +++ b/source/funkin/data/freeplay/AlbumRegistry.hx @@ -0,0 +1,84 @@ +package funkin.data.freeplay; + +import funkin.ui.freeplay.Album; +import funkin.data.freeplay.AlbumData; +import funkin.ui.freeplay.ScriptedAlbum; + +class AlbumRegistry extends BaseRegistry +{ + /** + * The current version string for the album data format. + * Handle breaking changes by incrementing this value + * and adding migration to the `migrateAlbumData()` function. + */ + public static final ALBUM_DATA_VERSION:thx.semver.Version = '1.0.0'; + + public static final ALBUM_DATA_VERSION_RULE:thx.semver.VersionRule = '1.0.x'; + + public static final instance:AlbumRegistry = new AlbumRegistry(); + + public function new() + { + super('ALBUM', 'ui/freeplay/albums', ALBUM_DATA_VERSION_RULE); + } + + /** + * Read, parse, and validate the JSON data and produce the corresponding data object. + * @param id The ID of the entry to load. + * @return The parsed data object. + */ + public function parseEntryData(id:String):Null + { + // JsonParser does not take type parameters, + // otherwise this function would be in BaseRegistry. + var parser:json2object.JsonParser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; + + switch (loadEntryFile(id)) + { + case {fileName: fileName, contents: contents}: + parser.fromJson(contents, fileName); + default: + return null; + } + + if (parser.errors.length > 0) + { + printErrors(parser.errors, id); + return null; + } + return parser.value; + } + + /** + * Parse and validate the JSON data and produce the corresponding data object. + * + * NOTE: Must be implemented on the implementation class. + * @param contents The JSON as a string. + * @param fileName An optional file name for error reporting. + * @return The parsed data object. + */ + public function parseEntryDataRaw(contents:String, ?fileName:String):Null + { + var parser:json2object.JsonParser = new json2object.JsonParser(); + parser.ignoreUnknownVariables = false; + parser.fromJson(contents, fileName); + + if (parser.errors.length > 0) + { + printErrors(parser.errors, fileName); + return null; + } + return parser.value; + } + + function createScriptedEntry(clsName:String):Album + { + return ScriptedAlbum.init(clsName, 'unknown'); + } + + function getScriptedClassNames():Array + { + return ScriptedAlbum.listScriptClasses(); + } +} diff --git a/source/funkin/graphics/adobeanimate/FlxAtlasSprite.hx b/source/funkin/graphics/adobeanimate/FlxAtlasSprite.hx index 9a2af8913..ec8c8413c 100644 --- a/source/funkin/graphics/adobeanimate/FlxAtlasSprite.hx +++ b/source/funkin/graphics/adobeanimate/FlxAtlasSprite.hx @@ -3,7 +3,9 @@ package funkin.graphics.adobeanimate; import flixel.util.FlxSignal.FlxTypedSignal; import flxanimate.FlxAnimate; import flxanimate.FlxAnimate.Settings; -import flixel.math.FlxPoint; +import flxanimate.frames.FlxAnimateFrames; +import openfl.display.BitmapData; +import openfl.utils.Assets; /** * A sprite which provides convenience functions for rendering a texture atlas with animations. @@ -19,6 +21,7 @@ class FlxAtlasSprite extends FlxAnimate ShowPivot: #if debug false #else false #end, Antialiasing: true, ScrollFactor: null, + OverrideGraphics: [], // Offset: new FlxPoint(0, 0), // This is just FlxSprite.offset }; @@ -31,7 +34,7 @@ class FlxAtlasSprite extends FlxAnimate var canPlayOtherAnims:Bool = true; - public function new(x:Float, y:Float, path:String, ?settings:Settings) + public function new(x:Float, y:Float, ?path:String, ?settings:Settings) { if (settings == null) settings = SETTINGS; diff --git a/source/funkin/modding/PolymodHandler.hx b/source/funkin/modding/PolymodHandler.hx index b1c6b511a..a88476d4d 100644 --- a/source/funkin/modding/PolymodHandler.hx +++ b/source/funkin/modding/PolymodHandler.hx @@ -8,6 +8,7 @@ import funkin.data.level.LevelRegistry; import funkin.data.notestyle.NoteStyleRegistry; import funkin.data.song.SongRegistry; import funkin.data.stage.StageRegistry; +import funkin.data.freeplay.AlbumRegistry; import funkin.modding.module.ModuleHandler; import funkin.play.character.CharacterData.CharacterDataParser; import funkin.save.Save; @@ -324,6 +325,7 @@ class PolymodHandler ConversationRegistry.instance.loadEntries(); DialogueBoxRegistry.instance.loadEntries(); SpeakerRegistry.instance.loadEntries(); + AlbumRegistry.instance.loadEntries(); StageRegistry.instance.loadEntries(); CharacterDataParser.loadCharacterCache(); // TODO: Migrate characters to BaseRegistry. ModuleHandler.loadModuleCache(); diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 1b7740408..d82b60de6 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -213,6 +213,26 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry + { + var result:Map = new Map(); + + for (difficultyId in difficulties.keys()) + { + var meta:Null = difficulties.get(difficultyId); + if (meta != null && meta.album != null) + { + result.set(difficultyId, meta.album); + } + } + + return result; + } + /** * Populate the difficulty data from the provided metadata. * Does not load chart data (that is triggered later when we want to play the song). diff --git a/source/funkin/ui/debug/dialogue/ConversationDebugState.hx b/source/funkin/ui/debug/dialogue/ConversationDebugState.hx index f165865c4..c2edcca5a 100644 --- a/source/funkin/ui/debug/dialogue/ConversationDebugState.hx +++ b/source/funkin/ui/debug/dialogue/ConversationDebugState.hx @@ -11,6 +11,7 @@ import funkin.data.dialogue.DialogueBoxData; import funkin.data.dialogue.DialogueBoxRegistry; import funkin.data.dialogue.SpeakerData; import funkin.data.dialogue.SpeakerRegistry; +import funkin.data.freeplay.AlbumRegistry; import funkin.play.cutscene.dialogue.Conversation; import funkin.play.cutscene.dialogue.DialogueBox; import funkin.play.cutscene.dialogue.Speaker; diff --git a/source/funkin/ui/freeplay/Album.hx b/source/funkin/ui/freeplay/Album.hx new file mode 100644 index 000000000..7291c7357 --- /dev/null +++ b/source/funkin/ui/freeplay/Album.hx @@ -0,0 +1,89 @@ +package funkin.ui.freeplay; + +import funkin.data.freeplay.AlbumData; +import funkin.data.freeplay.AlbumRegistry; +import funkin.data.IRegistryEntry; +import flixel.graphics.FlxGraphic; + +/** + * A class representing the data for an album as displayed in Freeplay. + */ +class Album implements IRegistryEntry +{ + /** + * The internal ID for this album. + */ + public final id:String; + + /** + * The full data for an album. + */ + public final _data:AlbumData; + + public function new(id:String) + { + this.id = id; + this._data = _fetchData(id); + + if (_data == null) + { + throw 'Could not parse album data for id: $id'; + } + } + + /** + * Return the name of the album. + * @ + */ + public function getAlbumName():String + { + return _data.name; + } + + /** + * Return the artists of the album. + * @return The list of artists + */ + public function getAlbumArtists():Array + { + return _data.artists; + } + + /** + * Get the asset key for the album art. + * @return The asset key + */ + public function getAlbumArtAssetKey():String + { + return _data.albumArtAsset; + } + + /** + * Get the album art as a graphic, ready to apply to a sprite. + * @return The built graphic + */ + public function getAlbumArtGraphic():FlxGraphic + { + return FlxG.bitmap.add(Paths.image(getAlbumArtAssetKey())); + } + + /** + * Get the asset key for the album title. + */ + public function getAlbumTitleAssetKey():String + { + return _data.albumTitleAsset; + } + + public function toString():String + { + return 'Album($id)'; + } + + public function destroy():Void {} + + static function _fetchData(id:String):Null + { + return AlbumRegistry.instance.parseEntryDataWithMigration(id, AlbumRegistry.instance.fetchEntryVersion(id)); + } +} diff --git a/source/funkin/ui/freeplay/AlbumRoll.hx b/source/funkin/ui/freeplay/AlbumRoll.hx new file mode 100644 index 000000000..f0c759666 --- /dev/null +++ b/source/funkin/ui/freeplay/AlbumRoll.hx @@ -0,0 +1,173 @@ +package funkin.ui.freeplay; + +import flixel.graphics.FlxGraphic; +import flixel.group.FlxSpriteGroup; +import flixel.util.FlxSort; +import funkin.data.freeplay.AlbumRegistry; +import funkin.graphics.adobeanimate.FlxAtlasSprite; +import funkin.graphics.FunkinSprite; +import funkin.util.SortUtil; + +/** + * The graphic for the album roll in the FreeplayState. + * Simply set `albumID` to fetch the required data and update the textures. + */ +class AlbumRoll extends FlxSpriteGroup +{ + /** + * The ID of the album to display. + * Modify this value to automatically update the album art and title. + */ + public var albumId(default, set):String; + + function set_albumId(value:String):String + { + if (this.albumId != value) + { + this.albumId = value; + updateAlbum(); + } + + return value; + } + + var albumArt:FlxAtlasSprite; + var albumTitle:FunkinSprite; + var difficultyStars:DifficultyStars; + + var albumData:Album; + + public function new() + { + super(); + + albumTitle = new FunkinSprite(947, 491); + albumTitle.visible = false; + albumTitle.zIndex = 200; + add(albumTitle); + + difficultyStars = new DifficultyStars(140, 39); + + difficultyStars.stars.visible = true; + albumTitle.visible = false; + // albumArtist.visible = false; + + // var albumArtist:FlxSprite = new FlxSprite(1010, 607).loadGraphic(Paths.image('freeplay/albumArtist-kawaisprite')); + } + + /** + * Load the album data by ID and update the textures. + */ + function updateAlbum():Void + { + albumData = AlbumRegistry.instance.fetchEntry(albumId); + + if (albumData == null) + { + FlxG.log.warn('Could not find album data for album ID: ${albumId}'); + + return; + }; + + var albumArtGraphics:Array = [null, albumData.getAlbumArtGraphic()]; + + if (albumArt != null) + { + albumArt.visible = false; + albumArt.anim.stop(); + albumArt.destroy(); + remove(albumArt); + } + + // I wasn't able to get replacing to work properly on an existing object, + // so I just throw the old one in the trash and make a new one. + albumArt = new FlxAtlasSprite(640, 360, Paths.animateAtlas('freeplay/albumRoll'), + { + OverrideGraphics: albumArtGraphics, + }); + albumArt.zIndex = 100; + + playIntro(); + add(albumArt); + + albumTitle.loadGraphic(Paths.image(albumData.getAlbumTitleAssetKey())); + + refresh(); + } + + public function refresh():Void + { + sort(SortUtil.byZIndex, FlxSort.ASCENDING); + } + + /** + * Apply exit movers for the album roll. + * @param exitMovers The exit movers to apply. + */ + public function applyExitMovers(exitMovers:FreeplayState.ExitMoverData):Void + { + exitMovers.set([albumArt], + { + x: FlxG.width, + speed: 0.4, + wait: 0 + }); + exitMovers.set([albumTitle], + { + x: FlxG.width, + speed: 0.2, + wait: 0.1 + }); + + /* + exitMovers.set([albumArtist], + { + x: FlxG.width * 1.1, + speed: 0.2, + wait: 0.2 + }); + */ + exitMovers.set([difficultyStars], + { + x: FlxG.width * 1.2, + speed: 0.2, + wait: 0.3 + }); + } + + /** + * Play the intro animation on the album art. + */ + public function playIntro():Void + { + albumArt.visible = true; + albumArt.anim.play(''); + albumArt.anim.onComplete = function() { + albumArt.anim.pause(); + }; + } + + public function setDifficultyStars(?difficulty:Int):Void + { + if (difficulty == null) return; + + difficultyStars.difficulty = difficulty; + } + + /** + * Make the album title graphic visible. + */ + public function showTitle():Void + { + albumTitle.visible = true; + } + + /** + * Make the album stars visible. + */ + public function showStars():Void + { + // albumArtist.visible = false; + difficultyStars.stars.visible = false; + } +} diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 7ade5a2a6..8d7ecb556 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -1,19 +1,14 @@ package funkin.ui.freeplay; -import openfl.text.TextField; -import flixel.addons.display.FlxGridOverlay; import flixel.addons.transition.FlxTransitionableState; import flixel.addons.ui.FlxInputText; import flixel.FlxCamera; -import flixel.FlxGame; import flixel.FlxSprite; -import flixel.FlxState; import flixel.group.FlxGroup; import flixel.group.FlxGroup.FlxTypedGroup; import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup; import flixel.input.touch.FlxTouch; import flixel.math.FlxAngle; -import flixel.math.FlxMath; import flixel.math.FlxPoint; import flixel.system.debug.watch.Tracker.TrackerProfile; import flixel.text.FlxText; @@ -25,7 +20,6 @@ import flixel.util.FlxTimer; import funkin.audio.FunkinSound; import funkin.data.level.LevelRegistry; import funkin.data.song.SongRegistry; -import funkin.graphics.adobeanimate.FlxAtlasSprite; import funkin.graphics.FunkinCamera; import funkin.graphics.FunkinSprite; import funkin.graphics.shaders.AngleMask; @@ -33,28 +27,16 @@ import funkin.graphics.shaders.HSVShader; import funkin.graphics.shaders.PureColor; import funkin.graphics.shaders.StrokeShader; import funkin.input.Controls; -import funkin.input.Controls.Control; -import funkin.play.components.HealthIcon; -import funkin.play.PlayState; import funkin.play.PlayStatePlaylist; import funkin.play.song.Song; import funkin.save.Save; import funkin.save.Save.SaveScoreData; import funkin.ui.AtlasText; -import funkin.ui.freeplay.BGScrollingText; -import funkin.ui.freeplay.DifficultyStars; -import funkin.ui.freeplay.DJBoyfriend; -import funkin.ui.freeplay.FreeplayScore; -import funkin.ui.freeplay.LetterSort; -import funkin.ui.freeplay.SongMenuItem; import funkin.ui.mainmenu.MainMenuState; -import funkin.ui.MusicBeatState; import funkin.ui.MusicBeatSubState; import funkin.ui.transition.LoadingState; import funkin.ui.transition.StickerSubState; import funkin.util.MathUtil; -import funkin.util.MathUtil; -import lime.app.Future; import lime.utils.Assets; /** @@ -65,6 +47,9 @@ typedef FreeplayStateParams = ?character:String, }; +/** + * The state for the freeplay menu, allowing the player to select any song to play. + */ class FreeplayState extends MusicBeatSubState { // @@ -120,30 +105,31 @@ class FreeplayState extends MusicBeatSubState var grpDifficulties:FlxTypedSpriteGroup; var coolColors:Array = [ - 0xff9271fd, - 0xff9271fd, - 0xff223344, + 0xFF9271FD, + 0xFF9271FD, + 0xFF223344, 0xFF941653, - 0xFFfc96d7, - 0xFFa0d1ff, - 0xffff78bf, - 0xfff6b604 + 0xFFFC96D7, + 0xFFA0D1FF, + 0xFFFF78BF, + 0xFFF6B604 ]; var grpSongs:FlxTypedGroup; var grpCapsules:FlxTypedGroup; var curCapsule:SongMenuItem; var curPlaying:Bool = false; - var ostName:FlxText; - var difficultyStars:DifficultyStars; var displayedVariations:Array; var dj:DJBoyfriend; + var ostName:FlxText; + var albumRoll:AlbumRoll; + var letterSort:LetterSort; var typing:FlxInputText; - var exitMovers:Map, MoveData> = new Map(); + var exitMovers:ExitMoverData = new Map(); var stickerSubState:StickerSubState; @@ -179,7 +165,7 @@ class FreeplayState extends MusicBeatSubState #if discord_rpc // Updating Discord Rich Presence - DiscordClient.changePresence("In the Menus", null); + DiscordClient.changePresence('In the Menus', null); #end var isDebug:Bool = false; @@ -195,7 +181,7 @@ class FreeplayState extends MusicBeatSubState // TODO: This makes custom variations disappear from Freeplay. Figure out a better solution later. // Default character (BF) shows default and Erect variations. Pico shows only Pico variations. - displayedVariations = (currentCharacter == "bf") ? [Constants.DEFAULT_VARIATION, "erect"] : [currentCharacter]; + displayedVariations = (currentCharacter == 'bf') ? [Constants.DEFAULT_VARIATION, 'erect'] : [currentCharacter]; // programmatically adds the songs via LevelRegistry and SongRegistry for (levelId in LevelRegistry.instance.listBaseGameLevelIds()) @@ -205,7 +191,7 @@ class FreeplayState extends MusicBeatSubState var song:Song = SongRegistry.instance.fetchEntry(songId); // Only display songs which actually have available charts for the current character. - var availableDifficultiesForSong = song.listDifficulties(displayedVariations); + var availableDifficultiesForSong:Array = song.listDifficulties(displayedVariations); if (availableDifficultiesForSong.length == 0) continue; songs.push(new FreeplaySongData(levelId, songId, song, displayedVariations)); @@ -226,16 +212,16 @@ class FreeplayState extends MusicBeatSubState trace(FlxCamera.defaultZoom); var pinkBack:FunkinSprite = FunkinSprite.create('freeplay/pinkBack'); - pinkBack.color = 0xFFffd4e9; // sets it to pink! + pinkBack.color = 0xFFFFD4E9; // sets it to pink! pinkBack.x -= pinkBack.width; FlxTween.tween(pinkBack, {x: 0}, 0.6, {ease: FlxEase.quartOut}); add(pinkBack); - var orangeBackShit:FunkinSprite = new FunkinSprite(84, 440).makeSolidColor(Std.int(pinkBack.width), 75, 0xFFfeda00); + var orangeBackShit:FunkinSprite = new FunkinSprite(84, 440).makeSolidColor(Std.int(pinkBack.width), 75, 0xFFFEDA00); add(orangeBackShit); - var alsoOrangeLOL:FunkinSprite = new FunkinSprite(0, orangeBackShit.y).makeSolidColor(100, Std.int(orangeBackShit.height), 0xFFffd400); + var alsoOrangeLOL:FunkinSprite = new FunkinSprite(0, orangeBackShit.y).makeSolidColor(100, Std.int(orangeBackShit.height), 0xFFFFD400); add(alsoOrangeLOL); exitMovers.set([pinkBack, orangeBackShit, alsoOrangeLOL], @@ -254,10 +240,10 @@ class FreeplayState extends MusicBeatSubState add(grpTxtScrolls); grpTxtScrolls.visible = false; - FlxG.debugger.addTrackerProfile(new TrackerProfile(BGScrollingText, ["x", "y", "speed", "size"])); + FlxG.debugger.addTrackerProfile(new TrackerProfile(BGScrollingText, ['x', 'y', 'speed', 'size'])); - var moreWays:BGScrollingText = new BGScrollingText(0, 160, "HOT BLOODED IN MORE WAYS THAN ONE", FlxG.width, true, 43); - moreWays.funnyColor = 0xFFfff383; + var moreWays:BGScrollingText = new BGScrollingText(0, 160, 'HOT BLOODED IN MORE WAYS THAN ONE', FlxG.width, true, 43); + moreWays.funnyColor = 0xFFFFF383; moreWays.speed = 6.8; grpTxtScrolls.add(moreWays); @@ -267,8 +253,8 @@ class FreeplayState extends MusicBeatSubState speed: 0.4, }); - var funnyScroll:BGScrollingText = new BGScrollingText(0, 220, "BOYFRIEND", FlxG.width / 2, false, 60); - funnyScroll.funnyColor = 0xFFff9963; + var funnyScroll:BGScrollingText = new BGScrollingText(0, 220, 'BOYFRIEND', FlxG.width / 2, false, 60); + funnyScroll.funnyColor = 0xFFFF9963; funnyScroll.speed = -3.8; grpTxtScrolls.add(funnyScroll); @@ -280,7 +266,7 @@ class FreeplayState extends MusicBeatSubState wait: 0 }); - var txtNuts:BGScrollingText = new BGScrollingText(0, 285, "PROTECT YO NUTS", FlxG.width / 2, true, 43); + var txtNuts:BGScrollingText = new BGScrollingText(0, 285, 'PROTECT YO NUTS', FlxG.width / 2, true, 43); txtNuts.speed = 3.5; grpTxtScrolls.add(txtNuts); exitMovers.set([txtNuts], @@ -289,8 +275,8 @@ class FreeplayState extends MusicBeatSubState speed: 0.4, }); - var funnyScroll2:BGScrollingText = new BGScrollingText(0, 335, "BOYFRIEND", FlxG.width / 2, false, 60); - funnyScroll2.funnyColor = 0xFFff9963; + var funnyScroll2:BGScrollingText = new BGScrollingText(0, 335, 'BOYFRIEND', FlxG.width / 2, false, 60); + funnyScroll2.funnyColor = 0xFFFF9963; funnyScroll2.speed = -3.8; grpTxtScrolls.add(funnyScroll2); @@ -300,8 +286,8 @@ class FreeplayState extends MusicBeatSubState speed: 0.5, }); - var moreWays2:BGScrollingText = new BGScrollingText(0, 397, "HOT BLOODED IN MORE WAYS THAN ONE", FlxG.width, true, 43); - moreWays2.funnyColor = 0xFFfff383; + var moreWays2:BGScrollingText = new BGScrollingText(0, 397, 'HOT BLOODED IN MORE WAYS THAN ONE', FlxG.width, true, 43); + moreWays2.funnyColor = 0xFFFFF383; moreWays2.speed = 6.8; grpTxtScrolls.add(moreWays2); @@ -311,8 +297,8 @@ class FreeplayState extends MusicBeatSubState speed: 0.4 }); - var funnyScroll3:BGScrollingText = new BGScrollingText(0, orangeBackShit.y + 10, "BOYFRIEND", FlxG.width / 2, 60); - funnyScroll3.funnyColor = 0xFFfea400; + var funnyScroll3:BGScrollingText = new BGScrollingText(0, orangeBackShit.y + 10, 'BOYFRIEND', FlxG.width / 2, 60); + funnyScroll3.funnyColor = 0xFFFEA400; funnyScroll3.speed = -3.8; grpTxtScrolls.add(funnyScroll3); @@ -328,8 +314,10 @@ class FreeplayState extends MusicBeatSubState x: -dj.width * 1.6, speed: 0.5 }); + // TODO: Replace this. - if (currentCharacter == "pico") dj.visible = false; + if (currentCharacter == 'pico') dj.visible = false; + add(dj); var bgDad:FlxSprite = new FlxSprite(pinkBack.width * 0.75, 0).loadGraphic(Paths.image('freeplay/freeplayBGdad')); @@ -387,62 +375,23 @@ class FreeplayState extends MusicBeatSubState if (diffSprite.difficultyId == currentDifficulty) diffSprite.visible = true; } - // NOTE: This is an AtlasSprite because we use an animation to bring it into view. - // TODO: Add the ability to select the album graphic. - var albumArt:FlxAtlasSprite = new FlxAtlasSprite(640, 360, Paths.animateAtlas("freeplay/albumRoll")); - albumArt.visible = false; - add(albumArt); + albumRoll = new AlbumRoll(); + albumRoll.albumId = 'volume1'; + add(albumRoll); - exitMovers.set([albumArt], - { - x: FlxG.width, - speed: 0.4, - wait: 0 - }); - - var albumTitle:FlxSprite = new FlxSprite(947, 491).loadGraphic(Paths.image('freeplay/albumTitle-fnfvol1')); - var albumArtist:FlxSprite = new FlxSprite(1010, 607).loadGraphic(Paths.image('freeplay/albumArtist-kawaisprite')); - difficultyStars = new DifficultyStars(140, 39); - - difficultyStars.stars.visible = false; - albumTitle.visible = false; - albumArtist.visible = false; - - exitMovers.set([albumTitle], - { - x: FlxG.width, - speed: 0.2, - wait: 0.1 - }); - - exitMovers.set([albumArtist], - { - x: FlxG.width * 1.1, - speed: 0.2, - wait: 0.2 - }); - exitMovers.set([difficultyStars], - { - x: FlxG.width * 1.2, - speed: 0.2, - wait: 0.3 - }); - - add(albumTitle); - add(albumArtist); - add(difficultyStars); + albumRoll.applyExitMovers(exitMovers); var overhangStuff:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, 64, FlxColor.BLACK); overhangStuff.y -= overhangStuff.height; add(overhangStuff); FlxTween.tween(overhangStuff, {y: 0}, 0.3, {ease: FlxEase.quartOut}); - var fnfFreeplay:FlxText = new FlxText(8, 8, 0, "FREEPLAY", 48); - fnfFreeplay.font = "VCR OSD Mono"; + var fnfFreeplay:FlxText = new FlxText(8, 8, 0, 'FREEPLAY', 48); + fnfFreeplay.font = 'VCR OSD Mono'; fnfFreeplay.visible = false; - ostName = new FlxText(8, 8, FlxG.width - 8 - 8, "OFFICIAL OST", 48); - ostName.font = "VCR OSD Mono"; + ostName = new FlxText(8, 8, FlxG.width - 8 - 8, 'OFFICIAL OST', 48); + ostName.font = 'VCR OSD Mono'; ostName.alignment = RIGHT; ostName.visible = false; @@ -454,21 +403,21 @@ class FreeplayState extends MusicBeatSubState wait: 0 }); - var sillyStroke = new StrokeShader(0xFFFFFFFF, 2, 2); + var sillyStroke:StrokeShader = new StrokeShader(0xFFFFFFFF, 2, 2); fnfFreeplay.shader = sillyStroke; add(fnfFreeplay); add(ostName); var fnfHighscoreSpr:FlxSprite = new FlxSprite(860, 70); fnfHighscoreSpr.frames = Paths.getSparrowAtlas('freeplay/highscore'); - fnfHighscoreSpr.animation.addByPrefix("highscore", "highscore small instance 1", 24, false); + fnfHighscoreSpr.animation.addByPrefix('highscore', 'highscore small instance 1', 24, false); fnfHighscoreSpr.visible = false; fnfHighscoreSpr.setGraphicSize(0, Std.int(fnfHighscoreSpr.height * 1)); fnfHighscoreSpr.updateHitbox(); add(fnfHighscoreSpr); new FlxTimer().start(FlxG.random.float(12, 50), function(tmr) { - fnfHighscoreSpr.animation.play("highscore"); + fnfHighscoreSpr.animation.play('highscore'); tmr.time = FlxG.random.float(20, 60); }, 0); @@ -479,7 +428,7 @@ class FreeplayState extends MusicBeatSubState var clearBoxSprite:FlxSprite = new FlxSprite(1165, 65).loadGraphic(Paths.image('freeplay/clearBox')); add(clearBoxSprite); - txtCompletion = new AtlasText(1185, 87, "69", AtlasFont.FREEPLAY_CLEAR); + txtCompletion = new AtlasText(1185, 87, '69', AtlasFont.FREEPLAY_CLEAR); txtCompletion.visible = false; add(txtCompletion); @@ -496,9 +445,9 @@ class FreeplayState extends MusicBeatSubState letterSort.changeSelectionCallback = (str) -> { switch (str) { - case "fav": + case 'fav': generateSongList({filterType: FAVORITE}, true); - case "ALL": + case 'ALL': generateSongList(null, true); default: generateSongList({filterType: REGEXP, filterData: str}, true); @@ -514,25 +463,20 @@ class FreeplayState extends MusicBeatSubState dj.onIntroDone.add(function() { // when boyfriend hits dat shiii - albumArt.visible = true; - albumArt.anim.play(""); - albumArt.anim.onComplete = function() { - albumArt.anim.pause(); - }; + albumRoll.playIntro(); new FlxTimer().start(1, function(_) { - albumTitle.visible = true; + albumRoll.showTitle(); }); new FlxTimer().start(35 / 24, function(_) { - albumArtist.visible = true; - difficultyStars.stars.visible = true; + albumRoll.showStars(); }); FlxTween.tween(grpDifficulties, {x: 90}, 0.6, {ease: FlxEase.quartOut}); - var diffSelLeft = new DifficultySelector(20, grpDifficulties.y - 10, false, controls); - var diffSelRight = new DifficultySelector(325, grpDifficulties.y - 10, true, controls); + var diffSelLeft:DifficultySelector = new DifficultySelector(20, grpDifficulties.y - 10, false, controls); + var diffSelRight:DifficultySelector = new DifficultySelector(325, grpDifficulties.y - 10, true, controls); add(diffSelLeft); add(diffSelRight); @@ -562,7 +506,7 @@ class FreeplayState extends MusicBeatSubState }); }); - pinkBack.color = 0xFFffd863; + pinkBack.color = 0xFFFFD863; bgDad.visible = true; orangeBackShit.visible = true; alsoOrangeLOL.visible = true; @@ -571,9 +515,9 @@ class FreeplayState extends MusicBeatSubState generateSongList(null, false); - var swag:Alphabet = new Alphabet(1, 0, "swag"); + // var swag:Alphabet = new Alphabet(1, 0, 'swag'); - var funnyCam = new FunkinCamera(0, 0, FlxG.width, FlxG.height); + var funnyCam:FunkinCamera = new FunkinCamera(0, 0, FlxG.width, FlxG.height); funnyCam.bgColor = FlxColor.TRANSPARENT; FlxG.cameras.add(funnyCam); @@ -588,12 +532,20 @@ class FreeplayState extends MusicBeatSubState }); } + /** + * Given the current filter, rebuild the current song list. + * + * @param filterStuff A filter to apply to the song list (regex, startswith, all, favorite) + * @param force + */ public function generateSongList(?filterStuff:SongFilter, force:Bool = false):Void { curSelected = 1; for (cap in grpCapsules.members) + { cap.kill(); + } var tempSongs:Array = songs; @@ -604,7 +556,7 @@ class FreeplayState extends MusicBeatSubState case REGEXP: // filterStuff.filterData has a string with the first letter of the sorting range, and the second one // this creates a filter to return all the songs that start with a letter between those two - var filterRegexp = new EReg("^[" + filterStuff.filterData + "].*", "i"); + var filterRegexp:EReg = new EReg('^[' + filterStuff.filterData + '].*', 'i'); tempSongs = tempSongs.filter(str -> { if (str == null) return true; // Random return filterRegexp.match(str.songName); @@ -660,14 +612,19 @@ class FreeplayState extends MusicBeatSubState funnyMenu.favIcon.visible = tempSongs[i].isFav; funnyMenu.hsvShader = hsvShader; - if (i < 8) funnyMenu.initJumpIn(Math.min(i, 4), force); + if (i < 8) + { + funnyMenu.initJumpIn(Math.min(i, 4), force); + } else + { funnyMenu.forcePosition(); + } grpCapsules.add(funnyMenu); } - FlxG.console.registerFunction("changeSelection", changeSelection); + FlxG.console.registerFunction('changeSelection', changeSelection); rememberSelection(); @@ -699,7 +656,7 @@ class FreeplayState extends MusicBeatSubState { if (songs[curSelected] != null) { - var realShit = curSelected; + var realShit:Int = curSelected; songs[curSelected].isFav = !songs[curSelected].isFav; if (songs[curSelected].isFav) { @@ -708,7 +665,7 @@ class FreeplayState extends MusicBeatSubState ease: FlxEase.elasticOut, onComplete: _ -> { grpCapsules.members[realShit].favIcon.visible = true; - grpCapsules.members[realShit].favIcon.animation.play("fav"); + grpCapsules.members[realShit].favIcon.animation.play('fav'); } }); } @@ -772,9 +729,9 @@ class FreeplayState extends MusicBeatSubState { if (busy) return; - var upP = controls.UI_UP_P; - var downP = controls.UI_DOWN_P; - var accepted = controls.ACCEPT; + var upP:Bool = controls.UI_UP_P; + var downP:Bool = controls.UI_DOWN_P; + var accepted:Bool = controls.ACCEPT; if (FlxG.onMobile) { @@ -786,14 +743,14 @@ class FreeplayState extends MusicBeatSubState } if (touch.pressed) { - var dx = initTouchPos.x - touch.screenX; - var dy = initTouchPos.y - touch.screenY; + var dx:Float = initTouchPos.x - touch.screenX; + var dy:Float = initTouchPos.y - touch.screenY; - var angle = Math.atan2(dy, dx); - var length = Math.sqrt(dx * dx + dy * dy); + var angle:Float = Math.atan2(dy, dx); + var length:Float = Math.sqrt(dx * dx + dy * dy); - FlxG.watch.addQuick("LENGTH", length); - FlxG.watch.addQuick("ANGLE", Math.round(FlxAngle.asDegrees(angle))); + FlxG.watch.addQuick('LENGTH', length); + FlxG.watch.addQuick('ANGLE', Math.round(FlxAngle.asDegrees(angle))); } } @@ -858,9 +815,14 @@ class FreeplayState extends MusicBeatSubState { spamTimer = 0; - if (controls.UI_UP) changeSelection(-1); + if (controls.UI_UP) + { + changeSelection(-1); + } else + { changeSelection(1); + } } } else if (spamTimer >= 0.9) spamming = true; @@ -904,7 +866,7 @@ class FreeplayState extends MusicBeatSubState { var newParams:FreeplayStateParams = { - character: currentCharacter == "bf" ? "pico" : "bf", + character: currentCharacter == 'bf' ? 'pico' : 'bf', }; openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new funkin.ui.freeplay.FreeplayState(newParams, sticker))); } @@ -974,7 +936,7 @@ class FreeplayState extends MusicBeatSubState public override function destroy():Void { super.destroy(); - var daSong = songs[curSelected]; + var daSong:Null = songs[curSelected]; if (daSong != null) { clearDaCache(daSong.songName); @@ -985,7 +947,7 @@ class FreeplayState extends MusicBeatSubState { touchTimer = 0; - var currentDifficultyIndex = diffIdsCurrent.indexOf(currentDifficulty); + var currentDifficultyIndex:Int = diffIdsCurrent.indexOf(currentDifficulty); if (currentDifficultyIndex == -1) currentDifficultyIndex = diffIdsCurrent.indexOf(Constants.DEFAULT_DIFFICULTY); @@ -996,7 +958,7 @@ class FreeplayState extends MusicBeatSubState currentDifficulty = diffIdsCurrent[currentDifficultyIndex]; - var daSong = songs[curSelected]; + var daSong:Null = songs[curSelected]; if (daSong != null) { var songScore:SaveScoreData = Save.instance.getSongScore(songs[curSelected].songId, currentDifficulty); @@ -1060,11 +1022,12 @@ class FreeplayState extends MusicBeatSubState } // Set the difficulty star count on the right. - difficultyStars.difficulty = daSong?.songRating ?? difficultyStars.difficulty; // yay haxe 4.3 + albumRoll.setDifficultyStars(daSong?.songRating); + albumRoll.albumId = daSong?.albumId ?? Constants.DEFAULT_ALBUM_ID; } // Clears the cache of songs, frees up memory, they' ll have to be loaded in later tho function clearDaCache(actualSongTho:String) - function clearDaCache(actualSongTho:String) + function clearDaCache(actualSongTho:String):Void { for (song in songs) { @@ -1079,7 +1042,7 @@ class FreeplayState extends MusicBeatSubState function capsuleOnConfirmRandom(randomCapsule:SongMenuItem):Void { - trace("RANDOM SELECTED"); + trace('RANDOM SELECTED'); busy = true; letterSort.inputEnabled = false; @@ -1095,7 +1058,7 @@ class FreeplayState extends MusicBeatSubState if (availableSongCapsules.length == 0) { - trace("No songs available!"); + trace('No songs available!'); busy = false; letterSort.inputEnabled = true; FlxG.sound.play(Paths.sound('cancelMenu')); @@ -1167,24 +1130,23 @@ class FreeplayState extends MusicBeatSubState } // Set the difficulty star count on the right. - var daSong = songs[curSelected]; - difficultyStars.difficulty = daSong?.songRating ?? 0; + var daSong:Null = songs[curSelected]; + albumRoll.setDifficultyStars(daSong?.songRating ?? 0); } function changeSelection(change:Int = 0):Void { - // NGio.logEvent('Fresh'); FlxG.sound.play(Paths.sound('scrollMenu'), 0.4); // FlxG.sound.playMusic(Paths.inst(songs[curSelected].songName)); - var prevSelected = curSelected; + var prevSelected:Int = curSelected; curSelected += change; if (curSelected < 0) curSelected = grpCapsules.countLiving() - 1; if (curSelected >= grpCapsules.countLiving()) curSelected = 0; - var daSongCapsule = grpCapsules.members[curSelected]; + var daSongCapsule:SongMenuItem = grpCapsules.members[curSelected]; if (daSongCapsule.songData != null) { var songScore:SaveScoreData = Save.instance.getSongScore(daSongCapsule.songData.songId, currentDifficulty); @@ -1235,6 +1197,9 @@ class FreeplayState extends MusicBeatSubState } } +/** + * The difficulty selector arrows to the left and right of the difficulty. + */ class DifficultySelector extends FlxSprite { var controls:Controls; @@ -1247,7 +1212,7 @@ class DifficultySelector extends FlxSprite this.controls = controls; frames = Paths.getSparrowAtlas('freeplay/freeplaySelector'); - animation.addByPrefix('shine', "arrow pointer loop", 24); + animation.addByPrefix('shine', 'arrow pointer loop', 24); animation.play('shine'); whiteShader = new PureColor(FlxColor.WHITE); @@ -1281,34 +1246,62 @@ class DifficultySelector extends FlxSprite } } +/** + * Structure for the current song filter. + */ typedef SongFilter = { var filterType:FilterType; var ?filterData:Dynamic; } +/** + * Possible types to use for the song filter. + */ enum abstract FilterType(String) { - var STARTSWITH; - var REGEXP; - var FAVORITE; - var ALL; + /** + * Filter to songs which start with a string + */ + public var STARTSWITH; + + /** + * Filter to songs which match a regular expression + */ + public var REGEXP; + + /** + * Filter to songs which are favorited + */ + public var FAVORITE; + + /** + * Filter to all songs + */ + public var ALL; } +/** + * Data about a specific song in the freeplay menu. + */ class FreeplaySongData { + /** + * Whether or not the song has been favorited. + */ public var isFav:Bool = false; var song:Song; - public var levelId(default, null):String = ""; - public var songId(default, null):String = ""; + public var levelId(default, null):String = ''; + public var songId(default, null):String = ''; public var songDifficulties(default, null):Array = []; - public var songName(default, null):String = ""; - public var songCharacter(default, null):String = ""; + public var songName(default, null):String = ''; + public var songCharacter(default, null):String = ''; public var songRating(default, null):Int = 0; + public var albumId(default, null):String = ''; public var currentDifficulty(default, set):String = Constants.DEFAULT_DIFFICULTY; public var displayedVariations(default, null):Array = [Constants.DEFAULT_VARIATION]; @@ -1332,19 +1325,28 @@ class FreeplaySongData updateValues(displayedVariations); } - function updateValues(displayedVariations:Array):Void + function updateValues(variations:Array):Void { - this.songDifficulties = song.listDifficulties(displayedVariations); + this.songDifficulties = song.listDifficulties(variations); if (!this.songDifficulties.contains(currentDifficulty)) currentDifficulty = Constants.DEFAULT_DIFFICULTY; - var songDifficulty:SongDifficulty = song.getDifficulty(currentDifficulty, displayedVariations); + var songDifficulty:SongDifficulty = song.getDifficulty(currentDifficulty, variations); if (songDifficulty == null) return; this.songName = songDifficulty.songName; this.songCharacter = songDifficulty.characters.opponent; this.songRating = songDifficulty.difficultyRating; + this.albumId = songDifficulty.album; } } +/** + * The map storing information about the exit movers. + */ +typedef ExitMoverData = Map, MoveData>; + +/** + * The data for an exit mover. + */ typedef MoveData = { var ?x:Float; @@ -1353,8 +1355,14 @@ typedef MoveData = var ?wait:Float; } +/** + * The sprite for the difficulty + */ class DifficultySprite extends FlxSprite { + /** + * The difficulty id which this sprite represents. + */ public var difficultyId:String; public function new(diffId:String) diff --git a/source/funkin/ui/freeplay/ScriptedAlbum.hx b/source/funkin/ui/freeplay/ScriptedAlbum.hx new file mode 100644 index 000000000..737f97ad2 --- /dev/null +++ b/source/funkin/ui/freeplay/ScriptedAlbum.hx @@ -0,0 +1,9 @@ +package funkin.ui.freeplay; + +/** + * A script that can be tied to an Album. + * Create a scripted class that extends Album to use this. + * This allows you to customize how a specific album appears. + */ +@:hscriptClass +class ScriptedAlbum extends funkin.ui.freeplay.Album implements polymod.hscript.HScriptedClass {} diff --git a/source/funkin/ui/freeplay/SongMenuItem.hx b/source/funkin/ui/freeplay/SongMenuItem.hx index 06d113468..c20d81328 100644 --- a/source/funkin/ui/freeplay/SongMenuItem.hx +++ b/source/funkin/ui/freeplay/SongMenuItem.hx @@ -65,25 +65,26 @@ class SongMenuItem extends FlxSpriteGroup var rank:String = FlxG.random.getObject(ranks); ranking = new FlxSprite(capsule.width * 0.84, 30); - ranking.loadGraphic(Paths.image("freeplay/ranks/" + rank)); + ranking.loadGraphic(Paths.image('freeplay/ranks/' + rank)); ranking.scale.x = ranking.scale.y = realScaled; - ranking.alpha = 0.75; + // ranking.alpha = 0.75; + ranking.visible = false; ranking.origin.set(capsule.origin.x - ranking.x, capsule.origin.y - ranking.y); add(ranking); grpHide.add(ranking); switch (rank) { - case "perfect": + case 'perfect': ranking.x -= 10; } grayscaleShader = new Grayscale(1); - diffRatingSprite = new FlxSprite(145, 90).loadGraphic(Paths.image("freeplay/diffRatings/diff00")); + diffRatingSprite = new FlxSprite(145, 90).loadGraphic(Paths.image('freeplay/diffRatings/diff00')); diffRatingSprite.shader = grayscaleShader; - diffRatingSprite.visible = false; - add(diffRatingSprite); + // TODO: Readd once ratings are fully implemented + // add(diffRatingSprite); diffRatingSprite.origin.set(capsule.origin.x - diffRatingSprite.x, capsule.origin.y - diffRatingSprite.y); grpHide.add(diffRatingSprite); @@ -104,7 +105,7 @@ class SongMenuItem extends FlxSpriteGroup favIcon = new FlxSprite(400, 40); favIcon.frames = Paths.getSparrowAtlas('freeplay/favHeart'); - favIcon.animation.addByPrefix('fav', "favorite heart", 24, false); + favIcon.animation.addByPrefix('fav', 'favorite heart', 24, false); favIcon.animation.play('fav'); favIcon.setGraphicSize(50, 50); favIcon.visible = false; @@ -114,10 +115,11 @@ class SongMenuItem extends FlxSpriteGroup setVisibleGrp(false); } - function updateDifficultyRating(newRating:Int) + function updateDifficultyRating(newRating:Int):Void { var ratingPadded:String = newRating < 10 ? '0$newRating' : '$newRating'; diffRatingSprite.loadGraphic(Paths.image('freeplay/diffRatings/diff${ratingPadded}')); + diffRatingSprite.visible = false; } function set_hsvShader(value:HSVShader):HSVShader @@ -129,7 +131,7 @@ class SongMenuItem extends FlxSpriteGroup return value; } - function textAppear() + function textAppear():Void { songText.scale.x = 1.7; songText.scale.y = 0.2; @@ -144,7 +146,7 @@ class SongMenuItem extends FlxSpriteGroup }); } - function setVisibleGrp(value:Bool) + function setVisibleGrp(value:Bool):Void { for (spr in grpHide.members) { @@ -156,7 +158,7 @@ class SongMenuItem extends FlxSpriteGroup updateSelected(); } - public function init(?x:Float, ?y:Float, songData:Null) + public function init(?x:Float, ?y:Float, songData:Null):Void { if (x != null) this.x = x; if (y != null) this.y = y; @@ -176,7 +178,7 @@ class SongMenuItem extends FlxSpriteGroup * @param char The character ID used by this song. * If the character has no freeplay icon, a warning will be thrown and nothing will display. */ - public function setCharacter(char:String) + public function setCharacter(char:String):Void { var charPath:String = "freeplay/icons/"; @@ -186,18 +188,18 @@ class SongMenuItem extends FlxSpriteGroup // TODO: Also, can use CharacterDataParser.getCharPixelIconAsset() switch (char) { - case "monster-christmas": - charPath += "monsterpixel"; - case "mom-car": - charPath += "mommypixel"; - case "dad": - charPath += "daddypixel"; - case "darnell-blazin": - charPath += "darnellpixel"; - case "senpai-angry": - charPath += "senpaipixel"; + case 'monster-christmas': + charPath += 'monsterpixel'; + case 'mom-car': + charPath += 'mommypixel'; + case 'dad': + charPath += 'daddypixel'; + case 'darnell-blazin': + charPath += 'darnellpixel'; + case 'senpai-angry': + charPath += 'senpaipixel'; default: - charPath += char + "pixel"; + charPath += '${char}pixel'; } if (!openfl.utils.Assets.exists(Paths.image(charPath))) @@ -211,7 +213,7 @@ class SongMenuItem extends FlxSpriteGroup switch (char) { - case "parents-christmas": + case 'parents-christmas': pixelIcon.origin.x = 140; default: pixelIcon.origin.x = 100; @@ -262,7 +264,7 @@ class SongMenuItem extends FlxSpriteGroup var grpHide:FlxGroup; - public function forcePosition() + public function forcePosition():Void { visible = true; capsule.alpha = 1; @@ -287,7 +289,7 @@ class SongMenuItem extends FlxSpriteGroup setVisibleGrp(true); } - override function update(elapsed:Float) + override function update(elapsed:Float):Void { if (doJumpIn) { diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index 1005b312e..c9b99ed46 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -175,17 +175,22 @@ class Constants /** * The default name for songs. */ - public static final DEFAULT_SONGNAME:String = "Unknown"; + public static final DEFAULT_SONGNAME:String = 'Unknown'; /** * The default artist for songs. */ - public static final DEFAULT_ARTIST:String = "Unknown"; + public static final DEFAULT_ARTIST:String = 'Unknown'; /** * The default note style for songs. */ - public static final DEFAULT_NOTE_STYLE:String = "funkin"; + public static final DEFAULT_NOTE_STYLE:String = 'funkin'; + + /** + * The default album for songs in Freeplay. + */ + public static final DEFAULT_ALBUM_ID:String = 'volume1'; /** * The default timing format for songs.