Merge branch 'dev' into controller-support
No files matched your search
@@ -2,7 +2,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Reactor" Version="2.5.0-ci.371" />
|
<PackageReference Include="Reactor" Version="2.5.0-ci.371" />
|
||||||
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.735" Private="false" ExcludeAssets="runtime;native" />
|
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.735" Private="false" ExcludeAssets="runtime;native" />
|
||||||
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2026.8.18" PrivateAssets="all" />
|
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2026.9.29" PrivateAssets="all" />
|
||||||
|
|
||||||
<PackageReference Include="BepInEx.AutoPlugin" Version="1.1.0" PrivateAssets="all" />
|
<PackageReference Include="BepInEx.AutoPlugin" Version="1.1.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.1.0-rc.1" PrivateAssets="all" ExcludeAssets="runtime" />
|
<PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.1.0-rc.1" PrivateAssets="all" ExcludeAssets="runtime" />
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Il2CppSystem;
|
using MiraAPI.Example.Roles;
|
||||||
using MiraAPI.Example.Roles;
|
|
||||||
using MiraAPI.Modifiers.Types;
|
using MiraAPI.Modifiers.Types;
|
||||||
using MiraAPI.Translation;
|
using MiraAPI.Translation;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -28,7 +27,7 @@ public class FreezeModifier : TimedModifier
|
|||||||
|
|
||||||
if (Player.AmOwner || PlayerControl.LocalPlayer.Data.Role is FreezerRole)
|
if (Player.AmOwner || PlayerControl.LocalPlayer.Data.Role is FreezerRole)
|
||||||
{
|
{
|
||||||
Player.cosmetics.SetOutline(true, new Nullable<Color>(Palette.LightBlue));
|
Player.cosmetics.SetOutline(true, new Il2CppSystem.Nullable<Color>(Palette.LightBlue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public static class GameModeOption
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static readonly StringNames GamemodeName = MiraLocaleManager.GetOrCreateLocaleString("Gamemode");
|
internal static readonly StringNames GamemodeName = MiraLocaleManager.GetOrCreateLocaleString("MiraApi.Gamemode");
|
||||||
internal static readonly StringNames CustomName = MiraLocaleManager.GetOrCreateLocaleString("Custom");
|
internal static readonly StringNames CustomName = MiraLocaleManager.GetOrCreateLocaleString("Custom");
|
||||||
internal static readonly Dictionary<uint, StringNames> Values = new()
|
internal static readonly Dictionary<uint, StringNames> Values = new()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -121,4 +121,24 @@ public interface IModdedOption
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IModdedOptionList : IReadOnlyList<IModdedOption>
|
public interface IModdedOptionList : IReadOnlyList<IModdedOption>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the function to name the keys of the individual options in the configuration file.
|
||||||
|
/// <para/>
|
||||||
|
/// Return <see langword="null"/> to use the default of the property's name with its index appended.
|
||||||
|
/// </summary>
|
||||||
|
Func<int, string>? ConfigName { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for list of <typeparamref name="T"/> options.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of <see cref="IModdedOption"/>.</typeparam>
|
||||||
|
public interface IModdedOptionList<out T> : IModdedOptionList
|
||||||
|
where T : IModdedOption
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="IReadOnlyList{T}.this[int]"/>
|
||||||
|
new T this[int index] { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IEnumerable{T}.GetEnumerator"/>
|
||||||
|
new IEnumerator<T> GetEnumerator();
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MiraAPI.GameOptions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allows an option group to compress noisy option blocks in the wiki "Options" section.
|
||||||
|
/// Implementers can hide specific option keys and replace them with one or more summary lines.
|
||||||
|
/// </summary>
|
||||||
|
public interface ISummarizedOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the option string keys (StringNames) to omit from the wiki options list (e.g., a large set of related options).
|
||||||
|
/// </summary>
|
||||||
|
IReadOnlySet<StringNames> WikiHiddenOptionKeys { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets summary lines to insert when the first hidden option would have appeared.
|
||||||
|
/// Lines should already be formatted as "Title: Value".
|
||||||
|
/// </summary>
|
||||||
|
IEnumerable<string> GetWikiOptionSummaryLines();
|
||||||
|
}
|
||||||
@@ -198,9 +198,11 @@ public static class ModdedOptionsManager
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Func<int, string> configName = optionList.ConfigName ?? (i => property.Name + (i + 1));
|
||||||
|
|
||||||
for (int i = 0; i < optionList.Count; i++)
|
for (int i = 0; i < optionList.Count; i++)
|
||||||
{
|
{
|
||||||
RegisterOption(optionList[i], group, property.Name + i, pluginInfo);
|
RegisterOption(optionList[i], group, configName(i), pluginInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,7 +279,7 @@ public static class ModdedOptionsManager
|
|||||||
option.Visible = () => visibilityFunc(i);
|
option.Visible = () => visibilityFunc(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterOption(option, group, property.Name + i, pluginInfo);
|
RegisterOption(option, group, property.Name + (i + 1), pluginInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace MiraAPI.GameOptions.OptionTypes;
|
|||||||
/// Represents a modded option list.
|
/// Represents a modded option list.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of options.</typeparam>
|
/// <typeparam name="T">The type of options.</typeparam>
|
||||||
public class ModdedOptionList<T> : IModdedOptionList
|
public class ModdedOptionList<T> : IModdedOptionList<T>
|
||||||
where T : IModdedOption
|
where T : IModdedOption
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -20,6 +20,9 @@ public class ModdedOptionList<T> : IModdedOptionList
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IReadOnlyList<T> Options { get; }
|
public IReadOnlyList<T> Options { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public Func<int, string>? ConfigName { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ModdedOptionList{T}"/> class.
|
/// Initializes a new instance of the <see cref="ModdedOptionList{T}"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -41,10 +44,10 @@ public class ModdedOptionList<T> : IModdedOptionList
|
|||||||
Options = [.. options];
|
Options = [.. options];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc cref="IEnumerable{T}.GetEnumerator"/>
|
||||||
public IEnumerator<IModdedOption> GetEnumerator()
|
public IEnumerator<T> GetEnumerator()
|
||||||
{
|
{
|
||||||
return ((IEnumerable<IModdedOption>)Options).GetEnumerator();
|
return Options.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
@@ -52,6 +55,11 @@ public class ModdedOptionList<T> : IModdedOptionList
|
|||||||
return Options.GetEnumerator();
|
return Options.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IEnumerator<IModdedOption> IEnumerable<IModdedOption>.GetEnumerator()
|
||||||
|
{
|
||||||
|
return ((IEnumerable<IModdedOption>)Options).GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indexes the option of type <typeparamref name="T"/>.
|
/// Indexes the option of type <typeparamref name="T"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Il2CppSystem.Collections.Generic;
|
|
||||||
using MiraAPI.Networking;
|
using MiraAPI.Networking;
|
||||||
using MiraAPI.Translation;
|
using MiraAPI.Translation;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
@@ -43,7 +43,7 @@ public class ModdedPlayerOption : ModdedOption<int>
|
|||||||
data.Title = StringName;
|
data.Title = StringName;
|
||||||
data.Type = global::OptionTypes.Player;
|
data.Type = global::OptionTypes.Player;
|
||||||
|
|
||||||
Values = new List<NetworkedPlayerInfo>();
|
Values = new();
|
||||||
AllowNone = allowNone;
|
AllowNone = allowNone;
|
||||||
Value = DefaultValue;
|
Value = DefaultValue;
|
||||||
}
|
}
|
||||||
@@ -60,17 +60,16 @@ public class ModdedPlayerOption : ModdedOption<int>
|
|||||||
playerOption.name =
|
playerOption.name =
|
||||||
$"{ParentMod!.OptionsTitleText}.PlayerOption.{TranslationController.Instance.GetString(StringName)}";
|
$"{ParentMod!.OptionsTitleText}.PlayerOption.{TranslationController.Instance.GetString(StringName)}";
|
||||||
|
|
||||||
var filteredList = GetFilteredPlayers();
|
Values = GetFilteredPlayers();
|
||||||
Values = filteredList.ToIl2CppList();
|
|
||||||
|
|
||||||
playerOption.SetUpFromData(Data, 20);
|
playerOption.SetUpFromData(Data, 20);
|
||||||
playerOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
|
playerOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
|
||||||
|
|
||||||
playerOption.Title = StringName;
|
playerOption.Title = StringName;
|
||||||
playerOption.TitleText.text = Title.Translate();
|
playerOption.TitleText.text = Title.Translate();
|
||||||
playerOption.Values = Values;
|
playerOption.Values = Values.ToIl2CppList();
|
||||||
playerOption.Value = Value;
|
playerOption.Value = Value;
|
||||||
playerOption.playerIndex = filteredList.FindIndex(p => p.PlayerId == Value);
|
playerOption.playerIndex = Values.FindIndex(p => p.PlayerId == Value);
|
||||||
|
|
||||||
OptionBehaviour = playerOption;
|
OptionBehaviour = playerOption;
|
||||||
ModdedOptionsManager.CreatedPlayerOptions.TryAdd(playerOption, this);
|
ModdedOptionsManager.CreatedPlayerOptions.TryAdd(playerOption, this);
|
||||||
@@ -85,7 +84,7 @@ public class ModdedPlayerOption : ModdedOption<int>
|
|||||||
/// Returns a player ran through the filter.
|
/// Returns a player ran through the filter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A list of filtered players.</returns>
|
/// <returns>A list of filtered players.</returns>
|
||||||
public System.Collections.Generic.List<NetworkedPlayerInfo> GetFilteredPlayers()
|
public List<NetworkedPlayerInfo> GetFilteredPlayers()
|
||||||
{
|
{
|
||||||
return [.. GameData.Instance.AllPlayers.ToArray().Where(x => PlayerFilter?.Invoke(x) ?? true)];
|
return [.. GameData.Instance.AllPlayers.ToArray().Where(x => PlayerFilter?.Invoke(x) ?? true)];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using BepInEx;
|
|||||||
using BepInEx.Configuration;
|
using BepInEx.Configuration;
|
||||||
using BepInEx.Unity.IL2CPP;
|
using BepInEx.Unity.IL2CPP;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
|
using MiraAPI.Patches;
|
||||||
using MiraAPI.Patches.Roles;
|
using MiraAPI.Patches.Roles;
|
||||||
using MiraAPI.PluginLoading;
|
using MiraAPI.PluginLoading;
|
||||||
using MiraAPI.Translation;
|
using MiraAPI.Translation;
|
||||||
@@ -63,9 +64,30 @@ public partial class MiraApiPlugin : BasePlugin, IMiraPlugin
|
|||||||
private static MiraPluginManager? PluginManager { get; set; }
|
private static MiraPluginManager? PluginManager { get; set; }
|
||||||
internal Harmony Harmony { get; } = new(Id);
|
internal Harmony Harmony { get; } = new(Id);
|
||||||
|
|
||||||
|
public static ConfigEntry<SortingGroups> WikiSortingGroup { get; private set; }
|
||||||
|
|
||||||
|
public static ConfigEntry<SortingMethod> WikiSortingMethod { get; private set; }
|
||||||
|
|
||||||
|
public static ConfigEntry<SortingFilter> WikiSortingFilter { get; private set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Load()
|
public override void Load()
|
||||||
{
|
{
|
||||||
|
WikiSortingGroup = Config.Bind(
|
||||||
|
"Wiki",
|
||||||
|
"WikiSortingGroup",
|
||||||
|
SortingGroups.Ungrouped,
|
||||||
|
"Determines how clusters of roles / modifiers are grouped together, if at all.");
|
||||||
|
WikiSortingMethod = Config.Bind(
|
||||||
|
"Wiki",
|
||||||
|
"WikiSortingMethod",
|
||||||
|
SortingMethod.Alphabetical,
|
||||||
|
"Determines if the list of roles / modifiers are organized in ascending or descending order.");
|
||||||
|
WikiSortingFilter = Config.Bind(
|
||||||
|
"Wiki",
|
||||||
|
"WikiSortingFilter",
|
||||||
|
SortingFilter.AllRoles,
|
||||||
|
"Determines what roles / modifiers are displayed at once.");
|
||||||
Harmony.PatchAll();
|
Harmony.PatchAll();
|
||||||
RoleOptionsCollectionPatch.PatchRoleMethods(Harmony);
|
RoleOptionsCollectionPatch.PatchRoleMethods(Harmony);
|
||||||
UiResetEvents.Initialize();
|
UiResetEvents.Initialize();
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Il2CppInterop.Runtime.Attributes;
|
||||||
using MiraAPI.GameOptions;
|
using MiraAPI.GameOptions;
|
||||||
using MiraAPI.PluginLoading;
|
using MiraAPI.PluginLoading;
|
||||||
|
using MiraAPI.Roles;
|
||||||
|
using MiraAPI.Translation;
|
||||||
|
using MiraAPI.Utilities;
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
|
using TMPro;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Modifiers;
|
namespace MiraAPI.Modifiers;
|
||||||
@@ -44,16 +50,98 @@ public abstract class BaseModifier : IOptionable
|
|||||||
x => x.InternalModifiers.Exists(y => y.TypeId == TypeId))
|
x => x.InternalModifiers.Exists(y => y.TypeId == TypeId))
|
||||||
?? throw new InvalidOperationException("Modifier is not registered.");
|
?? throw new InvalidOperationException("Modifier is not registered.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the id part used to build the modifier's translation keys. It is recommended to simply call it what the modifier is, as other mods may utilize it.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string IdPart => GetType().Name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the id part used to build the modifier's translation keys. It is recommended to call it ModGuid.Modifier.Type.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string IdPrefix => GetType().Namespace!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the modifier name.
|
/// Gets the modifier name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract string ModifierName { get; }
|
public virtual string ModifierName => MiraLocaleManager.Get(ModifierNameLocale);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the modifier's name id for localization.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string ModifierNameLocale => MiraLocaleManager.BuildTranslationId(IdPrefix, IdPart);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the medium description of the modifier. Used in the modifier guide and options menu.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string ModifierMedDescription => MiraLocaleManager.Get(ModifierMedDescriptionLocale, GetDescription());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the modifier's medium description id for localization.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string ModifierMedDescriptionLocale => MiraLocaleManager.BuildTranslationId(IdPrefix, IdPart, "MedDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the wiki description of the modifier. Used in the wiki and normally appends the options text as well.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string ModifierWikiDescription => MiraLocaleManager.Get(ModifierWikiDescriptionLocale, GetDescription()) +
|
||||||
|
Helpers.GetOptionsText(GetType());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the modifier's wiki description id for localization.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string ModifierWikiDescriptionLocale => MiraLocaleManager.BuildTranslationId(IdPrefix, IdPart, "WikiDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the category of the modifier. Used in the wiki.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string ModifierCategoryTitle => MiraLocaleManager.Get("Modifier");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets whether the modifier is forcibly shown or disabled in the wiki screen.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns><see langword="true"/> if the modifier is always displayed, otherwise <see langword="false"/> if it is never displayable, or <see langword="null"/> if it is dictated by amount and chance.</returns>
|
||||||
|
public virtual bool? ForceShowModifierOnWiki => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the information to display in the wiki.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="guide">The guide object.</param>
|
||||||
|
/// <param name="titleText">The title text object.</param>
|
||||||
|
/// <param name="titleIcon">The title's icon.</param>
|
||||||
|
/// <param name="parent">The scroller parent.</param>
|
||||||
|
/// <returns>The <see cref="GameObject"/> of the wiki.</returns>
|
||||||
|
public virtual GameObject GetAdvancedWiki(MatchInfoGuide guide, TextMeshPro titleText, SpriteRenderer titleIcon, Scroller parent)
|
||||||
|
{
|
||||||
|
var abilities = WikiAbilities;
|
||||||
|
return Helpers.CreateAdvancedWikiPage(
|
||||||
|
guide,
|
||||||
|
titleText,
|
||||||
|
titleIcon,
|
||||||
|
parent,
|
||||||
|
ModifierNameLocale,
|
||||||
|
$"{ModifierName} ({ModifierCategoryTitle})".TrimStart(),
|
||||||
|
ModifierIcon ?? MiraAssets.IconNeutral.LoadAsset(),
|
||||||
|
ModifierWikiDescription,
|
||||||
|
abilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of abilities or other similar information to display below the text of a modifier's wiki page.
|
||||||
|
/// </summary>
|
||||||
|
[HideFromIl2Cpp]
|
||||||
|
public virtual List<AdvancedWikiAbilityDescription> WikiAbilities => [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the modifier icon. Useless if <see cref="HideOnUi"/> is <see langword="true"/>.
|
/// Gets the modifier icon. Useless if <see cref="HideOnUi"/> is <see langword="true"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual LoadableAsset<Sprite>? ModifierIcon => null;
|
public virtual LoadableAsset<Sprite>? ModifierIcon => null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="TMP_SpriteAsset"/> for the Modifier Icon.
|
||||||
|
/// </summary>
|
||||||
|
[HideFromIl2Cpp]
|
||||||
|
public virtual TMP_SpriteAsset IconTmp => null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the modifier is hidden on the UI. Will be hidden either way if no description is provided.
|
/// Gets a value indicating whether the modifier is hidden on the UI. Will be hidden either way if no description is provided.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -69,6 +157,11 @@ public abstract class BaseModifier : IOptionable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Color FreeplayFileColor => Color.gray;
|
public virtual Color FreeplayFileColor => Color.gray;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Color"/> of the modifier, used in the wiki and other UI outside freeplay.
|
||||||
|
/// </summary>
|
||||||
|
public virtual Color GeneralColor => FreeplayFileColor;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the modifier is unique. If <see langword="true"/>, the player can only have one instance of this modifier.
|
/// Gets a value indicating whether the modifier is unique. If <see langword="true"/>, the player can only have one instance of this modifier.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ namespace MiraAPI.Modifiers.Types;
|
|||||||
[MiraIgnore]
|
[MiraIgnore]
|
||||||
public abstract class GameModifier : BaseModifier
|
public abstract class GameModifier : BaseModifier
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool? ForceShowModifierOnWiki => null;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool ShowInFreeplay => true;
|
public override bool ShowInFreeplay => true;
|
||||||
|
|
||||||
|
|||||||
@@ -23,10 +23,18 @@ public static class VanillaButtonPatches
|
|||||||
{
|
{
|
||||||
playerTarget = role.Cast<TrackerRole>().currentTarget;
|
playerTarget = role.Cast<TrackerRole>().currentTarget;
|
||||||
}
|
}
|
||||||
|
else if (role.Role is RoleTypes.Detective)
|
||||||
|
{
|
||||||
|
playerTarget = role.Cast<DetectiveRole>().currentTarget;
|
||||||
|
}
|
||||||
else if (role.Role is RoleTypes.GuardianAngel)
|
else if (role.Role is RoleTypes.GuardianAngel)
|
||||||
{
|
{
|
||||||
playerTarget = role.Cast<GuardianAngelRole>().currentTarget;
|
playerTarget = role.Cast<GuardianAngelRole>().currentTarget;
|
||||||
}
|
}
|
||||||
|
else if (role.Role is RoleTypes.SpiritGuide)
|
||||||
|
{
|
||||||
|
playerTarget = role.Cast<SpiritGuideRole>().currentTarget;
|
||||||
|
}
|
||||||
else if (role.Role is RoleTypes.Engineer)
|
else if (role.Role is RoleTypes.Engineer)
|
||||||
{
|
{
|
||||||
ventTarget = role.Cast<EngineerRole>().currentTarget;
|
ventTarget = role.Cast<EngineerRole>().currentTarget;
|
||||||
@@ -53,6 +61,10 @@ public static class VanillaButtonPatches
|
|||||||
{
|
{
|
||||||
playerTarget = role.Cast<DetectiveRole>().currentTarget;
|
playerTarget = role.Cast<DetectiveRole>().currentTarget;
|
||||||
}
|
}
|
||||||
|
else if (role.Role is RoleTypes.SpiritGuide)
|
||||||
|
{
|
||||||
|
playerTarget = role.Cast<SpiritGuideRole>().currentTarget;
|
||||||
|
}
|
||||||
|
|
||||||
var genericEvent = new VanillaButtonClickEvent(__instance, playerTarget);
|
var genericEvent = new VanillaButtonClickEvent(__instance, playerTarget);
|
||||||
MiraEventManager.InvokeEvent(genericEvent);
|
MiraEventManager.InvokeEvent(genericEvent);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Il2CppSystem;
|
|
||||||
using MiraAPI.GameModes;
|
using MiraAPI.GameModes;
|
||||||
using MiraAPI.Translation;
|
using MiraAPI.Translation;
|
||||||
using Reactor.Utilities;
|
using Reactor.Utilities;
|
||||||
@@ -16,7 +15,7 @@ internal static class HudPatches
|
|||||||
[HarmonyPostfix, HarmonyPatch(nameof(HudManager.Update))]
|
[HarmonyPostfix, HarmonyPatch(nameof(HudManager.Update))]
|
||||||
public static void HudUpdatePatch(HudManager __instance)
|
public static void HudUpdatePatch(HudManager __instance)
|
||||||
{
|
{
|
||||||
if (GameManager.Instance != null && GameManager.Instance.GameHasStarted &&
|
if (GameManager.Instance && GameManager.Instance.GameHasStarted &&
|
||||||
CustomGameModeManager.ActiveMode != null)
|
CustomGameModeManager.ActiveMode != null)
|
||||||
{
|
{
|
||||||
CustomGameModeManager.ActiveMode.HudUpdate(__instance);
|
CustomGameModeManager.ActiveMode.HudUpdate(__instance);
|
||||||
@@ -32,7 +31,7 @@ internal static class HudPatches
|
|||||||
|
|
||||||
private static IEnumerator CoPostHudStart(HudManager instance)
|
private static IEnumerator CoPostHudStart(HudManager instance)
|
||||||
{
|
{
|
||||||
yield return new WaitUntil((Func<bool>)(() => GameManager.Instance != null));
|
yield return new WaitUntil((Il2CppSystem.Func<bool>)(() => GameManager.Instance != null));
|
||||||
if (GameManager.Instance.IsHideAndSeek())
|
if (GameManager.Instance.IsHideAndSeek())
|
||||||
yield return null;
|
yield return null;
|
||||||
var infoPane = instance.gameObject.transform.FindChild("LobbyInfoPane");
|
var infoPane = instance.gameObject.transform.FindChild("LobbyInfoPane");
|
||||||
@@ -42,7 +41,7 @@ internal static class HudPatches
|
|||||||
var modelText = modeLabel!.Find("Text_TMP").gameObject;
|
var modelText = modeLabel!.Find("Text_TMP").gameObject;
|
||||||
var modelTextClone = Object.Instantiate(modelText, modeLabel);
|
var modelTextClone = Object.Instantiate(modelText, modeLabel);
|
||||||
Object.Destroy(modelTextClone.GetComponent<TextTranslatorTMP>());
|
Object.Destroy(modelTextClone.GetComponent<TextTranslatorTMP>());
|
||||||
modelTextClone.GetComponent<TextMeshPro>().text = "Gamemode";
|
modelTextClone.GetComponent<TextMeshPro>().text = MiraLocaleManager.Get("MiraApi.Gamemode", "Gamemode");
|
||||||
var gmText = modeValue!.Find("GameModeText").gameObject;
|
var gmText = modeValue!.Find("GameModeText").gameObject;
|
||||||
var gmTextClone = Object.Instantiate(gmText, modeValue);
|
var gmTextClone = Object.Instantiate(gmText, modeValue);
|
||||||
gmText.SetActive(false);
|
gmText.SetActive(false);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using BepInEx.Unity.IL2CPP.Utils.Collections;
|
using BepInEx.Unity.IL2CPP.Utils.Collections;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||||
using Il2CppSystem.Collections.Generic;
|
|
||||||
using MiraAPI.GameModes;
|
using MiraAPI.GameModes;
|
||||||
using MiraAPI.GameOptions;
|
using MiraAPI.GameOptions;
|
||||||
using MiraAPI.Modifiers;
|
using MiraAPI.Modifiers;
|
||||||
@@ -28,9 +28,9 @@ internal static class GameOptionsMenuPatch
|
|||||||
private static readonly List<CategoryHeaderMasked> VanillaHeaders = new();
|
private static readonly List<CategoryHeaderMasked> VanillaHeaders = new();
|
||||||
private static readonly List<OptionBehaviour> VanillaOptions = new();
|
private static readonly List<OptionBehaviour> VanillaOptions = new();
|
||||||
private static readonly List<OptionBehaviour> MainOptions = new();
|
private static readonly List<OptionBehaviour> MainOptions = new();
|
||||||
private static readonly System.Collections.Generic.Dictionary<AbstractGameMode, System.Collections.Generic.List<AbstractOptionGroup>> GameModeGroups = [];
|
private static readonly Dictionary<AbstractGameMode, List<AbstractOptionGroup>> GameModeGroups = [];
|
||||||
private static readonly System.Collections.Generic.Dictionary<AbstractGameMode, System.Collections.Generic.List<OptionBehaviour>> GameModeOptions = [];
|
private static readonly Dictionary<AbstractGameMode, List<OptionBehaviour>> GameModeOptions = [];
|
||||||
private static readonly System.Collections.Generic.Dictionary<AbstractGameMode, System.Collections.Generic.List<CategoryHeaderMasked>> GameModeHeaders = [];
|
private static readonly Dictionary<AbstractGameMode, List<CategoryHeaderMasked>> GameModeHeaders = [];
|
||||||
private static TextMeshPro _gamemodeDescription = null!;
|
private static TextMeshPro _gamemodeDescription = null!;
|
||||||
private static SpriteRenderer _modIcon = null!;
|
private static SpriteRenderer _modIcon = null!;
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ internal static class GameOptionsMenuPatch
|
|||||||
[HarmonyPatch(nameof(GameOptionsMenu.Initialize))]
|
[HarmonyPatch(nameof(GameOptionsMenu.Initialize))]
|
||||||
public static bool InitPatch(GameOptionsMenu __instance)
|
public static bool InitPatch(GameOptionsMenu __instance)
|
||||||
{
|
{
|
||||||
__instance.Children ??= new List<OptionBehaviour>();
|
__instance.Children ??= new();
|
||||||
__instance.Children.Clear();
|
__instance.Children.Clear();
|
||||||
|
|
||||||
if (MenuState.Instance.CurrentModIdx == 0)
|
if (MenuState.Instance.CurrentModIdx == 0)
|
||||||
@@ -324,8 +324,8 @@ internal static class GameOptionsMenuPatch
|
|||||||
.ToList();
|
.ToList();
|
||||||
GameModeGroups.Add(mode, [.. filteredGroups]);
|
GameModeGroups.Add(mode, [.. filteredGroups]);
|
||||||
|
|
||||||
var optionBehaviours = new System.Collections.Generic.List<OptionBehaviour>();
|
var optionBehaviours = new List<OptionBehaviour>();
|
||||||
var categoryHeaders = new System.Collections.Generic.List<CategoryHeaderMasked>();
|
var categoryHeaders = new List<CategoryHeaderMasked>();
|
||||||
var newNum = mode.ShowNormalGameSettings ? num : num - additionalVanillaScrollNum;
|
var newNum = mode.ShowNormalGameSettings ? num : num - additionalVanillaScrollNum;
|
||||||
foreach (var group in filteredGroups)
|
foreach (var group in filteredGroups)
|
||||||
{
|
{
|
||||||
@@ -406,7 +406,7 @@ internal static class GameOptionsMenuPatch
|
|||||||
__instance.scrollBar.SetYBoundsMax(-num - 1.65f);
|
__instance.scrollBar.SetYBoundsMax(-num - 1.65f);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CreateGroup(GameOptionsMenu menu, AbstractOptionGroup group, Transform container, ref float num, ref System.Collections.Generic.List<OptionBehaviour> optionBehaviours, ref System.Collections.Generic.List<CategoryHeaderMasked> categoryHeaders)
|
private static void CreateGroup(GameOptionsMenu menu, AbstractOptionGroup group, Transform container, ref float num, ref List<OptionBehaviour> optionBehaviours, ref List<CategoryHeaderMasked> categoryHeaders)
|
||||||
{
|
{
|
||||||
var categoryHeaderMasked = Object.Instantiate(
|
var categoryHeaderMasked = Object.Instantiate(
|
||||||
menu.categoryHeaderOrigin,
|
menu.categoryHeaderOrigin,
|
||||||
@@ -618,6 +618,8 @@ internal static class GameOptionsMenuPatch
|
|||||||
{
|
{
|
||||||
menu.MapPicker.gameObject.SetActive(false);
|
menu.MapPicker.gameObject.SetActive(false);
|
||||||
var mod = MenuState.Instance.CurrentMod;
|
var mod = MenuState.Instance.CurrentMod;
|
||||||
|
var container = MenuState.Instance.CurrentContainer.transform;
|
||||||
|
PresetManager.DefaultPresets.TryGetValue(mod, out var defaultPreset);
|
||||||
|
|
||||||
var filteredGroups = MenuState.Instance.CurrentMenu switch
|
var filteredGroups = MenuState.Instance.CurrentMenu switch
|
||||||
{
|
{
|
||||||
@@ -643,15 +645,13 @@ internal static class GameOptionsMenuPatch
|
|||||||
{
|
{
|
||||||
foreach (var group in filteredGroups)
|
foreach (var group in filteredGroups)
|
||||||
{
|
{
|
||||||
yield return CoCreateGroup(menu, group);
|
yield return CoCreateGroup(menu, group, container, defaultPreset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerator CoCreateGroup(GameOptionsMenu menu, AbstractOptionGroup group)
|
private static IEnumerator CoCreateGroup(GameOptionsMenu menu, AbstractOptionGroup group, Transform container, OptionPreset? defaultPreset)
|
||||||
{
|
{
|
||||||
var container = MenuState.Instance.CurrentContainer.transform;
|
|
||||||
|
|
||||||
group.Ready = false;
|
group.Ready = false;
|
||||||
if (group.Header == null || !group.Header)
|
if (group.Header == null || !group.Header)
|
||||||
{
|
{
|
||||||
@@ -713,12 +713,6 @@ internal static class GameOptionsMenuPatch
|
|||||||
menu.playerOptionOrigin,
|
menu.playerOptionOrigin,
|
||||||
container));
|
container));
|
||||||
|
|
||||||
OptionPreset? defaultPreset = null;
|
|
||||||
if (PresetManager.DefaultPresets.TryGetValue(MenuState.Instance.CurrentMod, out var preset))
|
|
||||||
{
|
|
||||||
defaultPreset = preset;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return options.CoLoopWithBudget(newOpt =>
|
yield return options.CoLoopWithBudget(newOpt =>
|
||||||
{
|
{
|
||||||
newOpt.SetClickMask(menu.ButtonClickMask);
|
newOpt.SetClickMask(menu.ButtonClickMask);
|
||||||
@@ -765,73 +759,53 @@ internal static class GameOptionsMenuPatch
|
|||||||
}
|
}
|
||||||
|
|
||||||
menu.Children.Add(newOpt);
|
menu.Children.Add(newOpt);
|
||||||
var resetBtn = new GameObject("ResetOption")
|
if (defaultPreset != null && defaultPreset.IsOptionInPreset(newOpt) &&
|
||||||
|
newOpt is ToggleOption or NumberOption or StringOption)
|
||||||
{
|
{
|
||||||
transform =
|
var resetBtn = new GameObject("ResetOption")
|
||||||
{
|
{
|
||||||
parent = newOpt.transform,
|
transform =
|
||||||
localScale = new(.5f, .5f, 1),
|
{
|
||||||
localPosition = new Vector3(-3.1f, 0f, -2f),
|
parent = newOpt.transform,
|
||||||
},
|
localScale = new(.5f, .5f, 1),
|
||||||
layer = LayerMask.NameToLayer("UI"),
|
localPosition = new Vector3(-3.1f, 0f, -2f),
|
||||||
};
|
},
|
||||||
var resetRend = resetBtn.AddComponent<SpriteRenderer>();
|
layer = LayerMask.NameToLayer("UI"),
|
||||||
resetRend.sprite = MiraAssets.ResetButton.LoadAsset();
|
};
|
||||||
resetRend.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
|
var resetRend = resetBtn.AddComponent<SpriteRenderer>();
|
||||||
resetRend.color = group.GroupColor.Equals(MiraApiPlugin.DefaultHeaderColor)
|
resetRend.sprite = MiraAssets.ResetButton.LoadAsset();
|
||||||
? Color.white
|
resetRend.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
|
||||||
: group.GroupColor.FindAlternateColor();
|
resetRend.color = group.GroupColor.Equals(MiraApiPlugin.DefaultHeaderColor)
|
||||||
var resetBoxCol = resetBtn.gameObject.AddComponent<BoxCollider2D>();
|
? Color.white
|
||||||
resetBoxCol.size = new Vector2(1f, 1f);
|
: group.GroupColor.FindAlternateColor();
|
||||||
resetBoxCol.offset = new Vector2(0, 0);
|
var resetBoxCol = resetBtn.gameObject.AddComponent<BoxCollider2D>();
|
||||||
var passiveButton = resetBtn.AddComponent<PassiveButton>();
|
resetBoxCol.size = new Vector2(1f, 1f);
|
||||||
passiveButton.OnClick = new Button.ButtonClickedEvent();
|
resetBoxCol.offset = new Vector2(0, 0);
|
||||||
passiveButton.ClickSound = menu.BackButton.GetComponent<PassiveButton>().ClickSound;
|
var passiveButton = resetBtn.AddComponent<PassiveButton>();
|
||||||
passiveButton.OnMouseOver = new UnityEvent();
|
passiveButton.OnClick = new Button.ButtonClickedEvent();
|
||||||
passiveButton.OnMouseOver.AddListener(
|
passiveButton.ClickSound = menu.BackButton.GetComponent<PassiveButton>().ClickSound;
|
||||||
(UnityAction)(() =>
|
passiveButton.OnMouseOver = new UnityEvent();
|
||||||
{
|
passiveButton.OnMouseOver.AddListener(
|
||||||
resetRend.color = group.GroupColor != MiraApiPlugin.DefaultHeaderColor
|
(UnityAction)(() =>
|
||||||
? group.GroupColor
|
{
|
||||||
: MiraAssets.AcceptedTeal;
|
resetRend.color = group.GroupColor != MiraApiPlugin.DefaultHeaderColor
|
||||||
}));
|
? group.GroupColor
|
||||||
passiveButton.OnMouseOut = new UnityEvent();
|
: MiraAssets.AcceptedTeal;
|
||||||
passiveButton.OnMouseOut.AddListener(
|
}));
|
||||||
(UnityAction)(() =>
|
passiveButton.OnMouseOut = new UnityEvent();
|
||||||
{
|
passiveButton.OnMouseOut.AddListener(
|
||||||
resetRend.color = group.GroupColor.Equals(MiraApiPlugin.DefaultHeaderColor)
|
(UnityAction)(() =>
|
||||||
? Color.white
|
{
|
||||||
: group.GroupColor.FindAlternateColor();
|
resetRend.color = group.GroupColor.Equals(MiraApiPlugin.DefaultHeaderColor)
|
||||||
}));
|
? Color.white
|
||||||
if (newOpt is ToggleOption toggleOpt)
|
: group.GroupColor.FindAlternateColor();
|
||||||
{
|
}));
|
||||||
passiveButton.OnClick.AddListener(
|
passiveButton.OnClick.AddListener(
|
||||||
(UnityAction)(() =>
|
(UnityAction)(() =>
|
||||||
{
|
{
|
||||||
defaultPreset!.ResetOption(toggleOpt);
|
defaultPreset.ResetOption(newOpt);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
else if (newOpt is NumberOption numOpt)
|
|
||||||
{
|
|
||||||
passiveButton.OnClick.AddListener(
|
|
||||||
(UnityAction)(() =>
|
|
||||||
{
|
|
||||||
defaultPreset!.ResetOption(numOpt);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
else if (newOpt is StringOption strOpt)
|
|
||||||
{
|
|
||||||
passiveButton.OnClick.AddListener(
|
|
||||||
(UnityAction)(() =>
|
|
||||||
{
|
|
||||||
defaultPreset!.ResetOption(strOpt);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!defaultPreset!.IsOptionInPreset(newOpt))
|
|
||||||
{
|
|
||||||
resetBtn.Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
newOpt.Initialize();
|
newOpt.Initialize();
|
||||||
newOpt.gameObject.SetActive(false);
|
newOpt.gameObject.SetActive(false);
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Il2CppSystem;
|
|
||||||
using MiraAPI.GameOptions;
|
using MiraAPI.GameOptions;
|
||||||
using MiraAPI.Roles;
|
using MiraAPI.Roles;
|
||||||
using MiraAPI.Translation;
|
using MiraAPI.Translation;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Object = Il2CppSystem.Object;
|
|
||||||
|
|
||||||
namespace MiraAPI.Patches.Options;
|
namespace MiraAPI.Patches.Options;
|
||||||
|
|
||||||
@@ -165,7 +163,7 @@ public static class OptionsPatches
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
__instance.TitleText.text = TranslationController.Instance.GetString(__instance.Title, Array.Empty<Object>()).Translate();
|
__instance.TitleText.text = TranslationController.Instance.GetString(__instance.Title).Translate();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -314,8 +312,8 @@ public static class OptionsPatches
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
__instance.TitleText.text = TranslationController.Instance.GetString(__instance.Title, Array.Empty<Object>()).Translate();
|
__instance.TitleText.text = TranslationController.Instance.GetString(__instance.Title).Translate();
|
||||||
__instance.ValueText.text = TranslationController.Instance.GetString(__instance.Values[__instance.Value], Array.Empty<Object>());
|
__instance.ValueText.text = TranslationController.Instance.GetString(__instance.Values[__instance.Value]);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ public static class PlayerOptionPatches
|
|||||||
{
|
{
|
||||||
filteredPlayers.Sort((a, b) => a.PlayerId.CompareTo(b.PlayerId));
|
filteredPlayers.Sort((a, b) => a.PlayerId.CompareTo(b.PlayerId));
|
||||||
|
|
||||||
|
moddedPlrOpt.Values = filteredPlayers;
|
||||||
__instance.Values = filteredPlayers.ToIl2CppList();
|
__instance.Values = filteredPlayers.ToIl2CppList();
|
||||||
moddedPlrOpt.Values = __instance.Values;
|
|
||||||
__instance.playerIndex = filteredPlayers.FindIndex(p => p.PlayerId == __instance.Value);
|
__instance.playerIndex = filteredPlayers.FindIndex(p => p.PlayerId == __instance.Value);
|
||||||
__instance.SetValueText();
|
__instance.SetValueText();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Il2CppSystem;
|
|
||||||
using MiraAPI.Networking;
|
using MiraAPI.Networking;
|
||||||
using MiraAPI.Roles;
|
using MiraAPI.Roles;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -31,13 +30,13 @@ public static class KillButtonPatches
|
|||||||
|
|
||||||
if (__instance.currentTarget && __instance.currentTarget != target)
|
if (__instance.currentTarget && __instance.currentTarget != target)
|
||||||
{
|
{
|
||||||
__instance.currentTarget.cosmetics.SetOutline(false, new Nullable<Color>(Color.clear));
|
__instance.currentTarget.cosmetics.SetOutline(false, new Il2CppSystem.Nullable<Color>(Color.clear));
|
||||||
}
|
}
|
||||||
|
|
||||||
__instance.currentTarget = target;
|
__instance.currentTarget = target;
|
||||||
if (__instance.currentTarget)
|
if (__instance.currentTarget)
|
||||||
{
|
{
|
||||||
__instance.currentTarget.cosmetics.SetOutline(true, new Nullable<Color>(customRole.Configuration.KillButtonOutlineColor));
|
__instance.currentTarget.cosmetics.SetOutline(true, new Il2CppSystem.Nullable<Color>(customRole.Configuration.KillButtonOutlineColor));
|
||||||
__instance.SetEnabled();
|
__instance.SetEnabled();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AmongUs.GameOptions;
|
using AmongUs.GameOptions;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Il2CppSystem.Collections.Generic;
|
|
||||||
using MiraAPI.Roles;
|
using MiraAPI.Roles;
|
||||||
|
|
||||||
namespace MiraAPI.Patches.Roles;
|
namespace MiraAPI.Patches.Roles;
|
||||||
@@ -14,7 +14,7 @@ public static class LogicRoleSelectionHnsPatch
|
|||||||
[HarmonyPatch(nameof(LogicRoleSelectionHnS.AssignRolesForTeam))]
|
[HarmonyPatch(nameof(LogicRoleSelectionHnS.AssignRolesForTeam))]
|
||||||
public static bool AssignRolesForTeam(
|
public static bool AssignRolesForTeam(
|
||||||
LogicRoleSelectionHnS __instance,
|
LogicRoleSelectionHnS __instance,
|
||||||
List<NetworkedPlayerInfo> players,
|
Il2CppSystem.Collections.Generic.List<NetworkedPlayerInfo> players,
|
||||||
IGameOptions opts,
|
IGameOptions opts,
|
||||||
RoleTeamTypes team,
|
RoleTeamTypes team,
|
||||||
int teamMax,
|
int teamMax,
|
||||||
@@ -58,7 +58,7 @@ public static class LogicRoleSelectionHnsPatch
|
|||||||
|
|
||||||
case RoleTeamTypes.Impostor:
|
case RoleTeamTypes.Impostor:
|
||||||
Info($"MiraAPI.Patches.Roles.LogicRoleSelectionHnsPatch - AssignRolesForTeam: Before Guaranteed Assignment");
|
Info($"MiraAPI.Patches.Roles.LogicRoleSelectionHnsPatch - AssignRolesForTeam: Before Guaranteed Assignment");
|
||||||
var newImpostors = new List<NetworkedPlayerInfo>();
|
var newImpostors = new Il2CppSystem.Collections.Generic.List<NetworkedPlayerInfo>();
|
||||||
|
|
||||||
// Specified Seeker
|
// Specified Seeker
|
||||||
if (__instance.hnsManager.LogicOptionsHnS.HasImpostorPlayerID() &&
|
if (__instance.hnsManager.LogicOptionsHnS.HasImpostorPlayerID() &&
|
||||||
@@ -113,7 +113,7 @@ public static class LogicRoleSelectionHnsPatch
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AssignRolesFromList(List<NetworkedPlayerInfo> players, int teamMax, List<RoleTypes> roleList, ref int rolesAssigned)
|
public static void AssignRolesFromList(Il2CppSystem.Collections.Generic.List<NetworkedPlayerInfo> players, int teamMax, List<RoleTypes> roleList, ref int rolesAssigned)
|
||||||
{
|
{
|
||||||
while (roleList.Count > 0 && players.Count > 0 && rolesAssigned < teamMax)
|
while (roleList.Count > 0 && players.Count > 0 && rolesAssigned < teamMax)
|
||||||
{
|
{
|
||||||
@@ -128,7 +128,7 @@ public static class LogicRoleSelectionHnsPatch
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void AddGuaranteedRoles(
|
private static void AddGuaranteedRoles(
|
||||||
System.Collections.Generic.IEnumerable<RoleBehaviour> guaranteedRoles,
|
IEnumerable<RoleBehaviour> guaranteedRoles,
|
||||||
IGameOptions opts,
|
IGameOptions opts,
|
||||||
List<RoleTypes> list)
|
List<RoleTypes> list)
|
||||||
{
|
{
|
||||||
@@ -146,7 +146,7 @@ public static class LogicRoleSelectionHnsPatch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddPotentialRoles(System.Collections.Generic.IEnumerable<RoleBehaviour> source, IGameOptions opts, List<RoleTypes> list)
|
private static void AddPotentialRoles(IEnumerable<RoleBehaviour> source, IGameOptions opts, List<RoleTypes> list)
|
||||||
{
|
{
|
||||||
var roleOptions = opts.RoleOptions;
|
var roleOptions = opts.RoleOptions;
|
||||||
var potentialRoles = source.Where(x => !x.IsDead).Select(role => new RoleManager.RoleAssignmentData(
|
var potentialRoles = source.Where(x => !x.IsDead).Select(role => new RoleManager.RoleAssignmentData(
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Hazel;
|
using Hazel;
|
||||||
using Il2CppSystem.Text;
|
|
||||||
|
|
||||||
namespace MiraAPI.Patches.Stubs;
|
namespace MiraAPI.Patches.Stubs;
|
||||||
|
|
||||||
@@ -45,9 +44,9 @@ public static class RoleBehaviourStubs
|
|||||||
/// <param name="instance">The <see cref="RoleBehaviour"/> object.</param>
|
/// <param name="instance">The <see cref="RoleBehaviour"/> object.</param>
|
||||||
/// <param name="taskStringBuilder">The <see cref="StringBuilder"/> to append the task hint to.</param>
|
/// <param name="taskStringBuilder">The <see cref="StringBuilder"/> to append the task hint to.</param>
|
||||||
[HarmonyReversePatch]
|
[HarmonyReversePatch]
|
||||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.AppendTaskHint), typeof(StringBuilder))]
|
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.AppendTaskHint), typeof(Il2CppSystem.Text.StringBuilder))]
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public static void AppendTaskHint(RoleBehaviour instance, StringBuilder taskStringBuilder)
|
public static void AppendTaskHint(RoleBehaviour instance, Il2CppSystem.Text.StringBuilder taskStringBuilder)
|
||||||
{
|
{
|
||||||
// nothing needed
|
// nothing needed
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,12 @@ public class OptionPreset(string name, MiraPluginInfo plugin, ConfigFile presetC
|
|||||||
/// <param name="baseOption">The option to reset.</param>
|
/// <param name="baseOption">The option to reset.</param>
|
||||||
public void ResetOption(OptionBehaviour baseOption)
|
public void ResetOption(OptionBehaviour baseOption)
|
||||||
{
|
{
|
||||||
var selectedOpt = Plugin.InternalOptions.First(x => x.OptionBehaviour == baseOption);
|
var selectedOpt = Plugin.InternalOptions.FirstOrDefault(x => x.OptionBehaviour == baseOption);
|
||||||
|
if (selectedOpt == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
selectedOpt.LoadFromPreset(PresetConfig);
|
selectedOpt.LoadFromPreset(PresetConfig);
|
||||||
/*ModdedOptionsManager.SyncAllOptions();
|
/*ModdedOptionsManager.SyncAllOptions();
|
||||||
|
|
||||||
@@ -84,7 +89,7 @@ public class OptionPreset(string name, MiraPluginInfo plugin, ConfigFile presetC
|
|||||||
/// <returns>The value of whether the option is in the preset.</returns>
|
/// <returns>The value of whether the option is in the preset.</returns>
|
||||||
public bool IsOptionInPreset(OptionBehaviour baseOption)
|
public bool IsOptionInPreset(OptionBehaviour baseOption)
|
||||||
{
|
{
|
||||||
var selectedOpt = Plugin.InternalOptions.First(x => x.OptionBehaviour == baseOption);
|
var selectedOpt = Plugin.InternalOptions.FirstOrDefault(x => x.OptionBehaviour == baseOption);
|
||||||
return selectedOpt.ConfigDefinition != null && PresetConfig.ContainsKey(selectedOpt.ConfigDefinition);
|
return selectedOpt != null && selectedOpt.ConfigDefinition != null && PresetConfig.ContainsKey(selectedOpt.ConfigDefinition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,10 @@ using UnityEngine;
|
|||||||
using UnityEngine.Events;
|
using UnityEngine.Events;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
// TODO: for the love of fucking god please add a namespace on the asset bundle AND here - Atony.
|
||||||
|
/*
|
||||||
namespace MiraAPI.Presets;
|
namespace MiraAPI.Presets;
|
||||||
|
*/
|
||||||
|
|
||||||
[RegisterInIl2Cpp]
|
[RegisterInIl2Cpp]
|
||||||
[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity convention.")]
|
[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity convention.")]
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
<string name="MiraApi.CustomCategory2">Custom Category 2</string>
|
<string name="MiraApi.CustomCategory2">Custom Category 2</string>
|
||||||
<string name="MiraApi.ModifierMenuDescription">Configure modifiers and their settings here!</string>
|
<string name="MiraApi.ModifierMenuDescription">Configure modifiers and their settings here!</string>
|
||||||
<string name="MiraApi.CustomOptionMenuDescription">Apply game settings for this mod!</string>
|
<string name="MiraApi.CustomOptionMenuDescription">Apply game settings for this mod!</string>
|
||||||
|
<string name="MiraApi.Gamemode">Gamemode</string>
|
||||||
<string name="MiraApi.Gamemode.Classic">Classic</string>
|
<string name="MiraApi.Gamemode.Classic">Classic</string>
|
||||||
<string name="MiraApi.Gamemode.Classic.Description">The classic Among Us experience!
|
<string name="MiraApi.Gamemode.Classic.Description">The classic Among Us experience!
|
||||||
Find the Impostors or deceive the Crew.</string>
|
Find the Impostors or deceive the Crew.</string>
|
||||||
@@ -43,4 +44,19 @@ Outlive the timer or eliminate the crew.</string>
|
|||||||
<string name="MiraApi.ModifierDisplay.Page">Page</string>
|
<string name="MiraApi.ModifierDisplay.Page">Page</string>
|
||||||
<string name="MiraApi.Page">Page</string>
|
<string name="MiraApi.Page">Page</string>
|
||||||
<string name="MiraApi.Main">Main</string>
|
<string name="MiraApi.Main">Main</string>
|
||||||
|
<string name="MiraApi.AbilityType.Basic">Ability</string>
|
||||||
|
<string name="MiraApi.AbilityType.Indirect">Indirect Ability</string>
|
||||||
|
<string name="MiraApi.AbilityType.Interaction">Interaction Ability</string>
|
||||||
|
<string name="MiraApi.AbilityType.Radius">Radius Ability</string>
|
||||||
|
<string name="MiraApi.AbilityType.Menu">Menu Ability</string>
|
||||||
|
<string name="MiraApi.AbilityType.Meeting">Meeting Ability</string>
|
||||||
|
<string name="MiraApi.AbilityType.SelectiveMeeting">Selective Meeting Ability</string>
|
||||||
|
<string name="MiraApi.AbilityType.MeetingMenu">Meeting Menu Ability</string>
|
||||||
|
<string name="Options">Options</string>
|
||||||
|
<string name="MiraApi.Wiki.PlayersTab">Player List</string>
|
||||||
|
<string name="MiraApi.Wiki.SettingsTab">Game Settings</string>
|
||||||
|
<string name="MiraApi.Wiki.SearchPlaceholder">Search...</string>
|
||||||
|
<string name="MiraApi.Wiki.FilterLabel">Filter</string>
|
||||||
|
<string name="MiraApi.Wiki.GroupingLabel">Grouping</string>
|
||||||
|
<string name="MiraApi.Wiki.OrderLabel">Order</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
@@ -45,6 +45,11 @@ public static class CustomRoleManager
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static IReadOnlyList<RoleBehaviour> CustomRoleBehaviours { get; private set; } = [];
|
public static IReadOnlyList<RoleBehaviour> CustomRoleBehaviours { get; private set; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="IReadOnlyList{T}"/> of all roles as <see cref="RoleBehaviour"/> objects.
|
||||||
|
/// </summary>
|
||||||
|
public static IReadOnlyList<RoleBehaviour> AllStoredRoleBehaviours { get; private set; } = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="IReadOnlyList{T}"/> of custom roles as <see cref="ICustomRole"/> objects.
|
/// Gets the <see cref="IReadOnlyList{T}"/> of custom roles as <see cref="ICustomRole"/> objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -52,6 +57,7 @@ public static class CustomRoleManager
|
|||||||
|
|
||||||
internal static readonly Dictionary<ushort, RoleBehaviour> CustomRoles = [];
|
internal static readonly Dictionary<ushort, RoleBehaviour> CustomRoles = [];
|
||||||
internal static readonly Dictionary<Type, ushort> RoleIds = [];
|
internal static readonly Dictionary<Type, ushort> RoleIds = [];
|
||||||
|
internal static readonly Dictionary<Type, MiraPluginInfo> RoleParentMods = [];
|
||||||
|
|
||||||
private static CppCollections.List<BaseGameSetting>? _emptySettings;
|
private static CppCollections.List<BaseGameSetting>? _emptySettings;
|
||||||
private static Il2CppReferenceArray<OverlayKillAnimation>? _emptyKillAnimations;
|
private static Il2CppReferenceArray<OverlayKillAnimation>? _emptyKillAnimations;
|
||||||
@@ -77,6 +83,7 @@ public static class CustomRoleManager
|
|||||||
|
|
||||||
CustomRoleBehaviours = [.. CustomRoles.Values];
|
CustomRoleBehaviours = [.. CustomRoles.Values];
|
||||||
CustomMiraRoles = [.. CustomRoles.Values.OfType<ICustomRole>()];
|
CustomMiraRoles = [.. CustomRoles.Values.OfType<ICustomRole>()];
|
||||||
|
AllStoredRoleBehaviours = [.. RoleManager.Instance.AllRoles];
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void RegisterRoleTypes(List<Type> roles, MiraPluginInfo pluginInfo)
|
internal static void RegisterRoleTypes(List<Type> roles, MiraPluginInfo pluginInfo)
|
||||||
@@ -99,6 +106,7 @@ public static class CustomRoleManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
pluginInfo.InternalRoles.Add((ushort)role.Role, role);
|
pluginInfo.InternalRoles.Add((ushort)role.Role, role);
|
||||||
|
RoleParentMods[roleType] = pluginInfo;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -205,7 +213,9 @@ public static class CustomRoleManager
|
|||||||
/// <returns>A <see cref="MiraPluginInfo"/> object representing the parent mod of the role.</returns>
|
/// <returns>A <see cref="MiraPluginInfo"/> object representing the parent mod of the role.</returns>
|
||||||
public static MiraPluginInfo FindParentMod(ICustomRole role)
|
public static MiraPluginInfo FindParentMod(ICustomRole role)
|
||||||
{
|
{
|
||||||
return MiraPluginManager.Instance.RegisteredPlugins.First(plugin => plugin.InternalRoles.ContainsValue(role as RoleBehaviour ?? throw new InvalidOperationException()));
|
return RoleParentMods.TryGetValue(role.GetType(), out var mod)
|
||||||
|
? mod
|
||||||
|
: MiraPluginManager.Instance.RegisteredPlugins.First(plugin => plugin.InternalRoles.ContainsValue(role as RoleBehaviour ?? throw new InvalidOperationException()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using BepInEx.Configuration;
|
using BepInEx.Configuration;
|
||||||
|
using Il2CppInterop.Runtime.Attributes;
|
||||||
using MiraAPI.GameModes;
|
using MiraAPI.GameModes;
|
||||||
using MiraAPI.GameOptions;
|
using MiraAPI.GameOptions;
|
||||||
using MiraAPI.Modifiers;
|
using MiraAPI.Modifiers;
|
||||||
using MiraAPI.PluginLoading;
|
using MiraAPI.PluginLoading;
|
||||||
using MiraAPI.Translation;
|
using MiraAPI.Translation;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
|
using MiraAPI.Utilities.Assets;
|
||||||
using TMPro;
|
using TMPro;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@@ -68,9 +71,10 @@ public interface ICustomRole : IOptionable
|
|||||||
string RoleLongDescriptionLocale => MiraLocaleManager.BuildTranslationId(IdPrefix, IdPart, "TabDescription");
|
string RoleLongDescriptionLocale => MiraLocaleManager.BuildTranslationId(IdPrefix, IdPart, "TabDescription");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the wiki description of the role. Used in the wiki, but not currently required.
|
/// Gets the wiki description of the role. Used in the wiki and normally appends the options text as well.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string RoleWikiDescription => MiraLocaleManager.Get(RoleWikiDescriptionLocale, RoleLongDescription);
|
string RoleWikiDescription => MiraLocaleManager.Get(RoleWikiDescriptionLocale, RoleLongDescription) +
|
||||||
|
Helpers.GetOptionsText(GetType());
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the role's wiki description id for localization.
|
/// Gets the role's wiki description id for localization.
|
||||||
@@ -314,26 +318,34 @@ public interface ICustomRole : IOptionable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="guide">The guide object.</param>
|
/// <param name="guide">The guide object.</param>
|
||||||
/// <param name="titleText">The title text object.</param>
|
/// <param name="titleText">The title text object.</param>
|
||||||
|
/// <param name="titleIcon">The title's icon.</param>
|
||||||
/// <param name="parent">The scroller parent.</param>
|
/// <param name="parent">The scroller parent.</param>
|
||||||
/// <returns>The <see cref="GameObject"/> of the wiki.</returns>
|
/// <returns>The <see cref="GameObject"/> of the wiki.</returns>
|
||||||
GameObject GetAdvancedWiki(MatchInfoGuide guide, TextMeshPro titleText, Scroller parent)
|
GameObject GetAdvancedWiki(MatchInfoGuide guide, TextMeshPro titleText, SpriteRenderer titleIcon, Scroller parent)
|
||||||
{
|
{
|
||||||
parent.ScrollToTop();
|
var abilities = WikiAbilities;
|
||||||
var obj = Helpers.CreateAdvancedWikiTab(
|
return Helpers.CreateAdvancedWikiPage(
|
||||||
guide,
|
guide,
|
||||||
RoleNameLocale,
|
|
||||||
RoleName + $" ({RoleFactionTitle})",
|
|
||||||
RoleWikiDescription,
|
|
||||||
titleText,
|
titleText,
|
||||||
out var desc);
|
titleIcon,
|
||||||
obj.transform.SetParent(parent.Inner.transform);
|
parent,
|
||||||
obj.transform.localPosition = new Vector3(0f, 0f, 0f);
|
RoleNameLocale,
|
||||||
parent.SetYBoundsMax(Mathf.Clamp(desc.textBounds.size.y - 2, 0f, 999f));
|
$"{RoleName} ({RoleFactionTitle})",
|
||||||
return obj;
|
Configuration.Icon ?? MiraAssets.IconNeutral.LoadAsset(),
|
||||||
|
RoleWikiDescription,
|
||||||
|
abilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the function that determines whether the role should be toggled on or off in the game settings.
|
/// Gets the function that determines whether the role should be toggled on or off in the game settings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Func<bool> VisibleInSettings => () => true;
|
Func<bool> VisibleInSettings => () => true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of abilities or other similar information to display below the text of a role's wiki page.
|
||||||
|
/// </summary>
|
||||||
|
[HideFromIl2Cpp]
|
||||||
|
public List<AdvancedWikiAbilityDescription> WikiAbilities => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public record struct AdvancedWikiAbilityDescription(string Name, string AbilityType, string Description, LoadableAsset<Sprite> Icon);
|
||||||
@@ -19,7 +19,7 @@ public static class MiraAssets
|
|||||||
new Vector2(0.5f, 0.5f),
|
new Vector2(0.5f, 0.5f),
|
||||||
100f,
|
100f,
|
||||||
0U,
|
0U,
|
||||||
SpriteMeshType.Tight,
|
SpriteMeshType.FullRect,
|
||||||
new Vector4(20, 20, 20, 20));
|
new Vector4(20, 20, 20, 20));
|
||||||
|
|
||||||
RoundedBox = new LoadableAssetWrapper<Sprite>(boxSprite);
|
RoundedBox = new LoadableAssetWrapper<Sprite>(boxSprite);
|
||||||
@@ -160,5 +160,180 @@ public static class MiraAssets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LoadableResourceAsset ChatOpenSprite { get; } = new("MiraAPI.Resources.NormalChatOpen.png");
|
public static LoadableResourceAsset ChatOpenSprite { get; } = new("MiraAPI.Resources.NormalChatOpen.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for players button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset WikiPlayersButtonHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarPlayersButtonHover.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the players button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset WikiPlayersButtonIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarPlayersButtonIdle.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the players button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset WikiPlayersButtonOpenSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarPlayersButtonOpen.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the settings button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset WikiSettingsButtonHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarSettingsButtonHover.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the settings button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset WikiSettingsButtonIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarSettingsButtonIdle.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the settings button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset WikiSettingsButtonOpenSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarSettingsButtonOpen.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset WikiRolesButtonHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarRolesButtonHover.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset WikiRolesButtonIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarRolesButtonIdle.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset WikiRolesButtonOpenSprite { get; } = new("MiraAPI.Resources.Wiki.SidebarRolesButtonOpen.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset GroupCountHoverSprite { get; } = new("MiraAPI.Resources.Wiki.GroupCountHover.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset GroupCountIdleSprite { get; } = new("MiraAPI.Resources.Wiki.GroupCountIdle.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset GroupFactionHoverSprite { get; } = new("MiraAPI.Resources.Wiki.GroupFactionHover.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset GroupFactionIdleSprite { get; } = new("MiraAPI.Resources.Wiki.GroupFactionIdle.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset GroupNoneHoverSprite { get; } = new("MiraAPI.Resources.Wiki.GroupNoneHover.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset GroupNoneIdleSprite { get; } = new("MiraAPI.Resources.Wiki.GroupNoneIdle.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset SearchClearHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SearchClearHover.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset SearchClearIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SearchClearIdle.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset SearchIconHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SearchIconHover.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset SearchIconIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SearchIconIdle.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset SortingAzHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SortingAzHover.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset SortingAzIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SortingAzIdle.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset SortingZaHoverSprite { get; } = new("MiraAPI.Resources.Wiki.SortingZaHover.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset SortingZaIdleSprite { get; } = new("MiraAPI.Resources.Wiki.SortingZaIdle.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset VisibleAllHoverSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleAllHover.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset VisibleAllIdleSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleAllIdle.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset VisibleOffHoverSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleOffHover.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset VisibleOffIdleSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleOffIdle.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset VisibleOnHoverSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleOnHover.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the roles button while hovering.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset VisibleOnIdleSprite { get; } = new("MiraAPI.Resources.Wiki.VisibleOnIdle.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for crewmates.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset IconCrewmate { get; } = new("MiraAPI.Resources.Wiki.IconCrewmate.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for impostors.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset IconImpostor { get; } = new("MiraAPI.Resources.Wiki.IconImpostor.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for neutrals.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset IconNeutral { get; } = new("MiraAPI.Resources.Wiki.IconNeutral.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for the player list.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset IconPlayerList { get; } = new("MiraAPI.Resources.Wiki.IconPlayerList.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for settings.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset IconSettings { get; } = new("MiraAPI.Resources.Wiki.IconSettings.png");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sprite used for terminology.
|
||||||
|
/// </summary>
|
||||||
|
public static LoadableResourceAsset IconTerminology { get; } = new("MiraAPI.Resources.Wiki.IconTerminology.png");
|
||||||
|
|
||||||
internal static LoadableResourceAsset BlankSprite { get; } = new("MiraAPI.Resources.BlankSprite.png");
|
internal static LoadableResourceAsset BlankSprite { get; } = new("MiraAPI.Resources.BlankSprite.png");
|
||||||
}
|
}
|
||||||
@@ -48,7 +48,13 @@ public static class SpriteTools
|
|||||||
public static Sprite LoadSpriteFromPath(string resourcePath, Assembly assembly, float pixelsPerUnit)
|
public static Sprite LoadSpriteFromPath(string resourcePath, Assembly assembly, float pixelsPerUnit)
|
||||||
{
|
{
|
||||||
var tex = LoadTextureFromResourcePath(resourcePath, assembly);
|
var tex = LoadTextureFromResourcePath(resourcePath, assembly);
|
||||||
var sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f), pixelsPerUnit);
|
var sprite = Sprite.Create(
|
||||||
|
tex,
|
||||||
|
new Rect(0, 0, tex.width, tex.height),
|
||||||
|
new Vector2(0.5f, 0.5f),
|
||||||
|
pixelsPerUnit,
|
||||||
|
0,
|
||||||
|
SpriteMeshType.FullRect);
|
||||||
sprite.name = resourcePath;
|
sprite.name = resourcePath;
|
||||||
return sprite;
|
return sprite;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ public static class Extensions
|
|||||||
public static IEnumerator CoLoopWithBudget<T>(this IEnumerable<T> collection, Action<T> action)
|
public static IEnumerator CoLoopWithBudget<T>(this IEnumerable<T> collection, Action<T> action)
|
||||||
{
|
{
|
||||||
var fps = Application.targetFrameRate > 0 ? Application.targetFrameRate : 60;
|
var fps = Application.targetFrameRate > 0 ? Application.targetFrameRate : 60;
|
||||||
long budget = 1 / (fps * 2); // default is half of current frame time.
|
var budget = 1000L / (fps * 2); // default is half of current frame time.
|
||||||
yield return collection.CoLoopWithBudget(budget, action);
|
yield return collection.CoLoopWithBudget(budget, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,8 +355,8 @@ public static class Extensions
|
|||||||
public static void ClearGarbageCollector()
|
public static void ClearGarbageCollector()
|
||||||
{
|
{
|
||||||
Resources.UnloadUnusedAssets();
|
Resources.UnloadUnusedAssets();
|
||||||
Il2CppSystem.GC.Collect();
|
/*Il2CppSystem.GC.Collect();
|
||||||
GC.Collect();
|
GC.Collect();*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,17 +1,27 @@
|
|||||||
using System.Collections;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||||
|
using MiraAPI.GameOptions;
|
||||||
|
using MiraAPI.GameOptions.OptionTypes;
|
||||||
|
using MiraAPI.Modifiers;
|
||||||
using MiraAPI.Roles;
|
using MiraAPI.Roles;
|
||||||
|
using MiraAPI.Translation;
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
using Rewired;
|
using Rewired;
|
||||||
using TMPro;
|
using TMPro;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
using MethodBase = System.Reflection.MethodBase;
|
using MethodBase = System.Reflection.MethodBase;
|
||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
|
using Random = UnityEngine.Random;
|
||||||
|
|
||||||
namespace MiraAPI.Utilities;
|
namespace MiraAPI.Utilities;
|
||||||
|
|
||||||
@@ -20,6 +30,125 @@ namespace MiraAPI.Utilities;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class Helpers
|
public static class Helpers
|
||||||
{
|
{
|
||||||
|
private static readonly Regex TrailingZeroRegex = new(@"\.0+(?!\d)", RegexOptions.Compiled, TimeSpan.FromMilliseconds(100));
|
||||||
|
|
||||||
|
public static ReadOnlyCollection<IModdedOption>? GetModdedOptionsForType(Type classType)
|
||||||
|
{
|
||||||
|
var group = ModdedOptionsManager.Groups.FirstOrDefault(x => x.OptionableType == classType);
|
||||||
|
|
||||||
|
return group?.Children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetOptionsText(Type classType)
|
||||||
|
{
|
||||||
|
var group = ModdedOptionsManager.Groups.FirstOrDefault(x => x.OptionableType == classType);
|
||||||
|
var options = group?.Children;
|
||||||
|
var summaryProvider = group as ISummarizedOptions;
|
||||||
|
var hiddenKeys = summaryProvider?.WikiHiddenOptionKeys;
|
||||||
|
|
||||||
|
if (options == null)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lines = new List<string>();
|
||||||
|
var insertedSummary = false;
|
||||||
|
foreach (var option in options)
|
||||||
|
{
|
||||||
|
StringNames? key = option switch
|
||||||
|
{
|
||||||
|
ModdedToggleOption t => t.StringName,
|
||||||
|
ModdedEnumOption e => e.StringName,
|
||||||
|
ModdedNumberOption n => n.StringName,
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!insertedSummary && summaryProvider != null && hiddenKeys != null &&
|
||||||
|
key.HasValue && hiddenKeys.Contains(key.Value))
|
||||||
|
{
|
||||||
|
foreach (var line in summaryProvider.GetWikiOptionSummaryLines())
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(line))
|
||||||
|
{
|
||||||
|
lines.Add(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
insertedSummary = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!option.Visible())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.HasValue && hiddenKeys?.Contains(key.Value) == true)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (option)
|
||||||
|
{
|
||||||
|
case ModdedToggleOption toggleOption:
|
||||||
|
lines.Add(
|
||||||
|
TranslationController.Instance.GetString(toggleOption.StringName) + ": " +
|
||||||
|
toggleOption.Value);
|
||||||
|
break;
|
||||||
|
/*case ModdedMultiSelectOption<Enum> enumOption:
|
||||||
|
if (!enumOption.Visible())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.AppendLine(enumOption.Title + ": " + enumOption.Values[enumOption.Value]);
|
||||||
|
break;*/
|
||||||
|
case ModdedEnumOption enumOption:
|
||||||
|
lines.Add(
|
||||||
|
TranslationController.Instance.GetString(enumOption.StringName) + ": " +
|
||||||
|
MiraLocaleManager.Get(
|
||||||
|
enumOption.Values[enumOption.Value],
|
||||||
|
enumOption.Values[enumOption.Value]));
|
||||||
|
break;
|
||||||
|
case ModdedNumberOption numberOption:
|
||||||
|
var optionStr = TrailingZeroRegex.Replace(
|
||||||
|
numberOption.Data.GetValueString(numberOption.Value),
|
||||||
|
string.Empty);
|
||||||
|
|
||||||
|
var title = TranslationController.Instance.GetString(numberOption.StringName);
|
||||||
|
if (numberOption is { NegativeWordValue: not "#", Value: -1 })
|
||||||
|
{
|
||||||
|
lines.Add(title + $": {numberOption.NegativeWordValue}");
|
||||||
|
}
|
||||||
|
else if (numberOption is { ZeroWordValue: not "#", Value: 0 })
|
||||||
|
{
|
||||||
|
lines.Add(title + $": {numberOption.ZeroWordValue}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lines.Add(title + ": " + optionStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lines.Count == 0)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
builder.AppendLine(
|
||||||
|
MiraApiPlugin.Culture,
|
||||||
|
$"\n<size=50%> \n</size><b><color=#29D7B5>{MiraLocaleManager.Get("Options")}</color></b>");
|
||||||
|
foreach (var line in lines)
|
||||||
|
{
|
||||||
|
builder.AppendLine(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get all living players.
|
/// Get all living players.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -228,7 +357,7 @@ public static class Helpers
|
|||||||
var popper = HudManager.Instance.Notifier;
|
var popper = HudManager.Instance.Notifier;
|
||||||
var newMessage = Object.Instantiate(popper.notificationMessageOrigin, Vector3.zero, Quaternion.identity, popper.transform);
|
var newMessage = Object.Instantiate(popper.notificationMessageOrigin, Vector3.zero, Quaternion.identity, popper.transform);
|
||||||
newMessage.transform.localPosition = localPos;
|
newMessage.transform.localPosition = localPos;
|
||||||
newMessage.SetUp(text, spr ?? null, color, new System.Action(() => popper.OnMessageDestroy(newMessage)));
|
newMessage.SetUp(text, spr ?? null, color, new Action(() => popper.OnMessageDestroy(newMessage)));
|
||||||
popper.lastMessageKey = -1;
|
popper.lastMessageKey = -1;
|
||||||
popper.ShiftMessages();
|
popper.ShiftMessages();
|
||||||
popper.AddMessageToQueue(newMessage);
|
popper.AddMessageToQueue(newMessage);
|
||||||
@@ -280,9 +409,12 @@ public static class Helpers
|
|||||||
{
|
{
|
||||||
var results = new CppCollections.List<Collider2D>();
|
var results = new CppCollections.List<Collider2D>();
|
||||||
Physics2D.OverlapCircle(source, radius, filter, results);
|
Physics2D.OverlapCircle(source, radius, filter, results);
|
||||||
return [.. results.ToArray()
|
return
|
||||||
.Where(collider2D => collider2D.CompareTag("DeadBody"))
|
[
|
||||||
.Select(collider2D => collider2D.GetComponent<DeadBody>())];
|
.. results.ToArray()
|
||||||
|
.Where(collider2D => collider2D.CompareTag("DeadBody"))
|
||||||
|
.Select(collider2D => collider2D.GetComponent<DeadBody>())
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -299,9 +431,12 @@ public static class Helpers
|
|||||||
{
|
{
|
||||||
var results = new CppCollections.List<Collider2D>();
|
var results = new CppCollections.List<Collider2D>();
|
||||||
Physics2D.OverlapCircle(source, radius, filter, results);
|
Physics2D.OverlapCircle(source, radius, filter, results);
|
||||||
return [.. results.ToArray()
|
return
|
||||||
.Where(collider2D => colliderTag == null || collider2D.CompareTag(colliderTag))
|
[
|
||||||
.Select(collider2D => collider2D.GetComponent<T>())];
|
.. results.ToArray()
|
||||||
|
.Where(collider2D => colliderTag == null || collider2D.CompareTag(colliderTag))
|
||||||
|
.Select(collider2D => collider2D.GetComponent<T>())
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -320,15 +455,18 @@ public static class Helpers
|
|||||||
|
|
||||||
return !ignoreColliders
|
return !ignoreColliders
|
||||||
? newList
|
? newList
|
||||||
: [.. from player in newList
|
:
|
||||||
let vector = player.GetTruePosition() - source
|
[
|
||||||
let magnitude = vector.magnitude
|
.. from player in newList
|
||||||
where !PhysicsHelpers.AnyNonTriggersBetween(
|
let vector = player.GetTruePosition() - source
|
||||||
source,
|
let magnitude = vector.magnitude
|
||||||
vector.normalized,
|
where !PhysicsHelpers.AnyNonTriggersBetween(
|
||||||
magnitude,
|
source,
|
||||||
Constants.ShipAndObjectsMask)
|
vector.normalized,
|
||||||
select player];
|
magnitude,
|
||||||
|
Constants.ShipAndObjectsMask)
|
||||||
|
select player
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -389,17 +527,16 @@ public static class Helpers
|
|||||||
Constants.ShipAndObjectsMask))
|
Constants.ShipAndObjectsMask))
|
||||||
select playerControl);
|
select playerControl);
|
||||||
|
|
||||||
outputList.Sort(
|
outputList.Sort((a, b) =>
|
||||||
(a, b) =>
|
{
|
||||||
{
|
var magnitude2 = (a.GetTruePosition() - source).magnitude;
|
||||||
var magnitude2 = (a.GetTruePosition() - source).magnitude;
|
var magnitude3 = (b.GetTruePosition() - source).magnitude;
|
||||||
var magnitude3 = (b.GetTruePosition() - source).magnitude;
|
return magnitude2 > magnitude3
|
||||||
return magnitude2 > magnitude3
|
? 1
|
||||||
? 1
|
: magnitude2 < magnitude3
|
||||||
: magnitude2 < magnitude3
|
? -1
|
||||||
? -1
|
: 0;
|
||||||
: 0;
|
});
|
||||||
});
|
|
||||||
return outputList;
|
return outputList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -552,6 +689,40 @@ public static class Helpers
|
|||||||
return role is ICustomRole custom ? custom.RoleLongDescription : role.BlurbLong;
|
return role is ICustomRole custom ? custom.RoleLongDescription : role.BlurbLong;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the TextMeshPro sprite tag for a role, matching how role names are shown in-game.
|
||||||
|
/// Uses the role's <see cref="CustomRoleConfiguration.IconTmp"/> if set, otherwise falls back to the faction icon.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="role">The <see cref="RoleBehaviour"/>.</param>
|
||||||
|
/// <returns>A <c><sprite></c> rich text tag.</returns>
|
||||||
|
public static string GetTmpIcon(this RoleBehaviour role)
|
||||||
|
{
|
||||||
|
return role is ICustomRole custom ? custom.GetTmpIcon() : $"<sprite name=\"AmongUs.Role.{role.Role}\">";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the TextMeshPro sprite tag for a custom role, matching how role names are shown in-game.
|
||||||
|
/// Uses the role's <see cref="CustomRoleConfiguration.IconTmp"/> if set, otherwise falls back to the faction icon.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="role">The <see cref="ICustomRole"/>.</param>
|
||||||
|
/// <returns>A <c><sprite></c> rich text tag.</returns>
|
||||||
|
public static string GetTmpIcon(this ICustomRole role)
|
||||||
|
{
|
||||||
|
return role.Configuration.IconTmp
|
||||||
|
? $"<sprite name=\"{role.Configuration.IconTmp.name}\">"
|
||||||
|
: $"<sprite name=\"AmongUs.Role.{role.Team}\">";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the TextMeshPro sprite tag for a modifier, or an empty string if it has no <see cref="BaseModifier.IconTmp"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="modifier">The <see cref="BaseModifier"/>.</param>
|
||||||
|
/// <returns>A <c><sprite></c> rich text tag, or <see cref="string.Empty"/>.</returns>
|
||||||
|
public static string GetTmpIcon(this BaseModifier modifier)
|
||||||
|
{
|
||||||
|
return modifier.IconTmp ? $"<sprite name=\"{modifier.IconTmp.name}\">" : string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns whether the <see cref="RoleBehaviour"/> is blacklisted from appearing and spawning. (Only applicable to vanilla roles).
|
/// Returns whether the <see cref="RoleBehaviour"/> is blacklisted from appearing and spawning. (Only applicable to vanilla roles).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -570,14 +741,19 @@ public static class Helpers
|
|||||||
/// <param name="guide">The guide panel to attach the tab to.</param>
|
/// <param name="guide">The guide panel to attach the tab to.</param>
|
||||||
/// <param name="objName">The name of the tab.</param>
|
/// <param name="objName">The name of the tab.</param>
|
||||||
/// <param name="title">The title of the tab.</param>
|
/// <param name="title">The title of the tab.</param>
|
||||||
|
/// <param name="icon">The icon of the page.</param>
|
||||||
/// <param name="description">The description of the tab.</param>
|
/// <param name="description">The description of the tab.</param>
|
||||||
/// <param name="titleTmp">The <see cref="TextMeshPro"/> instance of the title.</param>
|
/// <param name="titleTmp">The <see cref="TextMeshPro"/> instance of the title.</param>
|
||||||
|
/// <param name="titleIcon">The <see cref="SpriteRenderer"/> instance for the title.</param>
|
||||||
/// <param name="descriptionTmp">The <see cref="TextMeshPro"/> instance of the description.</param>
|
/// <param name="descriptionTmp">The <see cref="TextMeshPro"/> instance of the description.</param>
|
||||||
/// <returns>The <see cref="GameObject"/> of the tab.</returns>
|
/// <returns>The <see cref="GameObject"/> of the tab.</returns>
|
||||||
public static GameObject CreateAdvancedWikiTab(MatchInfoGuide guide, string objName, string title, string description, TextMeshPro titleTmp, out TextMeshPro descriptionTmp)
|
public static GameObject CreateAdvancedWikiTab(MatchInfoGuide guide, string objName, string title, Sprite icon, string description, TextMeshPro titleTmp, SpriteRenderer titleIcon, out TextMeshPro descriptionTmp)
|
||||||
{
|
{
|
||||||
var obj = new GameObject(objName);
|
var obj = new GameObject(objName);
|
||||||
|
titleTmp.richText = true;
|
||||||
titleTmp.text = title;
|
titleTmp.text = title;
|
||||||
|
titleIcon.sprite = icon;
|
||||||
|
titleIcon.SetSizeLimit(0.55f);
|
||||||
descriptionTmp = Object.Instantiate(guide.MatchInfoRolePanelPrefab.roleCount, obj.transform);
|
descriptionTmp = Object.Instantiate(guide.MatchInfoRolePanelPrefab.roleCount, obj.transform);
|
||||||
descriptionTmp.fontSizeMin = descriptionTmp.fontSizeMax = descriptionTmp.fontSize = 2f;
|
descriptionTmp.fontSizeMin = descriptionTmp.fontSizeMax = descriptionTmp.fontSize = 2f;
|
||||||
var sourceTmp = HudManager.Instance.TaskPanel.taskText;
|
var sourceTmp = HudManager.Instance.TaskPanel.taskText;
|
||||||
@@ -591,4 +767,103 @@ public static class Helpers
|
|||||||
descriptionTmp.ForceMeshUpdate();
|
descriptionTmp.ForceMeshUpdate();
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a full advanced wiki page with a title, a description, and an optional grid of ability panels.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="guide">The guide object.</param>
|
||||||
|
/// <param name="titleTmp">The <see cref="TextMeshPro"/> instance of the title.</param>
|
||||||
|
/// <param name="titleIcon">The <see cref="SpriteRenderer"/> instance for the title.</param>
|
||||||
|
/// <param name="parent">The <see cref="Scroller"/> the page should be parented to.</param>
|
||||||
|
/// <param name="objName">The name of the page object.</param>
|
||||||
|
/// <param name="title">The title of the page.</param>
|
||||||
|
/// <param name="icon">The icon of the page.</param>
|
||||||
|
/// <param name="description">The description of the page.</param>
|
||||||
|
/// <param name="abilities">The abilities to display in a grid below the description.</param>
|
||||||
|
/// <param name="variableTextSizing">Whether to use variable text sizing for ability descriptions (allows different heights).</param>
|
||||||
|
/// <returns>The <see cref="GameObject"/> of the wiki page.</returns>
|
||||||
|
public static GameObject CreateAdvancedWikiPage(
|
||||||
|
MatchInfoGuide guide,
|
||||||
|
TextMeshPro titleTmp,
|
||||||
|
SpriteRenderer titleIcon,
|
||||||
|
Scroller parent,
|
||||||
|
string objName,
|
||||||
|
string title,
|
||||||
|
Sprite icon,
|
||||||
|
string description,
|
||||||
|
IReadOnlyCollection<AdvancedWikiAbilityDescription> abilities,
|
||||||
|
bool variableTextSizing = false)
|
||||||
|
{
|
||||||
|
parent.ScrollToTop();
|
||||||
|
var obj = CreateAdvancedWikiTab(
|
||||||
|
guide,
|
||||||
|
objName,
|
||||||
|
title,
|
||||||
|
icon,
|
||||||
|
description,
|
||||||
|
titleTmp,
|
||||||
|
titleIcon,
|
||||||
|
out var desc);
|
||||||
|
var num = 0;
|
||||||
|
var maxTextSize = 0f;
|
||||||
|
if (abilities.Count != 0)
|
||||||
|
{
|
||||||
|
var grid = Object.Instantiate(parent.Inner, obj.transform);
|
||||||
|
var layoutGroup = grid.GetComponent<GridLayoutGroup>();
|
||||||
|
layoutGroup.startAxis = GridLayoutGroup.Axis.Vertical;
|
||||||
|
layoutGroup.constraint = GridLayoutGroup.Constraint.FixedColumnCount;
|
||||||
|
layoutGroup.spacing = new Vector2(0.75f, 0.4f);
|
||||||
|
grid.DestroyChildren();
|
||||||
|
foreach (var ability in abilities)
|
||||||
|
{
|
||||||
|
num++;
|
||||||
|
var panel = Object.Instantiate(guide.MatchInfoRolePanelPrefab, grid);
|
||||||
|
SetupAbilityPanel(panel, ability, variableTextSizing);
|
||||||
|
if (variableTextSizing)
|
||||||
|
{
|
||||||
|
var descSize = panel.roleDescription.textBounds.size.y;
|
||||||
|
if (maxTextSize < descSize)
|
||||||
|
{
|
||||||
|
maxTextSize = descSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.localPosition = new Vector3(-3.9f, 1.1f - desc.textBounds.size.y, 0f);
|
||||||
|
grid.localScale = new Vector3(1.3f, 1.3f, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.transform.SetParent(parent.Inner.transform);
|
||||||
|
obj.transform.localPosition = new Vector3(0f, 0.5f, 0f);
|
||||||
|
var scrollHeight = variableTextSizing
|
||||||
|
? (desc.textBounds.size.y - 2.5f) + maxTextSize + 0.475f
|
||||||
|
: desc.textBounds.size.y - 2.5f + Mathf.Ceil(num / 2f) * 1.45f;
|
||||||
|
parent.SetYBoundsMax(Mathf.Clamp(scrollHeight, 0f, 999f));
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetupAbilityPanel(MatchInfoRolePanel panel, AdvancedWikiAbilityDescription ability, bool variableTextSizing = false)
|
||||||
|
{
|
||||||
|
panel.roleCount.text = ability.AbilityType;
|
||||||
|
panel.roleCount.transform.localPosition += new Vector3(-0.04f, 0);
|
||||||
|
panel.roleName.text = ability.Name;
|
||||||
|
panel.roleName.transform.localPosition += new Vector3(-0.04f, 0);
|
||||||
|
panel.roleDescription.text = ability.Description;
|
||||||
|
panel.roleDescription.rectTransform.sizeDelta = new Vector2(2.601f, 0.8f);
|
||||||
|
panel.roleDescription.transform.localPosition += new Vector3(0, -0.1f);
|
||||||
|
if (variableTextSizing)
|
||||||
|
{
|
||||||
|
panel.roleDescription.alignment = TextAlignmentOptions.Top;
|
||||||
|
panel.roleDescription.fontSizeMin = 1.5f;
|
||||||
|
panel.roleDescription.ForceMeshUpdate();
|
||||||
|
}
|
||||||
|
panel.roleIcon.sprite = ability.Icon.LoadAsset();
|
||||||
|
panel.roleIcon.SetSizeLimit(0.13f);
|
||||||
|
|
||||||
|
panel.roleIcon.material.SetInt(PlayerMaterial.MaskLayer, 50);
|
||||||
|
panel.roleName.fontMaterial.SetFloat(panel.STENCIL_NAME, 50f);
|
||||||
|
panel.roleDescription.fontMaterial.SetFloat(panel.STENCIL_NAME, 50f);
|
||||||
|
panel.roleCount.fontMaterial.SetFloat(panel.STENCIL_NAME, 50f);
|
||||||
|
panel.roleIcon.transform.localScale = new Vector3(3.5f, 3.5f, 1f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
using System;
|
||||||
|
using Reactor.Utilities.Attributes;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace MiraAPI.Utilities;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A spinning ring used to indicate that content is loading.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterInIl2Cpp]
|
||||||
|
public class LoadingRing(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
||||||
|
{
|
||||||
|
private static Sprite? _ringSprite;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the rotation speed in degrees per second.
|
||||||
|
/// </summary>
|
||||||
|
public float Speed { get; set; } = 270f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a <see cref="LoadingRing"/> on the UI layer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parent">The transform to parent the spinner to.</param>
|
||||||
|
/// <param name="localPosition">The local position of the spinner.</param>
|
||||||
|
/// <param name="scale">The uniform scale of the spinner.</param>
|
||||||
|
/// <returns>The created <see cref="LoadingRing"/>.</returns>
|
||||||
|
public static LoadingRing Create(Transform parent, Vector3 localPosition, float scale)
|
||||||
|
{
|
||||||
|
if (!_ringSprite)
|
||||||
|
{
|
||||||
|
_ringSprite = CreateRingSprite();
|
||||||
|
}
|
||||||
|
|
||||||
|
var obj = new GameObject("LoadingRing")
|
||||||
|
{
|
||||||
|
transform =
|
||||||
|
{
|
||||||
|
parent = parent,
|
||||||
|
localPosition = localPosition,
|
||||||
|
localScale = Vector3.one * scale,
|
||||||
|
},
|
||||||
|
layer = LayerMask.NameToLayer("UI"),
|
||||||
|
};
|
||||||
|
var renderer = obj.AddComponent<SpriteRenderer>();
|
||||||
|
renderer.sprite = _ringSprite;
|
||||||
|
return obj.AddComponent<LoadingRing>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotates the ring.
|
||||||
|
/// </summary>
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
transform.Rotate(0f, 0f, -Speed * Time.deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Sprite CreateRingSprite()
|
||||||
|
{
|
||||||
|
const int size = 128;
|
||||||
|
const float innerRadius = 46f;
|
||||||
|
const float outerRadius = 60f;
|
||||||
|
var texture = new Texture2D(size, size, TextureFormat.RGBA32, false)
|
||||||
|
{
|
||||||
|
filterMode = FilterMode.Bilinear,
|
||||||
|
wrapMode = TextureWrapMode.Clamp,
|
||||||
|
};
|
||||||
|
var pixels = new Color[size * size];
|
||||||
|
for (var y = 0; y < size; y++)
|
||||||
|
{
|
||||||
|
for (var x = 0; x < size; x++)
|
||||||
|
{
|
||||||
|
var dx = x + 0.5f - (size / 2f);
|
||||||
|
var dy = y + 0.5f - (size / 2f);
|
||||||
|
var radius = Mathf.Sqrt((dx * dx) + (dy * dy));
|
||||||
|
var ring = Mathf.Clamp01(radius - innerRadius) * Mathf.Clamp01(outerRadius - radius);
|
||||||
|
var angle = (Mathf.Atan2(dy, dx) + Mathf.PI) / (2f * Mathf.PI);
|
||||||
|
pixels[(y * size) + x] = new Color(1f, 1f, 1f, ring * Mathf.Lerp(1f, 0.1f, angle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
texture.SetPixels(pixels);
|
||||||
|
texture.Apply();
|
||||||
|
texture.hideFlags = HideFlags.HideAndDontSave;
|
||||||
|
var sprite = Sprite.Create(texture, new Rect(0, 0, size, size), new Vector2(0.5f, 0.5f), 100f);
|
||||||
|
sprite.hideFlags = HideFlags.HideAndDontSave;
|
||||||
|
return sprite;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -300,10 +300,7 @@ public static class VotingUtils
|
|||||||
// If modified, these will visually change.
|
// If modified, these will visually change.
|
||||||
votes = @event.Votes;
|
votes = @event.Votes;
|
||||||
|
|
||||||
MeetingHud.Instance.TitleText.text =
|
MeetingHud.Instance.TitleText.text = TranslationController.Instance.GetString(StringNames.MeetingVotingResults);
|
||||||
TranslationController.Instance.GetString(
|
|
||||||
StringNames.MeetingVotingResults,
|
|
||||||
Il2CppSystem.Array.Empty<Il2CppSystem.Object>());
|
|
||||||
|
|
||||||
var delays = new Dictionary<byte, int>();
|
var delays = new Dictionary<byte, int>();
|
||||||
var num = 0;
|
var num = 0;
|
||||||
|
|||||||