Files
FNF-i486-Engine/source/options/BaseOptionsMenu.hx
JordanSantiagoYT 49729e7d6a Quant Color Customization
+ in any options menu, pressing RESET now only resets the current option selected. To reset the entire menu at once, press SHIFT+RESET!
2025-01-27 20:32:10 -05:00

492 lines
13 KiB
Haxe

package options;
import flash.text.TextField;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.addons.display.FlxGridOverlay;
import flixel.group.FlxGroup.FlxTypedGroup;
import flixel.math.FlxMath;
import flixel.text.FlxText;
import flixel.util.FlxColor;
import lime.utils.Assets;
import flixel.FlxSubState;
import flash.text.TextField;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.util.FlxSave;
import haxe.Json;
import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
import flixel.util.FlxTimer;
import flixel.input.keyboard.FlxKey;
import flixel.graphics.FlxGraphic;
import Controls;
import flixel.ui.FlxButton;
import flixel.addons.ui.FlxUIInputText; //These are both for the search bars
using StringTools;
class BaseOptionsMenu extends MusicBeatSubstate
{
private var curOption:Option = null;
private var curSelected:Int = 0;
private var optionsArray:Array<Option>;
private var grpOptions:FlxTypedGroup<Alphabet>;
private var checkboxGroup:FlxTypedGroup<CheckboxThingie>;
private var grpTexts:FlxTypedGroup<AttachedText>;
private var boyfriend:Character = null;
private var descBox:FlxSprite;
private var descText:FlxText;
var optionSearchText:FlxUIInputText;
var searchText:FlxText;
public var title:String;
public var rpcTitle:String;
public function new()
{
super();
if(title == null) title = 'Options';
if(rpcTitle == null) rpcTitle = 'Options Menu';
#if desktop
DiscordClient.changePresence(rpcTitle, null);
#end
var bg:FlxSprite = new FlxSprite().loadGraphic(Paths.image('menuDesat'));
bg.color = 0xFFea71fd;
bg.screenCenter();
bg.antialiasing = ClientPrefs.globalAntialiasing;
add(bg);
// avoids lagspikes while scrolling through menus!
grpOptions = new FlxTypedGroup<Alphabet>();
add(grpOptions);
grpTexts = new FlxTypedGroup<AttachedText>();
add(grpTexts);
checkboxGroup = new FlxTypedGroup<CheckboxThingie>();
add(checkboxGroup);
descBox = new FlxSprite().makeGraphic(1, 1, FlxColor.BLACK);
descBox.alpha = 0.6;
add(descBox);
var titleText:Alphabet = new Alphabet(75, 40, title, true);
titleText.scaleX = 0.6;
titleText.scaleY = 0.6;
titleText.alpha = 0.4;
add(titleText);
descText = new FlxText(50, 600, 1180, "", 32);
descText.setFormat(Paths.font("vcr.ttf"), 32, FlxColor.WHITE, CENTER, FlxTextBorderStyle.OUTLINE, FlxColor.BLACK);
descText.scrollFactor.set();
descText.borderSize = 2.4;
add(descText);
for (i in 0...optionsArray.length)
{
var optionText:Alphabet = new Alphabet(290, 260, optionsArray[i].name, false);
optionText.isMenuItem = true;
/*optionText.forceX = 300;
optionText.yMult = 90;*/
optionText.targetY = i;
grpOptions.add(optionText);
if(optionsArray[i].type == 'bool') {
var checkbox:CheckboxThingie = new CheckboxThingie(optionText.x - 105, optionText.y, optionsArray[i].getValue() == true);
checkbox.sprTracker = optionText;
checkbox.ID = i;
checkboxGroup.add(checkbox);
} else if (optionsArray[i].type != 'link') {
optionText.x -= 80;
optionText.startPosition.x -= 80;
//optionText.xAdd -= 80;
var valueText:AttachedText = new AttachedText('' + optionsArray[i].getValue(), optionText.width + 80);
valueText.sprTracker = optionText;
valueText.copyAlpha = true;
valueText.ID = i;
grpTexts.add(valueText);
optionsArray[i].setChild(valueText);
}
//optionText.snapToPosition(); //Don't ignore me when i ask for not making a fucking pull request to uncomment this line ok
if(optionsArray[i].showBoyfriend && boyfriend == null)
{
reloadBoyfriend();
}
updateTextFrom(optionsArray[i]);
}
changeSelection();
reloadCheckboxes();
originalOptionsArray = optionsArray.copy();
optionSearchText = new FlxUIInputText(0, 0, 500, '', 16);
optionSearchText.x = FlxG.width - optionSearchText.width;
add(optionSearchText);
var buttonTop:FlxButton = new FlxButton(0, optionSearchText.y + optionSearchText.height + 5, "", function() {
optionsSearch(optionSearchText.text);
});
buttonTop.setGraphicSize(Std.int(optionSearchText.width), 50);
buttonTop.updateHitbox();
buttonTop.label.setFormat(Paths.font("vcr.ttf"), 24, FlxColor.BLACK, RIGHT);
buttonTop.x = FlxG.width - buttonTop.width;
add(buttonTop);
searchText = new FlxText(975, buttonTop.y + 20, 100, "Search", 24);
searchText.setFormat(Paths.font("vcr.ttf"), 24, FlxColor.BLACK);
add(searchText);
FlxG.mouse.visible = true;
}
public function addOption(option:Option) {
if(optionsArray == null || optionsArray.length < 1) optionsArray = [];
optionsArray.push(option);
}
var originalOptionsArray:Array<Option> = [];
var optionsFound:Array<Option> = [];
function optionsSearch(?query:String = '')
{
optionsFound = [];
var foundOptions:Int = 0;
final txt:FlxText = new FlxText(0, 0, 0, 'No options found matching your query', 16);
txt.setFormat(Paths.font("vcr.ttf"), 16, FlxColor.WHITE, CENTER, FlxTextBorderStyle.OUTLINE, FlxColor.BLACK);
txt.scrollFactor.set();
txt.screenCenter(XY);
for (i in 0...originalOptionsArray.length) {
if (query != null && query.length > 0) {
var optionName = originalOptionsArray[i].name.toLowerCase();
var q = query.toLowerCase();
if (optionName.indexOf(q) != -1)
{
optionsFound.push(originalOptionsArray[i]);
foundOptions++;
}
}
}
if (foundOptions > 0 || query.length <= 0){
if (txt != null)
remove(txt); // don't do destroy/kill on this btw
regenerateOptions(query);
}
else if (foundOptions <= 0){
add(txt);
new FlxTimer().start(3, function(timer) {
if (txt != null)
remove(txt);
});
return;
}
}
function regenerateOptions(?query:String = '') {
if (query.length > 0) optionsArray = optionsFound;
else if (optionsArray != originalOptionsArray) optionsArray = originalOptionsArray.copy();
regenList();
}
function regenList() {
grpOptions.forEach(option -> {
grpOptions.remove(option, true);
option.destroy();
});
grpTexts.forEach(text -> {
grpTexts.remove(text, true);
text.destroy();
});
checkboxGroup.forEach(check -> {
checkboxGroup.remove(check, true);
check.destroy();
});
//we clear the remaining ones
grpOptions.clear();
grpTexts.clear();
checkboxGroup.clear();
for (i in 0...optionsArray.length)
{
var optionText:Alphabet = new Alphabet(290, 260, optionsArray[i].name, false);
optionText.isMenuItem = true;
/*optionText.forceX = 300;
optionText.yMult = 90;*/
optionText.targetY = i;
grpOptions.add(optionText);
if(optionsArray[i].type == 'bool') {
var checkbox:CheckboxThingie = new CheckboxThingie(optionText.x - 105, optionText.y, optionsArray[i].getValue() == true);
checkbox.sprTracker = optionText;
checkbox.ID = i;
checkboxGroup.add(checkbox);
} else if (optionsArray[i].type != 'link') {
optionText.x -= 80;
optionText.startPosition.x -= 80;
//optionText.xAdd -= 80;
var valueText:AttachedText = new AttachedText('' + optionsArray[i].getValue(), optionText.width + 80);
valueText.sprTracker = optionText;
valueText.copyAlpha = true;
valueText.ID = i;
grpTexts.add(valueText);
optionsArray[i].setChild(valueText);
}
//optionText.snapToPosition(); //Don't ignore me when i ask for not making a fucking pull request to uncomment this line ok
if(optionsArray[i].showBoyfriend && boyfriend == null)
{
reloadBoyfriend();
}
updateTextFrom(optionsArray[i]);
}
changeSelection();
reloadCheckboxes();
}
var nextAccept:Int = 5;
var holdTime:Float = 0;
var holdValue:Float = 0;
override function update(elapsed:Float)
{
if (!optionSearchText.hasFocus)
{
if (controls.UI_UP_P)
{
changeSelection(-1);
}
if (controls.UI_DOWN_P)
{
changeSelection(1);
}
if (controls.BACK) {
close();
FlxG.sound.play(Paths.sound('cancelMenu'));
}
if(nextAccept <= 0)
{
var usesCheckbox = true;
if(curOption.type != 'bool')
{
usesCheckbox = false;
}
if(usesCheckbox)
{
if(controls.ACCEPT)
{
FlxG.sound.play(Paths.sound((curOption.type == 'link' ? 'confirmMenu' : 'scrollMenu')));
if (curOption.type == 'bool') curOption.setValue((curOption.getValue() == true) ? false : true);
curOption.change();
reloadCheckboxes();
}
} else {
if(controls.UI_LEFT || controls.UI_RIGHT) {
var pressed = (controls.UI_LEFT_P || controls.UI_RIGHT_P);
if(holdTime > 0.5 || pressed) {
if(pressed) {
var add:Dynamic = null;
if(curOption.type != 'string') {
add = controls.UI_LEFT ? -curOption.changeValue : curOption.changeValue;
}
switch(curOption.type)
{
case 'int' | 'float' | 'percent':
holdValue = curOption.getValue() + add;
if(holdValue < curOption.minValue) holdValue = curOption.minValue;
else if (holdValue > curOption.maxValue) holdValue = curOption.maxValue;
switch(curOption.type)
{
case 'int':
holdValue = Math.round(holdValue);
curOption.setValue(holdValue);
case 'float' | 'percent':
holdValue = FlxMath.roundDecimal(holdValue, curOption.decimals);
curOption.setValue(holdValue);
}
case 'string':
var num:Int = curOption.curOption; //lol
if(controls.UI_LEFT_P) --num;
else num++;
if(num < 0) {
num = curOption.options.length - 1;
} else if(num >= curOption.options.length) {
num = 0;
}
curOption.curOption = num;
curOption.setValue(curOption.options[num]); //lol
//trace(curOption.options[num]);
}
updateTextFrom(curOption);
curOption.change();
FlxG.sound.play(Paths.sound('scrollMenu'));
} else if(curOption.type != 'string') {
holdValue += curOption.scrollSpeed * elapsed * (controls.UI_LEFT ? -1 : 1);
if(holdValue < curOption.minValue) holdValue = curOption.minValue;
else if (holdValue > curOption.maxValue) holdValue = curOption.maxValue;
switch(curOption.type)
{
case 'int':
curOption.setValue(Math.round(holdValue));
case 'float' | 'percent':
curOption.setValue(FlxMath.roundDecimal(holdValue, curOption.decimals));
}
updateTextFrom(curOption);
curOption.change();
}
}
if(curOption.type != 'string') {
holdTime += elapsed;
}
} else if(controls.UI_LEFT_R || controls.UI_RIGHT_R) {
clearHold();
}
}
if(controls.RESET)
{
if (!FlxG.keys.pressed.SHIFT)
{
var leOption:Option = optionsArray[curSelected];
leOption.setValue(leOption.defaultValue);
if(leOption.type != 'bool')
{
if(leOption.type == 'string')
{
leOption.curOption = leOption.options.indexOf(leOption.getValue());
}
updateTextFrom(leOption);
}
leOption.change();
}
else
for (i in 0...optionsArray.length)
{
var leOption:Option = optionsArray[i];
leOption.setValue(leOption.defaultValue);
if(leOption.type != 'bool')
{
if(leOption.type == 'string')
{
leOption.curOption = leOption.options.indexOf(leOption.getValue());
}
updateTextFrom(leOption);
}
leOption.change();
}
FlxG.sound.play(Paths.sound('cancelMenu'));
reloadCheckboxes();
}
}
}
if(boyfriend != null && boyfriend.animation.curAnim.finished) {
boyfriend.dance();
}
if(nextAccept > 0) {
nextAccept -= 1;
}
super.update(elapsed);
}
function updateTextFrom(option:Option) {
var text:String = option.displayFormat;
var val:Dynamic = option.getValue();
if(option.type == 'percent') val *= 100;
var def:Dynamic = option.defaultValue;
option.text = text.replace('%v', val).replace('%d', def);
}
function clearHold()
{
if(holdTime > 0.5) {
FlxG.sound.play(Paths.sound('scrollMenu'));
}
holdTime = 0;
}
function changeSelection(change:Int = 0)
{
curSelected += change;
if (curSelected < 0)
curSelected = optionsArray.length - 1;
if (curSelected >= optionsArray.length)
curSelected = 0;
descText.text = optionsArray[curSelected].description;
descText.screenCenter(Y);
descText.y += 270;
var bullShit:Int = 0;
for (item in grpOptions.members) {
item.targetY = bullShit - curSelected;
bullShit++;
item.alpha = 0.6;
if (item.targetY == 0) {
item.alpha = 1;
}
}
for (text in grpTexts) {
text.alpha = 0.6;
if(text.ID == curSelected) {
text.alpha = 1;
}
}
descBox.setPosition(descText.x - 10, descText.y - 10);
descBox.setGraphicSize(Std.int(descText.width + 20), Std.int(descText.height + 25));
descBox.updateHitbox();
if(boyfriend != null)
{
boyfriend.visible = optionsArray[curSelected].showBoyfriend;
}
curOption = optionsArray[curSelected]; //shorter lol
FlxG.sound.play(Paths.sound('scrollMenu'));
}
public function reloadBoyfriend()
{
var wasVisible:Bool = false;
if(boyfriend != null) {
wasVisible = boyfriend.visible;
boyfriend.kill();
remove(boyfriend);
boyfriend.destroy();
}
boyfriend = new Character(840, 170, 'bf', true);
boyfriend.setGraphicSize(Std.int(boyfriend.width * 0.75));
boyfriend.updateHitbox();
boyfriend.dance();
insert(1, boyfriend);
boyfriend.visible = wasVisible;
}
function reloadCheckboxes() {
for (checkbox in checkboxGroup) {
checkbox.daValue = (optionsArray[checkbox.ID].getValue() == true);
}
}
}