Files

1122 lines
46 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using AmongUs.GameOptions;
using Hazel;
using InnerNet;
using System;
using System.IO;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
namespace AmongUsRevamped;
[HarmonyPatch(typeof(ChatController), nameof(ChatController.Update))]
internal static class ChatControllerUpdatePatch
{
public static void Postfix(ChatController __instance)
{
if (!__instance||!__instance.freeChatField||!__instance.freeChatField.textArea||!__instance.freeChatField.background||__instance.freeChatField.textArea.compoText == null||!__instance.freeChatField.textArea.outputText) return;
if (!__instance.quickChatField||!__instance.quickChatField.background||__instance.quickChatField.text==null) return;
if (Main.DarkTheme.Value)
{
__instance.freeChatField.background.color = new Color32(40, 40, 40, byte.MaxValue);
__instance.freeChatField.textArea.compoText.Color(Color.white);
__instance.freeChatField.textArea.outputText.color = Color.white;
__instance.quickChatField.background.color = new Color32(40, 40, 40, byte.MaxValue);
__instance.quickChatField.text.color = Color.white;
}
else
{
__instance.freeChatField.background.color = Color.white;
__instance.freeChatField.textArea.compoText.Color(Color.black);
__instance.freeChatField.textArea.outputText.color = Color.black;
__instance.quickChatField.background.color = Color.white;
__instance.quickChatField.text.color = Color.black;
}
if (Main.DisableChatModifier.Value && !__instance.freeChatField.textArea.allowAllCharacters)
{
__instance.freeChatField.textArea.AllowSymbols = false;
__instance.freeChatField.textArea.AllowEmail = false;
__instance.freeChatField.textArea.characterLimit = 100;
}
if (!Main.DisableChatModifier.Value)
{
if (__instance.timeSinceLastMessage < 0.9f)
{
__instance.timeSinceLastMessage = 0.9f;
}
__instance.freeChatField.textArea.AllowSymbols = true;
__instance.freeChatField.textArea.AllowEmail = true;
__instance.freeChatField.textArea.characterLimit = 120;
}
}
}
[HarmonyPatch(typeof(ChatBubble), nameof(ChatBubble.SetName))]
internal static class ChatBubbleSetNamePatch
{
public static void Postfix(ChatBubble __instance, [HarmonyArgument(2)] bool voted)
{
if (!__instance||!__instance.playerInfo||!__instance.playerInfo.Object||!__instance.playerInfo.Object.Data||!__instance.TextArea||!__instance.Background) return;
PlayerControl target = __instance.playerInfo.Object;
if (Main.DarkTheme.Value)
{
__instance.Background.color = new(0.1f, 0.1f, 0.1f, 1f);
__instance.TextArea.color = Color.white;
if (__instance.playerInfo.Object.Data.IsDead && Utils.InGame) __instance.Background.color = new(0.1f, 0.1f, 0.1f, 0.7f);
}
}
}
[HarmonyPatch(typeof(ChatController), nameof(ChatController.SendChat))]
internal static class SendChatPatch
{
public static string ConvertNum(string input)
{
if (string.IsNullOrEmpty(input)) return input;
int digitCount = 0;
for (int i = 0; i < input.Length; i++)
{
if (char.IsDigit(input[i]) && ++digitCount > 5)
{
var sb = new System.Text.StringBuilder(input.Length);
foreach (char c in input)
{
if (char.IsDigit(c))
sb.Append(Main.CircledDigits[c - '0']);
else
sb.Append(c);
}
return sb.ToString();
}
}
return input;
}
public static bool Prefix(ChatController __instance)
{
string msgtext = __instance.freeChatField.textArea.text.Trim();
string text = msgtext.ToLower();
string converted = ConvertNum(msgtext);
if (!AmongUsClient.Instance.AmHost) return true;
if (text == "/reload")
{
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, $"{Translator.Get("translationReloaded")}");
Translator.Reload();
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
if (text == "/dump")
{
Utils.DumpLog();
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
if (text == "/help")
{
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, $"{Translator.Get("allCommandsFull")}");
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
if (text == "/s" || text == "/start")
{
GameStartManager.Instance.BeginGame();
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
if (text == "/eg" || text == "/endgame")
{
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
if (!Utils.InGame) return false;
MessageWriter writer = AmongUsClient.Instance.StartEndGame();
writer.Write((byte)GameOverReason.ImpostorDisconnect);
AmongUsClient.Instance.FinishEndGame(writer);
return false;
}
if (text == "/em" || text == "/endmeeting")
{
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
if ( !Utils.InGame || !Utils.IsMeeting) return false;
MeetingHud.Instance.RpcClose();
return false;
}
if (text == "/private")
{
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
if (Utils.InGame) return false;
AmongUsClient.Instance.ChangeGamePublic(false);
}
if (text == "/public")
{
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
if (Utils.InGame) return false;
AmongUsClient.Instance.ChangeGamePublic(true);
}
if (text.StartsWith("/vip "))
{
PlayerControl target = null;
string arg = text.Substring(5).Trim();
foreach (PlayerControl p in PlayerControl.AllPlayerControls)
{
if (p.Data == null || p == PlayerControl.LocalPlayer) continue;
if (p.Data.PlayerName.Equals(arg, StringComparison.OrdinalIgnoreCase))
{
target = p;
break;
}
}
if (target == null)
{
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("permFail", arg));
}
else
{
File.AppendAllText(BanManager.VipListPath, "\n" + target.Data.FriendCode);
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("vipAdd", target.Data.PlayerName));
}
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
if (text.StartsWith("/moderator "))
{
PlayerControl target = null;
string arg = text.Substring(11).Trim();
foreach (PlayerControl p in PlayerControl.AllPlayerControls)
{
if (p.Data == null || p == PlayerControl.LocalPlayer) continue;
if (p.Data.PlayerName.Equals(arg, StringComparison.OrdinalIgnoreCase))
{
target = p;
break;
}
}
if (target == null)
{
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("permFail", arg));
}
else
{
File.AppendAllText(BanManager.ModeratorListPath, "\n" + target.Data.FriendCode);
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("moderatorAdd", target.Data.PlayerName));
}
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
if (text.StartsWith("/admin "))
{
PlayerControl target = null;
string arg = text.Substring(7).Trim();
foreach (PlayerControl p in PlayerControl.AllPlayerControls)
{
if (p.Data == null || p == PlayerControl.LocalPlayer) continue;
if (p.Data.PlayerName.Equals(arg, StringComparison.OrdinalIgnoreCase))
{
target = p;
break;
}
}
if (target == null)
{
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("permFail", arg));
}
else
{
File.AppendAllText(BanManager.AdminListPath, "\n" + target.Data.FriendCode);
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("adminAdd", target.Data.PlayerName));
}
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
if (text.StartsWith("/removevip "))
{
PlayerControl target = null;
string arg = text.Substring(11).Trim();
foreach (PlayerControl p in PlayerControl.AllPlayerControls)
{
if (p.Data == null || p == PlayerControl.LocalPlayer) continue;
if (p.Data.PlayerName.Equals(arg, StringComparison.OrdinalIgnoreCase))
{
target = p;
break;
}
}
if (target == null)
{
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("permFail", arg));
}
else
{
File.WriteAllLines(BanManager.VipListPath, File.ReadAllLines(BanManager.VipListPath).Where(x => x.Trim() != target.Data.FriendCode));
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("vipRemove", target.Data.PlayerName));
}
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
if (text.StartsWith("/removemoderator "))
{
PlayerControl target = null;
string arg = text.Substring(17).Trim();
foreach (PlayerControl p in PlayerControl.AllPlayerControls)
{
if (p.Data == null || p == PlayerControl.LocalPlayer) continue;
if (p.Data.PlayerName.Equals(arg, StringComparison.OrdinalIgnoreCase))
{
target = p;
break;
}
}
if (target == null)
{
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("permFail", arg));
}
else
{
File.WriteAllLines(BanManager.ModeratorListPath, File.ReadAllLines(BanManager.ModeratorListPath).Where(x => x.Trim() != target.Data.FriendCode));
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("moderatorRemove", target.Data.PlayerName));
}
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
if (text.StartsWith("/removeadmin "))
{
PlayerControl target = null;
string arg = text.Substring(13).Trim();
foreach (PlayerControl p in PlayerControl.AllPlayerControls)
{
if (p.Data == null || p == PlayerControl.LocalPlayer) continue;
if (p.Data.PlayerName.Equals(arg, StringComparison.OrdinalIgnoreCase))
{
target = p;
break;
}
}
if (target == null)
{
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("permFail", arg));
}
else
{
File.WriteAllLines(BanManager.AdminListPath, File.ReadAllLines(BanManager.AdminListPath).Where(x => x.Trim() != target.Data.FriendCode));
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("adminRemove", target.Data.PlayerName));
}
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
if (text.StartsWith("/seeker "))
{
if (!Utils.IsLobby || !Utils.isHideNSeek)
{
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
string argSeeker = text.Substring(8).Trim();
bool found = false;
foreach (PlayerControl p in PlayerControl.AllPlayerControls)
{
if (p.Data == null) continue;
if (p.Data.PlayerName.Equals(argSeeker, StringComparison.OrdinalIgnoreCase))
{
found = true;
PlayerControlSetRolePatch.manualSeekers.Add(p.PlayerId);
break;
}
}
if (found)
{
List<string> names = new();
foreach (PlayerControl pl in PlayerControl.AllPlayerControls)
{
if (PlayerControlSetRolePatch.manualSeekers.Contains(pl.PlayerId)) names.Add(pl.Data.PlayerName);
}
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("seekers") + string.Join(", ", names));
}
if (!found)
{
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, $"Player '{argSeeker}' not found.");
}
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
if (text == "/clearseeker")
{
PlayerControlSetRolePatch.manualSeekers.Clear();
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("clearedSeekers"));
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
if (text == "/seekers")
{
List<string> n = new();
foreach (PlayerControl pc in PlayerControl.AllPlayerControls)
{
if (PlayerControlSetRolePatch.manualSeekers.Contains(pc.PlayerId)) n.Add(pc.Data.PlayerName);
}
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("seekers") + string.Join(", ", n));
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
if (__instance.timeSinceLastMessage < 3f || OnGameJoinedPatch.WaitingForChat) return false;
if (text == "/mapvote")
{
if (Utils.IsLobby)
{
Utils.MapVote(false);
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
}
if (text == "/gmvote")
{
if (Utils.IsLobby)
{
Utils.ModeVote(false);
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
}
if (text == "/vote a")
{
if (Utils.MapVoteActive)
{
if (Utils.HasVoted.Contains(PlayerControl.LocalPlayer.Data.PlayerId)) return true;
Utils.skeldVotes++;
Utils.HasVoted.Add(PlayerControl.LocalPlayer.Data.PlayerId);
}
else if (Utils.ModeVoteActive)
{
if (Utils.HasModeVoted.Contains(PlayerControl.LocalPlayer.Data.PlayerId)) return true;
Utils.standardVotes++;
Utils.HasModeVoted.Add(PlayerControl.LocalPlayer.Data.PlayerId);
}
}
if (text == "/vote b")
{
if (Utils.MapVoteActive)
{
if (Utils.HasVoted.Contains(PlayerControl.LocalPlayer.Data.PlayerId)) return true;
Utils.miraVotes++;
Utils.HasVoted.Add(PlayerControl.LocalPlayer.Data.PlayerId);
}
else if (Utils.ModeVoteActive)
{
if (Utils.HasModeVoted.Contains(PlayerControl.LocalPlayer.Data.PlayerId)) return true;
Utils.noKillCooldownVotes++;
Utils.HasModeVoted.Add(PlayerControl.LocalPlayer.Data.PlayerId);
}
}
if (text == "/vote c")
{
if (Utils.MapVoteActive)
{
if (Utils.HasVoted.Contains(PlayerControl.LocalPlayer.Data.PlayerId)) return true;
Utils.polusVotes++;
Utils.HasVoted.Add(PlayerControl.LocalPlayer.Data.PlayerId);
}
else if (Utils.ModeVoteActive)
{
if (Utils.HasModeVoted.Contains(PlayerControl.LocalPlayer.Data.PlayerId)) return true;
Utils.speedrunVotes++;
Utils.HasModeVoted.Add(PlayerControl.LocalPlayer.Data.PlayerId);
}
}
if (text == "/vote d")
{
if (Utils.MapVoteActive)
{
if (Utils.HasVoted.Contains(PlayerControl.LocalPlayer.Data.PlayerId)) return true;
Utils.airshipVotes++;
Utils.HasVoted.Add(PlayerControl.LocalPlayer.Data.PlayerId);
}
else if (Utils.ModeVoteActive)
{
if (Utils.HasModeVoted.Contains(PlayerControl.LocalPlayer.Data.PlayerId)) return true;
Utils.shiftAndSeekVotes++;
Utils.HasModeVoted.Add(PlayerControl.LocalPlayer.Data.PlayerId);
}
}
if (text == "/vote e")
{
if (Utils.MapVoteActive)
{
if (Utils.HasVoted.Contains(PlayerControl.LocalPlayer.Data.PlayerId)) return true;
Utils.fungleVotes++;
Utils.HasVoted.Add(PlayerControl.LocalPlayer.Data.PlayerId);
}
else if (Utils.ModeVoteActive)
{
if (Utils.HasModeVoted.Contains(PlayerControl.LocalPlayer.Data.PlayerId)) return true;
Utils.poofAndSeekVotes++;
Utils.HasModeVoted.Add(PlayerControl.LocalPlayer.Data.PlayerId);
}
}
if (text == "/vote f")
{
if (Utils.MapVoteActive)
{
if (Utils.HasVoted.Contains(PlayerControl.LocalPlayer.Data.PlayerId)) return true;
Utils.dleksVotes++;
Utils.HasVoted.Add(PlayerControl.LocalPlayer.Data.PlayerId);
}
}
if (text == "/l" || text == "/lastgame")
{
if (string.IsNullOrEmpty(NormalGameEndChecker.LastWinReason) || Utils.InGame) return false;
Utils.ChatCommand(__instance, $"{NormalGameEndChecker.LastWinReason}", "", false);
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
if (text == "/aur" || text == "/socials")
{
Utils.ChatCommand(__instance, "AUR socials:\n\ng i t h u b . c o m /\nApeMV/AmongUsRevamped\n\nd i s c о r d . g g /\n83Zhzhyhya", "", false);
return false;
}
if (text == "/0kc" || text == "/0killcooldown")
{
Utils.ChatCommand(__instance, "0 Kill Cooldown:\n\nImpostors have no kill cooldown, and optionally can't kill after a game starts for 5 seconds", "", false);
return false;
}
if (text == "/sns" || text == "/shiftandseek")
{
Utils.ChatCommand(__instance, "Shift and Seek:\n\nImpostors can only kill someone while shapeshifted as them\nMeetings & Reports = Off", $"Crewmates win by tasks/surviving {Options.CrewAutoWinsGameAfter.GetInt()}s\nImpostors win by killing Crewmates", true);
return false;
}
if (text == "/sns2" || text == "/shiftandseek2")
{
Utils.ChatCommand(__instance, "Correctly killing a target will directly turn them into a ghost and leave no dead body", "", false);
return false;
}
if (text == "/sr" || text == "/speedrun")
{
Utils.ChatCommand(__instance, $"Speedrun:\n\nEveryone is a crewmate. The 1st player to finish tasks wins the game. Game auto ends after {Options.GameAutoEndsAfter.GetInt()}s", "", false);
return false;
}
if (text == "/pns" || text == "/poofandseek")
{
Utils.ChatCommand(__instance, $"Poof and Seek:\n\nImpostors can only move while vanished\n Meetings & Reports = Off\nVisibly moving {Options.BadMoveTimeToSuicide.GetInt()}s as Phantom = Suicide", $"Crewmates win by doing tasks or surviving {Options.PNSCrewAutoWinsGameAfter.GetInt()}s\nImpostors win by killing everyone", true);
return false;
}
if (text == "/r" || text == "/roles")
{
switch (Options.Gamemode.GetValue())
{
case 0:
if (GameOptionsManager.Instance.CurrentGameOptions.GetFloat(FloatOptionNames.KillCooldown) == 0.001f)
{
Utils.ChatCommand(__instance, "0 Kill Cooldown:\n\nImpostors have no kill cooldown, and optionally can't kill after a game starts for 5 seconds", "", false);
}
break;
case 1:
Utils.ChatCommand(__instance, "Shift and Seek:\n\nImpostors can only kill someone while shapeshifted as them\nMeetings & Reports = Off", $"Crewmates win by tasks/surviving {Options.CrewAutoWinsGameAfter.GetInt()}s\nImpostors win by killing Crewmates", true);
break;
case 2:
Utils.ChatCommand(__instance, $"Speedrun:\n\nEveryone is a crewmate. The 1st player to finish tasks wins the game. Game auto ends after {Options.GameAutoEndsAfter.GetInt()}s", "", false);
break;
case 3:
Utils.ChatCommand(__instance, $"Poof and Seek:\n\nImpostors can only move while vanished\n Meetings & Reports = Off\nVisibly moving {Options.BadMoveTimeToSuicide.GetInt()}s as Phantom = Suicide", $"Crewmates win by doing tasks or surviving {Options.PNSCrewAutoWinsGameAfter.GetInt()}s\nImpostors win by killing everyone", true);
break;
}
__instance.timeSinceLastMessage = 0.8f;
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
if (text.StartsWith("/t "))
{
BanManager.LoadTemplates();
string templateName = text[3..].Trim().ToLower();
if (BanManager.Templates.TryGetValue(templateName, out string templateMessage))
{
if (templateMessage.Length < 121)
{
Utils.ChatCommand(__instance, BanManager.CheckTemplate(templateMessage), "", false);
}
else
{
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("tooLongTemplate"));
}
}
else
{
Logger.Info($"Could not find template '{templateName}'", "TemplateManager");
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, $"Template '{templateName}' not found.");
}
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
return false;
}
bool col1 = text.StartsWith("/col ");
bool col2 = text.StartsWith("/color ");
bool col3 = text.StartsWith("/colour ");
if (col1 || col2 || col3)
{
string argCol = text.Substring(col1 ? 5 : col2 ? 7 : col3 ? 8 : 0).Trim();
if (Utils.TryGetColorId(argCol, out byte colId) && (col1 || col2 || col3))
{
PlayerControl.LocalPlayer.RpcSetColor(colId);
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
}
return false;
}
else
{
bool isKick = text.StartsWith("/kick ");
bool isBan = text.StartsWith("/ban ");
bool isColorKick = text.StartsWith("/ckick ");
bool isColorBan = text.StartsWith("/cban ");
bool banLog = isBan || isColorBan;
if (!isKick && !isBan && !isColorKick && !isColorBan)
{
//__instance.freeChatField.textArea.SetText(converted);
//Utils.ChatCommand(__instance, $"{converted}", "", false);
Logger.Info($" {PlayerControl.LocalPlayer.Data.PlayerName}: {msgtext}", "SendChat");
return true;
}
string arg = text.Substring(isKick ? 6 : isBan ? 5 : isColorKick ? 7 : isColorBan ? 6 : 0).Trim();
PlayerControl target = null;
foreach (PlayerControl p in PlayerControl.AllPlayerControls)
{
if (p.Data == null || p == PlayerControl.LocalPlayer) continue;
if ((isKick || isBan) && p.Data.PlayerName.Equals(arg, StringComparison.OrdinalIgnoreCase))
{
target = p;
break;
}
if ((isColorKick || isColorBan) && Utils.TryGetColorId(arg, out byte colorId))
{
if (p.Data.DefaultOutfit.ColorId == colorId)
{
target = p;
break;
}
}
}
if (target != null)
{
AmongUsClient.Instance.KickPlayer(target.Data.ClientId, isBan || isColorBan);
Logger.Info($" {(banLog ? "banned" : "kicked")} {target.Data.PlayerName}", "Kick&BanCommand");
__instance.freeChatField.textArea.Clear();
__instance.freeChatField.textArea.SetText(string.Empty);
}
return false;
}
}
}
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.HandleRpc))]
public static class RPCHandlerPatch
{
public static void Prefix(PlayerControl __instance, [HarmonyArgument(0)] byte callId, [HarmonyArgument(1)] MessageReader reader)
{
if (!AmongUsClient.Instance.AmHost) return;
var rpcType = (RpcCalls)callId;
MessageReader subReader = MessageReader.Get(reader);
switch (rpcType)
{
case RpcCalls.SendChat:
{
string msgtext = subReader.ReadString();
string text = msgtext.ToLower();
Logger.Info($" {__instance.Data.PlayerName}: {msgtext}", "SendChat");
BanManager.IsStartWord(__instance, text);
BanManager.IsWordBanned(__instance, text);
if (text.StartsWith("/seeker ") && Utils.CheckAccessLevel(__instance.Data.FriendCode) >= Options.SlashMapAndSeekerCmd.GetValue())
{
if (!Utils.IsLobby || !Utils.isHideNSeek)
{
return;
}
string argSeeker = text.Substring(8).Trim();
bool found = false;
foreach (PlayerControl p in PlayerControl.AllPlayerControls)
{
if (p.Data == null) continue;
if (p.Data.PlayerName.Equals(argSeeker, StringComparison.OrdinalIgnoreCase))
{
found = true;
PlayerControlSetRolePatch.manualSeekers.Add(p.PlayerId);
break;
}
}
if (found)
{
List<string> names = new();
foreach (PlayerControl pl in PlayerControl.AllPlayerControls)
{
if (PlayerControlSetRolePatch.manualSeekers.Contains(pl.PlayerId)) names.Add(pl.Data.PlayerName);
}
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("seekers") + string.Join(", ", names));
}
if (!found)
{
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, $"Player '{argSeeker}' not found.");
}
}
if (text == "/clearseeker")
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashMapAndSeekerCmd.GetValue()) return;
PlayerControlSetRolePatch.manualSeekers.Clear();
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("clearedSeekers"));
}
bool col1 = text.StartsWith("/col ");
bool col2 = text.StartsWith("/color ");
bool col3 = text.StartsWith("/colour ");
if ((col1 || col2 || col3) && !Utils.InGame)
{
string argCol = text.Substring(col1 ? 5 : col2 ? 7 : col3 ? 8 : 0).Trim();
if (Utils.TryGetColorId(argCol, out byte colId))
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) >= Options.SlashColorCmd.GetValue())
{
if (colId > 17 && !Options.AllowFortegreen.GetBool()) return;
__instance.RpcSetColor(colId);
}
}
}
// Banning works by name and color. Commands are separated incase someone has a color as their name
bool isKick = text.StartsWith("/kick ");
bool isBan = text.StartsWith("/ban ");
bool isColorKick = text.StartsWith("/ckick ");
bool isColorBan = text.StartsWith("/cban ");
bool banLog = isBan || isColorBan;
if (isKick || isBan || isColorKick || isColorBan)
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) >= Options.SlashKickCmd.GetValue())
{
string arg = text.Substring(isKick ? 6 : isBan ? 5 : isColorKick ? 7 : isColorBan ? 6 : 0).Trim();
PlayerControl target = null;
foreach (PlayerControl p in PlayerControl.AllPlayerControls)
{
if (p.Data == null || p == PlayerControl.LocalPlayer || Utils.CheckAccessLevel(p.Data.FriendCode) >= 1) continue;
if ((isKick || isBan) && p.Data.PlayerName.Equals(arg, StringComparison.OrdinalIgnoreCase))
{
target = p;
break;
}
if ((isColorKick || isColorBan) && Utils.TryGetColorId(arg, out byte colorId))
{
if (p.Data.DefaultOutfit.ColorId == colorId)
{
target = p;
break;
}
}
}
if (banLog && Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashBanCmd.GetValue()) return;
if (target != null)
{
AmongUsClient.Instance.KickPlayer(target.Data.ClientId, isBan || isColorBan);
Logger.Info($" {__instance.Data.PlayerName} {(banLog ? "banned" : "kicked")} {target.Data.PlayerName}", "Kick&BanCommand");
}
}
}
if (text == "/eg" || text == "/endgame")
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashStartAndEndGameCmd.GetValue()) return;
MessageWriter writer = AmongUsClient.Instance.StartEndGame();
writer.Write((byte)GameOverReason.ImpostorDisconnect);
AmongUsClient.Instance.FinishEndGame(writer);
}
if (text == "/em" || text == "/endmeeting")
{
if (Utils.IsMeeting)
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashEndMeetingCmd.GetValue()) return;
MeetingHud.Instance.RpcClose();
}
}
if (text == "/private")
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashStartAndEndGameCmd.GetValue() || Utils.InGame) return;
AmongUsClient.Instance.ChangeGamePublic(false);
}
if (text == "/public")
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashStartAndEndGameCmd.GetValue() || Utils.InGame) return;
AmongUsClient.Instance.ChangeGamePublic(true);
}
if (text == "/s" || text == "/start")
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashStartAndEndGameCmd.GetValue()) return;
GameStartManager.Instance.BeginGame();
}
if (OnGameJoinedPatch.WaitingForChat || GameStartManagerUpdatePatch.CountingDown) return;
if (text == "/mapvote")
{
if (Utils.IsLobby)
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashMapAndSeekerCmd.GetValue()) return;
Utils.MapVote(true);
}
}
if (text == "/gmvote")
{
if (Utils.IsLobby)
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashMapAndSeekerCmd.GetValue()) return;
Utils.ModeVote(true);
}
}
if (text == "/vote a")
{
if (Utils.MapVoteActive)
{
if (Utils.HasVoted.Contains(__instance.Data.PlayerId)) return;
Utils.skeldVotes++;
Utils.HasVoted.Add(__instance.Data.PlayerId);
}
else if (Utils.ModeVoteActive)
{
if (Utils.HasModeVoted.Contains(__instance.Data.PlayerId)) return;
Utils.standardVotes++;
Utils.HasModeVoted.Add(__instance.Data.PlayerId);
}
}
if (text == "/vote b")
{
if (Utils.MapVoteActive)
{
if (Utils.HasVoted.Contains(__instance.Data.PlayerId)) return;
Utils.miraVotes++;
Utils.HasVoted.Add(__instance.Data.PlayerId);
}
else if (Utils.ModeVoteActive)
{
if (Utils.HasModeVoted.Contains(__instance.Data.PlayerId)) return;
Utils.noKillCooldownVotes++;
Utils.HasModeVoted.Add(__instance.Data.PlayerId);
}
}
if (text == "/vote c")
{
if (Utils.MapVoteActive)
{
if (Utils.HasVoted.Contains(__instance.Data.PlayerId)) return;
Utils.polusVotes++;
Utils.HasVoted.Add(__instance.Data.PlayerId);
}
else if (Utils.ModeVoteActive)
{
if (Utils.HasModeVoted.Contains(__instance.Data.PlayerId)) return;
Utils.speedrunVotes++;
Utils.HasModeVoted.Add(__instance.Data.PlayerId);
}
}
if (text == "/vote d")
{
if (Utils.MapVoteActive)
{
if (Utils.HasVoted.Contains(__instance.Data.PlayerId)) return;
Utils.airshipVotes++;
Utils.HasVoted.Add(__instance.Data.PlayerId);
}
else if (Utils.ModeVoteActive)
{
if (Utils.HasModeVoted.Contains(__instance.Data.PlayerId)) return;
Utils.shiftAndSeekVotes++;
Utils.HasModeVoted.Add(__instance.Data.PlayerId);
}
}
if (text == "/vote e")
{
if (Utils.MapVoteActive)
{
if (Utils.HasVoted.Contains(__instance.Data.PlayerId)) return;
Utils.fungleVotes++;
Utils.HasVoted.Add(__instance.Data.PlayerId);
}
else if (Utils.ModeVoteActive)
{
if (Utils.HasModeVoted.Contains(__instance.Data.PlayerId)) return;
Utils.poofAndSeekVotes++;
Utils.HasModeVoted.Add(__instance.Data.PlayerId);
}
}
if (text == "/vote f")
{
if (Utils.MapVoteActive)
{
if (Utils.HasVoted.Contains(__instance.Data.PlayerId)) return;
Utils.dleksVotes++;
Utils.HasVoted.Add(__instance.Data.PlayerId);
}
}
if (text == "/l" || text == "/lastgame")
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashLastGameCmd.GetValue()) return;
if (string.IsNullOrEmpty(NormalGameEndChecker.LastWinReason) || Utils.InGame) return;
Utils.ModeratorChatCommand($"{NormalGameEndChecker.LastWinReason}", "", false);
}
if (text == "/aur" || text == "/socials")
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashLastGameCmd.GetValue()) return;
Utils.ModeratorChatCommand("AUR socials:\n\ng i t h u b . c o m /\nApeMV/AmongUsRevamped\n\nd i s c о r d . g g /\n83Zhzhyhya", "", false);
}
if (text == "/0kc" || text == "/0killcooldown")
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashRolesAndGamemodeCmd.GetValue()) return;
Utils.ModeratorChatCommand("0 Kill Cooldown:\n\nImpostors have no kill cooldown, and optionally can't kill after a game starts for 5 seconds", "", false);
}
if (text == "/sns" || text == "/shiftandseek")
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashRolesAndGamemodeCmd.GetValue()) return;
Utils.ModeratorChatCommand("Shift and Seek:\n\nImpostors can only kill someone while shapeshifted as them\nMeetings & Reports = Off", $"Crewmates win by tasks/surviving {Options.CrewAutoWinsGameAfter.GetInt()}s\nImpostors win by killing Crewmates", true);
}
if (text == "/sns2" || text == "/shiftandseek2")
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashRolesAndGamemodeCmd.GetValue()) return;
Utils.ModeratorChatCommand("Correctly killing a target will directly turn them into a ghost and leave no dead body", "", false);
}
if (text == "/sr" || text == "/speedrun")
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashRolesAndGamemodeCmd.GetValue()) return;
Utils.ModeratorChatCommand($"Speedrun:\n\nEveryone is a crewmate. The 1st player to finish tasks wins the game. Game auto ends after {Options.GameAutoEndsAfter.GetInt()}s", "", false);
}
if (text == "/pns" || text == "/poofandseek")
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashRolesAndGamemodeCmd.GetValue()) return;
Utils.ModeratorChatCommand($"Poof and Seek:\n\nImpostors can only move while vanished\n Meetings & Reports = Off\nVisibly moving {Options.BadMoveTimeToSuicide.GetInt()}s as Phantom = Suicide", $"Crewmates win by doing tasks or surviving {Options.PNSCrewAutoWinsGameAfter.GetInt()}s\nImpostors win by killing everyone", true);
}
if (text == "/r" || text == "/roles")
{
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashRolesAndGamemodeCmd.GetValue()) return;
switch (Options.Gamemode.GetValue())
{
case 0:
if (GameOptionsManager.Instance.CurrentGameOptions.GetFloat(FloatOptionNames.KillCooldown) == 0.001f)
{
Utils.ModeratorChatCommand("0 Kill Cooldown:\n\nImpostors have no kill cooldown, and optionally can't kill after a game starts for 5 seconds", "", false);
}
break;
case 1:
Utils.ModeratorChatCommand("Shift and Seek:\n\nImpostors can only kill someone while shapeshifted as them\nMeetings & Reports = Off", $"Crewmates win by tasks/surviving {Options.CrewAutoWinsGameAfter.GetInt()}s\nImpostors win by killing Crewmates", true);
break;
case 2:
Utils.ModeratorChatCommand($"Speedrun:\n\nEveryone is a crewmate. The 1st player to finish tasks wins the game. Game auto ends after {Options.GameAutoEndsAfter.GetInt()}s", "", false);
break;
case 3:
Utils.ModeratorChatCommand($"Poof and Seek:\n\nImpostors can only move while vanished\n Meetings & Reports = Off\nVisibly moving {Options.BadMoveTimeToSuicide.GetInt()}s as Phantom = Suicide", $"Crewmates win by doing tasks or surviving {Options.PNSCrewAutoWinsGameAfter.GetInt()}s\nImpostors win by killing everyone", true);
break;
}
}
if (Utils.CheckAccessLevel(__instance.Data.FriendCode) < Options.SlashRolesAndGamemodeCmd.GetValue()) return;
if (text.StartsWith("/t "))
{
BanManager.LoadTemplates();
string templateName = text[3..].Trim().ToLower();
if (BanManager.Templates.TryGetValue(templateName, out string templateMessage))
{
if (templateMessage.Length < 121)
{
Utils.ModeratorChatCommand(BanManager.CheckTemplate(templateMessage), "", false);
}
else
{
HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, Translator.Get("tooLongTemplate"));
}
}
}
break;
}
}
}
}
[HarmonyPatch(typeof(FreeChatInputField), nameof(FreeChatInputField.UpdateCharCount))]
public static class FreeChatInputFieldUpdateCharCountPatch
{
public static void Postfix(FreeChatInputField __instance)
{
if (!Main.DisableChatModifier.Value)
{
__instance.charCountText.SetText($"{__instance.textArea.text.Length}/120");
}
}
}
// https://github.com/astra1dev/AUnlocker/blob/main/src/Patches/ChatPatches.cs
[HarmonyPatch(typeof(TextBoxTMP), nameof(TextBoxTMP.Update))]
public static class TextBoxTMPUpdatePatch
{
public static void Postfix(TextBoxTMP __instance)
{
if (!Main.DisableChatModifier.Value && __instance.hasFocus)
{
if (!Input.GetKey(KeyCode.LeftControl) && !Input.GetKey(KeyCode.RightControl)) return;
if (Input.GetKeyDown(KeyCode.C))
{
GUIUtility.systemCopyBuffer = __instance.text;
}
if (Input.GetKeyDown(KeyCode.V))
{
__instance.SetText(__instance.text + GUIUtility.systemCopyBuffer);
}
if (Input.GetKeyDown(KeyCode.X))
{
GUIUtility.systemCopyBuffer = __instance.text;
__instance.SetText("");
}
}
}
}