mirror of
https://github.com/D1GQ/BetterAmongUs.git
synced 2026-10-20 01:46:19 +00:00
Rework settings menu
This commit is contained in:
1 parent
29ac652280
commit
1407d30375
34 files changed
+2017
-1341
No files matched your search
@@ -0,0 +1,99 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Helpers;
|
||||
|
||||
internal static class Colors
|
||||
{
|
||||
// Convert a string to a colored string using a Unity Color object
|
||||
/// <summary>
|
||||
/// Converts the provided string into a colored string by wrapping it with a
|
||||
/// <color> tag using the Unity Color object. The Unity Color is automatically
|
||||
/// converted to its hexadecimal representation before being applied to the string.
|
||||
/// </summary>
|
||||
/// <param name="str">The string to be colored.</param>
|
||||
/// <param name="color">The Unity Color object representing the desired color.</param>
|
||||
/// <returns>A string wrapped in a color tag, displaying the string in the specified Unity color.</returns>
|
||||
internal static string ToColor(this string str, Color color) => $"<{Color32ToHex(color)}>{str}</color>";
|
||||
|
||||
// Modify the alpha value of an existing color
|
||||
/// <summary>
|
||||
/// Returns a new color that preserves the RGB (Red, Green, Blue) values of the
|
||||
/// original color, but applies a new alpha (opacity) value from the provided new color.
|
||||
/// This can be used to adjust the transparency of an existing color without changing its color components.
|
||||
/// </summary>
|
||||
/// <param name="oldColor">The original color whose RGB values will be preserved.</param>
|
||||
/// <param name="newColor">The color that provides the new alpha value.</param>
|
||||
/// <returns>A new color with the same RGB values as the original color, but with the new alpha value.</returns>
|
||||
internal static Color ToColor(this Color oldColor, Color newColor) => new(newColor.r, newColor.g, newColor.b, oldColor.a);
|
||||
|
||||
// Set a new alpha value while keeping the original RGB values
|
||||
/// <summary>
|
||||
/// Creates and returns a new color with the same RGB values as the original color,
|
||||
/// but with the specified alpha (transparency) value. This method is useful for
|
||||
/// changing the transparency of a color while maintaining its original color components.
|
||||
/// </summary>
|
||||
/// <param name="oldColor">The original color whose RGB values will remain the same.</param>
|
||||
/// <param name="alpha">The new alpha (transparency) value to apply to the color.</param>
|
||||
/// <returns>A new color with the same RGB values as the original color, but with the specified alpha value.</returns>
|
||||
internal static Color ToAlpha(this Color oldColor, float alpha) => new(oldColor.r, oldColor.g, oldColor.b, alpha);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Color32 object to a hexadecimal string representation.
|
||||
/// </summary>
|
||||
/// <param name="color">The Color32 object to convert.</param>
|
||||
/// <returns>A hexadecimal string representing the Color32 object.</returns>
|
||||
internal static string Color32ToHex(this Color32 color) => $"#{color.r:X2}{color.g:X2}{color.b:X2}{255:X2}";
|
||||
|
||||
/// <summary>
|
||||
/// Converts a hexadecimal color string to a Color32 object.
|
||||
/// </summary>
|
||||
/// <param name="hex">The hexadecimal color string to convert.</param>
|
||||
/// <returns>A Color32 object representing the hexadecimal string.</returns>
|
||||
internal static Color HexToColor(this string hex)
|
||||
{
|
||||
if (hex.StartsWith("#"))
|
||||
{
|
||||
hex = hex.Substring(1);
|
||||
}
|
||||
|
||||
byte r = byte.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
|
||||
byte g = byte.Parse(hex.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
|
||||
byte b = byte.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
|
||||
|
||||
return new Color32(r, g, b, 255);
|
||||
}
|
||||
|
||||
internal static Color32 ColorToColor32(this Color color)
|
||||
{
|
||||
return new Color32(
|
||||
(byte)(color.r * 255),
|
||||
(byte)(color.g * 255),
|
||||
(byte)(color.b * 255),
|
||||
(byte)(color.a * 255)
|
||||
);
|
||||
}
|
||||
|
||||
internal static Color LerpColor(this Color[] colors, (float min, float max) lerpRange, float t, bool reverse = false)
|
||||
{
|
||||
float normalizedT = Mathf.InverseLerp(lerpRange.min, lerpRange.max, t);
|
||||
|
||||
if (colors.Length == 1)
|
||||
return colors[0];
|
||||
|
||||
if (reverse)
|
||||
{
|
||||
colors.Reverse();
|
||||
}
|
||||
|
||||
if (normalizedT <= 0f)
|
||||
return colors[0];
|
||||
if (normalizedT >= 1f)
|
||||
return colors[^1];
|
||||
|
||||
float segmentSize = 1f / (colors.Length - 1);
|
||||
int segmentIndex = (int)(normalizedT / segmentSize);
|
||||
float segmentT = (normalizedT - segmentIndex * segmentSize) / segmentSize;
|
||||
|
||||
return Color.Lerp(colors[segmentIndex], colors[segmentIndex + 1], segmentT);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
namespace BetterAmongUs.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for IEnumerable collections, including shuffling, selecting a random element, and retrieving the middle element.
|
||||
/// </summary>
|
||||
internal static class IEnumerableExtension
|
||||
{
|
||||
private static readonly Random rng = new();
|
||||
|
||||
/// <summary>
|
||||
/// Shuffles all elements in a collection randomly.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements in the collection.</typeparam>
|
||||
/// <param name="collection">The collection to shuffle.</param>
|
||||
/// <returns>The shuffled collection.</returns>
|
||||
internal static IEnumerable<T> Shuffle<T>(this IEnumerable<T> collection)
|
||||
{
|
||||
var list = collection.ToList();
|
||||
int n = list.Count;
|
||||
while (n > 1)
|
||||
{
|
||||
n--;
|
||||
int k = rng.Next(n + 1);
|
||||
(list[n], list[k]) = (list[k], list[n]);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects a random non-null element from the collection.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements in the collection.</typeparam>
|
||||
/// <param name="collection">The collection to select from.</param>
|
||||
/// <returns>A random non-null element from the collection, or <c>null</c> if the collection is empty or only contains null values.</returns>
|
||||
internal static T? Random<T>(this IEnumerable<T?> collection) where T : class
|
||||
{
|
||||
if (collection == null || !collection.Any()) return null;
|
||||
|
||||
var shuffled = collection.Where(item => item != null).Shuffle();
|
||||
return shuffled.FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects a random non-null element from the collection and returns both the element and its original index.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements in the collection.</typeparam>
|
||||
/// <param name="collection">The collection to select from.</param>
|
||||
/// <returns>A tuple containing:
|
||||
/// - The random non-null element (or null if no valid elements found)
|
||||
/// - The original index of the element (or -1 if no valid elements found)
|
||||
/// </returns>
|
||||
internal static (T? element, int index) RandomIndex<T>(this IEnumerable<T?> collection) where T : class
|
||||
{
|
||||
if (collection == null || !collection.Any())
|
||||
return (null, -1);
|
||||
|
||||
var indexedItems = collection
|
||||
.Select((item, index) => (item, index))
|
||||
.Where(x => x.item != null)
|
||||
.ToList();
|
||||
|
||||
if (indexedItems.Count == 0)
|
||||
return (null, -1);
|
||||
|
||||
var shuffled = indexedItems.Shuffle();
|
||||
var selected = shuffled.First();
|
||||
|
||||
return (selected.item, selected.index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the middle element of a collection.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements in the collection.</typeparam>
|
||||
/// <param name="collection">The collection to retrieve the middle element from.</param>
|
||||
/// <returns>The middle element of the collection.</returns>
|
||||
/// <exception cref="InvalidOperationException">Thrown if the collection is null or empty.</exception>
|
||||
internal static T Middle<T>(this IEnumerable<T> collection)
|
||||
{
|
||||
if (collection == null || !collection.Any())
|
||||
throw new InvalidOperationException("Collection cannot be null or empty.");
|
||||
|
||||
int middleIndex = collection.Count() / 2;
|
||||
return collection.Skip(middleIndex).First();
|
||||
}
|
||||
}
|
||||
+27
-9
@@ -4,6 +4,10 @@ namespace BetterAmongUs.Helpers;
|
||||
|
||||
internal static class ObjectHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Finds a GameObject by its name in the scene, including inactive objects.
|
||||
/// Returns null if no object with the specified name is found.
|
||||
/// </summary>
|
||||
internal static GameObject? FindObjectByName(string objectName)
|
||||
{
|
||||
GameObject[] allObjects = UnityEngine.Object.FindObjectsOfType<GameObject>(true);
|
||||
@@ -18,6 +22,10 @@ internal static class ObjectHelper
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys a GameObject if it is not null.
|
||||
/// </summary>
|
||||
internal static void DestroyObj(this GameObject obj)
|
||||
{
|
||||
if (obj != null)
|
||||
@@ -25,18 +33,28 @@ internal static class ObjectHelper
|
||||
UnityEngine.Object.Destroy(obj);
|
||||
}
|
||||
}
|
||||
internal static void DestroyObj(this UnityEngine.Object obj) => obj.DestroyObj();
|
||||
internal static void DestroyCom(this Component com) => com.DestroyObj();
|
||||
|
||||
/// <summary>
|
||||
/// Destroys the GameObject associated with a MonoBehaviour if it is not null.
|
||||
/// </summary>
|
||||
internal static void DestroyObj(this MonoBehaviour mono) => mono?.gameObject?.DestroyObj();
|
||||
|
||||
/// <summary>
|
||||
/// Destroys a MonoBehaviour component if it is not null.
|
||||
/// </summary>
|
||||
internal static void DestroyMono(this MonoBehaviour mono) => UnityEngine.Object.Destroy(mono);
|
||||
|
||||
internal static void DestroyTextTranslator(this GameObject obj)
|
||||
/// <summary>
|
||||
/// Destroys all TextTranslatorTMP components in the children of a GameObject.
|
||||
/// </summary>
|
||||
internal static void DestroyTextTranslators(this GameObject obj)
|
||||
{
|
||||
var translator = obj.GetComponent<TextTranslatorTMP>();
|
||||
if (translator != null)
|
||||
{
|
||||
UnityEngine.Object.Destroy(translator);
|
||||
}
|
||||
var translators = obj.GetComponentsInChildren<TextTranslatorTMP>();
|
||||
if (translators.Length > 0) translators.ToList().ForEach(com => com.DestroyMono());
|
||||
}
|
||||
internal static void DestroyTextTranslator(this MonoBehaviour mono) => mono.gameObject.DestroyTextTranslator();
|
||||
|
||||
/// <summary>
|
||||
/// Destroys all TextTranslatorTMP components in the children of a MonoBehaviour's GameObject.
|
||||
/// </summary>
|
||||
internal static void DestroyTextTranslators(this MonoBehaviour mono) => mono.gameObject.DestroyTextTranslators();
|
||||
}
|
||||
@@ -73,12 +73,12 @@ static class PlayerControlHelper
|
||||
|
||||
if (AntiCheatBan)
|
||||
{
|
||||
if (BetterGameSettings.WhenCheating.GetValue() == 0 && !forceBan)
|
||||
if (BetterGameSettings.WhenCheating.GetStringValue() == 0 && !forceBan)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Ban = (Ban && BetterGameSettings.WhenCheating.GetValue() == 2) || forceBan;
|
||||
Ban = (Ban && BetterGameSettings.WhenCheating.GetStringValue() == 2) || forceBan;
|
||||
}
|
||||
|
||||
if (setReasonInfo != "")
|
||||
|
||||
+46
-3
@@ -13,6 +13,18 @@ namespace BetterAmongUs.Helpers;
|
||||
|
||||
internal static class Utils
|
||||
{
|
||||
internal static string Size(this string str, float size) => $"<size={size}%>{str}</size>";
|
||||
|
||||
internal static string RemoveSizeHtmlText(string text)
|
||||
{
|
||||
text = Regex.Replace(text, "<size=[^>]*>", "", RegexOptions.IgnoreCase);
|
||||
text = Regex.Replace(text, "</size>", "", RegexOptions.IgnoreCase);
|
||||
text = Regex.Replace(text, "{[^}]*}", "");
|
||||
text = text.Replace("\n", " ").Replace("\r", " ").Trim();
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
internal static bool IsInternetAvailable()
|
||||
{
|
||||
if (Application.internetReachability == NetworkReachability.NotReachable)
|
||||
@@ -144,9 +156,6 @@ internal static class Utils
|
||||
return text;
|
||||
}
|
||||
|
||||
internal static string ToColor(this string str, string hexColor) => $"<{hexColor}>{str}</color>";
|
||||
internal static string ToColor(this string str, Color color) => $"<{Color32ToHex(color)}>{str}</color>";
|
||||
|
||||
internal static bool IsHtmlText(string text)
|
||||
{
|
||||
if (Regex.IsMatch(text, "<[^>]*>"))
|
||||
@@ -232,6 +241,40 @@ internal static class Utils
|
||||
}
|
||||
}
|
||||
|
||||
// Synchronizes the settings change notification across the network
|
||||
/// <summary>
|
||||
/// This method synchronizes the settings change notification across the network, updating any existing notification or
|
||||
/// creating a new one if necessary. The message is updated or a new notification is created to reflect the changes.
|
||||
/// A sound can also be played to notify players.
|
||||
/// </summary>
|
||||
/// <param name="Id">The ID of the setting being changed.</param>
|
||||
/// <param name="text">The message text describing the change.</param>
|
||||
/// <param name="playSound">Flag to determine if a sound should be played during the notification.</param>
|
||||
internal static void SettingsChangeNotifier(int Id, string text, bool playSound = true)
|
||||
{
|
||||
var Notifier = HudManager.Instance.Notifier;
|
||||
if (Notifier.lastMessageKey == Id && Notifier.activeMessages.Count > 0)
|
||||
{
|
||||
Notifier.activeMessages[Notifier.activeMessages.Count - 1].UpdateMessage(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
Notifier.lastMessageKey = Id;
|
||||
LobbyNotificationMessage newMessage = UnityEngine.Object.Instantiate(Notifier.notificationMessageOrigin, Vector3.zero, Quaternion.identity, Notifier.transform);
|
||||
newMessage.transform.localPosition = new Vector3(0f, 0f, -2f);
|
||||
newMessage.SetUp(text, Notifier.settingsChangeSprite, Notifier.settingsChangeColor, (Action)(() =>
|
||||
{
|
||||
Notifier.OnMessageDestroy(newMessage);
|
||||
}));
|
||||
Notifier.ShiftMessages();
|
||||
Notifier.AddMessageToQueue(newMessage);
|
||||
}
|
||||
if (playSound)
|
||||
{
|
||||
SoundManager.Instance.PlaySoundImmediate(Notifier.settingsChangeSound, false, 1f, 1f, null);
|
||||
}
|
||||
}
|
||||
|
||||
// Disconnect client
|
||||
internal static void DisconnectSelf(string reason, bool showReason = true)
|
||||
{
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
using BetterAmongUs.Data;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
internal class BetterOptionCheckboxItem : BetterOptionItem
|
||||
{
|
||||
private ToggleOption? ThisOption;
|
||||
private bool? IsChecked;
|
||||
|
||||
internal override bool ShowChildrenCondition() => IsChecked == true;
|
||||
internal override bool SelfShowCondition() => ShowCondition != null ? ShowCondition() : base.SelfShowCondition();
|
||||
internal Func<bool>? ShowCondition = null;
|
||||
|
||||
internal BetterOptionItem Create(int id, GameOptionsMenu gameOptionsMenu, string name, bool DefaultValue = true, BetterOptionItem? Parent = null, Func<bool>? selfShowCondition = null)
|
||||
{
|
||||
Id = id;
|
||||
Tab = gameOptionsMenu;
|
||||
Name = name;
|
||||
IsChecked = DefaultValue;
|
||||
ShowCondition = selfShowCondition;
|
||||
|
||||
if (gameOptionsMenu == null)
|
||||
{
|
||||
Load(DefaultValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
ToggleOption optionBehaviour = UnityEngine.Object.Instantiate(gameOptionsMenu.checkboxOrigin, Vector3.zero, Quaternion.identity, gameOptionsMenu.settingsContainer);
|
||||
optionBehaviour.enabled = false;
|
||||
optionBehaviour.transform.localPosition = new Vector3(0.952f, 2f, -2f);
|
||||
SetUp(optionBehaviour);
|
||||
optionBehaviour.OnValueChanged = new Action<OptionBehaviour>((option) => ValueChanged(id, option));
|
||||
|
||||
optionBehaviour.LabelBackground.transform.localScale = new Vector3(1.6f, 0.78f);
|
||||
optionBehaviour.LabelBackground.transform.SetLocalX(-2.4f);
|
||||
optionBehaviour.TitleText.enableAutoSizing = false;
|
||||
optionBehaviour.TitleText.transform.SetLocalX(-1.5f);
|
||||
optionBehaviour.TitleText.alignment = TMPro.TextAlignmentOptions.Right;
|
||||
optionBehaviour.TitleText.enableWordWrapping = false;
|
||||
optionBehaviour.TitleText.fontSize = 2.5f;
|
||||
|
||||
// Set data
|
||||
optionBehaviour.CheckMark.GetComponent<SpriteRenderer>().enabled = DefaultValue;
|
||||
TitleText = optionBehaviour.TitleText;
|
||||
Option = optionBehaviour;
|
||||
ThisOption = optionBehaviour;
|
||||
|
||||
Load(DefaultValue);
|
||||
|
||||
BetterOptionItems.Add(this);
|
||||
obj = optionBehaviour.gameObject;
|
||||
|
||||
if (Parent != null)
|
||||
{
|
||||
int Index = 1;
|
||||
var tempParent = Parent;
|
||||
|
||||
while (tempParent.ThisParent != null)
|
||||
{
|
||||
tempParent = tempParent.ThisParent;
|
||||
Index++;
|
||||
}
|
||||
|
||||
optionBehaviour.LabelBackground.GetComponent<SpriteRenderer>().color -= new Color(0.25f, 0.25f, 0.25f, 0f) * Index;
|
||||
optionBehaviour.LabelBackground.transform.localScale -= new Vector3(0.04f, 0f, 0f) * Index;
|
||||
optionBehaviour.LabelBackground.transform.position += new Vector3(0.04f, 0f, 0f) * Index;
|
||||
optionBehaviour.LabelBackground.transform.SetLocalZ(1f);
|
||||
ThisParent = Parent;
|
||||
IsChild = true;
|
||||
Parent.ChildrenList.Add(this);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
internal void Load(bool DefaultValue)
|
||||
{
|
||||
var Bool = BetterDataManager.LoadSetting(Id, DefaultValue);
|
||||
if (ThisOption != null)
|
||||
{
|
||||
ThisOption.CheckMark.GetComponent<SpriteRenderer>().enabled = Bool;
|
||||
}
|
||||
IsChecked = Bool;
|
||||
}
|
||||
|
||||
internal override bool GetBool()
|
||||
{
|
||||
if (BetterDataManager.CanLoadSetting<bool>(Id))
|
||||
{
|
||||
return BetterDataManager.LoadSetting<bool>(Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return IsChecked ??= false;
|
||||
}
|
||||
}
|
||||
|
||||
internal override void SetData(OptionBehaviour optionBehaviour)
|
||||
{
|
||||
optionBehaviour.data = new BaseGameSetting
|
||||
{
|
||||
Title = StringNames.None,
|
||||
Type = OptionTypes.Checkbox,
|
||||
};
|
||||
}
|
||||
|
||||
internal override void ValueChanged(int id, OptionBehaviour optionBehaviour)
|
||||
{
|
||||
IsChecked = !IsChecked;
|
||||
BetterDataManager.SaveSetting(Id, IsChecked);
|
||||
|
||||
if (IsParent || IsChild)
|
||||
{
|
||||
bool Bool = ShowChildrenCondition();
|
||||
foreach (var item in ChildrenList)
|
||||
{
|
||||
item.obj.SetActive(Bool && item.SelfShowCondition());
|
||||
}
|
||||
UpdatePositions();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,209 +0,0 @@
|
||||
using BetterAmongUs.Data;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
internal class BetterOptionFloatItem : BetterOptionItem
|
||||
{
|
||||
private NumberOption? ThisOption;
|
||||
internal float CurrentValue;
|
||||
internal FloatRange floatRange = new(0f, 180f);
|
||||
internal float Increment = 2.5f;
|
||||
private string? PostFix;
|
||||
private string? PreFix;
|
||||
|
||||
internal override bool ShowChildrenCondition() => CurrentValue > floatRange.min;
|
||||
internal override bool SelfShowCondition() => ShowCondition != null ? ShowCondition() : base.SelfShowCondition();
|
||||
internal Func<bool>? ShowCondition = null;
|
||||
|
||||
internal BetterOptionItem Create(int id, GameOptionsMenu gameOptionsMenu, string name, float[] values, float DefaultValue, string preFix = "", string postFix = "", BetterOptionItem? Parent = null, Func<bool>? selfShowCondition = null)
|
||||
{
|
||||
Id = id;
|
||||
floatRange = new(values[0], values[1]);
|
||||
Increment = values[2];
|
||||
if (DefaultValue < floatRange.min) DefaultValue = floatRange.min;
|
||||
if (DefaultValue > floatRange.max) DefaultValue = floatRange.max;
|
||||
CurrentValue = DefaultValue;
|
||||
ShowCondition = selfShowCondition;
|
||||
|
||||
if (gameOptionsMenu == null)
|
||||
{
|
||||
Load(DefaultValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
if (values.Length is < 3 or > 3) return null;
|
||||
|
||||
NumberOption optionBehaviour = UnityEngine.Object.Instantiate(gameOptionsMenu.numberOptionOrigin, Vector3.zero, Quaternion.identity, gameOptionsMenu.settingsContainer);
|
||||
optionBehaviour.enabled = false;
|
||||
optionBehaviour.transform.localPosition = new Vector3(0.952f, 2f, -2f);
|
||||
SetUp(optionBehaviour);
|
||||
optionBehaviour.OnValueChanged = new Action<OptionBehaviour>((option) => ValueChanged(id, option));
|
||||
|
||||
optionBehaviour.PlusBtn.OnClick.RemoveAllListeners();
|
||||
optionBehaviour.MinusBtn.OnClick.RemoveAllListeners();
|
||||
optionBehaviour.PlusBtn.OnClick.AddListener(new Action(() => Increase()));
|
||||
optionBehaviour.MinusBtn.OnClick.AddListener(new Action(() => Decrease()));
|
||||
optionBehaviour.PlusBtn.OnClick.AddListener(new Action(() => ValueChanged(id, optionBehaviour)));
|
||||
optionBehaviour.MinusBtn.OnClick.AddListener(new Action(() => ValueChanged(id, optionBehaviour)));
|
||||
|
||||
optionBehaviour.LabelBackground.transform.localScale = new Vector3(1.6f, 0.78f);
|
||||
optionBehaviour.LabelBackground.transform.SetLocalX(-2.4f);
|
||||
optionBehaviour.TitleText.enableAutoSizing = false;
|
||||
optionBehaviour.TitleText.transform.SetLocalX(-1.5f);
|
||||
optionBehaviour.TitleText.alignment = TMPro.TextAlignmentOptions.Right;
|
||||
optionBehaviour.TitleText.enableWordWrapping = false;
|
||||
optionBehaviour.TitleText.fontSize = 2.5f;
|
||||
|
||||
// Set data
|
||||
Tab = gameOptionsMenu;
|
||||
Name = name;
|
||||
TitleText = optionBehaviour.TitleText;
|
||||
Option = optionBehaviour;
|
||||
PostFix = postFix;
|
||||
PreFix = preFix;
|
||||
ThisOption = optionBehaviour;
|
||||
|
||||
Load(DefaultValue);
|
||||
AdjustButtonsActiveState();
|
||||
|
||||
BetterOptionItems.Add(this);
|
||||
obj = optionBehaviour.gameObject;
|
||||
|
||||
if (Parent != null)
|
||||
{
|
||||
int Index = 1;
|
||||
var tempParent = Parent;
|
||||
|
||||
while (tempParent.ThisParent != null)
|
||||
{
|
||||
tempParent = tempParent.ThisParent;
|
||||
Index++;
|
||||
}
|
||||
|
||||
optionBehaviour.LabelBackground.GetComponent<SpriteRenderer>().color -= new Color(0.25f, 0.25f, 0.25f, 0f) * Index;
|
||||
optionBehaviour.LabelBackground.transform.localScale -= new Vector3(0.04f, 0f, 0f) * Index;
|
||||
optionBehaviour.LabelBackground.transform.position += new Vector3(0.04f, 0f, 0f) * Index;
|
||||
optionBehaviour.LabelBackground.transform.SetLocalZ(1f);
|
||||
ThisParent = Parent;
|
||||
IsChild = true;
|
||||
Parent.ChildrenList.Add(this);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void AdjustButtonsActiveState()
|
||||
{
|
||||
if (ThisOption == null) return;
|
||||
|
||||
ThisOption.ValueText.text = PreFix + CurrentValue.ToString() + PostFix;
|
||||
|
||||
if (CurrentValue + Increment > floatRange.max)
|
||||
{
|
||||
ThisOption.PlusBtn.SetInteractable(false);
|
||||
ThisOption.MinusBtn.SetInteractable(true);
|
||||
}
|
||||
else if (CurrentValue - Increment < floatRange.min)
|
||||
{
|
||||
ThisOption.PlusBtn.SetInteractable(true);
|
||||
ThisOption.MinusBtn.SetInteractable(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ThisOption.PlusBtn.SetInteractable(true);
|
||||
ThisOption.MinusBtn.SetInteractable(true);
|
||||
}
|
||||
|
||||
BetterDataManager.SaveSetting(Id, CurrentValue);
|
||||
}
|
||||
|
||||
internal void Increase()
|
||||
{
|
||||
int times = 1;
|
||||
if (Input.GetKey(KeyCode.LeftShift))
|
||||
times = 5;
|
||||
if (Input.GetKey(KeyCode.LeftControl))
|
||||
times = 10;
|
||||
|
||||
if (CurrentValue + Increment * times <= floatRange.max)
|
||||
{
|
||||
CurrentValue += Increment * times;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentValue = floatRange.max;
|
||||
}
|
||||
|
||||
AdjustButtonsActiveState();
|
||||
}
|
||||
|
||||
internal void Decrease()
|
||||
{
|
||||
int times = 1;
|
||||
if (Input.GetKey(KeyCode.LeftShift))
|
||||
times = 5;
|
||||
if (Input.GetKey(KeyCode.LeftControl))
|
||||
times = 10;
|
||||
|
||||
if (CurrentValue - Increment * times >= floatRange.min)
|
||||
{
|
||||
CurrentValue -= Increment * times;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentValue = floatRange.min;
|
||||
}
|
||||
|
||||
AdjustButtonsActiveState();
|
||||
}
|
||||
|
||||
internal void Load(float DefaultValue)
|
||||
{
|
||||
var Float = BetterDataManager.LoadSetting(Id, DefaultValue);
|
||||
|
||||
if (Float > floatRange.max || Float < floatRange.min)
|
||||
{
|
||||
Float = DefaultValue;
|
||||
BetterDataManager.SaveSetting(Id, DefaultValue);
|
||||
}
|
||||
|
||||
CurrentValue = Float;
|
||||
}
|
||||
|
||||
internal override float GetFloat()
|
||||
{
|
||||
if (BetterDataManager.CanLoadSetting<float>(Id))
|
||||
{
|
||||
return BetterDataManager.LoadSetting<float>(Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CurrentValue;
|
||||
}
|
||||
}
|
||||
|
||||
internal override int GetInt() => (int)GetFloat();
|
||||
|
||||
internal override void SetData(OptionBehaviour optionBehaviour)
|
||||
{
|
||||
optionBehaviour.data = new BaseGameSetting
|
||||
{
|
||||
Title = StringNames.None,
|
||||
Type = OptionTypes.Float,
|
||||
};
|
||||
}
|
||||
|
||||
internal override void ValueChanged(int id, OptionBehaviour optionBehaviour)
|
||||
{
|
||||
if (IsParent || IsChild)
|
||||
{
|
||||
bool Bool = ShowChildrenCondition();
|
||||
foreach (var item in ChildrenList)
|
||||
{
|
||||
item.obj.SetActive(Bool && item.SelfShowCondition());
|
||||
}
|
||||
UpdatePositions();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,209 +0,0 @@
|
||||
using BetterAmongUs.Data;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
internal class BetterOptionIntItem : BetterOptionItem
|
||||
{
|
||||
private NumberOption? ThisOption;
|
||||
internal int CurrentValue;
|
||||
internal IntRange intRange = new(0, 180);
|
||||
internal int Increment = 1;
|
||||
private string? PostFix;
|
||||
private string? PreFix;
|
||||
|
||||
internal override bool ShowChildrenCondition() => CurrentValue > intRange.min;
|
||||
internal override bool SelfShowCondition() => ShowCondition != null ? ShowCondition() : base.SelfShowCondition();
|
||||
internal Func<bool>? ShowCondition = null;
|
||||
|
||||
internal BetterOptionItem Create(int id, GameOptionsMenu gameOptionsMenu, string name, int[] values, int DefaultValue, string preFix = "", string postFix = "", BetterOptionItem? Parent = null, Func<bool>? selfShowCondition = null)
|
||||
{
|
||||
Id = id;
|
||||
intRange = new(values[0], values[1]);
|
||||
Increment = values[2];
|
||||
if (DefaultValue < intRange.min) DefaultValue = intRange.min;
|
||||
if (DefaultValue > intRange.max) DefaultValue = intRange.max;
|
||||
CurrentValue = DefaultValue;
|
||||
ShowCondition = selfShowCondition;
|
||||
|
||||
if (gameOptionsMenu == null)
|
||||
{
|
||||
Load(DefaultValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
if (values.Length is < 3 or > 3) return null;
|
||||
|
||||
NumberOption optionBehaviour = UnityEngine.Object.Instantiate(gameOptionsMenu.numberOptionOrigin, Vector3.zero, Quaternion.identity, gameOptionsMenu.settingsContainer);
|
||||
optionBehaviour.enabled = false;
|
||||
optionBehaviour.transform.localPosition = new Vector3(0.952f, 2f, -2f);
|
||||
SetUp(optionBehaviour);
|
||||
optionBehaviour.OnValueChanged = new Action<OptionBehaviour>((option) => ValueChanged(id, option));
|
||||
|
||||
optionBehaviour.PlusBtn.OnClick.RemoveAllListeners();
|
||||
optionBehaviour.MinusBtn.OnClick.RemoveAllListeners();
|
||||
optionBehaviour.PlusBtn.OnClick.AddListener(new Action(() => Increase()));
|
||||
optionBehaviour.MinusBtn.OnClick.AddListener(new Action(() => Decrease()));
|
||||
optionBehaviour.PlusBtn.OnClick.AddListener(new Action(() => ValueChanged(id, optionBehaviour)));
|
||||
optionBehaviour.MinusBtn.OnClick.AddListener(new Action(() => ValueChanged(id, optionBehaviour)));
|
||||
|
||||
optionBehaviour.LabelBackground.transform.localScale = new Vector3(1.6f, 0.78f);
|
||||
optionBehaviour.LabelBackground.transform.SetLocalX(-2.4f);
|
||||
optionBehaviour.TitleText.enableAutoSizing = false;
|
||||
optionBehaviour.TitleText.transform.SetLocalX(-1.5f);
|
||||
optionBehaviour.TitleText.alignment = TMPro.TextAlignmentOptions.Right;
|
||||
optionBehaviour.TitleText.enableWordWrapping = false;
|
||||
optionBehaviour.TitleText.fontSize = 2.5f;
|
||||
|
||||
// Set data
|
||||
Tab = gameOptionsMenu;
|
||||
Name = name;
|
||||
TitleText = optionBehaviour.TitleText;
|
||||
Option = optionBehaviour;
|
||||
PostFix = postFix;
|
||||
PreFix = preFix;
|
||||
ThisOption = optionBehaviour;
|
||||
|
||||
Load(DefaultValue);
|
||||
AdjustButtonsActiveState();
|
||||
|
||||
BetterOptionItems.Add(this);
|
||||
obj = optionBehaviour.gameObject;
|
||||
|
||||
if (Parent != null)
|
||||
{
|
||||
int Index = 1;
|
||||
var tempParent = Parent;
|
||||
|
||||
while (tempParent.ThisParent != null)
|
||||
{
|
||||
tempParent = tempParent.ThisParent;
|
||||
Index++;
|
||||
}
|
||||
|
||||
optionBehaviour.LabelBackground.GetComponent<SpriteRenderer>().color -= new Color(0.25f, 0.25f, 0.25f, 0f) * Index;
|
||||
optionBehaviour.LabelBackground.transform.localScale -= new Vector3(0.04f, 0f, 0f) * Index;
|
||||
optionBehaviour.LabelBackground.transform.position += new Vector3(0.04f, 0f, 0f) * Index;
|
||||
optionBehaviour.LabelBackground.transform.SetLocalZ(1f);
|
||||
ThisParent = Parent;
|
||||
IsChild = true;
|
||||
Parent.ChildrenList.Add(this);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void AdjustButtonsActiveState()
|
||||
{
|
||||
if (ThisOption == null) return;
|
||||
|
||||
ThisOption.ValueText.text = PreFix + CurrentValue.ToString() + PostFix;
|
||||
|
||||
if (CurrentValue + Increment > intRange.max)
|
||||
{
|
||||
ThisOption.PlusBtn.SetInteractable(false);
|
||||
ThisOption.MinusBtn.SetInteractable(true);
|
||||
}
|
||||
else if (CurrentValue - Increment < intRange.min)
|
||||
{
|
||||
ThisOption.PlusBtn.SetInteractable(true);
|
||||
ThisOption.MinusBtn.SetInteractable(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ThisOption.PlusBtn.SetInteractable(true);
|
||||
ThisOption.MinusBtn.SetInteractable(true);
|
||||
}
|
||||
|
||||
BetterDataManager.SaveSetting(Id, CurrentValue);
|
||||
}
|
||||
|
||||
internal void Increase()
|
||||
{
|
||||
int times = 1;
|
||||
if (Input.GetKey(KeyCode.LeftShift))
|
||||
times = 5;
|
||||
if (Input.GetKey(KeyCode.LeftControl))
|
||||
times = 10;
|
||||
|
||||
if (CurrentValue + Increment * times <= intRange.max)
|
||||
{
|
||||
CurrentValue += Increment * times;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentValue = intRange.max;
|
||||
}
|
||||
|
||||
AdjustButtonsActiveState();
|
||||
}
|
||||
|
||||
internal void Decrease()
|
||||
{
|
||||
int times = 1;
|
||||
if (Input.GetKey(KeyCode.LeftShift))
|
||||
times = 5;
|
||||
if (Input.GetKey(KeyCode.LeftControl))
|
||||
times = 10;
|
||||
|
||||
if (CurrentValue - Increment * times >= intRange.min)
|
||||
{
|
||||
CurrentValue -= Increment * times;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentValue = intRange.min;
|
||||
}
|
||||
|
||||
AdjustButtonsActiveState();
|
||||
}
|
||||
|
||||
internal void Load(int DefaultValue)
|
||||
{
|
||||
var Int = BetterDataManager.LoadSetting(Id, DefaultValue);
|
||||
|
||||
if (Int > intRange.max || Int < intRange.min)
|
||||
{
|
||||
Int = DefaultValue;
|
||||
BetterDataManager.SaveSetting(Id, DefaultValue);
|
||||
}
|
||||
|
||||
CurrentValue = Int;
|
||||
}
|
||||
|
||||
internal override float GetFloat() => GetInt();
|
||||
|
||||
internal override int GetInt()
|
||||
{
|
||||
if (BetterDataManager.CanLoadSetting<int>(Id))
|
||||
{
|
||||
return BetterDataManager.LoadSetting<int>(Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CurrentValue;
|
||||
}
|
||||
}
|
||||
|
||||
internal override void SetData(OptionBehaviour optionBehaviour)
|
||||
{
|
||||
optionBehaviour.data = new BaseGameSetting
|
||||
{
|
||||
Title = StringNames.None,
|
||||
Type = OptionTypes.Int,
|
||||
};
|
||||
}
|
||||
|
||||
internal override void ValueChanged(int id, OptionBehaviour optionBehaviour)
|
||||
{
|
||||
if (IsParent || IsChild)
|
||||
{
|
||||
bool Bool = ShowChildrenCondition();
|
||||
foreach (var item in ChildrenList)
|
||||
{
|
||||
item.obj.SetActive(Bool && item.SelfShowCondition());
|
||||
}
|
||||
UpdatePositions();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
using BetterAmongUs.Helpers;
|
||||
using BetterAmongUs.Patches.Gameplay.UI.Settings;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
internal class BetterOptionItem
|
||||
{
|
||||
internal float StaticSpacingNum => 1f;
|
||||
internal float StaticSpacingNumPlus => 0.45f;
|
||||
internal static Dictionary<int, int> TempPlayerOptionData = [];
|
||||
internal static int TempPlayerOptionDataNum = 0;
|
||||
internal static List<BetterOptionItem> BetterOptionItems = [];
|
||||
internal static float SpacingNum = 0;
|
||||
|
||||
internal int maskLayer = 20;
|
||||
internal int Id = 0;
|
||||
internal GameOptionsMenu? Tab;
|
||||
internal OptionBehaviour? Option;
|
||||
internal string? Name = "None";
|
||||
internal TextMeshPro? TitleText;
|
||||
internal GameObject? obj;
|
||||
|
||||
internal BetterOptionItem? ThisParent;
|
||||
internal bool IsChild = false;
|
||||
internal bool IsParent => ChildrenList.Count > 0;
|
||||
internal List<BetterOptionItem> ChildrenList = [];
|
||||
internal virtual bool ShowChildrenCondition() => false;
|
||||
internal virtual bool SelfShowCondition() => true;
|
||||
|
||||
internal static void UpdatePositions()
|
||||
{
|
||||
SpacingNum = 0f;
|
||||
|
||||
foreach (var item in BetterOptionItems)
|
||||
{
|
||||
try
|
||||
{
|
||||
item.obj.transform.SetLocalY(2f);
|
||||
|
||||
// Need to fix name not setting
|
||||
if (item.ThisParent != null)
|
||||
{
|
||||
_ = new LateTask(() =>
|
||||
{
|
||||
item.obj.SetActive(item.ThisParent.ShowChildrenCondition() && item.SelfShowCondition() && item.ThisParent.Option.gameObject.active);
|
||||
}, 0.005f, shouldLog: false);
|
||||
if (!(item.ThisParent.ShowChildrenCondition() && item.SelfShowCondition() && item.ThisParent.Option.gameObject.active))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item is BetterOptionPlayerItem player)
|
||||
{
|
||||
player.Load();
|
||||
}
|
||||
|
||||
SpacingNum += item switch
|
||||
{
|
||||
BetterOptionHeaderItem => 0.1f,
|
||||
BetterOptionDividerItem => 0.15f,
|
||||
_ => 0f,
|
||||
};
|
||||
|
||||
item.obj.transform.SetLocalY(2f - 1f * SpacingNum);
|
||||
|
||||
SpacingNum += item switch
|
||||
{
|
||||
BetterOptionHeaderItem => 0.75f,
|
||||
BetterOptionTitleItem => 0.50f,
|
||||
_ => 0.45f,
|
||||
};
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
GameSettingMenuPatch.BetterSettingsTab.scrollBar.SetYBoundsMax(1.5f * SpacingNum / 2);
|
||||
GameSettingMenuPatch.BetterSettingsTab.scrollBar.ScrollRelative(new(0f, 0f));
|
||||
}
|
||||
|
||||
internal void SetUp(OptionBehaviour optionBehaviour)
|
||||
{
|
||||
SpriteRenderer[] componentsInChildren = optionBehaviour.GetComponentsInChildren<SpriteRenderer>(true);
|
||||
for (int i = 0; i < componentsInChildren.Length; i++)
|
||||
{
|
||||
componentsInChildren[i].material.SetInt(PlayerMaterial.MaskLayer, maskLayer);
|
||||
}
|
||||
foreach (TextMeshPro textMeshPro in optionBehaviour.GetComponentsInChildren<TextMeshPro>(true))
|
||||
{
|
||||
textMeshPro.fontMaterial.SetFloat("_StencilComp", 3f);
|
||||
textMeshPro.fontMaterial.SetFloat("_Stencil", maskLayer);
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual bool GetBool()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal virtual float GetFloat()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal virtual int GetInt()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal virtual int GetValue()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal virtual void SetData(OptionBehaviour optionBehaviour)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal virtual void ValueChanged(int id, OptionBehaviour optionBehaviour)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
using BetterAmongUs.Helpers;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
internal class BetterOptionPlayerItem : BetterOptionItem
|
||||
{
|
||||
private NumberOption? ThisOption;
|
||||
internal int CurrentIndex = -1;
|
||||
|
||||
internal override bool ShowChildrenCondition() => CurrentIndex > -1;
|
||||
internal override bool SelfShowCondition() => ShowCondition != null ? ShowCondition() : base.SelfShowCondition();
|
||||
internal Func<bool>? ShowCondition = null;
|
||||
|
||||
internal BetterOptionItem Create(GameOptionsMenu gameOptionsMenu, string name, BetterOptionItem? Parent = null, Func<bool>? selfShowCondition = null)
|
||||
{
|
||||
Id = TempPlayerOptionDataNum + 1;
|
||||
Tab = gameOptionsMenu;
|
||||
Name = name;
|
||||
ShowCondition = selfShowCondition;
|
||||
|
||||
if (gameOptionsMenu == null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
NumberOption optionBehaviour = UnityEngine.Object.Instantiate(gameOptionsMenu.numberOptionOrigin, Vector3.zero, Quaternion.identity, gameOptionsMenu.settingsContainer);
|
||||
optionBehaviour.enabled = false;
|
||||
optionBehaviour.transform.localPosition = new Vector3(0.952f, 2f, -2f);
|
||||
SetUp(optionBehaviour);
|
||||
optionBehaviour.OnValueChanged = new Action<OptionBehaviour>((option) => ValueChanged(0, option));
|
||||
|
||||
optionBehaviour.PlusBtn.OnClick.RemoveAllListeners();
|
||||
optionBehaviour.MinusBtn.OnClick.RemoveAllListeners();
|
||||
optionBehaviour.PlusBtn.OnClick.AddListener(new Action(() => Increase()));
|
||||
optionBehaviour.MinusBtn.OnClick.AddListener(new Action(() => Decrease()));
|
||||
optionBehaviour.PlusBtn.OnClick.AddListener(new Action(() => ValueChanged(Id, optionBehaviour)));
|
||||
optionBehaviour.MinusBtn.OnClick.AddListener(new Action(() => ValueChanged(Id, optionBehaviour)));
|
||||
|
||||
optionBehaviour.LabelBackground.transform.localScale = new Vector3(1.6f, 0.78f);
|
||||
optionBehaviour.LabelBackground.transform.SetLocalX(-2.4f);
|
||||
optionBehaviour.TitleText.enableAutoSizing = false;
|
||||
optionBehaviour.TitleText.transform.SetLocalX(-1.5f);
|
||||
optionBehaviour.TitleText.alignment = TMPro.TextAlignmentOptions.Right;
|
||||
optionBehaviour.TitleText.enableWordWrapping = false;
|
||||
optionBehaviour.TitleText.fontSize = 2.5f;
|
||||
|
||||
// Set data
|
||||
TitleText = optionBehaviour.TitleText;
|
||||
Option = optionBehaviour;
|
||||
ThisOption = optionBehaviour;
|
||||
|
||||
Load();
|
||||
BetterOptionItems.Add(this);
|
||||
obj = optionBehaviour.gameObject;
|
||||
|
||||
if (Parent != null)
|
||||
{
|
||||
int Index = 1;
|
||||
var tempParent = Parent;
|
||||
|
||||
while (tempParent.ThisParent != null)
|
||||
{
|
||||
tempParent = tempParent.ThisParent;
|
||||
Index++;
|
||||
}
|
||||
|
||||
optionBehaviour.LabelBackground.GetComponent<SpriteRenderer>().color -= new Color(0.25f, 0.25f, 0.25f, 0f) * Index;
|
||||
optionBehaviour.LabelBackground.transform.localScale -= new Vector3(0.04f, 0f, 0f) * Index;
|
||||
optionBehaviour.LabelBackground.transform.position += new Vector3(0.04f, 0f, 0f) * Index;
|
||||
optionBehaviour.LabelBackground.transform.SetLocalZ(1f);
|
||||
ThisParent = Parent;
|
||||
IsChild = true;
|
||||
Parent.ChildrenList.Add(this);
|
||||
}
|
||||
|
||||
TempPlayerOptionDataNum++;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void AdjustButtonsActiveState()
|
||||
{
|
||||
if (ThisOption == null) return;
|
||||
|
||||
if (CurrentIndex >= 0)
|
||||
{
|
||||
ThisOption.ValueText.text = Utils.PlayerFromPlayerId(CurrentIndex).GetPlayerNameAndColor();
|
||||
}
|
||||
else
|
||||
{
|
||||
ThisOption.ValueText.text = "<color=#ababab>Random</color>";
|
||||
}
|
||||
|
||||
if (CurrentIndex >= BAUPlugin.AllPlayerControls.Count - 1)
|
||||
{
|
||||
ThisOption.PlusBtn.SetInteractable(false);
|
||||
ThisOption.MinusBtn.SetInteractable(true);
|
||||
}
|
||||
else if (CurrentIndex <= -1)
|
||||
{
|
||||
ThisOption.PlusBtn.SetInteractable(true);
|
||||
ThisOption.MinusBtn.SetInteractable(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ThisOption.PlusBtn.SetInteractable(true);
|
||||
ThisOption.MinusBtn.SetInteractable(true);
|
||||
}
|
||||
|
||||
TempPlayerOptionData[Id] = CurrentIndex;
|
||||
}
|
||||
|
||||
internal void Increase()
|
||||
{
|
||||
if (CurrentIndex < BAUPlugin.AllPlayerControls.Count)
|
||||
{
|
||||
CurrentIndex++;
|
||||
AdjustButtonsActiveState();
|
||||
}
|
||||
}
|
||||
|
||||
internal void Decrease()
|
||||
{
|
||||
if (CurrentIndex > -1)
|
||||
{
|
||||
CurrentIndex--;
|
||||
AdjustButtonsActiveState();
|
||||
}
|
||||
}
|
||||
|
||||
internal int Load()
|
||||
{
|
||||
if (TempPlayerOptionData.ContainsKey(Id))
|
||||
{
|
||||
var saveindex = TempPlayerOptionData[Id];
|
||||
|
||||
if (saveindex != -1 && Utils.PlayerFromPlayerId(saveindex) == null)
|
||||
saveindex = BAUPlugin.AllPlayerControls.Count - 1;
|
||||
|
||||
CurrentIndex = saveindex;
|
||||
}
|
||||
else
|
||||
{
|
||||
TempPlayerOptionData[Id] = -1;
|
||||
CurrentIndex = TempPlayerOptionData[Id];
|
||||
}
|
||||
|
||||
AdjustButtonsActiveState();
|
||||
|
||||
return CurrentIndex;
|
||||
}
|
||||
|
||||
internal override int GetValue()
|
||||
{
|
||||
if (SelfShowCondition())
|
||||
{
|
||||
return Load();
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
internal override void SetData(OptionBehaviour optionBehaviour)
|
||||
{
|
||||
optionBehaviour.data = new BaseGameSetting
|
||||
{
|
||||
Title = StringNames.None,
|
||||
Type = OptionTypes.Int,
|
||||
};
|
||||
}
|
||||
|
||||
internal override void ValueChanged(int id, OptionBehaviour optionBehaviour)
|
||||
{
|
||||
if (IsParent || IsChild)
|
||||
{
|
||||
bool Bool = ShowChildrenCondition();
|
||||
foreach (var item in ChildrenList)
|
||||
{
|
||||
item.obj.SetActive(Bool && item.SelfShowCondition());
|
||||
}
|
||||
UpdatePositions();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
using BetterAmongUs.Data;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
internal class BetterOptionStringItem : BetterOptionItem
|
||||
{
|
||||
private StringOption? ThisOption;
|
||||
internal string[] Values = [];
|
||||
internal int CurrentValue;
|
||||
|
||||
internal override bool ShowChildrenCondition() => CurrentValue > 0;
|
||||
internal override bool SelfShowCondition() => ShowCondition != null ? ShowCondition() : base.SelfShowCondition();
|
||||
internal Func<bool>? ShowCondition = null;
|
||||
|
||||
internal BetterOptionItem Create(int id, GameOptionsMenu gameOptionsMenu, string name, string[] strings, int DefaultValue = 0, BetterOptionItem? Parent = null, Func<bool>? selfShowCondition = null)
|
||||
{
|
||||
Id = id;
|
||||
Values = strings;
|
||||
Tab = gameOptionsMenu;
|
||||
Name = name;
|
||||
if (DefaultValue < 0) DefaultValue = 0;
|
||||
if (DefaultValue > Values.Length) DefaultValue = Values.Length;
|
||||
CurrentValue = DefaultValue;
|
||||
ShowCondition = selfShowCondition;
|
||||
|
||||
if (gameOptionsMenu == null)
|
||||
{
|
||||
Load(DefaultValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
StringOption optionBehaviour = UnityEngine.Object.Instantiate(gameOptionsMenu.stringOptionOrigin, Vector3.zero, Quaternion.identity, gameOptionsMenu.settingsContainer);
|
||||
optionBehaviour.enabled = false;
|
||||
optionBehaviour.transform.localPosition = new Vector3(0.952f, 2f, -2f);
|
||||
SetUp(optionBehaviour);
|
||||
optionBehaviour.OnValueChanged = new Action<OptionBehaviour>((option) => ValueChanged(id, option));
|
||||
|
||||
optionBehaviour.PlusBtn.OnClick.RemoveAllListeners();
|
||||
optionBehaviour.MinusBtn.OnClick.RemoveAllListeners();
|
||||
optionBehaviour.PlusBtn.OnClick.AddListener(new Action(() => Increase()));
|
||||
optionBehaviour.MinusBtn.OnClick.AddListener(new Action(() => Decrease()));
|
||||
optionBehaviour.PlusBtn.OnClick.AddListener(new Action(() => ValueChanged(id, optionBehaviour)));
|
||||
optionBehaviour.MinusBtn.OnClick.AddListener(new Action(() => ValueChanged(id, optionBehaviour)));
|
||||
|
||||
optionBehaviour.LabelBackground.transform.localScale = new Vector3(1.6f, 0.78f);
|
||||
optionBehaviour.LabelBackground.transform.SetLocalX(-2.4f);
|
||||
optionBehaviour.TitleText.enableAutoSizing = false;
|
||||
optionBehaviour.TitleText.transform.SetLocalX(-1.5f);
|
||||
optionBehaviour.TitleText.alignment = TMPro.TextAlignmentOptions.Right;
|
||||
optionBehaviour.TitleText.enableWordWrapping = false;
|
||||
optionBehaviour.TitleText.fontSize = 2.5f;
|
||||
|
||||
// Set data
|
||||
TitleText = optionBehaviour.TitleText;
|
||||
Option = optionBehaviour;
|
||||
ThisOption = optionBehaviour;
|
||||
|
||||
Load(DefaultValue);
|
||||
AdjustButtonsActiveState();
|
||||
|
||||
BetterOptionItems.Add(this);
|
||||
obj = optionBehaviour.gameObject;
|
||||
|
||||
if (Parent != null)
|
||||
{
|
||||
int Index = 1;
|
||||
var tempParent = Parent;
|
||||
|
||||
while (tempParent.ThisParent != null)
|
||||
{
|
||||
tempParent = tempParent.ThisParent;
|
||||
Index++;
|
||||
}
|
||||
|
||||
optionBehaviour.LabelBackground.GetComponent<SpriteRenderer>().color -= new Color(0.25f, 0.25f, 0.25f, 0f) * Index;
|
||||
optionBehaviour.LabelBackground.transform.localScale -= new Vector3(0.04f, 0f, 0f) * Index;
|
||||
optionBehaviour.LabelBackground.transform.position += new Vector3(0.04f, 0f, 0f) * Index;
|
||||
optionBehaviour.LabelBackground.transform.SetLocalZ(1f);
|
||||
ThisParent = Parent;
|
||||
IsChild = true;
|
||||
Parent.ChildrenList.Add(this);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void AdjustButtonsActiveState()
|
||||
{
|
||||
if (ThisOption == null) return;
|
||||
|
||||
if (CurrentValue <= Values.Length - 1 && CurrentValue >= 0)
|
||||
{
|
||||
ThisOption.ValueText.text = Values[CurrentValue];
|
||||
}
|
||||
|
||||
if (CurrentValue >= Values.Length - 1)
|
||||
{
|
||||
ThisOption.PlusBtn.SetInteractable(false);
|
||||
ThisOption.MinusBtn.SetInteractable(true);
|
||||
}
|
||||
else if (CurrentValue <= 0)
|
||||
{
|
||||
ThisOption.PlusBtn.SetInteractable(true);
|
||||
ThisOption.MinusBtn.SetInteractable(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ThisOption.PlusBtn.SetInteractable(true);
|
||||
ThisOption.MinusBtn.SetInteractable(true);
|
||||
}
|
||||
|
||||
BetterDataManager.SaveSetting(Id, CurrentValue);
|
||||
}
|
||||
|
||||
internal void Increase()
|
||||
{
|
||||
if (CurrentValue < Values.Length)
|
||||
{
|
||||
CurrentValue++;
|
||||
AdjustButtonsActiveState();
|
||||
}
|
||||
}
|
||||
|
||||
internal void Decrease()
|
||||
{
|
||||
if (CurrentValue > 0)
|
||||
{
|
||||
CurrentValue--;
|
||||
AdjustButtonsActiveState();
|
||||
}
|
||||
}
|
||||
|
||||
internal void Load(int DefaultValue)
|
||||
{
|
||||
var Int = BetterDataManager.LoadSetting(Id, DefaultValue);
|
||||
|
||||
if (Int > Values.Length - 1 || Int < 0)
|
||||
{
|
||||
Int = DefaultValue;
|
||||
BetterDataManager.SaveSetting(Id, DefaultValue);
|
||||
}
|
||||
|
||||
CurrentValue = Int;
|
||||
}
|
||||
|
||||
internal override int GetValue()
|
||||
{
|
||||
if (BetterDataManager.CanLoadSetting<int>(Id))
|
||||
{
|
||||
return BetterDataManager.LoadSetting<int>(Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CurrentValue;
|
||||
}
|
||||
}
|
||||
|
||||
internal override void SetData(OptionBehaviour optionBehaviour)
|
||||
{
|
||||
optionBehaviour.data = new BaseGameSetting
|
||||
{
|
||||
Title = StringNames.None,
|
||||
Type = OptionTypes.String,
|
||||
};
|
||||
}
|
||||
|
||||
internal override void ValueChanged(int id, OptionBehaviour optionBehaviour)
|
||||
{
|
||||
if (IsParent || IsChild)
|
||||
{
|
||||
bool Bool = ShowChildrenCondition();
|
||||
foreach (var item in ChildrenList)
|
||||
{
|
||||
item.obj.SetActive(Bool && item.SelfShowCondition());
|
||||
}
|
||||
UpdatePositions();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using BetterAmongUs.Helpers;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
internal class BetterOptionDividerItem : BetterOptionItem
|
||||
{
|
||||
internal BetterOptionItem Create(GameOptionsMenu gameOptionsMenu)
|
||||
{
|
||||
if (gameOptionsMenu == null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
Tab = gameOptionsMenu;
|
||||
Name = "Divider";
|
||||
CategoryHeaderMasked categoryHeaderMasked = UnityEngine.Object.Instantiate(gameOptionsMenu.categoryHeaderOrigin, Vector3.zero, Quaternion.identity, gameOptionsMenu.settingsContainer);
|
||||
categoryHeaderMasked.transform.localScale = Vector3.one * 0.63f;
|
||||
categoryHeaderMasked.transform.localPosition = new Vector3(-0.903f, 2f, -2f);
|
||||
categoryHeaderMasked.Background.gameObject.DestroyObj();
|
||||
categoryHeaderMasked.Title.gameObject.DestroyObj();
|
||||
if (categoryHeaderMasked.Divider != null)
|
||||
{
|
||||
categoryHeaderMasked.Divider.material.SetInt(PlayerMaterial.MaskLayer, maskLayer);
|
||||
}
|
||||
|
||||
BetterOptionItems.Add(this);
|
||||
obj = categoryHeaderMasked.gameObject;
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
internal class BetterOptionHeaderItem : BetterOptionItem
|
||||
{
|
||||
internal BetterOptionItem Create(GameOptionsMenu gameOptionsMenu, string name)
|
||||
{
|
||||
if (gameOptionsMenu == null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
Tab = gameOptionsMenu;
|
||||
Name = name;
|
||||
CategoryHeaderMasked categoryHeaderMasked = UnityEngine.Object.Instantiate(gameOptionsMenu.categoryHeaderOrigin, Vector3.zero, Quaternion.identity, gameOptionsMenu.settingsContainer);
|
||||
categoryHeaderMasked.transform.localScale = Vector3.one * 0.63f;
|
||||
categoryHeaderMasked.transform.localPosition = new Vector3(-0.903f, 2f, -2f);
|
||||
categoryHeaderMasked.Title.text = name;
|
||||
categoryHeaderMasked.Background.material.SetInt(PlayerMaterial.MaskLayer, maskLayer);
|
||||
if (categoryHeaderMasked.Divider != null)
|
||||
{
|
||||
categoryHeaderMasked.Divider.material.SetInt(PlayerMaterial.MaskLayer, maskLayer);
|
||||
}
|
||||
categoryHeaderMasked.Title.fontMaterial.SetFloat("_StencilComp", 3f);
|
||||
categoryHeaderMasked.Title.fontMaterial.SetFloat("_Stencil", maskLayer);
|
||||
|
||||
BetterOptionItems.Add(this);
|
||||
obj = categoryHeaderMasked.gameObject;
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
using BetterAmongUs.Helpers;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
internal class BetterOptionTitleItem : BetterOptionItem
|
||||
{
|
||||
internal BetterOptionItem Create(GameOptionsMenu gameOptionsMenu, string name)
|
||||
{
|
||||
if (gameOptionsMenu == null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
ToggleOption optionBehaviour = UnityEngine.Object.Instantiate(gameOptionsMenu.checkboxOrigin, Vector3.zero, Quaternion.identity, gameOptionsMenu.settingsContainer);
|
||||
optionBehaviour.transform.localPosition = new Vector3(0.952f, 2f, -2f);
|
||||
SetUp(optionBehaviour);
|
||||
|
||||
optionBehaviour.CheckMark.transform.parent.gameObject.DestroyObj();
|
||||
optionBehaviour.GetComponent<ToggleOption>().DestroyMono();
|
||||
optionBehaviour.TitleText.alignment = TMPro.TextAlignmentOptions.Center;
|
||||
optionBehaviour.TitleText.outlineColor = Color.black;
|
||||
optionBehaviour.TitleText.outlineWidth = 0.2f;
|
||||
optionBehaviour.TitleText.transform.localPosition += new Vector3(0f, 0.05f, 0f);
|
||||
optionBehaviour.LabelBackground.color = new Color(0.6f, 0.6f, 0.6f, 1f);
|
||||
optionBehaviour.LabelBackground.transform.SetLocalZ(1f);
|
||||
|
||||
optionBehaviour.LabelBackground.transform.localScale = new Vector3(1.6f, 1f);
|
||||
optionBehaviour.LabelBackground.transform.SetLocalX(-2.4f);
|
||||
optionBehaviour.TitleText.enableAutoSizing = false;
|
||||
optionBehaviour.TitleText.transform.SetLocalX(-2.4f);
|
||||
optionBehaviour.TitleText.alignment = TMPro.TextAlignmentOptions.Center;
|
||||
optionBehaviour.TitleText.enableWordWrapping = false;
|
||||
optionBehaviour.TitleText.fontSize = 2.5f;
|
||||
|
||||
// Set data
|
||||
Tab = gameOptionsMenu;
|
||||
Name = $"<b><size=150%>{name}</size></b>";
|
||||
Option = optionBehaviour;
|
||||
TitleText = optionBehaviour.TitleText;
|
||||
|
||||
BetterOptionItems.Add(this);
|
||||
obj = optionBehaviour.gameObject;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
internal override void SetData(OptionBehaviour optionBehaviour)
|
||||
{
|
||||
optionBehaviour.data = new BaseGameSetting
|
||||
{
|
||||
Title = StringNames.None,
|
||||
Type = OptionTypes.Checkbox,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using BetterAmongUs.Helpers;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems.NoneOption;
|
||||
|
||||
internal class OptionDividerItem : OptionItem
|
||||
{
|
||||
internal override bool CanLoad => false;
|
||||
internal override bool IsOption => false;
|
||||
internal (float top, float bottom) Distance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new divider item for the options menu. The divider is placed within the specified tab with configurable top and bottom distances.
|
||||
/// </summary>
|
||||
/// <param name="tab">The tab where the divider item will be placed.</param>
|
||||
/// <param name="topDistance">The distance from the top of the tab to the divider. Default is 0.26f.</param>
|
||||
/// <param name="bottomDistance">The distance from the bottom of the tab to the divider. Default is 0.50f.</param>
|
||||
/// <returns>The created <see cref="OptionDividerItem"/> instance.</returns>
|
||||
internal static OptionDividerItem Create(OptionTab tab, float topDistance = 0.26f, float bottomDistance = 0.50f)
|
||||
{
|
||||
var Item = new OptionDividerItem
|
||||
{
|
||||
Tab = tab,
|
||||
Distance = (topDistance, bottomDistance)
|
||||
};
|
||||
Item.CreateBehavior();
|
||||
|
||||
return Item;
|
||||
}
|
||||
|
||||
protected void CreateBehavior()
|
||||
{
|
||||
if (!GameSettingMenu.Instance) return;
|
||||
AllTBROptionsTemp.Add(this);
|
||||
CategoryHeaderMasked categoryHeaderMasked = UnityEngine.Object.Instantiate(Tab.AUTab.categoryHeaderOrigin, Tab.AUTab.settingsContainer);
|
||||
Obj = categoryHeaderMasked.gameObject;
|
||||
categoryHeaderMasked.transform.localScale = Vector3.one * 0.63f;
|
||||
categoryHeaderMasked.Background.gameObject.DestroyObj();
|
||||
categoryHeaderMasked.Title.DestroyObj();
|
||||
if (categoryHeaderMasked.Divider != null)
|
||||
{
|
||||
categoryHeaderMasked.Divider.material.SetInt(PlayerMaterial.MaskLayer, MaskLayer);
|
||||
}
|
||||
Tab.Children.Add(this);
|
||||
}
|
||||
|
||||
internal override string ValueAsString()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems.NoneOption;
|
||||
|
||||
internal class OptionHeaderItem : OptionItem
|
||||
{
|
||||
private CategoryHeaderMasked categoryHeaderMasked;
|
||||
internal override bool CanLoad => false;
|
||||
internal override bool IsOption => false;
|
||||
internal (float top, float bottom) Distance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new header item for the options menu. The header is placed within the specified tab with configurable top and bottom distances.
|
||||
/// </summary>
|
||||
/// <param name="tab">The tab where the header item will be placed.</param>
|
||||
/// <param name="tranStr">The translation string for the header item.</param>
|
||||
/// <param name="topDistance">The distance from the top of the tab to the header. Default is 0.35f.</param>
|
||||
/// <param name="bottomDistance">The distance from the bottom of the tab to the header. Default is 0.80f.</param>
|
||||
/// <returns>The created <see cref="OptionHeaderItem"/> instance.</returns>
|
||||
internal static OptionHeaderItem Create(OptionTab tab, string tranStr, float topDistance = 0.35f, float bottomDistance = 0.80f)
|
||||
{
|
||||
var Item = new OptionHeaderItem
|
||||
{
|
||||
Translation = tranStr,
|
||||
Tab = tab,
|
||||
Distance = (topDistance, bottomDistance)
|
||||
};
|
||||
Item.CreateBehavior();
|
||||
|
||||
return Item;
|
||||
}
|
||||
|
||||
protected void CreateBehavior()
|
||||
{
|
||||
if (!GameSettingMenu.Instance) return;
|
||||
AllTBROptionsTemp.Add(this);
|
||||
categoryHeaderMasked = UnityEngine.Object.Instantiate(Tab.AUTab.categoryHeaderOrigin, Tab.AUTab.settingsContainer);
|
||||
Obj = categoryHeaderMasked.gameObject;
|
||||
categoryHeaderMasked.transform.localScale = Vector3.one * 0.63f;
|
||||
categoryHeaderMasked.transform.localPosition = new Vector3(-0.903f, 2f, -2f);
|
||||
categoryHeaderMasked.Title.text = Name;
|
||||
categoryHeaderMasked.Title.outlineColor = Color.black;
|
||||
categoryHeaderMasked.Title.outlineWidth = 0.2f;
|
||||
categoryHeaderMasked.Title.fontSizeMax = 5f;
|
||||
categoryHeaderMasked.Background.material.SetInt(PlayerMaterial.MaskLayer, MaskLayer);
|
||||
if (categoryHeaderMasked.Divider != null)
|
||||
{
|
||||
categoryHeaderMasked.Divider.material.SetInt(PlayerMaterial.MaskLayer, MaskLayer);
|
||||
}
|
||||
categoryHeaderMasked.Title.fontMaterial.SetFloat("_StencilComp", 3f);
|
||||
categoryHeaderMasked.Title.fontMaterial.SetFloat("_Stencil", MaskLayer);
|
||||
Tab.Children.Add(this);
|
||||
}
|
||||
|
||||
internal override void UpdateVisuals(bool updateTabVisuals = true)
|
||||
{
|
||||
if (categoryHeaderMasked != null)
|
||||
{
|
||||
categoryHeaderMasked.Title.text = Name;
|
||||
}
|
||||
}
|
||||
|
||||
internal override string ValueAsString()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using BetterAmongUs.Helpers;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems.NoneOption;
|
||||
|
||||
internal class OptionTitleItem : OptionItem
|
||||
{
|
||||
private ToggleOption optionBehaviour;
|
||||
internal override bool CanLoad => false;
|
||||
internal (float top, float bottom) Distance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new title item for the options menu. The title is placed within the specified tab with configurable top and bottom distances.
|
||||
/// </summary>
|
||||
/// <param name="tab">The tab where the title item will be placed.</param>
|
||||
/// <param name="tranStr">The translation string for the title item.</param>
|
||||
/// <param name="topDistance">The distance from the top of the tab to the title. Default is 0.15f.</param>
|
||||
/// <param name="bottomDistance">The distance from the bottom of the tab to the title. Default is 0.50f.</param>
|
||||
/// <returns>The created <see cref="OptionTitleItem"/> instance.</returns>
|
||||
internal static OptionTitleItem Create(OptionTab tab, string tranStr, float topDistance = 0.15f, float bottomDistance = 0.50f)
|
||||
{
|
||||
var Item = new OptionTitleItem
|
||||
{
|
||||
Translation = tranStr,
|
||||
Tab = tab,
|
||||
Distance = (topDistance, bottomDistance)
|
||||
};
|
||||
Item.CreateBehavior();
|
||||
|
||||
return Item;
|
||||
}
|
||||
|
||||
protected void CreateBehavior()
|
||||
{
|
||||
if (!GameSettingMenu.Instance) return;
|
||||
AllTBROptionsTemp.Add(this);
|
||||
optionBehaviour = UnityEngine.Object.Instantiate(Tab.AUTab.checkboxOrigin, Tab.AUTab.settingsContainer);
|
||||
Obj = optionBehaviour.gameObject;
|
||||
optionBehaviour.transform.localPosition = new Vector3(0.952f, 2f, -2f);
|
||||
SetupAUOption(optionBehaviour);
|
||||
|
||||
optionBehaviour.CheckMark.transform.parent.gameObject.DestroyObj();
|
||||
optionBehaviour.GetComponent<ToggleOption>().DestroyMono();
|
||||
optionBehaviour.TitleText.DestroyTextTranslators();
|
||||
optionBehaviour.TitleText.text = Name;
|
||||
optionBehaviour.TitleText.alignment = TMPro.TextAlignmentOptions.Center;
|
||||
optionBehaviour.TitleText.outlineColor = Color.black;
|
||||
optionBehaviour.TitleText.outlineWidth = 0.2f;
|
||||
optionBehaviour.TitleText.transform.localPosition += new Vector3(0f, 0.05f, 0f);
|
||||
optionBehaviour.LabelBackground.color = new Color(0.6f, 0.6f, 0.6f, 1f);
|
||||
optionBehaviour.LabelBackground.transform.SetLocalZ(1f);
|
||||
|
||||
optionBehaviour.LabelBackground.transform.localScale = new Vector3(1.6f, 1f);
|
||||
optionBehaviour.LabelBackground.transform.SetLocalX(-2.4f);
|
||||
optionBehaviour.TitleText.enableAutoSizing = false;
|
||||
optionBehaviour.TitleText.transform.SetLocalX(-2.4f);
|
||||
optionBehaviour.TitleText.alignment = TMPro.TextAlignmentOptions.Center;
|
||||
optionBehaviour.TitleText.enableWordWrapping = false;
|
||||
optionBehaviour.TitleText.fontSize = 3.5f;
|
||||
Tab.Children.Add(this);
|
||||
}
|
||||
|
||||
internal override void UpdateVisuals(bool updateTabVisuals = true)
|
||||
{
|
||||
if (optionBehaviour != null)
|
||||
{
|
||||
optionBehaviour.TitleText.text = Name;
|
||||
}
|
||||
}
|
||||
|
||||
internal override string ValueAsString()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using BetterAmongUs.Helpers;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
internal class OptionCheckboxItem : OptionItem<bool>
|
||||
{
|
||||
internal override bool ShowChildren => base.ShowChildren && Value;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new checkbox item for the options menu. If an item with the specified ID already exists,
|
||||
/// it reuses the existing item and sets up its behavior.
|
||||
/// </summary>
|
||||
/// <param name="id">The unique identifier for the checkbox item.</param>
|
||||
/// <param name="tab">The tab to which the checkbox item belongs.</param>
|
||||
/// <param name="tranStr">The translation string for the checkbox item label.</param>
|
||||
/// <param name="defaultValue">The default value (checked/unchecked) for the checkbox.</param>
|
||||
/// <param name="parent">An optional parent option item that this checkbox item belongs to.</param>
|
||||
/// <param name="vanillaOption">An optional vanilla option name, if any, for this checkbox item.</param>
|
||||
/// <returns>The created or reused <see cref="OptionCheckboxItem"/> instance.</returns>
|
||||
internal static OptionCheckboxItem Create(int id, OptionTab tab, string tranStr, bool defaultValue, OptionItem parent = null)
|
||||
{
|
||||
if (GetOptionById(id) is OptionCheckboxItem checkboxItem)
|
||||
{
|
||||
checkboxItem.CreateBehavior();
|
||||
return checkboxItem;
|
||||
}
|
||||
|
||||
OptionCheckboxItem Item = new();
|
||||
AllTBROptions.Add(Item);
|
||||
Item._id = id;
|
||||
Item.Tab = tab;
|
||||
Item.Translation = tranStr;
|
||||
Item.DefaultValue = defaultValue;
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
Item.Parent = parent;
|
||||
parent.Children.Add(Item);
|
||||
}
|
||||
|
||||
Item.CreateBehavior();
|
||||
return Item;
|
||||
}
|
||||
|
||||
protected override void CreateBehavior()
|
||||
{
|
||||
TryLoad();
|
||||
if (!GameSettingMenu.Instance) return;
|
||||
AllTBROptionsTemp.Add(this);
|
||||
var ToggleOption = UnityEngine.Object.Instantiate(Tab.AUTab.checkboxOrigin, Tab.AUTab.settingsContainer);
|
||||
Option = ToggleOption;
|
||||
Obj = Option.gameObject;
|
||||
Option.enabled = false;
|
||||
Tab.Children.Add(this);
|
||||
TitleTMP = ToggleOption.TitleText;
|
||||
SetupText(ToggleOption.TitleText);
|
||||
SetupOptionBehavior();
|
||||
SetOptionVisuals();
|
||||
}
|
||||
|
||||
protected override void SetupOptionBehavior()
|
||||
{
|
||||
if (Option is ToggleOption toggleOption)
|
||||
{
|
||||
SetupAUOption(Option);
|
||||
toggleOption.DestroyTextTranslators();
|
||||
toggleOption.TitleText.text = Name;
|
||||
var button = toggleOption.buttons[0];
|
||||
button.OnClick = new();
|
||||
button.OnClick.AddListener((Action)(() => SetValue(!Value)));
|
||||
}
|
||||
}
|
||||
|
||||
internal override void UpdateVisuals(bool updateTabVisuals = true)
|
||||
{
|
||||
if (Option is ToggleOption toggleOption)
|
||||
{
|
||||
toggleOption.CheckMark.enabled = Value;
|
||||
}
|
||||
|
||||
if (updateTabVisuals)
|
||||
{
|
||||
Tab.UpdateVisuals();
|
||||
}
|
||||
}
|
||||
|
||||
internal override string ValueAsString()
|
||||
{
|
||||
Color color = Value ? Color.green : Color.red;
|
||||
string @bool = Value ? "On" : "Off";
|
||||
return $"<color={Colors.Color32ToHex(color)}>{@bool}</color>";
|
||||
}
|
||||
|
||||
internal override bool GetBool() => GetValue();
|
||||
internal override bool Is(bool @bool) => @bool == GetBool();
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
using BetterAmongUs.Helpers;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
internal class OptionFloatItem : OptionItem<float>
|
||||
{
|
||||
internal override bool ShowChildren => base.ShowChildren && Value > 0f;
|
||||
protected FloatRange Range { get; set; }
|
||||
protected float Increment { get; set; }
|
||||
protected bool CanBeInfinite { get; set; }
|
||||
protected (string prefix, string postfix) Fixs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new float item for the options menu. If an item with the specified ID already exists,
|
||||
/// it reuses the existing item and sets up its behavior.
|
||||
/// </summary>
|
||||
/// <param name="id">The unique identifier for the float item.</param>
|
||||
/// <param name="tab">The tab to which the float item belongs.</param>
|
||||
/// <param name="tranStr">The translation string for the float item label.</param>
|
||||
/// <param name="Min_Max_Increment">A tuple containing the minimum value, maximum value, and increment value for the float item's range.</param>
|
||||
/// <param name="defaultValue">The default value for the float item.</param>
|
||||
/// <param name="Prefix_Postfix">A tuple containing the prefix and postfix to be displayed alongside the float value.</param>
|
||||
/// <param name="parent">An optional parent option item that this float item belongs to.</param>
|
||||
/// <param name="canBeInfinite">A flag indicating whether the float value can be infinite.</param>
|
||||
/// <param name="vanillaOption">An optional vanilla option name, if any, for this float item.</param>
|
||||
/// <returns>The created or reused <see cref="OptionFloatItem"/> instance.</returns>
|
||||
internal static OptionFloatItem Create(int id, OptionTab tab, string tranStr, (float minValue, float maxValue, float incrementValue) Min_Max_Increment, float defaultValue, (string prefix, string postfix) Prefix_Postfix = new(), OptionItem parent = null, bool canBeInfinite = false)
|
||||
{
|
||||
if (GetOptionById(id) is OptionFloatItem floatItem)
|
||||
{
|
||||
floatItem.CreateBehavior();
|
||||
return floatItem;
|
||||
}
|
||||
|
||||
OptionFloatItem Item = new();
|
||||
AllTBROptions.Add(Item);
|
||||
Item._id = id;
|
||||
Item.Tab = tab;
|
||||
Item.Translation = tranStr;
|
||||
Item.Increment = Min_Max_Increment.incrementValue;
|
||||
Item.CanBeInfinite = canBeInfinite;
|
||||
Item.Range = new FloatRange(Min_Max_Increment.minValue, Min_Max_Increment.maxValue);
|
||||
Item.DefaultValue = defaultValue;
|
||||
Item.Fixs = Prefix_Postfix;
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
Item.Parent = parent;
|
||||
parent.Children.Add(Item);
|
||||
}
|
||||
|
||||
Item.CreateBehavior();
|
||||
return Item;
|
||||
}
|
||||
|
||||
protected override void CreateBehavior()
|
||||
{
|
||||
TryLoad();
|
||||
if (!GameSettingMenu.Instance) return;
|
||||
AllTBROptionsTemp.Add(this);
|
||||
var numberOption = UnityEngine.Object.Instantiate(Tab.AUTab.numberOptionOrigin, Tab.AUTab.settingsContainer);
|
||||
Option = numberOption;
|
||||
Obj = Option.gameObject;
|
||||
Option.enabled = false;
|
||||
Tab.Children.Add(this);
|
||||
TitleTMP = numberOption.TitleText;
|
||||
ValueTMP = numberOption.ValueText;
|
||||
SetupText(numberOption.TitleText);
|
||||
SetupOptionBehavior();
|
||||
SetOptionVisuals();
|
||||
}
|
||||
|
||||
protected override void SetupOptionBehavior()
|
||||
{
|
||||
if (Option is NumberOption numberOption)
|
||||
{
|
||||
SetupAUOption(Option);
|
||||
numberOption.DestroyTextTranslators();
|
||||
numberOption.TitleText.text = Name;
|
||||
numberOption.PlusBtn.OnClick = new();
|
||||
numberOption.PlusBtn.OnClick.AddListener((Action)(() => Increase()));
|
||||
numberOption.MinusBtn.OnClick = new();
|
||||
numberOption.MinusBtn.OnClick.AddListener((Action)(() => Decrease()));
|
||||
}
|
||||
}
|
||||
|
||||
protected void Increase()
|
||||
{
|
||||
int plus = 1;
|
||||
if (Input.GetKey(KeyCode.LeftShift))
|
||||
plus = 5;
|
||||
if (Input.GetKey(KeyCode.LeftControl))
|
||||
plus = 10;
|
||||
if (Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.LeftControl))
|
||||
plus = 25;
|
||||
var value = Value;
|
||||
value += Increment * plus;
|
||||
SetValue(value);
|
||||
}
|
||||
|
||||
protected void Decrease()
|
||||
{
|
||||
int plus = 1;
|
||||
if (Input.GetKey(KeyCode.LeftShift))
|
||||
plus = 5;
|
||||
if (Input.GetKey(KeyCode.LeftControl))
|
||||
plus = 10;
|
||||
if (Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.LeftControl))
|
||||
plus = 25;
|
||||
var value = Value;
|
||||
value -= Increment * plus;
|
||||
SetValue(value);
|
||||
}
|
||||
|
||||
internal override void SetValue(float newValue)
|
||||
{
|
||||
newValue = Math.Clamp(newValue, Range.min, Range.max);
|
||||
base.SetValue(newValue);
|
||||
}
|
||||
|
||||
internal override void UpdateVisuals(bool updateTabVisuals = true)
|
||||
{
|
||||
if (Option is NumberOption numberOption)
|
||||
{
|
||||
numberOption.PlusBtn.SetInteractable(false);
|
||||
numberOption.MinusBtn.SetInteractable(false);
|
||||
|
||||
if (Value < Range.max)
|
||||
{
|
||||
numberOption.PlusBtn.SetInteractable(true);
|
||||
}
|
||||
if (Value > Range.min)
|
||||
{
|
||||
numberOption.MinusBtn.SetInteractable(true);
|
||||
}
|
||||
|
||||
numberOption.ValueText.text = ValueAsString().Replace(InfiniteIcon, InfiniteIcon.Size(200f));
|
||||
}
|
||||
|
||||
if (updateTabVisuals)
|
||||
{
|
||||
Tab.UpdateVisuals();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal override string ValueAsString()
|
||||
{
|
||||
if (CanBeInfinite)
|
||||
{
|
||||
if (Value <= 0f)
|
||||
{
|
||||
return InfiniteIcon;
|
||||
}
|
||||
}
|
||||
|
||||
return $"{Fixs.prefix}{Value}{Fixs.postfix}";
|
||||
}
|
||||
|
||||
internal override float GetFloat() => GetValue();
|
||||
internal override bool Is(float @float) => @float == GetFloat();
|
||||
internal override bool Is(int @int) => @int == GetFloat();
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
using BetterAmongUs.Helpers;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
/// <summary>
|
||||
/// Int option.
|
||||
/// Type: Int
|
||||
/// </summary>
|
||||
internal class OptionIntItem : OptionItem<int>
|
||||
{
|
||||
internal override bool ShowChildren => base.ShowChildren && Value > 0;
|
||||
protected IntRange Range { get; set; }
|
||||
protected int Increment { get; set; }
|
||||
protected bool CanBeInfinite { get; set; }
|
||||
protected (string prefix, string postfix) Fixs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new integer item for the options menu. If an item with the specified ID already exists,
|
||||
/// it reuses the existing item and sets up its behavior.
|
||||
/// </summary>
|
||||
/// <param name="id">The unique identifier for the integer item.</param>
|
||||
/// <param name="tab">The tab to which the integer item belongs.</param>
|
||||
/// <param name="tranStr">The translation string for the integer item label.</param>
|
||||
/// <param name="Min_Max_Increment">A tuple containing the minimum value, maximum value, and increment value for the integer item's range.</param>
|
||||
/// <param name="defaultValue">The default value for the integer item.</param>
|
||||
/// <param name="Prefix_Postfix">A tuple containing the prefix and postfix to be displayed alongside the integer value.</param>
|
||||
/// <param name="parent">An optional parent option item that this integer item belongs to.</param>
|
||||
/// <param name="canBeInfinite">A flag indicating whether the integer value can be infinite.</param>
|
||||
/// <param name="vanillaOption">An optional vanilla option name, if any, for this integer item.</param>
|
||||
/// <returns>The created or reused <see cref="OptionIntItem"/> instance.</returns>
|
||||
internal static OptionIntItem Create(int id, OptionTab tab, string tranStr, (int minValue, int maxValue, int incrementValue) Min_Max_Increment, int defaultValue, (string prefix, string postfix) Prefix_Postfix = new(), OptionItem parent = null, bool canBeInfinite = false)
|
||||
{
|
||||
if (GetOptionById(id) is OptionIntItem intItem)
|
||||
{
|
||||
intItem.CreateBehavior();
|
||||
return intItem;
|
||||
}
|
||||
|
||||
OptionIntItem Item = new();
|
||||
AllTBROptions.Add(Item);
|
||||
Item._id = id;
|
||||
Item.Tab = tab;
|
||||
Item.Translation = tranStr;
|
||||
Item.Increment = Min_Max_Increment.incrementValue;
|
||||
Item.CanBeInfinite = canBeInfinite;
|
||||
Item.Range = new IntRange(Min_Max_Increment.minValue, Min_Max_Increment.maxValue);
|
||||
Item.DefaultValue = defaultValue;
|
||||
Item.Fixs = Prefix_Postfix;
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
Item.Parent = parent;
|
||||
parent.Children.Add(Item);
|
||||
}
|
||||
|
||||
Item.CreateBehavior();
|
||||
return Item;
|
||||
}
|
||||
|
||||
protected override void CreateBehavior()
|
||||
{
|
||||
TryLoad();
|
||||
if (!GameSettingMenu.Instance) return;
|
||||
AllTBROptionsTemp.Add(this);
|
||||
var numberOption = UnityEngine.Object.Instantiate(Tab.AUTab.numberOptionOrigin, Tab.AUTab.settingsContainer);
|
||||
Option = numberOption;
|
||||
Obj = Option.gameObject;
|
||||
Option.enabled = false;
|
||||
Tab.Children.Add(this);
|
||||
TitleTMP = numberOption.TitleText;
|
||||
ValueTMP = numberOption.ValueText;
|
||||
SetupText(numberOption.TitleText);
|
||||
SetupOptionBehavior();
|
||||
SetOptionVisuals();
|
||||
}
|
||||
|
||||
protected override void SetupOptionBehavior()
|
||||
{
|
||||
if (Option is NumberOption numberOption)
|
||||
{
|
||||
SetupAUOption(Option);
|
||||
numberOption.DestroyTextTranslators();
|
||||
numberOption.TitleText.text = Name;
|
||||
numberOption.PlusBtn.OnClick = new();
|
||||
numberOption.PlusBtn.OnClick.AddListener((Action)(() => Increase()));
|
||||
numberOption.MinusBtn.OnClick = new();
|
||||
numberOption.MinusBtn.OnClick.AddListener((Action)(() => Decrease()));
|
||||
}
|
||||
}
|
||||
|
||||
private void Increase()
|
||||
{
|
||||
int plus = 1;
|
||||
if (Input.GetKey(KeyCode.LeftShift))
|
||||
plus = 5;
|
||||
if (Input.GetKey(KeyCode.LeftControl))
|
||||
plus = 10;
|
||||
if (Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.LeftControl))
|
||||
plus = 25;
|
||||
var value = Value;
|
||||
value += Increment * plus;
|
||||
SetValue(value);
|
||||
}
|
||||
|
||||
private void Decrease()
|
||||
{
|
||||
int plus = 1;
|
||||
if (Input.GetKey(KeyCode.LeftShift))
|
||||
plus = 5;
|
||||
if (Input.GetKey(KeyCode.LeftControl))
|
||||
plus = 10;
|
||||
if (Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.LeftControl))
|
||||
plus = 25;
|
||||
var value = Value;
|
||||
value -= Increment * plus;
|
||||
SetValue(value);
|
||||
}
|
||||
|
||||
internal override void SetValue(int newValue)
|
||||
{
|
||||
newValue = Math.Clamp(newValue, Range.min, Range.max);
|
||||
base.SetValue(newValue);
|
||||
}
|
||||
|
||||
internal override void UpdateVisuals(bool updateTabVisuals = true)
|
||||
{
|
||||
if (Option is NumberOption numberOption)
|
||||
{
|
||||
numberOption.PlusBtn.SetInteractable(false);
|
||||
numberOption.MinusBtn.SetInteractable(false);
|
||||
|
||||
if (Value < Range.max)
|
||||
{
|
||||
numberOption.PlusBtn.SetInteractable(true);
|
||||
}
|
||||
if (Value > Range.min)
|
||||
{
|
||||
numberOption.MinusBtn.SetInteractable(true);
|
||||
}
|
||||
|
||||
numberOption.ValueText.text = ValueAsString().Replace(InfiniteIcon, InfiniteIcon.Size(200f));
|
||||
}
|
||||
|
||||
if (updateTabVisuals)
|
||||
{
|
||||
Tab.UpdateVisuals();
|
||||
}
|
||||
}
|
||||
|
||||
internal override string ValueAsString()
|
||||
{
|
||||
if (CanBeInfinite)
|
||||
{
|
||||
if (Value <= 0)
|
||||
{
|
||||
return InfiniteIcon;
|
||||
}
|
||||
}
|
||||
|
||||
return $"{Fixs.prefix}{Value}{Fixs.postfix}";
|
||||
}
|
||||
|
||||
internal override int GetInt() => GetValue();
|
||||
internal override float GetFloat() => GetValue();
|
||||
internal override bool Is(int @int) => @int == GetInt();
|
||||
internal override bool Is(float @float) => @float == GetFloat();
|
||||
}
|
||||
@@ -0,0 +1,479 @@
|
||||
using BetterAmongUs.Data;
|
||||
using BetterAmongUs.Helpers;
|
||||
using BetterAmongUs.Modules;
|
||||
using System.Text;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
internal class OptionAttributes
|
||||
{
|
||||
internal int Amount = 0;
|
||||
internal float Cooldown = 0f;
|
||||
internal float Duration = 0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base Option class.
|
||||
/// </summary>
|
||||
internal abstract class OptionItem
|
||||
{
|
||||
internal static int MaskLayer => 20;
|
||||
internal static List<OptionItem> AllTBROptions = [];
|
||||
internal static List<OptionItem> AllTBROptionsTemp = [];
|
||||
internal const string InfiniteIcon = "<b>∞</b>";
|
||||
internal virtual bool CanLoad => true;
|
||||
internal virtual bool IsOption => true;
|
||||
internal string Name => Translation != null ? Translator.GetString(Translation, showInvalid: false) : "None";
|
||||
internal int Id => _id ?? -1;
|
||||
protected int? _id { get; set; } = null;
|
||||
protected string? Translation { get; set; } = null;
|
||||
internal OptionTab? Tab { get; set; }
|
||||
internal OptionBehaviour? Option { get; set; }
|
||||
internal GameObject? Obj { get; set; }
|
||||
internal OptionItem? Parent { get; set; }
|
||||
internal bool IsParent => Children.Count > 0;
|
||||
internal List<OptionItem?> Children { get; set; } = [];
|
||||
internal virtual bool Show => ShowCondition.Invoke();
|
||||
internal virtual bool ShowChildren => Show;
|
||||
internal Func<bool>? ShowCondition = () => { return true; };
|
||||
internal bool Hide => !Show || GetParents().Any(opt => !opt.ShowChildren);
|
||||
internal static OptionItem? GetOptionById(int id) => AllTBROptions.FirstOrDefault(opt => opt._id == id);
|
||||
internal virtual void UpdateVisuals(bool updateTabVisuals = true) { }
|
||||
internal abstract string ValueAsString();
|
||||
internal virtual void TryLoad(bool forceLoad = false) { }
|
||||
internal virtual void SetToDefault() { }
|
||||
|
||||
protected void SetupAUOption(OptionBehaviour optionBehaviour)
|
||||
{
|
||||
Option?.SetClickMask(Tab.AUTab.ButtonClickMask);
|
||||
|
||||
SpriteRenderer[] componentsInChildren = optionBehaviour.GetComponentsInChildren<SpriteRenderer>(true);
|
||||
for (int i = 0; i < componentsInChildren.Length; i++)
|
||||
{
|
||||
componentsInChildren[i].material.SetInt(PlayerMaterial.MaskLayer, MaskLayer);
|
||||
}
|
||||
foreach (TextMeshPro textMeshPro in optionBehaviour.GetComponentsInChildren<TextMeshPro>(true))
|
||||
{
|
||||
textMeshPro.fontMaterial.SetFloat("_StencilComp", 3f);
|
||||
textMeshPro.fontMaterial.SetFloat("_Stencil", MaskLayer);
|
||||
}
|
||||
}
|
||||
|
||||
internal void PopNotification(string custom = "")
|
||||
{
|
||||
if (_id == null) return;
|
||||
string value = custom == string.Empty ? ValueAsString() : custom;
|
||||
string msg = $"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">{GetParentPath()} " +
|
||||
$"<color=#868686><size=85%>{Translator.GetString("BetterSetting.SetTo")}</size></color> {value}";
|
||||
Utils.SettingsChangeNotifier(Id, msg, false);
|
||||
}
|
||||
|
||||
internal string GetParentPath()
|
||||
{
|
||||
List<string> names = [Name ?? "???"];
|
||||
OptionItem tempOption = this;
|
||||
|
||||
while (tempOption.Parent != null)
|
||||
{
|
||||
names.Add(tempOption.Parent.Name);
|
||||
tempOption = tempOption.Parent;
|
||||
}
|
||||
return Utils.RemoveSizeHtmlText(string.Join("<b><color=#868686>/</color></b>", names.AsEnumerable().Reverse()));
|
||||
}
|
||||
|
||||
internal OptionItem? GetLastParent() => GetParents().LastOrDefault();
|
||||
|
||||
internal IEnumerable<OptionItem> GetParents()
|
||||
{
|
||||
if (Parent == null) yield break;
|
||||
|
||||
var target = Parent;
|
||||
while (target != null)
|
||||
{
|
||||
yield return target;
|
||||
target = target.Parent;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get child index of option.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal int GetChildIndex()
|
||||
{
|
||||
int index = 0;
|
||||
var target = this;
|
||||
while (target.Parent != null)
|
||||
{
|
||||
index++;
|
||||
target = target.Parent;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a automatic tree text display for option.
|
||||
/// </summary>
|
||||
/// <param name="size">Size of text</param>
|
||||
/// <returns>string</returns>
|
||||
internal string FormatOptionsToTextTree(float size = 50f, bool showForPercentOption = true)
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
sb.Append($"<size={size}%>");
|
||||
|
||||
string arrow = "▶";
|
||||
string branch = "━";
|
||||
string midBranch = "┣";
|
||||
string closeBranch = "┗";
|
||||
string vertical = "┃";
|
||||
|
||||
List<TreeNode> treeNodes = [];
|
||||
|
||||
void CollectTreeData(OptionItem option, int depth, bool isLastChild, TreeNode parent)
|
||||
{
|
||||
var node = new TreeNode
|
||||
{
|
||||
ParentNode = parent,
|
||||
Text = $"{Utils.RemoveSizeHtmlText(option.Name)}: {option.ValueAsString()}",
|
||||
Depth = depth,
|
||||
IsLastChild = isLastChild
|
||||
};
|
||||
treeNodes.Add(node);
|
||||
|
||||
if (option.IsParent && option.ShowChildren || option.TryCast<OptionPercentItem>() && showForPercentOption)
|
||||
{
|
||||
for (int i = 0; i < option.Children.Count; i++)
|
||||
{
|
||||
CollectTreeData(option.Children[i], depth + option.GetChildIndex(), i == option.Children.Count - 1, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CollectTreeData(this, 0, true, null);
|
||||
|
||||
bool isSingleOption = treeNodes.Count == 1;
|
||||
|
||||
for (int i = 0; i < treeNodes.Count; i++)
|
||||
{
|
||||
TreeNode node = treeNodes[i];
|
||||
|
||||
StringBuilder indent = new();
|
||||
|
||||
if (node.Depth > 0)
|
||||
{
|
||||
bool parentHasSibling = node.ParentNode?.IsLastChild == false;
|
||||
indent.Append(parentHasSibling ? $"{vertical} " : " ");
|
||||
}
|
||||
|
||||
string prefix;
|
||||
if (isSingleOption)
|
||||
{
|
||||
prefix = branch;
|
||||
}
|
||||
else
|
||||
{
|
||||
prefix = i == 0 ? "┏" : node.IsLastChild ? closeBranch : midBranch;
|
||||
}
|
||||
|
||||
sb.AppendLine($"{indent}{prefix}{branch}{arrow} {node.Text}");
|
||||
}
|
||||
|
||||
sb.Append("</size>");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
internal static string FormatOptionsToTextTrees(OptionItem?[] optionItems, float size = 50f, bool showForPercentOption = true)
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
sb.Append($"<size={size}%>");
|
||||
|
||||
string arrow = "▶";
|
||||
string branch = "━";
|
||||
string midBranch = "┣";
|
||||
string closeBranch = "┗";
|
||||
string vertical = "┃";
|
||||
string rootPrefix = "┏";
|
||||
|
||||
List<TreeNode> treeNodes = [];
|
||||
|
||||
void CollectTreeData(OptionItem option, int depth, bool isLastChild, TreeNode parent)
|
||||
{
|
||||
var node = new TreeNode
|
||||
{
|
||||
ParentNode = parent,
|
||||
Text = $"{Utils.RemoveSizeHtmlText(option.Name)}: {option.ValueAsString()}",
|
||||
Depth = depth,
|
||||
IsLastChild = isLastChild
|
||||
};
|
||||
treeNodes.Add(node);
|
||||
|
||||
if (option.IsParent && option.ShowChildren || option.TryCast<OptionPercentItem>() && showForPercentOption)
|
||||
{
|
||||
for (int i = 0; i < option.Children.Count; i++)
|
||||
{
|
||||
CollectTreeData(option.Children[i], depth + option.GetChildIndex(), i == option.Children.Count - 1, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < optionItems.Length; i++)
|
||||
{
|
||||
if (optionItems[i] == null) continue;
|
||||
CollectTreeData(optionItems[i], 0, i == optionItems.Length - 1, null);
|
||||
}
|
||||
|
||||
bool isSingleOption = optionItems.Length == 1 && treeNodes.Count == 1;
|
||||
|
||||
for (int i = 0; i < treeNodes.Count; i++)
|
||||
{
|
||||
TreeNode node = treeNodes[i];
|
||||
|
||||
StringBuilder indent = new();
|
||||
|
||||
if (node.Depth > 0)
|
||||
{
|
||||
bool parentHasSibling = node.ParentNode?.IsLastChild == false;
|
||||
indent.Append(parentHasSibling ? $"{vertical} " : " ");
|
||||
}
|
||||
|
||||
string prefix;
|
||||
if (isSingleOption)
|
||||
{
|
||||
prefix = branch;
|
||||
}
|
||||
else if (node.Depth == 0)
|
||||
{
|
||||
prefix = i == 0 ? rootPrefix : node.IsLastChild ? closeBranch : midBranch;
|
||||
}
|
||||
else
|
||||
{
|
||||
prefix = node.IsLastChild ? closeBranch : midBranch;
|
||||
}
|
||||
|
||||
sb.AppendLine($"{indent}{prefix}{branch}{arrow} {node.Text}");
|
||||
}
|
||||
|
||||
sb.Append("</size>");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
internal void CreateDescriptionButton(string text)
|
||||
{
|
||||
if (Option == null) return;
|
||||
|
||||
NumberOption optionBehaviourNum = UnityEngine.Object.Instantiate(Tab.AUTab.numberOptionOrigin, Vector3.zero, Quaternion.identity, Tab.AUTab.settingsContainer);
|
||||
SetupAUOption(optionBehaviourNum);
|
||||
var button = UnityEngine.Object.Instantiate(optionBehaviourNum.PlusBtn, Option.transform);
|
||||
optionBehaviourNum.DestroyObj();
|
||||
button.transform.position = button.transform.position - new Vector3(4.75f, 0f, 0f);
|
||||
button.transform.GetComponentInChildren<TextMeshPro>(true).gameObject.DestroyObj();
|
||||
button.ReceiveMouseOut();
|
||||
button.interactableHoveredColor = Color.gray;
|
||||
button.interactableClickColor = Color.white;
|
||||
button.buttonSprite.sprite = Utils.LoadSprite("TheBetterRoles.Resources.Images.Icons.QuestionMark.png", 50);
|
||||
button.OnClick = new();
|
||||
button.OnClick.AddListener((Action)(() =>
|
||||
{
|
||||
var menu = GameSettingMenu.Instance;
|
||||
if (menu != null)
|
||||
{
|
||||
menu.MenuDescriptionText.text = text;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get bool for CheckboxOption, could throw exception if option is not a CheckboxOption.
|
||||
/// </summary>
|
||||
/// <returns>bool</returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
internal virtual bool GetBool()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get float for FloatOption, could throw exception if option is not a FloatOption.
|
||||
/// </summary>
|
||||
/// <returns>float</returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
internal virtual float GetFloat()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get float for IntOption, could throw exception if option is not a IntOption.
|
||||
/// </summary>
|
||||
/// <returns>int</returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
internal virtual int GetInt()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get int for StringOption and PlayerOption, could throw exception if option is not a StringOption.
|
||||
/// </summary>
|
||||
/// <returns>int</returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
internal virtual int GetStringValue()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the value is a boolean.
|
||||
/// </summary>
|
||||
/// <param name="@bool">The boolean value to check.</param>
|
||||
/// <returns>True if the value matches, otherwise false.</returns>
|
||||
/// <exception cref="NotImplementedException">Thrown if the method is not implemented.</exception>
|
||||
internal virtual bool Is(bool @bool)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the value is a float.
|
||||
/// </summary>
|
||||
/// <param name="@float">The float value to check.</param>
|
||||
/// <returns>True if the value matches, otherwise false.</returns>
|
||||
/// <exception cref="NotImplementedException">Thrown if the method is not implemented.</exception>
|
||||
internal virtual bool Is(float @float)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the value is an integer.
|
||||
/// </summary>
|
||||
/// <param name="@int">The integer value to check.</param>
|
||||
/// <returns>True if the value matches, otherwise false.</returns>
|
||||
/// <exception cref="NotImplementedException">Thrown if the method is not implemented.</exception>
|
||||
internal virtual bool Is(int @int)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the value is a string.
|
||||
/// </summary>
|
||||
/// <param name="@string">The string value to check.</param>
|
||||
/// <returns>True if the value matches, otherwise false.</returns>
|
||||
/// <exception cref="NotImplementedException">Thrown if the method is not implemented.</exception>
|
||||
internal virtual bool Is(string @string)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
class TreeNode
|
||||
{
|
||||
internal TreeNode? ParentNode { get; set; }
|
||||
internal string Text { get; set; }
|
||||
internal int Depth { get; set; }
|
||||
internal bool IsLastChild { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class OptionItem<T> : OptionItem
|
||||
{
|
||||
protected TextMeshPro? TitleTMP { get; set; }
|
||||
protected TextMeshPro? ValueTMP { get; set; }
|
||||
private bool HasLoadValue { get; set; }
|
||||
protected T? Value { get; set; } = default;
|
||||
protected T? DefaultValue { get; set; } = default;
|
||||
internal virtual T? GetValue() => Value;
|
||||
internal virtual T? GetDefaultValue() => DefaultValue;
|
||||
internal override string ValueAsString() => Value?.ToString() ?? string.Empty;
|
||||
internal override void SetToDefault()
|
||||
{
|
||||
Value = DefaultValue;
|
||||
}
|
||||
protected abstract void CreateBehavior();
|
||||
internal virtual void OnValueChange(T oldValue, T newValue) { }
|
||||
internal Action<OptionItem>? OnValueChangeAction = (opt) => { };
|
||||
|
||||
protected void SetupText(TextMeshPro textPro)
|
||||
{
|
||||
textPro.transform.SetLocalX(-2.5f);
|
||||
textPro.transform.SetLocalY(-0.05f);
|
||||
textPro.alignment = TextAlignmentOptions.Right;
|
||||
textPro.enableWordWrapping = false;
|
||||
textPro.enableAutoSizing = true;
|
||||
textPro.fontSize = 3.3f;
|
||||
textPro.fontSizeMax = 3.3f;
|
||||
textPro.fontSizeMin = 1f;
|
||||
textPro.rectTransform.sizeDelta = new(4.5f, 1f);
|
||||
textPro.outlineColor = Color.black;
|
||||
textPro.outlineWidth = 0.25f;
|
||||
}
|
||||
|
||||
protected virtual void SetupOptionBehavior() { }
|
||||
|
||||
protected void SetOptionVisuals()
|
||||
{
|
||||
if (Option != null)
|
||||
{
|
||||
float colorNum = 1f - 0.25f * GetChildIndex();
|
||||
Option.LabelBackground.color = new Color(colorNum, colorNum, colorNum, 1f);
|
||||
Option.LabelBackground.transform.SetLocalZ(1f);
|
||||
Option.LabelBackground.transform.localScale = new Vector3(1.6f, 0.8f, 1f);
|
||||
Option.LabelBackground.transform.SetLocalX(-2.4f);
|
||||
float resize = 0f + 0.1f * GetChildIndex();
|
||||
if (resize > 0f)
|
||||
{
|
||||
if (TitleTMP != null)
|
||||
{
|
||||
TitleTMP.rectTransform.sizeDelta -= new Vector2(resize * 2.5f, 0f);
|
||||
TitleTMP.transform.SetLocalX(TitleTMP.transform.localPosition.x + resize * 2.5f);
|
||||
}
|
||||
var pos = Option.LabelBackground.transform.localPosition;
|
||||
var size = Option.LabelBackground.transform.localScale;
|
||||
Option.LabelBackground.transform.localPosition = new Vector3(pos.x + resize * 1.8f, pos.y, pos.z);
|
||||
Option.LabelBackground.transform.localScale = new Vector3(size.x - resize, size.y, size.z);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
internal virtual void SetValue(T newValue)
|
||||
{
|
||||
T oldValue = Value;
|
||||
Value = newValue;
|
||||
UpdateVisuals();
|
||||
PopNotification();
|
||||
Save();
|
||||
OnValueChange(oldValue, newValue);
|
||||
OnValueChangeAction.Invoke(this);
|
||||
}
|
||||
|
||||
internal override void TryLoad(bool forceLoad = false)
|
||||
{
|
||||
if (!CanLoad) return;
|
||||
|
||||
if (!HasLoadValue || forceLoad)
|
||||
{
|
||||
HasLoadValue = true;
|
||||
Load();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Load()
|
||||
{
|
||||
if (!CanLoad) return;
|
||||
|
||||
if (_id == null) return;
|
||||
Value = BetterDataManager.LoadSetting(Id, DefaultValue);
|
||||
}
|
||||
|
||||
internal virtual void Save()
|
||||
{
|
||||
if (!CanLoad) return;
|
||||
|
||||
if (_id == null) return;
|
||||
BetterDataManager.SaveSetting(Id, Value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
/// <summary>
|
||||
/// Percent option.
|
||||
/// Type: Float
|
||||
/// </summary>
|
||||
internal class OptionPercentItem : OptionFloatItem
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new percent item for the options menu. If an item with the specified ID already exists,
|
||||
/// it reuses the existing item and sets up its behavior.
|
||||
/// </summary>
|
||||
/// <param name="id">The unique identifier for the percent item.</param>
|
||||
/// <param name="tab">The tab to which the percent item belongs.</param>
|
||||
/// <param name="tranStr">The translation string for the percent item label.</param>
|
||||
/// <param name="defaultValue">The default value for the percent item (in the range of 0 to 100).</param>
|
||||
/// <param name="parent">An optional parent option item that this percent item belongs to.</param>
|
||||
/// <returns>The created or reused <see cref="OptionPercentItem"/> instance.</returns>
|
||||
internal static OptionPercentItem Create(int id, OptionTab tab, string tranStr, float defaultValue, OptionItem parent = null)
|
||||
{
|
||||
if (GetOptionById(id) is OptionPercentItem floatItem)
|
||||
{
|
||||
floatItem.CreateBehavior();
|
||||
return floatItem;
|
||||
}
|
||||
|
||||
OptionPercentItem Item = new();
|
||||
AllTBROptions.Add(Item);
|
||||
Item._id = id;
|
||||
Item.Tab = tab;
|
||||
Item.Translation = tranStr;
|
||||
Item.Increment = 5;
|
||||
Item.Range = new FloatRange(0f, 100f);
|
||||
Item.DefaultValue = defaultValue;
|
||||
Item.Fixs = ("", "");
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
Item.Parent = parent;
|
||||
parent.Children.Add(Item);
|
||||
}
|
||||
|
||||
Item.CreateBehavior();
|
||||
return Item;
|
||||
}
|
||||
|
||||
internal override string ValueAsString() => $"<color={GetColor(Value)}>{Value}%</color>";
|
||||
|
||||
internal string GetColor(float num)
|
||||
{
|
||||
switch (num)
|
||||
{
|
||||
case float n when n <= 0f:
|
||||
return "#ff0600";
|
||||
case float n when n <= 25f:
|
||||
return "#ff9d00";
|
||||
case float n when n <= 50f:
|
||||
return "#fff900";
|
||||
case float n when n <= 75f:
|
||||
return "#80ff00";
|
||||
default:
|
||||
return "#80ff00";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
using BetterAmongUs.Helpers;
|
||||
using BetterAmongUs.Modules;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
/// <summary>
|
||||
/// Int option.
|
||||
/// Type: Int
|
||||
/// </summary>
|
||||
internal class OptionPlayerItem : OptionItem<int>
|
||||
{
|
||||
internal override bool ShowChildren => base.ShowChildren && Value > Min;
|
||||
private int Max => BAUPlugin.AllPlayerControls.Count - 1;
|
||||
private int Min => CanBeRandom ? -1 : 0;
|
||||
protected bool CanBeRandom { get; set; }
|
||||
internal override bool CanLoad => false;
|
||||
|
||||
private static List<OptionPlayerItem> optionPlayerItems = [];
|
||||
|
||||
internal static OptionPlayerItem Create(int id, OptionTab tab, string tranStr, OptionItem parent = null, bool canBeRandom = true)
|
||||
{
|
||||
if (optionPlayerItems.FirstOrDefault(opt => opt.Id == id) is OptionPlayerItem playerItem)
|
||||
{
|
||||
playerItem.CreateBehavior();
|
||||
return playerItem;
|
||||
}
|
||||
|
||||
OptionPlayerItem Item = new();
|
||||
optionPlayerItems.Add(Item);
|
||||
Item.Value = canBeRandom ? -1 : 0; ;
|
||||
Item._id = id;
|
||||
Item.Tab = tab;
|
||||
Item.Translation = tranStr;
|
||||
Item.CanBeRandom = canBeRandom;
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
Item.Parent = parent;
|
||||
parent.Children.Add(Item);
|
||||
}
|
||||
|
||||
Item.CreateBehavior();
|
||||
return Item;
|
||||
}
|
||||
|
||||
internal override void Save()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void CreateBehavior()
|
||||
{
|
||||
if (!GameSettingMenu.Instance) return;
|
||||
AllTBROptionsTemp.Add(this);
|
||||
var numberOption = UnityEngine.Object.Instantiate(Tab.AUTab.numberOptionOrigin, Tab.AUTab.settingsContainer);
|
||||
Option = numberOption;
|
||||
Obj = Option.gameObject;
|
||||
Option.enabled = false;
|
||||
Tab.Children.Add(this);
|
||||
TitleTMP = numberOption.TitleText;
|
||||
ValueTMP = numberOption.ValueText;
|
||||
SetupText(numberOption.TitleText);
|
||||
SetupOptionBehavior();
|
||||
SetOptionVisuals();
|
||||
}
|
||||
|
||||
protected override void SetupOptionBehavior()
|
||||
{
|
||||
if (Option is NumberOption numberOption)
|
||||
{
|
||||
SetupAUOption(Option);
|
||||
numberOption.DestroyTextTranslators();
|
||||
numberOption.TitleText.text = Name;
|
||||
numberOption.PlusBtn.OnClick = new();
|
||||
numberOption.PlusBtn.OnClick.AddListener((Action)(() => Increase()));
|
||||
numberOption.MinusBtn.OnClick = new();
|
||||
numberOption.MinusBtn.OnClick.AddListener((Action)(() => Decrease()));
|
||||
}
|
||||
}
|
||||
|
||||
private void Increase()
|
||||
{
|
||||
int plus = 1;
|
||||
if (Input.GetKey(KeyCode.LeftShift))
|
||||
plus = 5;
|
||||
if (Input.GetKey(KeyCode.LeftControl))
|
||||
plus = 10;
|
||||
if (Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.LeftControl))
|
||||
plus = 25;
|
||||
var value = Value;
|
||||
value += 1 * plus;
|
||||
SetValue(value);
|
||||
}
|
||||
|
||||
private void Decrease()
|
||||
{
|
||||
int plus = 1;
|
||||
if (Input.GetKey(KeyCode.LeftShift))
|
||||
plus = 5;
|
||||
if (Input.GetKey(KeyCode.LeftControl))
|
||||
plus = 10;
|
||||
if (Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.LeftControl))
|
||||
plus = 25;
|
||||
var value = Value;
|
||||
value -= 1 * plus;
|
||||
SetValue(value);
|
||||
}
|
||||
|
||||
internal override void SetValue(int newValue)
|
||||
{
|
||||
newValue = Math.Clamp(newValue, Min, Max);
|
||||
base.SetValue(newValue);
|
||||
}
|
||||
|
||||
internal static void ResetAllValues()
|
||||
{
|
||||
foreach (var opt in optionPlayerItems)
|
||||
{
|
||||
opt.ResetValue();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void UpdateAllValues()
|
||||
{
|
||||
foreach (var opt in optionPlayerItems)
|
||||
{
|
||||
opt.UpdateValue();
|
||||
}
|
||||
}
|
||||
|
||||
internal void UpdateValue()
|
||||
{
|
||||
Value = Math.Clamp(Value, Min, Max);
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
internal void ResetValue()
|
||||
{
|
||||
Value = Min;
|
||||
}
|
||||
|
||||
internal override void UpdateVisuals(bool updateTabVisuals = true)
|
||||
{
|
||||
if (!GameSettingMenu.Instance) return;
|
||||
|
||||
if (Option is NumberOption numberOption)
|
||||
{
|
||||
numberOption.PlusBtn.SetInteractable(false);
|
||||
numberOption.MinusBtn.SetInteractable(false);
|
||||
|
||||
if (Value < Max)
|
||||
{
|
||||
numberOption.PlusBtn.SetInteractable(true);
|
||||
}
|
||||
if (Value > Min)
|
||||
{
|
||||
numberOption.MinusBtn.SetInteractable(true);
|
||||
}
|
||||
|
||||
numberOption.ValueText.text = ValueAsString().Replace(InfiniteIcon, InfiniteIcon.Size(200f));
|
||||
}
|
||||
|
||||
if (updateTabVisuals)
|
||||
{
|
||||
Tab.UpdateVisuals();
|
||||
}
|
||||
}
|
||||
|
||||
internal override string ValueAsString()
|
||||
{
|
||||
if (Value != -1)
|
||||
{
|
||||
var player = Utils.PlayerFromPlayerId(Value);
|
||||
if (player != null)
|
||||
return $"{player.GetPlayerNameAndColor()}";
|
||||
else
|
||||
return "???";
|
||||
}
|
||||
else
|
||||
{
|
||||
return Translator.GetString(StringNames.RoundRobin).ToColor(Color.gray);
|
||||
}
|
||||
}
|
||||
|
||||
internal override int GetInt() => GetValue();
|
||||
internal override float GetFloat() => GetValue();
|
||||
internal override bool Is(int @int) => @int == GetInt();
|
||||
internal override bool Is(float @float) => @float == GetFloat();
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
using BetterAmongUs.Helpers;
|
||||
using BetterAmongUs.Modules;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
/// <summary>
|
||||
/// String option.
|
||||
/// Type: Int
|
||||
/// </summary>
|
||||
internal class OptionStringItem : OptionItem<int>
|
||||
{
|
||||
protected IntRange Range { get; set; }
|
||||
protected string[] TranslatorStrings { get; set; }
|
||||
protected bool CanBeRandom { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new string item for the options menu. If an item with the specified ID already exists,
|
||||
/// it reuses the existing item and sets up its behavior. The method allows specifying translation strings
|
||||
/// and whether the option can be randomized.
|
||||
/// </summary>
|
||||
/// <param name="id">The unique identifier for the string item.</param>
|
||||
/// <param name="tab">The tab to which the string item belongs.</param>
|
||||
/// <param name="tranStr">The translation string for the string item label.</param>
|
||||
/// <param name="tranStrings">An array of translation strings representing the available options for the string item.</param>
|
||||
/// <param name="defaultValue">The default value (index) for the string item. If less than 0, the option can be randomized.</param>
|
||||
/// <param name="parent">An optional parent option item that this string item belongs to.</param>
|
||||
/// <param name="canBeRandom">A flag indicating whether the string item can have a random value.</param>
|
||||
/// <param name="vanillaOption">An optional vanilla option name, if any, for this string item.</param>
|
||||
/// <returns>The created or reused <see cref="OptionStringItem"/> instance.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown when <paramref name="tranStrings"/> has fewer than 2 strings.</exception>
|
||||
internal static OptionStringItem Create(int id, OptionTab tab, string tranStr, string[] tranStrings, int defaultValue, OptionItem parent = null, bool canBeRandom = false)
|
||||
{
|
||||
if (tranStrings.Length < 2)
|
||||
{
|
||||
throw new ArgumentException("tranStrings must have more then 1 string!");
|
||||
}
|
||||
|
||||
if (GetOptionById(id) is OptionStringItem stringItem)
|
||||
{
|
||||
stringItem.CreateBehavior();
|
||||
return stringItem;
|
||||
}
|
||||
|
||||
if (defaultValue < 0)
|
||||
{
|
||||
canBeRandom = true;
|
||||
}
|
||||
|
||||
OptionStringItem Item = new();
|
||||
AllTBROptions.Add(Item);
|
||||
Item._id = id;
|
||||
Item.Tab = tab;
|
||||
Item.Translation = tranStr;
|
||||
Item.TranslatorStrings = tranStrings;
|
||||
Item.Range = new IntRange(0, tranStrings.Length - 1);
|
||||
Item.DefaultValue = !canBeRandom ? defaultValue : defaultValue + 1;
|
||||
Item.CanBeRandom = canBeRandom;
|
||||
if (canBeRandom)
|
||||
{
|
||||
var list = Item.TranslatorStrings.ToList();
|
||||
list.Insert(0, "Option.RandomWithColor");
|
||||
Item.TranslatorStrings = [.. list];
|
||||
Item.Range = new IntRange(0, list.Count - 1);
|
||||
}
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
Item.Parent = parent;
|
||||
parent.Children.Add(Item);
|
||||
}
|
||||
|
||||
Item.CreateBehavior();
|
||||
return Item;
|
||||
}
|
||||
|
||||
protected override void CreateBehavior()
|
||||
{
|
||||
TryLoad();
|
||||
if (!GameSettingMenu.Instance) return;
|
||||
AllTBROptionsTemp.Add(this);
|
||||
var numberOption = UnityEngine.Object.Instantiate(Tab.AUTab.numberOptionOrigin, Tab.AUTab.settingsContainer);
|
||||
Option = numberOption;
|
||||
Obj = Option.gameObject;
|
||||
Option.enabled = false;
|
||||
Tab.Children.Add(this);
|
||||
TitleTMP = numberOption.TitleText;
|
||||
ValueTMP = numberOption.ValueText;
|
||||
SetupText(numberOption.TitleText);
|
||||
SetupOptionBehavior();
|
||||
SetOptionVisuals();
|
||||
}
|
||||
|
||||
protected override void SetupOptionBehavior()
|
||||
{
|
||||
if (Option is NumberOption numberOption)
|
||||
{
|
||||
SetupAUOption(Option);
|
||||
numberOption.DestroyTextTranslators();
|
||||
numberOption.TitleText.text = Name;
|
||||
numberOption.PlusBtn.OnClick = new();
|
||||
numberOption.PlusBtn.OnClick.AddListener((Action)(() => Increase()));
|
||||
numberOption.MinusBtn.OnClick = new();
|
||||
numberOption.MinusBtn.OnClick.AddListener((Action)(() => Decrease()));
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Increase()
|
||||
{
|
||||
SetValue(Value + 1);
|
||||
}
|
||||
|
||||
protected virtual private void Decrease()
|
||||
{
|
||||
SetValue(Value - 1);
|
||||
}
|
||||
|
||||
internal override void SetValue(int newValue)
|
||||
{
|
||||
newValue = Math.Clamp(newValue, Range.min, Range.max);
|
||||
base.SetValue(newValue);
|
||||
}
|
||||
|
||||
internal override void UpdateVisuals(bool updateTabVisuals = true)
|
||||
{
|
||||
if (Option is NumberOption numberOption)
|
||||
{
|
||||
numberOption.PlusBtn.SetInteractable(false);
|
||||
numberOption.MinusBtn.SetInteractable(false);
|
||||
|
||||
if (Value < Range.max)
|
||||
{
|
||||
numberOption.PlusBtn.SetInteractable(true);
|
||||
}
|
||||
if (Value > Range.min)
|
||||
{
|
||||
numberOption.MinusBtn.SetInteractable(true);
|
||||
}
|
||||
|
||||
numberOption.ValueText.text = $"{ValueAsString()}";
|
||||
}
|
||||
|
||||
if (updateTabVisuals)
|
||||
{
|
||||
Tab.UpdateVisuals();
|
||||
}
|
||||
}
|
||||
|
||||
internal override string ValueAsString() => Translator.GetString(TranslatorStrings[Value], showInvalid: false);
|
||||
internal override int GetStringValue()
|
||||
{
|
||||
var value = GetValue();
|
||||
if (!CanBeRandom)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value == 0)
|
||||
{
|
||||
return TranslatorStrings.Skip(1).RandomIndex().index;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal override bool Is(string @string) => TranslatorStrings[Value] == @string || ValueAsString() == @string;
|
||||
internal override bool Is(int @int) => !CanBeRandom ? Value == @int : Value == @int - 1;
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
using BetterAmongUs.Helpers;
|
||||
using BetterAmongUs.Items.OptionItems.NoneOption;
|
||||
using BetterAmongUs.Modules;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Items.OptionItems;
|
||||
|
||||
/// <summary>
|
||||
/// Option Tab.
|
||||
/// </summary>
|
||||
internal class OptionTab
|
||||
{
|
||||
internal static List<OptionTab> AllTabs = [];
|
||||
|
||||
internal readonly List<OptionItem> Children = [];
|
||||
internal int Id { get; private set; }
|
||||
internal string? Name => Translator.GetString(TranName);
|
||||
internal string? TranName { get; private set; }
|
||||
internal string? Description => Translator.GetString(TranDescription);
|
||||
internal string? TranDescription { get; private set; }
|
||||
internal GameOptionsMenu? AUTab { get; private set; }
|
||||
internal PassiveButton? TabButton { get; private set; }
|
||||
internal Color Color { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new option tab for the options menu. If an option tab with the specified ID already exists,
|
||||
/// it reuses the existing tab, clears its children, and sets up its behavior.
|
||||
/// </summary>
|
||||
/// <param name="Id">The unique identifier for the option tab.</param>
|
||||
/// <param name="tranName">The translation string for the name of the tab.</param>
|
||||
/// <param name="tranDescription">The translation string for the description of the tab.</param>
|
||||
/// <param name="Color">The color associated with the tab.</param>
|
||||
/// <param name="doNotDestroyMapPicker">A flag indicating whether the map picker should not be destroyed when recreating the tab.</param>
|
||||
/// <returns>The created or reused <see cref="OptionTab"/> instance.</returns>
|
||||
internal static OptionTab Create(int Id, string tranName, string tranDescription, Color Color, bool doNotDestroyMapPicker = false)
|
||||
{
|
||||
if (GetTabById(Id) is OptionTab optionTab)
|
||||
{
|
||||
optionTab.Children.Clear();
|
||||
optionTab.CreateBehavior(doNotDestroyMapPicker);
|
||||
return optionTab;
|
||||
}
|
||||
|
||||
var Item = new OptionTab
|
||||
{
|
||||
Id = Id,
|
||||
TranName = tranName,
|
||||
TranDescription = tranDescription,
|
||||
Color = Color
|
||||
};
|
||||
AllTabs.Add(Item);
|
||||
|
||||
Item.CreateBehavior(doNotDestroyMapPicker);
|
||||
return Item;
|
||||
}
|
||||
|
||||
internal static OptionTab? GetTabById(int id) => AllTabs.FirstOrDefault(tab => tab.Id == id);
|
||||
|
||||
private void CreateBehavior(bool doNotDestroyMapPicker)
|
||||
{
|
||||
if (!GameSettingMenu.Instance) return;
|
||||
|
||||
var SettingsButton = UnityEngine.Object.Instantiate(GameSettingMenu.Instance.GameSettingsButton, GameSettingMenu.Instance.GameSettingsButton.transform.parent);
|
||||
TabButton = SettingsButton;
|
||||
SettingsButton.DestroyTextTranslators();
|
||||
SettingsButton.GetComponentInChildren<TextMeshPro>().text = Name;
|
||||
|
||||
SettingsButton.gameObject.SetActive(true);
|
||||
SettingsButton.name = Name;
|
||||
SettingsButton.OnClick.RemoveAllListeners();
|
||||
SettingsButton.OnMouseOver.RemoveAllListeners();
|
||||
|
||||
SettingsButton.activeSprites.GetComponent<SpriteRenderer>().color = Color;
|
||||
SettingsButton.inactiveSprites.GetComponent<SpriteRenderer>().color = Color;
|
||||
SettingsButton.selectedSprites.GetComponent<SpriteRenderer>().color = Color;
|
||||
|
||||
SettingsButton.gameObject.GetComponent<BoxCollider2D>().size = new Vector2(2.5f, 0.6176f);
|
||||
|
||||
SettingsButton.OnClick.AddListener(new Action(() =>
|
||||
{
|
||||
GameSettingMenu.Instance.ChangeTab(Id, false);
|
||||
}));
|
||||
|
||||
var SettingsTab = UnityEngine.Object.Instantiate(GameSettingMenu.Instance.GameSettingsTab, GameSettingMenu.Instance.GameSettingsTab.transform.parent);
|
||||
AUTab = SettingsTab;
|
||||
SettingsTab.name = Name;
|
||||
if (!doNotDestroyMapPicker) SettingsTab.scrollBar.Inner.DestroyChildren();
|
||||
|
||||
AUTab.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
internal void UpdateVisuals()
|
||||
{
|
||||
ShowOptions();
|
||||
}
|
||||
|
||||
private void ShowOptions()
|
||||
{
|
||||
if (AUTab == null) return;
|
||||
|
||||
AUTab.gameObject.SetActive(true);
|
||||
float spacingNum = 0f;
|
||||
foreach (var opt in Children)
|
||||
{
|
||||
if (opt?.Obj == null) continue;
|
||||
if (opt?.Tab.Id != Id || opt.Hide)
|
||||
{
|
||||
opt.Obj.gameObject.SetActive(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
opt.Obj.gameObject.SetActive(true);
|
||||
|
||||
spacingNum += opt switch
|
||||
{
|
||||
OptionHeaderItem headerItem => headerItem.Distance.top,
|
||||
OptionTitleItem titleItem => titleItem.Distance.top,
|
||||
OptionDividerItem dividerItem => dividerItem.Distance.top,
|
||||
_ => 0f,
|
||||
};
|
||||
|
||||
if (opt.IsOption)
|
||||
{
|
||||
opt.Obj.transform.localPosition = new Vector3(1.4f, 2f - 1f * spacingNum, 0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
opt.Obj.transform.localPosition = new Vector3(-0.6f, 2f - 1f * spacingNum, 0f);
|
||||
}
|
||||
|
||||
spacingNum += opt switch
|
||||
{
|
||||
OptionHeaderItem headerItem => headerItem.Distance.bottom,
|
||||
OptionTitleItem titleItem => titleItem.Distance.bottom,
|
||||
OptionDividerItem dividerItem => dividerItem.Distance.bottom,
|
||||
_ => 0.45f,
|
||||
};
|
||||
|
||||
opt.UpdateVisuals(false);
|
||||
}
|
||||
|
||||
AUTab?.scrollBar?.SetYBoundsMax(spacingNum - 2.5f);
|
||||
AUTab?.scrollBar?.ScrollRelative(new(0f, 0f));
|
||||
}
|
||||
|
||||
internal static void FindOptions(string name)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ internal class MeetingInfoDisplay : PlayerInfoDisplay
|
||||
LevelDisplay.GetComponent<SpriteRenderer>().color = new Color(1f, 0f, 1f, 1f);
|
||||
var IdLabel = LevelDisplay.transform.Find("LevelLabel");
|
||||
var IdNumber = LevelDisplay.transform.Find("LevelNumber");
|
||||
IdLabel.gameObject.DestroyTextTranslator();
|
||||
IdLabel.gameObject.DestroyTextTranslators();
|
||||
IdLabel.GetComponent<TextMeshPro>().text = "ID";
|
||||
IdNumber.GetComponent<TextMeshPro>().text = pva.TargetPlayerId.ToString();
|
||||
IdLabel.name = "IdLabel";
|
||||
|
||||
@@ -212,6 +212,8 @@ internal class PlayerInfoDisplay : MonoBehaviour
|
||||
|
||||
private void SetLobbyInfo(ref string newName, ExtendedPlayerInfo betterData, StringBuilder sbTag)
|
||||
{
|
||||
if (betterData == null) return;
|
||||
|
||||
if (_player.IsHost() && BAUPlugin.LobbyPlayerInfo.Value)
|
||||
newName = _player.GetPlayerNameAndColor();
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ internal class MainMenuPatch
|
||||
|
||||
// Set button text
|
||||
var buttonText = button.transform.Find("FontPlacer/Text_TMP").GetComponent<TMP_Text>();
|
||||
buttonText.DestroyTextTranslator();
|
||||
buttonText.DestroyTextTranslators();
|
||||
buttonText.fontSize = buttonText.fontSizeMax = buttonText.fontSizeMin = 3.5f;
|
||||
buttonText.enableWordWrapping = false;
|
||||
buttonText.text = label;
|
||||
|
||||
@@ -52,7 +52,7 @@ internal class PrivateLobbyPatch
|
||||
var text = toggle.transform.Find("BlackSquare/ModeText")?.GetComponent<TextMeshPro>();
|
||||
if (text != null)
|
||||
{
|
||||
text.DestroyTextTranslator();
|
||||
text.DestroyTextTranslators();
|
||||
text.text = "Private Only Lobby";
|
||||
toggleText = text;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using BetterAmongUs.Helpers;
|
||||
using BetterAmongUs.Items.OptionItems;
|
||||
using HarmonyLib;
|
||||
|
||||
namespace BetterAmongUs.Patches.Gameplay.Player;
|
||||
@@ -11,6 +12,7 @@ class PlayerControlPatch
|
||||
internal static void Start_Postfix(PlayerControl __instance)
|
||||
{
|
||||
BAUPlugin.AllPlayerControls.Add(__instance);
|
||||
OptionPlayerItem.UpdateAllValues();
|
||||
}
|
||||
|
||||
[HarmonyPatch(nameof(PlayerControl.OnDestroy))]
|
||||
@@ -18,6 +20,7 @@ class PlayerControlPatch
|
||||
internal static void OnDestroy_Postfix(PlayerControl __instance)
|
||||
{
|
||||
BAUPlugin.AllPlayerControls.Remove(__instance);
|
||||
OptionPlayerItem.UpdateAllValues();
|
||||
}
|
||||
|
||||
[HarmonyPatch(nameof(PlayerControl.MurderPlayer))]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using AmongUs.GameOptions;
|
||||
using BetterAmongUs.Helpers;
|
||||
using BetterAmongUs.Items.OptionItems;
|
||||
using BetterAmongUs.Items.OptionItems.NoneOption;
|
||||
using BetterAmongUs.Modules;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
@@ -9,72 +10,66 @@ namespace BetterAmongUs.Patches.Gameplay.UI.Settings;
|
||||
|
||||
class BetterGameSettings
|
||||
{
|
||||
internal static BetterOptionItem? WhenCheating;
|
||||
internal static BetterOptionItem? InvalidFriendCode;
|
||||
internal static BetterOptionItem? UseBanPlayerList;
|
||||
internal static BetterOptionItem? UseBanNameList;
|
||||
internal static BetterOptionItem? UseBanWordList;
|
||||
internal static BetterOptionItem? UseBanWordListOnlyLobby;
|
||||
internal static BetterOptionItem? HideAndSeekImpNum;
|
||||
internal static BetterOptionItem? DetectedLevelAbove;
|
||||
internal static BetterOptionItem? DetectCheatClients;
|
||||
internal static BetterOptionItem? DetectInvalidRPCs;
|
||||
internal static BetterOptionItem? RoleRandomizer;
|
||||
internal static BetterOptionItem? DesyncRoles;
|
||||
internal static BetterOptionItem? CancelInvalidSabotage;
|
||||
internal static BetterOptionItem? CensorDetectionReason;
|
||||
internal static BetterOptionItem? RemovePetOnDeath;
|
||||
internal static BetterOptionItem? DisableSabotages;
|
||||
internal static OptionItem? WhenCheating;
|
||||
internal static OptionItem? InvalidFriendCode;
|
||||
internal static OptionItem? UseBanPlayerList;
|
||||
internal static OptionItem? UseBanNameList;
|
||||
internal static OptionItem? UseBanWordList;
|
||||
internal static OptionItem? UseBanWordListOnlyLobby;
|
||||
internal static OptionItem? HideAndSeekImpNum;
|
||||
internal static OptionItem? DetectedLevelAbove;
|
||||
internal static OptionItem? DetectCheatClients;
|
||||
internal static OptionItem? DetectInvalidRPCs;
|
||||
internal static OptionItem? RoleRandomizer;
|
||||
internal static OptionItem? DesyncRoles;
|
||||
internal static OptionItem? CancelInvalidSabotage;
|
||||
internal static OptionItem? CensorDetectionReason;
|
||||
internal static OptionItem? RemovePetOnDeath;
|
||||
internal static OptionItem? DisableSabotages;
|
||||
}
|
||||
|
||||
class BetterGameSettingsTemp
|
||||
{
|
||||
internal static BetterOptionItem? HideAndSeekImp2;
|
||||
internal static BetterOptionItem? HideAndSeekImp3;
|
||||
internal static BetterOptionItem? HideAndSeekImp4;
|
||||
internal static BetterOptionItem? HideAndSeekImp5;
|
||||
internal static OptionItem? HideAndSeekImp2;
|
||||
internal static OptionItem? HideAndSeekImp3;
|
||||
internal static OptionItem? HideAndSeekImp4;
|
||||
internal static OptionItem? HideAndSeekImp5;
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(GameSettingMenu))]
|
||||
static class GameSettingMenuPatch
|
||||
{
|
||||
private static PassiveButton BetterSettingsButton;
|
||||
internal static GameOptionsMenu BetterSettingsTab;
|
||||
private static List<BetterOptionItem> TitleList = [];
|
||||
internal static OptionTab? BetterSettingsTab;
|
||||
|
||||
internal static void SetupSettings(bool IsPreload = false)
|
||||
{
|
||||
BetterOptionItem.BetterOptionItems.Clear();
|
||||
BetterOptionItem.TempPlayerOptionDataNum = 0;
|
||||
TitleList.Clear();
|
||||
|
||||
// Use 1700 next ID
|
||||
|
||||
BetterSettingsTab = OptionTab.Create(3, "BetterSetting", "BetterSetting.Description", Color.green);
|
||||
|
||||
// Anti-Cheat Settings
|
||||
{
|
||||
TitleList.Add(new BetterOptionHeaderItem().Create(BetterSettingsTab, Translator.GetString("BetterSetting.MainHeader.AntiCheat")));
|
||||
OptionHeaderItem.Create(BetterSettingsTab, "BetterSetting.MainHeader.AntiCheat");
|
||||
|
||||
if (IsPreload || GameState.IsHost)
|
||||
{
|
||||
TitleList.Add(new BetterOptionTitleItem().Create(BetterSettingsTab, Translator.GetString("BetterSetting.TextHeader.HostOnly")));
|
||||
BetterGameSettings.WhenCheating = new BetterOptionStringItem().Create(100, BetterSettingsTab, Translator.GetString("BetterSetting.Setting.WhenCheating"),
|
||||
[Translator.GetString("BetterSetting.Setting.WhenCheating.Notify"),
|
||||
Translator.GetString("BetterSetting.Setting.WhenCheating.Kick"),
|
||||
Translator.GetString("BetterSetting.Setting.WhenCheating.Ban")], 2);
|
||||
BetterGameSettings.InvalidFriendCode = new BetterOptionCheckboxItem().Create(200, BetterSettingsTab, Translator.GetString("BetterSetting.Setting.InvalidFriendCode"), true);
|
||||
BetterGameSettings.CancelInvalidSabotage = new BetterOptionCheckboxItem().Create(900, BetterSettingsTab, Translator.GetString("BetterSetting.Setting.CancelInvalidSabotage"), true);
|
||||
BetterGameSettings.UseBanPlayerList = new BetterOptionCheckboxItem().Create(300, BetterSettingsTab, Translator.GetString("BetterSetting.Setting.UseBanPlayerList"), true);
|
||||
BetterGameSettings.UseBanNameList = new BetterOptionCheckboxItem().Create(400, BetterSettingsTab, Translator.GetString("BetterSetting.Setting.UseBanNameList"), true);
|
||||
BetterGameSettings.UseBanWordList = new BetterOptionCheckboxItem().Create(500, BetterSettingsTab, Translator.GetString("BetterSetting.Setting.UseBanWordList"), true);
|
||||
BetterGameSettings.UseBanWordListOnlyLobby = new BetterOptionCheckboxItem().Create(1400, BetterSettingsTab, Translator.GetString("BetterSetting.Setting.UseBanWordListOnlyLobby"), true, BetterGameSettings.UseBanWordList);
|
||||
TitleList.Add(new BetterOptionDividerItem().Create(BetterSettingsTab));
|
||||
OptionTitleItem.Create(BetterSettingsTab, "BetterSetting.TextHeader.HostOnly");
|
||||
BetterGameSettings.WhenCheating = OptionStringItem.Create(100, BetterSettingsTab, "BetterSetting.Setting.WhenCheating",
|
||||
["BetterSetting.Setting.WhenCheating.Notify", "BetterSetting.Setting.WhenCheating.Kick", "BetterSetting.Setting.WhenCheating.Ban"], 2);
|
||||
BetterGameSettings.InvalidFriendCode = OptionCheckboxItem.Create(200, BetterSettingsTab, "BetterSetting.Setting.InvalidFriendCode", true);
|
||||
BetterGameSettings.CancelInvalidSabotage = OptionCheckboxItem.Create(900, BetterSettingsTab, "BetterSetting.Setting.CancelInvalidSabotage", true);
|
||||
BetterGameSettings.UseBanPlayerList = OptionCheckboxItem.Create(300, BetterSettingsTab, "BetterSetting.Setting.UseBanPlayerList", true);
|
||||
BetterGameSettings.UseBanNameList = OptionCheckboxItem.Create(400, BetterSettingsTab, "BetterSetting.Setting.UseBanNameList", true);
|
||||
BetterGameSettings.UseBanWordList = OptionCheckboxItem.Create(500, BetterSettingsTab, "BetterSetting.Setting.UseBanWordList", true);
|
||||
BetterGameSettings.UseBanWordListOnlyLobby = OptionCheckboxItem.Create(1400, BetterSettingsTab, "BetterSetting.Setting.UseBanWordListOnlyLobby", true, BetterGameSettings.UseBanWordList);
|
||||
OptionDividerItem.Create(BetterSettingsTab);
|
||||
}
|
||||
|
||||
TitleList.Add(new BetterOptionTitleItem().Create(BetterSettingsTab, Translator.GetString("BetterSetting.TextHeader.Detections")));
|
||||
BetterGameSettings.CensorDetectionReason = new BetterOptionCheckboxItem().Create(1300, BetterSettingsTab, Translator.GetString("BetterSetting.Setting.CensorDetectionReason"), false);
|
||||
BetterGameSettings.DetectedLevelAbove = new BetterOptionIntItem().Create(600, BetterSettingsTab, Translator.GetString("BetterSetting.Setting.DetectedLevelAbove"), [100, 5000, 5], 200, "Lv ", "");
|
||||
BetterGameSettings.DetectCheatClients = new BetterOptionCheckboxItem().Create(700, BetterSettingsTab, Translator.GetString("BetterSetting.Setting.DetectCheatClients"), true);
|
||||
BetterGameSettings.DetectInvalidRPCs = new BetterOptionCheckboxItem().Create(800, BetterSettingsTab, Translator.GetString("BetterSetting.Setting.DetectInvalidRPCs"), true);
|
||||
OptionTitleItem.Create(BetterSettingsTab, "BetterSetting.TextHeader.Detections");
|
||||
BetterGameSettings.CensorDetectionReason = OptionCheckboxItem.Create(1300, BetterSettingsTab, "BetterSetting.Setting.CensorDetectionReason", false);
|
||||
BetterGameSettings.DetectedLevelAbove = OptionIntItem.Create(600, BetterSettingsTab, "BetterSetting.Setting.DetectedLevelAbove", (100, 5000, 5), 200, ("Lv ", ""));
|
||||
BetterGameSettings.DetectCheatClients = OptionCheckboxItem.Create(700, BetterSettingsTab, "BetterSetting.Setting.DetectCheatClients", true);
|
||||
BetterGameSettings.DetectInvalidRPCs = OptionCheckboxItem.Create(800, BetterSettingsTab, "BetterSetting.Setting.DetectInvalidRPCs", true);
|
||||
|
||||
/*
|
||||
TitleList.Add(new BetterOptionDividerItem().Create(BetterSettingsTab));
|
||||
@@ -85,9 +80,9 @@ static class GameSettingMenuPatch
|
||||
|
||||
if (IsPreload || GameState.IsHost)
|
||||
{
|
||||
TitleList.Add(new BetterOptionHeaderItem().Create(BetterSettingsTab, Translator.GetString("BetterSetting.MainHeader.RoleAlgorithm")));
|
||||
BetterGameSettings.RoleRandomizer = new BetterOptionStringItem().Create(1100, BetterSettingsTab, Translator.GetString("BetterSetting.Setting.RoleRandomizer"), ["System.Random", "UnityEngine.Random"], 0);
|
||||
BetterGameSettings.DesyncRoles = new BetterOptionCheckboxItem().Create(1200, BetterSettingsTab, Translator.GetString("BetterSetting.Setting.DesyncRoles"), true);
|
||||
OptionHeaderItem.Create(BetterSettingsTab, "BetterSetting.MainHeader.RoleAlgorithm");
|
||||
BetterGameSettings.RoleRandomizer = OptionStringItem.Create(1100, BetterSettingsTab, "BetterSetting.Setting.RoleRandomizer", ["System.Random", "UnityEngine.Random"], 0);
|
||||
BetterGameSettings.DesyncRoles = OptionCheckboxItem.Create(1200, BetterSettingsTab, "BetterSetting.Setting.DesyncRoles", true);
|
||||
}
|
||||
|
||||
// Gameplay Settings
|
||||
@@ -96,37 +91,20 @@ static class GameSettingMenuPatch
|
||||
{
|
||||
if (IsPreload || !GameState.IsHideNSeek)
|
||||
{
|
||||
new BetterOptionHeaderItem().Create(BetterSettingsTab, Translator.GetString("BetterSetting.MainHeader.Gameplay"));
|
||||
BetterGameSettings.DisableSabotages = new BetterOptionCheckboxItem().Create(1500, BetterSettingsTab, Translator.GetString("BetterSetting.Setting.DisableSabotages"), false);
|
||||
BetterGameSettings.RemovePetOnDeath = new BetterOptionCheckboxItem().Create(1600, BetterSettingsTab, Translator.GetString("BetterSetting.Setting.RemovePetOnDeath"), false);
|
||||
OptionHeaderItem.Create(BetterSettingsTab, "BetterSetting.MainHeader.Gameplay");
|
||||
BetterGameSettings.DisableSabotages = OptionCheckboxItem.Create(1500, BetterSettingsTab, "BetterSetting.Setting.DisableSabotages", false);
|
||||
BetterGameSettings.RemovePetOnDeath = OptionCheckboxItem.Create(1600, BetterSettingsTab, "BetterSetting.Setting.RemovePetOnDeath", false);
|
||||
}
|
||||
else if (IsPreload || GameState.IsHideNSeek)
|
||||
{
|
||||
new BetterOptionHeaderItem().Create(BetterSettingsTab, Translator.GetString("BetterSetting.MainHeader.HideNSeek"));
|
||||
new BetterOptionTitleItem().Create(BetterSettingsTab, $"<color={RoleTypes.Impostor.GetRoleHex()}>{Translator.GetString(StringNames.ImpostorsCategory)}</color>");
|
||||
BetterGameSettings.HideAndSeekImpNum = new BetterOptionIntItem().Create(1000, BetterSettingsTab, Translator.GetString("BetterSetting.Setting.HideAndSeekImpNum"), [1, 5, 1], 1, "", "");
|
||||
BetterGameSettingsTemp.HideAndSeekImp2 = new BetterOptionPlayerItem().Create(BetterSettingsTab, Translator.GetString("BetterSetting.TempSetting.HideAndSeekImpNum"), BetterGameSettings.HideAndSeekImpNum, new Func<bool>(() =>
|
||||
{
|
||||
return BetterGameSettings.HideAndSeekImpNum is BetterOptionIntItem betterOption && betterOption.CurrentValue > 1;
|
||||
}));
|
||||
BetterGameSettingsTemp.HideAndSeekImp3 = new BetterOptionPlayerItem().Create(BetterSettingsTab, Translator.GetString("BetterSetting.TempSetting.HideAndSeekImpNum"), BetterGameSettings.HideAndSeekImpNum, new Func<bool>(() =>
|
||||
{
|
||||
return BetterGameSettings.HideAndSeekImpNum is BetterOptionIntItem betterOption && betterOption.CurrentValue > 2
|
||||
&& BetterGameSettingsTemp.HideAndSeekImp2 is BetterOptionPlayerItem betterOption2 && betterOption2.CurrentIndex > -1;
|
||||
}));
|
||||
BetterGameSettingsTemp.HideAndSeekImp4 = new BetterOptionPlayerItem().Create(BetterSettingsTab, Translator.GetString("BetterSetting.TempSetting.HideAndSeekImpNum"), BetterGameSettings.HideAndSeekImpNum, new Func<bool>(() =>
|
||||
{
|
||||
return BetterGameSettings.HideAndSeekImpNum is BetterOptionIntItem betterOption && betterOption.CurrentValue > 3
|
||||
&& BetterGameSettingsTemp.HideAndSeekImp2 is BetterOptionPlayerItem betterOption2 && betterOption2.CurrentIndex > -1
|
||||
&& BetterGameSettingsTemp.HideAndSeekImp3 is BetterOptionPlayerItem betterOption3 && betterOption3.CurrentIndex > -1;
|
||||
}));
|
||||
BetterGameSettingsTemp.HideAndSeekImp5 = new BetterOptionPlayerItem().Create(BetterSettingsTab, Translator.GetString("BetterSetting.TempSetting.HideAndSeekImpNum"), BetterGameSettings.HideAndSeekImpNum, new Func<bool>(() =>
|
||||
{
|
||||
return BetterGameSettings.HideAndSeekImpNum is BetterOptionIntItem betterOption && betterOption.CurrentValue > 4
|
||||
&& BetterGameSettingsTemp.HideAndSeekImp2 is BetterOptionPlayerItem betterOption2 && betterOption2.CurrentIndex > -1
|
||||
&& BetterGameSettingsTemp.HideAndSeekImp3 is BetterOptionPlayerItem betterOption3 && betterOption3.CurrentIndex > -1
|
||||
&& BetterGameSettingsTemp.HideAndSeekImp4 is BetterOptionPlayerItem betterOption4 && betterOption4.CurrentIndex > -1;
|
||||
}));
|
||||
OptionHeaderItem.Create(BetterSettingsTab, "BetterSetting.MainHeader.HideNSeek");
|
||||
OptionTitleItem.Create(BetterSettingsTab, $"<color={RoleTypes.Impostor.GetRoleHex()}>{Translator.GetString(StringNames.ImpostorsCategory)}</color>");
|
||||
BetterGameSettings.HideAndSeekImpNum = OptionIntItem.Create(1000, BetterSettingsTab, "BetterSetting.Setting.HideAndSeekImpNum", (1, 5, 1), 1);
|
||||
|
||||
BetterGameSettingsTemp.HideAndSeekImp2 = OptionPlayerItem.Create(0, BetterSettingsTab, "BetterSetting.TempSetting.HideAndSeekImpNum", BetterGameSettings.HideAndSeekImpNum);
|
||||
BetterGameSettingsTemp.HideAndSeekImp3 = OptionPlayerItem.Create(1, BetterSettingsTab, "BetterSetting.TempSetting.HideAndSeekImpNum", BetterGameSettings.HideAndSeekImpNum);
|
||||
BetterGameSettingsTemp.HideAndSeekImp4 = OptionPlayerItem.Create(2, BetterSettingsTab, "BetterSetting.TempSetting.HideAndSeekImpNum", BetterGameSettings.HideAndSeekImpNum);
|
||||
BetterGameSettingsTemp.HideAndSeekImp5 = OptionPlayerItem.Create(3, BetterSettingsTab, "BetterSetting.TempSetting.HideAndSeekImpNum", BetterGameSettings.HideAndSeekImpNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,54 +118,12 @@ static class GameSettingMenuPatch
|
||||
*/
|
||||
}
|
||||
|
||||
private static void Initialize()
|
||||
{
|
||||
_ = new LateTask(() =>
|
||||
{
|
||||
foreach (var item in BetterOptionItem.BetterOptionItems)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
item.obj.SetActive(true);
|
||||
|
||||
if (item.TitleText != null)
|
||||
{
|
||||
item.TitleText.text = item.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BetterOptionItem.UpdatePositions();
|
||||
}, 0.005f, shouldLog: false);
|
||||
}
|
||||
|
||||
[HarmonyPatch(nameof(GameSettingMenu.Update))]
|
||||
[HarmonyPostfix]
|
||||
internal static void Update_Postfix(GameSettingMenu __instance)
|
||||
{
|
||||
if (BetterSettingsButton != null)
|
||||
{
|
||||
BetterSettingsButton.buttonText.SetText(Translator.GetString("BetterSetting"));
|
||||
|
||||
if (!BetterSettingsButton.selected && !BetterSettingsButton.activeSprites.active)
|
||||
{
|
||||
BetterSettingsButton.buttonText.color = new Color(0f, 1f, 0f, 1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
BetterSettingsButton.buttonText.color = new Color(0.35f, 1f, 0.35f, 1f);
|
||||
}
|
||||
if (BetterSettingsButton.selected)
|
||||
{
|
||||
__instance.MenuDescriptionText.text = Translator.GetString("BetterSetting.Description");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(nameof(GameSettingMenu.Start))]
|
||||
[HarmonyPostfix]
|
||||
internal static void Start_Postfix(GameSettingMenu __instance)
|
||||
{
|
||||
SetupSettings();
|
||||
|
||||
__instance.gameObject.transform.SetLocalY(-0.1f);
|
||||
GameObject PanelSprite = __instance.gameObject.transform.Find("PanelSprite").gameObject;
|
||||
if (PanelSprite != null)
|
||||
@@ -196,33 +132,12 @@ static class GameSettingMenuPatch
|
||||
PanelSprite.transform.localScale = new Vector3(PanelSprite.transform.localScale.x, 0.625f);
|
||||
}
|
||||
|
||||
BetterSettingsButton = UnityEngine.Object.Instantiate(__instance.GameSettingsButton, __instance.GameSettingsButton.transform.parent);
|
||||
|
||||
BetterSettingsButton.name = "BetterSettings";
|
||||
BetterSettingsButton.OnClick.RemoveAllListeners();
|
||||
BetterSettingsButton.OnMouseOver.RemoveAllListeners();
|
||||
|
||||
BetterSettingsButton.activeSprites.GetComponent<SpriteRenderer>().color = new Color(0f, 1f, 0.35f, 1f);
|
||||
BetterSettingsButton.inactiveSprites.GetComponent<SpriteRenderer>().color = new Color(0f, 1f, 0.35f, 1f);
|
||||
BetterSettingsButton.selectedSprites.GetComponent<SpriteRenderer>().color = new Color(0f, 1f, 0.35f, 1f);
|
||||
|
||||
|
||||
BetterSettingsButton.OnClick.AddListener(new Action(() =>
|
||||
{
|
||||
__instance.ChangeTab(3, false);
|
||||
BetterOptionItem.UpdatePositions();
|
||||
}));
|
||||
|
||||
BetterSettingsTab = UnityEngine.Object.Instantiate(__instance.GameSettingsTab, __instance.GameSettingsTab.transform.parent);
|
||||
BetterSettingsTab.name = "BETTER SETTINGS TAB";
|
||||
BetterSettingsTab.scrollBar.Inner.DestroyChildren();
|
||||
|
||||
__instance.GamePresetsButton.OnMouseOver.RemoveAllListeners();
|
||||
__instance.GameSettingsButton.OnMouseOver.RemoveAllListeners();
|
||||
__instance.RoleSettingsButton.OnMouseOver.RemoveAllListeners();
|
||||
|
||||
|
||||
BetterSettingsButton.transform.localPosition = BetterSettingsButton.transform.localPosition - new Vector3(0f, 1.265f, 0f);
|
||||
BetterSettingsTab.TabButton.transform.localPosition = BetterSettingsTab.TabButton.transform.localPosition - new Vector3(0f, 1.265f, 0f);
|
||||
if (!GameState.IsHideNSeek && GameState.IsHost)
|
||||
{
|
||||
__instance.ChangeTab(1, false);
|
||||
@@ -244,46 +159,28 @@ static class GameSettingMenuPatch
|
||||
__instance.RoleSettingsButton.inactiveSprites.GetComponent<SpriteRenderer>().color = new(0.5f, 0.5f, 0.5f, 1f);
|
||||
__instance.ChangeTab(3, false);
|
||||
}
|
||||
|
||||
SetupSettings();
|
||||
}
|
||||
|
||||
[HarmonyPatch(nameof(GameSettingMenu.ChangeTab))]
|
||||
[HarmonyPrefix]
|
||||
internal static void ChangeTab_Prefix(GameSettingMenu __instance, [HarmonyArgument(0)] int tabNum, [HarmonyArgument(1)] bool previewOnly)
|
||||
{
|
||||
if (BetterSettingsTab == null || BetterSettingsButton == null) return;
|
||||
if (BetterSettingsTab == null) return;
|
||||
|
||||
BetterSettingsTab.gameObject.SetActive(false);
|
||||
BetterSettingsButton.SelectButton(false);
|
||||
BetterSettingsTab.AUTab.gameObject.SetActive(false);
|
||||
BetterSettingsTab.TabButton?.SelectButton(false);
|
||||
|
||||
if (previewOnly && Controller.currentTouchType == Controller.TouchType.Joystick || !previewOnly)
|
||||
{
|
||||
switch (tabNum)
|
||||
{
|
||||
case 3:
|
||||
BetterSettingsTab.gameObject.SetActive(true);
|
||||
BetterSettingsTab.AUTab.gameObject.SetActive(true);
|
||||
__instance.MenuDescriptionText.text = BetterSettingsTab.Description;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(nameof(GameSettingMenu.ChangeTab))]
|
||||
[HarmonyPostfix]
|
||||
internal static void ChangeTab_Postfix(GameSettingMenu __instance, [HarmonyArgument(0)] int tabNum)
|
||||
{
|
||||
if (BetterSettingsTab == null || BetterSettingsButton == null) return;
|
||||
|
||||
BetterSettingsButton.buttonText.color = new Color(0f, 1f, 0f, 1f);
|
||||
|
||||
switch (tabNum)
|
||||
{
|
||||
case 3:
|
||||
BetterSettingsButton.SelectButton(true);
|
||||
Initialize();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(GameOptionsMenu))]
|
||||
@@ -293,7 +190,7 @@ static class GameOptionsMenuPatch
|
||||
[HarmonyPrefix]
|
||||
internal static bool CreateSettings_Prefix(GameOptionsMenu __instance)
|
||||
{
|
||||
if (__instance == GameSettingMenuPatch.BetterSettingsTab)
|
||||
if (__instance == GameSettingMenuPatch.BetterSettingsTab.AUTab)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using BetterAmongUs.Helpers;
|
||||
using BetterAmongUs.Items.OptionItems;
|
||||
using BetterAmongUs.Modules;
|
||||
using HarmonyLib;
|
||||
using System.Text;
|
||||
@@ -17,6 +18,7 @@ class GamePlayManager
|
||||
[HarmonyPostfix]
|
||||
private static void Start_Postfix(/*LobbyBehaviour __instance*/)
|
||||
{
|
||||
OptionPlayerItem.ResetAllValues();
|
||||
}
|
||||
|
||||
// Disabled annoying music
|
||||
|
||||
@@ -284,10 +284,10 @@ internal class RoleManagerPatch
|
||||
int[] betterImpostorSettings =
|
||||
[
|
||||
GameOptionsManager.Instance.currentHideNSeekGameOptions.ImpostorPlayerID,
|
||||
BetterGameSettingsTemp.HideAndSeekImp2?.GetValue() ?? -1,
|
||||
BetterGameSettingsTemp.HideAndSeekImp3?.GetValue() ?? -1,
|
||||
BetterGameSettingsTemp.HideAndSeekImp4?.GetValue() ?? -1,
|
||||
BetterGameSettingsTemp.HideAndSeekImp5?.GetValue() ?? -1
|
||||
BetterGameSettingsTemp.HideAndSeekImp2?.GetInt() ?? -1,
|
||||
BetterGameSettingsTemp.HideAndSeekImp3?.GetInt() ?? -1,
|
||||
BetterGameSettingsTemp.HideAndSeekImp4?.GetInt() ?? -1,
|
||||
BetterGameSettingsTemp.HideAndSeekImp5?.GetInt() ?? -1
|
||||
];
|
||||
|
||||
for (int i = 0; i < NumImpostors; i++)
|
||||
@@ -464,7 +464,7 @@ internal class RoleManagerPatch
|
||||
|
||||
internal static int RNG()
|
||||
{
|
||||
switch (BetterGameSettings.RoleRandomizer.GetValue())
|
||||
switch (BetterGameSettings.RoleRandomizer.GetStringValue())
|
||||
{
|
||||
case 1:
|
||||
return UnityEngine.Random.Range(0, 100);
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
|
||||
"BetterSetting": "Better Settings",
|
||||
"BetterSetting.Description": "Edit better settings for your lobby and gameplay.",
|
||||
"BetterSetting.SetTo": "Set To:",
|
||||
"BetterSetting.MainHeader.AntiCheat": "<color=#4f92ff>Anti-Cheat Settings</color>",
|
||||
"BetterSetting.MainHeader.RoleAlgorithm": "<color=#4f92ff>Role Algorithm Settings</color>",
|
||||
"BetterSetting.MainHeader.Gameplay": "<color=#d7d700>Gameplay Settings</color>",
|
||||
|
||||
Reference in new issue
Block a user