Decompiled source of Seidr Enchanting v0.5.0

BepInEx/plugins/SeidrEnchanting/SeidrEnchanting.dll

Decompiled 14 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SeidrEnchanting")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.5.0.0")]
[assembly: AssemblyInformationalVersion("0.5.0")]
[assembly: AssemblyProduct("SeidrEnchanting")]
[assembly: AssemblyTitle("SeidrEnchanting")]
[assembly: AssemblyVersion("0.5.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SeidrEnchanting
{
	public enum AffixStat
	{
		None,
		DamagePct,
		ArmorPct,
		Health,
		Stamina,
		Eitr,
		MoveSpeedPct,
		BlockPct,
		DurabilityPct,
		Fire,
		Frost,
		Lightning,
		Poison,
		Spirit,
		Regen,
		StaminaRegenPct,
		EitrRegenPct,
		HealthRegenPct,
		StealthPct,
		DamageReductionPct,
		PoisonResistPct,
		FrostResistPct,
		FireResistPct,
		LightningResistPct,
		StaggerResistPct,
		KnockbackResistPct,
		FallDamageReductionPct,
		JumpHeightPct,
		SwimSpeedPct,
		DodgeStaminaPct,
		BlockStaminaPct,
		ParryBonusPct,
		BackstabPct,
		BossDamagePct,
		AnimalDamagePct,
		UndeadDamagePct,
		PickaxeDamagePct,
		ChopDamagePct,
		BowDamagePct,
		SpellDamagePct,
		ArmorPenPct,
		LowHealthDamagePct,
		FoodDurationPct,
		FoodRegenPct,
		RestedBonusPct,
		ExplosionResistPct,
		CraftingBonusPct,
		SneakDamagePct,
		ReflectDamagePct,
		ProjectileDeflectPct
	}
	[Flags]
	public enum AffixPool
	{
		None = 0,
		Weapon = 1,
		Armor = 2,
		Shield = 4
	}
	public enum AffixProc
	{
		None,
		Stagger,
		Lifesteal,
		Frostbite,
		Ignite,
		ChainLightning,
		Bleed,
		Knockback,
		Root,
		ArmorBreak,
		ExtraHit,
		EarthSlam,
		PullLightning,
		SoulDrain,
		SummonVermin,
		Echo,
		ParrySlow,
		PhaseShift,
		Combust,
		Execute,
		OnKillBuff,
		Decay,
		Weakness,
		Riposte,
		GiantSlayer,
		ThornReflect,
		BlockCharge,
		LastStand,
		Vengeance,
		AbsorbImpact,
		Phoenix,
		FrostAura,
		EitrShield,
		Deflect,
		SprintTrail,
		MagmaAura,
		SecondWind,
		Invisibility,
		WaterBreath,
		RainProof,
		NightBuff,
		DayBuff,
		HomeRest
	}
	public sealed class StatWeight
	{
		public readonly AffixStat Stat;

		public readonly float Weight;

		public StatWeight(AffixStat stat, float weight)
		{
			Stat = stat;
			Weight = weight;
		}
	}
	public sealed class AffixDef
	{
		public readonly string Id;

		public readonly AffixPool Pool;

		public readonly StatWeight[] Stats;

		public readonly AffixProc Proc;

		public readonly float ProcChancePerTier;

		public readonly float ProcCooldown;

		public readonly float ProcWeight;

		public readonly bool ProcPercent;

		public readonly string Ru;

		public readonly string En;

		public readonly string HintRu;

		public readonly string HintEn;

		public bool HasProc => Proc != AffixProc.None;

		public float Cooldown
		{
			get
			{
				float num = ((Settings.AffixCooldown != null) ? Settings.AffixCooldown.Value : 1f);
				return Math.Max(0f, ProcCooldown * num);
			}
		}

		public AffixDef(string id, AffixPool pool, StatWeight[] stats, AffixProc proc, float procChancePerTier, float procCooldown, float procWeight, bool procPercent, string ru, string en, string hintRu = null, string hintEn = null)
		{
			Id = id;
			Pool = pool;
			Stats = stats ?? Array.Empty<StatWeight>();
			Proc = proc;
			ProcChancePerTier = procChancePerTier;
			ProcCooldown = procCooldown;
			ProcWeight = procWeight;
			ProcPercent = procPercent;
			Ru = ru;
			En = en;
			HintRu = hintRu;
			HintEn = hintEn;
		}

		public float Chance(int tier)
		{
			if (!HasProc)
			{
				return 0f;
			}
			float num = ((Settings.AffixChance != null) ? Settings.AffixChance.Value : 1f);
			return Math.Min(0.75f, ProcChancePerTier * (float)Math.Max(1, tier) * num);
		}
	}
	public sealed class Affix
	{
		public string Id;

		public int Tier;

		public float Value;

		public Affix()
		{
		}

		public Affix(string id, int tier, float value)
		{
			Id = id;
			Tier = Math.Max(1, Math.Min(5, tier));
			Value = value;
		}

		public Affix Clone()
		{
			return new Affix(Id, Tier, Value);
		}

		public override string ToString()
		{
			return string.Format("{0}:{1}:{2}", Id, Tier, Value.ToString("0.##", CultureInfo.InvariantCulture));
		}
	}
	public struct Bonuses
	{
		public float DamagePct;

		public float ArmorPct;

		public float Health;

		public float Stamina;

		public float Eitr;

		public float MoveSpeedPct;

		public float BlockPct;

		public float DurabilityPct;

		public float Fire;

		public float Frost;

		public float Lightning;

		public float Poison;

		public float Spirit;

		public float Regen;

		public float StaminaRegenPct;

		public float EitrRegenPct;

		public float HealthRegenPct;

		public float StealthPct;

		public float DamageReductionPct;

		public float PoisonResistPct;

		public float FrostResistPct;

		public float FireResistPct;

		public float LightningResistPct;

		public float StaggerResistPct;

		public float KnockbackResistPct;

		public float FallDamageReductionPct;

		public float JumpHeightPct;

		public float SwimSpeedPct;

		public float DodgeStaminaPct;

		public float BlockStaminaPct;

		public float ParryBonusPct;

		public float BackstabPct;

		public float BossDamagePct;

		public float AnimalDamagePct;

		public float UndeadDamagePct;

		public float PickaxeDamagePct;

		public float ChopDamagePct;

		public float BowDamagePct;

		public float SpellDamagePct;

		public float ArmorPenPct;

		public float LowHealthDamagePct;

		public float FoodDurationPct;

		public float FoodRegenPct;

		public float RestedBonusPct;

		public float ExplosionResistPct;

		public float CraftingBonusPct;

		public float SneakDamagePct;

		public float ReflectDamagePct;

		public float ProjectileDeflectPct;

		public void Add(Bonuses other)
		{
			DamagePct += other.DamagePct;
			ArmorPct += other.ArmorPct;
			Health += other.Health;
			Stamina += other.Stamina;
			Eitr += other.Eitr;
			MoveSpeedPct += other.MoveSpeedPct;
			BlockPct += other.BlockPct;
			DurabilityPct += other.DurabilityPct;
			Fire += other.Fire;
			Frost += other.Frost;
			Lightning += other.Lightning;
			Poison += other.Poison;
			Spirit += other.Spirit;
			Regen += other.Regen;
			StaminaRegenPct += other.StaminaRegenPct;
			EitrRegenPct += other.EitrRegenPct;
			HealthRegenPct += other.HealthRegenPct;
			StealthPct += other.StealthPct;
			DamageReductionPct += other.DamageReductionPct;
			PoisonResistPct += other.PoisonResistPct;
			FrostResistPct += other.FrostResistPct;
			FireResistPct += other.FireResistPct;
			LightningResistPct += other.LightningResistPct;
			StaggerResistPct += other.StaggerResistPct;
			KnockbackResistPct += other.KnockbackResistPct;
			FallDamageReductionPct += other.FallDamageReductionPct;
			JumpHeightPct += other.JumpHeightPct;
			SwimSpeedPct += other.SwimSpeedPct;
			DodgeStaminaPct += other.DodgeStaminaPct;
			BlockStaminaPct += other.BlockStaminaPct;
			ParryBonusPct += other.ParryBonusPct;
			BackstabPct += other.BackstabPct;
			BossDamagePct += other.BossDamagePct;
			AnimalDamagePct += other.AnimalDamagePct;
			UndeadDamagePct += other.UndeadDamagePct;
			PickaxeDamagePct += other.PickaxeDamagePct;
			ChopDamagePct += other.ChopDamagePct;
			BowDamagePct += other.BowDamagePct;
			SpellDamagePct += other.SpellDamagePct;
			ArmorPenPct += other.ArmorPenPct;
			LowHealthDamagePct += other.LowHealthDamagePct;
			FoodDurationPct += other.FoodDurationPct;
			FoodRegenPct += other.FoodRegenPct;
			RestedBonusPct += other.RestedBonusPct;
			ExplosionResistPct += other.ExplosionResistPct;
			CraftingBonusPct += other.CraftingBonusPct;
			SneakDamagePct += other.SneakDamagePct;
			ReflectDamagePct += other.ReflectDamagePct;
			ProjectileDeflectPct += other.ProjectileDeflectPct;
		}

		public void AddStat(AffixStat stat, float value)
		{
			switch (stat)
			{
			case AffixStat.DamagePct:
				DamagePct += value;
				break;
			case AffixStat.ArmorPct:
				ArmorPct += value;
				break;
			case AffixStat.Health:
				Health += value;
				break;
			case AffixStat.Stamina:
				Stamina += value;
				break;
			case AffixStat.Eitr:
				Eitr += value;
				break;
			case AffixStat.MoveSpeedPct:
				MoveSpeedPct += value;
				break;
			case AffixStat.BlockPct:
				BlockPct += value;
				break;
			case AffixStat.DurabilityPct:
				DurabilityPct += value;
				break;
			case AffixStat.Fire:
				Fire += value;
				break;
			case AffixStat.Frost:
				Frost += value;
				break;
			case AffixStat.Lightning:
				Lightning += value;
				break;
			case AffixStat.Poison:
				Poison += value;
				break;
			case AffixStat.Spirit:
				Spirit += value;
				break;
			case AffixStat.Regen:
				Regen += value;
				break;
			case AffixStat.StaminaRegenPct:
				StaminaRegenPct += value;
				break;
			case AffixStat.EitrRegenPct:
				EitrRegenPct += value;
				break;
			case AffixStat.HealthRegenPct:
				HealthRegenPct += value;
				break;
			case AffixStat.StealthPct:
				StealthPct += value;
				break;
			case AffixStat.DamageReductionPct:
				DamageReductionPct += value;
				break;
			case AffixStat.PoisonResistPct:
				PoisonResistPct += value;
				break;
			case AffixStat.FrostResistPct:
				FrostResistPct += value;
				break;
			case AffixStat.FireResistPct:
				FireResistPct += value;
				break;
			case AffixStat.LightningResistPct:
				LightningResistPct += value;
				break;
			case AffixStat.StaggerResistPct:
				StaggerResistPct += value;
				break;
			case AffixStat.KnockbackResistPct:
				KnockbackResistPct += value;
				break;
			case AffixStat.FallDamageReductionPct:
				FallDamageReductionPct += value;
				break;
			case AffixStat.JumpHeightPct:
				JumpHeightPct += value;
				break;
			case AffixStat.SwimSpeedPct:
				SwimSpeedPct += value;
				break;
			case AffixStat.DodgeStaminaPct:
				DodgeStaminaPct += value;
				break;
			case AffixStat.BlockStaminaPct:
				BlockStaminaPct += value;
				break;
			case AffixStat.ParryBonusPct:
				ParryBonusPct += value;
				break;
			case AffixStat.BackstabPct:
				BackstabPct += value;
				break;
			case AffixStat.BossDamagePct:
				BossDamagePct += value;
				break;
			case AffixStat.AnimalDamagePct:
				AnimalDamagePct += value;
				break;
			case AffixStat.UndeadDamagePct:
				UndeadDamagePct += value;
				break;
			case AffixStat.PickaxeDamagePct:
				PickaxeDamagePct += value;
				break;
			case AffixStat.ChopDamagePct:
				ChopDamagePct += value;
				break;
			case AffixStat.BowDamagePct:
				BowDamagePct += value;
				break;
			case AffixStat.SpellDamagePct:
				SpellDamagePct += value;
				break;
			case AffixStat.ArmorPenPct:
				ArmorPenPct += value;
				break;
			case AffixStat.LowHealthDamagePct:
				LowHealthDamagePct += value;
				break;
			case AffixStat.FoodDurationPct:
				FoodDurationPct += value;
				break;
			case AffixStat.FoodRegenPct:
				FoodRegenPct += value;
				break;
			case AffixStat.RestedBonusPct:
				RestedBonusPct += value;
				break;
			case AffixStat.ExplosionResistPct:
				ExplosionResistPct += value;
				break;
			case AffixStat.CraftingBonusPct:
				CraftingBonusPct += value;
				break;
			case AffixStat.SneakDamagePct:
				SneakDamagePct += value;
				break;
			case AffixStat.ReflectDamagePct:
				ReflectDamagePct += value;
				break;
			case AffixStat.ProjectileDeflectPct:
				ProjectileDeflectPct += value;
				break;
			}
		}
	}
	public static class Affixes
	{
		public const int MaxSlots = 6;

		public const int MaxTier = 5;

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

		public static readonly AffixDef[] All = BuildCatalog();

		private static float[] TierWeights = new float[5] { 50f, 28f, 14f, 6f, 2f };

		public static AffixDef Def(string id)
		{
			if (string.IsNullOrEmpty(id))
			{
				return null;
			}
			if (!ById.TryGetValue(id, out var value))
			{
				return null;
			}
			return value;
		}

		public static string Name(Affix affix)
		{
			AffixDef affixDef = Def(affix?.Id);
			if (affixDef == null)
			{
				return "?";
			}
			if (!Settings.Russian.Value)
			{
				return affixDef.En;
			}
			return affixDef.Ru;
		}

		public static string Describe(Affix affix)
		{
			AffixDef affixDef = Def(affix?.Id);
			if (affixDef == null)
			{
				return "";
			}
			bool value = Settings.Russian.Value;
			float num = affix.Value * ((Settings.AffixPower != null) ? Settings.AffixPower.Value : 1f);
			List<string> list = new List<string>();
			for (int i = 0; i < affixDef.Stats.Length; i++)
			{
				StatWeight statWeight = affixDef.Stats[i];
				if (statWeight.Stat != AffixStat.None)
				{
					list.Add(FormatStat(statWeight.Stat, num * statWeight.Weight, IsPercent(statWeight.Stat), value));
				}
			}
			if (affixDef.HasProc)
			{
				string text = (value ? affixDef.HintRu : affixDef.HintEn);
				if (!string.IsNullOrEmpty(text))
				{
					bool flag = text.IndexOf("{1", StringComparison.Ordinal) >= 0;
					try
					{
						text = string.Format(CultureInfo.InvariantCulture, text, num * affixDef.ProcWeight, affixDef.Chance(affix.Tier) * 100f);
					}
					catch (FormatException)
					{
					}
					list.Add(text);
					if (flag && affixDef.Cooldown > 0.3f)
					{
						list.Add(value ? ("КД " + affixDef.Cooldown.ToString("0.#", CultureInfo.InvariantCulture) + " с") : ("CD " + affixDef.Cooldown.ToString("0.#", CultureInfo.InvariantCulture) + " s"));
					}
				}
			}
			return string.Join(value ? " · " : " · ", list);
		}

		public static bool IsPercent(AffixStat stat)
		{
			switch (stat)
			{
			case AffixStat.DamagePct:
			case AffixStat.ArmorPct:
			case AffixStat.MoveSpeedPct:
			case AffixStat.BlockPct:
			case AffixStat.DurabilityPct:
			case AffixStat.StaminaRegenPct:
			case AffixStat.EitrRegenPct:
			case AffixStat.HealthRegenPct:
			case AffixStat.StealthPct:
			case AffixStat.DamageReductionPct:
			case AffixStat.PoisonResistPct:
			case AffixStat.FrostResistPct:
			case AffixStat.FireResistPct:
			case AffixStat.LightningResistPct:
			case AffixStat.StaggerResistPct:
			case AffixStat.KnockbackResistPct:
			case AffixStat.FallDamageReductionPct:
			case AffixStat.JumpHeightPct:
			case AffixStat.SwimSpeedPct:
			case AffixStat.DodgeStaminaPct:
			case AffixStat.BlockStaminaPct:
			case AffixStat.ParryBonusPct:
			case AffixStat.BackstabPct:
			case AffixStat.BossDamagePct:
			case AffixStat.AnimalDamagePct:
			case AffixStat.UndeadDamagePct:
			case AffixStat.PickaxeDamagePct:
			case AffixStat.ChopDamagePct:
			case AffixStat.BowDamagePct:
			case AffixStat.SpellDamagePct:
			case AffixStat.ArmorPenPct:
			case AffixStat.LowHealthDamagePct:
			case AffixStat.FoodDurationPct:
			case AffixStat.FoodRegenPct:
			case AffixStat.RestedBonusPct:
			case AffixStat.ExplosionResistPct:
			case AffixStat.CraftingBonusPct:
			case AffixStat.SneakDamagePct:
			case AffixStat.ReflectDamagePct:
			case AffixStat.ProjectileDeflectPct:
				return true;
			default:
				return false;
			}
		}

		public static string StatName(AffixStat stat, bool ru)
		{
			switch (stat)
			{
			case AffixStat.DamagePct:
				if (!ru)
				{
					return "damage";
				}
				return "урона";
			case AffixStat.ArmorPct:
				if (!ru)
				{
					return "armor";
				}
				return "брони";
			case AffixStat.Health:
				if (!ru)
				{
					return "health";
				}
				return "здоровья";
			case AffixStat.Stamina:
				if (!ru)
				{
					return "stamina";
				}
				return "выносливости";
			case AffixStat.Eitr:
				if (!ru)
				{
					return "eitr";
				}
				return "эйтра";
			case AffixStat.MoveSpeedPct:
				if (!ru)
				{
					return "movement speed";
				}
				return "скорости";
			case AffixStat.BlockPct:
				if (!ru)
				{
					return "block";
				}
				return "блока";
			case AffixStat.DurabilityPct:
				if (!ru)
				{
					return "durability";
				}
				return "прочности";
			case AffixStat.Fire:
				if (!ru)
				{
					return "fire";
				}
				return "огня";
			case AffixStat.Frost:
				if (!ru)
				{
					return "frost";
				}
				return "мороза";
			case AffixStat.Lightning:
				if (!ru)
				{
					return "lightning";
				}
				return "молнии";
			case AffixStat.Poison:
				if (!ru)
				{
					return "poison";
				}
				return "яда";
			case AffixStat.Spirit:
				if (!ru)
				{
					return "spirit";
				}
				return "духа";
			case AffixStat.Regen:
				if (!ru)
				{
					return "HP/s";
				}
				return "HP/с";
			case AffixStat.StaminaRegenPct:
				if (!ru)
				{
					return "stamina regen";
				}
				return "регенерации выносливости";
			case AffixStat.EitrRegenPct:
				if (!ru)
				{
					return "eitr regen";
				}
				return "регенерации эйтра";
			case AffixStat.HealthRegenPct:
				if (!ru)
				{
					return "health regen";
				}
				return "регенерации здоровья";
			case AffixStat.StealthPct:
				if (!ru)
				{
					return "stealth";
				}
				return "скрытности";
			case AffixStat.DamageReductionPct:
				if (!ru)
				{
					return "damage reduction";
				}
				return "снижения урона";
			case AffixStat.PoisonResistPct:
				if (!ru)
				{
					return "poison resistance";
				}
				return "сопр. яду";
			case AffixStat.FrostResistPct:
				if (!ru)
				{
					return "frost resistance";
				}
				return "сопр. морозу";
			case AffixStat.FireResistPct:
				if (!ru)
				{
					return "fire resistance";
				}
				return "сопр. огню";
			case AffixStat.LightningResistPct:
				if (!ru)
				{
					return "lightning resistance";
				}
				return "сопр. молнии";
			case AffixStat.StaggerResistPct:
				if (!ru)
				{
					return "stagger resistance";
				}
				return "сопр. оглушению";
			case AffixStat.KnockbackResistPct:
				if (!ru)
				{
					return "knockback resistance";
				}
				return "сопр. отбрасыванию";
			case AffixStat.FallDamageReductionPct:
				if (!ru)
				{
					return "fall protection";
				}
				return "защиты от падения";
			case AffixStat.JumpHeightPct:
				if (!ru)
				{
					return "jump height";
				}
				return "высоты прыжка";
			case AffixStat.SwimSpeedPct:
				if (!ru)
				{
					return "swim speed";
				}
				return "скорости плавания";
			case AffixStat.DodgeStaminaPct:
				if (!ru)
				{
					return "dodge stamina";
				}
				return "экономии рывка";
			case AffixStat.BlockStaminaPct:
				if (!ru)
				{
					return "block stamina";
				}
				return "экономии блока";
			case AffixStat.ParryBonusPct:
				if (!ru)
				{
					return "parry power";
				}
				return "силы парирования";
			case AffixStat.BackstabPct:
				if (!ru)
				{
					return "backstab damage";
				}
				return "урона в спину";
			case AffixStat.BossDamagePct:
				if (!ru)
				{
					return "boss damage";
				}
				return "урона по боссам";
			case AffixStat.AnimalDamagePct:
				if (!ru)
				{
					return "beast damage";
				}
				return "урона по зверям";
			case AffixStat.UndeadDamagePct:
				if (!ru)
				{
					return "undead damage";
				}
				return "урона по нежити";
			case AffixStat.PickaxeDamagePct:
				if (!ru)
				{
					return "pickaxe damage";
				}
				return "урона киркой";
			case AffixStat.ChopDamagePct:
				if (!ru)
				{
					return "chopping damage";
				}
				return "урона рубке";
			case AffixStat.BowDamagePct:
				if (!ru)
				{
					return "bow damage";
				}
				return "урона из лука";
			case AffixStat.SpellDamagePct:
				if (!ru)
				{
					return "spell damage";
				}
				return "урона заклинаний";
			case AffixStat.ArmorPenPct:
				if (!ru)
				{
					return "armor penetration";
				}
				return "пробития брони";
			case AffixStat.LowHealthDamagePct:
				if (!ru)
				{
					return "low-health damage";
				}
				return "урона при низком HP";
			case AffixStat.FoodDurationPct:
				if (!ru)
				{
					return "food duration";
				}
				return "длительности еды";
			case AffixStat.FoodRegenPct:
				if (!ru)
				{
					return "food value";
				}
				return "пользы от еды";
			case AffixStat.RestedBonusPct:
				if (!ru)
				{
					return "comfort";
				}
				return "комфорта";
			case AffixStat.ExplosionResistPct:
				if (!ru)
				{
					return "blast resistance";
				}
				return "сопр. взрывам";
			case AffixStat.CraftingBonusPct:
				if (!ru)
				{
					return "crafting quality";
				}
				return "качества ремесла";
			case AffixStat.SneakDamagePct:
				if (!ru)
				{
					return "sneak damage";
				}
				return "урона из скрытности";
			case AffixStat.ReflectDamagePct:
				if (!ru)
				{
					return "damage reflect";
				}
				return "отражения урона";
			case AffixStat.ProjectileDeflectPct:
				if (!ru)
				{
					return "projectile deflect";
				}
				return "отражения снарядов";
			default:
				return "";
			}
		}

		public static string FormatStat(AffixStat stat, float value, bool percent, bool ru)
		{
			string text = (percent ? (value.ToString("0.#", CultureInfo.InvariantCulture) + "%") : value.ToString("0.#", CultureInfo.InvariantCulture));
			string text2 = StatName(stat, ru);
			return "+" + text + ((text2.Length > 0) ? (" " + text2) : "");
		}

		public static Affix Roll(int tier, AffixPool pool)
		{
			tier = Math.Max(1, Math.Min(5, tier));
			AffixDef[] array = ForPool(pool);
			AffixDef affixDef = array[Random.Range(0, array.Length)];
			float value = ((affixDef.Stats.Length != 0) ? RollStatValue(affixDef, tier) : RollProcValue(tier));
			return new Affix(affixDef.Id, tier, value);
		}

		public static float RollValue(AffixDef def, int tier)
		{
			tier = Math.Max(1, Math.Min(5, tier));
			if (def == null)
			{
				return 0f;
			}
			if (def.Stats.Length == 0)
			{
				return RollProcValue(tier);
			}
			return RollStatValue(def, tier);
		}

		private static float RollStatValue(AffixDef def, int tier)
		{
			return 4f * (float)tier + Random.Range(0f, 2f * (float)tier);
		}

		private static float RollProcValue(int tier)
		{
			return 6f * (float)tier + Random.Range(0f, 3f * (float)tier);
		}

		public static Affix RollForLevel(int level, AffixPool pool, int minTier = 1)
		{
			int num = TierForLevel(Math.Max(1, level));
			int num2 = Math.Max(1, Math.Min(num, minTier));
			if (num2 >= num)
			{
				return Roll(num, pool);
			}
			float num3 = 0f;
			for (int i = num2 - 1; i < num; i++)
			{
				num3 += TierWeights[i];
			}
			float num4 = Random.Range(0f, num3);
			for (int j = num2 - 1; j < num; j++)
			{
				num4 -= TierWeights[j];
				if (num4 <= 0f)
				{
					return Roll(j + 1, pool);
				}
			}
			return Roll(num, pool);
		}

		public static Affix RollForLevel(int level, AffixPool pool, IList<Affix> existing, int minTier = 1)
		{
			Affix affix = RollForLevel(level, pool, minTier);
			if (existing == null || existing.Count == 0)
			{
				return affix;
			}
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			for (int i = 0; i < existing.Count; i++)
			{
				if (existing[i] != null)
				{
					hashSet.Add(existing[i].Id);
				}
			}
			if (!hashSet.Contains(affix.Id))
			{
				return affix;
			}
			AffixDef[] array = ForPool(pool);
			List<AffixDef> list = new List<AffixDef>();
			for (int j = 0; j < array.Length; j++)
			{
				if (!hashSet.Contains(array[j].Id))
				{
					list.Add(array[j]);
				}
			}
			if (list.Count == 0)
			{
				return affix;
			}
			AffixDef affixDef = list[Random.Range(0, list.Count)];
			float value = ((affixDef.Stats.Length != 0) ? RollStatValue(affixDef, affix.Tier) : RollProcValue(affix.Tier));
			return new Affix(affixDef.Id, affix.Tier, value);
		}

		public static AffixPool PoolFor(ItemData item)
		{
			return ItemCatalog.PoolFor(item);
		}

		public static AffixDef[] ForPool(AffixPool pool)
		{
			List<AffixDef> list = new List<AffixDef>();
			for (int i = 0; i < All.Length; i++)
			{
				if ((All[i].Pool & pool) != AffixPool.None)
				{
					list.Add(All[i]);
				}
			}
			if (list.Count <= 0)
			{
				return All;
			}
			return list.ToArray();
		}

		public static string PoolName(AffixPool pool)
		{
			bool value = Settings.Russian.Value;
			switch (pool)
			{
			case AffixPool.Armor:
				if (!value)
				{
					return "ARMOR";
				}
				return "БРОНЯ";
			case AffixPool.Shield:
				if (!value)
				{
					return "SHIELD";
				}
				return "ЩИТ";
			default:
				if (!value)
				{
					return "WEAPON";
				}
				return "ОРУЖИЕ";
			}
		}

		public static int TierForLevel(int level)
		{
			if (level >= 17)
			{
				return 5;
			}
			if (level >= 13)
			{
				return 4;
			}
			if (level >= 9)
			{
				return 3;
			}
			if (level >= 5)
			{
				return 2;
			}
			return 1;
		}

		public static int SlotsForLevel(int level)
		{
			if (level >= 18)
			{
				return 6;
			}
			if (level >= 15)
			{
				return 5;
			}
			if (level >= 12)
			{
				return 4;
			}
			if (level >= 9)
			{
				return 3;
			}
			if (level >= 6)
			{
				return 2;
			}
			if (level >= 3)
			{
				return 1;
			}
			return 0;
		}

		public static string Serialize(Affix[] slots)
		{
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < 6; i++)
			{
				if (i > 0)
				{
					stringBuilder.Append(';');
				}
				Affix affix = ((slots != null && i < slots.Length) ? slots[i] : null);
				if (affix != null)
				{
					stringBuilder.Append(affix);
				}
			}
			return stringBuilder.ToString();
		}

		public static Affix[] Deserialize(string raw)
		{
			Affix[] array = new Affix[6];
			if (string.IsNullOrEmpty(raw))
			{
				return array;
			}
			string[] array2 = raw.Split(';');
			for (int i = 0; i < 6 && i < array2.Length; i++)
			{
				string text = array2[i];
				if (!string.IsNullOrEmpty(text))
				{
					string[] array3 = text.Split(':');
					if (array3.Length >= 3 && int.TryParse(array3[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && float.TryParse(array3[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && Def(array3[0]) != null)
					{
						array[i] = new Affix(array3[0], result, result2);
					}
				}
			}
			return array;
		}

		public static void AddBonuses(IEnumerable<Affix> affixes, ref Bonuses bonuses)
		{
			if (affixes == null)
			{
				return;
			}
			float num = ((Settings.AffixPower != null) ? Settings.AffixPower.Value : 1f);
			foreach (Affix affix in affixes)
			{
				AffixDef affixDef = Def(affix?.Id);
				if (affixDef != null)
				{
					float num2 = affix.Value * num;
					for (int i = 0; i < affixDef.Stats.Length; i++)
					{
						StatWeight statWeight = affixDef.Stats[i];
						bonuses.AddStat(statWeight.Stat, num2 * statWeight.Weight);
					}
				}
			}
		}

		private static StatWeight[] S(params StatWeight[] weights)
		{
			return weights;
		}

		private static StatWeight W(AffixStat stat, float weight = 1f)
		{
			return new StatWeight(stat, weight);
		}

		private static AffixDef Stat(string id, AffixPool pool, string ru, string en, params StatWeight[] stats)
		{
			return new AffixDef(id, pool, S(stats), AffixProc.None, 0f, 0f, 0f, procPercent: false, ru, en);
		}

		private static AffixDef Proc(string id, AffixPool pool, AffixProc proc, float chancePerTier, float cooldown, float weight, bool percent, string ru, string en, string hintRu, string hintEn)
		{
			return new AffixDef(id, pool, S(), proc, chancePerTier, cooldown, weight, percent, ru, en, hintRu, hintEn);
		}

		private static AffixDef Mix(string id, AffixPool pool, AffixProc proc, float chancePerTier, float cooldown, float weight, bool percent, string ru, string en, string hintRu, string hintEn, params StatWeight[] stats)
		{
			return new AffixDef(id, pool, S(stats), proc, chancePerTier, cooldown, weight, percent, ru, en, hintRu, hintEn);
		}

		private static AffixDef[] BuildCatalog()
		{
			List<AffixDef> list = new List<AffixDef>();
			list.Add(Stat("hunters_mark", AffixPool.Weapon, "Метка охотника", "Hunter's Mark", W(AffixStat.AnimalDamagePct)));
			list.Add(Stat("miners_joy", AffixPool.Weapon, "Радость шахтёра", "Miner's Joy", W(AffixStat.PickaxeDamagePct, 0.8f), W(AffixStat.Stamina, 0.25f)));
			list.Add(Stat("lumberjacks_edge", AffixPool.Weapon, "Грань лесоруба", "Lumberjack's Edge", W(AffixStat.ChopDamagePct, 0.8f), W(AffixStat.Stamina, 0.25f)));
			list.Add(Mix("precise_draw", AffixPool.Weapon, AffixProc.None, 0f, 0f, 0f, false, "Точный натяг", "Precise Draw", null, null, W(AffixStat.BowDamagePct, 0.8f), W(AffixStat.StaminaRegenPct, 0.2f)));
			list.Add(Proc("heavy_stagger", AffixPool.Weapon, AffixProc.Stagger, 0.05f, 7f, 1f, percent: false, "Тяжёлый удар", "Heavy Stagger", "шанс {1:0.#}%: оглушает цель", "chance {1:0.#}%: staggers the target"));
			list.Add(Proc("bloodlust", AffixPool.Weapon, AffixProc.Lifesteal, 1f, 0f, 0.4f, percent: true, "Жажда крови", "Bloodlust", "возвращает {0:0.#}% урона здоровьем", "returns {0:0.#}% damage as health"));
			list.Add(Mix("piercing_strike", AffixPool.Weapon, AffixProc.None, 0f, 0f, 0f, false, "Пронзающий удар", "Piercing Strike", null, null, W(AffixStat.ArmorPenPct, 0.7f), W(AffixStat.DamagePct, 0.2f)));
			list.Add(Mix("hallowed_spirit", AffixPool.Weapon, AffixProc.None, 0f, 0f, 0f, false, "Священный дух", "Hallowed Spirit", null, null, W(AffixStat.UndeadDamagePct, 0.7f), W(AffixStat.Spirit, 0.5f)));
			list.Add(Proc("frostbite_strike", AffixPool.Weapon, AffixProc.Frostbite, 0.35f, 0f, 0.7f, percent: false, "Ледяной укус", "Frostbite Strike", "наносит +{0:0.#} мороза и замедляет", "deals +{0:0.#} frost and slows"));
			list.Add(Proc("hellfire_burn", AffixPool.Weapon, AffixProc.Ignite, 0.35f, 0f, 0.7f, percent: false, "Адское пламя", "Hellfire Burn", "наносит +{0:0.#} огня и поджигает", "deals +{0:0.#} fire and ignites"));
			list.Add(Proc("thors_voice", AffixPool.Weapon, AffixProc.ChainLightning, 0.2f, 5f, 0.8f, percent: false, "Голос Тора", "Thor's Voice", "шанс {1:0.#}%: цепная молния на {0:0.#} урона", "chance {1:0.#}%: chain lightning for {0:0.#}"));
			list.Add(Mix("channeler_eitr", AffixPool.Weapon, AffixProc.None, 0f, 0f, 0f, false, "Проводник эйтра", "Channeler", null, null, W(AffixStat.EitrRegenPct, 0.7f), W(AffixStat.SpellDamagePct, 0.5f)));
			list.Add(Proc("serrated_edge", AffixPool.Weapon, AffixProc.Bleed, 0.3f, 0f, 0.5f, percent: false, "Зазубренное лезвие", "Serrated Edge", "шанс {1:0.#}%: кровотечение на {0:0.#} урона", "chance {1:0.#}%: bleed for {0:0.#}"));
			list.Add(Mix("duelist_focus", AffixPool.Weapon, AffixProc.None, 0f, 0f, 0f, false, "Стойка дуэлянта", "Duelist Focus", null, null, W(AffixStat.DamagePct, 0.5f), W(AffixStat.ParryBonusPct, 0.5f)));
			list.Add(Proc("pushback_wave", AffixPool.Weapon, AffixProc.Knockback, 0.2f, 8f, 1f, percent: false, "Волна отбрасывания", "Pushback Wave", "шанс {1:0.#}%: отбрасывает врагов", "chance {1:0.#}%: knocks enemies back"));
			list.Add(Mix("gale_force", AffixPool.Weapon, AffixProc.None, 0f, 0f, 0f, false, "Сила ветра", "Gale Force", null, null, W(AffixStat.StaminaRegenPct, 0.7f), W(AffixStat.MoveSpeedPct, 0.15f)));
			list.Add(Proc("rooting_strike", AffixPool.Weapon, AffixProc.Root, 0.15f, 9f, 1f, percent: false, "Сковывающий удар", "Rooting Strike", "шанс {1:0.#}%: обездвиживает цель", "chance {1:0.#}%: roots the target"));
			list.Add(Stat("backstabber_pro", AffixPool.Weapon, "Мастер спины", "Backstabber", W(AffixStat.BackstabPct), W(AffixStat.SneakDamagePct, 0.4f)));
			list.Add(Stat("boss_bane", AffixPool.Weapon, "Погибель боссов", "Boss Bane", W(AffixStat.BossDamagePct)));
			list.Add(Proc("shattering_blow", AffixPool.Weapon, AffixProc.ArmorBreak, 0.2f, 10f, 1f, percent: true, "Дробящий удар", "Shattering Blow", "шанс {1:0.#}%: снижает броню на {0:0.#}%", "chance {1:0.#}%: reduces armor by {0:0.#}%"));
			list.Add(Proc("phantom_strike", AffixPool.Weapon, AffixProc.ExtraHit, 0.12f, 4f, 0.6f, percent: true, "Призрачный удар", "Phantom Strike", "шанс {1:0.#}%: повторный удар на {0:0.#}% урона", "chance {1:0.#}%: extra hit for {0:0.#}% damage"));
			list.Add(Proc("earth_shaker", AffixPool.Weapon, AffixProc.EarthSlam, 0.1f, 12f, 0.8f, percent: false, "Землетряс", "Earth Shaker", "шанс {1:0.#}%: удар по земле на {0:0.#} урона", "chance {1:0.#}%: ground slam for {0:0.#}"));
			list.Add(Proc("harpooner_static", AffixPool.Weapon, AffixProc.PullLightning, 0.18f, 7f, 0.7f, percent: false, "Гарпун-разряд", "Harpooner Static", "шанс {1:0.#}%: притягивает и бьёт молнией на {0:0.#}", "chance {1:0.#}%: pulls and zaps for {0:0.#}"));
			list.Add(Mix("slinger_speed", AffixPool.Weapon, AffixProc.None, 0f, 0f, 0f, false, "Скорость пращника", "Slinger Speed", null, null, W(AffixStat.StaminaRegenPct, 0.6f), W(AffixStat.MoveSpeedPct, 0.2f)));
			list.Add(Mix("winded_strike", AffixPool.Weapon, AffixProc.None, 0f, 0f, 0f, false, "Дыхание в ударе", "Winded Strike", null, null, W(AffixStat.Stamina, 0.5f), W(AffixStat.StaminaRegenPct, 0.5f)));
			list.Add(Proc("soul_reaper", AffixPool.Weapon, AffixProc.SoulDrain, 0.15f, 4f, 0.6f, percent: false, "Жнец душ", "Soul Reaper", "шанс {1:0.#}%: добивает слабую цель и лечит на {0:0.#}", "chance {1:0.#}%: executes and heals {0:0.#}"));
			list.Add(Proc("vermin_host", AffixPool.Weapon, AffixProc.SummonVermin, 0.08f, 18f, 1f, percent: false, "Хозяин паразитов", "Vermin Host", "шанс {1:0.#}%: призывает паразитов", "chance {1:0.#}%: summons vermin"));
			list.Add(Proc("echoing_strike", AffixPool.Weapon, AffixProc.Echo, 0.12f, 6f, 0.5f, percent: true, "Эхо удара", "Echoing Strike", "шанс {1:0.#}%: эхо на {0:0.#}% урона", "chance {1:0.#}%: echo for {0:0.#}% damage"));
			list.Add(Mix("chrono_parry", AffixPool.Weapon, AffixProc.ParrySlow, 0.25f, 8f, 0.4f, true, "Хроно-парирование", "Chrono Parry", "идеальный блок замедляет врагов на {0:0.#}%", "perfect block slows enemies by {0:0.#}%", W(AffixStat.ParryBonusPct, 0.6f)));
			list.Add(Proc("phase_shift", AffixPool.Weapon, AffixProc.PhaseShift, 0.08f, 12f, 1f, percent: false, "Фазовый сдвиг", "Phase Shift", "шанс {1:0.#}%: уклонение от удара", "chance {1:0.#}%: dodge the hit"));
			list.Add(Proc("catalyst_wet", AffixPool.Weapon, AffixProc.Combust, 0.2f, 6f, 0.8f, percent: false, "Мокрый катализатор", "Catalyst Wet", "шанс {1:0.#}%: взрыв пара на {0:0.#} урона", "chance {1:0.#}%: steam burst for {0:0.#}"));
			list.Add(Proc("executioner_stagger", AffixPool.Weapon, AffixProc.Execute, 0.5f, 2f, 0.5f, percent: false, "Казнь", "Executioner", "добивает цель ниже {0:0.#}% HP и оглушает", "executes below {0:0.#}% HP and staggers"));
			list.Add(Proc("triumphant_strike", AffixPool.Weapon, AffixProc.OnKillBuff, 0.15f, 10f, 0.5f, percent: true, "Триумф", "Triumphant Strike", "шанс {1:0.#}%: +{0:0.#}% урона на 10 с", "chance {1:0.#}%: +{0:0.#}% damage for 10 s"));
			list.Add(Proc("chain_combustion", AffixPool.Weapon, AffixProc.Combust, 0.15f, 7f, 1f, percent: false, "Цепное возгорание", "Chain Combustion", "шанс {1:0.#}%: огненный взрыв на {0:0.#}", "chance {1:0.#}%: fire burst for {0:0.#}"));
			list.Add(Proc("seismic_slam", AffixPool.Weapon, AffixProc.EarthSlam, 0.08f, 15f, 1.2f, percent: false, "Сейсмический удар", "Seismic Slam", "шанс {1:0.#}%: сейсмический удар на {0:0.#}", "chance {1:0.#}%: seismic slam for {0:0.#}"));
			list.Add(Proc("decay_strike", AffixPool.Weapon, AffixProc.Decay, 0.3f, 0f, 0.6f, percent: false, "Удар тлена", "Decay Strike", "шанс {1:0.#}%: яд на {0:0.#} урона", "chance {1:0.#}%: poison for {0:0.#}"));
			list.Add(Proc("weakness_found", AffixPool.Weapon, AffixProc.Weakness, 0.25f, 6f, 0.3f, percent: true, "Найденная слабость", "Weakness Found", "шанс {1:0.#}%: +{0:0.#}% урона по оглушённым", "chance {1:0.#}%: +{0:0.#}% vs staggered"));
			list.Add(Proc("riposte_dodge", AffixPool.Weapon, AffixProc.Riposte, 0.2f, 8f, 0.6f, percent: true, "Ответный рывок", "Riposte", "шанс {1:0.#}%: контратака после уклонения на {0:0.#}%", "chance {1:0.#}%: counter after dodge for {0:0.#}%"));
			list.Add(Mix("giant_slayer", AffixPool.Weapon, AffixProc.GiantSlayer, 0.1f, 8f, 0.8f, true, "Убийца великанов", "Giant Slayer", "шанс {1:0.#}%: +{0:0.#}% урона по крупным врагам", "chance {1:0.#}%: +{0:0.#}% vs large foes", W(AffixStat.DamagePct, 0.3f)));
			list.Add(Stat("lightfoot", AffixPool.Armor | AffixPool.Shield, "Лёгкая поступь", "Lightfoot", W(AffixStat.MoveSpeedPct, 0.6f), W(AffixStat.FallDamageReductionPct, 0.4f)));
			list.Add(Stat("refreshing_stamina", AffixPool.Armor | AffixPool.Shield, "Бодрость", "Refreshing Stamina", W(AffixStat.StaminaRegenPct)));
			list.Add(Mix("shaded_stealth", AffixPool.Armor, AffixProc.None, 0f, 0f, 0f, false, "Тень", "Shaded", null, null, W(AffixStat.StealthPct, 0.8f), W(AffixStat.SneakDamagePct, 0.2f)));
			list.Add(Stat("thick_skinned", AffixPool.Armor, "Толстая шкура", "Thick Skinned", W(AffixStat.ArmorPct, 0.6f), W(AffixStat.DamageReductionPct, 0.4f)));
			list.Add(Stat("antivenom_proof", AffixPool.Armor | AffixPool.Shield, "Противоядие", "Antivenom Proof", W(AffixStat.PoisonResistPct)));
			list.Add(Proc("leech_touch", AffixPool.Armor | AffixPool.Shield, AffixProc.Lifesteal, 1f, 0f, 0.3f, percent: true, "Прикосновение пиявки", "Leech Touch", "возвращает {0:0.#}% урона здоровьем", "returns {0:0.#}% damage as health"));
			list.Add(Mix("ymirs_warmth", AffixPool.Armor, AffixProc.None, 0f, 0f, 0f, false, "Тепло Имира", "Ymir's Warmth", null, null, W(AffixStat.FrostResistPct, 0.8f), W(AffixStat.HealthRegenPct, 0.2f)));
			list.Add(Stat("mountaineer_climb", AffixPool.Armor, "Скалолаз", "Mountaineer", W(AffixStat.JumpHeightPct, 0.7f), W(AffixStat.FallDamageReductionPct, 0.5f)));
			list.Add(Stat("odins_fury", AffixPool.Armor | AffixPool.Shield, "Ярость Одина", "Odin's Fury", W(AffixStat.LowHealthDamagePct)));
			list.Add(Stat("windrider_mobility", AffixPool.Armor, "Ветрокрылый", "Windrider", W(AffixStat.MoveSpeedPct, 0.8f), W(AffixStat.StaminaRegenPct, 0.2f)));
			list.Add(Mix("yggdrasils_core", AffixPool.Armor, AffixProc.None, 0f, 0f, 0f, false, "Сердце Иггдрасиля", "Yggdrasil's Core", null, null, W(AffixStat.Health, 0.7f), W(AffixStat.HealthRegenPct, 0.3f)));
			list.Add(Mix("deceiver_mist", AffixPool.Armor, AffixProc.None, 0f, 0f, 0f, false, "Обман тумана", "Deceiver Mist", null, null, W(AffixStat.StealthPct, 0.7f), W(AffixStat.MoveSpeedPct, 0.2f)));
			list.Add(Mix("magma_core", AffixPool.Armor | AffixPool.Shield, AffixProc.MagmaAura, 0.5f, 2f, 0.5f, false, "Магмовое ядро", "Magma Core", "жжёт врагов рядом на {0:0.#} урона", "burns nearby enemies for {0:0.#}", W(AffixStat.FireResistPct, 0.6f)));
			list.Add(Proc("phoenix_rise", AffixPool.Armor | AffixPool.Shield, AffixProc.Phoenix, 0.5f, 90f, 2f, percent: true, "Восход Феникса", "Phoenix Rise", "при падении ниже 25% HP восстанавливает {0:0.#}% здоровья", "below 25% HP restores {0:0.#}% health"));
			list.Add(Mix("absolute_zero_aura", AffixPool.Armor | AffixPool.Shield, AffixProc.FrostAura, 0.5f, 2f, 0.5f, false, "Аура абсолютного нуля", "Absolute Zero Aura", "замораживает врагов рядом на {0:0.#} урона", "freezes nearby enemies for {0:0.#}", W(AffixStat.FrostResistPct, 0.4f)));
			list.Add(Stat("heavyweight_bulk", AffixPool.Armor, "Тяжёлая масса", "Heavyweight", W(AffixStat.ArmorPct, 0.7f), W(AffixStat.KnockbackResistPct, 0.4f)));
			list.Add(Stat("shield_wall_block", AffixPool.Shield, "Стена щитов", "Shield Wall", W(AffixStat.BlockPct), W(AffixStat.BlockStaminaPct, 0.2f)));
			list.Add(Mix("spike_armor_return", AffixPool.Armor | AffixPool.Shield, AffixProc.ThornReflect, 0.5f, 0f, 0.6f, true, "Шипастая броня", "Spike Armor", "возвращает {0:0.#}% полученного урона", "returns {0:0.#}% damage taken", W(AffixStat.ArmorPct, 0.3f)));
			list.Add(Mix("kinetic_charge_shield", AffixPool.Shield, AffixProc.BlockCharge, 0.4f, 8f, 0.6f, true, "Кинетический заряд", "Kinetic Charge", "блок заряжает удар на {0:0.#}% урона", "block charges a strike for {0:0.#}% damage", W(AffixStat.BlockPct, 0.3f)));
			list.Add(Mix("last_stand_shield", AffixPool.Shield, AffixProc.LastStand, 0.5f, 45f, 1.2f, true, "Последний рубеж", "Last Stand", "при HP ниже 30% даёт {0:0.#}% брони на 10 с", "below 30% HP grants {0:0.#}% armor for 10 s", W(AffixStat.BlockPct, 0.3f), W(AffixStat.ArmorPct, 0.3f)));
			list.Add(Proc("einherjars_will_buff", AffixPool.Armor | AffixPool.Shield, AffixProc.Vengeance, 0.3f, 8f, 0.5f, percent: true, "Воля эйнхерия", "Einherjar's Will", "блок даёт +{0:0.#}% урона на 8 с", "block grants +{0:0.#}% damage for 8 s"));
			list.Add(Stat("stonewall_resistance", AffixPool.Armor | AffixPool.Shield, "Каменная стена", "Stonewall", W(AffixStat.StaggerResistPct, 0.8f), W(AffixStat.KnockbackResistPct, 0.2f)));
			list.Add(Mix("impact_absorb_buff", AffixPool.Armor | AffixPool.Shield, AffixProc.AbsorbImpact, 0.25f, 6f, 0.5f, true, "Поглощение удара", "Impact Absorb", "шанс {1:0.#}%: поглощает удар и даёт {0:0.#}% брони", "chance {1:0.#}%: absorbs a hit and grants {0:0.#}% armor", W(AffixStat.DamageReductionPct, 0.4f)));
			list.Add(Mix("second_wind_stamina", AffixPool.Armor, AffixProc.SecondWind, 0.35f, 20f, 1f, true, "Второе дыхание", "Second Wind", "при нехватке выносливости возвращает {0:0.#}% запаса", "when exhausted restores {0:0.#}% stamina", W(AffixStat.StaminaRegenPct, 0.4f)));
			list.Add(Stat("acrobatic_dodge", AffixPool.Armor, "Акробатика", "Acrobatic Dodge", W(AffixStat.DodgeStaminaPct), W(AffixStat.MoveSpeedPct, 0.1f)));
			list.Add(Stat("wave_runner_swim", AffixPool.Armor, "Бегун волн", "Wave Runner", W(AffixStat.SwimSpeedPct, 0.8f), W(AffixStat.StaminaRegenPct, 0.2f)));
			list.Add(Mix("spook_invisibility", AffixPool.Armor, AffixProc.Invisibility, 0.5f, 2f, 1f, false, "Призрачная тень", "Spook", "в приседе маскирует вас от врагов", "crouching hides you from enemies", W(AffixStat.StealthPct, 0.6f)));
			list.Add(Mix("pathfinder_map", AffixPool.Armor, AffixProc.None, 0f, 0f, 0f, false, "Путеводная карта", "Pathfinder", null, null, W(AffixStat.MoveSpeedPct, 0.4f), W(AffixStat.StealthPct, 0.3f)));
			list.Add(Stat("artisan_bench", AffixPool.Armor, "Верстак мастера", "Artisan Bench", W(AffixStat.DurabilityPct, 0.7f), W(AffixStat.RestedBonusPct, 0.3f)));
			list.Add(Mix("deep_breath_water", AffixPool.Armor, AffixProc.WaterBreath, 0.5f, 2f, 1f, false, "Глубокий вдох", "Deep Breath", "позволяет дышать под водой", "lets you breathe underwater", W(AffixStat.SwimSpeedPct, 0.3f)));
			list.Add(Stat("well_fed_buff", AffixPool.Armor, "Сытость", "Well Fed", W(AffixStat.FoodDurationPct, 0.8f), W(AffixStat.Health, 0.2f)));
			list.Add(Mix("metabolism_boost", AffixPool.Armor, AffixProc.None, 0f, 0f, 0f, false, "Ускоренный обмен", "Metabolism", null, null, W(AffixStat.FoodRegenPct, 0.5f), W(AffixStat.HealthRegenPct, 0.4f)));
			list.Add(Mix("waterproof_rain", AffixPool.Armor, AffixProc.RainProof, 0.5f, 2f, 1f, false, "Дождевик", "Waterproof", "дождь и сырость не мешают", "rain and wet do not hinder you", W(AffixStat.PoisonResistPct, 0.2f)));
			list.Add(Mix("night_stalker_buff", AffixPool.Armor, AffixProc.NightBuff, 0.5f, 2f, 0.35f, true, "Ночной охотник", "Night Stalker", "ночью +{0:0.#}% урона и скрытности", "at night +{0:0.#}% damage and stealth", W(AffixStat.StealthPct, 0.3f)));
			list.Add(Mix("sun_blessed_buff", AffixPool.Armor, AffixProc.DayBuff, 0.5f, 2f, 0.35f, true, "Благословение солнца", "Sun Blessed", "днём +{0:0.#}% здоровья и регенерации", "by day +{0:0.#}% health and regen", W(AffixStat.HealthRegenPct, 0.2f)));
			list.Add(Stat("storm_shield_buff", AffixPool.Armor | AffixPool.Shield, "Штормовой щит", "Storm Shield", W(AffixStat.LightningResistPct)));
			list.Add(Stat("homebound_rest", AffixPool.Armor, "Домашний уют", "Homebound Rest", W(AffixStat.RestedBonusPct, 0.8f), W(AffixStat.StaminaRegenPct, 0.2f)));
			list.Add(Mix("mana_shield_eitr", AffixPool.Armor | AffixPool.Shield, AffixProc.EitrShield, 0.5f, 0f, 0.8f, true, "Эйтровый щит", "Mana Shield", "{0:0.#}% урона оплачивается эйтром", "{0:0.#}% of damage is paid with eitr", W(AffixStat.Eitr, 0.4f)));
			list.Add(Mix("warp_field_deflect", AffixPool.Armor | AffixPool.Shield, AffixProc.Deflect, 0.15f, 0f, 1f, false, "Поле искажения", "Warp Field", "шанс {1:0.#}%: отражает снаряд", "chance {1:0.#}%: deflects a projectile", W(AffixStat.DamageReductionPct, 0.2f)));
			list.Add(Mix("eitr_trail_sprint", AffixPool.Armor, AffixProc.SprintTrail, 0.5f, 3f, 0.5f, true, "Эйтровый след", "Eitr Trail", "бег оставляет эйтровый след ({0:0.#} урона)", "sprinting leaves an eitr trail ({0:0.#} damage)", W(AffixStat.StaminaRegenPct, 0.3f)));
			list.Add(Stat("blast_proof_self", AffixPool.Armor | AffixPool.Shield, "Взрывостойкость", "Blast Proof", W(AffixStat.ExplosionResistPct, 0.8f), W(AffixStat.DamageReductionPct, 0.2f)));
			List<AffixDef> list2 = list;
			ById.Clear();
			for (int i = 0; i < list2.Count; i++)
			{
				ById[list2[i].Id] = list2[i];
			}
			return list2.ToArray();
		}
	}
	public enum EnchantOutcome
	{
		Success,
		SafeFail,
		Downgrade,
		Destroyed,
		NoItem,
		NoScroll,
		MaxLevel,
		TierTooLow
	}
	public static class EnchantService
	{
		public const int RerollCost = 25;

		public const int LockCost = 40;

		public const int TransmuteCount = 3;

		private static readonly MethodInfo InventoryChanged = AccessTools.Method(typeof(Inventory), "Changed", new Type[2]
		{
			typeof(bool),
			typeof(bool)
		}, (Type[])null);

		private static readonly float[] Chances = new float[21]
		{
			0f, 100f, 95f, 90f, 82f, 76f, 70f, 62f, 55f, 48f,
			42f, 36f, 31f, 26f, 22f, 18f, 15f, 12f, 9f, 7f,
			5f
		};

		public static float SuccessChance(int targetLevel, int failStreak)
		{
			if (targetLevel <= 1)
			{
				return 100f;
			}
			int num = Mathf.Clamp(targetLevel, 1, Chances.Length - 1);
			float num2 = Chances[num];
			if (Settings.PityEnabled.Value)
			{
				num2 += (float)failStreak * Settings.PityStep.Value;
			}
			return Mathf.Clamp(num2, 1f, 99f);
		}

		public static string FormatChance(float chance)
		{
			return chance.ToString("0.#", CultureInfo.InvariantCulture) + "%";
		}

		public static void Refresh(Inventory inventory)
		{
			try
			{
				InventoryChanged?.Invoke(inventory, new object[2] { false, false });
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Inventory refresh: " + ex.Message));
			}
		}

		public static List<ItemData> FindScrolls(Inventory inventory)
		{
			List<ItemData> list = new List<ItemData>();
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (Scrolls.TryRead(allItem, out var _))
				{
					list.Add(allItem);
				}
			}
			return list;
		}

		public static bool FindBestScroll(Inventory inventory, ItemData target, ScrollTier? preferred, bool blessed, out ScrollInfo found)
		{
			found = default(ScrollInfo);
			if (target == null)
			{
				return false;
			}
			if (!ItemTiers.TryGet(target, out var tier))
			{
				return false;
			}
			if (preferred.HasValue && preferred.Value != tier)
			{
				return false;
			}
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (Scrolls.TryRead(allItem, out var info) && info.Tier == tier && info.Blessed == blessed)
				{
					found = info;
					return true;
				}
			}
			return false;
		}

		public static int CountAvailableScrolls(Inventory inventory, ItemData target, bool blessed)
		{
			if (target == null)
			{
				return 0;
			}
			if (!ItemTiers.TryGet(target, out var tier))
			{
				return 0;
			}
			int num = 0;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (Scrolls.TryRead(allItem, out var info) && info.Tier == tier && info.Blessed == blessed)
				{
					num += allItem.m_stack;
				}
			}
			return num;
		}

		public static EnchantOutcome TryEnchant(Player player, ItemData item, ScrollTier? preferred, bool blessed, out string message)
		{
			message = "";
			if ((Object)(object)player == (Object)null || item == null)
			{
				return EnchantOutcome.NoItem;
			}
			if (!SeidrData.IsEligible(item))
			{
				message = T("Этот предмет нельзя зачаровать.", "This item cannot be enchanted.");
				return EnchantOutcome.NoItem;
			}
			if (!ItemTiers.TryGet(item, out var tier))
			{
				message = T("Предмет не привязан к тиру. Добавьте его в ItemTiers.txt.", "This item has no tier. Add it to ItemTiers.txt.");
				return EnchantOutcome.NoItem;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			SeidrData seidrData = SeidrData.Load(item);
			int num = Math.Min(Settings.MaxLevel.Value, Scrolls.Cap(tier));
			if (seidrData.Level >= num)
			{
				message = T("Предмет уже достиг максимума.", "The item is already at maximum level.");
				return EnchantOutcome.MaxLevel;
			}
			if (!FindBestScroll(inventory, item, preferred, blessed, out var found))
			{
				string text = (blessed ? T("благословлённый свиток", "blessed scroll") : T("свиток", "scroll"));
				message = T("Нужен " + text + " " + Scrolls.Letter(tier) + " (" + Scrolls.BiomeName(tier) + ").", "A " + text + " " + Scrolls.Letter(tier) + " (" + Scrolls.BiomeName(tier) + ") is required.");
				return EnchantOutcome.NoScroll;
			}
			int num2 = seidrData.Level + 1;
			if (found.Tier != tier)
			{
				message = T("Свиток " + Scrolls.Letter(found.Tier) + " не подходит предмету тира " + Scrolls.Letter(tier) + ".", "A " + Scrolls.Letter(found.Tier) + " scroll does not fit a tier " + Scrolls.Letter(tier) + " item.");
				return EnchantOutcome.TierTooLow;
			}
			if (!ItemFactory.TakeScroll(inventory, found))
			{
				message = T("Не удалось взять свиток.", "Could not take the scroll.");
				return EnchantOutcome.NoScroll;
			}
			float num3 = (blessed ? 100f : SuccessChance(num2, seidrData.FailStreak));
			bool num4 = blessed || Random.Range(0f, 100f) < num3;
			string text2 = Scrolls.Color(found.Tier);
			if (num4)
			{
				seidrData.Level = num2;
				seidrData.FailStreak = 0;
				bool num5 = seidrData.AddAffixIfNeeded(item);
				if (!num5 && Random.Range(0f, 100f) < 40f)
				{
					seidrData.TryUpgradeRandomAffix();
				}
				seidrData.Save(item);
				Refresh(inventory);
				string text3 = (num5 ? T("\nОткрыт новый аффикс.", "\nA new affix unlocked.") : "");
				string text4 = (blessed ? T("Благословение!", "Blessing!") : T("Успех!", "Success!"));
				message = T($"<color={text2}>{text4}</color> {UiKit.Loc(item.m_shared.m_name)} теперь +{seidrData.Level}.{text3}", $"<color={text2}>{text4}</color> {UiKit.Loc(item.m_shared.m_name)} is now +{seidrData.Level}.{text3}");
				return EnchantOutcome.Success;
			}
			if (num2 <= Settings.SafetyLevel.Value)
			{
				seidrData.Save(item);
				Refresh(inventory);
				message = T("<color=#B9C0C7>Безопасный уровень.</color> Свиток сгорел, предмет цел.", "<color=#B9C0C7>Safe level.</color> The scroll is gone, the item is intact.");
				return EnchantOutcome.SafeFail;
			}
			if (Settings.DestroyOnFailure.Value)
			{
				inventory.RemoveItem(item);
				Refresh(inventory);
				message = T("<color=#FF6B5A>Провал!</color> " + UiKit.Loc(item.m_shared.m_name) + " уничтожен.", "<color=#FF6B5A>Failure!</color> " + UiKit.Loc(item.m_shared.m_name) + " was destroyed.");
				return EnchantOutcome.Destroyed;
			}
			seidrData.Level = Math.Max(0, seidrData.Level - 1);
			seidrData.FailStreak++;
			seidrData.Save(item);
			Refresh(inventory);
			message = T($"<color=#FF8A6B>Провал.</color> Уровень упал до +{seidrData.Level}. Шанс следующей попытки немного выше.", $"<color=#FF8A6B>Failure.</color> Level dropped to +{seidrData.Level}. The next attempt is a bit more likely.");
			return EnchantOutcome.Downgrade;
		}

		public static bool TryReroll(Player player, ItemData item, int slot, bool all, out string message)
		{
			message = "";
			if ((Object)(object)player == (Object)null || item == null)
			{
				return false;
			}
			SeidrData seidrData = SeidrData.Load(item);
			List<int> list = new List<int>();
			if (all)
			{
				for (int i = 0; i < seidrData.Slots.Length; i++)
				{
					if (seidrData.Slots[i] != null && !seidrData.Locks[i])
					{
						list.Add(i);
					}
				}
			}
			else if (slot >= 0 && slot < seidrData.Slots.Length && seidrData.Slots[slot] != null && !seidrData.Locks[slot])
			{
				list.Add(slot);
			}
			if (list.Count == 0)
			{
				message = T("Нет аффиксов для перековки (или все закрыты).", "No affixes to reroll (or all locked).");
				return false;
			}
			int num = 25 * list.Count;
			if (ItemFactory.CountDust(((Humanoid)player).GetInventory()) < num)
			{
				message = T($"Нужно {num} рунной пыли.", $"{num} runic dust required.");
				return false;
			}
			ItemFactory.RemoveDust(((Humanoid)player).GetInventory(), num);
			AffixPool pool = Affixes.PoolFor(item);
			int level = Math.Max(1, seidrData.Level);
			List<Affix> list2 = new List<Affix>();
			for (int j = 0; j < seidrData.Slots.Length; j++)
			{
				if (seidrData.Slots[j] != null && !list.Contains(j))
				{
					list2.Add(seidrData.Slots[j]);
				}
			}
			foreach (int item2 in list)
			{
				Affix affix = Affixes.RollForLevel(level, pool, list2);
				seidrData.Slots[item2] = affix;
				list2.Add(affix);
			}
			seidrData.Save(item);
			Refresh(((Humanoid)player).GetInventory());
			message = T($"Перековано аффиксов: {list.Count}.", $"Rerolled affixes: {list.Count}.");
			return true;
		}

		public static bool TryToggleLock(Player player, ItemData item, int slot, out string message)
		{
			message = "";
			if ((Object)(object)player == (Object)null || item == null)
			{
				return false;
			}
			SeidrData seidrData = SeidrData.Load(item);
			if (slot < 0 || slot >= seidrData.Locks.Length || seidrData.Slots[slot] == null)
			{
				return false;
			}
			if (!seidrData.Locks[slot])
			{
				if (ItemFactory.CountDust(((Humanoid)player).GetInventory()) < 40)
				{
					message = T($"Нужно {40} рунной пыли для замка.", $"{40} runic dust required to lock.");
					return false;
				}
				ItemFactory.RemoveDust(((Humanoid)player).GetInventory(), 40);
				seidrData.Locks[slot] = true;
				message = T("Аффикс закреплён.", "Affix locked.");
			}
			else
			{
				seidrData.Locks[slot] = false;
				message = T("Замок снят.", "Affix unlocked.");
			}
			seidrData.Save(item);
			Refresh(((Humanoid)player).GetInventory());
			return true;
		}

		public static bool TrySalvage(Player player, ItemData item, out int dust, out string message)
		{
			dust = 0;
			message = "";
			if ((Object)(object)player == (Object)null || item == null)
			{
				return false;
			}
			SeidrData seidrData = SeidrData.Load(item, allowImport: false);
			int num = seidrData.Slots.Count((Affix a) => a != null);
			dust = 5 + seidrData.Level * 4 + num * 3;
			((Humanoid)player).GetInventory().RemoveItem(item);
			ItemFactory.GiveDust(player, dust);
			Refresh(((Humanoid)player).GetInventory());
			message = T($"Предмет разобран в {dust} рунной пыли.", $"Salvaged into {dust} runic dust.");
			return true;
		}

		public static bool TryTransmute(Player player, ScrollInfo info, out string message)
		{
			message = "";
			if (info.Tier >= ScrollTier.SPlus)
			{
				message = T("Свитки тира S+ уже высшие.", "S+ scrolls are the highest.");
				return false;
			}
			ScrollInfo info2 = new ScrollInfo(info.Tier + 1, info.Blessed);
			string text = (info.Blessed ? T("благословлённых свитков", "blessed scrolls") : T("свитков", "scrolls"));
			if (ItemFactory.CountScrolls(((Humanoid)player).GetInventory(), info) < 3)
			{
				message = T($"Нужно {3} {text} {Scrolls.Letter(info.Tier)}.", $"{3} {Scrolls.Letter(info.Tier)} {text} required.");
				return false;
			}
			for (int i = 0; i < 3; i++)
			{
				ItemFactory.TakeScroll(((Humanoid)player).GetInventory(), info);
			}
			ItemFactory.GiveScroll(player, info2);
			Refresh(((Humanoid)player).GetInventory());
			message = T("Свитки объединены.", "Scrolls merged.");
			return true;
		}

		public static int UpgradeScrollTier(int level)
		{
			return level;
		}

		private static string T(string ru, string en)
		{
			if (!Settings.Russian.Value)
			{
				return en;
			}
			return ru;
		}
	}
	public enum ItemCategory
	{
		Auto,
		Weapon,
		Armor,
		Shield,
		Skip
	}
	internal sealed class ItemOverride
	{
		internal bool HasTier;

		internal ScrollTier Tier;

		internal bool HasCategory;

		internal ItemCategory Category;
	}
	public static class ItemCatalog
	{
		private static readonly Dictionary<string, ItemOverride> BuiltIn = new Dictionary<string, ItemOverride>(StringComparer.OrdinalIgnoreCase);

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

		private static bool _loaded;

		internal static int BuiltInCount => BuiltIn.Count;

		internal static IEnumerable<string> BuiltInNames => BuiltIn.Keys;

		public static string ConfigPath => Path.Combine(Path.Combine(Paths.ConfigPath, "SeidrEnchanting"), "AdditionalItems.txt");

		internal static bool IsBuiltIn(string prefab)
		{
			if (!string.IsNullOrEmpty(prefab))
			{
				return BuiltIn.ContainsKey(prefab);
			}
			return false;
		}

		internal static void Initialize()
		{
			Load();
		}

		internal static void RegisterBuiltIn(string prefab, ItemCategory category, ScrollTier tier)
		{
			if (!string.IsNullOrEmpty(prefab))
			{
				BuiltIn[prefab] = new ItemOverride
				{
					HasTier = true,
					Tier = tier,
					HasCategory = true,
					Category = category
				};
			}
		}

		internal static ItemOverride Resolve(string prefab)
		{
			if (string.IsNullOrEmpty(prefab))
			{
				return null;
			}
			Load();
			User.TryGetValue(prefab, out var value);
			BuiltIn.TryGetValue(prefab, out var value2);
			if (value == null && value2 == null)
			{
				return null;
			}
			ItemOverride itemOverride = new ItemOverride();
			if (value != null)
			{
				itemOverride.HasTier = value.HasTier;
				itemOverride.Tier = value.Tier;
				itemOverride.HasCategory = value.HasCategory;
				itemOverride.Category = value.Category;
			}
			if (!itemOverride.HasTier && value2 != null && value2.HasTier)
			{
				itemOverride.HasTier = true;
				itemOverride.Tier = value2.Tier;
			}
			if (!itemOverride.HasCategory && value2 != null && value2.HasCategory)
			{
				itemOverride.HasCategory = true;
				itemOverride.Category = value2.Category;
			}
			return itemOverride;
		}

		public static bool TryGetTier(string prefab, out ScrollTier tier)
		{
			ItemOverride itemOverride = Resolve(prefab);
			if (itemOverride != null && itemOverride.HasTier)
			{
				tier = itemOverride.Tier;
				return true;
			}
			tier = ScrollTier.E;
			return false;
		}

		public static ItemCategory CategoryOf(ItemData item)
		{
			string prefab = ItemTiers.PrefabName(item);
			ItemOverride itemOverride = Resolve(prefab);
			if (itemOverride != null && itemOverride.HasCategory)
			{
				return itemOverride.Category;
			}
			return ModSupport.GuessCategory(prefab);
		}

		public static bool IsEligible(ItemData item)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected I4, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Invalid comparison between Unknown and I4
			if (item == null || item.m_shared == null)
			{
				return false;
			}
			switch (CategoryOf(item))
			{
			case ItemCategory.Skip:
				return false;
			default:
				return true;
			case ItemCategory.Auto:
			{
				ItemType itemType = item.m_shared.m_itemType;
				switch (itemType - 3)
				{
				default:
					if ((int)itemType != 22)
					{
						break;
					}
					goto case 0;
				case 0:
				case 1:
				case 2:
				case 3:
				case 4:
				case 8:
				case 11:
				case 14:
					return true;
				case 5:
				case 6:
				case 7:
				case 9:
				case 10:
				case 12:
				case 13:
					break;
				}
				return false;
			}
			}
		}

		public static bool IsArmor(ItemData item)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Invalid comparison between Unknown and I4
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Invalid comparison between Unknown and I4
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Invalid comparison between Unknown and I4
			if (item == null || item.m_shared == null)
			{
				return false;
			}
			switch (CategoryOf(item))
			{
			case ItemCategory.Armor:
				return true;
			case ItemCategory.Weapon:
			case ItemCategory.Shield:
			case ItemCategory.Skip:
				return false;
			default:
			{
				ItemType itemType = item.m_shared.m_itemType;
				if (itemType - 6 <= 1 || (int)itemType == 11 || (int)itemType == 17)
				{
					return true;
				}
				return false;
			}
			}
		}

		public static AffixPool PoolFor(ItemData item)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected I4, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Invalid comparison between Unknown and I4
			if (item == null || item.m_shared == null)
			{
				return AffixPool.Weapon;
			}
			switch (CategoryOf(item))
			{
			case ItemCategory.Armor:
				return AffixPool.Armor;
			case ItemCategory.Shield:
				return AffixPool.Shield;
			case ItemCategory.Weapon:
				return AffixPool.Weapon;
			default:
			{
				ItemType itemType = item.m_shared.m_itemType;
				switch (itemType - 5)
				{
				default:
					if ((int)itemType != 17)
					{
						break;
					}
					goto case 1;
				case 1:
				case 2:
				case 6:
					return AffixPool.Armor;
				case 0:
					return AffixPool.Shield;
				case 3:
				case 4:
				case 5:
					break;
				}
				return AffixPool.Weapon;
			}
			}
		}

		private static void Load()
		{
			if (_loaded)
			{
				return;
			}
			_loaded = true;
			try
			{
				string configPath = ConfigPath;
				string directoryName = Path.GetDirectoryName(configPath);
				if (!string.IsNullOrEmpty(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				if (!File.Exists(configPath))
				{
					File.WriteAllText(configPath, BuildDefaultFile(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
					Plugin.Log.LogInfo((object)("Список дополнительных предметов создан: " + configPath));
				}
				ReadFile(configPath);
				Plugin.Log.LogInfo((object)$"Дополнительные предметы: загружено {User.Count} записей.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Не удалось прочитать AdditionalItems.txt: " + ex.Message));
			}
		}

		private static void ReadFile(string path)
		{
			string[] array = File.ReadAllLines(path);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length == 0 || text.StartsWith("#") || text.StartsWith("//") || text.StartsWith(";"))
				{
					continue;
				}
				int num = text.IndexOfAny(new char[2] { '=', ':' });
				if (num <= 0)
				{
					Warn(i + 1, "нет разделителя '=' или ':'");
					continue;
				}
				string text2 = text.Substring(0, num).Trim();
				string text3 = text.Substring(num + 1).Trim();
				if (text2.Length == 0 || text3.Length == 0)
				{
					Warn(i + 1, "пустое имя предмета или значение");
					continue;
				}
				ItemOverride itemOverride = new ItemOverride();
				bool flag = false;
				string[] array2 = text3.Split(new char[3] { ',', '|', ';' }, StringSplitOptions.RemoveEmptyEntries);
				for (int j = 0; j < array2.Length; j++)
				{
					string text4 = array2[j].Trim();
					if (text4.Length != 0)
					{
						ItemCategory category;
						if (TryParseTier(text4, out var tier))
						{
							itemOverride.HasTier = true;
							itemOverride.Tier = tier;
							flag = true;
						}
						else if (TryParseCategory(text4, out category))
						{
							itemOverride.HasCategory = true;
							itemOverride.Category = category;
							flag = true;
						}
						else
						{
							Warn(i + 1, "неизвестное значение '" + text4 + "'");
						}
					}
				}
				if (!flag)
				{
					Warn(i + 1, "не указан ни тир, ни категория");
				}
				else
				{
					User[text2] = itemOverride;
				}
			}
		}

		private static bool TryParseTier(string value, out ScrollTier tier)
		{
			tier = ScrollTier.E;
			if (ItemTiers.IsTierToken(value))
			{
				tier = Scrolls.TierFrom(value);
				return true;
			}
			for (int i = 0; i < Scrolls.BiomeRu.Length; i++)
			{
				if (string.Equals(value, Scrolls.BiomeRu[i], StringComparison.OrdinalIgnoreCase) || string.Equals(value, Scrolls.BiomeEn[i], StringComparison.OrdinalIgnoreCase))
				{
					tier = (ScrollTier)i;
					return true;
				}
			}
			return false;
		}

		private static bool TryParseCategory(string value, out ItemCategory category)
		{
			category = ItemCategory.Auto;
			switch (value.Trim().ToLowerInvariant())
			{
			case "weapon":
			case "оружие":
				category = ItemCategory.Weapon;
				return true;
			case "armour":
			case "armor":
			case "броня":
				category = ItemCategory.Armor;
				return true;
			case "shield":
			case "щит":
				category = ItemCategory.Shield;
				return true;
			case "auto":
			case "авто":
				category = ItemCategory.Auto;
				return true;
			case "нет":
			case "skip":
			case "exclude":
			case "исключить":
				category = ItemCategory.Skip;
				return true;
			default:
				return false;
			}
		}

		private static void Warn(int line, string message)
		{
			Plugin.Log.LogWarning((object)$"AdditionalItems.txt, строка {line}: {message}. Строка пропущена.");
		}

		private static string BuildDefaultFile()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("# Seidr Enchanting — дополнительные предметы из других модов.");
			stringBuilder.AppendLine("#");
			stringBuilder.AppendLine("# Формат:");
			stringBuilder.AppendLine("#   <PrefabName> = <тир>[, <категория>]");
			stringBuilder.AppendLine("#   <PrefabName> = <категория>");
			stringBuilder.AppendLine("#");
			stringBuilder.AppendLine("# Тиры: E, D, C, B, A, S, S+");
			stringBuilder.AppendLine("#   E  Луга и Чёрный лес");
			stringBuilder.AppendLine("#   D  Болота и Океан");
			stringBuilder.AppendLine("#   C  Горы");
			stringBuilder.AppendLine("#   B  Равнины");
			stringBuilder.AppendLine("#   A  Туманные земли");
			stringBuilder.AppendLine("#   S  Пепельные земли");
			stringBuilder.AppendLine("#   S+ Северные земли");
			stringBuilder.AppendLine("#");
			stringBuilder.AppendLine("# Категории (необязательно):");
			stringBuilder.AppendLine("#   weapon — пул аффиксов оружия;");
			stringBuilder.AppendLine("#   armor  — пул аффиксов брони;");
			stringBuilder.AppendLine("#   shield — пул аффиксов щитов;");
			stringBuilder.AppendLine("#   auto   — определить по типу предмета (по умолчанию);");
			stringBuilder.AppendLine("#   skip   — исключить предмет из зачарования.");
			stringBuilder.AppendLine("#");
			stringBuilder.AppendLine("# Если категория не указана, предмет должен иметь обычный");
			stringBuilder.AppendLine("# ItemType (меч, щит, шлем, нагрудник...). Для нестандартных");
			stringBuilder.AppendLine("# предметов укажите категорию вручную.");
			stringBuilder.AppendLine("#");
			stringBuilder.AppendLine("# Примеры:");
			stringBuilder.AppendLine("#   SwordMyMod = B");
			stringBuilder.AppendLine("#   ArmorMyMod = A, armor");
			stringBuilder.AppendLine("#   ShieldMyMod = S, shield");
			stringBuilder.AppendLine("#   QuestItemMyMod = skip");
			stringBuilder.AppendLine("#");
			stringBuilder.AppendLine("# Встроенная поддержка уже включена для:");
			stringBuilder.AppendLine("#   Therzie Armory, Therzie Warfare, SouthsilArmor, CAH.");
			stringBuilder.AppendLine("#   Их предметы не нужно добавлять сюда — список уже в моде.");
			stringBuilder.AppendLine("#");
			stringBuilder.AppendLine("# Точное имя префаба можно посмотреть командой `seidr item`");
			stringBuilder.AppendLine("# (наведитесь на предмет или возьмите его в руку).");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("# --- Ваши предметы ниже ---");
			stringBuilder.AppendLine();
			return stringBuilder.ToString();
		}
	}
	public static class ItemTiers
	{
		private static readonly Dictionary<string, ScrollTier> Map = new Dictionary<string, ScrollTier>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<SharedData, string> SharedNames = new Dictionary<SharedData, string>();

		private static bool _loaded;

		public static string ConfigPath => Path.Combine(Path.Combine(Paths.ConfigPath, "SeidrEnchanting"), "ItemTiers.txt");

		internal static void Initialize()
		{
			Load();
		}

		public static ScrollTier TierOf(ItemData item)
		{
			if (!TryGet(item, out var tier))
			{
				return ScrollTier.E;
			}
			return tier;
		}

		public static bool TryGet(ItemData item, out ScrollTier tier)
		{
			tier = ScrollTier.E;
			if (item == null)
			{
				return false;
			}
			Load();
			string text = PrefabName(item);
			if (!string.IsNullOrEmpty(text) && TryResolve(text, out tier))
			{
				return true;
			}
			if (item.m_shared != null && !string.IsNullOrEmpty(item.m_shared.m_name))
			{
				string text2 = item.m_shared.m_name;
				if (text2.StartsWith("$item_", StringComparison.OrdinalIgnoreCase))
				{
					text2 = text2.Substring(6);
				}
				if (TryResolve(text2, out tier))
				{
					return true;
				}
			}
			return false;
		}

		private static bool TryResolve(string prefab, out ScrollTier tier)
		{
			if (ItemCatalog.TryGetTier(prefab, out tier))
			{
				return true;
			}
			if (Map.TryGetValue(prefab, out tier))
			{
				return true;
			}
			if (ModSupport.TryGetTier(prefab, out tier))
			{
				return true;
			}
			return Guess(prefab, out tier);
		}

		public static string PrefabName(ItemData item)
		{
			if (item == null)
			{
				return null;
			}
			if ((Object)(object)item.m_dropPrefab != (Object)null)
			{
				return ((Object)item.m_dropPrefab).name;
			}
			Load();
			if (item.m_shared != null && SharedNames.TryGetValue(item.m_shared, out var value))
			{
				return value;
			}
			return null;
		}

		public static void RebuildShared(ObjectDB db)
		{
			if ((Object)(object)db == (Object)null || db.m_items == null)
			{
				return;
			}
			SharedNames.Clear();
			foreach (GameObject item in db.m_items)
			{
				if (!((Object)(object)item == (Object)null))
				{
					ItemDrop component = item.GetComponent<ItemDrop>();
					if (!((Object)(object)component == (Object)null) && component.m_itemData != null && component.m_itemData.m_shared != null)
					{
						SharedNames[component.m_itemData.m_shared] = ((Object)item).name;
					}
				}
			}
		}

		public static List<string> NamesOf(ScrollTier tier)
		{
			Load();
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, ScrollTier> item in Map)
			{
				if (item.Value == tier)
				{
					list.Add(item.Key);
				}
			}
			list.Sort(StringComparer.OrdinalIgnoreCase);
			return list;
		}

		public static int CountOf(ScrollTier tier)
		{
			return NamesOf(tier).Count;
		}

		private static void Load()
		{
			if (_loaded)
			{
				return;
			}
			_loaded = true;
			AddDefaults();
			try
			{
				string configPath = ConfigPath;
				string directoryName = Path.GetDirectoryName(configPath);
				if (!string.IsNullOrEmpty(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				if (!File.Exists(configPath))
				{
					File.WriteAllText(configPath, BuildDefaultFile(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
					Plugin.Log.LogInfo((object)("Список тиров создан: " + configPath));
				}
				ReadFile(configPath);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Не удалось прочитать ItemTiers.txt: " + ex.Message));
			}
		}

		private static void ReadFile(string path)
		{
			string[] array = File.ReadAllLines(path);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length == 0 || text.StartsWith("#") || text.StartsWith("//"))
				{
					continue;
				}
				int num = text.IndexOfAny(new char[2] { ':', '=' });
				if (num <= 0)
				{
					continue;
				}
				string text2 = text.Substring(0, num).Trim();
				if (!IsTierToken(text2))
				{
					continue;
				}
				ScrollTier value = Scrolls.TierFrom(text2);
				string text3 = text.Substring(num + 1);
				int num2 = text3.IndexOf('#');
				if (num2 >= 0)
				{
					text3 = text3.Substring(0, num2);
				}
				string[] array2 = text3.Split(',');
				for (int j = 0; j < array2.Length; j++)
				{
					string text4 = array2[j].Trim();
					if (text4.Length != 0)
					{
						Map[text4] = value;
					}
				}
			}
		}

		internal static bool IsTierToken(string token)
		{
			for (int i = 0; i < Scrolls.Letters.Length; i++)
			{
				if (token.Equals(Scrolls.Letters[i], StringComparison.OrdinalIgnoreCase) || token.Equals(Scrolls.Tokens[i], StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return token.Equals("SPlus", StringComparison.OrdinalIgnoreCase);
		}

		private static string BuildDefaultFile()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("# Seidr Enchanting — тиры предметов по биомам.");
			stringBuilder.AppendLine("# Формат: <тир>: Prefab1, Prefab2, ...");
			stringBuilder.AppendLine("# Тиры: E Луга и Чёрный лес, D Болота, C Горы, B Равнины,");
			stringBuilder.AppendLine("#       A Туманные земли, S Пепельные земли, S+ Северные земли.");
			stringBuilder.AppendLine("# Предмет должен быть в списке своего тира. Свиток того же тира");
			stringBuilder.AppendLine("# зачаровывает его до +20. Модовые предметы без списка определяются");
			stringBuilder.AppendLine("# по названию (bronze, iron, silver, blackmetal, carapace, flametal...).");
			stringBuilder.AppendLine();
			ScrollTier[] all = Scrolls.All;
			foreach (ScrollTier scrollTier in all)
			{
				stringBuilder.AppendLine("# " + Scrolls.Letter(scrollTier) + " — " + Scrolls.BiomeRu[(int)scrollTier]);
				stringBuilder.Append(Scrolls.Letter(scrollTier)).Append(": ");
				List<string> list = new List<string>();
				foreach (KeyValuePair<string, ScrollTier> item in Map)
				{
					if (item.Value == scrollTier)
					{
						list.Add(item.Key);
					}
				}
				list.Sort(StringComparer.OrdinalIgnoreCase);
				stringBuilder.AppendLine(string.Join(", ", list));
				stringBuilder.AppendLine();
			}
			return stringBuilder.ToString();
		}

		private static void Add(ScrollTier tier, params string[] names)
		{
			foreach (string text in names)
			{
				if (!string.IsNullOrEmpty(text))
				{
					Map[text] = tier;
				}
			}
		}

		private static void AddDefaults()
		{
			Add(ScrollTier.E, "Club", "AxeStone", "AxeFlint", "SpearFlint", "KnifeFlint", "AxeEarly", "SledgeStagbreaker", "KnifeButcher", "FistBjornClaw", "ShieldWood", "ShieldWoodTower", "Bow", "PickaxeAntler", "ArmorRagsChest", "ArmorRagsLegs", "HelmetLeather", "ArmorLeatherChest", "ArmorLeatherLegs", "CapeDeerHide");
			Add(ScrollTier.E, "KnifeCopper", "AtgeirBronze", "AxeBronze", "MaceBronze", "SpearBronze", "SwordBronze", "ShieldBronzeBuckler", "ShieldBoneTower", "BowFineWood", "PickaxeBronze", "HelmetTrollLeather", "ArmorTrollLeatherChest", "ArmorTrollLeatherLegs", "CapeTrollHide", "HelmetBronze", "ArmorBronzeChest", "ArmorBronzeLegs", "HelmetBerserkerHood", "ArmorBerserkerChest", "ArmorBerserkerLegs");
			Add(ScrollTier.D, "AtgeirIron", "AxeIron", "MaceIron", "SledgeIron", "SwordIron", "SpearElderbark", "KnifeChitin", "ShieldBanded", "ShieldIronBuckler", "ShieldIronTower", "ShieldSerpentscale", "BowHuntsman", "PickaxeIron", "HelmetIron", "ArmorIronChest", "ArmorIronLegs", "HelmetRoot", "ArmorRootChest", "ArmorRootLegs");
			Add(ScrollTier.C, "KnifeSilver", "SwordSilver", "MaceSilver", "SpearWolfFang", "BattleaxeCrystal", "FistFenrirClaw", "ShieldSilver", "BowDraugrFang", "HelmetDrake", "ArmorWolfChest", "ArmorWolfLegs", "CapeWolf", "HelmetFenring", "ArmorFenringChest", "ArmorFenringLegs");
			Add(ScrollTier.B, "AtgeirBlackmetal", "SwordBlackmetal", "AxeBlackMetal", "BattleaxeBlackmetal", "MaceNeedle", "FistBjornUndeadClaw", "KnifeBlackMetal", "ShieldBlackmetal", "ShieldBlackmetalTower", "PickaxeBlackMetal", "HelmetPadded", "ArmorPaddedCuirass", "ArmorPaddedGreaves", "HelmetBerserkerUndead", "ArmorBerserkerUndeadChest", "ArmorBerserkerUndeadLegs", "CapeLinen", "CapeLox");
			Add(ScrollTier.A, "AtgeirHimminAfl", "THSwordKrom", "SwordMistwalker", "AxeJotunBane", "BattleaxeSkullSplittur", "SledgeDemolisher", "SpearCarapace", "KnifeSkollAndHati", "ShieldCarapaceBuckler", "ShieldCarapace", "BowSpineSnap", "CrossbowArbalest", "StaffFireball", "StaffIceShards", "StaffSkeleton", "HelmetCarapace", "ArmorCarapaceChest", "ArmorCarapaceLegs", "HelmetMage", "ArmorMageChest", "ArmorMageLegs", "CapeFeather");
			Add(ScrollTier.S, "SwordNiedhogg", "SwordNiedhoggBlood", "SwordNiedhoggLightning", "SwordNiedhoggNature", "SwordDyrnwyn", "THSwordSlayer", "THSwordSlayerBlood", "THSwordSlayerNature", "THSwordSlayerLightning", "SpearSplitner", "SpearSplitner_Blood", "SpearSplitner_Nature", "SpearSplitner_Lightning", "AxeBerzerkr", "AxeBerzerkrBlood", "AxeBerzerkrLightning", "AxeBerzerkrNature", "MaceEldner", "MaceEldnerBlood", "MaceEldnerLightning", "MaceEldnerNature", "ShieldFlametal", "ShieldFlametalTower", "BowAshlands", "BowAshlandsBlood", "BowAshlandsRoot", "BowAshlandsStorm", "CrossbowRipper", "CrossbowRipperBlood", "CrossbowRipperLightning", "CrossbowRipperNature", "StaffClusterbomb", "StaffGreenRoots", "StaffLightning", "StaffRedTroll", "HelmetAshlandsMediumHood", "ArmorAshlandsMediumChest", "ArmorAshlandsMediumLegs", "HelmetMage_Ashlands", "ArmorMageChest_Ashlands", "ArmorMageLegs_Ashlands", "HelmetFlametal", "ArmorFlametalChest", "ArmorFlametalLegs", "CapeAsksvin", "CapeAsh");
			Add(ScrollTier.SPlus, "SwordCheat", "SledgeCheat", "HelmetFishingHat", "ArmorDeepNorthHeavyChest", "ArmorDeepNorthHeavylegs", "HelmetDNHeavy");
			ModItems.Register();
		}

		private static bool Guess(string rawName, out ScrollTier tier)
		{
			tier = ScrollTier.E;
			if (string.IsNullOrEmpty(rawName))
			{
				return false;
			}
			string text = rawName.ToLowerInvariant();
			text = text.Replace("$item_", "").Replace("$", "");
			if (Contains(text, "deepnorth", "helmetdn", "storr", "_dn_", "dnheavy", "fishinghat"))
			{
				tier = ScrollTier.SPlus;
				return true;
			}
			if (Contains(text, "flametal", "ashlands", "asksvin", "charred", "niedhogg", "dyrnwyn", "slayer", "splitner", "berzerkr", "eldner", "ripper", "staffclusterbomb", "staffgreenroots", "stafflightning", "staffredtroll", "capeash"))
			{
				tier = ScrollTier.S;
				return true;
			}
			if (Contains(text, "demonic", "bloodthirst", "vampiric", "scimitar", "scythe", "fader", "queen", "yagluth", "moder"))
			{
				tier = ScrollTier.S;
				return true;
			}
			if (Contains(text, "carapace", "dvergr", "mistwalker", "krom", "jotun", "skullsplittur", "demolisher", "spinesnap", "arbalest", "feather", "mage", "eitr", "softtissue", "yggdrasil", "himminafl", "skoll"))
			{
				tier = ScrollTier.A;
				return true;
			}
			if (Contains(text, "blackmetal", "padded", "linen", "lox", "needle", "berserkerundead", "bjornundead"))
			{
				tier = ScrollTier.B;
				return true;
			}
			if (Contains(text, "silver", "wolf", "fenrir", "drake", "crystal", "draugr", "obsidian", "chitin"))
			{
				tier = ScrollTier.C;
				return true;
			}
			if (Contains(text, "iron", "root", "banded", "huntsman", "elderbark", "serpent", "bonemass", "viper", "wrench", "greatclub"))
			{
				tier = ScrollTier.D;
				return true;
			}
			if (Contains(text, "bronze", "troll", "finewood", "bone", "copper"))
			{
				tier = ScrollTier.E;
				return true;
			}
			if (Contains(text, "flint", "wood", "eikthyr", "club", "rag", "leather", "deerhide"))
			{
				tier = ScrollTier.E;
				return true;
			}
			return false;
		}

		private static bool Contains(string haystack, params string[] needles)
		{
			for (int i = 0; i < needles.Length; i++)
			{
				if (haystack.IndexOf(needles[i], StringComparison.Ordinal) >= 0)
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class ModItems
	{
		private static bool _registered;

		internal static void Register()
		{
			if (!_registered)
			{
				_registered = true;
				RegisterArmory();
				RegisterWarfare();
				RegisterSouthsil();
				RegisterCah();
				Plugin.Log.LogInfo((object)($"[Mods] встроенных предметов: {ItemCatalog.BuiltInCount} " + "(Therzie Armory/Warfare, SouthsilArmor, CAH)."));
			}
		}

		private static void RegisterArmory()
		{
			Armor(ScrollTier.E, "HelmetLeather_TW", "ArmorLeatherChest_TW", "ArmorLeatherLegs_TW", "HelmetRazorback_TW", "ArmorRazorbackChest_TW", "ArmorRazorbackLegs_TW", "HelmetHunter_TW", "ArmorHunterChest_TW", "ArmorHunterLegs_TW", "HelmetRogue_TW", "ArmorRogueChest_TW", "ArmorRogueLegs_TW", "HelmetVigorous_TW", "ArmorVigorousChest_TW", "ArmorVigorousLegs_TW", "CapeTrollBlack_TW");
			Armor(ScrollTier.D, "HelmetHunterIron_TW", "ArmorHunterChestIron_TW", "ArmorHunterLegsIron_TW", "HelmetRogueIron_TW", "ArmorRogueIronChest_TW", "ArmorRogueIronLegs_TW", "HelmetVigorousIron_TW", "ArmorVigorousIronChest_TW", "ArmorVigorousIronLegs_TW", "HelmetWarrior_TW", "ArmorWarriorChest_TW", "ArmorWarriorLegs_TW");
			Armor(ScrollTier.C, "HelmetHunterSilver_TW", "ArmorHunterChestSilver_TW", "ArmorHunterLegsSilver_TW", "HelmetRogueSilver_TW", "ArmorRogueSilverChest_TW", "ArmorRogueSilverLegs_TW", "HelmetVigorousSilver_TW", "ArmorVigorousSilverChest_TW", "ArmorVigorousSilverLegs_TW", "HelmetWarriorSilver_TW", "ArmorWarriorSilverChest_TW", "ArmorWarriorSilverLegs_TW", "HelmetFenrir_TW", "ArmorFenrirChest_TW", "ArmorFenrirLegs_TW", "HelmetVidar_TW", "ArmorVidarChest_TW", "ArmorVidarLegs_TW");
			Armor(ScrollTier.B, "HelmetHunterBM_TW", "ArmorHunterChestBM_TW", "ArmorHunterLegsBM_TW", "HelmetRogueBM_TW", "ArmorRogueBMChest_TW", "ArmorRogueBMLegs_TW", "HelmetVigorousBM_TW", "ArmorVigorousBMChest_TW", "ArmorVigorousBMLegs_TW", "HelmetWarriorBM_TW", "ArmorWarriorBMChest_TW", "ArmorWarriorBMLegs_TW", "HelmetFenrirBM_TW", "ArmorFenrirBMChest_TW", "ArmorFenrirBMLegs_TW", "HelmetVidarBM_TW", "ArmorVidarBMChest_TW", "ArmorVidarBMLegs_TW", "HelmetBold_TW", "ArmorBoldChest_TW", "ArmorBoldLegs_TW");
			Armor(ScrollTier.A, "HelmetHunterCarapace_TW", "ArmorHunterChestCarapace_TW", "ArmorHunterLegsCarapace_TW", "HelmetRogueCarapace_TW", "ArmorRogueCarapaceChest_TW", "ArmorRogueCarapaceLegs_TW", "HelmetVigorousCarapace_TW", "ArmorVigorousCarapaceChest_TW", "ArmorVigorousCarapaceLegs_TW", "HelmetWarriorCarapace_TW", "ArmorWarriorCarapaceChest_TW", "ArmorWarriorCarapaceLegs_TW", "HelmetFenrirCarapace_TW", "ArmorFenrirCarapaceChest_TW", "ArmorFenrirCarapaceLegs_TW", "HelmetVidarCarapace_TW", "ArmorVidarCarapaceChest_TW", "ArmorVidarCarapaceLegs_TW", "HelmetBoldCarapace_TW", "ArmorBoldCarapaceChest_TW", "ArmorBoldCarapaceLegs_TW", "HelmetLegion_TW", "ArmorLegionChest_TW", "ArmorLegionLegs_TW");
			Armor(ScrollTier.S, "HelmetWarriorFlametal_TW", "ArmorWarriorFlametalChest_TW", "ArmorWarriorFlametalLegs_TW", "HelmetVidarFlametal_TW", "ArmorVidarFlametalChest_TW", "ArmorVidarFlametalLegs_TW", "HelmetBoldFlametal_TW", "ArmorBoldFlametalChest_TW", "ArmorBoldFlametalLegs_TW", "HelmetLegionFlametal_TW", "ArmorLegionFlametalChest_TW", "ArmorLegionFlametalLegs_TW");
			Armor(ScrollTier.SPlus, "HelmetRogueTyranium_TW", "ArmorRogueTyraniumChest_TW", "ArmorRogueTyraniumLegs_TW", "HelmetVigorousTyranium_TW", "ArmorVigorousTyraniumChest_TW", "ArmorVigorousTyraniumLegs_TW", "HelmetFenrirTyranium_TW", "ArmorFenrirTyraniumChest_TW", "ArmorFenrirTyraniumLegs_TW", "BeltYmir_TW");
		}

		private static void RegisterWarfare()
		{
			Weapon(ScrollTier.E, "AtgeirFlint_TW", "BastardFlint_TW", "BattleaxeFlint_TW", "BattleaxeBronze_TW", "BattlehammerElder_TW", "BowTrollBone_TW", "ClaymoreBronze_TW", "CrossbowWood_TW", "CrossbowEikthyr_TW", "CrossbowBronze_TW", "CudgelBronze_TW", "FistFlint_TW", "FistBronze_TW", "GreatClub_TW", "KnifeBronze_TW", "MaceFlint_TW", "SledgeStagbreaker_TW", "SledgeBronze_TW", "SwordFlint_TW", "ThrowAxeFlint_TW", "ThrowAxeBronze_TW", "WarpikeElder_TW");
			Weapon(ScrollTier.D, "BastardBone_TW", "BastardChitin_TW", "BattleaxeIron_TW", "BattlehammerTrollbone_TW", "BattlehammerIron_TW", "ClaymoreBone_TW", "ClaymoreChitin_TW", "ClaymoreIron_TW", "CrossbowChitin_TW", "CrossbowIron_TW", "CudgelIron_TW", "DualKnifeBone_TW", "DualKnifeChitin_TW", "DualKnifeIron_TW", "FistIron_TW", "FistChitin_TW", "KnifeIron_TW", "KnifeWrench_TW", "KnifeViper_TW", "MaceChitin_TW", "SledgeIron_TW", "SledgeBonemass_TW", "SwordBone_TW", "SwordChitin_TW", "ThrowAxeIron_TW", "WarpikeBone_TW", "WarpikeChitin_TW");
			Weapon(ScrollTier.C, "AxeSilver_TW", "AtgeirSilver_TW", "BastardSilver_TW", "BattleaxeSilver_TW", "BattleaxeCrystal_TW", "BattleaxeCrystalEmerald_TW", "BattleaxeCrystalAmethyst_TW", "BattleaxeCrystalSapphire_TW", "BattleaxeCrystalTopaz_TW", "BattlehammerSilver_TW", "ClaymoreSilver_TW", "CrossbowSilver_TW", "DualKnifeSilver_TW", "FistSilver_TW", "GreatbowModer_TW", "PickaxeSilver_TW", "SledgeSilver_TW", "ThrowAxeSilver_TW", "WarpikeObsidian_TW");
			Weapon(ScrollTier.B, "BastardBlackmetal_TW", "BattleaxeBlackmetal_TW", "BattlehammerBlackmetal_TW", "BladeYagluth_TW", "BowBlackmetal_TW", "ClaymoreBlackmetal_TW", "CrossbowBlackmetal_TW", "DualKnifeBM_TW", "FistBlackmetal_TW", "GreatbowBlackmetal_TW", "LanceBlackmetal_TW", "SledgeBlackmetal_TW", "SpearBlackmetal_TW", "ThrowAxeBlackMetal_TW", "TridentBlackmetal_TW", "WarpikeBlackmetal_TW", "DualSwordScimitar_TW", "SwordScimitar_TW");
			Weapon(ScrollTier.A, "AxeDvergr_TW", "BastardDvergr_TW", "BattleaxeDvergr_TW", "BattlehammerDvergr_TW", "FistDvergr_TW", "FistQueen_TW", "GreatbowDvergr_TW", "LanceDvergr_TW", "MaceDvergr_TW", "SledgeDemolisher_TW", "WarpikeDvergr_TW", "ClaymoreDvergr_TW", "ThrowAxeDvergr_TW");
			Weapon(ScrollTier.S, "AxeFlametal_TW", "BastardFlametal_TW", "BattleaxeFlametal_TW", "DualKnifeFlametal_TW", "DualaxeDemonic_TW", "DualScytheBloodthirst_TW", "FistFlametal_TW", "ScytheVampiric_TW", "SledgeFlametal_TW", "WarpikeFlametal_TW", "PickaxeFader_TW");
			Armor(ScrollTier.A, "CapeRotten_TW");
			Shield(ScrollTier.E, "ShieldBronzeBanded_TW", "ShieldBronzeTower_TW");
			Shield(ScrollTier.D, "ShieldChitin_TW", "ShieldChitinTower_TW", "ShieldBucklerChitin_TW", "ShieldChitinBuckler_TW");
			Shield(ScrollTier.C, "ShieldSilverBuckler_TW");
			Shield(ScrollTier.B, "ShieldBlackmetalBuckler_TW");
			Shield(ScrollTier.A, "ShieldCarapaceTower_TW");
			Skip("BombSpirit_TW");
		}

		private static void RegisterSouthsil()
		{
			Armor(ScrollTier.E, "neckhelm", "neckchest", "necklegs", "chiefhelmboar", "chiefhelmdeer", "chiefchest", "chieflegs", "trollhelm", "trolllegs", "bronzetrollhelm", "heavybronzehelm", "heavybronzechest", "heavybronzelegs", "ancienthelm", "ancientchest", "ancientlegs", "ss_cape_boar");
			Armor(ScrollTier.D, "ss_lightwraithhelm", "ss_lightwraith", "ss_lightwraithlegs", "ss_lightwraith_legs", "ss_cape_lightwraith", "knighthelm", "knightlegs", "knightchest", "bonetitanhelm", "bonetitanchest", "bonetitanlegs", "swamphelm", "swampchest", "swamplegs");
			Armor(ScrollTier.C, "ancientironhelm", "ancientironchest", "ancientironlegs", "heavywolfhelm", "heavywolfchest", "heavywolflegs", "skoghelm", "skogchest", "skoglegs", "sven", "svenchest", "svenlegs");
			Armor(ScrollTier.B, "norahhelm", "norahlegs", "norahchest", "norahhelmalt", "bphelm", "bpchest", "bplegs", "bearhelm", "bearlegs", "bearchest", "loxhunthelm", "loxhuntchest", "loxhuntlegs", "ss_barbhelm", "ss_barbchest", "ss_barblegs", "ss_serpentcape");
			Armor(ScrollTier.A, "frostmagehelm", "frostmagechest", "frostmagelegs", "obswolfhelm", "obswolfchest", "obswolflegs", "druidhelm", "druidchest", "druidlegs", "heavycarhelm", "heavycarchest", "heavycarlegs", "runeknighthelm", "runeknightchest", "runeknightlegs", "bearhelm2", "bearchest2", "bearlegs2", "samuraihelm", "samuraichest", "samurailegs");
			Armor(ScrollTier.S, "ss_wraithhelm", "ss_wraithchest", "ss_wraithlegs", "valkhelm", "valkchest", "valklegs", "warlordhelm", "warlordchest", "warlordlegs", "stjudehelm", "stjudechest", "stjudelegs", "heavybearhelm", "heavybearchest", "heavybearlegs", "ss_korokhelm", "ss_korokchest", "ss_koroklegs", "lagihelmalt", "lagichest", "lagipants", "ss_ashcape");
			Armor(ScrollTier.SPlus, "trueskoghelm", "trueskogchest", "trueskoglegs", "ss_dragonlordhelm", "ss_dragonlordchest", "ss_dragonlordlegs", "sven2", "sven2chest", "sven2legs", "sven3", "ss_frodehelm", "ss_frodechest", "ss_frodelegs", "ss_storrhelm", "ss_storrchest", "ss_storrlegs", "wshelm", "wschest", "wslegs", "ss_storrcape");
		}

		private static void RegisterCah()
		{
			CahWeapon(ScrollTier.E, "OrcSword", "OrcBattleaxe", "OrcMace", "OrcDagger", "OrcSpear", "OrcAtgeir", "OrcFists", "OrcBow", "OrcStaff", "ForestGreatsword", "ForestGreataxe", "ForestMace", "ForestDagger", "ForestSpear", "ForestScythe", "ForestFists", "ForestBow", "ForestChakram", "BeastlyBerry", "Ravencall", "RamHammer", "Goldtooth", "Ephemerance", "VioletReaper", "JestersToss", "SkullStrike", "Cervideus");
			CahShield(ScrollTier.E, "OrcShield", "ForestShield");
			CahWeapon(ScrollTier.D, "BloodstoneSword", "BloodstoneAxe", "BloodstoneMaul", "BloodstoneDaggers", "BloodstonePike", "BloodstoneClaws", "BloodstoneBow", "BloodstoneStaff", "Bonecleaver", "SoulThief", "SnakeSwordAxe", "Spiritbreakers", "SoulGlaive", "SaurusScythe", "HornedHandscythes", "DemonfaceMace", "FurnaceDagger", "FurnaceBow", "Carpshot", "Crabhammer", "OceanTrident", "SeaSong", "WaveCrusher");
			CahShield(ScrollTier.D, "BloodstoneShield", "FurnaceBuckler");
			CahWeapon(ScrollTier.C, "SilvercrystalGreatsword", "SilvercrystalAxes", "SilvercrystalHammer", "SilvercrystalDagger", "SilvercrystalSpear", "SilvercrystalAtgeir", "SilvercrystalKatars", "SilvercrystalBow", "SilvercrystalStaff", "Astralis", "FlowerVeil", "MountainCleaver", "Goldcleave", "Goldvein", "EchoCutter", "ToxifrostCrushers", "BloodcurseGlaives", "KrystaliumCrashers", "HallowsGrip", "WindHowl");
			CahShield(ScrollTier.C, "SilvercrystalShield", "Shiverwall");
			CahWeapon(ScrollTier.B, "SoulburnDualblades", "SoulburnGreatsword", "SoulburnAxe", "SoulburnGreathammer", "SoulburnDaggers", "SoulburnSpear", "SoulburnScythe", "SoulburnBow", "SoulburnCrossbow", "Arondight", "Vane", "Warmonger", "Corruptum", "Demora", "SicklySickle", "Tinkerblade", "Warbringer", "SolsticeSpear", "Sunforger", "SunfistWarpicks", "WildwindBow");
			CahShield(ScrollTier.B, "SoulburnShield");
			CahWeapon(ScrollTier.A, "SuccubineKatana", "SuccubineGreatsword", "SuccubineGreataxe", "SuccubineMace", "SuccubineDagger", "SuccubineSpear", "SuccubineScythe", "SuccubineSlicers", "SuccubineBow", "SuccubineRifle", "BlossomSong", "Infernus", "Jadecutter", "Soulrend", "Voidheart", "VoidAxes", "Voidshot", "DarkmoonReaper", "ReachCryonic", "ReachInfernal", "EmpiricGreataxe", "EmpiricSickles", "EmpiricSpear", "Malevolence", "Harrower", "Sparkgrinder", "Nocturata");
			CahShield(ScrollTier.A, "SuccubineShield", "Soulguard", "Sparkshield");
			CahWeapon(ScrollTier.S, "VolcanoKatana", "VolcanoGreatsword", "VolcanoGreataxe", "VolcanoGreathammer", "VolcanoDagger", "VolcanoCleavers", "VolcanoPike", "VolcanoGuantlets", "VolcanicBow", "VolcanoLauncher", "Laevateinn", "Rupture", "BloodsoulVane", "Arumeria", "Auretia", "Carmine", "TinkerersGlory", "Goldstride", "Deignfall", "Magmarium", "Titansbane", "DragonBow", "ThunderSteel", "UnholyStar", "EmeraldFlame");
			CahShield(ScrollTier.S, "VolcanoBuckler", "VolcanoShield");
			CahWeapon(ScrollTier.SPlus, "Kalduin", "Corundum", "Agnarr", "SunPiercer", "Drellvar", "StrideBreaker", "Xellumari", "Regalia", "Regulator", "Starshot", "Vastrix", "Sacrilege", "Voidmourne", "Frigada", "Agareth", "StormWalker", "StormSinger", "StormSlayers", "Sorrowshard", "Skulghasters", "Rahvitas", "Withercusp", "Shiverdeath", "DeathfrostShot", "Sieglinde", "Permafrost");
			CahShield(ScrollTier.SPlus, "Gauntreid");
		}

		private static void CahWeapon(ScrollTier tier, params string[] names)
		{
			Weapon(tier, WithSuffix(names, "_CAH"));
		}

		private static void CahShield(ScrollTier tier, params string[] names)
		{
			Shield(tier, WithSuffix(names, "_CAH"));
		}

		private static string[] WithSuffix(string[] names, string suffix)
		{
			string[] array = new string[names.Length];
			for (int i = 0; i < names.Length; i++)
			{
				array[i] = names[i] + suffix;
			}
			return array;
		}

		private static void Weapon(ScrollTier tier, params string[] names)
		{
			Add(ItemCategory.Weapon, tier, names);
		}

		private static void Armor(ScrollTier tier, params string[] names)
		{
			Add(ItemCategory.Armor, tier, names);
		}

		private static void Shield(ScrollTier tier, params string[] names)
		{
			Add(ItemCategory.Shield, tier, names);
		}

		private static void Skip(params string[] names)
		{
			Add(ItemCategory.Skip, ScrollTier.E, names);
		}

		private static void Add(ItemCategory category, ScrollTier tier, string[] names)
		{
			for (int i = 0; i < names.Length; i++)
			{
				ItemCatalog.RegisterBuiltIn(names[i], category, tier);
			}
		}
	}
	internal static class ModSupport
	{
		internal static bool TryGetTier(string prefab, out ScrollTier tier)
		{
			tier = ScrollTier.E;
			if (string.IsNullOrEmpty(prefab))
			{
				return false;
			}
			string text = prefab.ToLowerInvariant();
			if (text.EndsWith("_tw", StringComparison.Ordinal))
			{
				return TryTherzieTier(text, out tier);
			}
			if (text.StartsWith("ss_", StringComparison.Ordinal))
			{
				return TrySouthsilTier(text, out tier);
			}
			return false;
		}

		internal static ItemCategory GuessCategory(string prefab)
		{
			if (string.IsNullOrEmpty(prefab))
			{
				return ItemCategory.Auto;
			}
			string text = prefab.ToLowerInvariant();
			if (!text.EndsWith("_tw", StringComparison.Ordinal))
			{
				return ItemCategory.Auto;
			}
			if (Starts(text, "arrow", "bolt", "bomb", "mead", "rune", "mat_", "se_", "piece_", "ancientscroll", "amethyst", "diamond", "emerald", "onyx", "sapphire", "topaz", "pelt", "scraps", "essence", "fang"))
			{
				return ItemCategory.Auto;
			}
			if (Contains(text, "shield"))
			{
				return ItemCategory.Shield;
			}
			if (Starts(text, "helmet", "armor", "cape", "belt") || Contains(text, "armorchest", "armorlegs"))
			{
				return ItemCategory.Armor;
			}
			if (Starts(text, "axe", "atgeir", "bastard", "battleaxe", "battlehammer", "bow", "blade", "claymore", "crossbow", "cudgel", "dual", "fist", "greatbow", "greatclub", "knife", "lance", "mace", "pickaxe", "scythe", "sledge", "spear", "sword", "throw", "trident", "warpike", "staff"))
			{
				return ItemCategory.Weapon;
			}
			return ItemCategory.Auto;
		}

		private static bool TryTherzieTier(string name, out ScrollTier tier)
		{
			tier = ScrollTier.E;
			if (Contains(name, "tyranium"))
			{
				tier = ScrollTier.SPlus;
				return true;
			}
			if (Contains(name, "flametal", "ashlands", "asksvin", "charred", "fader", "niedhogg", "dyrnwyn", "slayer", "splitner", "berzerkr", "eldner", "ripper", "demonic", "bloodthirst", "vampiric", "scimitar", "sacrifice", "destruction", "capeash"))
			{
				tier = ScrollTier.S;
				return true;
			}
			if (Contains(name, "carapace", "dvergr", "demolisher", "queen", "rotten", "mistwalker", "krom", "jotun", "skullsplittur", "spinesnap", "arbalest", "feather", "mage", "eitr", "softtissue", "yggdrasil", "himminafl", "skoll", "legion"))
			{
				tier = ScrollTier.A;
				return true;
			}
			if (Contains(name, "blackmetal", "padded", "linen", "lox", "needle", "berserkerundead", "bjornundead", "yagluth", "bold") || ContainsToken(name, "bm") || Contains(name, "bm"))
			{
				tier = ScrollTier.B;
				return true;
			}
			if (Contains(name, "silver", "wolf", "fenrir", "drake", "crystal", "draugr", "obsidian", "moder", "ullr", "vidar"))
			{
				tier = ScrollTier.C;
				return true;
			}
			if (Contains(name, "iron", "root", "banded", "huntsman", "elderbark", "serpent", "bonemass", "viper", "wrench", "greatclub", "chitin", "elder", "bone", "trollbone", "bear", "ymir", "warrior"))
			{
				tier = ScrollTier.D;
				return true;
			}
			if (Contains(name, "bronze", "troll", "finewood", "copper", "leather", "razorback", "trollblack", "stag", "eikthyr"))
			{
				tier = ScrollTier.E;
				return true;
			}
			if (Contains(name, "flint", "wood", "club", "rag", "deerhide", "hunter", "rogue", "vigorous"))
			{
				tier = ScrollTier.E;
				return true;
			}
			return false;
		}

		private static bool TrySouthsilTier(string name, out ScrollTier tier)
		{
			tier = ScrollTier.E;
			if (Contains(name, "storr", "dragonlord", "frode", "wshelm", "wschest", "wslegs"))
			{
				tier = ScrollTier.SPlus;
				return true;
			}
			if (Contains(name, "korok"))
			{
				tier = ScrollTier.S;
				return true;
			}
			if (Contains(name, "wraith") && !Contains(name, "lightwraith"))
			{
				tier = ScrollTier.S;
				return true;
			}
			if (Contains(name, "ashcape", "heavybear", "valk", "warlord", "stjude", "lagi"))
			{
				tier = ScrollTier.S;
				return true;
			}
			if (Contains(name, "barb", "serpentcape"))
			{