mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-23 08:07:54 -05:00
Merge pull request #365 from FunkinCrew/bugfix/2hot-explosion-polymod
Bugfix/2hot explosion polymod
This commit is contained in:
commit
fb0386812c
5 changed files with 152 additions and 55 deletions
2
assets
2
assets
|
@ -1 +1 @@
|
||||||
Subproject commit 55c602f2adbbd84de541ea86e5e646c4d2a1df0b
|
Subproject commit 14b86f4369fddf61eb76116139eb33fa8f6e92d0
|
2
hmm.json
2
hmm.json
|
@ -146,7 +146,7 @@
|
||||||
"name": "polymod",
|
"name": "polymod",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "d5a3b8995f64d20b95f844454e8c3b38c3d3a9fa",
|
"ref": "be712450e5d3ba446008884921bb56873b299a64",
|
||||||
"url": "https://github.com/larsiusprime/polymod"
|
"url": "https://github.com/larsiusprime/polymod"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,7 +17,7 @@ typedef LevelData =
|
||||||
var version:String;
|
var version:String;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The title of the week, as seen in the top corner.
|
* The title of the level, as seen in the top corner.
|
||||||
*/
|
*/
|
||||||
var name:String;
|
var name:String;
|
||||||
|
|
||||||
|
@ -27,21 +27,35 @@ typedef LevelData =
|
||||||
@:jcustomparse(funkin.data.DataParse.stringNotEmpty)
|
@:jcustomparse(funkin.data.DataParse.stringNotEmpty)
|
||||||
var titleAsset:String;
|
var titleAsset:String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The props to display over the colored background.
|
||||||
|
* In the base game this is usually Boyfriend and the opponent.
|
||||||
|
*/
|
||||||
@:default([])
|
@:default([])
|
||||||
var props:Array<LevelPropData>;
|
var props:Array<LevelPropData>;
|
||||||
@:default(["bopeebo"])
|
|
||||||
|
/**
|
||||||
|
* The list of song IDs included in this level.
|
||||||
|
*/
|
||||||
|
@:default(['bopeebo'])
|
||||||
var songs:Array<String>;
|
var songs:Array<String>;
|
||||||
@:default("#F9CF51")
|
|
||||||
|
/**
|
||||||
|
* The background for the level behind the props.
|
||||||
|
*/
|
||||||
|
@:default('#F9CF51')
|
||||||
@:optional
|
@:optional
|
||||||
var background:String;
|
var background:String;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data for a single prop for a story mode level.
|
||||||
|
*/
|
||||||
typedef LevelPropData =
|
typedef LevelPropData =
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The image to use for the prop. May optionally be a sprite sheet.
|
* The image to use for the prop. May optionally be a sprite sheet.
|
||||||
*/
|
*/
|
||||||
// @:jcustomparse(funkin.data.DataParse.stringNotEmpty)
|
|
||||||
var assetPath:String;
|
var assetPath:String;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
package funkin.modding;
|
package funkin.modding;
|
||||||
|
|
||||||
import funkin.util.macro.ClassMacro;
|
|
||||||
import funkin.modding.module.ModuleHandler;
|
|
||||||
import funkin.data.song.SongData;
|
|
||||||
import funkin.data.stage.StageData;
|
|
||||||
import polymod.Polymod;
|
|
||||||
import polymod.backends.PolymodAssets.PolymodAssetType;
|
|
||||||
import polymod.format.ParseRules.TextFileFormat;
|
|
||||||
import funkin.data.event.SongEventRegistry;
|
|
||||||
import funkin.data.stage.StageRegistry;
|
|
||||||
import funkin.util.FileUtil;
|
|
||||||
import funkin.data.level.LevelRegistry;
|
|
||||||
import funkin.data.notestyle.NoteStyleRegistry;
|
|
||||||
import funkin.data.dialogue.ConversationRegistry;
|
import funkin.data.dialogue.ConversationRegistry;
|
||||||
import funkin.data.dialogue.DialogueBoxRegistry;
|
import funkin.data.dialogue.DialogueBoxRegistry;
|
||||||
import funkin.data.dialogue.SpeakerRegistry;
|
import funkin.data.dialogue.SpeakerRegistry;
|
||||||
|
import funkin.data.event.SongEventRegistry;
|
||||||
|
import funkin.data.level.LevelRegistry;
|
||||||
|
import funkin.data.notestyle.NoteStyleRegistry;
|
||||||
|
import funkin.data.song.SongRegistry;
|
||||||
|
import funkin.data.stage.StageRegistry;
|
||||||
|
import funkin.modding.module.ModuleHandler;
|
||||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||||
import funkin.save.Save;
|
import funkin.save.Save;
|
||||||
import funkin.data.song.SongRegistry;
|
import funkin.util.FileUtil;
|
||||||
|
import funkin.util.macro.ClassMacro;
|
||||||
|
import polymod.backends.PolymodAssets.PolymodAssetType;
|
||||||
|
import polymod.format.ParseRules.TextFileFormat;
|
||||||
|
import polymod.Polymod;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class for interacting with Polymod, the atomic modding framework for Haxe.
|
||||||
|
*/
|
||||||
class PolymodHandler
|
class PolymodHandler
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -27,16 +28,33 @@ class PolymodHandler
|
||||||
* Bug fixes increment the patch version, new features increment the minor version.
|
* Bug fixes increment the patch version, new features increment the minor version.
|
||||||
* Changes that break old mods increment the major version.
|
* Changes that break old mods increment the major version.
|
||||||
*/
|
*/
|
||||||
static final API_VERSION:String = "0.1.0";
|
static final API_VERSION:String = '0.1.0';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Where relative to the executable that mods are located.
|
* Where relative to the executable that mods are located.
|
||||||
*/
|
*/
|
||||||
static final MOD_FOLDER:String = #if (REDIRECT_ASSETS_FOLDER && macos) "../../../../../../../example_mods" #elseif REDIRECT_ASSETS_FOLDER "../../../../example_mods" #else "mods" #end;
|
static final MOD_FOLDER:String =
|
||||||
|
#if (REDIRECT_ASSETS_FOLDER && macos)
|
||||||
|
'../../../../../../../example_mods'
|
||||||
|
#elseif REDIRECT_ASSETS_FOLDER
|
||||||
|
'../../../../example_mods'
|
||||||
|
#else
|
||||||
|
'mods'
|
||||||
|
#end;
|
||||||
|
|
||||||
static final CORE_FOLDER:Null<String> = #if (REDIRECT_ASSETS_FOLDER && macos) "../../../../../../../assets" #elseif REDIRECT_ASSETS_FOLDER "../../../../assets" #else null #end;
|
static final CORE_FOLDER:Null<String> =
|
||||||
|
#if (REDIRECT_ASSETS_FOLDER && macos)
|
||||||
|
'../../../../../../../assets'
|
||||||
|
#elseif REDIRECT_ASSETS_FOLDER
|
||||||
|
'../../../../assets'
|
||||||
|
#else
|
||||||
|
null
|
||||||
|
#end;
|
||||||
|
|
||||||
public static function createModRoot()
|
/**
|
||||||
|
* If the mods folder doesn't exist, create it.
|
||||||
|
*/
|
||||||
|
public static function createModRoot():Void
|
||||||
{
|
{
|
||||||
FileUtil.createDirIfNotExists(MOD_FOLDER);
|
FileUtil.createDirIfNotExists(MOD_FOLDER);
|
||||||
}
|
}
|
||||||
|
@ -44,40 +62,44 @@ class PolymodHandler
|
||||||
/**
|
/**
|
||||||
* Loads the game with ALL mods enabled with Polymod.
|
* Loads the game with ALL mods enabled with Polymod.
|
||||||
*/
|
*/
|
||||||
public static function loadAllMods()
|
public static function loadAllMods():Void
|
||||||
{
|
{
|
||||||
// Create the mod root if it doesn't exist.
|
// Create the mod root if it doesn't exist.
|
||||||
createModRoot();
|
createModRoot();
|
||||||
trace("Initializing Polymod (using all mods)...");
|
trace('Initializing Polymod (using all mods)...');
|
||||||
loadModsById(getAllModIds());
|
loadModsById(getAllModIds());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the game with configured mods enabled with Polymod.
|
* Loads the game with configured mods enabled with Polymod.
|
||||||
*/
|
*/
|
||||||
public static function loadEnabledMods()
|
public static function loadEnabledMods():Void
|
||||||
{
|
{
|
||||||
// Create the mod root if it doesn't exist.
|
// Create the mod root if it doesn't exist.
|
||||||
createModRoot();
|
createModRoot();
|
||||||
|
|
||||||
trace("Initializing Polymod (using configured mods)...");
|
trace('Initializing Polymod (using configured mods)...');
|
||||||
loadModsById(Save.instance.enabledModIds);
|
loadModsById(Save.instance.enabledModIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the game without any mods enabled with Polymod.
|
* Loads the game without any mods enabled with Polymod.
|
||||||
*/
|
*/
|
||||||
public static function loadNoMods()
|
public static function loadNoMods():Void
|
||||||
{
|
{
|
||||||
// Create the mod root if it doesn't exist.
|
// Create the mod root if it doesn't exist.
|
||||||
createModRoot();
|
createModRoot();
|
||||||
|
|
||||||
// We still need to configure the debug print calls etc.
|
// We still need to configure the debug print calls etc.
|
||||||
trace("Initializing Polymod (using no mods)...");
|
trace('Initializing Polymod (using no mods)...');
|
||||||
loadModsById([]);
|
loadModsById([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function loadModsById(ids:Array<String>)
|
/**
|
||||||
|
* Load all the mods with the given ids.
|
||||||
|
* @param ids The ORDERED list of mod ids to load.
|
||||||
|
*/
|
||||||
|
public static function loadModsById(ids:Array<String>):Void
|
||||||
{
|
{
|
||||||
if (ids.length == 0)
|
if (ids.length == 0)
|
||||||
{
|
{
|
||||||
|
@ -90,7 +112,7 @@ class PolymodHandler
|
||||||
|
|
||||||
buildImports();
|
buildImports();
|
||||||
|
|
||||||
var loadedModList = polymod.Polymod.init(
|
var loadedModList:Array<ModMetadata> = polymod.Polymod.init(
|
||||||
{
|
{
|
||||||
// Root directory for all mods.
|
// Root directory for all mods.
|
||||||
modRoot: MOD_FOLDER,
|
modRoot: MOD_FOLDER,
|
||||||
|
@ -142,30 +164,40 @@ class PolymodHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
#if debug
|
#if debug
|
||||||
var fileList = Polymod.listModFiles(PolymodAssetType.IMAGE);
|
var fileList:Array<String> = Polymod.listModFiles(PolymodAssetType.IMAGE);
|
||||||
trace('Installed mods have replaced ${fileList.length} images.');
|
trace('Installed mods have replaced ${fileList.length} images.');
|
||||||
for (item in fileList)
|
for (item in fileList)
|
||||||
|
{
|
||||||
trace(' * $item');
|
trace(' * $item');
|
||||||
|
}
|
||||||
|
|
||||||
fileList = Polymod.listModFiles(PolymodAssetType.TEXT);
|
fileList = Polymod.listModFiles(PolymodAssetType.TEXT);
|
||||||
trace('Installed mods have added/replaced ${fileList.length} text files.');
|
trace('Installed mods have added/replaced ${fileList.length} text files.');
|
||||||
for (item in fileList)
|
for (item in fileList)
|
||||||
|
{
|
||||||
trace(' * $item');
|
trace(' * $item');
|
||||||
|
}
|
||||||
|
|
||||||
fileList = Polymod.listModFiles(PolymodAssetType.AUDIO_MUSIC);
|
fileList = Polymod.listModFiles(PolymodAssetType.AUDIO_MUSIC);
|
||||||
trace('Installed mods have replaced ${fileList.length} music files.');
|
trace('Installed mods have replaced ${fileList.length} music files.');
|
||||||
for (item in fileList)
|
for (item in fileList)
|
||||||
|
{
|
||||||
trace(' * $item');
|
trace(' * $item');
|
||||||
|
}
|
||||||
|
|
||||||
fileList = Polymod.listModFiles(PolymodAssetType.AUDIO_SOUND);
|
fileList = Polymod.listModFiles(PolymodAssetType.AUDIO_SOUND);
|
||||||
trace('Installed mods have replaced ${fileList.length} sound files.');
|
trace('Installed mods have replaced ${fileList.length} sound files.');
|
||||||
for (item in fileList)
|
for (item in fileList)
|
||||||
|
{
|
||||||
trace(' * $item');
|
trace(' * $item');
|
||||||
|
}
|
||||||
|
|
||||||
fileList = Polymod.listModFiles(PolymodAssetType.AUDIO_GENERIC);
|
fileList = Polymod.listModFiles(PolymodAssetType.AUDIO_GENERIC);
|
||||||
trace('Installed mods have replaced ${fileList.length} generic audio files.');
|
trace('Installed mods have replaced ${fileList.length} generic audio files.');
|
||||||
for (item in fileList)
|
for (item in fileList)
|
||||||
|
{
|
||||||
trace(' * $item');
|
trace(' * $item');
|
||||||
|
}
|
||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,21 +215,21 @@ class PolymodHandler
|
||||||
for (cls in ClassMacro.listClassesInPackage('polymod'))
|
for (cls in ClassMacro.listClassesInPackage('polymod'))
|
||||||
{
|
{
|
||||||
if (cls == null) continue;
|
if (cls == null) continue;
|
||||||
var className = Type.getClassName(cls);
|
var className:String = Type.getClassName(cls);
|
||||||
Polymod.blacklistImport(className);
|
Polymod.blacklistImport(className);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static function buildParseRules():polymod.format.ParseRules
|
static function buildParseRules():polymod.format.ParseRules
|
||||||
{
|
{
|
||||||
var output = polymod.format.ParseRules.getDefault();
|
var output:polymod.format.ParseRules = polymod.format.ParseRules.getDefault();
|
||||||
// Ensure TXT files have merge support.
|
// Ensure TXT files have merge support.
|
||||||
output.addType("txt", TextFileFormat.LINES);
|
output.addType('txt', TextFileFormat.LINES);
|
||||||
// Ensure script files have merge support.
|
// Ensure script files have merge support.
|
||||||
output.addType("hscript", TextFileFormat.PLAINTEXT);
|
output.addType('hscript', TextFileFormat.PLAINTEXT);
|
||||||
output.addType("hxs", TextFileFormat.PLAINTEXT);
|
output.addType('hxs', TextFileFormat.PLAINTEXT);
|
||||||
output.addType("hxc", TextFileFormat.PLAINTEXT);
|
output.addType('hxc', TextFileFormat.PLAINTEXT);
|
||||||
output.addType("hx", TextFileFormat.PLAINTEXT);
|
output.addType('hx', TextFileFormat.PLAINTEXT);
|
||||||
|
|
||||||
// You can specify the format of a specific file, with file extension.
|
// You can specify the format of a specific file, with file extension.
|
||||||
// output.addFile("data/introText.txt", TextFileFormat.LINES)
|
// output.addFile("data/introText.txt", TextFileFormat.LINES)
|
||||||
|
@ -208,17 +240,21 @@ class PolymodHandler
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
assetLibraryPaths: [
|
assetLibraryPaths: [
|
||||||
"default" => "preload", "shared" => "shared", "songs" => "songs", "tutorial" => "tutorial", "week1" => "week1", "week2" => "week2",
|
'default' => 'preload', 'shared' => 'shared', 'songs' => 'songs', 'tutorial' => 'tutorial', 'week1' => 'week1', 'week2' => 'week2',
|
||||||
"week3" => "week3", "week4" => "week4", "week5" => "week5", "week6" => "week6", "week7" => "week7", "weekend1" => "weekend1",
|
'week3' => 'week3', 'week4' => 'week4', 'week5' => 'week5', 'week6' => 'week6', 'week7' => 'week7', 'weekend1' => 'weekend1',
|
||||||
],
|
],
|
||||||
coreAssetRedirect: CORE_FOLDER,
|
coreAssetRedirect: CORE_FOLDER,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a list of metadata for ALL installed mods, including disabled mods.
|
||||||
|
* @return An array of mod metadata
|
||||||
|
*/
|
||||||
public static function getAllMods():Array<ModMetadata>
|
public static function getAllMods():Array<ModMetadata>
|
||||||
{
|
{
|
||||||
trace('Scanning the mods folder...');
|
trace('Scanning the mods folder...');
|
||||||
var modMetadata = Polymod.scan(
|
var modMetadata:Array<ModMetadata> = Polymod.scan(
|
||||||
{
|
{
|
||||||
modRoot: MOD_FOLDER,
|
modRoot: MOD_FOLDER,
|
||||||
apiVersionRule: API_VERSION,
|
apiVersionRule: API_VERSION,
|
||||||
|
@ -228,17 +264,25 @@ class PolymodHandler
|
||||||
return modMetadata;
|
return modMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a list of ALL mod IDs, including disabled mods.
|
||||||
|
* @return An array of mod IDs
|
||||||
|
*/
|
||||||
public static function getAllModIds():Array<String>
|
public static function getAllModIds():Array<String>
|
||||||
{
|
{
|
||||||
var modIds = [for (i in getAllMods()) i.id];
|
var modIds:Array<String> = [for (i in getAllMods()) i.id];
|
||||||
return modIds;
|
return modIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a list of metadata for all enabled mods.
|
||||||
|
* @return An array of mod metadata
|
||||||
|
*/
|
||||||
public static function getEnabledMods():Array<ModMetadata>
|
public static function getEnabledMods():Array<ModMetadata>
|
||||||
{
|
{
|
||||||
var modIds = Save.instance.enabledModIds;
|
var modIds:Array<String> = Save.instance.enabledModIds;
|
||||||
var modMetadata = getAllMods();
|
var modMetadata:Array<ModMetadata> = getAllMods();
|
||||||
var enabledMods = [];
|
var enabledMods:Array<ModMetadata> = [];
|
||||||
for (item in modMetadata)
|
for (item in modMetadata)
|
||||||
{
|
{
|
||||||
if (modIds.indexOf(item.id) != -1)
|
if (modIds.indexOf(item.id) != -1)
|
||||||
|
@ -249,7 +293,11 @@ class PolymodHandler
|
||||||
return enabledMods;
|
return enabledMods;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function forceReloadAssets()
|
/**
|
||||||
|
* Clear and reload from disk all data assets.
|
||||||
|
* Useful for "hot reloading" for fast iteration!
|
||||||
|
*/
|
||||||
|
public static function forceReloadAssets():Void
|
||||||
{
|
{
|
||||||
// Forcibly clear scripts so that scripts can be edited.
|
// Forcibly clear scripts so that scripts can be edited.
|
||||||
ModuleHandler.clearModuleCache();
|
ModuleHandler.clearModuleCache();
|
||||||
|
|
|
@ -51,6 +51,7 @@ class Level implements IRegistryEntry<LevelData>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the title of the level for display on the menu.
|
* Retrieve the title of the level for display on the menu.
|
||||||
|
* @return Title of the level as a string
|
||||||
*/
|
*/
|
||||||
public function getTitle():String
|
public function getTitle():String
|
||||||
{
|
{
|
||||||
|
@ -58,16 +59,21 @@ class Level implements IRegistryEntry<LevelData>
|
||||||
return _data.name;
|
return _data.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct the title graphic for the level.
|
||||||
|
* @return The constructed graphic as a sprite.
|
||||||
|
*/
|
||||||
public function buildTitleGraphic():FlxSprite
|
public function buildTitleGraphic():FlxSprite
|
||||||
{
|
{
|
||||||
var result = new FlxSprite().loadGraphic(Paths.image(_data.titleAsset));
|
var result:FlxSprite = new FlxSprite().loadGraphic(Paths.image(_data.titleAsset));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of songs in this level, as an array of names, for display on the menu.
|
* Get the list of songs in this level, as an array of names, for display on the menu.
|
||||||
* @return Array<String>
|
* @param difficulty The difficulty of the level being displayed
|
||||||
|
* @return The display names of the songs in this level
|
||||||
*/
|
*/
|
||||||
public function getSongDisplayNames(difficulty:String):Array<String>
|
public function getSongDisplayNames(difficulty:String):Array<String>
|
||||||
{
|
{
|
||||||
|
@ -88,7 +94,9 @@ class Level implements IRegistryEntry<LevelData>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this level is unlocked. If not, it will be greyed out on the menu and have a lock icon.
|
* Whether this level is unlocked. If not, it will be greyed out on the menu and have a lock icon.
|
||||||
* TODO: Change this behavior in a later release.
|
* Override this in a script.
|
||||||
|
* @default `true`
|
||||||
|
* @return Whether this level is unlocked
|
||||||
*/
|
*/
|
||||||
public function isUnlocked():Bool
|
public function isUnlocked():Bool
|
||||||
{
|
{
|
||||||
|
@ -97,6 +105,9 @@ class Level implements IRegistryEntry<LevelData>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this level is visible. If not, it will not be shown on the menu at all.
|
* Whether this level is visible. If not, it will not be shown on the menu at all.
|
||||||
|
* Override this in a script.
|
||||||
|
* @default `true`
|
||||||
|
* @return Whether this level is visible in the menu
|
||||||
*/
|
*/
|
||||||
public function isVisible():Bool
|
public function isVisible():Bool
|
||||||
{
|
{
|
||||||
|
@ -106,6 +117,7 @@ class Level implements IRegistryEntry<LevelData>
|
||||||
/**
|
/**
|
||||||
* Build a sprite for the background of the level.
|
* Build a sprite for the background of the level.
|
||||||
* Can be overriden by ScriptedLevel. Not used if `isBackgroundSimple` returns true.
|
* Can be overriden by ScriptedLevel. Not used if `isBackgroundSimple` returns true.
|
||||||
|
* @return The constructed sprite
|
||||||
*/
|
*/
|
||||||
public function buildBackground():FlxSprite
|
public function buildBackground():FlxSprite
|
||||||
{
|
{
|
||||||
|
@ -124,6 +136,7 @@ class Level implements IRegistryEntry<LevelData>
|
||||||
/**
|
/**
|
||||||
* Returns true if the background is a solid color.
|
* Returns true if the background is a solid color.
|
||||||
* If you have a ScriptedLevel with a fancy background, you may want to override this to false.
|
* If you have a ScriptedLevel with a fancy background, you may want to override this to false.
|
||||||
|
* @return Whether the background is a simple color
|
||||||
*/
|
*/
|
||||||
public function isBackgroundSimple():Bool
|
public function isBackgroundSimple():Bool
|
||||||
{
|
{
|
||||||
|
@ -133,30 +146,36 @@ class Level implements IRegistryEntry<LevelData>
|
||||||
/**
|
/**
|
||||||
* Returns true if the background is a solid color.
|
* Returns true if the background is a solid color.
|
||||||
* If you have a ScriptedLevel with a fancy background, you may want to override this to false.
|
* If you have a ScriptedLevel with a fancy background, you may want to override this to false.
|
||||||
|
* @return The background as a simple color. May not be valid if `isBackgroundSimple` returns false.
|
||||||
*/
|
*/
|
||||||
public function getBackgroundColor():FlxColor
|
public function getBackgroundColor():FlxColor
|
||||||
{
|
{
|
||||||
return FlxColor.fromString(_data.background);
|
return FlxColor.fromString(_data.background);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of difficulties the player can select from for this level.
|
||||||
|
* @return The difficulty IDs.
|
||||||
|
*/
|
||||||
public function getDifficulties():Array<String>
|
public function getDifficulties():Array<String>
|
||||||
{
|
{
|
||||||
var difficulties:Array<String> = [];
|
var difficulties:Array<String> = [];
|
||||||
|
|
||||||
var songList = getSongs();
|
var songList:Array<String> = getSongs();
|
||||||
|
|
||||||
var firstSongId:String = songList[0];
|
var firstSongId:String = songList[0];
|
||||||
var firstSong:Song = SongRegistry.instance.fetchEntry(firstSongId);
|
var firstSong:Song = SongRegistry.instance.fetchEntry(firstSongId);
|
||||||
|
|
||||||
if (firstSong != null)
|
if (firstSong != null)
|
||||||
{
|
{
|
||||||
// Don't display alternate characters in Story Mode.
|
// Don't display alternate characters in Story Mode. Only show `default` and `erect` variations.
|
||||||
for (difficulty in firstSong.listDifficulties([Constants.DEFAULT_VARIATION, "erect"]))
|
for (difficulty in firstSong.listDifficulties([Constants.DEFAULT_VARIATION, 'erect']))
|
||||||
{
|
{
|
||||||
difficulties.push(difficulty);
|
difficulties.push(difficulty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort in a specific order! Fall back to alphabetical.
|
||||||
difficulties.sort(SortUtil.defaultsThenAlphabetically.bind(Constants.DEFAULT_DIFFICULTY_LIST));
|
difficulties.sort(SortUtil.defaultsThenAlphabetically.bind(Constants.DEFAULT_DIFFICULTY_LIST));
|
||||||
|
|
||||||
// Filter to only include difficulties that are present in all songs
|
// Filter to only include difficulties that are present in all songs
|
||||||
|
@ -169,7 +188,7 @@ class Level implements IRegistryEntry<LevelData>
|
||||||
|
|
||||||
for (difficulty in difficulties)
|
for (difficulty in difficulties)
|
||||||
{
|
{
|
||||||
if (!song.hasDifficulty(difficulty, [Constants.DEFAULT_VARIATION, "erect"]))
|
if (!song.hasDifficulty(difficulty, [Constants.DEFAULT_VARIATION, 'erect']))
|
||||||
{
|
{
|
||||||
difficulties.remove(difficulty);
|
difficulties.remove(difficulty);
|
||||||
}
|
}
|
||||||
|
@ -181,6 +200,11 @@ class Level implements IRegistryEntry<LevelData>
|
||||||
return difficulties;
|
return difficulties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the props for display over the colored background.
|
||||||
|
* @param existingProps The existing prop sprites, if any.
|
||||||
|
* @return The constructed prop sprites
|
||||||
|
*/
|
||||||
public function buildProps(?existingProps:Array<LevelProp>):Array<LevelProp>
|
public function buildProps(?existingProps:Array<LevelProp>):Array<LevelProp>
|
||||||
{
|
{
|
||||||
var props:Array<LevelProp> = existingProps == null ? [] : [for (x in existingProps) x];
|
var props:Array<LevelProp> = existingProps == null ? [] : [for (x in existingProps) x];
|
||||||
|
@ -189,11 +213,13 @@ class Level implements IRegistryEntry<LevelData>
|
||||||
|
|
||||||
var hiddenProps:Array<LevelProp> = props.splice(_data.props.length - 1, props.length - 1);
|
var hiddenProps:Array<LevelProp> = props.splice(_data.props.length - 1, props.length - 1);
|
||||||
for (hiddenProp in hiddenProps)
|
for (hiddenProp in hiddenProps)
|
||||||
|
{
|
||||||
hiddenProp.visible = false;
|
hiddenProp.visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
for (propIndex in 0..._data.props.length)
|
for (propIndex in 0..._data.props.length)
|
||||||
{
|
{
|
||||||
var propData = _data.props[propIndex];
|
var propData:LevelPropData = _data.props[propIndex];
|
||||||
|
|
||||||
// Attempt to reuse the `LevelProp` object.
|
// Attempt to reuse the `LevelProp` object.
|
||||||
// This prevents animations from resetting.
|
// This prevents animations from resetting.
|
||||||
|
@ -224,6 +250,10 @@ class Level implements IRegistryEntry<LevelData>
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the level is destroyed.
|
||||||
|
* TODO: Document when this gets called
|
||||||
|
*/
|
||||||
public function destroy():Void {}
|
public function destroy():Void {}
|
||||||
|
|
||||||
public function toString():String
|
public function toString():String
|
||||||
|
@ -231,6 +261,11 @@ class Level implements IRegistryEntry<LevelData>
|
||||||
return 'Level($id)';
|
return 'Level($id)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve and parse the JSON data for a level by ID.
|
||||||
|
* @param id The ID of the level
|
||||||
|
* @return The parsed level data, or null if not found or invalid
|
||||||
|
*/
|
||||||
static function _fetchData(id:String):Null<LevelData>
|
static function _fetchData(id:String):Null<LevelData>
|
||||||
{
|
{
|
||||||
return LevelRegistry.instance.parseEntryDataWithMigration(id, LevelRegistry.instance.fetchEntryVersion(id));
|
return LevelRegistry.instance.parseEntryDataWithMigration(id, LevelRegistry.instance.fetchEntryVersion(id));
|
||||||
|
|
Loading…
Reference in a new issue