diff --git a/EXILED/Exiled.Events/EventArgs/Scp173/BeingObservedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp173/BeingObservedEventArgs.cs
new file mode 100755
index 000000000..e32410f31
--- /dev/null
+++ b/EXILED/Exiled.Events/EventArgs/Scp173/BeingObservedEventArgs.cs
@@ -0,0 +1,57 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.EventArgs.Scp173
+{
+ using Exiled.API.Features;
+ using Exiled.API.Features.Roles;
+ using Exiled.Events.EventArgs.Interfaces;
+
+ ///
+ /// Contains all the information before SCP-173 is observed.
+ ///
+ public class BeingObservedEventArgs : IScp173Event, IDeniableEvent
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The instance of the target.
+ ///
+ ///
+ /// The instance of the SCP-173.
+ ///
+ ///
+ /// Whether or not the target will be counted as observing the SCP-173.
+ ///
+ public BeingObservedEventArgs(API.Features.Player target, API.Features.Player scp173, bool isAllowed = true)
+ {
+ Target = target;
+ Player = scp173;
+ Scp173 = scp173.Role.As();
+ IsAllowed = isAllowed;
+ }
+
+ ///
+ /// Gets the player who's observing the SCP-173.
+ ///
+ public Player Target { get; }
+
+ ///
+ /// Gets the player who's being observed.
+ ///
+ public Player Player { get; }
+
+ ///
+ public Scp173Role Scp173 { get; }
+
+ ///
+ /// Gets or sets a value indicating whether or not the player can be counted as observing.
+ ///
+ public bool IsAllowed { get; set; }
+ }
+}
diff --git a/EXILED/Exiled.Events/Handlers/Scp173.cs b/EXILED/Exiled.Events/Handlers/Scp173.cs
index bf844714b..93e11329b 100644
--- a/EXILED/Exiled.Events/Handlers/Scp173.cs
+++ b/EXILED/Exiled.Events/Handlers/Scp173.cs
@@ -37,6 +37,11 @@ public static class Scp173
///
public static Event UsingBreakneckSpeeds { get; set; } = new();
+ ///
+ /// Invoked before SCP-173 is observed.
+ ///
+ public static Event BeingObserved { get; set; } = new();
+
///
/// Called before players near SCP-173 blink.
///
@@ -60,5 +65,11 @@ public static class Scp173
///
/// The instance.
public static void OnUsingBreakneckSpeeds(UsingBreakneckSpeedsEventArgs ev) => UsingBreakneckSpeeds.InvokeSafely(ev);
+
+ ///
+ /// Called before Scp 173 is observed.
+ ///
+ /// The instance.
+ public static void OnBeingObserved(BeingObservedEventArgs ev) => BeingObserved.InvokeSafely(ev);
}
-}
\ No newline at end of file
+}
diff --git a/EXILED/Exiled.Events/Patches/Events/Scp173/BeingObserved.cs b/EXILED/Exiled.Events/Patches/Events/Scp173/BeingObserved.cs
new file mode 100755
index 000000000..d9648aabd
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Events/Scp173/BeingObserved.cs
@@ -0,0 +1,89 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) Exiled Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.Patches.Events.Scp173
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Reflection;
+ using System.Reflection.Emit;
+
+ using Exiled.API.Features.Pools;
+ using Exiled.Events.Attributes;
+ using Exiled.Events.EventArgs.Scp173;
+ using HarmonyLib;
+ using PlayerRoles.PlayableScps.Scp173;
+ using PlayerRoles.Subroutines;
+ using PluginAPI.Events;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patches .
+ /// Adds the event.
+ ///
+ [EventPatch(typeof(Handlers.Scp173), nameof(Handlers.Scp173.BeingObserved))]
+ [HarmonyPatch(typeof(Scp173ObserversTracker), nameof(Scp173ObserversTracker.IsObservedBy), typeof(ReferenceHub), typeof(float))]
+ internal static class BeingObserved
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ Label continueLabel = generator.DefineLabel();
+
+ const int offset = -4;
+ var scp173ExecuteEvent = typeof(EventManager)
+ .GetMethods(BindingFlags.Public | BindingFlags.Static)
+ .FirstOrDefault(m => m.Name == nameof(EventManager.ExecuteEvent)
+ && !m.IsGenericMethod);
+ int index = newInstructions.FindLastIndex(i => i.Calls(scp173ExecuteEvent)) + offset;
+
+ newInstructions.InsertRange(
+ index,
+ new CodeInstruction[]
+ {
+ // Player.Get(target)
+ new(OpCodes.Ldarg_1),
+ new(OpCodes.Call, Method(typeof(API.Features.Player), nameof(API.Features.Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // Player.Get(base.Owner)
+ new(OpCodes.Ldarg_0),
+ new(OpCodes.Call, PropertyGetter(typeof(StandardSubroutine), nameof(StandardSubroutine.Owner))),
+ new(OpCodes.Call, Method(typeof(API.Features.Player), nameof(API.Features.Player.Get), new[] { typeof(ReferenceHub) })),
+
+ // true
+ new(OpCodes.Ldc_I4_1),
+
+ // BeingObservedEventArgs ev = new(Player, Player, bool)
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(BeingObservedEventArgs))[0]),
+ new(OpCodes.Dup),
+
+ // Handlers.Scp173.OnBeingObserved(ev)
+ new(OpCodes.Call, Method(typeof(Handlers.Scp173), nameof(Handlers.Scp173.OnBeingObserved))),
+
+ // if (ev.IsAllowed)
+ // goto continueLabel
+ new(OpCodes.Callvirt, PropertyGetter(typeof(BeingObservedEventArgs), nameof(BeingObservedEventArgs.IsAllowed))),
+ new(OpCodes.Brtrue, continueLabel),
+
+ // return false
+ new(OpCodes.Ldc_I4_0),
+ new(OpCodes.Ret),
+
+ // continueLabel:
+ new CodeInstruction(OpCodes.Nop).WithLabels(continueLabel),
+ });
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}