Decompiled source of CombatAdjustments v0.8.3

CombatAdjustments.ShieldRework.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using MushroomMods;
using MushroomSync;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("CombatAdjustments.ShieldRework")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+fb6e188389caf8c4c70b703d0ed970d1e986a288")]
[assembly: AssemblyProduct("CombatAdjustments.ShieldRework")]
[assembly: AssemblyTitle("CombatAdjustments.ShieldRework")]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MushroomMods
{
	internal static class PatchIsolation
	{
		internal static int PatchAllIsolated(Harmony harmony, Assembly assembly, ManualLogSource log)
		{
			int num = 0;
			Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(assembly);
			foreach (Type type in typesFromAssembly)
			{
				try
				{
					harmony.CreateClassProcessor(type).Patch();
				}
				catch (Exception ex)
				{
					num++;
					log.LogError((object)("Harmony patch class " + type.FullName + " was skipped and the rest of " + harmony.Id + " is still active. " + ex));
				}
			}
			return num;
		}
	}
}
namespace CombatAdjustments.ShieldRework
{
	internal static class ConfigPaths
	{
		internal static readonly Dictionary<string, string> OverlayDefaults = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		internal static bool UseDedicatedLayout => Application.isBatchMode;

		internal static string ClientPath(string pluginGuid)
		{
			return Path.Combine(Paths.ConfigPath, pluginGuid + ".cfg");
		}

		internal static string DedicatedPath(string pluginGuid)
		{
			return Path.Combine(Paths.GameRootPath, "config", "bepinex", pluginGuid + ".cfg");
		}

		internal static ConfigFile CreateMergedConfig(string pluginGuid)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			OverlayDefaults.Clear();
			string text = ClientPath(pluginGuid);
			string text2 = DedicatedPath(pluginGuid);
			bool flag = File.Exists(text);
			bool flag2 = File.Exists(text2);
			if (UseDedicatedLayout)
			{
				return CreateDedicatedConfig(pluginGuid, text, text2, flag, flag2);
			}
			if (flag2)
			{
				LoadOverlayDefaults(text2);
			}
			ConfigFile result = new ConfigFile(flag ? text : text2, true);
			if (flag && flag2)
			{
				ShieldReworkPlugin.Log.LogInfo((object)("Config: client using " + text + " with overlay from " + text2 + "."));
			}
			else if (flag2)
			{
				ShieldReworkPlugin.Log.LogInfo((object)("Config: client loaded " + text2 + "."));
			}
			else if (flag)
			{
				ShieldReworkPlugin.Log.LogInfo((object)("Config: client loaded " + text + "."));
			}
			else
			{
				ShieldReworkPlugin.Log.LogInfo((object)("Config: client — no file yet; will create " + text + " (also reads " + text2 + " when present)."));
			}
			return result;
		}

