Rework settings menu

This commit is contained in:
D1GQ committed 2025-10-18 19:22:54 -05:00
1 parent 29ac652280
commit 1407d30375
34 files changed
+2017 -1341

No files matched your search

+99
View File
@@ -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);
}
}
+86
View File
@@ -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
View File
@@ -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();
}
+2 -2
View File
@@ -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
View File
@@ -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();
}
}
}
-209
View File
@@ -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();
}
}
}
-209
View File
@@ -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();
}
}
}
-124
View File
@@ -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();
}
}
-187
View File
@@ -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();
}
}
}
-180
View File
@@ -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();
}
}
+97
View File
@@ -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();
}
+164
View File
@@ -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();
}
+168
View File
@@ -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();
}
+479
View File
@@ -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);
}
}
+66
View File
@@ -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";
}
}
}
+189
View File
@@ -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();
}
+171
View File
@@ -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;
}
+151
View File
@@ -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();
}
}
+1 -1
View File
@@ -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";
+2
View File
@@ -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();
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
}
+2
View File
@@ -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
+5 -5
View File
@@ -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);
+1
View File
@@ -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>",