Decompiled source of BouncingHuntress v1.1.0

BouncingHuntress.dll

Decompiled 12 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BouncingHuntress.ChainBallista;
using BouncingHuntress.Glaive;
using BouncingHuntress.PhaseBurst;
using BouncingHuntress.Shared;
using BouncingHuntress.Strafe;
using EntityStates;
using EntityStates.Huntress;
using EntityStates.Huntress.HuntressWeapon;
using EntityStates.Huntress.Weapon;
using HG.GeneralSerializer;
using HarmonyLib;
using RoR2;
using RoR2.ContentManagement;
using RoR2.Orbs;
using RoR2.Skills;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[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("BouncingHuntress")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("BouncingHuntress")]
[assembly: AssemblyTitle("BouncingHuntress")]
[assembly: AssemblyVersion("1.1.0.0")]
namespace BouncingHuntress
{
	[BepInPlugin("com.calvin.BouncingHuntress", "BouncingHuntress", "1.1.0")]
	public class BouncingHuntressPlugin : BaseUnityPlugin
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static CollectContentPackProvidersDelegate <>9__3_0;

			internal void <Awake>b__3_0(AddContentPackProviderDelegate add)
			{
				add.Invoke((IContentPackProvider)(object)new BHContent());
			}
		}

		public const string GUID = "com.calvin.BouncingHuntress";

		public const string Name = "BouncingHuntress";

		public const string Version = "1.1.0";

		private void Awake()
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_006d: Expected O, but got Unknown
			GreenFx.Prefix = "BouncingHuntress";
			GlaiveModule.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
			StrafeModule.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
			PhaseBurstModule.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
			ChainBallistaModule.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
			object obj = <>c.<>9__3_0;
			if (obj == null)
			{
				CollectContentPackProvidersDelegate val = delegate(AddContentPackProviderDelegate add)
				{
					add.Invoke((IContentPackProvider)(object)new BHContent());
				};
				<>c.<>9__3_0 = val;
				obj = (object)val;
			}
			ContentManager.collectContentPackProviders += (CollectContentPackProvidersDelegate)obj;
			Harmony val2 = new Harmony("com.calvin.BouncingHuntress");
			val2.PatchAll(typeof(GlaivePatches));
			val2.PatchAll(typeof(BouncingHuntress.Strafe.LanguagePatches));
			val2.PatchAll(typeof(BouncingHuntress.PhaseBurst.LanguagePatches));
			val2.PatchAll(typeof(BouncingHuntress.ChainBallista.LanguagePatches));
			val2.PatchAll(typeof(SharedPatches));
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Bouncing Huntress loaded: " + BHContent.SkillDefs.Count + " skills, " + GreenFx.EffectsToRegister.Count + " green effects."));
		}
	}
	internal class BHContent : IContentPackProvider
	{
		internal static readonly List<SkillDef> SkillDefs = new List<SkillDef>();

		internal static readonly List<Type> StateTypes = new List<Type>();

		private readonly ContentPack contentPack = new ContentPack();

		public string identifier => "com.calvin.BouncingHuntress";

		public IEnumerator LoadStaticContentAsync(LoadStaticContentAsyncArgs args)
		{
			contentPack.skillDefs.Add(SkillDefs.ToArray());
			contentPack.entityStateTypes.Add(StateTypes.ToArray());
			List<EffectDef> list = new List<EffectDef>();
			foreach (GameObject item in GreenFx.EffectsToRegister)
			{
				if (Object.op_Implicit((Object)(object)item))
				{
					list.Add(new EffectDef(item));
				}
			}
			contentPack.effectDefs.Add(list.ToArray());
			args.ReportProgress(1f);
			yield break;
		}

		public IEnumerator GenerateContentPackAsync(GetContentPackAsyncArgs args)
		{
			ContentPack.Copy(contentPack, args.output);
			args.ReportProgress(1f);
			yield break;
		}

		public IEnumerator FinalizeAsync(FinalizeAsyncArgs args)
		{
			args.ReportProgress(1f);
			yield break;
		}
	}
	internal static class SharedPatches
	{
		[HarmonyPatch(typeof(TemporaryOverlayInstance), "AddToCharacterModel")]
		[HarmonyPrefix]
		private static void AddOverlay_Prefix(TemporaryOverlayInstance __instance)
		{
			GreenFx.OverlayPrefix(__instance);
		}
	}
}
namespace BouncingHuntress.Strafe
{
	public class FireEndlessArrow : FireSeekingArrow
	{
		private const float DefaultHuntressRange = 60f;

		private static readonly FieldInfo[] tunedFields = typeof(FireSeekingArrow).GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);

