Decompiled source of Wider Blasts v0.2.0

WiderBlasts.dll

Decompiled 15 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates;
using EntityStates.Engi.EngiBubbleShield;
using EntityStates.Merc;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using R2API;
using RiskOfOptions;
using RiskOfOptions.OptionConfigs;
using RiskOfOptions.Options;
using RoR2;
using RoR2.Projectile;
using RoR2.Skills;
using RoR2.UI;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Events;
using UnityEngine.ResourceManagement.ResourceLocations;

[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("WiderBlasts")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0")]
[assembly: AssemblyProduct("WiderBlasts")]
[assembly: AssemblyTitle("WiderBlasts")]
[assembly: AssemblyVersion("0.2.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 WiderBlasts
{
	internal enum MeleeScalingMode
	{
		Off,
		NonPrimary,
		All
	}
	[HarmonyPatch]
	internal static class BlastHooks
	{
		private enum Context
		{
			None,
			Skill,
			Excluded
		}

		private class ScaledMarker : MonoBehaviour
		{
		}

		internal static readonly Dictionary<Type, string> SpecialCases = new Dictionary<Type, string>
		{
			{
				typeof(Deployed),
				"shield bubble"
			},
			{
				typeof(Evis),
				"target radius"
			},
			{
				typeof(EvisDash),
				"dash catch radius"
			}
		};

		private static readonly EntityStateMachine[] stateMachineStack = (EntityStateMachine[])(object)new EntityStateMachine[64];

		private static int stateMachineDepth;

		private static int procDepth;

		private static int detonateDepth;

		internal static bool MeleeAllowedForSlot(SkillSlot slot)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			return WiderBlastsPlugin.MeleeScaling.Value switch
			{
				MeleeScalingMode.All => true, 
				MeleeScalingMode.NonPrimary => (int)slot > 0, 
				_ => false, 
			};
		}

		internal static CharacterBody ResolveBody(GameObject source)
		{
			for (int i = 0; i < 4; i++)
			{
				if (!Object.op_Implicit((Object)(object)source))
				{
					break;
				}
				ProjectileController component = source.GetComponent<ProjectileController>();
				if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.owner) && (Object)(object)component.owner != (Object)(object)source)
				{
					source = component.owner;
					continue;
				}
				GenericOwnership component2 = source.GetComponent<GenericOwnership>();
				if (Object.op_Implicit((Object)(object)component2) && Object.op_Implicit((Object)(object)component2.ownerObject) && (Object)(object)component2.ownerObject != (Object)(object)source)
				{
					source = component2.ownerObject;
					continue;
				}
				return source.GetComponent<CharacterBody>();
			}
			return null;
		}

		private static Context GetContext(out EntityStateMachine machine, out Type stateType)
		{
			machine = null;
			stateType = null;
			int num = Math.Min(stateMachineDepth, stateMachineStack.Length) - 1;
			if (num < 0)
			{
				return Context.None;
			}
			machine = stateMachineStack[num];
			if (!Object.op_Implicit((Object)(object)machine) || machine.state == null)
			{
				return Context.None;
			}
			stateType = ((object)machine.state).GetType();
			if (SkillScanner.ExcludedStateTypes.Contains(stateType))
			{
				return Context.Excluded;
			}
			if (!SkillScanner.SkillStateTypes.Contains(stateType))
			{
				return Context.None;
			}
			return Context.Skill;
		}

		private static bool IsSkillTagged(DamageTypeCombo damageType)
		{
			//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)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			return (damageType.damageSource & 0xF) > 0;
		}

		private static void PushStateMachine(EntityStateMachine machine)
		{
			if (stateMachineDepth < stateMachineStack.Length)
			{
				stateMachineStack[stateMachineDepth] = machine;
			}
			stateMachineDepth++;
		}

		private static void PopStateMachine()
		{
			if (stateMachineDepth > 0)
			{
				stateMachineDepth--;
				if (stateMachineDepth < stateMachineStack.Length)
				{
					stateMachineStack[stateMachineDepth] = null;
				}
			}
		}

		[HarmonyPatch(typeof(EntityStateMachine), "ManagedUpdate")]
		[HarmonyPrefix]
		private static void ManagedUpdatePrefix(EntityStateMachine __instance)
		{
			PushStateMachine(__instance);
		}

		[HarmonyPatch(typeof(EntityStateMachine), "ManagedUpdate")]
		[HarmonyFinalizer]
		private static void ManagedUpdateFinalizer()
		{
			PopStateMachine();
		}

		[HarmonyPatch(typeof(EntityStateMachine), "ManagedFixedUpdate")]
		[HarmonyPrefix]
		private static void ManagedFixedUpdatePrefix(EntityStateMachine __instance)
		{
			PushStateMachine(__instance);
		}

		[HarmonyPatch(typeof(EntityStateMachine), "ManagedFixedUpdate")]
		[HarmonyFinalizer]
		private static void ManagedFixedUpdateFinalizer()
		{
			PopStateMachine();
		}

		[HarmonyPatch(typeof(EntityStateMachine), "SetState")]
		[HarmonyPrefix]
		private static void SetStatePrefix(EntityStateMachine __instance)
		{
			PushStateMachine(__instance);
		}

		[HarmonyPatch(typeof(EntityStateMachine), "SetState")]
		[HarmonyFinalizer]
		private static void SetStateFinalizer()
		{
			PopStateMachine();
		}

		[HarmonyPatch(typeof(EntityStateMachine), "TriggerAnimationEvent")]
		[HarmonyPrefix]
		private static void AnimationEventPrefix(EntityStateMachine __instance)
		{
			PushStateMachine(__instance);
		}

		[HarmonyPatch(typeof(EntityStateMachine), "TriggerAnimationEvent")]
		[HarmonyFinalizer]
		private static void AnimationEventFinalizer()
		{
			PopStateMachine();
		}

		[HarmonyPatch(typeof(HealthComponent), "TakeDamage", new Type[] { typeof(DamageInfo) })]
		[HarmonyPrefix]
		private static void TakeDamagePrefix()
		{
			procDepth++;
		}

		[HarmonyPatch(typeof(HealthComponent), "TakeDamage", new Type[] { typeof(DamageInfo) })]
		[HarmonyFinalizer]
		private static void TakeDamageFinalizer()
		{
			procDepth--;
		}

		[HarmonyPatch(typeof(GlobalEventManager), "OnHitEnemy")]
		[HarmonyPrefix]
		private static void OnHitEnemyPrefix()
		{
			procDepth++;
		}

		[HarmonyPatch(typeof(GlobalEventManager), "OnHitEnemy")]
		[HarmonyFinalizer]
		private static void OnHitEnemyFinalizer()
		{
			procDepth--;
		}

		[HarmonyPatch(typeof(GlobalEventManager), "OnHitAll")]
		[HarmonyPrefix]
		private static void OnHitAllPrefix()
		{
			procDepth++;
		}

		[HarmonyPatch(typeof(GlobalEventManager), "OnHitAll")]
		[HarmonyFinalizer]
		private static void OnHitAllFinalizer()
		{
			procDepth--;
		}

		[HarmonyPatch(typeof(GlobalEventManager), "HandleCharacterDeath")]
		[HarmonyPrefix]
		private static void HandleDeathPrefix()
		{
			procDepth++;
		}

		[HarmonyPatch(typeof(GlobalEventManager), "HandleCharacterDeath")]
		[HarmonyFinalizer]
		private static void HandleDeathFinalizer()
		{
			procDepth--;
		}

		[HarmonyPatch(typeof(GlobalEventManager), "TriggerCharacterDeathProc")]
		[HarmonyPrefix]
		private static void DeathProcPrefix()
		{
			procDepth++;
		}

		[HarmonyPatch(typeof(GlobalEventManager), "TriggerCharacterDeathProc")]
		[HarmonyFinalizer]
		private static void DeathProcFinalizer()
		{
			procDepth--;
		}

		[HarmonyPatch(typeof(ProjectileExplosion), "DetonateServer")]
		[HarmonyPrefix]
		private static void DetonatePrefix(ProjectileExplosion __instance, ProjectileController ___projectileController, ProjectileDamage ___projectileDamage, out float __state)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			__state = -1f;
			detonateDepth++;
			if (Object.op_Implicit((Object)(object)___projectileController) && !(__instance.blastRadius <= 0f) && (SkillScanner.ExplosionProjectileIndices.Contains(___projectileController.catalogIndex) || (Object.op_Implicit((Object)(object)___projectileDamage) && IsSkillTagged(___projectileDamage.damageType))))
			{
				float radiusMultiplier = WiderBlastsPlugin.GetRadiusMultiplier(___projectileController.owner);
				if (radiusMultiplier > 1f)
				{
					__state = __instance.blastRadius;
					__instance.blastRadius *= radiusMultiplier;
				}
			}
		}

		[HarmonyPatch(typeof(ProjectileExplosion), "DetonateServer")]
		[HarmonyFinalizer]
		private static void DetonateFinalizer(ProjectileExplosion __instance, float __state)
		{
			detonateDepth--;
			if (__state >= 0f && Object.op_Implicit((Object)(object)__instance))
			{
				__instance.blastRadius = __state;
			}
		}

		[HarmonyPatch(typeof(BlastAttack), "Fire")]
		[HarmonyPrefix]
		private static void BlastFirePrefix(BlastAttack __instance, out float __state)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			__state = -1f;
			if (detonateDepth > 0 || procDepth > 0)
			{
				return;
			}
			EntityStateMachine machine;
			Type stateType;
			Context context = GetContext(out machine, out stateType);
			if (context != Context.Excluded && (IsSkillTagged(__instance.damageType) || context == Context.Skill))
			{
				float radiusMultiplier = WiderBlastsPlugin.GetRadiusMultiplier(Object.op_Implicit((Object)(object)__instance.attacker) ? __instance.attacker : (Object.op_Implicit((Object)(object)__instance.inflictor) ? __instance.inflictor : (Object.op_Implicit((Object)(object)machine) ? ((Component)machine).gameObject : null)));
				if (radiusMultiplier > 1f)
				{
					__state = __instance.radius;
					__instance.radius *= radiusMultiplier;
				}
			}
		}

		[HarmonyPatch(typeof(BlastAttack), "Fire")]
		[HarmonyFinalizer]
		private static void BlastFireFinalizer(BlastAttack __instance, float __state)
		{
			if (__state >= 0f)
			{
				__instance.radius = __state;
			}
		}

		[HarmonyPatch(typeof(ProjectileController), "Start")]
		[HarmonyPostfix]
		private static void ProjectileStartPostfix(ProjectileController __instance)
		{
			//IL_002e: 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 (SkillScanner.ZoneProjectileIndices.Contains(__instance.catalogIndex))
			{
				float radiusMultiplier = WiderBlastsPlugin.GetRadiusMultiplier(__instance.owner);
				if (radiusMultiplier > 1f)
				{
					Transform transform = ((Component)__instance).transform;
					transform.localScale *= radiusMultiplier;
				}
			}
		}

		[HarmonyPatch(typeof(OverlapAttack), "Fire")]
		[HarmonyPrefix]
		private static void OverlapFirePrefix(OverlapAttack __instance, out Vector3[] __state)
		{
			//IL_0050: 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)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Invalid comparison between Unknown and I4
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			__state = null;
			if (WiderBlastsPlugin.MeleeScaling.Value == MeleeScalingMode.Off || procDepth > 0 || !Object.op_Implicit((Object)(object)__instance.hitBoxGroup) || (Object.op_Implicit((Object)(object)__instance.inflictor) && Object.op_Implicit((Object)(object)__instance.inflictor.GetComponent<ProjectileController>())))
			{
				return;
			}
			EntityStateMachine machine;
			Type stateType;
			Context context = GetContext(out machine, out stateType);
			bool flag = IsSkillTagged(__instance.damageType);
			if (context == Context.Excluded || (!flag && context != Context.Skill) || ((flag ? ((__instance.damageType.damageSource & 0xF) == 1) : (SkillScanner.StateOnlyPrimary.TryGetValue(stateType, out var value) && value)) && WiderBlastsPlugin.MeleeScaling.Value == MeleeScalingMode.NonPrimary))
			{
				return;
			}
			float radiusMultiplier = WiderBlastsPlugin.GetRadiusMultiplier(Object.op_Implicit((Object)(object)__instance.attacker) ? __instance.attacker : (Object.op_Implicit((Object)(object)machine) ? ((Component)machine).gameObject : null));
			if (radiusMultiplier <= 1f)
			{
				return;
			}
			HitBox[] hitBoxes = __instance.hitBoxGroup.hitBoxes;
			__state = (Vector3[])(object)new Vector3[hitBoxes.Length];
			for (int i = 0; i < hitBoxes.Length; i++)
			{
				if (Object.op_Implicit((Object)(object)hitBoxes[i]))
				{
					Transform transform = ((Component)hitBoxes[i]).transform;
					__state[i] = transform.localScale;
					transform.localScale = __state[i] * radiusMultiplier;
				}
			}
		}

		[HarmonyPatch(typeof(OverlapAttack), "Fire")]
		[HarmonyFinalizer]
		private static void OverlapFireFinalizer(OverlapAttack __instance, Vector3[] __state)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (__state == null || !Object.op_Implicit((Object)(object)__instance.hitBoxGroup))
			{
				return;
			}
			HitBox[] hitBoxes = __instance.hitBoxGroup.hitBoxes;
			for (int i = 0; i < hitBoxes.Length && i < __state.Length; i++)
			{
				if (Object.op_Implicit((Object)(object)hitBoxes[i]))
				{
					((Component)hitBoxes[i]).transform.localScale = __state[i];
				}
			}
		}

		[HarmonyPatch(typeof(SphereSearch), "RefreshCandidates")]
		[HarmonyPrefix]
		private static void SphereSearchPrefix(SphereSearch __instance, out float __state)
		{
			__state = -1f;
			if (procDepth <= 0 && detonateDepth <= 0 && GetContext(out var machine, out var _) == Context.Skill)
			{
				float radiusMultiplier = WiderBlastsPlugin.GetRadiusMultiplier(((Component)machine).gameObject);
				if (radiusMultiplier > 1f)
				{
					__state = __instance.radius;
					__instance.radius *= radiusMultiplier;
				}
			}
		}

		[HarmonyPatch(typeof(SphereSearch), "RefreshCandidates")]
		[HarmonyFinalizer]
		private static void SphereSearchFinalizer(SphereSearch __instance, float __state)
		{
			if (__state >= 0f)
			{
				__instance.radius = __state;
			}
		}

		[HarmonyPatch(typeof(Deployed), "FixedUpdate")]
		[HarmonyPostfix]
		private static void BubbleDeployedPostfix(Deployed __instance, bool ___hasDeployed)
		{
			//IL_0072: 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 (!___hasDeployed || (Object)(object)((EntityState)__instance).outer == (Object)null)
			{
				return;
			}
			ChildLocator component = ((Component)((EntityState)__instance).outer).GetComponent<ChildLocator>();
			Transform val = (Object.op_Implicit((Object)(object)component) ? component.FindChild(Deployed.childLocatorString) : null);
			if (Object.op_Implicit((Object)(object)val) && !Object.op_Implicit((Object)(object)((Component)val).GetComponent<ScaledMarker>()))
			{
				((Component)val).gameObject.AddComponent<ScaledMarker>();
				float radiusMultiplier = WiderBlastsPlugin.GetRadiusMultiplier(((Component)((EntityState)__instance).outer).gameObject);
				if (radiusMultiplier > 1f)
				{
					val.localScale *= radiusMultiplier;
				}
			}
		}

		[HarmonyPatch(typeof(Evis), "SearchForTarget")]
		[HarmonyPrefix]
		private static void EvisSearchPrefix(Evis __instance, out float __state)
		{
			__state = -1f;
			float radiusMultiplier = WiderBlastsPlugin.GetRadiusMultiplier(Object.op_Implicit((Object)(object)((EntityState)__instance).outer) ? ((Component)((EntityState)__instance).outer).gameObject : null);
			if (radiusMultiplier > 1f)
			{
				__state = Evis.maxRadius;
				Evis.maxRadius *= radiusMultiplier;
			}
		}

		[HarmonyPatch(typeof(Evis), "SearchForTarget")]
		[HarmonyFinalizer]
		private static void EvisSearchFinalizer(float __state)
		{
			if (__state >= 0f)
			{
				Evis.maxRadius = __state;
			}
		}

		[HarmonyPatch(typeof(EvisDash), "FixedUpdate")]
		[HarmonyPrefix]
		private static void EvisDashPrefix(EvisDash __instance, out float __state)
		{
			__state = -1f;
			float radiusMultiplier = WiderBlastsPlugin.GetRadiusMultiplier(Object.op_Implicit((Object)(object)((EntityState)__instance).outer) ? ((Component)((EntityState)__instance).outer).gameObject : null);
			if (radiusMultiplier > 1f)
			{
				__state = EvisDash.overlapSphereRadius;
				EvisDash.overlapSphereRadius *= radiusMultiplier;
			}
		}

		[HarmonyPatch(typeof(EvisDash), "FixedUpdate")]
		[HarmonyFinalizer]
		private static void EvisDashFinalizer(float __state)
		{
			if (__state >= 0f)
			{
				EvisDash.overlapSphereRadius = __state;
			}
		}
	}
	[BepInPlugin("com.ewan.WiderBlasts", "Wider Blasts", "0.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class WiderBlastsPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.ewan.WiderBlasts";

		public const string PluginName = "Wider Blasts";

		public const string PluginVersion = "0.2.0";

		internal const string TokenPrefix = "EWAN_WIDERBLASTS_";

		internal static ManualLogSource Log;

		internal static ItemDef ItemDef;

		internal static Sprite IconSprite;

		internal static ConfigEntry<float> AreaPerStack;

		internal static ConfigEntry<MeleeScalingMode> MeleeScaling;

		internal static ConfigEntry<string> ExcludedSkills;

		private static Harmony harmony;

		private static LanguageOverlay descriptionOverlay;

		private void Awake()
		{
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			AreaPerStack = ((BaseUnityPlugin)this).Config.Bind<float>("Item", "Area Per Stack", 0.1f, "Extra ground area covered by skill explosions, per stack of the item. 0.1 = +10% area per stack. Area grows linearly with stacks; the radius grows by the square root of that (+10% area is about +4.9% radius).");
			AreaPerStack.SettingChanged += delegate
			{
				UpdateDescriptionText();
			};
			MeleeScaling = ((BaseUnityPlugin)this).Config.Bind<MeleeScalingMode>("Item", "Melee Hitboxes", MeleeScalingMode.NonPrimary, "Which melee swing hitboxes the item grows. NonPrimary = Secondary/Utility/Special skills only.");
			ExcludedSkills = ((BaseUnityPlugin)this).Config.Bind<string>("Item", "Excluded Skills", "Ascent Protocol", "Comma-separated skill names the item never affects. Takes effect after restarting the game.");
			IconSprite = MakeIconSprite();
			CreateItem();
			harmony = new Harmony("com.ewan.WiderBlasts");
			harmony.PatchAll(typeof(BlastHooks));
			RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(OnGameLoaded));
			if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"))
			{
				try
				{
					OptionsMenu.Init();
				}
				catch (Exception arg)
				{
					Log.LogWarning((object)$"Risk Of Options setup failed: {arg}");
				}
			}
			Log.LogInfo((object)"Wider Blasts v0.2.0 initialized");
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}

		private void OnGameLoaded()
		{
			try
			{
				SkillScanner.Scan();
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Skill scan failed: {arg}");
				return;
			}
			string text = SkillScanner.BuildPlainReport();
			Log.LogInfo((object)("Affected skills:\n" + text));
			try
			{
				File.WriteAllText(Path.Combine(Paths.ConfigPath, "com.ewan.WiderBlasts.AffectedSkills.txt"), text);
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not write affected-skills file: " + ex.Message));
			}
			if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"))
			{
				try
				{
					OptionsMenu.AddSkillList();
				}
				catch (Exception arg2)
				{
					Log.LogWarning((object)$"Risk Of Options skill list failed: {arg2}");
				}
			}
		}

		internal static float GetRadiusMultiplier(GameObject source)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)source) || !Object.op_Implicit((Object)(object)ItemDef) || (int)ItemDef.itemIndex == -1)
			{
				return 1f;
			}
			CharacterBody val = BlastHooks.ResolveBody(source);
			Inventory val2 = (Object.op_Implicit((Object)(object)val) ? val.inventory : null);
			if (!Object.op_Implicit((Object)(object)val2))
			{
				return 1f;
			}
			int itemCountEffective = val2.GetItemCountEffective(ItemDef.itemIndex);
			if (itemCountEffective <= 0)
			{
				return 1f;
			}
			return Mathf.Sqrt(1f + AreaPerStack.Value * (float)itemCountEffective);
		}

		private static void CreateItem()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			ItemTierDef val = LoadTierDef();
			LanguageAPI.Add("EWAN_WIDERBLASTS_ITEM_NAME", "Shockwave Lens");
			LanguageAPI.Add("EWAN_WIDERBLASTS_ITEM_PICKUP", "Your skill explosions are bigger.");
			LanguageAPI.Add("EWAN_WIDERBLASTS_ITEM_LORE", "A cracked lens that bends every blast outward.");
			UpdateDescriptionText();
			ItemDisplayRuleDict val2 = new ItemDisplayRuleDict((ItemDisplayRule[])null);
			CustomItem val3 = new CustomItem("WiderBlastsLens", "EWAN_WIDERBLASTS_ITEM_NAME", "EWAN_WIDERBLASTS_ITEM_DESC", "EWAN_WIDERBLASTS_ITEM_LORE", "EWAN_WIDERBLASTS_ITEM_PICKUP", IconSprite, LoadPickupModel(), (ItemTier)(Object.op_Implicit((Object)(object)val) ? 1000 : 0), (ItemTag[])(object)new ItemTag[2]
			{
				(ItemTag)1,
				(ItemTag)3
			}, true, false, (UnlockableDef)null, val2, val);
			ItemDef = val3.ItemDef;
			ItemAPI.Add(val3);
		}

		private static void UpdateDescriptionText()
		{
			string text = (AreaPerStack.Value * 100f).ToString("0.#");
			string text2 = "Increases the <style=cIsDamage>area</style> of your <style=cIsDamage>skill explosions</style> by <style=cIsDamage>" + text + "%</style> <style=cStack>(+" + text + "% per stack)</style>.";
			LanguageOverlay obj = descriptionOverlay;
			if (obj != null)
			{
				obj.Remove();
			}
			descriptionOverlay = LanguageAPI.AddOverlay("EWAN_WIDERBLASTS_ITEM_DESC", text2);
		}

		private static ItemTierDef LoadTierDef()
		{
			string[] array = new string[2] { "Assets/RoR2/Base/Common/ItemTierDefs/Tier1Def.asset", "RoR2/Base/Common/Tier1Def.asset" };
			for (int i = 0; i < array.Length; i++)
			{
				ItemTierDef val = WiderBlastsPlugin.TryLoad<ItemTierDef>(array[i]);
				if (Object.op_Implicit((Object)(object)val))
				{
					return val;
				}
			}
			Log.LogWarning((object)"Could not load Tier1Def; falling back to R2API's tier lookup.");
			return null;
		}

		private static GameObject LoadPickupModel()
		{
			return WiderBlastsPlugin.TryLoad<GameObject>("Assets/RoR2/Base/MiscPickups/Mystery/PickupMystery.prefab") ?? WiderBlastsPlugin.TryLoad<GameObject>("RoR2/Base/Mystery/PickupMystery.prefab");
		}

		internal static T TryLoad<T>(string key) where T : Object
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				IList<IResourceLocation> list = Addressables.LoadResourceLocationsAsync((object)key, typeof(T)).WaitForCompletion();
				if (list == null || list.Count == 0)
				{
					return default(T);
				}
				return Addressables.LoadAssetAsync<T>((object)key).WaitForCompletion();
			}
			catch (Exception)
			{
				return default(T);
			}
		}

		private static Sprite MakeIconSprite()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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_009c: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: 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)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false);
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(1f, 0.62f, 0.2f);
			Color val3 = default(Color);
			((Color)(ref val3))..ctor(1f, 0.9f, 0.7f);
			float num = 64f;
			for (int i = 0; i < 128; i++)
			{
				for (int j = 0; j < 128; j++)
				{
					float num2 = Mathf.Sqrt(((float)j + 0.5f - num) * ((float)j + 0.5f - num) + ((float)i + 0.5f - num) * ((float)i + 0.5f - num)) / num;
					Color val4 = Color.clear;
					if (num2 < 0.2f)
					{
						val4 = Color.Lerp(val3, val2, num2 / 0.2f);
					}
					else
					{
						float[] array = new float[3] { 0.4f, 0.62f, 0.84f };
						for (int k = 0; k < array.Length; k++)
						{
							float num3 = Mathf.Abs(num2 - array[k]);
							float num4 = 0.055f - (float)k * 0.01f;
							if (num3 < num4)
							{
								float num5 = (1f - num3 / num4) * (1f - (float)k * 0.25f);
								((Color)(ref val4))..ctor(val2.r, val2.g, val2.b, Mathf.Max(val4.a, num5));
							}
						}
					}
					val.SetPixel(j, i, val4);
				}
			}
			val.Apply();
			return Sprite.Create(val, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f));
		}
	}
	internal static class OptionsMenu
	{
		private class SurvivorEntry
		{
			public SkillScanner.SurvivorInfo Survivor;

			public string NameToken;

			public string BodyToken;

			public LanguageOverlay NameOverlay;

			public LanguageOverlay BodyOverlay;
		}

		private const string Category = "Affected Skills";

		private static readonly List<SurvivorEntry> entries = new List<SurvivorEntry>();

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static void Init()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Expected O, but got Unknown
			//IL_00e3: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Expected O, but got Unknown
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Expected O, but got Unknown
			ModSettingsManager.SetModDescription("Adds the Shockwave Lens, a white item that makes skill areas bigger.\n\nScanning skills... open this menu again after the game finishes loading.", "com.ewan.WiderBlasts", "Wider Blasts");
			if (Object.op_Implicit((Object)(object)WiderBlastsPlugin.IconSprite))
			{
				ModSettingsManager.SetModIcon(WiderBlastsPlugin.IconSprite, "com.ewan.WiderBlasts", "Wider Blasts");
			}
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(WiderBlastsPlugin.AreaPerStack, new StepSliderConfig
			{
				min = 0.01f,
				max = 0.5f,
				increment = 0.01f,
				FormatString = "{0:P0}",
				category = "Item",
				name = "Area Per Stack",
				description = "Extra ground area covered by skill areas, per stack. Default 10% (about +4.9% radius for one stack)."
			}), "com.ewan.WiderBlasts", "Wider Blasts");
			ModSettingsManager.AddOption((BaseOption)new ChoiceOption((ConfigEntryBase)(object)WiderBlastsPlugin.MeleeScaling, new ChoiceConfig
			{
				category = "Item",
				name = "Melee Hitboxes",
				description = "Which melee swing hitboxes the item grows.\n\n<style=cIsDamage>NonPrimary</style>: Secondary, Utility and Special skills (default).\n<style=cIsDamage>All</style>: primaries too.\n<style=cIsDamage>Off</style>: no melee scaling."
			}), "com.ewan.WiderBlasts", "Wider Blasts");
			ModSettingsManager.AddOption((BaseOption)new StringInputFieldOption(WiderBlastsPlugin.ExcludedSkills, new InputFieldConfig
			{
				category = "Item",
				name = "Excluded Skills",
				description = "Comma-separated skill names the item never affects, e.g. \"Ascent Protocol, Abduct\". Needs a game restart.",
				submitOn = (SubmitEnum)6,
				restartRequired = true
			}), "com.ewan.WiderBlasts", "Wider Blasts");
			WiderBlastsPlugin.MeleeScaling.SettingChanged += delegate
			{
				Refresh();
			};
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static void AddSkillList()
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Expected O, but got Unknown
			HashSet<string> hashSet = new HashSet<string>();
			foreach (SkillScanner.SurvivorInfo result in SkillScanner.Results)
			{
				string text = result.Name;
				int num = 2;
				while (!hashSet.Add(text))
				{
					text = result.Name + " " + num;
					num++;
				}
				SurvivorEntry entry = new SurvivorEntry
				{
					Survivor = result,
					NameToken = "EWAN_WIDERBLASTS_LIST_NAME_" + hashSet.Count,
					BodyToken = "EWAN_WIDERBLASTS_LIST_BODY_" + hashSet.Count
				};
				entries.Add(entry);
				GenericButtonOption val = new GenericButtonOption(text, "Affected Skills", "", "Show", (UnityAction)delegate
				{
					ShowDialog(entry);
				});
				ModSettingsManager.AddOption((BaseOption)val, "com.ewan.WiderBlasts", "Wider Blasts", entry.NameToken, entry.BodyToken);
				LanguageAPI.Add(val.GetButtonLabelToken(), "Show");
			}
			Refresh();
		}

		private static void Refresh()
		{
			if (SkillScanner.Results.Count > 0)
			{
				ModSettingsManager.SetModDescription(SkillScanner.BuildSummary(), "com.ewan.WiderBlasts", "Wider Blasts");
			}
			foreach (SurvivorEntry entry in entries)
			{
				LanguageOverlay nameOverlay = entry.NameOverlay;
				if (nameOverlay != null)
				{
					nameOverlay.Remove();
				}
				LanguageOverlay bodyOverlay = entry.BodyOverlay;
				if (bodyOverlay != null)
				{
					bodyOverlay.Remove();
				}
				entry.NameOverlay = LanguageAPI.AddOverlay(entry.NameToken, $"{entry.Survivor.Name} ({entry.Survivor.AffectedCount} affected)");
				entry.BodyOverlay = LanguageAPI.AddOverlay(entry.BodyToken, SkillScanner.BuildSurvivorText(entry.Survivor));
			}
		}

		private static void ShowDialog(SurvivorEntry entry)
		{
			//IL_0012: 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)
			SimpleDialogBox obj = SimpleDialogBox.Create((MPEventSystem)null);
			obj.headerToken = new TokenParamsPair(entry.NameToken, Array.Empty<object>());
			obj.descriptionToken = new TokenParamsPair(entry.BodyToken, Array.Empty<object>());
			obj.AddCancelButton(CommonLanguageTokens.ok, Array.Empty<object>());
		}
	}
	internal static class SkillScanner
	{
		internal class SkillInfo
		{
			public string Slot;

			public string Name;

			public SkillSlot SlotEnum;

			public bool MainSlot;

			public bool Excluded;

			public readonly List<string> Explosions = new List<string>();

			public readonly List<string> Specials = new List<string>();

			public bool BlastInCode;

			public bool Zone;

			public bool AreaSearch;

			public bool Melee;

			public bool RawOverlap;

			public readonly HashSet<Type> States = new HashSet<Type>();

			public readonly HashSet<int> ExplosionProjectiles = new HashSet<int>();

			public readonly HashSet<int> ZoneProjectiles = new HashSet<int>();

			public bool MeleeScaled
			{
				get
				{
					//IL_0009: Unknown result type (might be due to invalid IL or missing references)
					if (Melee)
					{
						return BlastHooks.MeleeAllowedForSlot(SlotEnum);
					}
					return false;
				}
			}

			public bool Affected
			{
				get
				{
					if (!Excluded)
					{
						if (Explosions.Count <= 0 && Specials.Count <= 0 && !BlastInCode && !Zone && !AreaSearch)
						{
							return MeleeScaled;
						}
						return true;
					}
					return false;
				}
			}

			public bool HasUnscaledArea
			{
				get
				{
					if (!Affected)
					{
						if (!Melee && !RawOverlap && Explosions.Count <= 0 && Specials.Count <= 0 && !BlastInCode && !Zone)
						{
							return AreaSearch;
						}
						return true;
					}
					return false;
				}
			}

			public bool Visible
			{
				get
				{
					if (!MainSlot && !Affected)
					{
						return HasUnscaledArea;
					}
					return true;
				}
			}
		}

		internal class SurvivorInfo
		{
			public string Name;

			public readonly List<SkillInfo> Skills = new List<SkillInfo>();

			public int AffectedCount => Skills.Count((SkillInfo s) => s.Affected);
		}

		internal static readonly HashSet<int> ExplosionProjectileIndices = new HashSet<int>();

		internal static readonly HashSet<int> ZoneProjectileIndices = new HashSet<int>();

		internal static readonly HashSet<Type> SkillStateTypes = new HashSet<Type>();

		internal static readonly HashSet<Type> ExcludedStateTypes = new HashSet<Type>();

		internal static readonly Dictionary<Type, bool> StateOnlyPrimary = new Dictionary<Type, bool>();

		internal static readonly List<SurvivorInfo> Results = new List<SurvivorInfo>();

		private const int MaxStatesPerSkill = 64;

		private const int MaxPrefabDepth = 4;

		private const int MaxCallDepth = 2;

		private static readonly Dictionary<Assembly, ModuleDefinition> modules = new Dictionary<Assembly, ModuleDefinition>();

		private static readonly Dictionary<string, Assembly> assembliesByName = new Dictionary<string, Assembly>();

		private static Assembly ror2Assembly;

		private static HashSet<string> excludedNames;

		private static SkillInfo current;

		private static Queue<Type> stateQueue;

		private static HashSet<Type> visitedStates;

		private static HashSet<GameObject> visitedPrefabs;

		private static HashSet<MethodDefinition> visitedMethods;

		private static HashSet<Type> excludedStates;

		private static bool suppressRawOverlap;

		internal static void Scan()
		{
			ror2Assembly = typeof(BlastAttack).Assembly;
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				assembliesByName[assembly.GetName().Name] = assembly;
			}
			excludedNames = new HashSet<string>(from s in WiderBlastsPlugin.ExcludedSkills.Value.Split(',')
				select s.Trim() into s
				where s.Length > 0
				select s, StringComparer.OrdinalIgnoreCase);
			Results.Clear();
			try
			{
				foreach (SurvivorDef orderedSurvivorDef in SurvivorCatalog.orderedSurvivorDefs)
				{
					if (Object.op_Implicit((Object)(object)orderedSurvivorDef) && !orderedSurvivorDef.hidden && Object.op_Implicit((Object)(object)orderedSurvivorDef.bodyPrefab))
					{
						try
						{
							Results.Add(ScanSurvivor(orderedSurvivorDef));
						}
						catch (Exception ex)
						{
							WiderBlastsPlugin.Log.LogWarning((object)("Skipped survivor " + orderedSurvivorDef.cachedName + ": " + ex.Message));
						}
					}
				}
			}
			finally
			{
				foreach (ModuleDefinition value in modules.Values)
				{
					if (value != null)
					{
						value.Dispose();
					}
				}
				modules.Clear();
			}
			WiderBlastsPlugin.Log.LogInfo((object)($"Scanned {Results.Count} survivors: {SkillStateTypes.Count} skill states, " + $"{ExplosionProjectileIndices.Count} exploding and {ZoneProjectileIndices.Count} zone projectiles, {ExcludedStateTypes.Count} excluded states."));
		}

		private unsafe static SurvivorInfo ScanSurvivor(SurvivorDef survivor)
		{
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: 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)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Invalid comparison between Unknown and I4
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Invalid comparison between Unknown and I4
			GameObject bodyPrefab = survivor.bodyPrefab;
			SurvivorInfo survivorInfo = new SurvivorInfo
			{
				Name = Resolve(survivor.displayNameToken, ((Object)bodyPrefab).name)
			};
			excludedStates = new HashSet<Type>
			{
				typeof(Uninitialized),
				typeof(Idle),
				typeof(GenericCharacterMain)
			};
			EntityStateMachine[] components = bodyPrefab.GetComponents<EntityStateMachine>();
			foreach (EntityStateMachine val in components)
			{
				AddIfNotNull(excludedStates, ((SerializableEntityStateType)(ref val.initialStateType)).stateType);
				AddIfNotNull(excludedStates, ((SerializableEntityStateType)(ref val.mainStateType)).stateType);
			}
			SkillLocator component = bodyPrefab.GetComponent<SkillLocator>();
			HashSet<SkillDef> hashSet = new HashSet<SkillDef>();
			GenericSkill[] components2 = bodyPrefab.GetComponents<GenericSkill>();
			foreach (GenericSkill val2 in components2)
			{
				SkillFamily skillFamily = val2.skillFamily;
				if (!Object.op_Implicit((Object)(object)skillFamily))
				{
					continue;
				}
				SkillSlot val3 = (SkillSlot)((!Object.op_Implicit((Object)(object)component)) ? (-1) : ((int)component.FindSkillSlot(val2)));
				string slot = (((int)val3 != -1) ? ((object)(*(SkillSlot*)(&val3))/*cast due to .constrained prefix*/).ToString() : (string.IsNullOrEmpty(val2.skillName) ? "Other" : val2.skillName));
				Variant[] variants = skillFamily.variants;
				for (int j = 0; j < variants.Length; j++)
				{
					SkillDef skillDef = variants[j].skillDef;
					if (Object.op_Implicit((Object)(object)skillDef) && hashSet.Add(skillDef))
					{
						SkillInfo skillInfo = new SkillInfo
						{
							Slot = slot,
							SlotEnum = val3,
							MainSlot = ((int)val3 != -1),
							Name = Resolve(skillDef.skillNameToken, skillDef.skillName)
						};
						skillInfo.Excluded = excludedNames.Contains(skillInfo.Name) || excludedNames.Contains(skillDef.skillName ?? "") || excludedNames.Contains(skillDef.skillNameToken ?? "");
						try
						{
							ScanSkill(skillDef, skillInfo);
						}
						catch (Exception ex)
						{
							WiderBlastsPlugin.Log.LogWarning((object)("Error scanning " + survivorInfo.Name + " / " + skillInfo.Name + ": " + ex.Message));
						}
						Register(skillInfo);
						survivorInfo.Skills.Add(skillInfo);
					}
				}
			}
			return survivorInfo;
		}

		private static void Register(SkillInfo skill)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Invalid comparison between Unknown and I4
			if (skill.Excluded)
			{
				ExcludedStateTypes.UnionWith(skill.States);
				return;
			}
			SkillStateTypes.UnionWith(skill.States);
			ExplosionProjectileIndices.UnionWith(skill.ExplosionProjectiles);
			ZoneProjectileIndices.UnionWith(skill.ZoneProjectiles);
			bool flag = (int)skill.SlotEnum == 0;
			foreach (Type state in skill.States)
			{
				StateOnlyPrimary[state] = (!StateOnlyPrimary.TryGetValue(state, out var value) || value) && flag;
			}
		}

		private static void ScanSkill(SkillDef skillDef, SkillInfo skill)
		{
			current = skill;
			stateQueue = new Queue<Type>();
			visitedStates = new HashSet<Type>();
			visitedPrefabs = new HashSet<GameObject>();
			visitedMethods = new HashSet<MethodDefinition>();
			foreach (FieldInfo item in AllFields(((object)skillDef).GetType(), typeof(ScriptableObject)))
			{
				if (!item.IsStatic)
				{
					HandleValue(item.GetValue(skillDef), allowNested: true);
				}
			}
			while (stateQueue.Count > 0 && visitedStates.Count < 64)
			{
				Type type = stateQueue.Dequeue();
				if (visitedStates.Add(type) && !excludedStates.Contains(type))
				{
					skill.States.Add(type);
					if (BlastHooks.SpecialCases.TryGetValue(type, out var value) && !skill.Specials.Contains(value))
					{
						skill.Specials.Add(value);
					}
					ScanStateFields(type);
					ScanStateCode(type);
				}
			}
			current = null;
		}

		private static void EnqueueState(Type type)
		{
			if (type != null && !type.IsAbstract && typeof(EntityState).IsAssignableFrom(type) && !visitedStates.Contains(type))
			{
				stateQueue.Enqueue(type);
			}
		}

		private static void ScanStateFields(Type stateType)
		{
			EntityState val = null;
			try
			{
				val = EntityStateCatalog.InstantiateState(stateType);
			}
			catch (Exception)
			{
			}
			foreach (FieldInfo item in AllFields(stateType, typeof(EntityState)))
			{
				if (!item.DeclaringType.ContainsGenericParameters)
				{
					object value;
					try
					{
						value = (item.IsStatic ? item.GetValue(null) : ((val != null) ? item.GetValue(val) : null));
					}
					catch (Exception)
					{
						continue;
					}
					HandleValue(value, allowNested: false);
				}
			}
		}

		private static void HandleValue(object value, bool allowNested)
		{
			//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)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			if (value == null)
			{
				return;
			}
			GameObject val = (GameObject)((value is GameObject) ? value : null);
			if (val == null)
			{
				if (!(value is SerializableEntityStateType val2))
				{
					if (!(value is Type type))
					{
						if (!(value is GameObject[] array))
						{
							if (value is SerializableEntityStateType[] array2)
							{
								SerializableEntityStateType[] array3 = array2;
								for (int i = 0; i < array3.Length; i++)
								{
									SerializableEntityStateType val3 = array3[i];
									EnqueueState(((SerializableEntityStateType)(ref val3)).stateType);
								}
							}
							else
							{
								if (!allowNested || !(value is Array array4))
								{
									return;
								}
								foreach (object item in array4)
								{
									if (item != null && !(item is Object))
									{
										FieldInfo[] fields = item.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
										for (int i = 0; i < fields.Length; i++)
										{
											HandleValue(fields[i].GetValue(item), allowNested: false);
										}
									}
								}
							}
						}
						else
						{
							GameObject[] array5 = array;
							for (int i = 0; i < array5.Length; i++)
							{
								ScanPrefab(array5[i], 0);
							}
						}
					}
					else
					{
						EnqueueState(type);
					}
				}
				else
				{
					EnqueueState(((SerializableEntityStateType)(ref val2)).stateType);
				}
			}
			else
			{
				ScanPrefab(val, 0);
			}
		}

		private static void ScanPrefab(GameObject prefab, int depth)
		{
			if (!Object.op_Implicit((Object)(object)prefab) || depth > 4 || !visitedPrefabs.Add(prefab))
			{
				return;
			}
			ProjectileController component = prefab.GetComponent<ProjectileController>();
			if (!Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)prefab.GetComponent<CharacterBody>()))
			{
				return;
			}
			int num = (Object.op_Implicit((Object)(object)component) ? ProjectileCatalog.GetProjectileIndex(component) : (-1));
			ProjectileExplosion[] componentsInChildren = prefab.GetComponentsInChildren<ProjectileExplosion>(true);
			foreach (ProjectileExplosion val in componentsInChildren)
			{
				if (val.blastRadius > 0f && Object.op_Implicit((Object)(object)((Component)val).GetComponent<ProjectileDamage>()))
				{
					string item = $"{val.blastRadius:0.#} m explosion";
					if (!current.Explosions.Contains(item))
					{
						current.Explosions.Add(item);
					}
					if (num >= 0)
					{
						current.ExplosionProjectiles.Add(num);
					}
				}
			}
			bool flag = Object.op_Implicit((Object)(object)prefab.GetComponentInChildren<ProjectileDotZone>(true));
			if (!flag && Object.op_Implicit((Object)(object)prefab.GetComponentInChildren<ProjectileOverlapAttack>(true)))
			{
				ProjectileSimple component2 = prefab.GetComponent<ProjectileSimple>();
				flag = Object.op_Implicit((Object)(object)component2) && component2.desiredForwardSpeed <= 0f;
			}
			if (flag && num >= 0)
			{
				current.Zone = true;
				current.ZoneProjectiles.Add(num);
			}
			EntityStateMachine[] componentsInChildren2 = prefab.GetComponentsInChildren<EntityStateMachine>(true);
			foreach (EntityStateMachine obj in componentsInChildren2)
			{
				EnqueueState(((SerializableEntityStateType)(ref obj.initialStateType)).stateType);
				EnqueueState(((SerializableEntityStateType)(ref obj.mainStateType)).stateType);
			}
			MonoBehaviour[] componentsInChildren3 = prefab.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val2 in componentsInChildren3)
			{
				if (!Object.op_Implicit((Object)(object)val2))
				{
					continue;
				}
				foreach (FieldInfo item2 in AllFields(((object)val2).GetType(), typeof(MonoBehaviour)))
				{
					if (!item2.IsStatic && !(item2.FieldType != typeof(GameObject)))
					{
						object? value = item2.GetValue(val2);
						GameObject val3 = (GameObject)((value is GameObject) ? value : null);
						if (Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)val3.GetComponent<ProjectileController>()))
						{
							ScanPrefab(val3, depth + 1);
						}
					}
				}
			}
		}

		private static void ScanStateCode(Type stateType)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			suppressRawOverlap = BlastHooks.SpecialCases.ContainsKey(stateType);
			Type type = stateType;
			while (type != null && type != typeof(EntityState))
			{
				if (!(type == typeof(BaseState)) && !(type == typeof(BaseSkillState)))
				{
					TypeDefinition typeDefinition = GetTypeDefinition(type);
					if (typeDefinition != null)
					{
						Enumerator<MethodDefinition> enumerator = typeDefinition.Methods.GetEnumerator();
						try
						{
							while (enumerator.MoveNext())
							{
								ScanMethod(enumerator.Current, 0);
							}
						}
						finally
						{
							((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
						}
					}
				}
				type = type.BaseType;
			}
			suppressRawOverlap = false;
		}

		private static void ScanMethod(MethodDefinition method, int depth)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (method == null || !method.HasBody || !visitedMethods.Add(method))
			{
				return;
			}
			Enumerator<Instruction> enumerator = method.Body.Instructions.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					Instruction ins = enumerator.Current;
					try
					{
						ScanInstruction(method, ins, depth);
					}
					catch (Exception)
					{
					}
				}
			}
			finally
			{
				((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private static void ScanInstruction(MethodDefinition method, Instruction ins, int depth)
		{
			//IL_003a: 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)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			object operand = ins.Operand;
			MethodReference val = (MethodReference)((operand is MethodReference) ? operand : null);
			if (val == null)
			{
				FieldReference val2 = (FieldReference)((operand is FieldReference) ? operand : null);
				if (val2 == null)
				{
					TypeReference val3 = (TypeReference)((operand is TypeReference) ? operand : null);
					if (val3 != null && ins.OpCode == OpCodes.Ldtoken)
					{
						EnqueueState(ResolveType(val3));
					}
				}
				else
				{
					if (!(ins.OpCode == OpCodes.Ldsfld))
					{
						return;
					}
					string fullName = ((MemberReference)val2.FieldType).FullName;
					if (!(fullName != "UnityEngine.GameObject") || !(fullName != "UnityEngine.GameObject[]"))
					{
						Type type = ResolveType(((MemberReference)val2).DeclaringType);
						FieldInfo fieldInfo = type?.GetField(((MemberReference)val2).Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
						if (fieldInfo != null && !type.ContainsGenericParameters)
						{
							HandleValue(fieldInfo.GetValue(null), allowNested: false);
						}
					}
				}
				return;
			}
			string fullName2 = ((MemberReference)((MemberReference)val).DeclaringType).FullName;
			if (ins.OpCode == OpCodes.Newobj)
			{
				switch (fullName2)
				{
				case "RoR2.BlastAttack":
					current.BlastInCode = true;
					return;
				case "RoR2.SphereSearch":
					current.AreaSearch = true;
					return;
				case "RoR2.OverlapAttack":
					current.Melee = true;
					return;
				}
				Type type2 = ResolveType(((MemberReference)val).DeclaringType);
				if (type2 != null && typeof(EntityState).IsAssignableFrom(type2))
				{
					EnqueueState(type2);
					return;
				}
			}
			if (fullName2 == "RoR2.BlastAttack" && ((MemberReference)val).Name == "Fire")
			{
				current.BlastInCode = true;
			}
			else if (((MemberReference)val).Name == "InitMeleeOverlap")
			{
				current.Melee = true;
			}
			else if ((fullName2 == "UnityEngine.Physics" || fullName2 == "RoR2.HGPhysics") && ((MemberReference)val).Name.StartsWith("OverlapSphere"))
			{
				current.RawOverlap |= !suppressRawOverlap;
			}
			else if (depth < 2 && (object)((MemberReference)val).DeclaringType.Scope == ((MemberReference)method).Module && (((AssemblyNameReference)((MemberReference)method).Module.Assembly.Name).Name != ror2Assembly.GetName().Name || OuterNamespace(((MemberReference)val).DeclaringType).StartsWith("EntityStates")))
			{
				MethodDefinition val4 = val.Resolve();
				if (val4 != null && !IsEntityStateType(val4.DeclaringType))
				{
					ScanMethod(val4, depth + 1);
				}
			}
		}

		private static string OuterNamespace(TypeReference type)
		{
			while (((MemberReference)type).DeclaringType != null)
			{
				type = ((MemberReference)type).DeclaringType;
			}
			return type.Namespace ?? "";
		}

		private static bool IsEntityStateType(TypeDefinition typeDef)
		{
			Type type = ResolveType((TypeReference)(object)typeDef);
			if (type != null)
			{
				return typeof(EntityState).IsAssignableFrom(type);
			}
			return false;
		}

		private static TypeDefinition GetTypeDefinition(Type type)
		{
			//IL_0053: 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_0064: Expected O, but got Unknown
			Assembly assembly = type.Assembly;
			if (!modules.TryGetValue(assembly, out var value))
			{
				value = null;
				try
				{
					string text = assembly.Location;
					if (string.IsNullOrEmpty(text))
					{
						text = Path.Combine(Paths.ManagedPath, assembly.GetName().Name + ".dll");
					}
					if (File.Exists(text))
					{
						value = ModuleDefinition.ReadModule(text, new ReaderParameters
						{
							ReadingMode = (ReadingMode)2
						});
					}
					else
					{
						WiderBlastsPlugin.Log.LogWarning((object)("No file for " + assembly.GetName().Name + "; skill code in it is not scanned."));
					}
				}
				catch (Exception ex)
				{
					WiderBlastsPlugin.Log.LogDebug((object)("Cannot read " + assembly.GetName().Name + ": " + ex.Message));
				}
				modules[assembly] = value;
			}
			if (value == null)
			{
				return null;
			}
			Type type2 = (type.IsGenericType ? type.GetGenericTypeDefinition() : type);
			return value.GetType(type2.FullName.Replace('+', '/'));
		}

		private static Type ResolveType(TypeReference typeRef)
		{
			if (typeRef == null)
			{
				return null;
			}
			GenericInstanceType val = (GenericInstanceType)(object)((typeRef is GenericInstanceType) ? typeRef : null);
			if (val != null)
			{
				typeRef = ((TypeSpecification)val).ElementType;
			}
			IMetadataScope scope = typeRef.Scope;
			ModuleDefinition val2 = (ModuleDefinition)(object)((scope is ModuleDefinition) ? scope : null);
			string text;
			if (val2 == null)
			{
				AssemblyNameReference val3 = (AssemblyNameReference)(object)((scope is AssemblyNameReference) ? scope : null);
				text = ((val3 == null) ? null : val3.Name);
			}
			else
			{
				text = ((AssemblyNameReference)val2.Assembly.Name).Name;
			}
			string text2 = text;
			if (text2 == null || !assembliesByName.TryGetValue(text2, out var value))
			{
				return null;
			}
			return value.GetType(((MemberReference)typeRef).FullName.Replace('/', '+'), throwOnError: false);
		}

		private static IEnumerable<FieldInfo> AllFields(Type type, Type stopAt)
		{
			Type t = type;
			while (t != null && t != stopAt && t != typeof(object))
			{
				FieldInfo[] fields = t.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				for (int i = 0; i < fields.Length; i++)
				{
					yield return fields[i];
				}
				t = t.BaseType;
			}
		}

		private static void AddIfNotNull(HashSet<Type> set, Type type)
		{
			if (type != null)
			{
				set.Add(type);
			}
		}

		private static string Resolve(string token, string fallback)
		{
			if (string.IsNullOrEmpty(token))
			{
				return fallback;
			}
			string text = Language.GetString(token);
			if (!string.IsNullOrEmpty(text) && !(text == token))
			{
				return text;
			}
			if (!string.IsNullOrEmpty(fallback))
			{
				return fallback;
			}
			return token;
		}

		internal static string BuildSummary()
		{
			int num = Results.Count((SurvivorInfo r) => r.AffectedCount > 0);
			int num2 = Results.Sum((SurvivorInfo r) => r.AffectedCount);
			return "Adds the <style=cIsDamage>Shockwave Lens</style>, a white item that makes skill areas bigger: explosions, damage zones, area searches and (optionally) melee hitboxes.\n\n" + $"<style=cIsDamage>{num2}</style> skills across <style=cIsDamage>{num}</style> of {Results.Count} survivors are affected.\n" + "Open the <style=cIsUtility>Affected Skills</style> tab and hover a survivor to see which skills.";
		}

		internal static string BuildSurvivorText(SurvivorInfo survivor)
		{
			StringBuilder stringBuilder = new StringBuilder();
			List<SkillInfo> list = survivor.Skills.Where((SkillInfo s) => s.Affected).ToList();
			List<SkillInfo> list2 = survivor.Skills.Where((SkillInfo s) => s.HasUnscaledArea).ToList();
			List<SkillInfo> list3 = survivor.Skills.Where((SkillInfo s) => s.Visible && !s.Affected && !s.HasUnscaledArea).ToList();
			stringBuilder.Append("<style=cIsDamage>Bigger with Shockwave Lens:</style>\n");
			if (list.Count == 0)
			{
				stringBuilder.Append("  (none)\n");
			}
			foreach (SkillInfo item in list)
			{
				stringBuilder.Append("  " + item.Slot + ": " + item.Name + "  <style=cStack>" + Detail(item) + "</style>\n");
			}
			if (list2.Count > 0)
			{
				stringBuilder.Append("\n<style=cIsUtility>Has an area, but not scaled:</style>\n");
				foreach (SkillInfo item2 in list2)
				{
					stringBuilder.Append("  " + item2.Slot + ": " + item2.Name + "  <style=cStack>" + UnscaledReason(item2) + "</style>\n");
				}
			}
			if (list3.Count > 0)
			{
				stringBuilder.Append("\n<style=cStack>No area: ");
				stringBuilder.Append(string.Join(", ", list3.Select((SkillInfo s) => s.Name)));
				stringBuilder.Append("</style>");
			}
			return stringBuilder.ToString();
		}

		private static string Detail(SkillInfo s)
		{
			List<string> list = new List<string>(s.Explosions);
			list.AddRange(s.Specials);
			if (s.BlastInCode)
			{
				list.Add("blast in skill code");
			}
			if (s.Zone)
			{
				list.Add("damage zone");
			}
			if (s.AreaSearch)
			{
				list.Add("area search");
			}
			if (s.MeleeScaled)
			{
				list.Add("melee hitbox");
			}
			return string.Join(", ", list);
		}

		private static string UnscaledReason(SkillInfo s)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (s.Excluded)
			{
				return "excluded in settings";
			}
			if (s.Melee)
			{
				if ((int)s.SlotEnum != 0 || WiderBlastsPlugin.MeleeScaling.Value != MeleeScalingMode.NonPrimary)
				{
					return "melee hitbox (off in settings)";
				}
				return "primary melee hitbox (off in settings)";
			}
			return "uses a sphere check this mod can't scale yet";
		}

		internal static string BuildPlainReport()
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (SurvivorInfo result in Results)
			{
				stringBuilder.AppendLine($"{result.Name} ({result.AffectedCount} affected)");
				foreach (SkillInfo item in result.Skills.Where((SkillInfo s) => s.Visible))
				{
					if (item.Affected)
					{
						stringBuilder.AppendLine("  AFFECTED     " + item.Slot + ": " + item.Name + "  [" + Detail(item) + "]");
					}
					else if (item.HasUnscaledArea)
					{
						stringBuilder.AppendLine("  NOT SCALED   " + item.Slot + ": " + item.Name + "  [" + UnscaledReason(item) + "]");
					}
					else
					{
						stringBuilder.AppendLine("  -            " + item.Slot + ": " + item.Name);
					}
				}
			}
			return stringBuilder.ToString();
		}
	}
}