diff --git a/MiraAPI.Example/ExampleColors.cs b/MiraAPI.Example/ExampleColors.cs
index 6833d3c..d61eb49 100644
--- a/MiraAPI.Example/ExampleColors.cs
+++ b/MiraAPI.Example/ExampleColors.cs
@@ -6,7 +6,10 @@ namespace MiraAPI.Example;
[RegisterCustomColors]
public static class ExampleColors
{
- public static CustomColor Cerulean { get; } = new("Cerulean", new Color(0.0f, 0.48f, 0.65f));
+ public static CustomColor Cerulean { get; } = new("Cerulean", new Color(0.0f, 0.48f, 0.65f))
+ {
+ ColorBrightness = CustomColorBrightness.Lighter,
+ };
public static CustomColor Rose { get; } = new("Rose", new Color(0.98f, 0.26f, 0.62f));
diff --git a/MiraAPI.Example/Options/ExampleOptions2.cs b/MiraAPI.Example/Options/ExampleOptions2.cs
index 9abf375..bc3c910 100644
--- a/MiraAPI.Example/Options/ExampleOptions2.cs
+++ b/MiraAPI.Example/Options/ExampleOptions2.cs
@@ -10,6 +10,8 @@ public class ExampleOptions2 : AbstractOptionGroup
public override uint GroupPriority => 0; // This group will be displayed first. The default value is uint.MaxValue.
+ public ModdedPlayerOption PlayerOption2 { get; } = new("YOU MUST CHOSE A PLAYER", false);
+ public ModdedPlayerOption PlayerOption { get; } = new("Eh whatever");
public ModdedToggleOption ToggleOpt1 { get; } = new("Toggle Option 1", false);
public ModdedToggleOption ToggleOpt2 { get; } = new("Toggle Option 2", false)
diff --git a/MiraAPI/Colors/CustomColor.cs b/MiraAPI/Colors/CustomColor.cs
index 7bbe87a..89663d1 100644
--- a/MiraAPI/Colors/CustomColor.cs
+++ b/MiraAPI/Colors/CustomColor.cs
@@ -13,19 +13,24 @@ namespace MiraAPI.Colors;
public sealed class CustomColor(StringNames name, Color32 mainColor, Color32 shadowColor)
{
///
- /// Gets the main color.
+ /// Gets or sets the main color.
///
- public Color32 MainColor { get; } = mainColor;
+ public Color32 MainColor { get; set; } = mainColor;
///
- /// Gets the shadow color.
+ /// Gets or sets the shadow color.
///
- public Color32 ShadowColor { get; } = shadowColor;
+ public Color32 ShadowColor { get; set; } = shadowColor;
///
- /// Gets the name of the color.
+ /// Gets or sets the name of the color.
///
- public StringNames Name { get; } = name;
+ public StringNames Name { get; set; } = name;
+
+ ///
+ /// Gets or sets whether the color is lighter or darker. Can be used to help with colorblind stuff.
+ ///
+ public CustomColorBrightness ColorBrightness { get; set; } = CustomColorBrightness.Darker;
///
public CustomColor(StringNames name, Color32 mainColor) : this(name, mainColor, mainColor.GetShadowColor(60))
@@ -42,3 +47,19 @@ public sealed class CustomColor(StringNames name, Color32 mainColor, Color32 sha
{
}
}
+
+///
+/// Can be used to help with colorblind stuff.
+///
+public enum CustomColorBrightness
+{
+ ///
+ /// A lighter color.
+ ///
+ Lighter,
+
+ ///
+ /// A darker color.
+ ///
+ Darker,
+}
diff --git a/MiraAPI/GameOptions/IModdedOption.cs b/MiraAPI/GameOptions/IModdedOption.cs
index 95173fb..947b6ff 100644
--- a/MiraAPI/GameOptions/IModdedOption.cs
+++ b/MiraAPI/GameOptions/IModdedOption.cs
@@ -62,9 +62,10 @@ public interface IModdedOption
/// The ToggleOption template.
/// The NumberOption template.
/// The StringOption template.
+ /// The PlayerOption template.
/// >The Transform container for the option.
/// >The created OptionBehaviour object.
- OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container);
+ OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container);
///
/// Gets the value as a float.
diff --git a/MiraAPI/GameOptions/ModdedOptionsManager.cs b/MiraAPI/GameOptions/ModdedOptionsManager.cs
index 0adc461..86e2006 100644
--- a/MiraAPI/GameOptions/ModdedOptionsManager.cs
+++ b/MiraAPI/GameOptions/ModdedOptionsManager.cs
@@ -6,6 +6,7 @@ using System.Reflection;
using BepInEx.Configuration;
using HarmonyLib;
using MiraAPI.GameOptions.Attributes;
+using MiraAPI.GameOptions.OptionTypes;
using MiraAPI.Networking;
using MiraAPI.PluginLoading;
using MiraAPI.Utilities;
@@ -22,6 +23,7 @@ public static class ModdedOptionsManager
private static readonly Dictionary OptionAttributes = [];
private static readonly Dictionary TypeToGroup = [];
+ internal static readonly Dictionary CreatedPlayerOptions = [];
internal static readonly Dictionary ModdedOptions = [];
internal static readonly List Groups = [];
diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs
index 18f13c6..0bec22f 100644
--- a/MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs
+++ b/MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs
@@ -44,7 +44,7 @@ public class ModdedEnumOption : ModdedOption
}
///
- public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
+ public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
{
var stringOption = Object.Instantiate(stringOpt, container);
@@ -135,7 +135,7 @@ public class ModdedEnumOption : ModdedOption where T : Enum
}
///
- public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
+ public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
{
var stringOption = Object.Instantiate(stringOpt, container);
diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedNumberOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedNumberOption.cs
index a01ffe8..53378e1 100644
--- a/MiraAPI/GameOptions/OptionTypes/ModdedNumberOption.cs
+++ b/MiraAPI/GameOptions/OptionTypes/ModdedNumberOption.cs
@@ -93,6 +93,7 @@ public class ModdedNumberOption : ModdedOption
ToggleOption toggleOpt,
NumberOption numberOpt,
StringOption stringOpt,
+ PlayerOption playerOpt,
Transform container)
{
var numberOption = Object.Instantiate(numberOpt, Vector3.zero, Quaternion.identity, container);
diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs
index 3c98d24..311f294 100644
--- a/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs
+++ b/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs
@@ -37,6 +37,7 @@ public abstract class ModdedOption : IModdedOption
{
if (_parentMod != null || value == null) return;
_parentMod = value;
+
var entry = _parentMod.GetConfigFile().Bind(ConfigDefinition, DefaultValue);
Value = entry.Value;
}
@@ -177,6 +178,7 @@ public abstract class ModdedOption : IModdedOption
ToggleOption toggleOpt,
NumberOption numberOpt,
StringOption stringOpt,
+ PlayerOption playerOpt,
Transform container);
///
diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedPlayerOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedPlayerOption.cs
new file mode 100644
index 0000000..6069a2c
--- /dev/null
+++ b/MiraAPI/GameOptions/OptionTypes/ModdedPlayerOption.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Linq;
+using Il2CppSystem.Collections.Generic;
+using MiraAPI.Networking;
+using MiraAPI.Utilities;
+using UnityEngine;
+using Object = UnityEngine.Object;
+
+namespace MiraAPI.GameOptions.OptionTypes;
+
+///
+/// An option for selecting an ingame player. It returns an index of the values list, NOT A PLAYER ID. To get a player out of this, index the Values list.
+///
+public class ModdedPlayerOption : ModdedOption
+{
+ ///
+ /// Gets or sets the included players.
+ ///
+ public List Values { get; set; }
+
+ ///
+ /// Gets or sets a filter for the players included in the option.
+ ///
+ public Func? PlayerFilter { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the option includes a "None" option. If None is selected, value will return -1.
+ ///
+ public bool AllowNone { get; set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The title of the option.
+ /// Whether the option includes a none option. If None is selected, value will return -1.
+ public ModdedPlayerOption(string title, bool allowNone = true) : base(title, allowNone ? -1 : 0, false)
+ {
+ Data = ScriptableObject.CreateInstance();
+ var data = (PlayerSelectionGameSetting)Data;
+
+ data.Title = StringName;
+ data.Type = global::OptionTypes.Player;
+
+ Values = new List();
+ AllowNone = allowNone;
+ Value = DefaultValue;
+ }
+
+ ///
+ public override OptionBehaviour CreateOption(
+ ToggleOption toggleOpt,
+ NumberOption numberOpt,
+ StringOption stringOpt,
+ PlayerOption playerOpt,
+ Transform container)
+ {
+ var playerOption = Object.Instantiate(playerOpt, container);
+
+ var filteredList = GetFilteredPlayers();
+ Values = filteredList.ToIl2CppList();
+
+ playerOption.SetUpFromData(Data, 20);
+ playerOption.OnValueChanged = (Il2CppSystem.Action)ValueChanged;
+
+ playerOption.Title = StringName;
+ playerOption.TitleText.text = TranslationController.Instance.GetString(StringName);
+ playerOption.Values = Values;
+ playerOption.Value = Value;
+ playerOption.playerIndex = filteredList.FindIndex(p => p.PlayerId == Value);
+
+ OptionBehaviour = playerOption;
+ ModdedOptionsManager.CreatedPlayerOptions.TryAdd(playerOption, this);
+
+ playerOption.SetValueText();
+ playerOption.AdjustButtonsActiveState();
+
+ return playerOption;
+ }
+
+ ///
+ /// Returns a player ran through the filter.
+ ///
+ /// A list of filtered players.
+ public System.Collections.Generic.List GetFilteredPlayers()
+ {
+ return GameData.Instance.AllPlayers.ToArray()
+ .Where(x => PlayerFilter?.Invoke(x) ?? true)
+ .ToList();
+ }
+
+ ///
+ /// Returns a player from the value. If AllowNone is enabled and none is enabled this will return null.
+ ///
+ /// A player or null if chosen none.
+ public NetworkedPlayerInfo? GetPlayerValue()
+ {
+ return Value < 0 ? null : Values[Value];
+ }
+
+ ///
+ public override float GetFloatData()
+ {
+ return Value;
+ }
+
+ ///
+ public override NetData GetNetData()
+ {
+ return new NetData(Id, BitConverter.GetBytes(Value));
+ }
+
+ ///
+ public override void HandleNetData(byte[] data)
+ {
+ SetValue(BitConverter.ToInt32(data));
+ }
+
+ ///
+ public override int GetValueFromOptionBehaviour(OptionBehaviour optionBehaviour)
+ {
+ return optionBehaviour.GetInt();
+ }
+
+ ///
+ protected override void OnValueChanged(int newValue)
+ {
+ HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(newValue), false);
+ if (!OptionBehaviour)
+ {
+ return;
+ }
+
+ if (OptionBehaviour is PlayerOption opt)
+ {
+ opt.Value = newValue;
+ }
+ }
+}
diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedToggleOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedToggleOption.cs
index 26ecc74..2cdd0e1 100644
--- a/MiraAPI/GameOptions/OptionTypes/ModdedToggleOption.cs
+++ b/MiraAPI/GameOptions/OptionTypes/ModdedToggleOption.cs
@@ -26,7 +26,7 @@ public class ModdedToggleOption : ModdedOption
}
///
- public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
+ public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
{
var toggleOption = Object.Instantiate(toggleOpt, Vector3.zero, Quaternion.identity, container);
diff --git a/MiraAPI/Patches/ChatControllerPatch.cs b/MiraAPI/Patches/ChatControllerPatch.cs
new file mode 100644
index 0000000..a30307c
--- /dev/null
+++ b/MiraAPI/Patches/ChatControllerPatch.cs
@@ -0,0 +1,33 @@
+using HarmonyLib;
+using UnityEngine;
+
+namespace MiraAPI.Patches;
+
+///
+/// Allows players to paste text into chat.
+/// Source: https://github.com/CallOfCreator/NewMod/blob/main/NewMod/Patches/ClipboardPatch.cs
+///
+[HarmonyPatch(typeof(ChatController), nameof(ChatController.Update))]
+public static class ChatControllerPatch
+{
+ public static void Prefix(ChatController __instance)
+ {
+ if (!HudManager.Instance.Chat.IsOpenOrOpening) return;
+
+ var ctrlPressed = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
+
+ if (!ctrlPressed || !Input.GetKeyDown(KeyCode.V)) return;
+
+ var clipboard = GUIUtility.systemCopyBuffer;
+
+ if (string.IsNullOrWhiteSpace(clipboard)) return;
+ clipboard = clipboard.Replace("<", string.Empty)
+ .Replace(">", string.Empty)
+ .Replace("\r", string.Empty);
+
+ if (!Input.GetKey(KeyCode.LeftShift) && !Input.GetKey(KeyCode.RightShift))
+ clipboard = clipboard.Replace("\n", string.Empty);
+
+ __instance.freeChatField.textArea.SetText(__instance.freeChatField.textArea.text + clipboard);
+ }
+}
diff --git a/MiraAPI/Patches/Hud/ButtonResetPatches.cs b/MiraAPI/Patches/Hud/ButtonResetPatches.cs
index 0859bea..29b190d 100644
--- a/MiraAPI/Patches/Hud/ButtonResetPatches.cs
+++ b/MiraAPI/Patches/Hud/ButtonResetPatches.cs
@@ -1,37 +1,25 @@
using HarmonyLib;
using MiraAPI.Hud;
+using Reactor.Utilities;
namespace MiraAPI.Patches.Hud;
-///
-/// Reset button patches.
-///
-[HarmonyPatch]
+[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))]
+[HarmonyPatch(typeof(ExileController), nameof(ExileController.ReEnableGameplay))]
public static class ButtonResetPatches
{
- ///
- /// Resets the cooldown and effect of all custom buttons when the meeting starts.
- ///
- [HarmonyPostfix]
- [HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))]
- public static void MeetingHudStartPostfix()
+ public static void Postfix()
{
foreach (var customActionButton in CustomButtonManager.CustomButtons)
{
- customActionButton.ResetCooldownAndOrEffect();
- }
- }
-
- ///
- /// Resets the cooldown and effect of all custom buttons after the exile screen is closed.
- ///
- [HarmonyPostfix]
- [HarmonyPatch(typeof(ExileController), nameof(ExileController.ReEnableGameplay))]
- public static void ExileControllerReEnableGameplayPostfix()
- {
- foreach (var customActionButton in CustomButtonManager.CustomButtons)
- {
- customActionButton.ResetCooldownAndOrEffect();
+ try
+ {
+ customActionButton.ResetCooldownAndOrEffect();
+ }
+ catch (System.Exception ex)
+ {
+ Logger.Error($"Error resetting cooldown and effect for button {customActionButton.GetType().Name}: {ex}");
+ }
}
}
}
diff --git a/MiraAPI/Patches/HudManagerPatches.cs b/MiraAPI/Patches/HudManagerPatches.cs
index 27a8026..14c2444 100644
--- a/MiraAPI/Patches/HudManagerPatches.cs
+++ b/MiraAPI/Patches/HudManagerPatches.cs
@@ -1,5 +1,6 @@
using HarmonyLib;
using MiraAPI.Hud;
+using Reactor.Utilities;
using Reactor.Utilities.Extensions;
using UnityEngine;
using Object = UnityEngine.Object;
@@ -77,7 +78,14 @@ public static class HudManagerPatches
continue;
}
- button.CreateButton(location);
+ try
+ {
+ button.CreateButton(location);
+ }
+ catch (System.Exception e)
+ {
+ Logger.Error($"Failed to create custom button {button.GetType().Name}: {e}");
+ }
}
gridArrange.Start();
@@ -105,7 +113,14 @@ public static class HudManagerPatches
foreach (var button in CustomButtonManager.CustomButtons)
{
- button.SetActive(isActive, role);
+ try
+ {
+ button.SetActive(isActive, role);
+ }
+ catch (System.Exception e)
+ {
+ Logger.Error($"Failed to set custom button {button.GetType().Name} active: {e}");
+ }
}
}
}
diff --git a/MiraAPI/Patches/Menu/HatsTabPatches.cs b/MiraAPI/Patches/Menu/HatsTabPatches.cs
index daf87b1..f985027 100644
--- a/MiraAPI/Patches/Menu/HatsTabPatches.cs
+++ b/MiraAPI/Patches/Menu/HatsTabPatches.cs
@@ -114,7 +114,7 @@ public static class HatsTabPatches
yield return null;
}
- __instance.scroller.ContentYBounds.max = -(__instance.YStart - (hatIndex + 1) / __instance.NumPerRow * __instance.YOffset) - 3f;
+ __instance.SetScrollerBounds();
yield return new WaitForSeconds(0.01f);
}
__instance.currentHatIsEquipped = true;
diff --git a/MiraAPI/Patches/Menu/NameplatesTabPatches.cs b/MiraAPI/Patches/Menu/NameplatesTabPatches.cs
index d66c8f3..bb5482a 100644
--- a/MiraAPI/Patches/Menu/NameplatesTabPatches.cs
+++ b/MiraAPI/Patches/Menu/NameplatesTabPatches.cs
@@ -91,7 +91,7 @@ public static class NameplatesTabPatches
hatIndex += 1;
}
- __instance.scroller.ContentYBounds.max = -(__instance.YStart - (hatIndex + 1) / __instance.NumPerRow * __instance.YOffset) - 3f;
+ __instance.SetScrollerBounds();
__instance.currentNameplateIsEquipped = true;
}
diff --git a/MiraAPI/Patches/Menu/SkinsTabPatches.cs b/MiraAPI/Patches/Menu/SkinsTabPatches.cs
index b102fb1..2e9ef2e 100644
--- a/MiraAPI/Patches/Menu/SkinsTabPatches.cs
+++ b/MiraAPI/Patches/Menu/SkinsTabPatches.cs
@@ -94,7 +94,7 @@ public static class SkinsTabPatches
hatIndex += 1;
}
- __instance.scroller.ContentYBounds.max = -(__instance.YStart - (hatIndex + 1) / __instance.NumPerRow * __instance.YOffset) - 3f;
+ __instance.SetScrollerBounds();
__instance.currentSkinIsEquipped = true;
}
diff --git a/MiraAPI/Patches/Menu/VisorsTabPatches.cs b/MiraAPI/Patches/Menu/VisorsTabPatches.cs
index 81845c6..d88cdab 100644
--- a/MiraAPI/Patches/Menu/VisorsTabPatches.cs
+++ b/MiraAPI/Patches/Menu/VisorsTabPatches.cs
@@ -90,7 +90,7 @@ public static class VisorsTabPatches
hatIndex += 1;
}
- __instance.scroller.ContentYBounds.max = -(__instance.YStart - (hatIndex + 1) / __instance.NumPerRow * __instance.YOffset) - 3f;
+ __instance.SetScrollerBounds();
__instance.currentVisorIsEquipped = true;
}
diff --git a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs
index 0d88920..155b50d 100644
--- a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs
+++ b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs
@@ -220,6 +220,7 @@ internal static class GameOptionsMenuPatch
menu.checkboxOrigin,
menu.numberOptionOrigin,
menu.stringOptionOrigin,
+ menu.playerOptionOrigin,
menu.settingsContainer));
foreach (var newOpt in options)
diff --git a/MiraAPI/Patches/Options/GameSettingMenuPatches.cs b/MiraAPI/Patches/Options/GameSettingMenuPatches.cs
index 7313206..fd9c78b 100644
--- a/MiraAPI/Patches/Options/GameSettingMenuPatches.cs
+++ b/MiraAPI/Patches/Options/GameSettingMenuPatches.cs
@@ -288,7 +288,7 @@ internal static class GameSettingMenuPatches
{
if (_text is not null && SelectedModIdx == 0)
{
- _text.text = "Default";
+ _text.text = $"(Page 0/{MiraPluginManager.Instance.RegisteredPlugins.Length})\nDefault";
_text.fontSizeMax = 3.2f;
SelectedMod = null;
}
@@ -298,7 +298,7 @@ internal static class GameSettingMenuPatches
SelectedMod = MiraPluginManager.Instance.RegisteredPlugins[SelectedModIdx - 1];
var name = SelectedMod.MiraPlugin.OptionsTitleText;
- _text.text = name[..Math.Min(name.Length, 25)];
+ _text.text = $"(Page {SelectedModIdx}/{MiraPluginManager.Instance.RegisteredPlugins.Length})\n" + name[..Math.Min(name.Length, 25)];
}
bool replaceWithModifiers = true;
diff --git a/MiraAPI/Patches/Options/OptionsPatches.cs b/MiraAPI/Patches/Options/OptionsPatches.cs
index c61613c..469a053 100644
--- a/MiraAPI/Patches/Options/OptionsPatches.cs
+++ b/MiraAPI/Patches/Options/OptionsPatches.cs
@@ -1,12 +1,161 @@
-using HarmonyLib;
+using System.Collections.Generic;
+using System.Linq;
+using HarmonyLib;
using Il2CppSystem;
+using MiraAPI.GameOptions;
+using MiraAPI.GameOptions.OptionTypes;
+using MiraAPI.Roles;
using MiraAPI.Utilities;
+using UnityEngine;
+using Object = Il2CppSystem.Object;
namespace MiraAPI.Patches.Options;
[HarmonyPatch]
public static class OptionsPatches
{
+ [HarmonyPrefix]
+ [HarmonyPatch(typeof(RoleOptionSetting), nameof(RoleOptionSetting.IncreaseChance))]
+ public static bool RoleIncreaseChancePrefix(RoleOptionSetting __instance)
+ {
+ if (!__instance.Role.IsCustomRole())
+ {
+ return true;
+ }
+
+ if (__instance.roleChance == 0)
+ {
+ __instance.roleMaxCount = 1;
+ }
+
+ var increment = Input.GetKey(KeyCode.LeftShift) ? 5 : 10;
+ __instance.roleChance += increment;
+
+ if (__instance.roleChance > 100)
+ {
+ __instance.roleChance = 0;
+ }
+
+ __instance.OnValueChanged.Invoke(__instance);
+ return false;
+ }
+
+ [HarmonyPrefix]
+ [HarmonyPatch(typeof(RoleOptionSetting), nameof(RoleOptionSetting.DecreaseChance))]
+ public static bool RoleDecreaseChancePrefix(RoleOptionSetting __instance)
+ {
+ if (!__instance.Role.IsCustomRole())
+ {
+ return true;
+ }
+
+ if (__instance.roleChance == 0)
+ {
+ __instance.roleMaxCount = 1;
+ }
+
+ var increment = Input.GetKey(KeyCode.LeftShift) ? 5 : 10;
+ __instance.roleChance -= increment;
+
+ if (__instance.roleChance < 0)
+ {
+ __instance.roleChance = 100;
+ }
+
+ __instance.OnValueChanged.Invoke(__instance);
+ return false;
+ }
+
+ [HarmonyPrefix]
+ [HarmonyPatch(typeof(RoleOptionSetting), nameof(RoleOptionSetting.IncreaseCount))]
+ public static bool RoleIncreaseCountPrefix(RoleOptionSetting __instance)
+ {
+ if (!__instance.Role.IsCustomRole())
+ {
+ return true;
+ }
+
+ if (__instance.roleMaxCount == 0)
+ {
+ __instance.roleChance = 50;
+ }
+
+ __instance.roleMaxCount += 1;
+ if (__instance.roleMaxCount > __instance.role.MaxCount)
+ {
+ __instance.roleMaxCount = 0;
+ }
+
+ __instance.OnValueChanged.Invoke(__instance);
+ return false;
+ }
+
+ [HarmonyPrefix]
+ [HarmonyPatch(typeof(RoleOptionSetting), nameof(RoleOptionSetting.DecreaseCount))]
+ public static bool RoleDecreaseCountPrefix(RoleOptionSetting __instance)
+ {
+ if (!__instance.Role.IsCustomRole())
+ {
+ return true;
+ }
+
+ if (__instance.roleMaxCount == 0)
+ {
+ __instance.roleChance = 50;
+ }
+
+ __instance.roleMaxCount -= 1;
+ if (__instance.roleMaxCount < 0)
+ {
+ __instance.roleMaxCount = __instance.role.MaxCount;
+ }
+
+ __instance.OnValueChanged.Invoke(__instance);
+ return false;
+ }
+
+ [HarmonyPrefix]
+ [HarmonyPatch(typeof(NumberOption), nameof(NumberOption.AdjustButtonsActiveState))]
+ [HarmonyPatch(typeof(StringOption), nameof(StringOption.AdjustButtonsActiveState))]
+ [HarmonyPatch(typeof(PlayerOption), nameof(PlayerOption.AdjustButtonsActiveState))]
+ [HarmonyPatch(typeof(RoleOptionSetting), nameof(RoleOptionSetting.AdjustChanceButtonsActiveState))]
+ [HarmonyPatch(typeof(RoleOptionSetting), nameof(RoleOptionSetting.AdjustCountButtonsActiveState))]
+ public static bool AdjustButtonsPrefix(OptionBehaviour __instance)
+ {
+ if (__instance.IsCustom())
+ {
+ if (__instance.TryCast() is { } numberOption)
+ {
+ numberOption.MinusBtn.SetInteractable(true);
+ numberOption.PlusBtn.SetInteractable(true);
+ }
+ if (__instance.TryCast() is { } stringOption)
+ {
+ stringOption.MinusBtn.SetInteractable(true);
+ stringOption.PlusBtn.SetInteractable(true);
+ }
+ if (__instance.TryCast() is { } playerOption)
+ {
+ playerOption.MinusBtn.SetInteractable(true);
+ playerOption.PlusBtn.SetInteractable(true);
+ }
+
+ return false;
+ }
+
+ if (__instance.TryCast() is { } roleOptionSetting && roleOptionSetting.Role.IsCustomRole())
+ {
+ roleOptionSetting.CountMinusBtn.SetInteractable(true);
+ roleOptionSetting.CountPlusBtn.SetInteractable(true);
+ roleOptionSetting.ChanceMinusBtn.SetInteractable(true);
+ roleOptionSetting.ChancePlusBtn.SetInteractable(true);
+
+ return false;
+ }
+
+ return true;
+ }
+
[HarmonyPrefix]
[HarmonyPatch(typeof(ToggleOption), nameof(ToggleOption.Initialize))]
public static bool ToggleInit(ToggleOption __instance)
@@ -16,8 +165,7 @@ public static class OptionsPatches
return true;
}
- __instance.TitleText.text =
- TranslationController.Instance.GetString(__instance.Title, Array.Empty