add comments

This commit is contained in:
D1GQ committed 2026-02-27 23:40:40 -06:00
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 { }
}
}
}
}
+20 -7
View File
@@ -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)
{
+3 -1
View File
@@ -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;
}
}
}
+2 -1
View File
@@ -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);
}
}
}
+3 -1
View File
@@ -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);
}
+1 -1
View File
@@ -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");
}
}
}
+30 -9
View File
@@ -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);
+2 -1
View File
@@ -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;
}
}
}
+5 -2
View File
@@ -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);
}
}
}
+23 -6
View File
@@ -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;
}
}
}
+17 -5
View File
@@ -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);
}
}
}
}
+9 -3
View File
@@ -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;
}
}
}
+9 -1
View File
@@ -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
}));
}
}
}
}