diff --git a/EXILED/Exiled.Events/EventArgs/Player/HitEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/HitEventArgs.cs
new file mode 100644
index 0000000000..d9d18adc0e
--- /dev/null
+++ b/EXILED/Exiled.Events/EventArgs/Player/HitEventArgs.cs
@@ -0,0 +1,48 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) ExMod Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.EventArgs.Player
+{
+ using System.Collections.Generic;
+ using System.Linq;
+
+ using API.Features;
+ using Interfaces;
+ using PlayerRoles.PlayableScps.Subroutines;
+
+ ///
+ /// Contains all information after player sends an attack as an SCP.
+ ///
+ public class HitEventArgs : IPlayerEvent
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// the result of the attack.
+ /// the list of players who are getting hit.
+ public HitEventArgs(Player player, AttackResult result, HashSet playerHits)
+ {
+ Player = player;
+ Result = result;
+ PlayersAffected = playerHits.Select(Player.Get).ToList().AsReadOnly();
+ }
+
+ ///
+ public Player Player { get; }
+
+ ///
+ /// Gets the attack result for the server.
+ ///
+ public AttackResult Result { get; }
+
+ ///
+ /// Gets the attack result for the server.
+ ///
+ public IReadOnlyCollection PlayersAffected { get; }
+ }
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs
index 60cbd55ff6..e272c42f3c 100644
--- a/EXILED/Exiled.Events/Handlers/Player.cs
+++ b/EXILED/Exiled.Events/Handlers/Player.cs
@@ -26,6 +26,11 @@ namespace Exiled.Events.Handlers
///
public class Player
{
+ ///
+ /// Invoked after a player triggers the attack as an SCP.
+ ///
+ public static Event Hit { get; set; } = new ();
+
///
/// Invoked before authenticating a .
///
@@ -1294,5 +1299,11 @@ public static void OnItemRemoved(ReferenceHub referenceHub, InventorySystem.Item
///
/// instance.
public static void OnPreAuthenticating(PreAuthenticatingEventArgs ev) => PreAuthenticating.InvokeSafely(ev);
+
+ ///
+ /// Called after a player triggers the melee attack as an SCP.
+ ///
+ /// The instance.
+ public static void OnHit(HitEventArgs ev) => Hit.InvokeSafely(ev);
}
}
diff --git a/EXILED/Exiled.Events/Patches/Events/Player/Hit.cs b/EXILED/Exiled.Events/Patches/Events/Player/Hit.cs
new file mode 100644
index 0000000000..2002397b50
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Events/Player/Hit.cs
@@ -0,0 +1,68 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) ExMod Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Events.Player
+{
+ using System.Collections.Generic;
+ using System.Reflection.Emit;
+
+ using API.Features;
+ using API.Features.Pools;
+ using Attributes;
+ using Exiled.Events.EventArgs.Player;
+ using HarmonyLib;
+ using PlayerRoles.PlayableScps.Scp049.Zombies;
+ using PlayerRoles.PlayableScps.Subroutines;
+ using PlayerRoles.Subroutines;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patches ScpAttackAbilityBase.ServerPerformAttack
+ /// to add event.
+ ///
+ [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.Hit))]
+ [HarmonyPatch(typeof(ScpAttackAbilityBase), nameof(ScpAttackAbilityBase.ServerPerformAttack))]
+ public class Hit
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ int index = newInstructions.FindLastIndex(x => x.opcode == OpCodes.Ret);
+
+ newInstructions.InsertRange(
+ index,
+ new[]
+ {
+ // Player.Get(base.Owner);
+ new CodeInstruction(OpCodes.Ldarg_0),
+ new(OpCodes.Call, PropertyGetter(typeof(StandardSubroutine), nameof(StandardSubroutine.Owner))),
+ new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // this.LastAttackResult
+ new CodeInstruction(OpCodes.Ldarg_0),
+ new(OpCodes.Call, PropertyGetter(typeof(ScpAttackAbilityBase), nameof(ScpAttackAbilityBase.LastAttackResult))),
+
+ // this.DetectedPlayers
+ new CodeInstruction(OpCodes.Ldarg_0),
+ new(OpCodes.Ldfld, Field(typeof(ScpAttackAbilityBase), nameof(ScpAttackAbilityBase.DetectedPlayers))),
+
+ // new(ReferenceHub, AttackResult, HashSet)
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(HitEventArgs))[0]),
+
+ // Handlers.Player.OnHit(ev)
+ new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnHit))),
+ });
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
\ No newline at end of file