		public FireEndlessArrow()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			FireSeekingArrow obj = new FireSeekingArrow();
			FieldInfo[] array = tunedFields;
			foreach (FieldInfo fieldInfo in array)
			{
				fieldInfo.SetValue(this, fieldInfo.GetValue(obj));
			}
			if (Object.op_Implicit((Object)(object)StrafeModule.GreenMuzzleFlash))
			{
				base.muzzleflashEffectPrefab = StrafeModule.GreenMuzzleFlash;
			}
		}

		protected override GenericDamageOrb CreateArrowOrb()
		{
			HuntressTracker val = (Object.op_Implicit((Object)(object)((EntityState)this).gameObject) ? ((EntityState)this).gameObject.GetComponent<HuntressTracker>() : null);
			return (GenericDamageOrb)(object)new EndlessArrowOrb
			{
				bounceRange = (Object.op_Implicit((Object)(object)val) ? val.maxTrackingDistance : 60f),
				hitThisRound = new HashSet<HealthComponent>()
			};
		}
	}
	public class EndlessArrowOrb : HuntressArrowOrb
	{
		private const float MinBounceTime = 0.1f;

		public float bounceRange = 60f;

		public HashSet<HealthComponent> hitThisRound;

		public int bounceCount;

		public float originalDamage;

		public float originalProcCoefficient;

		private static readonly BullseyeSearch search = new BullseyeSearch();

		protected override GameObject GetOrbEffect()
		{
			if (!Object.op_Implicit((Object)(object)StrafeModule.GreenArrowOrb))
			{
				return ((HuntressArrowOrb)this).GetOrbEffect();
			}
			return StrafeModule.GreenArrowOrb;
		}

		public override void Begin()
		{
			((HuntressArrowOrb)this).Begin();
			if (bounceCount > 0 && ((Orb)this).duration < 0.1f)
			{
				((Orb)this).duration = 0.1f;
			}
		}

		public override void OnArrival()
		{
			//IL_0092: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: 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_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: 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)
			((GenericDamageOrb)this).OnArrival();
			if (!Object.op_Implicit((Object)(object)((Orb)this).target))
			{
				return;
			}
			int value = StrafeModule.BouncesPerShot.Value;
			if (value > 0 && bounceCount >= value)
			{
				return;
			}
			if (bounceCount == 0)
			{
				originalDamage = ((GenericDamageOrb)this).damageValue;
				originalProcCoefficient = ((GenericDamageOrb)this).procCoefficient;
			}
			float num = 1f - Mathf.Max(0f, StrafeModule.FalloffPerBounce.Value) * (float)(bounceCount + 1);
			if (num <= 0.001f)
			{
				return;
			}
			HealthComponent healthComponent = ((Orb)this).target.healthComponent;
			Vector3 position = ((Component)((Orb)this).target).transform.position;
			if (hitThisRound == null)
			{
				hitThisRound = new HashSet<HealthComponent>();
			}
			if (Object.op_Implicit((Object)(object)healthComponent))
			{
				hitThisRound.Add(healthComponent);
			}
			HurtBox val = FindNextTarget(position, healthComponent);
			if (!Object.op_Implicit((Object)(object)val))
			{
				hitThisRound.Clear();
				if (Object.op_Implicit((Object)(object)healthComponent))
				{
					hitThisRound.Add(healthComponent);
				}
				val = FindNextTarget(position, healthComponent);
			}
			if (Object.op_Implicit((Object)(object)val))
			{
				EndlessArrowOrb endlessArrowOrb = new EndlessArrowOrb
				{
					damageValue = originalDamage * num,
					isCrit = ((GenericDamageOrb)this).isCrit,
					attacker = ((GenericDamageOrb)this).attacker,
					teamIndex = ((GenericDamageOrb)this).teamIndex,
					procCoefficient = originalProcCoefficient * Mathf.Max(0f, StrafeModule.BounceProcMultiplier.Value),
					originalDamage = originalDamage,
					originalProcCoefficient = originalProcCoefficient,
					procChainMask = ((GenericDamageOrb)this).procChainMask,
					damageColorIndex = ((GenericDamageOrb)this).damageColorIndex,
					damageType = ((GenericDamageOrb)this).damageType,
					scale = ((GenericDamageOrb)this).scale,
					bounceRange = bounceRange,
					hitThisRound = hitThisRound,
					bounceCount = bounceCount + 1,
					origin = position,
					target = val
				};
				OrbManager.instance.AddOrb((Orb)(object)endlessArrowOrb);
			}
		}

		private HurtBox FindNextTarget(Vector3 from, HealthComponent current)
		{
			//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)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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)
			//IL_0028: 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_0033: 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)
			TeamMask allButNeutral = TeamMask.allButNeutral;
			((TeamMask)(ref allButNeutral)).RemoveTeam(((GenericDamageOrb)this).teamIndex);
			search.searchOrigin = from;
			search.searchDirection = Vector3.zero;
			search.teamMaskFilter = allButNeutral;
			search.filterByLoS = false;
			search.filterByDistinctEntity = true;
			search.sortMode = (SortMode)1;
			search.maxDistanceFilter = bounceRange;
			search.RefreshCandidates();
			foreach (HurtBox result in search.GetResults())
			{
				HealthComponent val = (Object.op_Implicit((Object)(object)result) ? result.healthComponent : null);
				if (Object.op_Implicit((Object)(object)val) && val.alive && !((Object)(object)val == (Object)(object)current) && !hitThisRound.Contains(val))
				{
					return result;
				}
			}
			return null;
		}
	}
	internal static class StrafeModule
	{
		private const string Section = "Bouncing Strafe";

		public const string NameToken = "HUNTRESS_PRIMARY_ENDLESSSTRAFE_NAME";

		public const string DescriptionToken = "HUNTRESS_PRIMARY_ENDLESSSTRAFE_DESCRIPTION";

		private const string VanillaStrafeKey = "RoR2/Base/Huntress/HuntressBodyFireSeekingArrow.asset";

		private const string PrimaryFamilyKey = "RoR2/Base/Huntress/HuntressBodyPrimaryFamily.asset";

		internal static ManualLogSource Log;

		internal static ConfigEntry<int> BouncesPerShot;

		internal static ConfigEntry<float> FalloffPerBounce;

		internal static ConfigEntry<float> BounceProcMultiplier;

		internal static SkillDef EndlessStrafeSkillDef;

		internal static GameObject GreenArrowOrb;

		internal static GameObject GreenMuzzleFlash;

		private const string FireSeekingArrowConfigKey = "RoR2/Base/Huntress/EntityStates.Huntress.HuntressWeapon.FireSeekingArrow.asset";

		internal static void Init(ConfigFile Config, ManualLogSource logger)
		{
			Log = logger;
			FalloffPerBounce = Config.Bind<float>("Bouncing Strafe", "FalloffPerBounce", 0.25f, "Each bounce loses this fraction of the arrow's original damage. 0.25 = 100% / 75% / 50% / 25%. 0 = no falloff. An arrow stops bouncing once its damage would reach 0.");
			BounceProcMultiplier = Config.Bind<float>("Bouncing Strafe", "BounceProcMultiplier", 0.5f, "Proc coefficient of bounces, relative to the first hit (0.5 = half as likely to trigger on-hit items). 1 = same as the first hit.");
			BouncesPerShot = Config.Bind<int>("Bouncing Strafe", "BouncesPerShot", 3, "How many times each arrow bounces after its first hit. 0 = unlimited.\nOnly the host's setting matters in multiplayer.");
			CreateSkill();
			if (Object.op_Implicit((Object)(object)EndlessStrafeSkillDef))
			{
				BHContent.SkillDefs.Add(EndlessStrafeSkillDef);
			}
			BHContent.StateTypes.Add(typeof(FireEndlessArrow));
			GreenArrowOrb = GreenFx.CloneEffect(GreenFx.LoadLegacy("Prefabs/Effects/OrbEffects/ArrowOrbEffect"));
			GreenMuzzleFlash = GreenFx.CloneEffect(GreenFx.FromStateConfig<GameObject>("RoR2/Base/Huntress/EntityStates.Huntress.HuntressWeapon.FireSeekingArrow.asset", "muzzleflashEffectPrefab"));
			Log.LogInfo((object)("Green visuals: arrow " + (Object.op_Implicit((Object)(object)GreenArrowOrb) ? "ok" : "missing") + ", flash " + (Object.op_Implicit((Object)(object)GreenMuzzleFlash) ? "ok" : "missing") + "."));
			LanguagePatches.ApplyToLoaded();
			Log.LogInfo((object)("Bouncing Strafe loaded (" + BouncesPerShot.Value + " bounces per shot)."));
		}

		private static void CreateSkill()
		{
			//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)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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_00fd: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			SkillDef val = Addressables.LoadAssetAsync<SkillDef>((object)"RoR2/Base/Huntress/HuntressBodyFireSeekingArrow.asset").WaitForCompletion();
			SkillFamily val2 = Addressables.LoadAssetAsync<SkillFamily>((object)"RoR2/Base/Huntress/HuntressBodyPrimaryFamily.asset").WaitForCompletion();
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val2))
			{
				Log.LogError((object)"Could not load the vanilla Strafe skill or Huntress primary family. The game's asset paths may have changed.");
				return;
			}
			SkillDef val3 = Object.Instantiate<SkillDef>(val);
			((Object)val3).name = "HuntressBodyEndlessStrafe";
			val3.skillName = "EndlessStrafe";
			val3.skillNameToken = "HUNTRESS_PRIMARY_ENDLESSSTRAFE_NAME";
			val3.skillDescriptionToken = "HUNTRESS_PRIMARY_ENDLESSSTRAFE_DESCRIPTION";
			val3.activationState = new SerializableEntityStateType(typeof(FireEndlessArrow));
			val3.icon = GreenFx.GreenIcon(val.icon);
			EndlessStrafeSkillDef = val3;
			int num = val2.variants.Length;
			Array.Resize(ref val2.variants, num + 1);
			Variant[] variants = val2.variants;
			Variant val4 = new Variant
			{
				skillDef = val3,
				unlockableName = "",
				unlockableDef = null
			};
			((Variant)(ref val4)).viewableNode = new Node(val3.skillNameToken, false, (Node)null);
			variants[num] = val4;
		}
	}
	internal static class LanguagePatches
	{
		private static string Description()
		{
			int value = StrafeModule.BouncesPerShot.Value;
			string text = ((value > 0) ? ("bounces up to <style=cIsUtility>" + value + "</style> " + ((value == 1) ? "time" : "times") + ((StrafeModule.FalloffPerBounce.Value > 0f) ? " with <style=cIsDamage>diminishing damage</style>" : "")) : "bounces <style=cIsUtility>endlessly</style> between enemies");
			return "<style=cIsUtility>Agile</style>. Quickly fire a seeking arrow for <style=cIsDamage>150% damage</style> that " + text + ".";
		}

		private static void Apply(Language language)
		{
			if (language != null)
			{
				language.SetStringByToken("HUNTRESS_PRIMARY_ENDLESSSTRAFE_NAME", "Bouncing Strafe");
				language.SetStringByToken("HUNTRESS_PRIMARY_ENDLESSSTRAFE_DESCRIPTION", Description());
			}
		}

		internal static void ApplyToLoaded()
		{
			try
			{
				Apply(Language.currentLanguage);
			}
			catch
			{
			}
		}

		[HarmonyPatch(typeof(Language), "LoadStrings")]
		[HarmonyPostfix]
		private static void LoadStrings_Postfix(Language __instance)
		{
			Apply(__instance);
		}
	}
}
namespace BouncingHuntress.Shared
{
	internal static class GreenFx
	{
		internal const float GreenHue = 0.36f;

		internal static string Prefix = "Mod";

		internal static readonly List<GameObject> EffectsToRegister = new List<GameObject>();

		private static GameObject holder;

		private static readonly Dictionary<GameObject, GameObject> effectCache = new Dictionary<GameObject, GameObject>();

		private static readonly HashSet<Material> greenMaterials = new HashSet<Material>();

		private const int MaxLinkedDepth = 3;

		private static readonly Dictionary<Material, Material> materialCache = new Dictionary<Material, Material>();

		private static readonly Dictionary<Texture, Texture> textureCache = new Dictionary<Texture, Texture>();

		internal static bool GreenOverlays;

