Decompiled source of Runecarved v1.0.0

IzzemisMod.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Runecarved")]
[assembly: AssemblyDescription("Rarity tiers, runes, and per-item modifiers for Valheim equipment.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Izzemi")]
[assembly: AssemblyProduct("Runecarved")]
[assembly: AssemblyCopyright("Copyright © 2026 Izzemi")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Runecarved;

internal static class ArmourModifiers
{
	private static IEnumerable<ItemData> Pieces(Player player)
	{
		yield return ((Humanoid)player).m_helmetItem;
		yield return ((Humanoid)player).m_chestItem;
		yield return ((Humanoid)player).m_legItem;
		yield return ((Humanoid)player).m_shoulderItem;
	}

	public static float Sum(Player player, ModifierEffectType effectType)
	{
		float num = 0f;
		if ((Object)(object)player == (Object)null)
		{
			return num;
		}
		foreach (ItemData item in Pieces(player))
		{
			if (item != null && ModifierCatalog.TryGetModifierValue(item, effectType, out var _, out var value))
			{
				num += value;
			}
		}
		return num;
	}

	public static float SumSkill(Player player, SkillType skill)
	{
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		float num = 0f;
		if ((Object)(object)player == (Object)null)
		{
			return num;
		}
		foreach (ItemData item in Pieces(player))
		{
			if (item == null)
			{
				continue;
			}
			foreach (ModifierDefinition item2 in ModifierCatalog.All)
			{
				if (item2.EffectType == ModifierEffectType.SkillLevel && item2.Skill == skill && item2.IsAllowedOn(item) && ItemModifierDataStore.TryGetModifierValue(item, item2.Id, out var value))
				{
					num += value;
				}
			}
		}
		return num;
	}
}
[HarmonyPatch(typeof(SEMan), "ModifyHealthRegen")]
internal static class HealthRegenModifierPatch
{
	private static readonly FieldRef<SEMan, Character> Owner = AccessTools.FieldRefAccess<SEMan, Character>("m_character");

	private static void Postfix(SEMan __instance, ref float regenMultiplier)
	{
		Character obj = Owner.Invoke(__instance);
		regenMultiplier += ArmourModifiers.Sum((Player)(object)((obj is Player) ? obj : null), ModifierEffectType.HealthRegen);
	}
}
[HarmonyPatch(typeof(SEMan), "ModifyStaminaRegen")]
internal static class StaminaRegenModifierPatch
{
	private static readonly FieldRef<SEMan, Character> Owner = AccessTools.FieldRefAccess<SEMan, Character>("m_character");

	private static void Postfix(SEMan __instance, ref float staminaMultiplier)
	{
		Character obj = Owner.Invoke(__instance);
		staminaMultiplier += ArmourModifiers.Sum((Player)(object)((obj is Player) ? obj : null), ModifierEffectType.StaminaRegen);
	}
}
[HarmonyPatch(typeof(Player), "GetTotalFoodValue")]
internal static class MaxHealthModifierPatch
{
	private static void Postfix(Player __instance, ref float hp)
	{
		hp += ArmourModifiers.Sum(__instance, ModifierEffectType.MaxHealth);
	}
}
[HarmonyPatch(typeof(Player), "GetEquipmentDodgeStaminaModifier")]
internal static class DodgeStaminaModifierPatch
{
	private static void Postfix(Player __instance, ref float __result)
	{
		__result += ArmourModifiers.Sum(__instance, ModifierEffectType.DodgeStaminaCost);
	}
}
[HarmonyPatch(typeof(Skills), "GetSkillLevel")]
internal static class SkillLevelModifierPatch
{
	private static readonly FieldRef<Skills, Player> Owner = AccessTools.FieldRefAccess<Skills, Player>("m_player");

	private static void Postfix(Skills __instance, SkillType skillType, ref float __result)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Invalid comparison between Unknown and I4
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		if ((int)skillType > 0)
		{
			__result += ArmourModifiers.SumSkill(Owner.Invoke(__instance), skillType);
		}
	}
}
[HarmonyPatch(typeof(Player), "OnDamaged")]
internal static class DamagedArmourModifierPatch
{
	private static bool _thornsActive;

	private static void Postfix(Player __instance, HitData hit)
	{
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Expected O, but got Unknown
		if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || hit.GetTotalDamage() <= 0f)
		{
			return;
		}
		float num = ArmourModifiers.Sum(__instance, ModifierEffectType.AdrenalineOnHit);
		if (num > 0f)
		{
			((Character)__instance).AddAdrenaline(num);
		}
		Character attacker = hit.GetAttacker();
		float num2 = ArmourModifiers.Sum(__instance, ModifierEffectType.Thorns);
		if (_thornsActive || num2 <= 0f || (Object)(object)attacker == (Object)null || (Object)(object)attacker == (Object)(object)__instance)
		{
			return;
		}
		float num3 = num2 * ((Character)__instance).GetBodyArmor();
		if (num3 <= 0f)
		{
			return;
		}
		_thornsActive = true;
		try
		{
			HitData val = new HitData
			{
				m_point = attacker.GetCenterPoint()
			};
			Vector3 val2 = ((Component)attacker).transform.position - ((Component)__instance).transform.position;
			val.m_dir = ((Vector3)(ref val2)).normalized;
			val.m_hitType = (HitType)2;
			HitData val3 = val;
			val3.m_damage.m_pierce = num3;
			val3.SetAttacker((Character)(object)__instance);
			attacker.Damage(val3);
		}
		finally
		{
			_thornsActive = false;
		}
	}
}
internal static class BloodMagicModifierHelpers
{
	public static float GetBaseHealthCost(float healthCost, float healthCostPercentage, Humanoid character, ItemData weapon)
	{
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)character == (Object)null || weapon?.m_shared == null)
		{
			return 0f;
		}
		float num = healthCost + ((Character)character).GetHealth() * healthCostPercentage / 100f;
		if (num <= 0f)
		{
			return 0f;
		}
		float skillFactor = ((Character)character).GetSkillFactor(weapon.m_shared.m_skillType);
		return Math.Max(0f, num - num * 0.33f * skillFactor);
	}

	public static float GetStaminaConversion(ItemData weapon, float baseHealthCost)
	{
		ModifierDefinition definition;
		float value;
		return (weapon != null && ModifierCatalog.TryGetModifierValue(weapon, ModifierEffectType.BloodHealthToStamina, out definition, out value)) ? (baseHealthCost * value) : 0f;
	}

	public static bool TryGetLowHealthBonus(ItemData weapon, Character character, out float bonus)
	{
		bonus = 0f;
		ModifierDefinition definition;
		return weapon != null && (Object)(object)character != (Object)null && character.GetHealth() < character.GetMaxHealth() * 0.5f && ModifierCatalog.TryGetModifierValue(weapon, ModifierEffectType.LowHealthEffect, out definition, out bonus);
	}
}
[HarmonyPatch(typeof(Attack), "GetAttackHealth")]
internal static class BloodMagicHealthCostModifierPatch
{
	private static void Postfix(Attack __instance, ref float __result, float ___m_attackHealth, float ___m_attackHealthPercentage)
	{
		ItemData weapon = __instance.m_weapon;
		if (weapon != null)
		{
			float num = 0f;
			if (ModifierCatalog.TryGetModifierValue(weapon, ModifierEffectType.BloodHealthCost, out var definition, out var value))
			{
				num += value;
			}
			if (ModifierCatalog.TryGetModifierValue(weapon, ModifierEffectType.BloodHealthToStamina, out definition, out var value2))
			{
				num += value2;
			}
			float baseHealthCost = BloodMagicModifierHelpers.GetBaseHealthCost(___m_attackHealth, ___m_attackHealthPercentage, __instance.m_character, weapon);
			__result = Math.Max(0f, baseHealthCost * (1f - num));
		}
	}
}
[HarmonyPatch(typeof(Attack), "GetAttackStamina")]
internal static class BloodMagicStaminaConversionPatch
{
	private static void Postfix(Attack __instance, ref float __result, float ___m_attackHealth, float ___m_attackHealthPercentage)
	{
		ItemData weapon = __instance.m_weapon;
		if (weapon != null)
		{
			float baseHealthCost = BloodMagicModifierHelpers.GetBaseHealthCost(___m_attackHealth, ___m_attackHealthPercentage, __instance.m_character, weapon);
			__result += BloodMagicModifierHelpers.GetStaminaConversion(weapon, baseHealthCost);
		}
	}
}
[HarmonyPatch(typeof(Projectile), "Setup")]
internal static class BloodMagicLowHealthDamagePatch
{
	private static void Postfix(ItemData item, Character owner, ref DamageTypes ___m_damage)
	{
		if (BloodMagicModifierHelpers.TryGetLowHealthBonus(item, owner, out var bonus))
		{
			((DamageTypes)(ref ___m_damage)).Modify(1f + bonus);
		}
	}
}
[HarmonyPatch(typeof(SE_Shield), "Setup")]
internal static class BloodMagicLowHealthShieldPatch
{
	private static readonly FieldRef<SE_Shield, float> TotalAbsorbDamage = AccessTools.FieldRefAccess<SE_Shield, float>("m_totalAbsorbDamage");

	private static void Postfix(SE_Shield __instance, Character character)
	{
		Humanoid val = (Humanoid)(object)((character is Humanoid) ? character : null);
		if (val != null && BloodMagicModifierHelpers.TryGetLowHealthBonus(val.GetCurrentWeapon(), character, out var bonus))
		{
			TotalAbsorbDamage.Invoke(__instance) *= 1f + bonus;
		}
	}
}
[HarmonyPatch(typeof(ItemData), "GetDamage", new Type[]
{
	typeof(int),
	typeof(float)
})]
internal static class ItemModifierDamagePatch
{
	private static void Postfix(ItemData __instance, ref DamageTypes __result)
	{
		if (__instance == null)
		{
			return;
		}
		foreach (ModifierDefinition item in ModifierCatalog.All)
		{
			if (item.DamageChannel != ModifierDamageChannel.None && item.IsAllowedOn(__instance) && ItemModifierDataStore.TryGetModifierValue(__instance, item.Id, out var value))
			{
				item.ApplyDamage(ref __result, value);
			}
		}
	}
}
[Serializable]
public sealed class ModifierRoll
{
	public string Id;

	public float Value;
}
[Serializable]
public sealed class ItemModifierData
{
	public int Version = 1;

	public string RarityId;

	public ModifierRoll[] Modifiers = new ModifierRoll[0];

	public bool HelTouched;
}
internal static class ItemModifierDataStore
{
	private const string CustomDataPrefix = "com.izzemi.myfirstmod.variant";

	private const string LegacyCustomDataKey = "com.izzemi.myfirstmod.variant";

	private const string VersionKey = "com.izzemi.myfirstmod.variant.version";

	private const string RarityKey = "com.izzemi.myfirstmod.variant.rarity";

	private const string HelKey = "com.izzemi.myfirstmod.variant.hel";

	private const string ModifierKeyPrefix = "com.izzemi.myfirstmod.variant.modifier.";

	public static bool TryGetRarityId(ItemData item, out string rarityId)
	{
		if (item == null)
		{
			throw new ArgumentNullException("item");
		}
		rarityId = null;
		if (item.m_customData == null)
		{
			return false;
		}
		if (item.m_customData.TryGetValue("com.izzemi.myfirstmod.variant.rarity", out rarityId))
		{
			return !string.IsNullOrWhiteSpace(rarityId);
		}
		if (!TryLoad(item, out var data) || string.IsNullOrWhiteSpace(data.RarityId))
		{
			return false;
		}
		rarityId = data.RarityId;
		return true;
	}

	public static void Clear(ItemData item)
	{
		if (item == null)
		{
			throw new ArgumentNullException("item");
		}
		if (item.m_customData == null)
		{
			return;
		}
		List<string> list = new List<string>();
		foreach (string key in item.m_customData.Keys)
		{
			if (key == "com.izzemi.myfirstmod.variant" || key.StartsWith("com.izzemi.myfirstmod.variant.", StringComparison.Ordinal))
			{
				list.Add(key);
			}
		}
		foreach (string item2 in list)
		{
			item.m_customData.Remove(item2);
		}
	}

	public static bool TryGetModifierValue(ItemData item, string modifierId, out float value)
	{
		if (item == null)
		{
			throw new ArgumentNullException("item");
		}
		value = 0f;
		if (item.m_customData == null || !item.m_customData.TryGetValue("com.izzemi.myfirstmod.variant.modifier." + modifierId, out var value2))
		{
			return false;
		}
		if (float.TryParse(value2, NumberStyles.Float, CultureInfo.InvariantCulture, out value))
		{
			return true;
		}
		Logger.LogError((object)("Invalid saved value '" + value2 + "' for variant modifier '" + modifierId + "'."));
		return false;
	}

