using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UKEnemyIdentifier.Components;
using UKEnemyIdentifier.Utils;
using UKEnemyIdentifier.Utils.Il;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("UKEnemyIdentifier")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("UKEnemyIdentifier")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("23B65D15-307A-40B5-B785-189FDD449F1A")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("1.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace UKEnemyIdentifier
{
[BepInProcess("ULTRAKILL.exe")]
[BepInPlugin("dev.flazhik.ukenemyidentifier", "UKEnemyIdentifier", "1.1.0")]
public class Plugin : BaseUnityPlugin
{
private Harmony _harmony;
private void Awake()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Expected O, but got Unknown
_harmony = new Harmony("dev.flazhik.ukenemyidentifier");
_harmony.PatchAll();
}
}
internal static class PluginInfo
{
public const string Guid = "dev.flazhik.ukenemyidentifier";
public const string Name = "UKEnemyIdentifier";
public const string Version = "1.1.0";
}
}
namespace UKEnemyIdentifier.Utils
{
public static class ObjectExtensions
{
public static bool IsOneOf(this object v, params object[] options)
{
return options.Any((object o) => o.Equals(v));
}
}
public static class ReflectionUtils
{
private const BindingFlags BindingFlagsFields = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
public static T GetPrivate<T>(object instance, string field)
{
return (T)instance.GetType().GetField(field, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).GetValue(instance);
}
public static CodeInstruction IL(OpCode opCode)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Expected O, but got Unknown
return new CodeInstruction(opCode, (object)null);
}
public static CodeInstruction IL(OpCode opCode, object inst)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Expected O, but got Unknown
return new CodeInstruction(opCode, inst);
}
public static IEnumerable<CodeInstruction> IL(params (OpCode opCode, object inst)[] instructions)
{
return ((IEnumerable<(OpCode, object)>)instructions).Select((Func<(OpCode, object), CodeInstruction>)(((OpCode opCode, object inst) i) => new CodeInstruction(i.opCode, i.inst))).ToList();
}
public static bool IsLdloc(CodeInstruction instruction)
{
return instruction.opcode.IsOneOf(OpCodes.Ldloc_0, OpCodes.Ldloc_1, OpCodes.Ldloc_2, OpCodes.Ldloc_3, OpCodes.Ldloc_S, OpCodes.Ldloc);
}
public static bool IsStloc(CodeInstruction instruction)
{
return instruction.opcode.IsOneOf(OpCodes.Stloc_0, OpCodes.Stloc_1, OpCodes.Stloc_2, OpCodes.Stloc_3, OpCodes.Stloc_S, OpCodes.Stloc);
}
public static int GetLocalIndex(CodeInstruction instruction)
{
if (instruction.opcode.IsOneOf(OpCodes.Ldloc_0, OpCodes.Stloc_0))
{
return 0;
}
if (instruction.opcode.IsOneOf(OpCodes.Ldloc_1, OpCodes.Stloc_1))
{
return 1;
}
if (instruction.opcode.IsOneOf(OpCodes.Ldloc_2, OpCodes.Stloc_2))
{
return 2;
}
if (instruction.opcode.IsOneOf(OpCodes.Ldloc_3, OpCodes.Stloc_3))
{
return 3;
}
if (!(instruction.operand is LocalBuilder localBuilder))
{
return -1;
}
return localBuilder.LocalIndex;
}
public static CodeInstruction MirrorLdloc(CodeInstruction instruction)
{
return (CodeInstruction)(GetLocalIndex(instruction) switch
{
0 => IL(OpCodes.Ldloc_0),
1 => IL(OpCodes.Ldloc_1),
2 => IL(OpCodes.Ldloc_2),
3 => IL(OpCodes.Ldloc_3),
-1 => null,
_ => (instruction.operand is LocalBuilder inst) ? IL(OpCodes.Ldloc, inst) : null,
});
}
public static Type LocalType(MethodBase method, int index)
{
MethodBody methodBody = method?.GetMethodBody();
if (methodBody == null || index < 0 || index >= methodBody.LocalVariables.Count)
{
return null;
}
return methodBody.LocalVariables[index].LocalType;
}
public static CodeInstruction FindObjectLocal(IReadOnlyList<CodeInstruction> instructions, int index, MethodBase method, Type type, int depth = 6)
{
int num = index - 1;
while (num >= 0 && num >= index - depth)
{
if (IsLdloc(instructions[num]))
{
Type type2 = LocalType(method, GetLocalIndex(instructions[num]));
if (type2 != null && type.IsAssignableFrom(type2))
{
return instructions[num];
}
}
num--;
}
return null;
}
public static IEnumerable<CodeInstruction> ToGameObject(CodeInstruction localLoad, Type localType)
{
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Expected O, but got Unknown
if (typeof(GameObject).IsAssignableFrom(localType))
{
return new List<CodeInstruction> { localLoad };
}
return new List<CodeInstruction>
{
localLoad,
new CodeInstruction(OpCodes.Callvirt, (object)AccessTools.Method(typeof(Component), "get_gameObject", (Type[])null, (Type[])null))
};
}
}
}
namespace UKEnemyIdentifier.Utils.Il
{
public static class EnemyIdentifierEmitters
{
private static readonly MethodInfo ManagerInstance = AccessTools.Method(typeof(EnemyIdentifierManager), "get_Instance", (Type[])null, (Type[])null);
private static readonly MethodInfo GetGameObject = AccessTools.Method(typeof(Component), "get_gameObject", (Type[])null, (Type[])null);
private static readonly FieldInfo LastHurtingFactorField = AccessTools.Field(typeof(EnemyIdentifierManager), "LastHurtingFactor");
private static readonly MethodInfo RegisterFactorMethod = AccessTools.Method(typeof(EnemyIdentifierManager), "RegisterFactor", new Type[2]
{
typeof(GameObject),
typeof(EnemyIdentifier)
}, (Type[])null);
private static readonly MethodInfo RegisterExplosionMethod = AccessTools.Method(typeof(EnemyIdentifierManager), "RegisterExplosion", new Type[2]
{
typeof(Component),
typeof(Explosion)
}, (Type[])null);
public static IEnumerable<CodeInstruction> RegisterExplosion(CodeInstruction explosionLoad)
{
return ReflectionUtils.IL((OpCodes.Call, ManagerInstance), (OpCodes.Ldarg_0, null)).Concat(new List<CodeInstruction> { explosionLoad }).Concat(ReflectionUtils.IL((OpCodes.Callvirt, RegisterExplosionMethod)));
}
public static List<CodeInstruction> LastHurtingFactor()
{
return ReflectionUtils.IL((OpCodes.Call, ManagerInstance), (OpCodes.Ldarg_0, null), (OpCodes.Call, GetGameObject), (OpCodes.Stfld, LastHurtingFactorField)).ToList();
}
public static IEnumerable<CodeInstruction> RegisterHurtingFactor<TOwner>(CodeInstruction valueLoad, Type valueType)
{
return ReflectionUtils.IL((OpCodes.Call, ManagerInstance)).Concat(ReflectionUtils.ToGameObject(valueLoad, valueType)).Concat(ReflectionUtils.IL((OpCodes.Ldarg_0, null), (OpCodes.Ldfld, AccessTools.Field(typeof(TOwner), "eid")), (OpCodes.Callvirt, RegisterFactorMethod)));
}
public static IEnumerable<CodeInstruction> RegisterHurtingFactor<TOwner>(LocalBuilder local, Type valueType)
{
return RegisterHurtingFactor<TOwner>(ReflectionUtils.IL(OpCodes.Ldloc, local), valueType);
}
}
public enum AnchorMatchMode
{
Single,
All,
First,
Optional
}
public sealed class TranspilerBuilder
{
private readonly MethodBase _original;
private readonly ILGenerator _generator;
private readonly string _method;
private List<CodeInstruction> Instructions { get; }
private TranspilerBuilder(IEnumerable<CodeInstruction> instructions, MethodBase original, ILGenerator generator)
{
Instructions = instructions.ToList();
_original = original;
_generator = generator;
_method = ((original == null) ? "?" : (original.DeclaringType?.Name + "." + original.Name));
}
public static TranspilerBuilder ForInstructions(IEnumerable<CodeInstruction> instructions, MethodBase original, ILGenerator generator = null)
{
return new TranspilerBuilder(instructions, original, generator);
}
public TranspilerBuilder Before(Anchor anchor, Func<List<CodeInstruction>> emit, AnchorMatchMode mode = AnchorMatchMode.Single)
{
return Apply(anchor, emit, mode, after: false);
}
public TranspilerBuilder After(Anchor anchor, Func<List<CodeInstruction>> emit, AnchorMatchMode mode = AnchorMatchMode.Single)
{
return Apply(anchor, emit, mode, after: true);
}
public TranspilerBuilder AfterStore(Anchor anchor, Type valueType, Func<CodeInstruction, Type, IEnumerable<CodeInstruction>> emit, AnchorMatchMode mode = AnchorMatchMode.Single, int depth = 6)
{
List<int> list = Select(Positions(anchor), mode);
if (list == null)
{
ReportAnchorError(anchor.Name, Positions(anchor).Count, mode);
return this;
}
for (int num = list.Count - 1; num >= 0; num--)
{
CodeInstruction val = ReflectionUtils.FindObjectLocal(Instructions, list[num], _original, valueType, depth);
CodeInstruction val2 = ((val == null) ? null : ReflectionUtils.MirrorLdloc(val));
if (val2 == null)
{
ReportAnchorError(anchor.Name, 0, mode);
}
else
{
Type arg = ReflectionUtils.LocalType(_original, ReflectionUtils.GetLocalIndex(val)) ?? valueType;
Instructions.InsertRange(list[num] + 1, emit(val2, arg));
}
}
return this;
}
public TranspilerBuilder AfterLocalStore(Type valueType, Func<CodeInstruction, Type, IEnumerable<CodeInstruction>> emit, AnchorMatchMode mode = AnchorMatchMode.Single)
{
List<int> list = new List<int>();
for (int i = 0; i < Instructions.Count; i++)
{
if (ReflectionUtils.IsStloc(Instructions[i]) && ReflectionUtils.LocalType(_original, ReflectionUtils.GetLocalIndex(Instructions[i])) == valueType)
{
list.Add(i);
}
}
string anchor = "store(" + valueType.Name + ")";
List<int> list2 = Select(list, mode);
if (list2 == null)
{
ReportAnchorError(anchor, list.Count, mode);
return this;
}
for (int num = list2.Count - 1; num >= 0; num--)
{
CodeInstruction val = ReflectionUtils.MirrorLdloc(Instructions[list2[num]]);
if (val == null)
{
ReportAnchorError(anchor, 0, mode);
}
else
{
Instructions.InsertRange(list2[num] + 1, emit(val, valueType));
}
}
return this;
}
public TranspilerBuilder AfterStack(Anchor anchor, Type valueType, Func<LocalBuilder, Type, IEnumerable<CodeInstruction>> emit, AnchorMatchMode mode = AnchorMatchMode.Single)
{
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Expected O, but got Unknown
List<int> list = Positions(anchor);
List<int> list2 = Select(list, mode);
if (list2 == null || _generator == null)
{
ReportAnchorError(anchor.Name, list.Count, mode);
return this;
}
for (int num = list2.Count - 1; num >= 0; num--)
{
LocalBuilder localBuilder = _generator.DeclareLocal(valueType);
List<CodeInstruction> list3 = new List<CodeInstruction>
{
new CodeInstruction(OpCodes.Stloc, (object)localBuilder)
};
list3.AddRange(emit(localBuilder, valueType));
list3.Add(ReflectionUtils.IL(OpCodes.Ldloc, localBuilder));
Instructions.InsertRange(list2[num] + 1, list3);
}
return this;
}
public IEnumerable<CodeInstruction> Build()
{
return Instructions;
}
private TranspilerBuilder Apply(Anchor anchor, Func<List<CodeInstruction>> emit, AnchorMatchMode mode, bool after)
{
List<int> list = Positions(anchor);
List<int> list2 = Select(list, mode);
if (list2 == null)
{
ReportAnchorError(anchor.Name, list.Count, mode);
return this;
}
for (int num = list2.Count - 1; num >= 0; num--)
{
Instructions.InsertRange(list2[num] + (after ? 1 : 0), emit());
}
return this;
}
private List<int> Positions(Anchor anchor)
{
List<int> list = new List<int>();
for (int i = 0; i < Instructions.Count; i++)
{
if (anchor.Matches(Instructions[i]))
{
list.Add(i);
}
}
return list;
}
private static List<int> Select(List<int> positions, AnchorMatchMode mode)
{
if (!IsAcceptable(positions.Count, mode))
{
return null;
}
if (mode != AnchorMatchMode.First)
{
return positions;
}
return positions.GetRange(0, 1);
}
private static bool IsAcceptable(int count, AnchorMatchMode mode)
{
return mode switch
{
AnchorMatchMode.Single => count == 1,
AnchorMatchMode.All => count > 0,
AnchorMatchMode.First => count > 0,
AnchorMatchMode.Optional => count <= 1,
_ => false,
};
}
private void ReportAnchorError(string anchor, int anchorsCount, AnchorMatchMode mode)
{
Debug.LogError(anchorsCount switch
{
0 => _method + ": anchor '" + anchor + "' not found, skipping injection",
1 => $"{_method}: anchor '{anchor}' cannot be used ({mode}), skipping injection",
_ => $"{_method}: anchor '{anchor}' matched {anchorsCount} times ({mode}), skipping injection",
});
}
}
public sealed class Anchor(string name, Func<CodeInstruction, bool> matches)
{
public string Name { get; } = name;
public Func<CodeInstruction, bool> Matches { get; } = matches;
}
public static class UltrakillInstructions
{
private static readonly MethodInfo NewMovementGetHurt = AccessTools.Method(typeof(NewMovement), "GetHurt", new Type[7]
{
typeof(int),
typeof(bool),
typeof(float),
typeof(bool),
typeof(bool),
typeof(float),
typeof(bool)
}, (Type[])null);
public static readonly Anchor GetHurt = new Anchor("NewMovement::GetHurt", (CodeInstruction i) => i.opcode == OpCodes.Callvirt && CodeInstructionExtensions.OperandIs(i, (MemberInfo)NewMovementGetHurt));
public static readonly Anchor ProjectileTarget = StoreTo(typeof(Projectile), "target", "targetHandle");
public static readonly Anchor Instantiate = new Anchor("Object::Instantiate", (CodeInstruction i) => i.opcode == OpCodes.Call && i.operand is MethodInfo { Name: "Instantiate" } methodInfo && methodInfo.DeclaringType == typeof(Object));
public static Anchor GetComponent(Type componentType)
{
return new Anchor("GetComponent<" + componentType.Name + ">", (CodeInstruction instruction) => instruction.opcode == OpCodes.Callvirt && instruction.operand is MethodInfo { Name: "GetComponent", IsGenericMethod: not false } methodInfo && methodInfo.GetGenericArguments()[0] == componentType);
}
public static Anchor CallTo(Type declaringType, string methodName)
{
return new Anchor(declaringType.Name + "::" + methodName, (CodeInstruction instruction) => instruction.opcode.IsOneOf(OpCodes.Call, OpCodes.Callvirt) && instruction.operand is MethodInfo methodInfo && methodInfo.Name == methodName && methodInfo.DeclaringType == declaringType);
}
public static Anchor StoreTo(Type declaringType, params string[] fields)
{
return new Anchor(declaringType.Name + "::" + string.Join("/", fields), delegate(CodeInstruction instruction)
{
if (instruction.opcode == OpCodes.Stfld && instruction.operand is FieldInfo fieldInfo && fieldInfo.DeclaringType == declaringType)
{
string name = fieldInfo.Name;
object[] options = fields;
return name.IsOneOf(options);
}
return false;
});
}
}
}
namespace UKEnemyIdentifier.Patches
{
[HarmonyPatch(typeof(BlackHoleProjectile))]
public class BlackHoleProjectilePatch
{
[HarmonyPrefix]
[HarmonyPatch(typeof(BlackHoleProjectile), "OnTriggerEnter")]
public static bool BlackHoleProjectile_OnTriggerEnter_Prefix(BlackHoleProjectile __instance, Collider other)
{
if (__instance.enemy && __instance.target != null && __instance.target.IsTargetTransform(((Component)other).gameObject.transform))
{
MonoSingleton<EnemyIdentifierManager>.Instance.LastHurtingFactor = ((Component)__instance).gameObject;
}
return true;
}
}
[HarmonyPatch(typeof(CancerousRodent))]
public class CancerousRodentPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(CancerousRodent), "FireBurst")]
public static IEnumerable<CodeInstruction> CancerousRodent_FireBurst_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterStore(UltrakillInstructions.StoreTo(typeof(Projectile), "damage"), typeof(Projectile), EnemyIdentifierEmitters.RegisterHurtingFactor<CancerousRodent>, AnchorMatchMode.Single, 10).Build();
}
}
[HarmonyPatch(typeof(Coin))]
public class CoinPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(Coin), "ShootAtPlayer")]
public static IEnumerable<CodeInstruction> Coin_ShootAtPlayer_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).Before(UltrakillInstructions.GetHurt, EnemyIdentifierEmitters.LastHurtingFactor).Build();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Coin), "SpawnBeam")]
public static void Coin_SpawnBeam_Postfix(GameObject __result, EnemyIdentifier ___eid)
{
if (!((Object)(object)__result == (Object)null) && !((Object)(object)___eid == (Object)null))
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(__result, ___eid);
}
}
}
[HarmonyPatch(typeof(ContinuousBeam))]
public class ContinuousBeamPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(ContinuousBeam), "Update")]
public static IEnumerable<CodeInstruction> ContinuousBeam_Update_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).Before(UltrakillInstructions.GetHurt, EnemyIdentifierEmitters.LastHurtingFactor, AnchorMatchMode.Optional).Build();
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(ContinuousBeam), "FixedUpdate")]
public static IEnumerable<CodeInstruction> ContinuousBeam_FixedUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).Before(UltrakillInstructions.GetHurt, EnemyIdentifierEmitters.LastHurtingFactor).Build();
}
}
[HarmonyPatch(typeof(DroneFlesh))]
public class DroneFleshPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(DroneFlesh), "ShootBeam")]
public static IEnumerable<CodeInstruction> DroneFlesh_ShootBeam_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterLocalStore(typeof(GameObject), EnemyIdentifierEmitters.RegisterHurtingFactor<DroneFlesh>, AnchorMatchMode.First).Build();
}
}
[HarmonyPatch(typeof(Drone))]
public class DronePatch
{
[HarmonyPostfix]
[HarmonyPatch(typeof(Drone), "SetProjectileSettings")]
public static void Drone_SetProjectileSettings_Postfix(Projectile proj, EnemyIdentifier ___eid)
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)proj).gameObject, ___eid);
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(Drone), "ShootSecondary")]
public static IEnumerable<CodeInstruction> Drone_ShootSecondary_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterStore(UltrakillInstructions.StoreTo(typeof(Pincer), "firedMessageReceiver"), typeof(Pincer), RegisterPincerBeams).Build();
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(Drone), "Explode")]
public static IEnumerable<CodeInstruction> Drone_Explode_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterLocalStore(typeof(Explosion), SetExplosionOrigin).Build();
}
private static IEnumerable<CodeInstruction> RegisterPincerBeams(CodeInstruction pincerLoad, Type pincerType)
{
return ReflectionUtils.ToGameObject(pincerLoad, pincerType).Concat(ReflectionUtils.IL((OpCodes.Ldarg_0, null), (OpCodes.Ldfld, AccessTools.Field(typeof(Drone), "eid")), (OpCodes.Call, AccessTools.Method(typeof(DronePatch), "RegisterBeamFactors", new Type[2]
{
typeof(GameObject),
typeof(EnemyIdentifier)
}, (Type[])null))));
}
private static IEnumerable<CodeInstruction> SetExplosionOrigin(CodeInstruction explosionLoad, Type _)
{
return new List<CodeInstruction> { explosionLoad }.Concat(ReflectionUtils.IL((OpCodes.Ldarg_0, null), (OpCodes.Ldfld, AccessTools.Field(typeof(Drone), "eid")), (OpCodes.Stfld, AccessTools.Field(typeof(Explosion), "originEnemy"))));
}
private static void RegisterBeamFactors(GameObject pincer, EnemyIdentifier eid)
{
if (!((Object)(object)pincer == (Object)null) && !((Object)(object)eid == (Object)null))
{
RevolverBeam[] componentsInChildren = pincer.GetComponentsInChildren<RevolverBeam>(true);
foreach (RevolverBeam val in componentsInChildren)
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)val).gameObject, eid);
}
ContinuousBeam[] componentsInChildren2 = pincer.GetComponentsInChildren<ContinuousBeam>(true);
foreach (ContinuousBeam val2 in componentsInChildren2)
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)val2).gameObject, eid);
}
}
}
}
[HarmonyPatch(typeof(EnemyNailgun))]
public class EnemyNailgunPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(EnemyNailgun), "FixedUpdate")]
public static IEnumerable<CodeInstruction> EnemyNailgun_FixedUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterLocalStore(typeof(GameObject), EnemyIdentifierEmitters.RegisterHurtingFactor<EnemyNailgun>, AnchorMatchMode.First).Build();
}
}
[HarmonyPatch(typeof(EnemyRevolver))]
public class EnemyRevolverPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(EnemyRevolver), "Fire")]
public static IEnumerable<CodeInstruction> EnemyRevolver_Fire_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
List<CodeInstruction> list = instructions.ToList();
RegisterBullet(list, generator, AccessTools.Field(typeof(EnemyRevolver), "bullet"));
SetRevolverHurtingFactor(list);
return list;
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(EnemyRevolver), "AltFire")]
public static IEnumerable<CodeInstruction> EnemyRevolver_AltFire_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
List<CodeInstruction> list = instructions.ToList();
RegisterBullet(list, generator, AccessTools.Field(typeof(EnemyRevolver), "altBullet"));
SetRevolverHurtingFactor(list);
return list;
}
private static void RegisterBullet(List<CodeInstruction> instructions, ILGenerator generator, FieldInfo bulletField)
{
if (bulletField == null)
{
return;
}
for (int i = 0; i < instructions.Count; i++)
{
if (instructions[i].opcode != OpCodes.Ldfld || !CodeInstructionExtensions.OperandIs(instructions[i], (MemberInfo)bulletField))
{
continue;
}
int num = -1;
for (int j = i + 1; j < instructions.Count && j <= i + 8; j++)
{
if (!(instructions[j].opcode != OpCodes.Call) && instructions[j].operand is MethodInfo methodInfo && !(methodInfo.Name != "Instantiate"))
{
num = j;
break;
}
}
if (num >= 0)
{
LocalBuilder item = generator.DeclareLocal(typeof(GameObject));
instructions.InsertRange(num + 1, ReflectionUtils.IL((OpCodes.Stloc, item), (OpCodes.Ldloc, item), (OpCodes.Call, AccessTools.Method(typeof(EnemyIdentifierManager), "get_Instance", (Type[])null, (Type[])null)), (OpCodes.Ldloc, item), (OpCodes.Ldarg_0, null), (OpCodes.Ldfld, AccessTools.Field(typeof(EnemyRevolver), "eid")), (OpCodes.Callvirt, AccessTools.Method(typeof(EnemyIdentifierManager), "RegisterFactor", new Type[2]
{
typeof(GameObject),
typeof(EnemyIdentifier)
}, (Type[])null))));
}
break;
}
}
private static void SetRevolverHurtingFactor(List<CodeInstruction> instructions)
{
IEnumerable<CodeInstruction> collection = ReflectionUtils.IL((OpCodes.Call, AccessTools.Method(typeof(EnemyIdentifierManager), "get_Instance", (Type[])null, (Type[])null)), (OpCodes.Ldloc_1, null), (OpCodes.Callvirt, AccessTools.Method(typeof(Component), "get_gameObject", (Type[])null, (Type[])null)), (OpCodes.Ldarg_0, null), (OpCodes.Ldfld, AccessTools.Field(typeof(EnemyRevolver), "eid")), (OpCodes.Callvirt, AccessTools.Method(typeof(EnemyIdentifierManager), "RegisterFactor", new Type[2]
{
typeof(GameObject),
typeof(EnemyIdentifier)
}, (Type[])null)));
instructions.InsertRange(instructions.Count - 1, collection);
}
}
[HarmonyPatch(typeof(EnemyShotgun))]
public class EnemyShotgunPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(EnemyShotgun), "Fire")]
public static IEnumerable<CodeInstruction> EnemyShotgun_Fire_Transpiler(IEnumerable<CodeInstruction> instructions)
{
LocalBuilder localBuilder = null;
List<CodeInstruction> list = instructions.ToList();
for (int i = 0; i < list.Count; i++)
{
if (ProjectileOperand(list[i]))
{
localBuilder = (LocalBuilder)list[i].operand;
}
if (FireInjectionPoint(list[i]))
{
if (localBuilder != null)
{
SetShotgunHurtingFactor(list, localBuilder, i);
}
break;
}
}
return list;
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(EnemyShotgun), "AltFire")]
public static IEnumerable<CodeInstruction> EnemyShotgun_AltFire_Transpiler(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> list = instructions.ToList();
for (int i = 0; i < list.Count; i++)
{
if (AltFireInjectionPoint(list[i]))
{
SetGrenadeHurtingFactor(list, i);
break;
}
}
return list;
}
private static bool FireInjectionPoint(CodeInstruction instruction)
{
if (instruction.opcode == OpCodes.Stfld)
{
return CodeInstructionExtensions.OperandIs(instruction, (MemberInfo)AccessTools.Field(typeof(Projectile), "spreaded"));
}
return false;
}
private static bool AltFireInjectionPoint(CodeInstruction instruction)
{
if (instruction.opcode == OpCodes.Stfld)
{
return CodeInstructionExtensions.OperandIs(instruction, (MemberInfo)AccessTools.Field(typeof(Grenade), "enemy"));
}
return false;
}
private static bool ProjectileOperand(CodeInstruction instruction)
{
if (instruction.opcode == OpCodes.Ldloc_S && instruction.operand is LocalBuilder localBuilder)
{
return localBuilder.LocalType == typeof(Projectile);
}
return false;
}
private static void SetShotgunHurtingFactor(List<CodeInstruction> instructions, LocalBuilder projectile, int index)
{
instructions.InsertRange(index, ReflectionUtils.IL((OpCodes.Call, AccessTools.Method(typeof(EnemyIdentifierManager), "get_Instance", (Type[])null, (Type[])null)), (OpCodes.Ldloc_S, projectile), (OpCodes.Callvirt, AccessTools.Method(typeof(Component), "get_gameObject", (Type[])null, (Type[])null)), (OpCodes.Ldarg_0, null), (OpCodes.Ldfld, AccessTools.Field(typeof(EnemyShotgun), "eid")), (OpCodes.Callvirt, AccessTools.Method(typeof(EnemyIdentifierManager), "RegisterFactor", new Type[2]
{
typeof(GameObject),
typeof(EnemyIdentifier)
}, (Type[])null))));
}
private static void SetGrenadeHurtingFactor(List<CodeInstruction> instructions, int index)
{
instructions.InsertRange(index, ReflectionUtils.IL((OpCodes.Ldloc_2, null), (OpCodes.Ldarg_0, null), (OpCodes.Ldfld, AccessTools.Field(typeof(EnemyShotgun), "eid")), (OpCodes.Stfld, AccessTools.Field(typeof(Grenade), "originEnemy"))));
}
}
[HarmonyPatch(typeof(Explosion))]
public class ExplosionPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(Explosion), "Collide")]
public static IEnumerable<CodeInstruction> Explosion_Collide_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).Before(UltrakillInstructions.GetHurt, EnemyIdentifierEmitters.LastHurtingFactor).Build();
}
}
[HarmonyPatch(typeof(Ferryman))]
public class FerrymanPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(Ferryman), "SpawnLightningBolt")]
public static IEnumerable<CodeInstruction> Ferryman_SpawnLightningBolt_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterLocalStore(typeof(LightningStrikeExplosive), EnemyIdentifierEmitters.RegisterHurtingFactor<Ferryman>).Build();
}
}
[HarmonyPatch(typeof(FireZone))]
public class FireZonePatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(FireZone), "OnTriggerStay")]
public static IEnumerable<CodeInstruction> FireZone_OnTriggerStay_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).Before(UltrakillInstructions.GetHurt, EnemyIdentifierEmitters.LastHurtingFactor).Build();
}
}
[HarmonyPatch(typeof(FleshPrison))]
public class FleshPrisonPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(FleshPrison), "Update")]
public static IEnumerable<CodeInstruction> FleshPrison_Update_Transpiler(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> list = instructions.ToList();
for (int i = 0; i < list.Count; i++)
{
if (!(list[i].opcode != OpCodes.Stloc_S) && list[i].operand is LocalBuilder && ((LocalBuilder)list[i].operand).LocalIndex == 11)
{
LocalBuilder projectile = (LocalBuilder)list[i].operand;
SetProjectileHurtingFactor(list, projectile, i + 1);
break;
}
}
return list;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(FleshPrison), "SpawnBlackHole")]
public static void FleshPrison_SpawnBlackHole_Postfix(FleshPrison __instance, BlackHoleProjectile ___currentBlackHole, EnemyIdentifier ___eid)
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)___currentBlackHole).gameObject, ___eid);
}
private static void SetProjectileHurtingFactor(List<CodeInstruction> instructions, LocalBuilder projectile, int index)
{
instructions.InsertRange(index, ReflectionUtils.IL((OpCodes.Call, AccessTools.Method(typeof(EnemyIdentifierManager), "get_Instance", (Type[])null, (Type[])null)), (OpCodes.Ldloc_S, projectile), (OpCodes.Ldarg_0, null), (OpCodes.Ldfld, AccessTools.Field(typeof(FleshPrison), "eid")), (OpCodes.Callvirt, AccessTools.Method(typeof(EnemyIdentifierManager), "RegisterFactor", new Type[2]
{
typeof(GameObject),
typeof(EnemyIdentifier)
}, (Type[])null))));
}
}
[HarmonyPatch(typeof(GabrielBase))]
public class GabrielBasePatch
{
[HarmonyPostfix]
[HarmonyPatch(typeof(GabrielSecond), "ThrowSwords")]
public static void GabrielSecond_ThrowSwords_Postfix(GabrielSecond __instance)
{
GabrielBase gabe = __instance.gabe;
if (!((Object)(object)gabe == (Object)null) && !((Object)(object)gabe.currentCombinedSwordsThrown == (Object)null) && !((Object)(object)gabe.eid == (Object)null))
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)gabe.currentCombinedSwordsThrown).gameObject, gabe.eid);
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(GabrielBase), "SpawnSummonedSwords")]
public static void GabrielBase_SpawnSummonedSwords_Postfix(GabrielBase __instance, GameObject ___currentSwords)
{
if (!((Object)(object)___currentSwords == (Object)null) && !((Object)(object)__instance.eid == (Object)null))
{
Projectile[] componentsInChildren = ___currentSwords.GetComponentsInChildren<Projectile>();
foreach (Projectile val in componentsInChildren)
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)val).gameObject, __instance.eid);
}
}
}
}
[HarmonyPatch(typeof(Gabriel))]
public class GabrielPatch
{
[HarmonyPostfix]
[HarmonyPatch(typeof(Gabriel), "ThrowWeapon")]
public static void Gabriel_ThrowWeapon_Postfix(Gabriel __instance, GameObject ___thrownObject)
{
GabrielBase component = ((Component)__instance).GetComponent<GabrielBase>();
Projectile[] componentsInChildren = ___thrownObject.GetComponentsInChildren<Projectile>();
foreach (Projectile val in componentsInChildren)
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)val).gameObject, component.eid);
}
}
}
[HarmonyPatch(typeof(GroundWave))]
public class GroundWavePatch
{
[HarmonyPostfix]
[HarmonyPatch(typeof(GroundWave), "Start")]
public static void GroundWave_Start_Postfix(HurtZone ___hurtzone, EnemyIdentifier ___eid)
{
if (!((Object)(object)___hurtzone == (Object)null) && !((Object)(object)___eid == (Object)null))
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)___hurtzone).gameObject, ___eid);
}
}
}
[HarmonyPatch(typeof(Gutterman))]
public class GuttermanPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(Gutterman), "FixedUpdate")]
public static IEnumerable<CodeInstruction> Gutterman_FixedUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod, ILGenerator generator)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod, generator).AfterStack(UltrakillInstructions.Instantiate, typeof(GameObject), EnemyIdentifierEmitters.RegisterHurtingFactor<Gutterman>).Build();
}
}
[HarmonyPatch(typeof(HurtZone))]
public class HurtZonePatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(HurtZone), "FixedUpdate")]
public static IEnumerable<CodeInstruction> HurtZone_FixedUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).Before(UltrakillInstructions.GetHurt, EnemyIdentifierEmitters.LastHurtingFactor, AnchorMatchMode.All).Build();
}
}
[HarmonyPatch(typeof(LightningStrikeExplosive))]
public class LightningStrikeExplosivePatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(LightningStrikeExplosive), "Start")]
public static IEnumerable<CodeInstruction> LightningStrikeExplosive_Start_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterLocalStore(typeof(Explosion), (CodeInstruction explosionLoad, Type _) => EnemyIdentifierEmitters.RegisterExplosion(explosionLoad), AnchorMatchMode.First).Build();
}
}
[HarmonyPatch(typeof(MaliciousFace))]
public class MaliciousFacePatch
{
[HarmonyPostfix]
[HarmonyPatch(typeof(MaliciousFace), "ShootProj")]
public static void MaliciousFace_ShootProj_Postfix(GameObject ___currentProj, EnemyIdentifier ___eid)
{
if (!((Object)(object)___currentProj == (Object)null) && !((Object)(object)___eid == (Object)null))
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(___currentProj, ___eid);
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(MaliciousFace), "BeamFire")]
public static void MaliciousFace_BeamFire_Postfix(GameObject ___currentBeam, EnemyIdentifier ___eid)
{
RevolverBeam val = default(RevolverBeam);
if (!((Object)(object)___currentBeam == (Object)null) && !((Object)(object)___eid == (Object)null) && ___currentBeam.TryGetComponent<RevolverBeam>(ref val))
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)val).gameObject, ___eid);
}
}
}
[HarmonyPatch(typeof(Mandalore))]
public class MandalorePatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(Mandalore), "FullBurst")]
public static IEnumerable<CodeInstruction> Mandalore_FullBurst_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
List<CodeInstruction> list = instructions.ToList();
for (int i = 0; i < list.Count; i++)
{
if (FullAutoInjectionPoint(list[i]))
{
SetFullAutoHurtingFactor(list, i + 2, generator);
break;
}
}
return list;
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(Mandalore), "FullerBurst")]
public static IEnumerable<CodeInstruction> Mandalore_FullerBurst_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
List<CodeInstruction> list = instructions.ToList();
for (int i = 0; i < list.Count; i++)
{
if (FullerAutoInjectionPoint(list[i]))
{
SetFullerAutoHurtingFactor(list, i + 2, generator);
break;
}
}
return list;
}
private static bool FullAutoInjectionPoint(CodeInstruction instruction)
{
if (instruction.opcode == OpCodes.Stfld)
{
return CodeInstructionExtensions.OperandIs(instruction, (MemberInfo)AccessTools.Field(typeof(Projectile), "precheckForCollisions"));
}
return false;
}
private static bool FullerAutoInjectionPoint(CodeInstruction instruction)
{
if (instruction.opcode == OpCodes.Stfld)
{
return CodeInstructionExtensions.OperandIs(instruction, (MemberInfo)AccessTools.Field(typeof(Projectile), "safeEnemyType"));
}
return false;
}
private static void SetFullAutoHurtingFactor(List<CodeInstruction> instructions, int index, ILGenerator generator)
{
LocalBuilder item = generator.DeclareLocal(typeof(Projectile));
instructions.InsertRange(index, ReflectionUtils.IL((OpCodes.Stloc_S, item), (OpCodes.Call, AccessTools.Method(typeof(EnemyIdentifierManager), "get_Instance", (Type[])null, (Type[])null)), (OpCodes.Ldloc_S, item), (OpCodes.Callvirt, AccessTools.Method(typeof(Component), "get_gameObject", (Type[])null, (Type[])null)), (OpCodes.Ldarg_0, null), (OpCodes.Ldfld, AccessTools.Field(typeof(Mandalore), "eid")), (OpCodes.Callvirt, AccessTools.Method(typeof(EnemyIdentifierManager), "RegisterFactor", new Type[2]
{
typeof(GameObject),
typeof(EnemyIdentifier)
}, (Type[])null)), (OpCodes.Dup, null)));
}
private static void SetFullerAutoHurtingFactor(List<CodeInstruction> instructions, int index, ILGenerator generator)
{
LocalBuilder item = generator.DeclareLocal(typeof(Projectile));
instructions.InsertRange(index, ReflectionUtils.IL((OpCodes.Stloc_S, item), (OpCodes.Call, AccessTools.Method(typeof(EnemyIdentifierManager), "get_Instance", (Type[])null, (Type[])null)), (OpCodes.Ldloc_S, item), (OpCodes.Callvirt, AccessTools.Method(typeof(Component), "get_gameObject", (Type[])null, (Type[])null)), (OpCodes.Ldarg_0, null), (OpCodes.Ldfld, AccessTools.Field(typeof(Mandalore), "eid")), (OpCodes.Callvirt, AccessTools.Method(typeof(EnemyIdentifierManager), "RegisterFactor", new Type[2]
{
typeof(GameObject),
typeof(EnemyIdentifier)
}, (Type[])null)), (OpCodes.Dup, null)));
}
}
[HarmonyPatch(typeof(Mannequin))]
public class MannequinPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(Mannequin), "ShootProjectile")]
public static IEnumerable<CodeInstruction> Mannequin_ShootProjectile_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterStore(UltrakillInstructions.ProjectileTarget, typeof(Projectile), EnemyIdentifierEmitters.RegisterHurtingFactor<Mannequin>).Build();
}
}
[HarmonyPatch(typeof(Mass))]
public class MassPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(Mass), "SlamImpact")]
private static IEnumerable<CodeInstruction> Mass_SlamImpact_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterLocalStore(typeof(PhysicalShockwave), EnemyIdentifierEmitters.RegisterHurtingFactor<Mass>, AnchorMatchMode.First).Build();
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(Mass), "SwingEnd")]
private static IEnumerable<CodeInstruction> Mass_SwingEnd_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod, ILGenerator generator)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod, generator).AfterStack(UltrakillInstructions.GetComponent(typeof(PhysicalShockwave)), typeof(PhysicalShockwave), EnemyIdentifierEmitters.RegisterHurtingFactor<Mass>, AnchorMatchMode.First).Build();
}
}
[HarmonyPatch]
internal static class MassShootProjectilePatch
{
private static MethodBase TargetMethod()
{
return AccessTools.Method(typeof(Mass), "ShootProjectile", (Type[])null, (Type[])null);
}
[HarmonyPrepare]
public static bool Prepare()
{
return TargetMethod() != null;
}
[HarmonyTranspiler]
public static IEnumerable<CodeInstruction> Mass_ShootProjectile_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterStore(UltrakillInstructions.ProjectileTarget, typeof(Projectile), EnemyIdentifierEmitters.RegisterHurtingFactor<Mass>).Build();
}
}
[HarmonyPatch(typeof(MassSpear))]
public class MassSpearPatch
{
[HarmonyPrefix]
[HarmonyPatch(typeof(MassSpear), "DelayedPlayerCheck")]
private static bool Mass_ShootHoming_Prefix(bool ___deflected, MassSpear __instance)
{
if (___deflected)
{
return false;
}
MonoSingleton<EnemyIdentifierManager>.Instance.LastHurtingFactor = ((Component)__instance).gameObject;
return true;
}
}
[HarmonyPatch(typeof(Mindflayer))]
public class MindflayerPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(Mindflayer), "ShootProjectiles")]
public static IEnumerable<CodeInstruction> Mindflayer_ShootProjectiles_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterStore(UltrakillInstructions.ProjectileTarget, typeof(Projectile), EnemyIdentifierEmitters.RegisterHurtingFactor<Mindflayer>, AnchorMatchMode.All, 10).Build();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Mindflayer), "StartBeam")]
public static void Mindflayer_StartBeam_Postfix(EnemyIdentifier ___eid, Mindflayer __instance)
{
ContinuousBeam val = default(ContinuousBeam);
if (((Component)__instance.tempBeam).TryGetComponent<ContinuousBeam>(ref val))
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)val).gameObject, ___eid);
}
}
}
[HarmonyPatch(typeof(MinosPrime))]
public class MinosPrimePatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(MinosPrime), "AirRaycastAttack")]
public static IEnumerable<CodeInstruction> MinosPrime_AirRaycastAttack_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).Before(UltrakillInstructions.GetHurt, EnemyIdentifierEmitters.LastHurtingFactor).AfterStore(UltrakillInstructions.StoreTo(typeof(PhysicalShockwave), "damage"), typeof(PhysicalShockwave), EnemyIdentifierEmitters.RegisterHurtingFactor<MinosPrime>, AnchorMatchMode.Single, 10)
.Build();
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(MinosPrime), "ProjectileShoot")]
public static IEnumerable<CodeInstruction> MinosPrime_ProjectileShoot_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterStore(UltrakillInstructions.ProjectileTarget, typeof(Projectile), EnemyIdentifierEmitters.RegisterHurtingFactor<MinosPrime>, AnchorMatchMode.Single, 12).Build();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(MinosPrime), "Start")]
public static void MinosPrime_Start_Postfix(MinosPrime __instance, EnemyIdentifier ___eid)
{
Explosion[] componentsInChildren = __instance.explosion.GetComponentsInChildren<Explosion>();
for (int i = 0; i < componentsInChildren.Length; i++)
{
componentsInChildren[i].originEnemy = ___eid;
}
}
}
[HarmonyPatch(typeof(Minotaur))]
public class MinotaurPatch
{
[HarmonyPostfix]
[HarmonyPatch(typeof(Minotaur), "Start")]
public static void Minotaur_Start_Postfix(GameObject ___hammerExplosion, GameObject ___hammerBigExplosion, EnemyIdentifier ___eid)
{
Explosion[] componentsInChildren = ___hammerExplosion.GetComponentsInChildren<Explosion>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
componentsInChildren[i].originEnemy = ___eid;
}
componentsInChildren = ___hammerBigExplosion.GetComponentsInChildren<Explosion>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
componentsInChildren[i].originEnemy = ___eid;
}
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(Minotaur), "MeatSplash")]
public static IEnumerable<CodeInstruction> Minotaur_MeatSplash_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).Before(UltrakillInstructions.CallTo(typeof(Transform), "SetParent"), EnemyIdentifierEmitters.LastHurtingFactor).Build();
}
}
[HarmonyPatch(typeof(MirrorReaper))]
public class MirrorReaperPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(MirrorReaper), "SpawnProjectiles")]
public static IEnumerable<CodeInstruction> MirrorReaper_SpawnProjectiles_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterStore(UltrakillInstructions.ProjectileTarget, typeof(Projectile), EnemyIdentifierEmitters.RegisterHurtingFactor<MirrorReaper>).Build();
}
}
[HarmonyPatch(typeof(MortarLauncher))]
public class MortarLauncherPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(MortarLauncher), "ShootHoming")]
public static IEnumerable<CodeInstruction> MortarLauncher_ShootHoming_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
List<CodeInstruction> list = instructions.ToList();
for (int i = 0; i < list.Count; i++)
{
if (InjectionPoint(list[i]))
{
SetProjectileHurtingFactor(list, i + 2, generator);
break;
}
}
return list;
}
private static bool InjectionPoint(CodeInstruction instruction)
{
if (instruction.opcode == OpCodes.Stfld)
{
return CodeInstructionExtensions.OperandIs(instruction, (MemberInfo)AccessTools.Field(typeof(Projectile), "damage"));
}
return false;
}
private static void SetProjectileHurtingFactor(List<CodeInstruction> instructions, int index, ILGenerator generator)
{
LocalBuilder item = generator.DeclareLocal(typeof(Projectile));
instructions.InsertRange(index, ReflectionUtils.IL((OpCodes.Stloc_S, item), (OpCodes.Call, AccessTools.Method(typeof(EnemyIdentifierManager), "get_Instance", (Type[])null, (Type[])null)), (OpCodes.Ldloc_S, item), (OpCodes.Callvirt, AccessTools.Method(typeof(Component), "get_gameObject", (Type[])null, (Type[])null)), (OpCodes.Ldarg_0, null), (OpCodes.Ldfld, AccessTools.Field(typeof(MortarLauncher), "eid")), (OpCodes.Callvirt, AccessTools.Method(typeof(EnemyIdentifierManager), "RegisterFactor", new Type[2]
{
typeof(GameObject),
typeof(EnemyIdentifier)
}, (Type[])null)), (OpCodes.Dup, null)));
}
}
[HarmonyPatch(typeof(Nail))]
public class NailPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(Nail), "OnCollisionEnter")]
public static IEnumerable<CodeInstruction> Nail_OnCollisionEnter_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).Before(UltrakillInstructions.GetHurt, EnemyIdentifierEmitters.LastHurtingFactor).Build();
}
}
[HarmonyPatch(typeof(NewMovement))]
public class NewMovementPatch
{
public struct NewMovementPatchState
{
public bool Invincible;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(NewMovement), "GetHurt")]
public static void NewMovement_GetHurt_Postfix(NewMovement __instance, NewMovementPatchState __state, int damage)
{
try
{
EnemyIdentifierManager instance = MonoSingleton<EnemyIdentifierManager>.Instance;
if (!instance.DeadAlready && damage != 0 && !__state.Invincible)
{
EnemyIdentifier eid = instance.IdentifyEnemy();
bool flag = __instance.hp == 0;
if (flag)
{
instance.DeadAlready = true;
}
instance.PlayerHurt(eid, damage, flag);
}
}
catch (Exception)
{
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(NewMovement), "Respawn")]
public static void NewMovement_Respawn_Prefix(NewMovement __instance)
{
EnemyIdentifierManager instance = MonoSingleton<EnemyIdentifierManager>.Instance;
if (instance != null)
{
instance.DeadAlready = false;
}
}
}
[HarmonyPatch(typeof(Explosion))]
public class PhysicalShockwavePatch
{
[HarmonyPrefix]
[HarmonyPatch(typeof(PhysicalShockwave), "CheckCollision")]
public static bool PhysicalShockwave_CheckCollision_Prefix(Collider col, PhysicalShockwave __instance)
{
if (!__instance.hasHurtPlayer && ((Component)col).gameObject.layer != 15 && ((Component)col).gameObject.CompareTag("Player"))
{
MonoSingleton<EnemyIdentifierManager>.Instance.LastHurtingFactor = ((Component)__instance).gameObject;
}
return true;
}
}
[HarmonyPatch(typeof(Power))]
public class PowerPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(Power), "ThrowSpear")]
public static IEnumerable<CodeInstruction> Power_ThrowSpear_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterLocalStore(typeof(Projectile), EnemyIdentifierEmitters.RegisterHurtingFactor<Power>, AnchorMatchMode.First).Build();
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(Power), "ThrowSpinner")]
public static IEnumerable<CodeInstruction> Power_ThrowSpinner_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterLocalStore(typeof(Projectile), EnemyIdentifierEmitters.RegisterHurtingFactor<Power>, AnchorMatchMode.First).Build();
}
}
[HarmonyPatch(typeof(Projectile))]
public class ProjectilePatch
{
[HarmonyPrefix]
[HarmonyPatch(typeof(Projectile), "TimeToDie")]
public static bool Projectile_TimeToDie_Prefix(Projectile __instance)
{
MonoSingleton<EnemyIdentifierManager>.Instance.LastHurtingFactor = ((Component)__instance).gameObject;
return true;
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(Projectile), "Explode")]
public static IEnumerable<CodeInstruction> Projectile_Explode_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod, ILGenerator generator)
{
return PatchExplosions(instructions, __originalMethod, generator);
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(Projectile), "CreateExplosionEffect")]
public static IEnumerable<CodeInstruction> Projectile_CreateExplosionEffect_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod, ILGenerator generator)
{
return PatchExplosions(instructions, __originalMethod, generator);
}
private static IEnumerable<CodeInstruction> PatchExplosions(IEnumerable<CodeInstruction> instructions, MethodBase originalMethod, ILGenerator generator)
{
return TranspilerBuilder.ForInstructions(instructions, originalMethod, generator).AfterStack(UltrakillInstructions.Instantiate, typeof(GameObject), RegisterEffectZones).AfterLocalStore(typeof(Explosion), SetExplosionOrigin, AnchorMatchMode.Optional)
.Build();
}
private static IEnumerable<CodeInstruction> RegisterEffectZones(LocalBuilder effect, Type _)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Expected O, but got Unknown
return new List<CodeInstruction>
{
new CodeInstruction(OpCodes.Ldloc, (object)effect)
}.Concat(ReflectionUtils.IL((OpCodes.Call, AccessTools.Method(typeof(EnemyIdentifierManager), "get_Instance", (Type[])null, (Type[])null)), (OpCodes.Ldarg_0, null), (OpCodes.Callvirt, AccessTools.Method(typeof(EnemyIdentifierManager), "GetIdentifierFor", new Type[1] { typeof(Component) }, (Type[])null)), (OpCodes.Call, AccessTools.Method(typeof(ProjectilePatch), "RegisterEffectZones", new Type[2]
{
typeof(GameObject),
typeof(EnemyIdentifier)
}, (Type[])null))));
}
private static IEnumerable<CodeInstruction> SetExplosionOrigin(CodeInstruction explosionLoad, Type _)
{
return new List<CodeInstruction> { explosionLoad }.Concat(ReflectionUtils.IL((OpCodes.Call, AccessTools.Method(typeof(EnemyIdentifierManager), "get_Instance", (Type[])null, (Type[])null)), (OpCodes.Ldarg_0, null), (OpCodes.Callvirt, AccessTools.Method(typeof(EnemyIdentifierManager), "GetIdentifierFor", new Type[1] { typeof(Component) }, (Type[])null)), (OpCodes.Stfld, AccessTools.Field(typeof(Explosion), "originEnemy"))));
}
private static void RegisterEffectZones(GameObject effect, EnemyIdentifier eid)
{
if (!((Object)(object)effect == (Object)null) && !((Object)(object)eid == (Object)null))
{
HurtZone[] componentsInChildren = effect.GetComponentsInChildren<HurtZone>(true);
foreach (HurtZone val in componentsInChildren)
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)val).gameObject, eid);
}
}
}
}
[HarmonyPatch(typeof(ProjectileSpread))]
public class ProjectileSpreadPatch
{
[HarmonyPrefix]
[HarmonyPatch(typeof(ProjectileSpread), "Start")]
private static bool ProjectileSpread_Start_Prefix(ProjectileSpread __instance, ref EnemyIdentifier __state)
{
EnemyIdentifier identifierFor = MonoSingleton<EnemyIdentifierManager>.Instance.GetIdentifierFor((Component)(object)((Component)__instance).GetComponentInChildren<Projectile>());
if ((Object)(object)identifierFor != (Object)null)
{
__state = identifierFor;
}
return true;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(ProjectileSpread), "Start")]
private static void ProjectileSpread_Start_Postfix(ProjectileSpread __instance, EnemyIdentifier __state)
{
if (!((Object)(object)__state == (Object)null))
{
Projectile[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<Projectile>();
foreach (Projectile val in componentsInChildren)
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)val).gameObject, __state);
}
}
}
}
[HarmonyPatch(typeof(RevolverBeam))]
public class RevolverBeamPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(RevolverBeam), "ExecuteHits")]
public static IEnumerable<CodeInstruction> RevolverBeam_ExecuteHits_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).Before(UltrakillInstructions.GetHurt, EnemyIdentifierEmitters.LastHurtingFactor).Build();
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(RevolverBeam), "HitSomething")]
public static IEnumerable<CodeInstruction> RevolverBeam_HitSomething_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterLocalStore(typeof(Explosion), (CodeInstruction explosionLoad, Type _) => EnemyIdentifierEmitters.RegisterExplosion(explosionLoad), AnchorMatchMode.All).Build();
}
}
[HarmonyPatch(typeof(Sisyphus))]
public class SisyphusPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(Sisyphus), "FixedUpdate")]
public static IEnumerable<CodeInstruction> StatueBoss_FixedUpdate_Transpiler(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> list = instructions.ToList();
for (int i = 0; i < list.Count; i++)
{
if (LandingWaveInjectionPoint(list[i]))
{
SetWaveHurtingFactor(list, i + 1);
break;
}
}
return list;
}
private static bool LandingWaveInjectionPoint(CodeInstruction instruction)
{
if (instruction.opcode == OpCodes.Stfld)
{
return CodeInstructionExtensions.OperandIs(instruction, (MemberInfo)AccessTools.Field(typeof(PhysicalShockwave), "speed"));
}
return false;
}
private static void SetWaveHurtingFactor(List<CodeInstruction> instructions, int index)
{
instructions.InsertRange(index, ReflectionUtils.IL((OpCodes.Call, AccessTools.Method(typeof(EnemyIdentifierManager), "get_Instance", (Type[])null, (Type[])null)), (OpCodes.Ldloc_2, null), (OpCodes.Callvirt, AccessTools.Method(typeof(Component), "get_gameObject", (Type[])null, (Type[])null)), (OpCodes.Ldarg_0, null), (OpCodes.Ldfld, AccessTools.Field(typeof(Sisyphus), "eid")), (OpCodes.Callvirt, AccessTools.Method(typeof(EnemyIdentifierManager), "RegisterFactor", new Type[2]
{
typeof(GameObject),
typeof(EnemyIdentifier)
}, (Type[])null))));
}
}
[HarmonyPatch(typeof(SisyphusPrime))]
public class SisyphusPrimePatch
{
[HarmonyPostfix]
[HarmonyPatch(typeof(SisyphusPrime), "CreateShockwave")]
public static void SisyphusPrime_CreateShockwave_Postfix(EnemyIdentifier ___eid, ref PhysicalShockwave __result)
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)__result).gameObject, ___eid);
}
[HarmonyPostfix]
[HarmonyPatch(typeof(SisyphusPrime), "Start")]
public static void SisyphusPrime_Start_Postfix(SisyphusPrime __instance, EnemyIdentifier ___eid)
{
Explosion[] componentsInChildren = __instance.explosion.GetComponentsInChildren<Explosion>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
componentsInChildren[i].originEnemy = ___eid;
}
componentsInChildren = __instance.sparkleExplosion.GetComponentsInChildren<Explosion>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
componentsInChildren[i].originEnemy = ___eid;
}
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(SisyphusPrime), "DropAttackActivate")]
public static IEnumerable<CodeInstruction> SisyphusPrime_DropAttackActivate_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).Before(UltrakillInstructions.GetHurt, EnemyIdentifierEmitters.LastHurtingFactor).AfterStore(UltrakillInstructions.StoreTo(typeof(PhysicalShockwave), "damage"), typeof(PhysicalShockwave), EnemyIdentifierEmitters.RegisterHurtingFactor<SisyphusPrime>, AnchorMatchMode.Single, 10)
.Build();
}
}
[HarmonyPatch(typeof(StatueBoss))]
public class StatueBossPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(StatueBoss), "OrbSpawn")]
public static IEnumerable<CodeInstruction> StatueBoss_OrbSpawn_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return RegisterAfter(instructions, __originalMethod, (CodeInstruction instruction) => instruction.opcode == OpCodes.Stfld && CodeInstructionExtensions.OperandIs(instruction, (MemberInfo)AccessTools.Field(typeof(Projectile), "target")), typeof(Projectile));
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(StatueBoss), "StompHit")]
public static IEnumerable<CodeInstruction> StatueBoss_StompHit_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return RegisterAfter(instructions, __originalMethod, (CodeInstruction instruction) => instruction.opcode == OpCodes.Stfld && CodeInstructionExtensions.OperandIs(instruction, (MemberInfo)AccessTools.Field(typeof(PhysicalShockwave), "enemyType")), typeof(PhysicalShockwave));
}
private static IEnumerable<CodeInstruction> RegisterAfter(IEnumerable<CodeInstruction> instructions, MethodBase originalMethod, Func<CodeInstruction, bool> storePredicate, Type spawnedType)
{
List<CodeInstruction> list = instructions.ToList();
CodeInstruction val = null;
Type localType = null;
for (int i = 0; i < list.Count; i++)
{
if (ReflectionUtils.IsLdloc(list[i]))
{
Type type = ReflectionUtils.LocalType(originalMethod, ReflectionUtils.GetLocalIndex(list[i]));
if (type != null && spawnedType.IsAssignableFrom(type))
{
val = list[i];
localType = type;
}
}
if (storePredicate(list[i]) && val != null)
{
CodeInstruction val2 = ReflectionUtils.MirrorLdloc(val);
if (val2 != null)
{
list.InsertRange(i + 1, ReflectionUtils.IL((OpCodes.Call, AccessTools.Method(typeof(EnemyIdentifierManager), "get_Instance", (Type[])null, (Type[])null))).Concat(ReflectionUtils.ToGameObject(val2, localType)).Concat(ReflectionUtils.IL((OpCodes.Ldarg_0, null), (OpCodes.Ldfld, AccessTools.Field(typeof(StatueBoss), "eid")), (OpCodes.Callvirt, AccessTools.Method(typeof(EnemyIdentifierManager), "RegisterFactor", new Type[2]
{
typeof(GameObject),
typeof(EnemyIdentifier)
}, (Type[])null)))));
}
break;
}
}
return list;
}
}
[HarmonyPatch(typeof(SwingCheck2))]
public class SwingCheck2Patch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(SwingCheck2), "CheckCollision")]
public static IEnumerable<CodeInstruction> SwingCheck2_CheckCollision_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).Before(UltrakillInstructions.GetHurt, EnemyIdentifierEmitters.LastHurtingFactor).Build();
}
}
[HarmonyPatch(typeof(Turret))]
public class TurretPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(Turret), "Shoot")]
public static IEnumerable<CodeInstruction> Turret_Shoot_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).AfterStore(UltrakillInstructions.StoreTo(typeof(RevolverBeam), "target"), typeof(RevolverBeam), EnemyIdentifierEmitters.RegisterHurtingFactor<Turret>).Build();
}
}
[HarmonyPatch(typeof(V2))]
public class V2Patch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(V2), "ThrowCoins")]
public static IEnumerable<CodeInstruction> V2_ThrowCoins_Transpiler(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> list = instructions.ToList();
for (int i = 0; i < list.Count; i++)
{
if (InjectionPoint(list[i]))
{
SetCoinEnemyId(list, i + 9);
break;
}
}
return list;
}
private static bool InjectionPoint(CodeInstruction instruction)
{
if (instruction.opcode == OpCodes.Ldfld)
{
return CodeInstructionExtensions.OperandIs(instruction, (MemberInfo)AccessTools.Field(typeof(Coin), "flash"));
}
return false;
}
private static void SetCoinEnemyId(List<CodeInstruction> instructions, int index)
{
instructions.InsertRange(index, ReflectionUtils.IL((OpCodes.Ldloc_2, null), (OpCodes.Ldarg_0, null), (OpCodes.Ldfld, AccessTools.Field(typeof(V2), "eid")), (OpCodes.Stfld, AccessTools.Field(typeof(Coin), "eid"))));
}
}
[HarmonyPatch(typeof(VirtueInsignia))]
public class VirtueInsigniaPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(VirtueInsignia), "OnTriggerEnter")]
public static IEnumerable<CodeInstruction> VirtueInsignia_OnTriggerEnter_Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
return TranspilerBuilder.ForInstructions(instructions, __originalMethod).Before(UltrakillInstructions.GetHurt, EnemyIdentifierEmitters.LastHurtingFactor).Build();
}
}
[HarmonyPatch(typeof(ZombieProjectiles))]
public class ZombieProjectilesPatch
{
[HarmonyPostfix]
[HarmonyPatch(typeof(ZombieProjectiles), "ThrowProjectile")]
public static void ZombieProjectiles_ThrowProjectile_Postfix(GameObject ___currentProjectile, EnemyIdentifier ___eid, ZombieProjectiles __instance)
{
Projectile componentInChildren = ___currentProjectile.gameObject.GetComponentInChildren<Projectile>();
if ((Object)(object)componentInChildren == (Object)null)
{
return;
}
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)componentInChildren).gameObject, ___eid);
ProjectileSpread val = default(ProjectileSpread);
if (___currentProjectile.TryGetComponent<ProjectileSpread>(ref val))
{
Projectile[] componentsInChildren = ___currentProjectile.GetComponentsInChildren<Projectile>();
foreach (Projectile val2 in componentsInChildren)
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)val2).gameObject, ___eid);
}
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(ZombieProjectiles), "ShootProjectile")]
public static void ZombieProjectiles_ShootProjectile_Postfix(GameObject ___currentProjectile, EnemyIdentifier ___eid, ZombieProjectiles __instance)
{
if (!((Object)(object)___currentProjectile == (Object)null))
{
Projectile val = default(Projectile);
if (___currentProjectile.TryGetComponent<Projectile>(ref val))
{
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)val).gameObject, ___eid);
}
ProjectileSpread val2 = default(ProjectileSpread);
if (___currentProjectile.TryGetComponent<ProjectileSpread>(ref val2))
{
ProjectileSpread componentInChildren = ((Component)val2).GetComponentInChildren<ProjectileSpread>();
MonoSingleton<EnemyIdentifierManager>.Instance.RegisterFactor(((Component)componentInChildren).gameObject, ___eid);
}
}
}
}
}
namespace UKEnemyIdentifier.Components
{
[ConfigureSingleton(/*Could not decode attribute arguments.*/)]
public class EnemyIdentifierManager : MonoSingleton<EnemyIdentifierManager>
{
public class PlayerHurtEvent
{
public EnemyIdentifier EnemyId;
public bool PlayerIsKilled;
public int Damage;
}
public delegate void PlayerHurtEventDelegate(PlayerHurtEvent data);
internal bool DeadAlready;
internal GameObject LastHurtingFactor;
private List<(GameObject go, EnemyIdentifier eid)> _killingFactorByOrigin = new List<(GameObject, EnemyIdentifier)>();
public event PlayerHurtEventDelegate OnPlayerHurt;
private void Start()
{
SceneManager.sceneLoaded += delegate
{
DeadAlready = false;
};
((MonoBehaviour)this).InvokeRepeating("ListCleanup", 1f, 1f);
}
private void ListCleanup()
{
_killingFactorByOrigin = _killingFactorByOrigin.Where(((GameObject go, EnemyIdentifier eid) e) => (Object)(object)e.go != (Object)null && (Object)(object)e.eid != (Object)null).ToList();
}
private void Update()
{
LastHurtingFactor = null;
}
internal void RegisterFactor(GameObject factor, EnemyIdentifier emitter)
{
_killingFactorByOrigin.Add((factor, emitter));
if ((Object)(object)factor == (Object)null || (Object)(object)emitter == (Object)null)
{
return;
}
foreach (Explosion item in from explosion in factor.GetComponentsInChildren<Explosion>(true)
where (Object)(object)explosion.originEnemy == (Object)null
select explosion)
{
item.originEnemy = emitter;
}
HurtZone[] componentsInChildren = factor.GetComponentsInChildren<HurtZone>(true);
foreach (HurtZone val in componentsInChildren)
{
_killingFactorByOrigin.Add((((Component)val).gameObject, emitter));
}
ContinuousBeam[] componentsInChildren2 = factor.GetComponentsInChildren<ContinuousBeam>(true);
foreach (ContinuousBeam val2 in componentsInChildren2)
{
_killingFactorByOrigin.Add((((Component)val2).gameObject, emitter));
}
RevolverBeam[] componentsInChildren3 = factor.GetComponentsInChildren<RevolverBeam>(true);
foreach (RevolverBeam val3 in componentsInChildren3)
{
_killingFactorByOrigin.Add((((Component)val3).gameObject, emitter));
}
}
internal EnemyIdentifier GetIdentifierFor(Component component)
{
return (from pair in _killingFactorByOrigin
where (Object)(object)pair.go == (Object)(object)component.gameObject
select pair.eid).FirstOrDefault();
}
internal void RegisterExplosion(Component component, Explosion explosion)
{
EnemyIdentifier identifierFor = GetIdentifierFor(component);
if (!((Object)(object)identifierFor == (Object)null))
{
explosion.originEnemy = identifierFor;
}
}
internal EnemyIdentifier IdentifyEnemy()
{
if ((Object)(object)LastHurtingFactor == (Object)null)
{
return null;
}
if (!EnemyItselfIsDamagingFactor(out var identifier) && !EnemyIdStoredInDictionary(out identifier) && !LookForEnemyIdInDamagingFactor(out identifier))
{
return null;
}
return identifier;
}
private bool EnemyIdStoredInDictionary(out EnemyIdentifier identifier)
{
Projectile val = default(Projectile);
PhysicalShockwave val2 = default(PhysicalShockwave);
MassSpear val3 = default(MassSpear);
RevolverBeam val4 = default(RevolverBeam);
ContinuousBeam val5 = default(ContinuousBeam);
Nail val6 = default(Nail);
HurtZone val7 = default(HurtZone);
BlackHoleProjectile val8 = default(BlackHoleProjectile);
if (LastHurtingFactor.TryGetComponent<Projectile>(ref val) || LastHurtingFactor.TryGetComponent<PhysicalShockwave>(ref val2) || LastHurtingFactor.TryGetComponent<MassSpear>(ref val3) || LastHurtingFactor.TryGetComponent<RevolverBeam>(ref val4) || LastHurtingFactor.TryGetComponent<ContinuousBeam>(ref val5) || LastHurtingFactor.TryGetComponent<Nail>(ref val6) || LastHurtingFactor.TryGetComponent<HurtZone>(ref val7) || LastHurtingFactor.TryGetComponent<BlackHoleProjectile>(ref val8))
{
identifier = FindByHurtingFactor((Object)(object)LastHurtingFactor);
return true;
}
identifier = null;
return false;
EnemyIdentifier FindByHurtingFactor(Object go)
{
return (from pair in _killingFactorByOrigin
where (Object)(object)pair.go == go
select pair.eid).FirstOrDefault();
}
}
private bool EnemyItselfIsDamagingFactor(out EnemyIdentifier identifier)
{
MinosPrime minos = default(MinosPrime);
if (LastHurtingFactor.TryGetComponent<MinosPrime>(ref minos))
{
return Found(() => ReflectionUtils.GetPrivate<EnemyIdentifier>(minos, "eid"), out identifier);
}
SisyphusPrime sissy = default(SisyphusPrime);
if (LastHurtingFactor.TryGetComponent<SisyphusPrime>(ref sissy))
{
return Found(() => ReflectionUtils.GetPrivate<EnemyIdentifier>(sissy, "eid"), out identifier);
}
GabrielSecond gabrielSecond = default(GabrielSecond);
if (LastHurtingFactor.TryGetComponent<GabrielSecond>(ref gabrielSecond))
{
return Found(() => ReflectionUtils.GetPrivate<EnemyIdentifier>(gabrielSecond, "eid"), out identifier);
}
identifier = null;
return false;
static bool Found(Func<EnemyIdentifier> callback, out EnemyIdentifier i)
{
i = callback();
return true;
}
}
private bool LookForEnemyIdInDamagingFactor(out EnemyIdentifier identifier)
{
SwingCheck2 swingCheck = default(SwingCheck2);
if (LastHurtingFactor.TryGetComponent<SwingCheck2>(ref swingCheck))
{
return Found(() => swingCheck.eid, out identifier);
}
Explosion explosion = default(Explosion);
if (LastHurtingFactor.TryGetComponent<Explosion>(ref explosion))
{
return Found(() => explosion.originEnemy, out identifier);
}
FireZone thisFffire = default(FireZone);
if (LastHurtingFactor.TryGetComponent<FireZone>(ref thisFffire))
{
return Found(() => ((int)thisFffire.source != 1) ? null : ReflectionUtils.GetPrivate<Streetcleaner>(thisFffire, "sc").eid, out identifier);
}
VirtueInsignia virtueBeam = default(VirtueInsignia);
if (LastHurtingFactor.TryGetComponent<VirtueInsignia>(ref virtueBeam))
{
return Found(() => ((Component)virtueBeam.parentEnemy).gameObject.GetComponent<EnemyIdentifier>(), out identifier);
}
Coin coin = default(Coin);
if (LastHurtingFactor.TryGetComponent<Coin>(ref coin))
{
return Found(() => ReflectionUtils.GetPrivate<EnemyIdentifier>(coin, "eid"), out identifier);
}
identifier = null;
return false;
static bool Found(Func<EnemyIdentifier> callback, out EnemyIdentifier i)
{
i = callback();
return true;
}
}
internal void PlayerHurt(EnemyIdentifier eid, int damage, bool playerKilled = false)
{
PlayerHurtEventDelegate playerHurtEventDelegate = this.OnPlayerHurt;
if (playerHurtEventDelegate == null)
{
return;
}
PlayerHurtEvent data = new PlayerHurtEvent
{
EnemyId = eid,
PlayerIsKilled = playerKilled,
Damage = damage
};
Delegate[] invocationList = playerHurtEventDelegate.GetInvocationList();
foreach (Delegate obj in invocationList)
{
try
{
((PlayerHurtEventDelegate)obj)(data);
}
catch (Exception)
{
}
}
}
}
}