From d23fc1e13cfdf48b1458e5796c0354c359fddacb Mon Sep 17 00:00:00 2001 From: D1GQ Date: Thu, 26 Feb 2026 15:02:36 -0600 Subject: [PATCH] Show sabotages on map --- src/Modules/VentGroups.cs | 27 ++++++++- src/Mono/AnimatedMapIcon.cs | 56 +++++++++++++++++++ .../Gameplay/UI/MiniMapBehaviourPatch.cs | 42 +++++++++++--- 3 files changed, 117 insertions(+), 8 deletions(-) create mode 100644 src/Mono/AnimatedMapIcon.cs diff --git a/src/Modules/VentGroups.cs b/src/Modules/VentGroups.cs index 58cd703..2a844c3 100644 --- a/src/Modules/VentGroups.cs +++ b/src/Modules/VentGroups.cs @@ -2,11 +2,29 @@ namespace BetterAmongUs.Modules; +/// +/// Provides functionality for grouping vents and assigning colors to vent groups. +/// internal static class VentGroups { + /// + /// Dictionary mapping each vent ID to the lowest ID in its group. + /// private static readonly Dictionary ventToLowestId = []; + + /// + /// Dictionary mapping group IDs (lowest vent ID in the group) to their assigned colors. + /// private static readonly Dictionary groupColors = []; + /// + /// Calculates all vent groups by performing a breadth-first search through connected vents. + /// + /// Array of all vents in the scene to process. + /// + /// Groups vents that are connected via Left, Right, or Center references. + /// Each group is assigned a color, and the lowest vent ID in the group becomes the group identifier. + /// internal static void CalculateAllVentGroups(Vent[] vents) { ventToLowestId.Clear(); @@ -82,6 +100,13 @@ internal static class VentGroups } } + /// + /// Gets the group color for a specific vent. + /// + /// The vent to get the group color for. + /// + /// The color assigned to the vent's group, or if the vent hasn't been processed. + /// internal static Color GetVentGroupColor(Vent vent) { if (ventToLowestId.TryGetValue(vent.Id, out int lowestId)) @@ -91,4 +116,4 @@ internal static class VentGroups return Color.black; } -} +} \ No newline at end of file diff --git a/src/Mono/AnimatedMapIcon.cs b/src/Mono/AnimatedMapIcon.cs new file mode 100644 index 0000000..65d3f36 --- /dev/null +++ b/src/Mono/AnimatedMapIcon.cs @@ -0,0 +1,56 @@ +using UnityEngine; + +namespace BetterAmongUs.Mono; + +/// +/// Animates a map icon by smoothly scaling it up and down when conditions are met. +/// +internal class AnimatedMapIcon : MonoBehaviour +{ + /// + /// Event that determines whether the icon should animate. + /// Returns true if animation should occur, false otherwise. + /// + internal event Func? ShouldAnimate; + + private Vector3 originalScale; + + /// + /// The multiplier applied to the original scale when fully animated. + /// + private readonly float scaleMultiplier = 1.2f; + + /// + /// The speed of the animation loop. + /// + private readonly float animationSpeed = 2f; + + /// + /// Initializes the component by storing the original scale of the icon. + /// + private void Awake() + { + originalScale = transform.localScale; + } + + /// + /// Updates the icon scale each frame based on the animation state. + /// When ShouldAnimate returns true, creates a smooth ping-pong scaling effect. + /// When ShouldAnimate returns false, resets to the original scale. + /// + private void Update() + { + if (ShouldAnimate?.Invoke() == true) + { + float pingPong = Mathf.PingPong(Time.time * animationSpeed, 1f); + float t = Mathf.SmoothStep(0f, 1f, pingPong); + Vector3 targetScale = originalScale * (1f + (scaleMultiplier - 1f) * t); + + transform.localScale = targetScale; + } + else + { + transform.localScale = originalScale; + } + } +} \ No newline at end of file diff --git a/src/Patches/Gameplay/UI/MiniMapBehaviourPatch.cs b/src/Patches/Gameplay/UI/MiniMapBehaviourPatch.cs index 72af9f3..412f7e4 100644 --- a/src/Patches/Gameplay/UI/MiniMapBehaviourPatch.cs +++ b/src/Patches/Gameplay/UI/MiniMapBehaviourPatch.cs @@ -1,6 +1,7 @@ using BetterAmongUs.Helpers; using BetterAmongUs.Modules; using BetterAmongUs.Modules.Support; +using BetterAmongUs.Mono; using HarmonyLib; using UnityEngine; @@ -46,6 +47,12 @@ internal static class MiniMapBehaviourPatch { if (BAUModdedSupportFlags.HasFlag(BAUModdedSupportFlags.Disable_MinimapIcons)) return; + 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); + } + if (_icons == null) { var icons = new GameObject("Icons") @@ -79,19 +86,40 @@ internal static class MiniMapBehaviourPatch icon.transform.localScale = Vector3.one * 0.25f; SetPosFromShip(zipline.transform.position, icon.transform, new Vector3(0f, 0.16f, UsableLayerOffset)); } + + foreach (var console in UnityEngine.Object.FindObjectsOfType()) + { + foreach (var taskType in console.TaskTypes) + { + 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)); + var animatedMapIcon = icon.gameObject.AddComponent(); + animatedMapIcon.ShouldAnimate += () => + { + return console.FindTask(PlayerControl.LocalPlayer) != null; + }; + break; + } + } + } } } private static void CreateVentIcon(Vent vent) { - var icon = CreateIcon(Utils.LoadSprite("BetterAmongUs.Resources.Images.Icons.Vent.png", 280), "VentIcon"); - icon.color = VentGroups.GetVentGroupColor(vent) * 0.8f; + var icon = CreateIcon(Utils.LoadSprite("BetterAmongUs.Resources.Images.Icons.Vent.png", 380), "VentIcon"); + var color = VentGroups.GetVentGroupColor(vent); + icon.color = new Color(color.r, color.g, color.b, 0.7f); SetPosFromShip(vent.transform.position, icon.transform, new Vector3(0f, 0f, VentLayerOffset)); Vent[] nearbyVents = [vent.Left, vent.Right, vent.Center]; - float maxSpreadShift = 1f; - float minSpreadShift = 0.3f; + float maxSpreadShift = 0.5f; + float minSpreadShift = 0.2f; float closeDistance = 10f; for (int i = 0; i < nearbyVents.Length; i++) @@ -99,7 +127,7 @@ internal static class MiniMapBehaviourPatch Vent neighborVent = nearbyVents[i]; if (neighborVent) { - var arrowIcon = CreateIcon(Utils.LoadSprite("BetterAmongUs.Resources.Images.Icons.Arrow.png", 500), "VentArrowIcon"); + var arrowIcon = CreateIcon(Utils.LoadSprite("BetterAmongUs.Resources.Images.Icons.Arrow.png", 600), "VentArrowIcon"); arrowIcon.color = VentGroups.GetVentGroupColor(neighborVent); arrowIcon.transform.SetParent(icon.transform); @@ -158,7 +186,7 @@ internal static class MiniMapBehaviourPatch if (systemConsole.MinigamePrefab.name == "EmergencyMinigame") { var icon = CreateIcon(Utils.LoadSprite("BetterAmongUs.Resources.Images.Icons.Meeting.png", 500), "MeetingIcon"); - icon.color = Color.white * 0.7f; + icon.color = new Color(1f, 1f, 1f, 0.7f); icon.transform.localScale = Vector3.one * 0.35f; SetPosFromShip(usable.Cast().transform.position, icon.transform, new Vector3(0f, 0f, UsableLayerOffset)); return; @@ -175,7 +203,7 @@ internal static class MiniMapBehaviourPatch if (HudManager.Instance.UseButton.fastUseSettings.TryGetValue(usable.UseIcon, out var settings)) { var icon = CreateIcon(settings.Image, "UsableIcon"); - icon.color = Color.white * 0.7f; + icon.color = new Color(1f, 1f, 1f, 0.7f); icon.transform.localScale = Vector3.one * 0.35f; SetPosFromShip(usable.Cast().transform.position, icon.transform, new Vector3(0f, 0f, UsableLayerOffset)); }