Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
bin/
obj/
References/
NewMod/Components
NewMod/Components/Minigames
NewMod/Components/Hidden.cs
/packages/
riderModule.iml
.idea
Expand Down
8 changes: 7 additions & 1 deletion NewMod/Buttons/EnergyThief/DrainButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using ET = NewMod.Roles.NeutralRoles.EnergyThief;
using UnityEngine;
using NewMod.Utilities;
using Rewired;

namespace NewMod.Buttons.EnergyThief
{
Expand Down Expand Up @@ -33,6 +34,11 @@ public class DrainButton : CustomActionButton<PlayerControl>
/// The on-screen position of this button.
/// </summary>
public override ButtonLocation Location => ButtonLocation.BottomRight;

/// <summary>
/// Default keybind for EnergyThief's Drain ability.
/// </summary>
public override KeyboardKeyCode Defaultkeybind => KeyboardKeyCode.F;

/// <summary>
/// The duration of the effect applied by this button; in this case, zero.
Expand All @@ -50,7 +56,7 @@ public class DrainButton : CustomActionButton<PlayerControl>
/// <returns>The closest valid PlayerControl, or null if none.</returns>
public override PlayerControl GetTarget()
{
return PlayerControl.LocalPlayer.GetClosestPlayer(true, Distance, false, p => !p.Data.IsDead && !p.Data.Disconnected);
return PlayerControl.LocalPlayer.GetClosestPlayer(true, Distance, false, false, p => !p.Data.IsDead && !p.Data.Disconnected);
}

/// <summary>
Expand Down
18 changes: 12 additions & 6 deletions NewMod/Buttons/Injector/InjectButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using MiraAPI.Utilities;
using System;
using static NewMod.Utilities.Utils;
using Rewired;

namespace NewMod.Buttons.Injector
{
Expand All @@ -29,7 +30,7 @@ public class InjectButton : CustomActionButton<PlayerControl>
/// <summary>
/// Maximum allowed injections, configured via <see cref="InjectorOptions"/>.
/// </summary>
public override int MaxUses => OptionGroupSingleton<InjectorOptions>.Instance.MaxSerumUses;
public override int MaxUses => (int)OptionGroupSingleton<InjectorOptions>.Instance.MaxSerumUses;

/// <summary>
/// Effect duration — unused here since injection is instant.
Expand All @@ -41,10 +42,15 @@ public class InjectButton : CustomActionButton<PlayerControl>
/// </summary>
public override ButtonLocation Location => ButtonLocation.BottomLeft;

/// <summary>
/// Default keybind for Injector's Inject ability.
/// </summary>
public override KeyboardKeyCode Defaultkeybind => KeyboardKeyCode.C;

/// <summary>
/// Sprite/icon displayed on the button.
/// </summary>
public override LoadableAsset<Sprite> Sprite => MiraAssets.Empty;
public override LoadableAsset<Sprite> Sprite => NewModAsset.InjectButton;

/// <summary>
/// Returns the closest valid player target within range,
Expand Down Expand Up @@ -81,10 +87,10 @@ public override bool Enabled(RoleBehaviour role)
/// </summary>
protected override void OnClick()
{
var serumValues = Enum.GetValues(typeof(SerumType));
SerumType randomSerum = (SerumType)serumValues.GetValue(UnityEngine.Random.Range(0, serumValues.Length));
RpcApplySerum(PlayerControl.LocalPlayer, Target, randomSerum);
var values = (SerumType[])Enum.GetValues(typeof(SerumType));
var serum = values[UnityEngine.Random.Range(0, values.Length)];

RpcApplySerum(PlayerControl.LocalPlayer, Target, serum);
}
}
}
6 changes: 6 additions & 0 deletions NewMod/Buttons/Necromancer/ReviveButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using NewMod.Roles.ImpostorRoles;
using UnityEngine;
using NewMod.Utilities;
using Rewired;

