Decompiled source of UltraMisery v0.1.0
BepInEx/plugins/UltraMisery/UltraMisery.dll
Decompiled 20 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using ULTRAKILL.Cheats; using ULTRAKILL.Enemy; using ULTRAKILL.Portal; using UnityEngine; using UnityEngine.AI; using UnityEngine.AddressableAssets; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("UltraMisery")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("UltraMisery")] [assembly: AssemblyTitle("UltraMisery")] [assembly: AssemblyVersion("1.0.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 UltraMisery { internal static class AiAttackCorrections { private sealed class Burst { internal bool Active; } private static readonly ConditionalWeakTable<Turret, Burst> Bursts = new ConditionalWeakTable<Turret, Burst>(); internal static void SetBurst(Turret sentry, bool active) { Bursts.GetOrCreateValue(sentry).Active = active; } internal static bool InBurst(Turret sentry) { if (UltraMiseryState.IsActive && Bursts.TryGetValue(sentry, out var value)) { return value.Active; } return false; } internal static EnemyIdentifier Target(Component shooter) { if (!LifestealRules.AiCombatAllowed || !Object.op_Implicit((Object)(object)shooter)) { return null; } EnemyIdentifier component = shooter.GetComponent<EnemyIdentifier>(); EnemyTarget val = ((Object.op_Implicit((Object)(object)component) && !component.dead) ? component.target : null); if (val == null || !val.isValid || !val.isEnemy) { return null; } return val.enemyIdentifier; } internal static Vector3 Aim(EnemyIdentifier target, Component shooter) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) Enemy component = ((Component)target).GetComponent<Enemy>(); return LargeBossTargetRules.Aim((Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.chest)) ? component.chest.transform.position : (Object.op_Implicit((Object)(object)target.overrideCenter) ? target.overrideCenter.position : ((Component)target).transform.position), shooter); } } [HarmonyPatch(typeof(Streetcleaner), "Update")] internal static class StreetcleanerResumeNavigationPatch { private static void Prefix(EnemyIdentifier ___eid, NavMeshAgent ___nma, bool ___dead, bool ___dodging) { if (!(!UltraMiseryState.IsActive || ___dead || ___dodging) && Object.op_Implicit((Object)(object)___eid) && ___eid.target != null && ___eid.target.isValid && Object.op_Implicit((Object)(object)___nma) && ((Behaviour)___nma).enabled && ___nma.isOnNavMesh && !___nma.isOnOffMeshLink) { ___nma.isStopped = false; } } } [HarmonyPatch(typeof(Guttertank), "UpdateLineOfSightTimer")] internal static class GuttertankDirectTargetRecoveryPatch { private static void Prefix(TargetHandle ___targetHandle, ref Vector3 ___lastDimensionalTarget) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (UltraMiseryState.IsActive && ___targetHandle != (TargetHandle)null && ((PortalHandleSequence)(ref ___targetHandle.portals)).Count == 0 && DroneTargetRules.IsLive(___targetHandle.target)) { ___lastDimensionalTarget = Vector3.zero; } } } [HarmonyPatch(typeof(Streetcleaner), "UpdateVision")] internal static class StreetcleanerDirectTargetRecoveryPatch { private static void Postfix(TargetHandle ___targetHandle, ref Vector3 ___lastDimensionalTarget) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (UltraMiseryState.IsActive && ___targetHandle != (TargetHandle)null && ((PortalHandleSequence)(ref ___targetHandle.portals)).Count == 0 && DroneTargetRules.IsLive(___targetHandle.target)) { ___lastDimensionalTarget = Vector3.zero; } } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class StreetcleanerVisionSafetyPatch { private static bool Prefix(Streetcleaner __instance, Enemy ___mach, ref Vector3 __result) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (!UltraMiseryState.IsActive || (Object.op_Implicit((Object)(object)___mach) && Object.op_Implicit((Object)(object)___mach.chest))) { return true; } __result = ((Component)__instance).transform.position + Vector3.up; return false; } } [HarmonyPatch(typeof(Turret), "AimAt")] internal static class SentryBodyAimPatch { private static void Prefix(Turret __instance, ref Vector3 position, ref Vector3 direction, ref float distance, PortalTraversalV2[] traversals) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) EnemyIdentifier val = AiAttackCorrections.Target((Component)(object)__instance); if (Object.op_Implicit((Object)(object)val) && (traversals == null || traversals.Length == 0)) { position = AiAttackCorrections.Aim(val, (Component)(object)__instance); Vector3 val2 = position - ((EnemyScript)__instance).VisionSourcePosition; direction = ((Vector3)(ref val2)).normalized; distance = ((Vector3)(ref val2)).magnitude; } } } [HarmonyPatch(typeof(Turret), "Shoot")] internal static class SentryShotAimPatch { private static void Prefix(Turret __instance, bool ___isBarrelPortalCrossed, Transform ___barrelTip, ref Quaternion ___shootRotation) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) EnemyIdentifier val = AiAttackCorrections.Target((Component)(object)__instance); if (!(!Object.op_Implicit((Object)(object)val) || ___isBarrelPortalCrossed) && Object.op_Implicit((Object)(object)___barrelTip)) { Vector3 position = ((Component)__instance).transform.position; position.y = ___barrelTip.position.y; Vector3 val2 = AiAttackCorrections.Aim(val, (Component)(object)__instance) - position; if (((Vector3)(ref val2)).sqrMagnitude > 0.001f) { ___shootRotation = Quaternion.LookRotation(val2); } } } } [HarmonyPatch(typeof(Turret), "StopAction")] internal static class SentryKeepFiringStancePatch { private static bool Prefix(Turret __instance) { if (AiAttackCorrections.InBurst(__instance)) { return !SentryEndlessBurstPatch.HasLivingTarget(__instance); } return true; } } [HarmonyPatch(typeof(Turret), "Update")] internal static class SentryContinueAcrossTargetsPatch { private static void Postfix(Turret __instance, bool ___aiming, Animator ___anim, ref bool ___inAction) { if (!AiAttackCorrections.InBurst(__instance)) { return; } if (!SentryEndlessBurstPatch.HasLivingTarget(__instance)) { AiAttackCorrections.SetBurst(__instance, active: false); __instance.CancelAim(false); ___inAction = false; return; } ___inAction = true; if (Object.op_Implicit((Object)(object)___anim)) { ___anim.SetBool("Aiming", true); } if (!___aiming && !((MonoBehaviour)__instance).IsInvoking("PreReAim") && !((MonoBehaviour)__instance).IsInvoking("ReAim")) { ((MonoBehaviour)__instance).Invoke("PreReAim", 0.25f); } } } [HarmonyPatch(typeof(Turret), "OnDisable")] internal static class SentryResetBurstPatch { private static void Postfix(Turret __instance) { AiAttackCorrections.SetBurst(__instance, active: false); } } [HarmonyPatch(typeof(Minotaur), "RamStart")] internal static class MinotaurRamEnemyHitboxesPatch { private static void Postfix(Minotaur __instance, EnemyIdentifier ___eid, GameObject ___ramStuff) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) if (LifestealRules.AiCombatAllowed && Object.op_Implicit((Object)(object)___ramStuff) && Object.op_Implicit((Object)(object)___eid)) { (((Component)__instance).GetComponent<UltraMiseryRamSweep>() ?? ((Component)__instance).gameObject.AddComponent<UltraMiseryRamSweep>()).Begin(__instance, ___eid, ___ramStuff); SwingCheck2[] componentsInChildren = ___ramStuff.GetComponentsInChildren<SwingCheck2>(true); foreach (SwingCheck2 obj in componentsInChildren) { obj.eid = ___eid; obj.type = ___eid.enemyType; obj.startActive = true; obj.DamageStart(); } } } } internal sealed class UltraMiseryRamSweep : MonoBehaviour { private static readonly MethodInfo HitEnemy = AccessTools.Method(typeof(SwingCheck2), "CheckEidCollision", (Type[])null, (Type[])null); private readonly Collider[] overlaps = (Collider[])(object)new Collider[64]; private Minotaur minotaur; private EnemyIdentifier owner; private SwingCheck2[] checks; private Collider[] boxes; private Vector3 previous; internal void Begin(Minotaur source, EnemyIdentifier eid, GameObject ram) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) minotaur = source; owner = eid; if (checks == null) { checks = ram.GetComponentsInChildren<SwingCheck2>(true); boxes = (Collider[])(object)new Collider[checks.Length]; for (int i = 0; i < checks.Length; i++) { boxes[i] = ((Component)checks[i]).GetComponent<Collider>(); } if (checks.Length == 0) { Plugin.Log.LogWarning((object)"Minotaur ram has no native SwingCheck2 hitbox; inspect this prefab."); } } previous = ((Component)this).transform.position; } private void FixedUpdate() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)minotaur) || !Object.op_Implicit((Object)(object)owner) || owner.dead || !LifestealRules.AiCombatAllowed || minotaur.ramTimer <= 0f) { previous = ((Component)this).transform.position; return; } Vector3 val = ((Component)this).transform.position - previous; previous = ((Component)this).transform.position; for (int i = 0; i < checks.Length; i++) { if (!(minotaur.ramTimer > 0f)) { break; } SwingCheck2 val2 = checks[i]; Collider val3 = boxes[i]; if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)val3) || !val3.enabled || !((Component)val3).gameObject.activeInHierarchy) { continue; } Bounds bounds = val3.bounds; ((Bounds)(ref bounds)).Encapsulate(new Bounds(((Bounds)(ref bounds)).center - val, ((Bounds)(ref bounds)).size)); int num = Physics.OverlapBoxNonAlloc(((Bounds)(ref bounds)).center, ((Bounds)(ref bounds)).extents, overlaps, Quaternion.identity, 5120, (QueryTriggerInteraction)2); for (int j = 0; j < num; j++) { if (!(minotaur.ramTimer > 0f)) { break; } Collider val4 = overlaps[j]; overlaps[j] = null; EnemyIdentifier enemy = FriendlyFireRules.GetEnemy(val4); if (Object.op_Implicit((Object)(object)enemy) && !((Object)(object)enemy == (Object)(object)owner) && !enemy.dead) { Bounds bounds2 = val3.bounds; Vector3 center = ((Bounds)(ref bounds2)).center; bounds2 = val4.bounds; if (!Physics.Linecast(center, ((Bounds)(ref bounds2)).center, LayerMask.op_Implicit(LayerMaskDefaults.Get((LMD)1)), (QueryTriggerInteraction)1)) { HitEnemy.Invoke(val2, new object[2] { enemy, val4 }); } } } } } } internal static class AiCombatRules { internal static bool AllowsAiCombat(bool active, bool cheatsEnabled, bool enemiesAttackEachOther) { return active && cheatsEnabled && enemiesAttackEachOther; } internal static EnemyType CollisionExclusionType(EnemyType original) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (!LifestealRules.AiCombatAllowed) { return original; } return (EnemyType)(-1); } internal static bool SupportRole(EnemyIdentifier eid) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 if (!SupportEnemyCombatRules.IsSupport(eid)) { return (int)eid.enemyType == 12; } return true; } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class StrictAiCombatTargetGatePatch { [HarmonyPriority(0)] private static void Postfix(EnemyIdentifier __instance, ref bool __result) { if (UltraMiseryState.IsActive && !AiCombatRules.SupportRole(__instance)) { __result = LifestealRules.AiCombatAllowed && !BlindEnemies.Blind; } } } [HarmonyPatch(typeof(EnemyIdentifier), "Update")] internal static class RefreshAiCombatGatePatch { private static void Prefix(EnemyIdentifier __instance) { if (UltraMiseryState.IsActive && !__instance.dead) { bool aiCombatAllowed = LifestealRules.AiCombatAllowed; __instance.immuneToFriendlyFire = !aiCombatAllowed; if (!AiCombatRules.SupportRole(__instance) && __instance.target != null && ((aiCombatAllowed && __instance.target.isPlayer) || (!aiCombatAllowed && __instance.target.isEnemy))) { __instance.target = null; __instance.UpdateTarget(); } } } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class AiCombatIgnorePlayerPatch { [HarmonyPriority(0)] private static void Postfix(ref bool __result) { if (LifestealRules.AiCombatAllowed) { __result = true; } } } [HarmonyPatch(typeof(EnemyIdentifier), "IsTypeFriendly")] internal static class AiSameSpeciesTargetPatch { private static void Postfix(EnemyIdentifier __instance, EnemyIdentifier owner, ref bool __result) { if (LifestealRules.AiCombatAllowed) { __result = (Object)(object)__instance == (Object)(object)owner; } } } [HarmonyPatch] internal static class AiHurtExceptionsPatch { private static IEnumerable<MethodBase> TargetMethods() { return from m in typeof(EnemyIdentifier).GetMethods(BindingFlags.Static | BindingFlags.Public) where m.Name == "CheckHurtException" select m; } private static void Postfix(ref bool __result) { if (LifestealRules.AiCombatAllowed) { __result = false; } } } [HarmonyPatch] internal static class AiSameSpeciesCollisionPatch { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(Projectile), "Collided", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(SwingCheck2), "CheckEidCollision", (Type[])null, (Type[])null); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod) { bool projectile = __originalMethod.DeclaringType == typeof(Projectile); FieldInfo field = AccessTools.Field(__originalMethod.DeclaringType, projectile ? "safeEnemyType" : "type"); int index = 0; int replaced = 0; foreach (CodeInstruction instruction in instructions) { yield return instruction; if (instruction.opcode == OpCodes.Ldfld && object.Equals(instruction.operand, field) && index++ == (projectile ? 1 : 0)) { yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(AiCombatRules), "CollisionExclusionType", (Type[])null, (Type[])null)); replaced++; } } if (replaced != 1) { throw new InvalidOperationException("AI species collision hook changed: " + __originalMethod); } } } [HarmonyPatch(typeof(Projectile), "Collided")] internal static class AiProjectileNoSelfHitPatch { private static bool Prefix(Projectile __instance, Collider other) { if (!LifestealRules.AiCombatAllowed) { return true; } EnemyIdentifier enemy = FriendlyFireRules.GetEnemy(other); if (__instance.parried || __instance.playerBullet) { return true; } UltraMiseryAttackOwner componentInParent = ((Component)__instance).GetComponentInParent<UltraMiseryAttackOwner>(); EnemyIdentifier val = ((Object.op_Implicit((Object)(object)componentInParent) && Object.op_Implicit((Object)(object)componentInParent.Owner)) ? componentInParent.Owner : LifestealRules.Resolve((Component)(object)__instance)); if (Object.op_Implicit((Object)(object)enemy)) { return (Object)(object)enemy != (Object)(object)val; } return true; } } [HarmonyPatch] internal static class AiSameSpeciesBeamPatch { private static IEnumerable<MethodBase> TargetMethods() { return from m in typeof(RevolverBeam).GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == "PiercingShotCheck" || m.Name == "ExecuteHits" select m; } private static void Prefix(RevolverBeam __instance) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 if (LifestealRules.AiCombatAllowed && !__instance.deflected && ((int)__instance.beamType == 3 || (int)__instance.beamType == 2)) { EnemyIdentifier val = LifestealRules.Resolve((Component)(object)__instance); if (Object.op_Implicit((Object)(object)val) && !__instance.hitEids.Contains(val)) { __instance.hitEids.Add(val); } } } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { FieldInfo field = AccessTools.Field(typeof(RevolverBeam), "ignoreEnemyType"); int replaced = 0; foreach (CodeInstruction instruction in instructions) { yield return instruction; if (instruction.opcode == OpCodes.Ldfld && object.Equals(instruction.operand, field)) { yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(AiCombatRules), "CollisionExclusionType", (Type[])null, (Type[])null)); replaced++; } } if (replaced != 2) { throw new InvalidOperationException("Enemy hitscan species gate changed: " + replaced); } } } [HarmonyPatch(typeof(EnemyIdentifier), "DeliverDamage")] internal static class AiAttributedSelfDamageGuardPatch { private static bool Prefix(EnemyIdentifier __instance) { if (LifestealRules.AiCombatAllowed && Object.op_Implicit((Object)(object)LifestealRules.Attacker)) { return (Object)(object)LifestealRules.Attacker != (Object)(object)__instance; } return true; } } [HarmonyPatch] internal static class AiSameSpeciesOtherRangedPatch { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(ContinuousBeam), "FixedUpdate", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Nail), "HitEnemy", (Type[])null, (Type[])null); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod) { FieldInfo field = AccessTools.Field(__originalMethod.DeclaringType, "safeEnemyType"); int count = 0; foreach (CodeInstruction instruction in instructions) { yield return instruction; if (instruction.opcode == OpCodes.Ldfld && object.Equals(instruction.operand, field)) { yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(AiCombatRules), "CollisionExclusionType", (Type[])null, (Type[])null)); count++; } } if (count != ((__originalMethod.DeclaringType == typeof(Nail)) ? 1 : 2)) { throw new InvalidOperationException("Ranged species gate changed: " + __originalMethod); } } } [HarmonyPatch(typeof(SwingCheck2), "CheckEidCollision")] internal static class AiMeleeNoSelfHitPatch { private static bool Prefix(SwingCheck2 __instance, EnemyIdentifier enid) { if (!LifestealRules.AiCombatAllowed) { return true; } if ((Object)(object)__instance.eid == (Object)(object)enid) { return false; } if (Object.op_Implicit((Object)(object)__instance.eid)) { __instance.eid.immuneToFriendlyFire = false; } return true; } } internal sealed class UltraMiseryDuelWatch : MonoBehaviour { internal AiStalemateRules.Duel Duel; private void LateUpdate() { if (Duel != null) { if (!Duel.Valid) { Duel = null; } else { Duel.Sample(); } } } } internal static class AiStalemateRules { internal sealed class Duel { internal EnemyIdentifier A; internal EnemyIdentifier B; internal Enemy BodyA; internal Enemy BodyB; internal float Since; internal float LowWater; internal float Threshold; internal float NextSample; internal bool Damping; internal bool Valid { get { if (LifestealRules.AiCombatAllowed && Object.op_Implicit((Object)(object)A) && Object.op_Implicit((Object)(object)B) && Object.op_Implicit((Object)(object)BodyA) && Object.op_Implicit((Object)(object)BodyB) && !A.dead && !B.dead && A.target != null && B.target != null && (Object)(object)A.target.enemyIdentifier == (Object)(object)B) { return (Object)(object)B.target.enemyIdentifier == (Object)(object)A; } return false; } } internal void Sample() { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) if (!(Time.time < NextSample)) { NextSample = Time.time + 0.25f; float num = BodyA.health + BodyB.health; if (!Damping && num <= LowWater - Threshold) { Since = Time.time; LowWater = num; } if (!Damping && Time.time - Since >= 15f) { Damping = true; Plugin.Log.LogInfo((object)$"AI stalemate: reducing lifesteal/parry healing equally for {A.enemyType} #{((Object)A).GetInstanceID()} and {B.enemyType} #{((Object)B).GetInstanceID()} over 30 seconds."); } } } } internal static bool AllowsHitLifesteal(EnemyType attacker, EnemyType victim) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) return attacker != victim; } internal static float HealingScale(float elapsed) { return Math.Max(0f, Math.Min(1f, 1f - Math.Max(0f, elapsed - 15f) / 30f)); } internal static float Scale(EnemyIdentifier enemy) { if (!LifestealRules.AiCombatAllowed || !Object.op_Implicit((Object)(object)enemy) || enemy.target == null || !enemy.target.isEnemy) { return 1f; } EnemyIdentifier enemyIdentifier = enemy.target.enemyIdentifier; if (!Object.op_Implicit((Object)(object)enemyIdentifier) || (Object)(object)enemyIdentifier == (Object)(object)enemy || enemyIdentifier.dead || enemyIdentifier.target == null || (Object)(object)enemyIdentifier.target.enemyIdentifier != (Object)(object)enemy) { return 1f; } UltraMiseryDuelWatch ultraMiseryDuelWatch = ((Component)enemy).GetComponent<UltraMiseryDuelWatch>() ?? ((Component)enemy).gameObject.AddComponent<UltraMiseryDuelWatch>(); if (ultraMiseryDuelWatch.Duel != null && ultraMiseryDuelWatch.Duel.Valid) { if (!ultraMiseryDuelWatch.Duel.Damping) { return 1f; } return HealingScale(Time.time - ultraMiseryDuelWatch.Duel.Since); } UltraMiseryDuelWatch ultraMiseryDuelWatch2 = ((Component)enemyIdentifier).GetComponent<UltraMiseryDuelWatch>() ?? ((Component)enemyIdentifier).gameObject.AddComponent<UltraMiseryDuelWatch>(); Enemy component = ((Component)enemy).GetComponent<Enemy>(); Enemy component2 = ((Component)enemyIdentifier).GetComponent<Enemy>(); if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component2)) { return 1f; } Duel duel = new Duel { A = enemy, B = enemyIdentifier, BodyA = component, BodyB = component2, Since = Time.time, LowWater = component.health + component2.health, Threshold = Mathf.Max(0.01f, (LifestealRules.State(enemy).MaximumHealth + LifestealRules.State(enemyIdentifier).MaximumHealth) * 0.01f) }; ultraMiseryDuelWatch.Duel = (ultraMiseryDuelWatch2.Duel = duel); return 1f; } } internal static class AiTargetRecoveryRules { private sealed class Watch { internal EnemyIdentifier Target; internal EnemyIdentifier Replacement; internal float LastDamage; internal float FailedSince = -1f; internal float NextCheck; internal float HoldUntil; internal readonly Dictionary<EnemyIdentifier, float> Avoid = new Dictionary<EnemyIdentifier, float>(); } private static readonly ConditionalWeakTable<EnemyIdentifier, Watch> Watches = new ConditionalWeakTable<EnemyIdentifier, Watch>(); internal static bool TimedOut(float now, float lastDamage, float failedSince) { if (!(now - lastDamage >= 12f)) { if (failedSince >= 0f && now - failedSince >= 6f) { return now - lastDamage >= 6f; } return false; } return true; } private static bool Alive(EnemyIdentifier e) { if (Object.op_Implicit((Object)(object)e) && !e.dead) { return ((Component)e).gameObject.activeInHierarchy; } return false; } internal static bool Avoided(EnemyIdentifier owner, EnemyIdentifier candidate) { if (Watches.TryGetValue(owner, out var value) && Object.op_Implicit((Object)(object)candidate) && value.Avoid.TryGetValue(candidate, out var value2)) { return Time.time < value2; } return false; } internal static void Damage(EnemyIdentifier owner, EnemyIdentifier victim, float amount) { if (amount > 0f && Object.op_Implicit((Object)(object)owner) && Object.op_Implicit((Object)(object)victim) && Watches.TryGetValue(owner, out var value) && (Object)(object)value.Target == (Object)(object)victim) { value.LastDamage = Time.time; value.FailedSince = -1f; } } internal static void Apply(EnemyIdentifier owner) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Invalid comparison between Unknown and I4 //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Expected O, but got Unknown if (!LifestealRules.AiCombatAllowed || BlindEnemies.Blind || owner.dead || AiCombatRules.SupportRole(owner)) { Watches.Remove(owner); return; } Watch orCreateValue = Watches.GetOrCreateValue(owner); float time = Time.time; if (Alive(orCreateValue.Replacement) && time < orCreateValue.HoldUntil && Avoided(owner, owner.target?.enemyIdentifier)) { owner.target = new EnemyTarget(((Component)orCreateValue.Replacement).transform); } EnemyIdentifier val = owner.target?.enemyIdentifier; if (!Alive(val)) { orCreateValue.Target = null; return; } if ((Object)(object)orCreateValue.Target != (Object)(object)val) { orCreateValue.Target = val; orCreateValue.LastDamage = time; orCreateValue.FailedSince = -1f; } if (time < orCreateValue.NextCheck) { return; } orCreateValue.NextCheck = time + 0.5f; NavMeshAgent component = ((Component)owner).GetComponent<NavMeshAgent>(); if (owner.stationary || !Object.op_Implicit((Object)(object)component) || !((Behaviour)component).enabled || !component.isOnNavMesh || component.isOnOffMeshLink || component.isStopped || component.pathPending || (int)component.pathStatus <= 0) { orCreateValue.FailedSince = -1f; } else if (orCreateValue.FailedSince < 0f) { orCreateValue.FailedSince = time; } if (!TimedOut(time, orCreateValue.LastDamage, orCreateValue.FailedSince)) { return; } EnemyTracker instance = MonoSingleton<EnemyTracker>.Instance; if (!Object.op_Implicit((Object)(object)instance)) { return; } EnemyIdentifier val2 = null; float num = float.PositiveInfinity; foreach (EnemyIdentifier currentEnemy in instance.GetCurrentEnemies()) { if (Alive(currentEnemy) && !((Object)(object)currentEnemy == (Object)(object)owner) && !((Object)(object)currentEnemy == (Object)(object)val) && !currentEnemy.ignoredByEnemies && !Avoided(owner, currentEnemy)) { Vector3 val3 = ((Component)currentEnemy).transform.position - ((Component)owner).transform.position; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (!(sqrMagnitude >= num) && new EnemyTarget(((Component)currentEnemy).transform).isValid) { val2 = currentEnemy; num = sqrMagnitude; } } } if (!Object.op_Implicit((Object)(object)val2)) { orCreateValue.NextCheck = time + 2f; return; } List<EnemyIdentifier> list = new List<EnemyIdentifier>(); foreach (KeyValuePair<EnemyIdentifier, float> item in orCreateValue.Avoid) { if (!Alive(item.Key) || item.Value <= time) { list.Add(item.Key); } } foreach (EnemyIdentifier item2 in list) { orCreateValue.Avoid.Remove(item2); } orCreateValue.Avoid[val] = time + 20f; orCreateValue.Replacement = val2; orCreateValue.HoldUntil = time + 20f; orCreateValue.Target = val2; orCreateValue.LastDamage = time; orCreateValue.FailedSince = -1f; SupportEnemyCombatRules.EnsureVisionTarget(val2); owner.target = new EnemyTarget(((Component)val2).transform); } } [HarmonyPatch(typeof(EnemyIdentifier), "Update")] internal static class AiTargetRecoveryUpdatePatch { private static void Postfix(EnemyIdentifier __instance) { AiTargetRecoveryRules.Apply(__instance); } } internal static class AllEnemiesEnrageBridge { private const string PluginTypeName = "AllEnemiesEnragable.AllEnemiesEnragablePlugin"; private static bool resolved; private static FieldInfo forceEnrageField; private static MethodInfo enrageEnemyMethod; internal static bool TryGetForceEnrage(out bool value) { Resolve(); if (forceEnrageField == null) { value = false; return false; } value = (bool)forceEnrageField.GetValue(null); return true; } internal static bool TrySetForceEnrage(bool value) { Resolve(); if (forceEnrageField == null) { return false; } forceEnrageField.SetValue(null, value); return true; } internal static bool TryEnrageEnemy(EnemyIdentifier enemy) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) Resolve(); if (enrageEnemyMethod == null || !Object.op_Implicit((Object)(object)enemy) || enemy.dead) { return false; } try { enrageEnemyMethod.Invoke(null, new object[1] { enemy }); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)$"All-enemy enrage failed for {enemy.enemyType}: {ex.GetBaseException().Message}"); return false; } } private static void Resolve() { if (resolved) { return; } resolved = true; Type type = AccessTools.TypeByName("AllEnemiesEnragable.AllEnemiesEnragablePlugin"); if (type == null) { Plugin.Log.LogWarning((object)"AllEnemiesEnragable was not found; only enemies with native enrage support can be enraged."); return; } forceEnrageField = AccessTools.Field(type, "ForceEnrage"); enrageEnemyMethod = AccessTools.Method(type, "EnrageEnemy", new Type[1] { typeof(EnemyIdentifier) }, (Type[])null); if (forceEnrageField == null || enrageEnemyMethod == null) { Plugin.Log.LogWarning((object)"AllEnemiesEnragable was found, but its force-enrage API was not compatible."); } else { Plugin.Log.LogInfo((object)"Connected to AllEnemiesEnragable force-enrage API."); } } } internal static class AngryCompatibility { private const string Name = "ULTRAMISERY"; private static Type manager; private static Type difficulty; private static Type config; private static object entry; private static FieldInfo ukmdIndex; private static readonly BindingFlags All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; internal static void Install(Harmony harmony) { if (!Chainloader.PluginInfos.TryGetValue("com.eternalUnion.angryLevelLoader", out var value)) { return; } try { Assembly assembly = ((object)value.Instance).GetType().Assembly; manager = assembly.GetType("AngryLevelLoader.Managers.AngryDifficultyManager", throwOnError: true); difficulty = assembly.GetType("AngryLevelLoader.Managers.AngryDifficulty", throwOnError: true); config = assembly.GetType("AngryLevelLoader.Managers.ConfigManager", throwOnError: true); harmony.Patch((MethodBase)manager.GetMethod("Init", All), (HarmonyMethod)null, Hook("Register"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)difficulty.GetMethod("SetDifficulty", All), (HarmonyMethod)null, Hook("Apply"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)difficulty.GetMethod("UnsetDifficulty", All), (HarmonyMethod)null, Hook("Unset"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)manager.GetMethod("SetDifficultyFromPrefs", All), Hook("FromPrefs"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); GuardUkmdRegistration(harmony); if ((bool)manager.GetField("_inited", All).GetValue(null)) { Register(); } ((MonoBehaviour)Plugin.Instance).StartCoroutine(RefreshField()); } catch (Exception ex) { Plugin.Log.LogError((object)("Angry integration failed: " + ex)); } } private static HarmonyMethod Hook(string method) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown return new HarmonyMethod(typeof(AngryCompatibility).GetMethod(method, All)); } private static void GuardUkmdRegistration(Harmony harmony) { if (Chainloader.PluginInfos.TryGetValue("com.whyis2plus2.UKMDUnlocker", out var value)) { Type? type = ((object)value.Instance).GetType().Assembly.GetType("UKMDUnlocker.Compat.AngryFix"); MethodInfo methodInfo = type?.GetNestedType("Patches", BindingFlags.NonPublic)?.GetMethod("AddUKMDToDifficultyList", All); ukmdIndex = type?.GetField("ukmdIdx", All); if (methodInfo == null || ukmdIndex == null) { Plugin.Log.LogWarning((object)"UKMD Unlocker registration guard unavailable for this version."); } else { harmony.Patch((MethodBase)methodInfo, Hook("KeepSingleUkmd"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } } internal static int FindNamedEntry(IList list, FieldInfo nameField, string name) { for (int i = 0; i < list.Count; i++) { if ((string)nameField.GetValue(list[i]) == name) { return i; } } return -1; } private static bool KeepSingleUkmd() { int num = FindNamedEntry((IList)manager.GetField("difficulties", All).GetValue(null), difficulty.GetField("name", All), "UKMD"); if (num < 0) { return true; } ukmdIndex.SetValue(null, num); return false; } private static void Register() { IList list = (IList)manager.GetField("difficulties", All).GetValue(null); int num = FindNamedEntry(list, difficulty.GetField("name", All), "ULTRAMISERY"); if (num >= 0) { entry = list[num]; return; } entry = Activator.CreateInstance(difficulty, "ULTRAMISERY", 5); list.Add(entry); Plugin.Log.LogInfo((object)"Registered ULTRAMISERY in Angry Level Loader difficulty list (UKMD base)."); } private static IEnumerator RefreshField() { yield return null; object value = config.GetField("difficultyField", All).GetValue(null); if (value == null) { yield break; } object value2 = value.GetType().GetField("internalDifficultyField", All).GetValue(value); if (!((IList)value2.GetType().GetField("values", All).GetValue(value2)).Contains("ULTRAMISERY")) { value2.GetType().GetMethod("AddValue", All).Invoke(value2, new object[1] { "ULTRAMISERY" }); } object value3 = value.GetType().GetField("currentUi", All).GetValue(value); Object val = (Object)((value3 is Object) ? value3 : null); if (val != null && Object.op_Implicit(val)) { object? value4 = value3.GetType().GetField("difficultyList", All).GetValue(value3); Dropdown val2 = (Dropdown)((value4 is Dropdown) ? value4 : null); if (Object.op_Implicit((Object)(object)val2) && !val2.options.Exists((OptionData o) => o.text == "ULTRAMISERY")) { val2.AddOptions(new List<string> { "ULTRAMISERY" }); } } } private static void Apply(object __instance) { UltraMiseryState.SetSelected(__instance == entry); } private static void Unset(object __instance) { if (__instance == entry) { UltraMiseryState.SetSelected(selected: false); } } private static bool FromPrefs() { if (!UltraMiseryState.IsActive || entry == null) { return true; } manager.GetMethod("ForceSetDifficulty", All).Invoke(null, new object[1] { entry }); return false; } } internal static class AttackRecoveryRules { internal sealed class Timer { internal float Age; } private static readonly ConditionalWeakTable<Component, Timer> Timers = new ConditionalWeakTable<Component, Timer>(); internal static void Reset(Component component) { Timers.Remove(component); } internal static bool Expired(Component component, bool busy, Animator animator) { if (!UltraMiseryState.IsActive || !busy || !Object.op_Implicit((Object)(object)component) || !component.gameObject.activeInHierarchy) { Reset(component); return false; } Timer orCreateValue = Timers.GetOrCreateValue(component); if (Object.op_Implicit((Object)(object)animator) && ((Behaviour)animator).enabled && animator.speed > 0f) { orCreateValue.Age += Time.deltaTime * animator.speed; } if (orCreateValue.Age < 8f) { return false; } Reset(component); return true; } internal static void StopAudioIfPresent(AudioSource source) { if (Object.op_Implicit((Object)(object)source) || !UltraMiseryState.IsActive) { source.Stop(); } } } [HarmonyPatch] internal static class FreshAirborneAttackAnimationPatch { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(ZombieProjectiles), "Swing", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(ZombieMelee), "Swing", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Turret), "StartWindup", (Type[])null, (Type[])null); } private static void Prefix(EnemyScript __instance, Animator ___anim) { if (EnemyAwarenessRules.CanAttack((Component)(object)__instance)) { AttackRecoveryRules.Reset((Component)(object)__instance); Enemy component = ((Component)__instance).GetComponent<Enemy>(); if (Object.op_Implicit((Object)(object)component) && !component.grounded && Object.op_Implicit((Object)(object)___anim)) { ___anim.ResetTrigger("StartFalling"); ___anim.SetBool("Falling", false); } } } } [HarmonyPatch(typeof(ZombieProjectiles), "Update")] internal static class ProjectileHuskAttackRecoveryPatch { private static void Postfix(ZombieProjectiles __instance, EnemyIdentifier ___eid, Animator ___anim) { if (!Object.op_Implicit((Object)(object)___eid) || ___eid.dead) { AttackRecoveryRules.Reset((Component)(object)__instance); } else if (AttackRecoveryRules.Expired((Component)(object)__instance, __instance.swinging, ___anim)) { __instance.DamageEnd(); __instance.CancelAttack(); __instance.SwingEnd(); } } } [HarmonyPatch(typeof(ZombieMelee), "Update")] internal static class MeleeHuskAttackRecoveryPatch { private static void Postfix(ZombieMelee __instance, EnemyIdentifier ___eid, Animator ___anim, bool ___inAction) { if (!Object.op_Implicit((Object)(object)___eid) || ___eid.dead) { AttackRecoveryRules.Reset((Component)(object)__instance); } else if (AttackRecoveryRules.Expired((Component)(object)__instance, ___inAction || __instance.damaging, ___anim)) { __instance.DamageEnd(); __instance.CancelAttack(); __instance.SwingEnd(); } } } [HarmonyPatch(typeof(MaliciousFace), "Update")] internal static class MaliciousFaceMissingChargeAudioPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { MethodInfo stop = AccessTools.Method(typeof(AudioSource), "Stop", Type.EmptyTypes, (Type[])null); int count = 0; foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, stop)) { instruction.opcode = OpCodes.Call; instruction.operand = AccessTools.Method(typeof(AttackRecoveryRules), "StopAudioIfPresent", (Type[])null, (Type[])null); count++; } yield return instruction; } if (count != 1) { throw new InvalidOperationException("Malicious Face charge-audio hook changed: " + count); } } } [HarmonyPatch(typeof(SwordsMachine), "HeatSwordThrow")] internal static class SwordsmachineLostThrowTargetPatch { private static bool Prefix(SwordsMachine __instance, EnemyIdentifier ___eid, Animator ___anim) { if (!UltraMiseryState.IsActive || !Object.op_Implicit((Object)(object)___eid) || ___eid.dead) { return true; } if (___eid.target != null && ___eid.target.isValid) { return true; } ___eid.UpdateTarget(); if (___eid.target != null && ___eid.target.isValid) { return true; } __instance.DamageStop(); __instance.CoolSword(); __instance.StopAction(); if (Object.op_Implicit((Object)(object)___anim)) { ___anim.SetTrigger("AnimationCancel"); } return false; } } [HarmonyPatch(typeof(EnemyIdentifier), "PuppetSpawn")] internal static class BloodTreePuppetSpawnPatch { private static void Prefix(EnemyIdentifier __instance) { if (UltraMiseryState.IsActive && Object.op_Implicit((Object)(object)__instance) && __instance.sandified) { __instance.Desandify(false); } } } [HarmonyPatch(typeof(EnemyIdentifier), "Sandify")] internal static class BloodTreePuppetSandifyPatch { private static bool Prefix(EnemyIdentifier __instance) { if (!UltraMiseryState.IsActive || !Object.op_Implicit((Object)(object)__instance) || !__instance.puppet) { return true; } if (__instance.sandified) { __instance.Desandify(false); } return false; } } internal sealed class UltraMiseryMassCannon : MonoBehaviour { } internal static class BossAiAreaDamageRules { private sealed class Contacts { internal readonly HashSet<int> Victims = new HashSet<int>(); } private static readonly ConditionalWeakTable<PhysicalShockwave, Contacts> Hits = new ConditionalWeakTable<PhysicalShockwave, Contacts>(); internal static bool SlamAllowed(bool aiCombat, EnemyType source) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Invalid comparison between Unknown and I4 if (aiCombat) { return (int)source == 0; } return false; } internal static void DamageSlam(PhysicalShockwave wave, Collider col, EnemyIdentifier victim) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) if (!SlamAllowed(LifestealRules.AiCombatAllowed, wave.enemyType) || !wave.enemy || !Object.op_Implicit((Object)(object)victim) || victim.dead) { return; } EnemyIdentifier val = LifestealRules.Resolve((Component)(object)wave); if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val == (Object)(object)victim || (int)val.enemyType != 0 || wave.damage <= 0 || !Hits.GetOrCreateValue(wave).Victims.Add(((Object)victim).GetInstanceID())) { return; } EnemyIdentifier attacker = LifestealRules.Attacker; try { LifestealRules.Attacker = val; victim.hitter = "enemy"; GameObject gameObject = ((Component)col).gameObject; Vector3 zero = Vector3.zero; Bounds bounds = col.bounds; victim.DeliverDamage(gameObject, zero, ((Bounds)(ref bounds)).center, (float)wave.damage / 10f, false, 0f, (GameObject)null, false, false); } finally { LifestealRules.Attacker = attacker; } } } [HarmonyPatch(typeof(Explosion), "Collide")] internal static class MassCannonAiExplosionPatch { internal struct State { internal bool Changed; internal bool Enemy; internal bool FriendlyFire; internal AffectedSubjects CanHit; internal List<EnemyType> Ignore; } private static bool Prefix(Explosion __instance, Collider other, out State __state) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) __state = default(State); if (!LifestealRules.AiCombatAllowed || !Object.op_Implicit((Object)(object)((Component)__instance).GetComponentInParent<UltraMiseryMassCannon>())) { return true; } EnemyIdentifier enemy = FriendlyFireRules.GetEnemy(other); if (!Object.op_Implicit((Object)(object)enemy)) { return true; } EnemyIdentifier val = LifestealRules.Resolve((Component)(object)__instance); if (Object.op_Implicit((Object)(object)val) && (Object)(object)enemy == (Object)(object)val) { return false; } __state = new State { Changed = true, Enemy = __instance.enemy, FriendlyFire = __instance.friendlyFire, CanHit = __instance.canHit, Ignore = __instance.toIgnore }; __instance.enemy = false; __instance.friendlyFire = true; __instance.canHit = (AffectedSubjects)0; __instance.toIgnore = ((__instance.toIgnore == null) ? new List<EnemyType>() : new List<EnemyType>(__instance.toIgnore)); __instance.toIgnore.RemoveAll((EnemyType type) => (int)type == 2); return true; } private static void Finalizer(Explosion __instance, State __state) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (__state.Changed && Object.op_Implicit((Object)(object)__instance)) { __instance.enemy = __state.Enemy; __instance.friendlyFire = __state.FriendlyFire; __instance.canHit = __state.CanHit; __instance.toIgnore = __state.Ignore; } } } internal static class BoundaryRules { [HarmonyPatch(typeof(OutOfBounds), "OnTriggerEnter")] private static class AuthoredBoundaryPatch { private static void Prefix(OutOfBounds __instance, Collider other) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Invalid comparison between Unknown and I4 //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) NewMovement instance = MonoSingleton<NewMovement>.Instance; CheatsController instance2 = MonoSingleton<CheatsController>.Instance; if (Object.op_Implicit((Object)(object)other) && ((Component)other).CompareTag("Player") && ShouldRecord(UltraMiseryState.IsActive, SceneHelper.IsPlayingCustom, Object.op_Implicit((Object)(object)MonoSingleton<SandboxNavmesh>.Instance), Object.op_Implicit((Object)(object)instance2) && instance2.cheatsEnabled, Object.op_Implicit((Object)(object)instance) && instance.hp > 0 && !instance.levelOver, (int)__instance.targets != 2)) { int sceneHandle = BoundaryRules.sceneHandle; Scene activeScene = SceneManager.GetActiveScene(); if (sceneHandle != ((Scene)(ref activeScene)).handle) { Reset(); } if (!crossed) { crossed = true; Plugin.Log.LogWarning((object)("UltraMisery: player entered authored OutOfBounds volume without cheats; this run cannot receive P rank. Volume: " + ((Object)__instance).name)); } } } } private static int sceneHandle = -1; private static bool crossed; internal static bool InvalidRun { get { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) int num = sceneHandle; Scene activeScene = SceneManager.GetActiveScene(); if (num == ((Scene)(ref activeScene)).handle) { return crossed; } return false; } } internal static void Reset() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); sceneHandle = ((Scene)(ref activeScene)).handle; crossed = false; } internal static bool ShouldRecord(bool active, bool custom, bool sandbox, bool cheats, bool alive, bool playerVolume) { return active && !custom && !sandbox && !cheats && alive && playerVolume; } } internal static class ChandelierRules { internal static bool IsChandelierLabel(string value) { if (!string.IsNullOrEmpty(value)) { return value.IndexOf("chandelier", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } internal static bool Matches(Component hazard) { if (!UltraMiseryState.IsActive || !Object.op_Implicit((Object)(object)hazard)) { return false; } DeathZone val = (DeathZone)(object)((hazard is DeathZone) ? hazard : null); if (val != null && IsChandelierLabel(val.deathType)) { return true; } Transform val2 = hazard.transform; int num = 0; while (Object.op_Implicit((Object)(object)val2) && num < 4) { if (IsChandelierLabel(((Object)val2).name)) { return true; } num++; val2 = val2.parent; } return false; } } [HarmonyPatch(typeof(DeathZone), "GotHit")] internal static class ChandelierEnemyDeathImmunityPatch { private static bool Prefix(DeathZone __instance, Collider other) { if (Object.op_Implicit((Object)(object)FriendlyFireRules.GetEnemy(other))) { return !ChandelierRules.Matches((Component)(object)__instance); } return true; } } [HarmonyPatch(typeof(HurtZone), "DamageEnemy")] internal static class ChandelierEnemyDamageImmunityPatch { private static bool Prefix(HurtZone __instance, ref bool __result) { if (!ChandelierRules.Matches((Component)(object)__instance)) { return true; } __result = true; return false; } } [HarmonyPatch(typeof(Explosion), "Collide")] internal static class ChandelierEnemyExplosionImmunityPatch { private static bool Prefix(Explosion __instance, Collider other) { if (Object.op_Implicit((Object)(object)FriendlyFireRules.GetEnemy(other))) { return !ChandelierRules.Matches((Component)(object)__instance); } return true; } } internal static class CutsceneAttackLockRules { private static readonly HashSet<CutsceneSkip> Active = new HashSet<CutsceneSkip>(); private static readonly HashSet<V2> V2Intros = new HashSet<V2>(); internal static bool Locked { get { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (!UltraMiseryState.IsActive || SceneHelper.IsPlayingCustom || Object.op_Implicit((Object)(object)MonoSingleton<SandboxNavmesh>.Instance)) { return false; } if (!Object.op_Implicit((Object)(object)MonoSingleton<NewMovement>.Instance) || MonoSingleton<NewMovement>.Instance.dead) { return false; } Scene activeScene = SceneManager.GetActiveScene(); int scene = ((Scene)(ref activeScene)).handle; Active.RemoveWhere(delegate(CutsceneSkip item) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)item) && ((Behaviour)item).isActiveAndEnabled) { Scene scene2 = ((Component)item).gameObject.scene; return ((Scene)(ref scene2)).handle != scene; } return true; }); V2Intros.RemoveWhere(delegate(V2 item) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)item) && ((Behaviour)item).isActiveAndEnabled && item.inIntro) { Scene scene2 = ((Component)item).gameObject.scene; return ((Scene)(ref scene2)).handle != scene; } return true; }); if (Active.Count == 0) { return V2Intros.Count != 0; } return true; } } internal static void Track(V2 boss) { if (Object.op_Implicit((Object)(object)boss) && boss.inIntro) { V2Intros.Add(boss); } } internal static void Begin(CutsceneSkip cutscene) { Active.Add(cutscene); } internal static void End(CutsceneSkip cutscene) { Active.Remove(cutscene); } internal static bool IsAttack(string name) { switch (name) { default: return name == "Hook"; case "PrimaryFire": case "SecondaryFire": case "Punch": return true; } } } [HarmonyPatch(typeof(V2), "Start")] internal static class V2IntroAttackLockPatch { private static void Postfix(V2 __instance) { CutsceneAttackLockRules.Track(__instance); } } [HarmonyPatch(typeof(CutsceneSkip), "OnEnable")] internal static class CutsceneAttackLockBeginPatch { private static void Prefix(CutsceneSkip __instance) { CutsceneAttackLockRules.Begin(__instance); } } [HarmonyPatch(typeof(CutsceneSkip), "OnDisable")] internal static class CutsceneAttackLockEndPatch { private static void Prefix(CutsceneSkip __instance) { CutsceneAttackLockRules.End(__instance); } } [HarmonyPatch(typeof(CutsceneSkip), "LateUpdate")] internal static class CutsceneAttackLockSkipPatch { private static void Prefix(bool ___waitingForInput, out bool __state) { __state = ___waitingForInput; } private static void Postfix(CutsceneSkip __instance, bool ___waitingForInput, bool __state) { if (__state && !___waitingForInput) { CutsceneAttackLockRules.End(__instance); } } } [HarmonyPatch] internal static class CutsceneAttackInputPatch { private static IEnumerable<MethodBase> TargetMethods() { string[] array = new string[3] { "IsPressed", "WasPerformedThisFrame", "WasCanceledThisFrame" }; foreach (string text in array) { yield return AccessTools.PropertyGetter(typeof(InputActionState), text); } } private static void Postfix(InputActionState __instance, ref bool __result) { if (__result && CutsceneAttackLockRules.IsAttack(__instance.Action.name) && CutsceneAttackLockRules.Locked) { __result = false; } } } [HarmonyPatch] internal static class CutsceneWeaponEmissionPatch { private static IEnumerable<MethodBase> TargetMethods() { (Type, string[])[] array = new(Type, string[])[7] { (typeof(Revolver), new string[3] { "Shoot", "ThrowCoin", "Punch" }), (typeof(Shotgun), new string[3] { "Shoot", "ShootSinks", "ShootSaw" }), (typeof(ShotgunHammer), new string[3] { "Impact", "ThrowNade", "ShootSaw" }), (typeof(Nailgun), new string[3] { "Shoot", "ShootMagnet", "ShootZapper" }), (typeof(Railcannon), new string[1] { "Shoot" }), (typeof(RocketLauncher), new string[3] { "Shoot", "ShootCannonball", "ShootNapalm" }), (typeof(Punch), new string[1] { "PunchStart" }) }; for (int i = 0; i < array.Length; i++) { (Type, string[]) entry = array[i]; MethodInfo[] methods = entry.Item1.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (Array.IndexOf(entry.Item2, methodInfo.Name) >= 0) { yield return methodInfo; } } } } private static bool Prefix() { return !CutsceneAttackLockRules.Locked; } } internal static class DamageBonusRules { internal static readonly MethodInfo FactorMethod = typeof(DamageBonusRules).GetMethod("Factor", BindingFlags.Static | BindingFlags.NonPublic); internal static float InvertBonus(float factor) { if (!(factor > 1f)) { return factor; } return 1f / factor; } internal static float InvertCritical(float critical, float limb) { if (critical <= 0f || limb <= 0f) { return critical; } return (1f / (1f + limb * critical) - 1f) / limb; } internal static float Factor(float value) { if (!UltraMiseryState.IsActive) { return value; } return InvertBonus(value); } } [HarmonyPatch] internal static class InvertedEnemyLocationalBonusPatch { private static IEnumerable<MethodBase> TargetMethods() { Type[] array = new Type[4] { typeof(Enemy), typeof(Zombie), typeof(Machine), typeof(Statue) }; foreach (Type type in array) { yield return AccessTools.DeclaredMethod(type, "GetHurt", (Type[])null, (Type[])null); } } private static void Prefix(GameObject target, ref float critMultiplier) { if (UltraMiseryState.IsActive && Object.op_Implicit((Object)(object)target)) { float limb = (target.CompareTag("Head") ? 1f : ((target.CompareTag("Limb") || target.CompareTag("EndLimb")) ? 0.5f : 0f)); critMultiplier = DamageBonusRules.InvertCritical(critMultiplier, limb); } } } [HarmonyPatch(typeof(Nail), "GetFodderDamageMultiplier")] internal static class InvertedNailSpeciesBonusPatch { private static void Postfix(ref float __result) { __result = DamageBonusRules.Factor(__result); } } [HarmonyPatch(typeof(EnemyIdentifier), "DeliverDamage")] internal static class InvertedEnemyWeaknessBonusPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { bool weaknessElement = false; int count = 0; List<CodeInstruction> code = new List<CodeInstruction>(instructions); for (int i = 0; i < code.Count; i++) { CodeInstruction instruction = code[i]; yield return instruction; if (instruction.opcode == OpCodes.Ldfld && instruction.operand is FieldInfo { Name: "weaknessMultipliers" }) { weaknessElement = true; } bool num = weaknessElement && instruction.opcode == OpCodes.Ldelem_R4; if (num) { weaknessElement = false; } if (num | (instruction.opcode == OpCodes.Ldfld && instruction.operand is FieldInfo fieldInfo2 && fieldInfo2.Name == "totalDamageTakenMultiplier") | (instruction.opcode == OpCodes.Ldc_R4 && object.Equals(instruction.operand, 1.5f) && i + 1 < code.Count && code[i + 1].opcode == OpCodes.Mul)) { yield return new CodeInstruction(OpCodes.Call, (object)DamageBonusRules.FactorMethod); count++; } } if (count != 3) { throw new InvalidOperationException("Enemy damage modifier IL changed: " + count); } } } [HarmonyPatch] internal static class InvertedEnemyWeakSpotBonusPatch { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(Enemy), "CalculateDamage", (Type[])null, (Type[])null); yield return AccessTools.DeclaredMethod(typeof(Statue), "GetHurt", (Type[])null, (Type[])null); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod) { List<CodeInstruction> code = new List<CodeInstruction>(instructions); int count = 0; for (int i = 0; i < code.Count; i++) { yield return code[i]; if (code[i].opcode == OpCodes.Ldfld && code[i].operand is FieldInfo { Name: "extraDamageMultiplier" } && i + 1 < code.Count && code[i + 1].opcode == OpCodes.Mul) { yield return new CodeInstruction(OpCodes.Call, (object)DamageBonusRules.FactorMethod); count++; } } if (count != ((!(__originalMethod.DeclaringType == typeof(Statue))) ? 1 : 3)) { throw new InvalidOperationException("Weak-spot modifier IL changed: " + __originalMethod?.ToString() + " " + count); } } } [HarmonyPatch] internal static class InvertedAttackSpecificBonusPatch { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(Enemy), "HandleParrying", (Type[])null, (Type[])null); yield return AccessTools.DeclaredMethod(typeof(Zombie), "GetHurt", (Type[])null, (Type[])null); yield return AccessTools.DeclaredMethod(typeof(Machine), "GetHurt", (Type[])null, (Type[])null); yield return AccessTools.DeclaredMethod(typeof(Statue), "GetHurt", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Explosion), "Collide", (Type[])null, (Type[])null); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod) { List<CodeInstruction> code = new List<CodeInstruction>(instructions); Type owner = __originalMethod.DeclaringType; bool explosion = owner == typeof(Explosion); int count = 0; for (int i = 0; i < code.Count; i++) { CodeInstruction instruction = code[i]; yield return instruction; if (i + 1 < code.Count && !(code[i + 1].opcode != OpCodes.Mul) && ((instruction.opcode == OpCodes.Ldc_R4 && (object.Equals(instruction.operand, 2f) || (owner != typeof(Zombie) && object.Equals(instruction.operand, 1.5f)))) | (explosion && instruction.opcode == OpCodes.Ldfld && instruction.operand is FieldInfo fieldInfo && fieldInfo.Name == "enemyDamageMultiplier"))) { yield return new CodeInstruction(OpCodes.Call, (object)DamageBonusRules.FactorMethod); count++; } } int num = (explosion ? 4 : ((!(owner == typeof(Enemy))) ? 1 : 2)); if (count != num) { throw new InvalidOperationException("Attack bonus IL changed: " + __originalMethod?.ToString() + " " + count); } } } [HarmonyPatch] internal static class InvertedAirborneHuskBonusPatch { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.DeclaredMethod(typeof(Enemy), "GetHurt", (Type[])null, (Type[])null); yield return AccessTools.DeclaredMethod(typeof(Zombie), "GetHurt", (Type[])null, (Type[])null); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { bool found = false; foreach (CodeInstruction instruction in instructions) { yield return instruction; if (!found && instruction.opcode == OpCodes.Ldc_R4 && object.Equals(instruction.operand, 1.5f)) { yield return new CodeInstruction(OpCodes.Call, (object)DamageBonusRules.FactorMethod); found = true; } } if (!found) { throw new InvalidOperationException("Airborne husk modifier IL changed"); } } } [HarmonyPatch(typeof(EnemyIdentifier), "ProcessDeath")] internal static class RemoveGuttermanCorpsePatch { private static void Postfix(EnemyIdentifier __instance) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 if (UltraMiseryState.IsActive && __instance.dead && (int)__instance.enemyType == 33) { Collider[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<Collider>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].enabled = false; } Renderer[] componentsInChildren2 = ((Component)__instance).GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { componentsInChildren2[i].enabled = false; } Object.Destroy((Object)(object)((Component)__instance).gameObject); } } } [HarmonyPatch(typeof(Gutterman), "Start")] internal static class RemovePreDeadGuttermanPatch { private static void Postfix(Gutterman __instance) { if (UltraMiseryState.IsActive && __instance.dead) { Object.Destroy((Object)(object)((Component)__instance).gameObject); } } } internal sealed class UltraMiseryHiddenGuttermanCorpse : MonoBehaviour { private Renderer[] renderers; private Collider[] colliders; private bool[] rendererStates; private bool[] colliderStates; private EnemyIdentifier enemy; private void Awake() { enemy = ((Component)this).GetComponent<EnemyIdentifier>(); renderers = ((Component)this).GetComponentsInChildren<Renderer>(true); colliders = ((Component)this).GetComponentsInChildren<Collider>(true); rendererStates = Array.ConvertAll(renderers, (Renderer item) => item.enabled); colliderStates = Array.ConvertAll(colliders, (Collider item) => item.enabled); } private void LateUpdate() { if (Object.op_Implicit((Object)(object)enemy) && !enemy.dead) { for (int i = 0; i < renderers.Length; i++) { if (Object.op_Implicit((Object)(object)renderers[i])) { renderers[i].enabled = rendererStates[i]; } } for (int j = 0; j < colliders.Length; j++) { if (Object.op_Implicit((Object)(object)colliders[j])) { colliders[j].enabled = colliderStates[j]; } } Object.Destroy((Object)(object)this); return; } Renderer[] array = renderers; foreach (Renderer val in array) { if (Object.op_Implicit((Object)(object)val)) { val.enabled = false; } } Collider[] array2 = colliders; foreach (Collider val2 in array2) { if (Object.op_Implicit((Object)(object)val2)) { val2.enabled = false; } } } internal void HideNow() { Renderer[] array = renderers; foreach (Renderer val in array) { if (Object.op_Implicit((Object)(object)val)) { val.enabled = false; } } Collider[] array2 = colliders; foreach (Collider val2 in array2) { if (Object.op_Implicit((Object)(object)val2)) { val2.enabled = false; } } } } [HarmonyPatch(typeof(Gutterman), "Death")] internal static class HideGuttermanCorpsePatch { private static void Prefix(Gutterman __instance) { if (UltraMiseryState.IsActive && !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<UltraMiseryHiddenGuttermanCorpse>())) { ((Component)__instance).gameObject.AddComponent<UltraMiseryHiddenGuttermanCorpse>(); } } private static void Postfix(Gutterman __instance) { if (UltraMiseryState.IsActive) { (((Component)__instance).GetComponent<UltraMiseryHiddenGuttermanCorpse>() ?? ((Component)__instance).gameObject.AddComponent<UltraMiseryHiddenGuttermanCorpse>()).HideNow(); } } } [HarmonyPatch] internal static class GroundWaveMissingTargetPatch { private static IEnumerable<MethodBase> TargetMethods() { string[] array = new string[3] { "Update", "FixedUpdate", "TrackTick" }; foreach (string text in array) { yield return AccessTools.Method(typeof(GroundWave), text, (Type[])null, (Type[])null); } } private static bool Prefix(GroundWave __instance) { if (!UltraMiseryState.IsActive || (__instance.target != null && Object.op_Implicit((Object)(object)__instance.target.trackedTransform))) { return true; } ((MonoBehaviour)__instance).CancelInvoke(); ((Component)__instance).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)__instance).gameObject); return false; } } [HarmonyPatch(typeof(Deathcatcher), "Start")] internal static class DeathcatcherNoIdolRevivalSetupPatch { private static void Postfix(Deathcatcher __instance) { if (UltraMiseryState.IsActive) { __instance.canRespawnIdols = false; } } } [HarmonyPatch(typeof(Deathcatcher), "EnemyDeath")] internal static class DeathcatcherNoIdolRevivalPatch { private static bool Prefix(EnemyIdentifier eid) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 if (UltraMiseryState.IsActive && Object.op_Implicit((Object)(object)eid)) { return (int)eid.enemyType != 21; } return true; } } internal sealed class UltraMiseryDifficultyMarker : MonoBehaviour { } internal static class DifficultySelectionUi { private const float VisibleHierarchySettleSeconds = 0.75f; private static int candidateParentId; private static float candidateFirstSeenAt; internal static void ResetReconciliation() { candidateParentId = 0; candidateFirstSeenAt = 0f; } internal static void ReconcileVisibleButton() { UltraMiseryDifficultyMarker ultraMiseryDifficultyMarker = FindVisibleButton(); if (Object.op_Implicit((Object)(object)ultraMiseryDifficultyMarker)) { DifficultyWheelInput.Ensure(((Component)ultraMiseryDifficultyMarker).transform); ResetReconciliation(); return; } DifficultySelectButton val = FindVisibleSourceButton(); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)((Component)val).transform.parent)) { ResetReconciliation(); return; } int instanceID = ((Object)((Component)val).transform.parent).GetInstanceID(); if (candidateParentId != instanceID) { candidateParentId = instanceID; candidateFirstSeenAt = Time.unscaledTime; } else if (!(Time.unscaledTime - candidateFirstSeenAt < 0.75f)) { RemoveObsoleteHiddenButtons(((Component)val).transform.parent); GameObject val2 = CreateButton(val); if (Object.op_Implicit((Object)(object)val2)) { Transform transform = val2.transform; RebuildContainingLayouts((RectTransform)(object)((transform is RectTransform) ? transform : null)); Plugin.Log.LogInfo((object)("Reconciled visible ULTRAMISERY difficulty button beside " + GetHierarchyPath(((Component)val).transform) + ".")); ResetReconciliation(); } } } private static GameObject CreateButton(DifficultySelectButton source) { //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(((Component)source).gameObject, ((Component)source).transform.parent); val.SetActive(false); ((Object)val).name = "UltraMisery"; DifficultySelectButton component = val.GetComponent<DifficultySelectButton>(); if (!Object.op_Implicit((Object)(object)component)) { Object.Destroy((Object)(object)val); return null; } component.difficulty = 5; val.AddComponent<UltraMiseryDifficultyMarker>(); TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true); TMP_Text val2 = null; TMP_Text[] array = componentsInChildren; foreach (TMP_Text val3 in array) { if (((Object)val3.transform).name == "Name") { val2 = val3; break; } } if (!Object.op_Implicit((Object)(object)val2) && componentsInChildren.Length != 0) { val2 = componentsInChildren[0]; } if (Object.op_Implicit((Object)(object)val2)) { val2.text = "ULTRAMISERY"; } val.transform.SetSiblingIndex(((Component)source).transform.GetSiblingIndex() + 1); Transform transform = ((Component)source).transform; RectTransform val4 = (RectTransform)(object)((transform is RectTransform) ? transform : null); Transform transform2 = val.transform; RectTransform val5 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null); if (Object.op_Implicit((Object)(object)val4) && Object.op_Implicit((Object)(object)val5) && !Object.op_Implicit((Object)(object)((Component)val.transform.parent).GetComponent<LayoutGroup>())) { Rect rect = val4.rect; float num = Mathf.Max(60f, ((Rect)(ref rect)).height + 8f); val5.anchoredPosition = val4.anchoredPosition + Vector2.down * num; } val.SetActive(true); DifficultyWheelInput.Ensure(val.transform); RebuildContainingLayouts(val5); return val; } private static UltraMiseryDifficultyMarker FindVisibleButton() { UltraMiseryDifficultyMarker[] array = Object.FindObjectsOfType<UltraMiseryDifficultyMarker>(); foreach (UltraMiseryDifficultyMarker ultraMiseryDifficultyMarker in array) { if (Object.op_Implicit((Object)(object)ultraMiseryDifficultyMarker) && ((Component)ultraMiseryDifficultyMarker).gameObject.activeInHierarchy) { return ultraMiseryDifficultyMarker; } } return null; } private static void RemoveObsoleteHiddenButtons(Transform visibleParent) { UltraMiseryDifficultyMarker[] array = Resources.FindObjectsOfTypeAll<UltraMiseryDifficultyMarker>(); foreach (UltraMiseryDifficultyMarker ultraMiseryDifficultyMarker in array) { if (Object.op_Implicit((Object)(object)ultraMiseryDifficultyMarker) && !((Component)ultraMiseryDifficultyMarker).gameObject.activeInHierarchy && (Object)(object)((Component)ultraMiseryDifficultyMarker).transform.parent != (Object)(object)visibleParent) { Object.Destroy((Object)(object)((Component)ultraMiseryDifficultyMarker).gameObject); } } } private static DifficultySelectButton FindVisibleSourceButton() { DifficultySelectButton result = null; DifficultySelectButton[] array = Object.FindObjectsOfType<DifficultySelectButton>(); foreach (DifficultySelectButton val in array) { if (Object.op_Implicit((Object)(object)val) && ((Component)val).gameObject.activeInHierarchy && !Object.op_Implicit((Object)(object)((Component)val).GetComponent<UltraMiseryDifficultyMarker>())) { if (val.difficulty == 5) { return val; } if (val.difficulty == 4) { result = val; } } } return result; } private static void RebuildContainingLayouts(RectTransform rect) { Canvas.ForceUpdateCanvases(); Transform val = (Transform)(object)rect; int num = 0; while (Object.op_Implicit((Object)(object)val) && num < 8) { RectTransform val2 = (RectTransform)(object)((val is RectTransform) ? val : null); if (Object.op_Implicit((Object)(object)val2)) { LayoutRebuilder.ForceRebuildLayoutImmediate(val2); } num++; val = val.parent; } Canvas.ForceUpdateCanvases(); } private static string GetHierarchyPath(Transform transform) { string text = (Object.op_Implicit((Object)(object)transform) ? ((Object)transform).name : "<missing>"); Transform val = (Object.op_Implicit((Object)(object)transform) ? transform.parent : null); while (Object.op_Implicit((Object)(object)val)) { text = ((Object)val).name + "/" + text; val = val.parent; } return text; } } [HarmonyPatch(typeof(DifficultySelectButton), "SetDifficulty")] internal static class UltraMiseryDifficultySelectionPatch { private static void Postfix(DifficultySelectButton __instance) { UltraMiseryState.SetSelected(Object.op_Implicit((Object)(object)__instance) && Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<UltraMiseryDifficultyMarker>())); } } [HarmonyPatch(typeof(DifficultyTitle), "Check")] internal static class UltraMiseryDifficultyTitlePatch { private static void Postfix(DifficultyTitle __instance) { if (UltraMiseryState.IsActive && Object.op_Implicit((Object)(object)__instance)) { TMP_Text component = ((Component)__instance).GetComponent<TMP_Text>(); if (Object.op_Implicit((Object)(object)component)) { component.text = (__instance.lines ? "-- ULTRAMISERY --" : "ULTRAMISERY"); } } } } internal sealed class DifficultyWheelInput : MonoBehaviour { private ScrollRect scroll; private Canvas canvas; private readonly List<RaycastResult> hits = new List<RaycastResult>(); internal int LastScrollFrame = -1; internal static void Ensure(Transform button) { ScrollRect componentInParent = ((Component)button).GetComponentInParent<ScrollRect>(); if (Object.op_Implicit((Object)(object)componentInParent) && !Object.op_Implicit((Object)(object)((Component)componentInParent).GetComponent<DifficultyWheelInput>())) { DifficultyWheelInput difficultyWheelInput = ((Component)componentInParent).gameObject.AddComponent<DifficultyWheelInput>(); difficultyWheelInput.scroll = componentInParent; difficultyWheelInput.canvas = ((Component)componentInParent).GetComponentInParent<Canvas>(); } } private void LateUpdate() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Expected O, but got Unknown //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)scroll) || !((UIBehaviour)scroll).IsActive() || !Object.op_Implicit((Object)(object)scroll.viewport) || LastScrollFrame == Time.frameCount || Mouse.current == null || !Object.op_Implicit((Object)(object)EventSystem.current)) { return; } Vector2 val = ((InputControl<Vector2>)(object)Mouse.current.scroll).ReadValue() / 120f; if (Mathf.Approximately(val.y, 0f)) { return; } Vector2 val2 = ((InputControl<Vector2>)(object)((Pointer)Mouse.current).position).ReadValue(); Camera val3 = ((Object.op_Implicit((Object)(object)canvas) && (int)canvas.renderMode != 0) ? canvas.worldCamera : null); if (!RectTransformUtility.RectangleContainsScreenPoint(scroll.viewport, val2, val3)) { return; } PointerEventData val4 = new PointerEventData(EventSystem.current) { position = val2, scrollDelta = val }; hits.Clear(); EventSystem.current.RaycastAll(val4, hits); if (hits.Count > 0) { RaycastResult val5 = hits[0]; if (!((RaycastResult)(ref val5)).gameObject.transform.IsChildOf(((Component)scroll).transform)) { return; } } scroll.OnScroll(val4); } } [HarmonyPatch(typeof(ScrollRect), "OnScroll")] internal static class DifficultyWheelDeliveredPatch { private static void Postfix(ScrollRect __instance) { DifficultyWheelInput component = ((Component)__instance).GetComponent<DifficultyWheelInput>(); if (Object.op_Implicit((Object)(object)component)) { component.LastScrollFrame = Time.frameCount; } } } [HarmonyPatch] internal static class DroneHalfMovementSpeedPatch { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(Drone), "FixedUpdate", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Drone), "Dodge", new Type[1] { typeof(Vector3) }, (Type[])null); } private static void Prefix(EnemyIdentifier ___eid, out float? __state) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 __state = null; if (UltraMiseryState.IsActive && Object.op_Implicit((Object)(object)___eid) && (int)___eid.enemyType == 1) { __state = ___eid.totalSpeedModifier; ___eid.totalSpeedModifier *= 0.5f; } } private static void Finalizer(EnemyIdentifier ___eid, float? __state) { if (Object.op_Implicit((Object)(object)___eid) && __state.HasValue) { ___eid.totalSpeedModifier = __state.Value; } } } internal static class DroneTargetRules { internal static bool IsLive(ITarget target) { if (target != null) { Object val = (Object)(object)((target is Object) ? target : null); if (val == null || Object.op_Implicit(val)) { GameObject gameObject = target.GameObject; if (!Object.op_Implicit((Object)(object)gameObject) || !gameObject.activeInHierarchy) { return false; } if (target is UltraMiserySupportTarget && !LifestealRules.AiCombatAllowed) { return false; } if (target.isEnemy) { if (Object.op_Implicit((Object)(object)target.EID)) { return !target.EID.dead; } return false; } return true; } } return false; } } [HarmonyPatch] internal static class DroneStaleTargetPatch { private static IEnumerable<MethodBase> TargetMethods() { string[] array = new string[4] { "Update", "FixedUpdate", "SightCheck", "Shoot" }; foreach (string text in array) { yield return AccessTools.Method(typeof(Drone), text, (Type[])null, (Type[])null); } } private static void Prefix(EnemyIdentifier ___eid, ref TargetHandle ___droneTargetHandle, ref TargetData ___droneTargetData, ref Vector3 ___lastDimensionalTarget) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) if (UltraMiseryState.IsActive && !(___droneTargetHandle == (TargetHandle)null) && ((Object.op_Implicit((Object)(object)___eid) && ___eid.target != null && ___eid.target.isEnemy && ___droneTargetHandle.target != null && (Object)(object)___droneTargetHandle.target.EID != (Object)(object)___eid.target.enemyIdentifier) || !DroneTargetRules.IsLive(___droneTargetHandle.target))) { ___droneTargetHandle = null; ___droneTargetData = default(TargetData); ___lastDimensionalTarget = Vector3.zero; } } } [HarmonyPatch(typeof(Drone), "ObstructionCheck", new Type[] { typeof(TargetData) })] internal static class OmniscientDroneFiringPatch { private static bool Prefix(Drone __instance, EnemyIdentifier ___eid, TargetData data, ref bool __result) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (!EnemyAwarenessRules.CanAttack((Component)(object)__instance) || (int)___eid.enemyType != 1) { return true; } if (ObstructedAttackRules.Approaching(___eid)) { return true; } __result = data.handle != (TargetHandle)null && DroneTargetRules.IsLive(data.handle.target); return false; } } internal sealed class UltraMiseryMortarClearance : MonoBehaviour { private Projectile shot; private Collider[] shells; private readonly List<(Collider Shot, Collider Unit)> changedPairs = new List<(Collider, Collider)>(); internal void Bind(EnemyIdentifier owner) { shot = ((Component)this).GetComponent<Projectile>(); shells = ((Component)this).GetComponentsInChildren<Collider>(true); Restore(); Collider[] componentsInChildren = ((Component)owner).GetComponentsInChildren<Collider>(true); Collider[] array = shells; foreach (Collider val in array) { Collider[] array2 = componentsInChildren; foreach (Collider val2 in array2) { if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val2) && (Object)(object)val != (Object)(object)val2 && EarthmoverDefenceRules.HitsOwner(owner, val2) && !Physics.GetIgnoreCollision(val, val2)) { Physics.IgnoreCollision(val, val2, true); changedPairs.Add((val, val2)); } } } } private void Restore() { foreach (var changedPair in changedPairs) { if (Object.op_Implicit((Object)(object)changedPair.Shot) && Object.op_Implicit((Object)(object)changedPair.Unit)) { Physics.IgnoreCollision(changedPair.Shot, changedPair.Unit, false); } } changedPairs.Clear(); } private void Update() { UltraMiseryAttackOwner component = ((Component)this).GetComponent<UltraMiseryAttackOwner>(); if (!UltraMiseryState.IsActive || !Object.op_Implicit((Object)(object)shot) || shot.parried || shot.friendly || shot.playerBullet || (Object.op_Implicit((Object)(object)component) && component.ReflectedByEnemy)) { Restore(); Object.Destroy((Object)(object)this); } } private void OnDestroy() { Restore(); } } internal static class EarthmoverDefenceRules { internal static bool IsDefence(EnemyIdentifier enemy) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 if (!Object.op_Implicit((Object)(object)enemy)) { return false; } if ((int)enemy.enemyType == 35 || Object.op_Implicit((Object)(object)((Component)enemy).GetComponentInChildren<MortarLauncher>(true))) { return true; } Transform val = ((Component)enemy).transform; while (Object.op_Implicit((Object)(object)val)) { if (((Object)val).name.StartsWith("Centaur", StringComparison.OrdinalIgnoreCase)) { return true; } val = val.parent; } return false; } internal static bool HitsOwner(EnemyIdentifier owner, Collider other) { if (Object.op_Implicit((Object)(object)owner) && Object.op_Implicit((Object)(object)other)) { return (Object)(object)FriendlyFireRules.GetEnemy(other) == (Object)(object)owner; } return false; } } internal sealed class UltraMiseryDefenceRageSize : MonoBehaviour { private Transform anchor; internal void Bind(Transform target) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) anchor = target; ((Component)this).transform.SetParent((Transform)null, true); ((Component)this).transform.localScale = Vector3.one * 0.5f; LateUpdate(); } private void LateUpdate() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)anchor)) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } ((Component)this).transform.position = anchor.position; ((Component)this).transform.localScale = Vector3.one * 0.5f; } } [HarmonyPatch(typeof(Projectile), "Collided")] internal static class MortarOwnerCollisionPatch { private static bool Prefix(Projectile __instance, Collider other) { if (!UltraMiseryState.IsActive || __instance.parried || __instance.friendly || __instance.playerBullet) { return true; } UltraMiseryAttackOwner componentInParent = ((Component)__instance).GetComponentInParent<UltraMiseryAttackOwner>(); if (Object.op_Implicit((Object)(object)componentInParent) && componentInParent.ReflectedByEnemy) { return true; } EnemyIdentifier val = LifestealRules.Resolve((Component)(object)__instance); if (!EarthmoverDefenceRules.HitsOwner(val, other)) { return true; } return !Object.op_Implicit((Object)(object)((Component)val).GetComponentInChildren<MortarLauncher>(true)); } } [HarmonyPatch(typeof(Explosion), "Collide")] internal static class MortarOwnerExplosionPatch { private static bool Prefix(Explosion __instance, Collider other) { if (!UltraMiseryState.IsActive) { return true; } UltraMiseryAttackOwner componentInParent = ((Component)__instance).GetComponentInParent<UltraMiseryAttackOwner>(); if (Object.op_Implicit((Object)(object)componentInParent) && componentInParent.ReflectedByEnemy) { return true; } EnemyIdentifier val = LifestealRules.Resolve((Component)(object)__instance); if (!EarthmoverDefenceRules.HitsOwner(val, other)) { return true; } return !Object.op_Implicit((Object)(object)((Component)val).GetComponentInChildren<MortarLauncher>(true)); } } [HarmonyPatch(typeof(Arena), "Awake")] internal static class ArenaSupportEnemyPatch { private static void Prefix(Arena __instance) { if (!UltraMiseryState.IsActive || SceneHelper.IsPlayingCustom || Object.op_Implicit((Object)(object)MonoSingleton<SandboxNavmesh>.Instance)) { return; } try { ActivateNextWave[] waves = __instance.GetWaves(); if (waves == null || waves.Length == 0) { return; } ActivateNextWave[] array = waves; foreach (ActivateNextWave val in array) { if (Object.op_Implicit((Object)(object)val) && ((Component)val).transform.childCount != 0 && !IsInfinitePuppetSpawnerWave(((Component)val).transform)) { Transform transform = ((Component)val).transform; List<Vector3> reserved = new List<Vector3>(); EnsureEnemyType(transform, (EnemyType)21, reserved); EnsureEnemyType(transform, (EnemyType)39, reserved); EnsureEnemyType(transform, (EnemyType)12, reserved); UltraMiseryEnrageAudioGate.Bind(transform, ((Object)__instance).GetInstanceID()); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"Arena support-enemy injection failed: {arg}"); } } internal static GameObject EnsureEnemyType(Transform wave, EnemyType type, List<Vector3> reserved) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) EnemyIdentifier[] componentsInChildren = ((Component)wave).GetComponentsInChildren<EnemyIdentifier>(true); foreach (EnemyIdentifier val in componentsInChildren) { if (IsSupportEnemy(val.enemyType)) { Reserve(((Component)val).transform.position, reserved); } if (val.enemyType == type) { return ((Component)val).gameObject; } } GameObject enemyPrefab = MonoSingleton<DefaultReferenceManager>.Instance.GetEnemyPrefab(type); if (!Object.op_Implicit((Object)(object)enemyPrefab)) { Plugin.Log.LogWarning((object)$"Could not find the {type} prefab for arena injection."); return null; } if (!TryFindPlacement(wave, reserved, out var position, out var rotation)) { Plugin.Log.LogWarning((object)$"No safe reachable placement was found for {type} in arena wave {((Object)wave).name}; skipped injection."); return null; } GameObject obj = Object.Instantiate<GameObject>(enemyPrefab, position, rotation, wave); ((Object)obj).name = $"UltraMisery Injected {type}"; obj.SetActive(false); Reserve(position, reserved); Plugin.Log.LogDebug((object)$"Injected {type} into arena wave {((Object)wave).name} at {position}."); return obj; } private static bool IsSupportEnemy(EnemyType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if ((int)type != 21 && (int)type != 39) { return (int)type == 12; } return true; } internal static bool IsInfinitePuppetSpawnerWave(Transform wave) { if (!Object.op_Implicit((Object)(object)wave)) { return false; } if (!Object.op_Implicit((Object)(object)((Component)wave).GetComponentInChildren<EnemySpawnRadius>(true)) && !Object.op_Implicit((Object)(object)((Component)wave).GetComponentInParent<EnemySpawnRadius>(true))) { return ((Object)wave).name.IndexOf("SuicideTree", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } internal static bool IsBossEncounter(Transform wave) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Invalid comparison between Unknown and I4 //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected I4, but got Unknown //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Invalid comparison between Unknown and I4 //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Invalid comparison between Unknown and I4 //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 if (Object.op_Implicit((Object)(object)((Component)wave).GetComponentInChildren<BossHealthBar>(true))) { return true; } EnemyIdentifier[] componentsInChildren = ((Component)wave).GetComponentsInChildren<EnemyIdentifier>(true); for (int i = 0; i < componentsInChildren.Length; i++) { EnemyType enemyType = componentsInChildren[i].enemyType; if ((int)enemyType <= 11) { if ((int)enemyType != 8 && (int)enemyType != 11) { continue; } } else { switch (enemyType - 16) { default: if ((int)enemyType != 42) { continue; } break; case 0: case 1: case 2: case 6: case 11: case 12: case 13: case 14: break; case 3: case 4: case 5: case 7: case 8: case 9: case 10: continue; } } return true; } return false; } private static bool TryFindPlacement(Transform wave, List<Vector3> reserved, out Vector3 position, out Quaternion rotation) { //IL_0022: Unknown result type (might be due to invalid IL or missing r