mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-23 08:07:54 -05:00
Work in progress on custom album art for freeplay
This commit is contained in:
parent
4c35b1d74f
commit
36a9c29720
14 changed files with 619 additions and 185 deletions
2
assets
2
assets
|
@ -1 +1 @@
|
|||
Subproject commit 0e2c5bf2134c7e517b70cf74afd58abe5c7b5e50
|
||||
Subproject commit 4e88fb2a50b284d92404af6afc95b9840d3cda8d
|
|
@ -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.
|
||||
|
|
36
source/funkin/data/freeplay/AlbumData.hx
Normal file
36
source/funkin/data/freeplay/AlbumData.hx
Normal file
|
@ -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<String>;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
84
source/funkin/data/freeplay/AlbumRegistry.hx
Normal file
84
source/funkin/data/freeplay/AlbumRegistry.hx
Normal file
|
@ -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<Album, AlbumData>
|
||||
{
|
||||
/**
|
||||
* 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<AlbumData>
|
||||
{
|
||||
// JsonParser does not take type parameters,
|
||||
// otherwise this function would be in BaseRegistry.
|
||||
var parser:json2object.JsonParser<AlbumData> = new json2object.JsonParser<AlbumData>();
|
||||
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<AlbumData>
|
||||
{
|
||||
var parser:json2object.JsonParser<AlbumData> = new json2object.JsonParser<AlbumData>();
|
||||
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<String>
|
||||
{
|
||||
return ScriptedAlbum.listScriptClasses();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -213,6 +213,26 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
|
|||
return _metadata.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* List the album IDs for each variation of the song.
|
||||
* @return A map of variation IDs to album IDs.
|
||||
*/
|
||||
public function listAlbums():Map<String, String>
|
||||
{
|
||||
var result:Map<String, String> = new Map<String, String>();
|
||||
|
||||
for (difficultyId in difficulties.keys())
|
||||
{
|
||||
var meta:Null<SongDifficulty> = 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).
|
||||
|
|
|
@ -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;
|
||||
|
|
89
source/funkin/ui/freeplay/Album.hx
Normal file
89
source/funkin/ui/freeplay/Album.hx
Normal file
|
@ -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<AlbumData>
|
||||
{
|
||||
/**
|
||||
* 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<String>
|
||||
{
|
||||
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<AlbumData>
|
||||
{
|
||||
return AlbumRegistry.instance.parseEntryDataWithMigration(id, AlbumRegistry.instance.fetchEntryVersion(id));
|
||||
}
|
||||
}
|
173
source/funkin/ui/freeplay/AlbumRoll.hx
Normal file
173
source/funkin/ui/freeplay/AlbumRoll.hx
Normal file
|
@ -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<FlxGraphic> = [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;
|
||||
}
|
||||
}
|
|
@ -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<DifficultySprite>;
|
||||
|
||||
var coolColors:Array<Int> = [
|
||||
0xff9271fd,
|
||||
0xff9271fd,
|
||||
0xff223344,
|
||||
0xFF9271FD,
|
||||
0xFF9271FD,
|
||||
0xFF223344,
|
||||
0xFF941653,
|
||||
0xFFfc96d7,
|
||||
0xFFa0d1ff,
|
||||
0xffff78bf,
|
||||
0xfff6b604
|
||||
0xFFFC96D7,
|
||||
0xFFA0D1FF,
|
||||
0xFFFF78BF,
|
||||
0xFFF6B604
|
||||
];
|
||||
|
||||
var grpSongs:FlxTypedGroup<Alphabet>;
|
||||
var grpCapsules:FlxTypedGroup<SongMenuItem>;
|
||||
var curCapsule:SongMenuItem;
|
||||
var curPlaying:Bool = false;
|
||||
var ostName:FlxText;
|
||||
var difficultyStars:DifficultyStars;
|
||||
|
||||
var displayedVariations:Array<String>;
|
||||
|
||||
var dj:DJBoyfriend;
|
||||
|
||||
var ostName:FlxText;
|
||||
var albumRoll:AlbumRoll;
|
||||
|
||||
var letterSort:LetterSort;
|
||||
var typing:FlxInputText;
|
||||
var exitMovers:Map<Array<FlxSprite>, 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<String> = 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<FreeplaySongData> = 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,11 +815,16 @@ 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;
|
||||
}
|
||||
else
|
||||
|
@ -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<FreeplaySongData> = 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<FreeplaySongData> = 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<FreeplaySongData> = 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<String> = [];
|
||||
|
||||
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<String> = [Constants.DEFAULT_VARIATION];
|
||||
|
@ -1332,19 +1325,28 @@ class FreeplaySongData
|
|||
updateValues(displayedVariations);
|
||||
}
|
||||
|
||||
function updateValues(displayedVariations:Array<String>):Void
|
||||
function updateValues(variations:Array<String>):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<Array<FlxSprite>, 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)
|
||||
|
|
9
source/funkin/ui/freeplay/ScriptedAlbum.hx
Normal file
9
source/funkin/ui/freeplay/ScriptedAlbum.hx
Normal file
|
@ -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 {}
|
|
@ -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<FreeplaySongData>)
|
||||
public function init(?x:Float, ?y:Float, songData:Null<FreeplaySongData>):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)
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue