Decompiled source of CollateralDamage v0.1.0

CollateralDamage.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("CollateralDamage")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+ce1fe04c1e0d3a2923c660dc5676ceccf87de5a5")]
[assembly: AssemblyProduct("CollateralDamage")]
[assembly: AssemblyTitle("CollateralDamage")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}
namespace OdinsMissingPatch
{
	[BepInPlugin("rauschekuh.collateraldamage", "Collateral Damage", "0.1.0")]
	public class CollateralDamagePlugin : BaseUnityPlugin
	{
		public const string GUID = "rauschekuh.collateraldamage";

		public const string NAME = "Collateral Damage";

		public const string VERSION = "0.1.0";

		private static readonly Tweak[] Tweaks = new Tweak[1] { CollateralDamage.Instance };

		private void Awake()
		{
			TweakHost.Start((BaseUnityPlugin)(object)this, ((BaseUnityPlugin)this).Logger, ((BaseUnityPlugin)this).Config, "rauschekuh.collateraldamage", Tweaks);
		}
	}
	internal sealed class CollateralDamage : Tweak
	{
		private struct Victim
		{
			internal Character Character;

			internal Collider Collider;

			internal Vector3 Point;
		}

		[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
		private static class MeleeSweep
		{
			private static void Postfix(Attack __instance)
			{
				//IL_0047: 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_004d: 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_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				//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_0081: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f6: Invalid comparison between Unknown and I4
				//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
				//IL_010d: Unknown result type (might be due to invalid IL or missing references)
				//IL_010f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0111: Unknown result type (might be due to invalid IL or missing references)
				//IL_0116: Unknown result type (might be due to invalid IL or missing references)
				//IL_011b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0104: Unknown result type (might be due to invalid IL or missing references)
				//IL_0109: Unknown result type (might be due to invalid IL or missing references)
				//IL_021d: Unknown result type (might be due to invalid IL or missing references)
				//IL_021f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0137: Unknown result type (might be due to invalid IL or missing references)
				//IL_013f: Unknown result type (might be due to invalid IL or missing references)
				//IL_024a: Unknown result type (might be due to invalid IL or missing references)
				//IL_024c: Unknown result type (might be due to invalid IL or missing references)
				//IL_024e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0187: Unknown result type (might be due to invalid IL or missing references)
				//IL_0189: Unknown result type (might be due to invalid IL or missing references)
				//IL_0194: Unknown result type (might be due to invalid IL or missing references)
				//IL_0199: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
				//IL_01da: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
				//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
				//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
				//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
				//IL_02db: Unknown result type (might be due to invalid IL or missing references)
				//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
				//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
				Humanoid character = __instance.m_character;
				if (!Instance.On || __instance.m_hitFriendly || !Instance.IsAttacker((Character)(object)character) || __instance.m_weapon == null)
				{
					return;
				}
				Transform val = default(Transform);
				Vector3 val2 = default(Vector3);
				__instance.GetMeleeAttackDir(ref val, ref val2);
				Transform transform = ((Component)character).transform;
				Vector3 val3 = transform.InverseTransformDirection(val2);
				Vector3 val4 = val.position + Vector3.up * __instance.m_attackHeight + transform.right * __instance.m_attackOffset;
				float num = __instance.m_attackAngle / 2f;
				int num2 = (__instance.m_hitTerrain ? Attack.m_attackMaskTerrain : Attack.m_attackMask);
				float num3 = __instance.m_attackRayWidth + __instance.m_attackRayWidthCharExtra;
				victims.Clear();
				for (float num4 = 0f - num; num4 <= num; num4 += 4f)
				{
					Quaternion val5 = Quaternion.identity;
					if ((int)__instance.m_attackType == 0)
					{
						val5 = Quaternion.Euler(0f, 0f - num4, 0f);
					}
					else if ((int)__instance.m_attackType == 1)
					{
						val5 = Quaternion.Euler(num4, 0f, 0f);
					}
					Vector3 val6 = transform.TransformDirection(val5 * val3);
					rayList.Clear();
					if (__instance.m_attackRayWidth > 0f)
					{
						AddRays(Physics.SphereCastNonAlloc(val4, __instance.m_attackRayWidth, val6, rayHits, Mathf.Max(0f, __instance.m_attackRange - __instance.m_attackRayWidth), num2, (QueryTriggerInteraction)1));
						if (__instance.m_attackRayWidthCharExtra > 0f || __instance.m_attackHeightChar1 != 0f)
						{
							AddRays(Physics.SphereCastNonAlloc(val4 + Vector3.up * __instance.m_attackHeightChar1, num3, val6, rayHits, Mathf.Max(0f, __instance.m_attackRange - num3), Attack.m_attackMaskCharacters, (QueryTriggerInteraction)1));
							if (__instance.m_attackHeightChar2 != __instance.m_attackHeightChar1)
							{
								AddRays(Physics.SphereCastNonAlloc(val4 + Vector3.up * __instance.m_attackHeightChar2, num3, val6, rayHits, Mathf.Max(0f, __instance.m_attackRange - num3), Attack.m_attackMaskCharacters, (QueryTriggerInteraction)1));
							}
						}
					}
					else
					{
						AddRays(Physics.RaycastNonAlloc(val4, val6, rayHits, __instance.m_attackRange, num2, (QueryTriggerInteraction)1));
					}
					rayList.Sort(ByDistance);
					WalkRay(__instance, character, val4, val6, val2);
				}
				float chainMultiplier = ((__instance.m_attackChainLevels > 1 && __instance.m_currentAttackCainLevel == __instance.m_attackChainLevels - 1) ? 2f : 1f);
				foreach (Victim victim3 in victims)
				{
					if (!Dodges(__instance, victim3.Character))
					{
						float randomSkillFactor = ((Character)character).GetRandomSkillFactor(__instance.m_weapon.m_shared.m_skillType);
						Victim victim = victim3;
						Victim victim2 = victim3;
						Vector3 val7 = victim3.Point - val4;
						Strike(__instance, victim, BuildHit(__instance, victim2, ((Vector3)(ref val7)).normalized, randomSkillFactor, chainMultiplier));
						if (!__instance.m_multiHit)
						{
							break;
						}
					}
				}
				victims.Clear();
			}

			private static void AddRays(int count)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				for (int i = 0; i < count; i++)
				{
					rayList.Add(rayHits[i]);
				}
			}

			private static void WalkRay(Attack a, Humanoid attacker, Vector3 origin, Vector3 dir, Vector3 attackDir)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: 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_003b: 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_0043: 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_0052: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a0: 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)
				//IL_00a2: 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_0080: Unknown result type (might be due to invalid IL or missing references)
				//IL_0081: Unknown result type (might be due to invalid IL or missing references)
				//IL_0088: Unknown result type (might be due to invalid IL or missing references)
				//IL_008d: 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_0079: Unknown result type (might be due to invalid IL or missing references)
				//IL_0092: Unknown result type (might be due to invalid IL or missing references)
				//IL_0103: Unknown result type (might be due to invalid IL or missing references)
				foreach (RaycastHit ray in rayList)
				{
					RaycastHit current = ray;
					if ((Object)(object)((Component)((RaycastHit)(ref current)).collider).gameObject == (Object)(object)((Component)attacker).gameObject)
					{
						continue;
					}
					Vector3 val = ((RaycastHit)(ref current)).point;
					if (((RaycastHit)(ref current)).normal == -dir && ((RaycastHit)(ref current)).point == Vector3.zero)
					{
						val = ((((RaycastHit)(ref current)).collider is MeshCollider) ? (origin + dir * a.m_attackRange) : ((RaycastHit)(ref current)).collider.ClosestPoint(origin));
					}
					if (a.m_attackAngle < 180f && Vector3.Dot(val - origin, attackDir) <= 0f)
					{
						continue;
					}
					GameObject val2 = Projectile.FindHitObject(((RaycastHit)(ref current)).collider);
					if ((Object)(object)val2 == (Object)null || (Object)(object)val2 == (Object)(object)((Component)attacker).gameObject)
					{
						continue;
					}
					Character component = val2.GetComponent<Character>();
					if ((Object)(object)component != (Object)null)
					{
						if (Instance.IsCollateral((Character)(object)attacker, component))
						{
							AddVictim(component, ((RaycastHit)(ref current)).collider, val);
						}
					}
					else if (!a.m_hitThroughWalls)
					{
						break;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Attack), "DoAreaAttack")]
		private static class AreaBlast
		{
			private static void Postfix(Attack __instance)
			{
				//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_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_005b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: 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_0081: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00da: Unknown result type (might be due to invalid IL or missing references)
				//IL_00db: 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_00eb: Unknown result type (might be due to invalid IL or missing references)
				//IL_0150: Unknown result type (might be due to invalid IL or missing references)
				//IL_0116: Unknown result type (might be due to invalid IL or missing references)
				//IL_0117: Unknown result type (might be due to invalid IL or missing references)
				//IL_0118: Unknown result type (might be due to invalid IL or missing references)
				//IL_0123: Unknown result type (might be due to invalid IL or missing references)
				//IL_0128: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
				//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
				//IL_01db: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
				//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
				Humanoid character = __instance.m_character;
				if (!Instance.On || __instance.m_hitFriendly || !Instance.IsAttacker((Character)(object)character) || __instance.m_weapon == null)
				{
					return;
				}
				Transform transform = ((Component)character).transform;
				Vector3 val = __instance.GetAttackOrigin().position + Vector3.up * __instance.m_attackHeight + transform.forward * __instance.m_attackRange + transform.right * __instance.m_attackOffset;
				float num = __instance.m_attackRayWidth + __instance.m_attackRayWidthCharExtra;
				victims.Clear();
				Collect(character, val, Physics.OverlapSphereNonAlloc(val, __instance.m_attackRayWidth, overlaps, Attack.m_attackMaskCharacters, (QueryTriggerInteraction)0));
				if (__instance.m_attackRayWidthCharExtra > 0f || __instance.m_attackHeightChar1 != 0f)
				{
					Collect(character, val, Physics.OverlapSphereNonAlloc(val + Vector3.up * __instance.m_attackHeightChar1, num, overlaps, Attack.m_attackMaskCharacters, (QueryTriggerInteraction)0));
					if (__instance.m_attackHeightChar2 != __instance.m_attackHeightChar1)
					{
						Collect(character, val, Physics.OverlapSphereNonAlloc(val + Vector3.up * __instance.m_attackHeightChar2, num, overlaps, Attack.m_attackMaskCharacters, (QueryTriggerInteraction)0));
					}
				}
				float randomSkillFactor = ((Character)character).GetRandomSkillFactor(__instance.m_weapon.m_shared.m_skillType);
				float chainMultiplier = ((__instance.m_attackChainLevels > 1 && __instance.m_currentAttackCainLevel == __instance.m_attackChainLevels - 1) ? __instance.m_lastChainDamageMultiplier : 1f);
				foreach (Victim victim in victims)
				{
					if (!Dodges(__instance, victim.Character))
					{
						Vector3 val2 = victim.Point - val;
						val2.y = 0f;
						Vector3 val3 = victim.Point - transform.position;
						if (Vector3.Dot(val3, val2) < 0f)
						{
							val2 = val3;
						}
						Strike(__instance, victim, BuildHit(__instance, victim, ((Vector3)(ref val2)).normalized, randomSkillFactor, chainMultiplier));
					}
				}
				victims.Clear();
			}

			private static void Collect(Humanoid attacker, Vector3 origin, int count)
			{
				//IL_004f: 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_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_0055: Unknown result type (might be due to invalid IL or missing references)
				//IL_0059: Unknown result type (might be due to invalid IL or missing references)
				for (int i = 0; i < count; i++)
				{
					Collider val = overlaps[i];
					GameObject val2 = Projectile.FindHitObject(val);
					Character val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<Character>() : null);
					if ((Object)(object)val3 != (Object)null && Instance.IsCollateral((Character)(object)attacker, val3))
					{
						Vector3 point = ((val is MeshCollider) ? val.ClosestPointOnBounds(origin) : val.ClosestPoint(origin));
						AddVictim(val3, val, point);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Projectile), "DoAOE")]
		private static class ProjectileBlast
		{
			private static void Prefix(Projectile __instance)
			{
				exploding = ((Instance.On && Instance.IsAttacker(__instance.m_owner)) ? __instance : null);
			}

			private static void Finalizer()
			{
				exploding = null;
			}
		}

		[HarmonyPatch(typeof(Projectile), "IsValidTarget")]
		private static class ProjectileTarget
		{
			private static void Postfix(Projectile __instance, IDestructible destr, ref bool __result)
			{
				if (!__result && !((Object)(object)exploding == (Object)null) && !((Object)(object)__instance != (Object)(object)exploding) && !__instance.m_noDamageFriendly)
				{
					Character val = (Character)(object)((destr is Character) ? destr : null);
					if (!((Object)(object)val == (Object)null) && (!__instance.m_dodgeable || !val.IsDodgeInvincible()))
					{
						__result = Instance.IsCollateral(__instance.m_owner, val);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Aoe), "ShouldHit")]
		private static class AreaEffect
		{
			private static void Postfix(Aoe __instance, Collider collider, ref bool __result)
			{
				if (__result || !Instance.On || !__instance.m_hitCharacters)
				{
					return;
				}
				Character owner = __instance.m_owner;
				if (Instance.IsAttacker(owner))
				{
					GameObject val = Projectile.FindHitObject(collider);
					Character val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Character>() : null);
					if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)owner) && (!((Object)(object)__instance.m_nview == (Object)null) || val2.IsOwner()) && (!__instance.m_dodgeable || !val2.IsDodgeInvincible()))
					{
						__result = Instance.IsCollateral(owner, val2);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Character), "RPC_Damage")]
		private static class VictimSide
		{
			private static void Prefix(Character __instance, HitData hit)
			{
				//IL_0072: Unknown result type (might be due to invalid IL or missing references)
				if (Instance.On && hit != null && hit.HaveAttacker() && !((Object)(object)__instance.m_nview == (Object)null) && __instance.m_nview.IsValid() && __instance.m_nview.IsOwner() && Instance.IsCollateral(hit.GetAttacker(), __instance))
				{
					hit.ApplyModifier(Instance.damage.Value);
					HitData obj = hit.Clone();
					DamageModifier val = default(DamageModifier);
					obj.ApplyResistance(__instance.GetDamageModifiers((WeakSpot)null), ref val);
					float num = Mathf.Min(obj.GetTotalDamage(), Mathf.Max(0f, __instance.GetHealth()));
					if (num > 0f)
					{
						ZDO zDO = __instance.m_nview.GetZDO();
						zDO.Set(CollateralKey, zDO.GetFloat(CollateralKey, 0f) + num);
					}
				}
			}
		}

		[HarmonyPatch(typeof(MonsterAI), "OnDamaged")]
		private static class NoAggro
		{
			private static bool Prefix(MonsterAI __instance, Character attacker)
			{
				if (!Instance.On || !Instance.IsCollateral(attacker, ((BaseAI)__instance).m_character))
				{
					return true;
				}
				((BaseAI)__instance).m_timeSinceHurt = 0f;
				return false;
			}
		}

		[HarmonyPatch(typeof(CharacterDrop), "OnDeath")]
		private static class Loot
		{
			private static bool Prefix(CharacterDrop __instance)
			{
				Character character = __instance.m_character;
				if (!Instance.On || (Object)(object)character == (Object)null)
				{
					return true;
				}
				ZDO zDO = GetZDO(character);
				float num = ((zDO != null) ? zDO.GetFloat(CollateralKey, 0f) : 0f);
				if (num <= 0f || (character.m_lastHit != null && character.m_lastHit.GetAttacker() is Player))
				{
					return true;
				}
				return num <= Instance.lootLimit.Value * character.GetMaxHealth();
			}
		}

		[HarmonyPatch(typeof(SpawnAbility), "SetupAoe")]
		private static class SpawnedByBoss
		{
			private static void Prefix(SpawnAbility __instance, Character owner)
			{
				if (Instance.On && (Object)(object)owner != (Object)null && (Object)(object)__instance.m_owner != (Object)null && __instance.m_owner.IsBoss())
				{
					MarkBossSpawn(owner);
				}
			}
		}

		internal static readonly CollateralDamage Instance = new CollateralDamage();

		private static readonly int BossSpawnKey = StringExtensionMethods.GetStableHashCode("omp_bossSpawn");

		private static readonly int CollateralKey = StringExtensionMethods.GetStableHashCode("omp_collateralDamage");

		private static readonly int QueenPrefab = StringExtensionMethods.GetStableHashCode("SeekerQueen");

		private const float SweepStep = 4f;

		private ConfigEntry<bool> bosses;

		private ConfigEntry<float> damage;

		private ConfigEntry<float> lootLimit;

		private HashSet<int> attackers = new HashSet<int>();

		private static readonly RaycastHit[] rayHits = (RaycastHit[])(object)new RaycastHit[128];

		private static readonly List<RaycastHit> rayList = new List<RaycastHit>();

		private static readonly Collider[] overlaps = (Collider[])(object)new Collider[128];

		private static readonly List<Victim> victims = new List<Victim>();

		private static readonly Comparison<RaycastHit> ByDistance = (RaycastHit x, RaycastHit y) => ((RaycastHit)(ref x)).distance.CompareTo(((RaycastHit)(ref y)).distance);

		private static Projectile exploding;

		internal override string Section => "Collateral Damage";

		protected override string Summary => "Trolls and bosses hit the creatures in their way - greydwarfs beside a troll's swing, dwarfs in Eikthyr's lightning, fulings and lox under Yagluth's meteors - without them fighting back or anyone picking new targets. What a boss spawns is never hit. Every player needs the mod for it to apply everywhere.";

		private CollateralDamage()
		{
		}

		protected override void Bind(ConfigFile config)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			BindList(config, "Creatures", "Troll", "Comma separated prefab names of the creatures whose attacks hit the creatures in their way, e.g. Troll, Abomination, Gjall. Tamed ones never do.", Parse);
			bosses = config.Bind<bool>(Section, "Bosses", true, "Every boss's attacks but the Queen's hit the creatures in their way too. What a boss spawns is never hit.");
			damage = BindMultiplier(config, "Damage", 1f, "Multiplier on the damage a creature takes from a troll or boss that did not mean to hit it.");
			lootLimit = config.Bind<float>(Section, "LootLimit", 0.5f, new ConfigDescription("A creature that was not finished by a player drops nothing once trolls and bosses hitting it by accident took more than this share of its health. 1 keeps all loot.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		}

		private void Parse(List<string> names)
		{
			HashSet<int> hashSet = new HashSet<int>();
			foreach (string name in names)
			{
				hashSet.Add(StringExtensionMethods.GetStableHashCode(name));
			}
			attackers = hashSet;
		}

		private static ZDO GetZDO(Character character)
		{
			ZNetView nview = character.m_nview;
			if (!((Object)(object)nview != (Object)null) || !nview.IsValid())
			{
				return null;
			}
			return nview.GetZDO();
		}

		private bool IsAttacker(Character character)
		{
			if ((Object)(object)character == (Object)null || character.IsPlayer() || character.IsTamed())
			{
				return false;
			}
			ZDO zDO = GetZDO(character);
			if (zDO == null)
			{
				return false;
			}
			int prefab = zDO.GetPrefab();
			if (!attackers.Contains(prefab))
			{
				if (bosses.Value && character.IsBoss())
				{
					return prefab != QueenPrefab;
				}
				return false;
			}
			return true;
		}

		private bool IsCollateral(Character attacker, Character victim)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Invalid comparison between Unknown and I4
			if ((Object)(object)victim == (Object)null || (Object)(object)victim == (Object)(object)attacker || !IsAttacker(attacker))
			{
				return false;
			}
			if (victim.IsPlayer() || victim.IsTamed() || victim.IsBoss() || (int)victim.m_faction == 8)
			{
				return false;
			}
			if (BaseAI.IsEnemy(attacker, victim))
			{
				return false;
			}
			ZDO zDO = GetZDO(victim);
			if (zDO != null)
			{
				return !zDO.GetBool(BossSpawnKey, false);
			}
			return false;
		}

		private static void MarkBossSpawn(Character character)
		{
			if ((Object)(object)character != (Object)null && (Object)(object)character.m_nview != (Object)null && character.m_nview.IsValid() && character.m_nview.IsOwner())
			{
				character.m_nview.GetZDO().Set(BossSpawnKey, true);
			}
		}

		private static void AddVictim(Character character, Collider collider, Vector3 point)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			foreach (Victim victim in victims)
			{
				if ((Object)(object)victim.Character == (Object)(object)character)
				{
					return;
				}
			}
			victims.Add(new Victim
			{
				Character = character,
				Collider = collider,
				Point = point
			});
		}

		private static HitData BuildHit(Attack attack, Victim victim, Vector3 dir, float factor, float chainMultiplier)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_006f: 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_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: 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_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			Humanoid character = attack.m_character;
			SharedData shared = attack.m_weapon.m_shared;
			HitData val = new HitData();
			val.m_toolTier = (short)shared.m_toolTier;
			val.m_statusEffectHash = (((Object)(object)shared.m_attackStatusEffect != (Object)null && (shared.m_attackStatusEffectChance == 1f || Random.Range(0f, 1f) < shared.m_attackStatusEffectChance)) ? shared.m_attackStatusEffect.NameHash() : 0);
			val.m_skillLevel = ((Character)character).GetSkillLevel(shared.m_skillType);
			val.m_itemLevel = (short)attack.m_weapon.m_quality;
			val.m_itemWorldLevel = (byte)attack.m_weapon.m_worldLevel;
			val.m_pushForce = shared.m_attackForce * factor * attack.m_forceMultiplier;
			val.m_backstabBonus = shared.m_backstabBonus;
			val.m_staggerMultiplier = attack.m_staggerMultiplier;
			val.m_dodgeable = shared.m_dodgeable;
			val.m_blockable = shared.m_blockable;
			val.m_skill = shared.m_skillType;
			val.m_skillRaiseAmount = attack.m_raiseSkillAmount;
			val.m_damage = attack.m_weapon.GetDamage();
			val.m_point = victim.Point;
			val.m_dir = dir;
			val.m_hitCollider = victim.Collider;
			val.SetAttacker((Character)(object)character);
			val.m_hitType = (HitType)1;
			val.m_variant = shared.m_hitVariant;
			attack.ModifyDamage(val, factor);
			if (chainMultiplier > 1f)
			{
				((DamageTypes)(ref val.m_damage)).Modify(chainMultiplier);
				HitData obj = val;
				obj.m_pushForce *= 1.2f;
			}
			((Character)character).GetSEMan().ModifyAttack(shared.m_skillType, ref val);
			return val;
		}

		private static void Strike(Attack attack, Victim victim, HitData hit)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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_002e: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			ZDOID zDOID = ((Character)attack.m_character).GetZDOID();
			attack.m_weapon.m_shared.m_hitEffect.Create(victim.Point, Quaternion.identity, (Transform)null, 1f, -1, zDOID);
			attack.m_hitEffect.Create(victim.Point, Quaternion.identity, (Transform)null, 1f, -1, zDOID);
			victim.Character.Damage(hit);
		}

		private static bool Dodges(Attack attack, Character victim)
		{
			if (attack.m_weapon.m_shared.m_dodgeable)
			{
				return victim.IsDodgeInvincible();
			}
			return false;
		}
	}
	internal static class Danger
	{
		[HarmonyPatch(typeof(Player), "RPC_OnTargeted")]
		[Serves(new Type[] { typeof(Danger) })]
		private static class NoticeEnragedEnemy
		{
			private static void Postfix(Player __instance, bool alerted)
			{
				if (alerted && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
				{
					lastEnraged = Time.time;
				}
			}
		}

		private const float CheckInterval = 0.25f;

		private const float EnragedMemory = 1.5f;

		internal const string Section = "General";

		internal static ConfigEntry<float> ThreatRadius;

		internal static ConfigEntry<bool> EnragedEnemies;

		internal static ConfigEntry<bool> BossFights;

		private static float lastCheck = float.NegativeInfinity;

		private static bool inDanger;

		private static float lastEnraged = float.NegativeInfinity;

		internal static void Bind(ConfigFile config, string effect)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			ThreatRadius = config.Bind<float>("General", "ThreatRadius", 25f, new ConfigDescription("Metres. A hostile creature closer than this puts you in combat, whether it has noticed you or not: " + effect, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), Array.Empty<object>()));
			EnragedEnemies = config.Bind<bool>("General", "EnragedEnemies", true, "An enemy that has noticed you and is coming for you puts you in combat at any distance, not only inside ThreatRadius. Off means only the radius counts.");
			BossFights = config.Bind<bool>("General", "BossFights", true, "A boss health bar on screen puts you in combat, whoever the boss is after and however far away it is.");
		}

		internal static bool Near(Player player)
		{
			if (Time.time - lastCheck < 0.25f)
			{
				return inDanger;
			}
			lastCheck = Time.time;
			inDanger = Enraged() || BossBarShowing() || HostileWithin(player, ThreatRadius.Value);
			return inDanger;
		}

		private static bool Enraged()
		{
			if (EnragedEnemies.Value)
			{
				return Time.time - lastEnraged < 1.5f;
			}
			return false;
		}

		private static bool BossBarShowing()
		{
			if (BossFights.Value && (Object)(object)EnemyHud.instance != (Object)null)
			{
				return EnemyHud.instance.ShowingBossHud();
			}
			return false;
		}

		private static bool HostileWithin(Player player, float radius)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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_0053: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)player).transform.position;
			float num = radius * radius;
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if (!((Object)(object)allCharacter == (Object)null) && !((Object)(object)allCharacter == (Object)(object)player) && !allCharacter.IsDead() && BaseAI.IsEnemy((Character)(object)player, allCharacter))
				{
					Vector3 val = ((Component)allCharacter).transform.position - position;
					if (((Vector3)(ref val)).sqrMagnitude <= num)
					{
						return true;
					}
				}
			}
			return false;
		}
	}
	internal static class FavoriteMark
	{
		internal const string Key = "OMP_Favorite";

		internal static bool IsSet(ItemData item)
		{
			if (item != null && item.m_customData != null && item.m_customData.TryGetValue("OMP_Favorite", out var value))
			{
				return value == "1";
			}
			return false;
		}
	}
	internal static class Hotkeys
	{
		internal static bool Pressed(KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0 || !ZInput.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey, false))
			{
				return false;
			}
			return ModifiersHeld(shortcut);
		}

		internal static bool Held(KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0 || !ZInput.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey, false))
			{
				return false;
			}
			return ModifiersHeld(shortcut);
		}

		internal static string Describe(params KeyboardShortcut[] chord)
		{
			//IL_000e: 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_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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)
			List<string> list = new List<string>();
			for (int i = 0; i < chord.Length; i++)
			{
				KeyboardShortcut val = chord[i];
				if ((int)((KeyboardShortcut)(ref val)).MainKey == 0)
				{
					continue;
				}
				foreach (KeyCode modifier in ((KeyboardShortcut)(ref val)).Modifiers)
				{
					list.Add(KeyName(modifier));
				}
				list.Add(KeyName(((KeyboardShortcut)(ref val)).MainKey));
			}
			return string.Join(" + ", list.ToArray());
		}

		private unsafe static string KeyName(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			string text = ZInput.KeyCodeToDisplayName(key);
			if (!string.IsNullOrEmpty(text) && !text.StartsWith("$"))
			{
				return text;
			}
			return ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString();
		}

		private static bool ModifiersHeld(KeyboardShortcut shortcut)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if (!ZInput.GetKey(modifier, false))
				{
					return false;
				}
			}
			return true;
		}
	}
	internal static class LegacyConfig
	{
		private const string OldFile = "rauschekuh.odinsmissingpatch.cfg";

		internal static HashSet<string> Sections(string path)
		{
			HashSet<string> hashSet = new HashSet<string>();
			try
			{
				if (File.Exists(path))
				{
					foreach (ConfigDefinition key in Read(path).Keys)
					{
						hashSet.Add(key.Section);
					}
				}
			}
			catch (Exception ex)
			{
				TweakHost.Log.LogWarning((object)("could not read " + path + ": " + ex.Message));
			}
			return hashSet;
		}

		internal static void Import(ConfigFile config, HashSet<string> known)
		{
			try
			{
				string path = Path.Combine(Paths.ConfigPath, "rauschekuh.odinsmissingpatch.cfg");
				if (!File.Exists(path))
				{
					return;
				}
				Dictionary<ConfigDefinition, string> dictionary = Read(path);
				int num = 0;
				foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in config)
				{
					if (!known.Contains(item.Key.Section) && dictionary.TryGetValue(item.Key, out var value))
					{
						item.Value.SetSerializedValue(value);
						num++;
					}
				}
				if (num > 0)
				{
					config.Save();
					TweakHost.Log.LogInfo((object)("took " + num + " setting(s) over from rauschekuh.odinsmissingpatch.cfg"));
				}
			}
			catch (Exception ex)
			{
				TweakHost.Log.LogWarning((object)("could not read the settings of rauschekuh.odinsmissingpatch.cfg: " + ex.Message));
			}
		}

		private static Dictionary<ConfigDefinition, string> Read(string path)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			Dictionary<ConfigDefinition, string> dictionary = new Dictionary<ConfigDefinition, string>();
			string text = "";
			string[] array = File.ReadAllLines(path);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length == 0 || text2.StartsWith("#"))
				{
					continue;
				}
				if (text2.StartsWith("[") && text2.EndsWith("]"))
				{
					text = text2.Substring(1, text2.Length - 2);
					continue;
				}
				int num = text2.IndexOf('=');
				if (num > 0 && text.Length > 0)
				{
					dictionary[new ConfigDefinition(text, text2.Substring(0, num).Trim())] = text2.Substring(num + 1).Trim();
				}
			}
			return dictionary;
		}
	}
	internal static class Palette
	{
		internal static readonly Color Gold = new Color(1f, 0.8f, 0.3f, 1f);

		internal static readonly Color ChestYellow = new Color(1f, 0.84f, 0.3f, 1f);

		internal const string ChestYellowTag = "<color=#ffd64d>";
	}
	[AttributeUsage(AttributeTargets.Class)]
	internal sealed class ServesAttribute : Attribute
	{
		internal readonly Type[] Tweaks;

		public bool Optional { get; set; }

		public ServesAttribute(params Type[] tweaks)
		{
			Tweaks = tweaks;
		}
	}
	[AttributeUsage(AttributeTargets.Class)]
	internal sealed class AlwaysAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class)]
	internal sealed class LoadHookAttribute : Attribute
	{
	}
	internal static class Patcher
	{
		private sealed class PatchClass
		{
			internal Type Type;

			internal Tweak[] Serves;

			internal bool Optional;

			internal bool LoadHook;

			internal bool Applied;

			internal bool Failed;
		}

		private static readonly List<PatchClass> classes = new List<PatchClass>();

		private static Harmony harmony;

		private static ManualLogSource log;

		internal static void Map(IList<Tweak> tweaks, ManualLogSource logSource)
		{
			log = logSource;
			Dictionary<Type, Tweak> byType = tweaks.ToDictionary((Tweak t) => t.GetType());
			Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(Assembly.GetExecutingAssembly());
			foreach (Type type in typesFromAssembly)
			{
				if (!type.IsDefined(typeof(HarmonyPatch), inherit: false))
				{
					continue;
				}
				Tweak[] array = Owners(type, byType);
				if (array != null)
				{
					classes.Add(new PatchClass
					{
						Type = type,
						Serves = array,
						Optional = type.GetCustomAttributes(typeof(ServesAttribute), inherit: false).Cast<ServesAttribute>().Any((ServesAttribute s) => s.Optional),
						LoadHook = type.IsDefined(typeof(LoadHookAttribute), inherit: false)
					});
				}
			}
		}

		private static Tweak[] Owners(Type type, Dictionary<Type, Tweak> byType)
		{
			if (type.IsDefined(typeof(AlwaysAttribute), inherit: false))
			{
				return new Tweak[0];
			}
			ServesAttribute servesAttribute = (ServesAttribute)type.GetCustomAttributes(typeof(ServesAttribute), inherit: false).FirstOrDefault();
			if (servesAttribute != null)
			{
				List<Tweak> list = new List<Tweak>();
				Type[] tweaks = servesAttribute.Tweaks;
				foreach (Type tweak in tweaks)
				{
					if (byType.TryGetValue(tweak, out var value))
					{
						list.Add(value);
						continue;
					}
					if (typeof(Tweak).IsAssignableFrom(tweak))
					{
						log.LogWarning((object)(type.FullName + " serves " + tweak.Name + ", which is not in the Tweaks list"));
						continue;
					}
					list.AddRange(byType.Values.Where((Tweak t) => t.Uses.Contains(tweak)));
				}
				if (list.Count <= 0)
				{
					return null;
				}
				return list.Distinct().ToArray();
			}
			Type declaringType = type.DeclaringType;
			while (declaringType != null)
			{
				if (byType.TryGetValue(declaringType, out var value2))
				{
					return new Tweak[1] { value2 };
				}
				declaringType = declaringType.DeclaringType;
			}
			log.LogWarning((object)(type.FullName + " belongs to no tweak and names none, so it is always applied"));
			return new Tweak[0];
		}

		internal static bool AnyServedOn(Type patchClass)
		{
			foreach (PatchClass @class in classes)
			{
				if (@class.Type != patchClass)
				{
					continue;
				}
				Tweak[] serves = @class.Serves;
				for (int i = 0; i < serves.Length; i++)
				{
					if (serves[i].On)
					{
						return true;
					}
				}
				return false;
			}
			return false;
		}

		internal static bool MayNeedRestart(Tweak tweak)
		{
			return classes.Any((PatchClass c) => c.LoadHook && c.Serves.Contains(tweak));
		}

		internal static void Apply(Harmony instance, IList<Tweak> tweaks)
		{
			harmony = instance;
			foreach (PatchClass @class in classes)
			{
				if (@class.Serves.Length == 0 || @class.Serves.Any((Tweak t) => t.Wanted && !t.Broken))
				{
					TryApply(@class);
				}
			}
			foreach (Tweak tweak in tweaks)
			{
				if (tweak.Wanted && !tweak.Broken)
				{
					GoLive(tweak);
				}
				tweak.Enabled.SettingChanged += delegate
				{
					SwitchedOn(tweak);
				};
			}
		}

		private static void SwitchedOn(Tweak tweak)
		{
			if (!tweak.Wanted || tweak.Patched || tweak.Broken)
			{
				return;
			}
			List<PatchClass> list = classes.Where((PatchClass c) => c.Serves.Contains(tweak) && !c.Applied && !c.Failed).ToList();
			if (list.Any((PatchClass c) => c.LoadHook))
			{
				log.LogInfo((object)(tweak.Section + " was off at launch and takes effect at the next start of the game"));
				return;
			}
			foreach (PatchClass item in list)
			{
				TryApply(item);
			}
			if (!tweak.Broken)
			{
				GoLive(tweak);
				log.LogInfo((object)(tweak.Section + " switched on"));
			}
		}

		private static void GoLive(Tweak tweak)
		{
			tweak.Patched = true;
			tweak.Refresh();
		}

		private static void TryApply(PatchClass patch)
		{
			try
			{
				harmony.CreateClassProcessor(patch.Type).Patch();
				patch.Applied = true;
			}
			catch (Exception ex)
			{
				patch.Failed = true;
				Unpatch(patch);
				string message = (ex.InnerException ?? ex).Message;
				if (patch.Serves.Length == 0 || patch.Optional)
				{
					log.LogError((object)(patch.Type.FullName + " could not be patched, carrying on without it: " + message));
					return;
				}
				Tweak[] serves = patch.Serves;
				for (int i = 0; i < serves.Length; i++)
				{
					Break(serves[i], patch.Type, message);
				}
			}
		}

		private static void Break(Tweak tweak, Type failed, string cause)
		{
			if (tweak.Broken)
			{
				return;
			}
			tweak.Broken = true;
			tweak.Patched = false;
			log.LogError((object)(tweak.Section + " is switched off: " + failed.FullName + " could not be patched, most likely because a game update changed it. " + cause));
			foreach (PatchClass @class in classes)
			{
				if (@class.Applied && @class.Serves.Contains(tweak) && !@class.Serves.Any((Tweak t) => !t.Broken && (t.Patched || t.Wanted)))
				{
					Unpatch(@class);
					@class.Applied = false;
				}
			}
			tweak.Refresh();
		}

		private static void Unpatch(PatchClass patch)
		{
			try
			{
				foreach (MethodBase item in harmony.GetPatchedMethods().ToList())
				{
					Patches patchInfo = Harmony.GetPatchInfo(item);
					if (patchInfo == null)
					{
						continue;
					}
					foreach (Patch item2 in patchInfo.Prefixes.Concat(patchInfo.Postfixes).Concat(patchInfo.Transpilers).Concat(patchInfo.Finalizers)
						.Concat(patchInfo.ILManipulators)
						.ToList())
					{
						if (item2.owner == harmony.Id && item2.PatchMethod.DeclaringType == patch.Type)
						{
							harmony.Unpatch(item, item2.PatchMethod);
						}
					}
				}
			}
			catch (Exception ex)
			{
				log.LogError((object)("could not take out " + patch.Type.FullName + ": " + ex.Message));
			}
		}
	}
	internal static class Translations
	{
		[HarmonyPatch(typeof(Localization), "SetupLanguage")]
		[Always]
		private static class Load
		{
			private static void Postfix(Localization __instance, string language)
			{
				if (__instance == null || !Read() || !Reader())
				{
					return;
				}
				object obj = null;
				try
				{
					obj = textAsset.Invoke(new object[1] { csv });
					loadCsv.Invoke(__instance, new object[2]
					{
						obj,
						Has(language) ? language : "English"
					});
					Revision++;
				}
				catch (Exception ex)
				{
					TweakHost.Log.LogWarning((object)("could not load translations.csv: " + ex.Message));
				}
				finally
				{
					Object val = (Object)((obj is Object) ? obj : null);
					if (val != (Object)null)
					{
						Object.Destroy(val);
					}
				}
			}
		}

		private const string FileName = "translations.csv";

		private const string Fallback = "English";

		private static string csv;

		private static string[] languages;

		private static ConstructorInfo textAsset;

		private static MethodInfo loadCsv;

		private static bool looked;

		internal static int Revision { get; private set; }

		private static bool Read()
		{
			if (languages != null)
			{
				return csv != null;
			}
			languages = new string[0];
			try
			{
				string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "translations.csv");
				if (!File.Exists(text))
				{
					TweakHost.Log.LogDebug((object)("no translations.csv beside the DLL: " + text));
					return false;
				}
				csv = File.ReadAllText(text);
				using (StringReader stringReader = new StringReader(csv))
				{
					string text2 = stringReader.ReadLine();
					languages = ((text2 != null) ? text2.Split(new char[1] { ',' }) : new string[0]);
				}
				for (int i = 0; i < languages.Length; i++)
				{
					languages[i] = languages[i].Trim().Trim(new char[1] { '"' });
				}
			}
			catch (Exception ex)
			{
				csv = null;
				TweakHost.Log.LogWarning((object)("could not read translations.csv: " + ex.Message));
			}
			return csv != null;
		}

		private static bool Has(string language)
		{
			string[] array = languages;
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i] == language)
				{
					return true;
				}
			}
			return false;
		}

		private static bool Reader()
		{
			if (looked)
			{
				if (loadCsv != null)
				{
					return textAsset != null;
				}
				return false;
			}
			looked = true;
			Type type = Type.GetType("UnityEngine.TextAsset, UnityEngine.CoreModule");
			if (type != null)
			{
				textAsset = type.GetConstructor(new Type[1] { typeof(string) });
				loadCsv = typeof(Localization).GetMethod("LoadCSV", new Type[2]
				{
					type,
					typeof(string)
				});
			}
			if (loadCsv == null || textAsset == null)
			{
				TweakHost.Log.LogWarning((object)"Localization.LoadCSV not found; the mod's words stay untranslated");
				return false;
			}
			return true;
		}
	}
	internal abstract class Tweak
	{
		private const float MinMultiplier = 0.1f;

		private const float MaxMultiplier = 20f;

		private const string RestartNote = " If it was off when the game started, switching it on may only take effect after a restart.";

		private ConfigEntry<bool> enabled;

		private readonly List<Action> settingHandlers = new List<Action>();

		internal abstract string Section { get; }

		protected abstract string Summary { get; }

		internal virtual Type[] Uses => Type.EmptyTypes;

		internal bool On
		{
			get
			{
				if (Patched)
				{
					return Wanted;
				}
				return false;
			}
		}

		internal bool Wanted
		{
			get
			{
				if (enabled != null)
				{
					return enabled.Value;
				}
				return false;
			}
		}

		internal ConfigEntry<bool> Enabled => enabled;

		internal bool Patched { get; set; }

		internal bool Broken { get; set; }

		protected virtual void Bind(ConfigFile config)
		{
		}

		internal void Setup(ConfigFile config, bool mayNeedRestart)
		{
			enabled = config.Bind<bool>(Section, "Enabled", true, Summary + (mayNeedRestart ? " If it was off when the game started, switching it on may only take effect after a restart." : ""));
			Bind(config);
		}

		internal void Refresh()
		{
			foreach (Action settingHandler in settingHandlers)
			{
				settingHandler();
			}
		}

		protected ConfigEntry<float> BindMultiplier(ConfigFile config, string key, float value, string description)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			return config.Bind<float>(Section, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>()));
		}

		protected ConfigEntry<string> BindList(ConfigFile config, string key, string value, string description, Action<List<string>> apply)
		{
			ConfigEntry<string> entry = config.Bind<string>(Section, key, value, description);
			entry.SettingChanged += delegate
			{
				apply(Items(entry.Value));
			};
			apply(Items(entry.Value));
			return entry;
		}

		internal static List<string> Items(string list)
		{
			List<string> list2 = new List<string>();
			string[] array = (list ?? "").Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0)
				{
					list2.Add(text);
				}
			}
			return list2;
		}

		protected void OnSettingChanged(ConfigFile config, Action handler)
		{
			settingHandlers.Add(handler);
			config.SettingChanged += delegate(object sender, SettingChangedEventArgs args)
			{
				if (args.ChangedSetting.Definition.Section == Section)
				{
					handler();
				}
			};
		}
	}
	internal static class TweakHost
	{
		internal static ManualLogSource Log;

		internal static BaseUnityPlugin Plugin;

		internal static void Start(BaseUnityPlugin plugin, ManualLogSource logger, ConfigFile config, string guid, Tweak[] tweaks, Action<ConfigFile> bindShared = null)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			Plugin = plugin;
			Log = logger;
			HashSet<string> known = LegacyConfig.Sections(config.ConfigFilePath);
			bindShared?.Invoke(config);
			Patcher.Map(tweaks, logger);
			foreach (Tweak tweak in tweaks)
			{
				tweak.Setup(config, Patcher.MayNeedRestart(tweak));
			}
			LegacyConfig.Import(config, known);
			Patcher.Apply(new Harmony(guid), tweaks);
			string text = string.Join(", ", (from t in tweaks
				where t.On
				select t.Section).ToArray());
			logger.LogInfo((object)((text.Length > 0) ? ("tweaks on: " + text) : "every tweak is switched off"));
		}
	}
	internal static class UiAssets
	{
		private static readonly Dictionary<string, Sprite> icons = new Dictionary<string, Sprite>();

		private static MethodInfo loadImage;

		internal static Sprite Icon(string name)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			if (icons.TryGetValue(name, out var value))
			{
				return value;
			}
			value = null;
			try
			{
				string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
				string text = IconPath(directoryName, name);
				if (text != null)
				{
					Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
					if (LoadPng(val, File.ReadAllBytes(text)))
					{
						((Texture)val).filterMode = (FilterMode)1;
						value = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
					}
				}
				else
				{
					TweakHost.Log.LogWarning((object)("icon missing: " + name + ".png, looked in " + Path.Combine(directoryName, "icons") + " and " + directoryName));
				}
			}
			catch (Exception ex)
			{
				TweakHost.Log.LogWarning((object)("could not load icon " + name + ": " + ex.Message));
			}
			icons[name] = value;
			return value;
		}

		private static string IconPath(string dir, string name)
		{
			string path = name + ".png";
			string[] array = new string[2]
			{
				Path.Combine(Path.Combine(dir, "icons"), path),
				Path.Combine(dir, path)
			};
			foreach (string text in array)
			{
				if (File.Exists(text))
				{
					return text;
				}
			}
			return null;
		}

		private static bool LoadPng(Texture2D texture, byte[] png)
		{
			if (loadImage == null)
			{
				Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule");
				loadImage = ((type != null) ? type.GetMethod("LoadImage", new Type[2]
				{
					typeof(Texture2D),
					typeof(byte[])
				}) : null);
				if (loadImage == null)
				{
					TweakHost.Log.LogWarning((object)"ImageConversion.LoadImage not found; icons stay blank");
					return false;
				}
			}
			return (bool)loadImage.Invoke(null, new object[2] { texture, png });
		}

		internal static GameObject TooltipPrefab(InventoryGui gui)
		{
			InventoryGrid playerGrid = gui.m_playerGrid;
			GameObject val = (((Object)(object)playerGrid != (Object)null) ? playerGrid.m_elementPrefab : null);
			InventoryElement val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<InventoryElement>() : null);
			if ((Object)(object)val2 != (Object)null && (Object)(object)val2.m_tooltip != (Object)null && (Object)(object)val2.m_tooltip.m_tooltipPrefab != (Object)null)
			{
				return val2.m_tooltip.m_tooltipPrefab;
			}
			UITooltip[] componentsInChildren = ((Component)gui).GetComponentsInChildren<UITooltip>(true);
			foreach (UITooltip val3 in componentsInChildren)
			{
				if ((Object)(object)val3.m_tooltipPrefab != (Object)null)
				{
					return val3.m_tooltipPrefab;
				}
			}
			return null;
		}
	}
}