mirror of
https://github.com/D1GQ/BetterAmongUs.git
synced 2026-10-19 15:51:52 +00:00
add comments
This commit is contained in:
1 parent
83a176e822
commit
589cf8285d
23 files changed
+242
-69
No files matched your search
@@ -14,10 +14,11 @@ internal class CheckPlayerLevelPatch
|
||||
{
|
||||
if (GameState.IsHost)
|
||||
{
|
||||
if (!__instance.IsLocalPlayer() && (__instance.Data.PlayerLevel < BetterGameSettings.KickLevelBelow.GetInt()))
|
||||
// Kick players below minimum level
|
||||
if (!__instance.IsLocalPlayer() && __instance.Data.PlayerLevel < BetterGameSettings.KickLevelBelow.GetInt())
|
||||
{
|
||||
__instance.Kick(setReasonInfo: $" is level {__instance.Data.PlayerLevel}, level must be equal or above {BetterGameSettings.KickLevelBelow.GetInt()} to join");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,10 +27,12 @@ internal class PlatformSpoofPatch
|
||||
|
||||
if (player != null && __instance?.Platform != null)
|
||||
{
|
||||
// Check Xbox/Windows store players for invalid platform ID length
|
||||
if (__instance.Platform is Platforms.StandaloneWin10 or Platforms.Xbox)
|
||||
{
|
||||
if (__instance.XboxPlatformId.ToString().Length is < 10 or > 16)
|
||||
{
|
||||
// Invalid ID length, likely spoofing
|
||||
player.ReportPlayer(ReportReasons.Cheating_Hacking);
|
||||
BetterNotificationManager.NotifyCheat(player,
|
||||
Translator.GetString("AntiCheat.Reason.PlatformSpoofer"),
|
||||
@@ -40,10 +42,12 @@ internal class PlatformSpoofPatch
|
||||
}
|
||||
}
|
||||
|
||||
// Check Playstation players for invalid platform ID length
|
||||
if (__instance.Platform is Platforms.Playstation)
|
||||
{
|
||||
if (__instance.PsnPlatformId.ToString().Length is < 14 or > 20)
|
||||
{
|
||||
// Invalid ID length, likely spoofing
|
||||
player.ReportPlayer(ReportReasons.Cheating_Hacking);
|
||||
BetterNotificationManager.NotifyCheat(player,
|
||||
Translator.GetString("AntiCheat.Reason.PlatformSpoofer"),
|
||||
@@ -53,6 +57,7 @@ internal class PlatformSpoofPatch
|
||||
}
|
||||
}
|
||||
|
||||
// Check for unknown or undefined platforms
|
||||
if (__instance.Platform is Platforms.Unknown || !Enum.IsDefined(__instance.Platform))
|
||||
{
|
||||
BetterNotificationManager.NotifyCheat(player,
|
||||
@@ -67,4 +72,4 @@ internal class PlatformSpoofPatch
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,10 +14,11 @@ internal static class LobbyPatch
|
||||
[HarmonyPostfix]
|
||||
private static void LobbyBehaviour_Start_Postfix()
|
||||
{
|
||||
// Reset player selection options when lobby starts
|
||||
OptionPlayerItem.ResetAllValues();
|
||||
}
|
||||
|
||||
// Disabled annoying music
|
||||
// Disable annoying lobby music if setting is enabled
|
||||
[HarmonyPatch(typeof(LobbyBehaviour), nameof(LobbyBehaviour.Update))]
|
||||
[HarmonyPostfix]
|
||||
private static void LobbyBehaviour_Update_Postfix()
|
||||
@@ -30,9 +31,10 @@ internal static class LobbyPatch
|
||||
[HarmonyPostfix]
|
||||
private static void LobbyBehaviour_RpcExtendLobbyTimer_Postfix()
|
||||
{
|
||||
lobbyTimer += 30f;
|
||||
lobbyTimer += 30f; // Add 30 seconds to lobby timer
|
||||
}
|
||||
|
||||
// Apply UI colors to settings pane buttons
|
||||
[HarmonyPatch(typeof(LobbyViewSettingsPane), nameof(LobbyViewSettingsPane.Awake))]
|
||||
[HarmonyPostfix]
|
||||
private static void LobbyViewSettingsPane_Awake_Postfix(LobbyViewSettingsPane __instance)
|
||||
@@ -42,20 +44,22 @@ internal static class LobbyPatch
|
||||
__instance.rolesTabButton.gameObject.SetUIColors("Icon");
|
||||
}
|
||||
|
||||
internal static float lobbyTimer = 600f;
|
||||
internal static float lobbyTimer = 600f; // 10 minute default
|
||||
internal static string lobbyTimerDisplay = "";
|
||||
|
||||
[HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.Start))]
|
||||
[HarmonyPostfix]
|
||||
private static void GameStartManager_Start_Postfix(GameStartManager __instance)
|
||||
{
|
||||
lobbyTimer = 600f;
|
||||
lobbyTimer = 600f; // Reset timer
|
||||
|
||||
// Apply UI colors to buttons
|
||||
__instance.StartButton?.gameObject?.SetUIColors("Icon");
|
||||
__instance.EditButton?.gameObject?.SetUIColors("Icon");
|
||||
__instance.ClientViewButton?.gameObject?.SetUIColors("Icon");
|
||||
__instance.HostViewButton?.gameObject?.SetUIColors("Icon");
|
||||
|
||||
// Move start buttons to host panel if ping tracker not disabled
|
||||
if (!BAUModdedSupportFlags.HasFlag(BAUModdedSupportFlags.Disable_BetterPingTracker))
|
||||
{
|
||||
__instance.StartButton?.transform?.SetParent(__instance.HostInfoPanel?.transform);
|
||||
@@ -67,12 +71,13 @@ internal static class LobbyPatch
|
||||
[HarmonyPrefix]
|
||||
private static void GameStartManager_Update_Prefix(GameStartManager __instance)
|
||||
{
|
||||
// Update lobby timer countdown
|
||||
lobbyTimer = Mathf.Max(0f, lobbyTimer -= Time.deltaTime);
|
||||
int minutes = (int)lobbyTimer / 60;
|
||||
int seconds = (int)lobbyTimer % 60;
|
||||
lobbyTimerDisplay = $"{minutes:00}:{seconds:00}";
|
||||
|
||||
__instance.MinPlayers = 1;
|
||||
__instance.MinPlayers = 1; // Allow starting with just 1 player
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.Update))]
|
||||
@@ -81,20 +86,25 @@ internal static class LobbyPatch
|
||||
{
|
||||
if (BAUModdedSupportFlags.HasFlag(BAUModdedSupportFlags.Disable_CancelStartingGame)) return;
|
||||
|
||||
// Hide start button for non-hosts
|
||||
if (!GameState.IsHost)
|
||||
{
|
||||
__instance.StartButton.gameObject.SetActive(false);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// Custom start button behavior for hosts
|
||||
__instance.GameStartTextParent.SetActive(false);
|
||||
__instance.StartButton.gameObject.SetActive(true);
|
||||
|
||||
if (__instance.startState == GameStartManager.StartingStates.Countdown)
|
||||
{
|
||||
// Show cancel button with countdown
|
||||
__instance.StartButton.buttonText.text = string.Format("{0}: {1}", Translator.GetString(StringNames.Cancel), (int)__instance.countDownTimer + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show normal start button
|
||||
__instance.StartButton.buttonText.text = Translator.GetString(StringNames.StartLabel);
|
||||
}
|
||||
}
|
||||
@@ -105,6 +115,7 @@ internal static class LobbyPatch
|
||||
{
|
||||
if (BAUModdedSupportFlags.HasFlag(BAUModdedSupportFlags.Disable_CancelStartingGame)) return true;
|
||||
|
||||
// If countdown is active, clicking cancels the start
|
||||
if (__instance.startState == GameStartManager.StartingStates.Countdown)
|
||||
{
|
||||
SoundManager.instance.StopSound(__instance.gameStartSound);
|
||||
@@ -112,6 +123,7 @@ internal static class LobbyPatch
|
||||
return false;
|
||||
}
|
||||
|
||||
// Shift+click starts game immediately (bypasses countdown)
|
||||
if (Input.GetKey(KeyCode.LeftShift))
|
||||
{
|
||||
__instance.startState = GameStartManager.StartingStates.Countdown;
|
||||
@@ -122,10 +134,11 @@ internal static class LobbyPatch
|
||||
return true;
|
||||
}
|
||||
|
||||
// Log game start info
|
||||
[HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.FinallyBegin))]
|
||||
[HarmonyPrefix]
|
||||
private static void GameStartManager_FinallyBegin_Prefix(/*GameStartManager __instance*/)
|
||||
{
|
||||
Logger_.LogHeader($"Game Has Started - {Enum.GetName(typeof(MapNames), GameState.GetActiveMapId)}/{GameState.GetActiveMapId}", "GamePlayManager");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,13 +10,15 @@ internal static class CosmeticsLayerPatch
|
||||
[HarmonyPrefix]
|
||||
private static bool CosmeticsLayer_GetColorBlindText_Prefix(CosmeticsLayer __instance, ref string __result)
|
||||
{
|
||||
// Skip processing if color ID is out of bounds (custom colors)
|
||||
// Skip for custom colors not in vanilla palette
|
||||
if (__instance.bodyMatProperties.ColorId > Palette.PlayerColors.Length) return true;
|
||||
|
||||
// Get color name from palette
|
||||
string colorName = Palette.GetColorName(__instance.bodyMatProperties.ColorId);
|
||||
|
||||
if (!string.IsNullOrEmpty(colorName))
|
||||
{
|
||||
// Capitalize first letter, lowercase rest, and apply color formatting
|
||||
__result = (char.ToUpperInvariant(colorName[0]) + colorName[1..].ToLowerInvariant())
|
||||
.ToColor(Palette.PlayerColors[__instance.bodyMatProperties.ColorId]);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using BepInEx.Unity.IL2CPP.Utils.Collections;
|
||||
using BetterAmongUs.Helpers;
|
||||
using BetterAmongUs.Modules;
|
||||
using BetterAmongUs.Modules.OptionItems;
|
||||
using BetterAmongUs.Mono;
|
||||
using HarmonyLib;
|
||||
@@ -26,6 +27,8 @@ internal static class PlayerControlPatch
|
||||
|
||||
private static IEnumerator CoSetFavoriteColor(PlayerControl player)
|
||||
{
|
||||
if (!GameState.IsLobby) yield break;
|
||||
|
||||
// Apply player's favorite color setting if they own this character
|
||||
if (player.AmOwner)
|
||||
{
|
||||
|
||||
@@ -10,13 +10,15 @@ internal static class RolePatch
|
||||
[HarmonyPrefix]
|
||||
private static bool NoisemakerRole_NotifyOfDeath_Prefix(NoisemakerRole __instance)
|
||||
{
|
||||
// Prevent duplicate noisemaker notifications
|
||||
if (__instance.Player.BetterData().RoleInfo.HasNoisemakerNotify)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mark that notification has been sent
|
||||
__instance.Player.BetterData().RoleInfo.HasNoisemakerNotify = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ internal static class ShipStatusPatch
|
||||
[HarmonyPostfix]
|
||||
private static void ShipStatus_Awake_Postfix(ShipStatus __instance)
|
||||
{
|
||||
// Calculate vent groups when ship initializes
|
||||
VentGroups.CalculateAllVentGroups(__instance.AllVents);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,10 @@ internal static class VentPatch
|
||||
[HarmonyPrefix]
|
||||
private static bool Vent_SetOutline_Prefix(Vent __instance, bool on, bool mainTarget)
|
||||
{
|
||||
// Skip if vent color groups are disabled - use vanilla behavior
|
||||
if (BAUModdedSupportFlags.HasFlag(BAUModdedSupportFlags.Disable_VentColorGroups)) return true;
|
||||
|
||||
// Get group color for this vent and apply outline
|
||||
Color color = VentGroups.GetVentGroupColor(__instance);
|
||||
__instance.myRend.material.SetFloat("_Outline", on ? 1f : 0f);
|
||||
__instance.myRend.material.SetColor("_OutlineColor", color);
|
||||
@@ -21,4 +23,4 @@ internal static class VentPatch
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ internal static class ChatNotificationPatch
|
||||
{
|
||||
if (BAUModdedSupportFlags.HasFlag(BAUModdedSupportFlags.Disable_BetterPingTracker)) return;
|
||||
|
||||
// Reposition to top left
|
||||
__instance.GetComponent<AspectPosition>().DistanceFromEdge = new Vector3(-2.8f, 0.3f, -40f);
|
||||
__instance.transform.localScale = new Vector3(0.45f, 0.42f, 1f);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ internal static class ChatPatch
|
||||
|
||||
[HarmonyPatch(typeof(ChatController), nameof(ChatController.Toggle))]
|
||||
[HarmonyPostfix]
|
||||
private static void ChatController_Toggle_Postfix(/*ChatController __instance*/)
|
||||
private static void ChatController_Toggle_Postfix()
|
||||
{
|
||||
// Apply chat theme when chat is opened/closed
|
||||
SetChatTheme();
|
||||
|
||||
@@ -11,6 +11,7 @@ internal static class QuickChatPatch
|
||||
[HarmonyPrefix]
|
||||
private static void QuickChatMenu_Awake_Prefix(QuickChatMenu __instance)
|
||||
{
|
||||
// Apply custom UI colors to close button
|
||||
__instance.closeButton?.gameObject?.SetUIColors("Icon");
|
||||
}
|
||||
|
||||
@@ -18,6 +19,7 @@ internal static class QuickChatPatch
|
||||
[HarmonyPrefix]
|
||||
private static void QuickChatMenuLandingPage_Initialize_Prefix(QuickChatMenuLandingPage __instance)
|
||||
{
|
||||
// Apply custom UI colors to landing page buttons
|
||||
__instance.buttonTemplate?.Button?.gameObject?.SetUIColors("Icon");
|
||||
__instance.favoritesButton?.Button?.gameObject?.SetUIColors("Icon");
|
||||
__instance.remarksButton?.Button?.gameObject?.SetUIColors("Icon");
|
||||
@@ -27,8 +29,9 @@ internal static class QuickChatPatch
|
||||
[HarmonyPrefix]
|
||||
private static void QuickChatMenuPhrasesPage_Awake_Prefix(QuickChatMenuPhrasesPage __instance)
|
||||
{
|
||||
// Apply custom UI colors to crewmate and phrase buttons with multiple color layers
|
||||
__instance.crewmateButtonTemplate?.Button?.gameObject?.SetUIColors("Icon", "Background", "PlayerMask", "Skin", "Visor", "Back", "Front", "Normal", "Horse", "Seeker",
|
||||
"LongBoiBody", "LongHead", "LongNeck", "ForegroundNeck", "LongHands");
|
||||
__instance.phraseButtonTemplate?.Button?.gameObject?.SetUIColors("Icon");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,20 +16,24 @@ internal static class GameSummaryPatch
|
||||
[HarmonyPostfix]
|
||||
private static void EndGameManager_SetEverythingUp_Postfix(EndGameManager __instance)
|
||||
{
|
||||
// Log game end to console
|
||||
LogGameEnd();
|
||||
|
||||
// Create visual summary unless disabled
|
||||
if (!BAUModdedSupportFlags.HasFlag(BAUModdedSupportFlags.Disable_EndGameSummary))
|
||||
{
|
||||
CreateGameSummary(__instance);
|
||||
}
|
||||
}
|
||||
|
||||
// Log game end info to console
|
||||
private static void LogGameEnd()
|
||||
{
|
||||
Logger_.LogHeader($"Game Has Ended - {Enum.GetName(typeof(MapNames), GameState.GetActiveMapId)}/{GameState.GetActiveMapId}", "GamePlayManager");
|
||||
Logger_.LogHeader("Game Summary Start", "GameSummary");
|
||||
}
|
||||
|
||||
// Creates the visual game summary on screen
|
||||
private static void CreateGameSummary(EndGameManager endGameManager)
|
||||
{
|
||||
var summaryObject = CreateSummaryObject(endGameManager);
|
||||
@@ -39,9 +43,11 @@ internal static class GameSummaryPatch
|
||||
|
||||
ConfigureSummaryText(summaryText);
|
||||
|
||||
// Get win condition info
|
||||
var (winTeam, winTag, winColor) = GetWinInfo();
|
||||
Logger_.Log($"{winTeam}: {winTag}", "GameSummary");
|
||||
|
||||
// Build and display summary text
|
||||
var summaryHeader = BuildSummaryHeader(winTeam, winTag, winColor);
|
||||
var playerList = BuildPlayerList();
|
||||
|
||||
@@ -49,6 +55,7 @@ internal static class GameSummaryPatch
|
||||
Logger_.LogHeader("Game Summary End", "GameSummary");
|
||||
}
|
||||
|
||||
// Creates the text object for the summary
|
||||
private static GameObject CreateSummaryObject(EndGameManager endGameManager)
|
||||
{
|
||||
var summaryObject = UnityEngine.Object.Instantiate(
|
||||
@@ -59,6 +66,7 @@ internal static class GameSummaryPatch
|
||||
summaryObject.name = "SummaryObj (TMP)";
|
||||
summaryObject.transform.SetSiblingIndex(0);
|
||||
|
||||
// Position in top-left corner
|
||||
var camera = HudManager.InstanceExists
|
||||
? HudManager.Instance.GetComponentInChildren<Camera>()
|
||||
: Camera.main;
|
||||
@@ -75,6 +83,7 @@ internal static class GameSummaryPatch
|
||||
return summaryObject;
|
||||
}
|
||||
|
||||
// Sets text properties for the summary
|
||||
private static void ConfigureSummaryText(TextMeshPro text)
|
||||
{
|
||||
text.autoSizeTextContainer = false;
|
||||
@@ -84,59 +93,66 @@ internal static class GameSummaryPatch
|
||||
text.color = Color.white;
|
||||
}
|
||||
|
||||
// Determines which team won and how
|
||||
private static (string Team, string Tag, string Color) GetWinInfo()
|
||||
{
|
||||
return EndGameResult.CachedGameOverReason switch
|
||||
{
|
||||
// Classic mode wins
|
||||
GameOverReason.CrewmatesByTask => (
|
||||
Translator.GetString(StringNames.Crewmates),
|
||||
Translator.GetString("Game.Summary.Result.TasksCompletion"),
|
||||
"#8cffff"
|
||||
Colors.CrewmateBlue.ColorToHex()
|
||||
),
|
||||
GameOverReason.CrewmatesByVote => (
|
||||
Translator.GetString(StringNames.Crewmates),
|
||||
Translator.GetString("Game.Summary.Result.ImpostersVotedOut"),
|
||||
"#8cffff"
|
||||
Colors.CrewmateBlue.ColorToHex()
|
||||
),
|
||||
GameOverReason.ImpostorDisconnect => (
|
||||
Translator.GetString(StringNames.Crewmates),
|
||||
Translator.GetString("Game.Summary.Result.ImpostorsDisconnected"),
|
||||
"#8cffff"
|
||||
Colors.CrewmateBlue.ColorToHex()
|
||||
),
|
||||
GameOverReason.ImpostorsByKill => (
|
||||
Translator.GetString(StringNames.ImpostorsCategory),
|
||||
Translator.GetString("Game.Summary.Result.CrewOutnumbered"),
|
||||
"#f00202"
|
||||
Colors.ImpostorRed.ColorToHex()
|
||||
),
|
||||
GameOverReason.ImpostorsBySabotage => (
|
||||
Translator.GetString(StringNames.ImpostorsCategory),
|
||||
Translator.GetString("Game.Summary.Result.Sabotage"),
|
||||
"#f00202"
|
||||
Colors.ImpostorRed.ColorToHex()
|
||||
),
|
||||
GameOverReason.ImpostorsByVote => (
|
||||
Translator.GetString(StringNames.ImpostorsCategory),
|
||||
Translator.GetString("Game.Summary.Result.CrewOutnumbered"),
|
||||
"#f00202"
|
||||
Colors.ImpostorRed.ColorToHex()
|
||||
),
|
||||
GameOverReason.CrewmateDisconnect => (
|
||||
Translator.GetString(StringNames.ImpostorsCategory),
|
||||
Translator.GetString("Game.Summary.Result.CrematesDisconnected"),
|
||||
"#f00202"
|
||||
Colors.ImpostorRed.ColorToHex()
|
||||
),
|
||||
|
||||
// Hide & Seek mode wins
|
||||
GameOverReason.HideAndSeek_CrewmatesByTimer => (
|
||||
Translator.GetString("Game.Summary.Hiders"),
|
||||
Translator.GetString("Game.Summary.Result.TimeOut"),
|
||||
"#8cffff"
|
||||
Colors.CrewmateBlue.ColorToHex()
|
||||
),
|
||||
GameOverReason.HideAndSeek_ImpostorsByKills => (
|
||||
Translator.GetString("Game.Summary.Seekers"),
|
||||
Translator.GetString("Game.Summary.Result.NoSurvivors"),
|
||||
"#f00202"
|
||||
Colors.ImpostorRed.ColorToHex()
|
||||
),
|
||||
|
||||
// Fallback for unknown win conditions
|
||||
_ => ("Unknown", "Unknown", "#ffffff")
|
||||
};
|
||||
}
|
||||
|
||||
// Builds the header text with win info
|
||||
private static string BuildSummaryHeader(string winTeam, string winTag, string winColor)
|
||||
{
|
||||
return $"<align=\"center\"><size=150%> {Translator.GetString("GameSummary")}</size></align>" +
|
||||
@@ -144,6 +160,7 @@ internal static class GameSummaryPatch
|
||||
$"\n<size=60%>\n{Translator.GetString("Game.Summary.By")} {winTag}</size>";
|
||||
}
|
||||
|
||||
// Sorts players for display: disconnected first, then dead, then alive
|
||||
private static NetworkedPlayerInfo[] GetSortedPlayers()
|
||||
{
|
||||
return GameData.Instance.AllPlayers
|
||||
@@ -154,6 +171,7 @@ internal static class GameSummaryPatch
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
// Builds the complete player list text
|
||||
private static StringBuilder BuildPlayerList()
|
||||
{
|
||||
var playersData = GetSortedPlayers();
|
||||
@@ -169,6 +187,7 @@ internal static class GameSummaryPatch
|
||||
return stringBuilder;
|
||||
}
|
||||
|
||||
// Builds a single player line with name, role info, and status
|
||||
private static string BuildPlayerLine(NetworkedPlayerInfo playerData)
|
||||
{
|
||||
var name = $"<color={Utils.Color32ToHex(Palette.PlayerColors[playerData.DefaultOutfit.ColorId])}>{playerData.BetterData().RealName}</color>";
|
||||
@@ -178,6 +197,7 @@ internal static class GameSummaryPatch
|
||||
return $"{name} {roleInfo} {deathReason}";
|
||||
}
|
||||
|
||||
// Builds role info with stats (kills for impostors, tasks for crew)
|
||||
private static string BuildRoleInfo(NetworkedPlayerInfo playerData)
|
||||
{
|
||||
var themeColor = Utils.GetTeamHexColor(playerData.Role.TeamType);
|
||||
@@ -196,6 +216,7 @@ internal static class GameSummaryPatch
|
||||
return $"({roleName}) → {theme($"{Translator.GetString("Tasks")}: {completedTasks}/{totalTasks}")}";
|
||||
}
|
||||
|
||||
// Builds player status (DC/Dead/Alive)
|
||||
private static string BuildDeathReason(NetworkedPlayerInfo playerData)
|
||||
{
|
||||
if (playerData.Disconnected)
|
||||
|
||||
@@ -13,20 +13,28 @@ internal static class IntroCutscenePatch
|
||||
[HarmonyPostfix]
|
||||
private static void IntroCutscene_CoBegin_Postfix(IntroCutscene __instance)
|
||||
{
|
||||
// Start coroutine to customize intro after text appears
|
||||
__instance.StartCoroutine(CoWaitForShowRole(__instance));
|
||||
}
|
||||
|
||||
// Waits for intro text to appear, then customizes colors to match player's role
|
||||
private static IEnumerator CoWaitForShowRole(IntroCutscene __instance)
|
||||
{
|
||||
// Wait until "You are" text is active
|
||||
while (!__instance.YouAreText.gameObject.active)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// Get role color for local player
|
||||
var introCutscene = __instance;
|
||||
Color RoleColor = Utils.HexToColor32(PlayerControl.LocalPlayer.Data.RoleType.GetRoleHex());
|
||||
|
||||
// Hide vanilla team text
|
||||
introCutscene.ImpostorText.gameObject.SetActive(false);
|
||||
introCutscene.TeamTitle.gameObject.SetActive(false);
|
||||
|
||||
// Apply role color to all intro elements
|
||||
introCutscene.BackgroundBar.material.color = RoleColor;
|
||||
introCutscene.BackgroundBar.transform.SetLocalZ(-15);
|
||||
introCutscene.transform.Find("BackgroundLayer").transform.SetLocalZ(-16);
|
||||
|
||||
@@ -11,6 +11,7 @@ internal static class KillOverlayPatch
|
||||
[HarmonyPrefix]
|
||||
private static bool KillOverlay_ShowKillAnimation_Prefix()
|
||||
{
|
||||
// Don't show kill animation if local player is dead
|
||||
if (!PlayerControl.LocalPlayer.IsAlive())
|
||||
{
|
||||
return false;
|
||||
@@ -18,4 +19,4 @@ internal static class KillOverlayPatch
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ internal static class MeetingHudPatch
|
||||
[HarmonyPostfix]
|
||||
private static void MeetingHud_Start_Postfix(MeetingHud __instance)
|
||||
{
|
||||
// Add meeting info display to each player state
|
||||
foreach (var pva in __instance.playerStates)
|
||||
{
|
||||
var target = Utils.PlayerFromPlayerId(pva.TargetPlayerId);
|
||||
@@ -23,7 +24,7 @@ internal static class MeetingHudPatch
|
||||
|
||||
if (!GameState.IsOnlineGame) return;
|
||||
|
||||
// Add host icon to meeting hud
|
||||
// Add host icon to meeting UI
|
||||
__instance.ProceedButton.gameObject.transform.localPosition = new(-2.5f, 2.2f, 0);
|
||||
__instance.ProceedButton.gameObject.GetComponent<SpriteRenderer>().enabled = false;
|
||||
__instance.ProceedButton.GetComponent<PassiveButton>().enabled = false;
|
||||
@@ -36,6 +37,7 @@ internal static class MeetingHudPatch
|
||||
Logger_.LogHeader("Meeting Has Started");
|
||||
}
|
||||
|
||||
// Updates host icon with current host info
|
||||
internal static void UpdateHostIcon()
|
||||
{
|
||||
if (MeetingHud.Instance == null) return;
|
||||
@@ -46,7 +48,7 @@ internal static class MeetingHudPatch
|
||||
|
||||
internal static float timeOpen = 0f;
|
||||
|
||||
// Set player meeting info
|
||||
// Track how long meeting has been open
|
||||
[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Update))]
|
||||
[HarmonyPostfix]
|
||||
private static void MeetingHud_Update_Postfix(MeetingHud __instance)
|
||||
@@ -61,6 +63,7 @@ internal static class MeetingHudPatch
|
||||
timeOpen = 0f;
|
||||
Logger_.LogHeader("Meeting Has Ended");
|
||||
|
||||
// Clear chat when meeting ends if gameplay chat is enabled
|
||||
if (BAUPlugin.ChatInGameplay.Value && !GameState.IsFreePlay && PlayerControl.LocalPlayer.IsAlive())
|
||||
{
|
||||
ChatPatch.ClearPlayerChats();
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace BetterAmongUs.Patches.Gameplay.UI;
|
||||
[HarmonyPatch]
|
||||
internal static class MiniMapBehaviourPatch
|
||||
{
|
||||
// Layer offsets for different icon types (prevents overlapping)
|
||||
private const float VentLayerOffset = -0.1f;
|
||||
private const float VentArrowLayerOffset = -0.1f; // VentLayerOffset + VentArrowLayerOffset = -0.2
|
||||
private const float UsableLayerOffset = -0.3f;
|
||||
@@ -17,35 +18,39 @@ internal static class MiniMapBehaviourPatch
|
||||
[HarmonyPatch(typeof(MapBehaviour), nameof(MapBehaviour.ShowNormalMap))]
|
||||
[HarmonyPostfix]
|
||||
private static void MapBehaviour_ShowNormalMap_Postfix(MapBehaviour __instance)
|
||||
=> __instance.ColorControl.SetColor(new Color(0.05f, 0.6f, 1f, 1f));
|
||||
=> __instance.ColorControl.SetColor(new Color(0.05f, 0.6f, 1f, 1f)); // Blue tint for normal map
|
||||
|
||||
[HarmonyPatch(typeof(MapBehaviour), nameof(MapBehaviour.ShowDetectiveMap))]
|
||||
[HarmonyPostfix]
|
||||
private static void MapBehaviour_ShowDetectiveMap_Postfix(MapBehaviour __instance)
|
||||
=> __instance.ColorControl.SetColor(new Color(0.05f, 0.6f, 1f, 1f));
|
||||
=> __instance.ColorControl.SetColor(new Color(0.05f, 0.6f, 1f, 1f)); // Blue tint for detective map
|
||||
|
||||
[HarmonyPatch(typeof(MapBehaviour), nameof(MapBehaviour.ShowSabotageMap))]
|
||||
[HarmonyPostfix]
|
||||
private static void MapBehaviour_ShowSabotageMap_Postfix(MapBehaviour __instance)
|
||||
=> __instance.ColorControl.SetColor(new Color(1f, 0.3f, 0f, 1f));
|
||||
=> __instance.ColorControl.SetColor(new Color(1f, 0.3f, 0f, 1f)); // Orange tint for sabotage map
|
||||
|
||||
[HarmonyPatch(typeof(MapCountOverlay), nameof(MapCountOverlay.OnEnable))]
|
||||
[HarmonyPostfix]
|
||||
private static void MapCountOverlay_OnEnable_Postfix(MapCountOverlay __instance)
|
||||
=> __instance.BackgroundColor.SetColor(PlayerTask.PlayerHasTaskOfType<IHudOverrideTask>(PlayerControl.LocalPlayer) ? Palette.DisabledGrey : new Color(0.2f, 0.5f, 0f, 1f));
|
||||
// Green background normally, gray if comms sabotaged
|
||||
=> __instance.BackgroundColor.SetColor(PlayerTask.PlayerHasTaskOfType<IHudOverrideTask>(PlayerControl.LocalPlayer) ? Palette.DisabledGrey : new Color(0.2f, 0.5f, 0f, 1f));
|
||||
|
||||
[HarmonyPatch(typeof(MapCountOverlay), nameof(MapCountOverlay.Update))]
|
||||
[HarmonyPrefix]
|
||||
private static void MapCountOverlay_Update_Prefix(MapCountOverlay __instance)
|
||||
{
|
||||
// Handle comms sabotage effect on map
|
||||
if (PlayerTask.PlayerHasTaskOfType<IHudOverrideTask>(PlayerControl.LocalPlayer))
|
||||
{
|
||||
// Comms sabotaged - disable map
|
||||
__instance.isSab = true;
|
||||
__instance.BackgroundColor.SetColor(Palette.DisabledGrey);
|
||||
__instance.SabotageText.gameObject.SetActive(true);
|
||||
}
|
||||
else if (!PlayerTask.PlayerHasTaskOfType<IHudOverrideTask>(PlayerControl.LocalPlayer))
|
||||
else
|
||||
{
|
||||
// Comms working - normal map
|
||||
__instance.isSab = false;
|
||||
__instance.BackgroundColor.SetColor(new Color(0.2f, 0.5f, 0f, 1f));
|
||||
__instance.SabotageText.gameObject.SetActive(false);
|
||||
@@ -55,9 +60,9 @@ internal static class MiniMapBehaviourPatch
|
||||
[HarmonyPatch(typeof(MapConsole), nameof(MapConsole.Use))]
|
||||
[HarmonyPostfix]
|
||||
private static void MapConsole_ShowCountOverlay_Postfix()
|
||||
=> MapBehaviour.Instance.ColorControl.SetColor(new Color(0.2f, 0.5f, 0f, 1f));
|
||||
=> MapBehaviour.Instance.ColorControl.SetColor(new Color(0.2f, 0.5f, 0f, 1f)); // Green tint for admin map
|
||||
|
||||
private static Transform? _icons;
|
||||
private static Transform? _icons; // Container for all custom map icons
|
||||
|
||||
[HarmonyPatch(typeof(MapBehaviour), nameof(MapBehaviour.Show))]
|
||||
[HarmonyPostfix]
|
||||
@@ -65,14 +70,17 @@ internal static class MiniMapBehaviourPatch
|
||||
{
|
||||
if (BAUModdedSupportFlags.HasFlag(BAUModdedSupportFlags.Disable_MinimapIcons)) return;
|
||||
|
||||
// Make infected overlay buttons semi-transparent and smaller
|
||||
foreach (var button in __instance.infectedOverlay.allButtons)
|
||||
{
|
||||
button.spriteRenderer.color = new Color(1f, 1f, 1f, 0.8f);
|
||||
button.transform.localScale = new Vector3(0.6f, 0.6f, 1f);
|
||||
}
|
||||
|
||||
// Create icons if they don't exist yet
|
||||
if (_icons == null)
|
||||
{
|
||||
// Create container for all icons
|
||||
var icons = new GameObject("Icons")
|
||||
{
|
||||
layer = LayerMask.NameToLayer("UI")
|
||||
@@ -82,21 +90,25 @@ internal static class MiniMapBehaviourPatch
|
||||
icons.transform.localScale = Vector3.one;
|
||||
_icons = icons.transform;
|
||||
|
||||
// Add vent icons
|
||||
foreach (var vent in BAUPlugin.AllVents)
|
||||
{
|
||||
CreateVentIcon(vent);
|
||||
}
|
||||
|
||||
// Add map console icons
|
||||
foreach (var map in UnityEngine.Object.FindObjectsOfType<MapConsole>())
|
||||
{
|
||||
CreateUsableIcon(map.Cast<IUsable>());
|
||||
}
|
||||
|
||||
// Add system console icons
|
||||
foreach (var system in UnityEngine.Object.FindObjectsOfType<SystemConsole>())
|
||||
{
|
||||
CreateSystemConsoleIcon(system);
|
||||
}
|
||||
|
||||
// Add zipline icons
|
||||
foreach (var zipline in UnityEngine.Object.FindObjectsOfType<ZiplineConsole>())
|
||||
{
|
||||
var icon = CreateIcon(zipline.image.sprite, "SystemIcon");
|
||||
@@ -105,16 +117,20 @@ internal static class MiniMapBehaviourPatch
|
||||
SetPosFromShip(zipline.transform.position, icon.transform, new Vector3(0f, 0.16f, UsableLayerOffset));
|
||||
}
|
||||
|
||||
// Add task console icons for critical sabotages
|
||||
foreach (var console in UnityEngine.Object.FindObjectsOfType<Console>())
|
||||
{
|
||||
foreach (var taskType in console.TaskTypes)
|
||||
{
|
||||
// Check if this console is for critical sabotage tasks
|
||||
if (taskType is TaskTypes.FixLights or TaskTypes.FixComms or TaskTypes.RestoreOxy or TaskTypes.ResetReactor or TaskTypes.ResetSeismic)
|
||||
{
|
||||
var icon = CreateIcon(console.Image.sprite, "ConsoleIcon");
|
||||
icon.color = Color.white * 0.7f;
|
||||
icon.transform.localScale = Vector3.one * 0.5f;
|
||||
SetPosFromShip(console.transform.position, icon.transform, new Vector3(0f, 0f, UsableLayerOffset));
|
||||
|
||||
// Add animation when player has this task
|
||||
var animatedMapIcon = icon.gameObject.AddComponent<AnimatedMapIcon>();
|
||||
animatedMapIcon.ShouldAnimate += () =>
|
||||
{
|
||||
@@ -127,6 +143,7 @@ internal static class MiniMapBehaviourPatch
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a vent icon with connection arrows to neighboring vents
|
||||
private static void CreateVentIcon(Vent vent)
|
||||
{
|
||||
var icon = CreateIcon(Utils.LoadSprite("BetterAmongUs.Resources.Images.Icons.Vent.png", 380), "VentIcon");
|
||||
@@ -135,11 +152,13 @@ internal static class MiniMapBehaviourPatch
|
||||
|
||||
SetPosFromShip(vent.transform.position, icon.transform, new Vector3(0f, 0f, VentLayerOffset));
|
||||
|
||||
// Get connected vents
|
||||
Vent[] nearbyVents = [vent.Left, vent.Right, vent.Center];
|
||||
float maxSpreadShift = 0.5f;
|
||||
float minSpreadShift = 0.2f;
|
||||
float closeDistance = 10f;
|
||||
|
||||
// Create arrows to each connected vent
|
||||
for (int i = 0; i < nearbyVents.Length; i++)
|
||||
{
|
||||
Vent neighborVent = nearbyVents[i];
|
||||
@@ -149,9 +168,11 @@ internal static class MiniMapBehaviourPatch
|
||||
arrowIcon.color = VentGroups.GetVentGroupColor(neighborVent);
|
||||
arrowIcon.transform.SetParent(icon.transform);
|
||||
|
||||
// Calculate arrow position and rotation based on neighbor location
|
||||
Vector3 directionToNeighbor = neighborVent.transform.position - vent.transform.position;
|
||||
float distanceToNeighbor = directionToNeighbor.magnitude;
|
||||
|
||||
// Adjust arrow spread based on distance
|
||||
float spreadShift;
|
||||
if (distanceToNeighbor < closeDistance)
|
||||
{
|
||||
@@ -168,6 +189,7 @@ internal static class MiniMapBehaviourPatch
|
||||
|
||||
SetPosFromShip(arrowOffset, arrowIcon.transform, new Vector3(0f, 0f, VentArrowLayerOffset));
|
||||
|
||||
// Rotate arrow to point toward neighbor
|
||||
Vector3 ventMapPos = vent.transform.position / ShipStatus.Instance.MapScale;
|
||||
ventMapPos.x *= Mathf.Sign(ShipStatus.Instance.transform.localScale.x);
|
||||
|
||||
@@ -182,6 +204,7 @@ internal static class MiniMapBehaviourPatch
|
||||
}
|
||||
}
|
||||
|
||||
// Creates icon for system consoles
|
||||
private static void CreateSystemConsoleIcon(SystemConsole systemConsole)
|
||||
{
|
||||
if (systemConsole.UseIcon is not ImageNames.UseButton)
|
||||
@@ -197,8 +220,10 @@ internal static class MiniMapBehaviourPatch
|
||||
}
|
||||
}
|
||||
|
||||
// Creates icon for usables
|
||||
private static void CreateUsableIcon(IUsable usable)
|
||||
{
|
||||
// Special handling for emergency buttons
|
||||
if (usable.TryCast<SystemConsole>(out var systemConsole))
|
||||
{
|
||||
if (systemConsole.MinigamePrefab.name == "EmergencyMinigame")
|
||||
@@ -213,11 +238,12 @@ internal static class MiniMapBehaviourPatch
|
||||
{
|
||||
if (systemConsole.UseIcon is ImageNames.UseButton)
|
||||
{
|
||||
return;
|
||||
return; // Skip default use button icons
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create icon based on use button settings
|
||||
if (HudManager.Instance.UseButton.fastUseSettings.TryGetValue(usable.UseIcon, out var settings))
|
||||
{
|
||||
var icon = CreateIcon(settings.Image, "UsableIcon");
|
||||
@@ -227,6 +253,7 @@ internal static class MiniMapBehaviourPatch
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to create a new icon sprite renderer
|
||||
private static SpriteRenderer CreateIcon(Sprite sprite, string name = "Icon")
|
||||
{
|
||||
var go = new GameObject(name)
|
||||
@@ -240,6 +267,7 @@ internal static class MiniMapBehaviourPatch
|
||||
return spriteRenderer;
|
||||
}
|
||||
|
||||
// Helper to position icons on map relative to ship position
|
||||
private static void SetPosFromShip(Vector3 shipPos, Transform mapTransform, Vector3? offset = null)
|
||||
{
|
||||
offset ??= Vector3.zero;
|
||||
@@ -249,4 +277,4 @@ internal static class MiniMapBehaviourPatch
|
||||
vector.z = -1f;
|
||||
mapTransform.transform.localPosition = new Vector3(vector.x + offset.Value.x, vector.y + offset.Value.y, offset.Value.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,13 +11,14 @@ namespace BetterAmongUs.Patches.Gameplay.UI;
|
||||
[HarmonyPatch]
|
||||
internal static class PlayerTabPatch
|
||||
{
|
||||
private static List<PassiveButton> presetButtons = [];
|
||||
private static float cooldown = 0f;
|
||||
private static List<PassiveButton> presetButtons = []; // Outfit preset buttons
|
||||
private static float cooldown = 0f; // Button click cooldown
|
||||
|
||||
[HarmonyPatch(typeof(PlayerTab), nameof(PlayerTab.OnEnable))]
|
||||
[HarmonyPrefix]
|
||||
private static void PlayerTab_OnEnable_Prefix(PlayerTab __instance)
|
||||
{
|
||||
// Clean up old preset buttons
|
||||
foreach (var button in presetButtons.ToArray())
|
||||
{
|
||||
if (button == null) continue;
|
||||
@@ -25,23 +26,28 @@ internal static class PlayerTabPatch
|
||||
}
|
||||
presetButtons.Clear();
|
||||
|
||||
// Create preset buttons (0 = Among Us preset, 1-5 = custom presets)
|
||||
for (int i = 0; i <= 5; i++)
|
||||
{
|
||||
int currentI = i;
|
||||
var name = currentI == 0 ? "Among Us Preset" : $"Preset {i}";
|
||||
var button = __instance.CreateButton(name, new Vector3(2.5f, 1.55f - currentI * 0.45f, 0f), () =>
|
||||
{
|
||||
// Ignore if cooldown active or same preset selected
|
||||
if (cooldown > 0f || BetterDataManager.BetterDataFile.SelectedOutfitPreset == currentI) return;
|
||||
cooldown = 0.5f;
|
||||
|
||||
// Update selected preset
|
||||
BetterDataManager.BetterDataFile.SelectedOutfitPreset = currentI;
|
||||
|
||||
// Reset all button hover states
|
||||
foreach (var button in presetButtons)
|
||||
{
|
||||
if (button == null) continue;
|
||||
button.SetPassiveButtonHoverStateInactive();
|
||||
}
|
||||
|
||||
// Load and apply outfit from preset
|
||||
var data = OutfitData.GetOutfitData(currentI);
|
||||
data.Load(() =>
|
||||
{
|
||||
@@ -67,31 +73,37 @@ internal static class PlayerTabPatch
|
||||
{
|
||||
_favoriteIcons.Clear();
|
||||
|
||||
// Add favorite functionality to color chips
|
||||
for (int i = 0; i < __instance.ColorChips.Count; i++)
|
||||
{
|
||||
var index = i;
|
||||
var colorChip = __instance.ColorChips[i];
|
||||
|
||||
// Override click behavior
|
||||
colorChip.Button.OnClick = new();
|
||||
colorChip.Button.OnClick.AddListener((Action)(() =>
|
||||
{
|
||||
// Shift+Click = toggle favorite
|
||||
if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
|
||||
{
|
||||
if (BAUPlugin.FavoriteColor.Value == index)
|
||||
{
|
||||
BAUPlugin.FavoriteColor.Value = -1;
|
||||
BAUPlugin.FavoriteColor.Value = -1; // Remove favorite
|
||||
}
|
||||
else
|
||||
{
|
||||
BAUPlugin.FavoriteColor.Value = index;
|
||||
BAUPlugin.FavoriteColor.Value = index; // Set favorite
|
||||
}
|
||||
|
||||
UpdateFavorite();
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal click = equip color
|
||||
__instance.ClickEquip();
|
||||
}));
|
||||
|
||||
// Add favorite star indicator
|
||||
var checkBox = colorChip.PlayerEquippedForeground.transform.Find("CheckMark").GetComponentInChildren<SpriteRenderer>();
|
||||
var favoriteIcon = UnityEngine.Object.Instantiate(checkBox, colorChip.transform);
|
||||
favoriteIcon.color = Color.yellow;
|
||||
@@ -102,6 +114,7 @@ internal static class PlayerTabPatch
|
||||
UpdateFavorite();
|
||||
}
|
||||
|
||||
// Update favorite star visibility
|
||||
private static void UpdateFavorite()
|
||||
{
|
||||
for (int i = 0; i < _favoriteIcons.Count; i++)
|
||||
@@ -111,6 +124,7 @@ internal static class PlayerTabPatch
|
||||
}
|
||||
}
|
||||
|
||||
// Apply outfit to local player
|
||||
private static bool LoadPlayerOutfit(OutfitData data)
|
||||
{
|
||||
var player = PlayerControl.LocalPlayer;
|
||||
@@ -127,6 +141,7 @@ internal static class PlayerTabPatch
|
||||
return false;
|
||||
}
|
||||
|
||||
// Helper to create preset buttons
|
||||
private static PassiveButton CreateButton(this PlayerTab __instance, string name, Vector3 pos, Action callback)
|
||||
{
|
||||
var button = UnityEngine.Object.Instantiate(MainMenuManagerPatch.ButtonPrefab, __instance.transform);
|
||||
@@ -146,6 +161,7 @@ internal static class PlayerTabPatch
|
||||
[HarmonyPrefix]
|
||||
private static void PlayerTab_Updatee_Postfix(PlayerTab __instance)
|
||||
{
|
||||
// Handle cooldown
|
||||
if (cooldown > 0f)
|
||||
{
|
||||
cooldown -= Time.deltaTime;
|
||||
@@ -155,14 +171,15 @@ internal static class PlayerTabPatch
|
||||
cooldown = 0f;
|
||||
}
|
||||
|
||||
// Update preset button hover states
|
||||
for (int i = 0; i < presetButtons.Count; i++)
|
||||
{
|
||||
PassiveButton? button = presetButtons[i];
|
||||
if (button == null) continue;
|
||||
if (i == BetterDataManager.BetterDataFile.SelectedOutfitPreset)
|
||||
{
|
||||
button.SetPassiveButtonHoverStateActive();
|
||||
button.SetPassiveButtonHoverStateActive(); // Highlight selected preset
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ internal static class RoomTrackerPatch
|
||||
[HarmonyPostfix]
|
||||
private static void RoomTracker_Awake_Postfix(RoomTracker __instance)
|
||||
{
|
||||
// Fix aspect positioning
|
||||
var originalParent = __instance.transform.parent;
|
||||
|
||||
var holder = new GameObject("RoomTrackerHolder");
|
||||
|
||||
@@ -9,7 +9,8 @@ using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs.Patches.Gameplay.UI.Settings;
|
||||
|
||||
class BetterGameSettings
|
||||
// Custom game settings definitions
|
||||
internal sealed class BetterGameSettings
|
||||
{
|
||||
internal static OptionStringItem? WhenCheating;
|
||||
internal static OptionCheckboxItem? InvalidFriendCode;
|
||||
@@ -30,7 +31,8 @@ class BetterGameSettings
|
||||
internal static OptionCheckboxItem? DisableSabotages;
|
||||
}
|
||||
|
||||
class BetterGameSettingsTemp
|
||||
// Temporary settings for Hide & Seek impostor selection
|
||||
internal sealed class BetterGameSettingsTemp
|
||||
{
|
||||
internal static OptionPlayerItem? HideAndSeekImp2;
|
||||
internal static OptionPlayerItem? HideAndSeekImp3;
|
||||
@@ -43,19 +45,22 @@ internal static class GameSettingsPatch
|
||||
{
|
||||
internal static OptionTab? BetterSettingsTab;
|
||||
|
||||
// Creates all custom game settings and organizes them in tabs
|
||||
internal static void SetupSettings(bool IsPreload = false)
|
||||
{
|
||||
// Use 1800 next ID
|
||||
// Note: Use 1800 next ID
|
||||
|
||||
// Create main settings tab
|
||||
BetterSettingsTab = OptionTab.Create(3, "BetterSetting", "BetterSetting.Description", Color.green);
|
||||
|
||||
OptionHeaderItem.Create(BetterSettingsTab, "BetterSetting.MainHeader.System");
|
||||
OptionPresetItem.Create();
|
||||
|
||||
// Anti-Cheat Settings
|
||||
// Anti-Cheat Settings section
|
||||
{
|
||||
OptionHeaderItem.Create(BetterSettingsTab, "BetterSetting.MainHeader.AntiCheat");
|
||||
|
||||
// Host-only anti-cheat settings
|
||||
if (IsPreload || GameState.IsHost)
|
||||
{
|
||||
OptionTitleItem.Create(BetterSettingsTab, "BetterSetting.TextHeader.HostOnly");
|
||||
@@ -69,6 +74,7 @@ internal static class GameSettingsPatch
|
||||
BetterGameSettings.UseBanWordListOnlyLobby = OptionCheckboxItem.Create(1400, BetterSettingsTab, "BetterSetting.Setting.UseBanWordListOnlyLobby", true, BetterGameSettings.UseBanWordList);
|
||||
}
|
||||
|
||||
// General detection settings (visible to all)
|
||||
OptionTitleItem.Create(BetterSettingsTab, "BetterSetting.TextHeader.Detections");
|
||||
BetterGameSettings.CensorDetectionReason = OptionCheckboxItem.Create(1300, BetterSettingsTab, "BetterSetting.Setting.CensorDetectionReason", false);
|
||||
BetterGameSettings.DetectedLevelAbove = OptionIntItem.Create(600, BetterSettingsTab, "BetterSetting.Setting.DetectedLevelAbove", (100, 10000, 5), 500, ("Lv ", ""));
|
||||
@@ -77,6 +83,7 @@ internal static class GameSettingsPatch
|
||||
BetterGameSettings.DetectInvalidRPCs = OptionCheckboxItem.Create(800, BetterSettingsTab, "BetterSetting.Setting.DetectInvalidRPCs", true);
|
||||
}
|
||||
|
||||
// Role algorithm settings
|
||||
if (IsPreload || GameState.IsHost)
|
||||
{
|
||||
OptionHeaderItem.Create(BetterSettingsTab, "BetterSetting.MainHeader.RoleAlgorithm");
|
||||
@@ -84,31 +91,38 @@ internal static class GameSettingsPatch
|
||||
BetterGameSettings.DesyncRoles = OptionCheckboxItem.Create(1200, BetterSettingsTab, "BetterSetting.Setting.DesyncRoles", true);
|
||||
}
|
||||
|
||||
// Gameplay Settings
|
||||
// Gameplay Settings section
|
||||
{
|
||||
// Show only for hosts in private lobbies
|
||||
if (IsPreload || GameState.IsHost && GameState.IsPrivateOnlyLobby)
|
||||
{
|
||||
// Normal game mode settings
|
||||
if (IsPreload || !GameState.IsHideNSeek)
|
||||
{
|
||||
OptionHeaderItem.Create(BetterSettingsTab, "BetterSetting.MainHeader.Gameplay");
|
||||
BetterGameSettings.DisableSabotages = OptionCheckboxItem.Create(1500, BetterSettingsTab, "BetterSetting.Setting.DisableSabotages", false);
|
||||
BetterGameSettings.RemovePetOnDeath = OptionCheckboxItem.Create(1600, BetterSettingsTab, "BetterSetting.Setting.RemovePetOnDeath", false);
|
||||
}
|
||||
// Hide & Seek specific settings with dynamic impostor selection
|
||||
else if (IsPreload || GameState.IsHideNSeek)
|
||||
{
|
||||
OptionHeaderItem.Create(BetterSettingsTab, "BetterSetting.MainHeader.HideNSeek");
|
||||
OptionTitleItem.Create(BetterSettingsTab, $"<color={RoleTypes.Impostor.GetRoleHex()}>{Translator.GetString(StringNames.ImpostorsCategory)}</color>");
|
||||
BetterGameSettings.HideAndSeekImpNum = OptionIntItem.Create(1000, BetterSettingsTab, "BetterSetting.Setting.HideAndSeekImpNum", (1, 5, 1), 1);
|
||||
|
||||
// Create player selection dropdowns that appear based on impostor count
|
||||
BetterGameSettingsTemp.HideAndSeekImp2 = OptionPlayerItem.Create(0, BetterSettingsTab, "BetterSetting.TempSetting.HideAndSeekImpNum", BetterGameSettings.HideAndSeekImpNum);
|
||||
BetterGameSettingsTemp.HideAndSeekImp2.ShowCondition = () => BetterGameSettings.HideAndSeekImpNum.GetValue() >= 2;
|
||||
|
||||
BetterGameSettingsTemp.HideAndSeekImp3 = OptionPlayerItem.Create(1, BetterSettingsTab, "BetterSetting.TempSetting.HideAndSeekImpNum", BetterGameSettings.HideAndSeekImpNum);
|
||||
BetterGameSettingsTemp.HideAndSeekImp3.ShowCondition = () => BetterGameSettings.HideAndSeekImpNum.GetValue() >= 3 &&
|
||||
BetterGameSettingsTemp.HideAndSeekImp2.GetValue() != -1;
|
||||
|
||||
BetterGameSettingsTemp.HideAndSeekImp4 = OptionPlayerItem.Create(2, BetterSettingsTab, "BetterSetting.TempSetting.HideAndSeekImpNum", BetterGameSettings.HideAndSeekImpNum);
|
||||
BetterGameSettingsTemp.HideAndSeekImp4.ShowCondition = () => BetterGameSettings.HideAndSeekImpNum.GetValue() >= 4 &&
|
||||
BetterGameSettingsTemp.HideAndSeekImp2.GetValue() != -1 &&
|
||||
BetterGameSettingsTemp.HideAndSeekImp3.GetValue() != -1;
|
||||
|
||||
BetterGameSettingsTemp.HideAndSeekImp5 = OptionPlayerItem.Create(3, BetterSettingsTab, "BetterSetting.TempSetting.HideAndSeekImpNum", BetterGameSettings.HideAndSeekImpNum);
|
||||
BetterGameSettingsTemp.HideAndSeekImp5.ShowCondition = () => BetterGameSettings.HideAndSeekImpNum.GetValue() >= 5 &&
|
||||
BetterGameSettingsTemp.HideAndSeekImp2.GetValue() != -1 &&
|
||||
@@ -121,6 +135,7 @@ internal static class GameSettingsPatch
|
||||
BetterSettingsTab.UpdateVisuals();
|
||||
}
|
||||
|
||||
// Initialize settings
|
||||
[HarmonyPatch(typeof(GameSettingMenu), nameof(GameSettingMenu.Start))]
|
||||
[HarmonyPostfix]
|
||||
private static void GameSettingMenu_Start_Postfix(GameSettingMenu __instance)
|
||||
@@ -129,6 +144,7 @@ internal static class GameSettingsPatch
|
||||
|
||||
SetupSettings();
|
||||
|
||||
// Adjust menu layout
|
||||
__instance.gameObject.transform.SetLocalY(-0.1f);
|
||||
GameObject PanelSprite = __instance.gameObject.transform.Find("PanelSprite").gameObject;
|
||||
if (PanelSprite != null)
|
||||
@@ -137,18 +153,21 @@ internal static class GameSettingsPatch
|
||||
PanelSprite.transform.localScale = new Vector3(PanelSprite.transform.localScale.x, 0.625f);
|
||||
}
|
||||
|
||||
// Clear hover effects
|
||||
__instance.GamePresetsButton.OnMouseOver.RemoveAllListeners();
|
||||
__instance.GameSettingsButton.OnMouseOver.RemoveAllListeners();
|
||||
__instance.RoleSettingsButton.OnMouseOver.RemoveAllListeners();
|
||||
|
||||
|
||||
// Configure tab behavior based on game mode and host status
|
||||
BetterSettingsTab.TabButton.transform.localPosition = BetterSettingsTab.TabButton.transform.localPosition - new Vector3(0f, 1.265f, 0f);
|
||||
|
||||
if (!GameState.IsHideNSeek && GameState.IsHost)
|
||||
{
|
||||
__instance.ChangeTab(1, false);
|
||||
__instance.ChangeTab(1, false); // Show game settings tab for hosts
|
||||
}
|
||||
else if (GameState.IsHost)
|
||||
{
|
||||
// Hide & Seek host: disable role button but keep visible
|
||||
__instance.RoleSettingsButton.gameObject.SetActive(true);
|
||||
__instance.RoleSettingsButton.GetComponent<PassiveButton>().enabled = false;
|
||||
__instance.RoleSettingsButton.inactiveSprites.GetComponent<SpriteRenderer>().color = new(0.5f, 0.5f, 0.5f, 1f);
|
||||
@@ -156,27 +175,30 @@ internal static class GameSettingsPatch
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non-hosts: disable all vanilla tabs and show custom tab
|
||||
__instance.GamePresetsButton.GetComponent<PassiveButton>().enabled = false;
|
||||
__instance.GameSettingsButton.GetComponent<PassiveButton>().enabled = false;
|
||||
__instance.RoleSettingsButton.GetComponent<PassiveButton>().enabled = false;
|
||||
__instance.GamePresetsButton.inactiveSprites.GetComponent<SpriteRenderer>().color = new(0.5f, 0.5f, 0.5f, 1f);
|
||||
__instance.GameSettingsButton.inactiveSprites.GetComponent<SpriteRenderer>().color = new(0.5f, 0.5f, 0.5f, 1f);
|
||||
__instance.RoleSettingsButton.inactiveSprites.GetComponent<SpriteRenderer>().color = new(0.5f, 0.5f, 0.5f, 1f);
|
||||
__instance.ChangeTab(3, false);
|
||||
__instance.ChangeTab(3, false); // Switch to custom tab
|
||||
}
|
||||
}
|
||||
|
||||
// Handle tab switching to show/hide custom settings tab
|
||||
[HarmonyPatch(typeof(GameSettingMenu), nameof(GameSettingMenu.ChangeTab))]
|
||||
[HarmonyPrefix]
|
||||
private static void GameSettingMenu_ChangeTab_Prefix(GameSettingMenu __instance, [HarmonyArgument(0)] int tabNum, [HarmonyArgument(1)] bool previewOnly)
|
||||
{
|
||||
if (BAUModdedSupportFlags.HasFlag(BAUModdedSupportFlags.Disable_AllGameOptions)) return;
|
||||
|
||||
if (BetterSettingsTab == null) return;
|
||||
|
||||
// Hide custom tab when switching away
|
||||
BetterSettingsTab.AUTab?.gameObject?.SetActive(false);
|
||||
BetterSettingsTab.TabButton?.SelectButton(false);
|
||||
|
||||
// Show custom tab when selected (tab 3)
|
||||
if (previewOnly && Controller.currentTouchType == Controller.TouchType.Joystick || !previewOnly)
|
||||
{
|
||||
switch (tabNum)
|
||||
@@ -190,12 +212,14 @@ internal static class GameSettingsPatch
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent vanilla settings from being created in custom tab
|
||||
[HarmonyPatch(typeof(GameOptionsMenu), nameof(GameOptionsMenu.CreateSettings))]
|
||||
[HarmonyPrefix]
|
||||
private static bool GameOptionsMenu_CreateSettings_Prefix(GameOptionsMenu __instance)
|
||||
{
|
||||
if (BAUModdedSupportFlags.HasFlag(BAUModdedSupportFlags.Disable_AllGameOptions)) return true;
|
||||
|
||||
// Skip creation if this is our custom tab
|
||||
if (__instance == BetterSettingsTab.AUTab)
|
||||
{
|
||||
return false;
|
||||
@@ -204,12 +228,13 @@ internal static class GameSettingsPatch
|
||||
return true;
|
||||
}
|
||||
|
||||
// Make OptionsConsole usable by anyone (not just host)
|
||||
[HarmonyPatch(typeof(OptionsConsole), nameof(OptionsConsole.CanUse))]
|
||||
[HarmonyPrefix]
|
||||
private static void OptionsConsole_CanUse_Prefix(OptionsConsole __instance)
|
||||
{
|
||||
if (BAUModdedSupportFlags.HasFlag(BAUModdedSupportFlags.Disable_AllGameOptions)) return;
|
||||
|
||||
__instance.HostOnly = false;
|
||||
__instance.HostOnly = false; // Allow non-hosts to use settings console
|
||||
}
|
||||
}
|
||||
@@ -13,23 +13,28 @@ internal static class NumberOptionPatch
|
||||
{
|
||||
if (BAUModdedSupportFlags.HasFlag(BAUModdedSupportFlags.Disable_AllGameOptions)) return true;
|
||||
|
||||
// Determine multiplier based on modifier keys
|
||||
int times = 1;
|
||||
if (Input.GetKey(KeyCode.LeftShift))
|
||||
times = 5;
|
||||
times = 5; // Shift = 5x
|
||||
if (Input.GetKey(KeyCode.LeftControl))
|
||||
times = 10;
|
||||
times = 10; // Control = 10x
|
||||
|
||||
// Increase value with bounds checking
|
||||
if (__instance.Value + __instance.Increment * times > __instance.ValidRange.max)
|
||||
{
|
||||
__instance.Value = __instance.ValidRange.max;
|
||||
__instance.Value = __instance.ValidRange.max; // Cap at max
|
||||
}
|
||||
else
|
||||
{
|
||||
__instance.Value = __instance.ValidRange.Clamp(__instance.Value + __instance.Increment * times);
|
||||
}
|
||||
|
||||
// Update UI and invoke events
|
||||
__instance.UpdateValue();
|
||||
__instance.OnValueChanged.Invoke(__instance);
|
||||
__instance.AdjustButtonsActiveState();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -39,23 +44,28 @@ internal static class NumberOptionPatch
|
||||
{
|
||||
if (BAUModdedSupportFlags.HasFlag(BAUModdedSupportFlags.Disable_AllGameOptions)) return true;
|
||||
|
||||
// Determine multiplier based on modifier keys
|
||||
int times = 1;
|
||||
if (Input.GetKey(KeyCode.LeftShift))
|
||||
times = 5;
|
||||
times = 5; // Shift = 5x
|
||||
if (Input.GetKey(KeyCode.LeftControl))
|
||||
times = 10;
|
||||
times = 10; // Control = 10x
|
||||
|
||||
// Decrease value with bounds checking
|
||||
if (__instance.Value - __instance.Increment * times < __instance.ValidRange.min)
|
||||
{
|
||||
__instance.Value = __instance.ValidRange.min;
|
||||
__instance.Value = __instance.ValidRange.min; // Cap at min
|
||||
}
|
||||
else
|
||||
{
|
||||
__instance.Value = __instance.ValidRange.Clamp(__instance.Value - __instance.Increment * times);
|
||||
}
|
||||
|
||||
// Update UI and invoke events
|
||||
__instance.UpdateValue();
|
||||
__instance.OnValueChanged.Invoke(__instance);
|
||||
__instance.AdjustButtonsActiveState();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,47 +9,56 @@ namespace BetterAmongUs.Patches.Gameplay;
|
||||
[HarmonyPatch]
|
||||
internal class ZoomPatch
|
||||
{
|
||||
private static bool _wasZooming = false;
|
||||
private static float _lastOrthographicSize = 0f;
|
||||
private static bool _wasZooming = false; // Track if user was zooming
|
||||
private static float _lastOrthographicSize = 0f; // Track last camera size
|
||||
|
||||
[HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))]
|
||||
[HarmonyPostfix]
|
||||
private static void HudManager_Update_Postfix()
|
||||
{
|
||||
// Determine if zooming is allowed:
|
||||
// - Player can move AND
|
||||
// - Not Guardian Angel AND
|
||||
// - Either not in gameplay OR player is dead
|
||||
bool canZoom = GameState.IsCanMove &&
|
||||
!PlayerControl.LocalPlayer.Is(RoleTypes.GuardianAngel) &&
|
||||
(!GameState.IsInGamePlay || !PlayerControl.LocalPlayer.IsAlive());
|
||||
|
||||
// Should we reset zoom (when player was zooming but no longer can)
|
||||
bool shouldReset = !canZoom && _wasZooming;
|
||||
|
||||
_lastOrthographicSize = Camera.main.orthographicSize;
|
||||
|
||||
if (shouldReset)
|
||||
{
|
||||
// Reset to default zoom
|
||||
SetZoomSize(reset: true);
|
||||
_wasZooming = false;
|
||||
}
|
||||
else if (canZoom)
|
||||
{
|
||||
// Handle scroll wheel input
|
||||
if (Input.mouseScrollDelta.y > 0 && Camera.main.orthographicSize > 3.0f)
|
||||
{
|
||||
_wasZooming = true;
|
||||
SetZoomSize(zoomIn: true);
|
||||
SetZoomSize(zoomIn: true); // Scroll up = zoom in
|
||||
}
|
||||
else if (Input.mouseScrollDelta.y < 0 &&
|
||||
(GameState.IsDead || GameState.IsFreePlay || GameState.IsLobby) &&
|
||||
Camera.main.orthographicSize < 18.0f)
|
||||
{
|
||||
_wasZooming = true;
|
||||
SetZoomSize(zoomOut: true);
|
||||
SetZoomSize(zoomOut: true); // Scroll down = zoom out
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handles zoom in/out and reset functionality
|
||||
private static void SetZoomSize(bool zoomIn = false, bool zoomOut = false, bool reset = false)
|
||||
{
|
||||
if (reset)
|
||||
{
|
||||
// Reset to default zoom (3.0)
|
||||
Camera.main.orthographicSize = 3.0f;
|
||||
HudManager.Instance.UICamera.orthographicSize = 3.0f;
|
||||
HudManager.Instance.Chat.transform.localScale = Vector3.one;
|
||||
@@ -59,15 +68,18 @@ internal class ZoomPatch
|
||||
}
|
||||
else if (zoomIn || zoomOut)
|
||||
{
|
||||
// Zoom in (multiply by 1/1.5 = 0.666) or zoom out (multiply by 1.5)
|
||||
float size = zoomIn ? 1 / 1.5f : 1.5f;
|
||||
Camera.main.orthographicSize *= size;
|
||||
HudManager.Instance.UICamera.orthographicSize *= size;
|
||||
}
|
||||
|
||||
// Show/hide shadow quad based on zoom level and if player is alive
|
||||
HudManager.Instance?.ShadowQuad?.gameObject?.SetActive(
|
||||
(reset || Camera.main.orthographicSize == 3.0f) &&
|
||||
PlayerControl.LocalPlayer.IsAlive());
|
||||
|
||||
// Trigger resolution change event if camera size changed
|
||||
if (Camera.main.orthographicSize != _lastOrthographicSize)
|
||||
{
|
||||
ResolutionManager.ResolutionChanged.Invoke(
|
||||
@@ -76,4 +88,4 @@ internal class ZoomPatch
|
||||
Screen.fullScreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,17 @@ namespace BetterAmongUs.Patches.Unity;
|
||||
[HarmonyPatch]
|
||||
internal static class StandaloneSteamPatch
|
||||
{
|
||||
// Try to get the SteamAPI type from the game assembly
|
||||
private static readonly Type? _type = Type.GetType("Steamworks.SteamAPI, Assembly-CSharp-firstpass", false);
|
||||
|
||||
// Only apply this patch if SteamAPI type exists (game has Steam integration)
|
||||
[HarmonyPrepare]
|
||||
private static bool Prepare()
|
||||
{
|
||||
return _type != null;
|
||||
}
|
||||
|
||||
// Target the RestartAppIfNecessary method in SteamAPI
|
||||
[HarmonyTargetMethod]
|
||||
private static MethodBase TargetMethod()
|
||||
{
|
||||
@@ -24,11 +27,14 @@ internal static class StandaloneSteamPatch
|
||||
{
|
||||
const string file = "steam_appid.txt";
|
||||
|
||||
// Create steam_appid.txt with Among Us app ID if it doesn't exist
|
||||
// This allows the game to run without Steam running
|
||||
if (!File.Exists(file))
|
||||
{
|
||||
File.WriteAllText(file, "945360");
|
||||
File.WriteAllText(file, "945360"); // Among Us Steam App ID
|
||||
}
|
||||
|
||||
return __result = false;
|
||||
__result = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,10 +10,12 @@ namespace BetterAmongUs.Patches.Unity;
|
||||
[HarmonyPatch]
|
||||
internal static class UnityWebRequestPatch
|
||||
{
|
||||
// Build mod version header string
|
||||
public static string GetHeader()
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
|
||||
// Format: "Version;BuildType;IsHotfix/HotfixNum/BetaNum"
|
||||
stringBuilder.Append(ModInfo.PLUGIN_VERSION);
|
||||
stringBuilder.Append(';');
|
||||
stringBuilder.Append(Enum.GetName(ModInfo.ReleaseBuildType));
|
||||
@@ -27,19 +29,23 @@ internal static class UnityWebRequestPatch
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
// Add custom header to game API requests
|
||||
[HarmonyPatch(typeof(UnityWebRequest), nameof(UnityWebRequest.SendWebRequest))]
|
||||
[HarmonyPrefix]
|
||||
private static void UnityWebRequest_SendWebRequest_Prefix(UnityWebRequest __instance)
|
||||
{
|
||||
if (BAUModdedSupportFlags.HasFlag(BAUModdedSupportFlags.Disable_BAUHttpHeader)) return;
|
||||
|
||||
// Check if this is a game API request
|
||||
var path = new Uri(__instance.url).AbsolutePath;
|
||||
if (path.Contains("/api/games"))
|
||||
{
|
||||
// Add mod version header so server knows we're modded
|
||||
__instance.SetRequestHeader("BAU-Mod", GetHeader());
|
||||
}
|
||||
}
|
||||
|
||||
// Check server response for mod support acknowledgment
|
||||
[HarmonyPatch(typeof(UnityWebRequest), nameof(UnityWebRequest.SendWebRequest))]
|
||||
[HarmonyPostfix]
|
||||
private static void UnityWebRequest_SendWebRequest_Postfix(UnityWebRequest __instance, UnityWebRequestAsyncOperation __result)
|
||||
@@ -49,10 +55,12 @@ internal static class UnityWebRequestPatch
|
||||
var path = new Uri(__instance.url).AbsolutePath;
|
||||
if (path.Contains("/api/games"))
|
||||
{
|
||||
// Add callback when request completes
|
||||
__result.add_completed((Action<AsyncOperation>)(_ =>
|
||||
{
|
||||
if (!HttpUtils.IsSuccess(__instance.responseCode)) return;
|
||||
|
||||
// Check if server supports BAU mod
|
||||
var responseHeader = __instance.GetResponseHeader("BAU-Mod-Processed");
|
||||
|
||||
if (responseHeader != null)
|
||||
@@ -62,4 +70,4 @@ internal static class UnityWebRequestPatch
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user