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)
480 lines
13 KiB
Haxe
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);
|
|
}
|
|
}
|
|
} |