		internal static T FromStateConfig<T>(string configKey, string fieldName) where T : Object
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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)
			try
			{
				EntityStateConfiguration val = Addressables.LoadAssetAsync<EntityStateConfiguration>((object)configKey).WaitForCompletion();
				if (!Object.op_Implicit((Object)(object)val) || val.serializedFieldsCollection.serializedFields == null)
				{
					return default(T);
				}
				SerializedField[] serializedFields = val.serializedFieldsCollection.serializedFields;
				foreach (SerializedField val2 in serializedFields)
				{
					if (val2.fieldName == fieldName)
					{
						Object objectValue = val2.fieldValue.objectValue;
						return (T)(object)((objectValue is T) ? objectValue : null);
					}
				}
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[" + Prefix + "] Couldn't read " + fieldName + " from " + configKey + ": " + ex.Message));
			}
			return default(T);
		}

		internal static GameObject LoadLegacy(string path)
		{
			try
			{
				return LegacyResourcesAPI.Load<GameObject>(path);
			}
			catch
			{
				return null;
			}
		}

		internal static GameObject CloneEffect(GameObject vanilla)
		{
			return CloneEffect(vanilla, 0);
		}

		private static GameObject CloneEffect(GameObject vanilla, int depth)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)vanilla))
			{
				return null;
			}
			if (effectCache.TryGetValue(vanilla, out var value))
			{
				return value;
			}
			if (!Object.op_Implicit((Object)(object)holder))
			{
				holder = new GameObject(Prefix + "_GreenPrefabs");
				Object.DontDestroyOnLoad((Object)(object)holder);
				holder.SetActive(false);
			}
			GameObject val = Object.Instantiate<GameObject>(vanilla, holder.transform);
			((Object)val).name = Prefix + "_Green_" + ((Object)vanilla).name;
			effectCache[vanilla] = val;
			try
			{
				Recolor(val);
				if (depth < 3)
				{
					GreenLinkedEffects(val, depth);
				}
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[" + Prefix + "] Couldn't fully recolor " + ((Object)vanilla).name + ": " + ex.Message));
			}
			if (Object.op_Implicit((Object)(object)val.GetComponent<EffectComponent>()))
			{
				EffectsToRegister.Add(val);
			}
			return val;
		}

		private static void GreenLinkedEffects(GameObject root, int depth)
		{
			MonoBehaviour[] componentsInChildren = root.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if (!Object.op_Implicit((Object)(object)val))
				{
					continue;
				}
				Type type = ((object)val).GetType();
				while (type != null && type != typeof(MonoBehaviour))
				{
					FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (FieldInfo fieldInfo in fields)
					{
						if (!fieldInfo.IsPublic && ((MemberInfo)fieldInfo).GetCustomAttribute<SerializeField>() == null)
						{
							continue;
						}
						if (fieldInfo.FieldType == typeof(GameObject))
						{
							object? value = fieldInfo.GetValue(val);
							GameObject val2 = GreenLinked((GameObject)((value is GameObject) ? value : null), depth);
							if (Object.op_Implicit((Object)(object)val2))
							{
								fieldInfo.SetValue(val, val2);
							}
						}
						else
						{
							if (!(fieldInfo.FieldType == typeof(GameObject[])) || !(fieldInfo.GetValue(val) is GameObject[] array))
							{
								continue;
							}
							for (int k = 0; k < array.Length; k++)
							{
								GameObject val3 = GreenLinked(array[k], depth);
								if (Object.op_Implicit((Object)(object)val3))
								{
									array[k] = val3;
								}
							}
						}
					}
					type = type.BaseType;
				}
			}
		}

		private static GameObject GreenLinked(GameObject linked, int depth)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)linked))
			{
				Scene scene = linked.scene;
				if (!((Scene)(ref scene)).IsValid() && Object.op_Implicit((Object)(object)linked.GetComponent<EffectComponent>()))
				{
					return CloneEffect(linked, depth + 1);
				}
			}
			return null;
		}

		internal static void Recolor(GameObject root)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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)
			//IL_0045: 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)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_009a: 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)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			ParticleSystem[] componentsInChildren = root.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem obj in componentsInChildren)
			{
				MainModule main = obj.main;
				((MainModule)(ref main)).startColor = Shift(((MainModule)(ref main)).startColor);
				ColorOverLifetimeModule colorOverLifetime = obj.colorOverLifetime;
				if (((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled)
				{
					((ColorOverLifetimeModule)(ref colorOverLifetime)).color = Shift(((ColorOverLifetimeModule)(ref colorOverLifetime)).color);
				}
				ColorBySpeedModule colorBySpeed = obj.colorBySpeed;
				if (((ColorBySpeedModule)(ref colorBySpeed)).enabled)
				{
					((ColorBySpeedModule)(ref colorBySpeed)).color = Shift(((ColorBySpeedModule)(ref colorBySpeed)).color);
				}
				TrailModule trails = obj.trails;
				if (((TrailModule)(ref trails)).enabled)
				{
					((TrailModule)(ref trails)).colorOverLifetime = Shift(((TrailModule)(ref trails)).colorOverLifetime);
					((TrailModule)(ref trails)).colorOverTrail = Shift(((TrailModule)(ref trails)).colorOverTrail);
				}
			}
			Renderer[] componentsInChildren2 = root.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren2)
			{
				Material[] sharedMaterials = val.sharedMaterials;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					sharedMaterials[j] = GreenMaterial(sharedMaterials[j]);
				}
				val.sharedMaterials = sharedMaterials;
				ParticleSystemRenderer val2 = (ParticleSystemRenderer)(object)((val is ParticleSystemRenderer) ? val : null);
				if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.trailMaterial))
				{
					val2.trailMaterial = GreenMaterial(val2.trailMaterial);
				}
				LineRenderer val3 = (LineRenderer)(object)((val is LineRenderer) ? val : null);
				if (Object.op_Implicit((Object)(object)val3))
				{
					val3.colorGradient = Shift(val3.colorGradient);
				}
				TrailRenderer val4 = (TrailRenderer)(object)((val is TrailRenderer) ? val : null);
				if (Object.op_Implicit((Object)(object)val4))
				{
					val4.colorGradient = Shift(val4.colorGradient);
				}
			}
			Light[] componentsInChildren3 = root.GetComponentsInChildren<Light>(true);
			foreach (Light obj2 in componentsInChildren3)
			{
				obj2.color = Shift(obj2.color);
			}
		}

		internal static Material GreenMaterial(Material original)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//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)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Invalid comparison between Unknown and I4
			//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)
			if (!Object.op_Implicit((Object)(object)original) || greenMaterials.Contains(original))
			{
				return original;
			}
			if (materialCache.TryGetValue(original, out var value))
			{
				return value;
			}
			Material val = new Material(original)
			{
				name = ((Object)original).name + "_Green"
			};
			Shader shader = original.shader;
			int num = (Object.op_Implicit((Object)(object)shader) ? shader.GetPropertyCount() : 0);
			for (int i = 0; i < num; i++)
			{
				string propertyName = shader.GetPropertyName(i);
				ShaderPropertyType propertyType = shader.GetPropertyType(i);
				if ((int)propertyType == 0)
				{
					val.SetColor(propertyName, Shift(original.GetColor(propertyName)));
				}
				else
				{
					if ((int)propertyType != 4)
					{
						continue;
					}
					string text = propertyName.ToLowerInvariant();
					if (!text.Contains("normal") && !text.Contains("bump") && !text.Contains("distort"))
					{
						Texture texture = original.GetTexture(propertyName);
						if (texture is Texture2D)
						{
							val.SetTexture(propertyName, GreenTexture(texture));
						}
					}
				}
			}
			materialCache[original] = val;
			greenMaterials.Add(val);
			return val;
		}

		internal static Texture GreenTexture(Texture original)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			if (!(original is Texture2D))
			{
				return original;
			}
			if (textureCache.TryGetValue(original, out var value))
			{
				return value;
			}
			Texture2D val = ReadableCopy(original, new Rect(0f, 0f, (float)original.width, (float)original.height));
			if (!Object.op_Implicit((Object)(object)val))
			{
				textureCache[original] = original;
				return original;
			}
			Color32[] pixels = val.GetPixels32();
			for (int i = 0; i < pixels.Length; i++)
			{
				pixels[i] = Color32.op_Implicit(Shift(Color32.op_Implicit(pixels[i])));
			}
			val.SetPixels32(pixels);
			val.Apply(true, false);
			((Object)val).name = ((Object)original).name + "_Green";
			((Texture)val).wrapMode = original.wrapMode;
			((Texture)val).filterMode = original.filterMode;
			((Texture)val).anisoLevel = original.anisoLevel;
			textureCache[original] = (Texture)(object)val;
			return (Texture)(object)val;
		}

		internal static Sprite GreenIcon(Sprite original)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)original))
			{
				return original;
			}
			try
			{
				Rect textureRect = original.textureRect;
				Texture2D val = ReadableCopy((Texture)(object)original.texture, textureRect);
				if (!Object.op_Implicit((Object)(object)val))
				{
					return original;
				}
				Color32[] pixels = val.GetPixels32();
				for (int i = 0; i < pixels.Length; i++)
				{
					pixels[i] = Color32.op_Implicit(Tint(Color32.op_Implicit(pixels[i])));
				}
				val.SetPixels32(pixels);
				val.Apply(true, false);
				((Object)val).name = ((Object)original).name + "_Green";
				((Texture)val).wrapMode = (TextureWrapMode)1;
				Vector2 val2 = default(Vector2);
				((Vector2)(ref val2))..ctor(original.pivot.x / ((Rect)(ref textureRect)).width, original.pivot.y / ((Rect)(ref textureRect)).height);
				Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), val2, original.pixelsPerUnit);
				((Object)obj).name = ((Object)original).name + "_Green";
				return obj;
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[" + Prefix + "] Couldn't tint icon " + ((Object)original).name + ": " + ex.Message));
				return original;
			}
		}

		private static Texture2D ReadableCopy(Texture source, Rect region)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)source))
			{
				return null;
			}
			RenderTexture active = RenderTexture.active;
			RenderTexture temporary = RenderTexture.GetTemporary(source.width, source.height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
			try
			{
				Graphics.Blit(source, temporary);
				RenderTexture.active = temporary;
				int num = Mathf.Max(1, Mathf.RoundToInt(((Rect)(ref region)).width));
				int num2 = Mathf.Max(1, Mathf.RoundToInt(((Rect)(ref region)).height));
				Texture2D val = new Texture2D(num, num2, (TextureFormat)4, true, false);
				val.ReadPixels(new Rect(((Rect)(ref region)).x, ((Rect)(ref region)).y, (float)num, (float)num2), 0, 0, false);
				val.Apply(false, false);
				return val;
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[" + Prefix + "] Couldn't copy texture " + ((Object)source).name + ": " + ex.Message));
				return null;
			}
			finally
			{
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
			}
		}

		internal static Color Shift(Color c)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_0026: 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_0014: Unknown result type (might be due to invalid IL or missing references)
			float num = default(float);
			float num2 = default(float);
			float num3 = default(float);
			Color.RGBToHSV(c, ref num, ref num2, ref num3);
			if (num2 < 0.08f)
			{
				return c;
			}
			Color result = Color.HSVToRGB(0.36f, num2, num3, true);
			result.a = c.a;
			return result;
		}

		private static Color Tint(Color c)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			float num = default(float);
			float num2 = default(float);
			float num3 = default(float);
			Color.RGBToHSV(c, ref num, ref num2, ref num3);
			Color result = Color.HSVToRGB(0.36f, Mathf.Max(num2, 0.55f), num3);
			result.a = c.a;
			return result;
		}

		internal static Gradient Shift(Gradient g)
		{
			//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)
			//IL_0028: 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_003c: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			if (g == null)
			{
				return null;
			}
			GradientColorKey[] colorKeys = g.colorKeys;
			for (int i = 0; i < colorKeys.Length; i++)
			{
				colorKeys[i].color = Shift(colorKeys[i].color);
			}
			Gradient val = new Gradient
			{
				mode = g.mode
			};
			val.SetKeys(colorKeys, g.alphaKeys);
			return val;
		}

		internal static MinMaxGradient Shift(MinMaxGradient m)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_0022: Expected I4, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_0060: 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_003d: 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_0049: 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_007e: 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)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			ParticleSystemGradientMode mode = ((MinMaxGradient)(ref m)).mode;
			switch ((int)mode)
			{
			case 0:
				return new MinMaxGradient(Shift(((MinMaxGradient)(ref m)).color));
			case 2:
				return new MinMaxGradient(Shift(((MinMaxGradient)(ref m)).colorMin), Shift(((MinMaxGradient)(ref m)).colorMax));
			case 1:
				return new MinMaxGradient(Shift(((MinMaxGradient)(ref m)).gradient));
			case 3:
				return new MinMaxGradient(Shift(((MinMaxGradient)(ref m)).gradientMin), Shift(((MinMaxGradient)(ref m)).gradientMax));
			case 4:
			{
				MinMaxGradient result = default(MinMaxGradient);
				((MinMaxGradient)(ref result))..ctor(Shift(((MinMaxGradient)(ref m)).gradient));
				((MinMaxGradient)(ref result)).mode = (ParticleSystemGradientMode)4;
				return result;
			}
			default:
				return m;
			}
		}

		internal static void OverlayPrefix(TemporaryOverlayInstance instance)
		{
			if (GreenOverlays && instance != null && Object.op_Implicit((Object)(object)instance.originalMaterial))
			{
				instance.originalMaterial = GreenMaterial(instance.originalMaterial);
			}
		}
	}
}
namespace BouncingHuntress.PhaseBurst
{
	internal static class PhaseBurstModule
	{
		private const string Section = "Phase Burst";

		public const string NameToken = "HUNTRESS_UTILITY_PHASEBURST_NAME";

