From b06e989214c842836c5a747aa1410e5c72909d8c Mon Sep 17 00:00:00 2001 From: Gurge44 Date: Tue, 29 Apr 2025 09:35:53 +0200 Subject: [PATCH] some improvements --- GameMode/CaptureTheFlag.cs | 44 +++++++++++++++++++++++++++++++ GameMode/HotPotato.cs | 27 ++++++++++++++++--- GameMode/KingOfTheZones.cs | 17 ++++++++++++ Modules/AntiBlackout.cs | 15 ++++++++--- Modules/CustomRpcSender.cs | 6 +++-- Modules/ExtendedPlayerControl.cs | 6 +++-- Modules/OptionHolder.cs | 17 ++++++++++++ Modules/RPC.cs | 8 +++++- Patches/ChatCommandPatch.cs | 8 +++--- Patches/PlayerControlPatch.cs | 4 ++- Patches/PlayerJoinAndLeftPatch.cs | 38 ++++++++++++++++++++++++++ Patches/SabotageSystemPatch.cs | 7 +++-- Patches/TaskAssignPatch.cs | 2 +- Roles/Crewmate/Battery.cs | 10 ++++++- 14 files changed, 189 insertions(+), 20 deletions(-) diff --git a/GameMode/CaptureTheFlag.cs b/GameMode/CaptureTheFlag.cs index 7c580c7c2..7181b3d4c 100644 --- a/GameMode/CaptureTheFlag.cs +++ b/GameMode/CaptureTheFlag.cs @@ -394,6 +394,50 @@ public static class CaptureTheFlag } } + try + { + foreach (CTFTeamData data in TeamData.Values) + { + try + { + foreach (byte id1 in data.Players) + { + try + { + var pc1 = id1.GetPlayer(); + if (pc1 == null) continue; + + int targetClientId = pc1.GetClientId(); + + foreach (byte id2 in data.Players) + { + try + { + if (id1 == id2) continue; + + var pc2 = id2.GetPlayer(); + if (pc2 == null) continue; + + hasValue |= sender.RpcSetRole(pc2, RoleTypes.Phantom, targetClientId); + + if (sender.stream.Length > 800) + { + sender.SendMessage(); + sender = CustomRpcSender.Create("CTF - OnGameStart", SendOption.Reliable); + hasValue = false; + } + } + catch (Exception e) { Utils.ThrowException(e); } + } + } + catch (Exception e) { Utils.ThrowException(e); } + } + } + catch (Exception e) { Utils.ThrowException(e); } + } + } + catch (Exception e) { Utils.ThrowException(e); } + sender.SendMessage(!hasValue); ValidTag = true; diff --git a/GameMode/HotPotato.cs b/GameMode/HotPotato.cs index c0460898c..bd11452c1 100644 --- a/GameMode/HotPotato.cs +++ b/GameMode/HotPotato.cs @@ -5,6 +5,7 @@ using System.Linq; using AmongUs.GameOptions; using EHR.Modules; using HarmonyLib; +using Hazel; using UnityEngine; namespace EHR; @@ -14,10 +15,13 @@ internal static class HotPotato private static OptionItem Time; private static OptionItem HolderSpeed; private static OptionItem Range; + private static OptionItem HolderCanPassViaKillButton; private static (byte HolderID, byte LastHolderID, int TimeLeft, int RoundNum) HotPotatoState; private static Dictionary SurvivalTimes; private static float DefaultSpeed; + + public static bool CanPassViaKillButton => HolderCanPassViaKillButton.GetBool(); public static (byte HolderID, byte LastHolderID) GetState() { @@ -41,6 +45,11 @@ internal static class HotPotato .SetGameMode(CustomGameMode.HotPotato) .SetValueFormat(OptionFormat.Multiplier) .SetColor(new Color32(232, 205, 70, byte.MaxValue)); + + HolderCanPassViaKillButton = new BooleanOptionItem(69_213_003, "HotPotato_HolderCanPassViaKillButton", false, TabGroup.GameSettings) + .SetGameMode(CustomGameMode.HotPotato) + .SetColor(new Color32(232, 205, 70, byte.MaxValue)) + .SetHeader(true); } public static void Init() @@ -73,6 +82,12 @@ internal static class HotPotato return $"{(HotPotatoState.HolderID == id ? $"{Translator.GetString("HotPotato_HoldingNotify")}\n" : string.Empty)}{Translator.GetString("HotPotato_TimeLeftSuffix")}{HotPotatoState.TimeLeft}s"; } + public static void ReceiveRPC(MessageReader reader) + { + HotPotatoState.HolderID = reader.ReadByte(); + HotPotatoState.LastHolderID = reader.ReadByte(); + } + [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.FixedUpdate))] private static class FixedUpdatePatch { @@ -114,7 +129,8 @@ internal static class HotPotato } PlayerControl[] aapc = Main.AllAlivePlayerControls; - if (HotPotatoState.HolderID != __instance.PlayerId || !aapc.Any(x => x.PlayerId != HotPotatoState.HolderID && (x.PlayerId != HotPotatoState.LastHolderID || aapc.Length == 2) && Vector2.Distance(x.Pos(), Holder.Pos()) <= Range.GetFloat())) return; + Vector2 pos = Holder.Pos(); + if (HotPotatoState.HolderID != __instance.PlayerId || !aapc.Any(x => x.PlayerId != HotPotatoState.HolderID && (x.PlayerId != HotPotatoState.LastHolderID || aapc.Length == 2) && Vector2.Distance(x.Pos(), pos) <= Range.GetFloat())) return; float wait = aapc.Length <= 2 ? 0.4f : 0.05f; UpdateDelay += UnityEngine.Time.fixedDeltaTime; @@ -122,7 +138,7 @@ internal static class HotPotato UpdateDelay = 0; - PlayerControl Target = aapc.OrderBy(x => Vector2.Distance(x.Pos(), Holder.Pos())).FirstOrDefault(x => x.PlayerId != HotPotatoState.HolderID && (x.PlayerId != HotPotatoState.LastHolderID || aapc.Length == 2)); + PlayerControl Target = aapc.OrderBy(x => Vector2.Distance(x.Pos(), pos)).FirstOrDefault(x => x.PlayerId != HotPotatoState.HolderID && (x.PlayerId != HotPotatoState.LastHolderID || aapc.Length == 2)); if (Target == null) return; PassHotPotato(Target, false); @@ -147,14 +163,19 @@ internal static class HotPotato HotPotatoState.LastHolderID = HotPotatoState.HolderID; HotPotatoState.HolderID = target.PlayerId; + + Utils.SendRPC(CustomRPC.HotPotatoSync, HotPotatoState.HolderID, HotPotatoState.LastHolderID); + if (CanPassViaKillButton) target.RpcChangeRoleBasis(CustomRoles.NSerialKiller); Main.AllPlayerSpeed[target.PlayerId] = HolderSpeed.GetFloat(); target.MarkDirtySettings(); - + PlayerControl LastHolder = Utils.GetPlayerById(HotPotatoState.LastHolderID); if (LastHolder != null) { + if (CanPassViaKillButton) LastHolder.RpcChangeRoleBasis(CustomRoles.Potato); + Main.AllPlayerSpeed[HotPotatoState.LastHolderID] = DefaultSpeed; LastHolder.MarkDirtySettings(); Utils.NotifyRoles(SpecifyTarget: LastHolder); diff --git a/GameMode/KingOfTheZones.cs b/GameMode/KingOfTheZones.cs index 91cd0bb38..19a01f11f 100644 --- a/GameMode/KingOfTheZones.cs +++ b/GameMode/KingOfTheZones.cs @@ -299,6 +299,23 @@ public static class KingOfTheZones writer = CustomRpcSender.Create("KOTZ.GameStart.TeamAssignmentNotifies", SendOption.Reliable); hasData = false; } + + try + { + int targetClientId = player.GetClientId(); + PlayerTeams.DoIf( + x => x.Key != id && x.Value == team, + // ReSharper disable once AccessToModifiedClosure + x => writer.RpcSetRole(x.Key.GetPlayer(), RoleTypes.Impostor, targetClientId)); + + if (writer.stream.Length > 800) + { + writer.SendMessage(); + writer = CustomRpcSender.Create("KOTZ.GameStart.TeamAssignmentNotifies", SendOption.Reliable); + hasData = false; + } + } + catch (Exception e) { Utils.ThrowException(e); } } catch (Exception e) { Utils.ThrowException(e); } diff --git a/Modules/AntiBlackout.cs b/Modules/AntiBlackout.cs index b2798a990..35f5d145b 100644 --- a/Modules/AntiBlackout.cs +++ b/Modules/AntiBlackout.cs @@ -194,7 +194,8 @@ public static class AntiBlackout switch (Options.CurrentGameMode) { - case CustomGameMode.Standard or CustomGameMode.HideAndSeek: + case CustomGameMode.Standard: + case CustomGameMode.HideAndSeek: { StartGameHostPatch.RpcSetRoleReplacer.ResetRoleMapMidGame(); @@ -255,7 +256,12 @@ public static class AntiBlackout break; } - case CustomGameMode.Speedrun or CustomGameMode.MoveAndStop or CustomGameMode.HotPotato or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.Quiz: + case CustomGameMode.Speedrun: + case CustomGameMode.MoveAndStop: + case CustomGameMode.HotPotato: + case CustomGameMode.NaturalDisasters: + case CustomGameMode.RoomRush: + case CustomGameMode.Quiz: { foreach (PlayerControl pc in Main.AllPlayerControls) { @@ -280,7 +286,10 @@ public static class AntiBlackout hasValue = true; break; } - case CustomGameMode.FFA or CustomGameMode.SoloKombat or CustomGameMode.CaptureTheFlag or CustomGameMode.KingOfTheZones: + case CustomGameMode.FFA: + case CustomGameMode.SoloKombat: + case CustomGameMode.CaptureTheFlag: + case CustomGameMode.KingOfTheZones: { sender.RpcSetRole(PlayerControl.LocalPlayer, RoleTypes.Crewmate, noRpcForSelf: true); RestartMessageIfTooLong(); diff --git a/Modules/CustomRpcSender.cs b/Modules/CustomRpcSender.cs index ed4f3e778..3eca9fa6a 100644 --- a/Modules/CustomRpcSender.cs +++ b/Modules/CustomRpcSender.cs @@ -370,18 +370,20 @@ public class CustomRpcSender public static class CustomRpcSenderExtensions { - public static void RpcSetRole(this CustomRpcSender sender, PlayerControl player, RoleTypes role, int targetClientId = -1, bool noRpcForSelf = true) + public static bool RpcSetRole(this CustomRpcSender sender, PlayerControl player, RoleTypes role, int targetClientId = -1, bool noRpcForSelf = true) { if (AmongUsClient.Instance.ClientId == targetClientId && noRpcForSelf) { player.SetRole(role); - return; + return false; } sender.AutoStartRpc(player.NetId, (byte)RpcCalls.SetRole, targetClientId) .Write((ushort)role) .Write(true) .EndRpc(); + + return true; } // From TOH: https://github.com/tukasa0001/TownOfHost diff --git a/Modules/ExtendedPlayerControl.cs b/Modules/ExtendedPlayerControl.cs index 893a86793..08d42e8c4 100644 --- a/Modules/ExtendedPlayerControl.cs +++ b/Modules/ExtendedPlayerControl.cs @@ -1158,9 +1158,11 @@ internal static class ExtendedPlayerControl switch (Options.CurrentGameMode) { - case CustomGameMode.HotPotato or CustomGameMode.MoveAndStop or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush: + case CustomGameMode.MoveAndStop or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush: case CustomGameMode.Speedrun when !Speedrun.CanKill.Contains(pc.PlayerId): return false; + case CustomGameMode.HotPotato: + return HotPotato.CanPassViaKillButton && HotPotato.GetState().HolderID == pc.PlayerId; case CustomGameMode.Quiz: return Quiz.AllowKills; case CustomGameMode.KingOfTheZones: @@ -1185,7 +1187,7 @@ internal static class ExtendedPlayerControl // Move And Stop CustomRoles.Tasker => false, // Hot Potato - CustomRoles.Potato => false, + CustomRoles.Potato => HotPotato.CanPassViaKillButton && HotPotato.GetState().HolderID == pc.PlayerId, // Speedrun CustomRoles.Runner => Speedrun.CanKill.Contains(pc.PlayerId), // Quiz diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index 94c1b4b4f..83831528a 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -761,6 +761,10 @@ public static class Options public static OptionItem MinWaitAutoStart; public static OptionItem MaxWaitAutoStart; public static OptionItem PlayerAutoStart; + public static OptionItem AutoGMPollCommandAfterJoin; + public static OptionItem AutoGMPollCommandCooldown; + public static OptionItem AutoDraftStartCommandAfterJoin; + public static OptionItem AutoDraftStartCommandCooldown; public static OptionItem DumpLogAfterGameEnd; @@ -1444,6 +1448,19 @@ public static class Options AutoPlayAgainCountdown = new IntegerOptionItem(44425, "AutoPlayAgainCountdown", new(1, 90, 1), 10, TabGroup.SystemSettings) .SetParent(AutoPlayAgain); + + AutoGMPollCommandAfterJoin = new BooleanOptionItem(19309, "AutoGMPollCommandAfterJoin", false, TabGroup.SystemSettings) + .SetHeader(true); + + AutoGMPollCommandCooldown = new IntegerOptionItem(19307, "AutoGMPollCommandCooldown", new(10, 600, 5), 30, TabGroup.SystemSettings) + .SetParent(AutoGMPollCommandAfterJoin) + .SetValueFormat(OptionFormat.Seconds); + + AutoDraftStartCommandAfterJoin = new BooleanOptionItem(19426, "AutoDraftStartCommandAfterJoin", false, TabGroup.SystemSettings); + + AutoDraftStartCommandCooldown = new IntegerOptionItem(19427, "AutoDraftStartCommandCooldown", new(10, 600, 5), 90, TabGroup.SystemSettings) + .SetParent(AutoDraftStartCommandAfterJoin) + .SetValueFormat(OptionFormat.Seconds); LowLoadMode = new BooleanOptionItem(19317, "LowLoadMode", true, TabGroup.SystemSettings) .SetHeader(true) diff --git a/Modules/RPC.cs b/Modules/RPC.cs index a9eb56d6f..b4a1ac30a 100644 --- a/Modules/RPC.cs +++ b/Modules/RPC.cs @@ -147,7 +147,8 @@ public enum CustomRPC // Game Modes RoomRushDataSync, FFAKill, - QuizSync + QuizSync, + HotPotatoSync } public enum Sounds @@ -1133,6 +1134,11 @@ internal static class RPCHandlerPatch Quiz.AllowKills = reader.ReadBoolean(); break; } + case CustomRPC.HotPotatoSync: + { + HotPotato.ReceiveRPC(reader); + break; + } } } } diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index 353198a3b..af4f58e00 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -178,7 +178,7 @@ internal static class ChatCommands new(["negotiation", "neg", "наказание", "谈判方式", "negociar", "negociação"], "{number}", GetString("CommandDescription.Negotiation"), Command.UsageLevels.Everyone, Command.UsageTimes.InMeeting, NegotiationCommand, true, false, [GetString("CommandArgs.Negotiation.Number")]), new(["mute", "мут", "禁言", "mutar", "silenciar"], "{id} [duration]", GetString("CommandDescription.Mute"), Command.UsageLevels.HostOrModerator, Command.UsageTimes.AfterDeathOrLobby, MuteCommand, true, false, [GetString("CommandArgs.Mute.Id"), GetString("CommandArgs.Mute.Duration")]), new(["unmute", "размут", "解禁", "desmutar", "desilenciar"], "{id}", GetString("CommandDescription.Unmute"), Command.UsageLevels.Host, Command.UsageTimes.Always, UnmuteCommand, true, false, [GetString("CommandArgs.Unmute.Id")]), - new(["draftstart", "ds", "драфтстарт", "启用草稿", "todosescolhem-iniciar"], "", GetString("CommandDescription.DraftStart"), Command.UsageLevels.Host, Command.UsageTimes.InLobby, DraftStartCommand, true, false), + new(["draftstart", "ds", "драфтстарт", "启用草稿", "todosescolhem-iniciar"], "", GetString("CommandDescription.DraftStart"), Command.UsageLevels.HostOrModerator, Command.UsageTimes.InLobby, DraftStartCommand, true, false), new(["dd", "draftdesc", "draftdescription", "драфтописание", "草稿描述", "todosescolhem-descricao"], "{index}", GetString("CommandDescription.DraftDescription"), Command.UsageLevels.Everyone, Command.UsageTimes.InLobby, DraftDescriptionCommand, false, false, [GetString("CommandArgs.DraftDescription.Index")]), new(["draft", "драфт", "选择草稿", "todosescolhem-escolher"], "{number}", GetString("CommandDescription.Draft"), Command.UsageLevels.Everyone, Command.UsageTimes.InLobby, DraftCommand, false, false, [GetString("CommandArgs.Draft.Number")]), new(["rc", "readycheck", "проверитьготовность", "准备检测", "verificação-de-prontidão"], "", GetString("CommandDescription.ReadyCheck"), Command.UsageLevels.Host, Command.UsageTimes.InLobby, ReadyCheckCommand, true, false), @@ -545,7 +545,7 @@ internal static class ChatCommands Utils.SendMessage(GetString($"8BallResponse.{IRandom.Instance.Next(20)}"), player.IsAlive() ? byte.MaxValue : player.PlayerId, GetString("8BallResponseTitle")); } - private static void GameModePollCommand(PlayerControl player, string text, string[] args) + public static void GameModePollCommand(PlayerControl player, string text, string[] args) { if (!AmongUsClient.Instance.AmHost) { @@ -916,11 +916,11 @@ internal static class ChatCommands ReadyPlayers.Add(player.PlayerId); } - private static void DraftStartCommand(PlayerControl player, string text, string[] args) + public static void DraftStartCommand(PlayerControl player, string text, string[] args) { if (!AmongUsClient.Instance.AmHost) { - RequestCommandProcessingFromHost(nameof(DraftStartCommand), text); + RequestCommandProcessingFromHost(nameof(DraftStartCommand), text, true); return; } diff --git a/Patches/PlayerControlPatch.cs b/Patches/PlayerControlPatch.cs index 8f7d1790c..2be1928a7 100644 --- a/Patches/PlayerControlPatch.cs +++ b/Patches/PlayerControlPatch.cs @@ -233,11 +233,13 @@ internal static class CheckMurderPatch case CustomGameMode.FFA: FreeForAll.OnPlayerAttack(killer, target); return false; - case CustomGameMode.MoveAndStop: case CustomGameMode.HotPotato: + return HotPotato.CanPassViaKillButton && HotPotato.GetState().HolderID == killer.PlayerId; + case CustomGameMode.MoveAndStop: case CustomGameMode.RoomRush: case CustomGameMode.NaturalDisasters: case CustomGameMode.Speedrun when !Speedrun.OnCheckMurder(killer, target): + return false; case CustomGameMode.Quiz: if (Quiz.AllowKills) killer.Kill(target); return false; diff --git a/Patches/PlayerJoinAndLeftPatch.cs b/Patches/PlayerJoinAndLeftPatch.cs index 64e4250f5..f5a549cf3 100644 --- a/Patches/PlayerJoinAndLeftPatch.cs +++ b/Patches/PlayerJoinAndLeftPatch.cs @@ -88,6 +88,44 @@ internal static class OnGameJoinedPatch } else Logger.Info($"Not sending lobby status to the server because the server type is {GameStates.CurrentServerType} (IsOnlineGame: {GameStates.IsOnlineGame})", "OnGameJoinedPatch"); }, 5f, "NotifyLobbyCreated"); + + if (Options.AutoGMPollCommandAfterJoin.GetBool()) + { + Main.Instance.StartCoroutine(CoRoutine()); + + System.Collections.IEnumerator CoRoutine() + { + float timer = Options.AutoGMPollCommandCooldown.GetInt(); + + while (timer > 0) + { + if (!GameStates.IsLobby) yield break; + timer -= Time.deltaTime; + yield return null; + } + + ChatCommands.GameModePollCommand(PlayerControl.LocalPlayer, "/gmpoll", ["/gmpoll"]); + } + } + + if (Options.AutoDraftStartCommandAfterJoin.GetBool()) + { + Main.Instance.StartCoroutine(CoRoutine()); + + System.Collections.IEnumerator CoRoutine() + { + float timer = Options.AutoDraftStartCommandCooldown.GetInt(); + + while (timer > 0) + { + if (!GameStates.IsLobby) yield break; + timer -= Time.deltaTime; + yield return null; + } + + ChatCommands.DraftStartCommand(PlayerControl.LocalPlayer, "/draftstart", ["/draftstart"]); + } + } } else LateTask.New(() => Main.Instance.StartCoroutine(OptionShower.GetText()), 10f, "OptionShower.GetText on client"); diff --git a/Patches/SabotageSystemPatch.cs b/Patches/SabotageSystemPatch.cs index 91697c032..6a6d5f980 100644 --- a/Patches/SabotageSystemPatch.cs +++ b/Patches/SabotageSystemPatch.cs @@ -313,7 +313,7 @@ public static class SabotageSystemTypeRepairDamagePatch ModifiedCooldownSec = Options.SabotageCooldown.GetFloat(); } - public static bool Prefix([HarmonyArgument(0)] PlayerControl player, [HarmonyArgument(1)] MessageReader msgReader) + public static bool Prefix(SabotageSystemType __instance, [HarmonyArgument(0)] PlayerControl player, [HarmonyArgument(1)] MessageReader msgReader) { if (!CustomGameMode.Standard.IsActiveOrIntegrated()) return false; @@ -363,9 +363,12 @@ public static class SabotageSystemTypeRepairDamagePatch } } - if (CustomRoles.Battery.RoleExist() && systemTypes == SystemTypes.Electrical) + if (systemTypes == SystemTypes.Electrical && Main.PlayerStates.Values.FindFirst(x => !x.IsDead && x.MainRole == CustomRoles.Battery && x.Player.GetAbilityUseLimit() >= 1f, out var batteryState)) { + batteryState.Player.RpcRemoveAbilityUse(); player.Notify(string.Format(Translator.GetString("BatteryNotify"), CustomRoles.Battery.ToColoredString()), 10f); + __instance.Timer = IsCooldownModificationEnabled ? ModifiedCooldownSec : 30f; + __instance.IsDirty = true; return false; } diff --git a/Patches/TaskAssignPatch.cs b/Patches/TaskAssignPatch.cs index e22e49f6c..edea93123 100644 --- a/Patches/TaskAssignPatch.cs +++ b/Patches/TaskAssignPatch.cs @@ -177,7 +177,7 @@ internal static class RpcSetTasksPatch } // GM and Lazy Guy have no tasks - if (pc.Is(CustomRoles.GM) || pc.Is(CustomRoles.Needy) || Options.CurrentGameMode is CustomGameMode.SoloKombat or CustomGameMode.FFA or CustomGameMode.HotPotato or CustomGameMode.NaturalDisasters) + if (pc.Is(CustomRoles.GM) || pc.Is(CustomRoles.Needy) || Options.CurrentGameMode is CustomGameMode.SoloKombat or CustomGameMode.FFA or CustomGameMode.HotPotato or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.Quiz or CustomGameMode.CaptureTheFlag or CustomGameMode.KingOfTheZones) { hasCommonTasks = false; NumShortTasks = 0; diff --git a/Roles/Crewmate/Battery.cs b/Roles/Crewmate/Battery.cs index ed658c1f6..e6f744ea1 100644 --- a/Roles/Crewmate/Battery.cs +++ b/Roles/Crewmate/Battery.cs @@ -6,9 +6,16 @@ public class Battery : RoleBase public override bool IsEnable => On; + private static OptionItem AbilityUseLimit; + private static OptionItem AbilityUseGainWithEachTaskCompleted; + private static OptionItem AbilityChargesWhenFinishedTasks; + public override void SetupCustomOption() { - StartSetup(651900); + StartSetup(651900) + .AutoSetupOption(ref AbilityUseLimit, 1, new IntegerValueRule(0, 20, 1), OptionFormat.Times) + .AutoSetupOption(ref AbilityUseGainWithEachTaskCompleted, 0.5f, new FloatValueRule(0f, 5f, 0.05f), OptionFormat.Times) + .AutoSetupOption(ref AbilityChargesWhenFinishedTasks, 0.2f, new FloatValueRule(0f, 5f, 0.05f), OptionFormat.Times); } public override void Init() @@ -19,5 +26,6 @@ public class Battery : RoleBase public override void Add(byte playerId) { On = true; + playerId.SetAbilityUseLimit(AbilityUseLimit.GetInt()); } } \ No newline at end of file