1
0
Fork 0
mirror of https://github.com/ninjamuffin99/Funkin.git synced 2025-09-01 03:15:53 +00:00
Funkin/source/funkin/ui/options/OptionsState.hx
2025-08-13 05:35:33 +08:00

325 lines
8.6 KiB
Haxe

package funkin.ui.options;
import funkin.ui.Page.PageName;
import funkin.ui.transition.LoadingState;
import funkin.ui.TextMenuList;
import funkin.ui.TextMenuList.TextMenuItem;
import flixel.math.FlxPoint;
import funkin.ui.TextMenuList;
import funkin.ui.TextMenuList.TextMenuItem;
import flixel.FlxSprite;
import flixel.FlxObject;
import flixel.FlxSubState;
import flixel.group.FlxGroup;
import flixel.util.FlxSignal;
import funkin.audio.FunkinSound;
import funkin.ui.mainmenu.MainMenuState;
import funkin.ui.MusicBeatState;
import funkin.graphics.shaders.HSVShader;
import funkin.input.Controls;
#if FEATURE_NEWGROUNDS
import funkin.api.newgrounds.NewgroundsClient;
#end
#if mobile
import funkin.util.TouchUtil;
import funkin.mobile.ui.FunkinBackButton;
import funkin.mobile.input.ControlsHandler;
import funkin.mobile.ui.options.ControlsSchemeMenu;
#end
#if FEATURE_MOBILE_IAP
import funkin.mobile.util.InAppPurchasesUtil;
#end
import flixel.util.FlxColor;
/**
* The main options menu
* It mainly is controlled via the "optionsCodex" object,
* which handles paging and going to the different submenus
*/
class OptionsState extends MusicBeatState
{
/**
* Instance of the OptionsState
*/
public static var instance:OptionsState;
var optionsCodex:Codex<OptionsMenuPageName>;
public var drumsBG:FunkinSound;
public static var rememberedSelectedIndex:Int = 0;
override function create():Void
{
instance = this;
persistentUpdate = true;
drumsBG = FunkinSound.load(Paths.music('offsetsLoop/drumsLoop'), 0, true, false, false, false);
var menuBG = new FlxSprite().loadGraphic(Paths.image('menuBG'));
var hsv = new HSVShader(-0.6, 0.9, 3.6);
menuBG.shader = hsv;
menuBG.setGraphicSize(Std.int(FlxG.width * 1.1));
menuBG.updateHitbox();
menuBG.screenCenter();
menuBG.scrollFactor.set(0, 0);
add(menuBG);
optionsCodex = new Codex<OptionsMenuPageName>(Options);
add(optionsCodex);
var saveData:SaveDataMenu = optionsCodex.addPage(SaveData, new SaveDataMenu());
var options:OptionsMenu = optionsCodex.addPage(Options, new OptionsMenu(saveData));
var preferences:PreferencesMenu = optionsCodex.addPage(Preferences, new PreferencesMenu());
var controls:ControlsMenu = optionsCodex.addPage(Controls, new ControlsMenu());
#if FEATURE_LAG_ADJUSTMENT
var offsets:OffsetMenu = optionsCodex.addPage(Offsets, new OffsetMenu());
#end
if (options.hasMultipleOptions())
{
options.onExit.add(exitToMainMenu);
controls.onExit.add(exitControls);
preferences.onExit.add(optionsCodex.switchPage.bind(Options));
#if FEATURE_LAG_ADJUSTMENT
offsets.onExit.add(exitOffsets);
#end
saveData.onExit.add(optionsCodex.switchPage.bind(Options));
}
else
{
// No need to show Options page
#if mobile
preferences.onExit.add(exitToMainMenu);
optionsCodex.setPage(Preferences);
#else
controls.onExit.add(exitToMainMenu);
optionsCodex.setPage(Controls);
#end
}
super.create();
#if mobile
addHitbox();
hitbox.visible = false;
#end
}
function exitOffsets():Void
{
if (drumsBG.volume > 0)
{
drumsBG.fadeOut(0.5, 0);
}
FlxG.sound.music.fadeOut(0.5, 0, function(tw) {
FunkinSound.playMusic('freakyMenu',
{
startingVolume: 0,
overrideExisting: true,
restartTrack: true,
persist: true
});
FlxG.sound.music.fadeIn(0.5, 1);
});
optionsCodex.switchPage(Options);
}
function exitControls():Void
{
// Apply any changes to the controls.
PlayerSettings.reset();
PlayerSettings.init();
optionsCodex.switchPage(Options);
}
function exitToMainMenu()
{
optionsCodex.currentPage.enabled = false;
// TODO: Animate this transition?
FlxG.keys.enabled = false;
FlxG.switchState(() -> new MainMenuState());
}
}
/**
* Our default Page when we enter the OptionsState, a bit of the root
*/
class OptionsMenu extends Page<OptionsMenuPageName>
{
var items:TextMenuList;
#if FEATURE_TOUCH_CONTROLS
var backButton:FunkinBackButton;
var goingBack:Bool = false;
#end
/**
* Camera focus point
*/
var camFocusPoint:FlxObject;
final CAMERA_MARGIN:Int = 150;
public function new(saveDataMenu:SaveDataMenu)
{
super();
add(items = new TextMenuList());
createItem("PREFERENCES", function() codex.switchPage(Preferences));
#if mobile
if (ControlsHandler.hasExternalInputDevice)
#end
createItem("CONTROLS", function() codex.switchPage(Controls));
// createItem("CONTROL SCHEMES", function() {
// FlxG.state.openSubState(new ControlsSchemeMenu());
// });
#if FEATURE_LAG_ADJUSTMENT
createItem("LAG ADJUSTMENT", function() {
FlxG.sound.music.fadeOut(0.5, 0, function(tw) {
FunkinSound.playMusic('offsetsLoop',
{
startingVolume: 0,
overrideExisting: true,
restartTrack: true,
loop: true
});
OptionsState.instance.drumsBG.play(true);
FlxG.sound.music.fadeIn(1, 1);
});
codex.switchPage(Offsets);
});
#end
#if FEATURE_MOBILE_IAP
createItem("RESTORE PURCHASES", function() {
InAppPurchasesUtil.restorePurchases();
});
#end
#if android
createItem("OPEN DATA FOLDER", function() {
funkin.external.android.DataFolderUtil.openDataFolder();
});
#end
#if FEATURE_NEWGROUNDS
if (NewgroundsClient.instance.isLoggedIn())
{
createItem("LOGOUT OF NG", function() {
NewgroundsClient.instance.logout(function() {
// Reset the options menu when logout succeeds.
// This means the login option will be displayed.
FlxG.resetState();
}, function() {
FlxG.log.warn("Newgrounds logout failed!");
});
});
}
else
{
createItem("LOGIN TO NG", function() {
NewgroundsClient.instance.login(function() {
// Reset the options menu when login succeeds.
// This means the logout option will be displayed.
// NOTE: If the user presses login and opens the browser,
// then navigates the UI
FlxG.resetState();
}, function() {
FlxG.log.warn("Newgrounds login failed!");
});
});
}
#end
// no need to show an entire new menu for just one option
if (saveDataMenu.hasMultipleOptions())
{
createItem("SAVE DATA OPTIONS", function() {
codex.switchPage(SaveData);
});
}
else
{
createItem("CLEAR SAVE DATA", saveDataMenu.openSaveDataPrompt);
}
#if NO_FEATURE_TOUCH_CONTROLS
createItem("EXIT", exit);
#else
backButton = new FunkinBackButton(FlxG.width - 230, FlxG.height - 200, exit, 1.0);
backButton.onConfirmStart.add(function() {
items.busy = true;
goingBack = true;
backButton.active = true;
});
add(backButton);
#end
// Create an object for the camera to track.
camFocusPoint = new FlxObject(0, 0, 140, 70);
add(camFocusPoint);
// Follow the camera focus as we scroll.
FlxG.camera.follow(camFocusPoint, null, 0.085);
FlxG.camera.deadzone.set(0, CAMERA_MARGIN / 2, FlxG.camera.width, FlxG.camera.height - CAMERA_MARGIN + 40);
FlxG.camera.minScrollY = -CAMERA_MARGIN / 2;
// Move the camera when the menu is scrolled.
items.onChange.add(onMenuChange);
onMenuChange(items.members[0]);
items.selectItem(OptionsState.rememberedSelectedIndex);
#if FEATURE_TOUCH_CONTROLS
FlxG.touches.swipeThreshold.y = 100;
#end
}
function onMenuChange(selected:TextMenuItem):Void
{
camFocusPoint.y = selected.y;
}
function createItem(name:String, callback:Void->Void, fireInstantly = false):TextMenuItem
{
var item = items.createItem(0, 100 + items.length * 100, name, BOLD, callback);
item.fireInstantly = fireInstantly;
item.screenCenter(X);
return item;
}
override function update(elapsed:Float):Void
{
#if FEATURE_TOUCH_CONTROLS
backButton.active = (!goingBack) ? !items.busy : true;
#end
super.update(elapsed);
}
override function set_enabled(value:Bool):Bool
{
items.enabled = value;
return super.set_enabled(value);
}
/**
* True if this page has multiple options, excluding the exit option.
* If false, there's no reason to ever show this page.
*/
public function hasMultipleOptions():Bool
{
return items.length > 2;
}
}
enum abstract OptionsMenuPageName(String) to PageName
{
var Options = "options";
var Controls = "controls";
var Colors = "colors";
var Mods = "mods";
var Preferences = "preferences";
var Offsets = "offsets";
var SaveData = "saveData";
}