mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-19 15:51:58 +00:00
716 lines
36 KiB
C#
716 lines
36 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using AmongUs.Data;
|
|
using AmongUs.GameOptions;
|
|
using EHR.Gamemodes;
|
|
using EHR.Patches;
|
|
using EHR.Roles;
|
|
using HarmonyLib;
|
|
using InnerNet;
|
|
using TMPro;
|
|
using UnityEngine;
|
|
using static EHR.Translator;
|
|
|
|
namespace EHR;
|
|
|
|
[HarmonyPatch]
|
|
public static class GameStartManagerPatch
|
|
{
|
|
public static long TimerStartTS;
|
|
private static TextMeshPro WarningText;
|
|
public static bool UpdateSpriteStartButton;
|
|
public static float Timer => Math.Max(0, 597f - (Utils.TimeStamp - TimerStartTS));
|
|
|
|
[HarmonyPatch(typeof(TimerTextTMP), nameof(TimerTextTMP.UpdateText))]
|
|
public static class TimerTextTMPUpdateTextPatch
|
|
{
|
|
public static bool Prefix(TimerTextTMP __instance)
|
|
{
|
|
int seconds = __instance.GetSecondsRemaining();
|
|
if (seconds < 60) return true;
|
|
__instance.text.text = string.Format(GetString("LobbyTimer"), seconds / 60, seconds % 60);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
[HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.Start))]
|
|
public static class GameStartManagerStartPatch
|
|
{
|
|
public static TextMeshPro HideName;
|
|
public static TextMeshPro GameCountdown;
|
|
|
|
public static void Postfix(GameStartManager __instance)
|
|
{
|
|
try
|
|
{
|
|
try { GameStartManagerUpdatePatch.DiscordManagerBridge.Init(); } catch (Exception e) { Utils.ThrowException(e); }
|
|
|
|
if (!__instance) return;
|
|
|
|
UpdateSpriteStartButton = true;
|
|
GameCountdown = Object.Instantiate(__instance.PlayerCounter, __instance.HostInfoPanel.transform);
|
|
GameCountdown.text = string.Empty;
|
|
|
|
if (GameData.Instance && HudManager.InstanceExists && AmongUsClient.Instance.NetworkMode != NetworkModes.LocalGame && GameStates.CurrentServerType == GameStates.ServerType.Vanilla)
|
|
{
|
|
HudManager hudManager = HudManager.Instance;
|
|
hudManager.ShowLobbyTimer(597);
|
|
hudManager.LobbyTimerExtensionUI.timerText.transform.parent.transform.Find("Icon").gameObject.SetActive(false);
|
|
GameStartManagerUpdatePatch.Warned = false;
|
|
}
|
|
|
|
if (AmongUsClient.Instance.AmHost)
|
|
{
|
|
__instance.GameStartTextParent.GetComponent<SpriteRenderer>().sprite = null;
|
|
__instance.StartButton.ChangeButtonText(TranslationController.Instance.GetString(StringNames.StartLabel));
|
|
__instance.GameStartText.transform.localPosition = new(__instance.GameStartText.transform.localPosition.x, 2f, __instance.GameStartText.transform.localPosition.z);
|
|
__instance.StartButton.activeTextColor = __instance.StartButton.inactiveTextColor = Color.white;
|
|
|
|
__instance.EditButton.activeTextColor = __instance.EditButton.inactiveTextColor = Color.black;
|
|
__instance.EditButton.inactiveSprites.GetComponent<SpriteRenderer>().color = new(0f, 0.647f, 1f, 1f);
|
|
__instance.EditButton.activeSprites.GetComponent<SpriteRenderer>().color = new(0f, 0.847f, 1f, 1f);
|
|
__instance.EditButton.inactiveSprites.transform.Find("Shine").GetComponent<SpriteRenderer>().color = new(0f, 1f, 1f, 0.5f);
|
|
|
|
__instance.HostViewButton.activeTextColor = __instance.HostViewButton.inactiveTextColor = Color.black;
|
|
__instance.HostViewButton.inactiveSprites.GetComponent<SpriteRenderer>().color = new(0f, 0.647f, 1f, 1f);
|
|
__instance.HostViewButton.activeSprites.GetComponent<SpriteRenderer>().color = new(0f, 0.847f, 1f, 1f);
|
|
__instance.HostViewButton.inactiveSprites.transform.Find("Shine").GetComponent<SpriteRenderer>().color = new(0f, 1f, 1f, 0.5f);
|
|
}
|
|
else
|
|
{
|
|
__instance.ClientViewButton.activeTextColor = __instance.ClientViewButton.inactiveTextColor = Color.black;
|
|
__instance.ClientViewButton.inactiveSprites.GetComponent<SpriteRenderer>().color = new(0f, 0.647f, 1f, 1f);
|
|
__instance.ClientViewButton.activeSprites.GetComponent<SpriteRenderer>().color = new(0f, 0.847f, 1f, 1f);
|
|
__instance.ClientViewButton.inactiveSprites.transform.Find("Shine").GetComponent<SpriteRenderer>().color = new(0f, 1f, 1f, 0.5f);
|
|
}
|
|
|
|
if (!AmongUsClient.Instance || AmongUsClient.Instance.IsGameStarted || GameStates.IsInGame || __instance.startState == GameStartManager.StartingStates.Starting) return;
|
|
|
|
__instance.GameRoomNameCode.text = GameCode.IntToGameName(AmongUsClient.Instance.GameId);
|
|
// Reset lobby countdown timer
|
|
TimerStartTS = Utils.TimeStamp;
|
|
|
|
HideName = Object.Instantiate(__instance.GameRoomNameCode, __instance.GameRoomNameCode.transform);
|
|
|
|
HideName.text = ColorUtility.TryParseHtmlString(Main.HideColor.Value, out _)
|
|
? $"<color={Main.HideColor.Value}>{Main.HideName.Value}</color>"
|
|
: $"<color={Main.ModColor}>{Main.HideName.Value}</color>";
|
|
|
|
WarningText = Object.Instantiate(__instance.GameStartText, __instance.transform.parent);
|
|
WarningText.name = "WarningText";
|
|
WarningText.transform.localPosition = new(0f, __instance.transform.localPosition.y + 3f, -1f);
|
|
WarningText.gameObject.SetActive(false);
|
|
|
|
if (!AmongUsClient.Instance.AmHost) return;
|
|
|
|
if (ModUpdater.IsBroken || ModUpdater.HasUpdate && ModUpdater.ForceUpdate || !Main.AllowPublicRoom)
|
|
{
|
|
// __instance.MakePublicButton.color = Palette.DisabledClear;
|
|
// __instance.privatePublicText.color = Palette.DisabledClear;
|
|
}
|
|
|
|
if (Main.NormalOptions.KillCooldown == 0f) Main.NormalOptions.KillCooldown = Main.LastKillCooldown.Value;
|
|
|
|
#if IL2CPP
|
|
AURoleOptions.SetOpt(Main.NormalOptions.CastFast<IGameOptions>());
|
|
#else
|
|
AURoleOptions.SetOpt(Main.NormalOptions);
|
|
#endif
|
|
if (AURoleOptions.ShapeshifterCooldown == 0f) AURoleOptions.ShapeshifterCooldown = Main.LastShapeshifterCooldown.Value;
|
|
|
|
AURoleOptions.ProtectionDurationSeconds = 0f;
|
|
}
|
|
catch (Exception ex) { Logger.Error(ex.ToString(), "GameStartManagerStartPatch.Postfix (1)"); }
|
|
}
|
|
}
|
|
|
|
[HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.Update))]
|
|
public static class GameStartManagerUpdatePatch
|
|
{
|
|
public static float ExitTimer = -1f;
|
|
private static float MinWait, MaxWait;
|
|
private static int MinPlayer;
|
|
private static SpriteRenderer LobbyTimerBg;
|
|
public static bool Warned;
|
|
|
|
public static class DiscordManagerBridge
|
|
{
|
|
private static bool Initialized;
|
|
public static bool Enabled;
|
|
|
|
public static Func<bool> InstanceExistsGetter;
|
|
public static Func<object> InstanceGetter;
|
|
public static MethodInfo SetInLobbyHost;
|
|
public static MethodInfo SetInLobbyClient;
|
|
|
|
public static void Init()
|
|
{
|
|
if (Initialized) return;
|
|
Initialized = true;
|
|
|
|
var discordType = AppDomain.CurrentDomain.GetAssemblies().Select(a =>
|
|
{
|
|
try { return a.GetType("DiscordManager"); }
|
|
catch { return null; }
|
|
}).FirstOrDefault(t => t != null);
|
|
|
|
if (discordType == null) return;
|
|
|
|
var instanceProp = discordType.BaseType!.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static);
|
|
InstanceGetter = (Func<object>)Delegate.CreateDelegate(typeof(Func<object>), instanceProp!.GetGetMethod()!);
|
|
var existsProp = discordType.BaseType.GetProperty("InstanceExists", BindingFlags.Public | BindingFlags.Static);
|
|
InstanceExistsGetter = (Func<bool>)Delegate.CreateDelegate(typeof(Func<bool>), existsProp!.GetGetMethod()!);
|
|
SetInLobbyHost = discordType.GetMethod("SetInLobbyHost", BindingFlags.Public | BindingFlags.Instance);
|
|
SetInLobbyClient = discordType.GetMethod("SetInLobbyClient", BindingFlags.Public | BindingFlags.Instance);
|
|
|
|
Enabled = true;
|
|
}
|
|
}
|
|
|
|
public static bool Prefix(GameStartManager __instance)
|
|
{
|
|
try
|
|
{
|
|
try { __instance.MinPlayers = 1; }
|
|
catch (Exception ex) { Logger.Error(ex.ToString(), "Surely this can't be causing an issue, right?"); }
|
|
|
|
if (!AmongUsClient.Instance) return false;
|
|
|
|
VanillaUpdate(__instance);
|
|
|
|
if (AmongUsClient.Instance.IsGameStarted || GameStates.IsInGame || !__instance || __instance.startState == GameStartManager.StartingStates.Starting) return false;
|
|
|
|
// Lobby code
|
|
if (DataManager.Settings != null && DataManager.Settings.Gameplay != null)
|
|
{
|
|
if (DataManager.Settings.Gameplay.StreamerMode)
|
|
{
|
|
if (__instance.GameRoomNameCode) __instance.GameRoomNameCode.color = new(255, 255, 255, 0);
|
|
if (GameStartManagerStartPatch.HideName) GameStartManagerStartPatch.HideName.enabled = true;
|
|
}
|
|
else
|
|
{
|
|
if (__instance.GameRoomNameCode) __instance.GameRoomNameCode.color = new(255, 255, 255, 255);
|
|
if (GameStartManagerStartPatch.HideName) GameStartManagerStartPatch.HideName.enabled = false;
|
|
}
|
|
}
|
|
|
|
if (!GameData.Instance) return true;
|
|
|
|
CheckAutoStart(__instance);
|
|
}
|
|
catch (NullReferenceException) { }
|
|
catch (Exception ex) { Logger.Error(ex.ToString(), "GameStartManagerUpdatePatch.Prefix (2)"); }
|
|
|
|
return false;
|
|
}
|
|
|
|
private static void CheckAutoStart(GameStartManager __instance)
|
|
{
|
|
MinWait = Options.MinWaitAutoStart.GetFloat();
|
|
MaxWait = Options.MaxWaitAutoStart.GetFloat();
|
|
MinPlayer = Options.PlayerAutoStart.GetInt();
|
|
MinWait = 600f - MinWait * 60f;
|
|
MaxWait *= 60f;
|
|
|
|
bool votedToStart = (int)Math.Round(ChatCommands.VotedToStart.Count / (float)PlayerControl.AllPlayerControls.Count * 100f) > 50;
|
|
|
|
if ((Main.AutoStart == null || !Main.AutoStart.Value) && !votedToStart) return;
|
|
|
|
float timer = Timer;
|
|
|
|
if (timer > 60 && GameSettingMenu.Instance) return;
|
|
|
|
Main.UpdateTime++;
|
|
if (Main.UpdateTime < 50) return;
|
|
Main.UpdateTime = 0;
|
|
|
|
if (GameStates.IsCountDown) return;
|
|
if ((GameData.Instance?.PlayerCount < MinPlayer || timer > MinWait) && timer > MaxWait && !votedToStart) return;
|
|
|
|
PlayerControl[] invalidColor = Main.EnumeratePlayerControls().Where(p => p.Data.DefaultOutfit.ColorId < 0 || Palette.PlayerColors.Length <= p.Data.DefaultOutfit.ColorId).ToArray();
|
|
|
|
if (invalidColor.Length > 0)
|
|
{
|
|
Main.UpdateTime = -100;
|
|
|
|
Main.EnumeratePlayerControls()
|
|
.Where(p => p.Data.DefaultOutfit.ColorId < 0 || Palette.PlayerColors.Length <= p.Data.DefaultOutfit.ColorId)
|
|
.Do(p => AmongUsClient.Instance.KickPlayer(p.OwnerId, false));
|
|
|
|
Logger.SendInGame(GetString("Error.InvalidColorPreventStart"), Color.yellow);
|
|
string msg = GetString("Error.InvalidColor");
|
|
msg += "\n" + invalidColor.Join(",", p => $"{p.GetRealName()}");
|
|
Utils.SendMessage(msg, importance: MessageImportance.Low);
|
|
}
|
|
|
|
UpdateSpriteStartButton = true;
|
|
|
|
if (Options.RandomMapsMode.GetBool())
|
|
{
|
|
Main.NormalOptions.MapId = GameStartRandomMap.SelectRandomMap();
|
|
GameOptionsMapPickerPatch.SetDleks = Main.CurrentMap == MapNames.Dleks;
|
|
}
|
|
else if (GameOptionsMapPickerPatch.SetDleks) Main.NormalOptions.MapId = 3;
|
|
else if (GameOptionsMapPickerPatch.SetSubmerged) Main.NormalOptions.MapId = 6;
|
|
|
|
if (Options.OverrideSpeedForEachMap.GetBool() && Options.MapSpeeds.TryGetValue(Main.CurrentMap, out var option))
|
|
Main.NormalOptions.PlayerSpeedMod = option.GetFloat();
|
|
|
|
if (Main.CurrentMap == MapNames.Dleks || Main.NormalOptions.MapId == 6)
|
|
{
|
|
#if IL2CPP
|
|
IGameOptions opt = Main.NormalOptions.CastFast<IGameOptions>();
|
|
#else
|
|
IGameOptions opt = Main.NormalOptions;
|
|
#endif
|
|
|
|
Options.DefaultKillCooldown = Main.NormalOptions.KillCooldown;
|
|
Main.LastKillCooldown.Value = Main.NormalOptions.KillCooldown;
|
|
AURoleOptions.SetOpt(opt);
|
|
Main.LastShapeshifterCooldown.Value = AURoleOptions.ShapeshifterCooldown;
|
|
AURoleOptions.ShapeshifterCooldown = 0f;
|
|
AURoleOptions.ImpostorsCanSeeProtect = false;
|
|
|
|
GameManager.Instance.LogicOptions.SetDirty();
|
|
OptionItem.SyncAllOptions();
|
|
}
|
|
|
|
GameStartManager.Instance.startState = GameStartManager.StartingStates.Countdown;
|
|
GameStartManager.Instance.countDownTimer = Options.AutoStartTimer.GetInt();
|
|
__instance?.StartButton.gameObject.SetActive(false);
|
|
|
|
if (HudManager.InstanceExists)
|
|
HudManager.Instance.Dialogue.Hide();
|
|
}
|
|
|
|
private static void VanillaUpdate(GameStartManager instance)
|
|
{
|
|
if (!GameData.Instance || !GameManager.Instance) return;
|
|
|
|
try { instance.UpdateMapImage((MapNames)GameManager.Instance.LogicOptions.MapId); }
|
|
catch (Exception e)
|
|
{
|
|
if (!(GameManager.Instance.LogicOptions.MapId == 6 && SubmergedCompatibility.Loaded))
|
|
{
|
|
if (GameManager.Instance.LogicOptions.MapId >= Main.MapNamesValues.Length)
|
|
ErrorText.Instance.AddError(ErrorCode.UnsupportedMap);
|
|
|
|
Utils.ThrowException(e);
|
|
}
|
|
}
|
|
|
|
instance.CheckSettingsDiffs();
|
|
instance.StartButton.gameObject.SetActive(AmongUsClient.Instance.AmHost);
|
|
instance.RulesPresetText.text = TranslationController.Instance.GetString(GameOptionsManager.Instance.CurrentGameOptions.GetRulesPresetTitle());
|
|
|
|
if (GameCode.IntToGameName(AmongUsClient.Instance.GameId) == null) instance.privatePublicPanelText.text = TranslationController.Instance.GetString(StringNames.LocalButton);
|
|
else if (AmongUsClient.Instance.IsGamePublic) instance.privatePublicPanelText.text = TranslationController.Instance.GetString(StringNames.PublicHeader);
|
|
else instance.privatePublicPanelText.text = TranslationController.Instance.GetString(StringNames.PrivateHeader);
|
|
|
|
instance.HostPrivateButton.gameObject.SetActive(!AmongUsClient.Instance.IsGamePublic);
|
|
instance.HostPublicButton.gameObject.SetActive(AmongUsClient.Instance.IsGamePublic);
|
|
|
|
if ((Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) && Input.GetKeyDown(KeyCode.C))
|
|
ClipboardHelper.PutClipboardString(GameCode.IntToGameName(AmongUsClient.Instance.GameId));
|
|
|
|
if (GameData.Instance.PlayerCount != instance.LastPlayerCount)
|
|
{
|
|
instance.LastPlayerCount = GameData.Instance.PlayerCount;
|
|
var text = "<color=#FF0000FF>";
|
|
if (instance.LastPlayerCount > instance.MinPlayers) text = "<color=#00FF00FF>";
|
|
if (instance.LastPlayerCount == instance.MinPlayers) text = "<color=#FFFF00FF>";
|
|
|
|
instance.PlayerCounter.text = $"{text}{instance.LastPlayerCount}/{(AmongUsClient.Instance.NetworkMode == NetworkModes.LocalGame ? 15 : GameManager.Instance.LogicOptions.MaxPlayers)}";
|
|
instance.StartButton.SetButtonEnableState(instance.LastPlayerCount >= instance.MinPlayers);
|
|
ActionMapGlyphDisplay startButtonGlyph = instance.StartButtonGlyph;
|
|
startButtonGlyph?.SetColor(instance.LastPlayerCount >= instance.MinPlayers ? Palette.EnabledColor : Palette.DisabledClear);
|
|
|
|
if (DiscordManagerBridge.Enabled && DiscordManagerBridge.InstanceExistsGetter())
|
|
{
|
|
var method = AmongUsClient.Instance.AmHost && AmongUsClient.Instance.NetworkMode == NetworkModes.OnlineGame ? DiscordManagerBridge.SetInLobbyHost : DiscordManagerBridge.SetInLobbyClient;
|
|
method.Invoke(DiscordManagerBridge.InstanceGetter(), [instance.LastPlayerCount, GameManager.Instance.LogicOptions.MaxPlayers, AmongUsClient.Instance.GameId]);
|
|
}
|
|
}
|
|
|
|
if (AmongUsClient.Instance.AmHost)
|
|
{
|
|
if (instance.startState == GameStartManager.StartingStates.Countdown)
|
|
{
|
|
instance.StartButton.ChangeButtonText(GetString("Cancel"));
|
|
if (UpdateSpriteStartButton)
|
|
{
|
|
instance.StartButton.inactiveSprites.GetComponent<SpriteRenderer>().color = new(0.8f, 0f, 0f, 1f);
|
|
instance.StartButton.activeSprites.GetComponent<SpriteRenderer>().color = Color.red;
|
|
instance.StartButton.inactiveSprites.transform.Find("Shine").GetComponent<SpriteRenderer>().color = new(0.8f, 0.4f, 0.4f, 1f);
|
|
instance.StartButton.activeTextColor = instance.StartButton.inactiveTextColor = Color.white;
|
|
}
|
|
int num = Mathf.CeilToInt(instance.countDownTimer);
|
|
instance.countDownTimer -= Time.deltaTime;
|
|
int num2 = Mathf.CeilToInt(instance.countDownTimer);
|
|
if (!instance.GameStartTextParent.activeSelf) SoundManager.Instance.PlaySound(instance.gameStartSound, false);
|
|
|
|
instance.GameStartTextParent.SetActive(true);
|
|
instance.GameStartText.text = TranslationController.Instance.GetString(StringNames.GameStarting, num2);
|
|
if (num != num2) PlayerControl.LocalPlayer.RpcSetStartCounter(num2);
|
|
|
|
if (num2 <= 0) instance.FinallyBegin();
|
|
}
|
|
else
|
|
{
|
|
instance.StartButton.ChangeButtonText(TranslationController.Instance.GetString(StringNames.StartLabel));
|
|
if (UpdateSpriteStartButton)
|
|
{
|
|
instance.StartButton.inactiveSprites.GetComponent<SpriteRenderer>().color = new(0.1f, 0.1f, 0.1f, 1f);
|
|
instance.StartButton.activeSprites.GetComponent<SpriteRenderer>().color = new(0.2f, 0.2f, 0.2f, 1f);
|
|
instance.StartButton.inactiveSprites.transform.Find("Shine").GetComponent<SpriteRenderer>().color = new(0.3f, 0.3f, 0.3f, 0.5f);
|
|
instance.StartButton.activeTextColor = instance.StartButton.inactiveTextColor = Color.white;
|
|
}
|
|
instance.GameStartTextParent.SetActive(false);
|
|
instance.GameStartText.text = string.Empty;
|
|
}
|
|
UpdateSpriteStartButton = false;
|
|
}
|
|
|
|
if (!HudManager.InstanceExists) return;
|
|
|
|
if (instance.LobbyInfoPane.gameObject.activeSelf)
|
|
{
|
|
var lobbyViewSettingsPane = instance.LobbyInfoPane.LobbyViewSettingsPane;
|
|
lobbyViewSettingsPane.scrollBar.enabled = !HudManager.Instance.Chat.IsOpenOrOpening;
|
|
}
|
|
|
|
//if (instance.LobbyInfoPane.gameObject.activeSelf && HudManager.Instance.Chat.IsOpenOrOpening)
|
|
// instance.LobbyInfoPane.DeactivatePane();
|
|
|
|
//instance.LobbyInfoPane.gameObject.SetActive(!HudManager.Instance.Chat.IsOpenOrOpening);
|
|
}
|
|
|
|
public static void Postfix(GameStartManager __instance)
|
|
{
|
|
try
|
|
{
|
|
if (!AmongUsClient.Instance || AmongUsClient.Instance.IsGameStarted || GameStates.IsInGame || !__instance || __instance.startState == GameStartManager.StartingStates.Starting) return;
|
|
|
|
var canStartGame = true;
|
|
var mismatchedClientName = string.Empty;
|
|
|
|
var warningMessage = "";
|
|
|
|
if (AmongUsClient.Instance.AmHost)
|
|
{
|
|
ClientData[] allClients = AmongUsClient.Instance.allClients.ToArray();
|
|
|
|
lock (allClients)
|
|
{
|
|
// ReSharper disable once ForCanBeConvertedToForeach
|
|
for (var index = 0; index < allClients.Length; index++)
|
|
{
|
|
ClientData client = allClients[index];
|
|
if (!client.Character) continue;
|
|
|
|
var dummyComponent = client.Character.GetComponent<DummyBehaviour>();
|
|
if (dummyComponent && dummyComponent.enabled) continue;
|
|
|
|
if (!MatchVersions(client.Character.PlayerId, true))
|
|
{
|
|
canStartGame = false;
|
|
mismatchedClientName = client.Character.PlayerId.ColoredPlayerName();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!canStartGame && __instance.StartButton) __instance.StartButton.gameObject.SetActive(false);
|
|
}
|
|
else
|
|
{
|
|
if (MatchVersions(0, true))
|
|
ExitTimer = 0;
|
|
else
|
|
{
|
|
ExitTimer += Time.deltaTime;
|
|
|
|
if (ExitTimer >= 5)
|
|
{
|
|
ExitTimer = 0;
|
|
AmongUsClient.Instance.ExitGame(DisconnectReasons.ExitGame);
|
|
SceneChanger.ChangeScene("MainMenu");
|
|
}
|
|
|
|
if (ExitTimer != 0)
|
|
warningMessage = Utils.ColorString(Color.red, string.Format(GetString("Warning.AutoExitAtMismatchedVersion"), $"<color={Main.ModColor}>{Main.ModName}</color>", ((int)Math.Round(5 - ExitTimer)).ToString()));
|
|
}
|
|
}
|
|
|
|
if (WarningText)
|
|
{
|
|
if (warningMessage == "")
|
|
WarningText.gameObject.SetActive(false);
|
|
else
|
|
{
|
|
WarningText.text = warningMessage;
|
|
WarningText.gameObject.SetActive(true);
|
|
}
|
|
}
|
|
|
|
__instance.RulesPresetText.text = GetString($"Preset_{OptionItem.CurrentPreset + 1}");
|
|
|
|
|
|
int estimatedGameLength = Options.CurrentGameMode switch
|
|
{
|
|
CustomGameMode.SoloPVP => SoloPVP.SoloPVP_GameTime.GetInt(),
|
|
CustomGameMode.FFA => Math.Clamp(FreeForAll.FFAKcd.GetInt() * (PlayerControl.AllPlayerControls.Count / 2) + FreeForAll.FFAKcd.GetInt(), FreeForAll.FFAKcd.GetInt(), FreeForAll.FFAGameTime.GetInt()),
|
|
CustomGameMode.StopAndGo => (Main.NormalOptions.NumShortTasks * 30 + Main.NormalOptions.NumLongTasks * 60 + Math.Min(3, Main.NormalOptions.NumCommonTasks) * 40) / (int)(Main.NormalOptions.PlayerSpeedMod - (Main.NormalOptions.PlayerSpeedMod - 1) / 2),
|
|
CustomGameMode.HotPotato => HotPotato.GetKillInterval() * (PlayerControl.AllPlayerControls.Count - 1),
|
|
CustomGameMode.HideAndSeek => Math.Min(Seeker.KillCooldown.GetInt() * (PlayerControl.AllPlayerControls.Count - Main.NormalOptions.NumImpostors) / Main.NormalOptions.NumImpostors + Seeker.BlindTime.GetInt() + 15, Math.Min(CustomHnS.MaximumGameLength, (Main.NormalOptions.NumShortTasks * 20 + Main.NormalOptions.NumLongTasks * 30 + Math.Min(3, Main.NormalOptions.NumCommonTasks) * 20) / (int)(Main.NormalOptions.PlayerSpeedMod - (Main.NormalOptions.PlayerSpeedMod - 1) / 2))),
|
|
CustomGameMode.Speedrun => Speedrun.TimeLimitValue * (Main.NormalOptions.NumShortTasks + Main.NormalOptions.NumLongTasks + Main.NormalOptions.NumCommonTasks) + Speedrun.KCD * (PlayerControl.AllPlayerControls.Count / (Speedrun.RestrictedKilling ? 3 : 4)),
|
|
CustomGameMode.CaptureTheFlag => CaptureTheFlag.GameEndCriteriaType == 2 ? CaptureTheFlag.MaxGameLength : CaptureTheFlag.IsDeathPossible ? 40 : Math.Max(30, 1500 / (int)Math.Pow(CaptureTheFlag.KCD + 0.5f, 2) * CaptureTheFlag.TotalRoundsToPlay),
|
|
CustomGameMode.NaturalDisasters => 180 + 15 * NaturalDisasters.FrequencyOfDisasters * Math.Max(1, Math.Min(20, PlayerControl.AllPlayerControls.Count) / 4),
|
|
CustomGameMode.RoomRush => (int)Math.Round((RoomRush.PointsSystem ? RoomRush.RawPointsToWin * 1.5f : PlayerControl.AllPlayerControls.Count - 1) * ((Main.NormalOptions.MapId is 0 or 3 ? 15 : 20) / Main.NormalOptions.PlayerSpeedMod)),
|
|
CustomGameMode.KingOfTheZones => Math.Min(KingOfTheZones.MaxGameTime, KingOfTheZones.MaxGameTimeByPoints),
|
|
CustomGameMode.Deathrace => Deathrace.LapsToWin * (int)Math.Ceiling(25 / Main.NormalOptions.PlayerSpeedMod),
|
|
_ => 0
|
|
};
|
|
|
|
string suffix = estimatedGameLength != 0 ? $"<size=70%>{GetString("EstimatedGameLength")} - {estimatedGameLength / 60:00}:{estimatedGameLength % 60:00}</size>" : " ";
|
|
|
|
if (Options.NoGameEnd.GetBool())
|
|
suffix = Utils.ColorString(Color.yellow, $"{GetString("NoGameEnd").ToUpper()}");
|
|
|
|
if (!canStartGame)
|
|
suffix = Utils.ColorString(Color.red, string.Format(GetString("VersionMismatch"), mismatchedClientName));
|
|
|
|
TextMeshPro tmp = GameStartManagerStartPatch.GameCountdown;
|
|
|
|
if (tmp)
|
|
{
|
|
if (tmp.text == string.Empty)
|
|
{
|
|
tmp.name = "LobbyInfoText";
|
|
tmp.fontSize = tmp.fontSizeMin = tmp.fontSizeMax = 3f;
|
|
tmp.autoSizeTextContainer = true;
|
|
tmp.alignment = TextAlignmentOptions.Center;
|
|
tmp.color = Color.cyan;
|
|
tmp.outlineColor = Color.black;
|
|
tmp.outlineWidth = LangHasSensitiveOutlineText() ? 0.1f : 0.4f;
|
|
tmp.transform.localPosition += new Vector3(-0.625f, -0.12f, 0f);
|
|
tmp.transform.localScale = new(0.6f, 0.6f, 1f);
|
|
}
|
|
|
|
tmp.text = suffix;
|
|
tmp.gameObject.SetActive(true);
|
|
}
|
|
|
|
// Lobby timer
|
|
if (GameData.Instance && HudManager.InstanceExists && AmongUsClient.Instance.NetworkMode != NetworkModes.LocalGame && GameStates.CurrentServerType == GameStates.ServerType.Vanilla)
|
|
{
|
|
float timer = Timer;
|
|
|
|
if (!LobbyTimerBg) LobbyTimerBg = HudManager.Instance.LobbyTimerExtensionUI.timerText.transform.parent.transform.Find("LabelBackground").GetComponent<SpriteRenderer>();
|
|
LobbyTimerBg.sprite = Utils.LoadSprite("EHR.Resources.Images.LobbyTimerBG.png", 100f);
|
|
LobbyTimerBg.color = GetTimerColor(timer);
|
|
|
|
if (timer <= 60 && !Warned && AmongUsClient.Instance.AmHost)
|
|
{
|
|
Warned = true;
|
|
LobbyTimerExtensionUI lobbyTimerExtensionUI = HudManager.Instance.LobbyTimerExtensionUI;
|
|
lobbyTimerExtensionUI.timerText.transform.parent.transform.Find("Icon")?.gameObject.SetActive(true);
|
|
SoundManager.Instance.PlaySound(lobbyTimerExtensionUI.lobbyTimerPopUpSound, false);
|
|
Utils.FlashColor(new(1f, 1f, 0f, 0.4f), 1.4f);
|
|
}
|
|
}
|
|
}
|
|
catch (NullReferenceException) { }
|
|
catch (Exception e) { Logger.Error(e.ToString(), "GameStartManagerUpdatePatch.Postfix (3)"); }
|
|
}
|
|
|
|
private static Color GetTimerColor(float timer)
|
|
{
|
|
switch (timer)
|
|
{
|
|
case >= 180f:
|
|
{
|
|
return new Color32(0x00, 0x04, 0x44, 0xFF);
|
|
}
|
|
case >= 120f:
|
|
{
|
|
// 120 → 180: #ffff00 → #00ffa5
|
|
float lerpT = (timer - 120f) / 60f;
|
|
return Color.Lerp(new Color32(0xFF, 0xFF, 0x00, 0xFF), new Color32(0x00, 0x04, 0x44, 0xFF), lerpT);
|
|
}
|
|
case >= 60f:
|
|
{
|
|
// 60 → 120: #ff0000 → #ffff00
|
|
float lerpT = (timer - 60f) / 60f;
|
|
return Color.Lerp(new Color32(0xFF, 0x00, 0x00, 0xFF), new Color32(0xFF, 0xFF, 0x00, 0xFF), lerpT);
|
|
}
|
|
default:
|
|
{
|
|
return new Color32(0xFF, 0x00, 0x00, 0xFF);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static bool MatchVersions(byte playerId, bool acceptVanilla = false)
|
|
{
|
|
if (!Main.PlayerVersion.TryGetValue(playerId, out PlayerVersion version)) return acceptVanilla;
|
|
|
|
return Main.ForkId == version.forkId
|
|
&& Main.Version.CompareTo(version.version) == 0
|
|
&& version.tag == $"{ThisAssembly.Git.Commit}({ThisAssembly.Git.Branch})";
|
|
}
|
|
}
|
|
|
|
[HarmonyPatch(typeof(TextBoxTMP), nameof(TextBoxTMP.SetText))]
|
|
public static class HiddenTextPatch
|
|
{
|
|
private static void Postfix(TextBoxTMP __instance)
|
|
{
|
|
if (__instance.name == "GameIdText") __instance.outputText.text = new('*', __instance.text.Length);
|
|
}
|
|
}
|
|
}
|
|
|
|
[HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.BeginGame))]
|
|
public static class GameStartRandomMap
|
|
{
|
|
public static bool Prefix(GameStartManager __instance)
|
|
{
|
|
PlayerControl[] invalidColor = Main.EnumeratePlayerControls().Where(p => p.Data.DefaultOutfit.ColorId < 0 || Palette.PlayerColors.Length <= p.Data.DefaultOutfit.ColorId).ToArray();
|
|
|
|
if (invalidColor.Length > 0)
|
|
{
|
|
Logger.SendInGame(GetString("Error.InvalidColorPreventStart"), Color.yellow);
|
|
string msg = GetString("Error.InvalidColor");
|
|
msg += "\n" + invalidColor.Join(",", p => $"{p.GetRealName()}");
|
|
Utils.SendMessage(msg, importance: MessageImportance.Low);
|
|
return false;
|
|
}
|
|
|
|
GameStartManagerPatch.UpdateSpriteStartButton = true;
|
|
|
|
if (Options.RandomMapsMode.GetBool())
|
|
{
|
|
Main.NormalOptions.MapId = SelectRandomMap();
|
|
GameOptionsMapPickerPatch.SetDleks = Main.CurrentMap == MapNames.Dleks;
|
|
}
|
|
else if (GameOptionsMapPickerPatch.SetDleks) Main.NormalOptions.MapId = 3;
|
|
else if (GameOptionsMapPickerPatch.SetSubmerged) Main.NormalOptions.MapId = 6;
|
|
|
|
if (Options.OverrideSpeedForEachMap.GetBool() && Options.MapSpeeds.TryGetValue(Main.CurrentMap, out var option))
|
|
Main.NormalOptions.PlayerSpeedMod = option.GetFloat();
|
|
|
|
if (__instance.startState != GameStartManager.StartingStates.Countdown)
|
|
{
|
|
Options.DefaultKillCooldown = Main.NormalOptions.KillCooldown;
|
|
Main.LastKillCooldown.Value = Main.NormalOptions.KillCooldown;
|
|
}
|
|
|
|
#if IL2CPP
|
|
IGameOptions opt = Main.NormalOptions.CastFast<IGameOptions>();
|
|
#else
|
|
IGameOptions opt = Main.NormalOptions;
|
|
#endif
|
|
AURoleOptions.SetOpt(opt);
|
|
|
|
if (__instance.startState == GameStartManager.StartingStates.Countdown)
|
|
AURoleOptions.ShapeshifterCooldown = Main.LastShapeshifterCooldown.Value;
|
|
else
|
|
{
|
|
Main.LastShapeshifterCooldown.Value = AURoleOptions.ShapeshifterCooldown;
|
|
AURoleOptions.ShapeshifterCooldown = 0f;
|
|
}
|
|
|
|
GameManager.Instance.LogicOptions.SetDirty();
|
|
OptionItem.SyncAllOptions();
|
|
|
|
__instance.ReallyBegin(false);
|
|
return false;
|
|
}
|
|
|
|
public static byte SelectRandomMap()
|
|
{
|
|
Dictionary<byte, int> chance = Enumerable.Range(0, 6).ToDictionary(x => (byte)x, x => x switch
|
|
{
|
|
0 => Options.SkeldChance.GetInt(),
|
|
1 => Options.MiraChance.GetInt(),
|
|
2 => Options.PolusChance.GetInt(),
|
|
3 => Options.DleksChance.GetInt(),
|
|
4 => Options.AirshipChance.GetInt(),
|
|
5 => Options.FungleChance.GetInt(),
|
|
_ => 0
|
|
});
|
|
|
|
int playerCount = PlayerControl.AllPlayerControls.Count;
|
|
if (playerCount < Options.MinPlayersForAirship.GetInt()) chance.Remove(4);
|
|
if (playerCount < Options.MinPlayersForFungle.GetInt()) chance.Remove(5);
|
|
|
|
byte[] pool = chance.SelectMany(x => Enumerable.Repeat(x.Key, x.Value / 5)).ToArray();
|
|
return pool.Length == 0 ? chance.Keys.RandomElement() : pool.RandomElement();
|
|
}
|
|
}
|
|
|
|
[HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.ResetStartState))]
|
|
internal static class ResetStartStatePatch
|
|
{
|
|
public static void Prefix(GameStartManager __instance)
|
|
{
|
|
SoundManager.Instance.StopSound(__instance.gameStartSound);
|
|
GameStartManagerPatch.UpdateSpriteStartButton = true;
|
|
}
|
|
}
|
|
|
|
[HarmonyPatch(typeof(IGameOptionsExtensions), nameof(IGameOptionsExtensions.GetAdjustedNumImpostors))]
|
|
internal static class UnrestrictedNumImpostorsPatch
|
|
{
|
|
public static bool Prefix(ref int __result)
|
|
{
|
|
__result = Main.NormalOptions.NumImpostors;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static class GameStartManagerBeginPatch
|
|
{
|
|
[HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.ReallyBegin))]
|
|
public static class GameStartManagerStartPatch
|
|
{
|
|
public static bool Prefix(GameStartManager __instance)
|
|
{
|
|
if (!AmongUsClient.Instance.AmHost) return true;
|
|
|
|
if (__instance.startState == GameStartManager.StartingStates.Countdown)
|
|
{
|
|
__instance.ResetStartState();
|
|
ChatCommands.VotedToStart.Clear();
|
|
return false;
|
|
}
|
|
|
|
__instance.startState = GameStartManager.StartingStates.Countdown;
|
|
__instance.GameSizePopup.SetActive(false);
|
|
DataManager.Player.Onboarding.AlwaysShowMinPlayerWarning = false;
|
|
DataManager.Player.Onboarding.ViewedMinPlayerWarning = true;
|
|
DataManager.Player.Save();
|
|
__instance.StartButton.gameObject.SetActive(false);
|
|
__instance.StartButtonClient.gameObject.SetActive(false);
|
|
__instance.GameStartTextParent.SetActive(false);
|
|
__instance.countDownTimer = 5.0001f;
|
|
__instance.startState = GameStartManager.StartingStates.Countdown;
|
|
AmongUsClient.Instance.KickNotJoinedPlayers();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
[HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.FinallyBegin))]
|
|
public static class GameStartManagerFinallyBeginPatch
|
|
{
|
|
public static void Prefix(GameStartManager __instance)
|
|
{
|
|
SoundManager.Instance.StopSound(__instance.gameStartSound);
|
|
}
|
|
|
|
}
|