diff --git a/EXILED/Exiled.Events/EventArgs/Player/SavingByAntiScp207EventArgs.cs b/EXILED/Exiled.Events/EventArgs/Player/SavingByAntiScp207EventArgs.cs new file mode 100644 index 0000000000..71cd25905b --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Player/SavingByAntiScp207EventArgs.cs @@ -0,0 +1,74 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Player +{ + using CustomPlayerEffects; + using Exiled.API.Features; + using Exiled.API.Features.DamageHandlers; + using Exiled.Events.EventArgs.Interfaces; + + /// + /// Contains all information before a player is saved from death by the Anti-SCP-207 effect. + /// + public class SavingByAntiScp207EventArgs : IPlayerEvent, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// The player who is being saved. + /// The amount of damage that would have been applied. + /// The damage handler that describes the damage. + /// The hitbox that was hit. + public SavingByAntiScp207EventArgs(ReferenceHub player, float damageAmount, DamageHandlerBase handler, HitboxType hitboxType) + { + Player = Player.Get(player); + + Handler = handler; + HitboxType = hitboxType; + DamageAmount = damageAmount; + DamageMultiplier = (Player.Health + Player.ArtificialHealth - AntiScp207.DeathSaveHealth) / damageAmount; + IsAllowed = true; + } + + /// + /// Gets the player who is being saved. + /// + public Player Player { get; } + + /// + /// Gets the amount of damage that would have been applied. + /// + public float DamageAmount { get; } + + /// + /// Gets or sets the multiplier for the damage that is applied when the event is allowed. + /// + public float DamageMultiplier { get; set; } + + /// + /// Gets or sets the multiplier for the damage that if event denied. + /// + public float DeniedDamageMultiplier { get; set; } = 1; + + /// + /// Gets the damage handler that describes the incoming damage. + /// + public DamageHandlerBase Handler { get; } + + /// + /// Gets the hitbox that was hit. + /// + public HitboxType HitboxType { get; } + + /// + /// Gets or sets a value indicating whether the event is allowed. + /// If set to false, the event will be denied. + /// + public bool IsAllowed { get; set; } + } +} diff --git a/EXILED/Exiled.Events/Handlers/Player.cs b/EXILED/Exiled.Events/Handlers/Player.cs index 7037747e7e..590e4924d1 100644 --- a/EXILED/Exiled.Events/Handlers/Player.cs +++ b/EXILED/Exiled.Events/Handlers/Player.cs @@ -113,6 +113,11 @@ public class Player /// public static Event Interacted { get; set; } = new(); + /// + /// Invoked before a is saved from death by the Anti-SCP-207 effect. + /// + public static Event SavingByAntiScp207 { get; set; } = new(); + /// /// Invoked before spawning a . /// @@ -1239,6 +1244,12 @@ public static void OnItemRemoved(ReferenceHub referenceHub, InventorySystem.Item /// The instance. public static void OnHealed(HealedEventArgs ev) => Healed.InvokeSafely(ev); + /// + /// Called before a is saved from death by the Anti-SCP-207 effect. + /// + /// The instance. + public static void OnSavingByAntiScp207(SavingByAntiScp207EventArgs ev) => SavingByAntiScp207.InvokeSafely(ev); + /// /// Called before a dies. /// diff --git a/EXILED/Exiled.Events/Patches/Events/Player/SavingByAntiScp207.cs b/EXILED/Exiled.Events/Patches/Events/Player/SavingByAntiScp207.cs new file mode 100644 index 0000000000..e3275e0a95 --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Player/SavingByAntiScp207.cs @@ -0,0 +1,96 @@ +// ----------------------------------------------------------------------- +// +// 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 CustomPlayerEffects; + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Player; + + using HarmonyLib; + + using static HarmonyLib.AccessTools; + + /// + /// Patches . + /// Adds the event before the player is saved from Anti-SCP-207 damage. + /// + [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.SavingByAntiScp207))] + [HarmonyPatch(typeof(AntiScp207), nameof(AntiScp207.GetDamageModifier))] + internal class SavingByAntiScp207 + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + LocalBuilder ev = generator.DeclareLocal(typeof(SavingByAntiScp207EventArgs)); + + int offset = -1; + int index = newInstructions.FindLastIndex(i => i.Calls(Method(typeof(StatusEffectBase), nameof(StatusEffectBase.DisableEffect)))) + offset; + + Label skipLabel = generator.DefineLabel(); + Label gotoEventLabel = newInstructions[index].labels[0]; + + newInstructions[index].labels = new List