		public const string DescriptionToken = "HUNTRESS_UTILITY_PHASEBURST_DESCRIPTION";

		private const string UtilityFamilyKey = "RoR2/Base/Huntress/HuntressBodyUtilityFamily.asset";

		internal static ManualLogSource Log;

		internal static ConfigEntry<float> Radius;

		internal static ConfigEntry<float> DamageCoefficient;

		internal static ConfigEntry<string> VisualEffectKey;

		internal static ConfigEntry<float> VisualScale;

		internal static SkillDef PhaseBurstSkillDef;

		internal static GameObject BurstEffectPrefab;

		internal static GameObject GreenBlinkEffect;

		internal static void Init(ConfigFile Config, ManualLogSource logger)
		{
			Log = logger;
			DamageCoefficient = Config.Bind<float>("Phase Burst", "Damage", 3f, "Burst damage as a multiple of Huntress's base damage (3 = 300%, about Laser Glaive's 2nd bounce).");
			Radius = Config.Bind<float>("Phase Burst", "Radius", 6f, "Radius (meters) of the damage burst at the end of each blink (the green visual follows it).");
			VisualEffectKey = Config.Bind<string>("Phase Burst", "EffectAsset", "RoR2/Base/Captain/CaptainTazerNova.prefab", "Game effect used for the burst (an Addressables key); it's recolored green. Leave empty for no visual.");
			VisualScale = Config.Bind<float>("Phase Burst", "SizeMultiplier", 1f, "Multiplies the visual's size. 1 = drawn at the damage radius. Tweak if it looks bigger or smaller than the hit area.");
			CreateSkill();
			if (Object.op_Implicit((Object)(object)PhaseBurstSkillDef))
			{
				BHContent.SkillDefs.Add(PhaseBurstSkillDef);
			}
			BHContent.StateTypes.Add(typeof(PhaseBurstState));
			CreateBurstEffect();
			GreenBlinkEffect = GreenFx.CloneEffect(GreenFx.FromStateConfig<GameObject>("RoR2/Base/Huntress/EntityStates.Huntress.MiniBlinkState.asset", "blinkPrefab") ?? GreenFx.FromStateConfig<GameObject>("RoR2/Base/Huntress/EntityStates.Huntress.BlinkState.asset", "blinkPrefab"));
			Log.LogInfo((object)("Green visuals: burst " + (Object.op_Implicit((Object)(object)BurstEffectPrefab) ? "ok" : "missing") + ", blink " + (Object.op_Implicit((Object)(object)GreenBlinkEffect) ? "ok" : "missing") + "."));
			LanguagePatches.ApplyToLoaded();
			Log.LogInfo((object)"Phase Burst loaded.");
		}

		private static void CreateBurstEffect()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			string value = VisualEffectKey.Value;
			if (string.IsNullOrEmpty(value))
			{
				return;
			}
			GameObject val = null;
			try
			{
				val = Addressables.LoadAssetAsync<GameObject>((object)value).WaitForCompletion();
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Burst visual '" + value + "' failed to load: " + ex.Message));
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				Log.LogWarning((object)("Burst visual '" + value + "' not found; the burst will be invisible."));
				return;
			}
			GameObject val2 = GreenFx.CloneEffect(val);
			EffectComponent val3 = (Object.op_Implicit((Object)(object)val2) ? val2.GetComponent<EffectComponent>() : null);
			if (!Object.op_Implicit((Object)(object)val3))
			{
				Log.LogWarning((object)("Burst visual '" + value + "' isn't a game effect; the burst will be invisible."));
				return;
			}
			val3.applyScale = true;
			BurstEffectPrefab = val2;
		}

		private static void CreateSkill()
		{
			//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)
			//IL_003f: 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_0046: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Expected O, but got Unknown
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			SkillFamily val = Addressables.LoadAssetAsync<SkillFamily>((object)"RoR2/Base/Huntress/HuntressBodyUtilityFamily.asset").WaitForCompletion();
			if (!Object.op_Implicit((Object)(object)val))
			{
				Log.LogError((object)"Could not load Huntress's utility skill family.");
				return;
			}
			SkillDef val2 = null;
			Variant[] variants = val.variants;
			foreach (Variant val3 in variants)
			{
				if (Object.op_Implicit((Object)(object)val3.skillDef) && ((SerializableEntityStateType)(ref val3.skillDef.activationState)).stateType == typeof(MiniBlinkState))
				{
					val2 = val3.skillDef;
					break;
				}
			}
			if (!Object.op_Implicit((Object)(object)val2))
			{
				Log.LogError((object)"Could not find Phase Blink in Huntress's utility skills.");
				return;
			}
			SkillDef val4 = Object.Instantiate<SkillDef>(val2);
			((Object)val4).name = "HuntressBodyPhaseBurst";
			val4.skillName = "PhaseBurst";
			val4.skillNameToken = "HUNTRESS_UTILITY_PHASEBURST_NAME";
			val4.skillDescriptionToken = "HUNTRESS_UTILITY_PHASEBURST_DESCRIPTION";
			val4.activationState = new SerializableEntityStateType(typeof(PhaseBurstState));
			val4.icon = GreenFx.GreenIcon(val2.icon);
			PhaseBurstSkillDef = val4;
			int num = val.variants.Length;
			Array.Resize(ref val.variants, num + 1);
			Variant[] variants2 = val.variants;
			Variant val5 = new Variant
			{
				skillDef = val4,
				unlockableName = "",
				unlockableDef = null
			};
			((Variant)(ref val5)).viewableNode = new Node(val4.skillNameToken, false, (Node)null);
			variants2[num] = val5;
		}
	}
	internal static class LanguagePatches
	{
		private static string Description()
		{
			return "<style=cIsUtility>Agile</style>. <style=cIsUtility>Disappear</style> and <style=cIsUtility>teleport</style> a short distance, then release a burst that deals <style=cIsDamage>" + Mathf.RoundToInt(PhaseBurstModule.DamageCoefficient.Value * 100f) + "% damage</style> around you. If it kills, <style=cIsUtility>restore a charge</style>. Can store up to <style=cIsUtility>3</style> charges.";
		}

		private static void Apply(Language language)
		{
			if (language != null)
			{
				language.SetStringByToken("HUNTRESS_UTILITY_PHASEBURST_NAME", "Phase Burst");
				language.SetStringByToken("HUNTRESS_UTILITY_PHASEBURST_DESCRIPTION", Description());
			}
		}

		internal static void ApplyToLoaded()
		{
			try
			{
				Apply(Language.currentLanguage);
			}
			catch
			{
			}
		}

		[HarmonyPatch(typeof(Language), "LoadStrings")]
		[HarmonyPostfix]
		private static void LoadStrings_Postfix(Language __instance)
		{
			Apply(__instance);
		}
	}
	public class PhaseBurstState : MiniBlinkState
	{
		private static readonly FieldInfo[] tunedFields = typeof(BlinkState).GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);

		public PhaseBurstState()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			MiniBlinkState obj = new MiniBlinkState();
			FieldInfo[] array = tunedFields;
			foreach (FieldInfo fieldInfo in array)
			{
				fieldInfo.SetValue(this, fieldInfo.GetValue(obj));
			}
		}

		public override void OnEnter()
		{
			GameObject blinkPrefab = BlinkState.blinkPrefab;
			if (Object.op_Implicit((Object)(object)PhaseBurstModule.GreenBlinkEffect))
			{
				BlinkState.blinkPrefab = PhaseBurstModule.GreenBlinkEffect;
			}
			try
			{
				((BlinkState)this).OnEnter();
			}
			finally
			{
				BlinkState.blinkPrefab = blinkPrefab;
			}
		}

		public override void OnExit()
		{
			bool flag = Object.op_Implicit((Object)(object)((EntityState)this).outer) && ((EntityState)this).outer.destroying;
			GameObject blinkPrefab = BlinkState.blinkPrefab;
			if (Object.op_Implicit((Object)(object)PhaseBurstModule.GreenBlinkEffect))
			{
				BlinkState.blinkPrefab = PhaseBurstModule.GreenBlinkEffect;
			}
			GreenFx.GreenOverlays = true;
			try
			{
				((BlinkState)this).OnExit();
			}
			finally
			{
				BlinkState.blinkPrefab = blinkPrefab;
				GreenFx.GreenOverlays = false;
			}
			if (!flag && ((EntityState)this).isAuthority && Object.op_Implicit((Object)(object)((EntityState)this).characterBody))
			{
				PhaseBurstAttack.Fire(((EntityState)this).characterBody);
			}
		}
	}
	internal static class PhaseBurstAttack
	{
		private static bool loggedFirst;

		internal static float GlaiveFinalBounceCoefficient()
		{
			float num = ThrowGlaive.damageCoefficient * Mathf.Pow(ThrowGlaive.damageCoefficientPerBounce, (float)ThrowGlaive.maxBounceCount);
			if (!(num > 0f))
			{
				return 4.43f;
			}
			return num;
		}

		internal static void Fire(CharacterBody body)
		{
			//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_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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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)
			//IL_00c9: 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_00e1: 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_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_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: 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_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: 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_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Expected O, but got Unknown
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Max(0.5f, PhaseBurstModule.Radius.Value);
			Vector3 corePosition = body.corePosition;
			TeamIndex teamIndex = (TeamIndex)((!Object.op_Implicit((Object)(object)body.teamComponent)) ? 1 : ((int)body.teamComponent.teamIndex));
			HashSet<HealthComponent> hashSet = new HashSet<HealthComponent>();
			float num2 = num + 2f;
			LayerIndex entityPrecise = LayerIndex.entityPrecise;
			Collider[] array = Physics.OverlapSphere(corePosition, num2, LayerMask.op_Implicit(((LayerIndex)(ref entityPrecise)).mask), (QueryTriggerInteraction)2);
			for (int i = 0; i < array.Length; i++)
			{
				HurtBox component = ((Component)array[i]).GetComponent<HurtBox>();
				HealthComponent val = (Object.op_Implicit((Object)(object)component) ? component.healthComponent : null);
				if (Object.op_Implicit((Object)(object)val) && val.alive && (Object)(object)((Component)val).gameObject != (Object)(object)((Component)body).gameObject)
				{
					hashSet.Add(val);
				}
			}
			BlastAttack val2 = new BlastAttack
			{
				attacker = ((Component)body).gameObject,
				inflictor = ((Component)body).gameObject,
				teamIndex = teamIndex,
				attackerFiltering = (AttackerFiltering)2,
				position = corePosition,
				radius = num,
				falloffModel = (FalloffModel)0,
				baseDamage = body.damage * Mathf.Max(0f, PhaseBurstModule.DamageCoefficient.Value),
				baseForce = 0f,
				bonusForce = Vector3.zero,
				crit = body.RollCrit(),
				procCoefficient = ((ThrowGlaive.glaiveProcCoefficient > 0f) ? ThrowGlaive.glaiveProcCoefficient : 1f),
				damageColorIndex = (DamageColorIndex)0,
				losType = (LoSType)0
			};
			DamageTypeCombo damageType = DamageTypeCombo.op_Implicit((DamageType)0);
			damageType.damageSource = (DamageSource)4;
			val2.damageType = damageType;
			Result val3 = val2.Fire();
			if (Object.op_Implicit((Object)(object)PhaseBurstModule.BurstEffectPrefab))
			{
				EffectManager.SpawnEffect(PhaseBurstModule.BurstEffectPrefab, new EffectData
				{
					origin = corePosition,
					scale = num * Mathf.Max(0.01f, PhaseBurstModule.VisualScale.Value)
				}, true);
			}
			if (!loggedFirst)
			{
				loggedFirst = true;
				PhaseBurstModule.Log.LogInfo((object)("First Phase Burst: " + (PhaseBurstModule.DamageCoefficient.Value * 100f).ToString("0") + "% damage, radius " + num + "m, hit " + val3.hitCount + "."));
			}
			List<HealthComponent> list = new List<HealthComponent>();
			if (val3.hitPoints != null)
			{
				HitPoint[] hitPoints = val3.hitPoints;
				foreach (HitPoint val4 in hitPoints)
				{
					HealthComponent val5 = (Object.op_Implicit((Object)(object)val4.hurtBox) ? val4.hurtBox.healthComponent : null);
					if (Object.op_Implicit((Object)(object)val5) && hashSet.Contains(val5) && !list.Contains(val5))
					{
						list.Add(val5);
					}
				}
			}
			if (list.Count != 0)
			{
				PhaseBurstRefund phaseBurstRefund = ((Component)body).GetComponent<PhaseBurstRefund>();
				if (!Object.op_Implicit((Object)(object)phaseBurstRefund))
				{
					phaseBurstRefund = ((Component)body).gameObject.AddComponent<PhaseBurstRefund>();
				}
				phaseBurstRefund.Watch(list);
			}
		}
	}
	internal class PhaseBurstRefund : MonoBehaviour
	{
		private class Pending
		{
			public List<HealthComponent> victims;

			public float timeLeft;
		}

		private const float WatchSeconds = 1f;

		private readonly List<Pending> pending = new List<Pending>();

		private CharacterBody body;

		private void Awake()
		{
			body = ((Component)this).GetComponent<CharacterBody>();
		}

		public void Watch(List<HealthComponent> victims)
		{
			Pending pending = new Pending
			{
				victims = victims,
				timeLeft = 1f
			};
			if (!TryRefund(pending) && !NetworkServer.active)
			{
				this.pending.Add(pending);
			}
		}

		private void FixedUpdate()
		{
			for (int num = this.pending.Count - 1; num >= 0; num--)
			{
				Pending pending = this.pending[num];
				pending.timeLeft -= Time.fixedDeltaTime;
				if (TryRefund(pending) || pending.timeLeft <= 0f)
				{
					this.pending.RemoveAt(num);
				}
			}
		}

		private bool TryRefund(Pending p)
		{
			foreach (HealthComponent victim in p.victims)
			{
				if (!Object.op_Implicit((Object)(object)victim) || !victim.alive)
				{
					RefundOneCharge();
					return true;
				}
			}
			return false;
		}

		private void RefundOneCharge()
		{
			GenericSkill val = ((Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.skillLocator)) ? body.skillLocator.utility : null);
			if (Object.op_Implicit((Object)(object)val) && !((Object)(object)val.skillDef != (Object)(object)PhaseBurstModule.PhaseBurstSkillDef) && val.stock < val.maxStock)
			{
				val.stock += 1;
			}
		}
	}
}
namespace BouncingHuntress.Glaive
{
	public enum BounceMode
	{
		KeepBouncing,
		OncePerEnemy
	}
	internal static class GlaiveModule
	{
		private const string Section = "Endless Glaive";

