Decompiled source of HaldorExpansion v1.2.2

HaldorExpansion.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HaldorExpansion.Combat;
using HaldorExpansion.Compatibility;
using HaldorExpansion.Configuration;
using HaldorExpansion.Diagnostics;
using HaldorExpansion.Features.Brisingamen;
using HaldorExpansion.Features.Cestus;
using HaldorExpansion.Features.DelayedDoom;
using HaldorExpansion.Features.HelOath;
using HaldorExpansion.Features.NornThread;
using HaldorExpansion.Features.PeltOfHelheim;
using HaldorExpansion.Features.PitKing;
using HaldorExpansion.Features.ShadowCrossbow;
using HaldorExpansion.Features.StaminaCape;
using HaldorExpansion.Features.SteelHeart;
using HaldorExpansion.Features.WoundedBeast;
using HaldorExpansion.Integration;
using HaldorExpansion.Presentation;
using HaldorExpansion.Trading;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Extensions;
using Jotunn.Managers;
using Jotunn.Utils;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("HaldorExpansion")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("aveasura")]
[assembly: AssemblyProduct("HaldorExpansion")]
[assembly: AssemblyCopyright("Copyright © aveasura 2026")]
[assembly: AssemblyTrademark("aveasura")]
[assembly: ComVisible(false)]
[assembly: Guid("8A5C36D6-1908-4277-91DF-24E5D1B9B7BA")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.2.0.0")]
namespace HaldorExpansion
{
	[BepInPlugin("aveasura.haldor.expansion", "Haldor Expansion", "1.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class HaldorExpansionPlugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(CharacterAnimEvent), "CustomFixedUpdate")]
		private static class CestusAnimatorSpeedPatch
		{
			private static readonly FieldInfo CurrentAttackField = AccessTools.Field(typeof(Humanoid), "m_currentAttack");

			private static void Postfix(Character ___m_character, Animator ___m_animator)
			{
				if ((Object)(object)___m_character == (Object)null || (Object)(object)___m_animator == (Object)null)
				{
					return;
				}
				Player val = (Player)(object)((___m_character is Player) ? ___m_character : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				int instanceID = ((Object)___m_animator).GetInstanceID();
				if (!CestusAnimationRuntime.CestusAnimatorStates.TryGetValue(instanceID, out var value))
				{
					value = new CestusAnimationRuntime.CestusAnimatorSpeedState();
					CestusAnimationRuntime.CestusAnimatorStates[instanceID] = value;
				}
				float speed = ___m_animator.speed;
				float num = speed;
				if (value.Applied && Mathf.Abs(speed - value.LastAppliedSpeed) < 0.0001f)
				{
					num = value.LastBaseSpeed;
				}
				ItemData currentWeapon = ((Humanoid)val).GetCurrentWeapon();
				Attack val2 = null;
				if (CurrentAttackField != null)
				{
					object? value2 = CurrentAttackField.GetValue(val);
					val2 = (Attack)((value2 is Attack) ? value2 : null);
				}
				if (!((Character)val).InAttack() || !CestusEquipment.IsCestusWeapon(currentWeapon) || val2 == null || string.IsNullOrEmpty(val2.m_attackAnimation) || val2.m_attackAnimation.IndexOf("unarmed", StringComparison.OrdinalIgnoreCase) < 0)
				{
					value.Applied = false;
					value.LastBaseSpeed = speed;
					value.LastAppliedSpeed = speed;
					return;
				}
				float num2 = Mathf.Clamp(1.9f, 0.01f, 10f);
				float num3 = num * num2;
				if (Mathf.Abs(___m_animator.speed - num3) > 0.0001f)
				{
					___m_animator.speed = num3;
					DebugLog("Cestus animator speed applied: " + num.ToString("0.###") + " -> " + num3.ToString("0.###"));
				}
				value.Applied = true;
				value.LastBaseSpeed = num;
				value.LastAppliedSpeed = num3;
			}
		}

		[HarmonyPatch(typeof(Player), "GetTotalFoodValue")]
		private static class CestusMaxHealthPatch
		{
			private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr)
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					if (CestusEquipment.HasEquippedCestus(__instance))
					{
						hp += 30f;
					}
					DebugLog($"[HaldorExpansion] Cestus HP bonus: equipped={CestusEquipment.HasEquippedCestus(__instance)}, hpBeforeBonus={hp}");
				}
			}
		}

		[HarmonyPatch(typeof(Player), "GetBodyArmor")]
		private static class CestusArmorPenaltyPatch
		{
			private static void Postfix(Player __instance, ref float __result)
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					bool flag = CestusEquipment.HasEquippedCestus(__instance);
					if (flag)
					{
						__result = Mathf.Max(0f, __result - 5f);
					}
					DebugLog($"[HaldorExpansion] Cestus armor penalty: equipped={flag}, armorAfterPenalty={__result}");
				}
			}
		}

		[HarmonyPatch(typeof(Player), "GetTotalFoodValue")]
		private static class PitKingChestMaxHealthPatch
		{
			private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr)
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					bool flag = PitKingEquipment.HasPitKingChestEquipped(__instance);
					if (flag)
					{
						hp += 70f;
					}
					DebugLog($"[HaldorExpansion] Pit King chest HP bonus: equipped={flag}, hpAfterBonus={hp:0.##}");
				}
			}
		}

		internal const string ModGuid = "aveasura.haldor.expansion";

		private const string ModName = "Haldor Expansion";

		private const string ModVersion = "1.2.0";

		internal static ManualLogSource Log;

		internal static HaldorExpansionPlugin Instance;

		private static readonly bool DebugLogging;

		private readonly ShopConfiguration _shopConfiguration = new ShopConfiguration();

		private readonly SellPriceConfiguration _sellPriceConfiguration = new SellPriceConfiguration();

		internal static void DebugLog(string message)
		{
			if (DebugLogging)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogInfo((object)message);
				}
			}
		}

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			_shopConfiguration.RegisterShopProgressionConfig(((BaseUnityPlugin)this).Config);
			_sellPriceConfiguration.RegisterHaldorSellPriceConfig(((BaseUnityPlugin)this).Config);
			ModLocalization.AddLocalizations();
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "aveasura.haldor.expansion");
			if (DebugLogging)
			{
				AdrenalineDiagnostics.DumpAdrenalineReflection();
			}
			CestusInputRegistration.RegisterCestusInput(((BaseUnityPlugin)this).Config);
			HelOathConfiguration.Register(((BaseUnityPlugin)this).Config);
		}
	}
	[HarmonyPatch(typeof(Player), "Update")]
	internal static class WoundedBeastCapePlayerUpdatePatch
	{
		private static readonly HashSet<int> ProcessedPlayers = new HashSet<int>();

		private static void Postfix(Player __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)ObjectDB.instance == (Object)null))
			{
				int instanceID = ((Object)__instance).GetInstanceID();
				if (!ProcessedPlayers.Contains(instanceID))
				{
					WoundedBeastInventoryRebind.FixWoundedBeastCapeItemsInInventory(__instance);
					ProcessedPlayers.Add(instanceID);
				}
				WoundedBeastRuntime.UpdateWoundedBeastCapeRegen(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	internal static class StaminaCapeObjectDBAwakePatch
	{
		private static void Postfix()
		{
			StaminaCapeItemRegistration.ResetCaches();
			if ((Object)(object)HaldorExpansionPlugin.Instance != (Object)null)
			{
				((MonoBehaviour)HaldorExpansionPlugin.Instance).StartCoroutine(DelayedEnsure());
			}
		}

		private static IEnumerator DelayedEnsure()
		{
			yield return null;
			yield return (object)new WaitUntil((Func<bool>)(() => (Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_items != null && ObjectDB.instance.m_items.Count > 0 && ObjectDB.instance.m_recipes != null && ObjectDB.instance.m_recipes.Count > 0));
			StaminaCapeItemRegistration.EnsureReady();
			StaminaCapeItemRegistration.RegisterRecipe();
		}
	}
	[HarmonyPatch(typeof(Player), "Update")]
	internal static class StaminaCapeInventoryFixPatch
	{
		private static readonly HashSet<int> ProcessedPlayers = new HashSet<int>();

		private static void Postfix(Player __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)ObjectDB.instance == (Object)null))
			{
				int instanceID = ((Object)__instance).GetInstanceID();
				if (!ProcessedPlayers.Contains(instanceID))
				{
					StaminaCapeInventoryRebind.FixItemsInInventory(__instance);
					ProcessedPlayers.Add(instanceID);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class HaldorStaminaCapeShopPatch
	{
		private static MethodBase TargetMethod()
		{
			MethodInfo methodInfo = null;
			MethodInfo[] methods = typeof(Trader).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (!(methodInfo2.Name != "Interact"))
				{
					if (methodInfo == null)
					{
						methodInfo = methodInfo2;
					}
					ParameterInfo[] parameters = methodInfo2.GetParameters();
					if (parameters.Length >= 1 && typeof(Humanoid).IsAssignableFrom(parameters[0].ParameterType))
					{
						return methodInfo2;
					}
				}
			}
			return methodInfo;
		}

		private static void Prefix(Trader __instance)
		{
			if (IsHaldor(__instance))
			{
				if (__instance.m_items == null)
				{
					__instance.m_items = new List<TradeItem>();
				}
				StaminaCapeItemRegistration.EnsureReady();
				TryAddCape(__instance);
			}
		}

		private static void TryAddCape(Trader trader)
		{
			ItemDrop capeItemDrop = StaminaCapeItemRegistration.CapeItemDrop;
			if (!((Object)(object)capeItemDrop == (Object)null) && !HasPrefab(trader, "CapeFracturedBreath"))
			{
				AddTradeItem(trader, capeItemDrop, 2500, 1);
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Stamina cape added to Haldor shop");
			}
		}

		private static bool IsHaldor(Trader trader)
		{
			if ((Object)(object)trader != (Object)null && (Object)(object)((Component)trader).gameObject != (Object)null)
			{
				return ((Object)((Component)trader).gameObject).name.StartsWith("Haldor");
			}
			return false;
		}

		private static bool HasPrefab(Trader trader, string prefabName)
		{
			string shopRequiredGlobalKey = ShopConfiguration.GetShopRequiredGlobalKey(prefabName);
			foreach (TradeItem item in trader.m_items)
			{
				if ((Object)(object)item.m_prefab != (Object)null && ((Object)item.m_prefab).name == prefabName)
				{
					item.m_requiredGlobalKey = shopRequiredGlobalKey;
					item.m_price = ShopConfiguration.GetShopPrice(prefabName, item.m_price);
					return true;
				}
			}
			return false;
		}

		private static void AddTradeItem(Trader trader, ItemDrop itemDrop, int price, int stack)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			SharedData val = (((Object)(object)itemDrop != (Object)null) ? itemDrop.m_itemData : null)?.m_shared;
			string prefabName = (((Object)(object)itemDrop != (Object)null) ? ((Object)itemDrop).name : string.Empty);
			trader.m_items.Add(new TradeItem
			{
				m_prefab = itemDrop,
				m_price = ShopConfiguration.GetShopPrice(prefabName, price),
				m_stack = stack,
				m_requiredGlobalKey = ShopConfiguration.GetShopRequiredGlobalKey(prefabName),
				m_levelUpEffect = false,
				m_buyPlayerEffects = new EffectList(),
				m_icon = null,
				m_name = ((val != null) ? (val.m_name ?? string.Empty) : string.Empty),
				m_tooltip = ((val != null) ? (val.m_description ?? string.Empty) : string.Empty),
				m_buyKey = string.Empty,
				m_incrementKey = string.Empty,
				m_incrementAmount = 0
			});
		}
	}
}
namespace HaldorExpansion.Trading
{
	internal static class TrophyValueUpdater
	{
		internal const int DefaultTrophyValue = 10;

		private static readonly Dictionary<string, int> ExtraSellableItems = new Dictionary<string, int>
		{
			{ "SurtlingCore", 50 },
			{ "BlackCore", 100 },
			{ "MoltenCore", 150 }
		};

		private static readonly Dictionary<string, int> TrophyValueOverrides = new Dictionary<string, int>
		{
			{ "TrophyDeer", 15 },
			{ "TrophyBoar", 15 },
			{ "TrophyNeck", 25 },
			{ "TrophyEikthyr", 70 },
			{ "TrophyGreydwarf", 15 },
			{ "TrophySkeleton", 15 },
			{ "TrophyGreydwarfShaman", 20 },
			{ "TrophyGhost", 25 },
			{ "TrophyGreydwarfBrute", 20 },
			{ "TrophyBjorn", 50 },
			{ "TrophyFrostTroll", 50 },
			{ "TrophyForestTroll", 50 },
			{ "TrophySkeletonPoison", 50 },
			{ "TrophySkeletonHildir", 80 },
			{ "TrophyTheElder", 100 },
			{ "TrophySerpent", 500 },
			{ "TrophyBonemawSerpent", 500 },
			{ "TrophyBlob", 15 },
			{ "TrophyDraugr", 15 },
			{ "TrophyDraugrFem", 15 },
			{ "TrophyLeech", 15 },
			{ "TrophySurtling", 15 },
			{ "TrophyDraugrElite", 30 },
			{ "TrophyWraith", 35 },
			{ "TrophyAbomination", 75 },
			{ "TrophyKvastur", 80 },
			{ "TrophyBonemass", 150 },
			{ "TrophyWolf", 15 },
			{ "TrophyHatchling", 15 },
			{ "TrophyUlv", 20 },
			{ "TrophyFenring", 25 },
			{ "TrophyCultist", 40 },
			{ "TrophySGolem", 70 },
			{ "TrophyCultist_Hildir", 80 },
			{ "TrophyDragonQueen", 200 },
			{ "TrophyDeathsquito", 15 },
			{ "TrophyGoblin", 15 },
			{ "TrophyGrowth", 15 },
			{ "TrophyBjornUndead", 50 },
			{ "TrophyLox", 35 },
			{ "TrophyGoblinShaman", 30 },
			{ "TrophyGoblinBrute", 70 },
			{ "TrophyGoblinBruteBrosShaman", 80 },
			{ "TrophyGoblinBruteBrosBrute", 80 },
			{ "TrophyGoblinKing", 350 },
			{ "TrophySeeker", 20 },
			{ "TrophyTick", 20 },
			{ "TrophyDvergr", 20 },
			{ "TrophyHare", 20 },
			{ "TrophyGjall", 70 },
			{ "TrophySeekerBrute", 80 },
			{ "TrophySeekerQueen", 500 },
			{ "TrophyCharredArcher", 20 },
			{ "TrophyVolture", 20 },
			{ "TrophyAsksvin", 20 },
			{ "TrophyCharredMage", 25 },
			{ "TrophyCharredMelee", 25 },
			{ "TrophyBlob_Lava", 30 },
			{ "TrophyMorgen", 100 },
			{ "TrophyFallenValkyrie", 120 },
			{ "TrophyFader", 1000 },
			{ "TrophyBarka", 50 },
			{ "TrophyElaking", 50 },
			{ "TrophyMole", 50 },
			{ "TrophyBlob_Frost", 50 },
			{ "TrophyJotunWitch", 50 },
			{ "TrophyJotunWarrior", 50 },
			{ "TrophyMoose", 50 },
			{ "TrophyBlob_Morkhalla", 50 },
			{ "TrophySeal", 50 },
			{ "TrophyWrithan", 50 },
			{ "TrophyDeerWhite", 50 }
		};

		internal static void ApplyTrophyValues(ObjectDB db)
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Invalid comparison between Unknown and I4
			if ((Object)(object)db == (Object)null || db.m_items == null)
			{
				return;
			}
			foreach (GameObject item in db.m_items)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				ItemDrop component = item.GetComponent<ItemDrop>();
				if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null)
				{
					continue;
				}
				SharedData shared = component.m_itemData.m_shared;
				if (ExtraSellableItems.TryGetValue(((Object)item).name, out var value))
				{
					HaldorExpansionPlugin.DebugLog(string.Format(arg2: shared.m_value = SellPriceConfiguration.GetConfiguredHaldorSellPrice(((Object)item).name, value), format: "[HaldorExpansion] Extra sellable item value set: prefab={0}, key={1}, value={2}", arg0: ((Object)item).name, arg1: shared.m_name));
				}
				else if ((int)shared.m_itemType == 13)
				{
					int num = SellPriceConfiguration.GetDefaultTrophySellPrice();
					if (TrophyValueOverrides.TryGetValue(((Object)item).name, out var value2))
					{
						num = SellPriceConfiguration.GetConfiguredHaldorSellPrice(((Object)item).name, value2);
					}
					shared.m_value = num;
					HaldorExpansionPlugin.DebugLog($"[HaldorExpansion] Trophy value set: prefab={((Object)item).name}, key={shared.m_name}, value={num}");
				}
			}
		}

		internal static bool IsSellableToHaldor(ItemData item)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Invalid comparison between Unknown and I4
			if (item == null || item.m_shared == null)
			{
				return false;
			}
			string text = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : null);
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			if (ExtraSellableItems.ContainsKey(text))
			{
				return item.m_shared.m_value > 0;
			}
			if ((int)item.m_shared.m_itemType == 13)
			{
				return item.m_shared.m_value > 0;
			}
			return false;
		}
	}
	internal static class HaldorShopUpdater
	{
		private sealed class ShopItemDefinition
		{
			public string PrefabName { get; private set; }

			public int Price { get; private set; }

			public int Stack { get; private set; }

			public bool UseMaxStack { get; private set; }

			public ShopItemDefinition(string prefabName, int price, int stack, bool useMaxStack = false)
			{
				PrefabName = prefabName;
				Price = price;
				Stack = stack;
				UseMaxStack = useMaxStack;
			}
		}

		private static readonly ShopItemDefinition[] ShopItems = new ShopItemDefinition[24]
		{
			new ShopItemDefinition("Iron", 225, 30),
			new ShopItemDefinition("Copper", 310, 30),
			new ShopItemDefinition("Tin", 180, 30),
			new ShopItemDefinition("Silver", 550, 30),
			new ShopItemDefinition("Flametal", 800, 30),
			new ShopItemDefinition("Stone", 20, 1, useMaxStack: true),
			new ShopItemDefinition("Grausten", 25, 1, useMaxStack: true),
			new ShopItemDefinition("BlackMarble", 40, 1, useMaxStack: true),
			new ShopItemDefinition("Wood", 10, 1, useMaxStack: true),
			new ShopItemDefinition("RoundLog", 10, 1, useMaxStack: true),
			new ShopItemDefinition("ElderBark", 30, 1, useMaxStack: true),
			new ShopItemDefinition("FineWood", 150, 1, useMaxStack: true),
			new ShopItemDefinition("YggdrasilWood", 250, 1, useMaxStack: true),
			new ShopItemDefinition("Ashwood", 30, 1, useMaxStack: true),
			new ShopItemDefinition("Blackwood", 100, 1, useMaxStack: true),
			new ShopItemDefinition("CharredWood", 50, 1, useMaxStack: true),
			new ShopItemDefinition("JuteRed", 250, 1, useMaxStack: true),
			new ShopItemDefinition("JuteBlue", 250, 1, useMaxStack: true),
			new ShopItemDefinition("Resin", 100, 1, useMaxStack: true),
			new ShopItemDefinition("Feathers", 150, 100),
			new ShopItemDefinition("GreydwarfEye", 200, 1, useMaxStack: true),
			new ShopItemDefinition("Tar", 250, 1, useMaxStack: true),
			new ShopItemDefinition("Crystal", 250, 1, useMaxStack: true),
			new ShopItemDefinition("Needle", 250, 1, useMaxStack: true)
		};

		internal static void TryAddPeltOfHelheim(Trader trader)
		{
			PeltOfHelheimItemRegistration.EnsureReady();
			ItemDrop capeItemDrop = PeltOfHelheimItemRegistration.CapeItemDrop;
			if (!((Object)(object)capeItemDrop == (Object)null) && !HasPrefab(trader, "CapePeltOfHelheim"))
			{
				AddTradeItem(trader, capeItemDrop, 2500, 1);
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Pelt of Helheim added to Haldor shop");
			}
		}

		internal static void TryAddWoundedBeastCape(Trader trader)
		{
			WoundedBeastItemRegistration.EnsureWoundedBeastCapeReady();
			ItemDrop woundedBeastCapeItemDrop = WoundedBeastItemRegistration.WoundedBeastCapeItemDrop;
			if (!((Object)(object)woundedBeastCapeItemDrop == (Object)null) && !HasPrefab(trader, "CapeWoundedBeast"))
			{
				AddTradeItem(trader, woundedBeastCapeItemDrop, 2500, 1);
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Wounded Beast cape added to Haldor shop");
			}
		}

		internal static void TryAddHelOath(Trader trader)
		{
			HelOathItemRegistration.EnsureHelOathReady();
			ItemDrop helOathItemDrop = HelOathItemRegistration.HelOathItemDrop;
			if (!((Object)(object)helOathItemDrop == (Object)null) && !HasPrefab(trader, "BowHelOath"))
			{
				AddTradeItem(trader, helOathItemDrop, 2500, 1);
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Shadow crossbow added to Haldor shop");
			}
		}

		internal static void TryAddShadowCrossbow(Trader trader)
		{
			ShadowCrossbowItemRegistration.EnsureShadowCrossbowReady();
			ItemDrop shadowCrossbowItemDrop = ShadowCrossbowItemRegistration.ShadowCrossbowItemDrop;
			if (!((Object)(object)shadowCrossbowItemDrop == (Object)null) && !HasPrefab(trader, "CrossbowSilentHunt"))
			{
				AddTradeItem(trader, shadowCrossbowItemDrop, 2500, 1);
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Shadow crossbow added to Haldor shop");
			}
		}

		internal static void TryAddPitKingChest(Trader trader)
		{
			PitKingItemRegistration.EnsurePitKingChestReady();
			ItemDrop pitKingChestItemDrop = PitKingItemRegistration.PitKingChestItemDrop;
			if (!((Object)(object)pitKingChestItemDrop == (Object)null) && !HasPrefab(trader, "ArmorPitKingChest"))
			{
				AddTradeItem(trader, pitKingChestItemDrop, 4000, 1);
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Pit King chest added to Haldor shop");
			}
		}

		internal static void TryAddCestus(Trader trader)
		{
			CestusItemRegistration.EnsureCestusReady();
			ItemDrop gritCestusItemDrop = CestusItemRegistration.GritCestusItemDrop;
			if (!((Object)(object)gritCestusItemDrop == (Object)null) && !HasPrefab(trader, "Bone_crushers"))
			{
				AddTradeItem(trader, gritCestusItemDrop, 2500, 1);
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Cestus added to Haldor shop");
			}
		}

		internal static void TryAddDelayedDoomChest(Trader trader)
		{
			DelayedDoomItemRegistration.EnsureDelayedDoomChestReady();
			ItemDrop delayedDoomChestItemDrop = DelayedDoomItemRegistration.DelayedDoomChestItemDrop;
			if (!((Object)(object)delayedDoomChestItemDrop == (Object)null) && !HasPrefab(trader, "ArmorDelayedDoomChest"))
			{
				AddTradeItem(trader, delayedDoomChestItemDrop, 4000, 1);
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Delayed Doom chest added to Haldor shop");
			}
		}

		internal static bool IsHaldor(Trader trader)
		{
			if ((Object)(object)trader != (Object)null && (Object)(object)((Component)trader).gameObject != (Object)null)
			{
				return ((Object)((Component)trader).gameObject).name.StartsWith("Haldor");
			}
			return false;
		}

		internal static void TryAddConfiguredItems(Trader trader)
		{
			if (!((Object)(object)ObjectDB.instance == (Object)null))
			{
				ShopItemDefinition[] shopItems = ShopItems;
				foreach (ShopItemDefinition item in shopItems)
				{
					TryAddConfiguredItem(trader, item);
				}
			}
		}

		private static void TryAddConfiguredItem(Trader trader, ShopItemDefinition item)
		{
			if ((Object)(object)ObjectDB.instance == (Object)null || HasPrefab(trader, item.PrefabName))
			{
				return;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item.PrefabName);
			if ((Object)(object)itemPrefab == (Object)null)
			{
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Prefab not found: " + item.PrefabName);
				return;
			}
			ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				ManualLogSource log = HaldorExpansionPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[HaldorExpansion] ItemDrop missing on prefab: " + item.PrefabName));
				}
				return;
			}
			int stack = ResolveStack(component, item);
			AddTradeItem(trader, component, item.Price, stack);
			int shopPrice = ShopConfiguration.GetShopPrice(item.PrefabName, item.Price);
			HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Added " + item.PrefabName + " x" + stack + " for " + shopPrice + " coins");
		}

		private static int ResolveStack(ItemDrop itemDrop, ShopItemDefinition item)
		{
			if (!item.UseMaxStack)
			{
				return item.Stack;
			}
			if (itemDrop.m_itemData != null && itemDrop.m_itemData.m_shared != null)
			{
				int maxStackSize = itemDrop.m_itemData.m_shared.m_maxStackSize;
				if (maxStackSize > 0)
				{
					return maxStackSize;
				}
			}
			return 1;
		}

		internal static void TryAddRing(Trader trader)
		{
			BrisingamenItemRegistration.EnsureRingReady();
			ItemDrop ringItemDrop = BrisingamenItemRegistration.RingItemDrop;
			if (!((Object)(object)ringItemDrop == (Object)null) && !HasPrefab(trader, "BrisingamenRing"))
			{
				AddTradeItem(trader, ringItemDrop, 1600, 1);
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Ring added to Haldor shop");
			}
		}

		internal static void TryAddNornThread(Trader trader)
		{
			NornThreadItemRegistration.EnsureReady();
			ItemDrop nornThreadItemDrop = NornThreadItemRegistration.NornThreadItemDrop;
			if (!((Object)(object)nornThreadItemDrop == (Object)null) && !HasPrefab(trader, "NornThreadAmulet"))
			{
				AddTradeItem(trader, nornThreadItemDrop, 6666, 1);
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Thread of the Norns added to Haldor shop");
			}
		}

		private static bool HasPrefab(Trader trader, string prefabName)
		{
			string shopRequiredGlobalKey = ShopConfiguration.GetShopRequiredGlobalKey(prefabName);
			foreach (TradeItem item in trader.m_items)
			{
				if ((Object)(object)item.m_prefab != (Object)null && ((Object)item.m_prefab).name == prefabName)
				{
					item.m_requiredGlobalKey = shopRequiredGlobalKey;
					item.m_price = ShopConfiguration.GetShopPrice(prefabName, item.m_price);
					return true;
				}
			}
			return false;
		}

		private static void AddTradeItem(Trader trader, ItemDrop itemDrop, int price, int stack)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			SharedData val = (((Object)(object)itemDrop != (Object)null) ? itemDrop.m_itemData : null)?.m_shared;
			string prefabName = (((Object)(object)itemDrop != (Object)null) ? ((Object)itemDrop).name : string.Empty);
			trader.m_items.Add(new TradeItem
			{
				m_prefab = itemDrop,
				m_price = ShopConfiguration.GetShopPrice(prefabName, price),
				m_stack = stack,
				m_requiredGlobalKey = ShopConfiguration.GetShopRequiredGlobalKey(prefabName),
				m_levelUpEffect = false,
				m_buyPlayerEffects = new EffectList(),
				m_icon = null,
				m_name = ((val != null) ? (val.m_name ?? string.Empty) : string.Empty),
				m_tooltip = ((val != null) ? (val.m_description ?? string.Empty) : string.Empty),
				m_buyKey = string.Empty,
				m_incrementKey = string.Empty,
				m_incrementAmount = 0
			});
		}
	}
}
namespace HaldorExpansion.Configuration
{
	internal sealed class ShopConfiguration
	{
		private ConfigFile Config;

		private static readonly Dictionary<string, ConfigEntry<string>> ShopRequiredGlobalKeys = new Dictionary<string, ConfigEntry<string>>();

		private static readonly Dictionary<string, ConfigEntry<int>> ShopPrices = new Dictionary<string, ConfigEntry<int>>();

		private readonly HashSet<string> ShopProgressionSectionsWithBossHelp = new HashSet<string>();

		private const string ShopProgressionDescription = "World global key required before this item appears in Haldor's shop. Leave empty to keep the item always available.";

		private const string ShopPriceDescription = "Price in coins for this item in Haldor's shop. Negative values are treated as 0.";

		private const string BossGlobalKeyHelp = "World global key required before this item appears in Haldor's shop. Leave empty to keep the item always available.\nVanilla boss keys:\ndefeated_eikthyr - Eikthyr\ndefeated_gdking - The Elder\ndefeated_bonemass - Bonemass\ndefeated_dragon - Moder\ndefeated_goblinking - Yagluth\ndefeated_queen - The Queen\ndefeated_fader - Fader\ndefeated_frozenking - Kall Fimbulbringer";

		internal void RegisterShopProgressionConfig(ConfigFile config)
		{
			Config = config;
			BindShopItemConfig("Shop Progression - Custom Items", "BrisingamenRing", "Corrupted Brisingamen", 1600);
			BindShopItemConfig("Shop Progression - Custom Items", "NornThreadAmulet", "Thread of the Norns", 6666);
			BindShopItemConfig("Shop Progression - Custom Items", "CapeWoundedBeast", "Cloak of the Wounded Beast", 2500);
			BindShopItemConfig("Shop Progression - Custom Items", "CapeFracturedBreath", "Fractured Breath Cape", 2500);
			BindShopItemConfig("Shop Progression - Custom Items", "CapePeltOfHelheim", "Pelt of Helheim", 2500);
			BindShopItemConfig("Shop Progression - Custom Items", "ArmorDelayedDoomChest", "Cuirass of Silent Reckoning", 4000);
			BindShopItemConfig("Shop Progression - Custom Items", "ArmorPitKingChest", "Pit King's Cuirass", 4000);
			BindShopItemConfig("Shop Progression - Custom Items", "Bone_crushers", "Grit Cestus", 2500);
			BindShopItemConfig("Shop Progression - Custom Items", "CrossbowSilentHunt", "Crossbow of the Shadow Hunt", 2500);
			BindShopItemConfig("Shop Progression - Custom Items", "BowHelOath", "Hel Oath", 2500);
			BindShopItemConfig("Shop Progression - Metals", "Iron", "Iron", 225);
			BindShopItemConfig("Shop Progression - Metals", "Copper", "Copper", 310);
			BindShopItemConfig("Shop Progression - Metals", "Tin", "Tin", 180);
			BindShopItemConfig("Shop Progression - Metals", "Silver", "Silver", 550);
			BindShopItemConfig("Shop Progression - Metals", "Flametal", "Flametal", 800);
			BindShopItemConfig("Shop Progression - Building Materials", "Stone", "Stone", 20);
			BindShopItemConfig("Shop Progression - Building Materials", "Grausten", "Grausten", 25);
			BindShopItemConfig("Shop Progression - Building Materials", "BlackMarble", "Black Marble", 40);
			BindShopItemConfig("Shop Progression - Wood", "Wood", "Wood", 10);
			BindShopItemConfig("Shop Progression - Wood", "RoundLog", "Core Wood", 10);
			BindShopItemConfig("Shop Progression - Wood", "ElderBark", "Ancient Bark", 30);
			BindShopItemConfig("Shop Progression - Wood", "FineWood", "Fine Wood", 150);
			BindShopItemConfig("Shop Progression - Wood", "YggdrasilWood", "Yggdrasil Wood", 250);
			BindShopItemConfig("Shop Progression - Wood", "Ashwood", "Ashwood", 30);
			BindShopItemConfig("Shop Progression - Wood", "Blackwood", "Blackwood", 100);
			BindShopItemConfig("Shop Progression - Wood", "CharredWood", "Charred Wood", 50);
			BindShopItemConfig("Shop Progression - Textiles", "JuteRed", "Red Jute", 250);
			BindShopItemConfig("Shop Progression - Textiles", "JuteBlue", "Blue Jute", 250);
			BindShopItemConfig("Shop Progression - Materials", "Resin", "Resin", 100);
			BindShopItemConfig("Shop Progression - Materials", "Feathers", "Feathers", 150);
			BindShopItemConfig("Shop Progression - Materials", "GreydwarfEye", "Greydwarf Eye", 200);
			BindShopItemConfig("Shop Progression - Materials", "Tar", "Tar", 250);
			BindShopItemConfig("Shop Progression - Materials", "Crystal", "Crystal", 250);
			BindShopItemConfig("Shop Progression - Materials", "Needle", "Needle", 250);
		}

		private void BindShopItemConfig(string section, string prefabName, string displayName, int defaultPrice)
		{
			BindShopPrice(section, prefabName, displayName, defaultPrice);
			BindShopRequiredGlobalKey(section, prefabName, displayName);
		}

		private void BindShopPrice(string section, string prefabName, string displayName, int defaultPrice)
		{
			string text = ConfigKey.SanitizeConfigKey(displayName) + " Price";
			ConfigEntry<int> value = ConfigFileExtensions.BindConfig<int>(Config, section, text, defaultPrice, "Price in coins for this item in Haldor's shop. Negative values are treated as 0.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			ShopPrices[prefabName] = value;
		}

		private void BindShopRequiredGlobalKey(string section, string prefabName, string displayName)
		{
			bool flag = ShopProgressionSectionsWithBossHelp.Add(section);
			string text = ConfigKey.SanitizeConfigKey(displayName) + " RequiredGlobalKey";
			ConfigEntry<string> value = ConfigFileExtensions.BindConfig<string>(Config, section, text, string.Empty, flag ? "World global key required before this item appears in Haldor's shop. Leave empty to keep the item always available.\nVanilla boss keys:\ndefeated_eikthyr - Eikthyr\ndefeated_gdking - The Elder\ndefeated_bonemass - Bonemass\ndefeated_dragon - Moder\ndefeated_goblinking - Yagluth\ndefeated_queen - The Queen\ndefeated_fader - Fader\ndefeated_frozenking - Kall Fimbulbringer" : "World global key required before this item appears in Haldor's shop. Leave empty to keep the item always available.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			ShopRequiredGlobalKeys[prefabName] = value;
		}

		internal static int GetShopPrice(string prefabName, int fallbackPrice)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				if (fallbackPrice >= 0)
				{
					return fallbackPrice;
				}
				return 0;
			}
			if (!ShopPrices.TryGetValue(prefabName, out var value) || value == null)
			{
				if (fallbackPrice >= 0)
				{
					return fallbackPrice;
				}
				return 0;
			}
			if (value.Value >= 0)
			{
				return value.Value;
			}
			return 0;
		}

		internal static string GetShopRequiredGlobalKey(string prefabName)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				return string.Empty;
			}
			if (!ShopRequiredGlobalKeys.TryGetValue(prefabName, out var value) || value == null)
			{
				return string.Empty;
			}
			return NormalizeGlobalKey(value.Value);
		}

		private static string NormalizeGlobalKey(string value)
		{
			if (!string.IsNullOrWhiteSpace(value))
			{
				return value.Trim();
			}
			return string.Empty;
		}
	}
	internal static class ConfigKey
	{
		internal static string SanitizeConfigKey(string value)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				return "Item";
			}
			return value.Replace("=", string.Empty).Replace("\n", " ").Replace("\r", " ")
				.Replace("\t", " ")
				.Replace("\\", string.Empty)
				.Replace("\"", string.Empty)
				.Replace("'", string.Empty)
				.Replace("[", "(")
				.Replace("]", ")")
				.Trim();
		}
	}
	internal sealed class SellPriceConfiguration
	{
		private ConfigFile Config;

		private static readonly Dictionary<string, ConfigEntry<int>> HaldorSellPrices = new Dictionary<string, ConfigEntry<int>>();

		private static ConfigEntry<int> DefaultTrophySellPriceConfig;

		private const string TrophySellPriceDescription = "Sell price in coins when this trophy is sold to Haldor. Set to 0 to disable selling it. Negative values are treated as 0.";

		private const string ExtraSellablePriceDescription = "Sell price in coins when this item is sold to Haldor. Set to 0 to disable selling it. Negative values are treated as 0.";

		internal void RegisterHaldorSellPriceConfig(ConfigFile config)
		{
			Config = config;
			DefaultTrophySellPriceConfig = ConfigFileExtensions.BindConfig<int>(Config, "Sell Prices - General", "Unlisted Trophy Price", 10, "Fallback sell price for trophy prefabs that are not explicitly listed below, including trophies added by other mods or future game updates. Set to 0 to disable selling unlisted trophies. Negative values are treated as 0.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			WatchSellPriceEntry(DefaultTrophySellPriceConfig);
			BindTrophySellPrice("Sell Prices - Meadows", "TrophyDeer", "Deer Trophy", 15);
			BindTrophySellPrice("Sell Prices - Meadows", "TrophyBoar", "Boar Trophy", 15);
			BindTrophySellPrice("Sell Prices - Meadows", "TrophyNeck", "Neck Trophy", 25);
			BindTrophySellPrice("Sell Prices - Meadows", "TrophyEikthyr", "Eikthyr Trophy", 70);
			BindTrophySellPrice("Sell Prices - Black Forest", "TrophyGreydwarf", "Greydwarf Trophy", 15);
			BindTrophySellPrice("Sell Prices - Black Forest", "TrophySkeleton", "Skeleton Trophy", 15);
			BindTrophySellPrice("Sell Prices - Black Forest", "TrophyGreydwarfShaman", "Greydwarf Shaman Trophy", 20);
			BindTrophySellPrice("Sell Prices - Black Forest", "TrophyGhost", "Ghost Trophy", 25);
			BindTrophySellPrice("Sell Prices - Black Forest", "TrophyGreydwarfBrute", "Greydwarf Brute Trophy", 20);
			BindTrophySellPrice("Sell Prices - Black Forest", "TrophyBjorn", "Bear Trophy", 50);
			BindTrophySellPrice("Sell Prices - Black Forest", "TrophyFrostTroll", "Troll Trophy", 50);
			BindTrophySellPriceAlias("TrophyForestTroll", "TrophyFrostTroll");
			BindTrophySellPrice("Sell Prices - Black Forest", "TrophySkeletonPoison", "Rancid Remains Trophy", 50);
			BindTrophySellPrice("Sell Prices - Black Forest", "TrophySkeletonHildir", "Brenna Trophy", 80);
			BindTrophySellPrice("Sell Prices - Black Forest", "TrophyTheElder", "The Elder Trophy", 100);
			BindTrophySellPrice("Sell Prices - Ocean", "TrophySerpent", "Serpent Trophy", 500);
			BindTrophySellPrice("Sell Prices - Ocean", "TrophyBonemawSerpent", "Bonemaw Trophy", 500);
			BindTrophySellPrice("Sell Prices - Swamp", "TrophyBlob", "Blob Trophy", 15);
			BindTrophySellPrice("Sell Prices - Swamp", "TrophyDraugr", "Draugr Trophy", 15);
			BindTrophySellPriceAlias("TrophyDraugrFem", "TrophyDraugr");
			BindTrophySellPrice("Sell Prices - Swamp", "TrophyLeech", "Leech Trophy", 15);
			BindTrophySellPrice("Sell Prices - Swamp", "TrophySurtling", "Surtling Trophy", 15);
			BindTrophySellPrice("Sell Prices - Swamp", "TrophyDraugrElite", "Draugr Elite Trophy", 30);
			BindTrophySellPrice("Sell Prices - Swamp", "TrophyWraith", "Wraith Trophy", 35);
			BindTrophySellPrice("Sell Prices - Swamp", "TrophyAbomination", "Abomination Trophy", 75);
			BindTrophySellPrice("Sell Prices - Swamp", "TrophyKvastur", "Kvastur Trophy", 80);
			BindTrophySellPrice("Sell Prices - Swamp", "TrophyBonemass", "Bonemass Trophy", 150);
			BindTrophySellPrice("Sell Prices - Mountains", "TrophyWolf", "Wolf Trophy", 15);
			BindTrophySellPrice("Sell Prices - Mountains", "TrophyHatchling", "Drake Trophy", 15);
			BindTrophySellPrice("Sell Prices - Mountains", "TrophyUlv", "Ulv Trophy", 20);
			BindTrophySellPrice("Sell Prices - Mountains", "TrophyFenring", "Fenring Trophy", 25);
			BindTrophySellPrice("Sell Prices - Mountains", "TrophyCultist", "Cultist Trophy", 40);
			BindTrophySellPrice("Sell Prices - Mountains", "TrophySGolem", "Stone Golem Trophy", 70);
			BindTrophySellPrice("Sell Prices - Mountains", "TrophyCultist_Hildir", "Geirrhafa Trophy", 80);
			BindTrophySellPrice("Sell Prices - Mountains", "TrophyDragonQueen", "Moder Trophy", 200);
			BindTrophySellPrice("Sell Prices - Plains", "TrophyDeathsquito", "Deathsquito Trophy", 15);
			BindTrophySellPrice("Sell Prices - Plains", "TrophyGoblin", "Fuling Trophy", 15);
			BindTrophySellPrice("Sell Prices - Plains", "TrophyGrowth", "Growth Trophy", 15);
			BindTrophySellPrice("Sell Prices - Plains", "TrophyBjornUndead", "Vile Trophy", 50);
			BindTrophySellPrice("Sell Prices - Plains", "TrophyLox", "Lox Trophy", 35);
			BindTrophySellPrice("Sell Prices - Plains", "TrophyGoblinShaman", "Fuling Shaman Trophy", 30);
			BindTrophySellPrice("Sell Prices - Plains", "TrophyGoblinBrute", "Fuling Berserker Trophy", 70);
			BindTrophySellPrice("Sell Prices - Plains", "TrophyGoblinBruteBrosShaman", "Zil Trophy", 80);
			BindTrophySellPrice("Sell Prices - Plains", "TrophyGoblinBruteBrosBrute", "Thungr Trophy", 80);
			BindTrophySellPrice("Sell Prices - Plains", "TrophyGoblinKing", "Yagluth Trophy", 350);
			BindTrophySellPrice("Sell Prices - Mistlands", "TrophySeeker", "Seeker Trophy", 20);
			BindTrophySellPrice("Sell Prices - Mistlands", "TrophyTick", "Tick Trophy", 20);
			BindTrophySellPrice("Sell Prices - Mistlands", "TrophyDvergr", "Dvergr Trophy", 20);
			BindTrophySellPrice("Sell Prices - Mistlands", "TrophyHare", "Hare Trophy", 20);
			BindTrophySellPrice("Sell Prices - Mistlands", "TrophyGjall", "Gjall Trophy", 70);
			BindTrophySellPrice("Sell Prices - Mistlands", "TrophySeekerBrute", "Seeker Soldier Trophy", 80);
			BindTrophySellPrice("Sell Prices - Mistlands", "TrophySeekerQueen", "The Queen Trophy", 500);
			BindTrophySellPrice("Sell Prices - Ashlands", "TrophyCharredArcher", "Marksman Trophy", 20);
			BindTrophySellPrice("Sell Prices - Ashlands", "TrophyVolture", "Volture Trophy", 20);
			BindTrophySellPrice("Sell Prices - Ashlands", "TrophyAsksvin", "Asksvin Trophy", 20);
			BindTrophySellPrice("Sell Prices - Ashlands", "TrophyCharredMage", "Warlock Trophy", 25);
			BindTrophySellPrice("Sell Prices - Ashlands", "TrophyCharredMelee", "Warrior Trophy", 25);
			BindTrophySellPrice("Sell Prices - Ashlands", "TrophyBlob_Lava", "Lava Blob Trophy", 30);
			BindTrophySellPrice("Sell Prices - Ashlands", "TrophyMorgen", "Morgen Trophy", 100);
			BindTrophySellPrice("Sell Prices - Ashlands", "TrophyFallenValkyrie", "Fallen Valkyrie Trophy", 120);
			BindTrophySellPrice("Sell Prices - Ashlands", "TrophyFader", "Fader Trophy", 1000);
			BindTrophySellPrice("Sell Prices - Deep North", "TrophyBarka", "Barka Trophy", 50);
			BindTrophySellPrice("Sell Prices - Deep North", "TrophyElaking", "Elaking Trophy", 50);
			BindTrophySellPrice("Sell Prices - Deep North", "TrophyMole", "Eyeless One Trophy", 50);
			BindTrophySellPrice("Sell Prices - Deep North", "TrophyBlob_Frost", "Frost Blob Trophy", 50);
			BindTrophySellPrice("Sell Prices - Deep North", "TrophyJotunWitch", "Hexen Trophy", 50);
			BindTrophySellPrice("Sell Prices - Deep North", "TrophyJotunWarrior", "Krigen Trophy", 50);
			BindTrophySellPrice("Sell Prices - Deep North", "TrophyMoose", "Moose Trophy", 50);
			BindTrophySellPrice("Sell Prices - Deep North", "TrophyBlob_Morkhalla", "Pulp Trophy", 50);
			BindTrophySellPrice("Sell Prices - Deep North", "TrophySeal", "Seal Trophy", 50);
			BindTrophySellPrice("Sell Prices - Deep North", "TrophyWrithan", "Writhan Trophy", 50);
			BindTrophySellPrice("Sell Prices - Deep North", "TrophyDeerWhite", "White Deer Trophy", 50);
			BindExtraSellPrice("Sell Prices - Cores", "SurtlingCore", "Surtling Core", 50);
			BindExtraSellPrice("Sell Prices - Cores", "BlackCore", "Black Core", 100);
			BindExtraSellPrice("Sell Prices - Cores", "MoltenCore", "Molten Core", 150);
		}

		private void BindTrophySellPrice(string section, string prefabName, string displayName, int defaultPrice)
		{
			BindHaldorSellPrice(section, prefabName, displayName, defaultPrice, "Sell price in coins when this trophy is sold to Haldor. Set to 0 to disable selling it. Negative values are treated as 0.");
		}

		private void BindExtraSellPrice(string section, string prefabName, string displayName, int defaultPrice)
		{
			BindHaldorSellPrice(section, prefabName, displayName, defaultPrice, "Sell price in coins when this item is sold to Haldor. Set to 0 to disable selling it. Negative values are treated as 0.");
		}

		private void BindHaldorSellPrice(string section, string prefabName, string displayName, int defaultPrice, string description)
		{
			ConfigEntry<int> val = ConfigFileExtensions.BindConfig<int>(Config, section, ConfigKey.SanitizeConfigKey(displayName) + " Price", defaultPrice, description, true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			HaldorSellPrices[prefabName] = val;
			WatchSellPriceEntry(val);
		}

		private static void BindTrophySellPriceAlias(string aliasPrefabName, string sourcePrefabName)
		{
			if (HaldorSellPrices.TryGetValue(sourcePrefabName, out var value) && value != null)
			{
				HaldorSellPrices[aliasPrefabName] = value;
			}
		}

		private static void WatchSellPriceEntry(ConfigEntry<int> entry)
		{
			if (entry != null)
			{
				entry.SettingChanged += OnHaldorSellPriceChanged;
			}
		}

		private static void OnHaldorSellPriceChanged(object sender, EventArgs e)
		{
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				TrophyValueUpdater.ApplyTrophyValues(ObjectDB.instance);
			}
		}

		internal static int GetConfiguredHaldorSellPrice(string prefabName, int fallbackPrice)
		{
			if (!string.IsNullOrEmpty(prefabName) && HaldorSellPrices.TryGetValue(prefabName, out var value) && value != null)
			{
				if (value.Value >= 0)
				{
					return value.Value;
				}
				return 0;
			}
			if (fallbackPrice >= 0)
			{
				return fallbackPrice;
			}
			return 0;
		}

		internal static int GetDefaultTrophySellPrice()
		{
			if (DefaultTrophySellPriceConfig == null)
			{
				return 10;
			}
			if (DefaultTrophySellPriceConfig.Value >= 0)
			{
				return DefaultTrophySellPriceConfig.Value;
			}
			return 0;
		}
	}
}
namespace HaldorExpansion.Integration
{
	internal static class ItemCacheReset
	{
		internal static void ResetItemCaches()
		{
			HelOathItemRegistration.HelOathPrefab = null;
			HelOathItemRegistration.HelOathItemDrop = null;
			BrisingamenItemRegistration.RingPrefab = null;
			BrisingamenItemRegistration.RingItemDrop = null;
			NornThreadItemRegistration.Prefab = null;
			NornThreadItemRegistration.NornThreadItemDrop = null;
			DelayedDoomItemRegistration.DelayedDoomChestPrefab = null;
			DelayedDoomItemRegistration.DelayedDoomChestItemDrop = null;
			PitKingItemRegistration.PitKingChestPrefab = null;
			PitKingItemRegistration.PitKingChestItemDrop = null;
			CestusItemRegistration.GritCestusPrefab = null;
			CestusItemRegistration.GritCestusItemDrop = null;
			ShadowCrossbowItemRegistration.ShadowCrossbowPrefab = null;
			ShadowCrossbowItemRegistration.ShadowCrossbowItemDrop = null;
			WoundedBeastRuntime.ResetWoundedBeastCapeState();
			PeltOfHelheimItemRegistration.ResetCaches();
			PeltOfHelheimStatus.ResetRegistration();
			BrisingamenItemRegistration._ringReadyLogged = false;
			NornThreadItemRegistration._readyLogged = false;
		}
	}
}
namespace HaldorExpansion.Compatibility
{
	internal static class ReflectionAccess
	{
		internal static void SetFieldIfExists(object obj, string fieldName, object value)
		{
			FieldInfo field = obj.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				field.SetValue(obj, value);
			}
		}

		internal static void CopyFieldIfExists(object src, object dst, string fieldName)
		{
			FieldInfo field = src.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			FieldInfo field2 = dst.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null && field2 != null)
			{
				object value = field.GetValue(src);
				field2.SetValue(dst, value);
			}
		}

		private static object GetFieldValueObject(object instance, string fieldName)
		{
			if (instance == null || string.IsNullOrEmpty(fieldName))
			{
				return null;
			}
			Type type = instance.GetType();
			while (type != null)
			{
				FieldInfo field = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					return field.GetValue(instance);
				}
				type = type.BaseType;
			}
			return null;
		}

		private static T GetFieldValue<T>(object instance, string fieldName)
		{
			object fieldValueObject = GetFieldValueObject(instance, fieldName);
			if (fieldValueObject == null)
			{
				return default(T);
			}
			if (fieldValueObject is T)
			{
				return (T)fieldValueObject;
			}
			return default(T);
		}
	}
	internal static class CharacterHealthAccess
	{
		internal static float GetCharacterMaxHealth(Character character)
		{
			return InvokeFloatMethod(character, "GetMaxHealth");
		}

		internal static float GetCharacterHealth(Character character)
		{
			return InvokeFloatMethod(character, "GetHealth");
		}

		internal static void SetCharacterHealth(Character character, float health)
		{
			if ((Object)(object)character == (Object)null)
			{
				return;
			}
			health = Mathf.Max(0f, health);
			Type type = ((object)character).GetType();
			while (type != null)
			{
				MethodInfo method = type.GetMethod("SetHealth", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(float) }, null);
				if (method != null)
				{
					method.Invoke(character, new object[1] { health });
					return;
				}
				type = type.BaseType;
			}
			FieldInfo field = ((object)character).GetType().GetField("m_health", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				field.SetValue(character, health);
			}
		}

		private static float InvokeFloatMethod(object target, string methodName)
		{
			if (target == null)
			{
				return 0f;
			}
			Type type = target.GetType();
			while (type != null)
			{
				MethodInfo method = type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
				if (method != null && method.ReturnType == typeof(float))
				{
					object obj = method.Invoke(target, null);
					if (obj is float)
					{
						return (float)obj;
					}
				}
				type = type.BaseType;
			}
			return 0f;
		}
	}
}
namespace HaldorExpansion.Presentation
{
	internal static class EmbeddedIconLoader
	{
		private const string EmbeddedIconPrefix = "HaldorExpansion.Assets.Icons.";

		internal static bool TrySetEmbeddedIcon(SharedData shared, string iconFileName)
		{
			if (shared == null)
			{
				return false;
			}
			Sprite val = LoadEmbeddedIcon("HaldorExpansion.Assets.Icons." + iconFileName);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			shared.m_icons = (Sprite[])(object)new Sprite[1] { val };
			HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Embedded icon applied: " + iconFileName);
			return true;
		}

		private static Sprite LoadEmbeddedIcon(string resourceName)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
				if (stream == null)
				{
					HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Embedded icon not found: " + resourceName);
					return null;
				}
				byte[] bytes = ReadAllBytes(stream);
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!TryLoadTextureImage(val, bytes))
				{
					HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Failed to load embedded icon image: " + resourceName);
					return null;
				}
				((Object)val).name = resourceName;
				return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
			}
			catch (Exception ex)
			{
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Failed to load embedded icon " + resourceName + ": " + ex);
				return null;
			}
		}

		private static bool TryLoadTextureImage(Texture2D texture, byte[] bytes)
		{
			try
			{
				Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule");
				if (type == null)
				{
					HaldorExpansionPlugin.DebugLog("[HaldorExpansion] UnityEngine.ImageConversion type not found");
					return false;
				}
				MethodInfo method = type.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[3]
				{
					typeof(Texture2D),
					typeof(byte[]),
					typeof(bool)
				}, null);
				if (method != null)
				{
					object obj = method.Invoke(null, new object[3] { texture, bytes, false });
					bool flag = default(bool);
					int num;
					if (obj is bool)
					{
						flag = (bool)obj;
						num = 1;
					}
					else
					{
						num = 0;
					}
					return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
				}
				method = type.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
				{
					typeof(Texture2D),
					typeof(byte[])
				}, null);
				if (method != null)
				{
					object obj2 = method.Invoke(null, new object[2] { texture, bytes });
					bool flag2 = default(bool);
					int num2;
					if (obj2 is bool)
					{
						flag2 = (bool)obj2;
						num2 = 1;
					}
					else
					{
						num2 = 0;
					}
					return (byte)((uint)num2 & (flag2 ? 1u : 0u)) != 0;
				}
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] UnityEngine.ImageConversion.LoadImage method not found");
				return false;
			}
			catch (Exception ex)
			{
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] TryLoadTextureImage error: " + ex);
				return false;
			}
		}

		private static byte[] ReadAllBytes(Stream stream)
		{
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			return memoryStream.ToArray();
		}
	}
	internal static class ModLocalization
	{
		internal static void AddLocalizations()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "Russian";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				["$item_bow_heloath"] = "Клятва Хель",
				["$item_bow_heloath_desc"] = "Холод Хельхейма дремлет в его тетиве. Каждая пролитая им кровь приближает исполнение Клятвы — и когда она будет исполнена, откроются Объятия Хель.\n\n<color=#9EDFF2><b>Фенрис — Касание Хель:</b></color> полный сет пробуждает Касание Хель от урона луком. Каждый стак улучшает подвижность персонажа.\n\n<color=#D5F5FF><b>Объятия Хель:</b></color> урон луком заряжает активную способность. При применении следующая стрела взрывается. <b>чем меньше максимум здоровья и выше максимум выносливости, тем сильнее Объятия Хель.</b> Касание V значительно усиливает их.",
				["$se_heloath_sacrifice"] = "Жертва Хель",
				["$se_heloath_sacrifice_desc"] = "50% максимального здоровья превращается в максимальную выносливость.",
				["$he_hel_ability"] = "Объятия Хель",
				["$he_hel_prepared"] = "Клятва пробуждена",
				["$se_hel_touch_1"] = "Касание Хель I",
				["$se_hel_touch_1_desc"] = "+5% к скорости передвижения.\n-4% затрат выносливости на все действия.",
				["$se_hel_touch_2"] = "Касание Хель II",
				["$se_hel_touch_2_desc"] = "+10% к скорости передвижения.\n-8% затрат выносливости на все действия.",
				["$se_hel_touch_3"] = "Касание Хель III",
				["$se_hel_touch_3_desc"] = "+15% к скорости передвижения.\n-12% затрат выносливости на все действия.",
				["$se_hel_touch_4"] = "Касание Хель IV",
				["$se_hel_touch_4_desc"] = "+20% к скорости передвижения.\n-16% затрат выносливости на все действия.",
				["$se_hel_touch_5"] = "Касание Хель V",
				["$se_hel_touch_5_desc"] = "+25% к скорости передвижения.\n-20% затрат выносливости на все действия.\nОбъятия Хель значительно усилены.",
				["$item_brisingamen"] = "Осквернённый Бризингамен",
				["$item_brisingamen_desc"] = "Легендарное золотое ожерелье, чья древняя сила облегчает даже самую тяжёлую ношу.",
				["$item_norn_thread"] = "Нить Норн",
				["$item_norn_thread_desc"] = "Тонкая нить, сплетённая там, где даже смерть ещё не решена. Когда судьба обрывается, она рвётся первой.",
				["$se_norn_thread"] = "Последняя нить",
				["$se_norn_thread_desc"] = "Смертельный урон уничтожает амулет вместо владельца. Здоровье становится равным 50% от значения до смертельного удара. После разрыва — 1,5 с защиты от потери здоровья.",
				["$msg_norn_thread_broken"] = "Нить судьбы оборвалась.",
				["$item_chest_delayeddoom"] = "Кираса безмолвной расплаты",
				["$item_chest_delayeddoom_desc"] = "Если удар после брони должен снести больше половины максимального здоровья, только часть урона проходит сразу, а остальное возвращается отложенной болью через несколько секунд.\nОна не спасает от расплаты — лишь даёт время нанести ответный удар.",
				["$se_delayeddoom_regen"] = "Безмолвная живучесть",
				["$se_delayeddoom_regen_desc"] = "+5 к восстановлению здоровья.",
				["$item_crossbow_silenthunt"] = "Арбалет теневой охоты",
				["$item_crossbow_silenthunt_desc"] = "Тяжёлый арбалет для тех, кто предпочитает решать бой первым и единственным выстрелом. Особенно беспощаден к целям, которые ещё не поняли, что на них уже открыли охоту.",
				["$item_weapon_gritcestus"] = "Костоломы",
				["$item_weapon_gritcestus_desc"] = "Рождённые в грязи и закалённые кровью, эти кастеты признают лишь один закон: кто выстоял под ударом, тот и забирает победу.\nНи одна стойка врага не выдержит их бешеного ритма ударов.\nПолучая урон, владелец накапливает боевой запал.\nАктивное умение: при полном запасе боевого запала нажмите колесико мыши, чтобы выпустить круговой выброс силы и получить краткий защитный покров.",
				["$se_weapon_gritcestus"] = "Закон арены",
				["$se_weapon_gritcestus_desc"] = "+30 к максимуму здоровья.\n+90% к скорости атаки.\n-5 брони.",
				["$item_chest_pitking"] = "Накидка хозяина ямы",
				["$item_chest_pitking_desc"] = "Её не создавали для защиты. Она создана для тех, кто выходит на арену не прятаться за сталью, а ломать кости голыми руками.",
				["$se_pitking_vigor"] = "Воля хозяина ямы",
				["$se_pitking_vigor_desc"] = "+70 к максимуму здоровья.",
				["$itemset_steelheart"] = "Стальное сердце",
				["$itemset_steelheart_desc"] = "Сет с кастетом: активка кастета получает на 50% больше силы щита и урона ударной волны.",
				["$item_cape_peltofhelheim"] = "Шкура Хельхейма",
				["$item_cape_peltofhelheim_desc"] = "Чёрная шкура, напитанная холодом Хельхейма. Она отвечает лишь тому, кто довёл охоту до совершенства.\n\n<color=#9EDFF2><b>Покров Хельхейма:</b></color> если надет полный сет Фенриса, в руках Клятва Хель и активно Касание Хель V, владелец получает <b>очень высокую устойчивость к колющему урону.</b>",
				["$se_peltofhelheim"] = "Покров Хельхейма",
				["$se_peltofhelheim_desc"] = "Касание Хель V завершает связь Фенриса с Хельхеймом.\nОчень высокая устойчивость к колющему урону.",
				["$item_cape_woundedbeast"] = "Плащ раненого зверя",
				["$item_cape_woundedbeast_desc"] = "Пока кровь ещё не остыла, зверь отказывается падать.\nЧем ближе смерть, тем яростнее он цепляется за жизнь — но каждая рана вгрызается глубже.",
				["$se_cape_woundedbeast"] = "Раненый зверь",
				["$se_cape_woundedbeast_desc"] = "Получаемый урон +18%.\nРаз в секунду восстанавливает здоровье: чем ниже текущее здоровье, тем сильнее восстановление.\nОгонь, яд и дух подавляют регенерацию на 2 секунды.\n\nПри использовании вместе с Кирасой безмолвной расплаты эффект лечения сокращается в 2 раза.",
				["$item_cape_fracturedbreath"] = "Плащ выжженной стойкости",
				["$item_cape_fracturedbreath_desc"] = "Часть полученного урона принимает на себя выносливость. Но когда силы иссякают, расплата становится тяжелее.",
				["$se_cape_fracturedbreath"] = "Выжженная стойкость",
				["$se_cape_fracturedbreath_desc"] = "25% полученного урона уходит в выносливость, но плата за эту отсрочку — усиленное истощение. Если выносливости не хватает, недостающий урон проходит по здоровью на 75% сильнее."
			});
			text = "English";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				["$item_bow_heloath"] = "Hel's Oath",
				["$item_bow_heloath_desc"] = "Helheim's cold slumbers in its string. Every drop of blood it spills brings the Oath closer to fulfillment — and when it is fulfilled, Hel's Embrace is revealed.\n\n<color=#9EDFF2><b>Fenris — Hel's Touch:</b></color> wearing the full set awakens Hel's Touch through bow damage. Each stack improves the character's mobility.\n\n<color=#D5F5FF><b>Hel's Embrace:</b></color> bow damage charges the active ability. When activated, the next arrow explodes on impact. <b>the lower the maximum health and the higher the maximum stamina, the stronger Hel's Embrace becomes.</b> Hel's Touch V greatly empowers it.",
				["$se_heloath_sacrifice"] = "Hel's Sacrifice",
				["$se_heloath_sacrifice_desc"] = "50% of maximum health is converted into maximum stamina.",
				["$he_hel_ability"] = "Hel's Embrace",
				["$he_hel_prepared"] = "Oath Awakened",
				["$se_hel_touch_1"] = "Hel's Touch I",
				["$se_hel_touch_1_desc"] = "+5% movement speed.\n-4% stamina cost for all actions.",
				["$se_hel_touch_2"] = "Hel's Touch II",
				["$se_hel_touch_2_desc"] = "+10% movement speed.\n-8% stamina cost for all actions.",
				["$se_hel_touch_3"] = "Hel's Touch III",
				["$se_hel_touch_3_desc"] = "+15% movement speed.\n-12% stamina cost for all actions.",
				["$se_hel_touch_4"] = "Hel's Touch IV",
				["$se_hel_touch_4_desc"] = "+20% movement speed.\n-16% stamina cost for all actions.",
				["$se_hel_touch_5"] = "Hel's Touch V",
				["$se_hel_touch_5_desc"] = "+25% movement speed.\n-20% stamina cost for all actions.\nHel's Embrace is greatly empowered.",
				["$item_brisingamen"] = "Corrupted Brisingamen",
				["$item_brisingamen_desc"] = "A legendary golden necklace whose ancient power makes even the heaviest burden easier to bear.",
				["$item_norn_thread"] = "Thread of the Norns",
				["$item_norn_thread_desc"] = "A slender thread woven where even death has not yet been decided. When fate breaks, the thread breaks first.",
				["$se_norn_thread"] = "The Last Thread",
				["$se_norn_thread_desc"] = "Lethal damage destroys the amulet instead of its wearer. Health becomes 50% of the amount held before the lethal hit. After breaking, health cannot be lost for 1.5 seconds.",
				["$msg_norn_thread_broken"] = "The thread of fate has snapped.",
				["$item_chest_delayeddoom"] = "Cuirass of Silent Reckoning",
				["$item_chest_delayeddoom_desc"] = "If a post-armor hit would take more than half of your maximum health, only part of the damage is taken immediately, while the rest returns as delayed pain over the next few seconds.\nIt does not save you from the reckoning — it only gives you time to strike back.",
				["$se_delayeddoom_regen"] = "Silent Vitality",
				["$se_delayeddoom_regen_desc"] = "+5 health regeneration.",
				["$item_crossbow_silenthunt"] = "Crossbow of the Shadow Hunt",
				["$item_crossbow_silenthunt_desc"] = "A heavy crossbow for those who prefer to decide the battle with the first and only shot. Especially ruthless against targets that do not yet realize the hunt has already begun.",
				["$item_weapon_gritcestus"] = "Bone Crushers",
				["$item_weapon_gritcestus_desc"] = "Born in the mud and tempered in blood, these cestus obey only one law: the one who endures the blow claims the victory.\nNo enemy stance can withstand their savage rhythm of strikes.\nTaking damage builds battle fervor.\nActive ability: when battle fervor is full, press the middle mouse button to release a circular burst of force and gain a brief protective barrier.",
				["$se_weapon_gritcestus"] = "Law of the Arena",
				["$se_weapon_gritcestus_desc"] = "+30 to maximum health.\n+90% attack speed.\n-5 armor.",
				["$item_chest_pitking"] = "Pit King's Cuirass",
				["$item_chest_pitking_desc"] = "It was not forged for protection. It was made for those who step into the pit not to hide behind steel, but to break bones with bare hands.",
				["$se_pitking_vigor"] = "Pit King's Vigor",
				["$se_pitking_vigor_desc"] = "+70 to maximum health.",
				["$itemset_steelheart"] = "Steel Heart",
				["$itemset_steelheart_desc"] = "Set with the cestus: the cestus active ability gains 50% more barrier strength and shockwave damage.",
				["$item_cape_peltofhelheim"] = "Pelt of Helheim",
				["$item_cape_peltofhelheim_desc"] = "A blackened pelt steeped in Helheim's cold. It answers only to a hunter who has brought the chase to perfection.\n\n<color=#9EDFF2><b>Helheim's Ward:</b></color> while wearing the full Fenris set, wielding Hel's Oath, and maintaining Hel's Touch V, the wearer becomes <b>very resistant to Pierce damage.</b>",
				["$se_peltofhelheim"] = "Helheim's Ward",
				["$se_peltofhelheim_desc"] = "Hel's Touch V completes the bond between Fenris and Helheim.\nVery resistant to Pierce damage.",
				["$item_cape_woundedbeast"] = "Cloak of the Wounded Beast",
				["$item_cape_woundedbeast_desc"] = "While the blood still burns, the beast refuses to fall.\nThe closer death comes, the more fiercely it clings to life — but every wound bites deeper.",
				["$se_cape_woundedbeast"] = "Wounded Beast",
				["$se_cape_woundedbeast_desc"] = "Incoming damage +18%.\nRestores health once per second: the lower your current health is, the stronger the regeneration becomes.\nFire, poison, and spirit suppress regeneration for 2 seconds.\n\nWhen used together with the Cuirass of Silent Reckoning, its healing effect is halved.",
				["$item_cape_fracturedbreath"] = "Cloak of Burned Resolve",
				["$item_cape_fracturedbreath_desc"] = "Part of the damage taken is absorbed by stamina. But when strength runs dry, the reckoning grows harsher.",
				["$se_cape_fracturedbreath"] = "Burned Resolve",
				["$se_cape_fracturedbreath_desc"] = "25% of damage taken is redirected into stamina, but this delayed pain drains stamina harder. If you do not have enough stamina, the missing damage hits health 75% harder."
			});
		}
	}
}
namespace HaldorExpansion.Combat
{
	internal static class HitDamageMath
	{
		internal static float GetHitTotalDamage(HitData hit)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if (hit == null)
			{
				return 0f;
			}
			DamageTypes damage = hit.m_damage;
			return Mathf.Max(0f, damage.m_damage + damage.m_blunt + damage.m_slash + damage.m_pierce + damage.m_fire + damage.m_frost + damage.m_lightning + damage.m_poison + damage.m_spirit);
		}
	}
}
namespace HaldorExpansion.Diagnostics
{
	internal static class PlayerDiagnostics
	{
		internal static string GetCestusDebugPlayerTag(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return "player=null";
			}
			ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon();
			ItemData playerHandItem = CestusEquipment.GetPlayerHandItem(player, "m_rightItem");
			ItemData playerHandItem2 = CestusEquipment.GetPlayerHandItem(player, "m_leftItem");
			bool flag = (Object)(object)player == (Object)(object)Player.m_localPlayer;
			ZNetView playerNView = CestusNetworkState.GetPlayerNView(player);
			bool flag2 = (Object)(object)playerNView != (Object)null && playerNView.IsValid() && playerNView.IsOwner();
			return "name=" + ((Object)player).name + ", " + $"local={flag}, " + $"owner={flag2}, " + $"pid={player.GetPlayerID()}, " + $"iid={((Object)player).GetInstanceID()}, " + "current=" + GetCestusItemDebugName(currentWeapon) + ", right=" + GetCestusItemDebugName(playerHandItem) + ", left=" + GetCestusItemDebugName(playerHandItem2);
		}