namespace NewMod.Buttons.Necromancer
{
Expand Down Expand Up @@ -33,6 +34,11 @@ public class ReviveButton : CustomActionButton
/// </summary>
public override float EffectDuration => 0f;

/// <summary>
/// Default keybind for Necromancer's Revive ability.
/// </summary>
public override KeyboardKeyCode Defaultkeybind => KeyboardKeyCode.V;

/// <summary>
/// Defines where on the screen this button should appear.
/// </summary>
Expand Down
13 changes: 13 additions & 0 deletions NewMod/Buttons/Overload/OverloadButton.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using MiraAPI.Hud;
using MiraAPI.Utilities.Assets;
using NewMod.Roles.NeutralRoles;
using Rewired;
using UnityEngine;

namespace NewMod.Buttons.Overload
Expand Down Expand Up @@ -41,6 +42,12 @@ public class OverloadButton : CustomActionButton
/// </summary>
public float absorbedCooldown;

/// <summary>
/// Stores the default key assigned to the absorbed button's action.
/// Mirrors the keybind of the original absorbed button.
/// </summary>
public KeyboardKeyCode absorbedKeybind;

/// <summary>
/// The name displayed on the button.
/// </summary>
Expand All @@ -56,6 +63,11 @@ public class OverloadButton : CustomActionButton
/// </summary>
public override int MaxUses => absorbedMaxUses;

/// <summary>
/// Default keybind for Overload's Overload ability.
/// </summary>
public override KeyboardKeyCode Defaultkeybind => absorbedKeybind;

/// <summary>
/// Determines how long the effect from clicking the button lasts. In this case, no duration is set.
/// </summary>
Expand All @@ -81,6 +93,7 @@ public void Absorb(CustomActionButton target)
absorbedCooldown = target.Cooldown;
absorbedMaxUses = target.MaxUses;
absorbedSprite = target.Sprite;
absorbedKeybind = target.Defaultkeybind;
absorbedOnClick = () => target.GetType().GetMethod("OnClick", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
?.Invoke(target, null);

Expand Down
6 changes: 6 additions & 0 deletions NewMod/Buttons/Prankster/FakeBodyButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using PRK = NewMod.Roles.NeutralRoles.Prankster;
using UnityEngine;
using NewMod.Utilities;
using Rewired;

namespace NewMod.Buttons.Prankster
{
Expand Down Expand Up @@ -34,6 +35,11 @@ public class FakeBodyButton : CustomActionButton
/// </summary>
public override ButtonLocation Location => ButtonLocation.BottomRight;

/// <summary>
/// Default keybind for Prankster's Fake Body ability.
/// </summary>
public override KeyboardKeyCode Defaultkeybind => KeyboardKeyCode.Z;

/// <summary>
/// The duration of any effect caused by this button press; in this case, no effect duration is used.
/// </summary>
Expand Down
154 changes: 154 additions & 0 deletions NewMod/Buttons/PulseBlade/StrikeButton.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
using System.Collections;
using System.Linq;
using MiraAPI.GameOptions;
using MiraAPI.Hud;
using MiraAPI.Utilities.Assets;
using UnityEngine;
using Pb = NewMod.Roles.ImpostorRoles.PulseBlade;
using MiraAPI.Networking;
using NewMod.Options.Roles.PulseBladeOptions;
using Reactor.Utilities;
using MiraAPI.Utilities;
using NewMod.Utilities;
using Reactor.Networking.Attributes;
using Rewired;

namespace NewMod.Buttons.Pulseblade
{
/// <summary>
/// Custom button for the Pulseblade role to perform a high-speed strike on the closest player in aim direction.
/// The strike teleports the user toward the target and executes a stealthy instant kill.
/// </summary>
public class StrikeButton : CustomActionButton
{
/// <summary>
/// Display name for the button (not shown by default).
/// </summary>
public override string Name => "Strike";

/// <summary>
/// Cooldown between strikes, pulled from <see cref="PulseBladeOptions.StrikeCooldown"/>.
/// </summary>
public override float Cooldown => OptionGroupSingleton<PulseBladeOptions>.Instance.StrikeCooldown;

/// <summary>
/// Maximum number of strike uses, from <see cref="PulseBladeOptions.MaxStrikeUses"/>.
/// </summary>
public override int MaxUses => (int)OptionGroupSingleton<PulseBladeOptions>.Instance.MaxStrikeUses;

/// <summary>
/// Effect duration (not used for this button).
/// </summary>
public override float EffectDuration => 0f;

/// <summary>
/// Placement of the button on the HUD.
/// </summary>
public override ButtonLocation Location => ButtonLocation.BottomRight;

/// <summary>
/// Default keybind for Pulseblade's Strike ability.
/// Requires Shift as a modifier to prevent accidental use.
/// </summary>
public override KeyboardKeyCode Defaultkeybind => KeyboardKeyCode.G;
public override ModifierKey Modifier1 => ModifierKey.Shift;
/// <summary>
/// Sprite used for the button — set to empty;
/// </summary>
public override LoadableAsset<Sprite> Sprite => NewModAsset.StrikeButton;

/// <summary>
/// Determines whether the button is active for a given role.
/// </summary>
/// <param name="role">The current player's role.</param>
/// <returns>True only for Pulseblade role.</returns>
public override bool Enabled(RoleBehaviour role) => role is Pb;

/// <summary>
/// Called when the button is pressed by the player.
/// Searches for a valid target and executes the strike.
/// </summary>
protected override void OnClick()
{
var player = PlayerControl.LocalPlayer;

var target = PlayerControl.AllPlayerControls
.ToArray()
.Where(p => p != player && !p.Data.IsDead && !p.Data.Disconnected && !p.inVent)
.OrderBy(p => Vector2.Distance(player.GetTruePosition(), p.GetTruePosition()))
.FirstOrDefault(p => Vector2.Distance(player.GetTruePosition(), p.GetTruePosition()) <= OptionGroupSingleton<PulseBladeOptions>.Instance.StrikeRange);

RpcPulseStrike(player, target);
}

/// <summary>
/// RPC method to perform a Pulseblade strike on a target.
/// </summary>
/// <param name="source">The player performing the strike.</param>
/// <param name="target">The victim of the strike.</param>
[MethodRpc((uint)CustomRPC.Dash)]
public static void RpcPulseStrike(PlayerControl source, PlayerControl target)
{
Coroutines.Start(DoPulseStrike(source, target));
}

/// <summary>
/// Executes the strike: dashes to the target and performs a kill.
/// Hides the body for a short time.
/// </summary>
/// <param name="killer">The Pulseblade player.</param>
/// <param name="target">The struck victim.</param>
/// <returns>IEnumerator.</returns>
public static IEnumerator DoPulseStrike(PlayerControl killer, PlayerControl target)
{
var sound = NewModAsset.StrikeSound.LoadAsset();
float originalSpeed = killer.MyPhysics.Speed;
float dashSpeed = OptionGroupSingleton<PulseBladeOptions>.Instance.DashSpeed;

killer.moveable = false;
killer.MyPhysics.inputHandler.enabled = false;
killer.MyPhysics.Speed = dashSpeed;

while (Vector2.Distance(killer.GetTruePosition(), target.GetTruePosition()) > 0.1f)
{
Vector2 dir = target.GetTruePosition() - killer.GetTruePosition();
killer.MyPhysics.SetNormalizedVelocity(dir.normalized);

float step = killer.MyPhysics.TrueSpeed * Time.fixedDeltaTime;
if (step >= dir.magnitude) break;

yield return new WaitForFixedUpdate();
}

killer.MyPhysics.SetNormalizedVelocity(Vector2.zero);
killer.MyPhysics.Speed = originalSpeed;
killer.MyPhysics.inputHandler.enabled = true;
killer.moveable = true;

SoundManager.Instance.PlaySound(sound, false, 1f);

killer.RpcCustomMurder(
target,
didSucceed: true,
resetKillTimer: false,
createDeadBody: true,
teleportMurderer: false,
showKillAnim: false,
playKillSound: false
);

Utils.RegisterStrikeKill(killer, target);

var notif = Helpers.CreateAndShowNotification($"Perfect kill {target.Data.PlayerName} eliminated", new(1f, 0.25f, 0.25f), spr: NewModAsset.StrikeIcon.LoadAsset());
notif.Text.SetOutlineThickness(0.30f);

var bodies = Helpers.GetNearestDeadBodies(target.GetTruePosition(), 0.5f, Helpers.CreateFilter(Constants.NotShipMask));
if (bodies != null && bodies.Count > 0)
{
foreach (var b in bodies) if (b) b.gameObject.SetActive(false);
yield return new WaitForSeconds(OptionGroupSingleton<PulseBladeOptions>.Instance.HideBodyDuration);
foreach (var b in bodies) if (b) b.gameObject.SetActive(true);
}
}
}
}
12 changes: 11 additions & 1 deletion NewMod/Buttons/Revenant/DoomAwakening.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using NewMod.Utilities;
using Reactor.Utilities;
using UnityEngine;
using TMPro;
using Rewired;

namespace NewMod.Buttons.Revenant
{
Expand Down Expand Up @@ -37,6 +39,12 @@ public class DoomAwakening : CustomActionButton
/// </summary>
public override ButtonLocation Location => ButtonLocation.BottomLeft;

/// <summary>
/// Default keybind for Doom's Awakening ability.
/// Requires Alt as a modifier to prevent accidental use.
/// </summary>
public override KeyboardKeyCode Defaultkeybind => KeyboardKeyCode.B;
public override ModifierKey Modifier1 => ModifierKey.Alt;
/// <summary>
/// Determines how long the effect lasts. Configured in <see cref="RevenantOptions"/>.
/// </summary>
Expand Down Expand Up @@ -191,7 +199,9 @@ public System.Collections.IEnumerator StartDoomAwakening(PlayerControl player)
SoundManager.Instance.StopSound(clip);
RV.StalkingStates.Remove(player.PlayerId);
Coroutines.Start(CoroutinesHelper.CoNotify("<color=green>Doom Awakening ended.</color>"));
Helpers.CreateAndShowNotification($"Doom Awakening killed {killCount} players", Color.red, null, null);

var doomNotif = Helpers.CreateAndShowNotification($"<font=\"LiberationSans SDF\" material=\"LiberationSans SDF - Masked>Doom Awakening killed {killCount} players", Color.red, null, null);
doomNotif.Text.SetOutlineThickness(0.36f);
killedPlayers.Clear();
}
}
Expand Down
8 changes: 8 additions & 0 deletions NewMod/Buttons/Revenant/FeignDeathButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using NewMod.Utilities;
using Reactor.Utilities;
using UnityEngine;
using Rewired;

namespace NewMod.Buttons.Revenant
{
Expand Down Expand Up @@ -34,6 +35,13 @@ public class FeignDeathButton : CustomActionButton
/// </summary>
public override ButtonLocation Location => ButtonLocation.BottomRight;

/// <summary>
/// Default keybind for Revenant's Feign Death ability.
/// Requires Ctrl as a modifier to prevent accidental use.
/// </summary>
public override KeyboardKeyCode Defaultkeybind => KeyboardKeyCode.T;
public override ModifierKey Modifier1 => ModifierKey.Control;

/// <summary>
/// The duration of any effect from this button. In this case, zero.
/// </summary>
Expand Down
Loading
Loading