		public const string NameToken = "HUNTRESS_SECONDARY_ENDLESSGLAIVE_NAME";

		public const string DescriptionToken = "HUNTRESS_SECONDARY_ENDLESSGLAIVE_DESCRIPTION";

		private const string VanillaGlaiveKey = "RoR2/Base/Huntress/HuntressBodyGlaive.asset";

		private const string SecondaryFamilyKey = "RoR2/Base/Huntress/HuntressBodySecondaryFamily.asset";

		internal static ManualLogSource Log;

		internal static ConfigEntry<BounceMode> Mode;

		internal static ConfigEntry<int> GrowthStopsAfterBounce;

		internal static SkillDef EndlessGlaiveSkillDef;

		internal static GameObject GreenGlaiveOrb;

		internal static GameObject GreenChargeEffect;

		internal static GameObject GreenMuzzleFlash;

		private const string ThrowGlaiveConfigKey = "RoR2/Base/Huntress/EntityStates.Huntress.HuntressWeapon.ThrowGlaive.asset";

		internal static void Init(ConfigFile Config, ManualLogSource logger)
		{
			Log = logger;
			Mode = Config.Bind<BounceMode>("Endless Glaive", "BounceMode", BounceMode.KeepBouncing, "KeepBouncing: the glaive hits every enemy in range, then starts another round, and only stops when there is no other living enemy within bounce range.\nOncePerEnemy: like vanilla (never hits the same enemy twice), but with no limit on the number of bounces.\nOnly the host's setting matters in multiplayer.");
			GrowthStopsAfterBounce = Config.Bind<int>("Endless Glaive", "GrowthStopsAfterBounce", 6, "The +10% damage per bounce stops after this many bounces (6 = vanilla Laser Glaive's last bounce, ~443%). Every bounce after that hits for the same damage. 0 = no limit (damage keeps growing forever).");
			CreateSkill();
			if (Object.op_Implicit((Object)(object)EndlessGlaiveSkillDef))
			{
				BHContent.SkillDefs.Add(EndlessGlaiveSkillDef);
			}
			BHContent.StateTypes.Add(typeof(ThrowEndlessGlaive));
			CreateGreenVisuals();
			GlaivePatches.ApplyLanguageToLoaded();
			Log.LogInfo((object)("Endless Glaive loaded. Mode = " + Mode.Value));
		}

		private static void CreateGreenVisuals()
		{
			GreenGlaiveOrb = GreenFx.CloneEffect(GreenFx.LoadLegacy("Prefabs/Effects/OrbEffects/HuntressGlaiveOrbEffect"));
			GreenChargeEffect = GreenFx.CloneEffect(GreenFx.FromStateConfig<GameObject>("RoR2/Base/Huntress/EntityStates.Huntress.HuntressWeapon.ThrowGlaive.asset", "chargePrefab"));
			GreenMuzzleFlash = GreenFx.CloneEffect(GreenFx.FromStateConfig<GameObject>("RoR2/Base/Huntress/EntityStates.Huntress.HuntressWeapon.ThrowGlaive.asset", "muzzleFlashPrefab"));
			Log.LogInfo((object)("Green visuals: glaive " + (Object.op_Implicit((Object)(object)GreenGlaiveOrb) ? "ok" : "missing") + ", charge " + (Object.op_Implicit((Object)(object)GreenChargeEffect) ? "ok" : "missing") + ", flash " + (Object.op_Implicit((Object)(object)GreenMuzzleFlash) ? "ok" : "missing") + "."));
		}

