Options Rewrite WIP Appearance Restructure
This commit is contained in:
@@ -12,10 +12,11 @@
|
||||
|
||||
<str id="optionsTree.gameplay-name">Gameplay</str>
|
||||
<str id="optionsTree.gameplay-desc">Change Gameplay options such as Downscroll, Scroll Speed, Naughtyness...</str>
|
||||
<str id="optionsTree.gameplay.advanced-desc">Change more advanced options such as Window Size, Streaming Audio...</str>
|
||||
<str id="optionsTree.gameplay.advanced-desc">Change more advanced options such as Hit Window Size, Streaming Audio...</str>
|
||||
|
||||
<str id="optionsTree.appearance-name">Appearance</str>
|
||||
<str id="optionsTree.appearance-desc">Change Appearance options such as Flashing menus...</str>
|
||||
<str id="optionsTree.appearance.advanced-desc">Change more advanced options such as VRAM-Only Sprites, Antialiasing, Shaders</str>
|
||||
|
||||
<str id="optionsTree.language-name">Language</str>
|
||||
<str id="optionsTree.language-desc">Change the language that the engine uses.</str>
|
||||
@@ -62,8 +63,15 @@
|
||||
<str id="framerate-name">Framerate</str>
|
||||
<str id="framerate-desc">Pretty self explanatory, isn't it?</str>
|
||||
|
||||
<str id="antialiasing-name">Antialiasing</str>
|
||||
<str id="antialiasing-desc">If unchecked, will disable antialiasing on every sprite. Can boost performances at the cost of sharper, more pixely sprites.</str>
|
||||
<str id="flashingMenu-name">Flashing Menu</str>
|
||||
<str id="flashingMenu-desc">If unchecked, will disable menu flashing when you select an option in the Main Menu, and other flashes will be slower.</str>
|
||||
|
||||
<str id="quality-name">Quality</str>
|
||||
<str id="quality-desc">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.</str>
|
||||
<str id="quality-low">LOW</str>
|
||||
<str id="quality-high">HIGH</str>
|
||||
<str id="quality-custom">CUSTOM</str>
|
||||
<str id="quality-optionDisabled-desc">Following option is locked for Quality Option, to unlock set Quality to CUSTOM</str>
|
||||
|
||||
<str id="colorHealthBar-name">Colored Healthbar</str>
|
||||
<str id="colorHealthBar-desc">If unchecked, the game will use the original red/green health bar from the week 6 fnf game.</str>
|
||||
@@ -71,17 +79,19 @@
|
||||
<str id="week6PixelPerfect-name">Pixel Perfect Effect</str>
|
||||
<str id="week6PixelPerfect-desc">If checked, Week 6 will have a pixel perfect effect to it enabled, aligning every pixel on the screen.</str>
|
||||
|
||||
<str id="gameplayShaders-name">Gameplay Shaders</str>
|
||||
<str id="gameplayShaders-desc">If unchecked, gameplay shaders (visual effects like Thorns's Chromatic Aberration) wont be loaded; this may be helpful on weak devices.</str>
|
||||
<group name="AppearanceOptionsAdvanced" prefix="Advanced.">
|
||||
<str id="antialiasing-name">Antialiasing</str>
|
||||
<str id="antialiasing-desc">If unchecked, will disable antialiasing on every sprite. Can boost performances at the cost of sharper, more pixely sprites.</str>
|
||||
|
||||
<str id="flashingMenu-name">Flashing Menu</str>
|
||||
<str id="flashingMenu-desc">If unchecked, will disable menu flashing when you select an option in the Main Menu, and other flashes will be slower.</str>
|
||||
<str id="lowMemoryMode-name">Low Memory Mode</str>
|
||||
<str id="lowMemoryMode-desc">If checked, will disable certain background elements in stages to reduce memory usage.</str>
|
||||
|
||||
<str id="lowMemoryMode-name">Low Memory Mode</str>
|
||||
<str id="lowMemoryMode-desc">If checked, will disable certain background elements in stages to reduce memory usage.</str>
|
||||
<str id="gameplayShaders-name">Gameplay Shaders</str>
|
||||
<str id="gameplayShaders-desc">If unchecked, gameplay shaders (visual effects like Thorns's Chromatic Aberration) wont be loaded; this may be helpful on weak devices.</str>
|
||||
|
||||
<str id="gpuOnlyBitmaps-name">VRAM-Only Sprites</str>
|
||||
<str id="gpuOnlyBitmaps-desc">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.</str>
|
||||
<str id="gpuOnlyBitmaps-name">VRAM-Only Sprites</str>
|
||||
<str id="gpuOnlyBitmaps-desc">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.</str>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="GameplayOptions" prefix="GameplayOptions.">
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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<FlxTextFormatMarkerPair> = [];
|
||||
|
||||
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<CreditsGitHubContributor> = [];
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -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<OptionType> = [];
|
||||
|
||||
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<OptionType> {
|
||||
var credsMenus:Array<OptionType> = [];
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package funkin.menus.ui;
|
||||
|
||||
class Slider extends FlxSprite {
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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<OptionsScreen, Class<OptionsScreen>, (name:String, desc:String) -> OptionsScreen>;
|
||||
var ?state:OneOfThree<TreeMenuScreen, Class<TreeMenuScreen>, (name:String, desc:String) -> TreeMenuScreen>;
|
||||
var ?substate:OneOfThree<MusicBeatSubstate, Class<MusicBeatSubstate>, (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<TreeMenuScreen>
|
||||
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<TreeMenuScreen>
|
||||
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<OptionType> {
|
||||
var options:Array<OptionType> = [];
|
||||
|
||||
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<Dynamic> = [];
|
||||
var optionDisplayOptions:Array<String> = [];
|
||||
|
||||
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;
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
// REMOVE THIS WHEN COMPLETE
|
||||
|
||||
package funkin.options;
|
||||
|
||||
import funkin.options.type.OptionType;
|
||||
@@ -92,13 +94,13 @@ class OptionsScreen extends FlxTypedSpriteGroup<OptionType> {
|
||||
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();
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
// REMOVE THIS WHEN COMPLETE
|
||||
|
||||
package funkin.options;
|
||||
|
||||
class OptionsTree extends FlxTypedGroup<OptionsScreen> {
|
||||
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) {
|
||||
}
|
||||
}
|
||||
@@ -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:FlxTypedSignal<TreeMenuScreen->Void> = new FlxTypedSignal();
|
||||
public var onMenuChanged:FlxTypedSignal<TreeMenuScreen->Void> = new FlxTypedSignal();
|
||||
|
||||
public var tree(default, null):Array<TreeMenuScreen>;
|
||||
public var length(default, null):Int = 0;
|
||||
public var lastMenu:Null<TreeMenuScreen>;
|
||||
public var tree(default, null):Array<TreeMenuScreen> = [];
|
||||
public var treeLength(default, null):Int = 0;
|
||||
public var previousMenus:Array<TreeMenuScreen> = [];
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -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<Dynamic>):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<TurboBasics>;
|
||||
var turboBasics:Array<TurboBasic>;
|
||||
|
||||
var curOption:ITreeOption;
|
||||
var _firstFrame:Bool = true;
|
||||
var __firstFrame:Bool = true;
|
||||
|
||||
public function new(name:String, desc:String, ?prefix:String, ?options:Array<OptionType>) {
|
||||
public function new(name:String, desc:String, ?prefix:String, ?objects:Array<FlxSprite>) {
|
||||
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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.");
|
||||
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@@ -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<Dynamic>;
|
||||
public var displayOptions:Array<String>;
|
||||
@@ -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<Dynamic>, displayOptions:Array<String>, ?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<Dynamic>, displayOptions:Array<String>, ?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() {}
|
||||
}
|
||||
@@ -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<String, FlxPoint> = [
|
||||
"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() {
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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() {}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user