modifier options (WIP)

This commit is contained in:
XtraCube committed 2025-03-01 18:34:18 -05:00
1 parent 6f248221d6
commit bbff2dd2d9
15 files changed
+458 -195

No files matched your search

@@ -5,14 +5,4 @@ namespace MiraAPI.Example.Modifiers;
public class CaptainModifier : GameModifier
{
public override string ModifierName => "Captain";
public override int GetAmountPerGame()
{
return 1;
}
public override int GetAssignmentChance()
{
return 100;
}
}
@@ -5,15 +5,6 @@ namespace MiraAPI.Example.Modifiers;
public class HighPriorityModifier : GameModifier
{
public override string ModifierName => "High Priority";
public override int GetAssignmentChance()
{
return 100;
}
public override int GetAmountPerGame()
{
return 1;
}
public override int Priority()
{
@@ -0,0 +1,13 @@
using MiraAPI.Example.Modifiers;
using MiraAPI.GameOptions;
using MiraAPI.GameOptions.Attributes;
namespace MiraAPI.Example.Options.Modifiers;
public class CaptainModifierSettings : AbstractOptionGroup<CaptainModifier>
{
public override string GroupName => "Captain Settings";
[ModdedNumberOption("Uses", 1, 5)]
public float NumUses { get; set; } = 3;
}
@@ -0,0 +1,15 @@
using System.Linq;
namespace MiraAPI.GameOptions;
internal class ModifierOptionGroup : AbstractOptionGroup
{
public override string GroupName { get; }
public ModifierOptionGroup(string name, IModdedOption[] options, params AbstractOptionGroup[] others)
{
GroupName = name;
Options.AddRange(options);
Options.AddRange(others.SelectMany(x=>x.Options));
}
}
@@ -75,11 +75,11 @@ public class ModdedNumberOption : ModdedOption<float>
data.Increment = Increment;
data.ValidRange = new FloatRange(Min, Max);
data.FormatString = formatString ??
(!Mathf.Approximately(defaultValue, 0) ||
!Mathf.Approximately(Increment % 1, 0) ||
!Mathf.Approximately(Value % 1, 0) ||
!Mathf.Approximately(Min % 1, 0) ||
!Mathf.Approximately(Max % 1, 0) ? "0.0" : "0");
(defaultValue.IsInteger() &&
Increment.IsInteger() &&
Value.IsInteger() &&
Min.IsInteger() &&
Max.IsInteger() ? "0" : "0.0");
data.ZeroIsInfinity = ZeroInfinity;
data.SuffixType = (NumberSuffixes)SuffixType;
@@ -0,0 +1,10 @@
namespace MiraAPI.Modifiers;
/// <summary>
/// Represents the assignment configuration for a game modifier.
/// </summary>
/// <param name="DefaultAmount">The default amount of players that can have this modifier in a game.</param>
/// <param name="DefaultChance">The default chance of the modifier being assigned to a player.</param>
/// <param name="CreateAmountOption">Whether Mira should create an amount option for the modifier.</param>
/// <param name="CreateChanceOption">Whether Mira should create a chance option for the modifier.</param>
public record struct AssignmentConfiguration(int DefaultAmount, int DefaultChance, bool CreateAmountOption, bool CreateChanceOption);
+13 -1
View File
@@ -1,11 +1,13 @@
using System;
using MiraAPI.GameOptions;
using MiraAPI.PluginLoading;
namespace MiraAPI.Modifiers;
/// <summary>
/// Base class for all modifiers.
/// </summary>
public abstract class BaseModifier
public abstract class BaseModifier : IOptionable
{
/// <summary>
/// Gets the player that the modifier is attached to.
@@ -32,6 +34,16 @@ public abstract class BaseModifier
/// </summary>
public uint TypeId => ModifierManager.GetModifierTypeId(GetType()) ?? throw new InvalidOperationException("Modifier is not registered.");
/// <summary>
/// Gets the parent mod of the modifier.
/// </summary>
public MiraPluginInfo ParentMod => Array.Find(
MiraPluginManager.Instance.RegisteredPlugins(),
x => x.Modifiers.Exists(y => y.TypeId == TypeId)
) ?? throw new InvalidOperationException("Modifier is not registered.");
internal ModifierOptionGroup? ModifierOptionsGroup { get; set; }
/// <summary>
/// Gets the modifier name.
/// </summary>
+17 -1
View File
@@ -71,7 +71,23 @@ public static class ModifierManager
return true;
}
var mod = Activator.CreateInstance(modifierType) as GameModifier;
if (modifierType.GetConstructor(Type.EmptyTypes) == null)
{
Logger<MiraApiPlugin>.Error($"Modifier {modifierType.FullName} does not have a parameterless constructor!");
return false;
}
if (Activator.CreateInstance(modifierType) is not GameModifier mod)
{
Logger<MiraApiPlugin>.Error($"Modifier {modifierType.FullName} could not be cast to GameModifier!");
return false;
}
info.GameModifiers.Add(mod);
info.PluginConfig.Bind(mod.AmountDefinition, 0);
info.PluginConfig.Bind(mod.ChanceDefinition, 0);
var priority = mod!.Priority();
if (!PrioritiesToIdsMap.TryGetValue(priority, out var list))
+64 -3
View File
@@ -1,4 +1,10 @@
namespace MiraAPI.Modifiers.Types;
using System;
using BepInEx.Configuration;
using MiraAPI.GameOptions.OptionTypes;
using MiraAPI.Utilities;
using Reactor.Utilities;
namespace MiraAPI.Modifiers.Types;
/// <summary>
/// The base class for a game modifier. Game modifiers are applied at the start of the game on top of the player's role.
@@ -8,17 +14,72 @@ public abstract class GameModifier : BaseModifier
/// <inheritdoc />
public override bool ShowInFreeplay => true;
/// <summary>
/// Gets the assignment configuration for the modifier.
/// </summary>
public virtual AssignmentConfiguration AssignmentConfiguration => new(0, 0, true, true);
internal ConfigDefinition AmountDefinition => new("Modifiers", $"Amount {GetType().FullName}");
internal ConfigDefinition ChanceDefinition => new("Modifiers", $"Chance {GetType().FullName}");
internal ModdedNumberOption AmountOption { get; } = new("Amount", 0, 0, 15, 1, MiraNumberSuffixes.None);
internal ModdedNumberOption ChanceOption { get; } = new("Chance", 0, 0, 100, 1, MiraNumberSuffixes.Percent);
/// <summary>
/// Gets the chance of the modifier being assigned to a player.
/// </summary>
/// <returns>An int value between 0 and 100 representing percent.</returns>
public abstract int GetAssignmentChance();
public virtual int GetAssignmentChance()
{
return AssignmentConfiguration.CreateChanceOption &&
ParentMod.PluginConfig.TryGetEntry(ChanceDefinition, out ConfigEntry<int> entry)
? entry.Value
: AssignmentConfiguration.DefaultChance;
}
/// <summary>
/// Gets the amount of players that can have this modifier in a game.
/// </summary>
/// <returns>An int value greater than or equal to zero.</returns>
public abstract int GetAmountPerGame();
public virtual int GetAmountPerGame()
{
return AssignmentConfiguration.CreateAmountOption &&
ParentMod.PluginConfig.TryGetEntry(AmountDefinition, out ConfigEntry<int> entry)
? entry.Value
: AssignmentConfiguration.DefaultAmount;
}
/// <summary>
/// Sets the chance of the modifier being assigned to a player.
/// </summary>
/// <param name="chance">The chance between 0 and 100.</param>
public virtual void SetAssignmentChance(int chance)
{
if (ParentMod.PluginConfig.TryGetEntry(ChanceDefinition, out ConfigEntry<int> entry))
{
entry.Value = Math.Clamp(chance, 0, 100);
return;
}
Logger<MiraApiPlugin>.Error($"Error getting chance configuration for modifier: {ModifierName}");
}
/// <summary>
/// Sets the amount of players that can have this modifier in a game.
/// </summary>
/// <param name="amount">The amount of players between zero and the max player count.</param>
public virtual void SetAmountPerGame(int amount)
{
if (ParentMod.PluginConfig.TryGetEntry(AmountDefinition, out ConfigEntry<int> entry))
{
entry.Value = Math.Max(amount, 0);
return;
}
Logger<MiraApiPlugin>.Error($"Error getting amount configuration for modifier: {ModifierName}");
}
/// <summary>
/// Gets the priority at which the modifier will spawn. The higher the value, the higher up on the assignment list.
+205 -147
View File
@@ -1,14 +1,18 @@
using System.Linq;
using System;
using System.Linq;
using HarmonyLib;
using MiraAPI.GameOptions;
using MiraAPI.Modifiers.Types;
using MiraAPI.Roles;
using MiraAPI.Utilities;
using MiraAPI.Utilities.Assets;
using Reactor.Localization.Utilities;
using Reactor.Utilities;
using Reactor.Utilities.Extensions;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using Object = UnityEngine.Object;
namespace MiraAPI.Patches.Options;
@@ -32,64 +36,105 @@ public static class GameOptionsMenuPatch
}
var num = 2.1f;
var filteredGroups =
GameSettingMenuPatches.SelectedMod?.OptionGroups
.Where(x=> x is not IOptionableGroup) ?? [];
foreach (var group in filteredGroups)
if (__instance.name == "MODIFIERS TAB")
{
if (group.Options.Count == 0 || group.Header is null)
ModifiersUpdate(ref num);
}
else
{
var filteredGroups =
GameSettingMenuPatches.SelectedMod?.OptionGroups
.Where(x => x is not IOptionableGroup) ?? [];
foreach (var group in filteredGroups)
{
continue;
}
if (!group.GroupVisible.Invoke())
{
group.Header.gameObject.SetActive(false);
foreach (var option in group.Options)
{
option.OptionBehaviour?.gameObject.SetActive(false);
}
continue;
}
group.Header.gameObject.SetActive(true);
group.Header.transform.localScale = Vector3.one * 0.63f;
group.Header.transform.localPosition = new Vector3(-0.903f, num, -2f);
num -= 0.58f;
foreach (var opt in group.Options)
{
var newOpt = opt.OptionBehaviour;
if (newOpt is null)
{
continue;
}
if (!opt.Visible.Invoke())
{
newOpt.gameObject.SetActive(false);
continue;
}
if (!group.AllOptionsHidden)
{
newOpt.gameObject.SetActive(true);
newOpt.transform.localPosition = new Vector3(0.952f, num, -2f);
num -= 0.45f;
}
else
{
newOpt.gameObject.SetActive(false);
}
UpdateGroup(group, ref num);
}
}
__instance.scrollBar.SetYBoundsMax(-num - 1.65f);
}
private static void UpdateGroup(AbstractOptionGroup group, ref float num)
{
if (group.Options.Count == 0 || group.Header is null)
{
return;
}
if (!group.GroupVisible.Invoke())
{
group.Header.gameObject.SetActive(false);
foreach (var option in group.Options)
{
option.OptionBehaviour?.gameObject.SetActive(false);
}
return;
}
group.Header.gameObject.SetActive(true);
group.Header.transform.localScale = Vector3.one * 0.63f;
group.Header.transform.localPosition = new Vector3(-0.903f, num, -2f);
num -= 0.58f;
foreach (var opt in group.Options)
{
var newOpt = opt.OptionBehaviour;
if (newOpt is null)
{
continue;
}
if (!opt.Visible.Invoke())
{
newOpt.gameObject.SetActive(false);
continue;
}
if (!group.AllOptionsHidden)
{
newOpt.gameObject.SetActive(true);
newOpt.transform.localPosition = new Vector3(0.952f, num, -2f);
num -= 0.45f;
}
else
{
newOpt.gameObject.SetActive(false);
}
}
}
private static void ModifiersUpdate(ref float num)
{
var modifiers = GameSettingMenuPatches.SelectedMod?.Modifiers.Select(x=>x.ModifierOptionsGroup) ?? [];
foreach (var modGroup in modifiers)
{
if (modGroup != null)
{
UpdateGroup(modGroup, ref num);
}
}
}
private static void ModifiersCreate(GameOptionsMenu menu)
{
var modifiers = GameSettingMenuPatches.SelectedMod?.GameModifiers ?? [];
var optLookup = GameSettingMenuPatches.SelectedMod?.OptionGroups
.Where(x => x is IOptionableGroup group && group.OptionableType.IsAssignableTo(typeof(GameModifier)))
.ToLookup(x => (x as IOptionableGroup)!.OptionableType);
foreach (var mod in modifiers)
{
mod.ModifierOptionsGroup = new ModifierOptionGroup(mod.ModifierName, [mod.AmountOption, mod.ChanceOption], [.. optLookup?[mod.GetType()] ?? []]);
CreateGroup(menu, mod.ModifierOptionsGroup);
}
}
[HarmonyPrefix]
[HarmonyPatch(nameof(GameOptionsMenu.CreateSettings))]
public static bool SettingsPatch(GameOptionsMenu __instance)
@@ -101,107 +146,19 @@ public static class GameOptionsMenuPatch
__instance.MapPicker.gameObject.SetActive(false);
if (__instance.name == "MODIFIERS TAB")
{
Logger<MiraApiPlugin>.Error("Creating modifiers");
ModifiersCreate(__instance);
return false;
}
var filteredGroups = GameSettingMenuPatches.SelectedMod?.OptionGroups
.Where(x => x is not IOptionableGroup) ?? [];
foreach (var group in filteredGroups)
{
var categoryHeaderMasked = Object.Instantiate(
__instance.categoryHeaderOrigin,
Vector3.zero,
Quaternion.identity,
__instance.settingsContainer);
categoryHeaderMasked.SetHeader(CustomStringName.CreateAndRegister(group.GroupName), 20);
if (group.GroupColor != Color.clear)
{
categoryHeaderMasked.Background.color = group.GroupColor;
categoryHeaderMasked.Divider.color = group.GroupColor;
categoryHeaderMasked.Title.color = group.GroupColor.GetAlternateColor();
}
categoryHeaderMasked.Background.size = new Vector2(
categoryHeaderMasked.Background.size.x + 1.5f,
categoryHeaderMasked.Background.size.y);
categoryHeaderMasked.gameObject.SetActive(false);
group.Header = categoryHeaderMasked;
var newText = Object.Instantiate(categoryHeaderMasked.Title, categoryHeaderMasked.transform);
newText.text = "<size=70%>(Click to close)</size>";
newText.transform.localPosition = new Vector3(2.6249f, -0.165f, 0f);
newText.gameObject.GetComponent<TextTranslatorTMP>().Destroy();
var options = group.Options.Select(
opt => opt.CreateOption(
__instance.checkboxOrigin,
__instance.numberOptionOrigin,
__instance.stringOptionOrigin,
__instance.settingsContainer));
foreach (var newOpt in options)
{
newOpt.SetClickMask(__instance.ButtonClickMask);
SpriteRenderer[] componentsInChildren = newOpt.GetComponentsInChildren<SpriteRenderer>(true);
foreach (var renderer in componentsInChildren)
{
if (group.GroupColor != Color.clear)
{
renderer.color = group.GroupColor.GetAlternateColor();
if (renderer.transform.parent.TryGetComponent<GameOptionButton>(out var btn))
{
btn.interactableColor = group.GroupColor.GetAlternateColor();
btn.interactableHoveredColor = Color.white;
}
}
renderer.material.SetInt(PlayerMaterial.MaskLayer, 20);
}
foreach (var textMeshPro in newOpt.GetComponentsInChildren<TextMeshPro>(true))
{
if (group.GroupColor != Color.clear)
{
textMeshPro.color = group.GroupColor;
}
textMeshPro.fontMaterial.SetFloat(ShaderID.StencilComp, 3f);
textMeshPro.fontMaterial.SetFloat(ShaderID.Stencil, 20);
}
if (newOpt is ToggleOption toggle)
{
toggle.CheckMark.sprite = MiraAssets.Checkmark.LoadAsset();
toggle.CheckMark.color =
group.GroupColor != Color.clear ? group.GroupColor : MiraAssets.AcceptedTeal;
var rend = toggle.CheckMark.transform.parent.FindChild("ActiveSprite")
.GetComponent<SpriteRenderer>();
rend.sprite = MiraAssets.CheckmarkBox.LoadAsset();
rend.color = group.GroupColor != Color.clear ? group.GroupColor : MiraAssets.AcceptedTeal;
}
__instance.Children.Add(newOpt);
newOpt.Initialize();
newOpt.gameObject.SetActive(false);
}
var boxCol = categoryHeaderMasked.gameObject.AddComponent<BoxCollider2D>();
boxCol.size = new Vector2(7, 0.7f);
boxCol.offset = new Vector2(1.5f, -0.3f);
var headerBtn = categoryHeaderMasked.gameObject.AddComponent<PassiveButton>();
headerBtn.ClickSound = __instance.BackButton.GetComponent<PassiveButton>().ClickSound;
headerBtn.OnMouseOver = new UnityEvent();
headerBtn.OnMouseOut = new UnityEvent();
headerBtn.OnClick.AddListener(
(UnityAction)(() =>
{
group.AllOptionsHidden = !group.AllOptionsHidden;
newText.text = group.AllOptionsHidden
? "<size=70%>(Click to open)</size>"
: "<size=70%>(Click to close)</size>";
}));
headerBtn.SetButtonEnableState(true);
CreateGroup(__instance, group);
}
return false;
@@ -241,4 +198,105 @@ public static class GameOptionsMenuPatch
return false;
}
private static void CreateGroup(GameOptionsMenu menu, AbstractOptionGroup group)
{
var categoryHeaderMasked = Object.Instantiate(
menu.categoryHeaderOrigin,
Vector3.zero,
Quaternion.identity,
menu.settingsContainer);
categoryHeaderMasked.SetHeader(CustomStringName.CreateAndRegister(group.GroupName), 20);
if (group.GroupColor != Color.clear)
{
categoryHeaderMasked.Background.color = group.GroupColor;
categoryHeaderMasked.Divider.color = group.GroupColor;
categoryHeaderMasked.Title.color = group.GroupColor.GetAlternateColor();
}
categoryHeaderMasked.Background.size = new Vector2(
categoryHeaderMasked.Background.size.x + 1.5f,
categoryHeaderMasked.Background.size.y);
categoryHeaderMasked.gameObject.SetActive(false);
group.Header = categoryHeaderMasked;
var newText = Object.Instantiate(categoryHeaderMasked.Title, categoryHeaderMasked.transform);
newText.text = "<size=70%>(Click to close)</size>";
newText.transform.localPosition = new Vector3(2.6249f, -0.165f, 0f);
newText.gameObject.GetComponent<TextTranslatorTMP>().Destroy();
var options = group.Options.Select(
opt => opt.CreateOption(
menu.checkboxOrigin,
menu.numberOptionOrigin,
menu.stringOptionOrigin,
menu.settingsContainer));
foreach (var newOpt in options)
{
newOpt.SetClickMask(menu.ButtonClickMask);
SpriteRenderer[] componentsInChildren = newOpt.GetComponentsInChildren<SpriteRenderer>(true);
foreach (var renderer in componentsInChildren)
{
if (group.GroupColor != Color.clear)
{
renderer.color = group.GroupColor.GetAlternateColor();
if (renderer.transform.parent.TryGetComponent<GameOptionButton>(out var btn))
{
btn.interactableColor = group.GroupColor.GetAlternateColor();
btn.interactableHoveredColor = Color.white;
}
}
renderer.material.SetInt(PlayerMaterial.MaskLayer, 20);
}
foreach (var textMeshPro in newOpt.GetComponentsInChildren<TextMeshPro>(true))
{
if (group.GroupColor != Color.clear)
{
textMeshPro.color = group.GroupColor;
}
textMeshPro.fontMaterial.SetFloat(ShaderID.StencilComp, 3f);
textMeshPro.fontMaterial.SetFloat(ShaderID.Stencil, 20);
}
if (newOpt is ToggleOption toggle)
{
toggle.CheckMark.sprite = MiraAssets.Checkmark.LoadAsset();
toggle.CheckMark.color =
group.GroupColor != Color.clear ? group.GroupColor : MiraAssets.AcceptedTeal;
var rend = toggle.CheckMark.transform.parent.FindChild("ActiveSprite")
.GetComponent<SpriteRenderer>();
rend.sprite = MiraAssets.CheckmarkBox.LoadAsset();
rend.color = group.GroupColor != Color.clear ? group.GroupColor : MiraAssets.AcceptedTeal;
}
menu.Children.Add(newOpt);
newOpt.Initialize();
newOpt.gameObject.SetActive(false);
}
var boxCol = categoryHeaderMasked.gameObject.AddComponent<BoxCollider2D>();
boxCol.size = new Vector2(7, 0.7f);
boxCol.offset = new Vector2(1.5f, -0.3f);
var headerBtn = categoryHeaderMasked.gameObject.AddComponent<PassiveButton>();
headerBtn.ClickSound = menu.BackButton.GetComponent<PassiveButton>().ClickSound;
headerBtn.OnMouseOver = new UnityEvent();
headerBtn.OnMouseOut = new UnityEvent();
headerBtn.OnClick.AddListener(
(UnityAction)(() =>
{
group.AllOptionsHidden = !group.AllOptionsHidden;
newText.text = group.AllOptionsHidden
? "<size=70%>(Click to open)</size>"
: "<size=70%>(Click to close)</size>";
}));
headerBtn.SetButtonEnableState(true);
}
}
+100 -16
View File
@@ -1,5 +1,4 @@
using System;
using System.Linq;
using HarmonyLib;
using MiraAPI.PluginLoading;
using MiraAPI.Utilities.Assets;
@@ -12,26 +11,41 @@ using Object = UnityEngine.Object;
namespace MiraAPI.Patches.Options;
/// <summary>
/// Patches for the <see cref="GameSettingMenu"/> to add support for custom options.
/// </summary>
[HarmonyPatch(typeof(GameSettingMenu))]
public static class GameSettingMenuPatches
internal static class GameSettingMenuPatches
{
/// <summary>
/// Gets the currently selected mod index.
/// </summary>
public static int SelectedModIdx { get; private set; }
/// <summary>
/// Gets the currently selected mod.
/// </summary>
public static MiraPluginInfo? SelectedMod { get; private set; }
private static TextMeshPro? _text;
private static Vector3 _roleBtnOgPos;
private static GameOptionsMenu? _modifiersTab;
private static PassiveButton? _modifiersButton;
private static PassiveButton? _smallRolesButton;
[HarmonyPostfix]
[HarmonyPatch(nameof(GameSettingMenu.ChangeTab))]
public static void ChangeTabPostfix(GameSettingMenu __instance, int tabNum, bool previewOnly)
{
if ((previewOnly && Controller.currentTouchType == Controller.TouchType.Joystick) || !previewOnly)
{
_modifiersTab?.gameObject.SetActive(tabNum == 3);
_modifiersButton?.SelectButton(tabNum == 3);
_smallRolesButton?.SelectButton(tabNum == 2);
}
if (previewOnly)
{
return;
}
_modifiersButton?.SelectButton(tabNum == 3);
_smallRolesButton?.SelectButton(tabNum == 2);
}
/// <summary>
/// Prefix for the <see cref="GameSettingMenu.Start"/> method. Sets up the custom options.
/// </summary>
@@ -54,8 +68,6 @@ public static class GameSettingMenuPatches
_text.fontSizeMax = 3.2f;
_text.overflowMode = TextOverflowModes.Overflow;
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
_text.alignment = TextAlignmentOptions.Center;
var nextButton = Object.Instantiate(__instance.BackButton, __instance.BackButton.transform.parent).gameObject;
@@ -91,6 +103,61 @@ public static class GameSettingMenuPatches
}
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
}));
// clone game settings tab for modifiers
_modifiersTab = Object.Instantiate(__instance.GameSettingsTab, __instance.GameSettingsTab.transform.parent);
_modifiersTab.name = "MODIFIERS TAB";
// create button for modifiers
__instance.RoleSettingsButton.gameObject.SetActive(false);
_smallRolesButton = Object.Instantiate(__instance.RoleSettingsButton, __instance.RoleSettingsButton.transform.parent);
var pos = new Vector3(-3.65f, _smallRolesButton.transform.localPosition.y, _smallRolesButton.transform.localPosition.z);
_smallRolesButton.transform.localPosition = pos;
_smallRolesButton.OnClick.AddListener((UnityAction)(() =>
{
__instance.ChangeTab(2, false);
}));
_smallRolesButton.OnMouseOver.AddListener((UnityAction)(() =>
{
__instance.ChangeTab(2, true);
}));
var roleText = _smallRolesButton.buttonText;
roleText.text = "Roles";
roleText.GetComponent<TextTranslatorTMP>().Destroy();
roleText.alignment = TextAlignmentOptions.Center;
roleText.transform.parent.localPosition = new Vector3(-.525f, roleText.transform.parent.localPosition.y, roleText.transform.parent.localPosition.z);
foreach (var collider in _smallRolesButton.Colliders)
{
if (collider.TryCast<BoxCollider2D>() is { } col)
{
col.size = new Vector2(col.size.x / 2, col.size.y);
}
}
foreach (var rend in _smallRolesButton.GetComponentsInChildren<SpriteRenderer>(true))
{
rend.size = new Vector2(rend.size.x / 2, rend.size.y);
}
_modifiersButton = Object.Instantiate(_smallRolesButton, _smallRolesButton.transform.parent);
_modifiersButton.OnClick = new ButtonClickedEvent();
_modifiersButton.OnClick.AddListener((UnityAction)(() =>
{
__instance.ChangeTab(3, false);
}));
_modifiersButton.OnMouseOver = new UnityEvent();
_modifiersButton.OnMouseOver.AddListener((UnityAction)(() =>
{
__instance.ChangeTab(3, true);
}));
_modifiersButton.buttonText.text = "Modifiers";
pos.x = -2.27f;
_modifiersButton.transform.localPosition = pos;
_modifiersButton.name = "ModifiersButton";
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
}
private static void UpdateText(GameSettingMenu menu, GameOptionsMenu settings, RolesSettingsMenu roles)
@@ -109,9 +176,26 @@ public static class GameSettingMenuPatches
_text.text = name[..Math.Min(name.Length, 25)];
}
menu.RoleSettingsButton.transform.localPosition = _roleBtnOgPos;
menu.GameSettingsButton.gameObject.SetActive(true);
menu.RoleSettingsButton.gameObject.SetActive(true);
_modifiersButton.gameObject.SetActive(false);
_smallRolesButton.gameObject.SetActive(false);
menu.RoleSettingsButton.gameObject.SetActive(false);
if (SelectedModIdx != 0 && SelectedMod?.GameModifiers.Count != 0)
{
_modifiersButton.gameObject.SetActive(true);
_smallRolesButton.gameObject.SetActive(true);
}
else
{
menu.RoleSettingsButton.gameObject.SetActive(true);
if (SelectedModIdx == 0 && _modifiersTab.gameObject.active)
{
menu.ChangeTab(0, false);
}
}
//menu.RoleSettingsButton.transform.localPosition = _roleBtnOgPos;
//menu.GameSettingsButton.gameObject.SetActive(true);
//menu.RoleSettingsButton.gameObject.SetActive(true);
// TODO: reimplement this
/*
@@ -504,7 +504,7 @@ public static class RoleSettingMenuPatches
if (index < GameSettingMenuPatches.SelectedMod?.CustomRoles.Count - 1)
{
ScrollerNum += -0.43f;
ScrollerNum -= 0.43f;
}
return roleOptionSetting;
+3
View File
@@ -6,6 +6,7 @@ using MiraAPI.GameModes;
using MiraAPI.GameOptions;
using MiraAPI.Hud;
using MiraAPI.Modifiers;
using MiraAPI.Modifiers.Types;
namespace MiraAPI.PluginLoading;
@@ -73,6 +74,8 @@ public class MiraPluginInfo
internal List<BaseModifier> Modifiers { get; } = [];
internal List<GameModifier> GameModifiers { get; } = [];
internal Dictionary<ushort, RoleBehaviour> CustomRoles { get; } = [];
internal Dictionary<int, CustomGameMode> GameModes { get; } = [];
+2 -2
View File
@@ -47,7 +47,7 @@ public interface ICustomRole : IOptionable
/// <summary>
/// Gets the role options group.
/// </summary>
public RoleOptionsGroup RoleOptionsGroup => Team switch
RoleOptionsGroup RoleOptionsGroup => Team switch
{
ModdedRoleTeams.Crewmate => RoleOptionsGroup.Crewmate,
ModdedRoleTeams.Impostor => RoleOptionsGroup.Impostor,
@@ -58,7 +58,7 @@ public interface ICustomRole : IOptionable
/// <summary>
/// Gets the role's TeamIntroCutscene configuration.
/// </summary>
public TeamIntroConfiguration? IntroConfiguration => Team switch
TeamIntroConfiguration? IntroConfiguration => Team switch
{
ModdedRoleTeams.Custom => TeamIntroConfiguration.Neutral,
_ => null,
+10
View File
@@ -39,6 +39,16 @@ public static class Extensions
BitConverter.GetBytes(count.Value).AddRangeToArray(BitConverter.GetBytes(chance.Value)));
}
/// <summary>
/// Determines if a float is an integer.
/// </summary>
/// <param name="number">The float number.</param>
/// <returns>True if the float is an integer, false otherwise.</returns>
public static bool IsInteger(this float number)
{
return Mathf.Approximately(number, Mathf.Round(number));
}
/// <summary>
/// Gets the best constructor for a type based on the specified arguments.
/// </summary>