diff --git a/EXILED/Exiled.Events/EventArgs/Player/ConsumableActivatingEffectsEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/ConsumableActivatingEffectsEventArgs.cs
new file mode 100644
index 000000000..7210db91c
--- /dev/null
+++ b/EXILED/Exiled.Events/EventArgs/Player/ConsumableActivatingEffectsEventArgs.cs
@@ -0,0 +1,46 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) ExMod Team. All rights reserved.
+// Licensed under the CC BY-SA 3.0 license.
+//
+// -----------------------------------------------------------------------
+
+namespace Exiled.Events.EventArgs.Player
+{
+ using Exiled.API.Features.Items;
+ using Exiled.Events.EventArgs.Interfaces;
+
+ using BaseConsumable = InventorySystem.Items.Usables.Consumable;
+
+ ///
+ /// Interesting.
+ ///
+ public class ConsumableActivatingEffectsEventArgs : IPlayerEvent, IDeniableEvent
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ ///
+ ///
+ public ConsumableActivatingEffectsEventArgs(ReferenceHub referenceHub, BaseConsumable consumable, bool isAllowed = true)
+ {
+ Player = API.Features.Player.Get(referenceHub);
+ IsAllowed = isAllowed;
+ Consumable = (Consumable)Item.Get(consumable);
+ }
+
+ ///
+ /// Gets the player that consumed the .
+ ///
+ public API.Features.Player Player { get; }
+
+ ///
+ public bool IsAllowed { get; set; }
+
+ ///
+ /// Gets the that was consumed.
+ ///
+ public Consumable Consumable { get; }
+ }
+}
\ No newline at end of file
diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs
index c03bcebeb..10cb36799 100644
--- a/EXILED/Exiled.Events/Handlers/Player.cs
+++ b/EXILED/Exiled.Events/Handlers/Player.cs
@@ -651,6 +651,11 @@ public class Player
///
public static Event Scp1576TransmissionEnded { get; set; } = new();
+ ///
+ /// Invoked before 's consumable activates effects.
+ ///
+ public static Event ConsumableActivatingEffects { get; set; } = new();
+
///
/// Called before a player's emotion changed.
///
@@ -1434,5 +1439,11 @@ public static void OnItemRemoved(ReferenceHub referenceHub, InventorySystem.Item
///
/// The instance.
public static void OnScp1576TransmissionEnded(Scp1576TransmissionEndedEventArgs ev) => Scp1576TransmissionEnded.InvokeSafely(ev);
+
+ ///
+ /// Called before 's consumable activates its effects.
+ ///
+ /// The instance.
+ public static void OnConsumableActivatingEffects(ConsumableActivatingEffectsEventArgs ev) => ConsumableActivatingEffects.InvokeSafely(ev);
}
}
diff --git a/EXILED/Exiled.Events/Patches/Events/Player/ConsumableActivatingEffects.cs b/EXILED/Exiled.Events/Patches/Events/Player/ConsumableActivatingEffects.cs
new file mode 100644
index 000000000..c4e944b8d
--- /dev/null
+++ b/EXILED/Exiled.Events/Patches/Events/Player/ConsumableActivatingEffects.cs
@@ -0,0 +1,76 @@
+// -----------------------------------------------------------------------
+//
+// 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 Exiled.API.Features.Pools;
+ using Exiled.Events.Attributes;
+ using Exiled.Events.EventArgs.Player;
+ using HarmonyLib;
+ using InventorySystem.Items.Usables;
+
+ using static HarmonyLib.AccessTools;
+
+ ///
+ /// Patches and adds event.
+ ///
+ [HarmonyPatch(typeof(Consumable), nameof(Consumable.ActivateEffects))]
+ [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.ConsumableActivatingEffects))]
+ internal static class ConsumableActivatingEffects
+ {
+ private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
+ {
+ List newInstructions = ListPool.Pool.Get(instructions);
+
+ Label continueLabel = generator.DefineLabel();
+
+ int secondOffset = 1;
+ int secondIndex = newInstructions.FindIndex(i => i.opcode == OpCodes.Ldarg_0) + secondOffset;
+
+ int firstOffset = -1;
+ int firstIndex = newInstructions.FindIndex(i => i.opcode == OpCodes.Callvirt) + firstOffset;
+ newInstructions[firstIndex].WithLabels(continueLabel);
+ newInstructions.InsertRange(firstIndex, new List()
+ {
+ new(OpCodes.Ldarg_0),
+ });
+
+ newInstructions.InsertRange(secondIndex, new List()
+ {
+ // this.Owner
+ new(OpCodes.Callvirt, PropertyGetter(typeof(Consumable), nameof(Consumable.Owner))),
+
+ // this
+ new(OpCodes.Ldarg_0),
+
+ // true
+ new(OpCodes.Ldc_I4_1),
+
+ // ConsumableActivatingEffectsEventArgs ev = new(this.Owner, this, true)
+ new(OpCodes.Newobj, GetDeclaredConstructors(typeof(ConsumableActivatingEffectsEventArgs))[0]),
+ new(OpCodes.Dup),
+
+ // OnConsumableActivatingEffects(ev)
+ new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnConsumableActivatingEffects))),
+
+ // if (!ev.IsAllowed)
+ // return;
+ new(OpCodes.Callvirt, PropertyGetter(typeof(ConsumableActivatingEffectsEventArgs), nameof(ConsumableActivatingEffectsEventArgs.IsAllowed))),
+ new(OpCodes.Brtrue_S, continueLabel),
+ new(OpCodes.Ret),
+ });
+
+ for (int z = 0; z < newInstructions.Count; z++)
+ yield return newInstructions[z];
+
+ ListPool.Pool.Return(newInstructions);
+ }
+ }
+}
\ No newline at end of file