mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-20 01:46:25 +00:00
a ton of fixes
This commit is contained in:
1 parent
5eb5cb31fe
commit
333d00d22b
32 files changed
+170
-109
No files matched your search
@@ -379,7 +379,7 @@ public static class CaptureTheFlag
|
||||
try
|
||||
{
|
||||
var pc1 = id1.GetPlayer();
|
||||
if (pc1 == null) continue;
|
||||
if (pc1 == null || pc1.AmOwner) continue;
|
||||
|
||||
var sender = CustomRpcSender.Create("CTF Set Teams");
|
||||
sender.StartMessage(pc1.OwnerId);
|
||||
|
||||
@@ -196,6 +196,7 @@ public class Main : BasePlugin
|
||||
public static ConfigEntry<bool> SwitchVanilla { get; private set; }
|
||||
public static ConfigEntry<bool> GodMode { get; private set; }
|
||||
public static ConfigEntry<bool> DarkTheme { get; private set; }
|
||||
public static ConfigEntry<bool> DarkThemeForMeetingUI { get; private set; }
|
||||
public static ConfigEntry<bool> HorseMode { get; private set; }
|
||||
public static ConfigEntry<bool> LongMode { get; private set; }
|
||||
public static ConfigEntry<bool> ShowPlayerInfoInLobby { get; private set; }
|
||||
@@ -298,6 +299,7 @@ public class Main : BasePlugin
|
||||
SwitchVanilla = Config.Bind("Client Options", "SwitchVanilla", false);
|
||||
GodMode = Config.Bind("Client Options", "GodMode", false);
|
||||
DarkTheme = Config.Bind("Client Options", "DarkTheme", true);
|
||||
DarkThemeForMeetingUI = Config.Bind("Client Options", "DarkThemeForMeetingUI", false);
|
||||
HorseMode = Config.Bind("Client Options", "HorseMode", false);
|
||||
LongMode = Config.Bind("Client Options", "LongMode", false);
|
||||
ShowPlayerInfoInLobby = Config.Bind("Client Options", "ShowPlayerInfoInLobby", false);
|
||||
|
||||
@@ -950,7 +950,7 @@ internal static class CustomRolesHelper
|
||||
|
||||
public static bool NeedUpdateOnLights(this CustomRoles role)
|
||||
{
|
||||
return !role.UsesPetInsteadOfKill() && role is CustomRoles.Lighter or CustomRoles.Wiper;
|
||||
return role is CustomRoles.Wiper;
|
||||
}
|
||||
|
||||
public static bool IsBetrayalAddon(this CustomRoles role)
|
||||
@@ -1213,7 +1213,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Beartrap when pc.Is(CustomRoles.GuardianAngelEHR) => false,
|
||||
CustomRoles.Reach when pc.GetRoleTypes() is not (RoleTypes.Impostor or RoleTypes.Phantom or RoleTypes.Shapeshifter or RoleTypes.Viper) => false,
|
||||
CustomRoles.Magnet when pc.GetRoleTypes() is not (RoleTypes.Impostor or RoleTypes.Phantom or RoleTypes.Shapeshifter or RoleTypes.Viper) => false,
|
||||
CustomRoles.Haste when pc.GetRoleTypes() is not (RoleTypes.Impostor or RoleTypes.Phantom or RoleTypes.Shapeshifter or RoleTypes.Viper) || !pc.CanUseImpostorVentButton() => false,
|
||||
CustomRoles.Haste when pc.GetRoleTypes() is not (RoleTypes.Impostor or RoleTypes.Phantom or RoleTypes.Shapeshifter or RoleTypes.Viper) || !pc.CanUseImpostorVentButton() || pc.Is(CustomRoles.Glitch) => false,
|
||||
CustomRoles.Diseased when pc.Is(CustomRoles.Antidote) => false,
|
||||
CustomRoles.Antidote when pc.Is(CustomRoles.Diseased) => false,
|
||||
CustomRoles.Flashman or CustomRoles.Giant when pc.GetCustomRole() is CustomRoles.Swooper or CustomRoles.Wraith or CustomRoles.Chameleon or CustomRoles.Alchemist or CustomRoles.Ankylosaurus => false,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using Hazel;
|
||||
using UnityEngine;
|
||||
|
||||
namespace EHR.Modules;
|
||||
@@ -78,8 +80,10 @@ internal static class CustomTeamManager
|
||||
UpdateEnabledTeams();
|
||||
if (EnabledCustomTeams.Count == 0) return;
|
||||
|
||||
PlayerControl[] aapc = Main.AllAlivePlayerControls;
|
||||
|
||||
CustomTeamPlayerIds = Main.PlayerStates
|
||||
.IntersectBy(Main.AllAlivePlayerControls.Select(x => x.PlayerId), x => x.Key)
|
||||
.IntersectBy(aapc.Select(x => x.PlayerId), x => x.Key)
|
||||
.GroupBy(x => EnabledCustomTeams.FirstOrDefault(t => t.TeamMembers.Contains(x.Value.MainRole)), x => x.Key)
|
||||
.Where(x => x.Key != null)
|
||||
.ToDictionary(x => x.Key, x => TakeAsManyAsSet(x, x.Key));
|
||||
@@ -107,6 +111,19 @@ internal static class CustomTeamManager
|
||||
}
|
||||
}
|
||||
|
||||
var imps = aapc.Where(x => x.IsImpostor() && !CustomTeamPlayerIds.Values.Any(l => l.Contains(x.PlayerId))).ToList();
|
||||
|
||||
if (imps.Count > 0)
|
||||
{
|
||||
CustomTeamPlayerIds.Values.Flatten().ToValidPlayers().DoIf(x => x != null && x.IsImpostor() && !IsSettingEnabledForPlayerTeam(x.PlayerId, CTAOption.WinWithOriginalTeam), ctp =>
|
||||
{
|
||||
imps.ForEach(imp => ctp.RpcSetRoleDesync(RoleTypes.Crewmate, imp.OwnerId, setRoleMap: true));
|
||||
var sender = CustomRpcSender.Create("CustomTeamManager_SetImpostorDesync", SendOption.Reliable);
|
||||
imps.ForEach(imp => sender.RpcSetRole(imp, RoleTypes.Crewmate, ctp.OwnerId, changeRoleMap: true));
|
||||
sender.SendMessage();
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
static HashSet<byte> TakeAsManyAsSet(IEnumerable<byte> playerIds, CustomTeam customTeam)
|
||||
|
||||
@@ -377,7 +377,7 @@ internal static class ExtendedPlayerControl
|
||||
}
|
||||
|
||||
// If you use vanilla RpcSetRole, it will block further SetRole calls until the next game starts.
|
||||
public static void RpcSetRoleGlobal(this PlayerControl player, RoleTypes roleTypes)
|
||||
public static void RpcSetRoleGlobal(this PlayerControl player, RoleTypes roleTypes, bool setRoleMap = false)
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
if (AmongUsClient.Instance.AmClient) player.StartCoroutine(player.CoSetRole(roleTypes, true));
|
||||
@@ -386,6 +386,19 @@ internal static class ExtendedPlayerControl
|
||||
writer.Write(true);
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
Logger.Info($" {player.GetNameWithRole()} => {roleTypes}", "RpcSetRoleGlobal");
|
||||
|
||||
if (setRoleMap)
|
||||
{
|
||||
foreach ((byte seerID, byte targetID) in StartGameHostPatch.RpcSetRoleReplacer.RoleMap.Keys.ToArray())
|
||||
{
|
||||
if (targetID == player.PlayerId)
|
||||
{
|
||||
var value = StartGameHostPatch.RpcSetRoleReplacer.RoleMap[(seerID, targetID)];
|
||||
value.RoleType = roleTypes;
|
||||
StartGameHostPatch.RpcSetRoleReplacer.RoleMap[(seerID, targetID)] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void RpcSetRoleDesync(this PlayerControl player, RoleTypes role, int clientId, bool setRoleMap = false)
|
||||
|
||||
@@ -127,6 +127,13 @@ public static class FixedUpdateCaller
|
||||
}
|
||||
catch { }
|
||||
|
||||
try
|
||||
{
|
||||
if (amongUsClient.AmHost && GameStates.InGame && !GameStates.IsEnded)
|
||||
FixedUpdatePatch.LoversSuicide();
|
||||
}
|
||||
catch (Exception e) { Utils.ThrowException(e); }
|
||||
|
||||
bool lobby = GameStates.IsLobby;
|
||||
|
||||
if (lobby || (Main.IntroDestroyed && GameStates.InGame && !GameStates.IsMeeting && !ExileController.Instance && !AntiBlackout.SkipTasks))
|
||||
|
||||
@@ -59,7 +59,7 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
|
||||
{
|
||||
GameOptionsSender allSender = AllSenders[index];
|
||||
|
||||
if (allSender is PlayerGameOptionsSender { IsDirty: false } sender && sender.player.IsAlive() && (sender.player.HasDesyncRole() || sender.player.GetCustomRole() == CustomRoles.Transporter || sender.player.Is(CustomRoles.Torch) || sender.player.Is(CustomRoles.Mare) || sender.player.Is(CustomRoles.Sleep) || Beacon.IsAffectedPlayer(sender.player.PlayerId)))
|
||||
if (allSender is PlayerGameOptionsSender { IsDirty: false } sender && sender.player.IsAlive() && (sender.player.HasDesyncRole() || sender.player.GetCustomRole() is CustomRoles.Transporter or CustomRoles.Lighter || sender.player.Is(CustomRoles.Torch) || sender.player.Is(CustomRoles.Mare) || sender.player.Is(CustomRoles.Sleep) || Beacon.IsAffectedPlayer(sender.player.PlayerId)))
|
||||
sender.SetDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ public class PlayerState(byte playerId)
|
||||
|
||||
public void SetMainRole(CustomRoles role)
|
||||
{
|
||||
try { Utils.RemovePlayerFromPreviousRoleData(Player); }
|
||||
try { Role.Remove(PlayerId); }
|
||||
catch (Exception e) { Utils.ThrowException(e); }
|
||||
|
||||
if (Main.IntroDestroyed && (RoleHistory.Count == 0 || RoleHistory[^1] != MainRole))
|
||||
|
||||
@@ -999,7 +999,7 @@ public static class GuessManager
|
||||
if (selectedButton != button)
|
||||
{
|
||||
selectedButton = button;
|
||||
buttons.ForEach(x => x.GetComponent<SpriteRenderer>().color = x == selectedButton ? Utils.GetRoleColor(PlayerControl.LocalPlayer.GetCustomRole()) : Main.DarkTheme.Value ? new Color(0.1f, 0.1f, 0.1f) : Color.white);
|
||||
buttons.ForEach(x => x.GetComponent<SpriteRenderer>().color = x == selectedButton ? Utils.GetRoleColor(PlayerControl.LocalPlayer.GetCustomRole()) : Main.DarkThemeForMeetingUI.Value ? new Color(0.1f, 0.1f, 0.1f) : Color.white);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -146,11 +146,13 @@ public enum LobbyStatus
|
||||
Closed
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.ExitGame))]
|
||||
[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.DisconnectInternal))]
|
||||
internal static class ExitGamePatch
|
||||
{
|
||||
public static void Prefix()
|
||||
public static void Prefix(InnerNetClient __instance)
|
||||
{
|
||||
if (__instance is not AmongUsClient) return;
|
||||
|
||||
Logger.Msg("Exiting game", "ExitGamePatch.Prefix");
|
||||
|
||||
Main.RealOptionsData?.Restore(GameOptionsManager.Instance.CurrentGameOptions);
|
||||
@@ -162,8 +164,10 @@ internal static class ExitGamePatch
|
||||
}
|
||||
}
|
||||
|
||||
public static void Postfix()
|
||||
public static void Postfix(InnerNetClient __instance)
|
||||
{
|
||||
if (__instance is not AmongUsClient) return;
|
||||
|
||||
LobbySharingAPI.NotifyLobbyStatusChanged(LobbyStatus.Closed);
|
||||
|
||||
GameEndChecker.LoadingEndScreen = false;
|
||||
|
||||
+1
-3
@@ -1481,7 +1481,6 @@ internal static class RPC
|
||||
|
||||
int amountAllOptions = OptionItem.AllOptions.Count;
|
||||
|
||||
Logger.Msg(" Starting", "SyncCustomSettings");
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncCustomSettings, SendOption.Reliable, targetId);
|
||||
writer.Write(startAmount);
|
||||
writer.Write(lastAmount);
|
||||
@@ -1492,13 +1491,12 @@ internal static class RPC
|
||||
for (int option = startAmount; option < amountAllOptions && option <= lastAmount; option++) listOptions.Add(OptionItem.AllOptions[option]);
|
||||
|
||||
int countListOptions = listOptions.Count;
|
||||
Logger.Msg($"StartAmount: {startAmount} - LastAmount: {lastAmount} ({startAmount}/{lastAmount}) :--: ListOptionsCount: {countListOptions} - AllOptions: {amountAllOptions} ({countListOptions}/{amountAllOptions})", "SyncCustomSettings");
|
||||
Logger.Info($"StartAmount: {startAmount} - LastAmount: {lastAmount} ({startAmount}/{lastAmount}) :--: ListOptionsCount: {countListOptions} - AllOptions: {amountAllOptions} ({countListOptions}/{amountAllOptions})", "SyncCustomSettings");
|
||||
|
||||
// Sync Settings
|
||||
foreach (OptionItem option in listOptions) writer.WritePacked(option.GetValue());
|
||||
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
Logger.Msg(" Finished", "SyncCustomSettings");
|
||||
}
|
||||
|
||||
public static void PlaySoundRPC(byte playerID, Sounds sound)
|
||||
|
||||
@@ -165,7 +165,7 @@ public static class Translator
|
||||
|
||||
try
|
||||
{
|
||||
if (TranslateMaps.TryGetValue(str, out Dictionary<int, string> dic) && (!dic.TryGetValue((int)langId, out res) || string.IsNullOrWhiteSpace(res) || (langId is not SupportedLangs.SChinese and not SupportedLangs.TChinese && Regex.IsMatch(res, @"[\u4e00-\u9fa5]") && res == GetString(str, SupportedLangs.SChinese))))
|
||||
if (TranslateMaps.TryGetValue(str, out Dictionary<int, string> dic) && (!dic.TryGetValue((int)langId, out res) || string.IsNullOrEmpty(res) || (langId is not SupportedLangs.SChinese and not SupportedLangs.TChinese && Regex.IsMatch(res, @"[\u4e00-\u9fa5]") && res == GetString(str, SupportedLangs.SChinese))))
|
||||
res = langId == SupportedLangs.English ? $"*{str}" : GetString(str, SupportedLangs.English);
|
||||
|
||||
if (!TranslateMaps.ContainsKey(str) && Enum.GetValues<StringNames>().FindFirst(x => x.ToString() == str, out StringNames stringNames))
|
||||
|
||||
+1
-11
@@ -460,12 +460,6 @@ public static class Utils
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemovePlayerFromPreviousRoleData(PlayerControl target)
|
||||
{
|
||||
if (!Main.PlayerStates.TryGetValue(target.PlayerId, out PlayerState state)) return;
|
||||
state.Role.Remove(target.PlayerId);
|
||||
}
|
||||
|
||||
public static string GetDisplayRoleName(byte playerId, bool pure = false, bool seeTargetBetrayalAddons = false)
|
||||
{
|
||||
(string, Color) textData = GetRoleText(playerId, playerId, pure, seeTargetBetrayalAddons);
|
||||
@@ -1177,7 +1171,7 @@ public static class Utils
|
||||
}
|
||||
|
||||
TaskState taskState = state.TaskState;
|
||||
if (!taskState.HasTasks) return string.Empty;
|
||||
if (!taskState.HasTasks || taskState.AllTasksCount == 0) return string.Empty;
|
||||
|
||||
NetworkedPlayerInfo info = GetPlayerInfoById(playerId);
|
||||
bool hasTasks = HasTasks(info);
|
||||
@@ -3455,10 +3449,6 @@ public static class Utils
|
||||
|
||||
Main.AbilityCD[playerId] = (TimeStamp, cd);
|
||||
SendRPC(CustomRPC.SyncAbilityCD, 1, playerId, cd);
|
||||
|
||||
if (role.SimpleAbilityTrigger() &&
|
||||
(Options.UsePhantomBasis.GetBool() && (!role.IsNeutral() || Options.UsePhantomBasisForNKs.GetBool())) && !role.AlwaysUsesPhantomBase())
|
||||
GetPlayerById(playerId)?.RpcResetAbilityCooldown();
|
||||
}
|
||||
|
||||
public static (RoleTypes RoleType, CustomRoles CustomRole) GetRoleMap(byte seerId, byte targetId = byte.MaxValue)
|
||||
|
||||
@@ -291,17 +291,17 @@ internal static class GameEndChecker
|
||||
|
||||
if (WinnerTeam != CustomWinner.CustomTeam && CustomTeamManager.EnabledCustomTeams.Count > 0)
|
||||
{
|
||||
Dictionary<CustomTeamManager.CustomTeam, IEnumerable<byte>> teams = Main.AllPlayerControls
|
||||
Dictionary<CustomTeamManager.CustomTeam, byte[]> teams = Main.AllPlayerControls
|
||||
.Select(x => new { Team = CustomTeamManager.GetCustomTeam(x.PlayerId), Player = x })
|
||||
.Where(x => x.Team != null)
|
||||
.GroupBy(x => x.Team)
|
||||
.ToDictionary(x => x.Key, x => x.Select(y => y.Player.PlayerId));
|
||||
.ToDictionary(x => x.Key, x => x.Select(y => y.Player.PlayerId).ToArray());
|
||||
|
||||
foreach ((CustomTeamManager.CustomTeam team, IEnumerable<byte> playerIds) in teams)
|
||||
foreach ((CustomTeamManager.CustomTeam team, byte[] playerIds) in teams)
|
||||
{
|
||||
bool winWithOriginalTeam = CustomTeamManager.IsSettingEnabledForTeam(team, CTAOption.WinWithOriginalTeam);
|
||||
|
||||
if (CustomTeamManager.IsSettingEnabledForTeam(team, CTAOption.OriginalWinCondition) && (winWithOriginalTeam || WinnerTeam is not (CustomWinner.Impostor or CustomWinner.Crewmate or CustomWinner.Coven or CustomWinner.Neutrals)))
|
||||
if (CustomTeamManager.IsSettingEnabledForTeam(team, CTAOption.OriginalWinCondition) && playerIds.Any(WinnerIds.Contains) && (winWithOriginalTeam || WinnerTeam is not (CustomWinner.Impostor or CustomWinner.Crewmate or CustomWinner.Coven or CustomWinner.Neutrals)))
|
||||
WinnerIds.UnionWith(playerIds);
|
||||
else if (!winWithOriginalTeam)
|
||||
WinnerIds.ExceptWith(playerIds);
|
||||
|
||||
@@ -21,6 +21,7 @@ public static class OptionsMenuBehaviourStartPatch
|
||||
private static ClientOptionItem EnableCustomSoundEffect;
|
||||
private static ClientOptionItem SwitchVanilla;
|
||||
private static ClientOptionItem DarkTheme;
|
||||
private static ClientOptionItem DarkThemeForMeetingUI;
|
||||
private static ClientOptionItem HorseMode;
|
||||
private static ClientOptionItem LongMode;
|
||||
private static ClientOptionItem ShowPlayerInfoInLobby;
|
||||
@@ -130,6 +131,9 @@ public static class OptionsMenuBehaviourStartPatch
|
||||
|
||||
if (DarkTheme == null || DarkTheme.ToggleButton == null)
|
||||
DarkTheme = ClientOptionItem.Create("EnableDarkTheme", Main.DarkTheme, __instance);
|
||||
|
||||
if (DarkThemeForMeetingUI == null || DarkThemeForMeetingUI.ToggleButton == null)
|
||||
DarkThemeForMeetingUI = ClientOptionItem.Create("DarkThemeForMeetingUI", Main.DarkThemeForMeetingUI, __instance);
|
||||
|
||||
if (HorseMode == null || HorseMode.ToggleButton == null)
|
||||
{
|
||||
|
||||
@@ -89,7 +89,7 @@ internal static class ExileControllerWrapUpPatch
|
||||
}
|
||||
|
||||
pc.ResetKillCooldown(false);
|
||||
pc.RpcResetAbilityCooldown();
|
||||
if (!Utils.ShouldNotApplyAbilityCooldownAfterMeeting(pc)) pc.RpcResetAbilityCooldown();
|
||||
PetsHelper.RpcRemovePet(pc);
|
||||
}
|
||||
|
||||
|
||||
@@ -1418,7 +1418,7 @@ static class NamePlateDarkThemePatch
|
||||
{
|
||||
public static void Postfix(PlayerVoteArea __instance)
|
||||
{
|
||||
if (Main.DarkTheme.Value)
|
||||
if (Main.DarkThemeForMeetingUI.Value)
|
||||
__instance.Background.color = new Color(0.1f, 0.1f, 0.1f);
|
||||
}
|
||||
}
|
||||
@@ -1428,7 +1428,7 @@ static class MeetingHud_Start
|
||||
{
|
||||
public static void Postfix(MeetingHud __instance)
|
||||
{
|
||||
if (!Main.DarkTheme.Value) return;
|
||||
if (!Main.DarkThemeForMeetingUI.Value) return;
|
||||
__instance.meetingContents.transform.FindChild("PhoneUI").FindChild("baseColor").GetComponent<SpriteRenderer>().color = new Color(0.01f, 0.01f, 0.01f);
|
||||
__instance.Glass.color = new Color(0.7f, 0.7f, 0.7f, 0.3f);
|
||||
__instance.SkipVoteButton.GetComponent<SpriteRenderer>().color = new Color(0.4f, 0.4f, 0.4f);
|
||||
|
||||
@@ -869,26 +869,6 @@ internal static class StartGameHostPatch
|
||||
}
|
||||
catch (Exception e) { Utils.ThrowException(e); }
|
||||
|
||||
try
|
||||
{
|
||||
if (CustomTeamManager.EnabledCustomTeams.Count > 0)
|
||||
{
|
||||
var imps = RoleResult.Where(x => x.Value.IsImpostor() && !CustomTeamManager.CustomTeamPlayerIds.Values.Any(l => l.Contains(x.Key))).Select(x => x.Key).ToValidPlayers().ToHashSet();
|
||||
|
||||
if (imps.Count > 0)
|
||||
{
|
||||
CustomTeamManager.CustomTeamPlayerIds.Values.Flatten().ToValidPlayers().DoIf(x => x != null && x.IsImpostor() && !CustomTeamManager.IsSettingEnabledForPlayerTeam(x.PlayerId, CTAOption.WinWithOriginalTeam), ctp =>
|
||||
{
|
||||
imps.Do(imp => ctp.RpcSetRoleDesync(RoleTypes.Scientist, imp.OwnerId, setRoleMap: true));
|
||||
var sender = CustomRpcSender.Create("CustomTeamManager_SetImpostorDesync", SendOption.Reliable);
|
||||
imps.Do(imp => sender.RpcSetRole(imp, RoleTypes.Scientist, ctp.OwnerId, changeRoleMap: true));
|
||||
sender.SendMessage();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) { Utils.ThrowException(e); }
|
||||
|
||||
try
|
||||
{
|
||||
foreach (PlayerControl pc in Main.AllPlayerControls)
|
||||
@@ -1043,7 +1023,7 @@ internal static class StartGameHostPatch
|
||||
}
|
||||
catch (Exception e) { Utils.ThrowException(e); }
|
||||
|
||||
LateTask.New(CustomTeamManager.InitializeCustomTeamPlayers, 7f, log: false);
|
||||
LateTask.New(CustomTeamManager.InitializeCustomTeamPlayers, 4f, log: false);
|
||||
|
||||
if (overrideLovers) Logger.Msg(Main.LoversPlayers.Join(x => x?.GetRealName()), "Lovers");
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ public static class PhantomRolePatch
|
||||
{
|
||||
HudManager.Instance.AbilityButton.SetFromSettings(phantom.Data.Role.Ability);
|
||||
if (Utils.ShouldNotApplyAbilityCooldown(roleBase)) return false;
|
||||
phantom.Data.Role.SetCooldown();
|
||||
phantom.RpcResetAbilityCooldown();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -78,17 +78,13 @@ public static class PhantomRolePatch
|
||||
.Write(true)
|
||||
.EndRpc();
|
||||
|
||||
if (Utils.ShouldNotApplyAbilityCooldown(roleBase))
|
||||
if (!Utils.ShouldNotApplyAbilityCooldown(roleBase))
|
||||
{
|
||||
sender.EndMessage();
|
||||
sender.SendMessage();
|
||||
return false;
|
||||
sender.StartRpc(phantom.NetId, RpcCalls.ProtectPlayer)
|
||||
.WriteNetObject(phantom)
|
||||
.Write(0)
|
||||
.EndRpc();
|
||||
}
|
||||
|
||||
sender.StartRpc(phantom.NetId, RpcCalls.ProtectPlayer)
|
||||
.WriteNetObject(phantom)
|
||||
.Write(0)
|
||||
.EndRpc();
|
||||
|
||||
sender.EndMessage();
|
||||
sender.SendMessage();
|
||||
|
||||
@@ -648,7 +648,7 @@ internal static class MurderPlayerPatch
|
||||
if (target.AmOwner) RemoveDisableDevicesPatch.UpdateDisableDevices();
|
||||
|
||||
if (!target.Data.IsDead || !AmongUsClient.Instance.AmHost) return;
|
||||
if (Butcher.ButcherDeadPlayerList.Contains(target.PlayerId)) return;
|
||||
if (Butcher.ButcherDeadPlayerList.Contains(target.PlayerId) || (__instance.AmOwner && __instance.Is(CustomRoles.SoulCollector))) return;
|
||||
|
||||
PlayerControl killer = __instance; // Alternative variable
|
||||
|
||||
@@ -1377,7 +1377,8 @@ internal static class ReportDeadBodyPatch
|
||||
RpcChangeSkin(pc, new NetworkedPlayerInfo.PlayerOutfit().Set(name, 15, "", "", "", "", ""));
|
||||
}
|
||||
|
||||
if (pc.IsShifted()) pc.RpcShapeshift(pc, false);
|
||||
if (Main.CheckShapeshift.ContainsKey(pc.PlayerId))
|
||||
pc.RpcShapeshift(pc, false);
|
||||
}
|
||||
else if (!pc.Data.IsDead)
|
||||
pc.RpcExileV2();
|
||||
@@ -1671,9 +1672,6 @@ internal static class FixedUpdatePatch
|
||||
if (AmongUsClient.Instance.AmHost && inTask && alive && Options.LadderDeath.GetBool())
|
||||
FallFromLadder.FixedUpdate(player);
|
||||
|
||||
if (self && GameStates.IsInGame)
|
||||
LoversSuicide();
|
||||
|
||||
if (inTask && self && Options.DisableDevices.GetBool())
|
||||
DisableDevice.FixedUpdate();
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ public static class MushroomMixupSabotageSystemPatch
|
||||
LateTask.New(() =>
|
||||
{
|
||||
// After MushroomMixup sabotage, shapeshift cooldown sets to 0
|
||||
Main.AllAlivePlayerControls.DoIf(x => x.GetRoleTypes() != RoleTypes.Engineer, x => x.RpcResetAbilityCooldown());
|
||||
Main.AllAlivePlayerControls.DoIf(x => x.GetRoleTypes() == RoleTypes.Shapeshifter, x => x.RpcResetAbilityCooldown());
|
||||
|
||||
ReportDeadBodyPatch.CanReport.SetAllValues(true);
|
||||
}, 1.2f, "Reset Ability Cooldown Arter Mushroom Mixup");
|
||||
|
||||
@@ -1064,7 +1064,8 @@
|
||||
"ForceOwnLanguage": "Force mod to use your language if possible",
|
||||
"ForceOwnLanguageRoleName": "Force role names in your language if possible",
|
||||
"GodMode": "God Mode",
|
||||
"EnableDarkTheme": "Enable Dark Theme",
|
||||
"EnableDarkTheme": "Dark Theme for Chat UI",
|
||||
"DarkThemeForMeetingUI": "Dark Theme for Meeting UI",
|
||||
"AutoDisplayKillLog": "Display Kill-log",
|
||||
"AutoDisplayLastRoles": "Display Last Roles",
|
||||
"AutoDisplayLastAddOns": "Display Last Add-ons",
|
||||
@@ -1332,6 +1333,7 @@
|
||||
"CanKill": "Can Kill",
|
||||
"CanShapeshift": "Can <color=#ff1919>Shapeshift</color>",
|
||||
"CanGuess": "Can Guess in Guesser Mode",
|
||||
"CooldownsResetEachOther": "Ability Cooldown and Kill Cooldown Reset Each Other",
|
||||
"BombCooldown": "Bomb Cooldown",
|
||||
"AbilityUseGainWithEachTaskCompleted": "<color=#00ffff>Ability <color=#7FFFD2>Use Gains</color> With Each Task Completed</color>",
|
||||
"AbilityUseGainWithEachKill": "<color=#00ffff>Ability <color=#7FFFD2>Use Gains</color> With Each Kill</color>",
|
||||
@@ -9896,6 +9898,7 @@
|
||||
"ThiefInfo": "Steal a Killing Role",
|
||||
"ThiefInfoLong": "(Neutrals):\\nAs the Thief, you must kill someone to become their role:\\n<size=80%>- Impostor / Neutral Killing roles => become the same role as them\\n- Trickster => become Double Agent\\n- Maverick => become Serial Killer\\n- Madmate roles => become Renegade\\n- Coven roles (if enabled) => become Coven Member</size>\\nIf you kill any other role, you suicide.",
|
||||
"Thief.CanStealCovenRoles": "Can Steal <#7b3fbb>Coven</color> Roles",
|
||||
"Thief.CanKillRound1": "Can Kill on the First Round",
|
||||
"Sensor": "Sensor",
|
||||
"SensorInfo": "Whenever Someone Sabotages, You See an Arrow Towards Them",
|
||||
"SensorInfoLong": "(Crewmates):\\nAs the Sensor, whenever someone sabotages, you get a temporary arrow pointing at them.",
|
||||
|
||||
@@ -164,6 +164,9 @@ public class Dad : RoleBase
|
||||
public override void Remove(byte playerId)
|
||||
{
|
||||
Instances.Remove(this);
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
Main.AllPlayerSpeed[playerId] = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod);
|
||||
PlayerGameOptionsSender.SetDirty(playerId);
|
||||
}
|
||||
|
||||
public override void ApplyGameOptions(IGameOptions opt, byte playerId)
|
||||
|
||||
@@ -76,15 +76,18 @@ public class Imitator : RoleBase
|
||||
{
|
||||
var command = $"/imitate {playerId}";
|
||||
ChatCommands.ImitateCommand(PlayerControl.LocalPlayer, command, command.Split(' '));
|
||||
|
||||
if (ImitatingRole.ContainsKey(PlayerControl.LocalPlayer.PlayerId))
|
||||
{
|
||||
foreach (PlayerVoteArea pva in MeetingHud.Instance.playerStates)
|
||||
{
|
||||
Transform button = pva.transform.FindChild("ImitatorButton");
|
||||
if (button != null) Object.Destroy(button.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
SendRPC(playerId);
|
||||
|
||||
foreach (PlayerVoteArea pva in MeetingHud.Instance.playerStates)
|
||||
{
|
||||
Transform button = pva.transform.FindChild("ImitatorButton");
|
||||
if (button != null) Object.Destroy(button.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CreateImitatorButton(MeetingHud __instance)
|
||||
|
||||
@@ -439,7 +439,7 @@ public class Inspector : RoleBase
|
||||
|
||||
if (FirstPick.TryGetValue(lpcId, out byte firstPick))
|
||||
{
|
||||
InspectorCheckMsg(PlayerControl.LocalPlayer, $"/cp {playerId} {firstPick}");
|
||||
InspectorCheckMsg(lpcId.GetPlayer(), $"/cp {playerId} {firstPick}", lpcId.IsPlayerModdedClient());
|
||||
FirstPick.Remove(lpcId);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -18,6 +18,8 @@ public class Sapper : RoleBase
|
||||
private static OptionItem Delay;
|
||||
private static OptionItem Radius;
|
||||
private static OptionItem CanSabotage;
|
||||
private static OptionItem CanKill;
|
||||
private static OptionItem CooldownsResetEachOther;
|
||||
|
||||
private static Dictionary<Vector2, long> Bombs = [];
|
||||
|
||||
@@ -43,6 +45,12 @@ public class Sapper : RoleBase
|
||||
|
||||
CanSabotage = new BooleanOptionItem(Id + 14, "CanSabotage", false, TabGroup.ImpostorRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Sapper]);
|
||||
|
||||
CanKill = new BooleanOptionItem(Id + 15, "CanKill", true, TabGroup.ImpostorRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Sapper]);
|
||||
|
||||
CooldownsResetEachOther = new BooleanOptionItem(Id + 16, "CooldownsResetEachOther", true, TabGroup.ImpostorRoles)
|
||||
.SetParent(CanKill);
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
@@ -90,7 +98,17 @@ public class Sapper : RoleBase
|
||||
|
||||
public override bool CanUseKillButton(PlayerControl pc)
|
||||
{
|
||||
return false;
|
||||
return CanKill.GetBool();
|
||||
}
|
||||
|
||||
public override void OnMurder(PlayerControl killer, PlayerControl target)
|
||||
{
|
||||
if (!CooldownsResetEachOther.GetBool()) return;
|
||||
|
||||
if (UsePets.GetBool() && !UsePhantomBasis.GetBool())
|
||||
killer.AddAbilityCD();
|
||||
else
|
||||
killer.RpcResetAbilityCooldown();
|
||||
}
|
||||
|
||||
public override void OnPet(PlayerControl pc)
|
||||
@@ -108,6 +126,7 @@ public class Sapper : RoleBase
|
||||
if (pc == null) return false;
|
||||
if (!pc.IsAlive() || Pelican.IsEaten(pc.PlayerId)) return false;
|
||||
Bombs.TryAdd(pc.Pos(), TimeStamp);
|
||||
if (CanKill.GetBool() && CooldownsResetEachOther.GetBool()) pc.SetKillCooldown();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+26
-10
@@ -34,7 +34,7 @@ public class Silencer : RoleBase
|
||||
|
||||
public override void SetupCustomOption()
|
||||
{
|
||||
SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Silencer);
|
||||
SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Silencer, zeroOne: true);
|
||||
|
||||
SkillCooldown = new FloatOptionItem(Id + 5, "AbilityCooldown", new(2.5f, 60f, 0.5f), 30f, TabGroup.ImpostorRoles)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Silencer])
|
||||
@@ -83,12 +83,13 @@ public class Silencer : RoleBase
|
||||
|
||||
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
|
||||
{
|
||||
if (SilenceMode.GetValue() >= 1 || ForSilencer.Count >= 1) return true;
|
||||
if (SilenceMode.GetValue() >= 1) return true;
|
||||
|
||||
return killer.CheckDoubleTrigger(target, () =>
|
||||
{
|
||||
ForSilencer.Add(target.PlayerId);
|
||||
ForSilencer = [target.PlayerId];
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, killer.PlayerId, 1, target.PlayerId);
|
||||
Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target);
|
||||
killer.SetKillCooldown(3f);
|
||||
|
||||
if (killer.AmOwner)
|
||||
@@ -104,9 +105,9 @@ public class Silencer : RoleBase
|
||||
|
||||
public override bool OnShapeshift(PlayerControl shapeshifter, PlayerControl target, bool shapeshifting)
|
||||
{
|
||||
if (SilenceMode.GetValue() == 1 && ForSilencer.Count == 0 && shapeshifter.PlayerId != target.PlayerId)
|
||||
if (SilenceMode.GetValue() == 1&& shapeshifter.PlayerId != target.PlayerId)
|
||||
{
|
||||
ForSilencer.Add(target.PlayerId);
|
||||
ForSilencer = [target.PlayerId];
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, shapeshifter.PlayerId, 1, target.PlayerId);
|
||||
|
||||
if (shapeshifter.AmOwner)
|
||||
@@ -124,7 +125,7 @@ public class Silencer : RoleBase
|
||||
|
||||
public override bool OnVanish(PlayerControl pc)
|
||||
{
|
||||
if (SilenceMode.GetValue() == 2 && ForSilencer.Count == 0)
|
||||
if (SilenceMode.GetValue() == 2)
|
||||
{
|
||||
var pos = pc.Pos();
|
||||
var killRange = NormalGameOptionsV10.KillDistances[Mathf.Clamp(Main.NormalOptions.KillDistance, 0, 2)];
|
||||
@@ -132,8 +133,9 @@ public class Silencer : RoleBase
|
||||
PlayerControl target = nearPlayers.Length == 0 ? null : nearPlayers.MinBy(x => x.distance).pc;
|
||||
if (target == null) return false;
|
||||
|
||||
ForSilencer.Add(target.PlayerId);
|
||||
ForSilencer = [target.PlayerId];
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, pc.PlayerId, 1, target.PlayerId);
|
||||
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: target);
|
||||
|
||||
if (pc.AmOwner)
|
||||
{
|
||||
@@ -153,7 +155,7 @@ public class Silencer : RoleBase
|
||||
switch (reader.ReadPackedInt32())
|
||||
{
|
||||
case 1:
|
||||
ForSilencer.Add(reader.ReadByte());
|
||||
ForSilencer = [reader.ReadByte()];
|
||||
break;
|
||||
case 2:
|
||||
ForSilencer = [];
|
||||
@@ -163,8 +165,22 @@ public class Silencer : RoleBase
|
||||
|
||||
public override void AfterMeetingTasks()
|
||||
{
|
||||
if (ForSilencer.Count == 0) return;
|
||||
ForSilencer.Clear();
|
||||
if (PlayerIdList.Count == 0) return;
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, PlayerIdList[0], 2);
|
||||
PlayerIdList.ForEach(x => Utils.SendRPC(CustomRPC.SyncRoleData, x, 2));
|
||||
}
|
||||
|
||||
public override void OnReportDeadBody()
|
||||
{
|
||||
if (ForSilencer.Count == 0) return;
|
||||
Main.Instance.StartCoroutine(WaitForVote());
|
||||
return;
|
||||
|
||||
System.Collections.IEnumerator WaitForVote()
|
||||
{
|
||||
while (MeetingHud.Instance && MeetingHud.Instance.state is not (MeetingHud.VoteStates.NotVoted or MeetingHud.VoteStates.Voted) && !GameStates.IsEnded && GameStates.InGame && !ExileController.Instance) yield return null;
|
||||
if (!MeetingHud.Instance || GameStates.IsEnded || !GameStates.InGame || ExileController.Instance) yield break;
|
||||
ForSilencer.ForEach(x => MeetingHud.Instance.CastVote(x, 253)); // 253 is skip vote
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,7 +97,7 @@ public class Venerer : RoleBase
|
||||
Utils.NotifyRoles(SpecifyTarget: pc);
|
||||
LateTask.New(() =>
|
||||
{
|
||||
if (!ChangedSkin || pc == null || !pc.IsAlive()) return;
|
||||
if (!ChangedSkin || pc == null || !pc.IsAlive() || Camouflage.IsCamouflage) return;
|
||||
Utils.RpcChangeSkin(pc, outfit);
|
||||
ChangedSkin = false;
|
||||
Utils.NotifyRoles(SpecifyTarget: pc);
|
||||
|
||||
@@ -95,14 +95,17 @@ internal class Arsonist : RoleBase
|
||||
|
||||
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
|
||||
{
|
||||
float cooldown = ArsonistCooldown.GetFloat();
|
||||
|
||||
if (ArsonistCanIgniteAnytime.GetBool() && IsDoused[(killer.PlayerId, target.PlayerId)] && Utils.GetDousedPlayerCount(killer.PlayerId).Doused >= ArsonistMinPlayersToIgnite.GetInt())
|
||||
{
|
||||
killer.SetKillCooldown(cooldown);
|
||||
Ignite(killer.MyPhysics);
|
||||
return false;
|
||||
}
|
||||
|
||||
float douseTime = ArsonistDouseTime.GetFloat();
|
||||
killer.SetKillCooldown(Mathf.Approximately(douseTime, 0f) ? ArsonistCooldown.GetFloat() : douseTime);
|
||||
killer.SetKillCooldown(Mathf.Approximately(douseTime, 0f) ? cooldown : douseTime);
|
||||
|
||||
if (!IsDoused[(killer.PlayerId, target.PlayerId)] && !ArsonistTimer.ContainsKey(killer.PlayerId) && killer.RpcCheckAndMurder(target, check: true))
|
||||
{
|
||||
|
||||
+19
-14
@@ -1,4 +1,5 @@
|
||||
using AmongUs.GameOptions;
|
||||
using System.Diagnostics;
|
||||
using AmongUs.GameOptions;
|
||||
using EHR.Modules;
|
||||
using Hazel;
|
||||
|
||||
@@ -15,7 +16,7 @@ public class Duality : RoleBase
|
||||
public override bool IsEnable => On;
|
||||
|
||||
public bool KillingPhase;
|
||||
private long TimerEndTS;
|
||||
private Stopwatch Timer;
|
||||
private long LastUpdateTS;
|
||||
private byte DualityId;
|
||||
|
||||
@@ -37,7 +38,8 @@ public class Duality : RoleBase
|
||||
On = true;
|
||||
KillingPhase = true;
|
||||
DualityId = playerId;
|
||||
ResetTimer();
|
||||
Timer = new();
|
||||
LateTask.New(() => Timer = Stopwatch.StartNew(), 10f, log: false);
|
||||
}
|
||||
|
||||
public override bool CanUseKillButton(PlayerControl pc)
|
||||
@@ -71,7 +73,7 @@ public class Duality : RoleBase
|
||||
LateTask.New(() =>
|
||||
{
|
||||
KillingPhase = false;
|
||||
killer.RpcChangeRoleBasis(CanVent.GetBool() ? CustomRoles.EngineerEHR : CustomRoles.CrewmateEHR);
|
||||
killer.RpcSetRoleGlobal(CanVent.GetBool() ? RoleTypes.Engineer : RoleTypes.Crewmate);
|
||||
killer.RpcResetTasks();
|
||||
ResetTimer();
|
||||
}, 0.2f, log: false);
|
||||
@@ -92,7 +94,7 @@ public class Duality : RoleBase
|
||||
if (LastUpdateTS == now) return;
|
||||
LastUpdateTS = now;
|
||||
|
||||
if (now >= TimerEndTS)
|
||||
if (GetRemainingTime() <= 0)
|
||||
{
|
||||
pc.Suicide();
|
||||
if (pc.AmOwner) Achievements.Type.OutOfTime.Complete();
|
||||
@@ -102,30 +104,33 @@ public class Duality : RoleBase
|
||||
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
|
||||
}
|
||||
|
||||
public override void OnReportDeadBody()
|
||||
{
|
||||
Timer.Reset();
|
||||
}
|
||||
|
||||
public override void AfterMeetingTasks()
|
||||
{
|
||||
if (TimerEndTS - Utils.TimeStamp < 8)
|
||||
{
|
||||
TimerEndTS = Utils.TimeStamp + 8;
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, DualityId, TimerEndTS, KillingPhase);
|
||||
}
|
||||
ResetTimer();
|
||||
}
|
||||
|
||||
void ResetTimer()
|
||||
{
|
||||
TimerEndTS = Utils.TimeStamp + Time.GetInt() + (Main.IntroDestroyed ? 1 : 12);
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, DualityId, TimerEndTS, KillingPhase);
|
||||
Timer = Stopwatch.StartNew();
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, DualityId, KillingPhase);
|
||||
}
|
||||
|
||||
long GetRemainingTime() => Time.GetInt() - Timer.Elapsed.Seconds;
|
||||
|
||||
public void ReceiveRPC(MessageReader reader)
|
||||
{
|
||||
TimerEndTS = long.Parse(reader.ReadString());
|
||||
KillingPhase = reader.ReadBoolean();
|
||||
Timer = Stopwatch.StartNew();
|
||||
}
|
||||
|
||||
public override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool meeting = false)
|
||||
{
|
||||
if (seer.PlayerId != DualityId || seer.PlayerId != target.PlayerId || (!hud && seer.IsModdedClient()) || meeting || !seer.IsAlive()) return string.Empty;
|
||||
return $"<size=80%>{string.Format(Translator.GetString(KillingPhase ? "Duality.MustKill" : "Duality.MustDoTask"), TimerEndTS - Utils.TimeStamp)}</size>";
|
||||
return $"<size=80%>{string.Format(Translator.GetString(KillingPhase ? "Duality.MustKill" : "Duality.MustDoTask"), GetRemainingTime() - 1)}</size>";
|
||||
}
|
||||
}
|
||||
@@ -83,8 +83,6 @@ public class Shifter : RoleBase
|
||||
|
||||
CustomRoles targetRole = target.GetCustomRole();
|
||||
|
||||
Utils.RemovePlayerFromPreviousRoleData(target);
|
||||
|
||||
killer.RpcSetCustomRole(targetRole);
|
||||
killer.RpcChangeRoleBasis(targetRole);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ public class Thief : RoleBase
|
||||
|
||||
private static OptionItem CanStealCovenRoles;
|
||||
private static OptionItem ImpostorVision;
|
||||
private static OptionItem CanKillRound1;
|
||||
|
||||
public override bool IsEnable => On;
|
||||
|
||||
@@ -15,7 +16,8 @@ public class Thief : RoleBase
|
||||
{
|
||||
StartSetup(656400)
|
||||
.AutoSetupOption(ref CanStealCovenRoles, false)
|
||||
.AutoSetupOption(ref ImpostorVision, false);
|
||||
.AutoSetupOption(ref ImpostorVision, false)
|
||||
.AutoSetupOption(ref CanKillRound1, false);
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
@@ -30,7 +32,7 @@ public class Thief : RoleBase
|
||||
|
||||
public override bool CanUseKillButton(PlayerControl pc)
|
||||
{
|
||||
return pc.IsAlive();
|
||||
return !MeetingStates.FirstMeeting || CanKillRound1.GetBool();
|
||||
}
|
||||
|
||||
public override void ApplyGameOptions(IGameOptions opt, byte playerId)
|
||||
|
||||
Reference in new issue
Block a user