		private static string GetCestusItemDebugName(ItemData item)
		{
			if (item == null)
			{
				return "null";
			}
			if ((Object)(object)item.m_dropPrefab != (Object)null && !string.IsNullOrWhiteSpace(((Object)item.m_dropPrefab).name))
			{
				return ((Object)item.m_dropPrefab).name;
			}
			if (item.m_shared != null && !string.IsNullOrWhiteSpace(item.m_shared.m_name))
			{
				return item.m_shared.m_name;
			}
			return "unknown";
		}
	}
	internal static class AdrenalineDiagnostics
	{
		private static bool _adrenalineReflectionDumped;

		internal static void DumpAdrenalineReflection()
		{
			if (_adrenalineReflectionDumped)
			{
				return;
			}
			_adrenalineReflectionDumped = true;
			try
			{
				Assembly assembly = typeof(Player).Assembly;
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] ===== ADRENALINE / TRINKET REFLECTION DUMP START =====");
				string[] needles = new string[2] { "adren", "trinket" };
				Type[] array = (from t in assembly.GetTypes()
					where needles.Any((string n) => (t.FullName ?? string.Empty).IndexOf(n, StringComparison.OrdinalIgnoreCase) >= 0 || t.Name.IndexOf(n, StringComparison.OrdinalIgnoreCase) >= 0)
					orderby t.FullName
					select t).ToArray();
				foreach (Type type in array)
				{
					HaldorExpansionPlugin.DebugLog("[HaldorExpansion] [Reflect] TYPE: " + type.FullName);
					FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (FieldInfo fieldInfo in fields)
					{
						HaldorExpansionPlugin.DebugLog("[HaldorExpansion] [Reflect]   FIELD: " + fieldInfo.FieldType.Name + " " + fieldInfo.Name);
					}
					PropertyInfo[] properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (PropertyInfo propertyInfo in properties)
					{
						HaldorExpansionPlugin.DebugLog("[HaldorExpansion] [Reflect]   PROP: " + propertyInfo.PropertyType.Name + " " + propertyInfo.Name);
					}
					MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (MethodInfo m in methods)
					{
						if (needles.Any((string n) => m.Name.IndexOf(n, StringComparison.OrdinalIgnoreCase) >= 0))
						{
							string text = string.Join(", ", from p in m.GetParameters()
								select p.ParameterType.Name + " " + p.Name);
							HaldorExpansionPlugin.DebugLog("[HaldorExpansion] [Reflect]   METHOD: " + m.ReturnType.Name + " " + m.Name + "(" + text + ")");
						}
					}
				}
				DumpRelevantMembers(typeof(Player), "Player");
				DumpRelevantMembers(typeof(Hud), "Hud");
				DumpRelevantMembers(typeof(Humanoid), "Humanoid");
				DumpRelevantMembers(typeof(InventoryGui), "InventoryGui");
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] ===== ADRENALINE / TRINKET REFLECTION DUMP END =====");
			}
			catch (Exception arg)
			{
				ManualLogSource log = HaldorExpansionPlugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[HaldorExpansion] Adrenaline reflection dump failed: {arg}");
				}
			}
		}

		private static void DumpRelevantMembers(Type t, string label)
		{
			try
			{
				string[] source = new string[2] { "adren", "trinket" };
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] [Reflect] ===== " + label + " relevant members =====");
				FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo f in fields)
				{
					if (source.Any((string n) => f.Name.IndexOf(n, StringComparison.OrdinalIgnoreCase) >= 0))
					{
						HaldorExpansionPlugin.DebugLog("[HaldorExpansion] [Reflect]   FIELD: " + f.FieldType.Name + " " + f.Name);
					}
				}
				PropertyInfo[] properties = t.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (PropertyInfo p in properties)
				{
					if (source.Any((string n) => p.Name.IndexOf(n, StringComparison.OrdinalIgnoreCase) >= 0))
					{
						HaldorExpansionPlugin.DebugLog("[HaldorExpansion] [Reflect]   PROP: " + p.PropertyType.Name + " " + p.Name);
					}
				}
				MethodInfo[] methods = t.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo m in methods)
				{
					if (source.Any((string n) => m.Name.IndexOf(n, StringComparison.OrdinalIgnoreCase) >= 0))
					{
						string text = string.Join(", ", from parameterInfo in m.GetParameters()
							select parameterInfo.ParameterType.Name + " " + parameterInfo.Name);
						HaldorExpansionPlugin.DebugLog("[HaldorExpansion] [Reflect]   METHOD: " + m.ReturnType.Name + " " + m.Name + "(" + text + ")");
					}
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log = HaldorExpansionPlugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[HaldorExpansion] DumpRelevantMembers failed for {label}: {arg}");
				}
			}
		}
	}
}
namespace HaldorExpansion.Patches
{
	[HarmonyPatch(typeof(Player), "GetAdrenaline")]
	internal static class CestusAdrenalineValuePatch
	{
		private static void Postfix(Player __instance, ref float __result)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				if (CestusRuntime.ShouldForceHideCestusHudBar(__instance))
				{
					__result = 0f;
				}
				else if (CestusRuntime.ShouldMirrorCestusToAdrenaline(__instance))
				{
					__result = CestusChargeRuntime.GetCestusCharge(__instance);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "GetMaxAdrenaline")]
	internal static class CestusAdrenalineMaxPatch
	{
		private static void Postfix(Player __instance, ref float __result)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				if (CestusRuntime.ShouldForceHideCestusHudBar(__instance))
				{
					__result = 0f;
				}
				else if (CestusRuntime.ShouldMirrorCestusToAdrenaline(__instance))
				{
					__result = 100f;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "Update")]
	internal static class CestusActivationInputPatch
	{
		private static readonly Type ZInputType = AccessTools.TypeByName("ZInput");

