From ef6cdd5371939ff330aeb43b6e107ecab8203be8 Mon Sep 17 00:00:00 2001 From: Ralty <78720179+Raltyro@users.noreply.github.com> Date: Sat, 26 Jul 2025 18:53:25 +0700 Subject: [PATCH] Options Rewrite WIP Appearance Restructure --- assets/languages/en/Options.xml | 32 ++-- source/funkin/backend/system/Controls.hx | 2 +- source/funkin/editors/DebugOptions.hx | 64 +------- source/funkin/editors/EditorTreeMenu.hx | 6 + source/funkin/menus/MainMenuState.hx | 4 +- source/funkin/menus/PauseSubState.hx | 4 +- .../funkin/menus/credits/CreditsCodename.hx | 136 --------------- source/funkin/menus/credits/CreditsMain.hx | 106 ------------ source/funkin/menus/ui/Slider.hx | 5 + source/funkin/options/Options.hx | 15 +- source/funkin/options/OptionsMenu.hx | 107 +++++++++++- source/funkin/options/OptionsScreen.hx | 8 +- source/funkin/options/OptionsTree.hx | 91 ++++++++++ source/funkin/options/TreeMenu.hx | 155 ++++++++++-------- source/funkin/options/TreeMenuScreen.hx | 82 ++++++--- .../options/categories/AppearanceOptions.hx | 85 +++++----- .../options/categories/GameplayOptions.hx | 90 +--------- .../options/categories/LanguageOptions.hx | 2 +- .../funkin/options/categories/MiscOptions.hx | 33 +--- source/funkin/options/type/ArrayOption.hx | 48 +++--- source/funkin/options/type/Checkbox.hx | 69 ++++---- source/funkin/options/type/MeterOption.hx | 16 +- source/funkin/options/type/NumOption.hx | 80 ++++----- source/funkin/options/type/OptionType.hx | 14 +- source/funkin/options/type/RadioButton.hx | 4 +- source/funkin/options/type/Separator.hx | 30 ++++ source/funkin/options/type/SliderOption.hx | 13 +- source/funkin/options/type/TextOption.hx | 47 ++---- 28 files changed, 586 insertions(+), 762 deletions(-) delete mode 100644 source/funkin/menus/credits/CreditsCodename.hx delete mode 100644 source/funkin/menus/credits/CreditsMain.hx create mode 100644 source/funkin/menus/ui/Slider.hx create mode 100644 source/funkin/options/OptionsTree.hx create mode 100644 source/funkin/options/type/Separator.hx diff --git a/assets/languages/en/Options.xml b/assets/languages/en/Options.xml index f0ec9ea7..ad8a02f0 100644 --- a/assets/languages/en/Options.xml +++ b/assets/languages/en/Options.xml @@ -12,10 +12,11 @@ Gameplay Change Gameplay options such as Downscroll, Scroll Speed, Naughtyness... - Change more advanced options such as Window Size, Streaming Audio... + Change more advanced options such as Hit Window Size, Streaming Audio... Appearance Change Appearance options such as Flashing menus... + Change more advanced options such as VRAM-Only Sprites, Antialiasing, Shaders Language Change the language that the engine uses. @@ -62,8 +63,15 @@ Framerate Pretty self explanatory, isn't it? - Antialiasing - If unchecked, will disable antialiasing on every sprite. Can boost performances at the cost of sharper, more pixely sprites. + Flashing Menu + If unchecked, will disable menu flashing when you select an option in the Main Menu, and other flashes will be slower. + + Quality + Quality modes to choose, "LOW" = Disable every heavy visual effects as it can get to smoothen the gameplay, "HIGH" = Enable all of the visual effects, with the cost of performance, "CUSTOM" = Allow of custom options that is available in Advanced. + LOW + HIGH + CUSTOM + Following option is locked for Quality Option, to unlock set Quality to CUSTOM Colored Healthbar If unchecked, the game will use the original red/green health bar from the week 6 fnf game. @@ -71,17 +79,19 @@ Pixel Perfect Effect If checked, Week 6 will have a pixel perfect effect to it enabled, aligning every pixel on the screen. - Gameplay Shaders - If unchecked, gameplay shaders (visual effects like Thorns's Chromatic Aberration) wont be loaded; this may be helpful on weak devices. + + Antialiasing + If unchecked, will disable antialiasing on every sprite. Can boost performances at the cost of sharper, more pixely sprites. - Flashing Menu - If unchecked, will disable menu flashing when you select an option in the Main Menu, and other flashes will be slower. + Low Memory Mode + If checked, will disable certain background elements in stages to reduce memory usage. - Low Memory Mode - If checked, will disable certain background elements in stages to reduce memory usage. + Gameplay Shaders + If unchecked, gameplay shaders (visual effects like Thorns's Chromatic Aberration) wont be loaded; this may be helpful on weak devices. - VRAM-Only Sprites - If checked, will only store the bitmaps in the GPU, freeing a LOT of memory (EXPERIMENTAL). Turning this off will consume a lot of memory, especially on bigger sprites. If you aren't sure, leave this on. + VRAM-Only Sprites + If checked, will only store the bitmaps in the GPU, freeing a LOT of memory (EXPERIMENTAL). Turning this off will consume a lot of memory, especially on bigger sprites. If you aren't sure, leave this on. + diff --git a/source/funkin/backend/system/Controls.hx b/source/funkin/backend/system/Controls.hx index 0ccaac63..5f6f8f98 100644 --- a/source/funkin/backend/system/Controls.hx +++ b/source/funkin/backend/system/Controls.hx @@ -191,7 +191,7 @@ class Controls extends FlxActionSet setKeyboardScheme(scheme, false); } - public function getActionFromControl(control:Control):FLxAction return macro_getActionFromControl(control); + public function getActionFromControl(control:Control):FlxAction return macro_getActionFromControl(control); public function getKeyName(control:Control, idx:Int = 0):String { diff --git a/source/funkin/editors/DebugOptions.hx b/source/funkin/editors/DebugOptions.hx index 93d85992..0f3dc9fd 100644 --- a/source/funkin/editors/DebugOptions.hx +++ b/source/funkin/editors/DebugOptions.hx @@ -10,71 +10,9 @@ class DebugOptions extends TreeMenu { super.create(); FlxG.camera.fade(0xFF000000, 0.5, true); - - var bg:FlxSprite = new FlxSprite(-80).loadAnimatedGraphic(Paths.image('menus/menuBGBlue')); - // bg.scrollFactor.set(); - bg.scale.set(1.15, 1.15); - bg.updateHitbox(); - bg.screenCenter(); - bg.scrollFactor.set(); - bg.antialiasing = true; - add(bg); - - main = new DebugOptionsScreen(); } } class DebugOptionsScreen extends OptionsScreen { - public override function new() { - prefix = "DebugOptions."; - super(translate("title"), translate("desc"), prefix); - #if windows - add(new TextOption( - getName("showConsole"), - getDesc("showConsole"), - function() { - NativeAPI.allocConsole(); - })); - #end - add(new Checkbox( - getName("editorsResizable"), - getDesc("editorsResizable"), - "editorsResizable")); - add(new Checkbox( - getName("bypassEditorsResize"), - getDesc("bypassEditorsResize"), - "bypassEditorsResize")); - add(new Checkbox( - getName("editorSFX"), - getDesc("editorSFX"), - "editorSFX")); - add(new Checkbox( - getName("editorPrettyPrint"), - getDesc("editorPrettyPrint"), - "editorPrettyPrint")); - add(new Checkbox( - getName("intensiveBlur"), - getDesc("intensiveBlur"), - "intensiveBlur")); - add(new Checkbox( - getName("charterAutoSaves"), - getDesc("charterAutoSaves"), - "charterAutoSaves")); - add(new NumOption( - getName("charterAutoSaveTime"), - getDesc("charterAutoSaveTime"), - 60, 60*10, 30, - "charterAutoSaveTime" - )); - add(new NumOption( - getName("charterAutoSaveWarningTime"), - getDesc("charterAutoSaveWarningTime"), - 0, 15, 1, - "charterAutoSaveWarningTime" - )); - add(new Checkbox( - getName("charterAutoSavesSeparateFolder"), - getDesc("charterAutoSavesSeparateFolder"), - "charterAutoSavesSeparateFolder")); - } + } \ No newline at end of file diff --git a/source/funkin/editors/EditorTreeMenu.hx b/source/funkin/editors/EditorTreeMenu.hx index 7bf5a0fb..b4904866 100644 --- a/source/funkin/editors/EditorTreeMenu.hx +++ b/source/funkin/editors/EditorTreeMenu.hx @@ -9,6 +9,8 @@ class EditorTreeMenu extends TreeMenu { public var bgType:String = "default"; public var bgMovement:FlxPoint = new FlxPoint(); + public var main:OptionsScreen; + public override function create() { super.create(); @@ -31,4 +33,8 @@ class EditorTreeMenu extends TreeMenu { public override function exit() { FlxG.switchState(new MainMenuState()); } + + public function onMenuChange() { + + } } \ No newline at end of file diff --git a/source/funkin/menus/MainMenuState.hx b/source/funkin/menus/MainMenuState.hx index 1a68f4a2..1a931781 100644 --- a/source/funkin/menus/MainMenuState.hx +++ b/source/funkin/menus/MainMenuState.hx @@ -6,7 +6,7 @@ import flixel.tweens.FlxTween; import funkin.backend.FunkinText; import funkin.backend.scripting.events.menu.MenuChangeEvent; import funkin.backend.scripting.events.NameEvent; -import funkin.menus.credits.CreditsMain; +//import funkin.menus.credits.CreditsMain; import funkin.options.OptionsMenu; import lime.app.Application; @@ -168,7 +168,7 @@ class MainMenuState extends MusicBeatState { case 'story mode': FlxG.switchState(new StoryMenuState()); case 'freeplay': FlxG.switchState(new FreeplayState()); - case 'donate', 'credits': FlxG.switchState(new CreditsMain()); // kept donate for not breaking scripts, if you don't want donate to bring you to the credits menu, thats easy softcodable - Nex + //case 'donate', 'credits': FlxG.switchState(new CreditsMain()); // kept donate for not breaking scripts, if you don't want donate to bring you to the credits menu, thats easy softcodable - Nex case 'options': FlxG.switchState(new OptionsMenu()); } }); diff --git a/source/funkin/menus/PauseSubState.hx b/source/funkin/menus/PauseSubState.hx index f652b36c..2f054d9f 100644 --- a/source/funkin/menus/PauseSubState.hx +++ b/source/funkin/menus/PauseSubState.hx @@ -14,7 +14,6 @@ import funkin.backend.utils.FunkinParentDisabler; import funkin.editors.charter.Charter; import funkin.menus.StoryMenuState; import funkin.options.OptionsMenu; -import funkin.options.TreeMenu; import funkin.options.keybinds.KeybindsOptions; class PauseSubState extends MusicBeatSubstate @@ -166,8 +165,7 @@ class PauseSubState extends MusicBeatSubstate persistentDraw = false; openSubState(new KeybindsOptions()); case "Change Options": - TreeMenu.lastState = PlayState; - FlxG.switchState(new OptionsMenu()); + FlxG.switchState(new OptionsMenu((_) -> FlxG.switchState(new PlayState()))); case "Exit to charter": FlxG.switchState(new Charter(PlayState.SONG.meta.name, PlayState.difficulty, false)); case "Exit to menu": diff --git a/source/funkin/menus/credits/CreditsCodename.hx b/source/funkin/menus/credits/CreditsCodename.hx deleted file mode 100644 index 70e172dc..00000000 --- a/source/funkin/menus/credits/CreditsCodename.hx +++ /dev/null @@ -1,136 +0,0 @@ -package funkin.menus.credits; - -import flixel.text.FlxText; -import flixel.util.FlxColor; -import funkin.backend.system.github.GitHub; -import funkin.backend.system.github.GitHubContributor.CreditsGitHubContributor; -import funkin.options.PlayerSettings; -import funkin.options.type.GithubIconOption; - -using StringTools; - -class CreditsCodename extends funkin.options.OptionsScreen { - public var error:Bool = false; - public var totalContributions:Int = 0; - public var contribFormats:Array = []; - - public override function new() - { - super("Codename Engine", TU.translate("credits.allContributors")); - tryUpdating(true); - } - - // blame the secondary threads if the code has to look this bad - Nex - private var _canReset:Bool = true; - private var _downloadingSteps:Int = 0; - public override function update(elapsed:Float) { - super.update(elapsed); - - if (_downloadingSteps == 2) { - _downloadingSteps = 0; - _canReset = true; - displayList(); - } else if (_downloadingSteps == 1) { - _downloadingSteps = 0; - _canReset = true; - updateMenuDesc(); - } - else if(_canReset && PlayerSettings.solo.controls.RESET) tryUpdating(); - } - - public function tryUpdating(forceDisplaying:Bool = false) { - updateMenuDesc(TU.translate("credits.downloadingList")); - _canReset = false; - Main.execAsync(function() { - if(checkUpdate() || forceDisplaying) _downloadingSteps = 2; - else _downloadingSteps = 1; - }); - } - - public override function updateMenuDesc(?txt:String) { - if(!_canReset) return; - super.updateMenuDesc(txt); - updateMarkup(); - } - - public function updateMarkup() { - if(parent == null || parent.treeParent == null) return; - var text:String = parent.treeParent.pathDesc.text; - parent.treeParent.pathDesc.text = ""; - parent.treeParent.pathDesc.applyMarkup(text, contribFormats = [ - new FlxTextFormatMarkerPair(new FlxTextFormat(Flags.MAIN_DEVS_COLOR), '*'), - new FlxTextFormatMarkerPair(new FlxTextFormat(FlxColor.interpolate(Flags.MIN_CONTRIBUTIONS_COLOR, Flags.MAIN_DEVS_COLOR, Options.contributors[curSelected].contributions / totalContributions)), '~') - ]); - } - - override function close() { - super.close(); - for (frmt in contribFormats) parent.treeParent.pathDesc.removeFormat(frmt.format); - } - - public function checkUpdate():Bool { - var curTime:Float = Date.now().getTime(); - if(Options.lastUpdated != null && curTime < Options.lastUpdated + 120000) return false; // Fuck you Github rate limits - Nex - Options.lastUpdated = curTime; - - error = false; - var idk = GitHub.getContributors(Flags.REPO_OWNER, Flags.REPO_NAME, function(e) { - error = true; - var errMsg:String = 'Error while trying to download contributors list:\n${CoolUtil.removeIP(e.message)}'; - Logs.error(errMsg.replace('\n', ' ')); - funkin.backend.utils.NativeAPI.showMessageBox("Codename Engine Warning", errMsg, MSG_WARNING); - }); - if(error) return false; - if((idk is Array)) { - var contributors:Array = []; - for(e in idk) contributors.push({ - login: e.login, - avatar_url: e.avatar_url, - html_url: e.html_url, - id: e.id, - contributions: e.contributions - }); - Options.contributors = contributors; - } - Logs.verbose('[CreditsCodename] Contributors list Updated!'); - - var errorOnMain:Bool = false; - var idk2 = GitHub.getOrganizationMembers(Flags.REPO_OWNER, function(e) { - errorOnMain = true; - var errMsg:String = 'Error while trying to download ${Flags.REPO_OWNER} members list:\n${CoolUtil.removeIP(e.message)}'; - Logs.error(errMsg.replace('\n', ' ')); - funkin.backend.utils.NativeAPI.showMessageBox("Codename Engine Warning", errMsg, MSG_WARNING); - }); - if(!errorOnMain) { - Options.mainDevs = [for(m in idk2) m.id]; - Logs.verbose('[CreditsCodename] Main Devs list Updated!'); - } - - return true; - } - - public function displayList() { - //if (curSelected > Options.contributors.length - 1) changeSelection(-(curSelected - (Options.contributors.length - 1))); - if (curSelected > Options.contributors.length - 1) curSelected = Options.contributors.length - 1; - changeSelection(0, true); - - while (members.length > 0) { - members[0].destroy(); - remove(members[0], true); - } - - totalContributions = 0; - for(c in Options.contributors) totalContributions += c.contributions; - for(c in Options.contributors) { - var text = TU.translate("credits.totalContributions", [c.contributions, totalContributions, FlxMath.roundDecimal(c.contributions / totalContributions * 100, 2)]); - var opt:GithubIconOption = new GithubIconOption(c, text); - if(Options.mainDevs.contains(c.id)) { - opt.desc += TU.translate("credits.mainDev"); - @:privateAccess opt.__text.color = Flags.MAIN_DEVS_COLOR; - } - add(opt); - } - - updateMenuDesc(); - } -} \ No newline at end of file diff --git a/source/funkin/menus/credits/CreditsMain.hx b/source/funkin/menus/credits/CreditsMain.hx deleted file mode 100644 index 76485cbf..00000000 --- a/source/funkin/menus/credits/CreditsMain.hx +++ /dev/null @@ -1,106 +0,0 @@ -package funkin.menus.credits; - -import flixel.util.FlxColor; -import funkin.backend.assets.AssetSource; -import funkin.backend.system.github.GitHubContributor.CreditsGitHubContributor; -import funkin.options.OptionsScreen; -import funkin.options.TreeMenu; -import funkin.options.type.*; -import haxe.xml.Access; - -class CreditsMain extends TreeMenu { - var bg:FlxSprite; - var items:Array = []; - - public override function create() { - bg = new FlxSprite(-80).loadAnimatedGraphic(Paths.image('menus/menuBGBlue')); - // bg.scrollFactor.set(); - bg.scale.set(1.15, 1.15); - bg.updateHitbox(); - bg.screenCenter(); - bg.scrollFactor.set(); - bg.antialiasing = true; - add(bg); - - for (i in funkin.backend.assets.ModsFolder.getLoadedMods()) { - var xmlPath = Paths.xml('config/credits/LIB_$i'); - - if (Paths.assetsTree.existsSpecific(xmlPath, "TEXT")) { - var access:Access = null; - try access = new Access(Xml.parse(Paths.assetsTree.getSpecificAsset(xmlPath, "TEXT"))) - catch(e) Logs.trace('[CreditsMain] Error while parsing credits.xml: ${Std.string(e)}', ERROR); - if (access != null) for (c in parseCreditsFromXML(access)) items.push(c); - } - } - - items.push(new TextOption("Codename Engine >", TU.translate("credits.selectCodename"), function() { - optionsTree.add(Type.createInstance(CreditsCodename, [])); - })); - items.push(new TextOption("Friday Night Funkin'", TU.translate("credits.selectBase"), function() { - CoolUtil.openURL(Flags.URL_FNF_ITCH); - })); - - main = new OptionsScreen(TU.translate("credits.name"), TU.translate("credits.madePossible"), items); - super.create(); - - DiscordUtil.call("onMenuLoaded", ["Credits Menu"]); - } - - /** - * XML STUFF - */ - public function parseCreditsFromXML(xml:Access, source:AssetSource = BOTH):Array { - var credsMenus:Array = []; - - for(node in xml.elements) { - var desc = node.getAtt("desc").getDefault("No Description"); - - if (node.name == "github") { - if (!node.has.user) { - Logs.warn("A github node requires a user attribute.", "CreditsMain"); - continue; - } - - var username = node.getAtt("user"); - var user:CreditsGitHubContributor = { // Kind of forcing - login: username, - html_url: 'https://github.com/$username', - avatar_url: 'https://github.com/$username.png' - }; - var opt:GithubIconOption = new GithubIconOption(user, desc, null, - node.has.customName ? node.att.customName : null, - node.has.size ? Std.parseInt(node.att.size) : 96, - node.has.portrait ? node.att.portrait.toLowerCase() == "false" ? false : true : true - ); - if (node.has.color) - @:privateAccess opt.__text.color = FlxColor.fromString(node.att.color); - credsMenus.push(opt); - } else { - if (!node.has.name) { - Logs.warn("A credit node requires a name attribute.", "CreditsMain"); - continue; - } - var name = node.getAtt("name"); - - switch(node.name) { - case "credit": - var opt:PortraitOption = new PortraitOption(name, desc, function() if(node.has.url) CoolUtil.openURL(node.att.url), - node.has.icon && Paths.assetsTree.existsSpecific(Paths.image('credits/${node.att.icon}'), "IMAGE", source) ? - FlxG.bitmap.add(Paths.image('credits/${node.att.icon}')) : null, node.has.size ? Std.parseInt(node.att.size) : 96, - node.has.portrait ? node.att.portrait.toLowerCase() == "false" ? false : true : true - ); - if (node.has.color) - @:privateAccess opt.__text.color = FlxColor.fromString(node.att.color); - credsMenus.push(opt); - - case "menu": - credsMenus.push(new TextOption(name + " >", desc, function() { - optionsTree.add(new OptionsScreen(name, desc, parseCreditsFromXML(node, source))); - })); - } - } - } - - return credsMenus; - } -} diff --git a/source/funkin/menus/ui/Slider.hx b/source/funkin/menus/ui/Slider.hx new file mode 100644 index 00000000..45360ce7 --- /dev/null +++ b/source/funkin/menus/ui/Slider.hx @@ -0,0 +1,5 @@ +package funkin.menus.ui; + +class Slider extends FlxSprite { + +} \ No newline at end of file diff --git a/source/funkin/options/Options.hx b/source/funkin/options/Options.hx index bd39cd45..9551c51c 100644 --- a/source/funkin/options/Options.hx +++ b/source/funkin/options/Options.hx @@ -44,6 +44,7 @@ class Options public static var language = "en"; // default to english, Flags.DEFAULT_LANGUAGE should not modify this public static var streamedMusic:Bool = true; public static var streamedVocals:Bool = true; + public static var quality:Int = 1; #if MODCHARTING_FEATURES public static var modchartingHoldSubdivisions:Int = 4; #end @@ -207,7 +208,19 @@ class Options public static function applySettings() { applyKeybinds(); - FlxG.game.stage.quality = (FlxG.enableAntialiasing = antialiasing) ? LOW : BEST; + + switch (quality) { + case 0: + antialiasing = false; + lowMemoryMode = true; + gameplayShaders = false; + case 1: + antialiasing = true; + lowMemoryMode = false; + gameplayShaders = true; + } + + FlxG.game.stage.quality = (FlxG.enableAntialiasing = antialiasing) ? BEST : LOW; FlxG.autoPause = autoPause; if (FlxG.updateFramerate < framerate) FlxG.drawFramerate = FlxG.updateFramerate = framerate; else FlxG.updateFramerate = FlxG.drawFramerate = framerate; diff --git a/source/funkin/options/OptionsMenu.hx b/source/funkin/options/OptionsMenu.hx index 9f35c36f..ae184e0c 100644 --- a/source/funkin/options/OptionsMenu.hx +++ b/source/funkin/options/OptionsMenu.hx @@ -1,12 +1,15 @@ package funkin.options; +import haxe.xml.Access; +import flixel.util.typeLimit.OneOfThree; +import funkin.editors.ui.UIState; import funkin.options.categories.*; import funkin.options.type.*; typedef OptionCategory = { var name:String; var desc:String; - var ?state:OneOfThree, (name:String, desc:String) -> OptionsScreen>; + var ?state:OneOfThree, (name:String, desc:String) -> TreeMenuScreen>; var ?substate:OneOfThree, (name:String, desc:String) -> MusicBeatSubstate>; var ?suffix:String; } @@ -16,8 +19,8 @@ class OptionsMenu extends TreeMenu { { // name and desc are actually the translations ids! - Nex name: 'optionsTree.controls-name', desc: 'optionsTree.controls-desc', - suffix: ''; - substate: funkin.options.keybinds.KeybindsOptions; + suffix: '', + substate: funkin.options.keybinds.KeybindsOptions }, { name: 'optionsTree.gameplay-name', @@ -43,7 +46,7 @@ class OptionsMenu extends TreeMenu { } ]; - var bg:FunkinSprite; + var bg:FlxSprite; override function create() { super.create(); @@ -52,23 +55,54 @@ class OptionsMenu extends TreeMenu { DiscordUtil.call("onMenuLoaded", ["Options Menu"]); - add(bg = new FunkinSprite().loadAnimatedGraphic(Paths.image('menus/menuBGBlue'))); + add(bg = new FlxSprite().loadAnimatedGraphic(Paths.image('menus/menuBGBlue'))); bg.antialiasing = true; bg.scrollFactor.set(); updateBG(); - /*tree = [ - for (o in mainOptions) { + addMenu(new TreeMenuScreen('optionsMenu.header.title', 'optionsMenu.header.desc', [for (o in mainOptions) new TextOption(o.name, o.desc, o.suffix != null ? o.suffix : " >", () -> { + if (o.substate != null) { + persistentUpdate = false; + persistentDraw = true; + if (o.substate is MusicBeatSubstate) + openSubState(o.substate); + else if(Reflect.isFunction(o.substate)) { + var substate:(name:String, desc:String) -> MusicBeatSubstate = o.substate; + openSubState(substate(o.name, o.desc)); + } + else // o.substate is Class + openSubState(Type.createInstance(o.substate, [o.name, o.desc])); } - ];*/ + else { + if (o.state is TreeMenuScreen) + addMenu(o.state); + else if (Reflect.isFunction(o.state)) { + var state:(name:String, desc:String) -> TreeMenuScreen = o.state; + addMenu(state(o.name, o.desc)); + } + else { // o.state is Class + addMenu(Type.createInstance(o.state, [o.name, o.desc])); + } + } + })])); + for (i in funkin.backend.assets.ModsFolder.getLoadedMods()) { + var xmlPath = Paths.xml('config/options/LIB_$i'); + + if (Paths.assetsTree.existsSpecific(xmlPath, "TEXT")) { + var access:Access = null; + try access = new Access(Xml.parse(Paths.assetsTree.getSpecificAsset(xmlPath, "TEXT"))) + catch(e) Logs.trace('Error while parsing options.xml: ${Std.string(e)}', ERROR); + //if (access != null) for (o in parseOptionsFromXML(access)) main.add(o); + } + } } public function updateBG() { var scaleX:Float = FlxG.width / bg.width; var scaleY:Float = FlxG.height / bg.height; - bg.scale.x = bg.scale.y = Math.max(scaleX, scaleY); + bg.scale.x = bg.scale.y = Math.max(scaleX, scaleY) * 1.15; bg.screenCenter(); } @@ -84,4 +118,59 @@ class OptionsMenu extends TreeMenu { Options.applySettings(); super.exit(); } + + // XML STUFF + /* + public function parseOptionsFromXML(xml:Access):Array { + var options:Array = []; + + for(node in xml.elements) { + if (!node.has.name) { + Logs.warn("An option node requires a name attribute."); + continue; + } + var name = node.getAtt("name"); + var desc = node.getAtt("desc").getDefault("optionsMenu.desc-missing"); + + switch(node.name) { + case "checkbox": + if (!node.has.id) { + Logs.warn("A checkbox option requires an \"id\" for option saving."); + continue; + } + options.push(new Checkbox(name, desc, node.att.id, FlxG.save.data)); + + case "number": + if (!node.has.id) { + Logs.warn("A number option requires an \"id\" for option saving."); + continue; + } + options.push(new NumOption(name, desc, Std.parseFloat(node.att.min), Std.parseFloat(node.att.max), Std.parseFloat(node.att.change), node.att.id, null, FlxG.save.data)); + case "choice": + if (!node.has.id) { + Logs.warn("A choice option requires an \"id\" for option saving."); + continue; + } + + var optionOptions:Array = []; + var optionDisplayOptions:Array = []; + + for(choice in node.elements) { + optionOptions.push(choice.att.value); + optionDisplayOptions.push(choice.att.name); + } + + if(optionOptions.length > 0) + options.push(new ArrayOption(name, desc, optionOptions, optionDisplayOptions, node.att.id, null, FlxG.save.data)); + + case "menu": + options.push(new TextOption(name + " >", desc, function() { + optionsTree.add(new TreeMenuScreen(name, desc, parseOptionsFromXML(node))); + })); + } + } + + return options; + } + */ } \ No newline at end of file diff --git a/source/funkin/options/OptionsScreen.hx b/source/funkin/options/OptionsScreen.hx index 53dd5b06..672feb40 100644 --- a/source/funkin/options/OptionsScreen.hx +++ b/source/funkin/options/OptionsScreen.hx @@ -1,3 +1,5 @@ +// REMOVE THIS WHEN COMPLETE + package funkin.options; import funkin.options.type.OptionType; @@ -92,13 +94,13 @@ class OptionsScreen extends FlxTypedSpriteGroup { if (members.length > 0) { members[curSelected].selected = true; if (controls.ACCEPT || (FlxG.mouse.justReleased && Main.timeSinceFocus > 0.25)) { - members[curSelected].onSelect(); + members[curSelected].select(); onSelect(members[curSelected]); } if (controls.LEFT_P) - members[curSelected].onChangeSelection(-1); + members[curSelected].changeSelection(-1); if (controls.RIGHT_P) - members[curSelected].onChangeSelection(1); + members[curSelected].changeSelection(1); } if (controls.BACK || FlxG.mouse.justReleasedRight) close(); diff --git a/source/funkin/options/OptionsTree.hx b/source/funkin/options/OptionsTree.hx new file mode 100644 index 00000000..1f0bfcc7 --- /dev/null +++ b/source/funkin/options/OptionsTree.hx @@ -0,0 +1,91 @@ +// REMOVE THIS WHEN COMPLETE + +package funkin.options; + +class OptionsTree extends FlxTypedGroup { + public var lastMenu:OptionsScreen; + public var treeParent:TreeMenu; + public var wasClosing:Bool = false; + //public override function new() { + // super(); + //} + + public override function update(elapsed:Float) { + var last = members.last(); + if (last != null) + last.update(elapsed); + } + + public function updateAll(elapsed:Float) { + for (member in members) { + if(member == null) continue; + if(member.active && member.exists) { + member.update(elapsed); + } + } + } + + public override function draw() { + super.draw(); + if (lastMenu != null) { // manually draw lastMenu since it got removed from the members list + lastMenu.draw(); + } + } + + public function reloadStrings() { + for(o in members) { + o.reloadStrings(); + } + } + + public override function add(m:OptionsScreen) { + super.add(m); + setup(m); + clearLastMenu(); + wasClosing = false; + onMenuChange(); + return m; + } + public override function insert(pos:Int, m:OptionsScreen) { + var last = members.last(); + super.insert(pos, m); + setup(m); + if (last != members.last()) { + wasClosing = false; + onMenuChange(); + } + return m; + } + + public function setup(m:OptionsScreen) { + m.onClose = __subMenuClose; + m.id = members.indexOf(m); + m.parent = this; + m.update(0); + } + + function __subMenuClose(m:OptionsScreen) { + wasClosing = true; + clearLastMenu(); + lastMenu = m; + remove(m, true); + onMenuChange(); + onMenuClose(m); + } + + public function clearLastMenu() { + lastMenu = FlxDestroyUtil.destroy(lastMenu); + } + + public override function destroy() { + super.destroy(); + lastMenu = FlxDestroyUtil.destroy(lastMenu); + } + + public dynamic function onMenuChange() { + + } + + public dynamic function onMenuClose(m:OptionsScreen) { + } +} \ No newline at end of file diff --git a/source/funkin/options/TreeMenu.hx b/source/funkin/options/TreeMenu.hx index ba818c36..befed063 100644 --- a/source/funkin/options/TreeMenu.hx +++ b/source/funkin/options/TreeMenu.hx @@ -1,6 +1,10 @@ package funkin.options; +import flixel.tweens.FlxTween; +import flixel.util.FlxArrayUtil; +import flixel.util.FlxColor; import flixel.util.FlxSignal; +import funkin.backend.FunkinText; import funkin.backend.system.framerate.Framerate; import funkin.editors.ui.UIState; @@ -8,7 +12,8 @@ interface ITreeOption { var desc:String; var selected:Bool; - function changeSelection(change:Int); + function reloadStrings():Void; + function changeSelection(change:Int):Void; function select():Void; } @@ -16,9 +21,9 @@ class TreeMenu extends UIState { public var onMenuClosed:FlxTypedSignalVoid> = new FlxTypedSignal(); public var onMenuChanged:FlxTypedSignalVoid> = new FlxTypedSignal(); - public var tree(default, null):Array; - public var length(default, null):Int = 0; - public var lastMenu:Null; + public var tree(default, null):Array = []; + public var treeLength(default, null):Int = 0; + public var previousMenus:Array = []; public var destroyMenus:Bool = true; public var exitCallback:TreeMenu->Void; @@ -27,10 +32,13 @@ class TreeMenu extends UIState { public var descLabel:FunkinText; public var bgLabel:FlxSprite; - var menuChangeTween:FlxTween; - var _drawer:TreeMenuDrawer; + public var optionsTree:OptionsTree; - public function new(exitCallback:TreeMenu->Void, + var menuChangeTween:FlxTween; + var __drawer:TreeMenuDrawer; + var __treeCreated:Bool = false; + + public function new(?exitCallback:TreeMenu->Void, scriptsAllowed:Bool = true, ?scriptName:String) { super(scriptsAllowed, scriptName); @@ -44,40 +52,44 @@ class TreeMenu extends UIState { bgLabel.alpha = 0.25; bgLabel.scrollFactor.set(); - titleLabel = new FunkinText(4, 4, FlxG.camera.width - 8, 32); + titleLabel = new FunkinText(4, 4, FlxG.width - 8, 32); titleLabel.borderSize = 1.25; titleLabel.scrollFactor.set(); - descLabel = new FunkinText(4, 0, FlxG.camera.width - 8, 16); + descLabel = new FunkinText(4, 0, FlxG.width - 8, 16); descLabel.scrollFactor.set(); } override function createPost() { super.createPost(); - if ((length = tree.length) != 0) { + if ((treeLength = tree.length) != 0) { updateMenuPositions(true); tree.last().inputEnabled = true; } else - add(new TreeMenuScreen("Fallback TreeMenuScreen", "Please insert menus into \"tree\" variable in your extended class in create or before createPost")); + addMenu(new TreeMenuScreen("Fallback TreeMenuScreen", "Please insert menus into \"tree\" variable in your extended class in create or before createPost")); - add(_drawer = new TreeMenuDrawer(this)); + add(__drawer = new TreeMenuDrawer(this)); add(bgLabel); add(titleLabel); add(descLabel); updateLabels(); + + __treeCreated = true; } public function updateMenuPositions(fromIndex:Int = 0, cameraScroll = false) { - var last = tree[position - 1], menu:TreeMenuScreen; - while (fromIndex < length) if ((menu = tree[fromIndex++]) != null) { - menu.x = last == null ? 0 : last.x + Math.max(FlxG.camera.width, last.width); - last = menu; + var last = tree[fromIndex - 1], menu:TreeMenuScreen; + while (fromIndex < treeLength) if ((menu = tree[fromIndex++]) != null) { + menu.x = last == null ? 0 : last.x + Math.max(FlxG.width, last.width); + (last = menu).parent = this; } - if (menuChangeTween != null && menuChangeTween.active) menuChangeTween.cancel(); - if (cameraScroll) FlxG.camera.scroll.x = lastMenu.x; + if (cameraScroll && last != null) { + if (menuChangeTween != null && menuChangeTween.active) menuChangeTween.cancel(); + FlxG.camera.scroll.x = last.x; + } } public function updateLabels() { @@ -96,100 +108,102 @@ class TreeMenu extends UIState { descLabel.text = last.desc; if (customText != null && customText.length > 0) descLabel.text += "\n" + customText; else if (last.curSelected >= 0 && last.curSelected < last.length && last.members[last.curSelected] is ITreeOption) - descLabel.text += "\n" + (cast last.members[last.curSelected]:ITreeOption).desc; + descLabel.text += "\n" + cast(last.members[last.curSelected], ITreeOption).desc; - bgLabel.scale.set(FLxG.width, descLabel.y + descLabel.height + 2); + bgLabel.scale.set(FlxG.width, descLabel.y + descLabel.height + 2); bgLabel.updateHitbox(); Framerate.offset.y = bgLabel.height + 2; } - public function add(menu:TreeMenuScreen):TreeMenuScreen { + public function addMenu(menu:TreeMenuScreen):TreeMenuScreen { if (menu == null) return null; if (tree.indexOf(menu) != -1) return menu; tree.push(menu); + if (!__treeCreated) return menu; + menu.parent = this; - length++; + treeLength++; - var prev = tree[length - 1]; - menu.x = prev == null ? 0 : prev.x + Math.max(FlxG.camera.width, prev.width); + var prev = tree[treeLength - 2]; + menu.x = prev == null ? 0 : prev.x + Math.max(FlxG.width, prev.width); + destroyPreviousMenus(); menuChanged(); menu.inputEnabled = true; - prev.inputEnabled = false; + if (prev != null) prev.inputEnabled = false; return menu; } - public function insert(position:Int, menu:TreeMenuScreen):TreeMenuScreen { + public function insertMenu(position:Int, menu:TreeMenuScreen):TreeMenuScreen { if (menu == null) return null; if (tree.indexOf(menu) != -1) return menu; - if (position < 0) position = length - ((-position - 1) % length); + if (position < 0) position = treeLength - ((-position - 1) % treeLength); + tree.insert(position, menu); + if (!__treeCreated) return menu; + menu.parent = this; - var lastChanged = position >= length++; + var lastChanged = position >= treeLength++; updateMenuPositions(position, !lastChanged); if (lastChanged) { + destroyPreviousMenus(); menuChanged(); menu.inputEnabled = true; - tree[length - 1].inputEnabled = false; + if (treeLength > 0) tree[treeLength - 2].inputEnabled = false; } return menu; } - public function pop():TreeMenuScreen { - (lastMenu = tree.pop(position)).parent = null; - length--; + public function popMenu():TreeMenuScreen + return removeMenuPosition(treeLength - 1); - menuChanged(); - lastMenu.inputEnabled = false; - menu.inputEnabled = true; + public function removeMenu(menu:TreeMenuScreen):TreeMenuScreen + return if (menu == null) null; else removeMenuPosition(tree.indexOf(menu)); - return lastMenu; - } + public function removeMenuPosition(position:Int):TreeMenuScreen { + if (position < 0 || position >= treeLength || treeLength == 0) return null; - public function remove(menu:TreeMenuScreen):TreeMenuScreen { - return if (menu == null) null; else removePosition(tree.indexOf(menu)); - } + tree[position] = tree[tree.length - 1]; + var menu = tree.pop(); + menu.parent = null; - public function removePosition(position:Int):TreeMenuScreen { - if (position < 0 || position >= length) return null; + if (!__treeCreated) return menu; - destroyLastMenu(); - (lastMenu = tree.swapAndPop(position)).parent = null; - - if (position == --length) { + previousMenus.push(menu); + if (position == --treeLength) { menuChanged(); - lastMenu.inputEnabled = false; - tree[length - 1].inputEnabled = true; + menu.inputEnabled = false; + if (treeLength > 0) tree[treeLength - 1].inputEnabled = true; } else { updateMenuPositions(position, true); updateLabels(); } - return lastMenu; + onMenuClosed.dispatch(menu); + return menu; } public function menuChanged() { - if (length == 0) exit(); + if (treeLength == 0) exit(); else { updateLabels(); if (menuChangeTween != null && menuChangeTween.active) menuChangeTween.cancel(); - menuChangeTween = FlxTween.tween(FlxG.camera.scroll, {x: tree.last().x}, 1.5, {ease: menuTransitionEase, onComplete: (t) -> { for (menu in tree) if (menu != null) menu.transitioning = false; - lastMenu.transitioning = false; + for (menu in previousMenus) if (menu != null) menu.transitioning = false; }}); for (menu in tree) if (menu != null) menu.transitioning = true; - lastMenu.transitioning = true; + for (menu in previousMenus) if (menu != null) menu.transitioning = true; } } @@ -197,14 +211,18 @@ class TreeMenu extends UIState { super.update(elapsed); var i = 0, menu:TreeMenuScreen; - while (i < length) { + while (i < treeLength) { if ((menu = tree[i++]) == null || !menu.active || !menu.exists) continue; - if (i == length || menu.persistentUpdate || menu.transitioning) menu.update(elapsed); + if (i == treeLength || menu.persistentUpdate || menu.transitioning) menu.update(elapsed); } - if (lastMenu != null) { - if (lastMenu.transitioning) lastMenu.update(elapsed); - else destroyLastMenu(); + i = previousMenus.length; + while (i-- > 0) { + if ((menu = previousMenus[i]).transitioning) menu.update(elapsed); + else { + menu.destroy(); + FlxArrayUtil.swapAndPop(previousMenus, i); + } } // in case path gets so long it goes offscreen, ALTHOUGH this nevers happens anyway since we have set a expected width to the label. @@ -213,7 +231,7 @@ class TreeMenu extends UIState { override function destroy() { super.destroy(); - destroyLastMenu(); + destroyPreviousMenus(); } override function onResize(width:Int, height:Int) { @@ -226,21 +244,23 @@ class TreeMenu extends UIState { } updateMenuPositions(true); - descLabel.width = titleLabel.width = (bgLabel.width = width) - 8; + descLabel.width = titleLabel.width = (bgLabel.scale.x = width) - 8; + bgLabel.updateHitbox(); } public function reloadStrings() { for (menu in tree) if (menu != null) menu.reloadStrings(); } - public function destroyLastMenu() { - lastMenu = destroyMenus ? FlxDestroyUtil.destroy(lastMenu) : null; + public function destroyPreviousMenus() { + for (menu in previousMenus) menu.destroy(); + previousMenus.resize(0); } public function exit() { if (exitCallback != null) return exitCallback(this); - FlxG.switchState(new MainMenuState()); + FlxG.switchState(new funkin.menus.MainMenuState()); } public function updateAll(elapsed:Float) { @@ -253,17 +273,18 @@ class TreeMenu extends UIState { final class TreeMenuDrawer extends FlxBasic { public var parent:TreeMenu; public function new(parent:TreeMenu) { + super(); this.parent = parent; - moves = false; } override function draw() { var i = 0, menu:TreeMenuScreen; - while (i < parent.length) { + while (i < parent.treeLength) { if ((menu = parent.tree[i++]) == null || !menu.active || !menu.exists) continue; - if (i == length || menu.persistentUpdate || menu.transitioning) menu.update(elapsed); + if (i == parent.treeLength || menu.persistentUpdate || menu.transitioning) menu.draw(); } - if (parent.lastMenu != null) parent.lastMenu.draw(); + i = parent.previousMenus.length; + while (i-- > 0) if (parent.previousMenus[i] != null) parent.previousMenus[i].draw(); } } \ No newline at end of file diff --git a/source/funkin/options/TreeMenuScreen.hx b/source/funkin/options/TreeMenuScreen.hx index 7fa6e19f..b03ab959 100644 --- a/source/funkin/options/TreeMenuScreen.hx +++ b/source/funkin/options/TreeMenuScreen.hx @@ -1,9 +1,11 @@ package funkin.options; +import flixel.group.FlxSpriteGroup; import flixel.util.FlxSignal; import funkin.backend.system.Controls; import funkin.backend.TurboControls; import funkin.options.TreeMenu.ITreeOption; +import funkin.options.type.Separator; class TreeMenuScreen extends FlxSpriteGroup { public var persistentUpdate:Bool = false; @@ -15,7 +17,6 @@ class TreeMenuScreen extends FlxSpriteGroup { public var transitioning:Bool = false; public var inputEnabled:Bool = false; public var curSelected:Int = 0; - public var itemHeight:Float = 120; public var name:String; public var desc:String; @@ -28,74 +29,97 @@ class TreeMenuScreen extends FlxSpriteGroup { private var rawDesc(default, set):String; function set_rawName(v:String) { - if (rawName == (rawName = v)) return v; - name = TU.exists(rawName) ? TU.translate(rawName) : rawName; + rawName = v; + name = TU.exists(v) ? TU.translate(v) : v; return v; } function set_rawDesc(v:String) { - if (rawDesc == (rawDesc = v)) return v; - desc = TU.exists(rawDesc) ? TU.translate(rawDesc) : rawDesc; + rawDesc = v; + desc = TU.exists(v) ? TU.translate(v) : v; return v; } public inline function getNameID(name):String return prefix + name + "-name"; public inline function getDescID(name):String return prefix + name + "-desc"; + public inline function getID(name):String return prefix + name; + public function translate(name:String, ?args:Array):String return TU.translate(getID(name), args); public var controls(get, never):Controls; inline function get_controls():Controls return PlayerSettings.solo.controls; - var leftTurboControl:TurboControls = new TurboControls([Control.LEFT]); - var rightTurboControl:TurboControls = new TurboControls([Control.RIGHT]); + var leftTurboControl:TurboControls = new TurboControls([Control.LEFT], 0.2, 1 / 30); + var rightTurboControl:TurboControls = new TurboControls([Control.RIGHT], 0.2, 1 / 30); var upTurboControl:TurboControls = new TurboControls([Control.UP]); var downTurboControl:TurboControls = new TurboControls([Control.DOWN]); - var turboBasics:Array; + var turboBasics:Array; var curOption:ITreeOption; - var _firstFrame:Bool = true; + var __firstFrame:Bool = true; - public function new(name:String, desc:String, ?prefix:String, ?options:Array) { + public function new(name:String, desc:String, ?prefix:String, ?objects:Array) { super(); - + this.prefix = prefix; rawName = name; rawDesc = desc; turboBasics = [leftTurboControl, rightTurboControl, upTurboControl, downTurboControl]; + + if (objects != null) for (object in objects) add(object); } public function reloadStrings() { - name = TU.exists(rawName) ? TU.translate(rawName) : rawName; - desc = TU.exists(rawDesc) ? TU.translate(rawDesc) : rawDesc; + rawName = rawName; + rawDesc = rawDesc; - for (object in members) if (object != null) object.reloadStrings(); + for (object in members) if (object != null && object is ITreeOption) cast(object, ITreeOption).reloadStrings(); } override function update(elapsed:Float) { super.update(elapsed); - if (_firstFrame) { - _firstFrame = false; - if (members[curSelected] is ITreeOption) (curOption = cast members[curSelected]:ITreeOption).selected = true; + if (__firstFrame) { + __firstFrame = false; + if (members[curSelected] is ITreeOption) (curOption = cast members[curSelected]).selected = true; + updateItems(true); + return; } if (inputEnabled) { for (basic in turboBasics) basic.update(elapsed); changeSelection((upTurboControl.activated ? -1 : 0) + (downTurboControl.activated ? 1 : 0) - FlxG.mouse.wheel); - if (i > 0 && curOption != null) { - if (controls.ACCEPT || FLxG.mouse.justPressed) curOption.select(); + if (length > 0 && curOption != null) { + if (controls.ACCEPT || (FlxG.mouse.justPressed && FlxG.mouse.overlaps(members[curSelected]))) curOption.select(); if (leftTurboControl.activated) curOption.changeSelection(-1); if (rightTurboControl.activated) curOption.changeSelection(1); } - if (controls.BACK || FlxG.mouse.justPressedRight) close(); + if (controls.BACK || (FlxG.mouse.justPressedRight && Main.timeSinceFocus > 0.3)) close(); + } + + updateItems(); + } + + public function updateItems(force = false) { + var r = force ? 1 : 0.25, initY = FlxG.height * 0.5; + var i = curSelected, y = initY, object:FlxSprite = null, itemHeight:Float = 0; + + inline function updateItem() { + object.y = CoolUtil.fpsLerp(object.y, y - (itemHeight = object.height) * 0.5, r); + object.x = x + 100 - Math.pow(Math.abs((object.y - (FlxG.height - itemHeight) * 0.5) / itemHeight / FlxG.height * FlxG.initialHeight), 1.6) * 15; } - var i:Int = 0, object:FlxSprite; while (i < length) if ((object = members[i++]) != null) { - var h = object.height; - object.y = CoolUtil.fpsLerp(object.y, y + (FlxG.camera.height - h) * 0.5 + (i - curSelected) * itemHeight, 0.25); - object.x = x - 50 + Math.abs(Math.cos((object.y + (FlxG.camera.height + h) * 0.5 - FlxG.camera.scroll.y) / (FlxG.camera.height * 1.25) * Math.PI)) * 150; + updateItem(); + y += itemHeight; + } + + y = initY; + i = curSelected; + while (i-- > 0) if ((object = members[i]) != null) { + y -= itemHeight; + updateItem(); } } @@ -103,7 +127,7 @@ class TreeMenuScreen extends FlxSpriteGroup { onClose.dispatch(); if (parent == null) return destroy(); - else parent.remove(this); + else parent.removeMenu(this); CoolUtil.playMenuSFX(CANCEL); } @@ -111,8 +135,12 @@ class TreeMenuScreen extends FlxSpriteGroup { public function changeSelection(change:Int, force:Bool = false) { if (length == 0 || (change == 0 && !force)) return; - curSelected = FlxMath.wrap(curSelected + change, 0, members.length - 1); - if (members[curSelected] is ITreeOption) (curOption = cast members[curSelected]:ITreeOption).selected = true; + var prevSelect = curSelected = FlxMath.wrap(curSelected + change, 0, members.length - 1); + while (members[curSelected] is Separator) + if ((curSelected = FlxMath.wrap(curSelected + (change > 0 ? 1 : -1), 0, members.length - 1)) == prevSelect) break; + + if (curOption != null) curOption.selected = false; + if (members[curSelected] is ITreeOption) (curOption = cast members[curSelected]).selected = true; updateMenuDesc(); CoolUtil.playMenuSFX(SCROLL); diff --git a/source/funkin/options/categories/AppearanceOptions.hx b/source/funkin/options/categories/AppearanceOptions.hx index 0131a73d..125509a5 100644 --- a/source/funkin/options/categories/AppearanceOptions.hx +++ b/source/funkin/options/categories/AppearanceOptions.hx @@ -1,51 +1,24 @@ package funkin.options.categories; class AppearanceOptions extends TreeMenuScreen { - public override function new() { + public function new() { super('optionsTree.appearance-name', 'optionsTree.appearance-desc', "AppearanceOptions."); - /* - add(new NumOption( - getName("framerate"), - getDesc("framerate"), - 30, // minimum - 240, // maximum - 10, // change - "framerate", // save name or smth - __changeFPS)); // callback - add(new Checkbox( - getName("antialiasing"), - getDesc("antialiasing"), - "antialiasing")); - add(new Checkbox( - getName("colorHealthBar"), - getDesc("colorHealthBar"), - "colorHealthBar")); - add(new Checkbox( - getName("week6PixelPerfect"), - getDesc("week6PixelPerfect"), - "week6PixelPerfect")); - add(new Checkbox( - getName("gameplayShaders"), - getDesc("gameplayShaders"), - "gameplayShaders")); - add(new Checkbox( - getName("flashingMenu"), - getDesc("flashingMenu"), - "flashingMenu")); - add(new Checkbox( - getName("lowMemoryMode"), - getDesc("lowMemoryMode"), - "lowMemoryMode")); - #if sys - if (!Main.forceGPUOnlyBitmapsOff) { - add(new Checkbox( - getName("gpuOnlyBitmaps"), - getDesc("gpuOnlyBitmaps"), - "gpuOnlyBitmaps")); - } - #end - */ + add(new NumOption(getNameID('framerate'), getDescID('framerate'), + 30, 240, 1, + 'framerate', __changeFPS + )); + add(new Checkbox(getNameID('flashingMenu'), getDescID('flashingMenu'), 'flashingMenu')); + add(new ArrayOption(getNameID('quality'), getDescID('quality'), + [0, 1, 2], [getID('quality-low'), getID('quality-high'), getID('quality-custom')], + 'quality', __changeQuality, null + )); + add(new Checkbox(getNameID('colorHealthBar'), getDescID('colorHealthBar'), 'colorHealthBar')); + add(new Checkbox(getNameID('week6PixelPerfect'), getDescID('week6PixelPerfect'), 'week6PixelPerfect')); + + add(new Separator()); + add(new TextOption('optionsMenu.advanced', 'optionsTree.appearance.advanced-desc', ' >', () -> + parent.addMenu(new AdvancedAppearanceOptions()))); } private function __changeFPS(value:Float) { @@ -53,4 +26,30 @@ class AppearanceOptions extends TreeMenuScreen { if (FlxG.updateFramerate < framerate) FlxG.drawFramerate = FlxG.updateFramerate = framerate; else FlxG.updateFramerate = FlxG.drawFramerate = framerate; } + + private function __changeQuality(value:Dynamic) { + var antialiasing = value == 0 ? false : (value == 1 ? true : Options.antialiasing); + FlxG.game.stage.quality = (FlxG.enableAntialiasing = antialiasing) ? BEST : LOW; + } +} + +class AdvancedAppearanceOptions extends TreeMenuScreen { + public function new() { + super('optionsMenu.advanced', 'optionsTree.appearance.advanced-desc', "AppearanceOptions.Advanced."); + + for (option in [ + new Checkbox(getNameID('antialiasing'), getDescID('antialiasing'), 'antialiasing', __changeAntialiasing), + new Checkbox(getNameID('lowMemoryMode'), getDescID('lowMemoryMode'), 'lowMemoryMode'), + new Checkbox(getNameID('gameplayShaders'), getDescID('gameplayShaders'), 'gameplayShaders') + ]) { + add(option); + if (option.locked = Options.quality != 2) option.rawDesc = 'AppearanceOptions.quality-optionDisabled-desc'; + } + + add(new Checkbox(getNameID('gpuOnlyBitmaps'), getDescID('gpuOnlyBitmaps'), 'gpuOnlyBitmaps')); + } + + private function __changeAntialiasing() { + FlxG.game.stage.quality = (FlxG.enableAntialiasing = Options.antialiasing) ? BEST : LOW; + } } \ No newline at end of file diff --git a/source/funkin/options/categories/GameplayOptions.hx b/source/funkin/options/categories/GameplayOptions.hx index 3064a588..0abcbae1 100644 --- a/source/funkin/options/categories/GameplayOptions.hx +++ b/source/funkin/options/categories/GameplayOptions.hx @@ -3,96 +3,8 @@ package funkin.options.categories; import flixel.util.FlxTimer; import funkin.backend.system.Conductor; -class GameplayOptions extends OptionsScreen { - var __metronome = FlxG.sound.load(Paths.sound('editors/charter/metronome')); - - var offsetSetting:NumOption; - - public override function new(title:String, desc:String) { - super(title, desc, "GameplayOptions."); - add(new Checkbox( - getName("downscroll"), - getDesc("downscroll"), - "downscroll")); - add(new Checkbox( - getName("ghostTapping"), - getDesc("ghostTapping"), - "ghostTapping")); - add(new Checkbox( - getName("naughtyness"), - getDesc("naughtyness"), - "naughtyness")); - add(new Checkbox( - getName("camZoomOnBeat"), - getDesc("camZoomOnBeat"), - "camZoomOnBeat")); - add(new Checkbox( - getName("autoPause"), - getDesc("autoPause"), - "autoPause")); - /*add(new MeterOption( - getName("volumeSFX"), - getDesc("volumeSFX"), - 0, // minimum - 1, // maximum - 0.1, // change - "volumeSFX"));*/ - add(offsetSetting = new NumOption( - getName("songOffset"), - getDesc("songOffset"), - -999, // minimum - 999, // maximum - 1, // change - "songOffset", // save name or smth - __changeOffset)); // callback - add(new TextOption('optionsMenu.advanced', 'optionsTree.gameplay.advanced-desc', ' >', () -> - parent.add(new AdvancedGameplayOptions('optionsMenu.advanced', 'optionsTree.gameplay.advanced-desc')))); - } - - private function __changeOffset(offset) - Conductor.songOffset = offset; - - var __lastBeat:Int = 0; - var __lastSongBeat:Int = 0; - - override function update(elapsed) { - super.update(elapsed); - FlxG.camera.zoom = CoolUtil.fpsLerp(FlxG.camera.zoom, 1, 0.04); - - if (offsetSetting.selected) { - FlxG.sound.music.volume = 0.5; - if (__lastBeat != Conductor.curBeat) { - FlxG.camera.zoom += 0.03; - __lastBeat = Conductor.curBeat; - } - - var beat = Math.floor(Conductor.getTimeInBeats(FlxG.sound.music.time)); - if (__lastSongBeat != beat) { - __metronome.replay(); - __lastSongBeat = beat; - } - } - else - FlxG.sound.music.volume = 1; - } - - override function close() { - FlxG.camera.zoom = 1; - FlxG.sound.music.volume = 1; - super.close(); - } +class GameplayOptions extends TreeMenuScreen { } class AdvancedGameplayOptions extends OptionsScreen { - public override function new(title:String, desc:String) { - super(title, desc, "GameplayOptions.Advanced."); - add(new Checkbox( - getName("streamedMusic"), - getDesc("streamedMusic"), - "streamedMusic")); - add(new Checkbox( - getName("streamedVocals"), - getDesc("streamedVocals"), - "streamedVocals")); - } } diff --git a/source/funkin/options/categories/LanguageOptions.hx b/source/funkin/options/categories/LanguageOptions.hx index b3e64433..d166643e 100644 --- a/source/funkin/options/categories/LanguageOptions.hx +++ b/source/funkin/options/categories/LanguageOptions.hx @@ -33,7 +33,7 @@ class LanguageRadio extends RadioButton { } } -class LanguageOptions extends OptionsScreen { +class LanguageOptions extends TreeMenuScreen { public override function new(title:String, desc:String) { super(title, desc, "LanguageOptions."); diff --git a/source/funkin/options/categories/MiscOptions.hx b/source/funkin/options/categories/MiscOptions.hx index 95b55aef..ffa8eadd 100644 --- a/source/funkin/options/categories/MiscOptions.hx +++ b/source/funkin/options/categories/MiscOptions.hx @@ -1,35 +1,4 @@ package funkin.options.categories; -class MiscOptions extends OptionsScreen { - public override function new(title:String, desc:String) { - super(title, desc, "MiscOptions."); - add(new Checkbox( - getName("devMode"), - getDesc("devMode"), - "devMode")); - #if UPDATE_CHECKING - add(new Checkbox( - getName("betaUpdates"), - getDesc("betaUpdates"), - "betaUpdates")); - add(new TextOption( - getName("checkForUpdates"), - getDesc("checkForUpdates"), - function() { - var report = funkin.backend.system.updating.UpdateUtil.checkForUpdates(); - if (report.newUpdate) { - FlxG.switchState(new funkin.backend.system.updating.UpdateAvailableScreen(report)); - } else { - CoolUtil.playMenuSFX(CANCEL); - updateDescText(TU.translate(prefix + "checkForUpdates-noUpdateFound")); - } - })); - #end - add(new TextOption( - getName("resetSaveData"), - getDesc("resetSaveData"), - function() { - // TODO: SAVE DATA RESETTING - })); - } +class MiscOptions extends TreeMenuScreen { } diff --git a/source/funkin/options/type/ArrayOption.hx b/source/funkin/options/type/ArrayOption.hx index 81184aeb..b143e16b 100644 --- a/source/funkin/options/type/ArrayOption.hx +++ b/source/funkin/options/type/ArrayOption.hx @@ -1,7 +1,7 @@ package funkin.options.type; -class ArrayOption extends OptionType { - public var selectCallback:String->Void; +class ArrayOption extends TextOption { + public var changedCallback:String->Void; public var options:Array; public var displayOptions:Array; @@ -10,36 +10,32 @@ class ArrayOption extends OptionType { public var parent:Dynamic; public var optionName:String; - var __text:Alphabet; var __selectionText:Alphabet; - public function new(text:String, desc:String, options:Array, displayOptions:Array, ?optionName:String, ?selectCallback:String->Void = null, ?parent:Dynamic) { - super(text, desc); - this.selectCallback = selectCallback; + override function set_text(v:String) { + super.set_text(v); + __selectionText.x = __text.x + __text.width + 12; + return v; + } + + public function new(text:String, desc:String, options:Array, displayOptions:Array, ?optionName:String, ?changedCallback:Dynamic->Void = null, ?parent:Dynamic) { + this.changedCallback = changedCallback; this.displayOptions = displayOptions; this.options = options; - this.parent = parent = parent != null ? parent : Options; this.optionName = optionName; + this.parent = parent = parent != null ? parent : Options; var fieldValue = Reflect.field(parent, optionName); if (fieldValue != null) currentSelection = CoolUtil.maxInt(0, options.indexOf(fieldValue)); - - add(__text = new Alphabet(20, 0, text, 'bold')); - add(__selectionText = new Alphabet(__text.x + __text.width + 12, 0, formatTextOption(), 'bold')); + + __selectionText = new Alphabet(0, 20, formatTextOption(), 'bold'); + super(text, desc); + add(__selectionText); } override function reloadStrings() { - super.reloadStrings(); - __selectiontext.x = __text.x + __text.width + 12; - __selectiontext.text = formatTextOption(); - } - - override function changeSelection(change:Int) { - currentSelection = FlxMath.wrap(currentSelection + change, 0, options.length - 1); __selectionText.text = formatTextOption(); - CoolUtil.playMenuSFX(SCROLL); - - if (selectCallback != null) selectCallback(options[currentSelection]); + super.reloadStrings(); } function formatTextOption() { @@ -54,4 +50,16 @@ class ArrayOption extends OptionType { return s; } + + override function changeSelection(change:Int) { + if (locked) return; + currentSelection = FlxMath.wrap(currentSelection + change, 0, options.length - 1); + __selectionText.text = formatTextOption(); + CoolUtil.playMenuSFX(SCROLL); + + if (optionName != null) Reflect.setField(parent, optionName, options[currentSelection]); + if (changedCallback != null) changedCallback(options[currentSelection]); + } + + override function select() {} } \ No newline at end of file diff --git a/source/funkin/options/type/Checkbox.hx b/source/funkin/options/type/Checkbox.hx index 77947bd7..5ac65391 100644 --- a/source/funkin/options/type/Checkbox.hx +++ b/source/funkin/options/type/Checkbox.hx @@ -10,25 +10,21 @@ class Checkbox extends TextOption { public var checked(default, set):Bool; public var parent:Dynamic; - public var optionName:String; private var offsets:Map = [ "unchecked" => FlxPoint.get(0, -70), - "checked" => FlxPoint.get(23, -30), + "checked" => FlxPoint.get(23, -32), "unchecking" => FlxPoint.get(25, -12), - "checking" => FlxPoint.get(35, 31) + "checking" => FlxPoint.get(35, 29) ]; - public function new(text:String, desc:String, optionName:String, ?parent:Dynamic) { - super(text, desc, null); + public function new(text:String, desc:String, optionName:String, ?selectCallback:Void->Void = null, ?parent:Dynamic) { + super(text, desc); + this.optionName = optionName; + this.parent = parent = parent != null ? parent : Options; - if (parent == null) - parent = Options; - - this.parent = parent; - - checkbox = new FlxSprite(10, -40); + add(checkbox = new FlxSprite(10, -30)); checkbox.frames = Paths.getFrames('menus/options/checkboxThingie'); checkbox.animation.addByPrefix("unchecked", "Check Box unselected0", 24); checkbox.animation.addByPrefix("checked", "Check Box Selected Static0", 24); @@ -37,61 +33,52 @@ class Checkbox extends TextOption { checkbox.antialiasing = true; checkbox.scale.set(0.75, 0.75); checkbox.updateHitbox(); - add(checkbox); - this.optionName = optionName; - if(optionName != null) { - checked = Reflect.field(parent, optionName); - } else { - checked = false; - } + __text.x = 100; + + var fieldValue = Reflect.field(parent, optionName); + checked = fieldValue != null && fieldValue; } public var firstFrame:Bool = true; public override function update(elapsed:Float) { - if(checkbox.animation.curAnim == null) { - checkbox.animation.play(checked ? "checked" : "unchecked", true); - } + if (checkbox.animation.curAnim == null) checkbox.animation.play(checked ? "checked" : "unchecked", true); super.update(elapsed); - switch(checkbox.animation.curAnim.name) { - case "unchecking": - if(checkbox.animation.curAnim.finished) { - checkbox.animation.play("unchecked", true); - } - case "checking": - if(checkbox.animation.curAnim.finished) { - checkbox.animation.play("checked", true); - } + + if (checkbox.animation.curAnim.finished) switch(checkbox.animation.curAnim.name) { + case "unchecking": checkbox.animation.play("unchecked", true); + case "checking": checkbox.animation.play("checked", true); } firstFrame = false; } override function draw() { - if(checkbox.animation.curAnim != null) { + if (checkbox.animation.curAnim != null) { var offset = offsets[checkbox.animation.curAnim.name]; - if (offset != null) - checkbox.frameOffset.set(offset.x, offset.y); + if (offset != null) checkbox.frameOffset.set(offset.x, offset.y); } super.draw(); } function set_checked(v:Bool) { - if(checked != v) { + if (checked != v) { checked = v; - if(!firstFrame) { - checkbox.animation.play(checked ? "checking" : "unchecking", true); - } + if (!firstFrame) checkbox.animation.play(checked ? "checking" : "unchecking", true); } return v; } - public override function onSelect() { + public override function select() { + if (locked) return; checked = !checked; - if(optionName != null) { - Reflect.setField(parent, optionName, checked); - } + if (optionName != null) Reflect.setField(parent, optionName, checked); + + if (checked) CoolUtil.playMenuSFX(CHECKED); + else CoolUtil.playMenuSFX(UNCHECKED); + + if (selectCallback != null) selectCallback(); } public override function destroy() { diff --git a/source/funkin/options/type/MeterOption.hx b/source/funkin/options/type/MeterOption.hx index 7902e09e..831a4adc 100644 --- a/source/funkin/options/type/MeterOption.hx +++ b/source/funkin/options/type/MeterOption.hx @@ -20,11 +20,7 @@ class MeterOption extends OptionType { public var barWidth(default, set):Int; - private var rawText(default, set):String; - - public var text(get, set):String; - private function get_text() {return __text.text;} - private function set_text(v:String) {return __text.text = v;} + override function set_text(v:String) return __text.text = text = v; private var __text:Alphabet; var optionName:String; @@ -43,7 +39,7 @@ class MeterOption extends OptionType { public function new(text:String, desc:String, min:Float, max:Float, changeVal:Float, optionName:String, barWidth:Int = 520, ?selectCallback:Float->Void = null, ?parent:Dynamic) { - super(desc); + super(text, desc); this.selectCallback = selectCallback; this.min = min; @@ -162,12 +158,6 @@ class MeterOption extends OptionType { x += temp * barScale; } - function set_rawText(v:String) { - rawText = v; - __text.text = TU.exists(rawText) ? TU.translate(rawText) : rawText; - return v; - } - override function draw() { lastX = x; @@ -196,7 +186,7 @@ class MeterOption extends OptionType { this.rawText = rawText; } - override function onChangeSelection(change:Float) { + override function changeSelection(change:Float) { if (currentSelection <= min && change == -1 || currentSelection >= max && change == 1) return; currentSelection = FlxMath.roundDecimal(currentSelection + (change * changeVal), FlxMath.getDecimals(changeVal)); diff --git a/source/funkin/options/type/NumOption.hx b/source/funkin/options/type/NumOption.hx index e570e197..70848275 100644 --- a/source/funkin/options/type/NumOption.hx +++ b/source/funkin/options/type/NumOption.hx @@ -1,72 +1,54 @@ package funkin.options.type; -import flixel.effects.FlxFlicker; - /** * Option type that allows stepping through a number. **/ -class NumOption extends OptionType { - public var selectCallback:Float->Void; - - private var __text:Alphabet; - private var __number:Alphabet; +class NumOption extends TextOption { + public var changedCallback:Float->Void; public var min:Float; public var max:Float; + public var step:Float; public var currentSelection:Float; - public var changeVal:Float; - - var optionName:String; public var parent:Dynamic; + public var optionName:String; - private var rawText(default, set):String; + var __number:Alphabet; - public var text(get, set):String; - private function get_text() {return __text.text;} - private function set_text(v:String) {return __text.text = v;} - - public function new(text:String, desc:String, min:Float, max:Float, changeVal:Float, optionName:String, ?selectCallback:Float->Void = null, ?parent:Dynamic) { - super(desc); - this.selectCallback = selectCallback; - this.min = min; - this.max = max; - if (parent == null) - parent = Options; - - this.parent = parent; - - if(Reflect.field(parent, optionName) != null) - this.currentSelection = Reflect.field(parent, optionName); - this.changeVal = changeVal; - this.optionName = optionName; - - add(__text = new Alphabet(20, 20, "", "bold")); - add(__number = new Alphabet(0, 20, ': $currentSelection', "bold")); - rawText = text; - } - - override function reloadStrings() { - super.reloadStrings(); - this.rawText = rawText; - } - - function set_rawText(v:String) { - rawText = v; - __text.text = TU.exists(rawText) ? TU.translate(rawText) : rawText; + override function set_text(v:String) { + super.set_text(v); __number.x = __text.x + __text.width + 12; return v; } - override function onChangeSelection(change:Float):Void - { - if(currentSelection <= min && change == -1 || currentSelection >= max && change == 1) return; - currentSelection = FlxMath.roundDecimal(currentSelection + (change * changeVal), FlxMath.getDecimals(changeVal)); + public function new(text:String, desc:String, min:Float, max:Float, step:Float, optionName:String, ?changedCallback:Float->Void = null, ?parent:Dynamic) { + this.changedCallback = changedCallback; + this.min = min; + this.max = max; + this.step = step; + this.optionName = optionName; + this.parent = parent = parent != null ? parent : Options; + + var fieldValue = Reflect.field(parent, optionName); + if (fieldValue != null) currentSelection = fieldValue; + + __number = new Alphabet(0, 20, ': $currentSelection', 'bold'); + super(text, desc); + add(__number); + } + + override function changeSelection(change:Int):Void { + if (locked) return; + if (currentSelection == (currentSelection = FlxMath.bound(currentSelection + change, min, max))) return; __number.text = ': $currentSelection'; Reflect.setField(parent, optionName, currentSelection); - if(selectCallback != null) - selectCallback(currentSelection); + if (changedCallback != null) changedCallback(currentSelection); + + CoolUtil.playMenuSFX(SCROLL); } + + override function select() {} } \ No newline at end of file diff --git a/source/funkin/options/type/OptionType.hx b/source/funkin/options/type/OptionType.hx index 7429a64a..41f4302c 100644 --- a/source/funkin/options/type/OptionType.hx +++ b/source/funkin/options/type/OptionType.hx @@ -10,15 +10,25 @@ import funkin.options.TreeMenu.ITreeOption; **/ class OptionType extends FlxSpriteGroup implements ITreeOption { public var selected:Bool = false; + public var locked(default, set):Bool; public var text(default, set):String; public var rawText(default, set):String; public var desc:String; public var rawDesc(default, set):String; + public var itemHeight:Float = 120; + public function new(text:String, desc:String) { super(); - reloadStrings(); + rawText = text; + rawDesc = desc; + } + + function set_locked(v:Bool) { + if (locked == (locked = v)) return v; + color = locked ? 0xFF7F7F7F : 0xFFFFFFFF; + return v; } function set_text(v:String) return text = v; @@ -46,4 +56,6 @@ class OptionType extends FlxSpriteGroup implements ITreeOption { public function changeSelection(change:Int) {} public function select() {} + + override function get_height() return itemHeight; } \ No newline at end of file diff --git a/source/funkin/options/type/RadioButton.hx b/source/funkin/options/type/RadioButton.hx index d43240ac..ac48eafa 100644 --- a/source/funkin/options/type/RadioButton.hx +++ b/source/funkin/options/type/RadioButton.hx @@ -101,7 +101,9 @@ class RadioButton extends TextOption { return v; } - public override function onSelect() { + public override function select() { + if (locked) return; + checked = true; if(checked) { onSet(value); diff --git a/source/funkin/options/type/Separator.hx b/source/funkin/options/type/Separator.hx new file mode 100644 index 00000000..716c3576 --- /dev/null +++ b/source/funkin/options/type/Separator.hx @@ -0,0 +1,30 @@ +package funkin.options.type; + +import flixel.math.FlxPoint; +import flixel.util.FlxDestroyUtil; +import flixel.FlxBasic; + +class Separator extends FlxSprite { + var separatorHeight:Float; + public function new(height = 67) { + super(); + separatorHeight = height; + } + + override function initVars() { + flixelType = OBJECT; + + offset = FlxPoint.get(); + origin = FlxPoint.get(); + scale = FlxPoint.get(1, 1); + scrollFactor = FlxPoint.get(1, 1); + + initMotionVars(); + } + + override function update(elapsed:Float) {} + override function draw() {} + + override function get_height():Float return separatorHeight; + override function get_width():Float return 600; +} \ No newline at end of file diff --git a/source/funkin/options/type/SliderOption.hx b/source/funkin/options/type/SliderOption.hx index 37f4f4fc..5831a47d 100644 --- a/source/funkin/options/type/SliderOption.hx +++ b/source/funkin/options/type/SliderOption.hx @@ -13,10 +13,7 @@ class SliderOption extends OptionType { //public var barWidth(get, set):Int; - public var text(get, set):String; - private function get_text() {return __text.text;} - private function set_text(v:String) {return __text.text = v;} - private var rawText(default, set):String; + override function set_text(v:String) return __text.text = text = v; var __text:Alphabet; var optionName:String; @@ -24,12 +21,6 @@ class SliderOption extends OptionType { public function new(text:String, desc:String, min:Float, max:Float, segmentVal:Float, optionName:String, barWidth:Int = 520, ?selectCallback:Float->Void = null, ?parent:Dynamic) { - super(desc); - } - - function set_rawText(v:String) { - rawText = v; - __text.text = TU.exists(rawText) ? TU.translate(rawText) : rawText; - return v; + super(text, desc); } } \ No newline at end of file diff --git a/source/funkin/options/type/TextOption.hx b/source/funkin/options/type/TextOption.hx index 2d2b5187..74ccfc2b 100644 --- a/source/funkin/options/type/TextOption.hx +++ b/source/funkin/options/type/TextOption.hx @@ -6,46 +6,29 @@ import flixel.effects.FlxFlicker; * Option type that has text. **/ class TextOption extends OptionType { + public var suffix:String; public var selectCallback:Void->Void; - private var __text:Alphabet; - private var rawText(default, set):String; - - public var text(get, set):String; - private function get_text() {return __text.text;} - private function set_text(v:String) {return __text.text = v;} - - /** - * If you change this afterwards you will need to call `reloadStrings()`, or manually set rawText to rawText. - **/ - public var suffix:String; + var __text:Alphabet; + override function set_text(v:String) { + __text.text = v + suffix; + return text = v; + } public function new(text:String, desc:String, ?suffix:String = "", ?selectCallback:Void->Void = null) { - super(desc); - this.selectCallback = selectCallback; - add(__text = new Alphabet(100, 20, "", "bold")); this.suffix = suffix; - rawText = text; + this.selectCallback = selectCallback; + + __text = new Alphabet(20, 20, "", "bold"); + + super(text, desc); + add(__text); } - override function reloadStrings() { - super.reloadStrings(); - this.rawText = rawText; - } - - function set_rawText(v:String) { - rawText = v; - __text.text = (TU.exists(rawText) ? TU.translate(rawText) : rawText) + suffix; - return v; - } - - public override function draw() { - super.draw(); - } - public override function onSelect() { - super.onSelect(); + override function select() { + if (locked) return; CoolUtil.playMenuSFX(CONFIRM); FlxFlicker.flicker(this, 1, Options.flashingMenu ? 0.06 : 0.15, true, false); - selectCallback(); + if (selectCallback != null) selectCallback(); } } \ No newline at end of file