mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-21 13:37:54 +00:00
Compare commits
331
Commits
android
...
dev-update
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e901abfc60 | ||
|
|
853a94681a | ||
|
|
f230cff5e5 | ||
|
|
7c7d184d1f | ||
|
|
6b923cfe01 | ||
|
|
247c765176 | ||
|
|
a3668b3150 | ||
|
|
aa4dd24ac3 | ||
|
|
cb0afe3095 | ||
|
|
883222be82 | ||
|
|
6b774500dd | ||
|
|
f96f75cea1 | ||
|
|
75662a6c25 | ||
|
|
73e4506016 | ||
|
|
a491592669 | ||
|
|
01fef0f747 | ||
|
|
e22f4daf3e | ||
|
|
b83cb5cc29 | ||
|
|
fb164a54e3 | ||
|
|
b6475161f1 | ||
|
|
c7f3f9d5da | ||
|
|
5d54a0c2d3 | ||
|
|
cf1a75f5ea | ||
|
|
721bd20d2b | ||
|
|
0e3b6be5be | ||
|
|
411340d9e9 | ||
|
|
57d2a6a9b5 | ||
|
|
6f61a75bb7 | ||
|
|
06c746c632 | ||
|
|
95819cf83a | ||
|
|
d1d11e2bec | ||
|
|
b4ed14f7f2 | ||
|
|
951af42358 | ||
|
|
27e14488af | ||
|
|
9ab87955bb | ||
|
|
0141dfdea4 | ||
|
|
cd97fab3a2 | ||
|
|
3cd8db1f04 | ||
|
|
535967475d | ||
|
|
6fd5993959 | ||
|
|
b713599c13 | ||
|
|
f44ec15804 | ||
|
|
847a4dd287 | ||
|
|
83d55d409b | ||
|
|
7a00ea9174 | ||
|
|
22716b29ab | ||
|
|
43291bda50 | ||
|
|
d4a675f2a9 | ||
|
|
00c5c5c4ff | ||
|
|
abb6f3d161 | ||
|
|
eef098317e | ||
|
|
1c097b47df | ||
|
|
6fe2750545 | ||
|
|
a57f40fa79 | ||
|
|
54bfd3002b | ||
|
|
4c38189444 | ||
|
|
14ce020208 | ||
|
|
877fc15aec | ||
|
|
2160d1d823 | ||
|
|
4d187f3f79 | ||
|
|
4e37f8b3d4 | ||
|
|
015d175aa0 | ||
|
|
ca7da0c343 | ||
|
|
72fa908cb0 | ||
|
|
58067d9f21 | ||
|
|
b8b85e2bc3 | ||
|
|
043845ee11 | ||
|
|
df7c182abb | ||
|
|
2a4d16e65e | ||
|
|
9606871cbe | ||
|
|
ae45c506cb | ||
|
|
fd01273635 | ||
|
|
840761787f | ||
|
|
615d527c86 | ||
|
|
7628a41d86 | ||
|
|
121baeb178 | ||
|
|
0cf4954eaf | ||
|
|
8f403f5408 | ||
|
|
2f5c382ece | ||
|
|
1ab0c3f4a7 | ||
|
|
0230d98642 | ||
|
|
04b7a9905d | ||
|
|
317e0b6ea9 | ||
|
|
cbe44a40d0 | ||
|
|
d5c3905684 | ||
|
|
49d16b707c | ||
|
|
3eb5bfae01 | ||
|
|
b1293081fc | ||
|
|
83751a25a9 | ||
|
|
bd58fca7bd | ||
|
|
63d1003b2b | ||
|
|
0645c32cca | ||
|
|
8beabb20a2 | ||
|
|
3f28d70308 | ||
|
|
b919c55ef1 | ||
|
|
55a2161876 | ||
|
|
4ca2249fbd | ||
|
|
fc94c8e67e | ||
|
|
83e550c1f2 | ||
|
|
edee889ffe | ||
|
|
119d4c5152 | ||
|
|
c99f468abf | ||
|
|
adde6db1d0 | ||
|
|
0012fe8cd6 | ||
|
|
9148a1e8da | ||
|
|
8c5aee4beb | ||
|
|
30a39fa223 | ||
|
|
228ed9711a | ||
|
|
7c085b1072 | ||
|
|
8750e5c894 | ||
|
|
1b40b1c5e4 | ||
|
|
0a0ad74419 | ||
|
|
992bdbcbf8 | ||
|
|
f9721a8d69 | ||
|
|
e541840da9 | ||
|
|
eb18d82d8e | ||
|
|
7afd899e56 | ||
|
|
5cccc192b1 | ||
|
|
9d7e41a3c9 | ||
|
|
662b52f78d | ||
|
|
dac1d82d5c | ||
|
|
1b718092ee | ||
|
|
3eb0a4fdb3 | ||
|
|
850e82155c | ||
|
|
ff30d5fdd6 | ||
|
|
2eecba2e51 | ||
|
|
84321f290e | ||
|
|
d8d3cc202a | ||
|
|
e08e7e5f4b | ||
|
|
a5f0ed5975 | ||
|
|
d1f5e56cb9 | ||
|
|
127e3f600e | ||
|
|
47e02d3dcf | ||
|
|
f53e4fdc38 | ||
|
|
b1f0ec6da3 | ||
|
|
d0d5056e39 | ||
|
|
57e3f20cba | ||
|
|
7fdfd506e0 | ||
|
|
edf61e722f | ||
|
|
791daa08ad | ||
|
|
e4d2509895 | ||
|
|
62c8e27535 | ||
|
|
8852c014ab | ||
|
|
adb9a2823d | ||
|
|
ff658db6f1 | ||
|
|
750e00d06d | ||
|
|
3a5a397846 | ||
|
|
c846109d07 | ||
|
|
e3b0eb68c0 | ||
|
|
90921ff786 | ||
|
|
c1d0bb5d26 | ||
|
|
25a55b1b60 | ||
|
|
af2cc9a3c1 | ||
|
|
e9730f018d | ||
|
|
1d316bb02f | ||
|
|
c59ed8eaa6 | ||
|
|
2eac3d04f1 | ||
|
|
154b50fd76 | ||
|
|
390e4c1157 | ||
|
|
35b444854a | ||
|
|
8e5028c236 | ||
|
|
ad113a47ab | ||
|
|
59b8e92c48 | ||
|
|
d313089521 | ||
|
|
0852f769ae | ||
|
|
ae4b4d872b | ||
|
|
b33a66cbd9 | ||
|
|
ac87003d0a | ||
|
|
f7de7f127d | ||
|
|
d2fafc3650 | ||
|
|
0c0157fed2 | ||
|
|
e095e2da6a | ||
|
|
90bf402cbc | ||
|
|
50cb8ffc3d | ||
|
|
4f4b880ad4 | ||
|
|
b627006ba1 | ||
|
|
b0ceb129a4 | ||
|
|
bf7c800613 | ||
|
|
990bac4c06 | ||
|
|
08c6883a0d | ||
|
|
3066720e6e | ||
|
|
af363000c7 | ||
|
|
245f2e6919 | ||
|
|
fed3abafb2 | ||
|
|
925d47a275 | ||
|
|
45a3597ab2 | ||
|
|
faeb39d3de | ||
|
|
6b46cffe5e | ||
|
|
00a60bb7ad | ||
|
|
d89bce6956 | ||
|
|
7f92e94293 | ||
|
|
6199e55110 | ||
|
|
eac442443b | ||
|
|
6321753ec0 | ||
|
|
e66d45bd21 | ||
|
|
1e00181220 | ||
|
|
77c13bebdc | ||
|
|
fcd7856571 | ||
|
|
5680d27db1 | ||
|
|
00eaa2601c | ||
|
|
49d77fcf40 | ||
|
|
dcb4a3876f | ||
|
|
ba2deb66f1 | ||
|
|
bb5c212e97 | ||
|
|
f59e0af7e8 | ||
|
|
8f3a137877 | ||
|
|
44415019cc | ||
|
|
7125374cda | ||
|
|
cff46ebd19 | ||
|
|
9270de408d | ||
|
|
8940de76bb | ||
|
|
1813fe5a84 | ||
|
|
272b14f0e0 | ||
|
|
8b19271e34 | ||
|
|
c29e882d7e | ||
|
|
fdfb876b44 | ||
|
|
205eee96b2 | ||
|
|
8774c9da70 | ||
|
|
51c7e248f9 | ||
|
|
02f9c20804 | ||
|
|
6cc1d4b762 | ||
|
|
9dfad78df6 | ||
|
|
7f506000a4 | ||
|
|
795b6a81d7 | ||
|
|
bd8d7a3208 | ||
|
|
e8536e5d4b | ||
|
|
090db766b2 | ||
|
|
1f0027108e | ||
|
|
665724010d | ||
|
|
2d58c91289 | ||
|
|
b3ed6d67f9 | ||
|
|
64ef78e3a2 | ||
|
|
5e9e4012ef | ||
|
|
fe04a7033a | ||
|
|
ba0ee49255 | ||
|
|
97528b4380 | ||
|
|
50030c113b | ||
|
|
20e51cc993 | ||
|
|
64b5e01ba1 | ||
|
|
d4469153ab | ||
|
|
ab67c233d8 | ||
|
|
c72eacc7a2 | ||
|
|
13072d6834 | ||
|
|
c6342750ef | ||
|
|
5c2e95376d | ||
|
|
067859b9fd | ||
|
|
fe3bfcdbc4 | ||
|
|
5d01462a32 | ||
|
|
a9b6f40ed0 | ||
|
|
eae0024ec3 | ||
|
|
2907564d6a | ||
|
|
7ad003ed1e | ||
|
|
93eea6ea2f | ||
|
|
8e09b7fee0 | ||
|
|
1e4894538c | ||
|
|
303aedafc7 | ||
|
|
8ed4355504 | ||
|
|
76b02835a7 | ||
|
|
8d5bc710e7 | ||
|
|
798ce451d5 | ||
|
|
136bbde516 | ||
|
|
5252620108 | ||
|
|
c9b1c57774 | ||
|
|
d97df1a891 | ||
|
|
e93ef6fd1d | ||
|
|
3afe437101 | ||
|
|
62c01b2f72 | ||
|
|
089d2c1ea5 | ||
|
|
c65511d03e | ||
|
|
aee304fb96 | ||
|
|
11ba564eed | ||
|
|
259b9b7097 | ||
|
|
7e3a279b56 | ||
|
|
1fd2dd3539 | ||
|
|
3f60bcae2c | ||
|
|
fe1580bb7e | ||
|
|
8b23021b2a | ||
|
|
fdc715dac2 | ||
|
|
e1ca50be3e | ||
|
|
bf9b34e728 | ||
|
|
baf80618bb | ||
|
|
7d1976f772 | ||
|
|
4ce24c2a00 | ||
|
|
7fa75946fd | ||
|
|
43f92d4dc2 | ||
|
|
ee22b776eb | ||
|
|
f31349f6e8 | ||
|
|
448e2f9152 | ||
|
|
dde7e70406 | ||
|
|
713a7a2bcc | ||
|
|
056a9b6102 | ||
|
|
4b144a782d | ||
|
|
ae917a9c77 | ||
|
|
7a8d608b17 | ||
|
|
6503bbecb7 | ||
|
|
cb794c3fc2 | ||
|
|
88329bef79 | ||
|
|
eb7abecd75 | ||
|
|
fc9e9740be | ||
|
|
3c51c88963 | ||
|
|
e42f5e6029 | ||
|
|
61be7dda82 | ||
|
|
3220a4a820 | ||
|
|
8fd142a92e | ||
|
|
fcec6ad6e5 | ||
|
|
10a7ffe886 | ||
|
|
7e541733b7 | ||
|
|
99a275a97c | ||
|
|
67a5f0dd67 | ||
|
|
f13d46ec18 | ||
|
|
f9096b6160 | ||
|
|
7890ec9456 | ||
|
|
8bb191270f | ||
|
|
65cd177551 | ||
|
|
7801f81052 | ||
|
|
2d59b29c15 | ||
|
|
a62c75a13b | ||
|
|
c85cf7ef2f | ||
|
|
ead28339b0 | ||
|
|
9177d5b456 | ||
|
|
284a0f58b1 | ||
|
|
47dfa63423 | ||
|
|
1b261d7287 | ||
|
|
fa8ea9dbab | ||
|
|
9c15ca4d06 | ||
|
|
a4b1868690 | ||
|
|
409503a261 | ||
|
|
edca42247d | ||
|
|
b6ba8f59bd | ||
|
|
f9f7898277 | ||
|
|
dbacd044eb |
No files matched your search
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
<Project>
|
<Project>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Reactor" Version="2.3.1" />
|
<PackageReference Include="Reactor" Version="2.5.0-ci.371" />
|
||||||
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.735" Private="false" ExcludeAssets="runtime;native" />
|
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.735" Private="false" ExcludeAssets="runtime;native" />
|
||||||
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2025.9.9" PrivateAssets="all" />
|
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2026.8.18" 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" />
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||||
|
|
||||||
<VersionPrefix>0.3.1</VersionPrefix>
|
<VersionPrefix>0.4.3</VersionPrefix>
|
||||||
<VersionSuffix>dev</VersionSuffix>
|
<VersionSuffix>dev</VersionSuffix>
|
||||||
|
|
||||||
<Authors>All Of Us, XtraCube, Angxl</Authors>
|
<Authors>All Of Us, XtraCube, Angxl</Authors>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Linq;
|
using System.Globalization;
|
||||||
|
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;
|
||||||
@@ -17,7 +18,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}");
|
||||||
@@ -37,6 +38,21 @@ 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 _)
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
using System.Linq;
|
using BepInEx;
|
||||||
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.Utilities.Assets;
|
||||||
using Reactor;
|
using Reactor;
|
||||||
using Reactor.Networking;
|
using Reactor.Networking;
|
||||||
using Reactor.Networking.Attributes;
|
using Reactor.Networking.Attributes;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Example;
|
namespace MiraAPI.Example;
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ public partial class ExamplePlugin : BasePlugin, IMiraPlugin
|
|||||||
{
|
{
|
||||||
public Harmony Harmony { get; } = new(Id);
|
public Harmony Harmony { get; } = new(Id);
|
||||||
public string OptionsTitleText => "Mira API\nExample Mod";
|
public string OptionsTitleText => "Mira API\nExample Mod";
|
||||||
|
public string CustomOptionMenuNameTwo => "angxl's Options";
|
||||||
public ConfigFile GetConfigFile() => Config;
|
public ConfigFile GetConfigFile() => Config;
|
||||||
public override void Load()
|
public override void Load()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
@@ -10,6 +10,8 @@ public class ExampleOptions2 : AbstractOptionGroup
|
|||||||
|
|
||||||
public override uint GroupPriority => 0; // This group will be displayed first. The default value is uint.MaxValue.
|
public override uint GroupPriority => 0; // This group will be displayed first. The default value is uint.MaxValue.
|
||||||
|
|
||||||
|
public override MenuCategory ParentMenu => MenuCategory.CustomTwo;
|
||||||
|
|
||||||
public ModdedPlayerOption PlayerOption2 { get; } = new("YOU MUST CHOSE A PLAYER", false);
|
public ModdedPlayerOption PlayerOption2 { get; } = new("YOU MUST CHOSE A PLAYER", false);
|
||||||
public ModdedPlayerOption PlayerOption { get; } = new("Eh whatever");
|
public ModdedPlayerOption PlayerOption { get; } = new("Eh whatever");
|
||||||
public ModdedToggleOption ToggleOpt1 { get; } = new("Toggle Option 1", false);
|
public ModdedToggleOption ToggleOpt1 { get; } = new("Toggle Option 1", false);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ public class GeneralModifierOptions : AbstractOptionGroup
|
|||||||
|
|
||||||
public override uint GroupPriority => 0;
|
public override uint GroupPriority => 0;
|
||||||
|
|
||||||
public override bool ShowInModifiersMenu => true;
|
public override MenuCategory ParentMenu => MenuCategory.Modifiers;
|
||||||
|
|
||||||
[ModdedToggleOption("Some Boolean Option")]
|
[ModdedToggleOption("Some Boolean Option")]
|
||||||
public bool SomeBooleanOption { get; set; } = true;
|
public bool SomeBooleanOption { get; set; } = true;
|
||||||
|
|||||||
@@ -2,11 +2,17 @@
|
|||||||
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(
|
||||||
|
Palette.Blue,
|
||||||
|
TmpSpriteUtils.CreateSpriteAsset(
|
||||||
|
MiraAssets.ImpostorFile.LoadAsset(),
|
||||||
|
"ApiExample.Role.Impostor.FreezerRole"));
|
||||||
public override string GroupName => "Custom Role";
|
public override string GroupName => "Custom Role";
|
||||||
|
|
||||||
[ModdedNumberOption("Freeze Duration", 1, 15, 1, MiraNumberSuffixes.Seconds)]
|
[ModdedNumberOption("Freeze Duration", 1, 15, 1, MiraNumberSuffixes.Seconds)]
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using MiraAPI.Utilities;
|
|||||||
|
|
||||||
namespace MiraAPI.Example.Options.Roles;
|
namespace MiraAPI.Example.Options.Roles;
|
||||||
|
|
||||||
public class TeleporterOptions : AbstractOptionGroup<TeleporterRole>
|
public class TeleporterOptions : AbstractRoleOptionGroup<TeleporterRole>
|
||||||
{
|
{
|
||||||
public override string GroupName => "Teleporter";
|
public override string GroupName => "Teleporter";
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
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 TMPro;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -20,6 +21,8 @@ public class ChameloenRole : CrewmateRole, ICustomRole
|
|||||||
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),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using MiraAPI.Roles;
|
using MiraAPI.Roles;
|
||||||
|
using MiraAPI.Utilities.Assets;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Example.Roles;
|
namespace MiraAPI.Example.Roles;
|
||||||
@@ -13,6 +14,8 @@ public class FreezerRole : ImpostorRole, ICustomRole
|
|||||||
|
|
||||||
public CustomRoleConfiguration Configuration => new CustomRoleConfiguration(this)
|
public CustomRoleConfiguration Configuration => new CustomRoleConfiguration(this)
|
||||||
{
|
{
|
||||||
|
Icon = MiraAssets.ImpostorFile,
|
||||||
|
IconTmp = TmpSpriteUtils.CreateSpriteAsset(MiraAssets.ImpostorFile.LoadAsset(), "ApiExample.Role.Impostor.FreezerRole"),
|
||||||
OptionsScreenshot = ExampleAssets.Banner,
|
OptionsScreenshot = ExampleAssets.Banner,
|
||||||
MaxRoleCount = 2,
|
MaxRoleCount = 2,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ using HarmonyLib;
|
|||||||
namespace MiraAPI.Colors;
|
namespace MiraAPI.Colors;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to register and track custom colors.
|
/// Used to register and track <see cref="CustomColor"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class PaletteManager
|
public static class PaletteManager
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all registered custom colors.
|
/// Gets all registered <see cref="CustomColor"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static CustomColor[] RegisteredColors => [.. CustomColors];
|
public static CustomColor[] RegisteredColors => [.. CustomColors];
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace MiraAPI.Colors;
|
namespace MiraAPI.Colors;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to mark a class for custom colors registration.
|
/// Used to mark a class for <see cref="CustomColor"/> registration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
public class RegisterCustomColorsAttribute : Attribute;
|
public class RegisterCustomColorsAttribute : Attribute;
|
||||||
@@ -3,20 +3,20 @@
|
|||||||
namespace MiraAPI.Events.Mira;
|
namespace MiraAPI.Events.Mira;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked when a Mira Button click is cancelled. Do not use for vanilla buttons.
|
/// Invoked when a <see cref="CustomActionButton"/> click is cancelled. Do not use for vanilla <see cref="AbilityButton"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The Mira Button type.</typeparam>
|
/// <typeparam name="T">The <see cref="CustomActionButton"/> type.</typeparam>
|
||||||
public sealed class MiraButtonCancelledEvent<T> : MiraEvent where T : CustomActionButton
|
public sealed class MiraButtonCancelledEvent<T> : MiraEvent where T : CustomActionButton
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets Mira Button whose click was cancelled.
|
/// Gets the <see cref="CustomActionButton"/> whose click was cancelled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public T Button { get; }
|
public T Button { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MiraButtonCancelledEvent{T}"/> class.
|
/// Initializes a new instance of the <see cref="MiraButtonCancelledEvent{T}"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="button">The Mira Button whose click was cancelled.</param>
|
/// <param name="button">The <see cref="CustomActionButton"/> whose click was cancelled.</param>
|
||||||
public MiraButtonCancelledEvent(T button)
|
public MiraButtonCancelledEvent(T button)
|
||||||
{
|
{
|
||||||
Button = button;
|
Button = button;
|
||||||
@@ -24,19 +24,19 @@ public sealed class MiraButtonCancelledEvent<T> : MiraEvent where T : CustomActi
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked when a Mira Button click is cancelled. Do not use for vanilla buttons.
|
/// Invoked when a <see cref="CustomActionButton"/> click is cancelled. Do not use for vanilla <see cref="AbilityButton"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class MiraButtonCancelledEvent : MiraEvent
|
public sealed class MiraButtonCancelledEvent : MiraEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets Mira Button whose click was cancelled.
|
/// Gets the <see cref="CustomActionButton"/> whose click was cancelled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CustomActionButton Button { get; }
|
public CustomActionButton Button { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MiraButtonCancelledEvent"/> class.
|
/// Initializes a new instance of the <see cref="MiraButtonCancelledEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="button">The Mira Button whose click was cancelled.</param>
|
/// <param name="button">The <see cref="CustomActionButton"/> whose click was cancelled.</param>
|
||||||
public MiraButtonCancelledEvent(CustomActionButton button)
|
public MiraButtonCancelledEvent(CustomActionButton button)
|
||||||
{
|
{
|
||||||
Button = button;
|
Button = button;
|
||||||
|
|||||||
@@ -3,26 +3,26 @@
|
|||||||
namespace MiraAPI.Events.Mira;
|
namespace MiraAPI.Events.Mira;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Button click event for Mira Buttons only. Do not use for vanilla buttons.
|
/// Button click event for <see cref="CustomActionButton"/>s only. Do not use for vanilla <see cref="AbilityButton"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The Mira Button type.</typeparam>
|
/// <typeparam name="T">The <see cref="CustomActionButton"/> type.</typeparam>
|
||||||
public sealed class MiraButtonClickEvent<T> : MiraCancelableEvent where T : CustomActionButton
|
public class MiraButtonClickEvent<T> : MiraCancelableEvent where T : CustomActionButton
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets Mira Button that was clicked.
|
/// Gets the <see cref="CustomActionButton"/> that was clicked.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public T Button { get; }
|
public T Button { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the generic click event that is invoked before this button-specific event.
|
/// Gets the generic <see cref="MiraButtonClickEvent"/> that is invoked before this button-specific event.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MiraButtonClickEvent GenericClickEvent { get; }
|
public MiraButtonClickEvent GenericClickEvent { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MiraButtonClickEvent{T}"/> class.
|
/// Initializes a new instance of the <see cref="MiraButtonClickEvent{T}"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="button">The Mira Button that was clicked.</param>
|
/// <param name="button">The <see cref="CustomActionButton"/> that was clicked.</param>
|
||||||
/// <param name="genericClickEvent">The generic click event invoked before button-specific events.</param>
|
/// <param name="genericClickEvent">The generic <see cref="MiraButtonClickEvent"/> invoked before button-specific events.</param>
|
||||||
public MiraButtonClickEvent(T button, MiraButtonClickEvent genericClickEvent)
|
public MiraButtonClickEvent(T button, MiraButtonClickEvent genericClickEvent)
|
||||||
{
|
{
|
||||||
GenericClickEvent = genericClickEvent;
|
GenericClickEvent = genericClickEvent;
|
||||||
@@ -31,19 +31,19 @@ public sealed class MiraButtonClickEvent<T> : MiraCancelableEvent where T : Cust
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Button click event for Mira Buttons only. Do not use for vanilla buttons.
|
/// Button click event for <see cref="CustomActionButton"/>s only. Do not use for vanilla <see cref="AbilityButton"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class MiraButtonClickEvent : MiraCancelableEvent
|
public class MiraButtonClickEvent : MiraCancelableEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets Mira Button that was clicked.
|
/// Gets the <see cref="CustomActionButton"/> that was clicked.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CustomActionButton Button { get; }
|
public CustomActionButton Button { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MiraButtonClickEvent"/> class.
|
/// Initializes a new instance of the <see cref="MiraButtonClickEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="button">The Mira Button that was clicked.</param>
|
/// <param name="button">The <see cref="CustomActionButton"/> that was clicked.</param>
|
||||||
public MiraButtonClickEvent(CustomActionButton button)
|
public MiraButtonClickEvent(CustomActionButton button)
|
||||||
{
|
{
|
||||||
Button = button;
|
Button = button;
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
namespace MiraAPI.Events;
|
using MiraAPI.PluginLoading;
|
||||||
|
|
||||||
|
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,6 +1,9 @@
|
|||||||
namespace MiraAPI.Events;
|
using MiraAPI.PluginLoading;
|
||||||
|
|
||||||
|
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;
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace MiraAPI.Events;
|
namespace MiraAPI.Events;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event handle to use when unregistering an event.
|
/// Event handle to use when unregistering a <see cref="MiraEvent"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MiraEventHandle
|
public class MiraEventHandle
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
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;
|
||||||
|
|
||||||
@@ -13,11 +12,11 @@ public static class MiraEventManager
|
|||||||
private static readonly Dictionary<Type, List<MiraEventWrapper>> EventWrappers = [];
|
private static readonly Dictionary<Type, List<MiraEventWrapper>> EventWrappers = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoke an event.
|
/// Invoke a <see cref="MiraEvent"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="eventInstance">The event instance.</param>
|
/// <param name="eventInstance">The <typeparamref name="T"/> 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 true. Otherwise, return false.</returns>
|
/// <returns>If there was an event handler invoked for this event, return <see langword="true"/>. Otherwise, return <see langword="false"/>.</returns>
|
||||||
public static bool InvokeEvent<T>(T eventInstance) where T : MiraEvent
|
public static bool InvokeEvent<T>(T eventInstance) where T : MiraEvent
|
||||||
{
|
{
|
||||||
EventWrappers.TryGetValue(typeof(T), out var handlers);
|
EventWrappers.TryGetValue(typeof(T), out var handlers);
|
||||||
@@ -34,7 +33,7 @@ public static class MiraEventManager
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger<MiraApiPlugin>.Error($"Error invoking event handler for {typeof(T).Name}: {ex.ToString()}");
|
Error($"Error invoking event handler for {typeof(T).Name}: {ex.ToString()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,11 +41,11 @@ public static class MiraEventManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoke an event and use a specific type to find the handlers.
|
/// Invoke a <see cref="MiraEvent"/> and use a specific type to find the handlers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="eventInstance">The event instance.</param>
|
/// <param name="eventInstance">The <see cref="MiraEvent"/> 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 true. Otherwise, return false.</returns>
|
/// <returns>If there was an event handler invoked for this event, return <see langword="true"/>. Otherwise, return <see langword="false"/>.</returns>
|
||||||
public static bool InvokeEvent(MiraEvent eventInstance, Type type)
|
public static bool InvokeEvent(MiraEvent eventInstance, Type type)
|
||||||
{
|
{
|
||||||
EventWrappers.TryGetValue(type, out var handlers);
|
EventWrappers.TryGetValue(type, out var handlers);
|
||||||
@@ -63,7 +62,7 @@ public static class MiraEventManager
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger<MiraApiPlugin>.Error($"Error invoking event handler for {type.Name}: {ex.ToString()}");
|
Error($"Error invoking event handler for {type.Name}: {ex.ToString()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,12 +70,12 @@ public static class MiraEventManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register an event.
|
/// Register a <see cref="MiraEvent"/> handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">The type of event.</param>
|
/// <param name="type">The type of <see cref="MiraEvent"/> event.</param>
|
||||||
/// <param name="methodInfo">The MethodInfo of the event handler.</param>
|
/// <param name="methodInfo">The <see cref="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>An event handle to use when unregistering the event.</returns>
|
/// <returns>A <see cref="MiraEventHandle"/> 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)))
|
||||||
@@ -102,12 +101,12 @@ public static class MiraEventManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register an event.
|
/// Register a <typeparamref name="T"/> handler.
|
||||||
/// </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 event.</typeparam>
|
/// <typeparam name="T">Type of <see cref="MiraEvent"/> event.</typeparam>
|
||||||
/// <returns>An event handle to use when unregistering the event.</returns>
|
/// <returns>A <see cref="MiraEventHandle"/> to use when unregistering the event.</returns>
|
||||||
public static MiraEventHandle RegisterEventHandler<T>(Action<T> handler, int priority = 0) where T : MiraEvent
|
public static MiraEventHandle RegisterEventHandler<T>(Action<T> handler, int priority = 0) where T : MiraEvent
|
||||||
{
|
{
|
||||||
EventWrappers.TryAdd(typeof(T), []);
|
EventWrappers.TryAdd(typeof(T), []);
|
||||||
@@ -127,10 +126,10 @@ public static class MiraEventManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unregister an event using the event handle.
|
/// Unregister a <see cref="MiraEvent"/> handler using the <see cref="MiraEventHandle"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="eventHandle">A handle to the event.</param>
|
/// <param name="eventHandle">A handle to the event.</param>
|
||||||
/// <returns>True if the event was unregistered successfully, false otherwise.</returns>
|
/// <returns><see langword="true"/> if the event was unregistered successfully, <see langword="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))
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace MiraAPI.Events;
|
namespace MiraAPI.Events;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wrapper for event handlers.
|
/// Wrapper for <see cref="MiraEvent"/> handlers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MiraEventWrapper
|
public class MiraEventWrapper
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace MiraAPI.Events;
|
namespace MiraAPI.Events;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register an event.
|
/// Register a <see cref="MiraEvent"/> handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Method)]
|
[AttributeUsage(AttributeTargets.Method)]
|
||||||
public class RegisterEventAttribute : Attribute
|
public class RegisterEventAttribute : Attribute
|
||||||
|
|||||||
@@ -6,30 +6,86 @@
|
|||||||
public class AfterMurderEvent : MiraEvent
|
public class AfterMurderEvent : MiraEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the player that killed the target.
|
/// Gets the <see cref="PlayerControl"/> that killed the <see cref="Target"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PlayerControl Source { get; }
|
public PlayerControl Source { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the player that was killed.
|
/// Gets the <see cref="PlayerControl"/> that was killed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PlayerControl Target { get; }
|
public PlayerControl Target { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the player's body, if it exists.
|
/// Gets the <see cref="PlayerControl"/> that was framed, if any.
|
||||||
|
/// </summary>
|
||||||
|
public PlayerControl? Framed { 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; }
|
||||||
|
|
||||||
|
/// <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; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Target"/>'s <see cref="DeadBody"/>, if it exists.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DeadBody? DeadBody { get; }
|
public DeadBody? DeadBody { get; }
|
||||||
|
|
||||||
/// <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 killer.</param>
|
/// <param name="source">The <see cref="PlayerControl"/> that killed the <paramref name="target"/>.</param>
|
||||||
/// <param name="target">The killed player.</param>
|
/// <param name="target">The <see cref="PlayerControl"/> that was killed.</param>
|
||||||
/// <param name="deadBody">The player's vody, if it exists.</param>
|
/// <param name="deadBody">The <paramref name="target"/>'s <see cref="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 AfterMurderEvent(PlayerControl source, PlayerControl target, DeadBody? deadBody, bool isIndirect, bool ignoreDefense = false)
|
||||||
|
{
|
||||||
|
Source = source;
|
||||||
|
Target = target;
|
||||||
|
Framed = null;
|
||||||
|
DeadBody = deadBody;
|
||||||
|
IsIndirectAttack = isIndirect;
|
||||||
|
IgnoreDefense = 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="framed">The <see cref="PlayerControl"/> that was framed.</param>
|
||||||
|
/// <param name="deadBody">The <paramref name="target"/>'s <see cref="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 AfterMurderEvent(PlayerControl source, PlayerControl target, PlayerControl framed, DeadBody? deadBody, bool isIndirect = true, bool ignoreDefense = false)
|
||||||
|
{
|
||||||
|
Source = source;
|
||||||
|
Target = target;
|
||||||
|
Framed = framed;
|
||||||
|
DeadBody = deadBody;
|
||||||
|
IsIndirectAttack = isIndirect;
|
||||||
|
IgnoreDefense = 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)
|
||||||
{
|
{
|
||||||
Source = source;
|
Source = source;
|
||||||
Target = target;
|
Target = target;
|
||||||
|
Framed = null;
|
||||||
DeadBody = deadBody;
|
DeadBody = deadBody;
|
||||||
|
IsIndirectAttack = false;
|
||||||
|
IgnoreDefense = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace MiraAPI.Events.Vanilla.Gameplay;
|
namespace MiraAPI.Events.Vanilla.Gameplay;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked before RpcEndGame is called, allowing cancellation of the game end entirely.
|
/// Invoked before <see cref="GameManager.RpcEndGame"/> is called, allowing cancellation of the game end entirely.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BeforeGameEndEvent : MiraCancelableEvent
|
public class BeforeGameEndEvent : MiraCancelableEvent
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace MiraAPI.Events.Vanilla.Gameplay;
|
using MiraAPI.Networking;
|
||||||
|
|
||||||
|
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.
|
||||||
@@ -6,23 +8,101 @@
|
|||||||
public sealed class BeforeMurderEvent : MiraCancelableEvent
|
public sealed class BeforeMurderEvent : MiraCancelableEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the player that is killing the target.
|
/// Gets the <see cref="PlayerControl"/> that is killing the <see cref="Target"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PlayerControl Source { get; }
|
public PlayerControl Source { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the player that is being killed.
|
/// Gets the <see cref="PlayerControl"/> that is being killed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PlayerControl Target { get; }
|
public PlayerControl Target { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="PlayerControl"/> that is being framed, if any.
|
||||||
|
/// </summary>
|
||||||
|
public PlayerControl? Framed { get; }
|
||||||
|
|
||||||
|
/// <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; }
|
||||||
|
|
||||||
|
/// <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; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets whether the murder was meant to be done in a meeting, via an enum.
|
||||||
|
/// </summary>
|
||||||
|
public MeetingCheck InMeeting { get; }
|
||||||
|
|
||||||
/// <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 player that is killing the target.</param>
|
/// <param name="source">The <see cref="PlayerControl"/> that is killing the <paramref name="target"/>.</param>
|
||||||
/// <param name="target">The player that is being killed.</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)
|
||||||
|
{
|
||||||
|
Source = source;
|
||||||
|
Target = target;
|
||||||
|
Framed = null;
|
||||||
|
IsIndirectAttack = isIndirect;
|
||||||
|
IgnoreDefense = ignoreDefense;
|
||||||
|
InMeeting = 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="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 BeforeMurderEvent(PlayerControl source, PlayerControl target, PlayerControl framed, bool isIndirect = true, bool ignoreDefense = false, MeetingCheck inMeeting = MeetingCheck.Ignore)
|
||||||
|
{
|
||||||
|
Source = source;
|
||||||
|
Target = target;
|
||||||
|
Framed = framed;
|
||||||
|
IsIndirectAttack = isIndirect;
|
||||||
|
IgnoreDefense = ignoreDefense;
|
||||||
|
InMeeting = 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="inMeeting">Whether the murder is intended to be triggered in a meeting.</param>
|
||||||
|
public BeforeMurderEvent(PlayerControl source, PlayerControl target, MeetingCheck inMeeting)
|
||||||
|
{
|
||||||
|
Source = source;
|
||||||
|
Target = target;
|
||||||
|
Framed = null;
|
||||||
|
IsIndirectAttack = false;
|
||||||
|
IgnoreDefense = false;
|
||||||
|
InMeeting = 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>
|
||||||
public BeforeMurderEvent(PlayerControl source, PlayerControl target)
|
public BeforeMurderEvent(PlayerControl source, PlayerControl target)
|
||||||
{
|
{
|
||||||
Source = source;
|
Source = source;
|
||||||
Target = target;
|
Target = target;
|
||||||
|
Framed = null;
|
||||||
|
IsIndirectAttack = false;
|
||||||
|
IgnoreDefense = false;
|
||||||
|
InMeeting = MeetingCheck.Ignore;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
namespace MiraAPI.Events.Vanilla.Gameplay;
|
namespace MiraAPI.Events.Vanilla.Gameplay;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event invoked on IntroCutscene.OnDestroy and ExileController.WrapUp to determine if it should run the round event or not.
|
/// 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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BeforeRoundStartEvent : MiraCancelableEvent
|
public class BeforeRoundStartEvent : MiraCancelableEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the event was triggered by the IntroCutscene or ExileController.
|
/// Gets a value indicating whether the event was triggered by the <see cref="IntroCutscene"/> or <see cref="ExileController"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TriggeredByIntro { get; }
|
public bool TriggeredByIntro { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -6,14 +6,14 @@
|
|||||||
public class GameEndEvent : MiraEvent
|
public class GameEndEvent : MiraEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the instance of the EndGameManager.
|
/// Gets the <see cref="global::EndGameManager"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public EndGameManager EndGameManager { get; }
|
public EndGameManager EndGameManager { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="GameEndEvent"/> class.
|
/// Initializes a new instance of the <see cref="GameEndEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="manager">The instance of the EndGameManager.</param>
|
/// <param name="manager">The <see cref="global::EndGameManager"/> instance.</param>
|
||||||
public GameEndEvent(EndGameManager manager)
|
public GameEndEvent(EndGameManager manager)
|
||||||
{
|
{
|
||||||
EndGameManager = manager;
|
EndGameManager = manager;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
public class IntroBeginEvent : MiraEvent
|
public class IntroBeginEvent : MiraEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the instance of the IntroCutscene.
|
/// Gets the <see cref="global::IntroCutscene"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IntroCutscene IntroCutscene { get; }
|
public IntroCutscene IntroCutscene { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
public class IntroEndEvent(IntroCutscene introCutscene) : MiraEvent
|
public class IntroEndEvent(IntroCutscene introCutscene) : MiraEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the instance of the IntroCutscene.
|
/// Gets the <see cref="global::IntroCutscene"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IntroCutscene IntroCutscene { get; } = introCutscene;
|
public IntroCutscene IntroCutscene { get; } = introCutscene;
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
public class IntroRoleRevealEvent : MiraEvent
|
public class IntroRoleRevealEvent : MiraEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the instance of the IntroCutscene.
|
/// Gets the <see cref="global::IntroCutscene"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IntroCutscene IntroCutscene { get; }
|
public IntroCutscene IntroCutscene { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
namespace MiraAPI.Events.Vanilla.Gameplay;
|
namespace MiraAPI.Events.Vanilla.Gameplay;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Start Round event, invoked on IntroCutscene.OnDestroy and ExileController.WrapUp if the event isn't cancelled.
|
/// Start Round event, invoked on <see cref="IntroCutscene.OnDestroy"/> and <see cref="ExileController.WrapUp"/>
|
||||||
|
/// if the <see cref="BeforeRoundStartEvent"/> isn't cancelled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RoundStartEvent : MiraEvent
|
public class RoundStartEvent : MiraEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the event was triggered by the IntroCutscene or ExileController.
|
/// Gets a value indicating whether the event was triggered by the <see cref="IntroCutscene"/> or <see cref="ExileController"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TriggeredByIntro { get; }
|
public bool TriggeredByIntro { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace MiraAPI.Events.Vanilla.Gameplay;
|
|||||||
public class SetRoleEvent : MiraEvent
|
public class SetRoleEvent : MiraEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the player whos role was changed.
|
/// Gets the <see cref="PlayerControl"/> whose role was changed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PlayerControl Player { get; }
|
public PlayerControl Player { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
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>
|
||||||
|
public sealed class VanillaButtonCancelledEvent<T> : MiraEvent where T : AbilityButton
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Vanilla <see cref="AbilityButton"/> whose click was cancelled.
|
||||||
|
/// </summary>
|
||||||
|
public T Button { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="VanillaButtonCancelledEvent{T}"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="button">The vanilla <see cref="AbilityButton"/> whose click was cancelled.</param>
|
||||||
|
public VanillaButtonCancelledEvent(T button)
|
||||||
|
{
|
||||||
|
Button = button;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when a Vanilla <see cref="AbilityButton"/> click is cancelled. Do not use for <see cref="CustomActionButton"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class VanillaButtonCancelledEvent : MiraEvent
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Vanilla <see cref="AbilityButton"/> whose click was cancelled.
|
||||||
|
/// </summary>
|
||||||
|
public AbilityButton Button { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="VanillaButtonCancelledEvent"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="button">The vanilla <see cref="AbilityButton"/> whose click was cancelled.</param>
|
||||||
|
public VanillaButtonCancelledEvent(AbilityButton button)
|
||||||
|
{
|
||||||
|
Button = button;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
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>
|
||||||
|
public sealed class VanillaButtonClickEvent<T> : MiraCancelableEvent where T : AbilityButton
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the vanilla <see cref="AbilityButton"/> that was clicked.
|
||||||
|
/// </summary>
|
||||||
|
public T Button { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the generic <see cref="VanillaButtonClickEvent"/> that is invoked before this button-specific event.
|
||||||
|
/// </summary>
|
||||||
|
public VanillaButtonClickEvent GenericClickEvent { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="VanillaButtonClickEvent{T}"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <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 VanillaButtonClickEvent(T button, VanillaButtonClickEvent genericClickEvent)
|
||||||
|
{
|
||||||
|
GenericClickEvent = genericClickEvent;
|
||||||
|
Button = button;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Button click event for Vanilla <see cref="AbilityButton"/> only. Do not use for <see cref="CustomActionButton"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class VanillaButtonClickEvent : MiraCancelableEvent
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Vanilla <see cref="AbilityButton"/> that was clicked.
|
||||||
|
/// </summary>
|
||||||
|
public AbilityButton Button { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the target <see cref="PlayerControl"/>, if any, of the Vanilla <see cref="AbilityButton"/> that was clicked.
|
||||||
|
/// </summary>
|
||||||
|
public PlayerControl? PlayerTarget { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the target <see cref="Vent"/>, if any, of the Vanilla <see cref="AbilityButton"/> that was clicked.
|
||||||
|
/// </summary>
|
||||||
|
public Vent? VentTarget { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="VanillaButtonClickEvent"/> class.
|
||||||
|
/// </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 VanillaButtonClickEvent(AbilityButton button, PlayerControl? playerTarget = null, Vent? ventTarget = null)
|
||||||
|
{
|
||||||
|
Button = button;
|
||||||
|
PlayerTarget = playerTarget;
|
||||||
|
VentTarget = ventTarget;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,14 +6,14 @@
|
|||||||
public class PlayerOpenSabotageEvent : MiraCancelableEvent
|
public class PlayerOpenSabotageEvent : MiraCancelableEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the MapBehaviour.
|
/// Gets the <see cref="global::MapBehaviour"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MapBehaviour MapBehaviour { get; }
|
public MapBehaviour MapBehaviour { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="PlayerOpenSabotageEvent"/> class.
|
/// Initializes a new instance of the <see cref="PlayerOpenSabotageEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="mapBehaviour">The MapBehaviour.</param>
|
/// <param name="mapBehaviour">The <see cref="global::MapBehaviour"/>.</param>
|
||||||
public PlayerOpenSabotageEvent(MapBehaviour mapBehaviour)
|
public PlayerOpenSabotageEvent(MapBehaviour mapBehaviour)
|
||||||
{
|
{
|
||||||
MapBehaviour = mapBehaviour;
|
MapBehaviour = mapBehaviour;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace MiraAPI.Events.Vanilla.Map;
|
namespace MiraAPI.Events.Vanilla.Map;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cancelable event that is invoked before a system is updated. Usually used for sabotage events.
|
/// <see cref="MiraCancelableEvent"/> that is invoked before a system is updated. Usually used for sabotage events.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class UpdateSystemEvent : MiraCancelableEvent
|
public class UpdateSystemEvent : MiraCancelableEvent
|
||||||
{
|
{
|
||||||
@@ -11,7 +11,7 @@ public class UpdateSystemEvent : MiraCancelableEvent
|
|||||||
public SystemTypes SystemType { get; }
|
public SystemTypes SystemType { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the player that is updating the system.
|
/// Gets the <see cref="PlayerControl"/> that is updating the system.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PlayerControl Player { get; }
|
public PlayerControl Player { get; }
|
||||||
|
|
||||||
@@ -21,10 +21,10 @@ public class UpdateSystemEvent : MiraCancelableEvent
|
|||||||
public byte Amount { get; }
|
public byte Amount { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="UpdateSystemEvent"/> class.
|
/// Initializes a new instance of the <see cref="UpdateSystemEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="systemType">The SystemType being updated.</param>
|
/// <param name="systemType">The <see cref="SystemTypes"/> being updated.</param>
|
||||||
/// <param name="player">The player that is updating the system.</param>
|
/// <param name="player">The <see cref="PlayerControl"/> that is updating the system.</param>
|
||||||
/// <param name="amount">Amount to update System to.</param>
|
/// <param name="amount">Amount to update System to.</param>
|
||||||
public UpdateSystemEvent(SystemTypes systemType, PlayerControl player, byte amount)
|
public UpdateSystemEvent(SystemTypes systemType, PlayerControl player, byte amount)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,14 +6,14 @@
|
|||||||
public class EjectionEvent : MiraEvent
|
public class EjectionEvent : MiraEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the instance of the ExileController.
|
/// Gets the <see cref="global::ExileController"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ExileController ExileController { get; }
|
public ExileController ExileController { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="EjectionEvent"/> class.
|
/// Initializes a new instance of the <see cref="EjectionEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="controller">The exile controller.</param>
|
/// <param name="controller">The <see cref="global::ExileController"/> instance.</param>
|
||||||
public EjectionEvent(ExileController controller)
|
public EjectionEvent(ExileController controller)
|
||||||
{
|
{
|
||||||
ExileController = controller;
|
ExileController = controller;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
public class EndMeetingEvent(MeetingHud meetingHud) : MiraEvent
|
public class EndMeetingEvent(MeetingHud meetingHud) : MiraEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the MeetingHud instance.
|
/// Gets the <see cref="global::MeetingHud"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MeetingHud MeetingHud { get; } = meetingHud;
|
public MeetingHud MeetingHud { get; } = meetingHud;
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The event that is invoked when a body is reported.
|
/// The event that is invoked when a body is reported.
|
||||||
/// This is invoked in CmdReportBody.
|
/// This is invoked in <see cref="PlayerControl.CmdReportDeadBody(NetworkedPlayerInfo)"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ReportBodyEvent : MiraCancelableEvent
|
public class ReportBodyEvent : MiraCancelableEvent
|
||||||
{
|
{
|
||||||
@@ -12,12 +12,12 @@ public class ReportBodyEvent : MiraCancelableEvent
|
|||||||
public PlayerControl Reporter { get; }
|
public PlayerControl Reporter { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the player that is being reported. Will be null for emergency meeting.
|
/// Gets the player that is being reported. Will be <see langword="null"/> for emergency meeting.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NetworkedPlayerInfo? Target { get; }
|
public NetworkedPlayerInfo? Target { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the body that is being reported. Will be null for emergency meeting.
|
/// Gets the <see cref="DeadBody"/> that is being reported. Will be <see langword="null"/> for emergency meeting.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DeadBody? Body { get; }
|
public DeadBody? Body { get; }
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ public class ReportBodyEvent : MiraCancelableEvent
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="reporter">The player who reported the body.</param>
|
/// <param name="reporter">The player who reported the body.</param>
|
||||||
/// <param name="target">The player being reported.</param>
|
/// <param name="target">The player being reported.</param>
|
||||||
/// <param name="body">The body being reported.</param>
|
/// <param name="body">The <see cref="DeadBody"/> being reported.</param>
|
||||||
public ReportBodyEvent(PlayerControl reporter, NetworkedPlayerInfo? target, DeadBody? body)
|
public ReportBodyEvent(PlayerControl reporter, NetworkedPlayerInfo? target, DeadBody? body)
|
||||||
{
|
{
|
||||||
Reporter = reporter;
|
Reporter = reporter;
|
||||||
|
|||||||
@@ -7,14 +7,14 @@
|
|||||||
public class StartMeetingEvent : MiraEvent
|
public class StartMeetingEvent : MiraEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the MeetingHud instance.
|
/// Gets the <see cref="global::MeetingHud"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MeetingHud MeetingHud { get; }
|
public MeetingHud MeetingHud { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="StartMeetingEvent"/> class.
|
/// Initializes a new instance of the <see cref="StartMeetingEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="meetingHud">The MeetingHud instance.</param>
|
/// <param name="meetingHud">The <see cref="global::MeetingHud"/> instance.</param>
|
||||||
public StartMeetingEvent(MeetingHud meetingHud)
|
public StartMeetingEvent(MeetingHud meetingHud)
|
||||||
{
|
{
|
||||||
MeetingHud = meetingHud;
|
MeetingHud = meetingHud;
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using MiraAPI.Voting;
|
namespace MiraAPI.Events.Vanilla.Meeting.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.
|
||||||
@@ -8,7 +6,7 @@ namespace MiraAPI.Events.Vanilla.Meeting.Voting;
|
|||||||
public class AfterVoteEvent : MiraEvent
|
public class AfterVoteEvent : MiraEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the instance of the voter's vote data.
|
/// Gets the instance of the voter's <see cref="PlayerVoteArea"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PlayerVoteArea VoteArea { get; }
|
public PlayerVoteArea VoteArea { get; }
|
||||||
|
|
||||||
@@ -20,7 +18,7 @@ public class AfterVoteEvent : MiraEvent
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="AfterVoteEvent"/> class.
|
/// Initializes a new instance of the <see cref="AfterVoteEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="playerVoteArea">The player vote area that was voted on.</param>
|
/// <param name="playerVoteArea">The <see cref="PlayerVoteArea"/> that was voted on.</param>
|
||||||
/// <param name="voter">The player who voted.</param>
|
/// <param name="voter">The player who voted.</param>
|
||||||
public AfterVoteEvent(PlayerVoteArea playerVoteArea, PlayerControl voter)
|
public AfterVoteEvent(PlayerVoteArea playerVoteArea, PlayerControl voter)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using MiraAPI.Voting;
|
namespace MiraAPI.Events.Vanilla.Meeting.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.
|
||||||
@@ -8,7 +6,7 @@ namespace MiraAPI.Events.Vanilla.Meeting.Voting;
|
|||||||
public class BeforeVoteEvent : MiraCancelableEvent
|
public class BeforeVoteEvent : MiraCancelableEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the instance of the voter's vote data.
|
/// Gets the instance of the voter's <see cref="PlayerVoteArea"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PlayerVoteArea VoteArea { get; }
|
public PlayerVoteArea VoteArea { get; }
|
||||||
|
|
||||||
@@ -20,7 +18,7 @@ public class BeforeVoteEvent : MiraCancelableEvent
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="BeforeVoteEvent"/> class.
|
/// Initializes a new instance of the <see cref="BeforeVoteEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="playerVoteArea">The player vote area that was voted on.</param>
|
/// <param name="playerVoteArea">The <see cref="PlayerVoteArea"/> that was voted on.</param>
|
||||||
/// <param name="voter">The player who voted.</param>
|
/// <param name="voter">The player who voted.</param>
|
||||||
public BeforeVoteEvent(PlayerVoteArea playerVoteArea, PlayerControl voter)
|
public BeforeVoteEvent(PlayerVoteArea playerVoteArea, PlayerControl voter)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class CheckForEndVotingEvent : MiraCancelableEvent
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="CheckForEndVotingEvent"/> class.
|
/// Initializes a new instance of the <see cref="CheckForEndVotingEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="isVotingComplete">>True if voting is complete, false otherwise.</param>
|
/// <param name="isVotingComplete"><see langword="true"/> if voting is complete, <see langword="false"/> otherwise.</param>
|
||||||
public CheckForEndVotingEvent(bool isVotingComplete)
|
public CheckForEndVotingEvent(bool isVotingComplete)
|
||||||
{
|
{
|
||||||
IsVotingComplete = isVotingComplete;
|
IsVotingComplete = isVotingComplete;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class DummyVoteEvent : MiraCancelableEvent
|
|||||||
public DummyBehaviour Dummy { get; }
|
public DummyBehaviour Dummy { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the instance of the dummy's vote data.
|
/// Gets the instance of the dummy's <see cref="PlayerVoteData"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PlayerVoteData VoteData { get; }
|
public PlayerVoteData VoteData { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ 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 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.
|
/// 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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class HandleVoteEvent : MiraCancelableEvent
|
public class HandleVoteEvent : MiraCancelableEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the instance of the voter's vote data.
|
/// Gets the instance of the voter's <see cref="PlayerVoteData"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PlayerVoteData VoteData { get; }
|
public PlayerVoteData VoteData { get; }
|
||||||
|
|
||||||
@@ -25,19 +25,24 @@ public class HandleVoteEvent : MiraCancelableEvent
|
|||||||
public byte TargetId { get; }
|
public byte TargetId { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether to prevent the vote from commencing.
|
/// Gets or sets a value indicating whether to prevent the vote from commencing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool PreventVote { get; }
|
public bool PreventVote { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the player info of the target.
|
/// Gets the <see cref="NetworkedPlayerInfo"/> of the target.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NetworkedPlayerInfo TargetPlayerInfo { get; }
|
public NetworkedPlayerInfo TargetPlayerInfo { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether the vote event is an Overrule caused by a Judge.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsOverruling { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="HandleVoteEvent"/> class.
|
/// Initializes a new instance of the <see cref="HandleVoteEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="playerVoteData">The voter's data.</param>
|
/// <param name="playerVoteData">The voter's <see cref="PlayerVoteData"/>.</param>
|
||||||
/// <param name="targetId">The target's playerId.</param>
|
/// <param name="targetId">The target's playerId.</param>
|
||||||
public HandleVoteEvent(PlayerVoteData playerVoteData, byte targetId)
|
public HandleVoteEvent(PlayerVoteData playerVoteData, byte targetId)
|
||||||
{
|
{
|
||||||
@@ -47,4 +52,20 @@ public class HandleVoteEvent : MiraCancelableEvent
|
|||||||
PreventVote = false;
|
PreventVote = false;
|
||||||
TargetPlayerInfo = GameData.Instance.GetPlayerById(targetId);
|
TargetPlayerInfo = GameData.Instance.GetPlayerById(targetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HandleVoteEvent"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <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 HandleVoteEvent(PlayerVoteData playerVoteData, byte targetId, bool isOverruling)
|
||||||
|
{
|
||||||
|
VoteData = playerVoteData;
|
||||||
|
Player = playerVoteData.Owner;
|
||||||
|
TargetId = targetId;
|
||||||
|
PreventVote = false;
|
||||||
|
IsOverruling = isOverruling;
|
||||||
|
TargetPlayerInfo = GameData.Instance.GetPlayerById(targetId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@ namespace MiraAPI.Events.Vanilla.Meeting.Voting;
|
|||||||
public class MeetingSelectEvent : MiraEvent
|
public class MeetingSelectEvent : MiraEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the instance of the voter's vote data.
|
/// Gets the instance of the voter's <see cref="PlayerVoteData"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PlayerVoteData VoteData { get; }
|
public PlayerVoteData VoteData { get; }
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ public class MeetingSelectEvent : MiraEvent
|
|||||||
public int TargetId { get; }
|
public int TargetId { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the player info of the target.
|
/// Gets the <see cref="NetworkedPlayerInfo"/> of the target.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NetworkedPlayerInfo TargetPlayerInfo { get; }
|
public NetworkedPlayerInfo TargetPlayerInfo { get; }
|
||||||
|
|
||||||
@@ -30,9 +30,9 @@ public class MeetingSelectEvent : MiraEvent
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MeetingSelectEvent"/> class.
|
/// Initializes a new instance of the <see cref="MeetingSelectEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="playerVoteData">The voter's data.</param>
|
/// <param name="playerVoteData">The voter's <see cref="PlayerVoteData"/>.</param>
|
||||||
/// <param name="targetId">The target's playerId.</param>
|
/// <param name="targetId">The target's playerId.</param>
|
||||||
/// <param name="allowSelect">>Whether the player is allowed to select the target.</param>
|
/// <param name="allowSelect">Whether the player is allowed to select the target.</param>
|
||||||
public MeetingSelectEvent(PlayerVoteData playerVoteData, int targetId, bool allowSelect)
|
public MeetingSelectEvent(PlayerVoteData playerVoteData, int targetId, bool allowSelect)
|
||||||
{
|
{
|
||||||
VoteData = playerVoteData;
|
VoteData = playerVoteData;
|
||||||
|
|||||||
@@ -4,20 +4,20 @@ using MiraAPI.Voting;
|
|||||||
namespace MiraAPI.Events.Vanilla.Meeting.Voting;
|
namespace MiraAPI.Events.Vanilla.Meeting.Voting;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called in VotingUtils.HandlePopulateResults.
|
/// Called in <see cref="VotingUtils.HandlePopulateResults"/>.
|
||||||
/// 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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class PopulateResultsEvent : MiraCancelableEvent
|
public class PopulateResultsEvent : MiraCancelableEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a list of networked votes.
|
/// Gets a list of networked <see cref="CustomVote"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<CustomVote> Votes { get; }
|
public List<CustomVote> Votes { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="PopulateResultsEvent"/> class.
|
/// Initializes a new instance of the <see cref="PopulateResultsEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="votes">The list of votes.</param>
|
/// <param name="votes">The list of <see cref="CustomVote"/>s.</param>
|
||||||
public PopulateResultsEvent(List<CustomVote> votes)
|
public PopulateResultsEvent(List<CustomVote> votes)
|
||||||
{
|
{
|
||||||
Votes = votes;
|
Votes = votes;
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ namespace MiraAPI.Events.Vanilla.Meeting.Voting;
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Initializes a new instance of the <see cref="ProcessVotesEvent"/> class.
|
/// Initializes a new instance of the <see cref="ProcessVotesEvent"/> class.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="votes">>The list of votes that are being processed.</param>
|
/// <param name="votes">The list of <see cref="CustomVote"/>s that are being processed.</param>
|
||||||
/// <param name="exiledPlayer">The player to be exiled. Will be null if no player is to be exiled.</param>
|
/// <param name="exiledPlayer">The player to be exiled. Will be <see langword="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];
|
||||||
@@ -29,12 +29,22 @@ public class ProcessVotesEvent(List<CustomVote> votes, NetworkedPlayerInfo? exil
|
|||||||
public bool VotesModified => !Votes.SequenceEqual(_originalVotes);
|
public bool VotesModified => !Votes.SequenceEqual(_originalVotes);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the list of votes that are being processed.
|
/// Gets the list of <see cref="CustomVote"/>s that are being processed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<CustomVote> Votes { get; } = votes;
|
public List<CustomVote> Votes { get; } = votes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the player to be exiled. Will be null if no player is to be exiled.
|
/// Gets or sets a value indicating whether an overruling was done. Normally set by judge but can be overwritten.
|
||||||
|
/// </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>
|
/// </summary>
|
||||||
public NetworkedPlayerInfo? ExiledPlayer
|
public NetworkedPlayerInfo? 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 MeetingHud instance.</param>
|
/// <param name="meetingHud">The <see cref="global::MeetingHud"/> instance.</param>
|
||||||
public class VotingCompleteEvent(MeetingHud meetingHud) : MiraEvent
|
public class VotingCompleteEvent(MeetingHud meetingHud) : MiraEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the MeetingHud instance.
|
/// Gets the <see cref="global::MeetingHud"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MeetingHud MeetingHud { get; } = meetingHud;
|
public MeetingHud MeetingHud { get; } = meetingHud;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
namespace MiraAPI.Events.Vanilla.Player;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The event that is invoked when a player completes a task within Hide and Seek. Non-cancelable.
|
||||||
|
/// </summary>
|
||||||
|
public class CompleteHnsTaskEvent : MiraEvent
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the instance of the <see cref="PlayerControl"/>.
|
||||||
|
/// </summary>
|
||||||
|
public PlayerControl Player { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the instance of the <see cref="PlayerTask"/> that the player completed.
|
||||||
|
/// </summary>
|
||||||
|
public PlayerTask Task { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the instance of the <see cref="HideAndSeekManager"/> attached to the game.
|
||||||
|
/// </summary>
|
||||||
|
public HideAndSeekManager HnsManager { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CompleteHnsTaskEvent"/> class.
|
||||||
|
/// </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 CompleteHnsTaskEvent(HideAndSeekManager hnsManager, PlayerControl player, PlayerTask task)
|
||||||
|
{
|
||||||
|
HnsManager = hnsManager;
|
||||||
|
Player = player;
|
||||||
|
Task = task;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ public class PlayerDeathEvent : MiraEvent
|
|||||||
public DeathReason DeathReason { get; }
|
public DeathReason DeathReason { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the dead body associated with the player, if any.
|
/// Gets the <see cref="global::DeadBody"/> associated with the player, if any.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DeadBody? DeadBody { get; }
|
public DeadBody? DeadBody { get; }
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ public class PlayerDeathEvent : MiraEvent
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="player">The player who died.</param>
|
/// <param name="player">The player who died.</param>
|
||||||
/// <param name="reason">The reason the player died.</param>
|
/// <param name="reason">The reason the player died.</param>
|
||||||
/// <param name="deadBody">The player's body, if it exists.</param>
|
/// <param name="deadBody">The player's <see cref="global::DeadBody"/>, if it exists.</param>
|
||||||
public PlayerDeathEvent(PlayerControl player, DeathReason reason, DeadBody? deadBody)
|
public PlayerDeathEvent(PlayerControl player, DeathReason reason, DeadBody? deadBody)
|
||||||
{
|
{
|
||||||
Player = player;
|
Player = player;
|
||||||
|
|||||||
@@ -6,20 +6,20 @@
|
|||||||
public class EnterVentEvent : MiraCancelableEvent
|
public class EnterVentEvent : MiraCancelableEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the player that is entering the vent.
|
/// Gets the <see cref="PlayerControl"/> that is entering the <see cref="Vent"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PlayerControl Player { get; }
|
public PlayerControl Player { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the vent that the player is entering.
|
/// Gets the <see cref="global::Vent"/> that the <see cref="Player"/> is entering.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Vent? Vent { get; }
|
public Vent? Vent { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="EnterVentEvent"/> class.
|
/// Initializes a new instance of the <see cref="EnterVentEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="player">The player that is entering the vent.</param>
|
/// <param name="player">The <see cref="PlayerControl"/> that is entering the <paramref name="vent"/>.</param>
|
||||||
/// <param name="vent">The vent being entered.</param>
|
/// <param name="vent">The <see cref="global::Vent"/> being entered.</param>
|
||||||
public EnterVentEvent(PlayerControl player, Vent? vent)
|
public EnterVentEvent(PlayerControl player, Vent? vent)
|
||||||
{
|
{
|
||||||
Player = player;
|
Player = player;
|
||||||
|
|||||||
@@ -6,20 +6,20 @@
|
|||||||
public class ExitVentEvent : MiraCancelableEvent
|
public class ExitVentEvent : MiraCancelableEvent
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the player that is exiting the vent.
|
/// Gets the <see cref="PlayerControl"/> that is exiting the <see cref="Vent"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PlayerControl Player { get; }
|
public PlayerControl Player { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the vent that the player is exiting.
|
/// Gets the <see cref="global::Vent"/> that the <see cref="Player"/> is exiting.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Vent? Vent { get; }
|
public Vent? Vent { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ExitVentEvent"/> class.
|
/// Initializes a new instance of the <see cref="ExitVentEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="player">The player who is exiting the vent.</param>
|
/// <param name="player">The <see cref="PlayerControl"/> who is exiting the <paramref name="vent"/>.</param>
|
||||||
/// <param name="vent">The vent being exited from.</param>
|
/// <param name="vent">The <see cref="global::Vent"/> being exited from.</param>
|
||||||
public ExitVentEvent(PlayerControl player, Vent? vent)
|
public ExitVentEvent(PlayerControl player, Vent? vent)
|
||||||
{
|
{
|
||||||
Player = player;
|
Player = player;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ public class PlayerCanUseEvent : PlayerUseEvent
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="PlayerCanUseEvent"/> class.
|
/// Initializes a new instance of the <see cref="PlayerCanUseEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="usable">The IUsable.</param>
|
/// <param name="usable">The <see cref="IUsable"/>.</param>
|
||||||
public PlayerCanUseEvent(IUsable usable) : base(usable)
|
public PlayerCanUseEvent(IUsable usable) : base(usable)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,19 +11,19 @@ public class PlayerUseEvent : MiraCancelableEvent
|
|||||||
public IUsable Usable { get; }
|
public IUsable Usable { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the IUsable is a <see cref="Console"/>, <see cref="MapConsole"/>, or <see cref="SystemConsole"/>.
|
/// Gets a value indicating whether the <see cref="Usable"/> is a <see cref="Console"/>, <see cref="MapConsole"/>, or <see cref="SystemConsole"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsPrimaryConsole { get; }
|
public bool IsPrimaryConsole { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the IUsable is a <see cref="Vent"/>.
|
/// Gets a value indicating whether the <see cref="Usable"/> is a <see cref="Vent"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsVent { get; }
|
public bool IsVent { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="PlayerUseEvent"/> class.
|
/// Initializes a new instance of the <see cref="PlayerUseEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="usable">The IUsable.</param>
|
/// <param name="usable">The <see cref="IUsable"/>.</param>
|
||||||
public PlayerUseEvent(IUsable usable)
|
public PlayerUseEvent(IUsable usable)
|
||||||
{
|
{
|
||||||
Usable = usable;
|
Usable = usable;
|
||||||
|
|||||||
@@ -10,44 +10,44 @@ namespace MiraAPI.GameEnd;
|
|||||||
public abstract class CustomGameOver
|
public abstract class CustomGameOver
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current CustomGameOver.
|
/// Gets the current <see cref="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 CustomGameOver is met.
|
/// Verifies if the condition for this <see cref="CustomGameOver"/> is met.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="playerControl">The PlayerControl that requested the Game Over.</param>
|
/// <param name="playerControl">The <see cref="PlayerControl"/> that requested the Game Over.</param>
|
||||||
/// <param name="winners">The collection of winners.</param>
|
/// <param name="winners">The collection of winners.</param>
|
||||||
/// <returns>True if the condition is met, otherwise false.</returns>
|
/// <returns><see langword="true"/> if the condition is met, otherwise <see langword="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 EndGameManager.SetEverythingUp.
|
/// Runs before the base game calls <see cref="EndGameManager.SetEverythingUp"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="endGameManager">The EndGameManager instance.</param>
|
/// <param name="endGameManager">The <see cref="EndGameManager"/> instance.</param>
|
||||||
/// <returns>Return True to use the run the original method, return False to skip it.</returns>
|
/// <returns>Return <see langword="true"/> to use the run the original method, return <see langword="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 EndGameManager.SetEverythingUp.
|
/// Runs after the base game calls <see cref="EndGameManager.SetEverythingUp"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="endGameManager">The EndGameManager instance.</param>
|
/// <param name="endGameManager">The <see cref="EndGameManager"/> instance.</param>
|
||||||
public virtual void AfterEndGameSetup(EndGameManager endGameManager)
|
public virtual void AfterEndGameSetup(EndGameManager endGameManager)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the GameOverReason associated with this CustomGameOver.
|
/// Get the <see cref="global::GameOverReason"/> associated with this <see cref ="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 GameOverReason associated with the custom game over.</returns>
|
/// <returns>The <see cref="global::GameOverReason"/> associated with the custom game over.</returns>
|
||||||
public static GameOverReason GameOverReason<T>() where T : CustomGameOver
|
public static GameOverReason GameOverReason<T>() where T : CustomGameOver
|
||||||
{
|
{
|
||||||
return (GameOverReason)GameOverManager.GetGameOverId<T>();
|
return (GameOverReason)GameOverManager.GetGameOverId<T>();
|
||||||
@@ -67,10 +67,10 @@ public abstract class CustomGameOver
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implicitly convert a CustomGameOver to a GameOverReason.
|
/// Implicitly convert a <see cref="CustomGameOver"/> to a <see cref="global::GameOverReason"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="gameOver">The CustomGameOver instance.</param>
|
/// <param name="gameOver">The <see cref="CustomGameOver"/> instance.</param>
|
||||||
/// <returns>The GameOverReason associated with the CustomGameOver.</returns>
|
/// <returns>The <see cref="global::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());
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
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 custom game overs.
|
/// Manage <see cref="CustomGameOver"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class GameOverManager
|
public static class GameOverManager
|
||||||
{
|
{
|
||||||
@@ -16,11 +15,11 @@ public static class GameOverManager
|
|||||||
private static int _nextId = Enum.GetNames<GameOverReason>().Length;
|
private static int _nextId = Enum.GetNames<GameOverReason>().Length;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register a custom game over.
|
/// Register a <see cref="CustomGameOver"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="gameOverType">Type of the custom game over.</param>
|
/// <param name="gameOverType">Type of the <see cref="CustomGameOver"/>.</param>
|
||||||
/// <exception cref="ArgumentException">Thrown when the type is not a subclass of CustomGameOver, is abstract, or does not have a parameterless constructor.</exception>
|
/// <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>
|
||||||
/// <returns>>True if the game over was registered successfully, false otherwise.</returns>
|
/// <returns><see langword="true"/> if the game over was registered successfully, <see langword="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))
|
||||||
@@ -30,13 +29,13 @@ public static class GameOverManager
|
|||||||
|
|
||||||
if (gameOverType.IsAbstract)
|
if (gameOverType.IsAbstract)
|
||||||
{
|
{
|
||||||
Logger<MiraApiPlugin>.Error("The type must not be abstract.");
|
Error("The type must not be abstract.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gameOverType.GetConstructor(Type.EmptyTypes) == null)
|
if (gameOverType.GetConstructor(Type.EmptyTypes) == null)
|
||||||
{
|
{
|
||||||
Logger<MiraApiPlugin>.Error("The type must have a parameterless constructor.");
|
Error("The type must have a parameterless constructor.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,11 +46,11 @@ public static class GameOverManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create an instance of a custom game over.
|
/// Create an instance of a <see cref="CustomGameOver"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">ID of the custom game over.</param>
|
/// <param name="id">ID of the <see cref="CustomGameOver"/>.</param>
|
||||||
/// <param name="customGameOver">The created instance of the custom game over.</param>
|
/// <param name="customGameOver">The created instance of the <see cref="CustomGameOver"/>.</param>
|
||||||
/// <returns>An instance of the custom game over.</returns>
|
/// <returns>An instance of the <see cref="CustomGameOver"/>.</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))
|
||||||
@@ -65,20 +64,20 @@ public static class GameOverManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the ID of a custom game over.
|
/// Get the ID of a <see cref="CustomGameOver"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">Type of the custom game over.</typeparam>
|
/// <typeparam name="T">Type of the <see cref="CustomGameOver"/>.</typeparam>
|
||||||
/// <returns>The ID of the custom game over.</returns>
|
/// <returns>The ID of the <see cref="CustomGameOver"/>.</returns>
|
||||||
public static int GetGameOverId<T>() where T : CustomGameOver
|
public static int GetGameOverId<T>() where T : CustomGameOver
|
||||||
{
|
{
|
||||||
return GetGameOverId(typeof(T));
|
return GetGameOverId(typeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the ID of a custom game over.
|
/// Get the ID of a <see cref="CustomGameOver"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="gameOverType">Type of the custom game over.</param>
|
/// <param name="gameOverType">Type of the <see cref="CustomGameOver"/>.</param>
|
||||||
/// <returns>The ID of the custom game over.</returns>
|
/// <returns>The ID of the <see cref="CustomGameOver"/>.</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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,296 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using AmongUs.GameOptions;
|
||||||
|
using MiraAPI.GameOptions;
|
||||||
|
using MiraAPI.PluginLoading;
|
||||||
|
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 description.
|
||||||
|
/// </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 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=#{this.Color.ToHtmlStringRGBA()}>{this.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)
|
||||||
|
{
|
||||||
|
if (AprilFoolsMode.ShouldHorseAround())
|
||||||
|
{
|
||||||
|
return PlayerBodyTypes.Horse;
|
||||||
|
}
|
||||||
|
if (AprilFoolsMode.ShouldLongAround())
|
||||||
|
{
|
||||||
|
return PlayerBodyTypes.Long;
|
||||||
|
}
|
||||||
|
return 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() => null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The IEnumerator that plays the intro cutscene for this gamemode.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="__instance">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 __instance)
|
||||||
|
{
|
||||||
|
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) => 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) => 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) => 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) => 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) => 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) => true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Does the task bar appear in the gamemode.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the task bar is enabled in this mode.</returns>
|
||||||
|
public virtual bool ShowTaskBar => true;
|
||||||
|
|
||||||
|
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;
|
||||||
|
Vector3 vector = instance.background.sprite.bounds.extents;
|
||||||
|
vector.y = -vector.y;
|
||||||
|
vector = vector.Mul(instance.background.transform.localScale);
|
||||||
|
instance.background.transform.localPosition = vector;
|
||||||
|
Vector3 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);
|
||||||
|
if (instance.open)
|
||||||
|
{
|
||||||
|
instance.timer = Mathf.Min(1f, instance.timer + Time.deltaTime / instance.animationTimeSeconds);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
instance.timer = 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() => Name;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using MiraAPI.PluginLoading;
|
||||||
|
using MiraAPI.Utilities.Assets;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace MiraAPI.GameModes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The classic game mode.
|
||||||
|
/// </summary>
|
||||||
|
[MiraIgnore]
|
||||||
|
public class ClassicMode : AbstractGameMode
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string Name => "Classic";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string Description => "The classic Among Us experience!\nFind the Impostors or deceive the Crew.";
|
||||||
|
|
||||||
|
public override LoadableAsset<Sprite>? Icon => MiraAssets.ClassicGamemodeIcon;
|
||||||
|
}
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace MiraAPI.GameModes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Base class for custom gamemodes.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class CustomGameMode
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the game mode name.
|
|
||||||
/// </summary>
|
|
||||||
public abstract string Name { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the game mode description.
|
|
||||||
/// </summary>
|
|
||||||
public abstract string Description { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the game mode ID.
|
|
||||||
/// </summary>
|
|
||||||
public abstract int Id { get; }
|
|
||||||
|
|
||||||
/// <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>
|
|
||||||
public virtual void OnDeath(PlayerControl player)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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 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>
|
|
||||||
/// Should Roles Settings be available when this gamemode is selected.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>True if Role Settings are enabled in this game mode.</returns>
|
|
||||||
public virtual bool AreRoleSettingsEnabled() => true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Should Game Settings be available when this gamemode is selected.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>True if Game Settings are enabled in this mode.</returns>
|
|
||||||
public virtual bool AreGameSettingsEnabled() => true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Custom winner selection.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>List of winners or null.</returns>
|
|
||||||
public virtual List<NetworkedPlayerInfo>? CalculateWinners() => null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Show gamemode in Intro Cutscene.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>True if the game mode should be shown in the intro cutscene.</returns>
|
|
||||||
public virtual bool ShowGameModeIntroCutscene() => false;
|
|
||||||
|
|
||||||
/// <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) => 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) => 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) => 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) => 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) => true;
|
|
||||||
|
|
||||||
/// <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) => true;
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using MiraAPI.PluginLoading;
|
||||||
using Reactor.Utilities;
|
using Reactor.Utilities;
|
||||||
|
|
||||||
namespace MiraAPI.GameModes;
|
namespace MiraAPI.GameModes;
|
||||||
@@ -10,62 +11,113 @@ namespace MiraAPI.GameModes;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class CustomGameModeManager
|
public static class CustomGameModeManager
|
||||||
{
|
{
|
||||||
/// <summary>
|
internal static readonly Dictionary<uint, AbstractGameMode> IdToModeMap = [];
|
||||||
/// List of registered gamemodes.
|
|
||||||
/// </summary>
|
|
||||||
internal static readonly Dictionary<int, CustomGameMode> GameModes = [];
|
|
||||||
|
|
||||||
public static bool IsDefault()
|
private static uint GetNextId() => ++LastId;
|
||||||
{
|
|
||||||
return ActiveMode?.Id == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
private static uint LastId { get; set; }
|
||||||
/// Gets the current gamemode.
|
|
||||||
/// </summary>
|
|
||||||
public static CustomGameMode? ActiveMode { get; internal set; } = new DefaultMode();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set current gamemode.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">gamemode ID.</param>
|
|
||||||
public static void SetGameMode(int id)
|
|
||||||
{
|
|
||||||
if (GameModes.TryGetValue(id, out var gameMode))
|
|
||||||
{
|
|
||||||
ActiveMode = gameMode;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger<MiraApiPlugin>.Error($"No gamemode with id {id} found!");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register gamemode from type.
|
/// Register gamemode from type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="gameModeType">Type of gamemode class, should inherit from <see cref="CustomGameMode"/>.</param>
|
/// <param name="gameModeType">Type of gamemode class, should inherit from <see cref="AbstractGameMode"/>.</param>
|
||||||
internal static void RegisterGameMode(Type gameModeType)
|
/// <param name="pluginInfo">The custom plugin info of the mod.</param>
|
||||||
|
/// <returns>Whether the gamemode was successfully registered.</returns>
|
||||||
|
internal static bool RegisterGameMode(Type gameModeType, MiraPluginInfo pluginInfo)
|
||||||
{
|
{
|
||||||
if (!typeof(CustomGameMode).IsAssignableFrom(gameModeType))
|
if (!typeof(AbstractGameMode).IsAssignableFrom(gameModeType))
|
||||||
{
|
{
|
||||||
Logger<MiraApiPlugin>.Warning($"{gameModeType.Name} does not inherit CustomGameMode!");
|
Warning($"{gameModeType.Name} does not inherit CustomGameMode!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var instance = Activator.CreateInstance(gameModeType);
|
||||||
|
|
||||||
|
if (instance is not AbstractGameMode mode)
|
||||||
|
{
|
||||||
|
Error($"Failed to create instance of {gameModeType.Name}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mode.HideMode)
|
||||||
|
{
|
||||||
|
IdToModeMap.Add(GetNextId(), mode);
|
||||||
|
pluginInfo.GameModes.Add(LastId, mode);
|
||||||
|
mode.ID = LastId;
|
||||||
|
GameModeOption.AddOption(mode);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks to see if the current game mode is an instance of the classic mode.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the classic mode is the current one.</returns>
|
||||||
|
public static bool IsClassic() => ActiveMode != null && ActiveMode.GetType().IsAssignableTo(typeof(ClassicMode));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks to see if the current game mode is an instance of the HNS mode.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the Hide & Seek mode is the current one.</returns>
|
||||||
|
public static bool IsHideNSeek() => ActiveMode != null && ActiveMode.GetType().IsAssignableTo(typeof(HideAndSeekMode));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a provided GameMode is the current active one.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The AbstractGameMode subclass being checked.</typeparam>
|
||||||
|
/// <returns>Whether the provided mode is the current active one.</returns>
|
||||||
|
public static bool IsActiveGameMode<T>() where T : AbstractGameMode => ActiveMode is T;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current gamemode.
|
||||||
|
/// </summary>
|
||||||
|
public static AbstractGameMode? ActiveMode { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a gamemode from an ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the gamemode to fetch.</param>
|
||||||
|
/// <returns>The gamemode matching that ID.</returns>
|
||||||
|
public static AbstractGameMode GetMode(uint id) => IdToModeMap[id];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the parent mod of a custom gamemode.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="gameMode">The <see cref="AbstractGameMode"/> object.</param>
|
||||||
|
/// <returns>A <see cref="MiraPluginInfo"/> object representing the parent mod of the gamemode.</returns>
|
||||||
|
public static MiraPluginInfo? FindParentMod(AbstractGameMode gameMode)
|
||||||
|
{
|
||||||
|
return MiraPluginManager.Instance.RegisteredPlugins.FirstOrDefault(plugin => plugin.GameModes.ContainsValue(gameMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void RegisterDefaultMode()
|
||||||
|
{
|
||||||
|
var defaultMode = new ClassicMode();
|
||||||
|
IdToModeMap.Add(0, defaultMode);
|
||||||
|
// no need to add to game mode option as it already contains it
|
||||||
|
// because we cannot have the option be created with no values
|
||||||
|
defaultMode.ID = 0;
|
||||||
|
var hnsMode = new HideAndSeekMode();
|
||||||
|
if (!hnsMode.HideMode)
|
||||||
|
{
|
||||||
|
IdToModeMap.Add(1, hnsMode);
|
||||||
|
hnsMode.ID = 1;
|
||||||
|
GameModeOption.AddOption(hnsMode);
|
||||||
|
LastId++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void GetAndSetGameMode()
|
||||||
|
{
|
||||||
|
var id = (uint)GameModeOption.Value;
|
||||||
|
|
||||||
|
if (IdToModeMap.TryGetValue(id, out var mode))
|
||||||
|
{
|
||||||
|
ActiveMode = mode;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var modeObj = Activator.CreateInstance(gameModeType);
|
ActiveMode = IdToModeMap[0];
|
||||||
|
Logger<MiraApiPlugin>.Warning($"Unable to find game mode of id {id}!");
|
||||||
if (modeObj is not CustomGameMode gameMode)
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"Failed to create instance of {gameModeType.Name}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GameModes.Any(x => x.Key == gameMode.Id))
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"ID for gamemode {gameMode.Name} already exists!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GameModes.Add(gameMode.Id, gameMode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
namespace MiraAPI.GameModes;
|
|
||||||
|
|
||||||
public class DefaultMode : CustomGameMode
|
|
||||||
{
|
|
||||||
public override string Name => "Default";
|
|
||||||
public override string Description => "Default Among Us GameMode";
|
|
||||||
public override int Id => 0;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using HarmonyLib;
|
||||||
|
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||||
|
using MiraAPI.GameOptions;
|
||||||
|
using MiraAPI.Networking;
|
||||||
|
using MiraAPI.Patches.GameModes;
|
||||||
|
using MiraAPI.Patches.Options;
|
||||||
|
using MiraAPI.Utilities;
|
||||||
|
using MiraAPI.Utilities.Assets;
|
||||||
|
using Reactor.Localization.Utilities;
|
||||||
|
using Reactor.Networking.Attributes;
|
||||||
|
using Reactor.Utilities.Extensions;
|
||||||
|
using TMPro;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
using UnityEngine.ProBuilder;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
|
namespace MiraAPI.GameModes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The game mode option.
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPatch]
|
||||||
|
public static class GameModeOption
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current index of the Game Mode Option
|
||||||
|
/// For the value as an <see cref="AbstractGameMode"/>, see <see cref="CustomGameModeManager.ActiveMode"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static int Value
|
||||||
|
{
|
||||||
|
get =>
|
||||||
|
OptionBehaviour != null
|
||||||
|
? OptionBehaviour.GetInt()
|
||||||
|
: _lastValue;
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
_lastValue = value;
|
||||||
|
if (OptionBehaviour == null)
|
||||||
|
return;
|
||||||
|
OptionBehaviour.Value = value;
|
||||||
|
OptionBehaviour.UpdateValue();
|
||||||
|
_lastValue = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal static StringOption OptionBehaviour { get; set; } = null!;
|
||||||
|
|
||||||
|
internal static int _lastValue;
|
||||||
|
internal static readonly StringNames GamemodeName = CustomStringName.CreateAndRegister("Gamemode");
|
||||||
|
internal static readonly StringNames CustomName = CustomStringName.CreateAndRegister("Custom");
|
||||||
|
internal static readonly Dictionary<uint, StringNames> Values = new()
|
||||||
|
{
|
||||||
|
[0] = CustomStringName.CreateAndRegister("Classic"),
|
||||||
|
};
|
||||||
|
|
||||||
|
internal static void AddOption(AbstractGameMode mode)
|
||||||
|
{
|
||||||
|
if (!Values.ContainsKey(mode.ID))
|
||||||
|
Values.Add(mode.ID, CustomStringName.CreateAndRegister(mode.ColoredName));
|
||||||
|
}
|
||||||
|
/*[HarmonyPatch(typeof(GameOptionsMenu), nameof(GameOptionsMenu.CreateSettings))]
|
||||||
|
[HarmonyPostfix]
|
||||||
|
private static void CreateSettingsPatch(GameOptionsMenu __instance)
|
||||||
|
{
|
||||||
|
if (MenuState.Instance.CurrentModIdx != 0 || GameManager.Instance.IsHideAndSeek() || CustomGameModeManager.ActiveMode == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var num = 0.713f;
|
||||||
|
|
||||||
|
foreach (var category in __instance.settingsContainer.GetComponentsInChildren<CategoryHeaderMasked>())
|
||||||
|
{
|
||||||
|
if (category)
|
||||||
|
category.gameObject.transform.localPosition -= new Vector3(0, 1.3f, 0);
|
||||||
|
}
|
||||||
|
CategoryHeaderMasked categoryHeaderMasked = Object.Instantiate(__instance.categoryHeaderOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer);
|
||||||
|
categoryHeaderMasked.SetHeader(CustomName, 20);
|
||||||
|
categoryHeaderMasked.transform.localScale = Vector3.one * 0.63f;
|
||||||
|
categoryHeaderMasked.transform.localPosition = new Vector3(-0.903f, num, -2f);
|
||||||
|
OptionBehaviour = Object.Instantiate(
|
||||||
|
__instance.stringOptionOrigin,
|
||||||
|
Vector3.zero,
|
||||||
|
Quaternion.identity,
|
||||||
|
__instance.settingsContainer);
|
||||||
|
num -= 0.63f;
|
||||||
|
OptionBehaviour.transform.localPosition = new Vector3(0.952f, num, -2f);
|
||||||
|
OptionBehaviour.SetClickMask(__instance.ButtonClickMask);
|
||||||
|
StringGameSetting setting = ScriptableObject.CreateInstance<StringGameSetting>();
|
||||||
|
setting.Type = OptionTypes.MultipleChoice;
|
||||||
|
setting.Title = GamemodeName;
|
||||||
|
setting.Index = _lastValue;
|
||||||
|
setting.Values = new Il2CppStructArray<StringNames>([Values[0]]);
|
||||||
|
OptionBehaviour.SetUpFromData(setting, 20);
|
||||||
|
Set(_lastValue);
|
||||||
|
OptionBehaviour.TitleText.fontSize = 3;
|
||||||
|
foreach (var optionBehaviour in __instance.Children.ToArray().Skip(1))
|
||||||
|
{
|
||||||
|
optionBehaviour.gameObject.transform.localPosition -= new Vector3(0, 1.3f, 0);
|
||||||
|
}
|
||||||
|
__instance.Children.Add(OptionBehaviour);
|
||||||
|
for (var i = 1; i < Values.Count; i++)
|
||||||
|
OptionBehaviour.Values = (Il2CppStructArray<StringNames>)OptionBehaviour.Values.Add(Values.ElementAt(i).Value);
|
||||||
|
__instance.scrollBar.SetYBoundsMax(__instance.scrollBar.GetYBounds().max + 1);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
internal static void Set(int val)
|
||||||
|
{
|
||||||
|
Value = val;
|
||||||
|
var previousMode = CustomGameModeManager.ActiveMode;
|
||||||
|
CustomGameModeManager.GetAndSetGameMode();
|
||||||
|
HudPatches.SetGameModeText(CustomGameModeManager.GetMode(Values.ElementAt(_lastValue).Key).ColoredName);
|
||||||
|
var gm = CustomGameModeManager.ActiveMode!;
|
||||||
|
if (gm != previousMode)
|
||||||
|
{
|
||||||
|
ModdedOptionsManager.AddSettingsChangeMessage(
|
||||||
|
HudManager.Instance.Notifier,
|
||||||
|
GamemodeName,
|
||||||
|
gm.ColoredName,
|
||||||
|
new Color(0.7333f, 0.7333f, 0.7333f, 1),
|
||||||
|
gm.TmpIcon,
|
||||||
|
true);
|
||||||
|
if (MenuState.Instance)
|
||||||
|
{
|
||||||
|
// should force reset roles for gamemodes properly
|
||||||
|
foreach (var roleMenu in MenuState.Instance.QueuedRoleMenuRefresh)
|
||||||
|
{
|
||||||
|
MenuState.Instance.QueuedRoleMenuRefresh[roleMenu.Key] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// could make Values a dict of AbstractGameMode too
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(GameOptionsMenu), nameof(GameOptionsMenu.ValueChanged))]
|
||||||
|
[HarmonyPrefix]
|
||||||
|
private static bool ValueChanged(GameOptionsMenu __instance, OptionBehaviour option)
|
||||||
|
{
|
||||||
|
if (OptionBehaviour.Equals(option))
|
||||||
|
{
|
||||||
|
Info($"Game mode changed to {option.GetInt()}");
|
||||||
|
RpcSyncGamemode(PlayerControl.LocalPlayer, option.GetInt());
|
||||||
|
if (GameSettingMenu.Instance && CustomGameModeManager.ActiveMode != null)
|
||||||
|
{
|
||||||
|
GameOptionsMenuPatch.ToggleGamemodeOptions(CustomGameModeManager.ActiveMode, __instance);
|
||||||
|
GameSettingMenu.Instance.RoleSettingsButton.gameObject.SetActive(CustomGameModeManager.ActiveMode.ShowNormalRoleSettings);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodRpc((uint) MiraRpc.SyncGamemodeOption)]
|
||||||
|
internal static void RpcSyncGamemode(PlayerControl host, int data)
|
||||||
|
{
|
||||||
|
Set(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,534 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using AmongUs.Data;
|
||||||
|
using AmongUs.GameOptions;
|
||||||
|
using HarmonyLib;
|
||||||
|
using InnerNet;
|
||||||
|
using MiraAPI.GameOptions;
|
||||||
|
using MiraAPI.HnsReimplemented;
|
||||||
|
using MiraAPI.HnsReimplemented.Options;
|
||||||
|
using MiraAPI.PluginLoading;
|
||||||
|
using MiraAPI.Roles;
|
||||||
|
using MiraAPI.Utilities;
|
||||||
|
using MiraAPI.Utilities.Assets;
|
||||||
|
using PowerTools;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace MiraAPI.GameModes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The vanilla Hide and Seek game mode, ported to Mira.
|
||||||
|
/// </summary>
|
||||||
|
[MiraIgnore]
|
||||||
|
public class HideAndSeekMode : AbstractGameMode
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string Name => "Hide n Seek";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string Description => "You can run, but you can't hide!\nOutlive the timer or eliminate the crew.";
|
||||||
|
|
||||||
|
// TODO: Once the Hide n Seek port is ready for release, we will remove this.
|
||||||
|
public override bool HideMode => !MiraApiPlugin.IsDevBuild;
|
||||||
|
|
||||||
|
public override Color Color { get; } = new Color32(255, 88, 90, 255);
|
||||||
|
public override LoadableAsset<Sprite>? Icon => MiraAssets.HnSGamemodeIcon;
|
||||||
|
public override bool CanReport(DeadBody body) => false;
|
||||||
|
public override bool ShouldShowSabotageMap(MapBehaviour map) => false;
|
||||||
|
public override bool ShowGameModeIntroCutscene => true;
|
||||||
|
public override bool GameModeBodyTypeOverride => true;
|
||||||
|
public override bool ShowNormalGameSettings => false;
|
||||||
|
public override bool ShowNormalRoleSettings => false;
|
||||||
|
public override float DefaultImpostorKillCooldown => 1f;
|
||||||
|
|
||||||
|
public override bool ShowTaskBar => false;
|
||||||
|
public static int ImpostorPlayerID()
|
||||||
|
{
|
||||||
|
return OptionGroupSingleton<HnsImpostorOptions>.Instance.SelectedSeeker.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasImpostorPlayerID()
|
||||||
|
{
|
||||||
|
return ImpostorPlayerID() > -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ValidateImpostorPlayerID(List<NetworkedPlayerInfo> players)
|
||||||
|
{
|
||||||
|
return HasImpostorPlayerID() && players.Find((NetworkedPlayerInfo p) => (int)p.PlayerId == ImpostorPlayerID()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AssignRoles(out bool runOriginal, LogicRoleSelectionNormal instance)
|
||||||
|
{
|
||||||
|
runOriginal = false;
|
||||||
|
Il2CppSystem.Collections.Generic.List<ClientData> list = new();
|
||||||
|
AmongUsClient.Instance.GetAllClients(list);
|
||||||
|
List<NetworkedPlayerInfo> list2 = list.ToArray()
|
||||||
|
.Where(c => c.Character != null && c.Character.Data != null && !c.Character.Data.Disconnected &&
|
||||||
|
!c.Character.Data.IsDead).OrderBy(c => c.Id).Select(c => c.Character.Data)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (NetworkedPlayerInfo networkedPlayerInfo in GameData.Instance.AllPlayers)
|
||||||
|
{
|
||||||
|
if (networkedPlayerInfo.Object != null && networkedPlayerInfo.Object.isDummy)
|
||||||
|
{
|
||||||
|
list2.Add(networkedPlayerInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IGameOptions currentGameOptions = GameOptionsManager.Instance.CurrentGameOptions;
|
||||||
|
int adjustedNumImpostors = GameOptionsManager.Instance.CurrentGameOptions.GetAdjustedNumImpostors(list2.Count);
|
||||||
|
AssignRolesForTeam(list2, currentGameOptions, RoleTeamTypes.Impostor, Math.Max(adjustedNumImpostors, 1), RoleTypes.Impostor);
|
||||||
|
AssignRolesForTeam(list2, currentGameOptions, RoleTeamTypes.Crewmate, int.MaxValue, RoleTypes.Engineer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AssignRolesForTeam(
|
||||||
|
List<NetworkedPlayerInfo> players,
|
||||||
|
IGameOptions opts,
|
||||||
|
RoleTeamTypes team,
|
||||||
|
int teamMax,
|
||||||
|
RoleTypes defaultRole)
|
||||||
|
{
|
||||||
|
Error($"Hide And Seek Mode - AssignRolesForTeam: Team: {team}, Max: {teamMax}, Players: {players.Count}, DefaultRole: {defaultRole}");
|
||||||
|
int num = 0;
|
||||||
|
IRoleOptionsCollection roleOptions = opts.RoleOptions;
|
||||||
|
var source = RoleManager.Instance.AllRoles.ToArray()
|
||||||
|
.Where(role => role.TeamType == team && !RoleManager.IsGhostRole(role.Role) &&
|
||||||
|
CustomRoleUtils.CanSpawnOnCurrentMode(role));
|
||||||
|
var assignmentData = source.Where(x => !x.IsDead).Select(role =>
|
||||||
|
new RoleManager.RoleAssignmentData(
|
||||||
|
role,
|
||||||
|
roleOptions.GetNumPerGame(role.Role),
|
||||||
|
roleOptions.GetChancePerGame(role.Role))).ToList();
|
||||||
|
var source2 = CustomRoleUtils.GetPossibleRoles(assignmentData, x => x.Chance == 100);
|
||||||
|
var guaranteedRoles = source.Where(x => source2.Contains(((ushort)x.Role, 100)));
|
||||||
|
List<RoleTypes> list = new List<RoleTypes>();
|
||||||
|
if (team == RoleTeamTypes.Crewmate)
|
||||||
|
{
|
||||||
|
Error($"MiraAPI.Patches.Roles.LogicRoleSelectionHnsPatch - AssignRolesForTeam: Before Guaranteed Assignment");
|
||||||
|
foreach (RoleManager.RoleAssignmentData roleAssignmentData in guaranteedRoles.Select((x) =>
|
||||||
|
new RoleManager.RoleAssignmentData(x, roleOptions.GetNumPerGame(x.Role), 100)))
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
RoleManager.RoleAssignmentData roleAssignmentData2 = roleAssignmentData;
|
||||||
|
int count = roleAssignmentData2.Count;
|
||||||
|
roleAssignmentData2.Count = count - 1;
|
||||||
|
if (count <= 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
list.Add(roleAssignmentData.Role.Role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Error($"MiraAPI.Patches.Roles.LogicRoleSelectionHnsPatch - AssignRolesForTeam: After Guaranteed Assignment");
|
||||||
|
AssignRolesFromList(players, teamMax, list, ref num);
|
||||||
|
|
||||||
|
var list2 = source.Where(x => !x.IsDead).Select(role =>
|
||||||
|
new RoleManager.RoleAssignmentData(
|
||||||
|
role,
|
||||||
|
roleOptions.GetNumPerGame(role.Role),
|
||||||
|
roleOptions.GetChancePerGame(role.Role))).ToList();
|
||||||
|
|
||||||
|
list.Clear();
|
||||||
|
foreach (RoleManager.RoleAssignmentData roleAssignmentData3 in list2)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < roleAssignmentData3.Count; i++)
|
||||||
|
{
|
||||||
|
if (HashRandom.Next(101) < roleAssignmentData3.Chance)
|
||||||
|
{
|
||||||
|
list.Add(roleAssignmentData3.Role.Role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Error($"MiraAPI.Patches.Roles.LogicRoleSelectionHnsPatch - AssignRolesForTeam: After Potential Assignment");
|
||||||
|
|
||||||
|
AssignRolesFromList(players, teamMax, list, ref num);
|
||||||
|
var basicRole = RoleTypes.Engineer;
|
||||||
|
while (list.Count < players.Count && list.Count + num < teamMax)
|
||||||
|
{
|
||||||
|
list.Add(basicRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
AssignRolesFromList(players, teamMax, list, ref num);
|
||||||
|
Error($"MiraAPI.Patches.Roles.LogicRoleSelectionHnsPatch - AssignRolesForTeam: After Fallback Assignment");
|
||||||
|
}
|
||||||
|
else if (team == RoleTeamTypes.Impostor)
|
||||||
|
{
|
||||||
|
Error($"MiraAPI.Patches.Roles.LogicRoleSelectionHnsPatch - AssignRolesForTeam: Before Guaranteed Assignment");
|
||||||
|
var newImpostors = new List<NetworkedPlayerInfo>();
|
||||||
|
// Specified Seeker
|
||||||
|
if (HasImpostorPlayerID() &&
|
||||||
|
ValidateImpostorPlayerID(players) &&
|
||||||
|
!AmongUsClient.Instance.IsGamePublic)
|
||||||
|
{
|
||||||
|
NetworkedPlayerInfo networkedPlayerInfo = players.ToArray()
|
||||||
|
.First(p => p.PlayerId == ImpostorPlayerID());
|
||||||
|
players.Remove(networkedPlayerInfo);
|
||||||
|
newImpostors.Add(networkedPlayerInfo);
|
||||||
|
Error($"MiraAPI.Patches.Roles.LogicRoleSelectionHnsPatch - AssignRolesForTeam: Seeker is {networkedPlayerInfo.PlayerName}, ID: {networkedPlayerInfo.PlayerId}");
|
||||||
|
}
|
||||||
|
// Random Seeker
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int num2 = 0;
|
||||||
|
while (num2 < teamMax && players.Count > 0)
|
||||||
|
{
|
||||||
|
PseudoRandomList<NetworkedPlayerInfo> pseudoRandomList = new PseudoRandomList<NetworkedPlayerInfo>(AmongUsClient.Instance.GameId);
|
||||||
|
players.Do(x => pseudoRandomList.Add(x));
|
||||||
|
for (int i = 0; i < GameData.RoundsPlayedInSession; i++)
|
||||||
|
{
|
||||||
|
pseudoRandomList.PickRandom();
|
||||||
|
}
|
||||||
|
NetworkedPlayerInfo networkedPlayerInfo = pseudoRandomList.PickRandom();
|
||||||
|
players.Remove(networkedPlayerInfo);
|
||||||
|
newImpostors.Add(networkedPlayerInfo);
|
||||||
|
num2++;
|
||||||
|
Error($"MiraAPI.Patches.Roles.LogicRoleSelectionHnsPatch - AssignRolesForTeam: Seeker is {networkedPlayerInfo.PlayerName}, ID: {networkedPlayerInfo.PlayerId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Error($"MiraAPI.Patches.Roles.LogicRoleSelectionHnsPatch - AssignRolesForTeam: After Guaranteed Assignment");
|
||||||
|
foreach (RoleManager.RoleAssignmentData roleAssignmentData in guaranteedRoles.Select((x) =>
|
||||||
|
new RoleManager.RoleAssignmentData(x, roleOptions.GetNumPerGame(x.Role), 100)))
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
RoleManager.RoleAssignmentData roleAssignmentData2 = roleAssignmentData;
|
||||||
|
int count = roleAssignmentData2.Count;
|
||||||
|
roleAssignmentData2.Count = count - 1;
|
||||||
|
if (count <= 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
list.Add(roleAssignmentData.Role.Role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AssignRolesFromList(newImpostors, teamMax, list, ref num);
|
||||||
|
|
||||||
|
var list2 = source.Where(x => !x.IsDead).Select(role =>
|
||||||
|
new RoleManager.RoleAssignmentData(
|
||||||
|
role,
|
||||||
|
roleOptions.GetNumPerGame(role.Role),
|
||||||
|
roleOptions.GetChancePerGame(role.Role))).ToList();
|
||||||
|
|
||||||
|
list.Clear();
|
||||||
|
foreach (RoleManager.RoleAssignmentData roleAssignmentData3 in list2)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < roleAssignmentData3.Count; i++)
|
||||||
|
{
|
||||||
|
if (HashRandom.Next(101) < roleAssignmentData3.Chance)
|
||||||
|
{
|
||||||
|
list.Add(roleAssignmentData3.Role.Role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AssignRolesFromList(newImpostors, teamMax, list, ref num);
|
||||||
|
var basicRole = RoleTypes.Impostor;
|
||||||
|
while (list.Count < newImpostors.Count && list.Count + num < teamMax)
|
||||||
|
{
|
||||||
|
list.Add(basicRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
AssignRolesFromList(newImpostors, teamMax, list, ref num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AssignRolesFromList(List<NetworkedPlayerInfo> players, int teamMax, List<RoleTypes> roleList, ref int rolesAssigned)
|
||||||
|
{
|
||||||
|
while (roleList.Count > 0 && players.Count > 0 && rolesAssigned < teamMax)
|
||||||
|
{
|
||||||
|
int index = HashRandom.FastNext(roleList.Count);
|
||||||
|
RoleTypes roleType = roleList[index];
|
||||||
|
roleList.RemoveAt(index);
|
||||||
|
int index2 = HashRandom.FastNext(players.Count);
|
||||||
|
players[index2].Object.RpcSetRole(roleType, false);
|
||||||
|
players.RemoveAt(index2);
|
||||||
|
rolesAssigned++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerator IntroCutscene(IntroCutscene __instance)
|
||||||
|
{
|
||||||
|
SoundManager.Instance.PlaySound(__instance.IntroStinger, false, 1f, null);
|
||||||
|
Logger.GlobalInstance.Info("IntroCutscene :: CoBegin() :: Game Mode: Hide and Seek (MiraAPI)", null);
|
||||||
|
__instance.LogPlayerRoleData();
|
||||||
|
__instance.HideAndSeekPanels.SetActive(true);
|
||||||
|
if (PlayerControl.LocalPlayer.Data.Role.IsImpostor)
|
||||||
|
{
|
||||||
|
__instance.CrewmateRules.SetActive(false);
|
||||||
|
__instance.ImpostorRules.SetActive(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
__instance.CrewmateRules.SetActive(true);
|
||||||
|
__instance.ImpostorRules.SetActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
__instance.ImpostorName.gameObject.SetActive(true);
|
||||||
|
__instance.ImpostorTitle.gameObject.SetActive(true);
|
||||||
|
__instance.BackgroundBar.enabled = false;
|
||||||
|
__instance.TeamTitle.gameObject.SetActive(false);
|
||||||
|
var impostor = PlayerControl.AllPlayerControls.ToArray().FirstOrDefault(x => x.Data.Role.IsImpostor);
|
||||||
|
if (impostor == null)
|
||||||
|
{
|
||||||
|
Logger.GlobalInstance.Error("IntroCutscene :: CoBegin() :: impostor is NULL", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
GameManager.Instance.SetSpecialCosmetics(impostor);
|
||||||
|
if (impostor != null)
|
||||||
|
{
|
||||||
|
__instance.ImpostorName.text = impostor.Data.PlayerName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
__instance.ImpostorName.text = "???";
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return new WaitForSecondsRealtime(0.1f);
|
||||||
|
if (impostor != null)
|
||||||
|
{
|
||||||
|
__instance.ImpostorTitle.text = impostor.Data.Role.GetRoleName();
|
||||||
|
}
|
||||||
|
PoolablePlayer playerSlot = null;
|
||||||
|
if (impostor != null)
|
||||||
|
{
|
||||||
|
playerSlot = __instance.CreatePlayer(1, 1, impostor.Data, false);
|
||||||
|
playerSlot.SetBodyType(PlayerBodyTypes.Normal);
|
||||||
|
playerSlot.SetFlipX(false);
|
||||||
|
playerSlot.transform.localPosition = __instance.impostorPos;
|
||||||
|
playerSlot.transform.localScale = Vector3.one * __instance.impostorScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return ShipStatus.Instance.CosmeticsCache.PopulateFromPlayers();
|
||||||
|
yield return new WaitForSecondsRealtime(6f);
|
||||||
|
if (playerSlot != null)
|
||||||
|
{
|
||||||
|
playerSlot.gameObject.SetActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
__instance.HideAndSeekPanels.SetActive(false);
|
||||||
|
__instance.CrewmateRules.SetActive(false);
|
||||||
|
__instance.ImpostorRules.SetActive(false);
|
||||||
|
HnsMusicHandler.Instance.StartMusicWithIntro();
|
||||||
|
var hideTimer = 10f;
|
||||||
|
|
||||||
|
if (PlayerControl.LocalPlayer.Data.Role.IsImpostor)
|
||||||
|
{
|
||||||
|
__instance.HideAndSeekTimerText.gameObject.SetActive(true);
|
||||||
|
PoolablePlayer poolablePlayer;
|
||||||
|
AnimationClip anim;
|
||||||
|
if (AprilFoolsMode.ShouldHorseAround())
|
||||||
|
{
|
||||||
|
poolablePlayer = __instance.HorseWrangleVisualSuit;
|
||||||
|
poolablePlayer.gameObject.SetActive(true);
|
||||||
|
poolablePlayer.SetBodyType(PlayerBodyTypes.Seeker);
|
||||||
|
anim = __instance.HnSSeekerSpawnHorseAnim;
|
||||||
|
__instance.HorseWrangleVisualPlayer.SetBodyType(PlayerBodyTypes.Normal);
|
||||||
|
__instance.HorseWrangleVisualPlayer.UpdateFromPlayerData(
|
||||||
|
PlayerControl.LocalPlayer.Data,
|
||||||
|
PlayerControl.LocalPlayer.CurrentOutfitType,
|
||||||
|
PlayerMaterial.MaskType.None,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
else if (AprilFoolsMode.ShouldLongAround())
|
||||||
|
{
|
||||||
|
poolablePlayer = __instance.HideAndSeekPlayerVisual;
|
||||||
|
poolablePlayer.gameObject.SetActive(true);
|
||||||
|
poolablePlayer.SetBodyType(PlayerBodyTypes.LongSeeker);
|
||||||
|
anim = __instance.HnSSeekerSpawnLongAnim;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
poolablePlayer = __instance.HideAndSeekPlayerVisual;
|
||||||
|
poolablePlayer.gameObject.SetActive(true);
|
||||||
|
poolablePlayer.SetBodyType(PlayerBodyTypes.Seeker);
|
||||||
|
anim = __instance.HnSSeekerSpawnAnim;
|
||||||
|
}
|
||||||
|
|
||||||
|
poolablePlayer.SetBodyCosmeticsVisible(false);
|
||||||
|
poolablePlayer.UpdateFromPlayerData(
|
||||||
|
PlayerControl.LocalPlayer.Data,
|
||||||
|
PlayerControl.LocalPlayer.CurrentOutfitType,
|
||||||
|
PlayerMaterial.MaskType.None,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
false);
|
||||||
|
SpriteAnim component = poolablePlayer.GetComponent<SpriteAnim>();
|
||||||
|
poolablePlayer.gameObject.SetActive(true);
|
||||||
|
poolablePlayer.ToggleName(false);
|
||||||
|
component.Play(anim, 1f);
|
||||||
|
while (hideTimer > 0f)
|
||||||
|
{
|
||||||
|
__instance.HideAndSeekTimerText.text = Mathf.RoundToInt(hideTimer).ToString();
|
||||||
|
hideTimer -= Time.deltaTime;
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HideAndSeekHudHelper.Instance.HideCountdown = hideTimer;
|
||||||
|
if (AprilFoolsMode.ShouldHorseAround())
|
||||||
|
{
|
||||||
|
if (impostor != null)
|
||||||
|
{
|
||||||
|
impostor.AnimateCustom(__instance.HnSSeekerSpawnHorseInGameAnim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (AprilFoolsMode.ShouldLongAround())
|
||||||
|
{
|
||||||
|
if (impostor != null)
|
||||||
|
{
|
||||||
|
impostor.AnimateCustom(__instance.HnSSeekerSpawnLongInGameAnim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (impostor != null)
|
||||||
|
{
|
||||||
|
impostor.AnimateCustom(__instance.HnSSeekerSpawnAnim);
|
||||||
|
impostor.cosmetics.SetBodyCosmeticsVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ShipStatus.Instance.StartSFX();
|
||||||
|
HnsMusicHandler.Instance.OnGameStart();
|
||||||
|
HnsDangerMeter.Instance.OnGameStart();
|
||||||
|
UnityEngine.Object.Destroy(__instance.gameObject);
|
||||||
|
}
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
deadPlayerCount = 0;
|
||||||
|
ShipStatus.Instance.BreakEmergencyButton();
|
||||||
|
PlayerControl.LocalPlayer.SetKillTimer(0.01f);
|
||||||
|
if (HudManager.InstanceExists)
|
||||||
|
{
|
||||||
|
HudManager.Instance.gameObject.AddComponent<HnsMusicHandler>();
|
||||||
|
HudManager.Instance.gameObject.AddComponent<HideAndSeekHudHelper>();
|
||||||
|
HudManager.Instance.gameObject.AddComponent<HnsDangerMeter>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override MapOptions GetMapOptions()
|
||||||
|
{
|
||||||
|
MapOptions mapOptions = new MapOptions
|
||||||
|
{
|
||||||
|
Mode = MapOptions.Modes.Normal,
|
||||||
|
};
|
||||||
|
if (PlayerControl.LocalPlayer.Data.Role.IsImpostor && HideAndSeekHudHelper.Instance.SeekerAdminMapEnabled(PlayerControl.LocalPlayer))
|
||||||
|
{
|
||||||
|
mapOptions.Mode = MapOptions.Modes.CountOverlay;
|
||||||
|
mapOptions.AllowMovementWhileMapOpen = true;
|
||||||
|
mapOptions.IncludeDeadBodies = false;
|
||||||
|
mapOptions.ShowLivePlayerPosition = false;
|
||||||
|
}
|
||||||
|
return mapOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CheckGameEnd(out bool runOriginal, LogicGameFlowNormal instance)
|
||||||
|
{
|
||||||
|
runOriginal = false;
|
||||||
|
if (Helpers.GetAlivePlayers().Count(x => x.Data.Role.IsImpostor) == 0)
|
||||||
|
{
|
||||||
|
instance.Manager.RpcEndGame(GameOverReason.ImpostorDisconnect, !DataManager.Player.Ads.HasPurchasedAdRemoval);
|
||||||
|
}
|
||||||
|
if (Helpers.GetAlivePlayers().Count(x => !x.Data.Role.IsImpostor) != 0)
|
||||||
|
{
|
||||||
|
if (HideAndSeekHudHelper.Instance.AllTimersExpired())
|
||||||
|
{
|
||||||
|
instance.Manager.RpcEndGame(GameOverReason.HideAndSeek_CrewmatesByTimer, !DataManager.Player.Ads.HasPurchasedAdRemoval);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
instance.Manager.RpcEndGame(GameOverReason.HideAndSeek_ImpostorsByKills, !DataManager.Player.Ads.HasPurchasedAdRemoval);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override PlayerBodyTypes GetBodyType(PlayerControl player)
|
||||||
|
{
|
||||||
|
if (player == null || player.Data == null || player.Data.Role == null)
|
||||||
|
{
|
||||||
|
if (AprilFoolsMode.ShouldHorseAround())
|
||||||
|
{
|
||||||
|
return PlayerBodyTypes.Horse;
|
||||||
|
}
|
||||||
|
if (AprilFoolsMode.ShouldLongAround())
|
||||||
|
{
|
||||||
|
return PlayerBodyTypes.Long;
|
||||||
|
}
|
||||||
|
return PlayerBodyTypes.Normal;
|
||||||
|
}
|
||||||
|
else if (AprilFoolsMode.ShouldHorseAround())
|
||||||
|
{
|
||||||
|
if (player.Data.Role.IsImpostor)
|
||||||
|
{
|
||||||
|
return PlayerBodyTypes.Normal;
|
||||||
|
}
|
||||||
|
return PlayerBodyTypes.Horse;
|
||||||
|
}
|
||||||
|
else if (AprilFoolsMode.ShouldLongAround())
|
||||||
|
{
|
||||||
|
if (player.Data.Role.IsImpostor)
|
||||||
|
{
|
||||||
|
return PlayerBodyTypes.LongSeeker;
|
||||||
|
}
|
||||||
|
return PlayerBodyTypes.Long;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (player.Data.Role.IsImpostor)
|
||||||
|
{
|
||||||
|
return PlayerBodyTypes.Seeker;
|
||||||
|
}
|
||||||
|
return PlayerBodyTypes.Normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override 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;
|
||||||
|
Vector3 vector = instance.background.sprite.bounds.extents;
|
||||||
|
vector.y = -vector.y;
|
||||||
|
vector = vector.Mul(instance.background.transform.localScale);
|
||||||
|
instance.background.transform.localPosition = vector;
|
||||||
|
Vector3 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 = 1.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);
|
||||||
|
if (instance.open)
|
||||||
|
{
|
||||||
|
instance.timer = Mathf.Min(1f, instance.timer + Time.deltaTime / instance.animationTimeSeconds);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
instance.timer = 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);
|
||||||
|
}
|
||||||
|
private int deadPlayerCount;
|
||||||
|
public override void OnPlayerDeath(PlayerControl player, bool assignGhostRole)
|
||||||
|
{
|
||||||
|
base.OnPlayerDeath(player, assignGhostRole);
|
||||||
|
HudManager.Instance.NotifyOfDeath();
|
||||||
|
var popup = GameManagerCreator.Instance.HideAndSeekManagerPrefab.DeathPopupPrefab;
|
||||||
|
deadPlayerCount++;
|
||||||
|
var item = UnityEngine.Object.Instantiate(popup, HudManager.Instance.transform.parent);
|
||||||
|
item.Show(player, deadPlayerCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using MiraAPI.Modifiers;
|
||||||
|
using MiraAPI.Roles;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.GameOptions;
|
namespace MiraAPI.GameOptions;
|
||||||
@@ -31,27 +34,42 @@ public abstract class AbstractOptionGroup
|
|||||||
/// Gets a value indicating whether the group should be shown in the modifiers menu.
|
/// Gets a value indicating whether the group should be shown in the modifiers menu.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
// TODO: make this not a boolean
|
// TODO: make this not a boolean
|
||||||
|
#pragma warning disable S1133
|
||||||
|
[Obsolete("Use ParentMenu instead.")]
|
||||||
|
#pragma warning restore S1133
|
||||||
public virtual bool ShowInModifiersMenu => false;
|
public virtual bool ShowInModifiersMenu => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating which menu the group is in.
|
||||||
|
/// </summary>
|
||||||
|
public virtual MenuCategory ParentMenu => MenuCategory.Game;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the function that determines whether the group should be visible or not.
|
/// Gets the function that determines whether the group should be visible or not.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Func<bool> GroupVisible => () => true;
|
public virtual Func<bool> GroupVisible => () => true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the group color. This is used to color the group in the options menu.
|
/// Gets the group <see cref="Color"/>. This is used to color the group in the options menu.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Color GroupColor => MiraApiPlugin.DefaultHeaderColor;
|
public virtual Color GroupColor => MiraApiPlugin.DefaultHeaderColor;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the group priority. This is used to determine the order in which groups are displayed in the options menu.
|
/// Gets the group priority. This is used to determine the order in which groups are displayed in the options menu.
|
||||||
/// Zero is the highest priority, and the default value is the max uint value.
|
/// Zero is the highest priority, and the default value is the max <see langword="uint"/> value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual uint GroupPriority => uint.MaxValue;
|
public virtual uint GroupPriority => uint.MaxValue;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the default notification settings for the group.
|
||||||
|
/// </summary>
|
||||||
|
public virtual OptionNotifConfiguration Configuration => new(new Color(0.7333f, 0.7333f, 0.7333f, 1));
|
||||||
|
|
||||||
internal bool AllOptionsHidden { get; set; }
|
internal bool AllOptionsHidden { get; set; }
|
||||||
|
|
||||||
internal CategoryHeaderMasked? Header { get; set; }
|
internal CategoryHeaderMasked? Header { get; set; }
|
||||||
|
|
||||||
|
internal bool Ready { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -62,4 +80,85 @@ public abstract class AbstractOptionGroup<T> : AbstractOptionGroup where T : IOp
|
|||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override Type OptionableType => typeof(T);
|
public override Type OptionableType => typeof(T);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override MenuCategory ParentMenu
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var type = typeof(T);
|
||||||
|
if (type == typeof(BaseModifier))
|
||||||
|
{
|
||||||
|
return MenuCategory.Modifiers;
|
||||||
|
}
|
||||||
|
else if (type == typeof(RoleBehaviour))
|
||||||
|
{
|
||||||
|
return MenuCategory.Roles;
|
||||||
|
}
|
||||||
|
return MenuCategory.Game;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for option groups. An option group is a collection of options that are displayed together in the options menu.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The custom role that the group is for.</typeparam>
|
||||||
|
public abstract class AbstractRoleOptionGroup<T>() : AbstractOptionGroup<T> where T : ICustomRole
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override Type OptionableType => typeof(T);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override MenuCategory ParentMenu => MenuCategory.Roles;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override OptionNotifConfiguration Configuration
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var role = CustomRoleManager.CustomMiraRoles.FirstOrDefault(x => x.GetType() == OptionableType);
|
||||||
|
if (role == null)
|
||||||
|
{
|
||||||
|
return new(new Color(0.7333f, 0.7333f, 0.7333f, 1));
|
||||||
|
}
|
||||||
|
return new(role.RoleColor, role.Configuration.IconTmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Menu categories for option groups.
|
||||||
|
/// </summary>
|
||||||
|
public enum MenuCategory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Placeholder for indexing purposes. Options don't exist in the presset tab.
|
||||||
|
/// </summary>
|
||||||
|
Preset,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the option group is in the game settings tab.
|
||||||
|
/// </summary>
|
||||||
|
Game,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the option group is in the role settings tab.
|
||||||
|
/// </summary>
|
||||||
|
Roles,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the option group is in the modifier settings tab.
|
||||||
|
/// </summary>
|
||||||
|
Modifiers,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the option group is in the first custom settings tab.
|
||||||
|
/// </summary>
|
||||||
|
CustomOne,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the option group is in the second custom settings tab.
|
||||||
|
/// </summary>
|
||||||
|
CustomTwo,
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@ using MiraAPI.GameOptions.OptionTypes;
|
|||||||
namespace MiraAPI.GameOptions.Attributes;
|
namespace MiraAPI.GameOptions.Attributes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for creating an enum option.
|
/// Attribute for creating a <see cref="ModdedEnumOption"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
[AttributeUsage(AttributeTargets.Property)]
|
||||||
public class ModdedEnumOptionAttribute(string title, Type enumType, string[]? values = null)
|
public class ModdedEnumOptionAttribute(string title, Type enumType, string[]? values = null)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using MiraAPI.Utilities;
|
|||||||
namespace MiraAPI.GameOptions.Attributes;
|
namespace MiraAPI.GameOptions.Attributes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A number option attribute for the modded options system.
|
/// Attribute for a <see cref="ModdedNumberOption"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
[AttributeUsage(AttributeTargets.Property)]
|
||||||
public class ModdedNumberOptionAttribute(
|
public class ModdedNumberOptionAttribute(
|
||||||
@@ -21,7 +21,15 @@ public class ModdedNumberOptionAttribute(
|
|||||||
{
|
{
|
||||||
internal override IModdedOption CreateOption(object? value, PropertyInfo property)
|
internal override IModdedOption CreateOption(object? value, PropertyInfo property)
|
||||||
{
|
{
|
||||||
return new ModdedNumberOption(Title, (float)(value ?? min+increment), min, max, increment, suffixType, formatString, zeroInfinity);
|
return new ModdedNumberOption(
|
||||||
|
Title,
|
||||||
|
(float)(value ?? min + increment),
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
increment,
|
||||||
|
suffixType,
|
||||||
|
formatString,
|
||||||
|
zeroInfinity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -4,12 +4,13 @@ using System.Reflection;
|
|||||||
namespace MiraAPI.GameOptions.Attributes;
|
namespace MiraAPI.GameOptions.Attributes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an attribute that is used to define a modded option.
|
/// Represents an attribute that is used to define an <see cref="IModdedOption"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The option title.</param>
|
/// <param name="title">The option title.</param>
|
||||||
/// <param name="roleType">Optional parameter to specify a role Type.</param>
|
/// <param name="roleType">Optional parameter to specify a role Type.</param>
|
||||||
|
/// <param name="modeType">Optional parameter to specify a game mode Type.</param>
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
[AttributeUsage(AttributeTargets.Property)]
|
||||||
public abstract class ModdedOptionAttribute(string title, Type? roleType = null) : Attribute
|
public abstract class ModdedOptionAttribute(string title, Type? roleType = null, Type? modeType = null) : Attribute
|
||||||
{
|
{
|
||||||
internal IModdedOption? HolderOption { get; set; }
|
internal IModdedOption? HolderOption { get; set; }
|
||||||
|
|
||||||
@@ -23,16 +24,21 @@ public abstract class ModdedOptionAttribute(string title, Type? roleType = null)
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected Type? RoleType { get; private set; } = roleType;
|
protected Type? RoleType { get; private set; } = roleType;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the game mode type of the option.
|
||||||
|
/// </summary>
|
||||||
|
protected Type? ModeType { get; private set; } = modeType;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the value of the option.
|
/// Sets the value of the option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The new value as an object.</param>
|
/// <param name="value">The new value as an <see langword="object"/>.</param>
|
||||||
public abstract void SetValue(object value);
|
public abstract void SetValue(object value);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the value of the option.
|
/// Gets the value of the option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The value of the option as an object.</returns>
|
/// <returns>The value of the option as an <see langword="object"/>.</returns>
|
||||||
public abstract object GetValue();
|
public abstract object GetValue();
|
||||||
|
|
||||||
internal abstract IModdedOption? CreateOption(object? value, PropertyInfo property);
|
internal abstract IModdedOption? CreateOption(object? value, PropertyInfo property);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using MiraAPI.GameOptions.OptionTypes;
|
|||||||
namespace MiraAPI.GameOptions.Attributes;
|
namespace MiraAPI.GameOptions.Attributes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute for a toggle option.
|
/// Attribute for a <see cref="ModdedToggleOption"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The option title.</param>
|
/// <param name="title">The option title.</param>
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
[AttributeUsage(AttributeTargets.Property)]
|
||||||
|
|||||||
@@ -17,27 +17,37 @@ public interface IModdedOption
|
|||||||
uint Id { get; }
|
uint Id { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the title of the option.
|
/// Gets or sets the title of the option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Title { get; }
|
string Title { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the StringName for the option, used for localization.
|
/// Gets or sets the parent <see cref="AbstractOptionGroup"/> of the option.
|
||||||
|
/// </summary>
|
||||||
|
AbstractOptionGroup ParentGroup { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the notification settings for the option.
|
||||||
|
/// </summary>
|
||||||
|
OptionNotifConfiguration Configuration { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="StringNames"/> for the option, used for localization.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
StringNames StringName { get; }
|
StringNames StringName { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the MiraPlugin that created this option.
|
/// Gets or sets the <see cref="IMiraPlugin"/> that created this option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IMiraPlugin? ParentMod { get; set; }
|
IMiraPlugin? ParentMod { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the game setting data for the option.
|
/// Gets the <see cref="BaseGameSetting"/> for the option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
BaseGameSetting Data { get; }
|
BaseGameSetting Data { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the OptionBehaviour object of the option.
|
/// Gets the <see cref="global::OptionBehaviour"/> object of the option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
OptionBehaviour? OptionBehaviour { get; }
|
OptionBehaviour? OptionBehaviour { get; }
|
||||||
|
|
||||||
@@ -52,55 +62,55 @@ public interface IModdedOption
|
|||||||
bool IncludeInPreset { get; set; }
|
bool IncludeInPreset { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the ConfigDefinition for the option, used for BepInEx configuration.
|
/// Gets or sets the <see cref="BepInEx.Configuration.ConfigDefinition"/> for the option, used for BepInEx configuration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ConfigDefinition? ConfigDefinition { get; set; }
|
ConfigDefinition? ConfigDefinition { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the option behaviour for the modded option.
|
/// Creates the option behaviour for the modded option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="toggleOpt">The ToggleOption template.</param>
|
/// <param name="toggleOpt">The <see cref="ToggleOption"/> template.</param>
|
||||||
/// <param name="numberOpt">The NumberOption template.</param>
|
/// <param name="numberOpt">The <see cref="NumberOption"/> template.</param>
|
||||||
/// <param name="stringOpt">The StringOption template.</param>
|
/// <param name="stringOpt">The <see cref="StringOption"/> template.</param>
|
||||||
/// <param name="playerOpt">The PlayerOption template.</param>
|
/// <param name="playerOpt">The <see cref="PlayerOption"/> template.</param>
|
||||||
/// <param name="container">>The Transform container for the option.</param>
|
/// <param name="container">The <see cref="Transform"/> container for the option.</param>
|
||||||
/// <returns>>The created OptionBehaviour object.</returns>
|
/// <returns>The created <see cref="global::OptionBehaviour"/> object.</returns>
|
||||||
OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container);
|
OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the value as a float.
|
/// Gets the value as a <see langword="float"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>>The value of the option as a float.</returns>
|
/// <returns>The value of the option as a <see langword="float"/>.</returns>
|
||||||
float GetFloatData();
|
float GetFloatData();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the NetData for the option, used for network synchronization.
|
/// Gets the <see cref="NetData"/> for the option, used for network synchronization.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>>Returns the NetData object for the option.</returns>
|
/// <returns>Returns the <see cref="NetData"/> object for the option.</returns>
|
||||||
NetData GetNetData();
|
NetData GetNetData();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles incoming network data for the option.
|
/// Handles incoming network data for the option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">>The byte array representing the network data.</param>
|
/// <param name="data">The byte array representing the network data.</param>
|
||||||
void HandleNetData(byte[] data);
|
void HandleNetData(byte[] data);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves the option to a preset configuration file.
|
/// Saves the option to a preset configuration file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="presetConfig">The ConfigFile representing the preset configuration.</param>
|
/// <param name="presetConfig">The <see cref="ConfigFile"/> representing the preset configuration.</param>
|
||||||
/// <param name="saveDefault">Indicates whether to save the default value instead of the current value.</param>
|
/// <param name="saveDefault">Indicates whether to save the default value instead of the current value.</param>
|
||||||
void SaveToPreset(ConfigFile presetConfig, bool saveDefault = false);
|
void SaveToPreset(ConfigFile presetConfig, bool saveDefault = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Binds the option to a configuration file.
|
/// Binds the option to a configuration file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config">The ConfigFile to bind the option to.</param>
|
/// <param name="config">The <see cref="ConfigFile"/> to bind the option to.</param>
|
||||||
void Bind(ConfigFile config);
|
void Bind(ConfigFile config);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads the option from a preset configuration file, applying the values to the option's configuration.
|
/// Loads the option from a preset configuration file, applying the values to the option's configuration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="presetConfig">The ConfigFile representing the preset configuration.</param>
|
/// <param name="presetConfig">The <see cref="ConfigFile"/> representing the preset configuration.</param>
|
||||||
void LoadFromPreset(ConfigFile presetConfig);
|
void LoadFromPreset(ConfigFile presetConfig);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using Il2CppInterop.Runtime.Attributes;
|
||||||
|
using MiraAPI.GameOptions.OptionTypes;
|
||||||
|
using Reactor.Utilities.Attributes;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace MiraAPI.GameOptions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Component added onto options generated via MiraAPI. This allows developers to hook patches onto options in general, without using a list.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterInIl2Cpp]
|
||||||
|
public class MiraNumberOptionComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="ModdedNumberOption"/> associated with the object.
|
||||||
|
/// </summary>
|
||||||
|
[HideFromIl2Cpp]
|
||||||
|
public ModdedNumberOption NumberOption { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the default increment.
|
||||||
|
/// </summary>
|
||||||
|
public float DefaultIncrement { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether holding shift will split the increment in half.
|
||||||
|
/// </summary>
|
||||||
|
public bool ShiftIncrementToggle { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating what Zero displays.
|
||||||
|
/// </summary>
|
||||||
|
public string ZeroValue { get; set; } = "#";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating what Negative One displays.
|
||||||
|
/// </summary>
|
||||||
|
public string NegativeValue { get; set; } = "#";
|
||||||
|
}
|
||||||
@@ -5,6 +5,8 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using BepInEx.Configuration;
|
using BepInEx.Configuration;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
|
using Il2CppInterop.Runtime.Injection;
|
||||||
|
using MiraAPI.GameModes;
|
||||||
using MiraAPI.GameOptions.Attributes;
|
using MiraAPI.GameOptions.Attributes;
|
||||||
using MiraAPI.GameOptions.OptionTypes;
|
using MiraAPI.GameOptions.OptionTypes;
|
||||||
using MiraAPI.Networking;
|
using MiraAPI.Networking;
|
||||||
@@ -12,11 +14,13 @@ using MiraAPI.PluginLoading;
|
|||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
using Reactor.Networking.Rpc;
|
using Reactor.Networking.Rpc;
|
||||||
using Reactor.Utilities;
|
using Reactor.Utilities;
|
||||||
|
using TMPro;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.GameOptions;
|
namespace MiraAPI.GameOptions;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles modded options.
|
/// Handles <see cref="IModdedOption"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ModdedOptionsManager
|
public static class ModdedOptionsManager
|
||||||
{
|
{
|
||||||
@@ -24,13 +28,45 @@ public static class ModdedOptionsManager
|
|||||||
private static readonly Dictionary<Type, AbstractOptionGroup> TypeToGroup = [];
|
private static readonly Dictionary<Type, AbstractOptionGroup> TypeToGroup = [];
|
||||||
|
|
||||||
internal static readonly Dictionary<OptionBehaviour, ModdedPlayerOption> CreatedPlayerOptions = [];
|
internal static readonly Dictionary<OptionBehaviour, ModdedPlayerOption> CreatedPlayerOptions = [];
|
||||||
|
internal static readonly Dictionary<OptionBehaviour, ModdedStringOption> CreatedStringOptions = [];
|
||||||
|
internal static readonly Dictionary<Type, List<AbstractOptionGroup>> GameModeOptionGroups = [];
|
||||||
internal static readonly Dictionary<uint, IModdedOption> ModdedOptions = [];
|
internal static readonly Dictionary<uint, IModdedOption> ModdedOptions = [];
|
||||||
internal static readonly List<AbstractOptionGroup> Groups = [];
|
internal static readonly List<AbstractOptionGroup> Groups = [];
|
||||||
|
|
||||||
internal static uint NextId => _nextId++;
|
internal static uint NextId => _nextId++;
|
||||||
private static uint _nextId = 1;
|
private static uint _nextId = 1;
|
||||||
|
|
||||||
internal static bool RegisterGroup(Type type, MiraPluginInfo pluginInfo)
|
public static void AddSettingsChangeMessage(NotificationPopper notif, StringNames key, string value, Color textColor, TMP_SpriteAsset? sprite, bool playSound = true)
|
||||||
|
{
|
||||||
|
string item;
|
||||||
|
var text = textColor.ToTextColor();
|
||||||
|
if (sprite != null)
|
||||||
|
{
|
||||||
|
item = TranslationController.Instance.GetString(
|
||||||
|
StringNames.LobbyChangeSettingNotification,
|
||||||
|
string.Concat(
|
||||||
|
"<sprite name=\"",
|
||||||
|
sprite.name,
|
||||||
|
"\"><font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">",
|
||||||
|
text,
|
||||||
|
TranslationController.Instance.GetString(key),
|
||||||
|
"</color></font>"),
|
||||||
|
"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + value + "</font>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item = TranslationController.Instance.GetString(
|
||||||
|
StringNames.LobbyChangeSettingNotification,
|
||||||
|
"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" +
|
||||||
|
text +
|
||||||
|
TranslationController.Instance.GetString(key) + "</color></font>",
|
||||||
|
"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + value + "</font>");
|
||||||
|
}
|
||||||
|
notif.SettingsChangeMessageLogic(key, item, playSound);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool RegisterGroup(Type type)
|
||||||
{
|
{
|
||||||
if (Activator.CreateInstance(type) is not AbstractOptionGroup group)
|
if (Activator.CreateInstance(type) is not AbstractOptionGroup group)
|
||||||
{
|
{
|
||||||
@@ -45,6 +81,40 @@ public static class ModdedOptionsManager
|
|||||||
|
|
||||||
Groups.Add(group);
|
Groups.Add(group);
|
||||||
TypeToGroup.Add(type, group);
|
TypeToGroup.Add(type, group);
|
||||||
|
|
||||||
|
typeof(OptionGroupSingleton<>).MakeGenericType(type)
|
||||||
|
.GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic)!
|
||||||
|
.SetValue(null, group);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool RegisterGroup(Type type, MiraPluginInfo pluginInfo)
|
||||||
|
{
|
||||||
|
if (Activator.CreateInstance(type) is not AbstractOptionGroup group)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TypeToGroup.ContainsKey(type))
|
||||||
|
{
|
||||||
|
Error($"Group {type.Name} already exists.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Groups.Add(group);
|
||||||
|
TypeToGroup.Add(type, group);
|
||||||
|
if (group.OptionableType?.IsAssignableTo(typeof(AbstractGameMode)) == true)
|
||||||
|
{
|
||||||
|
if (GameModeOptionGroups.TryGetValue(group.OptionableType, out var oldList))
|
||||||
|
{
|
||||||
|
oldList.Add(group);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GameModeOptionGroups.Add(group.OptionableType, new List<AbstractOptionGroup>() { group });
|
||||||
|
}
|
||||||
|
}
|
||||||
pluginInfo.InternalOptionGroups.Add(group);
|
pluginInfo.InternalOptionGroups.Add(group);
|
||||||
|
|
||||||
typeof(OptionGroupSingleton<>).MakeGenericType(type)
|
typeof(OptionGroupSingleton<>).MakeGenericType(type)
|
||||||
@@ -60,13 +130,13 @@ public static class ModdedOptionsManager
|
|||||||
{
|
{
|
||||||
if (!TypeToGroup.TryGetValue(type, out var group))
|
if (!TypeToGroup.TryGetValue(type, out var group))
|
||||||
{
|
{
|
||||||
Logger<MiraApiPlugin>.Error($"Failed to get group for {type.Name}");
|
Error($"Failed to get group for {type.Name}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property.GetValue(group) is not IModdedOption option)
|
if (property.GetValue(group) is not IModdedOption option)
|
||||||
{
|
{
|
||||||
Logger<MiraApiPlugin>.Error($"Failed to get option for {property.Name}");
|
Error($"Failed to get option for {property.Name}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,13 +151,13 @@ public static class ModdedOptionsManager
|
|||||||
{
|
{
|
||||||
if (OptionAttributes.ContainsKey(property))
|
if (OptionAttributes.ContainsKey(property))
|
||||||
{
|
{
|
||||||
Logger<MiraApiPlugin>.Error($"Property {property.Name} already has an attribute registered.");
|
Error($"Property {property.Name} already has an attribute registered.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TypeToGroup.TryGetValue(type, out var group))
|
if (!TypeToGroup.TryGetValue(type, out var group))
|
||||||
{
|
{
|
||||||
Logger<MiraApiPlugin>.Error($"Failed to get group for {type.Name}");
|
Error($"Failed to get group for {type.Name}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +165,7 @@ public static class ModdedOptionsManager
|
|||||||
|
|
||||||
if (option == null)
|
if (option == null)
|
||||||
{
|
{
|
||||||
Logger<MiraApiPlugin>.Error($"Failed to get option for {property.Name}");
|
Error($"Failed to get option for {property.Name}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,6 +193,7 @@ public static class ModdedOptionsManager
|
|||||||
|
|
||||||
option.ConfigDefinition = new ConfigDefinition(groupName, propertyName);
|
option.ConfigDefinition = new ConfigDefinition(groupName, propertyName);
|
||||||
|
|
||||||
|
option.ParentGroup = group;
|
||||||
option.ParentMod = pluginInfo.MiraPlugin;
|
option.ParentMod = pluginInfo.MiraPlugin;
|
||||||
pluginInfo.InternalOptions.Add(option);
|
pluginInfo.InternalOptions.Add(option);
|
||||||
ModdedOptions.Add(option.Id, option);
|
ModdedOptions.Add(option.Id, option);
|
||||||
@@ -192,7 +263,7 @@ public static class ModdedOptionsManager
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="__originalMethod">The original getter method.</param>
|
/// <param name="__originalMethod">The original getter method.</param>
|
||||||
/// <param name="__result">The result of the property getter.</param>
|
/// <param name="__result">The result of the property getter.</param>
|
||||||
/// <returns>False so the original getter gets skipped.</returns>
|
/// <returns><see langword="false"/> so the original getter gets skipped.</returns>
|
||||||
#pragma warning disable CA1707
|
#pragma warning disable CA1707
|
||||||
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Harmony naming convention")]
|
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Harmony naming convention")]
|
||||||
public static bool PropertyGetterPatch(MethodBase __originalMethod, ref object __result)
|
public static bool PropertyGetterPatch(MethodBase __originalMethod, ref object __result)
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using MiraAPI.PluginLoading;
|
||||||
|
|
||||||
namespace MiraAPI.GameOptions;
|
namespace MiraAPI.GameOptions;
|
||||||
|
|
||||||
#pragma warning disable CA1852
|
#pragma warning disable CA1852
|
||||||
|
[MiraIgnore]
|
||||||
internal class ModifierOptionGroup : AbstractOptionGroup
|
internal class ModifierOptionGroup : AbstractOptionGroup
|
||||||
#pragma warning restore CA1852
|
#pragma warning restore CA1852
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace MiraAPI.GameOptions;
|
namespace MiraAPI.GameOptions;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Singleton for option groups.
|
/// Singleton for <see cref="AbstractOptionGroup"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The option group type.</typeparam>
|
/// <typeparam name="T">The option group type.</typeparam>
|
||||||
public static class OptionGroupSingleton<T> where T : AbstractOptionGroup
|
public static class OptionGroupSingleton<T> where T : AbstractOptionGroup
|
||||||
@@ -11,7 +11,7 @@ public static class OptionGroupSingleton<T> where T : AbstractOptionGroup
|
|||||||
private static T? _instance;
|
private static T? _instance;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the instance of the option group.
|
/// Gets the instance of the <typeparamref name="T"/> group.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#pragma warning disable CA1000
|
#pragma warning disable CA1000
|
||||||
public static T Instance => _instance ??= ModdedOptionsManager.Groups.OfType<T>().Single();
|
public static T Instance => _instance ??= ModdedOptionsManager.Groups.OfType<T>().Single();
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using Il2CppInterop.Runtime.Attributes;
|
||||||
|
using TMPro;
|
||||||
|
using UnityEngine;
|
||||||
|
namespace MiraAPI.GameOptions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to configure the specific visuals for option notifications.
|
||||||
|
/// </summary>
|
||||||
|
public record struct OptionNotifConfiguration
|
||||||
|
{
|
||||||
|
#pragma warning disable S1133
|
||||||
|
[Obsolete("Default constructor is not supported")]
|
||||||
|
#pragma warning restore S1133
|
||||||
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||||
|
public OptionNotifConfiguration()
|
||||||
|
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("Default constructor is not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="OptionNotifConfiguration"/> struct based on a group.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="group">The <see cref="AbstractOptionGroup"/> in which you are configuring.</param>
|
||||||
|
public OptionNotifConfiguration(AbstractOptionGroup group)
|
||||||
|
{
|
||||||
|
PopUpIconTmp = group.Configuration.PopUpIconTmp;
|
||||||
|
PopUpTextColor = group.Configuration.PopUpTextColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="OptionNotifConfiguration"/> struct from scratch.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The text <see cref="Color"/> for the configuration.</param>
|
||||||
|
/// <param name="asset">The <see cref="TMP_SpriteAsset"/> icon for the configuration.</param>
|
||||||
|
public OptionNotifConfiguration(Color color, TMP_SpriteAsset asset = null!)
|
||||||
|
{
|
||||||
|
PopUpIconTmp = asset;
|
||||||
|
PopUpTextColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="TMP_SpriteAsset"/> for the icon on the options pop-up.
|
||||||
|
/// </summary>
|
||||||
|
public TMP_SpriteAsset PopUpIconTmp { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="Color"/> for the text on the options pop-up.
|
||||||
|
/// </summary>
|
||||||
|
[HideFromIl2Cpp]
|
||||||
|
public Color PopUpTextColor { get; set; }
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ using Object = UnityEngine.Object;
|
|||||||
namespace MiraAPI.GameOptions.OptionTypes;
|
namespace MiraAPI.GameOptions.OptionTypes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An option for selecting an enum value.
|
/// An option for selecting an <see langword="enum"/> value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ModdedEnumOption : ModdedOption<int>
|
public class ModdedEnumOption : ModdedOption<int>
|
||||||
{
|
{
|
||||||
@@ -25,8 +25,8 @@ public class ModdedEnumOption : ModdedOption<int>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The title of the option.</param>
|
/// <param name="title">The title of the option.</param>
|
||||||
/// <param name="defaultValue">The default value as an int.</param>
|
/// <param name="defaultValue">The default value as an int.</param>
|
||||||
/// <param name="enumType">The Enum type.</param>
|
/// <param name="enumType">The <see cref="Enum"/> type.</param>
|
||||||
/// <param name="values">An option list of string values to use in place of the enum name.</param>
|
/// <param name="values">An option list of string values to use in place of the <see langword="enum"/> name.</param>
|
||||||
/// <param name="includeInPreset">Whether to include this option in the preset or not.</param>
|
/// <param name="includeInPreset">Whether to include this option in the preset or not.</param>
|
||||||
public ModdedEnumOption(string title, int defaultValue, Type enumType, string[]? values = null, bool includeInPreset=true) : base(title, defaultValue, includeInPreset)
|
public ModdedEnumOption(string title, int defaultValue, Type enumType, string[]? values = null, bool includeInPreset=true) : base(title, defaultValue, includeInPreset)
|
||||||
{
|
{
|
||||||
@@ -47,6 +47,8 @@ public class ModdedEnumOption : ModdedOption<int>
|
|||||||
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
|
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
|
||||||
{
|
{
|
||||||
var stringOption = Object.Instantiate(stringOpt, container);
|
var stringOption = Object.Instantiate(stringOpt, container);
|
||||||
|
stringOption.name =
|
||||||
|
$"{ParentMod!.OptionsTitleText}.EnumOption.{TranslationController.Instance.GetString(StringName)}";
|
||||||
|
|
||||||
stringOption.SetUpFromData(Data, 20);
|
stringOption.SetUpFromData(Data, 20);
|
||||||
stringOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
|
stringOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
|
||||||
@@ -88,7 +90,13 @@ public class ModdedEnumOption : ModdedOption<int>
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnValueChanged(int newValue)
|
protected override void OnValueChanged(int newValue)
|
||||||
{
|
{
|
||||||
HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(newValue), false);
|
ModdedOptionsManager.AddSettingsChangeMessage(
|
||||||
|
HudManager.Instance.Notifier,
|
||||||
|
StringName,
|
||||||
|
Data.GetValueString(newValue),
|
||||||
|
Configuration.PopUpTextColor,
|
||||||
|
Configuration.PopUpIconTmp,
|
||||||
|
false);
|
||||||
if (!OptionBehaviour)
|
if (!OptionBehaviour)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -102,13 +110,13 @@ public class ModdedEnumOption : ModdedOption<int>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An option for selecting an enum value.
|
/// An option for selecting an <see langword="enum"/> value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The enum type.</typeparam>
|
/// <typeparam name="T">The <see cref="Enum"/> type.</typeparam>
|
||||||
public class ModdedEnumOption<T> : ModdedOption<T> where T : Enum
|
public class ModdedEnumOption<T> : ModdedOption<T> where T : Enum
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the string values of the enum.
|
/// Gets the string values of the <see langword="enum"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string[] Values { get; }
|
public string[] Values { get; }
|
||||||
|
|
||||||
@@ -116,8 +124,8 @@ public class ModdedEnumOption<T> : ModdedOption<T> where T : Enum
|
|||||||
/// Initializes a new instance of the <see cref="ModdedEnumOption{T}"/> class.
|
/// Initializes a new instance of the <see cref="ModdedEnumOption{T}"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The title of the option.</param>
|
/// <param name="title">The title of the option.</param>
|
||||||
/// <param name="defaultValue">The default value as an int.</param>
|
/// <param name="defaultValue">The default value as an <see langword="int"/>.</param>
|
||||||
/// <param name="values">An option list of string values to use in place of the enum name.</param>
|
/// <param name="values">An option list of string values to use in place of the <see langword="enum"/> name.</param>
|
||||||
/// <param name="includeInPreset">Whether to include this option in the preset or not.</param>
|
/// <param name="includeInPreset">Whether to include this option in the preset or not.</param>
|
||||||
public ModdedEnumOption(string title, T defaultValue, string[]? values = null, bool includeInPreset=true) : base(title, defaultValue, includeInPreset)
|
public ModdedEnumOption(string title, T defaultValue, string[]? values = null, bool includeInPreset=true) : base(title, defaultValue, includeInPreset)
|
||||||
{
|
{
|
||||||
@@ -138,6 +146,8 @@ public class ModdedEnumOption<T> : ModdedOption<T> where T : Enum
|
|||||||
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
|
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
|
||||||
{
|
{
|
||||||
var stringOption = Object.Instantiate(stringOpt, container);
|
var stringOption = Object.Instantiate(stringOpt, container);
|
||||||
|
stringOption.name =
|
||||||
|
$"{ParentMod!.OptionsTitleText}.EnumOption.{TranslationController.Instance.GetString(StringName)}";
|
||||||
|
|
||||||
stringOption.SetUpFromData(Data, 20);
|
stringOption.SetUpFromData(Data, 20);
|
||||||
stringOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
|
stringOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
|
||||||
@@ -179,7 +189,13 @@ public class ModdedEnumOption<T> : ModdedOption<T> where T : Enum
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnValueChanged(T newValue)
|
protected override void OnValueChanged(T newValue)
|
||||||
{
|
{
|
||||||
HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(Convert.ToInt32(newValue, NumberFormatInfo.InvariantInfo)), false);
|
ModdedOptionsManager.AddSettingsChangeMessage(
|
||||||
|
HudManager.Instance.Notifier,
|
||||||
|
StringName,
|
||||||
|
Data.GetValueString(Convert.ToInt32(newValue, NumberFormatInfo.InvariantInfo)),
|
||||||
|
Configuration.PopUpTextColor,
|
||||||
|
Configuration.PopUpIconTmp,
|
||||||
|
false);
|
||||||
if (!OptionBehaviour)
|
if (!OptionBehaviour)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -32,10 +32,82 @@ public class ModdedNumberOption : ModdedOption<float>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public MiraNumberSuffixes SuffixType { get; }
|
public MiraNumberSuffixes SuffixType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating what zero appears as.
|
||||||
|
/// </summary>
|
||||||
|
public string ZeroWordValue { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating what a negative one appears as.
|
||||||
|
/// </summary>
|
||||||
|
public string NegativeWordValue { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether zero is infinity.
|
/// Gets a value indicating whether zero is infinity.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ZeroInfinity { get; }
|
public bool ZeroInfinity => ZeroWordValue == "∞";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether holding shift will divide the increment.
|
||||||
|
/// </summary>
|
||||||
|
public bool ShiftIncrement { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ModdedNumberOption"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="title">The title of the option.</param>
|
||||||
|
/// <param name="defaultValue">The default value as a float.</param>
|
||||||
|
/// <param name="min">The minimum value.</param>
|
||||||
|
/// <param name="max">The maximum value.</param>
|
||||||
|
/// <param name="increment">The increment.</param>
|
||||||
|
/// <param name="suffixType">The suffix type.</param>
|
||||||
|
/// <param name="formatString">Optional format string for the option screen.</param>
|
||||||
|
/// <param name="zeroBehavior">Determines what is shown for zero. Options: ∞, #, or a word value (such as Off).</param>
|
||||||
|
/// <param name="negativeBehavior">Determines what is shown for negative 1. Options: ∞, #, or a word value (such as Off).</param>
|
||||||
|
/// <param name="halfIncrements">Whether increments can be split in half.</param>
|
||||||
|
/// <param name="includeInPreset">Whether to include this option in the preset or not.</param>
|
||||||
|
public ModdedNumberOption(
|
||||||
|
string title,
|
||||||
|
float defaultValue,
|
||||||
|
float min,
|
||||||
|
float max,
|
||||||
|
float increment,
|
||||||
|
string zeroBehavior,
|
||||||
|
string negativeBehavior,
|
||||||
|
MiraNumberSuffixes suffixType,
|
||||||
|
string? formatString = null,
|
||||||
|
bool halfIncrements = false,
|
||||||
|
bool includeInPreset = true) : base(title, defaultValue, includeInPreset)
|
||||||
|
{
|
||||||
|
Min = min;
|
||||||
|
Max = max;
|
||||||
|
Increment = increment;
|
||||||
|
SuffixType = suffixType;
|
||||||
|
ZeroWordValue = zeroBehavior;
|
||||||
|
NegativeWordValue = negativeBehavior;
|
||||||
|
ShiftIncrement = halfIncrements;
|
||||||
|
|
||||||
|
Value = Mathf.Clamp(defaultValue, min, max);
|
||||||
|
|
||||||
|
Data = ScriptableObject.CreateInstance<FloatGameSetting>();
|
||||||
|
|
||||||
|
var data = (FloatGameSetting)Data;
|
||||||
|
data.Type = global::OptionTypes.Float;
|
||||||
|
data.Title = StringName;
|
||||||
|
data.Value = Value;
|
||||||
|
data.Increment = Increment;
|
||||||
|
data.ValidRange = new FloatRange(Min, Max);
|
||||||
|
data.FormatString = formatString ??
|
||||||
|
(defaultValue.IsInteger() &&
|
||||||
|
Increment.IsInteger() &&
|
||||||
|
Value.IsInteger() &&
|
||||||
|
Min.IsInteger() &&
|
||||||
|
Max.IsInteger() ? "0" : "0.0");
|
||||||
|
|
||||||
|
data.ZeroIsInfinity = ZeroInfinity;
|
||||||
|
data.SuffixType = (NumberSuffixes)SuffixType;
|
||||||
|
data.OptionName = FloatOptionNames.Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ModdedNumberOption"/> class.
|
/// Initializes a new instance of the <see cref="ModdedNumberOption"/> class.
|
||||||
@@ -64,7 +136,9 @@ public class ModdedNumberOption : ModdedOption<float>
|
|||||||
Max = max;
|
Max = max;
|
||||||
Increment = increment;
|
Increment = increment;
|
||||||
SuffixType = suffixType;
|
SuffixType = suffixType;
|
||||||
ZeroInfinity = zeroInfinity;
|
ZeroWordValue = zeroInfinity ? "∞" : "#";
|
||||||
|
NegativeWordValue = "#";
|
||||||
|
ShiftIncrement = increment != 1f;
|
||||||
|
|
||||||
Value = Mathf.Clamp(defaultValue, min, max);
|
Value = Mathf.Clamp(defaultValue, min, max);
|
||||||
|
|
||||||
@@ -97,6 +171,14 @@ public class ModdedNumberOption : ModdedOption<float>
|
|||||||
Transform container)
|
Transform container)
|
||||||
{
|
{
|
||||||
var numberOption = Object.Instantiate(numberOpt, Vector3.zero, Quaternion.identity, container);
|
var numberOption = Object.Instantiate(numberOpt, Vector3.zero, Quaternion.identity, container);
|
||||||
|
numberOption.name =
|
||||||
|
$"{ParentMod!.OptionsTitleText}.NumberOption.{TranslationController.Instance.GetString(StringName)}";
|
||||||
|
var optionComponent = numberOption.gameObject.AddComponent<MiraNumberOptionComponent>();
|
||||||
|
optionComponent.NumberOption = this;
|
||||||
|
optionComponent.DefaultIncrement = Increment;
|
||||||
|
optionComponent.ShiftIncrementToggle = ShiftIncrement;
|
||||||
|
optionComponent.NegativeValue = NegativeWordValue;
|
||||||
|
optionComponent.ZeroValue = ZeroWordValue;
|
||||||
|
|
||||||
numberOption.SetUpFromData(Data, 20);
|
numberOption.SetUpFromData(Data, 20);
|
||||||
numberOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
|
numberOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
|
||||||
@@ -143,9 +225,12 @@ public class ModdedNumberOption : ModdedOption<float>
|
|||||||
protected override void OnValueChanged(float newValue)
|
protected override void OnValueChanged(float newValue)
|
||||||
{
|
{
|
||||||
Value = Mathf.Clamp(newValue, Min, Max);
|
Value = Mathf.Clamp(newValue, Min, Max);
|
||||||
HudManager.Instance.Notifier.AddSettingsChangeMessage(
|
ModdedOptionsManager.AddSettingsChangeMessage(
|
||||||
|
HudManager.Instance.Notifier,
|
||||||
StringName,
|
StringName,
|
||||||
Data.GetValueString(Value),
|
Data.GetValueString(newValue),
|
||||||
|
Configuration.PopUpTextColor,
|
||||||
|
Configuration.PopUpIconTmp,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
if (OptionBehaviour is NumberOption opt)
|
if (OptionBehaviour is NumberOption opt)
|
||||||
@@ -155,7 +240,7 @@ public class ModdedNumberOption : ModdedOption<float>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implicitly converts the option to an int.
|
/// Implicitly converts the option to an <see langword="int"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="option">The option.</param>
|
/// <param name="option">The option.</param>
|
||||||
/// <returns>Integer value.</returns>
|
/// <returns>Integer value.</returns>
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using BepInEx.Configuration;
|
using BepInEx.Configuration;
|
||||||
using MiraAPI.Networking;
|
using MiraAPI.Networking;
|
||||||
using MiraAPI.PluginLoading;
|
using MiraAPI.PluginLoading;
|
||||||
using Reactor.Localization.Utilities;
|
using Reactor.Localization.Utilities;
|
||||||
using Reactor.Networking.Rpc;
|
using Reactor.Networking.Rpc;
|
||||||
using Reactor.Utilities;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.GameOptions.OptionTypes;
|
namespace MiraAPI.GameOptions.OptionTypes;
|
||||||
@@ -21,7 +20,7 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
public uint Id { get; }
|
public uint Id { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Title { get; }
|
public string Title { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public StringNames StringName { get; }
|
public StringNames StringName { get; }
|
||||||
@@ -125,7 +124,7 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
{
|
{
|
||||||
if (ConfigDefinition is null)
|
if (ConfigDefinition is null)
|
||||||
{
|
{
|
||||||
Logger<MiraApiPlugin>.Error($"Attempted to save {Title} to preset, but ConfigDefinition is null.");
|
Error($"Attempted to save {Title} to preset, but ConfigDefinition is null.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Bind(presetConfig);
|
Bind(presetConfig);
|
||||||
@@ -147,7 +146,7 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger<MiraApiPlugin>.Error($"Attempted to load {Title} from preset, but ConfigDefinition is not found in preset.");
|
Error($"Attempted to load {Title} from preset, but ConfigDefinition is not found in preset.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,4 +189,10 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
{
|
{
|
||||||
return option.Value;
|
return option.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public AbstractOptionGroup ParentGroup { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual OptionNotifConfiguration Configuration => new(ParentGroup);
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ using Object = UnityEngine.Object;
|
|||||||
namespace MiraAPI.GameOptions.OptionTypes;
|
namespace MiraAPI.GameOptions.OptionTypes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An option for selecting an ingame player. It returns an index of the values list, NOT A PLAYER ID. To get a player out of this, index the Values list.
|
/// An option for selecting an ingame player. It returns an index of the values list, NOT A PLAYER ID. To get a player out of this, index the <see cref="Values"/> list.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ModdedPlayerOption : ModdedOption<int>
|
public class ModdedPlayerOption : ModdedOption<int>
|
||||||
{
|
{
|
||||||
@@ -55,6 +55,8 @@ public class ModdedPlayerOption : ModdedOption<int>
|
|||||||
Transform container)
|
Transform container)
|
||||||
{
|
{
|
||||||
var playerOption = Object.Instantiate(playerOpt, container);
|
var playerOption = Object.Instantiate(playerOpt, container);
|
||||||
|
playerOption.name =
|
||||||
|
$"{ParentMod!.OptionsTitleText}.PlayerOption.{TranslationController.Instance.GetString(StringName)}";
|
||||||
|
|
||||||
var filteredList = GetFilteredPlayers();
|
var filteredList = GetFilteredPlayers();
|
||||||
Values = filteredList.ToIl2CppList();
|
Values = filteredList.ToIl2CppList();
|
||||||
@@ -89,9 +91,9 @@ public class ModdedPlayerOption : ModdedOption<int>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a player from the value. If AllowNone is enabled and none is enabled this will return null.
|
/// Returns a player from the value. If <see cref="AllowNone"/> is enabled and none is enabled this will return <see langword="null"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A player or null if chosen none.</returns>
|
/// <returns>A player or <see langword="null"/> if chosen none.</returns>
|
||||||
public NetworkedPlayerInfo? GetPlayerValue()
|
public NetworkedPlayerInfo? GetPlayerValue()
|
||||||
{
|
{
|
||||||
return Value < 0 ? null : Values[Value];
|
return Value < 0 ? null : Values[Value];
|
||||||
@@ -124,7 +126,13 @@ public class ModdedPlayerOption : ModdedOption<int>
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnValueChanged(int newValue)
|
protected override void OnValueChanged(int newValue)
|
||||||
{
|
{
|
||||||
HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(newValue), false);
|
ModdedOptionsManager.AddSettingsChangeMessage(
|
||||||
|
HudManager.Instance.Notifier,
|
||||||
|
StringName,
|
||||||
|
Data.GetValueString(newValue),
|
||||||
|
Configuration.PopUpTextColor,
|
||||||
|
Configuration.PopUpIconTmp,
|
||||||
|
false);
|
||||||
if (!OptionBehaviour)
|
if (!OptionBehaviour)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||||
|
using MiraAPI.Networking;
|
||||||
|
using Reactor.Localization.Utilities;
|
||||||
|
using UnityEngine;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
|
namespace MiraAPI.GameOptions.OptionTypes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An option for selecting an enum value.
|
||||||
|
/// </summary>
|
||||||
|
public class ModdedStringOption : ModdedOption<string>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the string values of the option.
|
||||||
|
/// </summary>
|
||||||
|
public string[] Values { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the String Name values of the option.
|
||||||
|
/// </summary>
|
||||||
|
public StringNames[] StringNameValues { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the string's index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The option's string value.</param>
|
||||||
|
/// <returns>The option's value in the index.</returns>
|
||||||
|
public int GetIndex(string value, int location)
|
||||||
|
{
|
||||||
|
if (Values.Contains(value))
|
||||||
|
{
|
||||||
|
return Values.ToList().IndexOf(value);
|
||||||
|
}
|
||||||
|
Info($"Cannot find a valid index for {value} in {location}. Returning 0 instead. Values: {string.Join(", ", Values)}");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a value to the option.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The option's string value.</param>
|
||||||
|
/// <param name="index">The additional value's index on the list.</param>
|
||||||
|
public void RegisterExtraValue(string value, int index = -1)
|
||||||
|
{
|
||||||
|
if (!Values.Contains(value))
|
||||||
|
{
|
||||||
|
if (index <= -1)
|
||||||
|
index = Values.Length;
|
||||||
|
|
||||||
|
var newVals = Values.ToList();
|
||||||
|
newVals.Insert(index, value);
|
||||||
|
Values = newVals.ToArray();
|
||||||
|
var newStrVals = StringNameValues.ToList();
|
||||||
|
newStrVals.Insert(index, CustomStringName.CreateAndRegister(value));
|
||||||
|
StringNameValues = newStrVals.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Data != null)
|
||||||
|
{
|
||||||
|
var data = (StringGameSetting)Data;
|
||||||
|
data.Values = StringNameValues;
|
||||||
|
|
||||||
|
data.Index = GetIndex(Value, 1);
|
||||||
|
if (OptionBehaviour != null)
|
||||||
|
{
|
||||||
|
var strOpt = OptionBehaviour.TryCast<StringOption>();
|
||||||
|
if (strOpt != null)
|
||||||
|
{
|
||||||
|
strOpt.Values = StringNameValues;
|
||||||
|
strOpt.Value = GetIndex(Value, 2);
|
||||||
|
Warning("StringOption is valid");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error("StringOption is null.");
|
||||||
|
}
|
||||||
|
Warning("OptionBehaviour is valid");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error("OptionBehaviour is null.");
|
||||||
|
}
|
||||||
|
Warning("Data is valid");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error("Data is null.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ModdedStringOption"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="title">The title of the option.</param>
|
||||||
|
/// <param name="defaultValue">The default value as a string.</param>
|
||||||
|
/// <param name="values">An option list of string values to use.</param>
|
||||||
|
/// <param name="includeInPreset">Whether to include this option in the preset or not.</param>
|
||||||
|
public ModdedStringOption(string title, string defaultValue, string[] values, bool includeInPreset=true) : base(title, defaultValue, includeInPreset)
|
||||||
|
{
|
||||||
|
Values = values;
|
||||||
|
Data = ScriptableObject.CreateInstance<StringGameSetting>();
|
||||||
|
var data = (StringGameSetting)Data;
|
||||||
|
|
||||||
|
data.Title = StringName;
|
||||||
|
data.Type = global::OptionTypes.String;
|
||||||
|
StringNameValues = values.Select(CustomStringName.CreateAndRegister).ToArray();
|
||||||
|
data.Values = StringNameValues;
|
||||||
|
|
||||||
|
data.Index = GetIndex(Value, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
|
||||||
|
{
|
||||||
|
var stringOption = Object.Instantiate(stringOpt, container);
|
||||||
|
stringOption.name =
|
||||||
|
$"{ParentMod!.OptionsTitleText}.StringOption.{TranslationController.Instance.GetString(StringName)}";
|
||||||
|
|
||||||
|
stringOption.SetUpFromData(Data, 20);
|
||||||
|
stringOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
|
||||||
|
|
||||||
|
// SetUpFromData method doesnt work correctly so we must set the values manually
|
||||||
|
stringOption.Title = StringName;
|
||||||
|
stringOption.Values = (Data as StringGameSetting)?.Values ?? new Il2CppStructArray<StringNames>(0);
|
||||||
|
stringOption.Value = GetIndex(Value, 4);
|
||||||
|
|
||||||
|
OptionBehaviour = stringOption;
|
||||||
|
ModdedOptionsManager.CreatedStringOptions.TryAdd(stringOption, this);
|
||||||
|
|
||||||
|
return stringOption;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override float GetFloatData()
|
||||||
|
{
|
||||||
|
return Array.IndexOf(Values, Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override NetData GetNetData()
|
||||||
|
{
|
||||||
|
return new NetData(Id, Encoding.Unicode.GetBytes(Convert.ToString(Value, NumberFormatInfo.InvariantInfo)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void HandleNetData(byte[] data)
|
||||||
|
{
|
||||||
|
SetValue(Encoding.Unicode.GetString(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string GetValueFromOptionBehaviour(OptionBehaviour optionBehaviour)
|
||||||
|
{
|
||||||
|
return Values[optionBehaviour.GetInt()];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void OnValueChanged(string newValue)
|
||||||
|
{
|
||||||
|
HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(GetIndex(newValue, 5)), false);
|
||||||
|
if (!OptionBehaviour)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OptionBehaviour is StringOption opt)
|
||||||
|
{
|
||||||
|
opt.Value = GetIndex(newValue, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,8 @@ public class ModdedToggleOption : ModdedOption<bool>
|
|||||||
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
|
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
|
||||||
{
|
{
|
||||||
var toggleOption = Object.Instantiate(toggleOpt, Vector3.zero, Quaternion.identity, container);
|
var toggleOption = Object.Instantiate(toggleOpt, Vector3.zero, Quaternion.identity, container);
|
||||||
|
toggleOption.name =
|
||||||
|
$"{ParentMod!.OptionsTitleText}.ToggleOption.{TranslationController.Instance.GetString(StringName)}";
|
||||||
|
|
||||||
toggleOption.SetUpFromData(Data, 20);
|
toggleOption.SetUpFromData(Data, 20);
|
||||||
|
|
||||||
@@ -69,7 +71,13 @@ public class ModdedToggleOption : ModdedOption<bool>
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnValueChanged(bool newValue)
|
protected override void OnValueChanged(bool newValue)
|
||||||
{
|
{
|
||||||
HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, newValue ? "On" : "Off", false);
|
ModdedOptionsManager.AddSettingsChangeMessage(
|
||||||
|
HudManager.Instance.Notifier,
|
||||||
|
StringName,
|
||||||
|
newValue ? "On" : "Off",
|
||||||
|
Configuration.PopUpTextColor,
|
||||||
|
Configuration.PopUpIconTmp,
|
||||||
|
false);
|
||||||
if (!OptionBehaviour)
|
if (!OptionBehaviour)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -0,0 +1,285 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Linq;
|
||||||
|
using BepInEx.Unity.IL2CPP.Utils.Collections;
|
||||||
|
using MiraAPI.GameOptions;
|
||||||
|
using MiraAPI.HnsReimplemented.Options;
|
||||||
|
using MiraAPI.Utilities;
|
||||||
|
using Reactor.Utilities.Attributes;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace MiraAPI.HnsReimplemented;
|
||||||
|
|
||||||
|
[RegisterInIl2Cpp]
|
||||||
|
public sealed class HideAndSeekHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
|
||||||
|
{
|
||||||
|
public static HideAndSeekHudHelper Instance { get; private set; }
|
||||||
|
|
||||||
|
public AudioClip FinalHideAlertSfx;
|
||||||
|
|
||||||
|
public AudioClip FinalHideCountdownSfx;
|
||||||
|
|
||||||
|
private AudioClip TaskFinishedSound;
|
||||||
|
|
||||||
|
private const int SECONDS_TO_BEEP = 10;
|
||||||
|
|
||||||
|
private const float SECONDS_TO_SET_DIRTY = 1f;
|
||||||
|
|
||||||
|
private HideAndSeekTimerBar timerBar;
|
||||||
|
|
||||||
|
private float totalHideTime = float.MaxValue;
|
||||||
|
|
||||||
|
private float currentHideTime = float.MaxValue;
|
||||||
|
|
||||||
|
private float totalFinalHideTime = float.MaxValue;
|
||||||
|
|
||||||
|
private float currentFinalHideTime = float.MaxValue;
|
||||||
|
|
||||||
|
private float secondsSinceLastSetDirty;
|
||||||
|
private Coroutine beepCoroutine;
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
Instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsFinalCountdown
|
||||||
|
{
|
||||||
|
get { return currentHideTime <= 0f; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SeekerAdminMapEnabled(PlayerControl player)
|
||||||
|
{
|
||||||
|
int item = Helpers.GetAlivePlayers().Count(x => !x.Data.Role.IsImpostor);
|
||||||
|
return !player.inVent && player.Data != null && player.Data.Role != null &&
|
||||||
|
((!player.inVent && player.Data.Role.IsImpostor && IsFinalCountdown &&
|
||||||
|
OptionGroupSingleton<HnsFinalHideOptions>.Instance.FinalHideSeekMap.Value) ||
|
||||||
|
(player.Data.Role.IsImpostor &&
|
||||||
|
item <=
|
||||||
|
(GameData.Instance.PlayerCount - 1) / 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnTaskComplete(float timeDeduction)
|
||||||
|
{
|
||||||
|
if (timerBar != null)
|
||||||
|
{
|
||||||
|
timerBar.TaskComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
AdjustEscapeTimer(timeDeduction, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetTotalRoundTime()
|
||||||
|
{
|
||||||
|
float escapeTime = OptionGroupSingleton<HnsCrewmateOptions>.Instance.HidingTime.Value;
|
||||||
|
float finalCountdownTime = OptionGroupSingleton<HnsFinalHideOptions>.Instance.FinalHideTime.Value;
|
||||||
|
return escapeTime + finalCountdownTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetTotalTimeRemaining()
|
||||||
|
{
|
||||||
|
return currentHideTime + currentFinalHideTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetRoundTimeElapsed()
|
||||||
|
{
|
||||||
|
return GetTotalRoundTime() - GetTotalTimeRemaining();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
totalHideTime = OptionGroupSingleton<HnsCrewmateOptions>.Instance.HidingTime.Value;
|
||||||
|
currentHideTime = totalHideTime;
|
||||||
|
totalFinalHideTime = OptionGroupSingleton<HnsFinalHideOptions>.Instance.FinalHideTime.Value;
|
||||||
|
currentFinalHideTime = totalFinalHideTime;
|
||||||
|
if (timerBar != null)
|
||||||
|
{
|
||||||
|
Object.Destroy(timerBar);
|
||||||
|
}
|
||||||
|
|
||||||
|
FinalHideAlertSfx = GameManagerCreator.Instance.HideAndSeekManagerPrefab.FinalHideAlertSFX;
|
||||||
|
FinalHideCountdownSfx = GameManagerCreator.Instance.HideAndSeekManagerPrefab.FinalHideCountdownSFX;
|
||||||
|
TaskFinishedSound = GameManagerCreator.Instance.HideAndSeekManagerPrefab.TaskFinishedSound;
|
||||||
|
timerBar = Object.Instantiate<HideAndSeekTimerBar>(
|
||||||
|
GameManagerCreator.Instance.HideAndSeekManagerPrefab.TimerBarPrefab,
|
||||||
|
HudManager.Instance.transform.parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnGameEnd()
|
||||||
|
{
|
||||||
|
if (timerBar != null)
|
||||||
|
{
|
||||||
|
Object.Destroy(timerBar.gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (beepCoroutine != null)
|
||||||
|
{
|
||||||
|
StopCoroutine(beepCoroutine);
|
||||||
|
}
|
||||||
|
|
||||||
|
beepCoroutine = null!;
|
||||||
|
}
|
||||||
|
private float taskDirtyTimer;
|
||||||
|
public float HideCountdown { get; set; }
|
||||||
|
|
||||||
|
public void LateUpdate()
|
||||||
|
{
|
||||||
|
if (!HudManager.InstanceExists)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (HideCountdown > 0f && taskDirtyTimer > 0.25f)
|
||||||
|
{
|
||||||
|
float num = taskDirtyTimer;
|
||||||
|
taskDirtyTimer = 0f;
|
||||||
|
if (!PlayerControl.LocalPlayer)
|
||||||
|
{
|
||||||
|
HudManager.Instance.TaskPanel.SetTaskText(string.Empty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NetworkedPlayerInfo data = PlayerControl.LocalPlayer.Data;
|
||||||
|
if (data == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool flag = data.Role != null && data.Role.IsImpostor;
|
||||||
|
HudManager.Instance.tasksString.Clear();
|
||||||
|
if (PlayerControl.LocalPlayer.myTasks == null || PlayerControl.LocalPlayer.myTasks.Count == 0)
|
||||||
|
{
|
||||||
|
HudManager.Instance.tasksString.Append("None");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < PlayerControl.LocalPlayer.myTasks.Count; i++)
|
||||||
|
{
|
||||||
|
PlayerTask playerTask = PlayerControl.LocalPlayer.myTasks[i];
|
||||||
|
if (playerTask)
|
||||||
|
{
|
||||||
|
if (playerTask.TaskType == TaskTypes.FixComms && !flag)
|
||||||
|
{
|
||||||
|
HudManager.Instance.tasksString.Clear();
|
||||||
|
playerTask.AppendTaskText(HudManager.Instance.tasksString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
playerTask.AppendTaskText(HudManager.Instance.tasksString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data.Role != null)
|
||||||
|
{
|
||||||
|
data.Role.AppendTaskHint(HudManager.Instance.tasksString);
|
||||||
|
}
|
||||||
|
if (HideCountdown > 0f)
|
||||||
|
{
|
||||||
|
HideCountdown -= num;
|
||||||
|
HudManager.Instance.tasksString.Append("\n\n" + ((int)HideCountdown));
|
||||||
|
}
|
||||||
|
HudManager.Instance.tasksString.TrimEnd();
|
||||||
|
}
|
||||||
|
HudManager.Instance.TaskPanel.SetTaskText(HudManager.Instance.tasksString.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void FixedUpdate()
|
||||||
|
{
|
||||||
|
secondsSinceLastSetDirty += Time.fixedDeltaTime;
|
||||||
|
if (IsFinalCountdown)
|
||||||
|
{
|
||||||
|
AdjustFinalEscapeTimer(Time.fixedDeltaTime);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AdjustEscapeTimer(Time.fixedDeltaTime, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnDestroy()
|
||||||
|
{
|
||||||
|
if (timerBar != null)
|
||||||
|
{
|
||||||
|
Object.Destroy(timerBar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFinalCountdownTriggered()
|
||||||
|
{
|
||||||
|
foreach (PlayerControl playerControl in PlayerControl.AllPlayerControls)
|
||||||
|
{
|
||||||
|
if (!playerControl.Data.Role.IsImpostor && !playerControl.Data.IsDead)
|
||||||
|
{
|
||||||
|
playerControl.ClearTasks();
|
||||||
|
PlayerTask.GetOrCreateTask<ImportantTextTask>(playerControl, 0).Text =
|
||||||
|
DestroyableSingleton<TranslationController>.Instance.GetString(StringNames.HideActionButton);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PlayerControl.LocalPlayer.Data.IsDead && Minigame.Instance != null)
|
||||||
|
{
|
||||||
|
Minigame instance = Minigame.Instance;
|
||||||
|
if (instance != null)
|
||||||
|
{
|
||||||
|
instance.ForceClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
timerBar.StartFinalHide();
|
||||||
|
SoundManager.Instance.PlaySound(FinalHideAlertSfx, false, 1f, null);
|
||||||
|
DestroyableSingleton<HudManager>.Instance.SetAlertOverlay(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AdjustEscapeTimer(float timeDeduction, bool forceDirty)
|
||||||
|
{
|
||||||
|
float num = currentHideTime;
|
||||||
|
currentHideTime -= timeDeduction;
|
||||||
|
currentHideTime = Mathf.Max(currentHideTime, 0f);
|
||||||
|
if (currentHideTime <= 10f && beepCoroutine == null)
|
||||||
|
{
|
||||||
|
beepCoroutine = StartCoroutine(BeepAlmostEverySecond().WrapToIl2Cpp());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num > 0f && currentHideTime <= 0f)
|
||||||
|
{
|
||||||
|
OnFinalCountdownTriggered();
|
||||||
|
}
|
||||||
|
|
||||||
|
timerBar.UpdateTimer(currentHideTime, totalHideTime);
|
||||||
|
if (forceDirty || secondsSinceLastSetDirty > 1f)
|
||||||
|
{
|
||||||
|
secondsSinceLastSetDirty = 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator BeepAlmostEverySecond()
|
||||||
|
{
|
||||||
|
while (!IsFinalCountdown)
|
||||||
|
{
|
||||||
|
float num = currentHideTime / 10f;
|
||||||
|
float pitch = 1.5f - num / 2f;
|
||||||
|
SoundManager.Instance.PlaySoundImmediate(FinalHideCountdownSfx, false, 1f, pitch, null);
|
||||||
|
yield return new WaitForSeconds(1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return Effects.Wait(currentFinalHideTime - 10f);
|
||||||
|
while (currentFinalHideTime > 0f)
|
||||||
|
{
|
||||||
|
float num2 = currentFinalHideTime / 10f;
|
||||||
|
float pitch2 = 1.5f - num2 / 2f;
|
||||||
|
SoundManager.Instance.PlaySoundImmediate(FinalHideCountdownSfx, false, 1f, pitch2, null);
|
||||||
|
yield return new WaitForSeconds(1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AdjustFinalEscapeTimer(float timeDeduction)
|
||||||
|
{
|
||||||
|
currentFinalHideTime -= timeDeduction;
|
||||||
|
currentFinalHideTime = Mathf.Max(currentFinalHideTime, 0f);
|
||||||
|
timerBar.UpdateTimer(currentFinalHideTime, totalFinalHideTime);
|
||||||
|
if (secondsSinceLastSetDirty > 1f)
|
||||||
|
{
|
||||||
|
secondsSinceLastSetDirty = 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AllTimersExpired()
|
||||||
|
{
|
||||||
|
return currentHideTime <= 0f && currentFinalHideTime <= 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using MiraAPI.GameOptions;
|
||||||
|
using MiraAPI.HnsReimplemented.Options;
|
||||||
|
using MiraAPI.Utilities;
|
||||||
|
using Reactor.Utilities.Attributes;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace MiraAPI.HnsReimplemented;
|
||||||
|
|
||||||
|
[RegisterInIl2Cpp]
|
||||||
|
public sealed class HnsDangerMeter(nint cppPtr) : MonoBehaviour(cppPtr)
|
||||||
|
{
|
||||||
|
public static HnsDangerMeter Instance;
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
Instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DangerMeter dangerMeter;
|
||||||
|
|
||||||
|
private List<PlayerControl> impostors = [];
|
||||||
|
|
||||||
|
private float scaryMusicDistance;
|
||||||
|
|
||||||
|
private float veryScaryMusicDistance;
|
||||||
|
|
||||||
|
private float dangerLevel1;
|
||||||
|
|
||||||
|
private float dangerLevel2;
|
||||||
|
|
||||||
|
private bool firstMusicActivation;
|
||||||
|
|
||||||
|
private float firstCrossfadeCountdown;
|
||||||
|
|
||||||
|
public void FixedUpdate()
|
||||||
|
{
|
||||||
|
PlayerControl localPlayer = PlayerControl.LocalPlayer;
|
||||||
|
if (impostors == null || localPlayer == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (impostors.Count <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float num = float.MaxValue;
|
||||||
|
foreach (PlayerControl playerControl in impostors)
|
||||||
|
{
|
||||||
|
if (!(playerControl == null))
|
||||||
|
{
|
||||||
|
float sqrMagnitude = (playerControl.transform.position - localPlayer.transform.position).sqrMagnitude;
|
||||||
|
if (sqrMagnitude < scaryMusicDistance && num > sqrMagnitude)
|
||||||
|
{
|
||||||
|
num = sqrMagnitude;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HideAndSeekHudHelper.Instance.HideCountdown > 0f)
|
||||||
|
{
|
||||||
|
dangerLevel1 = 0f;
|
||||||
|
dangerLevel2 = 0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (firstMusicActivation)
|
||||||
|
{
|
||||||
|
firstMusicActivation = false;
|
||||||
|
firstCrossfadeCountdown = 3f;
|
||||||
|
HnsMusicHandler.Instance.SetMusicCrossfadeSpeed(0.6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstCrossfadeCountdown > 0f)
|
||||||
|
{
|
||||||
|
firstCrossfadeCountdown -= Time.deltaTime;
|
||||||
|
if (firstCrossfadeCountdown <= 0f)
|
||||||
|
{
|
||||||
|
HnsMusicHandler.Instance.SetMusicCrossfadeSpeed(5f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dangerLevel1 = Mathf.Clamp01(
|
||||||
|
(scaryMusicDistance - num) / (scaryMusicDistance - veryScaryMusicDistance));
|
||||||
|
dangerLevel2 = Mathf.Clamp01((veryScaryMusicDistance - num) / veryScaryMusicDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateDangerMeter();
|
||||||
|
UpdateDangerMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateDangerMusic()
|
||||||
|
{
|
||||||
|
PlayerControl localPlayer = PlayerControl.LocalPlayer;
|
||||||
|
if (localPlayer != null && localPlayer.Data != null && localPlayer.Data.IsDead)
|
||||||
|
{
|
||||||
|
HnsMusicHandler.Instance.SetTaskState(false);
|
||||||
|
HnsMusicHandler.Instance.ResetMusic();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HnsMusicHandler.Instance.SetMusicValues(dangerLevel1, dangerLevel2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateDangerMeter()
|
||||||
|
{
|
||||||
|
if (dangerMeter == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dangerMeter.SetDangerValue(dangerLevel1, dangerLevel2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnGameStart()
|
||||||
|
{
|
||||||
|
firstMusicActivation = true;
|
||||||
|
if (!PlayerControl.LocalPlayer.Data.Role.IsImpostor)
|
||||||
|
{
|
||||||
|
dangerMeter = HudManager.Instance.DangerMeter;
|
||||||
|
dangerMeter.gameObject.SetActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
impostors = Helpers.GetAlivePlayers().Where(x => x.Data.Role.IsImpostor).ToList();
|
||||||
|
|
||||||
|
var baseSpeed = OptionGroupSingleton<HnsCrewmateOptions>.Instance.PlayerSpeed.Value;
|
||||||
|
scaryMusicDistance = 55f *
|
||||||
|
baseSpeed;
|
||||||
|
veryScaryMusicDistance = 15f *
|
||||||
|
baseSpeed;
|
||||||
|
if (scaryMusicDistance < veryScaryMusicDistance)
|
||||||
|
{
|
||||||
|
float num = veryScaryMusicDistance;
|
||||||
|
float num2 = scaryMusicDistance;
|
||||||
|
scaryMusicDistance = num;
|
||||||
|
veryScaryMusicDistance = num2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,237 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Amongus.GameModes.HideAndSeek;
|
||||||
|
using MiraAPI.GameOptions;
|
||||||
|
using MiraAPI.HnsReimplemented.Options;
|
||||||
|
using Reactor.Utilities.Attributes;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace MiraAPI.HnsReimplemented;
|
||||||
|
|
||||||
|
[RegisterInIl2Cpp]
|
||||||
|
public sealed class HnsMusicHandler(nint cppPtr) : MonoBehaviour(cppPtr)
|
||||||
|
{
|
||||||
|
public static HnsMusicHandler Instance;
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
Instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HideAndSeekMusicCollection musicCollection;
|
||||||
|
|
||||||
|
private float lastMusicSyncTime;
|
||||||
|
|
||||||
|
private bool isDoingTask;
|
||||||
|
|
||||||
|
private float normalVolume;
|
||||||
|
|
||||||
|
private float taskVolume;
|
||||||
|
|
||||||
|
private float dangerLevel1Volume;
|
||||||
|
|
||||||
|
private float dangerLevel2Volume;
|
||||||
|
|
||||||
|
private AudioSource normalSource;
|
||||||
|
|
||||||
|
private AudioSource taskSource;
|
||||||
|
|
||||||
|
private AudioSource dangerLevel1Source;
|
||||||
|
|
||||||
|
private AudioSource dangerLevel2Source;
|
||||||
|
|
||||||
|
private float musicLerpSpeed = 5f;
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
musicCollection = GameManagerCreator.Instance.HideAndSeekManagerPrefab.MusicCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnGameStart()
|
||||||
|
{
|
||||||
|
InitMusic();
|
||||||
|
ResetMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnDestroy()
|
||||||
|
{
|
||||||
|
ResetMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitMusic()
|
||||||
|
{
|
||||||
|
if (normalSource == null)
|
||||||
|
{
|
||||||
|
normalSource =
|
||||||
|
SoundManager.Instance.GetNamedSfxSource(musicNames[LogicHnSMusic.HideAndSeekMusicTrack.Normal]);
|
||||||
|
}
|
||||||
|
|
||||||
|
normalSource.outputAudioMixerGroup = SoundManager.Instance.MusicChannel;
|
||||||
|
normalSource.clip = musicCollection.NormalMusic;
|
||||||
|
normalSource.loop = true;
|
||||||
|
if (taskSource == null)
|
||||||
|
{
|
||||||
|
taskSource =
|
||||||
|
SoundManager.Instance.GetNamedSfxSource(musicNames[LogicHnSMusic.HideAndSeekMusicTrack.Task]);
|
||||||
|
}
|
||||||
|
|
||||||
|
taskSource.outputAudioMixerGroup = SoundManager.Instance.MusicChannel;
|
||||||
|
taskSource.volume = 0f;
|
||||||
|
taskSource.clip = musicCollection.TaskMusic;
|
||||||
|
taskSource.loop = true;
|
||||||
|
if (dangerLevel1Source == null)
|
||||||
|
{
|
||||||
|
dangerLevel1Source =
|
||||||
|
SoundManager.Instance.GetNamedSfxSource(
|
||||||
|
musicNames[LogicHnSMusic.HideAndSeekMusicTrack.DangerLevel1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
dangerLevel1Source.outputAudioMixerGroup = SoundManager.Instance.MusicChannel;
|
||||||
|
dangerLevel1Source.volume = 0f;
|
||||||
|
dangerLevel1Source.clip = musicCollection.DangerLevel1Music;
|
||||||
|
dangerLevel1Source.loop = true;
|
||||||
|
if (dangerLevel2Source == null)
|
||||||
|
{
|
||||||
|
dangerLevel2Source =
|
||||||
|
SoundManager.Instance.GetNamedSfxSource(
|
||||||
|
musicNames[LogicHnSMusic.HideAndSeekMusicTrack.DangerLevel2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
dangerLevel2Source.outputAudioMixerGroup = SoundManager.Instance.MusicChannel;
|
||||||
|
dangerLevel2Source.volume = 0f;
|
||||||
|
dangerLevel2Source.clip = musicCollection.DangerLevel2Music;
|
||||||
|
dangerLevel2Source.loop = true;
|
||||||
|
normalSource.Play();
|
||||||
|
taskSource.Play();
|
||||||
|
dangerLevel1Source.Play();
|
||||||
|
dangerLevel2Source.Play();
|
||||||
|
SyncMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartMusicWithIntro()
|
||||||
|
{
|
||||||
|
if (PlayerControl.LocalPlayer.Data.Role.IsImpostor)
|
||||||
|
{
|
||||||
|
AudioClip clip = OptionGroupSingleton<HnsCrewmateOptions>.Instance.HidingTime.Value <= 180f
|
||||||
|
? musicCollection.ImpostorShortMusic
|
||||||
|
: musicCollection.ImpostorLongMusic;
|
||||||
|
if (AprilFoolsMode.ShouldHorseAround())
|
||||||
|
{
|
||||||
|
clip = musicCollection.ImpostorRanchMusic;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundManager.Instance.PlaySound(clip, true, 1f, SoundManager.Instance.MusicChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTaskState(bool isDoingTask)
|
||||||
|
{
|
||||||
|
isDoingTask = isDoingTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FixedUpdate()
|
||||||
|
{
|
||||||
|
if (normalSource == null || taskSource == null || dangerLevel1Source == null ||
|
||||||
|
dangerLevel2Source == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Time.unscaledTime > lastMusicSyncTime + 1f)
|
||||||
|
{
|
||||||
|
SyncMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
normalSource.volume = Mathf.Lerp(
|
||||||
|
normalSource.volume,
|
||||||
|
normalVolume,
|
||||||
|
Time.fixedDeltaTime * musicLerpSpeed);
|
||||||
|
taskSource.volume = Mathf.Lerp(
|
||||||
|
taskSource.volume,
|
||||||
|
taskVolume,
|
||||||
|
Time.fixedDeltaTime * musicLerpSpeed);
|
||||||
|
dangerLevel1Source.volume = Mathf.Lerp(
|
||||||
|
dangerLevel1Source.volume,
|
||||||
|
dangerLevel1Volume,
|
||||||
|
Time.fixedDeltaTime * musicLerpSpeed);
|
||||||
|
dangerLevel2Source.volume = Mathf.Lerp(
|
||||||
|
dangerLevel2Source.volume,
|
||||||
|
dangerLevel2Volume,
|
||||||
|
Time.fixedDeltaTime * musicLerpSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SyncMusic()
|
||||||
|
{
|
||||||
|
taskSource.timeSamples = normalSource.timeSamples;
|
||||||
|
dangerLevel1Source.timeSamples = normalSource.timeSamples;
|
||||||
|
dangerLevel2Source.timeSamples = normalSource.timeSamples;
|
||||||
|
lastMusicSyncTime = Time.unscaledTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetMusic()
|
||||||
|
{
|
||||||
|
SetMusicValues(0f, 0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetMusicCrossfadeSpeed(float lerpSpeed)
|
||||||
|
{
|
||||||
|
musicLerpSpeed = lerpSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetMusicValues(float dangerLevel1, float dangerLevel2)
|
||||||
|
{
|
||||||
|
if (PlayerControl.LocalPlayer != null && PlayerControl.LocalPlayer.Data.Role.IsImpostor)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalSource == null || taskSource == null || dangerLevel1Source == null ||
|
||||||
|
dangerLevel2Source == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
normalVolume = (isDoingTask ? 0f : 1f);
|
||||||
|
taskVolume = (isDoingTask ? 1f : 0f);
|
||||||
|
dangerLevel1Volume = 0f;
|
||||||
|
dangerLevel2Volume = 0f;
|
||||||
|
if (dangerLevel1 > 0f)
|
||||||
|
{
|
||||||
|
dangerLevel1Volume = dangerLevel1;
|
||||||
|
if (isDoingTask)
|
||||||
|
{
|
||||||
|
taskVolume = 1f - dangerLevel1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
normalVolume = 1f - dangerLevel1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dangerLevel2 > 0f)
|
||||||
|
{
|
||||||
|
dangerLevel2Volume = dangerLevel2;
|
||||||
|
dangerLevel1Volume = 1f - dangerLevel2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<LogicHnSMusic.HideAndSeekMusicTrack, string> musicNames =
|
||||||
|
new Dictionary<LogicHnSMusic.HideAndSeekMusicTrack, string>
|
||||||
|
{
|
||||||
|
{
|
||||||
|
LogicHnSMusic.HideAndSeekMusicTrack.Normal,
|
||||||
|
"HnS_Music_Normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
LogicHnSMusic.HideAndSeekMusicTrack.Task,
|
||||||
|
"HnS_Music_Task"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
LogicHnSMusic.HideAndSeekMusicTrack.DangerLevel1,
|
||||||
|
"HnS_Music_DangerLevel1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
LogicHnSMusic.HideAndSeekMusicTrack.DangerLevel2,
|
||||||
|
"HnS_Music_DangerLevel2"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
using MiraAPI.GameModes;
|
||||||
|
using MiraAPI.GameOptions;
|
||||||
|
using MiraAPI.GameOptions.OptionTypes;
|
||||||
|
using MiraAPI.Utilities;
|
||||||
|
|
||||||
|
namespace MiraAPI.HnsReimplemented.Options;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public class HnsCrewmateOptions : AbstractOptionGroup<HideAndSeekMode>
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string GroupName => "Crewmates";
|
||||||
|
|
||||||
|
public ModdedNumberOption PlayerSpeed { get; set; } = new(
|
||||||
|
"Player Speed",
|
||||||
|
1f,
|
||||||
|
0.5f,
|
||||||
|
3f,
|
||||||
|
0.25f,
|
||||||
|
"#",
|
||||||
|
"#",
|
||||||
|
MiraNumberSuffixes.Multiplier,
|
||||||
|
"0.00");
|
||||||
|
|
||||||
|
public ModdedNumberOption HidingTime { get; set; } = new(
|
||||||
|
"Hiding Time",
|
||||||
|
200,
|
||||||
|
160,
|
||||||
|
300,
|
||||||
|
20,
|
||||||
|
"#",
|
||||||
|
"#",
|
||||||
|
MiraNumberSuffixes.Seconds);
|
||||||
|
|
||||||
|
public ModdedNumberOption CrewmateVision { get; set; } = new(
|
||||||
|
"Crewmate Vision",
|
||||||
|
0.6f,
|
||||||
|
0.25f,
|
||||||
|
1,
|
||||||
|
0.05f,
|
||||||
|
"#",
|
||||||
|
"#",
|
||||||
|
MiraNumberSuffixes.Multiplier,
|
||||||
|
"0.00");
|
||||||
|
|
||||||
|
public ModdedNumberOption MaxVentUses { get; set; } = new(
|
||||||
|
"Max Vent Uses",
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
5,
|
||||||
|
1,
|
||||||
|
"#",
|
||||||
|
"#",
|
||||||
|
MiraNumberSuffixes.None);
|
||||||
|
|
||||||
|
public ModdedNumberOption MaxTimeInVent { get; set; } = new(
|
||||||
|
"Max Time in Vent",
|
||||||
|
3,
|
||||||
|
1,
|
||||||
|
10,
|
||||||
|
1,
|
||||||
|
"#",
|
||||||
|
"#",
|
||||||
|
MiraNumberSuffixes.Seconds)
|
||||||
|
{
|
||||||
|
Visible = () => (int)OptionGroupSingleton<HnsCrewmateOptions>.Instance.MaxVentUses.Value > 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
public ModdedToggleOption FlashlightMode { get; set; } = new(
|
||||||
|
"Flashlight Mode",
|
||||||
|
true);
|
||||||
|
|
||||||
|
public ModdedNumberOption CrewmateFlashlightSize { get; set; } = new(
|
||||||
|
"Crewmate Flashlight Size",
|
||||||
|
0.35f,
|
||||||
|
0.1f,
|
||||||
|
0.5f,
|
||||||
|
0.05f,
|
||||||
|
"#",
|
||||||
|
"#",
|
||||||
|
MiraNumberSuffixes.Multiplier)
|
||||||
|
{
|
||||||
|
Visible = () => OptionGroupSingleton<HnsCrewmateOptions>.Instance.FlashlightMode.Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
public ModdedToggleOption ShowNames { get; set; } = new(
|
||||||
|
"Show Names",
|
||||||
|
false);
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
using MiraAPI.GameModes;
|
||||||
|
using MiraAPI.GameOptions;
|
||||||
|
using MiraAPI.GameOptions.OptionTypes;
|
||||||
|
using MiraAPI.Utilities;
|
||||||
|
|
||||||
|
namespace MiraAPI.HnsReimplemented.Options;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public class HnsFinalHideOptions : AbstractOptionGroup<HideAndSeekMode>
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string GroupName => "Final Hide";
|
||||||
|
|
||||||
|
public ModdedNumberOption FinalHideTime { get; set; } = new(
|
||||||
|
"Hiding Time",
|
||||||
|
50,
|
||||||
|
30,
|
||||||
|
120,
|
||||||
|
5,
|
||||||
|
"#",
|
||||||
|
"#",
|
||||||
|
MiraNumberSuffixes.Seconds);
|
||||||
|
|
||||||
|
public ModdedToggleOption FinalHidePings { get; set; } = new(
|
||||||
|
"Final Hide Pings",
|
||||||
|
true);
|
||||||
|
|
||||||
|
public ModdedNumberOption FinalHideImpostorSpeed { get; set; } = new(
|
||||||
|
"Final Hide Impostor Speed",
|
||||||
|
1.2f,
|
||||||
|
1f,
|
||||||
|
3,
|
||||||
|
0.05f,
|
||||||
|
"#",
|
||||||
|
"#",
|
||||||
|
MiraNumberSuffixes.Multiplier,
|
||||||
|
"0.00");
|
||||||
|
|
||||||
|
public ModdedNumberOption PingInterval { get; set; } = new(
|
||||||
|
"Ping Interval",
|
||||||
|
6,
|
||||||
|
3,
|
||||||
|
10,
|
||||||
|
5,
|
||||||
|
"#",
|
||||||
|
"#",
|
||||||
|
MiraNumberSuffixes.Seconds);
|
||||||
|
|
||||||
|
public ModdedToggleOption FinalHideSeekMap { get; set; } = new(
|
||||||
|
"Final Hide Seek Map",
|
||||||
|
true);
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using MiraAPI.GameModes;
|
||||||
|
using MiraAPI.GameOptions;
|
||||||
|
using MiraAPI.GameOptions.OptionTypes;
|
||||||
|
using MiraAPI.Utilities;
|
||||||
|
|
||||||
|
namespace MiraAPI.HnsReimplemented.Options;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public class HnsImpostorOptions : AbstractOptionGroup<HideAndSeekMode>
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string GroupName => "Impostors";
|
||||||
|
|
||||||
|
public ModdedPlayerOption SelectedSeeker { get; set; } = new(
|
||||||
|
"Forced Impostor");
|
||||||
|
|
||||||
|
public ModdedNumberOption ImpostorVision { get; set; } = new(
|
||||||
|
"Impostor Vision",
|
||||||
|
0.6f,
|
||||||
|
0.25f,
|
||||||
|
1,
|
||||||
|
0.05f,
|
||||||
|
"#",
|
||||||
|
"#",
|
||||||
|
MiraNumberSuffixes.Multiplier,
|
||||||
|
"0.00");
|
||||||
|
|
||||||
|
public ModdedNumberOption ImpostorFlashlightSize { get; set; } = new(
|
||||||
|
"Impostor Flashlight Size",
|
||||||
|
0.35f,
|
||||||
|
0.1f,
|
||||||
|
0.5f,
|
||||||
|
0.05f,
|
||||||
|
"#",
|
||||||
|
"#",
|
||||||
|
MiraNumberSuffixes.Multiplier)
|
||||||
|
{
|
||||||
|
Visible = () => OptionGroupSingleton<HnsCrewmateOptions>.Instance.FlashlightMode.Value,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
using MiraAPI.GameModes;
|
||||||
|
using MiraAPI.GameOptions;
|
||||||
|
using MiraAPI.GameOptions.OptionTypes;
|
||||||
|
using MiraAPI.Utilities;
|
||||||
|
|
||||||
|
namespace MiraAPI.HnsReimplemented.Options;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public class HnsTaskOptions : AbstractOptionGroup<HideAndSeekMode>
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string GroupName => "Tasks";
|
||||||
|
|
||||||
|
public ModdedNumberOption CommonTasks { get; set; } = new(
|
||||||
|
"# Common Tasks",
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
4,
|
||||||
|
1,
|
||||||
|
"#",
|
||||||
|
"#",
|
||||||
|
MiraNumberSuffixes.None);
|
||||||
|
|
||||||
|
public ModdedNumberOption LongTasks { get; set; } = new(
|
||||||
|
"# Long Tasks",
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
4,
|
||||||
|
1,
|
||||||
|
"#",
|
||||||
|
"#",
|
||||||
|
MiraNumberSuffixes.None);
|
||||||
|
|
||||||
|
public ModdedNumberOption ShortTasks { get; set; } = new(
|
||||||
|
"# Short Tasks",
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
8,
|
||||||
|
1,
|
||||||
|
"#",
|
||||||
|
"#",
|
||||||
|
MiraNumberSuffixes.None);
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace MiraAPI.Hud;
|
namespace MiraAPI.Hud;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The location of the custom button on the screen.
|
/// The location of the <see cref="CustomActionButton"/> on the screen.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum ButtonLocation
|
public enum ButtonLocation
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace MiraAPI.Hud;
|
namespace MiraAPI.Hud;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The uses mode for custom buttons.
|
/// The uses mode for <see cref="CustomActionButton"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum ButtonUsesMode
|
public enum ButtonUsesMode
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using MiraAPI.LocalSettings;
|
|||||||
using MiraAPI.Patches;
|
using MiraAPI.Patches;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
using Reactor.Utilities;
|
|
||||||
using Rewired;
|
using Rewired;
|
||||||
using TMPro;
|
using TMPro;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -18,7 +17,7 @@ using Object = UnityEngine.Object;
|
|||||||
namespace MiraAPI.Hud;
|
namespace MiraAPI.Hud;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class for making custom action buttons. More customizable than the default Action/Ability buttons in the base game.
|
/// Class for making custom action buttons. More customizable than the default <see cref="ActionButton"/>/<see cref="AbilityButton"/>s in the base game.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class CustomActionButton
|
public abstract class CustomActionButton
|
||||||
{
|
{
|
||||||
@@ -54,7 +53,7 @@ public abstract class CustomActionButton
|
|||||||
public virtual string CooldownTimerFormatString => "0";
|
public virtual string CooldownTimerFormatString => "0";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the button has an effect ability. By default true if <see cref="EffectDuration"/> is greater than 0.
|
/// Gets a value indicating whether the button has an effect ability. By default <see langword="true"/> if <see cref="EffectDuration"/> is greater than 0.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool HasEffect => EffectDuration > 0;
|
public virtual bool HasEffect => EffectDuration > 0;
|
||||||
|
|
||||||
@@ -64,9 +63,14 @@ public abstract class CustomActionButton
|
|||||||
public virtual float EffectDuration => 0;
|
public virtual float EffectDuration => 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the maximum amount of uses the button has. If the button has infinite uses, set to 0.
|
/// Gets a value indicating whether the button has limited uses.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual int MaxUses => 0;
|
public bool LimitedUses => ZeroIsInfinite ? MaxUses > 0 : MaxUses >= 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the maximum number of uses the button has. If the button has infinite uses, set to 0 or -1 based on what value that ZeroIsInfinite is set to.
|
||||||
|
/// </summary>
|
||||||
|
public virtual int MaxUses => ZeroIsInfinite ? 0 : -1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the value indicating uses mode.
|
/// Gets the value indicating uses mode.
|
||||||
@@ -74,24 +78,24 @@ public abstract class CustomActionButton
|
|||||||
public virtual ButtonUsesMode UsesMode => ButtonUsesMode.PerGame;
|
public virtual ButtonUsesMode UsesMode => ButtonUsesMode.PerGame;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the keybind for this button. If null, no keybind will be added.
|
/// Gets the keybind for this button. If <see langword="null"/>, no keybind will be added.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual BaseKeybind? Keybind => null;
|
public virtual BaseKeybind? Keybind => null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the button's text outline color.
|
/// Gets the button's text outline <see cref="Color"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Color TextOutlineColor => Color.clear;
|
public virtual Color TextOutlineColor => Color.clear;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the location of the button on the screen.
|
/// Gets or sets the <see cref="ButtonLocation"/> on the screen.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual ButtonLocation Location { get; set; } = ButtonLocation.BottomLeft;
|
public virtual ButtonLocation Location { get; set; } = ButtonLocation.BottomLeft;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the button has limited uses.
|
/// Gets or sets a value indicating whether limited uses are determined via zero or a negative number of uses.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool LimitedUses => MaxUses > 0;
|
public virtual bool ZeroIsInfinite { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether the effect is currently active, if there is one.
|
/// Gets or sets a value indicating whether the effect is currently active, if there is one.
|
||||||
@@ -114,12 +118,12 @@ public abstract class CustomActionButton
|
|||||||
public float Timer { get; set; }
|
public float Timer { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the button object in game. This is created by Mira API automatically.
|
/// Gets or sets the <see cref="ActionButton"/> object in game. This is created by Mira API automatically.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ActionButton? Button { get; set; }
|
public ActionButton? Button { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the gameObject used for the keybind icon.
|
/// Gets the <see cref="GameObject"/> used for the keybind icon.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GameObject? KeybindIcon { get; private set; }
|
public GameObject? KeybindIcon { get; private set; }
|
||||||
|
|
||||||
@@ -206,7 +210,39 @@ public abstract class CustomActionButton
|
|||||||
{
|
{
|
||||||
if (Enabled(PlayerControl.LocalPlayer.Data.Role))
|
if (Enabled(PlayerControl.LocalPlayer.Data.Role))
|
||||||
{
|
{
|
||||||
ClickHandler();
|
// Invoke the generic button click event.
|
||||||
|
var genericEvent = new MiraButtonClickEvent(this);
|
||||||
|
MiraEventManager.InvokeEvent(genericEvent);
|
||||||
|
if (genericEvent.IsCancelled)
|
||||||
|
{
|
||||||
|
MiraEventManager.InvokeEvent(new MiraButtonCancelledEvent(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoke the button click event for specific button.
|
||||||
|
var eventType = CustomButtonManager.ButtonEventTypes[GetType()];
|
||||||
|
var @event = (MiraCancelableEvent)Activator.CreateInstance(eventType, this, genericEvent)!;
|
||||||
|
var specificInvoked = MiraEventManager.InvokeEvent(@event, eventType);
|
||||||
|
if (@event.IsCancelled)
|
||||||
|
{
|
||||||
|
var cancelEventType = CustomButtonManager.ButtonCancelledEventTypes[GetType()];
|
||||||
|
var cancelEvent = (MiraEvent)Activator.CreateInstance(cancelEventType, this)!;
|
||||||
|
MiraEventManager.InvokeEvent(cancelEvent, cancelEventType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (specificInvoked)
|
||||||
|
{
|
||||||
|
if (!@event.IsCancelled)
|
||||||
|
{
|
||||||
|
ClickHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!genericEvent.IsCancelled)
|
||||||
|
{
|
||||||
|
ClickHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -214,9 +250,10 @@ public abstract class CustomActionButton
|
|||||||
Helpers.CreateKeybindIcon(
|
Helpers.CreateKeybindIcon(
|
||||||
Button.gameObject,
|
Button.gameObject,
|
||||||
Keybind.CurrentKey,
|
Keybind.CurrentKey,
|
||||||
new Vector3(MaxUses <= 0 ? -0.4f : 0.4f, 0.45f, -9f)
|
new Vector3(0.4f, 0.45f, -9f)
|
||||||
);
|
);
|
||||||
KeybindText = KeybindIcon.transform.GetChild(0).GetComponent<TextMeshPro>();
|
KeybindText = KeybindIcon.transform.GetChild(0).GetComponent<TextMeshPro>();
|
||||||
|
HudManagerPatches.ModdedKeybindIcons.Add(KeybindText);
|
||||||
Button.usesRemainingSprite.transform.localPosition = new(-0.341f, 0.45f, -0.1f);
|
Button.usesRemainingSprite.transform.localPosition = new(-0.341f, 0.45f, -0.1f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,7 +270,7 @@ public abstract class CustomActionButton
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Location = location;
|
Location = location;
|
||||||
|
|
||||||
if (!moveButton)
|
if (!moveButton)
|
||||||
{
|
{
|
||||||
@@ -278,18 +315,18 @@ public abstract class CustomActionButton
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A utility function to change the outline color of the button's text.
|
/// A utility function to change the outline <see cref="Color"/> of the button's text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="color">The new color.</param>
|
/// <param name="color">The new <see cref="Color"/>.</param>
|
||||||
public virtual void SetTextOutline(Color color)
|
public virtual void SetTextOutline(Color color)
|
||||||
{
|
{
|
||||||
Button?.buttonLabelText.SetOutlineColor(color);
|
Button?.buttonLabelText.SetOutlineColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A utility function to override the sprite of the button.
|
/// A utility function to override the <see cref="UnityEngine.Sprite"/> of the button.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sprite">The new sprite to override with.</param>
|
/// <param name="sprite">The new <see cref="UnityEngine.Sprite"/> to override with.</param>
|
||||||
public virtual void OverrideSprite(Sprite sprite)
|
public virtual void OverrideSprite(Sprite sprite)
|
||||||
{
|
{
|
||||||
if (Button != null)
|
if (Button != null)
|
||||||
@@ -377,7 +414,7 @@ public abstract class CustomActionButton
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A utility function that runs with the local PlayerControl's FixedUpdate if the button is enabled.
|
/// A utility function that runs with the local player's <see cref="PlayerControl.FixedUpdate"/> if the button is enabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="playerControl">the local PlayerControl.</param>
|
/// <param name="playerControl">the local PlayerControl.</param>
|
||||||
protected virtual void FixedUpdate(PlayerControl playerControl)
|
protected virtual void FixedUpdate(PlayerControl playerControl)
|
||||||
@@ -391,10 +428,10 @@ public abstract class CustomActionButton
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This method determines if the button should be active or not.
|
/// This method determines if the button should be active or not.
|
||||||
/// True means the button is active, false means the button is disabled.
|
/// <see langword="true"/> means the button is active, <see langword="false"/> means the button is disabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="role">The role of the local player.</param>
|
/// <param name="role">The <see cref="RoleBehaviour"/> of the local player.</param>
|
||||||
/// <returns>True if the button is enabled, false otherwise.</returns>
|
/// <returns><see langword="true"/> if the button is enabled, <see langword="false"/> otherwise.</returns>
|
||||||
public abstract bool Enabled(RoleBehaviour? role);
|
public abstract bool Enabled(RoleBehaviour? role);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -407,7 +444,7 @@ public abstract class CustomActionButton
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a value indicating whether the effect can be ended early by the player.
|
/// Returns a value indicating whether the effect can be ended early by the player.
|
||||||
/// Always false by default.
|
/// Always <see langword="false"/> by default.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Can the effect be canceled.</returns>
|
/// <returns>Can the effect be canceled.</returns>
|
||||||
public virtual bool IsEffectCancellable() => false;
|
public virtual bool IsEffectCancellable() => false;
|
||||||
@@ -435,12 +472,12 @@ public abstract class CustomActionButton
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This method is called on the HudManager.SetHudActive method. It determines whether the button should be visible or not.
|
/// This method is called on the <see cref="HudManager.SetHudActive(PlayerControl, RoleBehaviour, bool)"/> method. It determines whether the button should be visible or not.
|
||||||
/// The default behavior is to show the button if the <paramref name="visible"/> parameter and the <see cref="Enabled"/> method return true.
|
/// The default behavior is to show the button if the <paramref name="visible"/> parameter and the <see cref="Enabled"/> method return <see langword="true"/>.
|
||||||
/// It can be overridden for custom behavior.
|
/// It can be overridden for custom behavior.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="visible">Passed in from HudManager.SetHudActive, should hud be active.</param>
|
/// <param name="visible">Passed in from <see cref="HudManager.SetHudActive(PlayerControl, RoleBehaviour, bool)"/>, should hud be active.</param>
|
||||||
/// <param name="role">Passed in from HudManager.SetHudActive, the current role of the player.</param>
|
/// <param name="role">Passed in from <see cref="HudManager.SetHudActive(PlayerControl, RoleBehaviour, bool)"/>, the current role of the player.</param>
|
||||||
public virtual void SetActive(bool visible, RoleBehaviour role)
|
public virtual void SetActive(bool visible, RoleBehaviour role)
|
||||||
{
|
{
|
||||||
Button?.ToggleVisible(visible && Enabled(role));
|
Button?.ToggleVisible(visible && Enabled(role));
|
||||||
@@ -484,7 +521,7 @@ public abstract class CustomActionButton
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This method is called on the PlayerControl.FixedUpdate method. It is a wrapper for the <see cref="FixedUpdate"/> method.
|
/// This method is called on the <see cref="PlayerControl.FixedUpdate"/> method. It is a wrapper for the <see cref="FixedUpdate"/> method.
|
||||||
/// By default, it handles the cooldown and effect timers, and sets the button to enabled or disabled.
|
/// By default, it handles the cooldown and effect timers, and sets the button to enabled or disabled.
|
||||||
/// It can be overridden for custom behavior.
|
/// It can be overridden for custom behavior.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -494,7 +531,7 @@ public abstract class CustomActionButton
|
|||||||
if (Keybind != null && KeybindText != null)
|
if (Keybind != null && KeybindText != null)
|
||||||
{
|
{
|
||||||
KeybindText.text = Keybind.CurrentKey.ToString();
|
KeybindText.text = Keybind.CurrentKey.ToString();
|
||||||
KeybindIcon?.SetActive(ActiveInputManager.currentControlType == ActiveInputManager.InputType.Keyboard &&
|
KeybindIcon?.SetActive(ActiveInputManager.currentControlType is ActiveInputManager.InputType.Keyboard &&
|
||||||
LocalSettingsTabSingleton<MiraApiSettings>.Instance.ShowKeybinds.Value &&
|
LocalSettingsTabSingleton<MiraApiSettings>.Instance.ShowKeybinds.Value &&
|
||||||
Keybind.CurrentKey != KeyboardKeyCode.None);
|
Keybind.CurrentKey != KeyboardKeyCode.None);
|
||||||
}
|
}
|
||||||
@@ -542,39 +579,39 @@ public abstract class CustomActionButton
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Custom action button that has a target object.
|
/// Custom action button that has a target <typeparamref name="T"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the target object.</typeparam>
|
/// <typeparam name="T">The type of the target object.</typeparam>
|
||||||
public abstract class CustomActionButton<T> : CustomActionButton where T : MonoBehaviour
|
public abstract class CustomActionButton<T> : CustomActionButton where T : MonoBehaviour
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the target object of the button.
|
/// Gets or sets the target <typeparamref name="T"/> of the button.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public T? Target { get; set; }
|
public T? Target { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the distance the player must be from the target object to use the button.
|
/// Gets the distance the player must be from the target <typeparamref name="T"/> to use the button.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual float Distance => PlayerControl.LocalPlayer.Data.Role.GetAbilityDistance();
|
public virtual float Distance => PlayerControl.LocalPlayer.Data.Role.GetAbilityDistance();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines if the target object is valid.
|
/// Determines if the target <typeparamref name="T"/> is valid.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="target">The target object being checked.</param>
|
/// <param name="target">The target <typeparamref name="T"/> being checked.</param>
|
||||||
/// <returns>True if the target object is valid, false otherwise.</returns>
|
/// <returns><see langword="true"/> if the target <typeparamref name="T"/> is valid, <see langword="false"/> otherwise.</returns>
|
||||||
public virtual bool IsTargetValid(T? target)
|
public virtual bool IsTargetValid(T? target)
|
||||||
{
|
{
|
||||||
return target != null;
|
return target != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The method used to get the target object.
|
/// The method used to get the target <typeparamref name="T"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The target object or null if it isn't found.</returns>
|
/// <returns>The target <typeparamref name="T"/> or <see langword="null"/> if it isn't found.</returns>
|
||||||
public abstract T? GetTarget();
|
public abstract T? GetTarget();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the outline of the target object.
|
/// Sets the outline of the target <typeparamref name="T"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="active">Should the outline be active.</param>
|
/// <param name="active">Should the outline be active.</param>
|
||||||
public abstract void SetOutline(bool active);
|
public abstract void SetOutline(bool active);
|
||||||
|
|||||||
@@ -4,20 +4,33 @@ using System.Collections.ObjectModel;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using MiraAPI.Events.Mira;
|
using MiraAPI.Events.Mira;
|
||||||
using MiraAPI.PluginLoading;
|
using MiraAPI.PluginLoading;
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace MiraAPI.Hud;
|
namespace MiraAPI.Hud;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Custom button manager for handling custom buttons.
|
/// Custom button manager for handling <see cref="CustomActionButton"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class CustomButtonManager
|
public static class CustomButtonManager
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a list of all registered custom buttons.
|
/// Gets a list of all registered custom <see cref="CustomActionButton"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static ReadOnlyCollection<CustomActionButton> Buttons { get; internal set; } = new([]);
|
public static ReadOnlyCollection<CustomActionButton> Buttons { get; internal set; } = new([]);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of all registered button-specific <see cref="MiraButtonClickEvent"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public static ReadOnlyDictionary<Type, Type> EventTypes { get; internal set; } = new(
|
||||||
|
new Dictionary<Type, Type>
|
||||||
|
{ });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of all registered button-specific <see cref="MiraButtonCancelledEvent"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public static ReadOnlyDictionary<Type, Type> CancelledEventTypes { get; internal set; } = new(
|
||||||
|
new Dictionary<Type, Type>
|
||||||
|
{ });
|
||||||
|
|
||||||
internal static readonly List<CustomActionButton> CustomButtons = [];
|
internal static readonly List<CustomActionButton> CustomButtons = [];
|
||||||
internal static readonly Dictionary<Type, Type> ButtonEventTypes = [];
|
internal static readonly Dictionary<Type, Type> ButtonEventTypes = [];
|
||||||
internal static readonly Dictionary<Type, Type> ButtonCancelledEventTypes = [];
|
internal static readonly Dictionary<Type, Type> ButtonCancelledEventTypes = [];
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using System.Linq;
|
|||||||
namespace MiraAPI.Hud;
|
namespace MiraAPI.Hud;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A utility class to get the instance of a custom action button.
|
/// A utility class to get the instance of a <see cref="CustomActionButton"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the button you are trying to access.</typeparam>
|
/// <typeparam name="T">The type of the button you are trying to access.</typeparam>
|
||||||
public static class CustomButtonSingleton<T> where T : CustomActionButton
|
public static class CustomButtonSingleton<T> where T : CustomActionButton
|
||||||
@@ -12,7 +12,7 @@ public static class CustomButtonSingleton<T> where T : CustomActionButton
|
|||||||
private static T? _instance;
|
private static T? _instance;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the instance of the button.
|
/// Gets the instance of the <typeparamref name="T"/> button.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SuppressMessage("Design", "CA1000:Do not declare static members on generic types", Justification = "This is a utility class to get the instance of a custom action button.")]
|
[SuppressMessage("Design", "CA1000:Do not declare static members on generic types", Justification = "This is a utility class to get the instance of a custom action button.")]
|
||||||
public static T Instance => _instance ??= CustomButtonManager.CustomButtons.OfType<T>().Single();
|
public static T Instance => _instance ??= CustomButtonManager.CustomButtons.OfType<T>().Single();
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ using UnityEngine.Events;
|
|||||||
namespace MiraAPI.Hud;
|
namespace MiraAPI.Hud;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Custom Player Menu using the ShapeshifterPanel as a base.
|
/// Custom Player Menu using the <see cref="ShapeshifterPanel"/> as a base.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="il2CppPtr">Used by Il2Cpp. Do not use constructor, this is a MonoBehaviour.</param>
|
/// <param name="il2CppPtr">Used by Il2Cpp. Do not use constructor, this is a <see cref="MonoBehaviour"/>.</param>
|
||||||
[RegisterInIl2Cpp]
|
[RegisterInIl2Cpp]
|
||||||
[SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "Unity Convention")]
|
[SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "Unity Convention")]
|
||||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Unity Convention")]
|
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Unity Convention")]
|
||||||
@@ -34,9 +34,9 @@ public class CustomPlayerMenu(IntPtr il2CppPtr) : Minigame(il2CppPtr)
|
|||||||
public List<ShapeshifterPanel> potentialVictims;
|
public List<ShapeshifterPanel> potentialVictims;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a CustomPlayerMenu.
|
/// Creates a <see cref="CustomPlayerMenu"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>New CustomPlayerMenu object.</returns>
|
/// <returns>New <see cref="CustomPlayerMenu"/> object.</returns>
|
||||||
public static CustomPlayerMenu Create()
|
public static CustomPlayerMenu Create()
|
||||||
{
|
{
|
||||||
var shapeShifterRole = RoleManager.Instance.GetRole(RoleTypes.Shapeshifter);
|
var shapeShifterRole = RoleManager.Instance.GetRole(RoleTypes.Shapeshifter);
|
||||||
@@ -84,7 +84,7 @@ public class CustomPlayerMenu(IntPtr il2CppPtr) : Minigame(il2CppPtr)
|
|||||||
/// Begins/opens the custom player menu.
|
/// Begins/opens the custom player menu.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="playerMatch">Function to determine if player should show in the custom menu.</param>
|
/// <param name="playerMatch">Function to determine if player should show in the custom menu.</param>
|
||||||
/// <param name="onClick">Onclick action for player.</param>
|
/// <param name="onClick"><see cref="PassiveButton.OnClick"/> action for player.</param>
|
||||||
[HideFromIl2Cpp]
|
[HideFromIl2Cpp]
|
||||||
public void Begin(Func<PlayerControl, bool> playerMatch, Action<PlayerControl?> onClick)
|
public void Begin(Func<PlayerControl, bool> playerMatch, Action<PlayerControl?> onClick)
|
||||||
{
|
{
|
||||||
@@ -96,7 +96,7 @@ public class CustomPlayerMenu(IntPtr il2CppPtr) : Minigame(il2CppPtr)
|
|||||||
onClick(null);
|
onClick(null);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
DestroyableSingleton<DebugAnalytics>.Instance.Analytics.MinigameOpened(PlayerControl.LocalPlayer.Data, TaskType);
|
DebugAnalytics.Instance.Analytics.MinigameOpened(PlayerControl.LocalPlayer.Data, TaskType);
|
||||||
var list = PlayerControl.AllPlayerControls.ToArray().Where(playerMatch).ToList();
|
var list = PlayerControl.AllPlayerControls.ToArray().Where(playerMatch).ToList();
|
||||||
potentialVictims = [];
|
potentialVictims = [];
|
||||||
var list2 = new Il2CppSystem.Collections.Generic.List<UiElement>();
|
var list2 = new Il2CppSystem.Collections.Generic.List<UiElement>();
|
||||||
|
|||||||
@@ -0,0 +1,203 @@
|
|||||||
|
using BepInEx.Unity.IL2CPP.Utils.Collections;
|
||||||
|
using InnerNet;
|
||||||
|
using MiraAPI.LocalSettings;
|
||||||
|
using MiraAPI.Modifiers.ModifierDisplay;
|
||||||
|
using Reactor.Utilities.Attributes;
|
||||||
|
using Reactor.Utilities.Extensions;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace MiraAPI.Hud;
|
||||||
|
|
||||||
|
[RegisterInIl2Cpp]
|
||||||
|
public sealed class MiraHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
|
||||||
|
{
|
||||||
|
public static MiraHudHelper Instance { get; private set; }
|
||||||
|
public static GameObject ModifierDisplayObject;
|
||||||
|
public static GameObject VanillaMatchInfoButton;
|
||||||
|
public static bool ModifierDisplayOnRight;
|
||||||
|
public static GameObject ClonedChatButton;
|
||||||
|
public static GameObject ExtraUiTopRight;
|
||||||
|
public static GridArrange ExtraUiGrid;
|
||||||
|
public static AspectPosition ExtraUiAspectPos;
|
||||||
|
public static GameObject UiTopRight;
|
||||||
|
public static GridArrange UiGrid;
|
||||||
|
public static AspectPosition UiAspectPos;
|
||||||
|
public static GameObject SubmergedFloorButton;
|
||||||
|
public static SpriteRenderer SubmergedFloorButtonRenderer;
|
||||||
|
public static SpriteRenderer SubmergedFloorButtonRendererHover;
|
||||||
|
public void Awake()
|
||||||
|
{
|
||||||
|
Instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
MiraApiSettings.OldButtonScaleFactor =
|
||||||
|
LocalSettingsTabSingleton<MiraApiSettings>.Instance.TopRightButtonsFactorSlider.Value;
|
||||||
|
StartCoroutine(MiraApiSettings.CoResizeSettingsUI().WrapToIl2Cpp());
|
||||||
|
}
|
||||||
|
#pragma warning disable S2325
|
||||||
|
#pragma warning disable CA1822
|
||||||
|
public void FixedUpdate()
|
||||||
|
{
|
||||||
|
if (!HudManager.InstanceExists || !PlayerControl.LocalPlayer || !PlayerControl.LocalPlayer.Data)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var instance = HudManager.Instance;
|
||||||
|
|
||||||
|
CreateUiRow(instance);
|
||||||
|
CreateNewUiRow(instance);
|
||||||
|
AdjustModifierTab();
|
||||||
|
|
||||||
|
if (!PlayerControl.LocalPlayer || !PlayerControl.LocalPlayer.Data || !PlayerControl.LocalPlayer.Data.Role ||
|
||||||
|
!ShipStatus.Instance ||
|
||||||
|
(AmongUsClient.Instance.GameState != InnerNetClient.GameStates.Started &&
|
||||||
|
!TutorialManager.InstanceExists))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UpdateSubmergedButtons(instance);
|
||||||
|
}
|
||||||
|
#pragma warning restore CA1822
|
||||||
|
#pragma warning restore S2325
|
||||||
|
|
||||||
|
public static Vector3 BelowOptionPos = new(0.435f, 1.25f, 0f);
|
||||||
|
public static Vector3 FullTopPos = new(0.435f, 0.475f, 0f);
|
||||||
|
public static void CreateUiRow(HudManager instance)
|
||||||
|
{
|
||||||
|
if (!UiTopRight)
|
||||||
|
{
|
||||||
|
UiTopRight = instance.MapButton.transform.parent.gameObject;
|
||||||
|
|
||||||
|
UiGrid = UiTopRight.AddComponent<GridArrange>();
|
||||||
|
UiAspectPos = UiTopRight.AddComponent<AspectPosition>();
|
||||||
|
|
||||||
|
UiGrid.Alignment = GridArrange.StartAlign.Left;
|
||||||
|
UiGrid.CellSize = new Vector2(0.85f, 0.85f);
|
||||||
|
UiGrid.MaxColumns = 6;
|
||||||
|
UiAspectPos.Alignment = AspectPosition.EdgeAlignments.RightTop;
|
||||||
|
UiGrid.Start();
|
||||||
|
UiAspectPos.DistanceFromEdge = FullTopPos;
|
||||||
|
var mapButton = instance.MapButton.gameObject;
|
||||||
|
mapButton.GetComponent<AspectPosition>().Destroy();
|
||||||
|
var settingsButton = instance.SettingsButton;
|
||||||
|
settingsButton.GetComponent<AspectPosition>().Destroy();
|
||||||
|
VanillaMatchInfoButton = instance.MatchInfoButton.gameObject;
|
||||||
|
VanillaMatchInfoButton.GetComponent<AspectPosition>().Destroy();
|
||||||
|
var oldPos = settingsButton.transform.localPosition;
|
||||||
|
settingsButton.transform.localPosition = new Vector3(oldPos.x, oldPos.y, -100);
|
||||||
|
var chatButton = instance.Chat.chatButton.gameObject;
|
||||||
|
ClonedChatButton = Object.Instantiate(chatButton, chatButton.transform.parent);
|
||||||
|
ClonedChatButton.SetActive(false);
|
||||||
|
instance.Chat.chatButtonAspectPosition = ClonedChatButton.GetComponent<AspectPosition>();
|
||||||
|
chatButton.GetComponent<AspectPosition>().Destroy();
|
||||||
|
var inactivePos = settingsButton.transform.GetChild(1).transform.localPosition;
|
||||||
|
var bg = settingsButton.transform.GetChild(2).gameObject;
|
||||||
|
var bgPos = bg.transform.localPosition;
|
||||||
|
var bgSprite = bg.GetComponent<SpriteRenderer>().sprite;
|
||||||
|
var activePos = settingsButton.transform.GetChild(3).transform.localPosition;
|
||||||
|
var selectedPos = settingsButton.transform.GetChild(4).transform.localPosition;
|
||||||
|
chatButton.transform.GetChild(2).transform.localPosition = inactivePos;
|
||||||
|
var chatBg = chatButton.transform.GetChild(3);
|
||||||
|
chatBg.transform.localPosition = bgPos;
|
||||||
|
chatBg.GetComponent<SpriteRenderer>().sprite = bgSprite;
|
||||||
|
chatButton.transform.GetChild(4).transform.localPosition = activePos;
|
||||||
|
chatButton.transform.GetChild(5).transform.localPosition = selectedPos;
|
||||||
|
var collider = chatButton.GetComponent<BoxCollider2D>();
|
||||||
|
collider.size = new Vector2(0.4354f, 0.4003f);
|
||||||
|
collider.offset = new Vector2(0.0025f, 0.0254f);
|
||||||
|
if (FriendsListManager.InstanceExists && !TutorialManager.InstanceExists)
|
||||||
|
{
|
||||||
|
var listButton = FriendsListManager.Instance.FriendsListButton.transform.GetChild(0);
|
||||||
|
listButton.transform.SetParent(UiTopRight.transform, false);
|
||||||
|
FriendsListManager.Instance.FriendsListButton = listButton.GetComponent<FriendsListButton>();
|
||||||
|
listButton.GetComponent<AspectPosition>().Destroy();
|
||||||
|
listButton.localPosition = new Vector3(0, 0, 0);
|
||||||
|
}
|
||||||
|
settingsButton.transform.SetAsLastSibling();
|
||||||
|
chatButton.transform.SetParent(UiTopRight.transform, false);
|
||||||
|
instance.Chat.chatButton = chatButton.GetComponent<PassiveButton>();
|
||||||
|
var iconContainer = new GameObject("iconContainer")
|
||||||
|
{
|
||||||
|
layer = LayerMask.NameToLayer("UI"),
|
||||||
|
};
|
||||||
|
iconContainer.transform.SetParent(chatButton.transform, false);
|
||||||
|
iconContainer.transform.localPosition = new Vector3(0.1f, -0.1f, 0);
|
||||||
|
instance.Chat.chatNotifyDot.transform.SetParent(iconContainer.transform, false);
|
||||||
|
instance.Chat.chatNotifyDot = iconContainer.transform.GetChild(0).GetComponent<SpriteRenderer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UiTopRight && UiGrid)
|
||||||
|
{
|
||||||
|
var isChatButtonVisible = HudManager.Instance.Chat.isActiveAndEnabled;
|
||||||
|
instance.Chat.chatButton.gameObject.SetActive(isChatButtonVisible);
|
||||||
|
if (VanillaMatchInfoButton)
|
||||||
|
{
|
||||||
|
VanillaMatchInfoButton.SetActive(!GameSettingMenu.Instance && !Minigame.Instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void UpdateSubmergedButtons(HudManager instance)
|
||||||
|
{
|
||||||
|
if (ModCompatibility.IsSubmerged() && !SubmergedFloorButton && ExtraUiTopRight)
|
||||||
|
{
|
||||||
|
if (!SubmergedFloorButton && ExtraUiTopRight)
|
||||||
|
{
|
||||||
|
var transform = instance.MapButton.transform.parent.Find(instance.MapButton.name + "(Clone)");
|
||||||
|
if (transform != null)
|
||||||
|
{
|
||||||
|
SubmergedFloorButton = transform.gameObject;
|
||||||
|
SubmergedFloorButton.transform.SetParent(ExtraUiTopRight.transform, false);
|
||||||
|
|
||||||
|
SubmergedFloorButtonRenderer =
|
||||||
|
SubmergedFloorButton.transform.Find("Inactive").GetComponent<SpriteRenderer>();
|
||||||
|
SubmergedFloorButtonRendererHover =
|
||||||
|
SubmergedFloorButton.transform.Find("Active").GetComponent<SpriteRenderer>();
|
||||||
|
|
||||||
|
MiraApiSettings.SetUpButtonPositions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AdjustModifierTab()
|
||||||
|
{
|
||||||
|
if (!ModifierDisplayObject && UiTopRight && ExtraUiTopRight && ModifierDisplayComponent.Instance)
|
||||||
|
{
|
||||||
|
ModifierDisplayObject = ModifierDisplayComponent.Instance?.gameObject ?? null!;
|
||||||
|
ModifierDisplayOnRight = !LocalSettingsTabSingleton<MiraApiSettings>.Instance.ModifiersHudLeftSide.Value;
|
||||||
|
if (ModifierDisplayOnRight)
|
||||||
|
{
|
||||||
|
ModifierDisplayObject.transform.SetParent(ExtraUiTopRight.transform, false);
|
||||||
|
ModifierDisplayObject.GetComponent<AspectPosition>().Destroy();
|
||||||
|
var oldPos = ModifierDisplayObject.transform.GetChild(0).localPosition;
|
||||||
|
ModifierDisplayObject.transform.GetChild(0).localPosition = new Vector3(-1.1757f, -2.1633f, oldPos.z);
|
||||||
|
oldPos = ModifierDisplayObject.transform.GetChild(1).localPosition;
|
||||||
|
ModifierDisplayObject.transform.GetChild(1).localPosition = new Vector3(-0.45f, 0.3f, oldPos.z);
|
||||||
|
}
|
||||||
|
MiraApiSettings.SetUpButtonPositions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void CreateNewUiRow(HudManager instance)
|
||||||
|
{
|
||||||
|
if (!ExtraUiTopRight && UiTopRight)
|
||||||
|
{
|
||||||
|
ExtraUiTopRight = new GameObject("ExtraUiTopRight")
|
||||||
|
{
|
||||||
|
layer = UiTopRight.layer
|
||||||
|
};
|
||||||
|
ExtraUiTopRight.transform.SetParent(instance.MapButton.transform.parent.parent, false);
|
||||||
|
|
||||||
|
ExtraUiGrid = ExtraUiTopRight.AddComponent<GridArrange>();
|
||||||
|
ExtraUiAspectPos = ExtraUiTopRight.AddComponent<AspectPosition>();
|
||||||
|
|
||||||
|
ExtraUiGrid.Alignment = GridArrange.StartAlign.Left;
|
||||||
|
ExtraUiGrid.CellSize = new Vector2(0.85f, 0.85f);
|
||||||
|
ExtraUiAspectPos.Alignment = AspectPosition.EdgeAlignments.RightTop;
|
||||||
|
ExtraUiAspectPos.DistanceFromEdge = BelowOptionPos;
|
||||||
|
ExtraUiGrid.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Reactor.Utilities.Extensions;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Hud;
|
namespace MiraAPI.Hud;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Custom action button that has multiple target objects.
|
/// <see cref="CustomActionButton"/> that has multiple target objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the target objects.</typeparam>
|
/// <typeparam name="T">The type of the target objects.</typeparam>
|
||||||
public abstract class MultiTargetButton<T> : CustomActionButton where T : MonoBehaviour
|
public abstract class MultiTargetButton<T> : CustomActionButton where T : MonoBehaviour
|
||||||
@@ -36,8 +35,11 @@ public abstract class MultiTargetButton<T> : CustomActionButton where T : MonoBe
|
|||||||
/// <returns>The list of target objects.</returns>
|
/// <returns>The list of target objects.</returns>
|
||||||
public abstract T[] GetTargets();
|
public abstract T[] GetTargets();
|
||||||
|
|
||||||
/// <inheritdoc cref="CustomActionButton{T}.SetOutline"/>
|
/// <summary>
|
||||||
/// <param name="target">The target object to set the oultine.</param>
|
/// Sets the outline of the target <typeparamref name="T"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">The target <typeparamref name="T"/> to set the oultine.</param>
|
||||||
|
/// <param name="active">Should the outline be active.</param>
|
||||||
public abstract void SetOutline(T target, bool active);
|
public abstract void SetOutline(T target, bool active);
|
||||||
|
|
||||||
/// <inheritdoc cref="CustomActionButton{T}.CanUse"/>
|
/// <inheritdoc cref="CustomActionButton{T}.CanUse"/>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public class BaseKeybind
|
|||||||
public InputAction? RewiredInputAction { get; internal set; }
|
public InputAction? RewiredInputAction { get; internal set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the unique identifier for this keybind. Used in Rewired.
|
/// Gets or sets the unique identifier for this keybind. Used in Rewired.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Id { get; protected set; }
|
public string Id { get; protected set; }
|
||||||
|
|
||||||
|
|||||||
@@ -3,18 +3,17 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Il2CppInterop.Runtime.Attributes;
|
using Il2CppInterop.Runtime.Attributes;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
using Reactor.Utilities;
|
|
||||||
using Rewired;
|
using Rewired;
|
||||||
|
|
||||||
namespace MiraAPI.Keybinds;
|
namespace MiraAPI.Keybinds;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lets you register and manage mod keybinds with conflict checks and rebinding support.
|
/// Lets you register and manage mod <see cref="MiraKeybind"/>s with conflict checks and rebinding support.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class KeybindManager
|
public static class KeybindManager
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a list of all registered keybinds.
|
/// Gets a list of all registered <see cref="MiraKeybind"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static List<MiraKeybind> Keybinds { get; } = new();
|
public static List<MiraKeybind> Keybinds { get; } = new();
|
||||||
|
|
||||||
@@ -26,11 +25,11 @@ public static class KeybindManager
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var instance = KeybindUtils.RewiredInputManager!;
|
var instance = KeybindUtils.RewiredInputManager!;
|
||||||
foreach (var keybind in KeybindManager.Keybinds)
|
foreach (var keybind in Keybinds)
|
||||||
{
|
{
|
||||||
if (instance.userData.actions.ToArray().Any(x => x.name == keybind.Id))
|
if (instance.userData.actions.ToArray().Any(x => x.name == keybind.Id))
|
||||||
{
|
{
|
||||||
Logger<MiraApiPlugin>.Warning($"Keybind of id {keybind.Id} already exists. Skipping it");
|
Warning($"Keybind of id {keybind.Id} already exists. Skipping it");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,12 +43,12 @@ public static class KeybindManager
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger<MiraApiPlugin>.Error($"Error while registering keybinds in Rewired: {e}");
|
Error($"Error while registering keybinds in Rewired: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns all conflicts where keybinds use the same key.
|
/// Returns all conflicts where <see cref="MiraKeybind"/>s use the same key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A list of pairs of keybinds that conflict.</returns>
|
/// <returns>A list of pairs of keybinds that conflict.</returns>
|
||||||
public static Dictionary<KeyboardKeyCode, List<MiraKeybind>> GetConflicts()
|
public static Dictionary<KeyboardKeyCode, List<MiraKeybind>> GetConflicts()
|
||||||
@@ -77,11 +76,11 @@ public static class KeybindManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns all keybinds for a specified keycode.
|
/// Returns all <see cref="MiraKeybind"/>s for a specified keycode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="keyCode">The key to look for.</param>
|
/// <param name="keyCode">The key to look for.</param>
|
||||||
/// /// <param name="exclusiveCheck">Should only exlusive keybinds be present.</param>
|
/// /// <param name="exclusiveCheck">Should only exlusive keybinds be present.</param>
|
||||||
/// <returns>The list of keybinds.</returns>
|
/// <returns>The list of <see cref="MiraKeybind"/>s.</returns>
|
||||||
public static MiraKeybind[] GetKeybindsForKey(KeyboardKeyCode keyCode, bool exclusiveCheck = false)
|
public static MiraKeybind[] GetKeybindsForKey(KeyboardKeyCode keyCode, bool exclusiveCheck = false)
|
||||||
{
|
{
|
||||||
var all = new List<MiraKeybind>();
|
var all = new List<MiraKeybind>();
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ public static class KeybindUtils
|
|||||||
public static InputManager_Base? RewiredInputManager { get; internal set; }
|
public static InputManager_Base? RewiredInputManager { get; internal set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the currently assigned keycode of a keybind.
|
/// Returns the currently assigned keycode of a <see cref="BaseKeybind"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="keybind">The keybind to get the keycode from.</param>
|
/// <param name="keybind">The <see cref="BaseKeybind"/> to get the keycode from.</param>
|
||||||
/// <returns>The currently assigned keycode.</returns>
|
/// <returns>The currently assigned keycode.</returns>
|
||||||
public static KeyboardKeyCode GetKeycodeByKeybind(BaseKeybind keybind)
|
public static KeyboardKeyCode GetKeycodeByKeybind(BaseKeybind keybind)
|
||||||
{
|
{
|
||||||
@@ -29,7 +29,7 @@ public static class KeybindUtils
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the keycode for an action with ReInput.
|
/// Gets the keycode for an action with <see cref="ReInput"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="actionId">The action ID.</param>
|
/// <param name="actionId">The action ID.</param>
|
||||||
/// <returns>The keyboard keycode.</returns>
|
/// <returns>The keyboard keycode.</returns>
|
||||||
@@ -39,7 +39,7 @@ public static class KeybindUtils
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a <see cref="ActionElementMap"/> by id with ReInput.
|
/// Gets a <see cref="ActionElementMap"/> by id with <see cref="ReInput"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="actionId">The action ID.</param>
|
/// <param name="actionId">The action ID.</param>
|
||||||
/// <returns>The keyboard keycode.</returns>
|
/// <returns>The keyboard keycode.</returns>
|
||||||
@@ -65,7 +65,7 @@ public static class KeybindUtils
|
|||||||
/// <param name="exclude">The KeyCode to skip during the search.</param>
|
/// <param name="exclude">The KeyCode to skip during the search.</param>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// The first available KeyCode not currently used by any registered keybind,
|
/// The first available KeyCode not currently used by any registered keybind,
|
||||||
/// or KeyCode.None if none are available.
|
/// or <see cref="KeyboardKeyCode.None"/> if none are available.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
public static KeyboardKeyCode FindAvailableKey(KeyboardKeyCode exclude)
|
public static KeyboardKeyCode FindAvailableKey(KeyboardKeyCode exclude)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace MiraAPI.Keybinds;
|
namespace MiraAPI.Keybinds;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class containing all default keybinds.
|
/// Class containing all default <see cref="MiraKeybind"/>s.
|
||||||
/// Recommended for cross-mod compatibility.
|
/// Recommended for cross-mod compatibility.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterCustomKeybinds]
|
[RegisterCustomKeybinds]
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace MiraAPI.Keybinds;
|
|||||||
public class MiraKeybind : BaseKeybind
|
public class MiraKeybind : BaseKeybind
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets name of the keybind
|
/// Gets name of the keybind.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
@@ -19,8 +19,8 @@ public class MiraKeybind : BaseKeybind
|
|||||||
public KeyboardKeyCode DefaultKey { get; }
|
public KeyboardKeyCode DefaultKey { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the modifier keys assigned to this keybind.
|
/// Gets the <see cref="ModifierKey"/>s assigned to this keybind.
|
||||||
/// Due to Rewired limitations, there can only be 3 modifier keys.
|
/// Due to Rewired limitations, there can only be 3 <see cref="ModifierKey"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ModifierKey[] ModifierKeys { get; }
|
public ModifierKey[] ModifierKeys { get; }
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ public class MiraKeybind : BaseKeybind
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The name of the keybind.</param>
|
/// <param name="name">The name of the keybind.</param>
|
||||||
/// <param name="defaultKeycode">The default keycode.</param>
|
/// <param name="defaultKeycode">The default keycode.</param>
|
||||||
/// <param name="modifierKeys">Up to 3 optional modifier keys.</param>
|
/// <param name="modifierKeys">Up to 3 optional <see cref="ModifierKey"/>s.</param>
|
||||||
/// <param name="exclusive">Is exclusive.</param>
|
/// <param name="exclusive">Is exclusive.</param>
|
||||||
public MiraKeybind(
|
public MiraKeybind(
|
||||||
string name,
|
string name,
|
||||||
|
|||||||
Loaded 100 of 262 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user