		private static void CreateSkill()
		{
			//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)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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_00fd: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			SkillDef val = Addressables.LoadAssetAsync<SkillDef>((object)"RoR2/Base/Huntress/HuntressBodyGlaive.asset").WaitForCompletion();
			SkillFamily val2 = Addressables.LoadAssetAsync<SkillFamily>((object)"RoR2/Base/Huntress/HuntressBodySecondaryFamily.asset").WaitForCompletion();
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val2))
			{
				Log.LogError((object)"Could not load the vanilla Laser Glaive skill or Huntress secondary family. The game's asset paths may have changed.");
				return;
			}
			SkillDef val3 = Object.Instantiate<SkillDef>(val);
			((Object)val3).name = "HuntressBodyEndlessGlaive";
			val3.skillName = "EndlessGlaive";
			val3.skillNameToken = "HUNTRESS_SECONDARY_ENDLESSGLAIVE_NAME";
			val3.skillDescriptionToken = "HUNTRESS_SECONDARY_ENDLESSGLAIVE_DESCRIPTION";
			val3.activationState = new SerializableEntityStateType(typeof(ThrowEndlessGlaive));
			val3.icon = GreenFx.GreenIcon(val.icon);
			EndlessGlaiveSkillDef = val3;
			int num = val2.variants.Length;
			Array.Resize(ref val2.variants, num + 1);
			Variant[] variants = val2.variants;
			Variant val4 = new Variant
			{
				skillDef = val3,
				unlockableName = "",
				unlockableDef = null
			};
			((Variant)(ref val4)).viewableNode = new Node(val3.skillNameToken, false, (Node)null);
			variants[num] = val4;
		}
	}
	public class ThrowEndlessGlaive : ThrowGlaive
	{
		public override void OnEnter()
		{
			GameObject chargePrefab = ThrowGlaive.chargePrefab;
			if (Object.op_Implicit((Object)(object)GlaiveModule.GreenChargeEffect))
			{
				ThrowGlaive.chargePrefab = GlaiveModule.GreenChargeEffect;
			}
			try
			{
				((ThrowGlaive)this).OnEnter();
			}
			finally
			{
				ThrowGlaive.chargePrefab = chargePrefab;
			}
		}
	}
	internal static class GlaivePatches
	{
		private const int EndlessBounceCount = int.MaxValue;

		private const int EndlessThreshold = 1073741823;

		private const float MaxDamage = 1E+30f;

		private const int MaxPicksPerSearch = 512;

		private static bool swappedBounceCount;

		private static int savedBounceCount;

		private static GameObject savedMuzzleFlash;

		private static bool beginningEndlessOrb;

		private static bool inOurPick;

		private static bool loggedFirstThrow;

		[HarmonyPatch(typeof(ThrowGlaive), "FireOrbGlaive")]
		[HarmonyPrefix]
		private static void FireOrbGlaive_Prefix(ThrowGlaive __instance)
		{
			if (__instance is ThrowEndlessGlaive)
			{
				savedBounceCount = ThrowGlaive.maxBounceCount;
				ThrowGlaive.maxBounceCount = int.MaxValue;
				savedMuzzleFlash = ThrowGlaive.muzzleFlashPrefab;
				if (Object.op_Implicit((Object)(object)GlaiveModule.GreenMuzzleFlash))
				{
					ThrowGlaive.muzzleFlashPrefab = GlaiveModule.GreenMuzzleFlash;
				}
				swappedBounceCount = true;
				if (!loggedFirstThrow)
				{
					loggedFirstThrow = true;
					GlaiveModule.Log.LogInfo((object)("First Endless Glaive thrown (vanilla bounce count is " + savedBounceCount + ")."));
				}
			}
		}

		[HarmonyPatch(typeof(ThrowGlaive), "FireOrbGlaive")]
		[HarmonyFinalizer]
		private static Exception FireOrbGlaive_Finalizer(Exception __exception)
		{
			if (swappedBounceCount)
			{
				ThrowGlaive.maxBounceCount = savedBounceCount;
				ThrowGlaive.muzzleFlashPrefab = savedMuzzleFlash;
				swappedBounceCount = false;
			}
			return __exception;
		}

		private static bool IsEndless(LightningOrb orb)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)orb.lightningType == 4)
			{
				return orb.bouncesRemaining > 1073741823;
			}
			return false;
		}

		private static bool IsAlive(HurtBox hurtBox)
		{
			if (Object.op_Implicit((Object)(object)hurtBox) && Object.op_Implicit((Object)(object)hurtBox.healthComponent))
			{
				return hurtBox.healthComponent.alive;
			}
			return false;
		}

		private static HurtBox PickLivingTarget(LightningOrb orb, Vector3 position)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < 512; i++)
			{
				HurtBox val = orb.PickNextTarget(position);
				if (!Object.op_Implicit((Object)(object)val))
				{
					return null;
				}
				if (IsAlive(val))
				{
					return val;
				}
			}
			return null;
		}

		[HarmonyPatch(typeof(LightningOrb), "PickNextTarget")]
		[HarmonyPostfix]
		private static void PickNextTarget_Postfix(LightningOrb __instance, Vector3 position, ref HurtBox __result)
		{
			//IL_006d: 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)
			if (inOurPick || !IsEndless(__instance))
			{
				return;
			}
			inOurPick = true;
			try
			{
				if (__instance.damageValue > 1E+30f)
				{
					__instance.damageValue = 1E+30f;
				}
				int value = GlaiveModule.GrowthStopsAfterBounce.Value;
				int num = int.MaxValue - __instance.bouncesRemaining;
				if (value > 0 && num >= value)
				{
					__instance.damageCoefficientPerBounce = 1f;
				}
				if (Object.op_Implicit((Object)(object)__result) && !IsAlive(__result))
				{
					__result = PickLivingTarget(__instance, position);
				}
				if (!Object.op_Implicit((Object)(object)__result) && GlaiveModule.Mode.Value == BounceMode.KeepBouncing && __instance.bouncedObjects != null)
				{
					__instance.bouncedObjects.Clear();
					if (Object.op_Implicit((Object)(object)((Orb)__instance).target) && Object.op_Implicit((Object)(object)((Orb)__instance).target.healthComponent))
					{
						__instance.bouncedObjects.Add(((Orb)__instance).target.healthComponent);
					}
					__result = PickLivingTarget(__instance, position);
				}
			}
			finally
			{
				inOurPick = false;
			}
		}

		[HarmonyPatch(typeof(LightningOrb), "Begin")]
		[HarmonyPrefix]
		private static void LightningOrbBegin_Prefix(LightningOrb __instance)
		{
			beginningEndlessOrb = IsEndless(__instance);
		}

		[HarmonyPatch(typeof(LightningOrb), "Begin")]
		[HarmonyFinalizer]
		private static Exception LightningOrbBegin_Finalizer(Exception __exception)
		{
			beginningEndlessOrb = false;
			return __exception;
		}

		[HarmonyPatch(typeof(OrbStorageUtility), "Get")]
		[HarmonyPostfix]
		private static void OrbStorageGet_Postfix(string __0, ref GameObject __result)
		{
			if (beginningEndlessOrb && Object.op_Implicit((Object)(object)GlaiveModule.GreenGlaiveOrb) && __0 != null && __0.Contains("HuntressGlaiveOrbEffect"))
			{
				__result = GlaiveModule.GreenGlaiveOrb;
			}
		}

		private static string Description()
		{
			string text = ((GlaiveModule.Mode.Value == BounceMode.KeepBouncing) ? "bounces <style=cIsUtility>endlessly</style> between enemies" : "bounces to <style=cIsUtility>every enemy in range</style>");
			int value = GlaiveModule.GrowthStopsAfterBounce.Value;
			string text2 = ((value > 0) ? ("Damage increases by <style=cIsDamage>10%</style> per bounce, up to the <style=cIsDamage>" + Ordinal(value) + "</style> bounce.") : "Damage increases by <style=cIsDamage>10%</style> per bounce.");
			return "Throw a seeking glaive that " + text + " for <style=cIsDamage>250% damage</style>. " + text2;
		}

		private static string Ordinal(int n)
		{
			if (n % 100 >= 11 && n % 100 <= 13)
			{
				return n + "th";
			}
			return (n % 10) switch
			{
				1 => n + "st", 
				2 => n + "nd", 
				3 => n + "rd", 
				_ => n + "th", 
			};
		}

		private static void ApplyLanguage(Language language)
		{
			if (language != null)
			{
				language.SetStringByToken("HUNTRESS_SECONDARY_ENDLESSGLAIVE_NAME", "Endless Glaive");
				language.SetStringByToken("HUNTRESS_SECONDARY_ENDLESSGLAIVE_DESCRIPTION", Description());
			}
		}

		internal static void ApplyLanguageToLoaded()
		{
			try
			{
				ApplyLanguage(Language.currentLanguage);
			}
			catch
			{
			}
		}

		[HarmonyPatch(typeof(Language), "LoadStrings")]
		[HarmonyPostfix]
		private static void LoadStrings_Postfix(Language __instance)
		{
			ApplyLanguage(__instance);
		}
	}
}
namespace BouncingHuntress.ChainBallista
{
	internal static class ChainBallistaModule
	{
		private const string Section = "Chain Ballista";

		public const string NameToken = "HUNTRESS_SPECIAL_CHAINBALLISTA_NAME";

		public const string DescriptionToken = "HUNTRESS_SPECIAL_CHAINBALLISTA_DESCRIPTION";

		private const string SpecialFamilyKey = "RoR2/Base/Huntress/HuntressBodySpecialFamily.asset";

		private static readonly string[] SnipeShotKeys = new string[3] { "RoR2/Base/Huntress/FireArrowSnipe.asset", "RoR2/Base/Huntress/AimArrowSnipe.asset", "RoR2/Base/Huntress/Skills.Huntress.Snipe.asset" };

		internal static ManualLogSource Log;

		internal static ConfigEntry<int> MaxBounces;

		internal static ConfigEntry<float> FinaleRadius;

		internal static ConfigEntry<float> FinaleDamageFraction;

		internal static ConfigEntry<float> BounceDelay;

		internal static ConfigEntry<string> VisualEffectKey;

		internal static ConfigEntry<float> VisualScale;

		internal static SkillDef ChainBallistaSkillDef;

		internal static SkillDef ChainShotSkillDef;

		internal static GameObject FinaleEffectPrefab;

		internal static GameObject GreenTracer;

		internal static GameObject GreenHitEffect;

		internal static GameObject GreenMuzzleFlash;

		internal static GameObject GreenLeapFlash;

		private const string FireArrowSnipeConfigKey = "RoR2/Base/Huntress/EntityStates.Huntress.Weapon.FireArrowSnipe.asset";

