diff --git a/EXILED/Exiled.API/Enums/EffectType.cs b/EXILED/Exiled.API/Enums/EffectType.cs index 4e7c6056d6..44c5b02301 100644 --- a/EXILED/Exiled.API/Enums/EffectType.cs +++ b/EXILED/Exiled.API/Enums/EffectType.cs @@ -216,7 +216,7 @@ public enum EffectType /// /// Makes you a marshmallow guy. /// - [Obsolete("Not functional in-game")] + // [Obsolete("Not functional in-game")] Marshmallow, /// diff --git a/EXILED/Exiled.API/Features/Items/Item.cs b/EXILED/Exiled.API/Features/Items/Item.cs index 04d4b72535..89bb189c42 100644 --- a/EXILED/Exiled.API/Features/Items/Item.cs +++ b/EXILED/Exiled.API/Features/Items/Item.cs @@ -22,6 +22,7 @@ namespace Exiled.API.Features.Items using InventorySystem.Items.Firearms.Ammo; using InventorySystem.Items.Jailbird; using InventorySystem.Items.Keycards; + using InventorySystem.Items.MarshmallowMan; using InventorySystem.Items.MicroHID; using InventorySystem.Items.Pickups; using InventorySystem.Items.Radio; @@ -260,6 +261,7 @@ public static Item Get(ItemBase itemBase) _ => new Throwable(throwable), }, Scp1509Item scp1509 => new Scp1509(scp1509), + MarshmallowItem marshmallow => new Marshmallow(marshmallow), _ => new(itemBase), }; } @@ -364,6 +366,7 @@ public static T Get(ushort serial) _ => new Throwable(type, owner), }, Scp1509Item => new Scp1509(), + MarshmallowItem => new Marshmallow(type, owner), _ => new(type), }; diff --git a/EXILED/Exiled.API/Features/Items/Marshmallow.cs b/EXILED/Exiled.API/Features/Items/Marshmallow.cs new file mode 100644 index 0000000000..05b8579cfe --- /dev/null +++ b/EXILED/Exiled.API/Features/Items/Marshmallow.cs @@ -0,0 +1,102 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.API.Features.Items +{ + using CustomPlayerEffects; + using Exiled.API.Interfaces; + using InventorySystem.Items.MarshmallowMan; + using PlayerStatsSystem; + using UnityEngine; + + /// + /// A wrapper class for . + /// + public class Marshmallow : Item, IWrapper + { + /// + /// Initializes a new instance of the class. + /// + /// The base class. + public Marshmallow(MarshmallowItem itemBase) + : base(itemBase) + { + Base = itemBase; + } + + /// + /// Initializes a new instance of the class. + /// + /// The of the marshmallow item. + /// The owner of the marshmallow item. Leave for no owner. + internal Marshmallow(ItemType type, Player owner = null) + : base((MarshmallowItem)(owner ?? Server.Host).Inventory.CreateItemInstance(new(type, 0), false)) + { + } + + /// + /// Gets the that this class is encapsulating. + /// + public new MarshmallowItem Base { get; } + + /// + /// Gets a value indicating whether this marshmallow man is evil. + /// + /// See in regards to making a marshmallow evil. + public bool Evil => Base.EvilMode; + + /// + /// Gets or sets the of the marshmallow man that would be used if he was evil. + /// + public AhpStat.AhpProcess EvilAhpProcess + { + get => Base.EvilAHPProcess; + set + { + if (Evil && value is null) + return; + + Base.EvilAHPProcess = value; + } + } + + /// + /// Cackles for the owner even if they are not evil. + /// + /// How long until the player can cackle again (negative values do not affect current cooldown). + /// How long players near the marshmallow man get effected by . + public void Cackle(double cooldown = -1, float duration = 5) + { + if (cooldown >= 0) + Base._cackleCooldown.Trigger(cooldown); + + Base.ServerSendPublicRpc(writer => + { + writer.WriteByte(4); + Base._cackleCooldown.WriteCooldown(writer); + }); + + foreach (Player player in Player.List) + { + if (Vector3.Distance(player.Position, Owner.Position) <= 5F && player.CurrentItem is not Marshmallow { Evil: true }) + player.EnableEffect(duration); + } + } + + /// + /// Makes the owner of this marshmallow evil. You CANNOT undo this without resetting the player. + /// + /// The of the new evil player. + public void MakeEvil(AhpStat.AhpProcess evilProcess = null) + { + if (Evil) + return; + + Base.ReleaseEvil(evilProcess ?? EvilAhpProcess ?? new AhpStat.AhpProcess(450F, 450F, 0F, 1F, 0F, true)); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Interfaces/IMarshmallowEvent.cs b/EXILED/Exiled.Events/EventArgs/Interfaces/IMarshmallowEvent.cs new file mode 100644 index 0000000000..fdd41cef5b --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Interfaces/IMarshmallowEvent.cs @@ -0,0 +1,22 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Interfaces +{ + using Exiled.API.Features.Items; + + /// + /// Represents all events related to the marshmallow man. + /// + public interface IMarshmallowEvent : IItemEvent + { + /// + /// Gets the marshmallow item related to this event. + /// + public Marshmallow Marshmallow { get; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Item/CacklingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/CacklingEventArgs.cs new file mode 100644 index 0000000000..69150fd226 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Item/CacklingEventArgs.cs @@ -0,0 +1,51 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Item +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.MarshmallowMan; + + /// + /// Contains all information before a marshmallow man punches. + /// + public class CacklingEventArgs : IMarshmallowEvent, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// The Player cackling. + /// The marshmallow item of the player cackling. + /// Whether the player is allowed to cackle. + public CacklingEventArgs(Player player, MarshmallowItem marshmallow, bool isAllowed = true) + { + Player = player; + Marshmallow = Item.Get(marshmallow); + IsAllowed = isAllowed; + } + + /// + /// Gets the player cackling. + /// + public Player Player { get; } + + /// + public API.Features.Items.Item Item => Marshmallow; + + /// + /// Gets the marshmallow item of the player cackling. + /// + public Marshmallow Marshmallow { get; } + + /// + /// Gets or sets a value indicating whether the player is allowed to cackle. + /// + public bool IsAllowed { get; set; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Item/PunchingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/PunchingEventArgs.cs new file mode 100644 index 0000000000..d616d34e93 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Item/PunchingEventArgs.cs @@ -0,0 +1,51 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Item +{ + using Exiled.API.Features; + using Exiled.API.Features.Items; + using Exiled.Events.EventArgs.Interfaces; + using InventorySystem.Items.MarshmallowMan; + + /// + /// Contains all information before a marshmallow man punches. + /// + public class PunchingEventArgs : IMarshmallowEvent, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// The Player attacking. + /// The marshmallow item of the player attacking. + /// Whether the player is allowed to punch. + public PunchingEventArgs(Player player, MarshmallowItem marshmallow, bool isAllowed = true) + { + Player = player; + Marshmallow = Item.Get(marshmallow); + IsAllowed = isAllowed; + } + + /// + /// Gets the player punching. + /// + public Player Player { get; } + + /// + public Item Item => Marshmallow; + + /// + /// Gets the marshmallow item of the player punching. + /// + public Marshmallow Marshmallow { get; } + + /// + /// Gets or sets a value indicating whether the punch is allowed. + /// + public bool IsAllowed { get; set; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/EventArgs/Scp2536/FoundPositionEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp2536/FoundPositionEventArgs.cs new file mode 100644 index 0000000000..d4935e6c92 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp2536/FoundPositionEventArgs.cs @@ -0,0 +1,40 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp2536 +{ + using Christmas.Scp2536; + using Exiled.API.Features; + using Exiled.Events.EventArgs.Interfaces; + + /// + /// Contains all information after SCP-2536 chooses target for spawning. + /// + public class FoundPositionEventArgs : IPlayerEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public FoundPositionEventArgs(Player player, Scp2536Spawnpoint spawnpoint) + { + Player = player; + Spawnpoint = spawnpoint; + } + + /// + /// Gets the player near whom SCP-2536 will spawn. + /// + public Player Player { get; } + + /// + /// Gets or sets the spawn point where SCP will spawn. + /// + public Scp2536Spawnpoint Spawnpoint { get; set; } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Item.cs b/EXILED/Exiled.Events/Handlers/Item.cs index 9ac83aafd3..b1ca257f09 100644 --- a/EXILED/Exiled.Events/Handlers/Item.cs +++ b/EXILED/Exiled.Events/Handlers/Item.cs @@ -89,6 +89,16 @@ public static class Item /// public static Event JailbirdChangedWearState { get; set; } = new(); + /// + /// Invoked before a marshmallow man punches. + /// + public static Event Punching { get; set; } = new(); + + /// + /// Invoked before a marshmallow man cackles. + /// + public static Event Cackling { get; set; } = new(); + /// /// Called before the Jailbird's is changed. /// @@ -173,5 +183,17 @@ public static class Item /// /// The instance. public static void OnInspectedItem(InspectedItemEventArgs ev) => InspectedItem.InvokeSafely(ev); + + /// + /// Called before a marshmallow man punches. + /// + /// The instance. + public static void OnPunching(PunchingEventArgs ev) => Punching.InvokeSafely(ev); + + /// + /// Called before a marshmallow man cackles. + /// + /// The instance. + public static void OnCackling(CacklingEventArgs ev) => Cackling.InvokeSafely(ev); } } \ No newline at end of file diff --git a/EXILED/Exiled.Events/Handlers/Scp2536.cs b/EXILED/Exiled.Events/Handlers/Scp2536.cs index 3f7dfd1c58..8c0d272583 100644 --- a/EXILED/Exiled.Events/Handlers/Scp2536.cs +++ b/EXILED/Exiled.Events/Handlers/Scp2536.cs @@ -21,6 +21,11 @@ public static class Scp2536 /// public static Event FindingPosition { get; set; } = new(); + /// + /// Invoked once SCP-2536 has found a spawn location. + /// + public static Event FoundPosition { get; set; } = new(); + /// /// Invoked before SCP-2536 gives a gift to a player. /// @@ -37,6 +42,12 @@ public static class Scp2536 /// The instance. public static void OnFindingPosition(FindingPositionEventArgs ev) => FindingPosition.InvokeSafely(ev); + /// + /// Called after SCP-2536 chooses a target. + /// + /// The instance. + public static void OnFoundPosition(FoundPositionEventArgs ev) => FoundPosition.InvokeSafely(ev); + /// /// Called before SCP-2536 gives a gift to a player. /// diff --git a/EXILED/Exiled.Events/Patches/Events/Item/Cackling.cs b/EXILED/Exiled.Events/Patches/Events/Item/Cackling.cs new file mode 100644 index 0000000000..9c71dd86c6 --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Item/Cackling.cs @@ -0,0 +1,69 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Item +{ + using System.Collections.Generic; + using System.Reflection.Emit; + + using Exiled.API.Features; + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Item; + using HarmonyLib; + using InventorySystem.Items.MarshmallowMan; + + using static HarmonyLib.AccessTools; + + /// + /// Patch the . + /// Adds the event. + /// + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.Cackling))] + [HarmonyPatch(typeof(MarshmallowItem), nameof(MarshmallowItem.ServerProcessCackle))] + public class Cackling + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + Label retLabel = generator.DefineLabel(); + + int offset = 1; + int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ret) + offset; + + newInstructions.InsertRange(index, new[] + { + // player = Player.Get(Owner); + new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), + new(OpCodes.Callvirt, PropertyGetter(typeof(MarshmallowItem), nameof(MarshmallowItem.Owner))), + + // item = this; + new(OpCodes.Ldarg_0), + + // true + new(OpCodes.Ldc_I4_1), + + // ev = new CacklingEventArgs(player, item, true); + new(OpCodes.Newobj, Constructor(typeof(CacklingEventArgs), new[] { typeof(Player), typeof(MarshmallowItem), typeof(bool) })), + new(OpCodes.Dup), + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnCackling))), + + // if (!ev.IsAllowed) return + new(OpCodes.Callvirt, PropertyGetter(typeof(CacklingEventArgs), nameof(CacklingEventArgs.IsAllowed))), + new(OpCodes.Brfalse_S, retLabel), + }); + + newInstructions[newInstructions.Count - 1].WithLabels(retLabel); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Item/Punching.cs b/EXILED/Exiled.Events/Patches/Events/Item/Punching.cs new file mode 100644 index 0000000000..e45e0bfe76 --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Item/Punching.cs @@ -0,0 +1,69 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Item +{ + using System.Collections.Generic; + using System.Reflection.Emit; + + using Exiled.API.Features; + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Item; + using HarmonyLib; + using InventorySystem.Items.MarshmallowMan; + + using static HarmonyLib.AccessTools; + + /// + /// Patch the . + /// Adds the event. + /// + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.Punching))] + [HarmonyPatch(typeof(MarshmallowItem), nameof(MarshmallowItem.ServerProcessCmd))] + public class Punching + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + Label retLabel = generator.DefineLabel(); + + int offset = 1; + int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ret) + offset; + + newInstructions[^1].WithLabels(retLabel); + + newInstructions.InsertRange(index, new[] + { + // player = Player.Get(Owner); + new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), + new(OpCodes.Callvirt, PropertyGetter(typeof(MarshmallowItem), nameof(MarshmallowItem.Owner))), + + // item = this; + new(OpCodes.Ldarg_0), + + // true + new(OpCodes.Ldc_I4_1), + + // ev = new PunchingEventArgs(player, item, true); + new(OpCodes.Newobj, Constructor(typeof(PunchingEventArgs), new[] { typeof(Player), typeof(MarshmallowItem), typeof(bool) })), + new(OpCodes.Dup), + new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnPunching))), + + // if (!ev.IsAllowed) return + new(OpCodes.Callvirt, PropertyGetter(typeof(PunchingEventArgs), nameof(PunchingEventArgs.IsAllowed))), + new(OpCodes.Brfalse_S, retLabel), + }); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Scp2536/FoundPosition.cs b/EXILED/Exiled.Events/Patches/Events/Scp2536/FoundPosition.cs new file mode 100644 index 0000000000..dd942042fb --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Scp2536/FoundPosition.cs @@ -0,0 +1,86 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Scp2536 +{ + using System.Collections.Generic; + using System.Reflection.Emit; + + using Christmas.Scp2536; + using Exiled.API.Features; + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Scp2536; + using HarmonyLib; + + using static HarmonyLib.AccessTools; + + /// + /// Patches + /// to add event. + /// + [EventPatch(typeof(Handlers.Scp2536), nameof(Handlers.Scp2536.FoundPosition))] + [HarmonyPatch(typeof(Scp2536Controller), nameof(Scp2536Controller.ServerFindTarget))] + public class FoundPosition + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + Label retLabel = generator.DefineLabel(); + + int index = newInstructions.Count - 1; + + newInstructions[index].WithLabels(retLabel); + + newInstructions.InsertRange(index, new CodeInstruction[] + { + // dupe the result (true / false if found) + new(OpCodes.Dup), + + // return w result if failed + new(OpCodes.Brfalse_S, retLabel), + new(OpCodes.Pop), + + // load ADDRESS of parameter "out Scp2536Spawnpoint spawnpoint" onto stack (so not actual value but address) + // this is used at end of transpiler + new(OpCodes.Ldarg_2), + + // load address of parameter "out ReferenceHub target" + new(OpCodes.Ldarg_1), + + // load value at address + new(OpCodes.Ldind_Ref), + + // player = Player.Get(target); + new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), + + // load address of parameter "out Scp2536Spawnpoint spawnpoint" + new(OpCodes.Ldarg_2), + + // load value at address + new(OpCodes.Ldind_Ref), + + // ev = new FoundPositionEventArgs(player, spawnpoint); + new(OpCodes.Newobj, Constructor(typeof(FoundPositionEventArgs), new[] { typeof(Player), typeof(Scp2536Spawnpoint) })), + new(OpCodes.Dup), + new(OpCodes.Call, Method(typeof(Handlers.Scp2536), nameof(Handlers.Scp2536.OnFoundPosition))), + + // spawnpoint = ev.Spawnpoint; + new(OpCodes.Callvirt, PropertyGetter(typeof(FoundPositionEventArgs), nameof(FoundPositionEventArgs.Spawnpoint))), + + // this uses the address already on stack (see 3rd comment) with the value from the event args + new(OpCodes.Stind_Ref), + }); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Fixes/FixMarshmallowManFF.cs b/EXILED/Exiled.Events/Patches/Fixes/FixMarshmallowManFF.cs index d91c2d0398..bdfc2e5f0d 100644 --- a/EXILED/Exiled.Events/Patches/Fixes/FixMarshmallowManFF.cs +++ b/EXILED/Exiled.Events/Patches/Fixes/FixMarshmallowManFF.cs @@ -35,7 +35,7 @@ internal class FixMarshmallowManFF : AttackerDamageHandler #pragma warning disable SA1600 // Elements should be documented public FixMarshmallowManFF(MarshmallowItem marshmallowItem) { - Attacker = new(marshmallowItem.Owner); + Attacker = new Footprint(marshmallowItem.Owner); Damage = marshmallowItem._attackDamage; AllowSelfDamage = false; ServerLogsText = "MarshmallowManFF Fix"; @@ -47,53 +47,36 @@ public FixMarshmallowManFF(MarshmallowItem marshmallowItem) public override float Damage { get; set; } - public override string RagdollInspectText { get; } + public override string RagdollInspectText { get; } = DeathTranslations.MarshmallowMan.RagdollTranslation; - public override CassieAnnouncement CassieDeathAnnouncement + public override CassieAnnouncement CassieDeathAnnouncement { get; } = new() { - get - { - return new CassieAnnouncement() - { - Announcement = "TERMINATED BY MARSHMALLOW MAN", - SubtitleParts = new SubtitlePart[] - { - new SubtitlePart(SubtitleType.TerminatedByMarshmallowMan, null), - }, - }; - } - } + Announcement = "TERMINATED BY MARSHMALLOW MAN", + SubtitleParts = + [ + new SubtitlePart(SubtitleType.TerminatedByMarshmallowMan, null), + ], + }; - public override string DeathScreenText { get; } + public override string DeathScreenText { get; } = DeathTranslations.MarshmallowMan.DeathscreenTranslation; public override string ServerLogsText { get; } #pragma warning restore SA1600 // Elements should be documented #pragma warning disable SA1313 // Parameter names should begin with lower-case letter - private static bool Prefix(MarshmallowItem __instance, ReferenceHub syncTarget) + private static IEnumerable Transpiler(IEnumerable instructions) { - foreach (IDestructible destructible in __instance.DetectDestructibles()) - { - HitboxIdentity hitboxIdentity = destructible as HitboxIdentity; - if ((hitboxIdentity == null || (!(hitboxIdentity.TargetHub != syncTarget) && (__instance.EvilMode || HitboxIdentity.IsDamageable(__instance.Owner, hitboxIdentity.TargetHub)))) && destructible.Damage(__instance._attackDamage, new FixMarshmallowManFF(__instance), destructible.CenterOfMass)) - { - HitboxIdentity hitboxIdentity2 = destructible as HitboxIdentity; - if (hitboxIdentity2 != null && !hitboxIdentity2.TargetHub.IsAlive()) - __instance.Owner.playerEffectsController.GetEffect().OnKill(); - - if (__instance.EvilMode) - __instance.EvilAHPProcess.CurrentAmount += 100f; - - Hitmarker.SendHitmarkerDirectly(__instance.Owner, 1f, true); - __instance.ServerSendPublicRpc(writer => - { - writer.WriteByte(1); - }); - break; - } - } - - return false; + List newInstructions = ListPool.Pool.Get(instructions); + + int index = newInstructions.FindIndex(instruction => instruction.Calls(PropertyGetter(typeof(MarshmallowItem), nameof(MarshmallowItem.NewDamageHandler)))); + + // replace the getter for NewDamageHandler with ctor of FixMarshmallowManFF + newInstructions[index] = new CodeInstruction(OpCodes.Newobj, Constructor(typeof(FixMarshmallowManFF), new[] { typeof(MarshmallowItem) })); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); } } }