Compare commits

..
Author SHA1 Message Date
Atony 0aa4a82d48 Add options to list (no logic)
Issue is mainly the button scale, that needs to update as soon as the change is made
2025-09-09 21:50:45 -05:00
445 changed files with 6044 additions and 25115 deletions

No files matched your search

+1 -106
View File
@@ -1,106 +1 @@
[*.{cs,vb}] [*.{cs,vb}]
# IDE0008: Use explicit type
dotnet_diagnostic.IDE0008.severity = none
# IDE0160: Convert to block scoped namespace
dotnet_diagnostic.IDE0160.severity = none
# IDE0011: Add braces
dotnet_diagnostic.IDE0011.severity = none
# CS8618: Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
dotnet_diagnostic.CS8618.severity = none
# CA1805: Do not initialize unnecessarily
dotnet_diagnostic.CA1805.severity = none
# S3358: Ternary operators should not be nested
dotnet_diagnostic.S3358.severity = none
# IDE1006: Naming Styles
dotnet_diagnostic.IDE1006.severity = none
# S3267: Use LINQ methods to simply foreach loops
dotnet_diagnostic.S3267.severity = none
# S125: Sections of code should not be commented out
dotnet_diagnostic.S125.severity = none
# SA1512: Single-line comments should not be followed by blank line
dotnet_diagnostic.SA1512.severity = none
# S2696: Instance members should not write to "static" fields
dotnet_diagnostic.S2696.severity = none
# S2245: Pseudorandom number generators (PRNGs) should not be used in security contexts
dotnet_diagnostic.S2245.severity = none
# IDE0130: Namespace does not match folder structure
dotnet_diagnostic.IDE0130.severity = none
# SA1633: File should have header
dotnet_diagnostic.SA1633.severity = none
# SA1101: Prefix local calls with this
dotnet_diagnostic.SA1101.severity = none
# SA1600: Elements should be documented
dotnet_diagnostic.SA1600.severity = none
# SA1516: Elements should be separated by blank line
dotnet_diagnostic.SA1516.severity = none
# SA1503: Braces should not be omitted
dotnet_diagnostic.SA1503.severity = none
# SA1201: Elements should appear in the correct order
dotnet_diagnostic.SA1201.severity = none
# SA1402: File may only contain a single type
dotnet_diagnostic.SA1402.severity = none
# SA1204: Static elements should appear before instance elements
dotnet_diagnostic.SA1204.severity = none
# SA1202: Elements should be ordered by access
dotnet_diagnostic.SA1202.severity = none
# SA1649: File name should match first type name
dotnet_diagnostic.SA1649.severity = none
# SA1313: Parameter names should begin with lower-case letter
dotnet_diagnostic.SA1313.severity = none
# SA1636: The file header copyright text should match the copyright text from the settings
dotnet_diagnostic.SA1636.severity = none
# SA1309: Field names should not begin with underscore
dotnet_diagnostic.SA1309.severity = none
# SA1407: Arithmetic expressions should declare precedence
dotnet_diagnostic.SA1407.severity = none
# SA1133: Each attribute should be placed in its own set of square brackets
dotnet_diagnostic.SA1133.severity = none
# IDE0001: Simplify Names
dotnet_diagnostic.IDE0001.severity = warning
# IDE0079: Remove unnecessary suppression
dotnet_diagnostic.IDE0079.severity = none
# S3903: Types should be defined in named namespaces
dotnet_diagnostic.S3903.severity = none
# IDE0045: Convert to conditional expression
dotnet_diagnostic.IDE0045.severity = none
# IDE0046: Convert to conditional expression
dotnet_diagnostic.IDE0046.severity = none
# S1244: Floating point numbers should not be tested for equality
dotnet_diagnostic.S1244.severity = none
# S2325: Methods and properties that don't access instance data should be static
dotnet_diagnostic.S2325.severity = none
+2 -2
View File
@@ -1,9 +1,9 @@
.git/ .git/
.idea/ .idea/
.vs*/ .vs/
obj/ obj/
bin/ bin/
.qodo/ .qodo/
*.user *.user
*.lock.json *.lock.json
+4 -4
View File
@@ -1,14 +1,14 @@
<Project> <Project>
<ItemGroup> <ItemGroup>
<PackageReference Include="Reactor" Version="2.5.0-ci.371" /> <PackageReference Include="Reactor" Version="2.3.1" />
<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.9.29" PrivateAssets="all" /> <PackageReference Include="AmongUs.GameLibs.Steam" Version="2025.4.15" 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" />
</ItemGroup> </ItemGroup>
<Target Name="Copy" AfterTargets="Build" Condition="'$(AmongUs)' != ''"> <Target Name="Copy" AfterTargets="Build" Condition="'$(AmongUs)' != ''">
<Copy SourceFiles="$(TargetPath)" DestinationFolder="$(AmongUs)/BepInEx/plugins/" UseSymboliclinksIfPossible="true" /> <Copy SourceFiles="$(TargetPath)" DestinationFolder="$(AmongUs)/BepInEx/plugins/" UseSymboliclinksIfPossible="true" />
</Target> </Target>
</Project> </Project>
+11 -8
View File
@@ -8,7 +8,7 @@
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile> <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<VersionPrefix>0.5.0</VersionPrefix> <VersionPrefix>0.2.1</VersionPrefix>
<VersionSuffix>dev</VersionSuffix> <VersionSuffix>dev</VersionSuffix>
<Authors>All Of Us, XtraCube, Angxl</Authors> <Authors>All Of Us, XtraCube, Angxl</Authors>
@@ -28,15 +28,18 @@
<AnalysisLevel>latest</AnalysisLevel> <AnalysisLevel>latest</AnalysisLevel>
<AnalysisMode>recommended</AnalysisMode> <AnalysisMode>recommended</AnalysisMode>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild> <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<NoWarn>$(NoWarn);SA0001</NoWarn>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Roslynator.Analyzers" Version="5.0.0" PrivateAssets="all" />
<PackageReference Include="Roslynator.Formatting.Analyzers" Version="5.0.0" PrivateAssets="all" />
<PackageReference Include="Roslynator.CodeAnalysis.Analyzers" Version="5.0.0" PrivateAssets="all" />
<PackageReference Include="SonarAnalyzer.CSharp" Version="10.32.0.713" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556" PrivateAssets="all" />
<AdditionalFiles Include="$(MSBuildThisFileDirectory)/stylecop.json" Link="stylecop.json" Visible="false" /> <AdditionalFiles Include="$(MSBuildThisFileDirectory)\stylecop.json" Link="stylecop.json" Visible="false" />
<PackageReference Include="SonarAnalyzer.CSharp" Version="10.7.0.110445">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
</Project> <PropertyGroup>
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)\stylecop.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>
-29
View File
@@ -1,29 +0,0 @@
<assembly name="0Harmony">
<member name="T:HarmonyLib.HarmonyPatch">
<attribute ctor="M:JetBrains.Annotations.MeansImplicitUseAttribute.#ctor(JetBrains.Annotations.ImplicitUseTargetFlags)">
<argument>3</argument>
</attribute>
</member>
<member name="T:HarmonyLib.HarmonyPrefix">
<attribute ctor="M:JetBrains.Annotations.MeansImplicitUseAttribute.#ctor" />
</member>
<member name="T:HarmonyLib.HarmonyPostfix">
<attribute ctor="M:JetBrains.Annotations.MeansImplicitUseAttribute.#ctor" />
</member>
<member name="T:HarmonyLib.HarmonyTranspiler">
<attribute ctor="M:JetBrains.Annotations.MeansImplicitUseAttribute.#ctor" />
</member>
<member name="T:HarmonyLib.HarmonyFinalizer">
<attribute ctor="M:JetBrains.Annotations.MeansImplicitUseAttribute.#ctor" />
</member>
<member name="T:HarmonyLib.HarmonyPrepare">
<attribute ctor="M:JetBrains.Annotations.MeansImplicitUseAttribute.#ctor" />
</member>
<member name="T:HarmonyLib.HarmonyTargetMethod">
<attribute ctor="M:JetBrains.Annotations.MeansImplicitUseAttribute.#ctor" />
</member>
<member name="T:HarmonyLib.HarmonyTargetMethods">
<attribute ctor="M:JetBrains.Annotations.MeansImplicitUseAttribute.#ctor" />
</member>
</assembly>
-7
View File
@@ -1,7 +0,0 @@
[*.{cs,vb}]
# SA1602: Enumeration items should be documented.
dotnet_diagnostic.SA1602.severity = none
# SA1601: Partial elements should be documented
dotnet_diagnostic.SA1601.severity = none
@@ -13,7 +13,7 @@ namespace MiraAPI.Example.Buttons.Freezer;
public class FreezeButton : CustomActionButton<PlayerControl> public class FreezeButton : CustomActionButton<PlayerControl>
{ {
public override string Name => "button.freeze"; public override string Name => "Freeze";
public override float Cooldown => OptionGroupSingleton<FreezerRoleSettings>.Instance.FreezeDuration; public override float Cooldown => OptionGroupSingleton<FreezerRoleSettings>.Instance.FreezeDuration;
public override bool PauseTimerInVent => true; public override bool PauseTimerInVent => true;
+6 -4
View File
@@ -9,8 +9,10 @@ namespace MiraAPI.Example.Buttons;
public class MeetingButton : CustomActionButton public class MeetingButton : CustomActionButton
{ {
public override string Name => "button.callMeeting"; public override string Name => "Call Meeting";
public override float Cooldown => 15; public override float Cooldown => 15;
public override int MaxUses => 3; public override int MaxUses => 3;
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton; public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
@@ -28,10 +30,10 @@ public class MeetingButton : CustomActionButton
PlayerControl.LocalPlayer.NetTransform.Halt(); PlayerControl.LocalPlayer.NetTransform.Halt();
var minigame = Object.Instantiate(bt.MinigamePrefab, Camera.main!.transform, false); var minigame = Object.Instantiate(bt.MinigamePrefab, Camera.main!.transform, false);
var taskAdderGame = minigame.TryCast<TaskAdderGame>(); var taskAdderGame = minigame as TaskAdderGame;
if (taskAdderGame) if (taskAdderGame != null)
{ {
taskAdderGame!.SafePositionWorld = bt.SafePositionLocal + (Vector2)bt.transform.position; taskAdderGame.SafePositionWorld = bt.SafePositionLocal + (Vector2)bt.transform.position;
} }
minigame.transform.localPosition = new Vector3(0f, 0f, -50f); minigame.transform.localPosition = new Vector3(0f, 0f, -50f);
@@ -10,7 +10,7 @@ namespace MiraAPI.Example.Buttons;
public class NeutralKillerButton : CustomActionButton public class NeutralKillerButton : CustomActionButton
{ {
public override string Name => "button.winGame"; public override string Name => "Win Game";
public override float Cooldown => 0f; public override float Cooldown => 0f;
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton; public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
public override MiraKeybind Keybind => ExampleKeybinds.NeutralWinKeybind; public override MiraKeybind Keybind => ExampleKeybinds.NeutralWinKeybind;
@@ -12,7 +12,7 @@ namespace MiraAPI.Example.Buttons.Teleporter;
public class TeleportButton : CustomActionButton public class TeleportButton : CustomActionButton
{ {
public override string Name => "button.teleport"; public override string Name => "Teleport";
public override float Cooldown => OptionGroupSingleton<TeleporterOptions>.Instance.TeleportCooldown.Value; public override float Cooldown => OptionGroupSingleton<TeleporterOptions>.Instance.TeleportCooldown.Value;
@@ -61,14 +61,11 @@ public class TeleportButton : CustomActionButton
{ {
Camera.main.orthographicSize = MeetingHud.Instance ? 3f : ft; Camera.main.orthographicSize = MeetingHud.Instance ? 3f : ft;
ResolutionManager.ResolutionChanged.Invoke((float)Screen.width / Screen.height, Screen.width, Screen.height, Screen.fullScreen); ResolutionManager.ResolutionChanged.Invoke((float)Screen.width / Screen.height, Screen.width, Screen.height, Screen.fullScreen);
foreach (var cam in Camera.allCameras) foreach (var cam in Camera.allCameras) cam.orthographicSize = Camera.main.orthographicSize;
cam.orthographicSize = Camera.main.orthographicSize;
yield return null; yield return null;
} }
foreach (var cam in Camera.allCameras) foreach (var cam in Camera.allCameras) cam.orthographicSize = zoomDistance;
cam.orthographicSize = zoomDistance;
ResolutionManager.ResolutionChanged.Invoke((float)Screen.width / Screen.height, Screen.width, Screen.height, Screen.fullScreen); ResolutionManager.ResolutionChanged.Invoke((float)Screen.width / Screen.height, Screen.width, Screen.height, Screen.fullScreen);
} }
@@ -78,14 +75,12 @@ public class TeleportButton : CustomActionButton
{ {
Camera.main.orthographicSize = MeetingHud.Instance ? 3f : ft; Camera.main.orthographicSize = MeetingHud.Instance ? 3f : ft;
ResolutionManager.ResolutionChanged.Invoke((float)Screen.width / Screen.height, Screen.width, Screen.height, Screen.fullScreen); ResolutionManager.ResolutionChanged.Invoke((float)Screen.width / Screen.height, Screen.width, Screen.height, Screen.fullScreen);
foreach (var cam in Camera.allCameras) foreach (var cam in Camera.allCameras) cam.orthographicSize = Camera.main.orthographicSize;
cam.orthographicSize = Camera.main.orthographicSize;
yield return null; yield return null;
} }
foreach (var cam in Camera.allCameras) foreach (var cam in Camera.allCameras) cam.orthographicSize = 3f;
cam.orthographicSize = 3f;
HudManager.Instance.ShadowQuad.gameObject.SetActive(true); HudManager.Instance.ShadowQuad.gameObject.SetActive(true);
IsZoom = false; IsZoom = false;
+4 -7
View File
@@ -1,6 +1,4 @@
using MiraAPI.Hud; using MiraAPI.Hud;
using MiraAPI.Keybinds;
using MiraAPI.Translation;
using MiraAPI.Utilities.Assets; using MiraAPI.Utilities.Assets;
using UnityEngine; using UnityEngine;
@@ -8,22 +6,21 @@ namespace MiraAPI.Example.Buttons;
public class ThinkButton : CustomActionButton public class ThinkButton : CustomActionButton
{ {
public override string Name => "button.think"; public override string Name => "Think";
public override float Cooldown => 15f; public override float Cooldown => 15f;
public override float EffectDuration => 10f; public override float EffectDuration => 10f;
public override int MaxUses => 1; public override int MaxUses => 1;
public override ButtonUsesMode UsesMode => ButtonUsesMode.PerRound; public override ButtonUsesMode UsesMode => ButtonUsesMode.PerRound;
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton; public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
public override MiraKeybind Keybind => MiraGlobalKeybinds.SecondaryAbility;
protected override void OnClick() protected override void OnClick()
{ {
Button!.OverrideText("button.think.thinking".Translate()); // This button does absolutely nothing besides changing its text
Button!.OverrideText("Thinking...");
} }
public override void OnEffectEnd() public override void OnEffectEnd()
{ {
Button!.OverrideText("button.think".Translate()); Button!.OverrideText("Think");
} }
public override bool IsEffectCancellable() public override bool IsEffectCancellable()
-1
View File
@@ -9,6 +9,5 @@ public static class ExampleAssets
// Credit to EpicHorrors for the teleport button asset. // Credit to EpicHorrors for the teleport button asset.
public static LoadableResourceAsset TeleportButton { get; } = new("MiraAPI.Example.Resources.TeleportButton.png"); public static LoadableResourceAsset TeleportButton { get; } = new("MiraAPI.Example.Resources.TeleportButton.png");
public static LoadableResourceAsset SharpshootButton { get; } = new("MiraAPI.Example.Resources.SharpshootButton.png");
public static LoadableResourceAsset Banner { get; } = new("MiraAPI.Example.Resources.FortniteBanner.jpeg"); public static LoadableResourceAsset Banner { get; } = new("MiraAPI.Example.Resources.FortniteBanner.jpeg");
} }
+3 -10
View File
@@ -1,6 +1,4 @@
using MiraAPI.Colors; using MiraAPI.Colors;
using MiraAPI.Colors.ColorSpaces;
using MiraAPI.Utilities;
using UnityEngine; using UnityEngine;
namespace MiraAPI.Example; namespace MiraAPI.Example;
@@ -8,17 +6,12 @@ namespace MiraAPI.Example;
[RegisterCustomColors] [RegisterCustomColors]
public static class ExampleColors public static class ExampleColors
{ {
public static CustomColor Cerulean { get; } = new("color.cerulean", new Color(0.0f, 0.48f, 0.65f)) public static CustomColor Cerulean { get; } = new("Cerulean", new Color(0.0f, 0.48f, 0.65f))
{ {
ColorBrightness = CustomColorBrightness.Lighter, ColorBrightness = CustomColorBrightness.Lighter,
}; };
public static CustomColor Rose { get; } = new("color.rose", new Color(0.98f, 0.26f, 0.62f)); public static CustomColor Rose { get; } = new("Rose", new Color(0.98f, 0.26f, 0.62f));
public static CustomColor Gold { get; } = new("color.gold", new Color(1.0f, 0.84f, 0.0f)); public static CustomColor Gold { get; } = new("Gold", new Color(1.0f, 0.84f, 0.0f));
public static VariableColor Rainbow { get; } = new("color.rainbow", t => new HsbColor(MathUtilities.PingPong(t, 1f, 0.3f), 1f, 1f))
{
ColorBrightness = CustomColorBrightness.Lighter,
};
} }
+2 -18
View File
@@ -1,5 +1,4 @@
using System.Globalization; using System.Linq;
using System.Linq;
using MiraAPI.Events; using MiraAPI.Events;
using MiraAPI.Events.Mira; using MiraAPI.Events.Mira;
using MiraAPI.Events.Vanilla.Gameplay; using MiraAPI.Events.Vanilla.Gameplay;
@@ -18,7 +17,7 @@ public static class ExampleEventHandlers
{ {
public static void Initialize() public static void Initialize()
{ {
// You can register event handlers with the MiraEventManager class // You can register event handlers with the MiraEventManager class.
var handle = MiraEventManager.RegisterEventHandler<BeforeMurderEvent>(@event => var handle = MiraEventManager.RegisterEventHandler<BeforeMurderEvent>(@event =>
{ {
Logger<ExamplePlugin>.Info($"{@event.Source.Data.PlayerName} is about to kill {@event.Target.Data.PlayerName}"); Logger<ExamplePlugin>.Info($"{@event.Source.Data.PlayerName} is about to kill {@event.Target.Data.PlayerName}");
@@ -38,21 +37,6 @@ public static class ExampleEventHandlers
MiraEventManager.UnregisterEventHandler(handle); MiraEventManager.UnregisterEventHandler(handle);
} }
// If you want to check vanilla buttons, use something like this!
[RegisterEvent]
public static void VanillaButtonClickHandler(VanillaButtonClickEvent @event)
{
Logger<ExamplePlugin>.Info($"{@event.Button.buttonLabelText.text} is being used!");
if (@event.PlayerTarget != null)
{
Logger<ExamplePlugin>.Info($"{@event.PlayerTarget.Data.PlayerName} is being targeted!");
}
else if (@event.VentTarget != null)
{
Logger<ExamplePlugin>.Info($"Vent with id {@event.VentTarget.Id.ToString(CultureInfo.InvariantCulture)} is being targeted!");
}
}
// If you want to add extra votes to a player, do something like this. // If you want to add extra votes to a player, do something like this.
[RegisterEvent] [RegisterEvent]
public static void StartMeetingEvent(StartMeetingEvent _) public static void StartMeetingEvent(StartMeetingEvent _)
+2 -2
View File
@@ -1,4 +1,4 @@
using MiraAPI.Keybinds; using MiraAPI.Keybinds;
using Rewired; using Rewired;
namespace MiraAPI.Example; namespace MiraAPI.Example;
@@ -6,5 +6,5 @@ namespace MiraAPI.Example;
[RegisterCustomKeybinds] [RegisterCustomKeybinds]
public static class ExampleKeybinds public static class ExampleKeybinds
{ {
public static MiraKeybind NeutralWinKeybind { get; } = new("Neutral Win", KeyboardKeyCode.C, ControllerButton.RightStick, [ModifierKey.Shift]); public static MiraKeybind NeutralWinKeybind { get; } = new("Neutral Win", KeyboardKeyCode.C, [ModifierKey.Shift]);
} }
+3 -3
View File
@@ -8,7 +8,7 @@ namespace MiraAPI.Example;
public class ExampleLocalSettings(ConfigFile config) : LocalSettingsTab(config) public class ExampleLocalSettings(ConfigFile config) : LocalSettingsTab(config)
{ {
public override string TabName => "settings.miraExample"; public override string TabName => "Mira Example";
protected override bool ShouldCreateLabels => false; protected override bool ShouldCreateLabels => false;
public override LocalSettingTabAppearance TabAppearance => new() public override LocalSettingTabAppearance TabAppearance => new()
@@ -18,7 +18,7 @@ public class ExampleLocalSettings(ConfigFile config) : LocalSettingsTab(config)
}; };
[LocalSettingsButton] [LocalSettingsButton]
public LocalSettingsButton ExampleButton { get; private set; } = new("settings.miraExample.button.exampleButton", OnExampleButtonClick); public LocalSettingsButton ExampleButton { get; private set; } = new("Example Button", OnExampleButtonClick);
[LocalToggleSetting] [LocalToggleSetting]
public ConfigEntry<bool> ExampleToggle { get; private set; } = config.Bind("General", "Example Bool", true); public ConfigEntry<bool> ExampleToggle { get; private set; } = config.Bind("General", "Example Bool", true);
@@ -33,7 +33,7 @@ public class ExampleLocalSettings(ConfigFile config) : LocalSettingsTab(config)
public ConfigEntry<float> ExampleNumber { get; private set; } = config.Bind("General", "Example Number", 4f); public ConfigEntry<float> ExampleNumber { get; private set; } = config.Bind("General", "Example Number", 4f);
[LocalNumberSetting(min: 0.1f, max: 2.5f, increment: 0.1f, formatString: "0.0", suffixType: MiraNumberSuffixes.Multiplier)] [LocalNumberSetting(min: 0.1f, max: 2.5f, increment: 0.1f, formatString: "0.0", suffixType: MiraNumberSuffixes.Multiplier)]
public ConfigEntry<float> ExampleFloatNumber { get; private set; } = config.Bind("General", "Example Multiplier", 1f); public ConfigEntry<float> ExampleFloatNumber { get; private set; } = config.Bind("General", "Example Multplier", 1f);
[LocalEnumSetting] [LocalEnumSetting]
public ConfigEntry<ExampleEnumSetting> ExampleEnum { get; private set; } = config.Bind("General", "Example Enum", ExampleEnumSetting.Fries); public ConfigEntry<ExampleEnumSetting> ExampleEnum { get; private set; } = config.Bind("General", "Example Enum", ExampleEnumSetting.Fries);
+4 -15
View File
@@ -1,9 +1,9 @@
using BepInEx; using System.Linq;
using BepInEx;
using BepInEx.Configuration; using BepInEx.Configuration;
using BepInEx.Unity.IL2CPP; using BepInEx.Unity.IL2CPP;
using HarmonyLib; using HarmonyLib;
using MiraAPI.PluginLoading; using MiraAPI.PluginLoading;
using MiraAPI.Translation;
using Reactor; using Reactor;
using Reactor.Networking; using Reactor.Networking;
using Reactor.Networking.Attributes; using Reactor.Networking.Attributes;
@@ -17,20 +17,9 @@ namespace MiraAPI.Example;
[ReactorModFlags(ModFlags.RequireOnAllClients)] [ReactorModFlags(ModFlags.RequireOnAllClients)]
public partial class ExamplePlugin : BasePlugin, IMiraPlugin public partial class ExamplePlugin : BasePlugin, IMiraPlugin
{ {
public ExamplePlugin()
{
MiraLocaleManager.Register("mira.example");
}
public Harmony Harmony { get; } = new(Id); public Harmony Harmony { get; } = new(Id);
public string OptionsTitleText { get; } = "Mira API\nExample Mod"; public string OptionsTitleText => "Mira API\nExample Mod";
public string CustomOptionMenuNameTwo { get; } = "Example Options"; public ConfigFile GetConfigFile() => Config;
public ConfigFile GetConfigFile()
{
return Config;
}
public override void Load() public override void Load()
{ {
ExampleEventHandlers.Initialize(); ExampleEventHandlers.Initialize();
-13
View File
@@ -1,13 +0,0 @@
using MiraAPI.GameModes;
using MiraAPI.Utilities.Assets;
using UnityEngine;
namespace MiraAPI.Example.GameModes;
public class ExampleMode : AbstractGameMode
{
public override string Name => "Example Mode";
public override string Description => "An example gamemode.";
public override LoadableAsset<Sprite>? Icon => ExampleAssets.ExampleButton;
public override Color Color => Color.red;
}
@@ -1,6 +1,5 @@
using MiraAPI.Example.Roles; using MiraAPI.Example.Roles;
using MiraAPI.GameEnd; using MiraAPI.GameEnd;
using MiraAPI.Translation;
using MiraAPI.Utilities; using MiraAPI.Utilities;
using UnityEngine; using UnityEngine;
@@ -15,7 +14,7 @@ public class NeutralKillerGameOver : CustomGameOver
public override void AfterEndGameSetup(EndGameManager endGameManager) public override void AfterEndGameSetup(EndGameManager endGameManager)
{ {
endGameManager.WinText.text = "gameover.outcastKiller.win".Translate(); endGameManager.WinText.text = "Outcast Killer Wins!";
endGameManager.WinText.color = Color.magenta; endGameManager.WinText.color = Color.magenta;
endGameManager.BackgroundBar.material.SetColor(ShaderID.Color, Color.magenta); endGameManager.BackgroundBar.material.SetColor(ShaderID.Color, Color.magenta);
} }
@@ -1,29 +0,0 @@
using MiraAPI.Example.Roles;
using MiraAPI.MeetingAbilities;
using MiraAPI.Utilities.Assets;
using UnityEngine;
namespace MiraAPI.Example.MeetingAbilities;
public class EndMeetingButton : MeetingActionButton
{
public override string Name => "End Meeting";
public override float Cooldown => 15;
public override float InitialCooldown => 30;
public override int MaxUses => 3;
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
public override bool Enabled(RoleBehaviour? role)
{
return PlayerControl.LocalPlayer != null && role is MayorRole;
}
protected override void OnClick()
{
MeetingHud.Instance.RpcClose();
}
}
@@ -1,37 +0,0 @@
using MiraAPI.MeetingAbilities;
using MiraAPI.Networking;
using MiraAPI.Utilities;
using MiraAPI.Utilities.Assets;
using UnityEngine;
namespace MiraAPI.Example.MeetingAbilities;
public class ShootButton : TargetedMeetingButton
{
public override string Name => "Shoot";
public override int MaxUses => 3;
public override float InitialCooldown => 5;
public override float Cooldown => 3;
public override LoadableAsset<Sprite> Sprite => ExampleAssets.SharpshootButton;
public override Color OutlineColor => Color.red;
public override bool Enabled(RoleBehaviour r)
{
return r.IsImpostor;
}
protected override void OnClick(PlayerVoteArea playerVoteArea)
{
playerVoteArea.SetDisabled();
var player = playerVoteArea.GetPlayer();
if (player != null)
{
PlayerControl.LocalPlayer.RpcCustomMurder(player);
}
}
}
@@ -1,54 +0,0 @@
using MiraAPI.MeetingAbilities;
using MiraAPI.Networking;
using MiraAPI.Utilities;
using MiraAPI.Utilities.Assets;
using UnityEngine;
namespace MiraAPI.Example.MeetingAbilities;
public class ShotgunButton : MultiTargetMeetingButton
{
public override string Name => "Shotgun";
public override int MaxUses => 3;
public override float InitialCooldown => 5;
public override float Cooldown => 3;
public override LoadableAsset<Sprite> Sprite => ExampleAssets.SharpshootButton;
public override Color OutlineColor => Color.red;
public override bool Enabled(RoleBehaviour r)
{
return r.IsImpostor;
}
protected override void OnClick(PlayerVoteArea playerVoteArea)
{
// Emptu because it only triggers the actual kills once all meeting abilities have been used.
}
public override LoadableAsset<Sprite> SpriteActive => ExampleAssets.CallMeetingButton;
public override int TargetsCount => 4;
protected override void OnSelect(PlayerVoteArea playerVoteArea, bool toggle)
{
HudManager.Instance.PlayerCam.ShakeScreen(0.5f, 2);
}
public override void OnFinish()
{
foreach (var playerVoteArea in Targets.Keys)
{
playerVoteArea.SetDisabled();
var player = playerVoteArea.GetPlayer();
if (player != null)
{
PlayerControl.LocalPlayer.RpcCustomMurder(player);
}
}
}
}
+6 -7
View File
@@ -1,18 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<Version>1.0.0</Version> <Version>1.0.0</Version>
<Description>Example mod for Mira API</Description> <Description>Example mod for Mira API</Description>
<Authors>Author Name</Authors> <Authors>Angxl, XtraCube</Authors>
<NoWarn>$(NoWarn);EnableGenerateDocumentationFile</NoWarn>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\MiraAPI\MiraAPI.csproj" /> <!-- You typically would use the nuget package here: AllOfUs.MiraAPI --> <ProjectReference Include="..\MiraAPI\MiraAPI.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Resources\**\*.*" /> <EmbeddedResource Include="Resources\**\*.*" />
</ItemGroup> </ItemGroup>
<Import Project="..\AmongUs.props" /> <Import Project="..\AmongUs.props" />
</Project> </Project>
+2 -3
View File
@@ -2,7 +2,6 @@
using MiraAPI.GameOptions; using MiraAPI.GameOptions;
using MiraAPI.Modifiers; using MiraAPI.Modifiers;
using MiraAPI.Modifiers.Types; using MiraAPI.Modifiers.Types;
using MiraAPI.Translation;
using MiraAPI.Utilities.Assets; using MiraAPI.Utilities.Assets;
using UnityEngine; using UnityEngine;
@@ -10,7 +9,7 @@ namespace MiraAPI.Example.Modifiers;
public class CaptainModifier : GameModifier public class CaptainModifier : GameModifier
{ {
public override string ModifierName => MiraLocaleManager.Get("modifier.captain"); public override string ModifierName => "Captain";
public override LoadableAsset<Sprite>? ModifierIcon => ExampleAssets.CallMeetingButton; public override LoadableAsset<Sprite>? ModifierIcon => ExampleAssets.CallMeetingButton;
public override void OnDeath(DeathReason reason) public override void OnDeath(DeathReason reason)
@@ -20,7 +19,7 @@ public class CaptainModifier : GameModifier
public override string GetDescription() public override string GetDescription()
{ {
return MiraLocaleManager.Get("modifier.captain.TabDescription"); return $"You can call a meeting from anywhere on the map.";
} }
public override int GetAssignmentChance() public override int GetAssignmentChance()
@@ -1,13 +1,13 @@
using MiraAPI.Example.Roles; using Il2CppSystem;
using MiraAPI.Example.Roles;
using MiraAPI.Modifiers.Types; using MiraAPI.Modifiers.Types;
using MiraAPI.Translation;
using UnityEngine; using UnityEngine;
namespace MiraAPI.Example.Modifiers.Freezer; namespace MiraAPI.Example.Modifiers.Freezer;
public class FreezeModifier : TimedModifier public class FreezeModifier : TimedModifier
{ {
public override string ModifierName => MiraLocaleManager.Get("modifier.freezed"); public override string ModifierName => "Freezed";
public override bool HideOnUi => false; public override bool HideOnUi => false;
public override float Duration => 15f; public override float Duration => 15f;
public override bool AutoStart => true; public override bool AutoStart => true;
@@ -27,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 Il2CppSystem.Nullable<Color>(Palette.LightBlue)); Player.cosmetics.SetOutline(true, new Nullable<Color>(Palette.LightBlue));
} }
} }
@@ -1,15 +1,14 @@
using MiraAPI.Modifiers.Types; using MiraAPI.Modifiers.Types;
using MiraAPI.Translation;
namespace MiraAPI.Example.Modifiers; namespace MiraAPI.Example.Modifiers;
public class HighPriorityModifier : GameModifier public class HighPriorityModifier : GameModifier
{ {
public override string ModifierName => MiraLocaleManager.Get("modifier.highPriority"); public override string ModifierName => "High Priority";
public override string GetDescription() public override string GetDescription()
{ {
return MiraLocaleManager.Get("modifier.highPriority.TabDescription"); return "You are high priority! Idrk what this means either tbh...";
} }
public override int GetAssignmentChance() public override int GetAssignmentChance()
+9 -66
View File
@@ -1,88 +1,31 @@
using System.Diagnostics.CodeAnalysis; using MiraAPI.GameOptions;
using MiraAPI.GameOptions;
using MiraAPI.GameOptions.Attributes; using MiraAPI.GameOptions.Attributes;
using MiraAPI.Utilities; using MiraAPI.Utilities;
using UnityEngine; using UnityEngine;
namespace MiraAPI.Example.Options; namespace MiraAPI.Example.Options;
[SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Demo.")]
[SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Read above.")]
[SuppressMessage("Minor Code Smell", "S3400:Methods should not return constants", Justification = "Read above.")]
public class ExampleOptions : AbstractOptionGroup public class ExampleOptions : AbstractOptionGroup
{ {
public override string GroupName => "options.exampleOptions1"; public override string GroupName => "Example Options 1";
public override Color GroupColor => Color.green; public override Color GroupColor => Color.green;
public override bool ShowInMatchInfoGuide => true;
[ModdedToggleOption("options.exampleOptions1.toggleOpt1")] [ModdedToggleOption("Toggle Opt 1")]
[ModdedOptionVisibility] // Automatically resolves to using ToggleOpt1Visibility, can also target toggle options public bool ToggleOpt { get; set; } = false;
public bool ToggleOpt1 { get; set; } = false;
[ModdedToggleOption("options.exampleOptions1.toggleOpt2")] [ModdedToggleOption("Toggle Opt 2")]
[ModdedOptionVisibility(nameof(ToggleOpt1))] // ToggleOpt2 will be visible only when ToggleOpt1 is true
public bool ToggleOpt2 { get; set; } = true; public bool ToggleOpt2 { get; set; } = true;
[ModdedNumberOption("options.exampleOptions1.numberOpt", min: 0, max: 10, increment: .25f, formatString: "0.00", suffixType: MiraNumberSuffixes.Percent)] [ModdedNumberOption("Number Opt", min: 0, max: 10, increment: .25f, formatString: "0.00", suffixType: MiraNumberSuffixes.Percent)]
[ModdedOptionVisibility(nameof(NumberOptVisibility))] // Can also target static methods
public float NumberOpt { get; set; } = 4f; public float NumberOpt { get; set; } = 4f;
[ModdedNumberOption("options.exampleOptions1.numberOpt", min: 0, max: 10, suffixType: MiraNumberSuffixes.Distance)] [ModdedEnumOption("Best API", typeof(BestApi), ["Mira API", "Mitochondria", "Reactor"])]
public int NumberOpt2 { get; set; } = 4; // Can also be int! public BestApi Opt { get; set; } = BestApi.MiraAPI;
[ModdedEnumOption("options.exampleOptions1.bestApi", typeof(Api), ["Mira API", "Mitochondria", "Reactor"])]
public Api BestApi { get; set; } = Api.MiraAPI;
[ModdedEnumOption<Api>("options.exampleOptions1.worstApi", ["Mira API", "Mitochondria", "Reactor"])]
// These three can target both instance and static methods
[ModdedOptionGetter(nameof(GetApi))] // Can also automatically resolve to {Option Name}Getter
[ModdedOptionSetter(nameof(SetApi))] // Can also automatically resolve to {Option Name}Setter
[ModdedOptionChanged(nameof(ApiChanged))] // Can also automatically resolve to {Option Name}Changed
public Api WorstApi { get; set; } = Api.MiraAPI;
[ModdedEnumOptionList<ValueState>("Value State {0}", ["None", "Primary", "Secondary"])]
public ModdedArray<ValueState> ValueStates { get; set; } = [ValueState.Primary, ValueState.Secondary, ValueState.None, ValueState.None, ValueState.None];
[ModdedPlayerOption("options.exampleOptions1.players")]
public NetworkedPlayerInfo PlayerSelected { get; set; }
public bool ToggleOpt1Visibility()
{
return true;
}
public static bool NumberOptVisibility()
{
return true;
}
public static Api GetApi(Api currentValue)
{
return currentValue;
}
public static Api SetApi(Api newValue, Api oldValue)
{
return default;
}
public static void ApiChanged(Api currentValue)
{
// Something
}
} }
public enum Api public enum BestApi
{ {
MiraAPI, MiraAPI,
Mitochondria, Mitochondria,
Reactor, Reactor,
} }
public enum ValueState
{
None,
Primary,
Secondary,
}
+7 -13
View File
@@ -6,28 +6,22 @@ namespace MiraAPI.Example.Options;
public class ExampleOptions2 : AbstractOptionGroup public class ExampleOptions2 : AbstractOptionGroup
{ {
public override string GroupName => "options.exampleOptions2"; public override string GroupName => "Example Options 2";
public override uint GroupPriority => 0; // This group will be displayed first. The default value is uint.MaxValue. public override uint GroupPriority => 0; // This group will be displayed first. The default value is uint.MaxValue.
public override MenuCategory ParentMenu => MenuCategory.CustomTwo;
public override bool ShowInMatchInfoGuide => true;
public ModdedPlayerOption PlayerOption2 { get; } = new("options.exampleOptions2.youMustChoseAPlayer", false); public ModdedPlayerOption PlayerOption2 { get; } = new("YOU MUST CHOSE A PLAYER", false);
public ModdedPlayerOption PlayerOption { get; } = new("options.exampleOptions2.ehWhatever"); public ModdedPlayerOption PlayerOption { get; } = new("Eh whatever");
public ModdedToggleOption ToggleOpt1 { get; } = new("options.exampleOptions2.toggleOption1", false); public ModdedToggleOption ToggleOpt1 { get; } = new("Toggle Option 1", false);
public ModdedOptionList<ModdedNumberOption> PlayerNums { get; } = new(5, i => public ModdedToggleOption ToggleOpt2 { get; } = new("Toggle Option 2", false)
new($"PlayerNum{i}", 2, 0, 5, 1, Utilities.MiraNumberSuffixes.None));
public ModdedToggleOption ToggleOpt2 { get; } = new("options.exampleOptions2.toggleOption2", false)
{ {
Visible = () => OptionGroupSingleton<ExampleOptions2>.Instance.ToggleOpt1, // implicit cast from ModdedToggleOption to bool Visible = () => OptionGroupSingleton<ExampleOptions2>.Instance.ToggleOpt1, // implicit cast from ModdedToggleOption to bool
}; };
public ModdedEnumOption<TestingData> EnumOpt { get; } = new("options.exampleOptions2.enumOpt", 0) public ModdedEnumOption<TestingData> EnumOpt { get; } = new("Enum Opt", 0)
{ {
ChangedEvent = x => Logger<ExamplePlugin>.Info($"changed Enum Opt to {x}"), ChangedEvent = x => Logger<ExamplePlugin>.Info($"changed Enum Opt to {x}"),
Getter = currentValue => currentValue,
Setter = (newValue, oldValue) => newValue,
}; };
} }
@@ -6,14 +6,14 @@ namespace MiraAPI.Example.Options.Modifiers;
public class CaptainModifierSettings : AbstractOptionGroup<CaptainModifier> public class CaptainModifierSettings : AbstractOptionGroup<CaptainModifier>
{ {
public override string GroupName => "options.captainSettings"; public override string GroupName => "Captain Settings";
[ModdedNumberOption("options.captainSettings.amount", 0, 5)] [ModdedNumberOption("Amount", 0, 5)]
public float Amount { get; set; } = 1; public float Amount { get; set; } = 1;
[ModdedNumberOption("options.captainSettings.chance", 0, 100, 10)] [ModdedNumberOption("Chance", 0, 100, 10)]
public float Chance { get; set; } = 50; public float Chance { get; set; } = 50;
[ModdedNumberOption("options.captainSettings.uses", 1, 5)] [ModdedNumberOption("Uses", 1, 5)]
public float NumUses { get; set; } = 3; public float NumUses { get; set; } = 3;
} }
@@ -6,8 +6,8 @@ namespace MiraAPI.Example.Options.Modifiers;
public class FreezeModifierSettings : AbstractOptionGroup<FreezeModifier> public class FreezeModifierSettings : AbstractOptionGroup<FreezeModifier>
{ {
public override string GroupName => "options.freezeModifierSettings"; public override string GroupName => "Freeze";
[ModdedToggleOption("options.freezeModifierSettings.useColor")] [ModdedToggleOption("Use Color")]
public bool UseColor { get; set; } = true; public bool UseColor { get; set; } = true;
} }
@@ -5,13 +5,15 @@ namespace MiraAPI.Example.Options.Modifiers;
public class GeneralModifierOptions : AbstractOptionGroup public class GeneralModifierOptions : AbstractOptionGroup
{ {
public override string GroupName => "options.generalModifier"; public override string GroupName => "General";
public override uint GroupPriority => 0;
public override MenuCategory ParentMenu => MenuCategory.Modifiers;
[ModdedToggleOption("options.generalModifier.someBooleanOption")] public override uint GroupPriority => 0;
public override bool ShowInModifiersMenu => true;
[ModdedToggleOption("Some Boolean Option")]
public bool SomeBooleanOption { get; set; } = true; public bool SomeBooleanOption { get; set; } = true;
[ModdedNumberOption("options.generalModifier.numberOption", 0, 10)] [ModdedNumberOption("Number Option", 0, 10, 1)]
public float NumberOption { get; set; } = 5; public float NumberOption { get; set; } = 5;
} }
@@ -2,22 +2,16 @@
using MiraAPI.GameOptions; using MiraAPI.GameOptions;
using MiraAPI.GameOptions.Attributes; using MiraAPI.GameOptions.Attributes;
using MiraAPI.Utilities; using MiraAPI.Utilities;
using MiraAPI.Utilities.Assets;
namespace MiraAPI.Example.Options.Roles; namespace MiraAPI.Example.Options.Roles;
public class FreezerRoleSettings : AbstractOptionGroup<FreezerRole> public class FreezerRoleSettings : AbstractOptionGroup<FreezerRole>
{ {
public override OptionNotifConfiguration Configuration => new( public override string GroupName => "Custom Role";
Palette.Blue,
TmpSpriteUtils.CreateSpriteAsset(
MiraAssets.ImpostorFile.LoadAsset(),
"ApiExample.Role.Impostor.FreezerRole"));
public override string GroupName => "ApiExample.Role.Freezer";
[ModdedNumberOption("ApiExample.Role.Freezer.Settings.FreezeDuration", 1, 15, 1, MiraNumberSuffixes.Seconds)] [ModdedNumberOption("Freeze Duration", 1, 15, 1, MiraNumberSuffixes.Seconds)]
public float FreezeDuration { get; set; } = 5; public float FreezeDuration { get; set; } = 5;
[ModdedNumberOption("ApiExample.Role.Freezer.Settings.FreezeUses", 1, 5)] [ModdedNumberOption("Freeze Uses", 1, 5)]
public float FreezeUses { get; set; } = 1; public float FreezeUses { get; set; } = 1;
} }
@@ -6,15 +6,15 @@ using MiraAPI.Utilities;
namespace MiraAPI.Example.Options.Roles; namespace MiraAPI.Example.Options.Roles;
public class TeleporterOptions : AbstractRoleOptionGroup<TeleporterRole> public class TeleporterOptions : AbstractOptionGroup<TeleporterRole>
{ {
public override string GroupName => "ApiExample.Role.Teleporter"; public override string GroupName => "Teleporter";
public ModdedNumberOption TeleportCooldown { get; set; } = new("ApiExample.Role.Teleporter.Settings.TeleportCooldown", 10, 5, 60, 2.5f, MiraNumberSuffixes.Seconds); public ModdedNumberOption TeleportCooldown { get; set; } = new("Teleport Cooldown", 10, 5, 60, 2.5f, MiraNumberSuffixes.Seconds);
[ModdedNumberOption("ApiExample.Role.Teleporter.Settings.TeleportDuration", 5, 25, 1, MiraNumberSuffixes.Seconds)] [ModdedNumberOption("Teleport Duration", 5, 25, 1, MiraNumberSuffixes.Seconds)]
public float TeleportDuration { get; set; } = 10; public float TeleportDuration { get; set; } = 10;
[ModdedNumberOption("ApiExample.Role.Teleporter.Settings.ZoomDistance", 4, 15)] [ModdedNumberOption("Zoom Distance", 4, 15)]
public float ZoomDistance { get; set; } = 6; public float ZoomDistance { get; set; } = 6;
} }
@@ -1,86 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="ApiExample.Role.Crewmate.Teleporter">Teleporter</string>
<string name="ApiExample.Role.Crewmate.Teleporter.IntroBlurb">Zoom out and teleport across the map!</string>
<string name="ApiExample.Role.Crewmate.Teleporter.MedDescription">Zoom out and teleport across the map!</string>
<string name="ApiExample.Role.Crewmate.Teleporter.TabDescription">Zoom out and teleport across the map!</string>
<string name="ApiExample.Role.Crewmate.Teleporter.WikiDescription">The Teleporter is a Crewmate role that can move around the map using their dope-ass ability.</string>
<string name="ApiExample.Role.Impostor.Freezer">Freezer</string>
<string name="ApiExample.Role.Impostor.Freezer.IntroBlurb">Get iced, nerd.</string>
<string name="ApiExample.Role.Impostor.Freezer.MedDescription">Freeze others for a duration of time.</string>
<string name="ApiExample.Role.Impostor.Freezer.TabDescription">Freeze another player for a duration of time.</string>
<string name="ApiExample.Role.Impostor.Freezer.WikiDescription">The Freezer is an Impostor role that can freeze players. Or something along those lines.</string>
<string name="ApiExample.Role.Crewmate.Mayor">Mayor</string>
<string name="ApiExample.Role.Crewmate.Mayor.IntroBlurb">Democracy is the best policy.</string>
<string name="ApiExample.Role.Crewmate.Mayor.MedDescription">Vote out the Impostors with more votes.
Your votes have double the power.</string>
<string name="ApiExample.Role.Crewmate.Mayor.TabDescription">You get one extra vote in the meeting!</string>
<string name="ApiExample.Role.Crewmate.Mayor.WikiDescription">The Mayor is a Crewmate role that gets two votes in the meeting, instead of the singular vote other Crewmates get.</string>
<string name="ApiExample.Role.Crewmate.Chameleon">Chameleon</string>
<string name="ApiExample.Role.Crewmate.Chameleon.IntroBlurb">Become one with the environment.</string>
<string name="ApiExample.Role.Crewmate.Chameleon.MedDescription">Fade out of everyone's vision by not moving.</string>
<string name="ApiExample.Role.Crewmate.Chameleon.TabDescription">Stay invisible while not moving.</string>
<string name="ApiExample.Role.Crewmate.Chameleon.WikiDescription">The Chameleon is a Crewmate role that slowly becomes invisible while standing still.</string>
<string name="ApiExample.Role.Outcast.OutcastKiller">Outcast Killer</string>
<string name="ApiExample.Role.Outcast.OutcastKiller.IntroBlurb">Kill everyone else.</string>
<string name="ApiExample.Role.Outcast.OutcastKiller.MedDescription">Be the last outcast standing.
Eliminate every other faction.</string>
<string name="ApiExample.Role.Outcast.OutcastKiller.TabDescription">Outcast who can kill.</string>
<string name="ApiExample.Role.Outcast.OutcastKiller.WikiDescription">The Outcast Killer is an Outcast role that can kill, like some sort of neutral killer...</string>
<string name="outcast">Outcast</string>
<string name="outcast.group">Outcast Roles</string>
<string name="outcast.roleTitle">OUTCAST</string>
<string name="outcast.teamIntroDescription">You are an Outcast. You do not have a team.</string>
<string name="button.think">Think</string>
<string name="button.think.thinking">Thinking...</string>
<string name="button.freeze">Freeze</string>
<string name="button.teleport">Teleport</string>
<string name="button.callMeeting">Call Meeting</string>
<string name="button.winGame">Win Game</string>
<string name="modifier.captain">Captain</string>
<string name="modifier.captain.TabDescription">You can call a meeting from anywhere on the map.</string>
<string name="modifier.freezed">Freezed</string>
<string name="modifier.highPriority">High Priority</string>
<string name="modifier.highPriority.TabDescription">You are high priority! Idrk what this means either tbh...</string>
<string name="options.exampleOptions1">Example Options 1</string>
<string name="options.exampleOptions1.toggleOpt1">Toggle Opt 1</string>
<string name="options.exampleOptions1.toggleOpt2">Toggle Opt 2</string>
<string name="options.exampleOptions1.numberOpt">Number Opt</string>
<string name="options.exampleOptions1.bestApi">Best API</string>
<string name="options.exampleOptions1.worstApi">Worst API</string>
<string name="options.exampleOptions1.players">Choose A Player</string>
<string name="options.exampleOptions2">Example Options 2</string>
<string name="options.exampleOptions2.youMustChoseAPlayer">YOU MUST CHOSE A PLAYER</string>
<string name="options.exampleOptions2.ehWhatever">Eh whatever</string>
<string name="options.exampleOptions2.toggleOption1">Toggle Option 1</string>
<string name="options.exampleOptions2.toggleOption2">Toggle Option 2</string>
<string name="options.exampleOptions2.enumOpt">Enum Opt</string>
<string name="options.captainSettings">Captain Settings</string>
<string name="options.captainSettings.amount">Amount</string>
<string name="options.captainSettings.chance">Chance</string>
<string name="options.captainSettings.uses">Uses</string>
<string name="options.freezeModifierSettings">Freeze</string>
<string name="options.freezeModifierSettings.useColor">Use Color</string>
<string name="options.generalModifier">General</string>
<string name="options.generalModifier.someBooleanOption">Some Boolean Option</string>
<string name="options.generalModifier.numberOption">Number Option</string>
<string name="options.freezerRoleSettings">Custom Role</string>
<string name="ApiExample.Role.Freezer.Settings.FreezeDuration">Freeze Duration</string>
<string name="ApiExample.Role.Freezer.Settings.FreezeUses">Freeze Uses</string>
<string name="ApiExample.Role.Teleporter.Settings.TeleportCooldown">Teleport Cooldown</string>
<string name="ApiExample.Role.Teleporter.Settings.TeleportDuration">Teleport Duration</string>
<string name="ApiExample.Role.Teleporter.Settings.ZoomDistance">Zoom Distance</string>
<string name="settings.miraExample">Mira Example</string>
<string name="settings.miraExample.exampleBool">Example Bool</string>
<string name="settings.miraExample.exampleBool2">Example Bool 2</string>
<string name="settings.miraExample.slider">Slider</string>
<string name="settings.miraExample.exampleNumber">Example Number</string>
<string name="settings.miraExample.exampleMultiplier">Example Multiplier</string>
<string name="settings.miraExample.exampleEnum">Example Enum</string>
<string name="settings.miraExample.button.exampleButton">Example Button</string>
<string name="gameover.outcastKiller.win">Outcast Killer Wins!</string>
<string name="color.cerulean">Cerulean</string>
<string name="color.rose">Rose</string>
<string name="color.gold">Gold</string>
<string name="color.rainbow">Rainbow</string>
</resources>
@@ -1,66 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="ApiExample.Role.Teleporter">传送者</string>
<string name="ApiExample.Role.Teleporter.IntroBlurb">缩小视野并在地图上传送!</string>
<string name="ApiExample.Role.Teleporter.MedDescription">缩小视野并在地图上传送!</string>
<string name="ApiExample.Role.Teleporter.TabDescription">缩小视野并在地图上传送!</string>
<string name="ApiExample.Role.Freezer">冰冻者</string>
<string name="ApiExample.Role.Freezer.TabDescription">将其他玩家冰冻一段时间。</string>
<string name="ApiExample.Role.Crewmate.Mayor">市长</string>
<string name="ApiExample.Role.Crewmate.Mayor.TabDescription">你拥有额外投票权!</string>
<string name="ApiExample.Role.Crewmate.Chamelon">变色龙</string>
<string name="ApiExample.Role.Crewmate.Chamelon.TabDescription">静止不动时保持隐身。</string>
<string name="ApiExample.Role.Outcast.OutcastKiller">流放杀手</string>
<string name="ApiExample.Role.Outcast.OutcastKiller.TabDescription">可以击杀的流放者。</string>
<string name="outcast">流放者</string>
<string name="outcast.roleTitle">流放者</string>
<string name="outcast.teamIntroDescription">你是流放者,你没有队伍。</string>
<string name="button.think">思考</string>
<string name="button.think.thinking">思考中...</string>
<string name="button.freeze">冰冻</string>
<string name="button.teleport">传送</string>
<string name="button.callMeeting">召集会议</string>
<string name="button.winGame">赢得游戏</string>
<string name="modifier.captain">队长</string>
<string name="modifier.captain.TabDescription">你可以在地图上任意位置召集会议。</string>
<string name="modifier.freezed">已被冰冻</string>
<string name="modifier.highPriority">高优先级</string>
<string name="modifier.highPriority.TabDescription">你是高优先级!老实说我也不太清楚这是什么意思……</string>
<string name="options.exampleOptions1">示例选项组 1</string>
<string name="options.exampleOptions1.toggleOpt1">开关选项 1</string>
<string name="options.exampleOptions1.toggleOpt2">开关选项 2</string>
<string name="options.exampleOptions1.numberOpt">数字选项</string>
<string name="options.exampleOptions1.bestApi">谁是最好的API</string>
<string name="options.exampleOptions2">示例选项组 2</string>
<string name="options.exampleOptions2.youMustChoseAPlayer">你必须选择一个玩家</string>
<string name="options.exampleOptions2.ehWhatever">咕咕嘎嘎</string>
<string name="options.exampleOptions2.toggleOption1">开关选项 1</string>
<string name="options.exampleOptions2.toggleOption2">开关选项 2</string>
<string name="options.exampleOptions2.enumOpt">枚举选项</string>
<string name="options.captainSettings">队长设置</string>
<string name="options.captainSettings.amount">数量</string>
<string name="options.captainSettings.chance">概率</string>
<string name="options.captainSettings.uses">使用次数</string>
<string name="options.freezeModifierSettings">冰冻</string>
<string name="options.freezeModifierSettings.useColor">使用颜色</string>
<string name="options.generalModifier">通用</string>
<string name="options.generalModifier.someBooleanOption">某个布尔选项</string>
<string name="options.generalModifier.numberOption">数字选项</string>
<string name="ApiExample.Role.Freezer.Settings.FreezeDuration">冰冻时长</string>
<string name="ApiExample.Role.Freezer.Settings.FreezeUses">冰冻次数</string>
<string name="ApiExample.Role.Teleporter.Settings.TeleportCooldown">传送冷却</string>
<string name="ApiExample.Role.Teleporter.Settings.TeleportDuration">传送持续时间</string>
<string name="ApiExample.Role.Teleporter.Settings.ZoomDistance">缩放距离</string>
<string name="settings.miraExample">Mira 示例插件</string>
<string name="settings.miraExample.exampleBool">示例布尔</string>
<string name="settings.miraExample.exampleBool2">示例布尔 2</string>
<string name="settings.miraExample.slider">滑块</string>
<string name="settings.miraExample.exampleNumber">示例数字</string>
<string name="settings.miraExample.exampleMultiplier">示例倍数</string>
<string name="settings.miraExample.exampleEnum">示例枚举</string>
<string name="settings.miraExample.button.exampleButton">示例按钮</string>
<string name="gameover.outcastKiller.win">流放杀手获胜!</string>
<string name="color.cerulean">天蓝</string>
<string name="color.rose">玫瑰红</string>
<string name="color.gold">金色</string>
</resources>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

+16 -26
View File
@@ -1,41 +1,38 @@
using AmongUs.GameOptions; using AmongUs.GameOptions;
using MiraAPI.Patches.Stubs; using MiraAPI.Patches.Stubs;
using MiraAPI.Roles; using MiraAPI.Roles;
using MiraAPI.Utilities.Assets;
using Reactor.Utilities; using Reactor.Utilities;
using TMPro;
using UnityEngine; using UnityEngine;
namespace MiraAPI.Example.Roles; namespace MiraAPI.Example.Roles;
public class ChameleonRole : CrewmateRole, ICustomRole public class ChameloenRole : CrewmateRole, ICustomRole
{ {
private bool shouldHide; public string RoleName => "Chamelon";
public string RoleLongDescription => "Stay invisible while not moving.";
public string IdPart => "Chameleon"; public string RoleDescription => RoleLongDescription;
public string IdPrefix => "ApiExample.Role.Crewmate";
public Color RoleColor => Palette.AcceptedGreen; public Color RoleColor => Palette.AcceptedGreen;
public ModdedRoleTeams Team => ModdedRoleTeams.Crewmate; public ModdedRoleTeams Team => ModdedRoleTeams.Crewmate;
private bool _shouldHide;
public CustomRoleConfiguration Configuration => new(this) public CustomRoleConfiguration Configuration => new(this)
{ {
OptionsScreenshot = ExampleAssets.Banner, OptionsScreenshot = ExampleAssets.Banner,
Icon = MiraAssets.CrewmateFile,
IconTmp = TmpSpriteUtils.CreateSpriteAsset(
MiraAssets.CrewmateFile.LoadAsset(),
"ApiExample.Role.Impostor.ChameleonRole"),
IntroSound = CustomRoleUtils.GetIntroSound(RoleTypes.Shapeshifter), IntroSound = CustomRoleUtils.GetIntroSound(RoleTypes.Shapeshifter),
}; };
public override void Initialize(PlayerControl player) public override void Initialize(PlayerControl player)
{ {
Logger<ExamplePlugin>.Info("Initializing ChameleonRole for player: " + player.PlayerId); Logger<ExamplePlugin>.Info("Initializing ChamelonRole for player: " + player.PlayerId);
RoleBehaviourStubs.Initialize(this, player); RoleBehaviourStubs.Initialize(this, player);
shouldHide = true; _shouldHide = true;
} }
public void FixedUpdate() public void FixedUpdate()
{ {
if (!Player || !shouldHide) if (!Player || !_shouldHide)
{ {
return; return;
} }
@@ -54,34 +51,27 @@ public class ChameleonRole : CrewmateRole, ICustomRole
} }
else else
{ {
var rend = Player.cosmetics.currentBodySprite.BodySprite; SpriteRenderer rend = Player.cosmetics.currentBodySprite.BodySprite;
var tmp = Player.cosmetics.nameText; TextMeshPro tmp = Player.cosmetics.nameText;
tmp.color = Color.Lerp( tmp.color = Color.Lerp(tmp.color, new Color(tmp.color.r, tmp.color.g, tmp.color.b, Player.AmOwner ? 0.3f : 0), Time.deltaTime * 4f);
tmp.color,
new Color(tmp.color.r, tmp.color.g, tmp.color.b, Player.AmOwner ? 0.3f : 0),
Time.deltaTime * 4f);
rend.color = Color.Lerp(rend.color, new Color(1, 1, 1, Player.AmOwner ? 0.3f : 0), Time.deltaTime * 4f); rend.color = Color.Lerp(rend.color, new Color(1, 1, 1, Player.AmOwner ? 0.3f : 0), Time.deltaTime * 4f);
foreach (var cosmetic in Player.cosmetics.transform.GetComponentsInChildren<SpriteRenderer>()) foreach (var cosmetic in Player.cosmetics.transform.GetComponentsInChildren<SpriteRenderer>())
{ {
cosmetic.color = Color.Lerp( cosmetic.color = Color.Lerp(cosmetic.color, new Color(1, 1, 1, Player.AmOwner ? 0.3f : 0), Time.deltaTime * 4f);
cosmetic.color,
new Color(1, 1, 1, Player.AmOwner ? 0.3f : 0),
Time.deltaTime * 4f);
} }
} }
} }
public override void Deinitialize(PlayerControl targetPlayer) public override void Deinitialize(PlayerControl targetPlayer)
{ {
Logger<ExamplePlugin>.Info("Deinitializing ChameleonRole for player: " + targetPlayer.PlayerId); Logger<ExamplePlugin>.Info("Deinitializing ChamelonRole for player: " + targetPlayer.PlayerId);
RoleBehaviourStubs.Deinitialize(this, targetPlayer); RoleBehaviourStubs.Deinitialize(this, targetPlayer);
shouldHide = false; _shouldHide = false;
foreach (var cosmetic in Player.cosmetics.transform.GetComponentsInChildren<SpriteRenderer>(true)) foreach (var cosmetic in Player.cosmetics.transform.GetComponentsInChildren<SpriteRenderer>(true))
{ {
cosmetic.color = Color.white; cosmetic.color = Color.white;
} }
Player.cosmetics.currentBodySprite.BodySprite.color = Color.white; Player.cosmetics.currentBodySprite.BodySprite.color = Color.white;
Player.cosmetics.nameText.color = Color.white; Player.cosmetics.nameText.color = Color.white;
} }
+4 -6
View File
@@ -1,20 +1,18 @@
using MiraAPI.Roles; using MiraAPI.Roles;
using MiraAPI.Utilities.Assets;
using UnityEngine; using UnityEngine;
namespace MiraAPI.Example.Roles; namespace MiraAPI.Example.Roles;
public class FreezerRole : ImpostorRole, ICustomRole public class FreezerRole : ImpostorRole, ICustomRole
{ {
public string IdPart => "Freezer"; public string RoleName => "Freezer";
public string IdPrefix => "ApiExample.Role.Impostor"; public string RoleLongDescription => "Freeze another player for a duration of time.";
public string RoleDescription => RoleLongDescription;
public Color RoleColor => Palette.Blue; public Color RoleColor => Palette.Blue;
public ModdedRoleTeams Team => ModdedRoleTeams.Impostor; public ModdedRoleTeams Team => ModdedRoleTeams.Impostor;
public CustomRoleConfiguration Configuration => new(this) public CustomRoleConfiguration Configuration => new CustomRoleConfiguration(this)
{ {
Icon = MiraAssets.ImpostorFile,
IconTmp = TmpSpriteUtils.CreateSpriteAsset(MiraAssets.ImpostorFile.LoadAsset(), "ApiExample.Role.Impostor.Freezer"),
OptionsScreenshot = ExampleAssets.Banner, OptionsScreenshot = ExampleAssets.Banner,
MaxRoleCount = 2, MaxRoleCount = 2,
}; };
+3 -2
View File
@@ -5,8 +5,9 @@ namespace MiraAPI.Example.Roles;
public class MayorRole : CrewmateRole, ICustomRole public class MayorRole : CrewmateRole, ICustomRole
{ {
public string IdPart => "Mayor"; public string RoleName => "Mayor";
public string IdPrefix => "ApiExample.Role.Crewmate"; public string RoleLongDescription => "You get extra votes!";
public string RoleDescription => RoleLongDescription;
public Color RoleColor => new Color32(221, 176, 152, 255); public Color RoleColor => new Color32(221, 176, 152, 255);
public ModdedRoleTeams Team => ModdedRoleTeams.Crewmate; public ModdedRoleTeams Team => ModdedRoleTeams.Crewmate;
public CustomRoleConfiguration Configuration => new(this); public CustomRoleConfiguration Configuration => new(this);
+7 -8
View File
@@ -1,5 +1,4 @@
using Il2CppInterop.Runtime.Attributes; using MiraAPI.Example.GameOver;
using MiraAPI.Example.GameOver;
using MiraAPI.GameEnd; using MiraAPI.GameEnd;
using MiraAPI.Roles; using MiraAPI.Roles;
using UnityEngine; using UnityEngine;
@@ -8,8 +7,9 @@ namespace MiraAPI.Example.Roles;
public class NeutralKillerRole : ImpostorRole, ICustomRole public class NeutralKillerRole : ImpostorRole, ICustomRole
{ {
public string IdPart => "OutcastKiller"; public string RoleName => "Outcast Killer";
public string IdPrefix => "ApiExample.Role.Outcast"; public string RoleDescription => "Outcast who can kill.";
public string RoleLongDescription => RoleDescription;
public Color RoleColor => Color.magenta; public Color RoleColor => Color.magenta;
public ModdedRoleTeams Team => ModdedRoleTeams.Custom; public ModdedRoleTeams Team => ModdedRoleTeams.Custom;
@@ -20,13 +20,12 @@ public class NeutralKillerRole : ImpostorRole, ICustomRole
CanUseVent = true, CanUseVent = true,
}; };
public RoleOptionsGroup RoleOptionsGroup { get; } = new("outcast.group", Color.gray); public RoleOptionsGroup RoleOptionsGroup { get; } = new("Outcast", Color.gray);
[HideFromIl2Cpp]
public TeamIntroConfiguration? IntroConfiguration { get; } = new( public TeamIntroConfiguration? IntroConfiguration { get; } = new(
Color.gray, Color.gray,
"outcast.roleTitle", "OUTCAST",
"outcast.teamIntroDescription"); "You are an Outcast. You do not have a team.");
public override void SpawnTaskHeader(PlayerControl playerControl) public override void SpawnTaskHeader(PlayerControl playerControl)
{ {
+4 -3
View File
@@ -5,12 +5,13 @@ namespace MiraAPI.Example.Roles;
public class TeleporterRole : CrewmateRole, ICustomRole public class TeleporterRole : CrewmateRole, ICustomRole
{ {
public string IdPart => "Teleporter"; public string RoleName => "Teleporter";
public string IdPrefix => "ApiExample.Role.Crewmate"; public string RoleLongDescription => "Zoom out and teleport across the map!";
public string RoleDescription => RoleLongDescription;
public Color RoleColor => new Color32(221, 176, 152, 255); public Color RoleColor => new Color32(221, 176, 152, 255);
public ModdedRoleTeams Team => ModdedRoleTeams.Crewmate; public ModdedRoleTeams Team => ModdedRoleTeams.Crewmate;
public CustomRoleConfiguration Configuration => new(this) public CustomRoleConfiguration Configuration => new CustomRoleConfiguration(this)
{ {
OptionsScreenshot = ExampleAssets.Banner, OptionsScreenshot = ExampleAssets.Banner,
CanModifyChance = false, CanModifyChance = false,
-107
View File
@@ -1,107 +0,0 @@
using System;
using System.Diagnostics.CodeAnalysis;
using MiraAPI.Utilities;
using UnityEngine;
namespace MiraAPI.Colors.ColorSpaces;
/// <summary>
/// A struct that denotes the CMYK (Cyan, Magenta, Yellow, Key) color space.
/// </summary>
/// <param name="c">The cyan component.</param>
/// <param name="m">The magenta component.</param>
/// <param name="y">The yellow component.</param>
/// <param name="k">The key component.</param>
/// <param name="a">The alpha component.</param>
[Serializable]
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "Unity parity.")]
public record struct CmykColor(float c, float m, float y, float k, float a = 1f)
{
/// <summary>
/// Implicitly converts a <see cref="CmykColor"/> to a Unity <see cref="Color"/>.
/// </summary>
/// <param name="c">The color being converted.</param>
public static implicit operator Color(CmykColor c)
{
return ToColor(c);
}
/// <summary>
/// Implicitly converts a Unity <see cref="Color"/> to a <see cref="CmykColor"/>.
/// </summary>
/// <param name="c">The color being converted.</param>
public static implicit operator CmykColor(Color c)
{
return FromColor(c);
}
/// <summary>
/// Converts a <see cref="CmykColor"/> to a standard Unity RGB <see cref="Color"/>.
/// </summary>
/// <param name="cmyk">The CMYK color to convert.</param>
/// <returns>A Unity <see cref="Color"/> representing the same visual color.</returns>
public static Color ToColor(CmykColor cmyk)
{
var key = 1f - cmyk.k;
var r = (1f - cmyk.c) * key;
var g = (1f - cmyk.m) * key;
var b = (1f - cmyk.y) * key;
return new Color(MathUtilities.Clamp01(r), MathUtilities.Clamp01(g), MathUtilities.Clamp01(b), cmyk.a);
}
/// <summary>
/// Converts a standard Unity RGB <see cref="Color"/> to a <see cref="CmykColor"/>.
/// </summary>
/// <param name="color">The Unity Color to convert.</param>
/// <returns>A <see cref="CmykColor"/> representing the same visual color.</returns>
public static CmykColor FromColor(Color color)
{
var r = color.r;
var g = color.g;
var b = color.b;
var k = 1f - MathF.Max(r, MathF.Max(g, b));
if (k >= 1f)
return new CmykColor(0f, 0f, 0f, 1f, color.a);
var invK = 1f / (1f - k);
var c = (1f - r - k) * invK;
var m = (1f - g - k) * invK;
var y = (1f - b - k) * invK;
return new CmykColor(MathUtilities.Clamp01(c), MathUtilities.Clamp01(m), MathUtilities.Clamp01(y), MathUtilities.Clamp01(k), color.a);
}
/// <summary>
/// Linearly interpolates between two <see cref="CmykColor"/> values.
/// </summary>
/// <param name="a">The starting color.</param>
/// <param name="b">The ending color.</param>
/// <param name="t">The interpolation value between the two colors, clamped to a 0 to 1 range.</param>
/// <returns>The interpolated <see cref="CmykColor"/>.</returns>
public static CmykColor Lerp(CmykColor a, CmykColor b, float t)
{
return LerpUnclamped(a, b, MathUtilities.Clamp01(t));
}
/// <summary>
/// Linearly interpolates between two <see cref="CmykColor"/> values without clamping the interpolant.
/// </summary>
/// <param name="a">The starting color.</param>
/// <param name="b">The ending color.</param>
/// <param name="t">The interpolation value between the two colors.</param>
/// <returns>The interpolated <see cref="CmykColor"/>.</returns>
public static CmykColor LerpUnclamped(CmykColor a, CmykColor b, float t)
{
return new CmykColor(
MathUtilities.LerpUnclamped(a.c, b.c, t),
MathUtilities.LerpUnclamped(a.m, b.m, t),
MathUtilities.LerpUnclamped(a.y, b.y, t),
MathUtilities.LerpUnclamped(a.k, b.k, t),
MathUtilities.LerpUnclamped(a.a, b.a, t));
}
}
-136
View File
@@ -1,136 +0,0 @@
using System;
using System.Diagnostics.CodeAnalysis;
using MiraAPI.Utilities;
using UnityEngine;
namespace MiraAPI.Colors.ColorSpaces;
/// <summary>
/// A struct that denotes the HSB (Hue, Saturation, Brightness) color space.
/// </summary>
/// <param name="h">The hue component.</param>
/// <param name="s">The saturation component.</param>
/// <param name="b">The brightness component.</param>
/// <param name="a">The alpha component.</param>
[Serializable]
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "Unity parity.")]
public record struct HsbColor(float h, float s, float b, float a = 1f)
{
/// <summary>
/// Implicitly converts an <see cref="HsbColor"/> to a Unity <see cref="Color"/>.
/// </summary>
/// <param name="c">The color being converted.</param>
public static implicit operator Color(HsbColor c)
{
return ToColor(c);
}
/// <summary>
/// Implicitly converts a Unity <see cref="Color"/> to an <see cref="HsbColor"/>.
/// </summary>
/// <param name="c">The color being converted.</param>
public static implicit operator HsbColor(Color c)
{
return FromColor(c);
}
/// <summary>
/// Converts an <see cref="HsbColor"/> to a standard Unity RGB <see cref="Color"/>.
/// </summary>
/// <param name="hsb">The HSB color to convert.</param>
/// <returns>A Unity <see cref="Color"/> representing the same visual color.</returns>
public static Color ToColor(HsbColor hsb)
{
if (hsb.s <= float.Epsilon)
return new Color(MathUtilities.Clamp01(hsb.b), MathUtilities.Clamp01(hsb.b), MathUtilities.Clamp01(hsb.b), hsb.a);
var c = hsb.b * hsb.s;
var hPrime = hsb.h * 6f;
var x = c * (1f - MathF.Abs((hPrime % 2f) - 1f));
var m = hsb.b - c;
var (r, g, b) = hPrime switch
{
< 1f => (c, x, 0f),
< 2f => (x, c, 0f),
< 3f => (0f, c, x),
< 4f => (0f, x, c),
< 5f => (x, 0f, c),
<= 6f => (c, 0f, x),
_ => (0f, 0f, 0f),
};
return new Color(
MathUtilities.Clamp01(r + m),
MathUtilities.Clamp01(g + m),
MathUtilities.Clamp01(b + m),
hsb.a);
}
/// <summary>
/// Converts a standard Unity RGB <see cref="Color"/> to an <see cref="HsbColor"/>.
/// </summary>
/// <param name="color">The Unity Color to convert.</param>
/// <returns>An <see cref="HsbColor"/> representing the same visual color.</returns>
public static HsbColor FromColor(Color color)
{
var max = MathF.Max(color.r, MathF.Max(color.g, color.b));
var min = MathF.Min(color.r, MathF.Min(color.g, color.b));
var delta = max - min;
var h = 0f;
if (delta > 0f)
{
if (max == color.r)
h = (color.g - color.b) / delta % 6f;
else if (max == color.g)
h = (color.b - color.r) / delta + 2f;
else
h = (color.r - color.g) / delta + 4f;
h /= 6f;
if (h < 0f)
h += 1f;
}
var s = max == 0f ? 0f : delta / max;
var b = max;
return new HsbColor(h, s, b, color.a);
}
/// <summary>
/// Linearly interpolates between two <see cref="HsbColor"/> values, using the shortest path for the hue.
/// </summary>
/// <param name="a">The starting color.</param>
/// <param name="b">The ending color.</param>
/// <param name="t">The interpolation value between the two colors, clamped to a 0 to 1 range.</param>
/// <returns>The interpolated <see cref="HsbColor"/>.</returns>
public static HsbColor Lerp(HsbColor a, HsbColor b, float t)
{
return LerpUnclamped(a, b, MathUtilities.Clamp01(t));
}
/// <summary>
/// Linearly interpolates between two <see cref="HsbColor"/> values without clamping the interpolant.
/// </summary>
/// <param name="a">The starting color.</param>
/// <param name="b">The ending color.</param>
/// <param name="t">The interpolation value between the two colors.</param>
/// <returns>The interpolated <see cref="HsbColor"/>.</returns>
public static HsbColor LerpUnclamped(HsbColor a, HsbColor b, float t)
{
var hueDifference = MathUtilities.Repeat(b.h - a.h, 1f);
if (hueDifference > 0.5f)
hueDifference -= 1f;
return new HsbColor(
MathUtilities.Repeat(a.h + (hueDifference * t), 1f),
MathUtilities.LerpUnclamped(a.s, b.s, t),
MathUtilities.LerpUnclamped(a.b, b.b, t),
MathUtilities.LerpUnclamped(a.a, b.a, t));
}
}
-132
View File
@@ -1,132 +0,0 @@
using System;
using System.Diagnostics.CodeAnalysis;
using MiraAPI.Utilities;
using UnityEngine;
namespace MiraAPI.Colors.ColorSpaces;
/// <summary>
/// A struct that denotes the HSL (Hue, Saturation, Lightness) color space.
/// </summary>
/// <param name="h">The hue component.</param>
/// <param name="s">The saturation component.</param>
/// <param name="l">The lightness component.</param>
/// <param name="a">The alpha component.</param>
[Serializable]
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "Unity parity.")]
public record struct HslColor(float h, float s, float l, float a = 1f)
{
/// <summary>
/// Implicitly converts an <see cref="HslColor"/> to a Unity <see cref="Color"/>.
/// </summary>
/// <param name="c">The color being converted.</param>
public static implicit operator Color(HslColor c)
{
return ToColor(c);
}
/// <summary>
/// Implicitly converts a Unity <see cref="Color"/> to an <see cref="HslColor"/>.
/// </summary>
/// <param name="c">The color being converted.</param>
public static implicit operator HslColor(Color c)
{
return FromColor(c);
}
/// <summary>
/// Converts an <see cref="HslColor"/> to a standard Unity RGB <see cref="Color"/>.
/// </summary>
/// <param name="hsl">The HSL color to convert.</param>
/// <returns>A Unity <see cref="Color"/> representing the same visual color.</returns>
public static Color ToColor(HslColor hsl)
{
if (hsl.s <= float.Epsilon)
return new Color(MathUtilities.Clamp01(hsl.l), MathUtilities.Clamp01(hsl.l), MathUtilities.Clamp01(hsl.l), hsl.a);
var c = (1f - MathF.Abs(2f * hsl.l - 1f)) * hsl.s;
var hPrime = hsl.h * 6f;
var x = c * (1f - MathF.Abs((hPrime % 2f) - 1f));
var m = hsl.l - c / 2f;
var (r, g, b) = hPrime switch
{
< 1f => (c, x, 0f),
< 2f => (x, c, 0f),
< 3f => (0f, c, x),
< 4f => (0f, x, c),
< 5f => (x, 0f, c),
<= 6f => (c, 0f, x),
_ => (0f, 0f, 0f),
};
return new Color(MathUtilities.Clamp01(r + m), MathUtilities.Clamp01(g + m), MathUtilities.Clamp01(b + m), hsl.a);
}
/// <summary>
/// Converts a standard Unity RGB <see cref="Color"/> to an <see cref="HslColor"/>.
/// </summary>
/// <param name="color">The Unity Color to convert.</param>
/// <returns>An <see cref="HslColor"/> representing the same visual color.</returns>
public static HslColor FromColor(Color color)
{
var max = MathF.Max(color.r, MathF.Max(color.g, color.b));
var min = MathF.Min(color.r, MathF.Min(color.g, color.b));
var l = (max + min) / 2f;
var delta = max - min;
var s = delta == 0f ? 0f : delta / (1f - MathF.Abs((2f * l) - 1f));
var h = 0f;
if (delta > 0f)
{
if (max == color.r)
h = (color.g - color.b) / delta % 6f;
else if (max == color.g)
h = (color.b - color.r) / delta + 2f;
else
h = (color.r - color.g) / delta + 4f;
h /= 6f;
if (h < 0f)
h += 1f;
}
return new HslColor(h, s, l, color.a);
}
/// <summary>
/// Linearly interpolates between two <see cref="HslColor"/> values, using the shortest path for the hue.
/// </summary>
/// <param name="a">The starting color.</param>
/// <param name="b">The ending color.</param>
/// <param name="t">The interpolation value between the two colors, clamped to a 0 to 1 range.</param>
/// <returns>The interpolated <see cref="HslColor"/>.</returns>
public static HslColor Lerp(HslColor a, HslColor b, float t)
{
return LerpUnclamped(a, b, MathUtilities.Clamp01(t));
}
/// <summary>
/// Linearly interpolates between two <see cref="HslColor"/> values without clamping the interpolant.
/// </summary>
/// <param name="a">The starting color.</param>
/// <param name="b">The ending color.</param>
/// <param name="t">The interpolation value between the two colors.</param>
/// <returns>The interpolated <see cref="HslColor"/>.</returns>
public static HslColor LerpUnclamped(HslColor a, HslColor b, float t)
{
var hueDifference = MathUtilities.Repeat(b.h - a.h, 1f);
if (hueDifference > 0.5f)
hueDifference -= 1f;
return new HslColor(
MathUtilities.Repeat(a.h + (hueDifference * t), 1f),
MathUtilities.LerpUnclamped(a.s, b.s, t),
MathUtilities.LerpUnclamped(a.l, b.l, t),
MathUtilities.LerpUnclamped(a.a, b.a, t));
}
}
+11 -43
View File
@@ -1,6 +1,5 @@
using System.Diagnostics.CodeAnalysis; using MiraAPI.Utilities;
using MiraAPI.Translation; using Reactor.Localization.Utilities;
using MiraAPI.Utilities;
using UnityEngine; using UnityEngine;
namespace MiraAPI.Colors; namespace MiraAPI.Colors;
@@ -11,37 +10,17 @@ namespace MiraAPI.Colors;
/// <param name="name">The name of the option.</param> /// <param name="name">The name of the option.</param>
/// <param name="mainColor">The main color.</param> /// <param name="mainColor">The main color.</param>
/// <param name="shadowColor">The shadow color.</param> /// <param name="shadowColor">The shadow color.</param>
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Internal code.")] public sealed class CustomColor(StringNames name, Color32 mainColor, Color32 shadowColor)
[SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1513:Closing brace should be followed by blank line", Justification = "Looks weird.")]
public class CustomColor(StringNames name, Color32 mainColor, Color32 shadowColor)
{ {
/// <summary> /// <summary>
/// Gets or sets the main color. /// Gets or sets the main color.
/// </summary> /// </summary>
public Color32 MainColor public Color32 MainColor { get; set; } = mainColor;
{
get;
set
{
field = value;
InternalMainColor = value;
}
}
= mainColor;
/// <summary> /// <summary>
/// Gets or sets the shadow color. /// Gets or sets the shadow color.
/// </summary> /// </summary>
public Color32 ShadowColor public Color32 ShadowColor { get; set; } = shadowColor;
{
get;
set
{
field = value;
InternalShadowColor = value;
}
}
= shadowColor;
/// <summary> /// <summary>
/// Gets or sets the name of the color. /// Gets or sets the name of the color.
@@ -53,24 +32,18 @@ public class CustomColor(StringNames name, Color32 mainColor, Color32 shadowColo
/// </summary> /// </summary>
public CustomColorBrightness ColorBrightness { get; set; } = CustomColorBrightness.Darker; public CustomColorBrightness ColorBrightness { get; set; } = CustomColorBrightness.Darker;
internal Color InternalMainColor = mainColor; /// <inheritdoc />
internal Color InternalShadowColor = shadowColor; public CustomColor(StringNames name, Color32 mainColor) : this(name, mainColor, mainColor.GetShadowColor(60))
/// <inheritdoc cref="CustomColor"/>
public CustomColor(StringNames name, Color32 mainColor)
: this(name, mainColor, mainColor.GetShadowColor(60))
{ {
} }
/// <inheritdoc cref="CustomColor"/> /// <inheritdoc />
public CustomColor(string name, Color32 mainColor) public CustomColor(string name, Color32 mainColor) : this(name, mainColor, mainColor.GetShadowColor(60))
: this(name, mainColor, mainColor.GetShadowColor(60))
{ {
} }
/// <inheritdoc cref="CustomColor"/> /// <inheritdoc />
public CustomColor(string name, Color32 mainColor, Color32 shadowColor) public CustomColor(string name, Color32 mainColor, Color32 shadowColor) : this(CustomStringName.CreateAndRegister(name), mainColor, shadowColor)
: this(MiraLocaleManager.GetOrCreateLocaleString(name), mainColor, shadowColor)
{ {
} }
} }
@@ -80,11 +53,6 @@ public class CustomColor(StringNames name, Color32 mainColor, Color32 shadowColo
/// </summary> /// </summary>
public enum CustomColorBrightness public enum CustomColorBrightness
{ {
/// <summary>
/// An invalid color.
/// </summary>
Invalid = -1,
/// <summary> /// <summary>
/// A lighter color. /// A lighter color.
/// </summary> /// </summary>
+2 -117
View File
@@ -1,52 +1,23 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using HarmonyLib; using HarmonyLib;
using UnityEngine;
namespace MiraAPI.Colors; namespace MiraAPI.Colors;
/// <summary> /// <summary>
/// Used to register and track <see cref="CustomColor"/>s. /// Used to register and track custom colors.
/// </summary> /// </summary>
public static class PaletteManager public static class PaletteManager
{ {
/// <summary> /// <summary>
/// Gets all registered <see cref="CustomColor"/>s. /// Gets all registered custom colors.
/// </summary> /// </summary>
public static CustomColor[] RegisteredColors => [.. CustomColors]; public static CustomColor[] RegisteredColors => [.. CustomColors];
internal static readonly List<CustomColor> CustomColors = []; internal static readonly List<CustomColor> CustomColors = [];
internal static readonly HashSet<StringNames> VariableColorNames = [];
private static readonly CustomColorBrightness[] ColorBrightnessMap =
[
CustomColorBrightness.Darker, // Red
CustomColorBrightness.Darker, // Blue
CustomColorBrightness.Darker, // Green
CustomColorBrightness.Lighter, // Pink
CustomColorBrightness.Lighter, // Orange
CustomColorBrightness.Lighter, // Yellow
CustomColorBrightness.Darker, // Black
CustomColorBrightness.Lighter, // White
CustomColorBrightness.Darker, // Purple
CustomColorBrightness.Darker, // Brown
CustomColorBrightness.Lighter, // Cyan
CustomColorBrightness.Lighter, // Lime
CustomColorBrightness.Darker, // Maroon
CustomColorBrightness.Lighter, // Rose
CustomColorBrightness.Lighter, // Banana
CustomColorBrightness.Darker, // Gray
CustomColorBrightness.Darker, // Tan
CustomColorBrightness.Lighter, // Coral
];
private static int originalLength;
internal static void RegisterAllColors() internal static void RegisterAllColors()
{ {
originalLength = Palette.PlayerColors.Length;
var colors = CustomColors.Select(x => x.MainColor).ToArray(); var colors = CustomColors.Select(x => x.MainColor).ToArray();
var shadowColors = CustomColors.Select(x => x.ShadowColor).ToArray(); var shadowColors = CustomColors.Select(x => x.ShadowColor).ToArray();
var stringNames = CustomColors.Select(x => x.Name).ToArray(); var stringNames = CustomColors.Select(x => x.Name).ToArray();
@@ -58,90 +29,4 @@ public static class PaletteManager
Palette.TextColors = Palette.TextColors.ToArray().AddRangeToArray(colors); Palette.TextColors = Palette.TextColors.ToArray().AddRangeToArray(colors);
Palette.TextOutlineColors = Palette.TextOutlineColors.ToArray().AddRangeToArray(shadowColors); Palette.TextOutlineColors = Palette.TextOutlineColors.ToArray().AddRangeToArray(shadowColors);
} }
/// <summary>
/// Checks to see if the provided color ID belongs to a variable color.
/// </summary>
/// <param name="colorId">The id of the color.</param>
/// <returns><c>true</c> if the color is a variable color; <c>false</c> otherwise.</returns>
public static bool IsVariable(int colorId)
{
if ((uint)colorId >= (uint)Palette.ColorNames.Length)
return false;
return VariableColorNames.Contains(Palette.ColorNames[colorId]);
}
/// <summary>
/// Checks to see if the provided color ID belongs to a custom color.
/// </summary>
/// <param name="colorId">The ID of the color.</param>
/// <returns><c>true</c> if the color is a custom color; <c>false</c> otherwise.</returns>
public static bool IsCustomColor(int colorId)
{
return (uint)(colorId - originalLength) < (uint)CustomColors.Count;
}
/// <summary>
/// Gets the main color of the provided color ID.
/// </summary>
/// <param name="colorId">The id of the color.</param>
/// <returns>The main color associated with the provided ID.</returns>
public static Color GetMainColor(int colorId)
{
if ((uint)colorId >= (uint)Palette.ColorNames.Length)
return Color.white;
return !TryGetCustomColor(colorId, out var custom)
? Palette.PlayerColors[colorId]
: (custom is VariableColor variable
? variable.EvaluateMainColor(Time.time)
: custom.InternalMainColor);
}
/// <summary>
/// Gets the shadow color of the provided color ID.
/// </summary>
/// <param name="colorId">The ID of the color.</param>
/// <returns>The shadow color associated with the provided ID.</returns>
public static Color GetShadowColor(int colorId)
{
if ((uint)colorId >= (uint)Palette.ColorNames.Length)
return Color.white;
return !TryGetCustomColor(colorId, out var custom)
? Palette.ShadowColors[colorId]
: (custom is VariableColor variable
? variable.EvaluateShadowColor(Time.time)
: custom.InternalShadowColor);
}
/// <summary>
/// Gets the brightness type of the color associated with the provided ID.
/// </summary>
/// <param name="colorId">The ID of the color.</param>
/// <returns>The brightness type of the provided ID.</returns>
public static CustomColorBrightness GetBrightness(int colorId)
{
if ((uint)colorId >= (uint)Palette.ColorNames.Length)
return CustomColorBrightness.Invalid;
return TryGetCustomColor(colorId, out var custom)
? custom.ColorBrightness
: ColorBrightnessMap[colorId];
}
internal static bool TryGetCustomColor(int colorId, [NotNullWhen(true)] out CustomColor? custom)
{
var index = colorId - originalLength;
if ((uint)index >= (uint)CustomColors.Count)
{
custom = null;
return false;
}
custom = CustomColors[index];
return true;
}
} }
@@ -3,7 +3,7 @@
namespace MiraAPI.Colors; namespace MiraAPI.Colors;
/// <summary> /// <summary>
/// Used to mark a class for <see cref="CustomColor"/> registration. /// Used to mark a class for custom colors registration.
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Class)] [AttributeUsage(AttributeTargets.Class)]
public class RegisterCustomColorsAttribute : Attribute; public class RegisterCustomColorsAttribute : Attribute;
-72
View File
@@ -1,72 +0,0 @@
using System;
using MiraAPI.LocalSettings;
using MiraAPI.Translation;
using MiraAPI.Utilities;
using UnityEngine;
namespace MiraAPI.Colors;
/// <summary>
/// Represents a dynamic custom color that changes over time.
/// </summary>
/// <param name="name">The name of the color.</param>
/// <param name="mainEvaluator">The function to evaluate the dynamic main color.</param>
/// <param name="shadowEvaluator">The function to evaluate the dynamic shadow color.</param>
/// <param name="mainColor">The static main color used when dynamic colors are disabled.</param>
/// <param name="shadowColor">The static shadow color used when dynamic colors are disabled.</param>
/// <param name="defaultTime">The default time that is used to automatically fill in the static colors when the latter is not provided.</param>
public sealed class VariableColor(StringNames name, Func<float, Color> mainEvaluator, Func<float, Color>? shadowEvaluator, Color32? mainColor = null, Color32? shadowColor = null, float defaultTime = 0f)
: CustomColor(name, mainColor ?? mainEvaluator(defaultTime), shadowColor ?? shadowEvaluator?.Invoke(defaultTime) ?? (mainColor ?? mainEvaluator(defaultTime)).GetShadowColor(60))
{
/// <summary>
/// Gets or sets a delegate that takes in a time value and returns the dynamic main color.
/// </summary>
public Func<float, Color> MainEvaluator { get; set; } = mainEvaluator;
/// <summary>
/// Gets or sets a delegate that takes in a time value and returns the dynamic shadow color.
/// </summary>
public Func<float, Color> ShadowEvaluator { get; set; } = shadowEvaluator ?? (t => mainEvaluator(t).GetShadowColor(0.24f));
/// <inheritdoc cref="VariableColor"/>
public VariableColor(StringNames name, Func<float, Color> mainEvaluator, Color32? mainColor = null, float defaultTime = 0f)
: this(name, mainEvaluator, null, mainColor, null, defaultTime)
{
}
/// <inheritdoc cref="VariableColor"/>
public VariableColor(string name, Func<float, Color> mainEvaluator, Color32? mainColor = null, float defaultTime = 0f)
: this(name, mainEvaluator, null, mainColor, null, defaultTime)
{
}
/// <inheritdoc cref="VariableColor"/>
public VariableColor(string name, Func<float, Color> mainEvaluator, Func<float, Color>? shadowEvaluator, Color32? mainColor = null, Color32? shadowColor = null, float defaultTime = 0f)
: this(MiraLocaleManager.GetOrCreateLocaleString(name), mainEvaluator, shadowEvaluator, mainColor, shadowColor, defaultTime)
{
}
/// <summary>
/// Evaluates the dynamic main color based on the provided time value.
/// </summary>
/// <param name="time">The time to evaluate the color against.</param>
/// <returns>The dynamically evaluated color, or the static <see cref="CustomColor.MainColor"/> if static variable colors are enabled in the user's settings.</returns>
public Color EvaluateMainColor(float time)
{
return LocalSettingsTabSingleton<MiraApiSettings>.Instance.EnableVariableColors.Value
? MainEvaluator(time)
: InternalMainColor;
}
/// <summary>
/// Evaluates the dynamic shadow color based on the provided time value.
/// </summary>
/// <param name="time">The time to evaluate the color against.</param>
/// <returns>The dynamically evaluated color, or the static <see cref="CustomColor.ShadowColor"/> if static variable colors are enabled in the user's settings.</returns>
public Color EvaluateShadowColor(float time)
{
return LocalSettingsTabSingleton<MiraApiSettings>.Instance.EnableVariableColors.Value
? ShadowEvaluator(time)
: InternalShadowColor;
}
}
-102
View File
@@ -1,102 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using Il2CppInterop.Runtime.Attributes;
using MiraAPI.Colors;
using MiraAPI.Utilities;
using Reactor.Utilities.Attributes;
using UnityEngine;
namespace MiraAPI;
/// <summary>
/// The base class for variable color behaviour on <see cref="SpriteRenderer"/>s.
/// </summary>
[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity methods.")]
[SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "Unity fields.")]
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Read above.")]
public abstract class BaseVariableColorBehaviour : MonoBehaviour
{
/// <summary>
/// The <see cref="VariableColor"/> to apply.
/// </summary>
protected VariableColor? color;
/// <summary>
/// Sets the current variable color.
/// </summary>
/// <param name="newColor">The new <see cref="VariableColor"/>.</param>
[HideFromIl2Cpp]
public void SetColor(VariableColor? newColor)
{
color = newColor;
}
}
/// <summary>
/// A mono script that adjusts the material colors of a <see cref="Renderer"/> component that it's attached to based on the provided variable color.
/// </summary>
[RegisterInIl2Cpp]
[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity methods.")]
public sealed class VariableColorBehaviour : BaseVariableColorBehaviour
{
private Renderer? rend;
private static readonly Color VisorColor = Palette.VisorColor;
/// <summary>
/// Sets the new <see cref="Renderer"/> target.
/// </summary>
/// <param name="newRend">The new <see cref="Renderer"/> that the script must target.</param>
public void SetRend(Renderer? newRend)
{
rend = newRend;
}
private void Awake()
{
rend = GetComponent<Renderer>();
}
private void Update()
{
if (color == null || rend == null)
return;
var time = Time.time;
var material = rend.material;
material.SetColor(ShaderID.VisorColor, VisorColor);
material.SetColor(ShaderID.BodyColor, color.EvaluateMainColor(time));
material.SetColor(ShaderID.BackColor, color.EvaluateShadowColor(time));
}
}
/// <summary>
/// A mono script that adjusts the graphic colors of a <see cref="SpriteRenderer"/> component that it's attached to based on the provided variable color.
/// </summary>
[RegisterInIl2Cpp]
[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity methods.")]
public sealed class BasicVariableColorBehaviour : BaseVariableColorBehaviour
{
private SpriteRenderer? rend;
/// <summary>
/// Sets the new <see cref="SpriteRenderer"/> target.
/// </summary>
/// <param name="newRend">The new <see cref="SpriteRenderer"/> that the script must target.</param>
public void SetRend(SpriteRenderer? newRend)
{
rend = newRend;
}
private void Awake()
{
rend = GetComponent<SpriteRenderer>();
}
private void Update()
{
if (color != null && rend != null)
rend.color = color.EvaluateMainColor(Time.time);
}
}
+27 -12
View File
@@ -3,27 +3,42 @@
namespace MiraAPI.Events.Mira; namespace MiraAPI.Events.Mira;
/// <summary> /// <summary>
/// Invoked when a <see cref="CustomActionButton"/> click is cancelled. Do not use for vanilla <see cref="AbilityButton"/>s. /// Invoked when a Mira Button click is cancelled. Do not use for vanilla buttons.
/// </summary> /// </summary>
/// <typeparam name="T">The <see cref="CustomActionButton"/> type.</typeparam> /// <typeparam name="T">The Mira Button type.</typeparam>
/// <param name="button">The <see cref="CustomActionButton"/> whose click was cancelled.</param> public sealed class MiraButtonCancelledEvent<T> : MiraEvent where T : CustomActionButton
public sealed class MiraButtonCancelledEvent<T>(T button) : MiraEvent
where T : CustomActionButton
{ {
/// <summary> /// <summary>
/// Gets the <see cref="CustomActionButton"/> whose click was cancelled. /// Gets Mira Button whose click was cancelled.
/// </summary> /// </summary>
public T Button { get; } = button; public T Button { get; }
/// <summary>
/// Initializes a new instance of the <see cref="MiraButtonCancelledEvent{T}"/> class.
/// </summary>
/// <param name="button">The Mira Button whose click was cancelled.</param>
public MiraButtonCancelledEvent(T button)
{
Button = button;
}
} }
/// <summary> /// <summary>
/// Invoked when a <see cref="CustomActionButton"/> click is cancelled. Do not use for vanilla <see cref="AbilityButton"/>s. /// Invoked when a Mira Button click is cancelled. Do not use for vanilla buttons.
/// </summary> /// </summary>
/// <param name="button">The <see cref="CustomActionButton"/> whose click was cancelled.</param> public sealed class MiraButtonCancelledEvent : MiraEvent
public sealed class MiraButtonCancelledEvent(CustomActionButton button) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="CustomActionButton"/> whose click was cancelled. /// Gets Mira Button whose click was cancelled.
/// </summary> /// </summary>
public CustomActionButton Button { get; } = button; public CustomActionButton Button { get; }
/// <summary>
/// Initializes a new instance of the <see cref="MiraButtonCancelledEvent"/> class.
/// </summary>
/// <param name="button">The Mira Button whose click was cancelled.</param>
public MiraButtonCancelledEvent(CustomActionButton button)
{
Button = button;
}
} }
+31 -15
View File
@@ -3,33 +3,49 @@
namespace MiraAPI.Events.Mira; namespace MiraAPI.Events.Mira;
/// <summary> /// <summary>
/// Button click event for <see cref="CustomActionButton"/>s only. Do not use for vanilla <see cref="AbilityButton"/>s. /// Button click event for Mira Buttons only. Do not use for vanilla buttons.
/// </summary> /// </summary>
/// <typeparam name="T">The <see cref="CustomActionButton"/> type.</typeparam> /// <typeparam name="T">The Mira Button type.</typeparam>
/// <param name="button">The <see cref="CustomActionButton"/> that was clicked.</param> public sealed class MiraButtonClickEvent<T> : MiraCancelableEvent where T : CustomActionButton
/// <param name="genericClickEvent">The generic <see cref="MiraButtonClickEvent"/> invoked before button-specific events.</param>
public class MiraButtonClickEvent<T>(T button, MiraButtonClickEvent genericClickEvent) : MiraCancelableEvent
where T : CustomActionButton
{ {
/// <summary> /// <summary>
/// Gets the <see cref="CustomActionButton"/> that was clicked. /// Gets Mira Button that was clicked.
/// </summary> /// </summary>
public T Button { get; } = button; public T Button { get; }
/// <summary> /// <summary>
/// Gets the generic <see cref="MiraButtonClickEvent"/> that is invoked before this button-specific event. /// Gets the generic click event that is invoked before this button-specific event.
/// </summary> /// </summary>
public MiraButtonClickEvent GenericClickEvent { get; } = genericClickEvent; public MiraButtonClickEvent GenericClickEvent { get; }
/// <summary>
/// Initializes a new instance of the <see cref="MiraButtonClickEvent{T}"/> class.
/// </summary>
/// <param name="button">The Mira Button that was clicked.</param>
/// <param name="genericClickEvent">The generic click event invoked before button-specific events.</param>
public MiraButtonClickEvent(T button, MiraButtonClickEvent genericClickEvent)
{
GenericClickEvent = genericClickEvent;
Button = button;
}
} }
/// <summary> /// <summary>
/// Button click event for <see cref="CustomActionButton"/>s only. Do not use for vanilla <see cref="AbilityButton"/>s. /// Button click event for Mira Buttons only. Do not use for vanilla buttons.
/// </summary> /// </summary>
/// <param name="button">The <see cref="CustomActionButton"/> that was clicked.</param> public sealed class MiraButtonClickEvent : MiraCancelableEvent
public class MiraButtonClickEvent(CustomActionButton button) : MiraCancelableEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="CustomActionButton"/> that was clicked. /// Gets Mira Button that was clicked.
/// </summary> /// </summary>
public CustomActionButton Button { get; } = button; public CustomActionButton Button { get; }
/// <summary>
/// Initializes a new instance of the <see cref="MiraButtonClickEvent"/> class.
/// </summary>
/// <param name="button">The Mira Button that was clicked.</param>
public MiraButtonClickEvent(CustomActionButton button)
{
Button = button;
}
} }
@@ -1,21 +0,0 @@
using UnityEngine;
namespace MiraAPI.Events.Mira;
/// <summary>
/// Event fired by Mira API to adjust the UI buttons at the top right of the screen.
/// </summary>
/// <param name="topUiRow">The <see cref="GameObject"/> for the top UI row.</param>
/// <param name="secondUiRow">The <see cref="GameObject"/> for the second UI row.</param>
public class UiButtonPostResetEvent(GameObject topUiRow, GameObject secondUiRow) : MiraEvent
{
/// <summary>
/// Gets the <see cref="GameObject"/> parent for the very top UI row.
/// </summary>
public GameObject MainTopUiRow { get; } = topUiRow;
/// <summary>
/// Gets the <see cref="GameObject"/> parent for the second top UI row.
/// </summary>
public GameObject SecondTopUiRow { get; } = secondUiRow;
}
-15
View File
@@ -1,15 +0,0 @@
namespace MiraAPI.Events.Mira;
/// <summary>
/// Event fired by Mira API prior to adjusting the UI buttons at the top right of the screen.
/// </summary>
public class UiButtonResetEvent : MiraEvent
{
/// <summary>
/// Initializes a new instance of the <see cref="UiButtonResetEvent"/> class.
/// </summary>
public UiButtonResetEvent()
{
// nothing!
}
}
+1 -4
View File
@@ -1,11 +1,8 @@
using MiraAPI.PluginLoading; namespace MiraAPI.Events;
namespace MiraAPI.Events;
/// <summary> /// <summary>
/// Abstract class for Mira Events that can be cancelled. /// Abstract class for Mira Events that can be cancelled.
/// </summary> /// </summary>
[MiraIgnore]
public abstract class MiraCancelableEvent : MiraEvent public abstract class MiraCancelableEvent : MiraEvent
{ {
/// <summary> /// <summary>
+1 -4
View File
@@ -1,9 +1,6 @@
using MiraAPI.PluginLoading; namespace MiraAPI.Events;
namespace MiraAPI.Events;
/// <summary> /// <summary>
/// Abstract class for Mira Events. /// Abstract class for Mira Events.
/// </summary> /// </summary>
[MiraIgnore]
public abstract class MiraEvent; public abstract class MiraEvent;
+1 -1
View File
@@ -3,7 +3,7 @@
namespace MiraAPI.Events; namespace MiraAPI.Events;
/// <summary> /// <summary>
/// Event handle to use when unregistering a <see cref="MiraEvent"/>. /// Event handle to use when unregistering an event.
/// </summary> /// </summary>
public class MiraEventHandle public class MiraEventHandle
{ {
+21 -25
View File
@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using Reactor.Utilities;
namespace MiraAPI.Events; namespace MiraAPI.Events;
@@ -12,16 +13,14 @@ public static class MiraEventManager
private static readonly Dictionary<Type, List<MiraEventWrapper>> EventWrappers = []; private static readonly Dictionary<Type, List<MiraEventWrapper>> EventWrappers = [];
/// <summary> /// <summary>
/// Invoke a <see cref="MiraEvent"/>. /// Invoke an event.
/// </summary> /// </summary>
/// <param name="eventInstance">The <typeparamref name="T"/> instance.</param> /// <param name="eventInstance">The event instance.</param>
/// <typeparam name="T">Type of Event.</typeparam> /// <typeparam name="T">Type of Event.</typeparam>
/// <returns>If there was an event handler invoked for this event, return <see langword="true"/>. Otherwise, return <see langword="false"/>.</returns> /// <returns>If there was an event handler invoked for this event, return true. Otherwise, return false.</returns>
public static bool InvokeEvent<T>(this T eventInstance) public static bool InvokeEvent<T>(T eventInstance) where T : MiraEvent
where T : MiraEvent
{ {
EventWrappers.TryGetValue(typeof(T), out var handlers); EventWrappers.TryGetValue(typeof(T), out var handlers);
if (handlers == null || handlers.Count == 0) if (handlers == null || handlers.Count == 0)
{ {
return false; return false;
@@ -35,7 +34,7 @@ public static class MiraEventManager
} }
catch (Exception ex) catch (Exception ex)
{ {
Error($"Error invoking event handler for {typeof(T).Name}: {ex.ToString()}"); Logger<MiraApiPlugin>.Error($"Error invoking event handler for {typeof(T).Name}: {ex.ToString()}");
} }
} }
@@ -43,15 +42,14 @@ public static class MiraEventManager
} }
/// <summary> /// <summary>
/// Invoke a <see cref="MiraEvent"/> and use a specific type to find the handlers. /// Invoke an event and use a specific type to find the handlers.
/// </summary> /// </summary>
/// <param name="eventInstance">The <see cref="MiraEvent"/> instance.</param> /// <param name="eventInstance">The event instance.</param>
/// <param name="type">The type to use for handler lookup.</param> /// <param name="type">The type to use for handler lookup.</param>
/// <returns>If there was an event handler invoked for this event, return <see langword="true"/>. Otherwise, return <see langword="false"/>.</returns> /// <returns>If there was an event handler invoked for this event, return true. Otherwise, return false.</returns>
public static bool InvokeEvent(this MiraEvent eventInstance, Type type) public static bool InvokeEvent(MiraEvent eventInstance, Type type)
{ {
EventWrappers.TryGetValue(type, out var handlers); EventWrappers.TryGetValue(type, out var handlers);
if (handlers == null || handlers.Count == 0) if (handlers == null || handlers.Count == 0)
{ {
return false; return false;
@@ -65,7 +63,7 @@ public static class MiraEventManager
} }
catch (Exception ex) catch (Exception ex)
{ {
Error($"Error invoking event handler for {type.Name}: {ex.ToString()}"); Logger<MiraApiPlugin>.Error($"Error invoking event handler for {type.Name}: {ex.ToString()}");
} }
} }
@@ -73,12 +71,12 @@ public static class MiraEventManager
} }
/// <summary> /// <summary>
/// Register a <see cref="MiraEvent"/> handler. /// Register an event.
/// </summary> /// </summary>
/// <param name="type">The type of <see cref="MiraEvent"/> event.</param> /// <param name="type">The type of event.</param>
/// <param name="methodInfo">The <see cref="MethodInfo"/> of the event handler.</param> /// <param name="methodInfo">The MethodInfo of the event handler.</param>
/// <param name="priority">The priority of the event handler. Lower values are called first.</param> /// <param name="priority">The priority of the event handler. Lower values are called first.</param>
/// <returns>A <see cref="MiraEventHandle"/> to use when unregistering the event.</returns> /// <returns>An event handle to use when unregistering the event.</returns>
public static MiraEventHandle RegisterEventHandler(Type type, MethodInfo methodInfo, int priority = 0) public static MiraEventHandle RegisterEventHandler(Type type, MethodInfo methodInfo, int priority = 0)
{ {
if (!type.IsSubclassOf(typeof(MiraEvent))) if (!type.IsSubclassOf(typeof(MiraEvent)))
@@ -104,14 +102,13 @@ public static class MiraEventManager
} }
/// <summary> /// <summary>
/// Register a <typeparamref name="T"/> handler. /// Register an event.
/// </summary> /// </summary>
/// <param name="handler">The callback method/handler for the event.</param> /// <param name="handler">The callback method/handler for the event.</param>
/// <param name="priority">The priority of the event handler. Lower values are called first.</param> /// <param name="priority">The priority of the event handler. Lower values are called first.</param>
/// <typeparam name="T">Type of <see cref="MiraEvent"/> event.</typeparam> /// <typeparam name="T">Type of event.</typeparam>
/// <returns>A <see cref="MiraEventHandle"/> to use when unregistering the event.</returns> /// <returns>An event handle to use when unregistering the event.</returns>
public static MiraEventHandle RegisterEventHandler<T>(Action<T> handler, int priority = 0) public static MiraEventHandle RegisterEventHandler<T>(Action<T> handler, int priority = 0) where T : MiraEvent
where T : MiraEvent
{ {
EventWrappers.TryAdd(typeof(T), []); EventWrappers.TryAdd(typeof(T), []);
@@ -130,10 +127,10 @@ public static class MiraEventManager
} }
/// <summary> /// <summary>
/// Unregister a <see cref="MiraEvent"/> handler using the <see cref="MiraEventHandle"/>. /// Unregister an event using the event handle.
/// </summary> /// </summary>
/// <param name="eventHandle">A handle to the event.</param> /// <param name="eventHandle">A handle to the event.</param>
/// <returns><see langword="true"/> if the event was unregistered successfully, <see langword="false"/> otherwise.</returns> /// <returns>True if the event was unregistered successfully, false otherwise.</returns>
public static bool UnregisterEventHandler(MiraEventHandle eventHandle) public static bool UnregisterEventHandler(MiraEventHandle eventHandle)
{ {
if (!EventWrappers.TryGetValue(eventHandle.EventType, out var handlers)) if (!EventWrappers.TryGetValue(eventHandle.EventType, out var handlers))
@@ -150,7 +147,6 @@ public static class MiraEventManager
{ {
EventWrappers.Remove(eventHandle.EventType); EventWrappers.Remove(eventHandle.EventType);
} }
return true; return true;
} }
} }
+15 -6
View File
@@ -3,19 +3,28 @@
namespace MiraAPI.Events; namespace MiraAPI.Events;
/// <summary> /// <summary>
/// Wrapper for <see cref="MiraEvent"/> handlers. /// Wrapper for event handlers.
/// </summary> /// </summary>
/// <param name="eventHandler">The action for the event handler.</param> public class MiraEventWrapper
/// <param name="priority">The priority of the handler.</param>
public class MiraEventWrapper(Delegate eventHandler, int priority)
{ {
/// <summary> /// <summary>
/// Gets the event handler delegate. /// Gets the event handler delegate.
/// </summary> /// </summary>
public Delegate EventHandler { get; } = eventHandler; public Delegate EventHandler { get; }
/// <summary> /// <summary>
/// Gets the priority of the handler. Lower values are called first. /// Gets the priority of the handler. Lower values are called first.
/// </summary> /// </summary>
public int Priority { get; } = priority; public int Priority { get; }
/// <summary>
/// Initializes a new instance of the <see cref="MiraEventWrapper"/> class.
/// </summary>
/// <param name="eventHandler">The action for the event handler.</param>
/// <param name="priority">The priority of the handler.</param>
public MiraEventWrapper(Delegate eventHandler, int priority)
{
EventHandler = eventHandler;
Priority = priority;
}
} }
+12 -4
View File
@@ -3,14 +3,22 @@
namespace MiraAPI.Events; namespace MiraAPI.Events;
/// <summary> /// <summary>
/// Register a <see cref="MiraEvent"/> handler. /// Register an event.
/// </summary> /// </summary>
/// <param name="priority">The priority of the event. Lower values are called first.</param>
[AttributeUsage(AttributeTargets.Method)] [AttributeUsage(AttributeTargets.Method)]
public class RegisterEventAttribute(int priority = 0) : Attribute public class RegisterEventAttribute : Attribute
{ {
/// <summary> /// <summary>
/// Gets the priority of the event. Lower values are called first. /// Gets the priority of the event. Lower values are called first.
/// </summary> /// </summary>
public int Priority { get; } = priority; public int Priority { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RegisterEventAttribute"/> class.
/// </summary>
/// <param name="priority">The priority of the event. Lower values are called first.</param>
public RegisterEventAttribute(int priority = 0)
{
Priority = priority;
}
} }
@@ -3,66 +3,33 @@
/// <summary> /// <summary>
/// Event that is invoked after a player is murdered. Only called after a successful murder. This event is not cancelable. /// Event that is invoked after a player is murdered. Only called after a successful murder. This event is not cancelable.
/// </summary> /// </summary>
/// <param name="source">The <see cref="PlayerControl"/> that killed the <paramref name="target"/>.</param> public class AfterMurderEvent : MiraEvent
/// <param name="target">The <see cref="PlayerControl"/> that was killed.</param>
/// <param name="framed">The <see cref="PlayerControl"/> that was framed.</param>
/// <param name="deadBody">The <paramref name="target"/>'s <see cref="global::DeadBody"/>, if it exists.</param>
/// <param name="isIndirect">Whether the murder was caused indirectly.</param>
/// <param name="ignoreDefense">Whether the murder ignored protection.</param>
public class AfterMurderEvent(PlayerControl source, PlayerControl target, PlayerControl? framed, DeadBody? deadBody, bool isIndirect = true, bool ignoreDefense = false) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="PlayerControl"/> that killed the <see cref="Target"/>. /// Gets the player that killed the target.
/// </summary> /// </summary>
public PlayerControl Source { get; } = source; public PlayerControl Source { get; }
/// <summary> /// <summary>
/// Gets the <see cref="PlayerControl"/> that was killed. /// Gets the player that was killed.
/// </summary> /// </summary>
public PlayerControl Target { get; } = target; public PlayerControl Target { get; }
/// <summary> /// <summary>
/// Gets the <see cref="PlayerControl"/> that was framed, if any. /// Gets the player's body, if it exists.
/// </summary> /// </summary>
public PlayerControl? Framed { get; } = framed; public DeadBody? DeadBody { get; }
/// <summary>
/// Gets a value indicating whether the murder was done indirectly.
/// This is commonly used to prevent the <see cref="Source"/> <see cref="PlayerControl"/> from being killed.
/// </summary>
public bool IsIndirectAttack { get; } = isIndirect;
/// <summary>
/// Gets a value indicating whether the murder was able to bypass protective roles or general defense, such as <see cref="GuardianAngelRole"/>.
/// </summary>
public bool IgnoreDefense { get; } = ignoreDefense;
/// <summary>
/// Gets the <see cref="Target"/>'s <see cref="DeadBody"/>, if it exists.
/// </summary>
public DeadBody? DeadBody { get; } = deadBody;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="AfterMurderEvent"/> class. /// Initializes a new instance of the <see cref="AfterMurderEvent"/> class.
/// </summary> /// </summary>
/// <param name="source">The <see cref="PlayerControl"/> that killed the <paramref name="target"/>.</param> /// <param name="source">The killer.</param>
/// <param name="target">The <see cref="PlayerControl"/> that was killed.</param> /// <param name="target">The killed player.</param>
/// <param name="deadBody">The <paramref name="target"/>'s <see cref="DeadBody"/>, if it exists.</param> /// <param name="deadBody">The player's vody, if it exists.</param>
/// <param name="isIndirect">Whether the murder was caused indirectly.</param>
/// <param name="ignoreDefense">Whether the murder ignored protection.</param>
public AfterMurderEvent(PlayerControl source, PlayerControl target, DeadBody? deadBody, bool isIndirect, bool ignoreDefense = false)
: this(source, target, null, deadBody, isIndirect, ignoreDefense)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AfterMurderEvent"/> class.
/// </summary>
/// <param name="source">The <see cref="PlayerControl"/> that killed the <paramref name="target"/>.</param>
/// <param name="target">The <see cref="PlayerControl"/> that was killed.</param>
/// <param name="deadBody">The <paramref name="target"/>'s <see cref="DeadBody"/>, if it exists.</param>
public AfterMurderEvent(PlayerControl source, PlayerControl target, DeadBody? deadBody) public AfterMurderEvent(PlayerControl source, PlayerControl target, DeadBody? deadBody)
: this(source, target, null, deadBody)
{ {
Source = source;
Target = target;
DeadBody = deadBody;
} }
} }
@@ -1,13 +1,21 @@
namespace MiraAPI.Events.Vanilla.Gameplay; namespace MiraAPI.Events.Vanilla.Gameplay;
/// <summary> /// <summary>
/// Invoked before <see cref="GameManager.RpcEndGame"/> is called, allowing cancellation of the game end entirely. /// Invoked before RpcEndGame is called, allowing cancellation of the game end entirely.
/// </summary> /// </summary>
/// <param name="reason">The reason for the game end.</param> public class BeforeGameEndEvent : MiraCancelableEvent
public class BeforeGameEndEvent(GameOverReason reason) : MiraCancelableEvent
{ {
/// <summary> /// <summary>
/// Gets the reason for the game end. /// Gets the reason for the game end.
/// </summary> /// </summary>
public GameOverReason Reason { get; } = reason; public GameOverReason Reason { get; }
/// <summary>
/// Initializes a new instance of the <see cref="BeforeGameEndEvent"/> class.
/// </summary>
/// <param name="reason">The reason for the game end.</param>
public BeforeGameEndEvent(GameOverReason reason)
{
Reason = reason;
}
} }
@@ -1,71 +1,28 @@
using MiraAPI.Networking; namespace MiraAPI.Events.Vanilla.Gameplay;
namespace MiraAPI.Events.Vanilla.Gameplay;
/// <summary> /// <summary>
/// Event that is invoked before a player is murdered. This event is cancelable. /// Event that is invoked before a player is murdered. This event is cancelable.
/// </summary> /// </summary>
/// <param name="source">The <see cref="PlayerControl"/> that is killing the <paramref name="target"/>.</param> public sealed class BeforeMurderEvent : MiraCancelableEvent
/// <param name="target">The <see cref="PlayerControl"/> that is being killed.</param>
/// <param name="framed">The <see cref="PlayerControl"/> that is being framed.</param>
/// <param name="isIndirect">Whether the murder is caused indirectly.</param>
/// <param name="ignoreDefense">Whether the murder should ignore protection.</param>
/// <param name="inMeeting">Whether the murder is intended to be triggered in a meeting.</param>
public sealed class BeforeMurderEvent(PlayerControl source, PlayerControl target, PlayerControl? framed, bool isIndirect = true, bool ignoreDefense = false, MeetingCheck inMeeting = MeetingCheck.Ignore)
: MiraCancelableEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="PlayerControl"/> that is killing the <see cref="Target"/>. /// Gets the player that is killing the target.
/// </summary> /// </summary>
public PlayerControl Source { get; } = source; public PlayerControl Source { get; }
/// <summary> /// <summary>
/// Gets the <see cref="PlayerControl"/> that is being killed. /// Gets the player that is being killed.
/// </summary> /// </summary>
public PlayerControl Target { get; } = target; public PlayerControl Target { get; }
/// <summary>
/// Gets the <see cref="PlayerControl"/> that is being framed, if any.
/// </summary>
public PlayerControl? Framed { get; } = framed;
/// <summary>
/// Gets or sets a value indicating whether the murder is done indirectly.
/// This is commonly used to prevent the <see cref="Source"/> <see cref="PlayerControl"/> from being killed.
/// </summary>
public bool IsIndirectAttack { get; set; } = isIndirect;
/// <summary>
/// Gets or sets a value indicating whether the murder should bypass protective roles or general defense, such as <see cref="GuardianAngelRole"/>.
/// </summary>
public bool IgnoreDefense { get; set; } = ignoreDefense;
/// <summary>
/// Gets whether the murder was meant to be done in a meeting, via an enum.
/// </summary>
public MeetingCheck InMeeting { get; } = inMeeting;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BeforeMurderEvent"/> class. /// Initializes a new instance of the <see cref="BeforeMurderEvent"/> class.
/// </summary> /// </summary>
/// <param name="source">The <see cref="PlayerControl"/> that is killing the <paramref name="target"/>.</param> /// <param name="source">The player that is killing the target.</param>
/// <param name="target">The <see cref="PlayerControl"/> that is being killed.</param> /// <param name="target">The player that is being killed.</param>
/// <param name="inMeeting">Whether the murder is intended to be triggered in a meeting.</param> public BeforeMurderEvent(PlayerControl source, PlayerControl target)
public BeforeMurderEvent(PlayerControl source, PlayerControl target, MeetingCheck inMeeting = MeetingCheck.Ignore)
: this(source, target, false, false, inMeeting)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BeforeMurderEvent"/> class.
/// </summary>
/// <param name="source">The <see cref="PlayerControl"/> that is killing the <paramref name="target"/>.</param>
/// <param name="target">The <see cref="PlayerControl"/> that is being killed.</param>
/// <param name="isIndirect">Whether the murder is caused indirectly.</param>
/// <param name="ignoreDefense">Whether the murder should ignore protection.</param>
/// <param name="inMeeting">Whether the murder is intended to be triggered in a meeting.</param>
public BeforeMurderEvent(PlayerControl source, PlayerControl target, bool isIndirect, bool ignoreDefense = false, MeetingCheck inMeeting = MeetingCheck.Ignore)
: this(source, target, null, isIndirect, ignoreDefense, inMeeting)
{ {
Source = source;
Target = target;
} }
} }
@@ -1,13 +1,21 @@
namespace MiraAPI.Events.Vanilla.Gameplay; namespace MiraAPI.Events.Vanilla.Gameplay;
/// <summary> /// <summary>
/// Event invoked on <see cref="IntroCutscene.OnDestroy"/> and <see cref="ExileController.WrapUp"/> to determine if it should run the <see cref="RoundStartEvent"/> event or not. /// Event invoked on IntroCutscene.OnDestroy and ExileController.WrapUp to determine if it should run the round event or not.
/// </summary> /// </summary>
/// <param name="triggeredByIntro">Whether the event was triggered by the intro or not.</param> public class BeforeRoundStartEvent : MiraCancelableEvent
public class BeforeRoundStartEvent(bool triggeredByIntro) : MiraCancelableEvent
{ {
/// <summary> /// <summary>
/// Gets a value indicating whether the event was triggered by the <see cref="IntroCutscene"/> or <see cref="ExileController"/>. /// Gets a value indicating whether the event was triggered by the IntroCutscene or ExileController.
/// </summary> /// </summary>
public bool TriggeredByIntro { get; } = triggeredByIntro; public bool TriggeredByIntro { get; }
/// <summary>
/// Initializes a new instance of the <see cref="BeforeRoundStartEvent"/> class.
/// </summary>
/// <param name="triggeredByIntro">Whether the event was triggered by the intro or not.</param>
public BeforeRoundStartEvent(bool triggeredByIntro)
{
TriggeredByIntro = triggeredByIntro;
}
} }
@@ -1,13 +1,21 @@
namespace MiraAPI.Events.Vanilla.Gameplay; namespace MiraAPI.Events.Vanilla.Gameplay;
/// <summary> /// <summary>
/// The event that is invoked when the end game screen is shown. Non-cancelable. /// The event that is invoked when the end game screen is shown. Non cancelable.
/// </summary> /// </summary>
/// <param name="manager">The <see cref="global::EndGameManager"/> instance.</param> public class GameEndEvent : MiraEvent
public class GameEndEvent(EndGameManager manager) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="global::EndGameManager"/> instance. /// Gets the instance of the EndGameManager.
/// </summary> /// </summary>
public EndGameManager EndGameManager { get; } = manager; public EndGameManager EndGameManager { get; }
/// <summary>
/// Initializes a new instance of the <see cref="GameEndEvent"/> class.
/// </summary>
/// <param name="manager">The instance of the EndGameManager.</param>
public GameEndEvent(EndGameManager manager)
{
EndGameManager = manager;
}
} }
@@ -1,13 +1,21 @@
namespace MiraAPI.Events.Vanilla.Gameplay; namespace MiraAPI.Events.Vanilla.Gameplay;
/// <summary> /// <summary>
/// The event that is invoked when the intro cutscene is shown. Non-cancelable. /// The event that is invoked when the intro cutscene is shown. Non cancelable.
/// </summary> /// </summary>
/// <param name="introCutscene">The intro cutscene.</param> public class IntroBeginEvent : MiraEvent
public class IntroBeginEvent(IntroCutscene introCutscene) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="global::IntroCutscene"/> instance. /// Gets the instance of the IntroCutscene.
/// </summary> /// </summary>
public IntroCutscene IntroCutscene { get; } = introCutscene; public IntroCutscene IntroCutscene { get; }
/// <summary>
/// Initializes a new instance of the <see cref="IntroBeginEvent"/> class.
/// </summary>
/// <param name="introCutscene">The intro cutscene.</param>
public IntroBeginEvent(IntroCutscene introCutscene)
{
IntroCutscene = introCutscene;
}
} }
@@ -3,11 +3,10 @@
/// <summary> /// <summary>
/// The event that is invoked when the intro cutscene has finished playing. /// The event that is invoked when the intro cutscene has finished playing.
/// </summary> /// </summary>
/// <param name="introCutscene">The intro cutscene.</param>
public class IntroEndEvent(IntroCutscene introCutscene) : MiraEvent public class IntroEndEvent(IntroCutscene introCutscene) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="global::IntroCutscene"/> instance. /// Gets the instance of the IntroCutscene.
/// </summary> /// </summary>
public IntroCutscene IntroCutscene { get; } = introCutscene; public IntroCutscene IntroCutscene { get; } = introCutscene;
} }
@@ -1,13 +1,21 @@
namespace MiraAPI.Events.Vanilla.Gameplay; namespace MiraAPI.Events.Vanilla.Gameplay;
/// <summary> /// <summary>
/// The event that is invoked when the player's role is shown on the intro cutscene. Non-cancelable. /// The event that is invoked when the player's role is shown on the intro cutscene. Non cancelable.
/// </summary> /// </summary>
/// <param name="introCutscene">The intro cutscene.</param> public class IntroRoleRevealEvent : MiraEvent
public class IntroRoleRevealEvent(IntroCutscene introCutscene) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="global::IntroCutscene"/> instance. /// Gets the instance of the IntroCutscene.
/// </summary> /// </summary>
public IntroCutscene IntroCutscene { get; } = introCutscene; public IntroCutscene IntroCutscene { get; }
/// <summary>
/// Initializes a new instance of the <see cref="IntroRoleRevealEvent"/> class.
/// </summary>
/// <param name="introCutscene">The intro cutscene.</param>
public IntroRoleRevealEvent(IntroCutscene introCutscene)
{
IntroCutscene = introCutscene;
}
} }
@@ -1,14 +1,21 @@
namespace MiraAPI.Events.Vanilla.Gameplay; namespace MiraAPI.Events.Vanilla.Gameplay;
/// <summary> /// <summary>
/// Start Round event, invoked on <see cref="IntroCutscene.OnDestroy"/> and <see cref="ExileController.WrapUp"/> /// Start Round event, invoked on IntroCutscene.OnDestroy and ExileController.WrapUp if the event isn't cancelled.
/// if the <see cref="BeforeRoundStartEvent"/> isn't cancelled.
/// </summary> /// </summary>
/// <param name="triggeredByIntro">Whether the event was triggered by the intro or not.</param> public class RoundStartEvent : MiraEvent
public class RoundStartEvent(bool triggeredByIntro) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets a value indicating whether the event was triggered by the <see cref="IntroCutscene"/> or <see cref="ExileController"/>. /// Gets a value indicating whether the event was triggered by the IntroCutscene or ExileController.
/// </summary> /// </summary>
public bool TriggeredByIntro { get; } = triggeredByIntro; public bool TriggeredByIntro { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RoundStartEvent"/> class.
/// </summary>
/// <param name="triggeredByIntro">Whether the event was triggered by the intro or not.</param>
public RoundStartEvent(bool triggeredByIntro)
{
TriggeredByIntro = triggeredByIntro;
}
} }
@@ -5,17 +5,26 @@ namespace MiraAPI.Events.Vanilla.Gameplay;
/// <summary> /// <summary>
/// Event that is invoked after a player's role is set. This event is not cancelable. /// Event that is invoked after a player's role is set. This event is not cancelable.
/// </summary> /// </summary>
/// <param name="player">The player.</param> public class SetRoleEvent : MiraEvent
/// <param name="role">The new role.</param>
public class SetRoleEvent(PlayerControl player, RoleTypes role) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="PlayerControl"/> whose role was changed. /// Gets the player whos role was changed.
/// </summary> /// </summary>
public PlayerControl Player { get; } = player; public PlayerControl Player { get; }
/// <summary> /// <summary>
/// Gets the role that the player was set to. /// Gets the role that the player was set to.
/// </summary> /// </summary>
public RoleTypes Role { get; } = role; public RoleTypes Role { get; }
/// <summary>
/// Initializes a new instance of the <see cref="SetRoleEvent"/> class.
/// </summary>
/// <param name="player">The player.</param>
/// <param name="role">The new role.</param>
public SetRoleEvent(PlayerControl player, RoleTypes role)
{
Player = player;
Role = role;
}
} }
@@ -1,29 +0,0 @@
using MiraAPI.Hud;
namespace MiraAPI.Events.Vanilla.Gameplay;
/// <summary>
/// Invoked when a Vanilla <see cref="AbilityButton"/> click is cancelled. Do not use for <see cref="CustomActionButton"/>.
/// </summary>
/// <typeparam name="T">The vanilla <see cref="AbilityButton"/> type.</typeparam>
/// <param name="button">The vanilla <see cref="AbilityButton"/> whose click was cancelled.</param>
public sealed class VanillaButtonCancelledEvent<T>(T button) : MiraEvent
where T : AbilityButton
{
/// <summary>
/// Gets the Vanilla <see cref="AbilityButton"/> whose click was cancelled.
/// </summary>
public T Button { get; } = button;
}
/// <summary>
/// Invoked when a Vanilla <see cref="AbilityButton"/> click is cancelled. Do not use for <see cref="CustomActionButton"/>s.
/// </summary>
/// <param name="button">The vanilla <see cref="AbilityButton"/> whose click was cancelled.</param>
public sealed class VanillaButtonCancelledEvent(AbilityButton button) : MiraEvent
{
/// <summary>
/// Gets the Vanilla <see cref="AbilityButton"/> whose click was cancelled.
/// </summary>
public AbilityButton Button { get; } = button;
}
@@ -1,47 +0,0 @@
using MiraAPI.Hud;
namespace MiraAPI.Events.Vanilla.Gameplay;
/// <summary>
/// Button click event for Vanilla <see cref="AbilityButton"/>s only. Do not use for <see cref="CustomActionButton"/>s.
/// </summary>
/// <typeparam name="T">The vanilla <see cref="AbilityButton"/> type.</typeparam>
/// <param name="button">The vanilla <see cref="AbilityButton"/> that was clicked.</param>
/// <param name="genericClickEvent">The generic <see cref="VanillaButtonClickEvent"/> invoked before button-specific events.</param>
public sealed class VanillaButtonClickEvent<T>(T button, VanillaButtonClickEvent genericClickEvent) : MiraCancelableEvent
where T : AbilityButton
{
/// <summary>
/// Gets the vanilla <see cref="AbilityButton"/> that was clicked.
/// </summary>
public T Button { get; } = button;
/// <summary>
/// Gets the generic <see cref="VanillaButtonClickEvent"/> that is invoked before this button-specific event.
/// </summary>
public VanillaButtonClickEvent GenericClickEvent { get; } = genericClickEvent;
}
/// <summary>
/// Button click event for Vanilla <see cref="AbilityButton"/> only. Do not use for <see cref="CustomActionButton"/>s.
/// </summary>
/// <param name="button">The Vanilla <see cref="AbilityButton"/> that was clicked.</param>
/// <param name="playerTarget">The <see cref="PlayerControl"/> target, if any.</param>
/// <param name="ventTarget">The <see cref="Vent"/> target, if any.</param>
public sealed class VanillaButtonClickEvent(AbilityButton button, PlayerControl? playerTarget = null, Vent? ventTarget = null) : MiraCancelableEvent
{
/// <summary>
/// Gets the Vanilla <see cref="AbilityButton"/> that was clicked.
/// </summary>
public AbilityButton Button { get; } = button;
/// <summary>
/// Gets the target <see cref="PlayerControl"/>, if any, of the Vanilla <see cref="AbilityButton"/> that was clicked.
/// </summary>
public PlayerControl? PlayerTarget { get; } = playerTarget;
/// <summary>
/// Gets the target <see cref="Vent"/>, if any, of the Vanilla <see cref="AbilityButton"/> that was clicked.
/// </summary>
public Vent? VentTarget { get; } = ventTarget;
}
+11 -3
View File
@@ -3,11 +3,19 @@
/// <summary> /// <summary>
/// Event fired when a player closes the doors in a room. /// Event fired when a player closes the doors in a room.
/// </summary> /// </summary>
/// <param name="room">The room that was closed.</param> public class CloseDoorsEvent : MiraCancelableEvent
public class CloseDoorsEvent(SystemTypes room) : MiraCancelableEvent
{ {
/// <summary> /// <summary>
/// Gets the room that the doors were closed in. /// Gets the room that the doors were closed in.
/// </summary> /// </summary>
public SystemTypes Room { get; } = room; public SystemTypes Room { get; }
/// <summary>
/// Initializes a new instance of the <see cref="CloseDoorsEvent"/> class.
/// </summary>
/// <param name="room">The room that was closed.</param>
public CloseDoorsEvent(SystemTypes room)
{
Room = room;
}
} }
@@ -3,11 +3,19 @@
/// <summary> /// <summary>
/// Sabotage from Vanilla Among Us. /// Sabotage from Vanilla Among Us.
/// </summary> /// </summary>
/// <param name="mapBehaviour">The <see cref="global::MapBehaviour"/>.</param> public class PlayerOpenSabotageEvent : MiraCancelableEvent
public class PlayerOpenSabotageEvent(MapBehaviour mapBehaviour) : MiraCancelableEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="global::MapBehaviour"/>. /// Gets the MapBehaviour.
/// </summary> /// </summary>
public MapBehaviour MapBehaviour { get; } = mapBehaviour; public MapBehaviour MapBehaviour { get; }
/// <summary>
/// Initializes a new instance of the <see cref="PlayerOpenSabotageEvent"/> class.
/// </summary>
/// <param name="mapBehaviour">The MapBehaviour.</param>
public PlayerOpenSabotageEvent(MapBehaviour mapBehaviour)
{
MapBehaviour = mapBehaviour;
}
} }
@@ -1,25 +1,35 @@
namespace MiraAPI.Events.Vanilla.Map; namespace MiraAPI.Events.Vanilla.Map;
/// <summary> /// <summary>
/// <see cref="MiraCancelableEvent"/> that is invoked before a system is updated. Usually used for sabotage events. /// Cancelable event that is invoked before a system is updated. Usually used for sabotage events.
/// </summary> /// </summary>
/// <param name="systemType">The <see cref="SystemTypes"/> being updated.</param> public class UpdateSystemEvent : MiraCancelableEvent
/// <param name="player">The <see cref="PlayerControl"/> that is updating the system.</param>
/// <param name="amount">Amount to update System to.</param>
public class UpdateSystemEvent(SystemTypes systemType, PlayerControl player, byte amount) : MiraCancelableEvent
{ {
/// <summary> /// <summary>
/// Gets the type of system that will be updated. /// Gets the type of system that will be updated.
/// </summary> /// </summary>
public SystemTypes SystemType { get; } = systemType; public SystemTypes SystemType { get; }
/// <summary> /// <summary>
/// Gets the <see cref="PlayerControl"/> that is updating the system. /// Gets the player that is updating the system.
/// </summary> /// </summary>
public PlayerControl Player { get; } = player; public PlayerControl Player { get; }
/// <summary> /// <summary>
/// Gets the byte amount the system is being updated by. /// Gets the byte amount the system is being updated by.
/// </summary> /// </summary>
public byte Amount { get; } = amount; public byte Amount { get; }
/// <summary>
/// Initializes a new instance of the <see cref="UpdateSystemEvent"/> class.
/// </summary>
/// <param name="systemType">The SystemType being updated.</param>
/// <param name="player">The player that is updating the system.</param>
/// <param name="amount">Amount to update System to.</param>
public UpdateSystemEvent(SystemTypes systemType, PlayerControl player, byte amount)
{
SystemType = systemType;
Player = player;
Amount = amount;
}
} }
@@ -3,11 +3,19 @@
/// <summary> /// <summary>
/// The event that is invoked when a player is ejected. Non-cancelable. /// The event that is invoked when a player is ejected. Non-cancelable.
/// </summary> /// </summary>
/// <param name="controller">The <see cref="global::ExileController"/> instance.</param> public class EjectionEvent : MiraEvent
public class EjectionEvent(ExileController controller) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="global::ExileController"/> instance. /// Gets the instance of the ExileController.
/// </summary> /// </summary>
public ExileController ExileController { get; } = controller; public ExileController ExileController { get; }
/// <summary>
/// Initializes a new instance of the <see cref="EjectionEvent"/> class.
/// </summary>
/// <param name="controller">The exile controller.</param>
public EjectionEvent(ExileController controller)
{
ExileController = controller;
}
} }
@@ -6,7 +6,7 @@
public class EndMeetingEvent(MeetingHud meetingHud) : MiraEvent public class EndMeetingEvent(MeetingHud meetingHud) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="global::MeetingHud"/> instance. /// Gets the MeetingHud instance.
/// </summary> /// </summary>
public MeetingHud MeetingHud { get; } = meetingHud; public MeetingHud MeetingHud { get; } = meetingHud;
} }
@@ -1,26 +1,36 @@
namespace MiraAPI.Events.Vanilla.Meeting; namespace MiraAPI.Events.Vanilla.Meeting;
/// <summary> /// <summary>
/// The event that is invoked when a body is reported.<br/> /// The event that is invoked when a body is reported.
/// This is invoked in <see cref="PlayerControl.CmdReportDeadBody(NetworkedPlayerInfo)"/>. /// This is invoked in CmdReportBody.
/// </summary> /// </summary>
/// <param name="reporter">The player who reported the body.</param> public class ReportBodyEvent : MiraCancelableEvent
/// <param name="target">The player being reported.</param>
/// <param name="body">The <see cref="DeadBody"/> being reported.</param>
public class ReportBodyEvent(PlayerControl reporter, NetworkedPlayerInfo? target, DeadBody? body) : MiraCancelableEvent
{ {
/// <summary> /// <summary>
/// Gets the player that is reporting the body. /// Gets the player that is reporting the body.
/// </summary> /// </summary>
public PlayerControl Reporter { get; } = reporter; public PlayerControl Reporter { get; }
/// <summary> /// <summary>
/// Gets the player that is being reported. Will be <see langword="null"/> for emergency meeting. /// Gets the player that is being reported. Will be null for emergency meeting.
/// </summary> /// </summary>
public NetworkedPlayerInfo? Target { get; } = target; public NetworkedPlayerInfo? Target { get; }
/// <summary> /// <summary>
/// Gets the <see cref="DeadBody"/> that is being reported. Will be <see langword="null"/> for emergency meeting. /// Gets the body that is being reported. Will be null for emergency meeting.
/// </summary> /// </summary>
public DeadBody? Body { get; } = body; public DeadBody? Body { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ReportBodyEvent"/> class.
/// </summary>
/// <param name="reporter">The player who reported the body.</param>
/// <param name="target">The player being reported.</param>
/// <param name="body">The body being reported.</param>
public ReportBodyEvent(PlayerControl reporter, NetworkedPlayerInfo? target, DeadBody? body)
{
Reporter = reporter;
Target = target;
Body = body;
}
} }
@@ -4,11 +4,19 @@
/// The event that is invoked when a meeting is called. This event is not cancelable. /// The event that is invoked when a meeting is called. This event is not cancelable.
/// This event is called after Mira resets votes, so if you plan on adding votes to a specific player, do it with this event. /// This event is called after Mira resets votes, so if you plan on adding votes to a specific player, do it with this event.
/// </summary> /// </summary>
/// <param name="meetingHud">The <see cref="global::MeetingHud"/> instance.</param> public class StartMeetingEvent : MiraEvent
public class StartMeetingEvent(MeetingHud meetingHud) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="global::MeetingHud"/> instance. /// Gets the MeetingHud instance.
/// </summary> /// </summary>
public MeetingHud MeetingHud { get; } = meetingHud; public MeetingHud MeetingHud { get; }
/// <summary>
/// Initializes a new instance of the <see cref="StartMeetingEvent"/> class.
/// </summary>
/// <param name="meetingHud">The MeetingHud instance.</param>
public StartMeetingEvent(MeetingHud meetingHud)
{
MeetingHud = meetingHud;
}
} }
@@ -1,19 +1,30 @@
namespace MiraAPI.Events.Vanilla.Meeting.Voting; using MiraAPI.Voting;
namespace MiraAPI.Events.Vanilla.Meeting.Voting;
/// <summary> /// <summary>
/// Event that is invoked after the local player successfully votes a player or skips. This event is not cancelable. /// Event that is invoked after the local player successfully votes a player or skips. This event is not cancelable.
/// </summary> /// </summary>
/// <param name="playerVoteArea">The <see cref="PlayerVoteArea"/> that was voted on.</param> public class AfterVoteEvent : MiraEvent
/// <param name="voter">The player who voted.</param>
public class AfterVoteEvent(PlayerVoteArea playerVoteArea, PlayerControl voter) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the instance of the voter's <see cref="PlayerVoteArea"/>. /// Gets the instance of the voter's vote data.
/// </summary> /// </summary>
public PlayerVoteArea VoteArea { get; } = playerVoteArea; public PlayerVoteArea VoteArea { get; }
/// <summary> /// <summary>
/// Gets the player who voted. /// Gets the player who voted.
/// </summary> /// </summary>
public PlayerControl Player { get; } = voter; public PlayerControl Player { get; }
/// <summary>
/// Initializes a new instance of the <see cref="AfterVoteEvent"/> class.
/// </summary>
/// <param name="playerVoteArea">The player vote area that was voted on.</param>
/// <param name="voter">The player who voted.</param>
public AfterVoteEvent(PlayerVoteArea playerVoteArea, PlayerControl voter)
{
VoteArea = playerVoteArea;
Player = voter;
}
} }
@@ -1,19 +1,30 @@
namespace MiraAPI.Events.Vanilla.Meeting.Voting; using MiraAPI.Voting;
namespace MiraAPI.Events.Vanilla.Meeting.Voting;
/// <summary> /// <summary>
/// Event that is invoked before the local player confirms a vote on a player or when skipping. This event is cancelable. /// Event that is invoked before the local player confirms a vote on a player or when skipping. This event is cancelable.
/// </summary> /// </summary>
/// <param name="playerVoteArea">The <see cref="PlayerVoteArea"/> that was voted on.</param> public class BeforeVoteEvent : MiraCancelableEvent
/// <param name="voter">The player who voted.</param>
public class BeforeVoteEvent(PlayerVoteArea playerVoteArea, PlayerControl voter) : MiraCancelableEvent
{ {
/// <summary> /// <summary>
/// Gets the instance of the voter's <see cref="PlayerVoteArea"/>. /// Gets the instance of the voter's vote data.
/// </summary> /// </summary>
public PlayerVoteArea VoteArea { get; } = playerVoteArea; public PlayerVoteArea VoteArea { get; }
/// <summary> /// <summary>
/// Gets the player who voted. /// Gets the player who voted.
/// </summary> /// </summary>
public PlayerControl Player { get; } = voter; public PlayerControl Player { get; }
/// <summary>
/// Initializes a new instance of the <see cref="BeforeVoteEvent"/> class.
/// </summary>
/// <param name="playerVoteArea">The player vote area that was voted on.</param>
/// <param name="voter">The player who voted.</param>
public BeforeVoteEvent(PlayerVoteArea playerVoteArea, PlayerControl voter)
{
VoteArea = playerVoteArea;
Player = voter;
}
} }
@@ -3,16 +3,24 @@
/// <summary> /// <summary>
/// Checks if voting is complete. If canceled, the default end voting logic will be skipped. /// Checks if voting is complete. If canceled, the default end voting logic will be skipped.
/// </summary> /// </summary>
/// <param name="isVotingComplete"><see langword="true"/> if voting is complete, <see langword="false"/> otherwise.</param> public class CheckForEndVotingEvent : MiraCancelableEvent
public class CheckForEndVotingEvent(bool isVotingComplete) : MiraCancelableEvent
{ {
/// <summary> /// <summary>
/// Gets a value indicating whether default voting logic determines that voting is complete. /// Gets a value indicating whether default voting logic determines that voting is complete.
/// </summary> /// </summary>
public bool IsVotingComplete { get; } = isVotingComplete; public bool IsVotingComplete { get; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the voting should be forced to end, regardless of the default logic. /// Gets or sets a value indicating whether the voting should be forced to end, regardless of the default logic.
/// </summary> /// </summary>
public bool ForceEndVoting { get; set; } public bool ForceEndVoting { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="CheckForEndVotingEvent"/> class.
/// </summary>
/// <param name="isVotingComplete">>True if voting is complete, false otherwise.</param>
public CheckForEndVotingEvent(bool isVotingComplete)
{
IsVotingComplete = isVotingComplete;
}
} }
@@ -7,27 +7,38 @@ namespace MiraAPI.Events.Vanilla.Meeting.Voting;
/// <summary> /// <summary>
/// Invoked before the dummy selects their vote. If canceled, the dummy won't vote. /// Invoked before the dummy selects their vote. If canceled, the dummy won't vote.
/// </summary> /// </summary>
/// <param name="dummy">The voting dummy.</param> public class DummyVoteEvent : MiraCancelableEvent
public class DummyVoteEvent(DummyBehaviour dummy) : MiraCancelableEvent
{ {
/// <summary> /// <summary>
/// Gets the dummy that needs to vote. /// Gets the dummy that needs to vote.
/// </summary> /// </summary>
public DummyBehaviour Dummy { get; } = dummy; public DummyBehaviour Dummy { get; }
/// <summary> /// <summary>
/// Gets the instance of the dummy's <see cref="PlayerVoteData"/>. /// Gets the instance of the dummy's vote data.
/// </summary> /// </summary>
public PlayerVoteData VoteData { get; } = dummy.myPlayer.GetVoteData(); public PlayerVoteData VoteData { get; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the dummy can vote to skip the meeting. /// Gets or sets a value indicating whether the dummy can vote to skip the meeting.
/// </summary> /// </summary>
public bool CanSkip { get; set; } = true; public bool CanSkip { get; set; }
/// <summary> /// <summary>
/// Gets or sets a predicate for validating whether the dummy can vote on a player. /// Gets or sets a predicate for validating whether the dummy can vote on a player.
/// By default, excludes dead and disconnected players. /// By default, excludes dead and disconnected players.
/// </summary> /// </summary>
public Predicate<PlayerControl> PlayerIsValid { get; set; } = x => !x.Data.IsDead && !x.Data.Disconnected; public Predicate<PlayerControl> PlayerIsValid { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="DummyVoteEvent"/> class.
/// </summary>
/// <param name="dummy">The voting dummy.</param>
public DummyVoteEvent(DummyBehaviour dummy)
{
Dummy = dummy;
VoteData = dummy.myPlayer.GetVoteData();
CanSkip = true;
PlayerIsValid = x => !x.Data.IsDead && !x.Data.Disconnected;
}
} }
@@ -4,43 +4,47 @@ namespace MiraAPI.Events.Vanilla.Meeting.Voting;
/// <summary> /// <summary>
/// The event that is invoked when Mira handles a vote. This is invoked before Mira's behaviour, so be cautious. /// The event that is invoked when Mira handles a vote. This is invoked before Mira's behaviour, so be cautious.
/// If you intend on adding custom vote behaviour, cancel the event and do so.
/// If you are NOT canceling the event, keep in mind that Mira automatically removes a vote and adds the suspect to the VotedPlayers list after this event is invoked.
/// </summary> /// </summary>
/// <remarks> public class HandleVoteEvent : MiraCancelableEvent
/// If you intend on adding custom vote behaviour, cancel the event and do so.<br/>
/// If you are NOT canceling the event, keep in mind that Mira automatically removes a vote and adds the suspect to the <see cref="PlayerVoteData.Votes"/> list after this event is invoked.
/// </remarks>
/// <param name="playerVoteData">The voter's <see cref="PlayerVoteData"/>.</param>
/// <param name="targetId">The target's playerId.</param>
/// <param name="isOverruling">Whether the vote is actually for a Judge.</param>
public class HandleVoteEvent(PlayerVoteData playerVoteData, byte targetId, bool isOverruling = false) : MiraCancelableEvent
{ {
/// <summary> /// <summary>
/// Gets the instance of the voter's <see cref="PlayerVoteData"/>. /// Gets the instance of the voter's vote data.
/// </summary> /// </summary>
public PlayerVoteData VoteData { get; } = playerVoteData; public PlayerVoteData VoteData { get; }
/// <summary> /// <summary>
/// Gets the player who voted. /// Gets the player who voted.
/// </summary> /// </summary>
public PlayerControl Player { get; } = playerVoteData.Owner; public PlayerControl Player { get; }
/// <summary> /// <summary>
/// Gets the player id of the target. /// Gets the player id of the target.
/// </summary> /// </summary>
public byte TargetId { get; } = targetId; public byte TargetId { get; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether to prevent the vote from commencing. /// Gets a value indicating whether to prevent the vote from commencing.
/// </summary> /// </summary>
public bool PreventVote { get; set; } = false; public bool PreventVote { get; }
/// <summary> /// <summary>
/// Gets the <see cref="NetworkedPlayerInfo"/> of the target. /// Gets the player info of the target.
/// </summary> /// </summary>
public NetworkedPlayerInfo TargetPlayerInfo { get; } = GameData.Instance.GetPlayerById(targetId); public NetworkedPlayerInfo TargetPlayerInfo { get; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the vote event is an Overrule caused by a Judge. /// Initializes a new instance of the <see cref="HandleVoteEvent"/> class.
/// </summary> /// </summary>
public bool IsOverruling { get; set; } = isOverruling; /// <param name="playerVoteData">The voter's data.</param>
/// <param name="targetId">The target's playerId.</param>
public HandleVoteEvent(PlayerVoteData playerVoteData, byte targetId)
{
VoteData = playerVoteData;
Player = playerVoteData.Owner;
TargetId = targetId;
PreventVote = false;
TargetPlayerInfo = GameData.Instance.GetPlayerById(targetId);
}
} }
@@ -5,28 +5,39 @@ namespace MiraAPI.Events.Vanilla.Meeting.Voting;
/// <summary> /// <summary>
/// The event that is invoked when the player tries to select another player to vote. /// The event that is invoked when the player tries to select another player to vote.
/// </summary> /// </summary>
/// <param name="playerVoteData">The voter's <see cref="PlayerVoteData"/>.</param> public class MeetingSelectEvent : MiraEvent
/// <param name="targetId">The target's playerId.</param>
/// <param name="allowSelect">Whether the player is allowed to select the target.</param>
public class MeetingSelectEvent(PlayerVoteData playerVoteData, int targetId, bool allowSelect) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the instance of the voter's <see cref="PlayerVoteData"/>. /// Gets the instance of the voter's vote data.
/// </summary> /// </summary>
public PlayerVoteData VoteData { get; } = playerVoteData; public PlayerVoteData VoteData { get; }
/// <summary> /// <summary>
/// Gets the player id of the target. /// Gets the player id of the target.
/// </summary> /// </summary>
public int TargetId { get; } = targetId; public int TargetId { get; }
/// <summary> /// <summary>
/// Gets the <see cref="NetworkedPlayerInfo"/> of the target. /// Gets the player info of the target.
/// </summary> /// </summary>
public NetworkedPlayerInfo TargetPlayerInfo { get; } = GameData.Instance.GetPlayerById((byte)targetId); public NetworkedPlayerInfo TargetPlayerInfo { get; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the player is allowed to select the target. /// Gets or sets a value indicating whether the player is allowed to select the target.
/// </summary> /// </summary>
public bool AllowSelect { get; set; } = allowSelect; public bool AllowSelect { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="MeetingSelectEvent"/> class.
/// </summary>
/// <param name="playerVoteData">The voter's data.</param>
/// <param name="targetId">The target's playerId.</param>
/// <param name="allowSelect">>Whether the player is allowed to select the target.</param>
public MeetingSelectEvent(PlayerVoteData playerVoteData, int targetId, bool allowSelect)
{
VoteData = playerVoteData;
TargetId = targetId;
TargetPlayerInfo = GameData.Instance.GetPlayerById((byte)targetId);
AllowSelect = allowSelect;
}
} }
@@ -4,16 +4,22 @@ using MiraAPI.Voting;
namespace MiraAPI.Events.Vanilla.Meeting.Voting; namespace MiraAPI.Events.Vanilla.Meeting.Voting;
/// <summary> /// <summary>
/// Called in <see cref="VotingUtils.HandlePopulateResults"/>. /// Called in VotingUtils.HandlePopulateResults.
/// </summary>
/// <remarks>
/// Cancelling is NOT advised but if you do plan on cancelling, please ensure you account for displaying ALL player's votes. /// Cancelling is NOT advised but if you do plan on cancelling, please ensure you account for displaying ALL player's votes.
/// </remarks> /// </summary>
/// <param name="votes">The list of <see cref="CustomVote"/>s.</param> public class PopulateResultsEvent : MiraCancelableEvent
public class PopulateResultsEvent(List<CustomVote> votes) : MiraCancelableEvent
{ {
/// <summary> /// <summary>
/// Gets a list of networked <see cref="CustomVote"/>s. /// Gets a list of networked votes.
/// </summary> /// </summary>
public List<CustomVote> Votes { get; } = votes; public List<CustomVote> Votes { get; }
/// <summary>
/// Initializes a new instance of the <see cref="PopulateResultsEvent"/> class.
/// </summary>
/// <param name="votes">The list of votes.</param>
public PopulateResultsEvent(List<CustomVote> votes)
{
Votes = votes;
}
} }
@@ -1,5 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using MiraAPI.Voting; using MiraAPI.Voting;
@@ -8,11 +7,16 @@ namespace MiraAPI.Events.Vanilla.Meeting.Voting;
/// <summary> /// <summary>
/// Ran after calculating votes and before displaying the results. Only ran on the host. /// Ran after calculating votes and before displaying the results. Only ran on the host.
/// </summary> /// </summary>
/// <param name="votes">The list of <see cref="CustomVote"/>s that are being processed.</param> /// <remarks>
/// <param name="exiledPlayer">The player to be exiled. Will be <see langword="null"/> if no player is to be exiled.</param> /// Initializes a new instance of the <see cref="ProcessVotesEvent"/> class.
/// </remarks>
/// <param name="votes">>The list of votes that are being processed.</param>
/// <param name="exiledPlayer">The player to be exiled. Will be null if no player is to be exiled.</param>
public class ProcessVotesEvent(List<CustomVote> votes, NetworkedPlayerInfo? exiledPlayer = null) : MiraEvent public class ProcessVotesEvent(List<CustomVote> votes, NetworkedPlayerInfo? exiledPlayer = null) : MiraEvent
{ {
private readonly List<CustomVote> originalVotes = [.. votes]; private readonly List<CustomVote> _originalVotes = [.. votes];
private NetworkedPlayerInfo? _exiledPlayer = exiledPlayer;
/// <summary> /// <summary>
/// Gets a value indicating whether the exiled player has been modified by the event. /// Gets a value indicating whether the exiled player has been modified by the event.
@@ -22,35 +26,23 @@ public class ProcessVotesEvent(List<CustomVote> votes, NetworkedPlayerInfo? exil
/// <summary> /// <summary>
/// Gets a value indicating whether the votes have been modified by the event. /// Gets a value indicating whether the votes have been modified by the event.
/// </summary> /// </summary>
public bool VotesModified => !Votes.SequenceEqual(originalVotes); public bool VotesModified => !Votes.SequenceEqual(_originalVotes);
/// <summary> /// <summary>
/// Gets the list of <see cref="CustomVote"/>s that are being processed. /// Gets the list of votes that are being processed.
/// </summary> /// </summary>
public List<CustomVote> Votes { get; } = votes; public List<CustomVote> Votes { get; } = votes;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether an overruling was done. Normally set by judge but can be overwritten. /// Gets or sets the player to be exiled. Will be null if no player is to be exiled.
/// </summary> /// </summary>
public bool OverruledVote { get; set; }
/// <summary>
/// Gets or sets a value specifically to determine which Judge (if any) caused the overruling. Normally set by judge but can be overwritten.
/// </summary>
public ushort OverruledNonce { get; set; }
/// <summary>
/// Gets or sets the player to be exiled. Will be <see langword="null"/> if no player is to be exiled.
/// </summary>
[SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1513:Closing brace should be followed by blank line", Justification = "Looks weird.")]
public NetworkedPlayerInfo? ExiledPlayer public NetworkedPlayerInfo? ExiledPlayer
{ {
get; get => _exiledPlayer;
set set
{ {
field = value; _exiledPlayer = value;
ExiledPlayerModified = true; ExiledPlayerModified = true;
} }
} }
= exiledPlayer;
} }
@@ -3,11 +3,11 @@
/// <summary> /// <summary>
/// The event that is invoked when the voting phase of a meeting is complete. /// The event that is invoked when the voting phase of a meeting is complete.
/// </summary> /// </summary>
/// <param name="meetingHud">The <see cref="global::MeetingHud"/> instance.</param> /// <param name="meetingHud">The MeetingHud instance.</param>
public class VotingCompleteEvent(MeetingHud meetingHud) : MiraEvent public class VotingCompleteEvent(MeetingHud meetingHud) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="global::MeetingHud"/> instance. /// Gets the MeetingHud instance.
/// </summary> /// </summary>
public MeetingHud MeetingHud { get; } = meetingHud; public MeetingHud MeetingHud { get; } = meetingHud;
} }
@@ -1,25 +0,0 @@
namespace MiraAPI.Events.Vanilla.Player;
/// <summary>
/// The event that is invoked when a player completes a task within Hide and Seek. Non-cancelable.
/// </summary>
/// <param name="hnsManager">The <see cref="HideAndSeekManager"/> currently active.</param>
/// <param name="player">The player who completed the task.</param>
/// <param name="task">The task that the player completed.</param>
public class CompleteHnsTaskEvent(HideAndSeekManager hnsManager, PlayerControl player, PlayerTask task) : MiraEvent
{
/// <summary>
/// Gets the instance of the <see cref="PlayerControl"/>.
/// </summary>
public PlayerControl Player { get; } = player;
/// <summary>
/// Gets the instance of the <see cref="PlayerTask"/> that the player completed.
/// </summary>
public PlayerTask Task { get; } = task;
/// <summary>
/// Gets the instance of the <see cref="HideAndSeekManager"/> attached to the game.
/// </summary>
public HideAndSeekManager HnsManager { get; } = hnsManager;
}
@@ -1,19 +1,28 @@
namespace MiraAPI.Events.Vanilla.Player; namespace MiraAPI.Events.Vanilla.Player;
/// <summary> /// <summary>
/// The event that is invoked when a player completes a task. Non-cancelable. /// The event that is invoked when a player completes a task. Non cancelable.
/// </summary> /// </summary>
/// <param name="player">The player who completed the task.</param> public class CompleteTaskEvent : MiraEvent
/// <param name="task">The task that the player completed.</param>
public class CompleteTaskEvent(PlayerControl player, PlayerTask task) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the instance of the <see cref="PlayerControl"/>. /// Gets the instance of the <see cref="PlayerControl"/>.
/// </summary> /// </summary>
public PlayerControl Player { get; } = player; public PlayerControl Player { get; }
/// <summary> /// <summary>
/// Gets the instance of the <see cref="PlayerTask"/> that the player completed. /// Gets the instance of the <see cref="PlayerTask"/> that the player completed.
/// </summary> /// </summary>
public PlayerTask Task { get; } = task; public PlayerTask Task { get; }
/// <summary>
/// Initializes a new instance of the <see cref="CompleteTaskEvent"/> class.
/// </summary>
/// <param name="player">The player who completed the task.</param>
/// <param name="task">The task that the player completed.</param>
public CompleteTaskEvent(PlayerControl player, PlayerTask task)
{
Player = player;
Task = task;
}
} }
@@ -1,25 +1,35 @@
namespace MiraAPI.Events.Vanilla.Player; namespace MiraAPI.Events.Vanilla.Player;
/// <summary> /// <summary>
/// Event that is invoked when a player dies. Non-cancelable. /// Event that is invoked when a player dies. Non cancelable.
/// </summary> /// </summary>
/// <param name="player">The player who died.</param> public class PlayerDeathEvent : MiraEvent
/// <param name="reason">The reason the player died.</param>
/// <param name="deadBody">The player's <see cref="global::DeadBody"/>, if it exists.</param>
public class PlayerDeathEvent(PlayerControl player, DeathReason reason, DeadBody? deadBody) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the player who died. /// Gets the player who died.
/// </summary> /// </summary>
public PlayerControl Player { get; } = player; public PlayerControl Player { get; }
/// <summary> /// <summary>
/// Gets the reason the player died. /// Gets the reason the player died.
/// </summary> /// </summary>
public DeathReason DeathReason { get; } = reason; public DeathReason DeathReason { get; }
/// <summary> /// <summary>
/// Gets the <see cref="global::DeadBody"/> associated with the player, if any. /// Gets the dead body associated with the player, if any.
/// </summary> /// </summary>
public DeadBody? DeadBody { get; } = deadBody; public DeadBody? DeadBody { get; }
/// <summary>
/// Initializes a new instance of the <see cref="PlayerDeathEvent"/> class.
/// </summary>
/// <param name="player">The player who died.</param>
/// <param name="reason">The reason the player died.</param>
/// <param name="deadBody">The player's body, if it exists.</param>
public PlayerDeathEvent(PlayerControl player, DeathReason reason, DeadBody? deadBody)
{
Player = player;
DeathReason = reason;
DeadBody = deadBody;
}
} }
@@ -3,13 +3,21 @@
namespace MiraAPI.Events.Vanilla.Player; namespace MiraAPI.Events.Vanilla.Player;
/// <summary> /// <summary>
/// Event that is invoked when a player joins the lobby. Non-cancelable. /// Event that is invoked when a player joins the lobby. Non cancelable.
/// </summary> /// </summary>
/// <param name="data">The data of the player who joined.</param> public class PlayerJoinEvent : MiraEvent
public class PlayerJoinEvent(ClientData data) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the player who joined. /// Gets the player who joined.
/// </summary> /// </summary>
public ClientData ClientData { get; } = data; public ClientData ClientData { get; }
/// <summary>
/// Initializes a new instance of the <see cref="PlayerJoinEvent"/> class.
/// </summary>
/// <param name="data">The data of the player who joined.</param>
public PlayerJoinEvent(ClientData data)
{
ClientData = data;
}
} }
@@ -3,19 +3,28 @@
namespace MiraAPI.Events.Vanilla.Player; namespace MiraAPI.Events.Vanilla.Player;
/// <summary> /// <summary>
/// Event that is invoked when a player leaves the game. Non-cancelable. /// Event that is invoked when a player leaves the game. Non cancelable.
/// </summary> /// </summary>
/// <param name="data">The data of the player who left.</param> public class PlayerLeaveEvent : MiraEvent
/// <param name="reason">The reason why the player left.</param>
public class PlayerLeaveEvent(ClientData data, DisconnectReasons reason) : MiraEvent
{ {
/// <summary> /// <summary>
/// Gets the player who left. /// Gets the player who left.
/// </summary> /// </summary>
public ClientData ClientData { get; } = data; public ClientData ClientData { get; }
/// <summary> /// <summary>
/// Gets the reason why the player left. /// Gets the reason why the player left.
/// </summary> /// </summary>
public DisconnectReasons Reason { get; } = reason; public DisconnectReasons Reason { get; }
/// <summary>
/// Initializes a new instance of the <see cref="PlayerLeaveEvent"/> class.
/// </summary>
/// <param name="data">The data of the player who left.</param>
/// <param name="reason">The reason why the player left.</param>
public PlayerLeaveEvent(ClientData data, DisconnectReasons reason)
{
ClientData = data;
Reason = reason;
}
} }
@@ -3,17 +3,26 @@
/// <summary> /// <summary>
/// Event that is invoked when a player enters a vent. This event is cancelable. /// Event that is invoked when a player enters a vent. This event is cancelable.
/// </summary> /// </summary>
/// <param name="player">The <see cref="PlayerControl"/> that is entering the <paramref name="vent"/>.</param> public class EnterVentEvent : MiraCancelableEvent
/// <param name="vent">The <see cref="global::Vent"/> being entered.</param>
public class EnterVentEvent(PlayerControl player, Vent? vent) : MiraCancelableEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="PlayerControl"/> that is entering the <see cref="Vent"/>. /// Gets the player that is entering the vent.
/// </summary> /// </summary>
public PlayerControl Player { get; } = player; public PlayerControl Player { get; }
/// <summary> /// <summary>
/// Gets the <see cref="global::Vent"/> that the <see cref="Player"/> is entering. /// Gets the vent that the player is entering.
/// </summary> /// </summary>
public Vent? Vent { get; } = vent; public Vent? Vent { get; }
/// <summary>
/// Initializes a new instance of the <see cref="EnterVentEvent"/> class.
/// </summary>
/// <param name="player">The player that is entering the vent.</param>
/// <param name="vent">The vent being entered.</param>
public EnterVentEvent(PlayerControl player, Vent? vent)
{
Player = player;
Vent = vent;
}
} }
@@ -3,17 +3,26 @@
/// <summary> /// <summary>
/// Event that is invoked when a player exits a vent. This event is cancelable. /// Event that is invoked when a player exits a vent. This event is cancelable.
/// </summary> /// </summary>
/// <param name="player">The <see cref="PlayerControl"/> who is exiting the <paramref name="vent"/>.</param> public class ExitVentEvent : MiraCancelableEvent
/// <param name="vent">The <see cref="global::Vent"/> being exited from.</param>
public class ExitVentEvent(PlayerControl player, Vent? vent) : MiraCancelableEvent
{ {
/// <summary> /// <summary>
/// Gets the <see cref="PlayerControl"/> that is exiting the <see cref="Vent"/>. /// Gets the player that is exiting the vent.
/// </summary> /// </summary>
public PlayerControl Player { get; } = player; public PlayerControl Player { get; }
/// <summary> /// <summary>
/// Gets the <see cref="global::Vent"/> that the <see cref="Player"/> is exiting. /// Gets the vent that the player is exiting.
/// </summary> /// </summary>
public Vent? Vent { get; } = vent; public Vent? Vent { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ExitVentEvent"/> class.
/// </summary>
/// <param name="player">The player who is exiting the vent.</param>
/// <param name="vent">The vent being exited from.</param>
public ExitVentEvent(PlayerControl player, Vent? vent)
{
Player = player;
Vent = vent;
}
} }
@@ -1,7 +1,15 @@
namespace MiraAPI.Events.Vanilla.Usables; namespace MiraAPI.Events.Vanilla.Usables;
/// <summary> /// <summary>
/// Event for if a <see cref="PlayerControl"/> can use an <see cref="IUsable"/> from Vanilla Among Us. Will always be run locally. /// Event for if a <see cref="PlayerControl"/> can use an <see cref="IUsable"/> from Vanilla Among Us. Will always be ran locally.
/// </summary> /// </summary>
/// <param name="usable">The <see cref="IUsable"/>.</param> public class PlayerCanUseEvent : PlayerUseEvent
public class PlayerCanUseEvent(IUsable usable) : PlayerUseEvent(usable); {
/// <summary>
/// Initializes a new instance of the <see cref="PlayerCanUseEvent"/> class.
/// </summary>
/// <param name="usable">The IUsable.</param>
public PlayerCanUseEvent(IUsable usable) : base(usable)
{
}
}
@@ -1,23 +1,34 @@
namespace MiraAPI.Events.Vanilla.Usables; namespace MiraAPI.Events.Vanilla.Usables;
/// <summary> /// <summary>
/// Event for <see cref="PlayerControl"/> using a <see cref="IUsable"/> from Vanilla Among Us. Will always be run locally. /// Event for <see cref="PlayerControl"/> using a <see cref="IUsable"/> from Vanilla Among Us. Will always be ran locally.
/// </summary> /// </summary>
/// <param name="usable">The <see cref="IUsable"/>.</param> public class PlayerUseEvent : MiraCancelableEvent
public class PlayerUseEvent(IUsable usable) : MiraCancelableEvent
{ {
/// <summary> /// <summary>
/// Gets the instance of <see cref="IUsable"/> that was used. /// Gets the instance of <see cref="IUsable"/> that was used.
/// </summary> /// </summary>
public IUsable Usable { get; } = usable; public IUsable Usable { get; }
/// <summary> /// <summary>
/// Gets a value indicating whether the <see cref="Usable"/> is a <see cref="Console"/>, <see cref="MapConsole"/>, or <see cref="SystemConsole"/>. /// Gets a value indicating whether the IUsable is a <see cref="Console"/>, <see cref="MapConsole"/>, or <see cref="SystemConsole"/>.
/// </summary> /// </summary>
public bool IsPrimaryConsole { get; } = usable.TryCast<Console>() || usable.TryCast<SystemConsole>() || usable.TryCast<MapConsole>(); public bool IsPrimaryConsole { get; }
/// <summary> /// <summary>
/// Gets a value indicating whether the <see cref="Usable"/> is a <see cref="Vent"/>. /// Gets a value indicating whether the IUsable is a <see cref="Vent"/>.
/// </summary> /// </summary>
public bool IsVent { get; } = usable.TryCast<Vent>(); public bool IsVent { get; }
/// <summary>
/// Initializes a new instance of the <see cref="PlayerUseEvent"/> class.
/// </summary>
/// <param name="usable">The IUsable.</param>
public PlayerUseEvent(IUsable usable)
{
Usable = usable;
IsPrimaryConsole = usable.TryCast<Console>() || usable.TryCast<SystemConsole>() || usable.TryCast<MapConsole>();
IsVent = usable.TryCast<Vent>();
}
} }
+16 -18
View File
@@ -10,46 +10,45 @@ namespace MiraAPI.GameEnd;
public abstract class CustomGameOver public abstract class CustomGameOver
{ {
/// <summary> /// <summary>
/// Gets the current <see cref="CustomGameOver"/>. /// Gets the current CustomGameOver.
/// </summary> /// </summary>
public static CustomGameOver? Instance { get; internal set; } public static CustomGameOver? Instance { get; internal set; }
/// <summary> /// <summary>
/// Verifies if the condition for this <see cref="CustomGameOver"/> is met. /// Verifies if the condition for this CustomGameOver is met.
/// </summary> /// </summary>
/// <param name="playerControl">The <see cref="PlayerControl"/> that requested the Game Over.</param> /// <param name="playerControl">The PlayerControl that requested the Game Over.</param>
/// <param name="winners">The collection of winners.</param> /// <param name="winners">The collection of winners.</param>
/// <returns><see langword="true"/> if the condition is met, otherwise <see langword="false"/>.</returns> /// <returns>True if the condition is met, otherwise false.</returns>
public virtual bool VerifyCondition(PlayerControl playerControl, NetworkedPlayerInfo[] winners) public virtual bool VerifyCondition(PlayerControl playerControl, NetworkedPlayerInfo[] winners)
{ {
return true; return true;
} }
/// <summary> /// <summary>
/// Runs before the base game calls <see cref="EndGameManager.SetEverythingUp"/>. /// Runs before the base game calls EndGameManager.SetEverythingUp.
/// </summary> /// </summary>
/// <param name="endGameManager">The <see cref="EndGameManager"/> instance.</param> /// <param name="endGameManager">The EndGameManager instance.</param>
/// <returns>Return <see langword="true"/> to use the run the original method, return <see langword="false"/> to skip it.</returns> /// <returns>Return True to use the run the original method, return False to skip it.</returns>
public virtual bool BeforeEndGameSetup(EndGameManager endGameManager) public virtual bool BeforeEndGameSetup(EndGameManager endGameManager)
{ {
return true; return true;
} }
/// <summary> /// <summary>
/// Runs after the base game calls <see cref="EndGameManager.SetEverythingUp"/>. /// Runs after the base game calls EndGameManager.SetEverythingUp.
/// </summary> /// </summary>
/// <param name="endGameManager">The <see cref="EndGameManager"/> instance.</param> /// <param name="endGameManager">The EndGameManager instance.</param>
public virtual void AfterEndGameSetup(EndGameManager endGameManager) public virtual void AfterEndGameSetup(EndGameManager endGameManager)
{ {
} }
/// <summary> /// <summary>
/// Get the <see cref="global::GameOverReason"/> associated with this <see cref ="CustomGameOver"/>. /// Get the GameOverReason associated with this CustomGameOver.
/// </summary> /// </summary>
/// <typeparam name="T">Type of the custom game over.</typeparam> /// <typeparam name="T">Type of the custom game over.</typeparam>
/// <returns>The <see cref="global::GameOverReason"/> associated with the custom game over.</returns> /// <returns>The GameOverReason associated with the custom game over.</returns>
public static GameOverReason GameOverReason<T>() public static GameOverReason GameOverReason<T>() where T : CustomGameOver
where T : CustomGameOver
{ {
return (GameOverReason)GameOverManager.GetGameOverId<T>(); return (GameOverReason)GameOverManager.GetGameOverId<T>();
} }
@@ -59,8 +58,7 @@ public abstract class CustomGameOver
/// </summary> /// </summary>
/// <param name="winners">A collection of winners.</param> /// <param name="winners">A collection of winners.</param>
/// <typeparam name="T">Type of the custom game over.</typeparam> /// <typeparam name="T">Type of the custom game over.</typeparam>
public static void Trigger<T>(IEnumerable<NetworkedPlayerInfo> winners) public static void Trigger<T>(IEnumerable<NetworkedPlayerInfo> winners) where T : CustomGameOver
where T : CustomGameOver
{ {
var reason = GameOverManager.GetGameOverId<T>(); var reason = GameOverManager.GetGameOverId<T>();
var data = new GameOverData(reason, [.. winners]); var data = new GameOverData(reason, [.. winners]);
@@ -69,10 +67,10 @@ public abstract class CustomGameOver
} }
/// <summary> /// <summary>
/// Implicitly convert a <see cref="CustomGameOver"/> to a <see cref="global::GameOverReason"/>. /// Implicitly convert a CustomGameOver to a GameOverReason.
/// </summary> /// </summary>
/// <param name="gameOver">The <see cref="CustomGameOver"/> instance.</param> /// <param name="gameOver">The CustomGameOver instance.</param>
/// <returns>The <see cref="global::GameOverReason"/> associated with the CustomGameOver.</returns> /// <returns>The GameOverReason associated with the CustomGameOver.</returns>
public static implicit operator GameOverReason(CustomGameOver gameOver) public static implicit operator GameOverReason(CustomGameOver gameOver)
{ {
return (GameOverReason)GameOverManager.GetGameOverId(gameOver.GetType()); return (GameOverReason)GameOverManager.GetGameOverId(gameOver.GetType());
+27 -26
View File
@@ -1,25 +1,26 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Reactor.Utilities;
namespace MiraAPI.GameEnd; namespace MiraAPI.GameEnd;
/// <summary> /// <summary>
/// Manage <see cref="CustomGameOver"/>s. /// Manage custom game overs.
/// </summary> /// </summary>
public static class GameOverManager public static class GameOverManager
{ {
private static readonly Dictionary<Type, int> GameOverIds = []; private static readonly Dictionary<Type, int> GameOverIds = [];
private static readonly Dictionary<int, Type> GameOverTypes = []; private static readonly Dictionary<int, Type> GameOverTypes = [];
private static int nextId = Enum.GetNames<GameOverReason>().Length; private static int _nextId = Enum.GetNames<GameOverReason>().Length;
/// <summary> /// <summary>
/// Register a <see cref="CustomGameOver"/>. /// Register a custom game over.
/// </summary> /// </summary>
/// <param name="gameOverType">Type of the <see cref="CustomGameOver"/>.</param> /// <param name="gameOverType">Type of the custom game over.</param>
/// <exception cref="ArgumentException">Thrown when the type is not a subclass of <see cref="CustomGameOver"/>, is abstract, or does not have a parameterless constructor.</exception> /// <exception cref="ArgumentException">Thrown when the type is not a subclass of CustomGameOver, is abstract, or does not have a parameterless constructor.</exception>
/// <returns><see langword="true"/> if the game over was registered successfully, <see langword="false"/> otherwise.</returns> /// <returns>>True if the game over was registered successfully, false otherwise.</returns>
public static bool RegisterGameOver(Type gameOverType) public static bool RegisterGameOver(Type gameOverType)
{ {
if (!typeof(CustomGameOver).IsAssignableFrom(gameOverType)) if (!typeof(CustomGameOver).IsAssignableFrom(gameOverType))
@@ -29,28 +30,28 @@ public static class GameOverManager
if (gameOverType.IsAbstract) if (gameOverType.IsAbstract)
{ {
Error("The type must not be abstract."); Logger<MiraApiPlugin>.Error("The type must not be abstract.");
return false; return false;
} }
if (gameOverType.GetConstructor(Type.EmptyTypes) == null) if (gameOverType.GetConstructor(Type.EmptyTypes) == null)
{ {
Error("The type must have a parameterless constructor."); Logger<MiraApiPlugin>.Error("The type must have a parameterless constructor.");
return false; return false;
} }
GameOverIds.Add(gameOverType, nextId); GameOverIds.Add(gameOverType, _nextId);
GameOverTypes.Add(nextId, gameOverType); GameOverTypes.Add(_nextId, gameOverType);
nextId++; _nextId++;
return true; return true;
} }
/// <summary> /// <summary>
/// Create an instance of a <see cref="CustomGameOver"/>. /// Create an instance of a custom game over.
/// </summary> /// </summary>
/// <param name="id">ID of the <see cref="CustomGameOver"/>.</param> /// <param name="id">ID of the custom game over.</param>
/// <param name="customGameOver">The created instance of the <see cref="CustomGameOver"/>.</param> /// <param name="customGameOver">The created instance of the custom game over.</param>
/// <returns>An instance of the <see cref="CustomGameOver"/>.</returns> /// <returns>An instance of the custom game over.</returns>
public static bool TryGetGameOver(int id, [NotNullWhen(true)] out CustomGameOver? customGameOver) public static bool TryGetGameOver(int id, [NotNullWhen(true)] out CustomGameOver? customGameOver)
{ {
if (GameOverTypes.TryGetValue(id, out var gameOverType)) if (GameOverTypes.TryGetValue(id, out var gameOverType))
@@ -64,26 +65,26 @@ public static class GameOverManager
} }
/// <summary> /// <summary>
/// Get the ID of a <see cref="CustomGameOver"/>. /// Get the ID of a custom game over.
/// </summary> /// </summary>
/// <typeparam name="T">Type of the <see cref="CustomGameOver"/>.</typeparam> /// <typeparam name="T">Type of the custom game over.</typeparam>
/// <returns>The ID of the <see cref="CustomGameOver"/>.</returns> /// <returns>The ID of the custom game over.</returns>
public static int GetGameOverId<T>() public static int GetGameOverId<T>() where T : CustomGameOver
where T : CustomGameOver
{ {
return GetGameOverId(typeof(T)); return GetGameOverId(typeof(T));
} }
/// <summary> /// <summary>
/// Get the ID of a <see cref="CustomGameOver"/>. /// Get the ID of a custom game over.
/// </summary> /// </summary>
/// <param name="gameOverType">Type of the <see cref="CustomGameOver"/>.</param> /// <param name="gameOverType">Type of the custom game over.</param>
/// <returns>The ID of the <see cref="CustomGameOver"/>.</returns> /// <returns>The ID of the custom game over.</returns>
/// <exception cref="ArgumentException">Thrown when the type is not registered.</exception> /// <exception cref="ArgumentException">Thrown when the type is not registered.</exception>
public static int GetGameOverId(Type gameOverType) public static int GetGameOverId(Type gameOverType)
{ {
return GameOverIds.TryGetValue(gameOverType, out var id) if (GameOverIds.TryGetValue(gameOverType, out var id))
? id return id;
: throw new ArgumentException($"{gameOverType.FullName} is not a registered custom game over!");
throw new ArgumentException($"{gameOverType.FullName} is not a registered custom game over!");
} }
} }
+2
View File
@@ -0,0 +1,2 @@
[*.cs]
dotnet_diagnostic.CS1591.severity = none
-317
View File
@@ -1,317 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using AmongUs.GameOptions;
using MiraAPI.GameOptions;
using MiraAPI.PluginLoading;
using MiraAPI.Translation;
using MiraAPI.Utilities.Assets;
using Reactor.Utilities.Extensions;
using TMPro;
using UnityEngine;
namespace MiraAPI.GameModes;
/// <summary>
/// Base class for custom gamemodes.
/// </summary>
[MiraIgnore]
public abstract class AbstractGameMode : IOptionable
{
/// <summary>
/// Gets the game mode name.
/// </summary>
public abstract string Name { get; }
/// <summary>
/// Gets a value indicating whether the mode is visible in the menu. Only checked at startup.
/// </summary>
public virtual bool HideMode => false;
/// <summary>
/// Gets the game mode description.
/// </summary>
public abstract string Description { get; }
/// <summary>
/// Gets the game mode color to display on the lobby pane.
/// </summary>
public virtual Color Color { get; } = Color.white;
/// <summary>
/// Gets the icon of the gamemode. Will be shown in options menu underneath the gamemode option.
/// </summary>
public virtual LoadableAsset<Sprite>? Icon => null;
/// <summary>
/// Gets or sets the icon of the gamemode for use on the options pop-up.
/// </summary>
public TMP_SpriteAsset TmpIcon { get; set; } = null!;
/// <summary>
/// Gets the colored game mode name, using the color and name properties.
/// </summary>
public string ColoredName => $"<color=#{Color.ToHtmlStringRGBA()}>{MiraLocaleManager.Get(Name)}</color>";
/// <summary>
/// Gets the game mode id.
/// </summary>
public uint ID { get; internal set; }
/// <summary>
/// Gets a value indicating whether a specific body type is used by the game mode.
/// </summary>
public virtual bool GameModeBodyTypeOverride => false;
/// <summary>
/// Gets a value indicating whether the gamemode removes the normal game settings.
/// </summary>
public virtual bool ShowNormalGameSettings => true;
/// <summary>
/// Gets a value indicating whether the gamemode removes the normal role settings.
/// </summary>
public virtual bool ShowNormalRoleSettings => true;
/// <summary>
/// Gets a value indicating the default kill cooldown for impostors in this mode.
/// </summary>
public virtual float DefaultImpostorKillCooldown => GameOptionsManager.Instance.CurrentGameOptions.GetFloat(FloatOptionNames.KillCooldown);
/// <summary>
/// Called on GameManager.GetBodyType().
/// </summary>
/// <param name="player">Player to get body type from.</param>
/// <returns>Resulting body type.</returns>
public virtual PlayerBodyTypes GetBodyType(PlayerControl player)
{
return AprilFoolsMode.ShouldHorseAround()
? PlayerBodyTypes.Horse
: (AprilFoolsMode.ShouldLongAround()
? PlayerBodyTypes.Long
: PlayerBodyTypes.Normal);
}
/// <summary>
/// Gets a value indicating whether a custom intro sequence is implemented by the game mode.
/// </summary>
public virtual bool ShowGameModeIntroCutscene => false;
/// <summary>
/// Called when Intro Cutscene is destroyed.
/// </summary>
public virtual void Initialize()
{
}
/// <summary>
/// Called on HudManager.Start().
/// </summary>
/// <param name="instance">Instance of HudManager.</param>
public virtual void HudStart(HudManager instance)
{
}
/// <summary>
/// Called every frame on HudManager.Update().
/// </summary>
/// <param name="instance">Instance of HudManager.</param>
public virtual void HudUpdate(HudManager instance)
{
}
/// <summary>
/// Called when a player is killed.
/// </summary>
/// <param name="player">PlayerControl that was killed.</param>
/// <param name="assignGhostRole">Determines whether to assign a ghost role on the player.</param>
public virtual void OnPlayerDeath(PlayerControl player, bool assignGhostRole)
{
GameManager.Instance.LogicRoleSelection.OnPlayerDeath(player, assignGhostRole);
}
/// <summary>
/// Calculate Game End logic.
/// </summary>
/// <param name="runOriginal">Should original game end logic be used.</param>
/// <param name="instance">Instance of LogicGameFlowNormal.</param>
public virtual void CheckGameEnd(out bool runOriginal, LogicGameFlowNormal instance)
{
runOriginal = true;
}
/// <summary>
/// Custom role assignment.
/// </summary>
/// <param name="runOriginal">Should original role assignment be used.</param>
/// <param name="instance">Instance of LogicRoleSelection.</param>
public virtual void AssignRoles(out bool runOriginal, LogicRoleSelectionNormal instance)
{
runOriginal = true;
}
/// <summary>
/// Custom role assignment to run after all roles are handed out.
/// </summary>
/// <param name="instance">Instance of LogicRoleSelection.</param>
public virtual void PostAssignRoles(LogicRoleSelectionNormal instance)
{
}
/// <summary>
/// Custom murder logic.
/// </summary>
/// <param name="runOriginal">Should the original murder logic be used.</param>
/// <param name="result">Result of custom murder logic.</param>
/// <param name="target">Target player for murder.</param>
public virtual void CanKill(out bool runOriginal, out bool result, PlayerControl target)
{
result = false;
runOriginal = true;
}
/// <summary>
/// Custom winner selection.
/// </summary>
/// <returns>List of winners or null.</returns>
public virtual List<NetworkedPlayerInfo>? CalculateWinners()
{
return null;
}
/// <summary>
/// The IEnumerator that plays the intro cutscene for this gamemode.
/// </summary>
/// <param name="introCutscene">An instance of IntroCutscene.</param>
/// <returns>An IEnumerator to run the intro cutscene instead of the base game one.</returns>
public virtual IEnumerator IntroCutscene(IntroCutscene introCutscene)
{
yield return new WaitForEndOfFrame();
}
/// <summary>
/// Can Admin be used in this gamemode.
/// </summary>
/// <param name="console">Admin Console.</param>
/// <returns>True if Admin console is enabled.</returns>
public virtual bool CanUseMapConsole(MapConsole console)
{
return true;
}
/// <summary>
/// Can a body be reported in this gamemode.
/// </summary>
/// <param name="body">Target body for reporting.</param>
/// <returns>True if dead bodies can be reported.</returns>
public virtual bool CanReport(DeadBody body)
{
return true;
}
/// <summary>
/// Can system consoles be used in this gamemode.
/// </summary>
/// <param name="console">System Console.</param>
/// <returns>True if system consoles are enabled in this mode.</returns>
public virtual bool CanUseSystemConsole(SystemConsole console)
{
return true;
}
/// <summary>
/// Can tasks be interacted with in this gamemode.
/// </summary>
/// <param name="console">Task console.</param>
/// <returns>True if tasks are enabled in this mode.</returns>
public virtual bool CanUseTasks(Console console)
{
return true;
}
/// <summary>
/// Should the sabotage map be used when attempting to open sabotage overlay.
/// </summary>
/// <param name="map">MapBehaviour object.</param>
/// <returns>True if the sabotage map should be shown.</returns>
public virtual bool ShouldShowSabotageMap(MapBehaviour map)
{
return true;
}
/// <summary>
/// Gets the <see cref="MapOptions"/> to display on the map.
/// </summary>
/// <returns>The <see cref="MapOptions"/> for the gamemode.</returns>
public virtual MapOptions GetMapOptions()
{
return new MapOptions
{
Mode = PlayerControl.LocalPlayer.Data.Role.IsImpostor && !MeetingHud.Instance
? MapOptions.Modes.Sabotage
: MapOptions.Modes.Normal,
};
}
/// <summary>
/// Can a player vent in this gamemode.
/// </summary>
/// <param name="vent">Target vent.</param>
/// <param name="playerInfo">Player attempting to vent.</param>
/// <returns>True if venting is enabled in this mode.</returns>
public virtual bool CanVent(Vent vent, NetworkedPlayerInfo playerInfo)
{
return true;
}
/// <summary>
/// Gets a value indicating whether the task bar appears in the gamemode.
/// </summary>
/// <returns>True if the task bar is enabled in this mode.</returns>
public virtual bool ShowTaskBar => true;
/// <summary>
/// Updates the task panel.
/// </summary>
/// <param name="instance">The task panel to update.</param>
public virtual void UpdateTaskPanel(TaskPanelBehaviour instance)
{
instance.background.transform.localScale = instance.taskText.textBounds.size.x > 0f
? new Vector3(instance.taskText.textBounds.size.x + 0.2f, instance.taskText.textBounds.size.y + 0.2f, 1f)
: Vector3.zero;
var vector = instance.background.sprite.bounds.extents;
vector.y = -vector.y;
vector = vector.Mul(instance.background.transform.localScale);
instance.background.transform.localPosition = vector;
var vector2 = instance.tab.sprite.bounds.extents;
vector2 = vector2.Mul(instance.tab.transform.localScale);
vector2.y = -vector2.y;
vector2.x += vector.x * 2f;
instance.tab.transform.localPosition = vector2;
if (GameManager.Instance == null)
{
return;
}
var yPos = 0.6f;
var xPos = -instance.background.sprite.bounds.size.x * instance.background.transform.localScale.x;
instance.closedPosition = new Vector3(xPos, yPos, instance.closedPosition.z);
instance.openPosition = new Vector3(instance.openPosition.x, yPos, instance.openPosition.z);
instance.timer = instance.open
? Mathf.Min(1f, instance.timer + (Time.deltaTime / instance.animationTimeSeconds))
: Mathf.Max(0f, instance.timer - (Time.deltaTime / instance.animationTimeSeconds));
Vector3 relativePos = new(
Mathf.SmoothStep(instance.closedPosition.x, instance.openPosition.x, instance.timer),
yPos,
instance.openPosition.z);
instance.transform.localPosition =
AspectPosition.ComputePosition(AspectPosition.EdgeAlignments.LeftTop, relativePos);
}
/// <inheritdoc/>
public override string ToString()
{
return Name;
}
}
Loaded 100 of 445 files, more files were not shown because too many files have changed in this diff. Show more