	public static void Save(ItemData item, ItemModifierData data)
	{
		if (item == null)
		{
			throw new ArgumentNullException("item");
		}
		if (data == null)
		{
			throw new ArgumentNullException("data");
		}
		if (item.m_customData == null)
		{
			item.m_customData = new Dictionary<string, string>();
		}
		List<string> list = new List<string>();
		foreach (string key in item.m_customData.Keys)
		{
			if (key == "com.izzemi.myfirstmod.variant" || key.StartsWith("com.izzemi.myfirstmod.variant.", StringComparison.Ordinal))
			{
				list.Add(key);
			}
		}
		foreach (string item2 in list)
		{
			item.m_customData.Remove(item2);
		}
		item.m_customData["com.izzemi.myfirstmod.variant.version"] = data.Version.ToString(CultureInfo.InvariantCulture);
		item.m_customData["com.izzemi.myfirstmod.variant.rarity"] = data.RarityId ?? string.Empty;
		if (data.HelTouched)
		{
			item.m_customData["com.izzemi.myfirstmod.variant.hel"] = "1";
		}
		if (data.Modifiers == null)
		{
			return;
		}
		ModifierRoll[] modifiers = data.Modifiers;
		foreach (ModifierRoll modifierRoll in modifiers)
		{
			if (modifierRoll != null && !string.IsNullOrEmpty(modifierRoll.Id))
			{
				item.m_customData["com.izzemi.myfirstmod.variant.modifier." + modifierRoll.Id] = modifierRoll.Value.ToString("R", CultureInfo.InvariantCulture);
			}
		}
	}

	public static bool TryLoad(ItemData item, out ItemModifierData data)
	{
		if (item == null)
		{
			throw new ArgumentNullException("item");
		}
		data = null;
		if (item.m_customData == null)
		{
			return false;
		}
		if (item.m_customData.TryGetValue("com.izzemi.myfirstmod.variant", out var value))
		{
			data = JsonUtility.FromJson<ItemModifierData>(value);
		}
		if (data == null && !item.m_customData.ContainsKey("com.izzemi.myfirstmod.variant.version") && !item.m_customData.ContainsKey("com.izzemi.myfirstmod.variant.rarity"))
		{
			return false;
		}
		data = data ?? new ItemModifierData();
		if (item.m_customData.TryGetValue("com.izzemi.myfirstmod.variant.version", out var value2) && int.TryParse(value2, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
		{
			data.Version = result;
		}
		if (item.m_customData.TryGetValue("com.izzemi.myfirstmod.variant.rarity", out var value3))
		{
			data.RarityId = value3;
		}
		data.HelTouched = item.m_customData.ContainsKey("com.izzemi.myfirstmod.variant.hel");
		List<ModifierRoll> list = new List<ModifierRoll>();
		List<string> list2 = new List<string>();
		foreach (KeyValuePair<string, string> customDatum in item.m_customData)
		{
			if (customDatum.Key.StartsWith("com.izzemi.myfirstmod.variant.modifier.", StringComparison.Ordinal))
			{
				string text = customDatum.Key.Substring("com.izzemi.myfirstmod.variant.modifier.".Length);
				if (!ModifierCatalog.TryGetById(text, out var _))
				{
					list2.Add(customDatum.Key);
					continue;
				}
				if (float.TryParse(customDatum.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
				{
					list.Add(new ModifierRoll
					{
						Id = text,
						Value = result2
					});
					continue;
				}
				Logger.LogError((object)("Invalid saved value '" + customDatum.Value + "' for variant modifier '" + text + "'."));
				list2.Add(customDatum.Key);
			}
		}
		foreach (string item2 in list2)
		{
			item.m_customData.Remove(item2);
		}
		data.Modifiers = list.ToArray();
		return true;
	}
}
internal static class MagicWeaponInfo
{
	private static readonly Dictionary<string, bool> AoeCache = new Dictionary<string, bool>();

	public static bool FiresProjectile(ItemData item)
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Invalid comparison between Unknown and I4
		Attack val = item?.m_shared?.m_attack;
		return val != null && (int)val.m_attackType == 2 && (Object)(object)val.m_attackProjectile != (Object)null;
	}

	public static bool HasAoe(ItemData item)
	{
		if (item?.m_shared == null)
		{
			return false;
		}
		string name = item.m_shared.m_name;
		if (AoeCache.TryGetValue(name, out var value))
		{
			return value;
		}
		bool flag = AttackHasAoe(item.m_shared.m_attack) || AttackHasAoe(item.m_shared.m_secondaryAttack);
		AoeCache[name] = flag;
		return flag;
	}

	private static bool AttackHasAoe(Attack attack)
	{
		GameObject val = attack?.m_attackProjectile;
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		if ((Object)(object)val.GetComponentInChildren<Aoe>(true) != (Object)null)
		{
			return true;
		}
		Projectile[] componentsInChildren = val.GetComponentsInChildren<Projectile>(true);
		foreach (Projectile val2 in componentsInChildren)
		{
			if (val2.m_aoe > 0f || ((Object)(object)val2.m_spawnOnHit != (Object)null && (Object)(object)val2.m_spawnOnHit.GetComponentInChildren<Aoe>(true) != (Object)null))
			{
				return true;
			}
		}
		return false;
	}
}
internal static class StaffShieldSource
{
	private const string StaffPrefabName = "StaffShield";

	private static SE_Shield _shield;

	private static SkillType _skill = (SkillType)10;

	private static bool _resolved;

	public static bool TryGet(out SE_Shield shield, out SkillType skill)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Expected I4, but got Unknown
		if (!_resolved && (Object)(object)ObjectDB.instance != (Object)null)
		{
			_resolved = true;
			Resolve();
		}
		shield = _shield;
		skill = (SkillType)(int)_skill;
		return (Object)(object)_shield != (Object)null;
	}

	public static bool IsStaffOfProtection(ItemData item)
	{
		return (Object)(object)item?.m_dropPrefab != (Object)null && string.Equals(((Object)item.m_dropPrefab).name, "StaffShield", StringComparison.Ordinal);
	}

	private static void Resolve()
	{
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Invalid comparison between Unknown and I4
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("StaffShield");
		ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
		if ((Object)(object)val != (Object)null)
		{
			SharedData shared = val.m_itemData.m_shared;
			if ((int)shared.m_skillType > 0)
			{
				_skill = shared.m_skillType;
			}
			StatusEffect attackStatusEffect = shared.m_attackStatusEffect;
			_shield = (SE_Shield)(((object)((attackStatusEffect is SE_Shield) ? attackStatusEffect : null)) ?? ((object)/*isinst with value type is only supported in some contexts*/));
			if ((Object)(object)_shield == (Object)null)
			{
				GameObject val2 = shared.m_attack?.m_attackProjectile;
				_shield = (((Object)(object)val2 != (Object)null) ? FindInProjectile(val2) : null);
			}
		}
		if ((Object)(object)_shield == (Object)null)
		{
			foreach (StatusEffect statusEffect in ObjectDB.instance.m_StatusEffects)
			{
				SE_Shield val3 = (SE_Shield)(object)((statusEffect is SE_Shield) ? statusEffect : null);
				if (val3 != null && ((Object)val3).name.IndexOf("shield", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					_shield = val3;
					Logger.LogWarning((object)("Staff of Protection shield not found; using '" + ((Object)val3).name + "'."));
					break;
				}
			}
		}
		if ((Object)(object)_shield == (Object)null)
		{
			Logger.LogError((object)"No shield status effect found for the shield modifier.");
		}
	}

	private static SE_Shield FindInProjectile(GameObject projectile)
	{
		Aoe[] componentsInChildren = projectile.GetComponentsInChildren<Aoe>(true);
		foreach (Aoe val in componentsInChildren)
		{
			SE_Shield val2 = Lookup(val.m_statusEffect) ?? Lookup(val.m_statusEffectIfPlayer);
			if ((Object)(object)val2 != (Object)null)
			{
				return val2;
			}
		}
		Projectile[] componentsInChildren2 = projectile.GetComponentsInChildren<Projectile>(true);
		foreach (Projectile val3 in componentsInChildren2)
		{
			SE_Shield val4 = Lookup(val3.m_statusEffect);
			if ((Object)(object)val4 == (Object)null && (Object)(object)val3.m_spawnOnHit != (Object)null)
			{
				val4 = FindInProjectile(val3.m_spawnOnHit);
			}
			if ((Object)(object)val4 != (Object)null)
			{
				return val4;
			}
		}
		return null;
	}

	private static SE_Shield Lookup(string name)
	{
		return (SE_Shield)(string.IsNullOrEmpty(name) ? null : /*isinst with value type is only supported in some contexts*/);
	}
}
[HarmonyPatch(typeof(Humanoid), "StartAttack")]
internal static class ShieldOnUseModifierPatch
{
	private static void Postfix(Humanoid __instance, bool __result)
	{
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		if (__result && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
		{
			ItemData currentWeapon = __instance.GetCurrentWeapon();
			if (currentWeapon != null && ModifierCatalog.TryGetModifierValue(currentWeapon, ModifierEffectType.ShieldOnUse, out var _, out var value) && Random.value < value && StaffShieldSource.TryGet(out var shield, out var skill))
			{
				((Character)__instance).GetSEMan().AddStatusEffect((StatusEffect)(object)shield, true, currentWeapon.m_quality, ((Character)__instance).GetSkillLevel(skill), (short)(-1));
			}
		}
	}
}
[HarmonyPatch(typeof(Attack), "OnAttackTrigger")]
internal static class ShieldAllyHealModifierPatch
{
	private static void Postfix(Attack __instance, Humanoid ___m_character)
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)___m_character == (Object)null || (Object)(object)___m_character != (Object)(object)Player.m_localPlayer)
		{
			return;
		}
		ItemData weapon = __instance.GetWeapon();
		if (weapon == null || !StaffShieldSource.IsStaffOfProtection(weapon) || !ModifierCatalog.TryGetModifierValue(weapon, ModifierEffectType.ShieldAllyHeal, out var _, out var value))
		{
			return;
		}
		Vector3 position = ((Component)___m_character).transform.position;
		List<Player> list = new List<Player>();
		Player.GetPlayersInRange(position, 10f, list);
		foreach (Player item in list)
		{
			if ((Object)(object)item != (Object)(object)___m_character && !((Character)item).IsDead())
			{
				((Character)item).Heal(value, true);
			}
		}
		foreach (Character allCharacter in Character.GetAllCharacters())
		{
			if (!(allCharacter is Player) && allCharacter.IsTamed() && !allCharacter.IsDead() && Vector3.Distance(((Component)allCharacter).transform.position, position) <= 10f)
			{
				allCharacter.Heal(value, true);
			}
		}
	}
}
[HarmonyPatch(typeof(Humanoid), "StartAttack")]
internal static class SummonRootsModifierPatch
{
	private static ItemData _staff;

	private static bool _resolved;

	private static void Postfix(Humanoid __instance, bool __result)
	{
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		if (!__result || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
		{
			return;
		}
		ItemData currentWeapon = __instance.GetCurrentWeapon();
		if (currentWeapon == null || !ModifierCatalog.TryGetModifierValue(currentWeapon, ModifierEffectType.SummonRoots, out var _, out var value) || Random.value >= value)
		{
			return;
		}
		ItemData staff = GetStaff();
		Attack val = staff?.m_shared.m_attack;
		if (val != null && !((Object)(object)val.m_attackProjectile == (Object)null))
		{
			Vector3 aimDir = __instance.GetAimDir(((Character)__instance).GetEyePoint());
			Vector3 val2 = ((Character)__instance).GetEyePoint() + aimDir * 0.5f;
			GameObject val3 = Object.Instantiate<GameObject>(val.m_attackProjectile, val2, Quaternion.LookRotation(aimDir));
			IProjectile component = val3.GetComponent<IProjectile>();
			if (component != null)
			{
				component.Setup((Character)(object)__instance, aimDir * val.m_projectileVel, -1f, (HitData)null, staff, (ItemData)null);
			}
		}
	}

	private static ItemData GetStaff()
	{
		if (!_resolved && (Object)(object)ObjectDB.instance != (Object)null)
		{
			_resolved = true;
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("StaffGreenRoots");
			_staff = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null)?.m_itemData;
			if (_staff == null)
			{
				Logger.LogError((object)"StaffGreenRoots not found; the summon roots modifier does nothing.");
			}
		}
		return _staff;
	}
}
[HarmonyPatch(typeof(Aoe), "Setup")]
internal static class AoeRadiusModifierPatch
{
	private static void Postfix(Aoe __instance, ItemData item)
	{
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		if (item != null && ModifierCatalog.TryGetModifierValue(item, ModifierEffectType.AoeRadius, out var definition, out var value))
		{
			float num = definition.ApplyScalar(1f, value);
			if ((Object)(object)__instance.m_useCollider != (Object)null)
			{
				BoxCollider useCollider = __instance.m_useCollider;
				useCollider.size *= num;
				BoxCollider useCollider2 = __instance.m_useCollider;
				useCollider2.center *= num;
			}
			else
			{
				__instance.m_radius *= num;
			}
			Transform transform = ((Component)__instance).transform;
			transform.localScale *= num;
		}
	}
}
[HarmonyPatch(typeof(Projectile), "Setup")]
internal static class ProjectileAoeModifierPatch
{
	private static void Postfix(Projectile __instance, ItemData item)
	{
		if (item != null && __instance.m_aoe > 0f && ModifierCatalog.TryGetModifierValue(item, ModifierEffectType.AoeRadius, out var definition, out var value))
		{
			__instance.m_aoe *= definition.ApplyScalar(1f, value);
		}
	}
}
[HarmonyPatch(typeof(Player), "GetEquipmentEitrRegenModifier")]
internal static class HeldEitrRegenModifierPatch
{
	private static void Postfix(Player __instance, ref float __result)
	{
		AddHeld(((Humanoid)__instance).m_rightItem, ref __result);
		if (((Humanoid)__instance).m_leftItem != ((Humanoid)__instance).m_rightItem)
		{
			AddHeld(((Humanoid)__instance).m_leftItem, ref __result);
		}
	}

	private static void AddHeld(ItemData item, ref float result)
	{
		if (item != null && ModifierCatalog.TryGetModifierValue(item, ModifierEffectType.EitrRegen, out var _, out var value))
		{
			result += value;
		}
	}
}
[HarmonyPatch(typeof(Humanoid), "BlockAttack")]
internal static class ParryRewardModifierPatch
{
	private static void Postfix(Humanoid __instance, HitData hit, Character attacker, bool __result)
	{
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_0127: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Expected O, but got Unknown
		if (!__result || (Object)(object)attacker == (Object)null)
		{
			return;
		}
		ItemData currentBlocker = __instance.GetCurrentBlocker();
		if (currentBlocker != null && !(currentBlocker.m_shared.m_timedBlockBonus <= 1f) && __instance.m_blockTimer != -1f && !(__instance.m_blockTimer >= 0.25f))
		{
			if (ModifierCatalog.TryGetModifierValue(currentBlocker, ModifierEffectType.ParryHealth, out var definition, out var value) && value > 0f)
			{
				((Character)__instance).Heal(value, true);
			}
			if (ModifierCatalog.TryGetModifierValue(currentBlocker, ModifierEffectType.ParryStamina, out definition, out var value2) && value2 > 0f)
			{
				((Character)__instance).AddStamina(value2);
			}
			if (!hit.m_ranged && ModifierCatalog.TryGetModifierValue(currentBlocker, ModifierEffectType.ParryDamage, out definition, out var value3) && value3 > 0f)
			{
				float blunt = currentBlocker.GetBlockPower(((Character)__instance).GetSkillFactor((SkillType)6)) * value3;
				HitData val = new HitData
				{
					m_point = attacker.GetCenterPoint()
				};
				Vector3 val2 = ((Component)attacker).transform.position - ((Component)__instance).transform.position;
				val.m_dir = ((Vector3)(ref val2)).normalized;
				val.m_hitType = (HitType)((!((Character)__instance).IsPlayer()) ? 1 : 2);
				HitData val3 = val;
				val3.m_damage.m_blunt = blunt;
				val3.SetAttacker((Character)(object)__instance);
				attacker.Damage(val3);
			}
		}
	}
}
[HarmonyPatch(typeof(Projectile), "Setup")]
internal static class ProjectileSpeedModifierPatch
{
	private static void Prefix(ref Vector3 velocity, ItemData item)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		if (item != null && ModifierCatalog.TryGetModifierValue(item, ModifierEffectType.ProjectileSpeed, out var definition, out var value))
		{
			velocity = definition.ApplyScalar(1f, value) * velocity;
		}
	}
}
[HarmonyPatch(typeof(Attack), "UseAmmo")]
internal static class AmmoSaveModifierPatch
{
	private static bool Prefix(Attack __instance, ref ItemData ammoItem, ref ItemData ___m_ammoItem, Humanoid ___m_character, ref bool __result)
	{
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Invalid comparison between Unknown and I4
		ItemData weapon = __instance.m_weapon;
		if (weapon == null || string.IsNullOrWhiteSpace(weapon.m_shared.m_ammoType) || !ModifierCatalog.TryGetModifierValue(weapon, ModifierEffectType.AmmoSaveChance, out var _, out var value) || Random.value >= value)
		{
			return true;
		}
		Inventory inventory = ___m_character.GetInventory();
		ItemData val = ___m_character.GetAmmoItem();
		if (val != null && (!inventory.ContainsItem(val) || val.m_shared.m_ammoType != weapon.m_shared.m_ammoType))
		{
			val = null;
		}
		if (val == null)
		{
			val = inventory.GetAmmoItem(weapon.m_shared.m_ammoType, (string)null);
		}
		if (val == null || (int)val.m_shared.m_itemType == 2)
		{
			return true;
		}
		ammoItem = val;
		___m_ammoItem = val;
		__result = true;
		return false;
	}
}
[HarmonyPatch(typeof(Attack), "FireProjectileBurst")]
internal static class ExtraProjectileModifierPatch
{
	private const float SideAngle = 10f;

	private static readonly float[] ExtraAngles = new float[2] { -10f, 10f };

	private static readonly FieldRef<Attack, bool> PerBurstUsage = AccessTools.FieldRefAccess<Attack, bool>("m_perBurstResourceUsage");

	private static readonly Action<Attack> FireBurst = (Action<Attack>)Delegate.CreateDelegate(typeof(Action<Attack>), AccessTools.Method(typeof(Attack), "FireProjectileBurst", (Type[])null, (Type[])null));

	internal static bool Firing;

	internal static float AngleOffset;

	private static void Postfix(Attack __instance)
	{
		ItemData weapon = __instance.m_weapon;
		if (Firing || weapon == null || PerBurstUsage.Invoke(__instance) || (!ModifierCatalog.TryGetModifierValue(weapon, ModifierEffectType.ExtraProjectileChance, out var definition, out var value) && !ModifierCatalog.TryGetModifierValue(weapon, ModifierEffectType.MagicExtraProjectile, out definition, out value)) || Random.value >= value)
		{
			return;
		}
		Firing = true;
		try
		{
			float[] extraAngles = ExtraAngles;
			foreach (float angleOffset in extraAngles)
			{
				AngleOffset = angleOffset;
				FireBurst(__instance);
			}
		}
		finally
		{
			AngleOffset = 0f;
			Firing = false;
		}
	}
}
[HarmonyPatch(typeof(Attack), "GetProjectileSpawnPoint")]
internal static class ExtraProjectileAimPatch
{
	private static void Postfix(ref Vector3 aimDir)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		if (ExtraProjectileModifierPatch.AngleOffset != 0f)
		{
			aimDir = Quaternion.AngleAxis(ExtraProjectileModifierPatch.AngleOffset, Vector3.up) * aimDir;
		}
	}
}
[HarmonyPatch(typeof(Attack), "GetAttackStamina")]
internal static class WeaponStaminaModifierPatch
{
	private static void Postfix(Attack __instance, ref float __result)
	{
		ItemData weapon = __instance.m_weapon;
		if (weapon != null && ModifierCatalog.TryGetModifierValue(weapon, ModifierEffectType.AttackStaminaCost, out var definition, out var value))
		{
			__result = definition.ApplyScalar(__result, value);
		}
	}
}
[HarmonyPatch(typeof(Attack), "GetAttackEitr", new Type[]
{
	typeof(Character),
	typeof(ItemData)
})]
internal static class WeaponEitrModifierPatch
{
	private static void Postfix(ItemData weapon, ref float __result)
	{
		if (weapon != null && ModifierCatalog.TryGetModifierValue(weapon, ModifierEffectType.AttackEitrCost, out var definition, out var value))
		{
			__result = Math.Max(0f, definition.ApplyScalar(__result, value));
		}
	}
}
[HarmonyPatch(typeof(ItemData), "GetDrawStaminaDrain")]
internal static class BowDrawStaminaModifierPatch
{
	private static void Postfix(ItemData __instance, ref float __result)
	{
		if (ModifierCatalog.TryGetModifierValue(__instance, ModifierEffectType.BowDrawStaminaCost, out var definition, out var value))
		{
			__result = Math.Max(0f, definition.ApplyScalar(__result, value));
		}
	}
}
[HarmonyPatch(typeof(ItemData), "GetWeaponLoadingTime")]
internal static class CrossbowReloadModifierPatch
{
	private static void Postfix(ItemData __instance, ref float __result)
	{
		if (ModifierCatalog.TryGetModifierValue(__instance, ModifierEffectType.ReloadTime, out var definition, out var value))
		{
			__result = Math.Max(0f, definition.ApplyScalar(__result, value));
		}
	}
}
[HarmonyPatch(typeof(Player), "GetEquipmentMovementModifier")]
internal static class MovementPenaltyModifierPatch
{
	private static void Postfix(Player __instance, ref float __result)
	{
		List<ItemData> list = new List<ItemData>();
		AddEquippedItem(list, ((Humanoid)__instance).GetCurrentWeapon());
		AddEquippedItem(list, ((Humanoid)__instance).m_leftItem);
		AddEquippedItem(list, ((Humanoid)__instance).m_rightItem);
		AddEquippedItem(list, ((Humanoid)__instance).m_helmetItem);
		AddEquippedItem(list, ((Humanoid)__instance).m_chestItem);
		AddEquippedItem(list, ((Humanoid)__instance).m_legItem);
		AddEquippedItem(list, ((Humanoid)__instance).m_shoulderItem);
		foreach (ItemData item in list)
		{
			if (item.m_shared.m_movementModifier < 0f && ModifierCatalog.TryGetModifierValue(item, ModifierEffectType.MovementPenalty, out var definition, out var value))
			{
				__result += Math.Min(value, 0f - item.m_shared.m_movementModifier);
			}
			if (ModifierCatalog.TryGetModifierValue(item, ModifierEffectType.MovementSpeedBonus, out definition, out var value2))
			{
				__result += value2;
			}
		}
	}

	private static void AddEquippedItem(List<ItemData> items, ItemData item)
	{
		if (item == null)
		{
			return;
		}
		foreach (ItemData item2 in items)
		{
			if (item2 == item)
			{
				return;
			}
		}
		items.Add(item);
	}
}
[HarmonyPatch(typeof(ItemData), "GetBaseBlockPower", new Type[] { typeof(int) })]
internal static class BlockArmourModifierPatch
{
	private static void Postfix(ItemData __instance, ref float __result)
	{
		if (ModifierCatalog.TryGetModifierValue(__instance, ModifierEffectType.BlockPower, out var definition, out var value))
		{
			__result = definition.ApplyScalar(__result, value);
		}
	}
}
[HarmonyPatch(typeof(ItemData), "GetArmor", new Type[]
{
	typeof(int),
	typeof(float)
})]
internal static class ArmourModifierPatch
{
	private static void Postfix(ItemData __instance, ref float __result)
	{
		if (ModifierCatalog.TryGetModifierValue(__instance, ModifierEffectType.ArmourFlat, out var definition, out var value))
		{
			__result = definition.ApplyScalar(__result, value);
		}
		if (ModifierCatalog.TryGetModifierValue(__instance, ModifierEffectType.ArmourPercentage, out var definition2, out var value2))
		{
			__result = (float)Math.Ceiling(definition2.ApplyScalar(__result, value2));
		}
	}
}
[HarmonyPatch(typeof(Humanoid), "BlockAttack")]
internal static class ParryBonusModifierPatch
{
	private struct State
	{
		public ItemData Item;

		public float OriginalTimedBlockBonus;

		public float OriginalBlockAdrenaline;

		public float OriginalPerfectBlockAdrenaline;

		public float OriginalBlockStaminaDrain;

		public float OriginalPerfectBlockStaminaDrain;

		public bool ModifiedTimedBlockBonus;

		public bool ModifiedAdrenaline;

		public bool ModifiedStamina;
	}

	private static void Prefix(Humanoid __instance, out State __state)
	{
		__state = default(State);
		ItemData currentBlocker = __instance.GetCurrentBlocker();
		if (currentBlocker != null)
		{
			if (ModifierCatalog.TryGetModifierValue(currentBlocker, ModifierEffectType.ParryBonus, out var definition, out var value))
			{
				__state.Item = currentBlocker;
				__state.OriginalTimedBlockBonus = currentBlocker.m_shared.m_timedBlockBonus;
				SharedData shared = currentBlocker.m_shared;
				shared.m_timedBlockBonus += value;
				__state.ModifiedTimedBlockBonus = true;
			}
			if (__instance.m_blockTimer != -1f && __instance.m_blockTimer < 0.25f && currentBlocker.m_shared.m_timedBlockBonus > 1f && ModifierCatalog.TryGetModifierValue(currentBlocker, ModifierEffectType.ParryAdrenaline, out definition, out var value2))
			{
				__state.Item = currentBlocker;
				__state.OriginalBlockAdrenaline = currentBlocker.m_shared.m_blockAdrenaline;
				__state.OriginalPerfectBlockAdrenaline = currentBlocker.m_shared.m_perfectBlockAdrenaline;
				SharedData shared2 = currentBlocker.m_shared;
				shared2.m_blockAdrenaline += value2;
				SharedData shared3 = currentBlocker.m_shared;
				shared3.m_perfectBlockAdrenaline += value2;
				__state.ModifiedAdrenaline = true;
			}
			if (ModifierCatalog.TryGetModifierValue(currentBlocker, ModifierEffectType.BlockStaminaCost, out var definition2, out var value3))
			{
				__state.OriginalBlockStaminaDrain = __instance.m_blockStaminaDrain;
				__state.OriginalPerfectBlockStaminaDrain = __instance.m_perfectBlockStaminaDrain;
				__instance.m_blockStaminaDrain = definition2.ApplyScalar(__instance.m_blockStaminaDrain, value3);
				__instance.m_perfectBlockStaminaDrain = definition2.ApplyScalar(__instance.m_perfectBlockStaminaDrain, value3);
				__state.ModifiedStamina = true;
			}
		}
	}

	private static Exception Finalizer(Humanoid __instance, State __state, Exception __exception)
	{
		if (__state.ModifiedTimedBlockBonus)
		{
			__state.Item.m_shared.m_timedBlockBonus = __state.OriginalTimedBlockBonus;
		}
		if (__state.ModifiedAdrenaline)
		{
			__state.Item.m_shared.m_blockAdrenaline = __state.OriginalBlockAdrenaline;
			__state.Item.m_shared.m_perfectBlockAdrenaline = __state.OriginalPerfectBlockAdrenaline;
		}
		if (__state.ModifiedStamina)
		{
			__instance.m_blockStaminaDrain = __state.OriginalBlockStaminaDrain;
			__instance.m_perfectBlockStaminaDrain = __state.OriginalPerfectBlockStaminaDrain;
		}
		return __exception;
	}
}
[HarmonyPatch(typeof(Character), "ApplyDamage", new Type[]
{
	typeof(HitData),
	typeof(bool),
	typeof(bool),
	typeof(DamageModifier)
})]
internal static class ArmourElementalResistancePatch
{
	private static void Prefix(Character __instance, HitData hit)
	{
		Player val = (Player)(object)((__instance is Player) ? __instance : null);
		if (val != null && hit != null)
		{
			ItemData[] armour = (ItemData[])(object)new ItemData[4]
			{
				((Humanoid)val).m_helmetItem,
				((Humanoid)val).m_chestItem,
				((Humanoid)val).m_legItem,
				((Humanoid)val).m_shoulderItem
			};
			hit.m_damage.m_fire *= 1f - GetResistance(armour, ModifierEffectType.FireResistance);
			hit.m_damage.m_frost *= 1f - GetResistance(armour, ModifierEffectType.FrostResistance);
			hit.m_damage.m_lightning *= 1f - GetResistance(armour, ModifierEffectType.LightningResistance);
			hit.m_damage.m_poison *= 1f - GetResistance(armour, ModifierEffectType.PoisonResistance);
		}
	}

	private static float GetResistance(ItemData[] armour, ModifierEffectType effectType)
	{
		float num = 0f;
		foreach (ItemData item in armour)
		{
			if (ModifierCatalog.TryGetModifierValue(item, effectType, out var _, out var value))
			{
				num = Math.Max(num, value);
			}
		}
		return Math.Max(0f, Math.Min(1f, num));
	}
}
[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
internal static class MeleeWeaponModifierPatch
{
	private struct State
	{
		public ItemData Weapon;

		public float OriginalBackstabBonus;
	}

	private static void Prefix(Attack __instance, out State __state)
	{
		__state = default(State);
		ItemData weapon = __instance.m_weapon;
		if (weapon != null && ModifierCatalog.TryGetModifierValue(weapon, ModifierEffectType.BackstabBonus, out var _, out var value))
		{
			__state.Weapon = weapon;
			__state.OriginalBackstabBonus = weapon.m_shared.m_backstabBonus;
			SharedData shared = weapon.m_shared;
			shared.m_backstabBonus += value;
		}
	}

	private static Exception Finalizer(State __state, Exception __exception)
	{
		if (__state.Weapon != null)
		{
			__state.Weapon.m_shared.m_backstabBonus = __state.OriginalBackstabBonus;
		}
		return __exception;
	}

	private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
	{
		MethodInfo addAdrenaline = AccessTools.Method(typeof(Character), "AddAdrenaline", new Type[1] { typeof(float) }, (Type[])null);
		MethodInfo addHitAdrenaline = AccessTools.Method(typeof(MeleeWeaponModifierPatch), "AddHitAdrenaline", (Type[])null, (Type[])null);
		bool patched = false;
		foreach (CodeInstruction instruction in instructions)
		{
			if (!patched && (instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt) && object.Equals(instruction.operand, addAdrenaline))
			{
				yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
				yield return new CodeInstruction(OpCodes.Call, (object)addHitAdrenaline);
				patched = true;
			}
			else
			{
				yield return instruction;
			}
		}
		if (!patched)
		{
			throw new InvalidOperationException("Could not find the melee hit adrenaline call to apply weapon modifiers.");
		}
	}

	private static void AddHitAdrenaline(Character character, float amount, Attack attack)
	{
		ItemData weapon = attack.m_weapon;
		if (weapon != null && ModifierCatalog.TryGetModifierValue(weapon, ModifierEffectType.AdrenalineGain, out var _, out var value))
		{
			amount += value;
		}
		character.AddAdrenaline(amount);
	}
}
[HarmonyPatch(typeof(Projectile), "OnHit", new Type[]
{
	typeof(Collider),
	typeof(Vector3),
	typeof(bool),
	typeof(Vector3)
})]
internal static class ProjectileWeaponModifierPatch
{
	private struct State
	{
		public float OriginalBackstabBonus;

		public float OriginalAdrenaline;

		public bool ModifiedBackstabBonus;

		public bool ModifiedAdrenaline;
	}

	private static void Prefix(Projectile __instance, out State __state)
	{
		__state = default(State);
		ItemData weapon = __instance.m_weapon;
		if (weapon != null)
		{
			if (ModifierCatalog.TryGetModifierValue(weapon, ModifierEffectType.BackstabBonus, out var definition, out var value))
			{
				__state.OriginalBackstabBonus = __instance.m_backstabBonus;
				__instance.m_backstabBonus += value;
				__state.ModifiedBackstabBonus = true;
			}
			if (ModifierCatalog.TryGetModifierValue(weapon, ModifierEffectType.AdrenalineGain, out definition, out var value2))
			{
				__state.OriginalAdrenaline = __instance.m_adrenaline;
				__instance.m_adrenaline += value2;
				__state.ModifiedAdrenaline = true;
			}
		}
	}

	private static Exception Finalizer(Projectile __instance, State __state, Exception __exception)
	{
		if (__state.ModifiedBackstabBonus)
		{
			__instance.m_backstabBonus = __state.OriginalBackstabBonus;
		}
		if (__state.ModifiedAdrenaline)
		{
			__instance.m_adrenaline = __state.OriginalAdrenaline;
		}
		return __exception;
	}
}
internal static class SummonWeaponInfo
{
	public static bool HasSummonAbility(ItemData item)
	{
		return HasSummonAbility(item?.m_shared?.m_attack) || HasSummonAbility(item?.m_shared?.m_secondaryAttack) || IsKnownSummonWeapon(item);
	}

	private static bool IsKnownSummonWeapon(ItemData item)
	{
		string text = (((Object)(object)item?.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : string.Empty);
		string text2 = item?.m_shared?.m_name ?? string.Empty;
		return text.IndexOf("StaffSkeleton", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("staffskeleton", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("dead raiser", StringComparison.OrdinalIgnoreCase) >= 0;
	}

	private static bool HasSummonAbility(Attack attack)
	{
		return GetSpawnAbilities(attack).Length != 0;
	}

	internal static SpawnAbility[] GetSpawnAbilities(Attack attack)
	{
		GameObject val = attack?.m_attackProjectile;
		if ((Object)(object)val == (Object)null)
		{
			return Array.Empty<SpawnAbility>();
		}
		List<SpawnAbility> list = new List<SpawnAbility>(val.GetComponentsInChildren<SpawnAbility>(true));
		Projectile[] componentsInChildren = val.GetComponentsInChildren<Projectile>(true);
		foreach (Projectile val2 in componentsInChildren)
		{
			if ((Object)(object)val2.m_spawnOnHit != (Object)null)
			{
				list.AddRange(val2.m_spawnOnHit.GetComponentsInChildren<SpawnAbility>(true));
			}
		}
		return list.ToArray();
	}
}
[HarmonyPatch(typeof(SpawnAbility), "Setup")]
internal static class SummonModifierSetupPatch
{
	private static void Prefix(SpawnAbility __instance, ItemData item)
	{
		if (item == null)
		{
			return;
		}
		if (ModifierCatalog.TryGetModifierValue(item, ModifierEffectType.SummonMaxCount, out var definition, out var value))
		{
			int num = Mathf.RoundToInt(value);
			if (__instance.m_maxSpawned > 0)
			{
				__instance.m_maxSpawned += num;
			}
			bool setMaxInstancesFromWeaponLevel = __instance.m_setMaxInstancesFromWeaponLevel;
			__instance.m_setMaxInstancesFromWeaponLevel = false;
			if (__instance.m_levelUpSettings != null)
			{
				foreach (LevelUpSettings levelUpSetting in __instance.m_levelUpSettings)
				{
					int num2 = (setMaxInstancesFromWeaponLevel ? item.m_quality : levelUpSetting.m_maxSpawns);
					levelUpSetting.m_maxSpawns = num2 + num;
				}
			}
		}
		if (ModifierCatalog.TryGetModifierValue(item, ModifierEffectType.ExtraSummonChance, out definition, out var value2) && Random.value < value2)
		{
			__instance.m_minToSpawn++;
			__instance.m_maxToSpawn++;
		}
		if (__instance.m_levelUpSettings == null || !ModifierCatalog.TryGetModifierValue(item, ModifierEffectType.ExtraSummonStars, out definition, out var value3) || !(Random.value < value3))
		{
			return;
		}
		int num3 = Random.Range(1, 3);
		foreach (LevelUpSettings levelUpSetting2 in __instance.m_levelUpSettings)
		{
			levelUpSetting2.m_setLevel = Mathf.Min(3, levelUpSetting2.m_setLevel + num3);
		}
	}
}
[HarmonyPatch(typeof(InventoryGrid), "CreateItemTooltip")]
internal static class ItemModifierTooltipPatch
{
	private static bool Prefix(InventoryGrid __instance, ItemData item, UITooltip tooltip)
	{
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0305: Unknown result type (might be due to invalid IL or missing references)
		//IL_030b: Unknown result type (might be due to invalid IL or missing references)
		string text = RuneEffects.DescribeValheimRune(item);
		if (text != null)
		{
			tooltip.Set(Localization.instance.Localize(item.m_shared.m_name), item.GetTooltip(-1).TrimEnd(Array.Empty<char>()) + "\n\n" + text, __instance.m_tooltipAnchor, default(Vector2));
			return false;
		}
		if (item == null || !ItemModifierDataStore.TryLoad(item, out var data))
		{
			return true;
		}
		string text2 = Localization.instance.Localize(item.m_shared.m_name);
		if (ItemRarityCatalog.TryGet(data.RarityId, out var definition))
		{
			text2 = text2 + " <color=" + definition.TooltipColor + ">(" + definition.DisplayName + ")</color>";
		}
		List<string> list = new List<string>();
		if (data.Modifiers != null)
		{
			int num = definition?.MaxModifiers ?? int.MaxValue;
			int num2 = -1;
			ModifierRoll[] modifiers = data.Modifiers;
			foreach (ModifierRoll modifierRoll in modifiers)
			{
				num2++;
				if (modifierRoll == null || string.IsNullOrWhiteSpace(modifierRoll.Id))
				{
					continue;
				}
				if (ModifierCatalog.TryGetById(modifierRoll.Id, out var definition2))
				{
					string text3 = definition2.FormatTooltipLine(modifierRoll.Value, num2 >= num);
					if (definition2.EffectType == ModifierEffectType.ParryBonus)
					{
						float value = item.m_shared.m_timedBlockBonus + modifierRoll.Value;
						text3 = text3 + " (total: " + FormatMultiplier(value) + ")";
					}
					else if (definition2.EffectType == ModifierEffectType.BackstabBonus)
					{
						float value2 = item.m_shared.m_backstabBonus + modifierRoll.Value;
						text3 = text3 + " (total: " + FormatMultiplier(value2) + ")";
					}
					list.Add(text3);
				}
				else
				{
					string text4 = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(modifierRoll.Id.Replace('_', ' ').ToLowerInvariant());
					string text5 = modifierRoll.Value.ToString("+0.##;-0.##;0", CultureInfo.InvariantCulture);
					list.Add("<color=#ADD8E6>" + text4 + ":</color> <color=green>" + text5 + "</color>");
				}
			}
		}
		string text6 = item.GetTooltip(-1);
		if (data.HelTouched)
		{
			list.Add("<color=#9B30FF>Touched by Hel</color>");
		}
		if (list.Count > 0)
		{
			text6 = text6.TrimEnd(Array.Empty<char>()) + "\n\n" + string.Join("\n", list);
		}
		tooltip.Set(text2, text6, __instance.m_tooltipAnchor, default(Vector2));
		return false;
	}

	private static string FormatMultiplier(float value)
	{
		return value.ToString("0.##", CultureInfo.InvariantCulture) + "x";
	}
}
[HarmonyPatch(typeof(InventoryGui), "DoCrafting", new Type[] { typeof(Player) })]
internal static class ItemModifierUpgradePatch
{
	private struct State
	{
		public bool Active;

		public Player Player;

		public ItemData SourceItem;

		public ItemModifierData ModifierData;

		public List<ItemData> ExistingItems;

		public string SharedName;

		public int Quality;

		public int Variant;
	}

	private static void Prefix(InventoryGui __instance, Player player, out State __state)
	{
		__state = default(State);
		ItemData craftUpgradeItem = __instance.m_craftUpgradeItem;
		if (craftUpgradeItem != null && !((Object)(object)player == (Object)null) && ItemModifierDataStore.TryLoad(craftUpgradeItem, out var data))
		{
			__state.Active = true;
			__state.Player = player;
			__state.SourceItem = craftUpgradeItem;
			__state.ModifierData = Clone(data);
			__state.ExistingItems = new List<ItemData>(((Humanoid)player).GetInventory().GetAllItems());
			__state.SharedName = craftUpgradeItem.m_shared.m_name;
			__state.Quality = craftUpgradeItem.m_quality;
			__state.Variant = craftUpgradeItem.m_variant;
		}
	}

	private static void Postfix(State __state)
	{
		if (!__state.Active || ContainsReference(((Humanoid)__state.Player).GetInventory().GetAllItems(), __state.SourceItem))
		{
			return;
		}
		foreach (ItemData allItem in ((Humanoid)__state.Player).GetInventory().GetAllItems())
		{
			if (!ContainsReference(__state.ExistingItems, allItem) && allItem.m_shared.m_name == __state.SharedName && allItem.m_quality != __state.Quality && allItem.m_variant == __state.Variant)
			{
				ItemModifierDataStore.Save(allItem, __state.ModifierData);
				break;
			}
		}
	}

	private static bool ContainsReference(List<ItemData> items, ItemData target)
	{
		foreach (ItemData item in items)
		{
			if (item == target)
			{
				return true;
			}
		}
		return false;
	}

	private static ItemModifierData Clone(ItemModifierData data)
	{
		List<ModifierRoll> list = new List<ModifierRoll>();
		if (data.Modifiers != null)
		{
			ModifierRoll[] modifiers = data.Modifiers;
			foreach (ModifierRoll modifierRoll in modifiers)
			{
				if (modifierRoll != null)
				{
					list.Add(new ModifierRoll
					{
						Id = modifierRoll.Id,
						Value = modifierRoll.Value
					});
				}
			}
		}
		return new ItemModifierData
		{
			Version = data.Version,
			RarityId = data.RarityId,
			HelTouched = data.HelTouched,
			Modifiers = list.ToArray()
		};
	}
}
internal sealed class ItemRarityDefinition
{
	public string Id { get; }

	public string DisplayName { get; }

	public string TooltipColor { get; }

	public Color GlowColor { get; }

	public int Rank { get; }

	public int MaxModifiers { get; }

	public ItemRarityDefinition(string id, string displayName, string tooltipColor, Color glowColor, int rank, int maxModifiers)
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		Id = id;
		DisplayName = displayName;
		TooltipColor = tooltipColor;
		GlowColor = glowColor;
		Rank = rank;
		MaxModifiers = maxModifiers;
	}
}
internal static class ItemRarityCatalog
{
	private static readonly ItemRarityDefinition[] Definitions = new ItemRarityDefinition[3]
	{
		new ItemRarityDefinition("magic", "Magic", "green", new Color(0.2f, 1f, 0.35f), 1, 1),
		new ItemRarityDefinition("rare", "Rare", "blue", new Color(0.25f, 0.55f, 1f), 2, 2),
		new ItemRarityDefinition("epic", "Epic", "purple", new Color(0.75f, 0.3f, 1f), 3, 4)
	};

	public static IReadOnlyList<ItemRarityDefinition> All => Definitions;

	public static List<string> GetCommandOptions()
	{
		List<string> list = new List<string>(Definitions.Length + 1) { "0" };
		ItemRarityDefinition[] definitions = Definitions;
		foreach (ItemRarityDefinition itemRarityDefinition in definitions)
		{
			list.Add(itemRarityDefinition.Id);
		}
		return list;
	}

	public static bool TryGet(string id, out ItemRarityDefinition definition)
	{
		ItemRarityDefinition[] definitions = Definitions;
		foreach (ItemRarityDefinition itemRarityDefinition in definitions)
		{
			if (string.Equals(itemRarityDefinition.Id, id, StringComparison.OrdinalIgnoreCase))
			{
				definition = itemRarityDefinition;
				return true;
			}
		}
		definition = null;
		return false;
	}
}
[HarmonyPatch(typeof(ItemDrop), "Start")]
internal static class WorldDropRarityGlowPatch
{
	private static void Postfix(ItemDrop __instance)
	{
		ItemRarityVisuals.SetWorldDropGlow(__instance);
	}
}
[HarmonyPatch(typeof(InventoryGrid), "UpdateInventory", new Type[]
{
	typeof(Inventory),
	typeof(Player),
	typeof(ItemData)
})]
internal static class InventoryIconRarityGlowPatch
{
	private static void Postfix(InventoryGrid __instance, Inventory ___m_inventory, List<InventoryElement> ___m_elements)
	{
		ItemRarityVisuals.ApplyInventoryIconRarity(__instance, ___m_inventory, ___m_elements);
	}
}
[HarmonyPatch(typeof(Humanoid), "EquipItem")]
internal static class EquipRarityGlowPatch
{
	private static void Postfix(Humanoid __instance)
	{
		ItemRarityVisuals.RefreshEquippedGlow(__instance);
	}
}
[HarmonyPatch(typeof(Humanoid), "UnequipItem")]
internal static class UnequipRarityGlowPatch
{
	private static void Postfix(Humanoid __instance)
	{
		ItemRarityVisuals.RefreshEquippedGlow(__instance);
	}
}
internal static class ItemRarityVisuals
{
	private const string GlowObjectName = "RunecarvedRarityGlow";

	private const float DropGlowRange = 4.5f;

	private const float DropGlowIntensity = 1.5f;

	private const float EquippedGlowRange = 4f;

	private const float EquippedGlowIntensity = 0.9f;

	public static bool TryGetRarity(ItemData item, out ItemRarityDefinition rarity)
	{
		rarity = null;
		string rarityId;
		return ItemModifierDataStore.TryGetRarityId(item, out rarityId) && ItemRarityCatalog.TryGet(rarityId, out rarity);
	}

	public static void SetWorldDropGlow(ItemDrop itemDrop)
	{
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)itemDrop == (Object)null))
		{
			if (TryGetRarity(itemDrop.m_itemData, out var rarity))
			{
				SetGlow(((Component)itemDrop).transform, rarity.GlowColor, new Vector3(0f, 0.25f, 0f), 4.5f, 1.5f);
			}
			else
			{
				SetGlow(((Component)itemDrop).transform, null, Vector3.zero, 0f, 0f);
			}
		}
	}

	public static void RefreshEquippedGlow(Humanoid humanoid)
	{
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)humanoid == (Object)null)
		{
			return;
		}
		ItemRarityDefinition itemRarityDefinition = null;
		Inventory inventory = humanoid.GetInventory();
		if (inventory != null)
		{
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (allItem.m_equipped && TryGetRarity(allItem, out var rarity) && (itemRarityDefinition == null || rarity.Rank > itemRarityDefinition.Rank))
				{
					itemRarityDefinition = rarity;
				}
			}
		}
		SetGlow(((Component)humanoid).transform, itemRarityDefinition?.GlowColor, new Vector3(0f, 1f, 0f), 4f, 0.9f);
	}

	public static void ApplyInventoryIconRarity(InventoryGrid grid, Inventory inventory, List<InventoryElement> elements)
	{
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)grid == (Object)null || inventory == null || elements == null)
		{
			return;
		}
		foreach (InventoryElement element in elements)
		{
			Outline component = ((Component)element.m_icon).GetComponent<Outline>();
			if ((Object)(object)component != (Object)null)
			{
				((Behaviour)component).enabled = false;
			}
		}
		int width = inventory.GetWidth();
		foreach (ItemData allItem in inventory.GetAllItems())
		{
			if (!TryGetRarity(allItem, out var rarity))
			{
				continue;
			}
			int num = allItem.m_gridPos.y * width + allItem.m_gridPos.x;
			if (num >= 0 && num < elements.Count)
			{
				Image icon = elements[num].m_icon;
				Outline val = ((Component)icon).GetComponent<Outline>();
				if ((Object)(object)val == (Object)null)
				{
					val = ((Component)icon).gameObject.AddComponent<Outline>();
				}
				Color glowColor = rarity.GlowColor;
				glowColor.a = 1f;
				((Shadow)val).effectColor = glowColor;
				((Shadow)val).effectDistance = new Vector2(3f, 3f);
				((Shadow)val).useGraphicAlpha = true;
				((Behaviour)val).enabled = true;
			}
		}
	}

	private static void SetGlow(Transform owner, Color? color, Vector3 localPosition, float range, float intensity)
	{
		//IL_0083: 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_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Expected O, but got Unknown
		Transform val = owner.Find("RunecarvedRarityGlow");
		if (!color.HasValue)
		{
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(false);
			}
			return;
		}
		if ((Object)(object)val == (Object)null)
		{
			GameObject val2 = new GameObject("RunecarvedRarityGlow");
			val = val2.transform;
			val.SetParent(owner, false);
			Light val3 = val2.AddComponent<Light>();
			val3.type = (LightType)2;
			val3.shadows = (LightShadows)0;
		}
		val.localPosition = localPosition;
		((Component)val).gameObject.SetActive(true);
		Light component = ((Component)val).GetComponent<Light>();
		component.color = color.Value;
		component.range = range;
		component.intensity = intensity;
	}
}
internal static class ModCommands
{
	private sealed class SetRarityCommand : ConsoleCommand
	{
		public override string Name => "set_rarity";

		public override bool IsCheat => true;

		public override string Help => "Sets rarity on an equipped item. Usage: set_rarity <rarity> [slot] (use 0 to clear rarity and modifiers).";

		public override List<string> CommandOptionList()
		{
			return ItemRarityCatalog.GetCommandOptions();
		}

		public override void Run(string[] args)
		{
			if (args.Length < 1 || string.IsNullOrWhiteSpace(args[0]))
			{
				Console.instance.Print(((ConsoleCommand)this).Help);
				return;
			}
			if (args.Length > 2)
			{
				Console.instance.Print(((ConsoleCommand)this).Help);
				return;
			}
			string text = args[0].Trim().ToLowerInvariant();
			ItemRarityDefinition definition = null;
			if (text != "0" && !ItemRarityCatalog.TryGet(text, out definition))
			{
				Console.instance.Print("Invalid rarity '" + args[0] + "'. Valid rarities are magic, rare, and epic; use 0 to remove rarity and modifiers.");
			}
			else
			{
				if (!TryGetEquippedItem(args, 1, out var item))
				{
					return;
				}
				if (text == "0")
				{
					ItemModifierDataStore.Clear(item);
					ItemRarityVisuals.RefreshEquippedGlow((Humanoid)(object)Player.m_localPlayer);
					Console.instance.Print("Cleared rarity and modifiers from the equipped item.");
					return;
				}
				if (!ItemModifierDataStore.TryLoad(item, out var data))
				{
					data = new ItemModifierData();
				}
				int modifierCount = GetModifierCount(data.Modifiers);
				if (modifierCount > definition.MaxModifiers)
				{
					Console.instance.Print($"Cannot set rarity to '{text}': the item has {modifierCount} modifiers, but {definition.DisplayName} allows at most {definition.MaxModifiers}. Remove modifiers first.");
				}
				else
				{
					data.RarityId = text;
					ItemModifierDataStore.Save(item, data);
					ItemRarityVisuals.RefreshEquippedGlow((Humanoid)(object)Player.m_localPlayer);
					Console.instance.Print("Set equipped item rarity to '" + data.RarityId + "'.");
				}
			}
		}
	}

	private sealed class ModifierCommand : ConsoleCommand
	{
		public override string Name => "modifier";

		public override bool IsCheat => true;

		public override string Help => "Adds a modifier to an equipped item at its max value. Usage: modifier <modifier> [value] [slot]. Value uses tooltip units (25 = 25% for percentage modifiers) and may exceed the normal range.";

		public override List<string> CommandOptionList()
		{
			return ModifierCatalog.GetCommandOptions();
		}

