Files
FNF-i486-Engine/source/options/BaseOptionsMenu.hx
JordanSantiagoYT 932a3ef6ac Good change commit!
The game should no longer look for song-normal if the Normal difficulty is all lowercase/uppercase
Added difficulty-based inst and voices!
Added the ability to change difficulty name in the Chart Editor
Fixed song not ending if you were on Rendering Mode and disabled the Time Bar (fixes #244)
Added an Options Search Bar (closes #245)
2024-03-16 17:31:17 -04:00

480 lines
13 KiB
Haxe

package options;
#if desktop
import DiscordClient;
#end
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)
{
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);
}
}
}