Compare commits

...
25 Commits
Author SHA1 Message Date
Gurge44 31fa873101 Merge remote-tracking branch 'origin/main' 2025-12-24 13:57:34 +01:00
Gurge44 8fb609da02 just more fixes 2025-12-24 13:57:22 +01:00
gurge44 (via Bot) d5dff9d184 Add EAC entry: f8452a9d1 2025-12-24 11:12:02 +00:00
Joshua Carter 476bf3329a Fixed a security vulnerability with RequestCommandProcessingFromHost (#445) 2025-12-24 08:54:37 +01:00
zypheruskhan711 (via Bot) d5501713a3 Edit EAC entry: b493df896 2025-12-23 18:19:06 +00:00
zypheruskhan711 (via Bot) 36d0791abc Edit EAC entry: 9e04dc5d5 2025-12-23 18:13:44 +00:00
Gurge44 de27150aa9 ver 2025-12-23 17:49:38 +01:00
Gurge44 197117f88f fix 2025-12-23 17:39:10 +01:00
Gurge44 b1bfaebd59 salt 2025-12-23 17:30:10 +01:00
Gurge44 f1022ffc7d Merge remote-tracking branch 'origin/main' 2025-12-23 17:26:25 +01:00
Gurge44 d87e3ae98c fix 2025-12-23 17:26:16 +01:00
Gurge44 aa4a844929 New Crowdin updates (#443)
* New translations en_us.json (Chinese Simplified)

* New translations en_us.json (Russian)

* New translations en_us.json (Chinese Simplified)

* New translations en_us.json (Polish)

* New translations en_us.json (Japanese)

* New translations en_us.json (Spanish)

* New translations en_us.json (German)

* New translations en_us.json (Hungarian)

* New translations en_us.json (Korean)

* New translations en_us.json (Chinese Traditional)

* New translations en_us.json (Portuguese, Brazilian)

* New translations en_us.json (Indonesian)

* New translations en_us.json (Persian)

* New translations en_us.json (French)

* New translations en_us.json (Romanian)

* New translations en_us.json (Vietnamese)

* New translations en_us.json (Czech)

* Update source file en_US.json
2025-12-23 17:26:05 +01:00
PEPPERcula 56f653760f String fixes (#444)
* Update Vector.cs

* Update RPC.cs

* Update Main.cs

* Update Magistrate.cs

* Update Gaslighter.cs

* Update Witch.cs
2025-12-23 17:25:54 +01:00
gurge44 (via Bot) 1c5dbae3d8 Add EAC entry: 9e04dc5d5 2025-12-23 15:53:44 +00:00
gurge44 (via Bot) e1410dec14 Add EAC entry: b493df896 2025-12-23 14:22:58 +00:00
Gurge44 ea2eaebef3 Merge remote-tracking branch 'origin/main' 2025-12-23 15:00:11 +01:00
Gurge44 06ecd40c47 more fixes 2025-12-23 14:59:58 +01:00
zypheruskhan711 (via Bot) cadc8ef35e Add EAC entry: (Contains n word) 2025-12-22 19:19:52 +00:00
Gurge44 9ce44032b3 ok noob 2025-12-22 19:51:52 +01:00
Gurge44 281e1876ab Merge remote-tracking branch 'origin/main' 2025-12-22 19:08:50 +01:00
Gurge44 333d00d22b a ton of fixes 2025-12-22 19:08:38 +01:00
zypheruskhan711 (via Bot) eba347a94d Remove EAC entry: Sarha5760 2025-12-22 16:45:08 +00:00
zypheruskhan711 (via Bot) 26ec6398f0 Add EAC entry: Sarha5760 - For Testing Purposes 2025-12-22 16:21:56 +00:00
ZypherusKhan a3a66d2fd1 Revise EACList format for player reporting (#442)
Updated the EACList.txt file to include a new format for listing cheaters, griefers, and other players, along with their associated reasons and notes.
2025-12-22 08:38:21 +01:00
PEPPERcula 15141867de Add GM color (#441)
* Update Utils.cs

* Update Utils.cs

* Update QuizMaster.cs

* Update ChatCommandPatch.cs

* Update ChatCommandPatch.cs

* Update CameraMan.cs

* Update Convener.cs

* Update Convener.cs

* Update OptionShower.cs

* Update Utils.cs
2025-12-21 20:10:50 +01:00
83 changed files with 845 additions and 668 deletions

No files matched your search

+1 -1
View File
@@ -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);
+3 -15
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Hazel;
using UnityEngine;
namespace EHR;
@@ -242,6 +243,7 @@ public static class Snowdown
public static void OnCheckMurder(PlayerControl killer, PlayerControl target)
{
killer.SetKillCooldown(5f);
if (!Data.TryGetValue(killer.PlayerId, out PlayerData killerData) || !Data.TryGetValue(target.PlayerId, out PlayerData targetData) || killerData.SnowballsReady < 1 || targetData.SnowballsReady >= targetData.MaxSnowballsReady) return;
killerData.SnowballsReady--;
targetData.SnowballsReady++;
@@ -279,20 +281,7 @@ public static class Snowdown
data.LastPosition = pos;
}
foreach (PlayerControl target in Main.AllAlivePlayerControls)
{
string suffix = GetSuffix(__instance, target);
if (!data.LastSuffix.TryGetValue(target.PlayerId, out string lastSuffix))
goto Skip;
if (lastSuffix != suffix)
Utils.NotifyRoles(SpecifySeer: __instance, SpecifyTarget: target);
Skip:
data.LastSuffix[target.PlayerId] = suffix;
}
Utils.NotifyRoles(SpecifySeer: __instance, SendOption: SendOption.None);
}
}
@@ -310,7 +299,6 @@ public static class Snowdown
private int ShopSelectedIndex;
public int Points;
private bool ShowHelp;
public readonly Dictionary<byte, string> LastSuffix = [];
public void OnSabotage(PlayerControl pc)
{
+4 -4
View File
@@ -42,8 +42,8 @@ public class Main : BasePlugin
private const string DebugKeyHash = "c0fd562955ba56af3ae20d7ec9e64c664f0facecef4b3e366e109306adeae29d";
private const string DebugKeySalt = "59687b";
private const string PluginGuid = "com.gurge44.endlesshostroles";
public const string PluginVersion = "7.0.0";
public const string PluginDisplayVersion = "7.0.0";
public const string PluginVersion = "7.0.2";
public const string PluginDisplayVersion = "7.0.2";
public const bool TestBuild = false;
public const string NeutralColor = "#ffab1b";
@@ -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);
@@ -1206,6 +1208,4 @@ public enum TieMode
Random
}
public class Coroutines : MonoBehaviour { }
+6 -3
View File
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using AmongUs.GameOptions;
using EHR.Modules;
using EHR.Patches;
using Hazel;
@@ -50,7 +51,7 @@ public static class AntiBlackout
dummyImp.RpcSetRoleGlobal(RoleTypes.Impostor);
players.Without(dummyImp).Where(x => x.GetRoleMap().RoleType != RoleTypes.Detective).Do(x => x.RpcSetRoleGlobal(RoleTypes.Crewmate));
Main.AllPlayerControls.DoIf(x => !x.IsAlive() && x.Data != null && x.Data.IsDead, x => x.RpcSetRoleGlobal(x.HasGhostRole() ? RoleTypes.GuardianAngel : RoleTypes.CrewmateGhost));
Main.AllPlayerControls.DoIf(x => !x.IsAlive() && x.Data != null && x.Data.IsDead, x => x.RpcSetRoleGlobal(GhostRolesManager.AssignedGhostRoles.TryGetValue(x.PlayerId, out var ghostRole) ? ghostRole.Instance.RoleTypes : RoleTypes.CrewmateGhost));
}
// After the ejection screen, we revert the role types to their actual values.
@@ -89,7 +90,7 @@ public static class AntiBlackout
if (seer == null || target == null) continue;
if (target.IsAlive()) target.RpcSetRoleDesync(roleType, seer.OwnerId);
else target.RpcSetRoleDesync(target.HasGhostRole() ? RoleTypes.GuardianAngel : seer.PlayerId == target.PlayerId && !(target.Is(CustomRoleTypes.Impostor) && Options.DeadImpCantSabotage.GetBool()) && Main.PlayerStates.TryGetValue(target.PlayerId, out var state) && state.Role.CanUseSabotage(target) ? RoleTypes.ImpostorGhost : RoleTypes.CrewmateGhost, seer.OwnerId);
else target.RpcSetRoleDesync(GhostRolesManager.AssignedGhostRoles.TryGetValue(targetId, out var ghostRole) ? ghostRole.Instance.RoleTypes : seerId == targetId && !(target.Is(CustomRoleTypes.Impostor) && Options.DeadImpCantSabotage.GetBool()) && Main.PlayerStates.TryGetValue(targetId, out var state) && state.Role.CanUseSabotage(target) ? RoleTypes.ImpostorGhost : RoleTypes.CrewmateGhost, seer.OwnerId);
}
catch (Exception e) { Utils.ThrowException(e); }
}
@@ -126,7 +127,9 @@ public static class AntiBlackout
pc.Exiled();
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(pc.NetId, 4, SendOption.Reliable);
AmongUsClient.Instance.FinishRpcImmediately(writer);
if (pc.HasGhostRole()) pc.RpcResetAbilityCooldown();
if (GhostRolesManager.AssignedGhostRoles.TryGetValue(pc.PlayerId, out var ghostRole) && ghostRole.Instance.RoleTypes == RoleTypes.GuardianAngel)
pc.RpcResetAbilityCooldown();
}
}
catch (Exception e) { Utils.ThrowException(e); }
+2 -2
View File
@@ -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,
+18 -1
View File
@@ -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)
+14 -1
View File
@@ -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)
+7
View File
@@ -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 or CustomRoles.Doomsayer || sender.player.Is(CustomRoles.Torch) || sender.player.Is(CustomRoles.Mare) || sender.player.Is(CustomRoles.Sleep) || Beacon.IsAffectedPlayer(sender.player.PlayerId)))
sender.SetDirty();
}
}
+1 -1
View File
@@ -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))
+3 -2
View File
@@ -33,12 +33,13 @@ internal static class GhostRolesManager
IGhostRole instance = CreateGhostRoleInstance(suitableRole);
pc.RpcSetCustomRole(suitableRole);
pc.RpcSetRoleDesync(RoleTypes.GuardianAngel, pc.OwnerId);
pc.RpcSetRoleDesync(instance.RoleTypes, pc.OwnerId);
instance.OnAssign(pc);
Main.ResetCamPlayerList.Add(pc.PlayerId);
AssignedGhostRoles[pc.PlayerId] = (suitableRole, instance);
if (suitableRole == CustomRoles.Haunter) GhostRoles.Remove(suitableRole);
if (suitableRole == CustomRoles.Haunter)
GhostRoles.Remove(suitableRole);
NotifyAboutGhostRole(pc, true);
}
+2 -2
View File
@@ -36,7 +36,7 @@ public static class GuessManager
public static string GetFormatString()
{
return Main.AllAlivePlayerControls.Aggregate(GetString("PlayerIdList"), (current, pc) => current + $"\n{pc.PlayerId.ToString()} → {pc.GetRealName()}");
return Main.AllPlayerControls.Aggregate(GetString("PlayerIdList"), (current, pc) => current + $"\n{pc.PlayerId.ToString()} → {pc.GetRealName()}");
}
private static bool CheckCommand(ref string msg, string command, bool exact = true)
@@ -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
{
+7 -3
View File
@@ -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;
+2 -2
View File
@@ -1026,7 +1026,7 @@ public static class Options
sb.AppendLine("| Command | Description | Arguments | Usage Level | Usage Time | Hidden |");
sb.AppendLine("|---------|-------------|-----------|-------------|------------|--------|");
foreach (Command command in ChatCommands.AllCommands)
foreach ((String key, Command command) in Command.AllCommands)
{
string forms = command.CommandForms.TakeWhile(x => x.All(char.IsAscii)).Join(x => $"/{x}", "<br>");
string description = command.Description;
@@ -1077,7 +1077,7 @@ public static class Options
}
sb.AppendLine("| | | | | | |");
sb.Append($"| {ChatCommands.AllCommands.Count} | | | | | |");
sb.Append($"| {Command.AllCommands.Count} | | | | | |");
const string path = "./commands.txt";
if (!File.Exists(path)) File.Create(path).Close();
+3 -2
View File
@@ -60,7 +60,7 @@ public static class OptionShower
{
if (Options.CurrentGameMode == CustomGameMode.Standard)
{
sb.Append($"<color={Utils.GetRoleColorCode(CustomRoles.GM)}>{Utils.GetRoleName(CustomRoles.GM)}:</color> {(Main.GM.Value ? GetString("RoleRate") : GetString("RoleOff"))}\n\n");
sb.Append($"<color={Utils.GetRoleColorCode(CustomRoles.GM)}>{Utils.GetRoleName(CustomRoles.GM)}</color>: {(Main.GM.Value ? GetString("RoleRate") : GetString("RoleOff"))}\n\n");
sb.Append(GetString("ActiveRolesList")).Append('\n');
var count = 4;
@@ -156,4 +156,5 @@ public static class OptionShower
if (opt.Value.GetBool()) ShowChildren(opt.Value, ref sb, color, deep + 1);
}
}
}
}
+17 -14
View File
@@ -474,7 +474,7 @@ internal static class RPCHandlerPatch
listOptions.Add(OptionItem.AllOptions[option]);
int countOptions = listOptions.Count;
Logger.Msg($"StartAmount: {startAmount} - LastAmount: {lastAmount} ({startAmount}/{lastAmount}) :--: ListOptionsCount: {countOptions} - AllOptions: {countAllOptions} ({countOptions}/{countAllOptions})", "SyncCustomSettings");
Logger.Info($"StartAmount: {startAmount} - LastAmount: {lastAmount} ({startAmount}/{lastAmount}) :--: ListOptionsCount: {countOptions} - AllOptions: {countAllOptions} ({countOptions}/{countAllOptions})", "SyncCustomSettings");
// Sync Settings
foreach (OptionItem option in listOptions)
@@ -666,18 +666,23 @@ internal static class RPCHandlerPatch
{
if (!AmongUsClient.Instance.AmHost) break;
string methodName = reader.ReadString();
string commandKey = reader.ReadString();
PlayerControl player = reader.ReadByte().GetPlayer();
string text = reader.ReadString();
bool modCommand = reader.ReadBoolean();
bool adminCommand = reader.ReadBoolean();
if (modCommand && !ChatCommands.IsPlayerModerator(player.FriendCode)) break;
if (adminCommand && !ChatCommands.IsPlayerAdmin(player.FriendCode)) break;
if (!Command.AllCommands.TryGetValue(commandKey, out Command command))
{
Logger.Error($"Invalid Command {commandKey}.", "RequestCommandProcessingFromHost");
break;
}
const BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public;
typeof(ChatCommands).GetMethod(methodName, flags)?.Invoke(null, [player, text, text.Split(' ')]);
Logger.Info($"Invoke Command: {methodName} ({player?.Data?.PlayerName}, {text})", "RequestCommandProcessing");
if (!command.CanUseCommand(player)) break;
command.Action(player, commandKey, text, text.Split(' '));
// const BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public;
// typeof(ChatCommands).GetMethod(methodName, flags)?.Invoke(null, [player, text, text.Split(' ')]);
Logger.Info($"Invoke Command: {command.Action.Method.Name} ({player?.Data?.PlayerName}, {text})", "RequestCommandProcessing");
break;
}
case CustomRPC.SyncPostman:
@@ -1360,13 +1365,13 @@ internal static class RPCHandlerPatch
{
int playerId = reader.ReadByte();
var command = $"/retribute {playerId}";
ChatCommands.RetributeCommand(__instance, command, command.Split(' '));
ChatCommands.RetributeCommand(__instance, "Command.Retribute", command, command.Split(' '));
break;
}
case CustomRPC.StarspawnClick:
{
var command = $"/daybreak";
ChatCommands.DayBreakCommand(__instance, command, command.Split(' '));
ChatCommands.DayBreakCommand(__instance, "Command.DayBreak", command, command.Split(' '));
break;
}
case CustomRPC.VentriloquistClick:
@@ -1481,7 +1486,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 +1496,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)
+1 -1
View File
@@ -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))
+4 -17
View File
@@ -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);
@@ -1395,7 +1389,7 @@ public static class Utils
}
StringBuilder sb = new("<size=80%>");
sb.Append($"{GetRoleName(CustomRoles.GM)}: {(Main.GM.Value ? GetString("RoleRate") : GetString("RoleOff"))}");
sb.Append($"<color={GetRoleColorCode(CustomRoles.GM)}>{GetRoleName(CustomRoles.GM)}</color>: {(Main.GM.Value ? GetString("RoleRate") : GetString("RoleOff"))}");
Dictionary<TabGroup, List<string>> roles = new()
{
@@ -1727,7 +1721,7 @@ public static class Utils
public static void ShowHelp(byte id)
{
PlayerControl player = GetPlayerById(id);
SendMessage(ChatCommands.AllCommands.Where(x => x.CanUseCommand(player, false) && !x.CommandForms.Contains("help")).Aggregate("<size=70%>", (s, c) => s + $"\n<b>/{c.CommandForms.TakeWhile(f => f.All(char.IsAscii)).MinBy(f => f.Length)}{(c.Arguments.Length == 0 ? string.Empty : $" {c.Arguments.Split(' ').Select((x, i) => id == 0 ? ColorString(GetColor(i), x) : x).Join(delimiter: " ")}")}</b> \u2192 {c.Description}"), id, GetString("CommandList"));
SendMessage(Command.AllCommands.Values.Where(x => x.CanUseCommand(player, false) && !x.CommandForms.Contains("help")).Aggregate("<size=70%>", (s, c) => s + $"\n<b>/{c.CommandForms.TakeWhile(f => f.All(char.IsAscii)).MinBy(f => f.Length)}{(c.Arguments.Length == 0 ? string.Empty : $" {c.Arguments.Split(' ').Select((x, i) => id == 0 ? ColorString(GetColor(i), x) : x).Join(delimiter: " ")}")}</b> \u2192 {c.Description}"), id, GetString("CommandList"));
return;
Color GetColor(int i) =>
@@ -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)
@@ -3549,16 +3539,13 @@ public static class Utils
}
Main.PlayerStates[pc.PlayerId].Role.AfterMeetingTasks();
if (pc.Is(CustomRoles.Phantasm) || pc.Is(CustomRoles.Haunter))
pc.RpcResetAbilityCooldown();
if (pc.Is(CustomRoles.TaskMaster))
TaskMaster.AfterMeetingTasks(pc);
Main.CheckShapeshift[pc.PlayerId] = false;
}
catch (System.Exception e) { ThrowException(e); }
catch (Exception e) { ThrowException(e); }
}
LateTask.New(() => Main.ProcessShapeshifts = true, 1f, log: false);
File diff suppressed because it is too large. Load diff
+4 -4
View File
@@ -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);
+4
View File
@@ -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)
{
+1 -1
View File
@@ -89,7 +89,7 @@ internal static class ExileControllerWrapUpPatch
}
pc.ResetKillCooldown(false);
pc.RpcResetAbilityCooldown();
if (!Utils.ShouldNotApplyAbilityCooldownAfterMeeting(pc)) pc.RpcResetAbilityCooldown();
PetsHelper.RpcRemovePet(pc);
}
-13
View File
@@ -1,7 +1,5 @@
using System;
using System.Linq;
using HarmonyLib;
using InnerNet;
using TMPro;
using UnityEngine;
@@ -79,16 +77,6 @@ public static class HostInfoPanelSetUpPatch
}
}
public static class LobbyPatch
{
public static bool IsGlitchedRoomCode()
{
string roomCode = GameCode.IntToGameName(AmongUsClient.Instance.GameId).ToUpper();
string[] badEndings = ["IJPG", "SZAF", "LDQG", "ALGG", "UMPG", "GFXG", "JTFG", "PATG", "WMPG", "FUGG", "YTHG", "UFLG", "FBGG", "ZCQG", "RGGG", "ZHLG", "PJDG", "KJQG", "VDXG", "LCAF"];
return badEndings.Any(roomCode.EndsWith);
}
}
// https://github.com/SuperNewRoles/SuperNewRoles/blob/master/SuperNewRoles/Patches/LobbyBehaviourPatch.cs
//[HarmonyPatch(typeof(LobbyBehaviour), nameof(LobbyBehaviour.Update))]
internal static class LobbyBehaviourUpdatePatch
@@ -110,5 +98,4 @@ internal static class LobbyBehaviourUpdatePatch
SoundManager.Instance.CrossFadeSound("MapTheme", __instance.MapTheme, 0.5f);
}
}
}
+10 -4
View File
@@ -108,7 +108,7 @@ internal static class CheckForEndVotingPatch
}
}
if (!shouldSkip && !__instance.playerStates.All(ps => ps == null || !Main.PlayerStates.TryGetValue(ps.TargetPlayerId, out PlayerState st) || st.IsDead || ps.AmDead || ps.DidVote || Utils.GetPlayerById(ps.TargetPlayerId) == null || Utils.GetPlayerById(ps.TargetPlayerId).Data == null || Utils.GetPlayerById(ps.TargetPlayerId).Data.Disconnected)) return false;
if (!shouldSkip && !__instance.playerStates.All(ps => ps == null || Silencer.ForSilencer.Contains(ps.TargetPlayerId) || !Main.PlayerStates.TryGetValue(ps.TargetPlayerId, out PlayerState st) || st.IsDead || ps.AmDead || ps.DidVote || Utils.GetPlayerById(ps.TargetPlayerId) == null || Utils.GetPlayerById(ps.TargetPlayerId).Data == null || Utils.GetPlayerById(ps.TargetPlayerId).Data.Disconnected)) return false;
NetworkedPlayerInfo exiledPlayer = PlayerControl.LocalPlayer.Data;
var tie = false;
@@ -1372,6 +1372,12 @@ internal static class MeetingHudCastVotePatch
voteCanceled = true;
}
if (Silencer.ForSilencer.Contains(srcPlayerId))
{
ShouldCancelVoteList.TryAdd(srcPlayerId, (__instance, pvaSrc, pcSrc));
voteCanceled = true;
}
Logger.Info($"{pcSrc.GetNameWithRole()} => {(skip ? "Skip" : pcTarget.GetNameWithRole())}{(voteCanceled ? " (Canceled)" : string.Empty)}", "Vote");
return skip || !voteCanceled; // return false to use the vote as a trigger; skips and invalid votes are never canceled
@@ -1418,7 +1424,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 +1434,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);
@@ -1545,7 +1551,7 @@ internal static class ExileControllerBeginPatch
{
public static void Postfix(ExileController __instance, [HarmonyArgument(0)] ExileController.InitProperties init)
{
if (Options.CurrentGameMode is CustomGameMode.Standard or CustomGameMode.TheMindGame && init is { outfit: not null })
if (CheckForEndVotingPatch.EjectionText.EndsWith("<size=0>") && Options.CurrentGameMode is CustomGameMode.Standard or CustomGameMode.TheMindGame && init is { outfit: not null })
__instance.completeString = CheckForEndVotingPatch.EjectionText[..^8];
}
+1 -21
View File
@@ -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");
+6 -10
View File
@@ -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();
+36 -7
View File
@@ -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();
@@ -1541,7 +1542,7 @@ internal static class FixedUpdatePatch
if (!BanManager.TempBanWhiteList.Contains(hashedPuid)) BanManager.TempBanWhiteList.Add(hashedPuid);
}
if (!Main.AllPlayerControls.All(x => x.Data.PlayerLevel <= 1) && !LobbyPatch.IsGlitchedRoomCode())
if (!Main.AllPlayerControls.All(x => x.Data.PlayerLevel <= 1))
{
string msg = string.Format(GetString("KickBecauseLowLevel"), player.GetRealName().RemoveHtmlTags());
Logger.SendInGame(msg, Color.yellow);
@@ -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();
@@ -2261,6 +2259,35 @@ internal static class PlayerControlCompleteTaskPatch
}
}
[HarmonyPatch(typeof(GameManager), nameof(GameManager.OnPlayerDeath))]
static class GameManagerOnPlayerDeathPatch
{
public static void Prefix([HarmonyArgument(0)] PlayerControl player, [HarmonyArgument(1)] ref bool assignGhostRole)
{
if (!ReportDeadBodyPatch.MeetingStarted && !GameStates.IsMeeting && Main.PlayerStates.Values.Any(x => x.Role is SoulCollector sc && sc.ToExile.Contains(player.PlayerId)))
assignGhostRole = false;
}
}
[HarmonyPatch(typeof(LogicRoleSelectionNormal), nameof(LogicRoleSelectionNormal.OnPlayerDeath))]
static class LogicRoleSelectionNormalOnPlayerDeathPatch
{
public static void Prefix([HarmonyArgument(0)] PlayerControl player, [HarmonyArgument(1)] ref bool assignGhostRole)
{
if (!ReportDeadBodyPatch.MeetingStarted && !GameStates.IsMeeting && Main.PlayerStates.Values.Any(x => x.Role is SoulCollector sc && sc.ToExile.Contains(player.PlayerId)))
assignGhostRole = false;
}
}
[HarmonyPatch(typeof(RoleManager), nameof(RoleManager.AssignRoleOnDeath))]
static class RoleManagerAssignRoleOnDeathPatch
{
public static bool Prefix([HarmonyArgument(0)] PlayerControl player)
{
return ReportDeadBodyPatch.MeetingStarted || GameStates.IsMeeting || !Main.PlayerStates.Values.Any(x => x.Role is SoulCollector sc && sc.ToExile.Contains(player.PlayerId));
}
}
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.Die))]
public static class PlayerControlDiePatch
{
@@ -2347,7 +2374,9 @@ internal static class PlayerControlSetRolePatch
if (roleType is RoleTypes.CrewmateGhost or RoleTypes.ImpostorGhost)
{
if (__instance.HasGhostRole() || GhostRolesManager.ShouldHaveGhostRole(__instance))
if (GhostRolesManager.AssignedGhostRoles.TryGetValue(__instance.PlayerId, out var ghostRole))
roleType = ghostRole.Instance.RoleTypes;
else if (GhostRolesManager.ShouldHaveGhostRole(__instance))
roleType = RoleTypes.GuardianAngel;
else if (!(__instance.Is(CustomRoleTypes.Impostor) && Options.DeadImpCantSabotage.GetBool()) && Main.PlayerStates.TryGetValue(__instance.PlayerId, out var state) && state.Role.CanUseSabotage(__instance))
roleType = RoleTypes.ImpostorGhost;
+4 -4
View File
@@ -141,7 +141,7 @@ internal static class OnGameJoinedPatch
}
if (Options.AutoGMPollCommandAfterJoin.GetBool() && !Options.AutoGMRotationEnabled)
ChatCommands.GameModePollCommand(PlayerControl.LocalPlayer, "/gmpoll", ["/gmpoll"]);
ChatCommands.GameModePollCommand(PlayerControl.LocalPlayer, "Command.GameModePoll", "/gmpoll", ["/gmpoll"]);
}
}
@@ -161,7 +161,7 @@ internal static class OnGameJoinedPatch
}
if (Options.AutoMPollCommandAfterJoin.GetBool() && !Options.RandomMapsMode.GetBool())
ChatCommands.MapPollCommand(PlayerControl.LocalPlayer, "/mpoll", ["/mpoll"]);
ChatCommands.MapPollCommand(PlayerControl.LocalPlayer, "Command.MapPoll", "/mpoll", ["/mpoll"]);
}
}
@@ -181,7 +181,7 @@ internal static class OnGameJoinedPatch
}
if (Options.AutoDraftStartCommandAfterJoin.GetBool())
ChatCommands.DraftStartCommand(PlayerControl.LocalPlayer, "/draftstart", ["/draftstart"]);
ChatCommands.DraftStartCommand(PlayerControl.LocalPlayer, "Command.DraftStart", "/draftstart", ["/draftstart"]);
}
}
@@ -217,7 +217,7 @@ internal static class OnGameJoinedPatch
if (Options.AutoGMRotationEnabled)
{
if (nextGM == CustomGameMode.All) ChatCommands.GameModePollCommand(PlayerControl.LocalPlayer, "/gmpoll", ["/gmpoll"]);
if (nextGM == CustomGameMode.All) ChatCommands.GameModePollCommand(PlayerControl.LocalPlayer, "Command.GameModePoll", "/gmpoll", ["/gmpoll"]);
else Options.GameMode.SetValue((int)nextGM - 1);
Logger.Info($"Auto GM Rotation: Next Game Mode = {nextGM}", "Auto GM Rotation");
+1 -1
View File
@@ -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");
+2 -2
View File
@@ -132,9 +132,9 @@ public static class TextBoxPatch
var exactMatch = false;
bool english = TranslationController.Instance.currentLanguage.languageID == SupportedLangs.English;
foreach (Command cmd in ChatCommands.AllCommands)
foreach ((string key, Command cmd) in Command.AllCommands)
{
string[] commandForms = english ? cmd.CommandForms.TakeWhile(x => x.All(char.IsAscii)).ToArray() : cmd.CommandForms;
string[] commandForms = english ? [.. cmd.CommandForms.TakeWhile(x => x.All(char.IsAscii))] : cmd.CommandForms;
foreach (string form in commandForms)
{
+125 -120
View File
@@ -1,124 +1,129 @@
## Hackers and cheaters
e3b0cb855
chancygrid#7957,1466867f1
flowerfit#4735,422cfefe8
wideink#3618,677db6a5c, Fastpathos // Hacking streamer's lobby
wiggreeny#9194,91f48d4e0
wreckastir#1163,c4088d65
ourregion#2992,米娜桑
muddytee#7260,帅哥别刀我
rugglace#7257,你好啊
dailymaze#3669,Paperchips
dewsupply#4199,Pinchic
awewitted#1541,jim
awareawe#3725,Briskflask
tilemousy#6919,三次元
homeyrifle#9095,CR7
supblond#8721,Musterrrrr
sakecivic#3834,Longmoor
fleetkey#2790,Russetpore
fizzycurve#5875,和
mediumlace#6059,Slickname
insidesnug#5858,你在干什么
innerdodge#6269,原版非mod
agileneap#1421,Dishfa
halcyondew#6797,IShowSpeed
localclue#9040,b站 残暴fell?
flexsleepy#7693,煎饼
squishsafe#1232,花生味的名字
tipbright#9969,11
nounpurple#8471,ewr32424
quillearly#9466,?
stuckink#8892,AI人机
needremiss#2326,69
shinylure#0346,MD11
visualbow#0206,【貓貓限定】我是狼
takingcent#8384,i
superbfilm#8098,Jesse
insidesnug#5858,你在干什么
tilemousy#6919,好臭的人
halfawake#6342,YOU
micesage#5792,Clamity
pupalshank#4261,999感冒灵
witfervid#6713,raven
medianoast#0198,foxy
comicfox#0635,pride
finishbaby#2850,pop666
tipsyelite#3556,Linus
joggerleft#7093,Run4Life
lordlyatom#8997,0
plaincode#3260,I
solidhay#2143,ILoveYou
homelysofa#7210,Nagva
moviebulky#3847,le ghoste
cosapt#6243,卡斯特
splaytale#9633,
socialfee#5455,原神忠诚玩家
screenawed#9893,Mealfloral
vetpiebald#7783,傻狗Windy
seemlysofa#9106,Sawdesktop
blondclue#2905,是稽不是寄
dramatoy#4080,CCBlueX
bonnyfibre#6777,TOMsuppn
nestshy#8262,A
spafain#1094,AUM
storedusty#6125,o O
farcorn#5146,Acfun
tilesteep#2740,Engineer
imagetense#5619,Chinese
gabledebb#2717.部屋潰しガチ勢SEX
lawnhoppy#4726,封禁
larkyprow#0965,9eb11d42b,hacker
rapidmatch#3120,7a320d676,rawpotato6
panslushy#9362,34aaba1bd,No one
socialnest#0628,2dc0c9013,ROFL
53b5b1a76,Cheifalike //Android No friendcode hacker
curtsyboth#4114,1f9bbee79,龙傲天》//MalumMenu
shyfortune#7692,526f950da,B站日常无语的无语君 //AUM
0a4f7e294,Melani //no friendcode hacker
sprysign#5596,064c15bb6,Onion
errantlug#6514,79f0cbe07,Kerbpoetic //AUM
levelposse#7723,virajwins // Hacking while also streaming it
gummytub#2962,0f6992415
dollepic#0847,17be4645c // DESTRUCT10
donehoof#2148
coachcalm#9343,354aa4ac3,Twinfabled // Hacking the game
goldapex#3225,a89e4420e,BoomplayYT
woveelixir#4088,42044d211,DMD 3CD //hacker and probably BoomplayYT's alt
tenpalace#1924,6a259fcd9,Goaty
pinbrittle#1538,4955c179f,Moralmaser // Cheating and disrupting lobbies
dollfly#4791,5ba449454,Mari // Spamming RPCs to crash lobbies
# Format: friendcode | hashPUID | ign | reason | notes
## Griefers, toxic, harrasing, morons
setmolar#4374,藏族顶针
overtfeast#5802,黑影
roomybump#8560,中国国民党
whipsame#5558,齐心 习母
epicdoer#2966,毛泽车
ternaryjog#6069,习皇帝万岁
bigtunnel#1506,카제하야가꿈 //Discrimination against Chinese
feeprim#7337,Athena //Racism
sassycalf#9283,db2adda95,Caesar
afootauto#1216,026ad9f54,你妈阴道有蛆
rubykop#0410,a1de8a400,习主席近平
netgaff#6739,01b5992f0,李克强
apemv#5959,77c89daa8
lineraring#9796,02c2ce996 //Toxic, was attempting to hack games
secretname#8564,aa9e48c80
polkaoval#0453,自作Modな橋本環奈
driedbreak#2568, 2f9986d9f, ASHHHOLE //(toxic)
markedfee#5991, 10e7b3318, (name-not-known) //(toxic)
freepurse#4452, ee4c01545, Brinysouth //spamming with the n word
jetevery#3237, f00da9258, Nigertien //the n word
jumpypool#9964, 7475bd199, NigH8R // the n word
gougesole#0734,ed140c20d // Pedophile Behaviour
deltamalty#8755,Nggeereee
polarsail#2468,hatenggers
primesnow#4272,65b98a6de, HiverXM // the n word
## Cheaters
| e3b0cb855 | | Cheating |
chancygrid#7957 | 1466867f1 | | Cheating |
flowerfit#4735 | 422cfefe8 | | Cheating |
wideink#3618 | 677db6a5c | Fastpathos | Cheating | Cheating in streamer's lobby
wiggreeny#9194 | 91f48d4e0 | | Cheating |
wreckastir#1163 | c4088d65 | | Cheating |
ourregion#2992 | | 米娜桑 | Cheating |
muddytee#7260 | | 帅哥别刀我 | Cheating |
rugglace#7257 | | 你好啊 | Cheating |
dailymaze#3669 | | Paperchips | Cheating |
dewsupply#4199 | | Pinchic | Cheating |
awewitted#1541 | | jim | Cheating |
awareawe#3725 | | Briskflask | Cheating |
tilemousy#6919 | | 三次元 | Cheating |
homeyrifle#9095 | | CR7 | Cheating |
supblond#8721 | | Musterrrrr | Cheating |
sakecivic#3834 | | Longmoor | Cheating |
fleetkey#2790 | | Russetpore | Cheating |
fizzycurve#5875 | | 和 | Cheating |
mediumlace#6059 | | Slickname | Cheating |
insidesnug#5858 | | 你在干什么 | Cheating |
innerdodge#6269 | | 原版非mod | Cheating |
agileneap#1421 | | Dishfa | Cheating |
halcyondew#6797 | | IShowSpeed | Cheating |
localclue#9040 | | b站 残暴fell? | Cheating |
flexsleepy#7693 | | 煎饼 | Cheating |
squishsafe#1232 | | 花生味的名字 | Cheating |
tipbright#9969 | | 11 | Cheating |
nounpurple#8471 | | ewr32424 | Cheating |
quillearly#9466 | | ? | Cheating |
stuckink#8892 | | AI人机 | Cheating |
needremiss#2326 | | 69 | Cheating |
shinylure#0346 | | MD11 | Cheating |
visualbow#0206 | | 【貓貓限定】我是狼 | Cheating |
takingcent#8384 | | i | Cheating |
superbfilm#8098 | | Jesse | Cheating |
insidesnug#5858 | | 你在干什么 | Cheating |
tilemousy#6919 | | 好臭的人 | Cheating |
halfawake#6342 | | YOU | Cheating |
micesage#5792 | | Clamity | Cheating |
pupalshank#4261 | | 999感冒灵 | Cheating |
witfervid#6713 | | raven | Cheating |
medianoast#0198 | | foxy | Cheating |
comicfox#0635 | | pride | Cheating |
finishbaby#2850 | | pop666 | Cheating |
tipsyelite#3556 | | Linus | Cheating |
joggerleft#7093 | | Run4Life | Cheating |
lordlyatom#8997 | | 0 | Cheating |
plaincode#3260 | | I | Cheating |
solidhay#2143 | | ILoveYou | Cheating |
homelysofa#7210 | | Nagva | Cheating |
moviebulky#3847 | | le ghoste | Cheating |
cosapt#6243 | | 卡斯特 | Cheating |
splaytale#9633 | | | Cheating |
socialfee#5455 | | 原神忠诚玩家 | Cheating |
screenawed#9893 | | Mealfloral | Cheating |
vetpiebald#7783 | | 傻狗Windy | Cheating |
seemlysofa#9106 | | Sawdesktop | Cheating |
blondclue#2905 | | 是稽不是寄 | Cheating |
dramatoy#4080 | | CCBlueX | Cheating |
bonnyfibre#6777 | | TOMsuppn | Cheating |
nestshy#8262 | | A | Cheating |
spafain#1094 | | AUM | Cheating |
storedusty#6125 | | o O | Cheating |
farcorn#5146 | | Acfun | Cheating |
tilesteep#2740 | | Engineer | Cheating |
imagetense#5619 | | Chinese | Cheating |
gabledebb#2717 | | 部屋潰しガチ勢SEX | Cheating |
lawnhoppy#4726 | | 封禁 | Cheating |
larkyprow#0965 | 9eb11d42b | Cheater| Cheating |
rapidmatch#3120 | 7a320d676 | rawpotato6 | Cheating |
panslushy#9362 | 34aaba1bd | No one | Cheating |
socialnest#0628 | 2dc0c9013 | ROFL | Cheating |
| 53b5b1a76 | Cheifalike | Cheating | No friendcode cheater
curtsyboth#4114 | 1f9bbee79 | 龙傲天》 | Cheating | MalumMenu
shyfortune#7692 | 526f950da | B站日常无语的无语君 | Cheating | AUM
| 0a4f7e294 | Melani | Cheating | No friendcode cheater
sprysign#5596 | 064c15bb6 | Onion | Cheating |
errantlug#6514 | 79f0cbe07 | Kerbpoetic | Cheating | AUM
levelposse#7723 | | virajwins | Cheating | Cheating while also streaming it
gummytub#2962 | 0f6992415 | | Cheating |
dollepic#0847 | 17be4645c | | Cheating | DESTRUCT10
donehoof#2148 | | | Cheating |
coachcalm#9343 | 354aa4ac3 | Twinfabled | Cheating |
goldapex#3225 | a89e4420e | BoomplayYT | Cheating |
woveelixir#4088 | 42044d211 | DMD 3CD | Cheating | Cheater and probably BoomplayYT's alt
tenpalace#1924 | 6a259fcd9 | Goaty | Cheating |
pinbrittle#1538 | 4955c179f | Moralmaser | Cheating | Cheating and disrupting lobbies
dollfly#4791 | 5ba449454 | Mari | Cheating | Spamming RPCs to crash lobbies
byechic#6270 | 91e0145f1 | (Contains n word) | Harassing a streamer with a slur in the IGN |
waiverfore#0496 | b493df896 | | Cheating in Syl's lobby |
whaleutter#4768 | 9e04dc5d5 | | Cheating in Syl's lobby | No name cheater
whimrecent#6558 | f8452a9d1 | | Cheating | no name cheater
## Griefers, Toxic, harrasing, morons
setmolar#4374 | | 藏族顶针 | Toxic |
overtfeast#5802 | | 黑影 | Toxic |
roomybump#8560 | | 中国国民党 | Toxic |
whipsame#5558 | | 齐心 习母 | Toxic |
epicdoer#2966 | | 毛泽车 | Toxic |
ternaryjog#6069 | | 习皇帝万岁 | Toxic |
bigtunnel#1506 | | 카제하야가꿈 | Toxic | Discrimination against Chinese
feeprim#7337 | | Athena | Toxic | Racism
sassycalf#9283 | db2adda95 | Caesar | Toxic |
afootauto#1216 | 026ad9f54 | 你妈阴道有蛆 | Toxic |
rubykop#0410 | a1de8a400 | 习主席近平 | Toxic |
netgaff#6739 | 01b5992f0 | 李克强 | Toxic |
apemv#5959 | 77c89daa8 | | Toxic |
lineraring#9796 | 02c2ce996 | | Toxic | Toxic, was attempting to hack games
secretname#8564 | aa9e48c80 | | Toxic |
polkaoval#0453 | | 自作Modな橋本環奈 | Toxic |
driedbreak#2568 | 2f9986d9f | ASHHHOLE | Toxic |
markedfee#5991 | 10e7b3318 | (name-not-known) | Toxic |
freepurse#4452 | ee4c01545 | Brinysouth | Toxic | Spamming with the n word
jetevery#3237 | f00da9258 | Nigertien | Toxic | The n word
jumpypool#9964 | 7475bd199 | NigH8R | Toxic | The n word
gougesole#0734 | ed140c20d | | Toxic | Pedophile Behaviour
deltamalty#8755 | | Nggeereee | Toxic |
polarsail#2468 | | hatenggers | Toxic |
primesnow#4272 | 65b98a6de | HiverXM | Toxic | The n word
## Other
tenthrope#3476,Oldishwire
greencorps#9587,4a403fe31,ellsbells
finlucky#6381,433b2e672,Wuwu
nattertame#9540,0abd54784,Wuwu // Alt account
tenthrope#3476 | | Oldishwire | Other |
greencorps#9587 | 4a403fe31 | ellsbells | Other |
finlucky#6381 | 433b2e672 | Wuwu | Other |
nattertame#9540 | 0abd54784 | Wuwu | Other | Alt account
+4 -1
View File
@@ -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.",
+4 -1
View File
@@ -1064,7 +1064,8 @@
"ForceOwnLanguage": "Erzwinge, dass der Mod nach Möglichkeit deine Sprache verwendet",
"ForceOwnLanguageRoleName": "Erzwingen Sie Rollennamen nach Möglichkeit in Ihrer Sprache",
"GodMode": "Gott-Modus",
"EnableDarkTheme": "Dunkles Thema aktivieren",
"EnableDarkTheme": "Dark Theme for Chat UI",
"DarkThemeForMeetingUI": "Dark Theme for Meeting UI",
"AutoDisplayKillLog": "Kill-Protokoll anzeigen",
"AutoDisplayLastRoles": "Letzte Rollen anzeigen",
"AutoDisplayLastAddOns": "Letzte Add-ons anzeigen",
@@ -1332,6 +1333,7 @@
"CanKill": "Kann Schächte nutzen",
"CanShapeshift": "Kann sich </color>Formwandeln</color>",
"CanGuess": "Kann im Ratemodus raten",
"CooldownsResetEachOther": "Ability Cooldown and Kill Cooldown Reset Each Other",
"BombCooldown": "Abklingzeit der Bombe",
"AbilityUseGainWithEachTaskCompleted": "<color=#00ffff>Fähigkeit <color=#7FFFD2>Gewinn</color> mit jeder erledigten Aufgabe</color>",
"AbilityUseGainWithEachKill": "<color=#00ffff>Fähigkeit <color=#7FFFD2>Gewinn</color> mit jedem Kill</color>",
@@ -9896,6 +9898,7 @@
"ThiefInfo": "Stelle eine Killer-Rolle",
"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": "Kann <#7b3fbb>Hexenzirkel</color> Rolle stehlen",
"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.",
+4 -1
View File
@@ -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.",
+4 -1
View File
@@ -1064,7 +1064,8 @@
"ForceOwnLanguage": "Forzar al mod a usar tu idioma si es posible",
"ForceOwnLanguageRoleName": "Forzar nombres de roles en tu idioma si es posible",
"GodMode": "Modo Dios",
"EnableDarkTheme": "Activar Modo Oscuro",
"EnableDarkTheme": "Dark Theme for Chat UI",
"DarkThemeForMeetingUI": "Dark Theme for Meeting UI",
"AutoDisplayKillLog": "Mostrar Registro de Asesinatos",
"AutoDisplayLastRoles": "Mostrar Roles Pasados",
"AutoDisplayLastAddOns": "Mostrar Complementos Pasados",
@@ -1332,6 +1333,7 @@
"CanKill": "Puede Matar",
"CanShapeshift": "Puede <color=#ff1919>Cambiar de Forma</color>",
"CanGuess": "Puede Adivinar en Modo Adivino",
"CooldownsResetEachOther": "Ability Cooldown and Kill Cooldown Reset Each Other",
"BombCooldown": "Tiempo de Reutilización Bomba",
"AbilityUseGainWithEachTaskCompleted": "<color=#00ffff>Usos de Habilidad <color=#7FFFD2>Ganados</color> Con Cada Tarea Completada</color>",
"AbilityUseGainWithEachKill": "<color=#00ffff>Usos de Habilidad <color=#7FFFD2>Ganados</color> Con Cada Asesinato</color>",
@@ -9896,6 +9898,7 @@
"ThiefInfo": "Steal a Killing Role",
"ThiefInfoLong": "(Neutrales):\\ncomo ladrón, debes matar a alguien para convertirse en su rol:\\n<size=80%>- Impostor / Roles de Matanza Neutral => convertirse en el mismo rol que ellos\\n- Trickster => convertirse en Doble Agente\\n- Maverick => convertirse en Asesino Serial\\n- roles Malvado => convertirse en Renegado\\n- Roles del aquelarre (si están habilitado) => convertirse en Miembro del aquelarre</size>\\nSi matas cualquier otro rol, suicidio.",
"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.",
+4 -1
View File
@@ -1064,7 +1064,8 @@
"ForceOwnLanguage": "ماد را مجبور کن تا در صورت امکان از زبان شما استفاده کند",
"ForceOwnLanguageRoleName": "نمایش اجباری اسامی نقش‌ها به زبان شما (در صورت امکان)",
"GodMode": "گاد مود",
"EnableDarkTheme": "فعال کردن تم تاریک",
"EnableDarkTheme": "Dark Theme for Chat UI",
"DarkThemeForMeetingUI": "Dark Theme for Meeting UI",
"AutoDisplayKillLog": "نمایش کیل-لاگ",
"AutoDisplayLastRoles": "نمایش آخرین نقش‌ها",
"AutoDisplayLastAddOns": "نمایش آخرین افزونه‌ها",
@@ -1332,6 +1333,7 @@
"CanKill": "می‌تواند بکشد",
"CanShapeshift": "می‌تواند <color=#ff1919>Shapeshift</color> کند",
"CanGuess": "می‌تواند در حالت Guesser حدس بزند",
"CooldownsResetEachOther": "Ability Cooldown and Kill Cooldown Reset Each Other",
"BombCooldown": "Bomb Cooldown",
"AbilityUseGainWithEachTaskCompleted": "<color=#00ffff>با هر تسک انجام شده، قابلیت <color=#7FFFD2>یک استفاده جدید</color> به دست می‌آورد</color>",
"AbilityUseGainWithEachKill": "<color=#00ffff>با هر کیل، قابلیت <color=#7FFFD2>یک استفاده جدید</color> به دست می‌آورد</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.",
+4 -1
View File
@@ -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": "(Neutres):\\nEn tant que Voleur, vous devez tuer quelqu'un pour devenir à votre tour son rôle :\\n<size=80%>- Imposteur / Rôle Neutre Tueur => devenez le même rôle qu'eux\\n- Filou => devenez Agent Double\\n- Maverick => devenez Tueur en Série\\n- Rôles Complices => devenez Renégat\\n- Rôles Coven (si activé) => devenez Membre de Coven</size>\\nSi vous tuez un autre rôle, vous vous suicidez.",
"Thief.CanStealCovenRoles": "Can Steal <#7b3fbb>Coven</color> Roles",
"Thief.CanKillRound1": "Can Kill on the First Round",
"Sensor": "Sondeur",
"SensorInfo": "À chaque fois que quelqu'un Sabote, vous obtenez une flèche vers eux",
"SensorInfoLong": "(Coéquipier):\\nEn tant que Sondeur, chaque fois que quelqu'un sabotage, vous obtenez une flèche temporaire pointant vers eux.",
+4 -1
View File
@@ -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.",
+4 -1
View File
@@ -1064,7 +1064,8 @@
"ForceOwnLanguage": "Paksa mod menggunakan bahasa pilihanmu",
"ForceOwnLanguageRoleName": "Paksa nama peran dalam bahasa pilihanmu",
"GodMode": "Mode God",
"EnableDarkTheme": "Aktifkan Tema Gelap",
"EnableDarkTheme": "Dark Theme for Chat UI",
"DarkThemeForMeetingUI": "Dark Theme for Meeting UI",
"AutoDisplayKillLog": "Tampilkan Riwayat Pembunuhan",
"AutoDisplayLastRoles": "Tampilkan Peran Terakhir",
"AutoDisplayLastAddOns": "Tampilkan Add-on Terakhir",
@@ -1332,6 +1333,7 @@
"CanKill": "Bisa Membunuh",
"CanShapeshift": "Bisa <color=#ff1919>Shapeshift</color>",
"CanGuess": "Bisa menebak dalam mode tebak",
"CooldownsResetEachOther": "Ability Cooldown and Kill Cooldown Reset Each Other",
"BombCooldown": "Bomb Cooldown",
"AbilityUseGainWithEachTaskCompleted": "<color=#7FFFD2>Tambahan penggunaan</color> <color=#00ffff>kemampuan seiring penyelesaian misi</color>",
"AbilityUseGainWithEachKill": "<color=#7FFFD2>Tambahan penggunaan</color> <color=#00ffff>kemampuan di setiap membunuh</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.",
+4 -1
View File
@@ -1064,7 +1064,8 @@
"ForceOwnLanguage": "可能な限り あなたの言語に MODに強制させる",
"ForceOwnLanguageRoleName": "可能な限り あなたの言語に 役割名に強制させる",
"GodMode": "神 モード",
"EnableDarkTheme": "ダークテーマーを有効",
"EnableDarkTheme": "Dark Theme for Chat UI",
"DarkThemeForMeetingUI": "Dark Theme for Meeting UI",
"AutoDisplayKillLog": "キル-ログを表示する",
"AutoDisplayLastRoles": "最後の役割を表示する",
"AutoDisplayLastAddOns": "最後の属性を表示する",
@@ -1332,6 +1333,7 @@
"CanKill": "殺害ができる",
"CanShapeshift": "<color=#ff1919>変身</color>ができる",
"CanGuess": "ゲッサーモードで推測ができる",
"CooldownsResetEachOther": "Ability Cooldown and Kill Cooldown Reset Each Other",
"BombCooldown": "爆弾のクールダウン",
"AbilityUseGainWithEachTaskCompleted": "<color=#00ffff>タスクの完了ごとの 能力<color=#7FFFD2>使用の獲得量</color></color>",
"AbilityUseGainWithEachKill": "<color=#00ffff>殺害ごとの 能力<color=#7FFFD2>使用の獲得量</color></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.",
+4 -1
View File
@@ -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.",
+4 -1
View File
@@ -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.",
+4 -1
View File
@@ -1064,7 +1064,8 @@
"ForceOwnLanguage": "Forçar o mod a usar seu idioma, se possível",
"ForceOwnLanguageRoleName": "Forçar nomes de função em seu idioma, se possível",
"GodMode": "Modo Deus",
"EnableDarkTheme": "Habilitar Tema Escuro",
"EnableDarkTheme": "Dark Theme for Chat UI",
"DarkThemeForMeetingUI": "Dark Theme for Meeting UI",
"AutoDisplayKillLog": "Exibição Automática de Mortes",
"AutoDisplayLastRoles": "Exibição Automática das Funções Passadas",
"AutoDisplayLastAddOns": "Exibição Automática dos Atributos Passados",
@@ -1332,6 +1333,7 @@
"CanKill": "Pode assassinar",
"CanShapeshift": "Pode Can <color=#ff1919>Metamorfar</color>",
"CanGuess": "Pode adivinhar no Modo Adivinhador",
"CooldownsResetEachOther": "Ability Cooldown and Kill Cooldown Reset Each Other",
"BombCooldown": "Recarga de Bomba",
"AbilityUseGainWithEachTaskCompleted": "Ganho de usos de habilidades a cada tarefa concluída",
"AbilityUseGainWithEachKill": "Ganho de usos de habilidades a cada abate sucedido",
@@ -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.",
+4 -1
View File
@@ -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.",
+4 -1
View File
@@ -1064,7 +1064,8 @@
"ForceOwnLanguage": "Использовать ваш язык если возможно",
"ForceOwnLanguageRoleName": "Использовать имя роли на вашем языке если возможно",
"GodMode": "Режим Бога",
"EnableDarkTheme": "Включить тёмную тему",
"EnableDarkTheme": "Dark Theme for Chat UI",
"DarkThemeForMeetingUI": "Dark Theme for Meeting UI",
"AutoDisplayKillLog": "Отображать килл-лог",
"AutoDisplayLastRoles": "Отображать роли прошлой игры",
"AutoDisplayLastAddOns": "Отображать атрибуты прошлой игры",
@@ -1332,6 +1333,7 @@
"CanKill": "Может убивать",
"CanShapeshift": "Может <color=#ff1919>морфиться</color>",
"CanGuess": "Может угадывать в режиме угадывателей",
"CooldownsResetEachOther": "Ability Cooldown and Kill Cooldown Reset Each Other",
"BombCooldown": "Откат бомбы",
"AbilityUseGainWithEachTaskCompleted": "<color=#00ffff>Кол-во способностей<color=#7FFFD2>, дающееся </color>за выполнение таска</color>",
"AbilityUseGainWithEachKill": "<color=#00ffff>Кол-во способностей<color=#7FFFD2>, дающееся </color>за убийство</color>",
@@ -9896,6 +9898,7 @@
"ThiefInfo": "Убейте и своруйте роль",
"ThiefInfoLong": "(Пассивный Нейтрал):\\nКак Вор, вы можете убить кого-то, чтобы забрать его роль:\\n<size=80%>- Пред/Нейтральный Убийца => Такая же роль\\n- Трюкач => Двойной Агент\\n- Индивидуалист => Маньяк\\n- Безумец => Отступник\\n-Ковен (если ВКЛ) => обычный Ковен</size>\\nЕсли вы убьёте кого-то другого, то умрёте.",
"Thief.CanStealCovenRoles": "Может своровать роль <#7b3fbb>Ковена</color>",
"Thief.CanKillRound1": "Can Kill on the First Round",
"Sensor": "Сенсор",
"SensorInfo": "Когда кто-то саботирует, вы видите на него стрелку",
"SensorInfoLong": "(Член Экипажа):\\nКак Сенсор, когда кто-то саботирует, вы получаете временную стрелку на него.",
+4 -1
View File
@@ -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.",
+10 -7
View File
@@ -145,7 +145,7 @@
"CTA.TeamEnabled.Suffix": " ",
"CTA.KnowRoles": "玩家知道他人的职业",
"CTA.WinWithOriginalTeam": "玩家可以与原来的阵营一起获胜",
"CTA.OriginalWinCondition": "Non-Teamed Original Win Condition Triggers a Team-Wide Win",
"CTA.OriginalWinCondition": "未组队时的职业的获胜条件可以作为自定义组队之后的共同获胜条件",
"CTA.KillEachOther": "玩家可以击杀他人",
"CTA.GuessEachOther": "玩家可以猜测他人",
"CTA.Arrows": "同阵营间的成员能看到彼此身上的箭头",
@@ -630,7 +630,7 @@
"ObliviousInfo": "我的天哪,好恐怖",
"BewilderInfo": "让你们也体会下弱视的感受!",
"WorkhorseInfo": "我爱当牛马,24h工作无休!",
"FoolInfo": "You can't fix lights & comms",
"FoolInfo": "你不会修理破坏",
"AvengerInfo": "我要你给我陪葬",
"YoutuberInfo": "家人们,我素材没了,重开",
"HasteInfo": "在管道中,你的击杀冷却时间会照常减少",
@@ -865,7 +865,7 @@
"BewilderInfoLong": "(附加职业):\\n迷幻者默认拥有较小的视野,当迷幻者被击杀时,凶手的视野将变得跟迷幻者一样小。",
"TruantInfoLong": "(附加职业):\\n迟疑症每轮会议后会被原地冻住一段时间。",
"WorkhorseInfoLong": "(附加职业):\\n加班狂在完成所有任务之后会获得额外的任务(任务多少取决于房主)。",
"FoolInfoLong": "(Add-ons):\\nYou can't fix Lights and Comms sabotages.",
"FoolInfoLong": "(附加职业:\\n你无法修理灯光和通讯破坏",
"AvengerInfoLong": "(附加职业):\\n房主可以设定内鬼是否可以成为复仇者。当复仇者被击杀时(被票出以及非常规击杀不算),复仇者会随机带走一名玩家。",
"YoutuberInfoLong": "(附加职业):\\n只有船员会成为UP主。当UP主是第一个在游戏中被击杀的玩家时,UP主会单独获得胜利,若UP主没有满足胜利条件,则UP主跟随船员阵营胜利。请注意:被放逐、被赌怪猜测等非直接击杀方式不会触发UP主的技能。",
"EgoistInfoLong": "(附加职业):\\n只有内鬼会成为利己主义者,利己主义者死亡就失败了。\\n利己主义者在<b>投出其他内鬼</b>且利己主义者存活到最后时单独胜利。",
@@ -1064,7 +1064,8 @@
"ForceOwnLanguage": "强制模组使用您的语言",
"ForceOwnLanguageRoleName": "强制用您的语言显示职业名",
"GodMode": "上帝模式",
"EnableDarkTheme": "应用深色主题",
"EnableDarkTheme": "Dark Theme for Chat UI",
"DarkThemeForMeetingUI": "Dark Theme for Meeting UI",
"AutoDisplayKillLog": "结束后自动显示击杀记录",
"AutoDisplayLastRoles": "结束后自动显示上局职业",
"AutoDisplayLastAddOns": "显示上局的附加职业",
@@ -1332,6 +1333,7 @@
"CanKill": "可以击杀",
"CanShapeshift": "可以 <color=#ff1919>变形</color>",
"CanGuess": "可以在赌怪模式下赌人",
"CooldownsResetEachOther": "Ability Cooldown and Kill Cooldown Reset Each Other",
"BombCooldown": "炸弹冷却",
"AbilityUseGainWithEachTaskCompleted": "<color=#00ffff>完成一项任务<color=#7FFFD2>获得</color>的技能</color>数量",
"AbilityUseGainWithEachKill": "<color=#00ffff>使用击杀时<color=#7FFFD2>获得</color>的技能</color>数量",
@@ -9896,6 +9898,7 @@
"ThiefInfo": "偷窃一个职业",
"ThiefInfoLong": "(中立职业):\\n盗贼必须击杀一名玩家并获得他的职业:\\n<size=80%>- 内鬼阵营/带刀中立职业 => 成为和他相同的职业\\n- 骗术师 => 成为双面间谍\\n- 独行者 => 成为连环杀手\\n- 叛徒阵营职业 => 成为逃亡者\\n- 巫师阵营职业 => 成为巫师阵营成员</size>\\n如果盗贼击杀其他职业的玩家,盗贼就会自杀。",
"Thief.CanStealCovenRoles": "可以偷窃<#7b3fbb>巫师</color>职业",
"Thief.CanKillRound1": "Can Kill on the First Round",
"Sensor": "传感器",
"SensorInfo": "感应一切破坏!",
"SensorInfoLong": "(船员职业):\\n传感器可以在玩家使用破坏时看到一个指向他们的临时箭头。",
@@ -10087,10 +10090,10 @@
"MoonDancerInfo": "贩卖&偷取附加职业",
"MoonDancerInfoLong": "(巫师职业):\\n巫师商人可以隐身来给自己一个随机的附加职业,你也可以用击杀键给目标一个。\\n对方如果也是巫师,你给他的是一个有益附加职业,反之是有害的(下一轮会议生效)。\\n双击击杀可以'进货'(偷走他们所有的附加职业<sup>*</sup>)\\n\\n拥有亡灵魔法后,双击会直接击杀目标并偷取他的附加职业<sup>*</sup>(如果设置允许)",
"MoonDancer.SelfAssignAddonCooldown": "Self-Assign Add-on Cooldown",
"MoonDancer.OthersAssignAddonCooldown": "Cooldown for Assigning Add-ons to Others",
"MoonDancer.StealAddonCooldown": "Add-on Stealing Cooldown",
"MoonDancer.OthersAssignAddonCooldown": "贩卖附加职业的冷却时间",
"MoonDancer.StealAddonCooldown": "附加职业偷取冷却时间",
"MoonDancer.CanStealAddonsWithoutNecronomicon": "没有亡灵魔法的情况下也能偷附加职业",
"MoonDancer.StealAllAddonsOnKill": "Steal All Add-ons On Kill",
"MoonDancer.StealAllAddonsOnKill": "在击杀后偷走所有附加职业",
"DCNotify.Hacking": "您因使用作弊工具而被<color=#ff1919>封禁</color> \\n\\n请停止你的行为。",
"DCNotify.Banned": "你已被该房间<color=#ff1919>封禁</color> \\n\\n如果这是一个错误,请联系房主。",
"DCNotify.Kicked": "你已经被 <color=#ffff00>踢出</color> 该房间.\\n\\n你可以尝试重新加入.",
+4 -1
View File
@@ -1064,7 +1064,8 @@
"ForceOwnLanguage": "強制模組使用您的語言",
"ForceOwnLanguageRoleName": "強制用您的語言顯示職業名",
"GodMode": "上帝模式",
"EnableDarkTheme": "啟用深色主題",
"EnableDarkTheme": "Dark Theme for Chat UI",
"DarkThemeForMeetingUI": "Dark Theme for Meeting UI",
"AutoDisplayKillLog": "結束後自動顯示殺人紀錄",
"AutoDisplayLastRoles": "結束後自動顯示上局職業",
"AutoDisplayLastAddOns": "結束後自動顯示上局附加職業",
@@ -1332,6 +1333,7 @@
"CanKill": "可以殺人",
"CanShapeshift": "可以<color=#ff1919>變形</color>",
"CanGuess": "可以在賭怪模式下賭人",
"CooldownsResetEachOther": "Ability Cooldown and Kill Cooldown Reset Each Other",
"BombCooldown": "炸彈冷卻時間",
"AbilityUseGainWithEachTaskCompleted": "<color=#00ffff>完成一項任務<color=#7FFFD2>獲得的</color>技能數量</color>",
"AbilityUseGainWithEachKill": "<color=#00ffff>殺死一名玩家<color=#7FFFD2>獲得的</color>技能數量</color>",
@@ -9896,6 +9898,7 @@
"ThiefInfo": "竊取被害人的職業",
"ThiefInfoLong": "(中立陣營):\\n作為小偷,你必須殺死某人才能成為他們的職業:\\n<size=80%>- 偽裝者/中立職業 => 成為與他們相同的職業\\n- 騙術師 => 成為臥底\\n- 獨行者 => 成為連環殺手\\n- 叛徒職業 => 成為逃亡者\\n- 巫師職業(如果有開) => 成為巫師陣營成員</size>\\n如果你殺死任何其他職業的玩家,你就會自殺。",
"Thief.CanStealCovenRoles": "可以偷取<#7b3fbb>巫師</color>職業",
"Thief.CanKillRound1": "Can Kill on the First Round",
"Sensor": "感測器",
"SensorInfo": "當有人進行破壞,你可以看到提示箭頭指著他們",
"SensorInfoLong": "(船員陣營):\\n作為感測器,每當有人進行破壞時,你都會得到一個指向他們的臨時箭頭。",
+2
View File
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using AmongUs.GameOptions;
using Hazel;
namespace EHR.AddOns.GhostRoles;
@@ -18,6 +19,7 @@ internal class Bloodmoon : IGhostRole
private byte BloodmoonID;
public Team Team => Team.Impostor | Team.Neutral;
public RoleTypes RoleTypes => RoleTypes.GuardianAngel;
public int Cooldown => CD.GetInt() + Main.PlayerStates.Values.Count(x => x.GetRealKiller() == BloodmoonID && x.deathReason == PlayerState.DeathReason.LossOfBlood) * CDIncreasePerUse.GetInt();
public void OnAssign(PlayerControl pc)
+4 -1
View File
@@ -1,10 +1,13 @@
namespace EHR.AddOns.GhostRoles;
using AmongUs.GameOptions;
namespace EHR.AddOns.GhostRoles;
public class Facilitator : IGhostRole
{
private static OptionItem CD;
public Team Team => Team.Coven;
public RoleTypes RoleTypes => RoleTypes.GuardianAngel;
public int Cooldown => CD.GetInt();
public void OnProtect(PlayerControl pc, PlayerControl target)
+2
View File
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using AmongUs.GameOptions;
namespace EHR.AddOns.GhostRoles;
@@ -10,6 +11,7 @@ internal class GA : IGhostRole
public HashSet<byte> ProtectionList = [];
public Team Team => Team.Crewmate;
public RoleTypes RoleTypes => RoleTypes.GuardianAngel;
public int Cooldown => CD.GetInt();
public void OnProtect(PlayerControl pc, PlayerControl target)
+10 -8
View File
@@ -14,7 +14,7 @@ internal class Haunter : IGhostRole
private static OptionItem RevealNeutralKillers;
private static OptionItem RevealMadmates;
private static OptionItem NumberOfReveals;
public static OptionItem CanWinWithCrewmates;
private static OptionItem CanWinWithCrewmates;
private static readonly string[] WinWithCrewOpts =
[
@@ -28,6 +28,7 @@ internal class Haunter : IGhostRole
private long WarnTimeStamp;
public Team Team => Team.Crewmate | Team.Neutral;
public RoleTypes RoleTypes => RoleTypes.CrewmateGhost;
public int Cooldown => 900;
public void OnProtect(PlayerControl pc, PlayerControl target) { }
@@ -47,7 +48,6 @@ internal class Haunter : IGhostRole
pc.RpcResetTasks();
pc.SyncSettings();
pc.RpcResetAbilityCooldown();
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
}, 1f, "Haunter Assign");
}
@@ -95,14 +95,14 @@ internal class Haunter : IGhostRole
};
});
WarnTimeStamp = Utils.TimeStamp + 2;
foreach (PlayerControl imp in filtered)
{
TargetArrow.Add(imp.PlayerId, pc.PlayerId);
WarnedImps.Add(imp.PlayerId);
imp.Notify(Translator.GetString("Haunter1TaskLeft"), 10f);
}
WarnTimeStamp = Utils.TimeStamp;
}
public void OnFinishedTasks(PlayerControl pc)
@@ -123,15 +123,17 @@ internal class Haunter : IGhostRole
AllHauntedPlayers.UnionWith(targets);
targets.ForEach(x => Utils.GetPlayerById(x)?.Notify(Translator.GetString("HaunterRevealedYou"), 7f));
WarnedImps.ForEach(x => Utils.GetPlayerById(x)?.Notify(Translator.GetString("HaunterFinishedTasks"), 7f));
var targetPcs = targets.ToValidPlayers();
targets.ToValidPlayers().ForEach(x => Utils.NotifyRoles(SpecifyTarget: x));
targetPcs.ForEach(x => x.Notify(Translator.GetString("HaunterRevealedYou"), 10f));
WarnedImps.ToValidPlayers().ForEach(x => x.Notify(Translator.GetString("HaunterFinishedTasks"), 10f));
targetPcs.ForEach(x => Utils.NotifyRoles(SpecifyTarget: x));
}
public void Update(PlayerControl pc)
{
if (WarnedImps.Count == 0 || WarnTimeStamp == Utils.TimeStamp) return;
if (WarnedImps.Count == 0 || WarnTimeStamp >= Utils.TimeStamp) return;
if (WarnedImps.Any(imp => TargetArrow.GetArrows(Utils.GetPlayerById(imp), pc.PlayerId) == "・"))
{
+4 -1
View File
@@ -1,8 +1,11 @@
namespace EHR.AddOns.GhostRoles;
using AmongUs.GameOptions;
namespace EHR.AddOns.GhostRoles;
public interface IGhostRole
{
public Team Team { get; }
public RoleTypes RoleTypes { get; }
public int Cooldown { get; }
public void OnProtect(PlayerControl pc, PlayerControl target);
public void OnAssign(PlayerControl pc);
+2
View File
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using AmongUs.GameOptions;
using EHR.Modules;
namespace EHR.AddOns.GhostRoles;
@@ -11,6 +12,7 @@ internal class Minion : IGhostRole
private static OptionItem CD;
public Team Team => Team.Impostor;
public RoleTypes RoleTypes => RoleTypes.GuardianAngel;
public int Cooldown => CD.GetInt();
public void OnProtect(PlayerControl pc, PlayerControl target)
+1 -1
View File
@@ -10,6 +10,7 @@ internal class Phantasm : IGhostRole
public bool IsWon;
public Team Team => Team.Neutral;
public RoleTypes RoleTypes => RoleTypes.CrewmateGhost;
public int Cooldown => 900;
public void OnAssign(PlayerControl pc)
@@ -27,7 +28,6 @@ internal class Phantasm : IGhostRole
pc.RpcResetTasks();
pc.SyncSettings();
pc.RpcResetAbilityCooldown();
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
}, 1f, "Phantasm Assign");
}
+2
View File
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using AmongUs.GameOptions;
namespace EHR.AddOns.GhostRoles;
@@ -9,6 +10,7 @@ public class Shade : IGhostRole
public HashSet<byte> Protected = [];
public Team Team => Team.Neutral;
public RoleTypes RoleTypes => RoleTypes.GuardianAngel;
public int Cooldown => CD.GetInt();
public void OnProtect(PlayerControl pc, PlayerControl target)
+2
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using AmongUs.GameOptions;
namespace EHR.AddOns.GhostRoles;
@@ -13,6 +14,7 @@ internal class Warden : IGhostRole
private readonly Dictionary<byte, (long StartTimeStamp, float OriginalSpeed)> SpeedList = [];
public Team Team => Team.Crewmate;
public RoleTypes RoleTypes => RoleTypes.GuardianAngel;
public int Cooldown => CD.GetInt();
public void OnProtect(PlayerControl pc, PlayerControl target)
+3 -3
View File
@@ -81,7 +81,7 @@ public class MoonDancer : Coven
{
if (HasNecronomicon && !StealAllAddonsOnKill.GetBool()) return true;
PlayerState state = Main.PlayerStates[target.PlayerId];
state.SubRoles.FindAll(x => !killer.Is(x) && !x.IsNotAssignableMidGame() && CustomRolesHelper.CheckAddonConflict(x, killer)).ForEach(x =>
state.SubRoles.FindAll(x => !killer.Is(x) && !x.IsNotAssignableMidGame() && !x.IsConverted() && CustomRolesHelper.CheckAddonConflict(x, killer)).ForEach(x =>
{
killer.RpcSetCustomRole(x);
state.RemoveSubRole(x);
@@ -94,7 +94,7 @@ public class MoonDancer : Coven
void GiveAddon()
{
CustomRoles addon = Options.GroupedAddons[target.Is(Team.Coven) ? AddonTypes.Helpful : AddonTypes.Harmful].Where(x => !target.Is(x) && !x.IsNotAssignableMidGame() && CustomRolesHelper.CheckAddonConflict(x, target)).RandomElement();
CustomRoles addon = Options.GroupedAddons[target.Is(Team.Coven) ? AddonTypes.Helpful : AddonTypes.Harmful].Where(x => !target.Is(x) && !x.IsNotAssignableMidGame() && !x.IsConverted() && CustomRolesHelper.CheckAddonConflict(x, target)).RandomElement();
if (addon == default(CustomRoles))
return;
@@ -109,7 +109,7 @@ public class MoonDancer : Coven
public override bool OnVanish(PlayerControl pc)
{
CustomRoles addon = Enum.GetValues<CustomRoles>().Where(x => x.IsAdditionRole() && !x.IsGhostRole() && !pc.Is(x) && !x.IsNotAssignableMidGame()).RandomElement();
CustomRoles addon = Enum.GetValues<CustomRoles>().Where(x => x.IsAdditionRole() && !x.IsGhostRole() && !pc.Is(x) && !x.IsNotAssignableMidGame() && !x.IsConverted()).RandomElement();
if (addon == default(CustomRoles)) return false;
pc.RpcSetCustomRole(addon);
return false;
+4 -1
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using AmongUs.GameOptions;
using EHR.Modules;
namespace EHR.Crewmate;
@@ -94,6 +95,7 @@ public class CameraMan : RoleBase
LateTask.New(() =>
{
BasePos = pc.Pos();
pc.RPCPlayCustomSound("teleport");
if (pc.TP(CameraPosition)) IsTeleported = true;
}, 2f, "CameraMan Teleport");
}
@@ -110,6 +112,7 @@ public class CameraMan : RoleBase
pc.RpcRemoveAbilityUse();
BasePos = pc.Pos();
pc.RPCPlayCustomSound("teleport");
if (pc.TP(CameraPosition)) IsTeleported = true;
}
else
@@ -133,4 +136,4 @@ public class CameraMan : RoleBase
{
return !IsThisRole(pc) || pc.Is(CustomRoles.Nimble) || pc.GetClosestVent()?.Id == ventId;
}
}
}
+1 -1
View File
@@ -83,7 +83,7 @@ public class Carrier : RoleBase
TaskMode = true;
break;
case false when pc.GetAbilityUseLimit() < 1 && pc.IsAlive():
pc.RpcSetRoleGlobal(RoleTypes.Crewmate);
pc.RpcSetRoleGlobal(RoleTypes.Crewmate, setRoleMap: true);
pc.Notify(Translator.GetString("OutOfAbilityUsesDoMoreTasks"));
TaskMode = true;
break;
+3 -1
View File
@@ -1,4 +1,5 @@
using AmongUs.GameOptions;
using EHR.Modules;
namespace EHR.Crewmate;
@@ -65,6 +66,7 @@ internal class Convener : RoleBase
{
if (pc == null || pc.GetAbilityUseLimit() < 1f) return;
pc.RPCPlayCustomSound("Teleport");
LateTask.New(() => Main.AllAlivePlayerControls.MassTP(pc.Pos(), log: true), isPet ? 0.5f : 2f, "Convener TP");
pc.RpcRemoveAbilityUse();
}
@@ -73,4 +75,4 @@ internal class Convener : RoleBase
{
return !IsThisRole(pc) || pc.Is(CustomRoles.Nimble) || pc.GetClosestVent()?.Id == ventId;
}
}
}
+3
View File
@@ -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)
+11 -8
View File
@@ -63,7 +63,7 @@ public class Imitator : RoleBase
{
int playerId = reader.ReadByte();
var command = $"/imitate {playerId}";
ChatCommands.ImitateCommand(pc, command, command.Split(' '));
ChatCommands.ImitateCommand(pc, "Command.Imitate", command, command.Split(' '));
}
private static void ImitatorOnClick(byte playerId /*, MeetingHud __instance*/)
@@ -75,16 +75,19 @@ public class Imitator : RoleBase
if (AmongUsClient.Instance.AmHost)
{
var command = $"/imitate {playerId}";
ChatCommands.ImitateCommand(PlayerControl.LocalPlayer, command, command.Split(' '));
ChatCommands.ImitateCommand(PlayerControl.LocalPlayer, "Command.Imitate", 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)
+1 -1
View File
@@ -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
+2 -2
View File
@@ -107,7 +107,7 @@ public class Retributionist : RoleBase
public override void OnMeetingShapeshift(PlayerControl shapeshifter, PlayerControl target)
{
var command = $"/retribute {target.PlayerId}";
ChatCommands.RetributeCommand(shapeshifter, command, command.Split(' '));
ChatCommands.RetributeCommand(shapeshifter, "Command.Retribute", command, command.Split(' '));
}
public void ReceiveRPC(MessageReader reader)
@@ -124,7 +124,7 @@ public class Retributionist : RoleBase
if (AmongUsClient.Instance.AmHost)
{
var command = $"/retribute {playerId}";
ChatCommands.RetributeCommand(PlayerControl.LocalPlayer, command, command.Split(' '));
ChatCommands.RetributeCommand(PlayerControl.LocalPlayer, "Command.Retribute", command, command.Split(' '));
}
else
{
+1 -1
View File
@@ -249,7 +249,7 @@ public class Wizard : RoleBase
Utils.SendRPC(CustomRPC.SyncRoleData, pc.PlayerId, 4, TaskMode);
break;
case false when pc.GetAbilityUseLimit() < 1 && pc.IsAlive():
pc.RpcSetRoleGlobal(RoleTypes.Crewmate);
pc.RpcSetRoleGlobal(RoleTypes.Crewmate, setRoleMap: true);
pc.Notify(Translator.GetString("OutOfAbilityUsesDoMoreTasks"));
TaskMode = true;
Utils.SendRPC(CustomRPC.SyncRoleData, pc.PlayerId, 4, TaskMode);
+20 -6
View File
@@ -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()
@@ -83,14 +91,19 @@ public class Sapper : RoleBase
return PlaceBomb(shapeshifter);
}
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
{
return false;
}
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 +121,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;
}
+12 -10
View File
@@ -34,7 +34,7 @@ public class Silencer : RoleBase
public override void SetupCustomOption()
{
SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Silencer);
SetupSingleRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Silencer);
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,8 @@ 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));
}
}
+1 -1
View File
@@ -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);
+3 -3
View File
@@ -44,14 +44,14 @@ public class Ventriloquist : RoleBase
public override void OnMeetingShapeshift(PlayerControl shapeshifter, PlayerControl target)
{
var command = $"/target {target.PlayerId}";
ChatCommands.TargetCommand(shapeshifter, command, command.Split(' '));
ChatCommands.TargetCommand(shapeshifter, "Command.Target", command, command.Split(' '));
}
public static void ReceiveRPC(MessageReader reader, PlayerControl pc)
{
int playerId = reader.ReadByte();
var command = $"/target {playerId}";
ChatCommands.TargetCommand(pc, command, command.Split(' '));
ChatCommands.TargetCommand(pc, "Command.Target", command, command.Split(' '));
}
private static void VentriloquisttOnClick(byte playerId /*, MeetingHud __instance*/)
@@ -63,7 +63,7 @@ public class Ventriloquist : RoleBase
if (AmongUsClient.Instance.AmHost)
{
var command = $"/target {playerId}";
ChatCommands.TargetCommand(PlayerControl.LocalPlayer, command, command.Split(' '));
ChatCommands.TargetCommand(PlayerControl.LocalPlayer, "Command.Target", command, command.Split(' '));
}
else
{
+8 -4
View File
@@ -34,7 +34,7 @@ public class Witch : RoleBase
private bool IsHM;
private List<byte> SpelledPlayer = [];
private byte WitchId;
private bool SpellMode;
public override bool IsEnable => PlayerIdList.Count > 0;
@@ -67,6 +67,7 @@ public class Witch : RoleBase
PlayerIdList.Add(playerId);
SpellMode = false;
SpelledPlayer = [];
WitchId = playerId;
IsHM = Main.PlayerStates[playerId].MainRole == CustomRoles.HexMaster;
if (!IsHM) playerId.SetAbilityUseLimit(MaxSpellsPerRound.GetInt());
@@ -312,7 +313,7 @@ public class Witch : RoleBase
public override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool meeting = false)
{
if (seer == null || meeting || seer.PlayerId != target.PlayerId || !seer.Is(CustomRoles.Witch) || (seer.IsModdedClient() && !hud)) return string.Empty;
if (seer.PlayerId != WitchId || seer.PlayerId != target.PlayerId || (seer.IsModdedClient() && !hud) || meeting) return string.Empty;
var str = new StringBuilder();
@@ -339,8 +340,11 @@ public class Witch : RoleBase
public override void SetButtonTexts(HudManager hud, byte id)
{
if (SpellMode && NowSwitchTrigger is not SwitchTrigger.DoubleTrigger and not SwitchTrigger.Vanish)
hud.KillButton.OverrideText(GetString("WitchSpellButtonText"));
if (SpellMode && NowSwitchTrigger != SwitchTrigger.DoubleTrigger)
{
ActionButton button = (NowSwitchTrigger == SwitchTrigger.Vanish ? hud.AbilityButton : hud.KillButton);
button.OverrideText(IsHM ? GetString("HexButtonText") : GetString("WitchSpellButtonText"));
}
else
hud.KillButton.OverrideText(GetString("KillButtonText"));
}
+4 -1
View File
@@ -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))
{
+20 -15
View File
@@ -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, setRoleMap: true);
killer.RpcResetTasks();
ResetTimer();
}, 0.2f, log: false);
@@ -80,7 +82,7 @@ public class Duality : RoleBase
public override void OnTaskComplete(PlayerControl pc, int completedTaskCount, int totalTaskCount)
{
KillingPhase = true;
pc.RpcChangeRoleBasis(CustomRoles.Duality);
pc.RpcSetRoleDesync(RoleTypes.Impostor, pc.OwnerId, setRoleMap: true);
ResetTimer();
}
@@ -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>";
}
}
+20 -1
View File
@@ -80,6 +80,22 @@ public class Gaslighter : RoleBase
};
}
public override void SetButtonTexts(HudManager hud, byte id)
{
switch (CurrentRound)
{
case Round.Knight:
hud.KillButton?.OverrideText(Translator.GetString("MonarchKillButtonText"));
break;
case Round.Curse:
hud.KillButton?.OverrideText(Translator.GetString("WarlockCurseButtonText"));
break;
case Round.Shield:
hud.KillButton?.OverrideText(Translator.GetString("MedicalerButtonText"));
break;
}
}
public static void OnExile(byte[] exileIds)
{
try
@@ -195,12 +211,15 @@ public class Gaslighter : RoleBase
killer.SetKillCooldown();
break;
case Round.Curse:
killer.RPCPlayCustomSound("Curse");
CursedPlayers.Add(target.PlayerId);
Utils.SendRPC(CustomRPC.SyncRoleData, GaslighterId, 1, target.PlayerId);
Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target);
killer.SetKillCooldown();
break;
case Round.Shield when killer.GetAbilityUseLimit() > 0:
killer.RPCPlayCustomSound("Shield");
target.RPCPlayCustomSound("Shield");
ShieldedPlayers.Add(target.PlayerId);
Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target);
Utils.NotifyRoles(SpecifySeer: target, SpecifyTarget: target);
@@ -273,4 +292,4 @@ public class Gaslighter : RoleBase
Curse,
Shield
}
}
}
+3 -1
View File
@@ -1,4 +1,5 @@
using AmongUs.GameOptions;
using EHR.Modules;
namespace EHR.Neutral;
@@ -79,6 +80,7 @@ public class Magistrate : RoleBase
private static void UseAbility(PlayerControl pc)
{
pc.RPCPlayCustomSound("Line");
pc.RpcRemoveAbilityUse();
CallCourtNextMeeting = true;
}
@@ -89,4 +91,4 @@ public class Magistrate : RoleBase
Pet,
Vanish
}
}
}
+1
View File
@@ -285,6 +285,7 @@ internal class QuizMaster : RoleBase
MessagesToSend[Target] = sample;
RPC.PlaySoundRPC(Target, Sounds.TaskUpdateSound);
Logger.Info($"Question for {Utils.GetPlayerById(Target)?.GetNameWithRole()}: {msgTitle} - Choices: {string.Join('/', CurrentQuestion.Answers)} - Correct Answer: {CurrentQuestion.Answers[CurrentQuestion.CorrectAnswerIndex]}", "QuizMaster");
}
-2
View File
@@ -83,8 +83,6 @@ public class Shifter : RoleBase
CustomRoles targetRole = target.GetCustomRole();
Utils.RemovePlayerFromPreviousRoleData(target);
killer.RpcSetCustomRole(targetRole);
killer.RpcChangeRoleBasis(targetRole);
+5 -2
View File
@@ -61,6 +61,7 @@ public class SoulCollector : RoleBase
{
state.deathReason = PlayerState.DeathReason.Kill;
state.SetDead();
target.SetRealKiller(killer);
}
if (killer.AmOwner)
@@ -108,14 +109,16 @@ public class SoulCollector : RoleBase
{
var sender = CustomRpcSender.Create("SoulCollector Post Exile", SendOption.Reliable);
sender.StartMessage();
ToExile.ToValidPlayers().ForEach(x =>
List<PlayerControl> toExile = ToExile.ToValidPlayers();
ToExile = [];
toExile.ForEach(x =>
{
Main.AllPlayerSpeed[x.PlayerId] = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod);
x.Exiled();
sender.StartRpc(x.NetId, RpcCalls.Exiled)
.EndRpc();
});
sender.SendMessage();
ToExile = [];
}
}
}
+5
View File
@@ -180,6 +180,11 @@ public class Spider : RoleBase
}
}
public override void OnReportDeadBody()
{
Webs.SetAllValues([]);
}
public static void OnAnyoneApplyGameOptions(IGameOptions opt, byte id)
{
foreach (Spider instance in Instances)
+2 -2
View File
@@ -77,7 +77,7 @@ public class Starspawn : RoleBase
public override void OnMeetingShapeshift(PlayerControl shapeshifter, PlayerControl target)
{
const string command = "/daybreak";
ChatCommands.DayBreakCommand(shapeshifter, command, command.Split(' '));
ChatCommands.DayBreakCommand(shapeshifter, "Command.Daybreak", command, command.Split(' '));
}
public void ReceiveRPC(MessageReader reader)
@@ -93,7 +93,7 @@ public class Starspawn : RoleBase
if (AmongUsClient.Instance.AmHost)
{
var command = $"/daybreak";
ChatCommands.DayBreakCommand(PlayerControl.LocalPlayer, command, command.Split(' '));
ChatCommands.DayBreakCommand(PlayerControl.LocalPlayer, "Command.Daybreak", command, command.Split(' '));
}
else
{
+11 -2
View File
@@ -8,6 +8,8 @@ public class Thief : RoleBase
private static OptionItem CanStealCovenRoles;
private static OptionItem ImpostorVision;
private static OptionItem CanKillRound1;
private static OptionItem KillCooldown;
public override bool IsEnable => On;
@@ -15,7 +17,9 @@ public class Thief : RoleBase
{
StartSetup(656400)
.AutoSetupOption(ref CanStealCovenRoles, false)
.AutoSetupOption(ref ImpostorVision, false);
.AutoSetupOption(ref ImpostorVision, false)
.AutoSetupOption(ref CanKillRound1, false)
.AutoSetupOption(ref KillCooldown, 30f, new FloatValueRule(0f, 120f, 0.5f), OptionFormat.Seconds);
}
public override void Init()
@@ -30,7 +34,12 @@ public class Thief : RoleBase
public override bool CanUseKillButton(PlayerControl pc)
{
return pc.IsAlive();
return !MeetingStates.FirstMeeting || CanKillRound1.GetBool();
}
public override void SetKillCooldown(byte id)
{
Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
}
public override void ApplyGameOptions(IGameOptions opt, byte playerId)
+3 -3
View File
@@ -81,11 +81,11 @@ internal class Vector : RoleBase
VectorVentCount[pc.PlayerId]++;
Utils.SendRPC(CustomRPC.SyncRoleData, pc.PlayerId, pc.PlayerId);
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
pc.RPCPlayCustomSound("VectorJump");
pc.RPCPlayCustomSound("MarioJump");
if (AmongUsClient.Instance.AmHost && VectorVentCount[pc.PlayerId] >= VectorVentNumWin)
{
pc.RPCPlayCustomSound("VectorCoin");
pc.RPCPlayCustomSound("MarioCoin");
CustomWinnerHolder.ResetAndSetWinner(CustomWinner.Vector);
CustomWinnerHolder.WinnerIds.Add(pc.PlayerId);
}
@@ -97,4 +97,4 @@ internal class Vector : RoleBase
VectorVentCount.TryAdd(id, 0);
VectorVentCount[id]++;
}
}
}
+1 -1
View File
@@ -134,7 +134,7 @@ public abstract class RoleBase : IComparable<RoleBase>
if (Imitator.PlayerIdList.Contains(pc.PlayerId))
{
string command = $"/imitate {target.PlayerId}";
ChatCommands.ImitateCommand(pc, command, command.Split(' '));
ChatCommands.ImitateCommand(pc, "Command.Imitate", command, command.Split(' '));
}
}