		private static ConfigFile CreateDedicatedConfig(string pluginGuid, string client, string dedicated, bool clientExists, bool dedicatedExists)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			ConfigFile result = new ConfigFile(dedicatedExists ? dedicated : client, true);
			if (dedicatedExists)
			{
				ShieldReworkPlugin.Log.LogInfo((object)("Config: dedicated server using " + dedicated + "."));
			}
			else if (clientExists)
			{
				ShieldReworkPlugin.Log.LogWarning((object)("Config: dedicated server — no file at " + dedicated + "; falling back to " + client + "."));
			}
			else
			{
				ShieldReworkPlugin.Log.LogInfo((object)("Config: dedicated server — no file yet; will create " + dedicated + "."));
			}
			return result;
		}

		internal static void ApplyOverlayAfterObjectDbLoad(ConfigFile config)
		{
			if (!UseDedicatedLayout)
			{
				string text = DedicatedPath("Abortipus.CombatAdjustments.ShieldRework");
				if (File.Exists(text))
				{
					LoadOverlayDefaults(text);
					ApplyOverlayToBoundEntries(config);
				}
			}
		}

		internal static bool TryGetOverlayDefault(string section, string key, out string serialized)
		{
			return OverlayDefaults.TryGetValue(BuildKey(section, key), out serialized);
		}

		internal static void ApplyOverlayToStaticEntries(ConfigFile config)
		{
			if (!UseDedicatedLayout)
			{
				string path = ClientPath("Abortipus.CombatAdjustments.ShieldRework");
				if (File.Exists(DedicatedPath("Abortipus.CombatAdjustments.ShieldRework")) && File.Exists(path))
				{
					ApplyOverlayAfterObjectDbLoad(config);
				}
			}
		}

		private static void LoadOverlayDefaults(string overlayPath)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			OverlayDefaults.Clear();
			if (!File.Exists(overlayPath))
			{
				return;
			}
			foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in new ConfigFile(overlayPath, false))
			{
				OverlayDefaults[BuildKey(item.Key.Section, item.Key.Key)] = item.Value.GetSerializedValue() ?? string.Empty;
			}
		}

		private static void ApplyOverlayToBoundEntries(ConfigFile target)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			foreach (KeyValuePair<string, string> overlayDefault in OverlayDefaults)
			{
				SplitKey(overlayDefault.Key, out string section, out string key);
				if (section == null || key == null)
				{
					continue;
				}
				ConfigDefinition val = new ConfigDefinition(section, key);
				foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in target)
				{
					if (item.Key.Equals(val))
					{
						item.Value.SetSerializedValue(overlayDefault.Value);
						break;
					}
				}
			}
		}

		private static string BuildKey(string? section, string? key)
		{
			return (section ?? string.Empty) + "\u001f" + (key ?? string.Empty);
		}

		private static void SplitKey(string path, out string? section, out string? key)
		{
			int num = path.IndexOf('\u001f');
			if (num < 0)
			{
				section = null;
				key = null;
			}
			else
			{
				section = path.Substring(0, num);
				key = path.Substring(num + 1);
			}
		}
	}
	internal static class ConsoleCommands
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ConsoleEvent <0>__PrintStagger;

			public static ConsoleEvent <1>__ToggleStaggerHud;

			public static ConsoleEvent <2>__DumpObjectDb;
		}

		private static bool _registered;

		internal static void Register()
		{
			//IL_003d: 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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0072: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_00a7: 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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			//IL_00dc: 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_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Expected O, but got Unknown
			if (_registered)
			{
				return;
			}
			_registered = true;
			try
			{
				object obj = <>O.<0>__PrintStagger;
				if (obj == null)
				{
					ConsoleEvent val = PrintStagger;
					<>O.<0>__PrintStagger = val;
					obj = (object)val;
				}
				new ConsoleCommand("shieldstagger", "print current stagger bar breakdown (base HP + shield grant)", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
				object obj2 = <>O.<0>__PrintStagger;
				if (obj2 == null)
				{
					ConsoleEvent val2 = PrintStagger;
					<>O.<0>__PrintStagger = val2;
					obj2 = (object)val2;
				}
				new ConsoleCommand("sstagger", "alias for shieldstagger", (ConsoleEvent)obj2, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
				object obj3 = <>O.<1>__ToggleStaggerHud;
				if (obj3 == null)
				{
					ConsoleEvent val3 = ToggleStaggerHud;
					<>O.<1>__ToggleStaggerHud = val3;
					obj3 = (object)val3;
				}
				new ConsoleCommand("staggerhud", "toggle on-screen stagger current/total under the stagger bar (optional: on|off)", (ConsoleEvent)obj3, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
				object obj4 = <>O.<1>__ToggleStaggerHud;
				if (obj4 == null)
				{
					ConsoleEvent val4 = ToggleStaggerHud;
					<>O.<1>__ToggleStaggerHud = val4;
					obj4 = (object)val4;
				}
				new ConsoleCommand("shud", "alias for staggerhud", (ConsoleEvent)obj4, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
				object obj5 = <>O.<2>__DumpObjectDb;
				if (obj5 == null)
				{
					ConsoleEvent val5 = DumpObjectDb;
					<>O.<2>__DumpObjectDb = val5;
					obj5 = (object)val5;
				}
				new ConsoleCommand("cadump", "write the ObjectDB / global-key diagnostics dump next to the mod config", (ConsoleEvent)obj5, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
				ShieldReworkPlugin.Log.LogInfo((object)"Console commands registered: shieldstagger, sstagger, staggerhud, shud, cadump");
			}
			catch (Exception ex)
			{
				ShieldReworkPlugin.Log.LogError((object)("Failed to register Shield Rework console commands; continuing without them: " + ex.Message));
			}
		}

		private static void DumpObjectDb(ConsoleEventArgs args)
		{
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				Terminal context = args.Context;
				if (context != null)
				{
					context.AddString("<color=red>ObjectDB not loaded yet — join a world first.</color>");
				}
				return;
			}
			string text = Diagnostics.Write(ObjectDB.instance, "cadump console command");
			Terminal context2 = args.Context;
			if (context2 != null)
			{
				context2.AddString((text == null) ? "<color=red>Dump failed; see the BepInEx log.</color>" : ("Dump written to " + text));
			}
		}

		private static void ToggleStaggerHud(ConsoleEventArgs args)
		{
			if (args.Length >= 2)
			{
				string text = args[1].ToLowerInvariant();
				bool flag;
				switch (text)
				{
				case "on":
				case "1":
				case "true":
					flag = true;
					break;
				default:
					flag = false;
					break;
				}
				if (flag)
				{
					StaggerDebugHud.SetVisible(visible: true, args);
					return;
				}
				switch (text)
				{
				case "off":
				case "0":
				case "false":
					flag = true;
					break;
				default:
					flag = false;
					break;
				}
				if (flag)
				{
					StaggerDebugHud.SetVisible(visible: false, args);
					return;
				}
			}
			StaggerDebugHud.Toggle(args);
		}

		private static void PrintStagger(ConsoleEventArgs args)
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Invalid comparison between Unknown and I4
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				Terminal context = args.Context;
				if (context != null)
				{
					context.AddString("<color=red>No local player.</color>");
				}
				return;
			}
			float maxHealth = ((Character)localPlayer).GetMaxHealth();
			float num = maxHealth * ((Character)localPlayer).m_staggerDamageFactor;
			float num2 = ShieldStats.GrantForEquippedShield((Humanoid)(object)localPlayer);
			float value = Traverse.Create((object)localPlayer).Method("GetStaggerTreshold", Array.Empty<object>()).GetValue<float>();
			float value2 = Traverse.Create((object)localPlayer).Field("m_staggerDamage").GetValue<float>();
			float num3 = ((Character)localPlayer).GetStaggerPercentage() * 100f;
			ItemData leftItem = ((Humanoid)localPlayer).LeftItem;
			string text = "none";
			if (leftItem?.m_shared != null && (int)leftItem.m_shared.m_itemType == 5)
			{
				string arg = (((Object)(object)leftItem.m_dropPrefab != (Object)null) ? ShieldStats.PrefabName(leftItem.m_dropPrefab) : leftItem.m_shared.m_name);
				text = $"{arg} (q{leftItem.m_quality})";
			}
			Terminal context2 = args.Context;
			if (context2 != null)
			{
				context2.AddString("=== Shield Rework: stagger ===");
			}
			Terminal context3 = args.Context;
			if (context3 != null)
			{
				context3.AddString($"Max HP:            {maxHealth:0.#}");
			}
			Terminal context4 = args.Context;
			if (context4 != null)
			{
				context4.AddString($"Base bar (40% HP): {num:0.#}");
			}
			Terminal context5 = args.Context;
			if (context5 != null)
			{
				context5.AddString("Shield equipped:   " + text);
			}
			Terminal context6 = args.Context;
			if (context6 != null)
			{
				context6.AddString($"Shield grant:      +{num2:0}");
			}
			Terminal context7 = args.Context;
			if (context7 != null)
			{
				context7.AddString($"<color=#E85AC8>Total threshold:   {value:0.#}</color>");
			}
			Terminal context8 = args.Context;
			if (context8 != null)
			{
				context8.AddString($"Current fill:      {value2:0.#}  ({num3:0.#}%)");
			}
			Terminal context9 = args.Context;
			if (context9 != null)
			{
				context9.AddString($"Drain rate:        {value / 5f:0.#}/s  (full bar empties in 5s)");
			}
			if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)MessageHud.instance != (Object)null)
			{
				MessageHud.instance.ShowMessage((MessageType)2, $"Stagger {value2:0}/{value:0}  (+{num2:0} from shield)", 0, (Sprite)null, false, true);
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	internal static class Terminal_InitTerminal_Patch
	{
		private static void Postfix()
		{
			try
			{
				ConsoleCommands.Register();
			}
			catch (Exception ex)
			{
				ShieldReworkPlugin.Log.LogError((object)("Terminal.InitTerminal postfix failed: " + ex.Message));
			}
		}
	}
	internal static class Diagnostics
	{
		private const string FileName = "CombatAdjustments.ShieldRework.objectdb-dump.txt";

		private static bool _dumped;

		private static readonly (string Boss, string Key)[] BossKeys = new(string, string)[8]
		{
			("Eikthyr", "defeated_eikthyr"),
			("Elder", "defeated_gdking"),
			("Bonemass", "defeated_bonemass"),
			("Moder", "defeated_dragon"),
			("Yagluth", "defeated_goblinking"),
			("Queen", "defeated_queen"),
			("Fader", "defeated_fader"),
			("FrozenKing", "defeated_frozenking")
		};

		internal static string DumpPath
		{
			get
			{
				string text = null;
				try
				{
					text = Path.GetDirectoryName(ShieldReworkPlugin.ModConfig.ConfigFilePath);
				}
				catch (Exception)
				{
				}
				if (string.IsNullOrEmpty(text))
				{
					text = Paths.ConfigPath;
				}
				return Path.Combine(text, "CombatAdjustments.ShieldRework.objectdb-dump.txt");
			}
		}

		internal static void DumpOnceIfEnabled(ObjectDB db)
		{
			if (!_dumped && ShieldReworkPlugin.DumpObjectDb != null && ShieldReworkPlugin.DumpObjectDb.Value)
			{
				_dumped = true;
				Write(db, "ObjectDB load, [Diagnostics] DumpObjectDb = true");
			}
		}

		internal static string? Write(ObjectDB? db, string reason)
		{
			string dumpPath = DumpPath;
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				Header(stringBuilder, reason);
				GlobalKeys(stringBuilder);
				TableCoverage(stringBuilder, db);
				Shields(stringBuilder, db);
				Foods(stringBuilder, db);
				AllItems(stringBuilder, db);
				stringBuilder.AppendLine("===== END DUMP =====");
				File.WriteAllText(dumpPath, stringBuilder.ToString());
				ShieldReworkPlugin.Log.LogInfo((object)("Diagnostics: ObjectDB dump written to " + dumpPath));
				return dumpPath;
			}
			catch (Exception ex)
			{
				ShieldReworkPlugin.Log.LogError((object)("Diagnostics: could not write " + dumpPath + ": " + ex.Message));
				return null;
			}
		}

		private static void Header(StringBuilder sb, string reason)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			sb.AppendLine("===== COMBAT ADJUSTMENTS :: OBJECTDB DUMP =====");
			sb.AppendLine("Plugin:   Combat Adjustments - Shield Rework 0.8.3");
			sb.AppendLine($"Game:     {Version.CurrentVersion}");
			sb.AppendLine("Written:  " + DateTime.UtcNow.ToString("u", CultureInfo.InvariantCulture));
			sb.AppendLine("Trigger:  " + reason);
			sb.AppendLine();
		}

		private static void GlobalKeys(StringBuilder sb)
		{
			sb.AppendLine("--- GLOBAL KEYS CURRENTLY SET ---");
			ZoneSystem instance = ZoneSystem.instance;
			if ((Object)(object)instance == (Object)null)
			{
				sb.AppendLine("  ZoneSystem not available (run this from inside a world).");
				sb.AppendLine();
				return;
			}
			bool flag = false;
			foreach (string globalKey in instance.GetGlobalKeys())
			{
				sb.AppendLine("  " + globalKey);
				flag = true;
			}
			if (!flag)
			{
				sb.AppendLine("  (none set on this world)");
			}
			sb.AppendLine();
			sb.AppendLine("--- BOSS KEYS THE FEAST GATE USES ---");
			(string, string)[] bossKeys = BossKeys;
			for (int i = 0; i < bossKeys.Length; i++)
			{
				var (text, text2) = bossKeys[i];
				sb.AppendLine("  " + text.PadRight(12) + "'" + text2 + "'".PadRight(24) + " set: " + instance.GetGlobalKey(text2));
			}
			sb.AppendLine("  NOTE: a boss you have killed whose row says set: False means the");
			sb.AppendLine("        spelling above is wrong. Copy the real key from the list at");
			sb.AppendLine("        the top of this section into FeastUnlocks.");
			sb.AppendLine();
		}

		private static void TableCoverage(StringBuilder sb, ObjectDB? db)
		{
			sb.AppendLine("--- MOD TABLE COVERAGE ---");
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			if (db?.m_items != null)
			{
				foreach (GameObject item in db.m_items)
				{
					if (!((Object)(object)item == (Object)null) && (Object)(object)item.GetComponent<ItemDrop>() != (Object)null)
					{
						hashSet.Add(ShieldStats.PrefabName(item));
					}
				}
			}
			if (hashSet.Count == 0)
			{
				sb.AppendLine("  ObjectDB not available; coverage cannot be checked.");
				sb.AppendLine();
				return;
			}
			Coverage(sb, hashSet, "FeastUnlocks spice gates", FeastUnlocks.TrackedSpicePrefabs);
			Coverage(sb, hashSet, "FeastUnlocks recipe gates", FeastUnlocks.TrackedRecipePrefabs, FeastUnlocks.TrackedRecipeAliases);
			Coverage(sb, hashSet, "FeastStats", FeastStats.TrackedPrefabs, FeastStats.AliasPrefabs);
			Coverage(sb, hashSet, "WeaponBlockStats", WeaponBlockStats.TrackedPrefabs);
			Coverage(sb, hashSet, "ShieldStats tower seeds", ShieldStats.TrackedTowerSeedPrefabs);
			Coverage(sb, hashSet, "ShieldStats grant steps", ShieldStats.TrackedGrantStepPrefabs);
			sb.AppendLine();
			sb.AppendLine("  NOTE: MISSING is a defect — a wrong spelling, or a prefab this game");
			sb.AppendLine("        version does not have. 'alias' rows are not: they are spare");
			sb.AppendLine("        spellings deliberately carried beside a real name, and ObjectDB");
			sb.AppendLine("        is not expected to contain them. A healthy dump has zero MISSING.");
			sb.AppendLine();
		}

		private static void Coverage(StringBuilder sb, HashSet<string> known, string label, IEnumerable<string> prefabs, IEnumerable<string>? aliases = null)
		{
			HashSet<string> hashSet = ((aliases == null) ? null : new HashSet<string>(aliases, StringComparer.OrdinalIgnoreCase));
			sb.AppendLine("  [" + label + "]");
			foreach (string prefab in prefabs)
			{
				string text = (known.Contains(prefab) ? "ok" : ((hashSet != null && hashSet.Contains(prefab)) ? "alias (not in this version)" : "MISSING — wrong spelling, or not in this game version"));
				sb.AppendLine("    " + prefab.PadRight(32) + text);
			}
		}

		private static void Shields(StringBuilder sb, ObjectDB? db)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Invalid comparison between Unknown and I4
			sb.AppendLine("--- SHIELDS ---");
			sb.AppendLine("  name / kind / maxQ / blockPower / perLevel / maxBlock / parryBonus / our grant");
			sb.AppendLine("  Block numbers are the CURRENT values. On a TOWER with");
			sb.AppendLine("  Shield.EnableTowerArmorBonus on they already carry this mod's +5%");
			sb.AppendLine("  (ceil per field), so divide it back out before re-deriving a seed:");
			sb.AppendLine("  a tower printed as 166/7 is vanilla 158/6, i.e. 170 at max quality.");
			if (db?.m_items == null)
			{
				sb.AppendLine("  ObjectDB not available.");
				sb.AppendLine();
				return;
			}
			foreach (GameObject item in db.m_items)
			{
				SharedData val = SharedOf(item);
				if (val != null && (int)val.m_itemType == 5)
				{
					string text = ShieldStats.PrefabName(item);
					ShieldKind shieldKind = ShieldStats.Classify(val);
					sb.AppendLine("  " + text.PadRight(30) + shieldKind.ToString().PadRight(9) + "q" + val.m_maxQuality.ToString(CultureInfo.InvariantCulture).PadRight(4) + Num(val.m_blockPower).PadRight(9) + Num(val.m_blockPowerPerLevel).PadRight(9) + Num(ShieldStats.MaxBaseBlockPower(val)).PadRight(10) + Num(val.m_timedBlockBonus).PadRight(8) + "+" + Num(ShieldStats.GetMaxGrant(text)));
				}
			}
			sb.AppendLine();
		}

		private static void Foods(StringBuilder sb, ObjectDB? db)
		{
			sb.AppendLine("--- FOODS (health / stamina / eitr / burn time) ---");
			sb.AppendLine("  Values shown are the CURRENT shared values, i.e. vanilla plus this mod's");
			sb.AppendLine("  feast bonuses. Feast rows also print the vanilla numbers FeastStats");
			sb.AppendLine("  cached before it applied anything, so 'what is vanilla X?' is answered");
			sb.AppendLine("  here without having to turn Feasts.EnableStatBonuses off and re-dump.");
			if (db?.m_items == null)
			{
				sb.AppendLine("  ObjectDB not available.");
				sb.AppendLine();
				return;
			}
			foreach (GameObject item in db.m_items)
			{
				SharedData val = SharedOf(item);
				if (val != null && (!(val.m_food <= 0f) || !(val.m_foodStamina <= 0f) || !(val.m_foodEitr <= 0f)))
				{
					string text = ShieldStats.PrefabName(item);
					(float, float, float) original;
					string text2 = (FeastStats.TryGetOriginal(text, out original) ? ("   vanilla " + Num(original.Item1) + " / " + Num(original.Item2) + " / " + Num(original.Item3)) : string.Empty);
					sb.AppendLine("  " + text.PadRight(32) + Num(val.m_food).PadRight(8) + Num(val.m_foodStamina).PadRight(8) + Num(val.m_foodEitr).PadRight(8) + Num(val.m_foodBurnTime).PadRight(8) + text2);
				}
			}
			sb.AppendLine();
		}

		private static void AllItems(StringBuilder sb, ObjectDB? db)
		{
			sb.AppendLine("--- ALL ITEMDROP PREFABS ---");
			if (db?.m_items == null)
			{
				sb.AppendLine("  ObjectDB not available.");
				return;
			}
			int num = 0;
			foreach (GameObject item in db.m_items)
			{
				SharedData val = SharedOf(item);
				if (val != null)
				{
					sb.AppendLine("  " + ShieldStats.PrefabName(item).PadRight(36) + ((object)Unsafe.As<ItemType, ItemType>(ref val.m_itemType)/*cast due to .constrained prefix*/).ToString());
					num++;
				}
			}
			sb.AppendLine($"  ({num} item prefabs)");
		}

		private static SharedData? SharedOf(GameObject? go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return null;
			}
			return go.GetComponent<ItemDrop>()?.m_itemData?.m_shared;
		}

		private static string Num(float value)
		{
			return value.ToString("0.##", CultureInfo.InvariantCulture);
		}
	}
	internal static class DifficultyScaling
	{
		internal static int UncappedPlayerDifficulty(Game game, Vector3 pos)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			int value = Traverse.Create((object)game).Field("m_forcePlayers").GetValue<int>();
			if (value > 0)
			{
				return value;
			}
			int playersInRangeXZ = Player.GetPlayersInRangeXZ(pos, game.m_difficultyScaleRange);
			if (playersInRangeXZ >= 1)
			{
				return playersInRangeXZ;
			}
			return 1;
		}

		internal static float EnemyDamageTakenScale(Game game, int players)
		{
			float num = 1f + (float)(players - 1) * game.m_healthScalePerPlayer;
			return 1f / num;
		}
	}
	[HarmonyPatch(typeof(Game), "GetDifficultyDamageScaleEnemy")]
	internal static class Game_GetDifficultyDamageScaleEnemy_Patch
	{
		private static void Postfix(Game __instance, Vector3 pos, ref float __result)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (ShieldReworkPlugin.EnableUncapHealthScaling.Value)
			{
				int players = DifficultyScaling.UncappedPlayerDifficulty(__instance, pos);
				__result = DifficultyScaling.EnemyDamageTakenScale(__instance, players);
			}
		}
	}
	internal static class FeastStats
	{
		private static readonly Dictionary<string, (float health, float stamina, float eitr)> Originals = new Dictionary<string, (float, float, float)>(StringComparer.OrdinalIgnoreCase);

		private static readonly string[] CanonicalPrefabs = new string[9] { "FeastMeadows", "FeastBlackforest", "FeastSwamps", "FeastOceans", "FeastMountains", "FeastPlains", "FeastMistlands", "FeastAshlands", "FeastDeepNorth" };

		internal static readonly HashSet<string> AliasPrefabs = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "FeastBlackForest", "FeastSwamp", "FeastOcean", "FeastMountain" };

		private static readonly Dictionary<string, FeastKind> PrefabKinds = new Dictionary<string, FeastKind>(StringComparer.OrdinalIgnoreCase)
		{
			["FeastMeadows"] = FeastKind.Meadows,
			["FeastBlackforest"] = FeastKind.BlackForest,
			["FeastBlackForest"] = FeastKind.BlackForest,
			["FeastSwamps"] = FeastKind.Swamp,
			["FeastSwamp"] = FeastKind.Swamp,
			["FeastOceans"] = FeastKind.Sailors,
			["FeastOcean"] = FeastKind.Sailors,
			["FeastMountains"] = FeastKind.Mountains,
			["FeastMountain"] = FeastKind.Mountains,
			["FeastPlains"] = FeastKind.Plains,
			["FeastMistlands"] = FeastKind.Mistlands,
			["FeastAshlands"] = FeastKind.Ashlands,
			["FeastDeepNorth"] = FeastKind.DeepNorth
		};

		internal static IEnumerable<string> TrackedPrefabs => PrefabKinds.Keys;

		internal static void ApplyToObjectDB(ObjectDB db)
		{
			if (db?.m_items == null || db.m_items.Count == 0)
			{
				return;
			}
			int num = 0;
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			foreach (GameObject item in db.m_items)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				ItemDrop component = item.GetComponent<ItemDrop>();
				if (component?.m_itemData?.m_shared != null)
				{
					string prefab = ShieldStats.PrefabName(item);
					if (TryIdentify(prefab, out var kind))
					{
						hashSet.Add(CanonicalPrefab(kind));
						ApplyToShared(prefab, kind, component.m_itemData.m_shared);
						num++;
					}
				}
			}
			string[] canonicalPrefabs = CanonicalPrefabs;
			foreach (string text in canonicalPrefabs)
			{
				if (!hashSet.Contains(text))
				{
					ShieldReworkPlugin.Log.LogWarning((object)("Feast stats: prefab '" + text + "' not found in ObjectDB."));
				}
			}
			ShieldReworkPlugin.Log.LogInfo((object)$"Applied feast bonuses to {num} feast items.");
		}

		internal static void ApplyToShared(string prefab, FeastKind kind, SharedData shared)
		{
			if (!Originals.ContainsKey(prefab))
			{
				Originals[prefab] = (shared.m_food, shared.m_foodStamina, shared.m_foodEitr);
			}
			(float, float, float) tuple = Originals[prefab];
			if (!ShieldReworkPlugin.EnableFeastStatBonuses.Value)
			{
				(shared.m_food, shared.m_foodStamina, shared.m_foodEitr) = tuple;
			}
			else
			{
				shared.m_food = tuple.Item1 + HealthBonus(kind);
				shared.m_foodStamina = tuple.Item2 + StaminaBonus(kind);
				shared.m_foodEitr = tuple.Item3 + EitrBonus(kind);
			}
		}

		internal static bool TryGetOriginal(string prefab, out (float health, float stamina, float eitr) original)
		{
			return Originals.TryGetValue(prefab, out original);
		}

		internal static bool TryIdentify(string prefab, out FeastKind kind)
		{
			if (PrefabKinds.TryGetValue(prefab, out kind))
			{
				return true;
			}
			kind = FeastKind.Meadows;
			return false;
		}

		private static float HealthBonus(FeastKind kind)
		{
			if (kind != FeastKind.Sailors)
			{
				return ShieldReworkPlugin.FeastHealthBonus.Value;
			}
			return ShieldReworkPlugin.SailorsFeastHealthBonus.Value;
		}

		private static float StaminaBonus(FeastKind kind)
		{
			if (kind != FeastKind.Sailors)
			{
				return ShieldReworkPlugin.FeastStaminaBonus.Value;
			}
			return ShieldReworkPlugin.SailorsFeastStaminaBonus.Value;
		}

		private static float EitrBonus(FeastKind kind)
		{
			return kind switch
			{
				FeastKind.Mistlands => ShieldReworkPlugin.MistlandsFeastEitrBonus.Value, 
				FeastKind.Ashlands => ShieldReworkPlugin.AshlandsFeastEitrBonus.Value, 
				FeastKind.DeepNorth => ShieldReworkPlugin.DeepNorthFeastEitrBonus.Value, 
				_ => 0f, 
			};
		}

		private static string CanonicalPrefab(FeastKind kind)
		{
			return kind switch
			{
				FeastKind.Meadows => "FeastMeadows", 
				FeastKind.BlackForest => "FeastBlackforest", 
				FeastKind.Swamp => "FeastSwamps", 
				FeastKind.Sailors => "FeastOceans", 
				FeastKind.Mountains => "FeastMountains", 
				FeastKind.Plains => "FeastPlains", 
				FeastKind.Mistlands => "FeastMistlands", 
				FeastKind.Ashlands => "FeastAshlands", 
				FeastKind.DeepNorth => "FeastDeepNorth", 
				_ => string.Empty, 
			};
		}
	}
	internal enum FeastKind
	{
		Meadows,
		BlackForest,
		Swamp,
		Sailors,
		Mountains,
		Plains,
		Mistlands,
		Ashlands,
		DeepNorth
	}
	internal static class FeastUnlocks
	{
		internal const string Eikthyr = "defeated_eikthyr";

		internal const string Elder = "defeated_gdking";

		internal const string Bonemass = "defeated_bonemass";

		internal const string Moder = "defeated_dragon";

		internal const string Yagluth = "defeated_goblinking";

		internal const string Queen = "defeated_queen";

		internal const string Fader = "defeated_fader";

		internal const string FrozenKing = "defeated_frozenking";

		private static readonly Dictionary<string, string> SpiceKeys = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			["SpiceForests"] = "",
			["SpiceMountains"] = "defeated_bonemass",
			["SpicePlains"] = "defeated_dragon",
			["SpiceMistlands"] = "defeated_goblinking",
			["SpiceAshlands"] = "defeated_queen",
			["SpiceDeepNorth"] = "defeated_fader"
		};

		private static readonly Dictionary<string, string> RecipeKeys = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			["FeastBlackforest"] = "defeated_eikthyr",
			["FeastBlackForest"] = "defeated_eikthyr",
			["FeastSwamps"] = "defeated_gdking",
			["FeastSwamp"] = "defeated_gdking",
			["FeastMountains"] = "defeated_bonemass",
			["FeastMountain"] = "defeated_bonemass",
			["FeastPlains"] = "defeated_dragon",
			["FeastMistlands"] = "defeated_goblinking",
			["FeastAshlands"] = "defeated_queen",
			["FeastDeepNorth"] = "defeated_fader"
		};

		private static readonly HashSet<int> RemappedTraders = new HashSet<int>();

		internal static IEnumerable<string> TrackedSpicePrefabs => SpiceKeys.Keys;

		internal static IEnumerable<string> TrackedRecipePrefabs => RecipeKeys.Keys;

		internal static IEnumerable<string> TrackedRecipeAliases => FeastStats.AliasPrefabs;

		internal static void ApplySpiceKeys(Trader trader)
		{
			if (trader?.m_items == null)
			{
				return;
			}
			int num = 0;
			foreach (TradeItem item in trader.m_items)
			{
				if (!((Object)(object)item?.m_prefab == (Object)null))
				{
					string key = ShieldStats.PrefabName(((Component)item.m_prefab).gameObject);
					if (SpiceKeys.TryGetValue(key, out string value) && !string.Equals(item.m_requiredGlobalKey, value, StringComparison.Ordinal))
					{
						item.m_requiredGlobalKey = value;
						num++;
					}
				}
			}
			if (num != 0)
			{
				int instanceID = ((Object)trader).GetInstanceID();
				if (RemappedTraders.Add(instanceID))
				{
					ShieldReworkPlugin.Log.LogInfo((object)$"Feast unlocks: remapped {num} Bog Witch spice gate(s) on '{ShieldStats.PrefabName(((Component)trader).gameObject)}'.");
				}
			}
		}

		internal static bool IsRecipeLocked(Recipe? recipe)
		{
			ItemDrop val = recipe?.m_item;
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			string key = ShieldStats.PrefabName(((Component)val).gameObject);
			if (!RecipeKeys.TryGetValue(key, out string value) || string.IsNullOrEmpty(value))
			{
				return false;
			}
			ZoneSystem instance = ZoneSystem.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return true;
			}
			return !instance.GetGlobalKey(value);
		}
	}
	[HarmonyPatch(typeof(Trader), "GetAvailableItems")]
	internal static class Trader_GetAvailableItems_FeastUnlocks_Patch
	{
		private static void Prefix(Trader __instance)
		{
			FeastUnlocks.ApplySpiceKeys(__instance);
		}
	}
	[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
	{
		typeof(Recipe),
		typeof(bool),
		typeof(int),
		typeof(int)
	})]
	internal static class Player_HaveRequirements_FeastUnlocks_Patch
	{
		private static void Postfix(Recipe recipe, ref bool __result)
		{
			if (__result && FeastUnlocks.IsRecipeLocked(recipe))
			{
				__result = false;
			}
		}
	}
	internal static class ForgeOfPotential
	{
		internal const float IntendedBreakChance = 0.1f;

		private static readonly Dictionary<string, float> OriginalBreakChance = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

		internal static void ApplyToObjectDB(ObjectDB db)
		{
			if (db?.m_items == null || db.m_items.Count == 0)
			{
				return;
			}
			int num = 0;
			foreach (GameObject item in db.m_items)
			{
				if ((Object)(object)item == (Object)null || !IsIdolPrefab(((Object)item).name))
				{
					continue;
				}
				SharedData val = item.GetComponent<ItemDrop>()?.m_itemData?.m_shared;
				if (val != null)
				{
					string name = ((Object)item).name;
					if (!OriginalBreakChance.ContainsKey(name))
					{
						OriginalBreakChance[name] = val.m_breakChance;
					}
					val.m_breakChance = (ShieldReworkPlugin.EnableForgeOfPotentialOdds.Value ? 0.1f : OriginalBreakChance[name]);
					num++;
				}
			}
			if (num > 0)
			{
				ShieldReworkPlugin.Log.LogInfo((object)(ShieldReworkPlugin.EnableForgeOfPotentialOdds.Value ? $"Forge of Potential: set break chance to {0.1f:0.##} on {num} idols (65% / 25% downgrade / 10% break)." : $"Forge of Potential: restored vanilla break chance on {num} idols."));
			}
		}

		internal static bool IsIdolPrefab(string? prefabName)
		{
			if (prefabName == null || prefabName.Length <= 0)
			{
				return false;
			}
			if (prefabName.StartsWith("Upgrader", StringComparison.Ordinal))
			{
				if (!prefabName.EndsWith("Weapon", StringComparison.Ordinal))
				{
					return prefabName.EndsWith("Armor", StringComparison.Ordinal);
				}
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
	internal static class InventoryGui_DoCrafting_ForgeMinLevel_Patch
	{
		internal sealed class SharedBreakOverride
		{
			private readonly SharedData _shared;

			private readonly float _original;

			internal SharedBreakOverride(SharedData shared, float original)
			{
				_shared = shared;
				_original = original;
			}

			internal void Restore()
			{
				_shared.m_breakChance = _original;
			}
		}

		private static void Prefix(InventoryGui __instance, out SharedBreakOverride? __state)
		{
			__state = null;
			if (!ShieldReworkPlugin.EnableForgeOfPotentialOdds.Value)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			CraftingStation val = ((localPlayer != null) ? localPlayer.GetCurrentCraftingStation() : null);
			if ((Object)(object)val == (Object)null || !val.m_upgrader)
			{
				return;
			}
			ItemData value = Traverse.Create((object)__instance).Field("m_craftUpgradeItem").GetValue<ItemData>();
			if (value != null && value.m_quality <= 1)
			{
				SharedData val2 = FindIdolShared(Traverse.Create((object)__instance).Field("m_craftRecipe").GetValue<Recipe>());
				if (val2 != null)
				{
					__state = new SharedBreakOverride(val2, val2.m_breakChance);
					val2.m_breakChance = 1f;
				}
			}
		}

		private static void Postfix(SharedBreakOverride? __state)
		{
			__state?.Restore();
		}

		private static SharedData? FindIdolShared(Recipe? recipe)
		{
			if (recipe?.m_resources == null)
			{
				return null;
			}
			Requirement[] resources = recipe.m_resources;
			foreach (Requirement val in resources)
			{
				if (val != null && val.m_upgraderResource)
				{
					return val.m_resItem?.m_itemData?.m_shared;
				}
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(Localization), "Localize", new Type[]
	{
		typeof(string),
		typeof(string[])
	})]
	internal static class Localization_Localize_UpgraderFailed_Patch
	{
		private static bool Prefix(Localization __instance, string text, string[] words, ref string __result)
		{
			if (!ShieldReworkPlugin.EnableForgeOfPotentialOdds.Value)
			{
				return true;
			}
			if (text != "$msg_upgrader_failed" || words == null || words.Length < 2)
			{
				return true;
			}
			string text2 = __instance.Localize(words[0]);
			__result = text2 + " downgraded to level " + words[1];
			return false;
		}
	}
	internal static class OceanWeather
	{
		private const string ThunderStormName = "ThunderStorm";

		private static readonly Dictionary<EnvEntry, float> OriginalWeights = new Dictionary<EnvEntry, float>();

		internal static void Apply()
		{
			if ((Object)(object)EnvMan.instance == (Object)null)
			{
				return;
			}
			foreach (BiomeEnvSetup biome in EnvMan.instance.m_biomes)
			{
				ApplyToBiome(biome);
			}
		}

		internal static void ApplyToBiome(BiomeEnvSetup biome)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			if ((int)biome.m_biome != 256)
			{
				return;
			}
			EnvEntry val = null;
			float num = 0f;
			foreach (EnvEntry environment in biome.m_environments)
			{
				if (environment.m_ashlandsOverride || environment.m_deepnorthOverride)
				{
					continue;
				}
				if (environment.m_environment == "ThunderStorm")
				{
					val = environment;
					if (!OriginalWeights.ContainsKey(environment))
					{
						OriginalWeights[environment] = environment.m_weight;
					}
				}
				else
				{
					num += environment.m_weight;
				}
			}
			if (val == null)
			{
				return;
			}
			if (!ShieldReworkPlugin.EnableOceanStormChance.Value)
			{
				val.m_weight = OriginalWeights[val];
				return;
			}
			float num2 = Mathf.Clamp01(ShieldReworkPlugin.OceanThunderStormChance.Value);
			if (num2 <= 0f)
			{
				val.m_weight = 0f;
			}
			else if (num2 >= 1f)
			{
				val.m_weight = Mathf.Max(num * 100f, 1f);
			}
			else
			{
				val.m_weight = num2 * num / (1f - num2);
			}
		}
	}
	[HarmonyPatch(typeof(EnvMan), "InitializeBiomeEnvSetup")]
	internal static class EnvMan_InitializeBiomeEnvSetup_Patch
	{
		private static void Postfix(BiomeEnvSetup biome)
		{
			OceanWeather.ApplyToBiome(biome);
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	internal static class ObjectDB_Awake_Patch
	{
		private static void Postfix(ObjectDB __instance)
		{
			ShieldStats.ApplyToObjectDB(__instance);
			WeaponBlockStats.ApplyToObjectDB(__instance);
			FeastStats.ApplyToObjectDB(__instance);
			ForgeOfPotential.ApplyToObjectDB(__instance);
			Diagnostics.DumpOnceIfEnabled(__instance);
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
	internal static class ObjectDB_CopyOtherDB_Patch
	{
		private static void Postfix(ObjectDB __instance)
		{
			ShieldStats.ApplyToObjectDB(__instance);
			WeaponBlockStats.ApplyToObjectDB(__instance);
			FeastStats.ApplyToObjectDB(__instance);
			ForgeOfPotential.ApplyToObjectDB(__instance);
			Diagnostics.DumpOnceIfEnabled(__instance);
		}
	}
	[HarmonyPatch(typeof(Character), "GetStaggerTreshold")]
	internal static class Character_GetStaggerTreshold_Patch
	{
		private static void Postfix(Character __instance, ref float __result)
		{
			if (ShieldReworkPlugin.EnableStaggerGrant.Value)
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val != null)
				{
					__result += ShieldStats.GrantForEquippedShield((Humanoid)(object)val);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Character), "UpdateStagger")]
	internal static class Character_UpdateStagger_Patch
	{
		private static bool Prefix(Character __instance, float dt, ref float ___m_staggerDamage)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val == null)
			{
				return true;
			}
			if (((Character)val).m_staggerDamageFactor <= 0f)
			{
				return false;
			}
			float value = Traverse.Create((object)val).Method("GetStaggerTreshold", Array.Empty<object>()).GetValue<float>();
			___m_staggerDamage -= value / 5f * dt;
			if (___m_staggerDamage < 0f)
			{
				___m_staggerDamage = 0f;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Humanoid), "EquipItem")]
	internal static class Humanoid_EquipItem_Patch
	{
		private static void Prefix(Humanoid __instance, ItemData item, out float __state)
		{
			__state = StaggerPercent.CaptureIfShield(__instance, item);
		}

		private static void Postfix(Humanoid __instance, ItemData item, bool __result, float __state)
		{
			if (!(__state < 0f) && __result)
			{
				StaggerPercent.Apply((Character)(object)__instance, __state);
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "UnequipItem")]
	internal static class Humanoid_UnequipItem_Patch
	{
		private static void Prefix(Humanoid __instance, ItemData item, out float __state)
		{
			__state = StaggerPercent.CaptureIfShield(__instance, item);
		}

		private static void Postfix(Humanoid __instance, ItemData item, float __state)
		{
			if (!(__state < 0f))
			{
				StaggerPercent.Apply((Character)(object)__instance, __state);
			}
		}
	}
	internal static class StaggerPercent
	{
		private const float Skip = -1f;

		internal static float CaptureIfShield(Humanoid humanoid, ItemData? item)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			if (!(humanoid is Player))
			{
				return -1f;
			}
			if (item?.m_shared == null || (int)item.m_shared.m_itemType != 5)
			{
				return -1f;
			}
			return Capture((Character)(object)humanoid);
		}

		internal static float Capture(Character character)
		{
			float value = Traverse.Create((object)character).Method("GetStaggerTreshold", Array.Empty<object>()).GetValue<float>();
			if (value <= 0f)
			{
				return 0f;
			}
			return Mathf.Clamp01(Traverse.Create((object)character).Field("m_staggerDamage").GetValue<float>() / value);
		}

		internal static void Apply(Character character, float percent)
		{
			float value = Traverse.Create((object)character).Method("GetStaggerTreshold", Array.Empty<object>()).GetValue<float>();
			float num = Mathf.Clamp(percent, 0f, 1f) * Mathf.Max(0f, value);
			Traverse.Create((object)character).Field("m_staggerDamage").SetValue((object)num);
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
	{
		typeof(ItemData),
		typeof(int),
		typeof(bool),
		typeof(float),
		typeof(int),
		typeof(bool)
	})]
	internal static class ItemData_GetTooltip_Patch
	{
		private static void Postfix(ItemData item, int qualityLevel, ref string __result)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			if (item?.m_shared == null || (int)item.m_shared.m_itemType != 5)
			{
				return;
			}
			int quality = item.m_quality;
			item.m_quality = qualityLevel;
			float num = ShieldStats.GrantForItem(item);
			item.m_quality = quality;
			if (num <= 0f)
			{
				return;
			}
			string text = $"\nStagger: <color=orange>+{num:0}</color>";
			int num2 = __result.IndexOf("$item_blockarmor:", StringComparison.Ordinal);
			if (num2 >= 0)
			{
				int num3 = __result.IndexOf('\n', num2);
				if (num3 < 0)
				{
					__result += text;
				}
				else
				{
					__result = __result.Insert(num3, text);
				}
			}
			else
			{
				__result += text;
			}
		}
	}
	internal static class SailingWind
	{
		internal static float ForceFactor(float windIntensity)
		{
			float value = ShieldReworkPlugin.SailingCalmForceFactor.Value;
			float value2 = ShieldReworkPlugin.SailingKneeForceFactor.Value;
			float value3 = ShieldReworkPlugin.SailingMaxForceFactor.Value;
			float num = Mathf.Clamp01(ShieldReworkPlugin.SailingCalmWindCeiling.Value);
			windIntensity = Mathf.Clamp01(windIntensity);
			if (num <= 0f)
			{
				return Mathf.Lerp(value2, value3, windIntensity);
			}
			if (windIntensity <= num)
			{
				return Mathf.Lerp(value, value2, windIntensity / num);
			}
			if (num >= 1f)
			{
				return value2;
			}
			return Mathf.Lerp(value2, value3, (windIntensity - num) / (1f - num));
		}
	}
	[HarmonyPatch(typeof(Ship), "GetSailForce")]
	internal static class Ship_GetSailForce_Patch
	{
		private static bool Prefix(Ship __instance, float sailSize, ref Vector3 __result, ref Vector3 ___m_sailForce, ref Vector3 ___m_windChangeVelocity)
		{
			//IL_0013: 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_0041: 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_0058: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (!ShieldReworkPlugin.EnableSailingWindCurve.Value)
			{
				return true;
			}
			Vector3 windDir = EnvMan.instance.GetWindDir();
			float num = SailingWind.ForceFactor(EnvMan.instance.GetWindIntensity());
			float num2 = __instance.GetWindAngleFactor() * num;
			Vector3 val = Vector3.Normalize(windDir + ((Component)__instance).transform.forward) * (num2 * __instance.m_sailForceFactor * sailSize);
			___m_sailForce = Vector3.SmoothDamp(___m_sailForce, val, ref ___m_windChangeVelocity, 1f, 99f);
			__result = ___m_sailForce;
			return false;
		}
	}
	[BepInPlugin("Abortipus.CombatAdjustments.ShieldRework", "Combat Adjustments - Shield Rework", "0.8.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class ShieldReworkPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "Abortipus.CombatAdjustments.ShieldRework";

		public const string PluginName = "Combat Adjustments - Shield Rework";

		public const string PluginVersion = "0.8.3";

		public const float FlametalTowerGrant = 70f;

		public const float FlametalRoundGrant = 45f;

		public const float CarapaceBucklerGrant = 20f;

		public const float TowerArmorMult = 1.05f;

		public const float DurabilityMult = 1.2f;

		public const int CurrentGrantTableVersion = 3;

		internal static ManualLogSource Log;

		internal static ShieldReworkPlugin Instance;

		internal static ConfigFile ModConfig;

		internal static ConfigEntry<bool> EnableStaggerGrant;

		internal static ConfigEntry<bool> SyncConfigInMultiplayer;

		internal static ConfigEntry<bool> EnableTowerArmorBonus;

		internal static ConfigEntry<bool> EnableDurabilityBonus;

		internal static ConfigEntry<bool> EnableTwoHandedCombat;

		internal static ConfigEntry<float> GreatswordPrimaryStaggerMultiplier;

		internal static ConfigEntry<bool> AreaAdrenalinePerEnemy;

		internal static ConfigEntry<bool> EnableWeaponBlockPerLevel;

		internal static ConfigEntry<int> GrantTableVersion;

		internal static ConfigEntry<string> TooltipColorHex;

		internal static ConfigEntry<bool> EnableFeastStatBonuses;

		internal static ConfigEntry<float> FeastHealthBonus;

		internal static ConfigEntry<float> FeastStaminaBonus;

		internal static ConfigEntry<float> SailorsFeastHealthBonus;

		internal static ConfigEntry<float> SailorsFeastStaminaBonus;

		internal static ConfigEntry<float> MistlandsFeastEitrBonus;

		internal static ConfigEntry<float> AshlandsFeastEitrBonus;

		internal static ConfigEntry<float> DeepNorthFeastEitrBonus;

		internal static ConfigEntry<bool> DumpObjectDb;

		internal static ConfigEntry<bool> EnableSailingWindCurve;

		internal static ConfigEntry<float> SailingCalmForceFactor;

		internal static ConfigEntry<float> SailingKneeForceFactor;

		internal static ConfigEntry<float> SailingMaxForceFactor;

		internal static ConfigEntry<float> SailingCalmWindCeiling;

		internal static ConfigEntry<bool> EnableOceanStormChance;

		internal static ConfigEntry<float> OceanThunderStormChance;

		internal static ConfigEntry<bool> EnableUncapHealthScaling;

		internal static ConfigEntry<bool> EnableForgeOfPotentialOdds;

		internal static ConfigSync Sync;

		private Harmony? _harmony;

		private void Awake()
		{
			//IL_060e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0618: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig = ConfigPaths.CreateMergedConfig("Abortipus.CombatAdjustments.ShieldRework");
			Sync = ConfigSync.Create("Abortipus.CombatAdjustments.ShieldRework", "0.8.3", ((BaseUnityPlugin)this).Logger).Protecting(ModConfig).GatedBy((Func<bool>)(() => SyncConfigInMultiplayer == null || SyncConfigInMultiplayer.Value))
				.AcceptedWhen((Func<bool>)(() => SyncConfigInMultiplayer == null || SyncConfigInMultiplayer.Value))
				.OnApplied((Action)ApplyRuntimeFromConfig)
				.Notifying((Action<string>)NotifyPlayer);
			EnableStaggerGrant = ModConfig.Bind<bool>("General", "EnableStaggerGrant", true, "Add flat stagger-bar capacity while a shield is equipped.");
			SyncConfigInMultiplayer = ModConfig.Bind<bool>("General", "SyncConfigInMultiplayer", true, "When hosting or on a dedicated server, send this installation's config to joining clients. Clients use host values at runtime without overwriting their local .cfg.");
			EnableTowerArmorBonus = ModConfig.Bind<bool>("General", "EnableTowerArmorBonus", true, "Apply +5% block armor (rounded up) to tower shields.");
			EnableDurabilityBonus = ModConfig.Bind<bool>("General", "EnableDurabilityBonus", true, "Apply +20% durability (ceil to nearest 5) to tower and round shields.");
			EnableTwoHandedCombat = ModConfig.Bind<bool>("Two-Handed Combat", "Enable", true, "Enable stagger-only hyper armor and damage/stagger adjustments for two-handed melee weapons.");
			GreatswordPrimaryStaggerMultiplier = ModConfig.Bind<float>("Two-Handed Combat", "GreatswordPrimaryStaggerMultiplier", 1.5f, "Final stagger multiplier for primary greatsword swings. 1.5 = +50%.");
			AreaAdrenalinePerEnemy = ModConfig.Bind<bool>("Two-Handed Combat", "AreaAdrenalinePerEnemy", true, "Two-handed club ground slams (Stagbreaker, Iron Sledge, Demolisher) grant adrenaline per enemy hit, like swing attacks, instead of once per slam.");
			EnableWeaponBlockPerLevel = ModConfig.Bind<bool>("Two-Handed Combat", "EnableWeaponBlockPerLevel", true, "Scale block armor per weapon quality for two-handed and dual-wield blocking weapons (replaces vanilla m_blockPowerPerLevel).");
			GrantTableVersion = ModConfig.Bind<int>("General", "GrantTableVersion", 0, "Internal. Bump with plugin to re-seed StaggerGrants.* to designed max-quality values.");
			TooltipColorHex = ModConfig.Bind<string>("Tooltip", "StaggerColorHex", "#E85AC8", "Hex color for the stagger grant tooltip line (matches HUD stagger pink).");
			EnableFeastStatBonuses = ModConfig.Bind<bool>("Feasts", "EnableStatBonuses", true, "Add extra health / stamina / eitr to feast foods. Boss unlocks are not configurable and always apply.");
			FeastHealthBonus = ModConfig.Bind<float>("Feasts", "HealthBonus", 10f, "Extra max health added to every feast except Sailor's Bounty.");
			FeastStaminaBonus = ModConfig.Bind<float>("Feasts", "StaminaBonus", 10f, "Extra max stamina added to every feast except Sailor's Bounty.");
			SailorsFeastHealthBonus = ModConfig.Bind<float>("Feasts", "SailorsHealthBonus", 15f, "Extra max health added to Sailor's Bounty (instead of HealthBonus).");
			SailorsFeastStaminaBonus = ModConfig.Bind<float>("Feasts", "SailorsStaminaBonus", 15f, "Extra max stamina added to Sailor's Bounty (instead of StaminaBonus).");
			MistlandsFeastEitrBonus = ModConfig.Bind<float>("Feasts", "MistlandsEitrBonus", 7f, "Extra eitr added to Mushrooms Galore à la Mistlands (vanilla 33 → 40). Also receives HealthBonus / StaminaBonus.");
			AshlandsFeastEitrBonus = ModConfig.Bind<float>("Feasts", "AshlandsEitrBonus", 12f, "Extra eitr added to Ashlands Gourmet Bowl (vanilla 38 → 50). Also receives HealthBonus / StaminaBonus.");
			DeepNorthFeastEitrBonus = ModConfig.Bind<float>("Feasts", "DeepNorthEitrBonus", 17f, "Extra eitr added to the Deep North feast (vanilla 43 → 60). Also receives HealthBonus / StaminaBonus.");
			DumpObjectDb = ModConfig.Bind<bool>("Diagnostics", "DumpObjectDb", false, "Write every ObjectDB item prefab, its item type, shield and food stats, and the world's global keys to a text file next to this config, once, on the next world load. Also available from the console as 'cadump'. Local only — never synced from a host.");
			EnableSailingWindCurve = ModConfig.Bind<bool>("Sailing", "EnableWindCurve", true, "Replace vanilla linear wind→sail force with a two-segment curve (calm matches vanilla to 60%, storms ramp higher).");
			SailingCalmForceFactor = ModConfig.Bind<float>("Sailing", "CalmForceFactor", 0.287f, "Sail intensity factor at 0% wind. Vanilla uses ~0.287 at the 5% clamp floor.");
			SailingKneeForceFactor = ModConfig.Bind<float>("Sailing", "KneeForceFactor", 0.7f, "Sail intensity factor at CalmWindCeiling (default 60%). Matches vanilla Lerp(0.25,1,0.6).");
			SailingMaxForceFactor = ModConfig.Bind<float>("Sailing", "MaxForceFactor", 2f, "Sail intensity factor at 100% wind (vanilla tops out at 1).");
			SailingCalmWindCeiling = ModConfig.Bind<float>("Sailing", "CalmWindCeiling", 0.6f, "Wind intensity (0–1) where the calm segment ends and the storm ramp begins. Clear weather tops out here.");
			EnableOceanStormChance = ModConfig.Bind<bool>("Sailing", "EnableOceanStormChance", true, "Raise Ocean biome ThunderStorm weight so storms occur more often while sailing.");
			OceanThunderStormChance = ModConfig.Bind<float>("Sailing", "OceanThunderStormChance", 0.21f, "Target chance (0–1) of ThunderStorm on the Ocean biome. Vanilla is ~0.071 (7%). Default 0.21 = 21%.");
			EnableUncapHealthScaling = ModConfig.Bind<bool>("Difficulty", "EnableUncapHealthScaling", true, "Let effective enemy HP keep scaling with nearby players past vanilla's 5-player cap (+30% per extra player). Enemy damage dealt stays capped at 5.");
			EnableForgeOfPotentialOdds = ModConfig.Bind<bool>("Forge of Potential", "EnableIntendedOdds", true, "Restore code-default Forge of Potential odds: 65% success, 25% downgrade, 10% break. Vanilla idol prefabs set break chance to 1 so every failure destroys the item. Turn off when IronGate ships a real fix.");
			Sync.Register((ConfigEntryBase[])(object)new ConfigEntryBase[25]
			{
				(ConfigEntryBase)EnableStaggerGrant,
				(ConfigEntryBase)EnableTowerArmorBonus,
				(ConfigEntryBase)EnableDurabilityBonus,
				(ConfigEntryBase)EnableTwoHandedCombat,
				(ConfigEntryBase)GreatswordPrimaryStaggerMultiplier,
				(ConfigEntryBase)AreaAdrenalinePerEnemy,
				(ConfigEntryBase)EnableWeaponBlockPerLevel,
				(ConfigEntryBase)TooltipColorHex,
				(ConfigEntryBase)EnableFeastStatBonuses,
				(ConfigEntryBase)FeastHealthBonus,
				(ConfigEntryBase)FeastStaminaBonus,
				(ConfigEntryBase)SailorsFeastHealthBonus,
				(ConfigEntryBase)SailorsFeastStaminaBonus,
				(ConfigEntryBase)MistlandsFeastEitrBonus,
				(ConfigEntryBase)AshlandsFeastEitrBonus,
				(ConfigEntryBase)DeepNorthFeastEitrBonus,
				(ConfigEntryBase)EnableSailingWindCurve,
				(ConfigEntryBase)SailingCalmForceFactor,
				(ConfigEntryBase)SailingKneeForceFactor,
				(ConfigEntryBase)SailingMaxForceFactor,
				(ConfigEntryBase)SailingCalmWindCeiling,
				(ConfigEntryBase)EnableOceanStormChance,
				(ConfigEntryBase)OceanThunderStormChance,
				(ConfigEntryBase)EnableUncapHealthScaling,
				(ConfigEntryBase)EnableForgeOfPotentialOdds
			});
			Sync.Exclude((ConfigEntryBase)(object)GrantTableVersion).Exclude((ConfigEntryBase)(object)SyncConfigInMultiplayer).Exclude((ConfigEntryBase)(object)DumpObjectDb);
			HookFeastConfigChange<bool>(EnableFeastStatBonuses);
			HookFeastConfigChange<float>(FeastHealthBonus);
			HookFeastConfigChange<float>(FeastStaminaBonus);
			HookFeastConfigChange<float>(SailorsFeastHealthBonus);
			HookFeastConfigChange<float>(SailorsFeastStaminaBonus);
			HookFeastConfigChange<float>(MistlandsFeastEitrBonus);
			HookFeastConfigChange<float>(AshlandsFeastEitrBonus);
			HookFeastConfigChange<float>(DeepNorthFeastEitrBonus);
			HookOceanWeatherConfigChange<bool>(EnableOceanStormChance);
			HookOceanWeatherConfigChange<float>(OceanThunderStormChance);
			HookForgeOddsConfigChange<bool>(EnableForgeOfPotentialOdds);
			ApplyOverlayToStaticEntries();
			Sync.WatchForChanges(ModConfig).Start();
			OceanWeather.Apply();
			ConsoleCommands.Register();
			_harmony = new Harmony("Abortipus.CombatAdjustments.ShieldRework");
			int num = PatchIsolation.PatchAllIsolated(_harmony, Assembly.GetExecutingAssembly(), Log);
			Log.LogInfo((object)("Combat Adjustments - Shield Rework 0.8.3 loaded." + ((num > 0) ? $" {num} patch class(es) skipped - see the errors above." : string.Empty)));
		}

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

		internal static Color GetTooltipColor()
		{
			//IL_0024: 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)
			Color result = default(Color);
			if (ColorUtility.TryParseHtmlString(TooltipColorHex.Value, ref result))
			{
				return result;
			}
			return new Color(0.91f, 0.35f, 0.78f);
		}

		internal static string ColorToHex(Color color)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return "#" + ColorUtility.ToHtmlStringRGB(color);
		}

		private static void ApplyRuntimeFromConfig()
		{
			OceanWeather.Apply();
			if (!((Object)(object)ObjectDB.instance == (Object)null))
			{
				ShieldStats.ApplyToObjectDB(ObjectDB.instance);
				WeaponBlockStats.ApplyToObjectDB(ObjectDB.instance);
				FeastStats.ApplyToObjectDB(ObjectDB.instance);
				ForgeOfPotential.ApplyToObjectDB(ObjectDB.instance);
			}
		}

		private static void NotifyPlayer(string message)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				((Character)localPlayer).Message((MessageType)1, message, 0, (Sprite)null, false);
			}
		}

		private static void HookFeastConfigChange<T>(ConfigEntry<T> entry)
		{
			entry.SettingChanged += delegate
			{
				if ((Object)(object)ObjectDB.instance != (Object)null)
				{
					FeastStats.ApplyToObjectDB(ObjectDB.instance);
				}
			};
		}

		private static void HookForgeOddsConfigChange<T>(ConfigEntry<T> entry)
		{
			entry.SettingChanged += delegate
			{
				if ((Object)(object)ObjectDB.instance != (Object)null)
				{
					ForgeOfPotential.ApplyToObjectDB(ObjectDB.instance);
				}
			};
		}

		private static void HookOceanWeatherConfigChange<T>(ConfigEntry<T> entry)
		{
			entry.SettingChanged += delegate
			{
				OceanWeather.Apply();
			};
		}

		private static void ApplyOverlayToStaticEntries()
		{
			ConfigPaths.ApplyOverlayToStaticEntries(ModConfig);
		}
	}
	internal static class ShieldStats
	{
		internal static readonly Dictionary<string, ConfigEntry<float>> GrantConfigs = new Dictionary<string, ConfigEntry<float>>(StringComparer.OrdinalIgnoreCase);

		internal static readonly Dictionary<string, float> RuntimeGrants = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

		internal static readonly Dictionary<string, float> SharedNameToGrant = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, (float power, float perLevel)> OriginalArmor = new Dictionary<string, (float, float)>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, (float max, float perLevel)> OriginalDurability = new Dictionary<string, (float, float)>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, float> TowerLeftoverSeeds = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase)
		{
			["ShieldWoodTower"] = 5f,
			["ShieldBoneTower"] = 15f,
			["ShieldIronTower"] = 25f,
			["ShieldSerpentscale"] = 50f,
			["ShieldBlackmetalTower"] = 55f,
			["ShieldFlametalTower"] = 70f,
			["ShieldGoldTower"] = 80f
		};

		private static readonly HashSet<string> GrantStep3 = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "ShieldFlametal", "ShieldFlametalTower", "ShieldGold", "ShieldGoldTower", "ShieldGoldBuckler" };

		private static readonly HashSet<string> GrantStep2 = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "ShieldSerpentscale", "ShieldBlackmetalTower", "ShieldSilver", "ShieldBlackmetal", "ShieldCarapace", "ShieldKnight" };

		internal static IEnumerable<string> TrackedTowerSeedPrefabs => TowerLeftoverSeeds.Keys;

		internal static IEnumerable<string> TrackedGrantStepPrefabs
		{
			get
			{
				foreach (string item in GrantStep3)
				{
					yield return item;
				}
				foreach (string item2 in GrantStep2)
				{
					yield return item2;
				}
			}
		}

		internal static ShieldKind Classify(SharedData shared)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)shared.m_itemType != 5)
			{
				return ShieldKind.Unknown;
			}
			float timedBlockBonus = shared.m_timedBlockBonus;
			if (timedBlockBonus >= 2.4f)
			{
				return ShieldKind.Buckler;
			}
			if (timedBlockBonus > 1.01f)
			{
				return ShieldKind.Round;
			}
			return ShieldKind.Tower;
		}

		internal static string PrefabName(GameObject go)
		{
			string name = ((Object)go).name;
			int num = name.IndexOf("(Clone)", StringComparison.Ordinal);
			if (num < 0)
			{
				return name;
			}
			return name.Substring(0, num).TrimEnd(Array.Empty<char>());
		}

		internal static float MaxBaseBlockPower(SharedData shared)
		{
			int num = Mathf.Max(1, shared.m_maxQuality);
			return shared.m_blockPower + (float)Mathf.Max(0, num - 1) * shared.m_blockPowerPerLevel;
		}

		internal static float SeedMaxGrant(ShieldKind kind, float maxBlockArmor, string? prefab = null)
		{
			if (kind == ShieldKind.Tower && prefab != null && TowerLeftoverSeeds.TryGetValue(prefab, out var value))
			{
				return value;
			}
			float num = kind switch
			{
				ShieldKind.Tower => maxBlockArmor * (35f / 76f), 
				ShieldKind.Round => maxBlockArmor * (5f / 14f), 
				ShieldKind.Buckler => maxBlockArmor * (2f / 9f), 
				_ => 0f, 
			};
			if (kind == ShieldKind.Round || kind == ShieldKind.Buckler || kind == ShieldKind.Tower)
			{
				return RoundToNearest5(num);
			}
			return Mathf.Round(num);
		}

		internal static float RoundToNearest5(float value)
		{
			return Mathf.Round(value / 5f) * 5f;
		}

		internal static float RoundDurability(float value)
		{
			return Mathf.Ceil(value * 1.2f / 5f) * 5f;
		}

		internal static float RoundArmorUp(float value)
		{
			return Mathf.Ceil(value * 1.05f);
		}

		internal static void EnsureGrantConfig(string prefab, float seed)
		{
			if (!GrantConfigs.ContainsKey(prefab))
			{
				float num = prefab switch
				{
					"ShieldFlametalTower" => 70f, 
					"ShieldFlametal" => 45f, 
					"ShieldCarapaceBuckler" => 20f, 
					_ => seed, 
				};
				if (ConfigPaths.TryGetOverlayDefault("StaggerGrants", prefab, out string serialized) && float.TryParse(serialized, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var result))
				{
					num = result;
				}
				GrantConfigs[prefab] = ShieldReworkPlugin.ModConfig.Bind<float>("StaggerGrants", prefab, num, "Max-quality flat stagger grant for " + prefab + ". 0 disables.");
				ShieldReworkPlugin.Sync.Register((ConfigEntryBase)(object)GrantConfigs[prefab]);
			}
		}

		internal static float GetMaxGrant(string prefab)
		{
			if (GrantConfigs.TryGetValue(prefab, out ConfigEntry<float> value))
			{
				return value.Value;
			}
			if (!RuntimeGrants.TryGetValue(prefab, out var value2))
			{
				return 0f;
			}
			return value2;
		}

		internal static float GrantForItem(ItemData? item)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			if (!ShieldReworkPlugin.EnableStaggerGrant.Value || item?.m_shared == null)
			{
				return 0f;
			}
			if ((int)item.m_shared.m_itemType != 5)
			{
				return 0f;
			}
			string prefab = null;
			float value = 0f;
			if ((Object)(object)item.m_dropPrefab != (Object)null)
			{
				prefab = PrefabName(item.m_dropPrefab);
				value = GetMaxGrant(prefab);
			}
			if (value <= 0f && !SharedNameToGrant.TryGetValue(item.m_shared.m_name, out value))
			{
				return 0f;
			}
			if (value <= 0f)
			{
				return 0f;
			}
			float perStep = GrantPerQualityStep(prefab, Classify(item.m_shared));
			return GrantAtQuality(value, item.m_quality, item.m_shared.m_maxQuality, perStep);
		}

		internal static float GrantPerQualityStep(string? prefab, ShieldKind kind = ShieldKind.Unknown)
		{
			if (kind == ShieldKind.Buckler)
			{
				return 1f;
			}
			if (string.IsNullOrEmpty(prefab))
			{
				return 1f;
			}
			if (GrantStep3.Contains(prefab))
			{
				return 3f;
			}
			if (GrantStep2.Contains(prefab))
			{
				return 2f;
			}
			return 1f;
		}

		internal static float GrantAtQuality(float maxGrant, int quality, int maxQuality, float perStep)
		{
			if (maxGrant <= 0f)
			{
				return 0f;
			}
			int num = Mathf.Max(1, maxQuality);
			int num2 = Mathf.Clamp(quality, 1, num);
			if (num == 1 || num2 >= num)
			{
				return maxGrant;
			}
			float num3 = Mathf.Max(0f, perStep);
			float num4 = maxGrant / (float)(num - 1);
			if (num3 > num4)
			{
				num3 = num4;
			}
			return Mathf.Round(maxGrant - (float)(num - 1) * num3 + (float)(num2 - 1) * num3);
		}

		internal static float GrantForEquippedShield(Humanoid humanoid)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			ItemData leftItem = humanoid.LeftItem;
			if (leftItem == null || (int)leftItem.m_shared.m_itemType != 5)
			{
				return 0f;
			}
			return GrantForItem(leftItem);
		}

		internal static void ApplyToObjectDB(ObjectDB db)
		{
			if (db?.m_items == null || db.m_items.Count == 0)
			{
				return;
			}
			bool flag = ConfigSync.IsServerAuthority() && ShieldReworkPlugin.GrantTableVersion.Value < 3;
			if (flag)
			{
				ShieldReworkPlugin.Log.LogInfo((object)$"Re-seeding StaggerGrants to designed max-quality table (cfg v{ShieldReworkPlugin.GrantTableVersion.Value} → v{3}).");
			}
			int num = 0;
			foreach (GameObject item in db.m_items)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				ItemDrop component = item.GetComponent<ItemDrop>();
				if (component?.m_itemData?.m_shared == null)
				{
					continue;
				}
				SharedData shared = component.m_itemData.m_shared;
				ShieldKind shieldKind = Classify(shared);
				if (shieldKind != ShieldKind.Unknown)
				{
					string text = PrefabName(item);
					float maxBlockArmor = MaxBaseBlockPower(shared);
					float num2 = SeedMaxGrant(shieldKind, maxBlockArmor, text);
					EnsureGrantConfig(text, num2);
					if (flag && GrantConfigs.TryGetValue(text, out ConfigEntry<float> value))
					{
						value.Value = num2;
					}
					float maxGrant = GetMaxGrant(text);
					RuntimeGrants[text] = maxGrant;
					SharedNameToGrant[shared.m_name] = maxGrant;
					num++;
					if (shieldKind == ShieldKind.Tower && !OriginalArmor.ContainsKey(text))
					{
						OriginalArmor[text] = (shared.m_blockPower, shared.m_blockPowerPerLevel);
					}
					if ((shieldKind == ShieldKind.Tower || shieldKind == ShieldKind.Round) && !OriginalDurability.ContainsKey(text))
					{
						OriginalDurability[text] = (shared.m_maxDurability, shared.m_durabilityPerLevel);
					}
					(float, float) value2;
					if (ShieldReworkPlugin.EnableTowerArmorBonus.Value && shieldKind == ShieldKind.Tower)
					{
						(float, float) tuple = OriginalArmor[text];
						shared.m_blockPower = RoundArmorUp(tuple.Item1);
						shared.m_blockPowerPerLevel = RoundArmorUp(tuple.Item2);
					}
					else if (OriginalArmor.TryGetValue(text, out value2))
					{
						(shared.m_blockPower, shared.m_blockPowerPerLevel) = value2;
					}
					(float, float) value3;
					if (ShieldReworkPlugin.EnableDurabilityBonus.Value && (shieldKind == ShieldKind.Tower || shieldKind == ShieldKind.Round))
					{
						(float, float) tuple3 = OriginalDurability[text];
						shared.m_maxDurability = RoundDurability(tuple3.Item1);
						shared.m_durabilityPerLevel = RoundDurability(tuple3.Item2);
					}
					else if (OriginalDurability.TryGetValue(text, out value3))
					{
						(shared.m_maxDurability, shared.m_durabilityPerLevel) = value3;
					}
				}
			}
			if (flag)
			{
				ShieldReworkPlugin.GrantTableVersion.Value = 3;
			}
			ConfigPaths.ApplyOverlayAfterObjectDbLoad(ShieldReworkPlugin.ModConfig);
			ShieldReworkPlugin.Log.LogInfo((object)$"Processed {num} shields from ObjectDB.");
		}
	}
	internal enum ShieldKind
	{
		Unknown,
		Tower,
		Round,
		Buckler
	}
	internal static class StaggerDebugHud
	{
		private const string RootName = "CombatAdjustments_StaggerDebug";

		private static bool _visible;

		private static TextMeshProUGUI? _label;

		internal static bool Visible => _visible;

		internal static void Toggle(ConsoleEventArgs? args = null)
		{
			SetVisible(!_visible, args);
		}

		internal static void SetVisible(bool visible, ConsoleEventArgs? args = null)
		{
			if (visible && !CanUseHudOverlay(out string message))
			{
				_visible = false;
				if (args != null)
				{
					Terminal context = args.Context;
					if (context != null)
					{
						context.AddString(message);
					}
				}
				return;
			}
			_visible = visible;
			if (_visible)
			{
				if (!EnsureLabel())
				{
					_visible = false;
					if (args != null)
					{
						Terminal context2 = args.Context;
						if (context2 != null)
						{
							context2.AddString("<color=yellow>Stagger HUD unavailable here.</color> Use <color=orange>shieldstagger</color> / <color=orange>sstagger</color> on dedicated server.");
						}
					}
					return;
				}
			}
			else if ((Object)(object)_label != (Object)null)
			{
				((Component)_label).gameObject.SetActive(false);
			}
			if (args != null)
			{
				Terminal context3 = args.Context;
				if (context3 != null)
				{
					context3.AddString(_visible ? "Stagger HUD: <color=orange>on</color> (current / total under stagger bar)" : "Stagger HUD: off");
				}
			}
		}

		private static bool CanUseHudOverlay(out string message)
		{
			if (IsHeadlessServerContext())
			{
				message = "<color=yellow>Stagger HUD is client-only.</color> Dedicated server has no player HUD — use <color=orange>shieldstagger</color> / <color=orange>sstagger</color>.";
				return false;
			}
			if ((Object)(object)Hud.instance == (Object)null)
			{
				message = "<color=yellow>Stagger HUD requires the in-game HUD (not available from console-only session).</color>";
				return false;
			}
			message = string.Empty;
			return true;
		}

		private static bool IsHeadlessServerContext()
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return false;
			}
			return (Object)(object)Player.m_localPlayer == (Object)null;
		}

		internal static void Refresh(Hud hud, Player player)
		{
			if (_visible && !((Object)(object)hud == (Object)null) && !((Object)(object)player == (Object)null) && EnsureLabel(hud))
			{
				((Component)_label).gameObject.SetActive(true);
				Animator value = Traverse.Create((object)hud).Field("m_staggerAnimator").GetValue<Animator>();
				if (value != null)
				{
					value.SetBool("Visible", true);
				}
				float value2 = Traverse.Create((object)player).Method("GetStaggerTreshold", Array.Empty<object>()).GetValue<float>();
				float value3 = Traverse.Create((object)player).Field("m_staggerDamage").GetValue<float>();
				float num = ShieldStats.GrantForEquippedShield((Humanoid)(object)player);
				if (num > 0f)
				{
					((TMP_Text)_label).text = $"{value3:0.#} / {value2:0.#}  (+{num:0})";
				}
				else
				{
					((TMP_Text)_label).text = $"{value3:0.#} / {value2:0.#}";
				}
			}
		}

		private static bool EnsureLabel(Hud? hud = null)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: 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_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: 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_0212: Unknown result type (might be due to invalid IL or missing references)
			if (hud == null)
			{
				hud = Hud.instance;
			}
			if ((Object)(object)hud == (Object)null)
			{
				return false;
			}
			if ((Object)(object)_label != (Object)null)
			{
				if (Object.op_Implicit((Object)(object)_label))
				{
					return true;
				}
				_label = null;
			}
			GuiBar value = Traverse.Create((object)hud).Field("m_staggerProgress").GetValue<GuiBar>();
			if ((Object)(object)value == (Object)null)
			{
				return false;
			}
			Transform transform = ((Component)value).transform;
			Transform val = transform.Find("CombatAdjustments_StaggerDebug");
			GameObject val2;
			if ((Object)(object)val != (Object)null)
			{
				val2 = ((Component)val).gameObject;
				_label = val2.GetComponent<TextMeshProUGUI>();
				if ((Object)(object)_label == (Object)null)
				{
					_label = val2.AddComponent<TextMeshProUGUI>();
				}
			}
			else
			{
				val2 = new GameObject("CombatAdjustments_StaggerDebug", new Type[1] { typeof(RectTransform) });
				val2.transform.SetParent(transform, false);
				_label = val2.AddComponent<TextMeshProUGUI>();
			}
			RectTransform val3 = (RectTransform)val2.transform;
			val3.anchorMin = new Vector2(0.5f, 0f);
			val3.anchorMax = new Vector2(0.5f, 0f);
			val3.pivot = new Vector2(0.5f, 1f);
			val3.sizeDelta = new Vector2(280f, 28f);
			val3.anchoredPosition = new Vector2(0f, -6f);
			TMP_Text val4 = Traverse.Create((object)hud).Field("m_staminaText").GetValue<TMP_Text>() ?? Traverse.Create((object)hud).Field("m_healthText").GetValue<TMP_Text>();
			if ((Object)(object)val4 != (Object)null)
			{
				((TMP_Text)_label).font = val4.font;
				((TMP_Text)_label).fontSharedMaterial = val4.fontSharedMaterial;
				((TMP_Text)_label).fontSize = Mathf.Max(14f, val4.fontSize * 0.85f);
			}
			else
			{
				if ((Object)(object)((TMP_Text)_label).font == (Object)null)
				{
					return false;
				}
				((TMP_Text)_label).fontSize = 16f;
			}
			((TMP_Text)_label).alignment = (TextAlignmentOptions)514;
			((Graphic)_label).color = new Color(1f, 0.65f, 0.2f, 1f);
			((TMP_Text)_label).textWrappingMode = (TextWrappingModes)0;
			((Graphic)_label).raycastTarget = false;
			ApplyOutline(_label);
			return true;
		}

		private static void ApplyOutline(TextMeshProUGUI label)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((TMP_Text)label).font == (Object)null)
			{
				return;
			}
			try
			{
				((TMP_Text)label).outlineWidth = 0.2f;
				((TMP_Text)label).outlineColor = new Color32((byte)0, (byte)0, (byte)0, (byte)200);
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(Hud), "UpdateStagger")]
	internal static class Hud_UpdateStagger_Patch
	{
		private static void Postfix(Hud __instance, Player player)
		{
			StaggerDebugHud.Refresh(__instance, player);
		}
	}
	internal static class TwoHandedCombat
	{
		internal const float TwoHandedDamageBonusFraction = 0.1f;

		internal static bool TooltipDamagePreview;

		private static readonly Dictionary<Player, Attack> ActiveHyperArmor = new Dictionary<Player, Attack>();

		private static bool Enabled => ShieldReworkPlugin.EnableTwoHandedCombat.Value;

		internal static bool IsTwoHandedMelee(ItemData? weapon)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Invalid comparison between Unknown and I4
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Invalid comparison between Unknown and I4
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Invalid comparison between Unknown and I4
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Invalid comparison between Unknown and I4
			if (weapon?.m_shared == null)
			{
				return false;
			}
			if ((int)weapon.m_shared.m_itemType != 14)
			{
				return false;
			}
			SkillType skillType = weapon.m_shared.m_skillType;
			if ((int)skillType != 1 && (int)skillType != 7 && (int)skillType != 3)
			{
				return (int)skillType == 4;
			}
			return true;
		}

		internal static bool HasBalancedHyperArmor(ItemData? weapon)
		{
			return HasTwoHandedDamageBonus(weapon);
		}

		internal static bool HasTwoHandedDamageBonus(ItemData? weapon)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Invalid comparison between Unknown and I4
			//IL_002e: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Invalid comparison between Unknown and I4
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Invalid comparison between Unknown and I4
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Invalid comparison between Unknown and I4
			if (!Enabled || weapon?.m_shared == null)
			{
				return false;
			}
			if ((int)weapon.m_shared.m_itemType != 14)
			{
				return false;
			}
			AnimationState animationState = weapon.m_shared.m_animationState;
			if ((int)animationState == 2 || (int)animationState == 8 || (int)animationState == 13)
			{
				return true;
			}
			return false;
		}

		internal static void ApplyRoundedTenPercentDamageBonus(ref DamageTypes damages)
		{
			damages.m_damage = AddRoundedPercentBonus(damages.m_damage);
			damages.m_blunt = AddRoundedPercentBonus(damages.m_blunt);
			damages.m_slash = AddRoundedPercentBonus(damages.m_slash);
			damages.m_pierce = AddRoundedPercentBonus(damages.m_pierce);
			damages.m_chop = AddRoundedPercentBonus(damages.m_chop);
			damages.m_pickaxe = AddRoundedPercentBonus(damages.m_pickaxe);
			damages.m_fire = AddRoundedPercentBonus(damages.m_fire);
			damages.m_frost = AddRoundedPercentBonus(damages.m_frost);
			damages.m_lightning = AddRoundedPercentBonus(damages.m_lightning);
			damages.m_poison = AddRoundedPercentBonus(damages.m_poison);
			damages.m_spirit = AddRoundedPercentBonus(damages.m_spirit);
			damages.m_nonPlayer = AddRoundedPercentBonus(damages.m_nonPlayer);
		}

		private static float AddRoundedPercentBonus(float value)
		{
			if (!(value <= 0f))
			{
				return value + Mathf.Floor(value * 0.1f);
			}
			return value;
		}

		internal static bool IsTwoHandedClub(ItemData? weapon)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			if (IsTwoHandedMelee(weapon))
			{
				return (int)weapon.m_shared.m_skillType == 3;
			}
			return false;
		}

		internal static bool IsGreatswordPrimary(Attack attack, ItemData? weapon)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			if (weapon?.m_shared != null && (int)weapon.m_shared.m_itemType == 14 && (int)weapon.m_shared.m_skillType == 1)
			{
				return attack.m_attackChainLevels > 1;
			}
			return false;
		}

		internal static void BeginBalancedHyperArmor(Attack attack)
		{
			if (Enabled)
			{
				ItemData weapon = attack.GetWeapon();
				Humanoid? obj = AttackOwner(attack);
				Player val = (Player)(object)((obj is Player) ? obj : null);
				if (val != null && ((Character)val).InAttack() && HasBalancedHyperArmor(weapon))
				{
					ActiveHyperArmor[val] = attack;
				}
			}
		}

		internal static void EndBalancedHyperArmor(Attack attack)
		{
			Humanoid? obj = AttackOwner(attack);
			Player val = (Player)(object)((obj is Player) ? obj : null);
			if (val != null && ActiveHyperArmor.TryGetValue(val, out Attack value) && value == attack)
			{
				ActiveHyperArmor.Remove(val);
			}
		}

		internal static bool HasActiveHyperArmor(Player player)
		{
			if (Enabled && ActiveHyperArmor.TryGetValue(player, out Attack value) && ((Character)player).InAttack())
			{
				return value.GetWeapon() == ((Humanoid)player).GetCurrentWeapon();
			}
			return false;
		}

		private static Humanoid? AttackOwner(Attack attack)
		{
			return Traverse.Create((object)attack).Field("m_character").GetValue<Humanoid>();
		}
	}
	internal static class AreaAdrenaline
	{
		private static Player? s_attacker;

		private static float s_multiplierSum;

		private static float s_multiplierMax;

		private static readonly HashSet<Character> s_counted = new HashSet<Character>();

		internal static bool Open(Attack attack, Humanoid? owner)
		{
			if (!ShieldReworkPlugin.EnableTwoHandedCombat.Value || !ShieldReworkPlugin.AreaAdrenalinePerEnemy.Value)
			{
				return false;
			}
			Player val = (Player)(object)((owner is Player) ? owner : null);
			if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			if (!TwoHandedCombat.IsTwoHandedClub(attack.GetWeapon()))
			{
				return false;
			}
			s_attacker = val;
			s_multiplierSum = 0f;
			s_multiplierMax = 0f;
			s_counted.Clear();
			return true;
		}

		internal static void RecordDamage(Character victim)
		{
			if (!((Object)(object)s_attacker == (Object)null) && !((Object)(object)victim == (Object)(object)s_attacker) && s_counted.Add(victim) && (BaseAI.IsEnemy((Character)(object)s_attacker, victim) || ((Object)(object)victim.GetBaseAI() != (Object)null && victim.GetBaseAI().IsAggravatable())))
			{
				s_multiplierSum += victim.m_enemyAdrenalineMultiplier;
				if (victim.m_enemyAdrenalineMultiplier > s_multiplierMax)
				{
					s_multiplierMax = victim.m_enemyAdrenalineMultiplier;
				}
			}
		}

		internal static void CloseAndAward(Attack attack)
		{
			Player val = s_attacker;
			s_attacker = null;
			s_counted.Clear();
			if (!((Object)(object)val == (Object)null))
			{
				float num = attack.m_attackAdrenaline * (s_multiplierSum - s_multiplierMax);
				if (num > 0f)
				{
					((Character)val).AddAdrenaline(num);
				}
			}
		}

		internal static void Abort()
		{
			s_attacker = null;
		}
	}
	[HarmonyPatch(typeof(Attack), "DoAreaAttack")]
	internal static class Attack_DoAreaAttack_Adrenaline_Patch
	{
		private static void Prefix(Attack __instance, Humanoid ___m_character)
		{
			AreaAdrenaline.Open(__instance, ___m_character);
		}

		private static void Postfix(Attack __instance)
		{
			AreaAdrenaline.CloseAndAward(__instance);
		}

		private static Exception? Finalizer(Exception __exception)
		{
			if (__exception != null)
			{
				AreaAdrenaline.Abort();
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Character), "Damage")]
	internal static class Character_Damage_AreaAdrenaline_Patch
	{
		private static void Prefix(Character __instance)
		{
			AreaAdrenaline.RecordDamage(__instance);
		}
	}
	[HarmonyPatch(typeof(Attack), "Update")]
	internal static class Attack_Update_HyperArmor_Patch
	{
		private static void Postfix(Attack __instance)
		{
			TwoHandedCombat.BeginBalancedHyperArmor(__instance);
		}
	}
	[HarmonyPatch(typeof(Attack), "OnAttackTrigger")]
	internal static class Attack_OnAttackTrigger_HyperArmor_Patch
	{
		private static void Postfix(Attack __instance)
		{
			TwoHandedCombat.EndBalancedHyperArmor(__instance);
		}
	}
	[HarmonyPatch(typeof(Attack), "Stop")]
	internal static class Attack_Stop_HyperArmor_Patch
	{
		private static void Postfix(Attack __instance)
		{
			TwoHandedCombat.EndBalancedHyperArmor(__instance);
		}
	}
	[HarmonyPatch(typeof(Character), "AddStaggerDamage")]
	internal static class Character_AddStaggerDamage_HyperArmor_Patch
	{
		private static bool Prefix(Character __instance, ref bool __result)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null && TwoHandedCombat.HasActiveHyperArmor(val))
			{
				__result = false;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Character), "Stagger")]
	internal static class Character_Stagger_HyperArmor_Patch
	{
		private static bool Prefix(Character __instance)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null)
			{
				return !TwoHandedCombat.HasActiveHyperArmor(val);
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Attack), "ModifyDamage")]
	internal static class Attack_ModifyDamage_TwoHanded_Patch
	{
		private static void Postfix(Attack __instance, HitData hitData)
		{
			if (!ShieldReworkPlugin.EnableTwoHandedCombat.Value)
			{
				return;
			}
			ItemData weapon = __instance.GetWeapon();
			if (TwoHandedCombat.HasTwoHandedDamageBonus(weapon))
			{
				TwoHandedCombat.ApplyRoundedTenPercentDamageBonus(ref hitData.m_damage);
				if (TwoHandedCombat.IsGreatswordPrimary(__instance, weapon))
				{
					hitData.m_staggerMultiplier *= ShieldReworkPlugin.GreatswordPrimaryStaggerMultiplier.Value;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetDamage", new Type[]
	{
		typeof(int),
		typeof(float)
	})]
	internal static class ItemData_GetDamage_TwoHandedTooltip_Patch
	{
		private static void Postfix(ItemData __instance, ref DamageTypes __result)
		{
			if (TwoHandedCombat.TooltipDamagePreview && ShieldReworkPlugin.EnableTwoHandedCombat.Value && TwoHandedCombat.HasTwoHandedDamageBonus(__instance))
			{
				TwoHandedCombat.ApplyRoundedTenPercentDamageBonus(ref __result);
			}
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
	{
		typeof(ItemData),
		typeof(int),
		typeof(bool),
		typeof(float),
		typeof(int),
		typeof(bool)
	})]
	internal static class ItemData_GetTooltip_TwoHanded_Patch
	{
		private static void Prefix()
		{
			TwoHandedCombat.TooltipDamagePreview = true;
		}

		private static void Postfix(ItemData item, ref string __result)
		{
			TwoHandedCombat.TooltipDamagePreview = false;
			if (!TwoHandedCombat.HasBalancedHyperArmor(item) || __result.IndexOf("Hyper-armor", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return;
			}
			int num = __result.IndexOf("$item_knockback:", StringComparison.Ordinal);
			if (num >= 0)
			{
				int num2 = __result.IndexOf('\n', num);
				if (num2 < 0)
				{
					__result += "\n<color=orange>Hyper-armor</color>";
				}
				else
				{
					__result = __result.Insert(num2, "\n<color=orange>Hyper-armor</color>");
				}
			}
			else
			{
				__result += "\n<color=orange>Hyper-armor</color>";
			}
		}
	}
	internal static class WeaponBlockStats
	{
		private static readonly Dictionary<string, float> BlockPerLevelByPrefab = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase)
		{
			["THSwordWood"] = 1f,
			["BattleaxeWood"] = 1f,
			["SledgeWood"] = 1f,
			["AtgeirWood"] = 1f,
			["SledgeStagbreaker"] = 1f,
			["AtgeirBronze"] = 1f,
			["AxeEarly"] = 1f,
			["FistBjornClaw"] = 1f,
			["Battleaxe"] = 2f,
			["SledgeIron"] = 2f,
			["AtgeirIron"] = 2f,
			["BattleaxeCrystal"] = 3f,
			["BattleaxeBlackmetal"] = 4f,
			["AtgeirBlackmetal"] = 4f,
			["AxeBerzerkr"] = 4f,
			["AxeBerzerkrBlood"] = 4f,
			["AxeBerzerkrLightning"] = 4f,
			["AxeBerzerkrNature"] = 4f,
			["FistBjornUndeadClaw"] = 4f,
			["AtgeirHimminAfl"] = 5f,
			["KnifeSkollAndHati"] = 5f,
			["FistFenrirClaw"] = 5f,
			["THSwordKrom"] = 6f,
			["THSwordSlayer"] = 6f,
			["THSwordSlayerBlood"] = 6f,
			["THSwordSlayerLightning"] = 6f,
			["THSwordSlayerNature"] = 6f,
			["BattleaxeSkullSplittur"] = 6f,
			["SledgeDemolisher"] = 6f,
			["THSwordGold"] = 7f,
			["THSwordGold_FrostFire"] = 7f,
			["THSwordGold_BloodLightning"] = 7f,
			["BattleaxeGold"] = 7f,
			["BattleaxeGold_FrostFire"] = 7f,
			["BattleaxeGold_BloodLightning"] = 7f,
			["SledgeGold"] = 7f,
			["SledgeGold_FrostFire"] = 7f,
			["SledgeGold_BloodLightning"] = 7f,
			["AtgeirGold"] = 7f,
			["AtgeirGold_FrostFire"] = 7f,
			["AtgeirGold_BloodLightning"] = 7f,
			["FistGold"] = 7f,
			["FistGold_FrostFire"] = 7f,
			["FistGold_BloodLightning"] = 7f,
			["AxeJotunBane"] = 7f
		};

		private static readonly Dictionary<string, float> OriginalPerLevel = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

		internal static IEnumerable<string> TrackedPrefabs => BlockPerLevelByPrefab.Keys;

		internal static void ApplyToObjectDB(ObjectDB db)
		{
			if (db?.m_items == null)
			{
				return;
			}
			int num = 0;
			foreach (GameObject item in db.m_items)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				ItemDrop component = item.GetComponent<ItemDrop>();
				if (component?.m_itemData?.m_shared == null)
				{
					continue;
				}
				string key = ShieldStats.PrefabName(item);
				if (BlockPerLevelByPrefab.TryGetValue(key, out var value))
				{
					SharedData shared = component.m_itemData.m_shared;
					if (!OriginalPerLevel.ContainsKey(key))
					{
						OriginalPerLevel[key] = shared.m_blockPowerPerLevel;
					}
					shared.m_blockPowerPerLevel = (ShieldReworkPlugin.EnableWeaponBlockPerLevel.Value ? value : OriginalPerLevel[key]);
					num++;
				}
			}
			if (num > 0)
			{
				ShieldReworkPlugin.Log.LogInfo((object)$"Weapon block per-level: applied table to {num} prefabs (enabled={ShieldReworkPlugin.EnableWeaponBlockPerLevel.Value}).");
			}
		}
	}
}