diff --git a/MiraAPI.Example/MeetingAbilities/ShotgunButton.cs b/MiraAPI.Example/MeetingAbilities/ShotgunButton.cs new file mode 100644 index 0000000..bc9f20c --- /dev/null +++ b/MiraAPI.Example/MeetingAbilities/ShotgunButton.cs @@ -0,0 +1,51 @@ +using System; +using MiraAPI.MeetingAbilities; +using MiraAPI.Networking; +using MiraAPI.Utilities; +using MiraAPI.Utilities.Assets; +using UnityEngine; + +namespace MiraAPI.Example.MeetingAbilities; + +public class ShotgunButton : MultiTargetMeetingButton +{ + public override string Name => "Shotgun"; + + public override int MaxUses => 3; + + public override float InitialCooldown => 5; + + public override float Cooldown => 3; + + public override LoadableAsset Sprite => ExampleAssets.SharpshootButton; + + public override Color OutlineColor => Color.red; + + public override bool Enabled(RoleBehaviour r) + { + return r.IsImpostor; + } + + protected override void OnClick(PlayerVoteArea playerVoteArea) + { + } + + public override LoadableAsset SpriteActive => ExampleAssets.CallMeetingButton; + + public override int TargetsCount => 4; + + protected override void OnSelect(PlayerVoteArea playerVoteArea, bool toggle) + { + HudManager.Instance.PlayerCam.ShakeScreen(0.5f, 2); + } + + public override void OnFinish() + { + foreach (var playerVoteArea in Targets.Keys) + { + playerVoteArea.SetDisabled(); + var player = playerVoteArea.GetPlayer(); + PlayerControl.LocalPlayer.RpcCustomMurder(player); + } + } +} \ No newline at end of file diff --git a/MiraAPI/MeetingAbilities/MultiTargetMeetingButton.cs b/MiraAPI/MeetingAbilities/MultiTargetMeetingButton.cs new file mode 100644 index 0000000..34ee068 --- /dev/null +++ b/MiraAPI/MeetingAbilities/MultiTargetMeetingButton.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using MiraAPI.Utilities.Assets; +using UnityEngine; +using UnityEngine.UI; + +namespace MiraAPI.MeetingAbilities; + +/// +/// Abstract class for creating multi target meeting abilities +/// +public abstract class MultiTargetMeetingButton : TargetedMeetingButton +{ + /// + /// The used for when the button is on. + /// + public abstract LoadableAsset SpriteActive { get; } + + /// + /// Gets the required targets count. + /// + public abstract int TargetsCount { get; } + + /// + /// Gets or sets all selected targets. + /// + public Dictionary Targets { get; set; } = new(); + + /// + public override void ClickHandler(MeetingAbilityBehaviour button, PlayerVoteArea playerVoteArea) + { + if (UsesRemaining <= 0 && LimitedUses) return; + if (Timer > 0) return; + var toggle = !Targets.Remove(playerVoteArea); + if (toggle) Targets.Add(playerVoteArea, button); + button.Renderer.sprite = toggle ? SpriteActive.LoadAsset() : Sprite.LoadAsset(); + if (Targets.Count >= TargetsCount) + { + playerVoteArea.Cancel(); + HandleFinish(); + return; + } + OnSelect(playerVoteArea, toggle); + } + + /// + /// Handles the finish logic, increasing timer, and decreasing uses. + /// + public virtual void HandleFinish() + { + Targets = Targets.Take(TargetsCount).ToDictionary(pair => pair.Key, pair => pair.Value); + foreach (var button in Targets.Values) + { + button.Renderer.sprite = Sprite.LoadAsset(); + } + Timer = Cooldown; + UsesRemaining -= 1; + OnFinish(); + Targets = new(); + } + + /// + /// Callback method for when a player is selected. + /// + /// The target . + /// Whether the button was toggled on/off. + protected abstract void OnSelect(PlayerVoteArea playerVoteArea, bool toggle); + + /// + /// Callback method for the button click. + /// USE INSTEAD!!!. + /// + /// The target . + protected override void OnClick(PlayerVoteArea playerVoteArea) + { + } + + /// + /// Callback method for when enough targets are chosen. + /// + public abstract void OnFinish(); + + /// + public override MeetingAbilityBehaviour CreateButton(PlayerVoteArea playerVoteArea) + { + Targets = new(); + var button = base.CreateButton(playerVoteArea); + button.Button.OnClick = new Button.ButtonClickedEvent(); + button.Button.OnClick.AddListener(new System.Action(() => { ClickHandler(button, playerVoteArea); })); + return button; + } +} diff --git a/MiraAPI/MeetingAbilities/TargetedMeetingButton.cs b/MiraAPI/MeetingAbilities/TargetedMeetingButton.cs index 606eeff..4b60f3e 100644 --- a/MiraAPI/MeetingAbilities/TargetedMeetingButton.cs +++ b/MiraAPI/MeetingAbilities/TargetedMeetingButton.cs @@ -6,7 +6,7 @@ using UnityEngine.UI; namespace MiraAPI.MeetingAbilities; /// -/// Abstract class for creating custom meeting abilities. +/// Abstract class for creating targeted meeting abilities. /// public abstract class TargetedMeetingButton { @@ -101,9 +101,9 @@ public abstract class TargetedMeetingButton btn.transform.GetChild(0).GetComponent().color = OutlineColor; btn.OnClick = new Button.ButtonClickedEvent(); - btn.OnClick.AddListener(new System.Action(() => ClickHandler(playerVoteArea))); var abilityBehaviour = btn.gameObject.AddComponent(); abilityBehaviour.Initialize(this, playerVoteArea); + btn.OnClick.AddListener(new System.Action(() => ClickHandler(abilityBehaviour, playerVoteArea))); Timer = InitialCooldown; return abilityBehaviour; @@ -131,8 +131,9 @@ public abstract class TargetedMeetingButton /// Called when the button is clicked /// Handles increasing cooldown and decreasing uses remaining. /// + /// The instance. /// The target . - public virtual void ClickHandler(PlayerVoteArea playerVoteArea) + public virtual void ClickHandler(MeetingAbilityBehaviour button, PlayerVoteArea playerVoteArea) { if (UsesRemaining <= 0 && LimitedUses) return; if (Timer > 0) return; diff --git a/MiraAPI/Patches/Voting/MeetingHudPatches.cs b/MiraAPI/Patches/Voting/MeetingHudPatches.cs index 062e162..fc7f533 100644 --- a/MiraAPI/Patches/Voting/MeetingHudPatches.cs +++ b/MiraAPI/Patches/Voting/MeetingHudPatches.cs @@ -106,9 +106,10 @@ internal static class MeetingHudPatches } } - foreach (var ability in TargetedMeetingButtonManager.Buttons.Where(x => x.ButtonUsesMode == MeetingButtonUsesMode.PerMeeting)) + foreach (var ability in TargetedMeetingButtonManager.Buttons) { - ability.UsesRemaining = ability.MaxUses; + if (ability.ButtonUsesMode == MeetingButtonUsesMode.PerMeeting) ability.UsesRemaining = ability.MaxUses; + if (ability is MultiTargetMeetingButton multiAbility) multiAbility.Targets = new(); } var @event = new StartMeetingEvent(__instance); MiraEventManager.InvokeEvent(@event);