		internal static void Init(ConfigFile Config, ManualLogSource logger)
		{
			Log = logger;
			MaxBounces = Config.Bind<int>("Chain Ballista", "MaxBounces", 6, "Most bounces a killing final shot can make. The big blast only happens if the chain reaches this many.");
			FinaleRadius = Config.Bind<float>("Chain Ballista", "FinaleRadius", 12f, "Radius (meters) of the green blast after the last bounce.");
			FinaleDamageFraction = Config.Bind<float>("Chain Ballista", "FinaleDamageFraction", 0.5f, "Blast damage as a fraction of one Ballista shot (0.5 = half).");
			BounceDelay = Config.Bind<float>("Chain Ballista", "BounceDelay", 0.15f, "Seconds between bounces, so you can see the chain travel.");
			VisualEffectKey = Config.Bind<string>("Chain Ballista", "EffectAsset", "RoR2/Base/Captain/CaptainTazerNova.prefab", "Game effect used for the blast (an Addressables key); it's recolored green. Leave empty for no visual.");
			VisualScale = Config.Bind<float>("Chain Ballista", "SizeMultiplier", 1f, "Multiplies the blast visual's size. 1 = drawn at the damage radius.");
			CreateSkills();
			if (Object.op_Implicit((Object)(object)ChainBallistaSkillDef) && Object.op_Implicit((Object)(object)ChainShotSkillDef))
			{
				BHContent.SkillDefs.Add(ChainBallistaSkillDef);
				BHContent.SkillDefs.Add(ChainShotSkillDef);
			}
			BHContent.StateTypes.Add(typeof(BeginChainSnipe));
			BHContent.StateTypes.Add(typeof(AimChainSnipe));
			BHContent.StateTypes.Add(typeof(FireChainSnipe));
			CreateFinaleEffect();
			GreenTracer = GreenFx.CloneEffect(GreenFx.FromStateConfig<GameObject>("RoR2/Base/Huntress/EntityStates.Huntress.Weapon.FireArrowSnipe.asset", "tracerEffectPrefab"));
			GreenHitEffect = GreenFx.CloneEffect(GreenFx.FromStateConfig<GameObject>("RoR2/Base/Huntress/EntityStates.Huntress.Weapon.FireArrowSnipe.asset", "hitEffectPrefab"));
			GreenMuzzleFlash = GreenFx.CloneEffect(GreenFx.FromStateConfig<GameObject>("RoR2/Base/Huntress/EntityStates.Huntress.Weapon.FireArrowSnipe.asset", "muzzleFlashPrefab"));
			GreenLeapFlash = GreenFx.CloneEffect(GreenFx.FromStateConfig<GameObject>("RoR2/Base/Huntress/EntityStates.Huntress.BeginArrowSnipe.asset", "blinkPrefab") ?? GreenFx.FromStateConfig<GameObject>("RoR2/Base/Huntress/EntityStates.Huntress.BaseBeginArrowBarrage.asset", "blinkPrefab"));
			Log.LogInfo((object)("Green visuals: bolt " + (Object.op_Implicit((Object)(object)GreenTracer) ? "ok" : "missing") + ", hit " + (Object.op_Implicit((Object)(object)GreenHitEffect) ? "ok" : "missing") + ", flash " + (Object.op_Implicit((Object)(object)GreenMuzzleFlash) ? "ok" : "missing") + ", leap " + (Object.op_Implicit((Object)(object)GreenLeapFlash) ? "ok" : "missing") + ", blast " + (Object.op_Implicit((Object)(object)FinaleEffectPrefab) ? "ok" : "missing") + "."));
			LanguagePatches.ApplyToLoaded();
			Log.LogInfo((object)"Chain Ballista loaded.");
		}

		private static void CreateSkills()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: 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_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Expected O, but got Unknown
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: 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_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_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			SkillDef val = null;
			string[] snipeShotKeys = SnipeShotKeys;
			foreach (string text in snipeShotKeys)
			{
				SkillDef val2 = null;
				try
				{
					val2 = Addressables.LoadAssetAsync<SkillDef>((object)text).WaitForCompletion();
				}
				catch
				{
				}
				if (Object.op_Implicit((Object)(object)val2) && ((SerializableEntityStateType)(ref val2.activationState)).stateType == typeof(FireArrowSnipe))
				{
					val = val2;
					break;
				}
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				Log.LogError((object)"Could not find Ballista's shot skill; Chain Ballista won't be added.");
				return;
			}
			SkillDef obj2 = Object.Instantiate<SkillDef>(val);
			((Object)obj2).name = "HuntressBodyChainBallistaShot";
			obj2.skillName = "ChainBallistaShot";
			obj2.activationState = new SerializableEntityStateType(typeof(FireChainSnipe));
			obj2.icon = GreenFx.GreenIcon(val.icon);
			ChainShotSkillDef = obj2;
			SkillFamily val3 = Addressables.LoadAssetAsync<SkillFamily>((object)"RoR2/Base/Huntress/HuntressBodySpecialFamily.asset").WaitForCompletion();
			SkillDef val4 = null;
			if (Object.op_Implicit((Object)(object)val3))
			{
				Variant[] variants = val3.variants;
				foreach (Variant val5 in variants)
				{
					if (Object.op_Implicit((Object)(object)val5.skillDef) && ((SerializableEntityStateType)(ref val5.skillDef.activationState)).stateType == typeof(BeginArrowSnipe))
					{
						val4 = val5.skillDef;
						break;
					}
				}
			}
			if (!Object.op_Implicit((Object)(object)val4))
			{
				Log.LogError((object)"Could not find Ballista in Huntress's special skills; Chain Ballista won't be added.");
				ChainShotSkillDef = null;
				return;
			}
			SkillDef val6 = Object.Instantiate<SkillDef>(val4);
			((Object)val6).name = "HuntressBodyChainBallista";
			val6.skillName = "ChainBallista";
			val6.skillNameToken = "HUNTRESS_SPECIAL_CHAINBALLISTA_NAME";
			val6.skillDescriptionToken = "HUNTRESS_SPECIAL_CHAINBALLISTA_DESCRIPTION";
			val6.activationState = new SerializableEntityStateType(typeof(BeginChainSnipe));
			val6.icon = GreenFx.GreenIcon(val4.icon);
			ChainBallistaSkillDef = val6;
			int num = val3.variants.Length;
			Array.Resize(ref val3.variants, num + 1);
			Variant[] variants2 = val3.variants;
			Variant val7 = new Variant
			{
				skillDef = val6,
				unlockableName = "",
				unlockableDef = null
			};
			((Variant)(ref val7)).viewableNode = new Node(val6.skillNameToken, false, (Node)null);
			variants2[num] = val7;
		}