		private static readonly MethodInfo GetButtonDownMethod = ((ZInputType != null) ? AccessTools.Method(ZInputType, "GetButtonDown", new Type[1] { typeof(string) }, (Type[])null) : null);

		private static bool IsCestusActivationPressed()
		{
			if (GetButtonDownMethod == null)
			{
				return false;
			}
			if (CestusInputRegistration.CestusAbilityButton == null)
			{
				return false;
			}
			object obj = GetButtonDownMethod.Invoke(null, new object[1] { CestusInputRegistration.CestusAbilityButton.Name });
			bool flag = default(bool);
			int num;
			if (obj is bool)
			{
				flag = (bool)obj;
				num = 1;
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		private static bool ShouldPoll(Player player)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			if (CestusInputRegistration.CestusAbilityButton == null)
			{
				return false;
			}
			if (!CestusEquipment.HasCestusEquipped(player))
			{
				return false;
			}
			if (!CestusChargeRuntime.HasFullCestusCharge(player))
			{
				return false;
			}
			if (CestusRuntime.IsCestusCasting(player))
			{
				return false;
			}
			if (CestusShieldRuntime.IsCestusShieldActive(player))
			{
				return false;
			}
			return true;
		}

		private static void Prefix(Player __instance)
		{
			CestusRuntime.UpdateCestusLocalEquipState(__instance);
			CestusChargeRuntime.UpdateCestusLocalDamageCharge(__instance);
			if (ShouldPoll(__instance) && IsCestusActivationPressed() && CestusAbility.TryActivateCestusShield(__instance))
			{
				CestusAbility.ClearHumanoidBlockState((Humanoid)(object)__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "StartAttack")]
	internal static class CestusAttackBlockDuringCastPatch
	{
		private static bool Prefix(Humanoid __instance, ref bool __result)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val == null)
			{
				return true;
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if (!CestusRuntime.IsCestusInputLocked(val))
			{
				return true;
			}
			CestusAbility.ClearHumanoidAttackState((Humanoid)(object)val);
			CestusAbility.ClearHumanoidBlockState((Humanoid)(object)val);
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Player), "SetControls")]
	internal static class CestusCastInputLockPatch
	{
		private static void Prefix(Player __instance, ref Vector3 movedir, ref bool attack, ref bool secondaryAttack, ref bool block, ref bool blockHold, ref bool jump, ref bool crouch)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && CestusRuntime.IsCestusInputLocked(__instance))
			{
				movedir = Vector3.zero;
				attack = false;
				secondaryAttack = false;
				block = false;
				blockHold = false;
				jump = false;
				crouch = false;
			}
		}
	}
	[HarmonyPatch(typeof(Hud), "Update")]
	internal static class CestusShieldHudPatch
	{
		private static void Postfix(Hud __instance)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				Player localPlayer = Player.m_localPlayer;
				CestusHudView.UpdateCestusShieldOverlay(__instance, localPlayer);
			}
		}
	}
	[HarmonyPatch(typeof(HitData), "ApplyArmor", new Type[] { typeof(float) })]
	internal static class DelayedDoomApplyArmorPatch
	{
		private static void Postfix(HitData __instance)
		{
			DelayedDoomDamagePatch.DamageContext damageContext = DelayedDoomDamagePatch.PeekContext();
			if (damageContext == null || !damageContext.Enabled || damageContext.ArmorProcessed)
			{
				return;
			}
			damageContext.ArmorProcessed = true;
			HaldorExpansionPlugin.DebugLog("[HaldorExpansion] ApplyArmor enter: " + PlayerDiagnostics.GetCestusDebugPlayerTag(damageContext.Player) + ", " + $"Cestus={damageContext.HasCestus}");
			float hitTotalDamage = HitDamageMath.GetHitTotalDamage(__instance);
			if (hitTotalDamage <= 0f)
			{
				return;
			}
			HaldorExpansionPlugin.DebugLog("[HaldorExpansion] ApplyArmor post-processing: " + $"hasCestus={damageContext.HasCestus}, " + $"postArmor={hitTotalDamage:0.##}, " + PlayerDiagnostics.GetCestusDebugPlayerTag(damageContext.Player));
			float hitTotalDamage2 = HitDamageMath.GetHitTotalDamage(__instance);
			if (damageContext.HasCestus && (Object)(object)damageContext.Player != (Object)null && hitTotalDamage2 > 0f)
			{
				float num = (damageContext.CestusShieldAbsorbedInApplyArmor = CestusShieldRuntime.AbsorbCestusShield(damageContext.Player, hitTotalDamage2));
				if (num > 0f)
				{
					float num2 = Mathf.Max(0f, hitTotalDamage2 - num);
					float num3 = ((hitTotalDamage2 > 0f) ? (num2 / hitTotalDamage2) : 0f);
					((DamageTypes)(ref __instance.m_damage)).Modify(num3);
					HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Cestus shield pre-armor absorb applied: " + $"incoming={hitTotalDamage2:0.##}, " + $"absorbed={num:0.##}, " + $"remaining={num2:0.##}, " + $"scale={num3:0.###}, " + PlayerDiagnostics.GetCestusDebugPlayerTag(damageContext.Player));
				}
			}
		}
	}
	[HarmonyPatch(typeof(Character), "ApplyDamage")]
	[HarmonyPriority(0)]
	internal static class DelayedDoomApplyDamagePatch
	{
		private sealed class ApplyDamageState
		{
			public Player Player;

			public bool DelayedDoomArmed;

			public bool DelayedDoomTriggered;

			public bool GracePrevented;

			public bool NornThreadTriggered;

			public float BeforeHealth;

			public float MaxHealth;

			public float IncomingDamage;

			public float ImmediateDamage;

			public float DelayedDamageTotal;

			public float FinalIncomingDamage;
		}

		private static void Prefix(Character __instance, HitData __0, ref ApplyDamageState __state)
		{
			__state = null;
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if ((Object)(object)val == (Object)null || __0 == null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			float characterHealth = CharacterHealthAccess.GetCharacterHealth((Character)(object)val);
			float characterMaxHealth = CharacterHealthAccess.GetCharacterMaxHealth((Character)(object)val);
			float hitTotalDamage = HitDamageMath.GetHitTotalDamage(__0);
			__state = new ApplyDamageState
			{
				Player = val,
				BeforeHealth = characterHealth,
				MaxHealth = characterMaxHealth,
				IncomingDamage = hitTotalDamage
			};
			if (characterHealth <= 0f || hitTotalDamage <= 0f)
			{
				return;
			}
			if (NornThreadRuntime.IsGraceActive(val))
			{
				((DamageTypes)(ref __0.m_damage)).Modify(0f);
				__state.GracePrevented = true;
				HaldorExpansionPlugin.DebugLog($"[HaldorExpansion] Norn Thread grace prevented damage: incoming={hitTotalDamage:0.##}, before={characterHealth:0.##}");
				return;
			}
			if (!DelayedDoomRuntime.IsDelayedDoomInternalDamage((Character)(object)val) && DelayedDoomEquipment.HasDelayedDoomEquipped(val))
			{
				__state.DelayedDoomArmed = true;
				float num = characterMaxHealth * 0.5f;
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Delayed Doom ApplyDamage prefix: " + $"incoming={hitTotalDamage:0.##}, before={characterHealth:0.##}, max={characterMaxHealth:0.##}, threshold={num:0.##}, " + PlayerDiagnostics.GetCestusDebugPlayerTag(val));
				if (characterMaxHealth > 0f && hitTotalDamage > num)
				{
					float num2 = hitTotalDamage * 0.5f;
					float num3 = hitTotalDamage * 0.7f;
					float num4 = num2 / hitTotalDamage;
					((DamageTypes)(ref __0.m_damage)).Modify(num4);
					__state.DelayedDoomTriggered = true;
					__state.ImmediateDamage = num2;
					__state.DelayedDamageTotal = num3;
					HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Delayed Doom ApplyDamage modified hit: " + $"incoming={hitTotalDamage:0.##}, immediate={num2:0.##}, delayed={num3:0.##}, scale={num4:0.###}, " + PlayerDiagnostics.GetCestusDebugPlayerTag(val));
				}
			}
			float hitTotalDamage2 = HitDamageMath.GetHitTotalDamage(__0);
			__state.FinalIncomingDamage = hitTotalDamage2;
			if (!(hitTotalDamage2 <= 0f) && !(hitTotalDamage2 < characterHealth) && NornThreadRuntime.TryConsume(val, out var consumed))
			{
				((DamageTypes)(ref __0.m_damage)).Modify(0f);
				__state.NornThreadTriggered = true;
				HaldorExpansionPlugin.DebugLog($"[HaldorExpansion] Norn Thread triggered: finalIncoming={hitTotalDamage2:0.##}, before={characterHealth:0.##}, " + "item=" + (consumed?.m_shared?.m_name ?? "<unknown>"));
			}
		}

		private static void Postfix(Character __instance, HitData __0, ApplyDamageState __state)
		{
			if (__state == null || (Object)(object)__state.Player == (Object)null)
			{
				return;
			}
			Player player = __state.Player;
			if (__state.NornThreadTriggered)
			{
				NornThreadRuntime.CompleteRescue(player, __state.BeforeHealth);
			}
			else if (!__state.GracePrevented && __state.DelayedDoomArmed && __state.DelayedDoomTriggered)
			{
				float characterHealth = CharacterHealthAccess.GetCharacterHealth((Character)(object)player);
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Delayed Doom ApplyDamage postfix: " + $"incoming={__state.IncomingDamage:0.##}, immediate={__state.ImmediateDamage:0.##}, delayed={__state.DelayedDamageTotal:0.##}, " + $"before={__state.BeforeHealth:0.##}, after={characterHealth:0.##}, " + PlayerDiagnostics.GetCestusDebugPlayerTag(player));
				if (((Character)player).IsDead() || characterHealth <= 0f)
				{
					HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Delayed Doom debt skipped because player died from immediate hit: " + $"incoming={__state.IncomingDamage:0.##}, immediate={__state.ImmediateDamage:0.##}, " + PlayerDiagnostics.GetCestusDebugPlayerTag(player));
				}
				else
				{
					DelayedDoomRuntime.AddDelayedDoomDebt(player, __state.DelayedDamageTotal);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Character), "ApplyDamage")]
	[HarmonyPriority(800)]
	internal static class StaminaCapeApplyDamagePatch
	{
		private static void Prefix(Character __instance, HitData __0)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if ((Object)(object)val == (Object)null || __0 == null || (Object)(object)val != (Object)(object)Player.m_localPlayer || DelayedDoomRuntime.IsDelayedDoomInternalDamage((Character)(object)val) || !StaminaCapeRuntime.HasEquipped(val))
			{
				return;
			}
			float hitTotalDamage = HitDamageMath.GetHitTotalDamage(__0);
			if (!(hitTotalDamage <= 0f))
			{
				float num = hitTotalDamage * 0.25f;
				float num2 = num * 2f;
				float num3 = Mathf.Max(0f, StaminaCapeRuntime.GetPlayerStamina(val));
				float num4 = ((num2 > 0f) ? Mathf.Clamp01(num3 / num2) : 1f);
				float num5 = num * num4;
				float num6 = Mathf.Min(num3, num2);
				float num7 = Mathf.Max(0f, num - num5);
				float num8 = ((!(num7 > 0.001f)) ? (hitTotalDamage - num5) : ((hitTotalDamage - num5) * 1.75f));
				num8 = Mathf.Max(0f, num8);
				float num9 = ((hitTotalDamage > 0f) ? (num8 / hitTotalDamage) : 1f);
				((DamageTypes)(ref __0.m_damage)).Modify(num9);
				if (num6 > 0.001f)
				{
					StaminaCapeRuntime.SpendPlayerStamina(val, num6);
				}
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Stamina cape ApplyDamage: " + $"incoming={hitTotalDamage:0.##}, " + $"redirectTarget={num:0.##}, " + $"staminaCost={num2:0.##}, " + $"staminaBefore={num3:0.##}, " + $"staminaSpent={num6:0.##}, " + $"missingRedirect={num7:0.##}, " + $"hpAfterCape={num8:0.##}, " + $"overflow={((num7 > 0.001f) ? 1 : 0)}, " + $"scale={num9:0.###}, " + PlayerDiagnostics.GetCestusDebugPlayerTag(val));
			}
		}
	}
	[HarmonyPatch(typeof(Character), "Damage")]
	internal static class DelayedDoomDamagePatch
	{
		internal sealed class DamageContext
		{
			public Player Player;

			public HitData Hit;

			public bool Enabled;

			public bool ArmorProcessed;

			public bool HasCestus;

			public float BeforeHealth;

			public float MaxHealth;

			public float CestusShieldAbsorbedInApplyArmor;

			public float CestusShieldCorrectedInPostfix;
		}

		private static readonly Stack<DamageContext> ContextStack = new Stack<DamageContext>();

		internal static DamageContext PeekContext()
		{
			if (ContextStack.Count <= 0)
			{
				return null;
			}
			return ContextStack.Peek();
		}

		private static void Prefix(Character __instance, HitData hit)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if ((Object)(object)val == (Object)null || hit == null)
			{
				return;
			}
			DamageContext damageContext = new DamageContext
			{
				Player = val,
				Hit = hit
			};
			bool flag = CestusEquipment.HasCestusEquipped(val);
			bool flag2 = CestusShieldRuntime.GetCestusEffectiveShieldRemaining(val) > 0.001f;
			bool flag3 = CestusRuntime.ShouldProcessCestusLocally(val) && (flag || flag2);
			HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Damage prefix: " + PlayerDiagnostics.GetCestusDebugPlayerTag(val) + ", " + $"CestusDetected={flag}, " + $"SyncedShieldActive={flag2}, " + $"CestusLocalRuntime={flag3}");
			bool num = DelayedDoomRuntime.IsDelayedDoomInternalDamage(__instance);
			if (num)
			{
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Damage prefix skip internal Delayed Doom damage: " + PlayerDiagnostics.GetCestusDebugPlayerTag(val));
			}
			if (!num && flag3)
			{
				float characterHealth = CharacterHealthAccess.GetCharacterHealth((Character)(object)val);
				float characterMaxHealth = CharacterHealthAccess.GetCharacterMaxHealth((Character)(object)val);
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Damage snapshot: " + $"before={characterHealth:0.##}, " + $"max={characterMaxHealth:0.##}, " + $"shieldActive={(flag2 ? 1 : 0)}");
				if (characterHealth > 0f && characterMaxHealth > 0f)
				{
					damageContext.Enabled = true;
					damageContext.BeforeHealth = characterHealth;
					damageContext.MaxHealth = characterMaxHealth;
					damageContext.HasCestus = flag3;
				}
			}
			ContextStack.Push(damageContext);
		}

		private static void Postfix(Character __instance, HitData hit)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if ((Object)(object)val == (Object)null || hit == null || ContextStack.Count == 0)
			{
				return;
			}
			DamageContext damageContext = ContextStack.Pop();
			if (!damageContext.Enabled)
			{
				return;
			}
			float characterHealth = CharacterHealthAccess.GetCharacterHealth((Character)(object)val);
			if (damageContext.HasCestus && damageContext.CestusShieldAbsorbedInApplyArmor <= 0.001f)
			{
				damageContext.CestusShieldCorrectedInPostfix = CestusShieldRuntime.CorrectCestusShieldAfterDamage(val, damageContext.BeforeHealth, characterHealth);
				if (damageContext.CestusShieldCorrectedInPostfix > 0.001f)
				{
					characterHealth = CharacterHealthAccess.GetCharacterHealth((Character)(object)val);
				}
			}
			if (damageContext.HasCestus)
			{
				HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Damage postfix after cestus handling: " + $"before={damageContext.BeforeHealth:0.##}, " + $"after={characterHealth:0.##}, " + $"cestusPreAbsorb={damageContext.CestusShieldAbsorbedInApplyArmor:0.##}, " + $"cestusPostfixCorrect={damageContext.CestusShieldCorrectedInPostfix:0.##}, " + PlayerDiagnostics.GetCestusDebugPlayerTag(val));
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateFood", new Type[]
	{
		typeof(float),
		typeof(bool)
	})]
	internal static class DelayedDoomFoodRegenPatch
	{
		private sealed class FoodRegenSnapshot
		{
			public Player Player;

			public bool Enabled;

			public float BeforeHealth;

			public float BaseFoodRegen;

			public float Dt;

			public bool ForceUpdate;
		}

		private static readonly Stack<FoodRegenSnapshot> Pending = new Stack<FoodRegenSnapshot>();

		private static void Prefix(Player __instance, float dt, bool forceUpdate)
		{
			FoodRegenSnapshot foodRegenSnapshot = new FoodRegenSnapshot
			{
				Player = __instance,
				Dt = dt,
				ForceUpdate = forceUpdate,
				Enabled = false,
				BeforeHealth = 0f,
				BaseFoodRegen = 0f
			};
			if ((Object)(object)__instance != (Object)null && DelayedDoomEquipment.HasDelayedDoomEquipped(__instance) && dt > 0f && !forceUpdate)
			{
				foodRegenSnapshot.Enabled = true;
				foodRegenSnapshot.BeforeHealth = CharacterHealthAccess.GetCharacterHealth((Character)(object)__instance);
				foodRegenSnapshot.BaseFoodRegen = DelayedDoomFoodRegen.GetPlayerBaseFoodRegen(__instance);
			}
			Pending.Push(foodRegenSnapshot);
		}

		private static void Postfix(Player __instance, float dt, bool forceUpdate)
		{
			if (Pending.Count == 0)
			{
				return;
			}
			FoodRegenSnapshot foodRegenSnapshot = Pending.Pop();
			if (!foodRegenSnapshot.Enabled || (Object)(object)__instance == (Object)null || foodRegenSnapshot.BaseFoodRegen <= 0.001f)
			{
				return;
			}
			float characterHealth = CharacterHealthAccess.GetCharacterHealth((Character)(object)__instance);
			float num = characterHealth - foodRegenSnapshot.BeforeHealth;
			if (num <= 0.001f)
			{
				return;
			}
			float num2 = num / foodRegenSnapshot.BaseFoodRegen;
			num2 = Mathf.Clamp(num2, 0f, 10f);
			float num3 = 5f * num2;
			if (!(num3 <= 0.001f))
			{
				float num4 = Mathf.Min(CharacterHealthAccess.GetCharacterMaxHealth((Character)(object)__instance), characterHealth + num3);
				if (!(num4 <= characterHealth + 0.001f))
				{
					CharacterHealthAccess.SetCharacterHealth((Character)(object)__instance, num4);
					HaldorExpansionPlugin.DebugLog("[HaldorExpansion] Food regen bonus applied: " + $"baseFoodRegen={foodRegenSnapshot.BaseFoodRegen:0.##}, " + $"foodHeal={num:0.##}, " + $"scale={num2:0.##}, " + $"bonus={num3:0.##}, " + $"after={characterHealth:0.##}, " + $"new={num4:0.##}, " + PlayerDiagnostics.GetCestusDebugPlayerTag(__instance));
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "Update")]
	internal static class DelayedDoomInventoryFixPatch
	{
		private static readonly HashSet<int> ProcessedPlayers = new HashSet<int>();

		private static void Postfix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			int instanceID = ((Object)__instance).GetInstanceID();
			if (ProcessedPlayers.Contains(instanceID))
			{
				return;
			}
			foreach (ItemData allItem in ((Humanoid)__instance).GetInventory().GetAllItems())
			{
				if (allItem != null && allItem.m_shared != null)
				{
					Recipe recipe = ObjectDB.instance.GetRecipe(allItem);
					string[] obj = new string[10]
					{
						"[RepairDebug] item=",
						allItem.m_shared.m_name,
						", recipe=",
						((Object)(object)recipe != (Object)null) ? ((Object)recipe).name : "null",
						", craft=",
						null,
						null,
						null,
						null,
						null
					};
					object obj2;
					if (!((Object)(object)recipe != (Object)null))
					{
						obj2 = "null";
					}
					else
					{
						CraftingStation craftingStation = recipe.m_craftingStation;
						obj2 = ((craftingStation != null) ? ((Object)craftingStation).name : null);
					}
					obj[5] = (string)obj2;
					obj[6] = ", repair=";
					object obj3;
					if (!((Object)(object)recipe != (Object)null))
					{
						obj3 = "null";
					}
					else
					{
						CraftingStation repairStation = recipe.m_repairStation;
						obj3 = ((repairStation != null) ? ((Object)repairStation).name : null);
					}
					obj[7] = (string)obj3;
					obj[8] = ", ";
					obj[9] = $"durability={allItem.m_durability:0.##}/{allItem.GetMaxDurability():0.##}";
					HaldorExpansionPlugin.DebugLog(string.Concat(obj));
				}
			}
			DelayedDoomInventoryRebind.FixDelayedDoomItemsInInventory(__instance);
			CestusInventoryRebind.FixCestusItemsInInventory(__instance);
			ProcessedPlayers.Add(instanceID);
		}
	}
	[HarmonyPatch]
	internal static class HaldorShopExpansionPatch
	{
		private static MethodBase TargetMethod()
		{
			MethodInfo methodInfo = null;
			MethodInfo[] methods = typeof(Trader).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (!(methodInfo2.Name != "Interact"))
				{
					if (methodInfo == null)
					{
						methodInfo = methodInfo2;
					}
					ParameterInfo[] parameters = methodInfo2.GetParameters();
					if (parameters.Length >= 1 && typeof(Humanoid).IsAssignableFrom(parameters[0].ParameterType))
					{
						return methodInfo2;
					}
				}
			}
			return methodInfo;
		}

		private static void Prefix(Trader __instance)
		{
			if (HaldorShopUpdater.IsHaldor(__instance))
			{
				TrophyValueUpdater.ApplyTrophyValues(ObjectDB.instance);
				if (__instance.m_items == null)
				{
					__instance.m_items = new List<TradeItem>();
				}
				HaldorShopUpdater.TryAddConfiguredItems(__instance);
				HaldorShopUpdater.TryAddRing(__instance);
				HaldorShopUpdater.TryAddNornThread(__instance);
				HaldorShopUpdater.TryAddWoundedBeastCape(__instance);
				HaldorShopUpdater.TryAddPeltOfHelheim(__instance);
				HaldorShopUpdater.TryAddDelayedDoomChest(__instance);
				HaldorShopUpdater.TryAddPitKingChest(__instance);
				HaldorShopUpdater.TryAddCestus(__instance);
				HaldorShopUpdater.TryAddShadowCrossbow(__instance);
				HaldorShopUpdater.TryAddHelOath(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	internal static class ObjectDB_Awake_Patch
	{
		private static void Postfix()
		{
			ItemCacheReset.ResetItemCaches();
			if ((Object)(object)HaldorExpansionPlugin.Instance != (Object)null)
			{
				((MonoBehaviour)HaldorExpansionPlugin.Instance).StartCoroutine(DelayedEnsure());
			}
		}

		private static IEnumerator DelayedEnsure()
		{
			yield return null;
			yield return (object)new WaitUntil((Func<bool>)(() => (Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_items != null && ObjectDB.instance.m_items.Count > 0 && ObjectDB.instance.m_recipes != null && ObjectDB.instance.m_recipes.Count > 0));
			BrisingamenItemRegistration.EnsureRingReady();
			NornThreadItemRegistration.EnsureReady();
			DelayedDoomItemRegistration.EnsureDelayedDoomChestReady();
			PitKingItemRegistration.EnsurePitKingChestReady();
			CestusItemRegistration.EnsureCestusReady();
			ShadowCrossbowItemRegistration.EnsureShadowCrossbowReady();
			HelOathItemRegistration.EnsureHelOathReady();
			HelOathTouchStatus.EnsureRegistered();
			WoundedBeastItemRegistration.EnsureWoundedBeastCapeReady();
			PeltOfHelheimItemRegistration.EnsureReady();
			PeltOfHelheimStatus.EnsureRegistered();
			ShadowCrossbowItemRegistration.RegisterShadowCrossbowRecipe();
			HelOathItemRegistration.RegisterHelOathRecipe();
			CestusItemRegistration.RegisterCestusRecipe();
			DelayedDoomItemRegistration.Regist