		public override void Run(string[] args)
		{
			if (args.Length < 1 || string.IsNullOrWhiteSpace(args[0]) || args.Length > 3)
			{
				Console.instance.Print(((ConsoleCommand)this).Help);
			}
			else
			{
				if (!TryGetModifierDefinition(args[0], out var definition))
				{
					return;
				}
				float? num = null;
				string text = null;
				for (int i = 1; i < args.Length; i++)
				{
					if (!num.HasValue && float.TryParse(args[i], NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
					{
						num = definition.FromDisplayValue(result);
						continue;
					}
					if (text == null)
					{
						text = args[i];
						continue;
					}
					Console.instance.Print(((ConsoleCommand)this).Help);
					return;
				}
				string id = definition.Id;
				string commandName = definition.CommandName;
				if (!TryGetEquippedItem(text, out var item))
				{
					return;
				}
				if (!definition.IsAllowedOn(item) && ModifierCatalog.TryGetItemCategory(item, out var category))
				{
					if (category == ModifierItemCategory.Shield && ModifierCatalog.IsTowerShield(item) && ModifierDefinition.IsParryOnlyEffect(definition.EffectType))
					{
						Console.instance.Print("Parry modifiers are not available for tower shields.");
						return;
					}
					Console.instance.Print("Modifier '" + commandName + "' is not compatible with " + ModifierCatalog.GetCategoryDisplayName(category) + " items.");
					return;
				}
				if (!ItemModifierDataStore.TryLoad(item, out var data))
				{
					data = new ItemModifierData();
				}
				ModifierRoll[] array = data.Modifiers ?? new ModifierRoll[0];
				ModifierRoll[] array2 = array;
				foreach (ModifierRoll modifierRoll in array2)
				{
					if (modifierRoll != null && modifierRoll.Id == id)
					{
						Console.instance.Print("Equipped item already has modifier '" + commandName + "'.");
						return;
					}
				}
				if (!ItemRarityCatalog.TryGet(data.RarityId, out var definition2))
				{
					Console.instance.Print("Set a rarity before adding modifiers. Magic allows 1, Rare allows 2, and Epic allows 4 modifiers.");
					return;
				}
				int modifierCount = GetModifierCount(array);
				if (modifierCount >= definition2.MaxModifiers)
				{
					Console.instance.Print($"{definition2.DisplayName} items can have at most {definition2.MaxModifiers} modifier(s).");
					return;
				}
				ModifierRoll[] array3 = new ModifierRoll[array.Length + 1];
				array.CopyTo(array3, 0);
				array3[^1] = new ModifierRoll
				{
					Id = id,
					Value = (num ?? definition.StrongestValue)
				};
				data.Modifiers = array3;
				ItemModifierDataStore.Save(item, data);
				Console.instance.Print("Added '" + commandName + "' to the equipped item (" + definition.FormatTooltipLine(array3[^1].Value) + ").");
			}
		}
	}

	private sealed class RemoveModifierCommand : ConsoleCommand
	{
		public override string Name => "remove_modifier";

		public override bool IsCheat => true;

		public override string Help => "Removes a modifier from an equipped item. Usage: remove_modifier <modifier> [slot].";

		public override List<string> CommandOptionList()
		{
			return ModifierCatalog.GetCommandOptions();
		}

		public override void Run(string[] args)
		{
			if (args.Length < 1 || string.IsNullOrWhiteSpace(args[0]) || args.Length > 2)
			{
				Console.instance.Print(((ConsoleCommand)this).Help);
			}
			else
			{
				if (!TryGetModifierDefinition(args[0], out var definition))
				{
					return;
				}
				string id = definition.Id;
				string commandName = definition.CommandName;
				if (!TryGetEquippedItem(args, 1, out var item))
				{
					return;
				}
				if (!ItemModifierDataStore.TryLoad(item, out var data) || data.Modifiers == null || data.Modifiers.Length == 0)
				{
					Console.instance.Print("Equipped item does not have modifier '" + commandName + "'.");
					return;
				}
				int num = 0;
				ModifierRoll[] modifiers = data.Modifiers;
				foreach (ModifierRoll modifierRoll in modifiers)
				{
					if (modifierRoll == null || modifierRoll.Id != id)
					{
						num++;
					}
				}
				if (num == data.Modifiers.Length)
				{
					Console.instance.Print("Equipped item does not have modifier '" + commandName + "'.");
					return;
				}
				ModifierRoll[] array = new ModifierRoll[num];
				int num2 = 0;
				ModifierRoll[] modifiers2 = data.Modifiers;
				foreach (ModifierRoll modifierRoll2 in modifiers2)
				{
					if (modifierRoll2 == null || modifierRoll2.Id != id)
					{
						array[num2++] = modifierRoll2;
					}
				}
				data.Modifiers = array;
				ItemModifierDataStore.Save(item, data);
				Console.instance.Print("Removed '" + commandName + "' from the equipped item.");
			}
		}
	}

	private sealed class DumpItemDataCommand : ConsoleCommand
	{
		public override string Name => "dump_item_data";

		public override string Help => "Prints the local player's inventory item data.";

		public override void Run(string[] args)
		{
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				Console.instance.Print("No local player is available.");
				return;
			}
			List<ItemData> allItems = ((Humanoid)localPlayer).GetInventory().GetAllItems();
			Console.instance.Print($"Inventory contains {allItems.Count} item entries.");
			for (int i = 0; i < allItems.Count; i++)
			{
				ItemData val = allItems[i];
				SharedData shared = val.m_shared;
				Console instance = Console.instance;
				string[] array = new string[5];
				object arg = i;
				GameObject dropPrefab = val.m_dropPrefab;
				array[0] = string.Format("Item {0}: prefab={1}, ", arg, ((dropPrefab != null) ? ((Object)dropPrefab).name : null) ?? "<none>");
				array[1] = $"name={shared.m_name}, quality={val.m_quality}, stack={val.m_stack}, ";
				array[2] = $"durability={val.m_durability}, worldLevel={val.m_worldLevel}, ";
				array[3] = $"variant={val.m_variant}, equipped={val.m_equipped}, ";
				array[4] = $"pickedUp={val.m_pickedUp}, crafter={val.m_crafterName} ({val.m_crafterID})";
				instance.Print(string.Concat(array));
				Console.instance.Print("  Base damage: " + ((DamageTypes)(ref shared.m_damages)).GetTooltipString());
				DamageTypes damage = val.GetDamage();
				Console.instance.Print("  Calculated damage: " + ((DamageTypes)(ref damage)).GetTooltipString());
				if (ItemModifierDataStore.TryLoad(val, out var data))
				{
					Console.instance.Print($"  Item data: rarity={data.RarityId}, version={data.Version}");
					if (data.Modifiers == null || data.Modifiers.Length == 0)
					{
						Console.instance.Print("  Modifiers: <none>");
					}
					else
					{
						Console.instance.Print("  Modifiers:");
						ModifierRoll[] modifiers = data.Modifiers;
						foreach (ModifierRoll modifierRoll in modifiers)
						{
							if (modifierRoll != null)
							{
								Console.instance.Print($"    {modifierRoll.Id} = {modifierRoll.Value}");
							}
						}
					}
				}
				else
				{
					Console.instance.Print("  Item data: <not found>");
				}
				if (val.m_customData == null || val.m_customData.Count == 0)
				{
					Console.instance.Print("  Custom data: <empty>");
					continue;
				}
				foreach (KeyValuePair<string, string> customDatum in val.m_customData)
				{
					Console.instance.Print("  Custom data [" + customDatum.Key + "] = " + customDatum.Value);
				}
			}
		}
	}

	public static void Register()
	{
		CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new SetRarityCommand());
		CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new ModifierCommand());
		CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new RemoveModifierCommand());
		CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new DumpItemDataCommand());
	}

	private static bool IsWeaponCategory(ModifierItemCategory category)
	{
		return category == ModifierItemCategory.Weapon || category == ModifierItemCategory.Bow || category == ModifierItemCategory.Crossbow || category == ModifierItemCategory.MagicWeapon;
	}

	private static void AddIfSupported(List<ItemData> items, ItemData item)
	{
		if (!ModifierCatalog.TryGetItemCategory(item, out var _))
		{
			return;
		}
		foreach (ItemData item2 in items)
		{
			if (item2 == item)
			{
				return;
			}
		}
		items.Add(item);
	}

	private static List<ItemData> GetEquippedArmourItems(Player player)
	{
		List<ItemData> list = new List<ItemData>();
		AddIfSupported(list, ((Humanoid)player).m_helmetItem);
		AddIfSupported(list, ((Humanoid)player).m_chestItem);
		AddIfSupported(list, ((Humanoid)player).m_legItem);
		AddIfSupported(list, ((Humanoid)player).m_shoulderItem);
		return list;
	}

	private static List<ItemData> GetSupportedEquippedItems(Player player)
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Invalid comparison between Unknown and I4
		List<ItemData> list = new List<ItemData>();
		AddIfSupported(list, ((Humanoid)player).GetCurrentWeapon());
		if (((Humanoid)player).m_leftItem != null && (int)((Humanoid)player).m_leftItem.m_shared.m_itemType == 5)
		{
			AddIfSupported(list, ((Humanoid)player).m_leftItem);
		}
		foreach (ItemData equippedArmourItem in GetEquippedArmourItems(player))
		{
			AddIfSupported(list, equippedArmourItem);
		}
		return list;
	}

	private static bool TryGetOneItem(List<ItemData> items, string slot, out ItemData item)
	{
		item = null;
		if (items.Count == 1)
		{
			item = items[0];
			return true;
		}
		if (items.Count == 0)
		{
			Console.instance.Print("No equipped " + slot + " was found.");
		}
		else
		{
			Console.instance.Print("More than one " + slot + " is equipped. Specify a specific slot.");
		}
		return false;
	}

	private static bool TryGetEquippedItem(string slotArgument, out ItemData item)
	{
		item = null;
		if ((Object)(object)Player.m_localPlayer == (Object)null)
		{
			Console.instance.Print("No local player is available.");
			return false;
		}
		Player localPlayer = Player.m_localPlayer;
		if (string.IsNullOrWhiteSpace(slotArgument))
		{
			List<ItemData> supportedEquippedItems = GetSupportedEquippedItems(localPlayer);
			if (supportedEquippedItems.Count == 1)
			{
				item = supportedEquippedItems[0];
				return true;
			}
			Console.instance.Print((supportedEquippedItems.Count == 0) ? "No supported weapon, shield, or armour is equipped." : "Multiple supported items are equipped. Specify weapon, shield, armour, helmet, chest, legs, or cape.");
			return false;
		}
		string text = slotArgument.Trim().ToLowerInvariant();
		switch (text)
		{
		case "weapon":
		{
			item = ((Humanoid)localPlayer).GetCurrentWeapon();
			if (ModifierCatalog.TryGetItemCategory(item, out var category2) && IsWeaponCategory(category2))
			{
				return true;
			}
			Console.instance.Print("No supported weapon is equipped in the weapon slot.");
			return false;
		}
		case "bow":
		case "crossbow":
		case "magic":
		case "magic_weapon":
		{
			item = ((Humanoid)localPlayer).GetCurrentWeapon();
			if (ModifierCatalog.TryGetItemCategory(item, out var category) && ((text == "bow" && category == ModifierItemCategory.Bow) || (text == "crossbow" && category == ModifierItemCategory.Crossbow) || ((text == "magic" || text == "magic_weapon") && category == ModifierItemCategory.MagicWeapon)))
			{
				return true;
			}
			Console.instance.Print("No equipped " + text.Replace('_', ' ') + " was found.");
			return false;
		}
		case "shield":
		{
			List<ItemData> list = new List<ItemData>();
			AddIfShield(list, ((Humanoid)localPlayer).m_leftItem);
			AddIfShield(list, ((Humanoid)localPlayer).m_rightItem);
			return TryGetOneItem(list, "shield", out item);
		}
		case "armour":
			return TryGetOneItem(GetEquippedArmourItems(localPlayer), "armour piece", out item);
		case "helmet":
			item = ((Humanoid)localPlayer).m_helmetItem;
			break;
		case "chest":
			item = ((Humanoid)localPlayer).m_chestItem;
			break;
		case "legs":
			item = ((Humanoid)localPlayer).m_legItem;
			break;
		case "cape":
			item = ((Humanoid)localPlayer).m_shoulderItem;
			break;
		default:
			Console.instance.Print("Invalid slot. Use weapon, shield, armour, helmet, chest, legs, cape, bow, crossbow, or magic.");
			return false;
		}
		if (ModifierCatalog.TryGetItemCategory(item, out var category3) && category3 == ModifierItemCategory.Armour)
		{
			return true;
		}
		Console.instance.Print("No equipped " + text + " was found.");
		return false;
	}

	private static void AddIfShield(List<ItemData> shields, ItemData item)
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Invalid comparison between Unknown and I4
		if (item != null && (int)item.m_shared.m_itemType == 5)
		{
			AddIfSupported(shields, item);
		}
	}

	private static bool TryGetEquippedItem(string[] args, int requiredArgumentCount, out ItemData item)
	{
		item = null;
		if (args.Length < requiredArgumentCount || args.Length > requiredArgumentCount + 1)
		{
			return false;
		}
		return TryGetEquippedItem((args.Length == requiredArgumentCount) ? null : args[requiredArgumentCount], out item);
	}

	private static bool TryGetModifierDefinition(string commandName, out ModifierDefinition definition)
	{
		if (ModifierCatalog.TryGetByCommandName(commandName.Trim(), out definition))
		{
			return true;
		}
		Console.instance.Print("Unknown modifier. Available modifiers: " + string.Join(", ", ModifierCatalog.GetCommandOptions()) + ".");
		return false;
	}

	private static int GetModifierCount(ModifierRoll[] modifiers)
	{
		if (modifiers == null)
		{
			return 0;
		}
		int num = 0;
		foreach (ModifierRoll modifierRoll in modifiers)
		{
			if (modifierRoll != null && !string.IsNullOrWhiteSpace(modifierRoll.Id))
			{
				num++;
			}
		}
		return num;
	}
}
[Flags]
internal enum ModifierItemCategory
{
	None = 0,
	Weapon = 1,
	Bow = 2,
	Crossbow = 4,
	MagicWeapon = 8,
	Shield = 0x10,
	Armour = 0x20
}
internal enum ModifierDamageChannel
{
	None,
	All,
	Slash,
	Pierce,
	Blunt,
	Chop,
	Pickaxe,
	Fire,
	Frost,
	Lightning,
	Poison,
	Spirit
}
internal enum ModifierValueType
{
	Percentage,
	PercentagePoints,
	Multiplier,
	Flat
}
internal enum ModifierEffectType
{
	None,
	AttackStaminaCost,
	MovementPenalty,
	BlockPower,
	ParryBonus,
	BackstabBonus,
	AdrenalineGain,
	BowDrawStaminaCost,
	ReloadTime,
	BlockStaminaCost,
	MovementSpeedBonus,
	ArmourFlat,
	ArmourPercentage,
	FireResistance,
	FrostResistance,
	LightningResistance,
	PoisonResistance,
	ParryAdrenaline,
	ProjectileSpeed,
	AmmoSaveChance,
	ExtraProjectileChance,
	ParryDamage,
	ParryHealth,
	ParryStamina,
	HealthRegen,
	StaminaRegen,
	MaxHealth,
	AdrenalineOnHit,
	DodgeStaminaCost,
	Thorns,
	SkillLevel,
	AttackEitrCost,
	ShieldOnUse,
	AoeRadius,
	EitrRegen,
	MagicExtraProjectile,
	SummonRoots,
	BloodHealthCost,
	BloodHealthToStamina,
	LowHealthEffect,
	ShieldAllyHeal,
	SummonMaxCount,
	ExtraSummonChance,
	ExtraSummonStars
}
internal sealed class ModifierDefinition
{
	public string Id { get; }