		private static void CreateFinaleEffect()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			string value = VisualEffectKey.Value;
			if (string.IsNullOrEmpty(value))
			{
				return;
			}
			GameObject val = null;
			try
			{
				val = Addressables.LoadAssetAsync<GameObject>((object)value).WaitForCompletion();
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Blast visual '" + value + "' failed to load: " + ex.Message));
			}
			if (Object.op_Implicit((Object)(object)val))
			{
				GameObject val2 = GreenFx.CloneEffect(val);
				EffectComponent val3 = (Object.op_Implicit((Object)(object)val2) ? val2.GetComponent<EffectComponent>() : null);
				if (Object.op_Implicit((Object)(object)val3))
				{
					val3.applyScale = true;
					FinaleEffectPrefab = val2;
				}
			}
		}

		internal static void CopyTuning(object target, object template, params Type[] declaringTypes)
		{
			for (int i = 0; i < declaringTypes.Length; i++)
			{
				FieldInfo[] fields = declaringTypes[i].GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
				foreach (FieldInfo fieldInfo in fields)
				{
					fieldInfo.SetValue(target, fieldInfo.GetValue(template));
				}
			}
		}
	}
	internal static class LanguagePatches
	{
		private static void Apply(Language language)
		{
			if (language != null)
			{
				int value = ChainBallistaModule.MaxBounces.Value;
				int num = Mathf.RoundToInt(900f * ChainBallistaModule.FinaleDamageFraction.Value);
				language.SetStringByToken("HUNTRESS_SPECIAL_CHAINBALLISTA_NAME", "Chain Ballista");
				language.SetStringByToken("HUNTRESS_SPECIAL_CHAINBALLISTA_DESCRIPTION", "<style=cIsUtility>Teleport</style> backwards into the sky. Fire up to <style=cIsDamage>3</style> energy bolts, dealing <style=cIsDamage>3x900% damage</style>. If the last bolt <style=cIsHealth>kills</style>, it jumps to the nearest enemy for <style=cIsDamage>900% damage</style>, and keeps jumping while it kills, up to <style=cIsUtility>" + value + "</style> times. The " + Ordinal(value) + " jump detonates for <style=cIsDamage>" + num + "% damage</style> in a large area.");
			}
		}

		private static string Ordinal(int n)
		{
			if (n % 100 >= 11 && n % 100 <= 13)
			{
				return n + "th";
			}
			return (n % 10) switch
			{
				1 => n + "st", 
				2 => n + "nd", 
				3 => n + "rd", 
				_ => n + "th", 
			};
		}

		internal static void ApplyToLoaded()
		{
			try
			{
				Apply(Language.currentLanguage);
			}
			catch
			{
			}
		}

		[HarmonyPatch(typeof(Language), "LoadStrings")]
		[HarmonyPostfix]
		private static void LoadStrings_Postfix(Language __instance)
		{
			Apply(__instance);
		}
	}
	internal class ChainShot
	{
		public GameObject owner;

		public TeamIndex team;

		public float damage;

		public bool isCrit;

		public float procCoefficient;

		public float force;

		public DamageTypeCombo damageType;

		public GameObject tracerEffectPrefab;

		public GameObject hitEffectPrefab;

		public float radius;

		public static ChainShot From(BulletAttack bullet, CharacterBody body)
		{
			//IL_0028: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			return new ChainShot
			{
				owner = ((Component)body).gameObject,
				team = (TeamIndex)((!Object.op_Implicit((Object)(object)body.teamComponent)) ? 1 : ((int)body.teamComponent.teamIndex)),
				damage = bullet.damage,
				isCrit = bullet.isCrit,
				procCoefficient = bullet.procCoefficient,
				force = bullet.force,
				damageType = bullet.damageType,
				tracerEffectPrefab = bullet.tracerEffectPrefab,
				hitEffectPrefab = bullet.hitEffectPrefab,
				radius = bullet.radius
			};
		}
	}
	internal class ChainRunner : MonoBehaviour
	{
		private const float ClientKillWait = 1f;

		private static readonly BullseyeSearch search = new BullseyeSearch();

		public void Begin(ChainShot shot, List<HealthComponent> victims, List<Vector3> positions)
		{
			((MonoBehaviour)this).StartCoroutine(Run(shot, victims, positions));
		}

		private IEnumerator Run(ChainShot shot, List<HealthComponent> victims, List<Vector3> positions)
		{
			float waited = 0f;
			int num;
			while (true)
			{
				num = FirstDeadIndex(victims);
				if (num >= 0 || NetworkServer.active || waited >= 1f)
				{
					break;
				}
				waited += Time.fixedDeltaTime;
				yield return (object)new WaitForFixedUpdate();
			}
			if (num < 0)
			{
				yield break;
			}
			HealthComponent current = victims[num];
			Vector3 from = positions[num];
			int maxBounces = Mathf.Max(1, ChainBallistaModule.MaxBounces.Value);
			float delay = Mathf.Max(0f, ChainBallistaModule.BounceDelay.Value);
			for (int bounce = 1; bounce <= maxBounces; bounce++)
			{
				if (delay > 0f)
				{
					yield return (object)new WaitForSeconds(delay);
				}
				HurtBox val = FindNearestEnemy(from, current, shot.team);
				if (!Object.op_Implicit((Object)(object)val))
				{
					break;
				}
				HealthComponent target = val.healthComponent;
				Vector3 targetPosition = (Object.op_Implicit((Object)(object)target.body) ? target.body.corePosition : ((Component)val).transform.position);
				FireBounce(shot, from, ((Component)val).transform.position);
				if (bounce == maxBounces)
				{
					Detonate(shot, targetPosition);
					break;
				}
				waited = 0f;
				while (Object.op_Implicit((Object)(object)target) && target.alive && !NetworkServer.active && waited < 1f)
				{
					waited += Time.fixedDeltaTime;
					yield return (object)new WaitForFixedUpdate();
				}
				if (Object.op_Implicit((Object)(object)target) && target.alive)
				{
					break;
				}
				current = target;
				from = targetPosition;
			}
		}

		private static int FirstDeadIndex(List<HealthComponent> victims)
		{
			for (int i = 0; i < victims.Count; i++)
			{
				HealthComponent val = victims[i];
				if (!Object.op_Implicit((Object)(object)val) || !val.alive)
				{
					return i;
				}
			}
			return -1;
		}

		private static HurtBox FindNearestEnemy(Vector3 from, HealthComponent exclude, TeamIndex attackerTeam)
		{
			//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)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			TeamMask allButNeutral = TeamMask.allButNeutral;
			((TeamMask)(ref allButNeutral)).RemoveTeam(attackerTeam);
			search.searchOrigin = from;
			search.searchDirection = Vector3.zero;
			search.teamMaskFilter = allButNeutral;
			search.filterByLoS = false;
			search.filterByDistinctEntity = true;
			search.sortMode = (SortMode)1;
			search.maxDistanceFilter = 100000f;
			search.RefreshCandidates();
			foreach (HurtBox result in search.GetResults())
			{
				HealthComponent val = (Object.op_Implicit((Object)(object)result) ? result.healthComponent : null);
				if (Object.op_Implicit((Object)(object)val) && val.alive && !((Object)(object)val == (Object)(object)exclude))
				{
					return result;
				}
			}
			return null;
		}

		private static void FireBounce(ChainShot shot, Vector3 from, Vector3 to)
		{
			//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_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_002f: 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)
			//IL_0041: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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_00a8: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: 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_00d8: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: 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_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Expected O, but got Unknown
			Vector3 val = to - from;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude < 0.01f)
			{
				val = Vector3.up;
			}
			BulletAttack val2 = new BulletAttack
			{
				owner = shot.owner,
				weapon = null,
				muzzleName = "",
				origin = from,
				aimVector = ((Vector3)(ref val)).normalized,
				maxDistance = magnitude + 2f,
				bulletCount = 1u,
				minSpread = 0f,
				maxSpread = 0f,
				radius = Mathf.Max(0.5f, shot.radius),
				smartCollision = false,
				damage = shot.damage,
				isCrit = shot.isCrit,
				procCoefficient = shot.procCoefficient,
				force = shot.force,
				damageType = shot.damageType,
				damageColorIndex = (DamageColorIndex)0,
				falloffModel = (FalloffModel)0,
				tracerEffectPrefab = null,
				hitEffectPrefab = shot.hitEffectPrefab
			};
			LayerIndex entityPrecise = LayerIndex.entityPrecise;
			val2.hitMask = ((LayerIndex)(ref entityPrecise)).mask;
			val2.stopperMask = LayerMask.op_Implicit(0);
			val2.Fire();
			if (Object.op_Implicit((Object)(object)shot.tracerEffectPrefab))
			{
				EffectManager.SpawnEffect(shot.tracerEffectPrefab, new EffectData
				{
					origin = to,
					start = from
				}, true);
			}
		}

		private unsafe static void Detonate(ChainShot shot, Vector3 position)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: 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_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Expected O, but got Unknown
			float num = Mathf.Max(0.5f, ChainBallistaModule.FinaleRadius.Value);
			BlastAttack val = new BlastAttack
			{
				attacker = shot.owner,
				inflictor = shot.owner,
				teamIndex = shot.team,
				attackerFiltering = (AttackerFiltering)2,
				position = position,
				radius = num,
				falloffModel = (FalloffModel)0,
				baseDamage = shot.damage * ChainBallistaModule.FinaleDamageFraction.Value,
				baseForce = 0f,
				bonusForce = Vector3.zero,
				crit = shot.isCrit,
				procCoefficient = 1f,
				damageColorIndex = (DamageColorIndex)0,
				losType = (LoSType)0
			};
			DamageTypeCombo damageType = DamageTypeCombo.op_Implicit((DamageType)0);
			damageType.damageSource = (DamageSource)8;
			val.damageType = damageType;
			val.Fire();
			if (Object.op_Implicit((Object)(object)ChainBallistaModule.FinaleEffectPrefab))
			{
				EffectManager.SpawnEffect(ChainBallistaModule.FinaleEffectPrefab, new EffectData
				{
					origin = position,
					scale = num * Mathf.Max(0.01f, ChainBallistaModule.VisualScale.Value)
				}, true);
			}
			ManualLogSource log = ChainBallistaModule.Log;
			Vector3 val2 = position;
			log.LogInfo((object)("Chain Ballista: full chain! Detonated at " + ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString() + "."));
		}
	}
	public class BeginChainSnipe : BeginArrowSnipe
	{
		public BeginChainSnipe()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			ChainBallistaModule.CopyTuning(this, (object)new BeginArrowSnipe(), typeof(BaseBeginArrowBarrage));
		}

		protected override EntityState InstantiateNextState()
		{
			return (EntityState)(object)new AimChainSnipe();
		}

		public override void OnEnter()
		{
			GameObject blinkPrefab = BaseBeginArrowBarrage.blinkPrefab;
			if (Object.op_Implicit((Object)(object)ChainBallistaModule.GreenLeapFlash))
			{
				BaseBeginArrowBarrage.blinkPrefab = ChainBallistaModule.GreenLeapFlash;
			}
			try
			{
				((BaseBeginArrowBarrage)this).OnEnter();
			}
			finally
			{
				BaseBeginArrowBarrage.blinkPrefab = blinkPrefab;
			}
		}

		public override void FixedUpdate()
		{
			GameObject blinkPrefab = BaseBeginArrowBarrage.blinkPrefab;
			if (Object.op_Implicit((Object)(object)ChainBallistaModule.GreenLeapFlash))
			{
				BaseBeginArrowBarrage.blinkPrefab = ChainBallistaModule.GreenLeapFlash;
			}
			try
			{
				((BaseBeginArrowBarrage)this).FixedUpdate();
			}
			finally
			{
				BaseBeginArrowBarrage.blinkPrefab = blinkPrefab;
			}
		}

		public override void OnExit()
		{
			GameObject blinkPrefab = BaseBeginArrowBarrage.blinkPrefab;
			if (Object.op_Implicit((Object)(object)ChainBallistaModule.GreenLeapFlash))
			{
				BaseBeginArrowBarrage.blinkPrefab = ChainBallistaModule.GreenLeapFlash;
			}
			GreenFx.GreenOverlays = true;
			try
			{
				((BaseBeginArrowBarrage)this).OnExit();
			}
			finally
			{
				BaseBeginArrowBarrage.blinkPrefab = blinkPrefab;
				GreenFx.GreenOverlays = false;
			}
		}
	}
	public class AimChainSnipe : AimArrowSnipe
	{
		private GenericSkill primary;

		public AimChainSnipe()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			ChainBallistaModule.CopyTuning(this, (object)new AimArrowSnipe(), typeof(BaseArrowBarrage));
		}

		public override void OnEnter()
		{
			((AimArrowSnipe)this).OnEnter();
			primary = (Object.op_Implicit((Object)(object)((EntityState)this).skillLocator) ? ((EntityState)this).skillLocator.primary : null);
			if (Object.op_Implicit((Object)(object)primary) && Object.op_Implicit((Object)(object)ChainBallistaModule.ChainShotSkillDef))
			{
				primary.UnsetSkillOverride((object)this, AimArrowSnipe.primarySkillDef, (SkillOverridePriority)4);
				primary.SetSkillOverride((object)this, ChainBallistaModule.ChainShotSkillDef, (SkillOverridePriority)4);
			}
		}

		public override void OnExit()
		{
			if (Object.op_Implicit((Object)(object)primary) && Object.op_Implicit((Object)(object)ChainBallistaModule.ChainShotSkillDef))
			{
				primary.UnsetSkillOverride((object)this, ChainBallistaModule.ChainShotSkillDef, (SkillOverridePriority)4);
			}
			((AimArrowSnipe)this).OnExit();
		}
	}
	public class FireChainSnipe : FireArrowSnipe
	{
		private bool isFinalShot;

		private BulletAttack firedBullet;

		private readonly List<HealthComponent> victims = new List<HealthComponent>();

		private readonly List<Vector3> victimPositions = new List<Vector3>();

		public FireChainSnipe()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			ChainBallistaModule.CopyTuning(this, (object)new FireArrowSnipe(), typeof(GenericBulletBaseState), typeof(FireArrowSnipe));
			if (Object.op_Implicit((Object)(object)ChainBallistaModule.GreenTracer))
			{
				((GenericBulletBaseState)this).tracerEffectPrefab = ChainBallistaModule.GreenTracer;
			}
			if (Object.op_Implicit((Object)(object)ChainBallistaModule.GreenHitEffect))
			{
				((GenericBulletBaseState)this).hitEffectPrefab = ChainBallistaModule.GreenHitEffect;
			}
			if (Object.op_Implicit((Object)(object)ChainBallistaModule.GreenMuzzleFlash))
			{
				((GenericBulletBaseState)this).muzzleFlashPrefab = ChainBallistaModule.GreenMuzzleFlash;
			}
		}

		public override void OnEnter()
		{
			isFinalShot = ((EntityState)this).isAuthority && Object.op_Implicit((Object)(object)((EntityState)this).skillLocator) && Object.op_Implicit((Object)(object)((EntityState)this).skillLocator.primary) && ((EntityState)this).skillLocator.primary.stock == 0;
			((GenericBulletBaseState)this).OnEnter();
		}

		protected override void ModifyBullet(BulletAttack bulletAttack)
		{
			((FireArrowSnipe)this).ModifyBullet(bulletAttack);
			firedBullet = bulletAttack;
		}

		protected override bool OnBulletImpact(BulletAttack bulletAttack, ref BulletHit hitInfo)
		{
			//IL_0077: 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)
			if (isFinalS