	public string CommandName { get; }

	public string DisplayName { get; }

	public float BaseValue { get; }

	public float WeakestValue { get; }

	public float StrongestValue { get; }

	public float Step { get; }

	public ModifierDamageChannel DamageChannel { get; }

	public ModifierValueType ValueType { get; }

	public ModifierEffectType EffectType { get; }

	public ModifierItemCategory AllowedItemCategories { get; }

	public SkillType Skill { get; }

	public ModifierDefinition(string id, string commandName, string displayName, float testValue, ModifierDamageChannel damageChannel, ModifierValueType valueType, ModifierEffectType effectType = ModifierEffectType.None, ModifierItemCategory allowedItemCategories = ModifierItemCategory.Weapon, SkillType skill = (SkillType)0)
	{
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		Id = id;
		CommandName = commandName;
		DisplayName = displayName;
		BaseValue = testValue;
		if (ModifierCatalog.RollRanges.TryGetValue(id, out var value))
		{
			WeakestValue = value[0];
			StrongestValue = value[1];
			Step = value[2];
		}
		else
		{
			WeakestValue = testValue * 0.5f;
			StrongestValue = testValue * 1.5f;
			Step = 0f;
		}
		DamageChannel = damageChannel;
		ValueType = valueType;
		EffectType = effectType;
		AllowedItemCategories = allowedItemCategories;
		Skill = skill;
	}

	public float FromDisplayValue(float displayValue)
	{
		return (ValueType == ModifierValueType.Percentage || ValueType == ModifierValueType.PercentagePoints) ? (displayValue / 100f) : displayValue;
	}

	public float Roll()
	{
		if (Step <= 0f)
		{
			return StrongestValue;
		}
		int num = (int)Math.Round(Math.Abs(StrongestValue - WeakestValue) / Step);
		int num2 = Random.Range(0, num + 1);
		float num3 = ((StrongestValue >= WeakestValue) ? 1f : (-1f));
		return (float)Math.Round(WeakestValue + num3 * (float)num2 * Step, 4);
	}

	public bool IsAllowedOn(ItemData item)
	{
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Invalid comparison between Unknown and I4
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Invalid comparison between Unknown and I4
		if (!ModifierCatalog.TryGetItemCategory(item, out var category) || (AllowedItemCategories & category) == 0)
		{
			return false;
		}
		if (EffectType == ModifierEffectType.MovementPenalty && item.m_shared.m_movementModifier >= 0f)
		{
			return false;
		}
		if (EffectType == ModifierEffectType.AoeRadius && !MagicWeaponInfo.HasAoe(item))
		{
			return false;
		}
		if ((EffectType == ModifierEffectType.MagicExtraProjectile || EffectType == ModifierEffectType.SummonRoots) && (int)item.m_shared.m_skillType != 9)
		{
			return false;
		}
		if ((EffectType == ModifierEffectType.BloodHealthCost || EffectType == ModifierEffectType.BloodHealthToStamina || EffectType == ModifierEffectType.LowHealthEffect) && (int)item.m_shared.m_skillType != 10)
		{
			return false;
		}
		if (EffectType == ModifierEffectType.ShieldAllyHeal && !StaffShieldSource.IsStaffOfProtection(item))
		{
			return false;
		}
		if ((EffectType == ModifierEffectType.SummonMaxCount || EffectType == ModifierEffectType.ExtraSummonChance || EffectType == ModifierEffectType.ExtraSummonStars) && !SummonWeaponInfo.HasSummonAbility(item))
		{
			return false;
		}
		if (EffectType == ModifierEffectType.MagicExtraProjectile && !MagicWeaponInfo.FiresProjectile(item))
		{
			return false;
		}
		return !IsParryOnlyEffect(EffectType) || category != ModifierItemCategory.Shield || !ModifierCatalog.IsTowerShield(item);
	}

	public static bool IsParryOnlyEffect(ModifierEffectType effectType)
	{
		return effectType == ModifierEffectType.ParryBonus || effectType == ModifierEffectType.ParryAdrenaline || effectType == ModifierEffectType.ParryDamage || effectType == ModifierEffectType.ParryHealth || effectType == ModifierEffectType.ParryStamina;
	}

	public void ApplyDamage(ref DamageTypes damage, float value)
	{
		switch (DamageChannel)
		{
		case ModifierDamageChannel.All:
			ApplyValue(ref damage.m_blunt, value);
			ApplyValue(ref damage.m_slash, value);
			ApplyValue(ref damage.m_pierce, value);
			ApplyValue(ref damage.m_chop, value);
			ApplyValue(ref damage.m_pickaxe, value);
			ApplyValue(ref damage.m_fire, value);
			ApplyValue(ref damage.m_frost, value);
			ApplyValue(ref damage.m_lightning, value);
			ApplyValue(ref damage.m_poison, value);
			ApplyValue(ref damage.m_spirit, value);
			break;
		case ModifierDamageChannel.Slash:
			ApplyValue(ref damage.m_slash, value);
			break;
		case ModifierDamageChannel.Pierce:
			ApplyValue(ref damage.m_pierce, value);
			break;
		case ModifierDamageChannel.Blunt:
			ApplyValue(ref damage.m_blunt, value);
			break;
		case ModifierDamageChannel.Chop:
			ApplyValue(ref damage.m_chop, value);
			break;
		case ModifierDamageChannel.Pickaxe:
			ApplyValue(ref damage.m_pickaxe, value);
			break;
		case ModifierDamageChannel.Fire:
			ApplyValue(ref damage.m_fire, value);
			break;
		case ModifierDamageChannel.Frost:
			ApplyValue(ref damage.m_frost, value);
			break;
		case ModifierDamageChannel.Lightning:
			ApplyValue(ref damage.m_lightning, value);
			break;
		case ModifierDamageChannel.Poison:
			ApplyValue(ref damage.m_poison, value);
			break;
		case ModifierDamageChannel.Spirit:
			ApplyValue(ref damage.m_spirit, value);
			break;
		}
	}

	private void ApplyValue(ref float damage, float value)
	{
		damage = ApplyScalar(damage, value);
	}

	public float ApplyScalar(float currentValue, float modifierValue)
	{
		return (ValueType == ModifierValueType.Percentage) ? (currentValue * (1f + modifierValue)) : (currentValue + modifierValue);
	}

	public bool IsOverLimit(float value)
	{
		return (StrongestValue >= WeakestValue) ? (value > StrongestValue + 0.0001f) : (value < StrongestValue - 0.0001f);
	}

	public string FormatTooltipLine(float value, bool wholeLinePurple = false)
	{
		string text;
		if (ValueType == ModifierValueType.Percentage || ValueType == ModifierValueType.PercentagePoints)
		{
			text = (value * 100f).ToString("+0.##;-0.##;0", CultureInfo.InvariantCulture) + "%";
		}
		else if (ValueType == ModifierValueType.Multiplier)
		{
			text = value.ToString("+0.##;-0.##;0", CultureInfo.InvariantCulture) + "x";
			if (EffectType == ModifierEffectType.ParryDamage)
			{
				text += " block armor";
			}
		}
		else
		{
			text = value.ToString("+0.##;-0.##;0", CultureInfo.InvariantCulture);
		}
		if (wholeLinePurple)
		{
			return "<color=#9B30FF>" + DisplayName + ": " + text + "</color>";
		}
		string text2 = (IsOverLimit(value) ? "#9B30FF" : "green");
		return "<color=#ADD8E6>" + DisplayName + ":</color> <color=" + text2 + ">" + text + "</color>";
	}
}
internal static class ModifierCatalog
{
	internal static readonly Dictionary<string, float[]> RollRanges = new Dictionary<string, float[]>
	{
		{
			"base_damage",
			new float[3] { 0.1f, 0.3f, 0.01f }
		},
		{
			"fire_damage",
			new float[3] { 5f, 15f, 1f }
		},
		{
			"frost_damage",
			new float[3] { 5f, 15f, 1f }
		},
		{
			"lightning_damage",
			new float[3] { 5f, 15f, 1f }
		},
		{
			"poison_damage",
			new float[3] { 5f, 15f, 1f }
		},
		{
			"spirit_damage",
			new float[3] { 5f, 15f, 1f }
		},
		{
			"stamina_cost",
			new float[3] { -0.05f, -0.15f, 0.01f }
		},
		{
			"eitr_cost",
			new float[3] { -0.1f, -0.2f, 0.01f }
		},
		{
			"shield_on_use",
			new float[3] { 0.1f, 0.2f, 0.01f }
		},
		{
			"aoe_radius",
			new float[3] { 0.25f, 0.5f, 0.01f }
		},
		{
			"eitr_regen",
			new float[3] { 0.15f, 0.3f, 0.01f }
		},
		{
			"magic_extra_projectile",
			new float[3] { 0.1f, 0.25f, 0.01f }
		},
		{
			"summon_roots",
			new float[3] { 0.1f, 0.2f, 0.01f }
		},
		{
			"blood_health_cost",
			new float[3] { 0.1f, 0.3f, 0.01f }
		},
		{
			"blood_health_to_stamina",
			new float[3] { 0.1f, 0.3f, 0.01f }
		},
		{
			"low_health_effect",
			new float[3] { 0.25f, 0.5f, 0.01f }
		},
		{
			"shield_ally_heal",
			new float[3] { 20f, 40f, 1f }
		},
		{
			"summon_max_count",
			new float[3] { 1f, 2f, 1f }
		},
		{
			"extra_summon_chance",
			new float[3] { 0.15f, 0.3f, 0.01f }
		},
		{
			"extra_summon_stars",
			new float[3] { 0.25f, 0.5f, 0.01f }
		},
		{
			"bow_draw_stamina",
			new float[3] { -1f, -3f, 1f }
		},
		{
			"crossbow_reload",
			new float[3] { -0.25f, -0.25f, 0f }
		},
		{
			"projectile_speed",
			new float[3] { 0.25f, 1f, 0.05f }
		},
		{
			"ammo_save_chance",
			new float[3] { 0.25f, 0.5f, 0.01f }
		},
		{
			"extra_projectile_chance",
			new float[3] { 0.25f, 0.5f, 0.01f }
		},
		{
			"movement_penalty",
			new float[3] { 0.5f, 1f, 0.05f }
		},
		{
			"block_armour",
			new float[3] { 0.1f, 0.3f, 0.01f }
		},
		{
			"parry_bonus",
			new float[3] { 0.25f, 0.75f, 0.05f }
		},
		{
			"backstab_bonus",
			new float[3] { 0.5f, 1.5f, 0.5f }
		},
		{
			"adrenaline_gain",
			new float[3] { 1f, 2f, 1f }
		},
		{
			"shield_block_stamina",
			new float[3] { -0.5f, -0.5f, 0f }
		},
		{
			"shield_movespeed",
			new float[3] { 0.03f, 0.07f, 0.01f }
		},
		{
			"armour_flat",
			new float[3] { 2f, 6f, 1f }
		},
		{
			"armour_percent",
			new float[3] { 0.1f, 0.3f, 0.01f }
		},
		{
			"armour_movespeed",
			new float[3] { 0.02f, 0.04f, 0.01f }
		},
		{
			"fire_resistance",
			new float[3] { 0.25f, 0.25f, 0f }
		},
		{
			"frost_resistance",
			new float[3] { 0.25f, 0.25f, 0f }
		},
		{
			"lightning_resistance",
			new float[3] { 0.25f, 0.25f, 0f }
		},
		{
			"poison_resistance",
			new float[3] { 0.25f, 0.25f, 0f }
		},
		{
			"parry_adrenaline",
			new float[3] { 3f, 7f, 1f }
		},
		{
			"parry_damage",
			new float[3] { 1f, 2f, 0.1f }
		},
		{
			"parry_health",
			new float[3] { 5f, 10f, 1f }
		},
		{
			"parry_stamina",
			new float[3] { 10f, 20f, 1f }
		},
		{
			"health_regen",
			new float[3] { 0.05f, 0.15f, 0.01f }
		},
		{
			"stamina_regen",
			new float[3] { 0.05f, 0.15f, 0.01f }
		},
		{
			"max_health",
			new float[3] { 2f, 5f, 1f }
		},
		{
			"adrenaline_on_hit",
			new float[3] { 1f, 4f, 1f }
		},
		{
			"dodge_stamina",
			new float[3] { -0.05f, -0.15f, 0.01f }
		},
		{
			"thorns",
			new float[3] { 0.2f, 0.4f, 0.01f }
		},
		{
			"skill_axes",
			new float[3] { 10f, 20f, 1f }
		},
		{
			"skill_blood_magic",
			new float[3] { 10f, 20f, 1f }
		},
		{
			"skill_bows",
			new float[3] { 10f, 20f, 1f }
		},
		{
			"skill_clubs",
			new float[3] { 10f, 20f, 1f }
		},
		{
			"skill_crossbows",
			new float[3] { 10f, 20f, 1f }
		},
		{
			"skill_elemental_magic",
			new float[3] { 10f, 20f, 1f }
		},
		{
			"skill_fists",
			new float[3] { 10f, 20f, 1f }
		},
		{
			"skill_knives",
			new float[3] { 10f, 20f, 1f }
		},
		{
			"skill_polearms",
			new float[3] { 10f, 20f, 1f }
		},
		{
			"skill_spears",
			new float[3] { 10f, 20f, 1f }
		},
		{
			"skill_swords",
			new float[3] { 10f, 20f, 1f }
		}
	};

	internal static readonly Dictionary<string, float> Weights = new Dictionary<string, float>
	{
		{ "base_damage", 5f },
		{ "fire_damage", 1f },
		{ "frost_damage", 1f },
		{ "lightning_damage", 1f },
		{ "poison_damage", 1f },
		{ "spirit_damage", 1f },
		{ "stamina_cost", 1f },
		{ "eitr_cost", 1f },
		{ "shield_on_use", 1f },
		{ "aoe_radius", 1f },
		{ "eitr_regen", 1f },
		{ "magic_extra_projectile", 1f },
		{ "summon_roots", 1f },
		{ "blood_health_cost", 1f },
		{ "blood_health_to_stamina", 1f },
		{ "low_health_effect", 1f },
		{ "shield_ally_heal", 1f },
		{ "summon_max_count", 1f },
		{ "extra_summon_chance", 1f },
		{ "extra_summon_stars", 1f },
		{ "backstab_bonus", 2f },
		{ "adrenaline_gain", 1f },
		{ "bow_draw_stamina", 2f },
		{ "crossbow_reload", 1f },
		{ "projectile_speed", 2f },
		{ "ammo_save_chance", 2f },
		{ "extra_projectile_chance", 1f },
		{ "movement_penalty", 2f },
		{ "block_armour", 1f },
		{ "parry_bonus", 2f },
		{ "shield_block_stamina", 4f },
		{ "shield_movespeed", 2f },
		{ "parry_adrenaline", 1f },
		{ "parry_damage", 1f },
		{ "parry_health", 1f },
		{ "parry_stamina", 1f },
		{ "armour_flat", 1f },
		{ "armour_percent", 3f },
		{ "armour_movespeed", 2f },
		{ "fire_resistance", 1f },
		{ "frost_resistance", 1f },
		{ "lightning_resistance", 1f },
		{ "poison_resistance", 1f },
		{ "health_regen", 1f },
		{ "stamina_regen", 1f },
		{ "max_health", 1f },
		{ "adrenaline_on_hit", 1f },
		{ "dodge_stamina", 1f },
		{ "thorns", 2f },
		{ "skill_axes", 0.2f },
		{ "skill_blood_magic", 0.2f },
		{ "skill_bows", 0.2f },
		{ "skill_clubs", 0.2f },
		{ "skill_crossbows", 0.2f },
		{ "skill_elemental_magic", 0.2f },
		{ "skill_fists", 0.2f },
		{ "skill_knives", 0.2f },
		{ "skill_polearms", 0.2f },
		{ "skill_spears", 0.2f },
		{ "skill_swords", 0.2f }
	};

	private static readonly ModifierDefinition[] Definitions = new ModifierDefinition[60]
	{
		new ModifierDefinition("base_damage", "base_damage", "Base damage", 0.2f, ModifierDamageChannel.All, ModifierValueType.Percentage, ModifierEffectType.None, ModifierItemCategory.Weapon | ModifierItemCategory.Bow | ModifierItemCategory.Crossbow | ModifierItemCategory.MagicWeapon, (SkillType)0),
		new ModifierDefinition("fire_damage", "fire_damage", "Fire damage", 10f, ModifierDamageChannel.Fire, ModifierValueType.Flat, ModifierEffectType.None, ModifierItemCategory.Weapon | ModifierItemCategory.Bow | ModifierItemCategory.Crossbow, (SkillType)0),
		new ModifierDefinition("frost_damage", "frost_damage", "Frost damage", 10f, ModifierDamageChannel.Frost, ModifierValueType.Flat, ModifierEffectType.None, ModifierItemCategory.Weapon | ModifierItemCategory.Bow | ModifierItemCategory.Crossbow, (SkillType)0),
		new ModifierDefinition("lightning_damage", "lightning_damage", "Lightning damage", 10f, ModifierDamageChannel.Lightning, ModifierValueType.Flat, ModifierEffectType.None, ModifierItemCategory.Weapon | ModifierItemCategory.Bow | ModifierItemCategory.Crossbow, (SkillType)0),
		new ModifierDefinition("poison_damage", "poison_damage", "Poison damage", 10f, ModifierDamageChannel.Poison, ModifierValueType.Flat, ModifierEffectType.None, ModifierItemCategory.Weapon | ModifierItemCategory.Bow | ModifierItemCategory.Crossbow, (SkillType)0),
		new ModifierDefinition("spirit_damage", "spirit_damage", "Spirit damage", 10f, ModifierDamageChannel.Spirit, ModifierValueType.Flat, ModifierEffectType.None, ModifierItemCategory.Weapon | ModifierItemCategory.Bow | ModifierItemCategory.Crossbow, (SkillType)0),
		new ModifierDefinition("stamina_cost", "stamina_cost", "Weapon stamina cost", -0.1f, ModifierDamageChannel.None, ModifierValueType.Percentage, ModifierEffectType.AttackStaminaCost, ModifierItemCategory.Weapon, (SkillType)0),
		new ModifierDefinition("eitr_cost", "eitr_cost", "Weapon eitr cost", -0.15f, ModifierDamageChannel.None, ModifierValueType.Percentage, ModifierEffectType.AttackEitrCost, ModifierItemCategory.MagicWeapon, (SkillType)0),
		new ModifierDefinition("shield_on_use", "shield_on_use", "Chance to gain a shield on use", 0.15f, ModifierDamageChannel.None, ModifierValueType.PercentagePoints, ModifierEffectType.ShieldOnUse, ModifierItemCategory.MagicWeapon, (SkillType)0),
		new ModifierDefinition("aoe_radius", "aoe_radius", "Area of effect radius", 0.35f, ModifierDamageChannel.None, ModifierValueType.Percentage, ModifierEffectType.AoeRadius, ModifierItemCategory.MagicWeapon, (SkillType)0),
		new ModifierDefinition("eitr_regen", "eitr_regen", "Eitr regeneration while held", 0.2f, ModifierDamageChannel.None, ModifierValueType.Percentage, ModifierEffectType.EitrRegen, ModifierItemCategory.MagicWeapon, (SkillType)0),
		new ModifierDefinition("magic_extra_projectile", "magic_extra_projectile", "Chance for additional projectiles", 0.15f, ModifierDamageChannel.None, ModifierValueType.PercentagePoints, ModifierEffectType.MagicExtraProjectile, ModifierItemCategory.MagicWeapon, (SkillType)0),
		new ModifierDefinition("summon_roots", "summon_roots", "Chance to summon roots on use", 0.15f, ModifierDamageChannel.None, ModifierValueType.PercentagePoints, ModifierEffectType.SummonRoots, ModifierItemCategory.MagicWeapon, (SkillType)0),
		new ModifierDefinition("blood_health_cost", "blood_health_cost", "Blood magic health cost", 0.2f, ModifierDamageChannel.None, ModifierValueType.Percentage, ModifierEffectType.BloodHealthCost, ModifierItemCategory.MagicWeapon, (SkillType)0),
		new ModifierDefinition("blood_health_to_stamina", "blood_health_to_stamina", "Convert health cost to stamina cost", 0.2f, ModifierDamageChannel.None, ModifierValueType.Percentage, ModifierEffectType.BloodHealthToStamina, ModifierItemCategory.MagicWeapon, (SkillType)0),
		new ModifierDefinition("low_health_effect", "low_health_effect", "Effect while below 50% health", 0.35f, ModifierDamageChannel.None, ModifierValueType.Percentage, ModifierEffectType.LowHealthEffect, ModifierItemCategory.MagicWeapon, (SkillType)0),
		new ModifierDefinition("shield_ally_heal", "shield_ally_heal", "Heal nearby allies when shield is granted", 30f, ModifierDamageChannel.None, ModifierValueType.Flat, ModifierEffectType.ShieldAllyHeal, ModifierItemCategory.MagicWeapon, (SkillType)0),
		new ModifierDefinition("summon_max_count", "summon_max_count", "Maximum summons", 1f, ModifierDamageChannel.None, ModifierValueType.Flat, ModifierEffectType.SummonMaxCount, ModifierItemCategory.Weapon | ModifierItemCategory.MagicWeapon, (SkillType)0),
		new ModifierDefinition("extra_summon_chance", "extra_summon_chance", "Chance to spawn an extra summon", 0.225f, ModifierDamageChannel.None, ModifierValueType.PercentagePoints, ModifierEffectType.ExtraSummonChance, ModifierItemCategory.Weapon | ModifierItemCategory.MagicWeapon, (SkillType)0),
		new ModifierDefinition("extra_summon_stars", "extra_summon_stars", "Chance for extra summon stars (max 2)", 0.375f, ModifierDamageChannel.None, ModifierValueType.PercentagePoints, ModifierEffectType.ExtraSummonStars, ModifierItemCategory.Weapon | ModifierItemCategory.MagicWeapon, (SkillType)0),
		new ModifierDefinition("bow_draw_stamina", "bow_draw_stamina", "Bow draw stamina cost", -2f, ModifierDamageChannel.None, ModifierValueType.Flat, ModifierEffectType.BowDrawStaminaCost, ModifierItemCategory.Bow, (SkillType)0),
		new ModifierDefinition("crossbow_reload", "crossbow_reload", "Crossbow reload time", -0.25f, ModifierDamageChannel.None, ModifierValueType.Percentage, ModifierEffectType.ReloadTime, ModifierItemCategory.Crossbow, (SkillType)0),
		new ModifierDefinition("projectile_speed", "projectile_speed", "Projectile speed", 0.6f, ModifierDamageChannel.None, ModifierValueType.Percentage, ModifierEffectType.ProjectileSpeed, ModifierItemCategory.Bow | ModifierItemCategory.Crossbow, (SkillType)0),
		new ModifierDefinition("ammo_save_chance", "ammo_save_chance", "Chance to not consume ammo", 0.35f, ModifierDamageChannel.None, ModifierValueType.PercentagePoints, ModifierEffectType.AmmoSaveChance, ModifierItemCategory.Bow | ModifierItemCategory.Crossbow, (SkillType)0),
		new ModifierDefinition("extra_projectile_chance", "extra_projectile_chance", "Chance to fire 2 extra projectiles", 0.4f, ModifierDamageChannel.None, ModifierValueType.PercentagePoints, ModifierEffectType.ExtraProjectileChance, ModifierItemCategory.Bow | ModifierItemCategory.Crossbow, (SkillType)0),
		new ModifierDefinition("movement_penalty", "movement_penalty", "Movement penalty reduction", 1f, ModifierDamageChannel.None, ModifierValueType.PercentagePoints, ModifierEffectType.MovementPenalty, ModifierItemCategory.Weapon | ModifierItemCategory.MagicWeapon | ModifierItemCategory.Shield | ModifierItemCategory.Armour, (SkillType)0),
		new ModifierDefinition("block_armour", "block_armour", "Block armour", 0.2f, ModifierDamageChannel.None, ModifierValueType.Percentage, ModifierEffectType.BlockPower, ModifierItemCategory.Weapon | ModifierItemCategory.MagicWeapon | ModifierItemCategory.Shield, (SkillType)0),
		new ModifierDefinition("parry_bonus", "parry_bonus", "Parry bonus", 0.5f, ModifierDamageChannel.None, ModifierValueType.Multiplier, ModifierEffectType.ParryBonus, ModifierItemCategory.Weapon | ModifierItemCategory.Shield, (SkillT