Decompiled source of Reforged Classes v0.1.0

plugins/ValheimReforged.dll

Decompiled a day 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 UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.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 ValheimReforged
{
	public enum Eff
	{
		None,
		MaxHealth,
		MaxStamina,
		MaxEitr,
		MoveSpeed,
		Damage,
		AbilityPower,
		HealthRegen,
		StaminaRegen,
		EitrRegen,
		LifeSteal,
		Cooldown,
		Crit,
		Resist,
		MeleeDamage,
		RangedDamage,
		MagicDamage,
		Execute,
		Opening,
		KillHeal,
		StaminaCost,
		SwordDamage,
		KnifeDamage,
		AxeDamage,
		ClubDamage,
		BowDamage,
		CrossbowDamage,
		ElementalDamage,
		BloodDamage,
		Experience,
		ArmorBonus,
		MiningDamage,
		ChoppingDamage,
		HarvestYield,
		FoodDuration,
		FishingSkill,
		ElementalResist,
		AmmoSave,
		FreeAmmo
	}
	public class Ability
	{
		public string Id;

		public string Glyph;

		public RpgClass Class;

		public int Col;

		public int Row;

		public string Parent;

		public int MaxRank = 5;

		public Eff Effect;

		public float PerRank;

		public int Cost = 1;

		public float Power = 1f;

		public float Cooldown;

		public Func<Player, int, bool> Cast;

		public Func<int, string> Preview;

		public string Name => L.T("ability." + Id + ".name");

		public string Desc
		{
			get
			{
				if (!Active)
				{
					return L.F("ui.per_rank", Stats.Describe(Effect, PerRank));
				}
				return L.T("ability." + Id + ".desc");
			}
		}

		public string Info
		{
			get
			{
				string key = "ability." + Id + ".info";
				if (!L.Has(key))
				{
					return null;
				}
				return L.T(key);
			}
		}

		public bool Active => Cast != null;
	}
	public class Buff
	{
		public string Id;

		public string Name;

		public float Expires;

		public float Duration;

		public Dictionary<Eff, float> Mods = new Dictionary<Eff, float>();
	}
	public static class Buffs
	{
		public static readonly List<Buff> Active = new List<Buff>();

		public static void Add(string id, string name, float duration, params KeyValuePair<Eff, float>[] mods)
		{
			Active.RemoveAll((Buff b) => b.Id == id);
			Buff buff = new Buff
			{
				Id = id,
				Name = name,
				Expires = Time.time + duration,
				Duration = duration
			};
			for (int num = 0; num < mods.Length; num++)
			{
				KeyValuePair<Eff, float> keyValuePair = mods[num];
				buff.Mods[keyValuePair.Key] = keyValuePair.Value;
			}
			Active.Add(buff);
		}

		public static KeyValuePair<Eff, float> M(Eff e, float v)
		{
			return new KeyValuePair<Eff, float>(e, v);
		}

		public static float Get(Eff e)
		{
			float num = 0f;
			for (int num2 = Active.Count - 1; num2 >= 0; num2--)
			{
				float value;
				if (Active[num2].Expires <= Time.time)
				{
					Active.RemoveAt(num2);
				}
				else if (Active[num2].Mods.TryGetValue(e, out value))
				{
					num += value;
				}
			}
			return num;
		}

		public static void Clear()
		{
			Active.Clear();
		}
	}
	public static class Stats
	{
		private static readonly Dictionary<Eff, float> Caps = new Dictionary<Eff, float>
		{
			{
				Eff.MoveSpeed,
				0.6f
			},
			{
				Eff.Crit,
				0.75f
			},
			{
				Eff.LifeSteal,
				0.3f
			},
			{
				Eff.Cooldown,
				0.5f
			},
			{
				Eff.StaminaCost,
				0.6f
			},
			{
				Eff.Resist,
				0.8f
			},
			{
				Eff.ElementalResist,
				0.75f
			},
			{
				Eff.AmmoSave,
				0.75f
			}
		};

		public static float Get(Eff e)
		{
			RpgData data = Plugin.Data;
			if (data == null || data.Class == RpgClass.None)
			{
				return 0f;
			}
			float num = Buffs.Get(e) + Talents.Bonus(e);
			foreach (Ability item in Abilities.For(data.Class))
			{
				if (item.Effect == e)
				{
					num += item.PerRank * (float)data.Rank(item.Id);
				}
			}
			if (!Caps.TryGetValue(e, out var value))
			{
				return num;
			}
			return Mathf.Min(num, value);
		}

		public static float GetPassive(Eff e)
		{
			return GetTree(e) + Talents.Bonus(e);
		}

		public static float GetTree(Eff e)
		{
			RpgData data = Plugin.Data;
			if (data == null || data.Class == RpgClass.None)
			{
				return 0f;
			}
			float num = 0f;
			foreach (Ability item in Abilities.For(data.Class))
			{
				if (item.Effect == e)
				{
					num += item.PerRank * (float)data.Rank(item.Id);
				}
			}
			return num;
		}

		public static string Describe(Eff e, float amount)
		{
			string text;
			switch (e)
			{
			case Eff.None:
				return "";
			case Eff.MaxHealth:
			case Eff.MaxStamina:
			case Eff.MaxEitr:
			case Eff.FishingSkill:
				text = amount.ToString("0.#");
				break;
			case Eff.HealthRegen:
			case Eff.StaminaRegen:
			case Eff.EitrRegen:
				text = amount.ToString("0.0");
				break;
			default:
				text = (amount * 100f).ToString("0.#");
				break;
			}
			return L.F("eff." + e, text);
		}
	}
	public static class Dash
	{
		private static Vector3 dir;

		private static float speed;

		private static float left;

		public static void Start(Player p, Vector3 direction, float distance, float duration)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			direction.y = 0f;
			dir = ((Vector3)(ref direction)).normalized;
			speed = distance / duration;
			left = duration;
		}

		public static void Step(Player p)
		{
			//IL_002d: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			if (left <= 0f)
			{
				return;
			}
			float fixedDeltaTime = Time.fixedDeltaTime;
			left -= fixedDeltaTime;
			float num = speed * fixedDeltaTime;
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(((Component)p).transform.position + Vector3.up * 0.9f, dir, ref val, num + 0.5f))
			{
				left = 0f;
				return;
			}
			Rigidbody component = ((Component)p).GetComponent<Rigidbody>();
			if ((Object)(object)component != (Object)null)
			{
				component.position += dir * num;
				return;
			}
			Transform transform = ((Component)p).transform;
			transform.position += dir * num;
		}
	}
	public static class Abilities
	{
		public static readonly List<Ability> All;

		private static readonly Dictionary<RpgClass, List<Ability>> byClass;

		private static readonly Dictionary<string, float> ready;

		private static readonly Dictionary<string, float> total;

		private static float CurrentPower;

		public static List<Ability> For(RpgClass c)
		{
			if (!byClass.TryGetValue(c, out var value))
			{
				return new List<Ability>();
			}
			return value;
		}

		public static Ability Find(string id)
		{
			return All.FirstOrDefault((Ability a) => a.Id == id);
		}

		public static float CooldownLeft(string id)
		{
			if (!ready.TryGetValue(id, out var value))
			{
				return 0f;
			}
			return Mathf.Max(0f, value - Time.time);
		}

		public static float CooldownTotal(string id)
		{
			if (!total.TryGetValue(id, out var value))
			{
				return 1f;
			}
			return value;
		}

		public static void Cast(Player p, RpgData d, int slot)
		{
			string text = d.Slots[slot];
			Ability ability = ((text == null) ? null : Find(text));
			if (ability == null || !ability.Active)
			{
				return;
			}
			int num = d.Rank(ability.Id);
			if (num <= 0)
			{
				return;
			}
			if (CooldownLeft(ability.Id) > 0f)
			{
				((Character)p).Message((MessageType)1, L.F("msg.cooldown", ability.Name), 0, (Sprite)null, false);
				return;
			}
			CurrentPower = ability.Power;
			if (ability.Cast(p, num))
			{
				float num2 = ability.Cooldown * (1f - Mathf.Min(0.5f, Stats.Get(Eff.Cooldown)));
				ready[ability.Id] = Time.time + num2;
				total[ability.Id] = num2;
			}
		}

		private static float FrenzyTime(int rank)
		{
			return 6f + (float)rank;
		}

		private static float FrenzyDamage(int rank)
		{
			return (0.2f + 0.06f * (float)rank) * CurrentPower;
		}

		private static float Scale(int rank, float basis, float perRank)
		{
			return (basis + perRank * (float)rank) * (1f + 0.02f * (float)((Plugin.Data == null) ? 1 : Plugin.Data.Level)) * (1f + Stats.Get(Eff.AbilityPower)) * Plugin.AbilityDamage.Value * CurrentPower;
		}

		private static void Burst(Player p, Vector3 center, float radius, DamageTypes dmg, float push)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			Character[] array = Character.GetAllCharacters().ToArray();
			foreach (Character val in array)
			{
				if (!((Object)(object)val == (Object)(object)p) && !val.IsDead() && BaseAI.IsEnemy((Character)(object)p, val) && !(Vector3.Distance(((Component)val).transform.position, center) > radius))
				{
					Strike(p, val, center, dmg, push);
				}
			}
		}

		private static void Strike(Player p, Character c, Vector3 from, DamageTypes dmg, float push)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			HitData val = new HitData
			{
				m_damage = dmg,
				m_attacker = ((Character)p).GetZDOID(),
				m_point = c.GetCenterPoint()
			};
			Vector3 val2 = ((Component)c).transform.position - from;
			val.m_dir = ((Vector3)(ref val2)).normalized;
			val.m_pushForce = push;
			HitData val3 = val;
			c.Damage(val3);
		}

		private static Vector3 AimPoint(Player p, float max)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			Transform val = (((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform : ((Component)p).transform);
			RaycastHit val2 = default(RaycastHit);
			if (Physics.Raycast(val.position, val.forward, ref val2, max))
			{
				return ((RaycastHit)(ref val2)).point;
			}
			return val.position + val.forward * max;
		}

		private static ItemData FindArrows(Player p, int count)
		{
			foreach (ItemData allItem in ((Humanoid)p).GetInventory().GetAllItems())
			{
				if (allItem.m_shared.m_ammoType == "$ammo_arrows" && allItem.m_stack >= count)
				{
					return allItem;
				}
			}
			return null;
		}

		private static bool Eitr(Player p, float cost)
		{
			if (!((Character)p).HaveEitr(cost))
			{
				((Character)p).Message((MessageType)2, L.T("msg.no_eitr"), 0, (Sprite)null, false);
				return false;
			}
			((Character)p).UseEitr(cost);
			return true;
		}

		private static float TakeArrows(Player p, int cost)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			ItemData val = FindArrows(p, cost);
			if (val == null)
			{
				((Character)p).Message((MessageType)2, L.F("msg.need_arrows", cost), 0, (Sprite)null, false);
				return -1f;
			}
			float pierce = val.GetDamage().m_pierce;
			((Humanoid)p).GetInventory().RemoveItem(val, cost);
			return pierce;
		}

		private static Ability P(RpgClass cls, string id, int col, int row, string parent, Eff e, float per, string glyph)
		{
			Ability obj = new Ability
			{
				Id = id,
				Class = cls,
				Col = col,
				Row = row,
				Parent = parent,
				Effect = e,
				PerRank = per,
				Glyph = glyph
			};
			Add(obj);
			return obj;
		}

		private static Ability A(RpgClass cls, string id, int col, int row, string parent, float cd, string glyph, Func<Player, int, bool> cast)
		{
			Ability ability = new Ability
			{
				Id = id,
				Class = cls,
				Col = col,
				Row = row,
				Parent = parent,
				Cooldown = cd,
				Glyph = glyph,
				Cast = cast
			};
			if (row == 4)
			{
				ability.MaxRank = 3;
			}
			Add(ability);
			return ability;
		}

		private static void Tip(string id, Func<int, string> preview)
		{
			Find(id).Preview = delegate(int r)
			{
				float currentPower = CurrentPower;
				CurrentPower = Find(id).Power;
				try
				{
					return preview(r);
				}
				finally
				{
					CurrentPower = currentPower;
				}
			};
		}

		private static void Add(Ability a)
		{
			All.Add(a);
			if (!byClass.TryGetValue(a.Class, out var value))
			{
				value = (byClass[a.Class] = new List<Ability>());
			}
			value.Add(a);
		}

		static Abilities()
		{
			All = new List<Ability>();
			byClass = new Dictionary<RpgClass, List<Ability>>();
			ready = new Dictionary<string, float>();
			total = new Dictionary<string, float>();
			CurrentPower = 1f;
			RpgClass cls = RpgClass.Archer;
			RpgClass cls2 = RpgClass.Mage;
			RpgClass cls3 = RpgClass.Rogue;
			P(RpgClass.Warrior, "w_str1", 0, 1, null, Eff.Damage, 0.02f, "sword");
			A(RpgClass.Warrior, "w_shock", 0, 2, "w_str1", 18f, "w_shock", delegate(Player p, int r)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: 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_0050: Unknown result type (might be due to invalid IL or missing references)
				Vfx.Cast("w_shock", ((Component)p).transform.position, ((Component)p).transform.position);
				Burst(p, ((Component)p).transform.position, 6f, new DamageTypes
				{
					m_blunt = Scale(r, 25f, 15f)
				}, 40f);
				return true;
			});
			P(RpgClass.Warrior, "w_crit", 0, 3, "w_shock", Eff.Crit, 0.02f, "crit");
			P(RpgClass.Warrior, "w_rage", 0, 4, "w_crit", Eff.MeleeDamage, 0.06f, "sword");
			P(RpgClass.Warrior, "w_iron", 1, 1, null, Eff.MaxHealth, 10f, "heart");
			A(RpgClass.Warrior, "w_wind", 1, 2, "w_iron", 45f, "w_wind", delegate(Player p, int r)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				Vfx.Cast("w_wind", ((Component)p).transform.position, ((Component)p).transform.position);
				((Character)p).Heal(((Character)p).GetMaxHealth() * (0.15f + 0.05f * (float)r), true);
				((Character)p).AddStamina(((Character)p).GetMaxStamina());
				return true;
			});
			P(RpgClass.Warrior, "w_regen", 1, 3, "w_wind", Eff.HealthRegen, 0.25f, "w_wind");
			P(RpgClass.Warrior, "w_wall", 1, 4, "w_regen", Eff.Resist, 0.05f, "w_iron");
			P(RpgClass.Warrior, "w_stam", 2, 1, null, Eff.MaxStamina, 6f, "a_endur");
			P(RpgClass.Warrior, "w_cry", 2, 2, "w_stam", Eff.StaminaCost, 0.03f, "r_reflex");
			P(RpgClass.Warrior, "w_drain", 2, 3, "w_cry", Eff.LifeSteal, 0.015f, "m_well");
			P(RpgClass.Warrior, "w_quake", 2, 4, "w_drain", Eff.Execute, 0.15f, "w_shock");
			P(cls, "a_sharp", 0, 1, null, Eff.Damage, 0.02f, "sword");
			A(cls, "a_rain", 0, 2, "a_sharp", 22f, "a_rain", delegate(Player p, int r)
			{
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				float num = TakeArrows(p, 5);
				if (num < 0f)
				{
					return false;
				}
				Vector3 val = AimPoint(p, 40f);
				Vfx.Cast("a_rain", ((Component)p).transform.position, val);
				Burst(p, val, 7f, new DamageTypes
				{
					m_pierce = Scale(r, 30f, 15f) + num * 2f
				}, 10f);
				return true;
			});
			P(cls, "a_crit", 0, 3, "a_rain", Eff.Crit, 0.02f, "crit");
			P(cls, "a_volley", 0, 4, "a_crit", Eff.RangedDamage, 0.06f, "a_rain");
			P(cls, "a_endur", 1, 1, null, Eff.MaxStamina, 4f, "a_endur");
			A(cls, "a_leap", 1, 2, "a_endur", 25f, "a_leap", delegate(Player p, int r)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				Vfx.Cast("a_leap", ((Component)p).transform.position, ((Component)p).transform.position);
				float v = FrenzyDamage(r);
				Buffs.Add("a_leap", L.T("ability.a_leap.name"), FrenzyTime(r), Buffs.M(Eff.BowDamage, v), Buffs.M(Eff.CrossbowDamage, v), Buffs.M(Eff.FreeAmmo, 1f));
				return true;
			});
			P(cls, "a_swift", 1, 3, "a_leap", Eff.MoveSpeed, 0.02f, "r_reflex");
			P(cls, "a_focus", 1, 4, "a_swift", Eff.Opening, 0.15f, "crit");
			P(cls, "a_vigor", 2, 1, null, Eff.MaxHealth, 6f, "heart");
			P(cls, "a_herbs", 2, 2, "a_vigor", Eff.KillHeal, 0.01f, "w_wind");
			P(cls, "a_second", 2, 3, "a_herbs", Eff.StaminaRegen, 0.4f, "a_endur");
			P(cls, "a_frost", 2, 4, "a_second", Eff.Execute, 0.15f, "snow");
			P(cls2, "m_power", 0, 1, null, Eff.AbilityPower, 0.03f, "m_blast");
			A(cls2, "m_blast", 0, 2, "m_power", 14f, "m_blast", delegate(Player p, int r)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				if (!Eitr(p, 25f))
				{
					return false;
				}
				Vector3 val = AimPoint(p, 35f);
				Vfx.Cast("m_blast", ((Component)p).transform.position, val);
				Burst(p, val, 5f, new DamageTypes
				{
					m_lightning = Scale(r, 35f, 20f)
				}, 20f);
				return true;
			});
			P(cls2, "m_crit", 0, 3, "m_blast", Eff.Crit, 0.02f, "crit");
			P(cls2, "m_storm", 0, 4, "m_crit", Eff.MagicDamage, 0.06f, "m_blast");
			P(cls2, "m_arcana", 1, 1, null, Eff.MaxEitr, 8f, "m_arcana");
			A(cls2, "m_well", 1, 2, "m_arcana", 40f, "m_well", delegate(Player p, int r)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				Vfx.Cast("m_well", ((Component)p).transform.position, ((Component)p).transform.position);
				((Character)p).AddEitr(((Character)p).GetMaxEitr() * (0.3f + 0.1f * (float)r));
				return true;
			});
			P(cls2, "m_flow", 1, 3, "m_well", Eff.EitrRegen, 0.4f, "m_well");
			P(cls2, "m_shield", 1, 4, "m_flow", Eff.Resist, 0.05f, "w_iron");
			P(cls2, "m_vit", 2, 1, null, Eff.MaxHealth, 5f, "heart");
			P(cls2, "m_frost", 2, 2, "m_vit", Eff.KillHeal, 0.01f, "snow");
			P(cls2, "m_cool", 2, 3, "m_frost", Eff.Cooldown, 0.03f, "clock");
			P(cls2, "m_meteor", 2, 4, "m_cool", Eff.AbilityPower, 0.08f, "fire");
			P(cls3, "r_blade", 0, 1, null, Eff.Damage, 0.02f, "sword");
			A(cls3, "r_step", 0, 2, "r_blade", 20f, "r_reflex", delegate(Player p, int r)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				Vfx.Cast("r_step", ((Component)p).transform.position, ((Component)p).transform.position);
				Buffs.Add("r_step", "Disparada", 5f + (float)r, Buffs.M(Eff.MoveSpeed, 0.2f + 0.05f * (float)r));
				return true;
			});
			P(cls3, "r_crit", 0, 3, "r_step", Eff.Crit, 0.03f, "crit");
			P(cls3, "r_execute", 0, 4, "r_crit", Eff.Execute, 0.15f, "crit");
			P(cls3, "r_reflex", 1, 1, null, Eff.MoveSpeed, 0.02f, "r_reflex");
			P(cls3, "r_smoke", 1, 2, "r_reflex", Eff.Resist, 0.03f, "r_venom");
			P(cls3, "r_agile", 1, 3, "r_smoke", Eff.StaminaRegen, 0.4f, "a_endur");
			P(cls3, "r_shadow", 1, 4, "r_agile", Eff.Opening, 0.15f, "r_step");
			P(cls3, "r_vit", 2, 1, null, Eff.MaxHealth, 4f, "heart");
			A(cls3, "r_venom", 2, 2, "r_vit", 20f, "r_venom", delegate(Player p, int r)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: 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_0067: Unknown result type (might be due to invalid IL or missing references)
				Vfx.Cast("r_venom", ((Component)p).transform.position, ((Component)p).transform.position);
				Burst(p, ((Component)p).transform.position, 5f, new DamageTypes
				{
					m_poison = Scale(r, 60f, 30f),
					m_pierce = Scale(r, 15f, 8f)
				}, 0f);
				return true;
			});
			P(cls3, "r_leech", 2, 3, "r_venom", Eff.LifeSteal, 0.01f, "m_well");
			P(cls3, "r_plague", 2, 4, "r_leech", Eff.AbilityPower, 0.08f, "r_venom");
			Tip("w_shock", (int r) => L.F("ability.w_shock.preview", Scale(r, 25f, 15f).ToString("0")));
			Tip("w_wind", (int r) => L.F("ability.w_wind.preview", ((0.15f + 0.05f * (float)r) * 100f).ToString("0")));
			Tip("a_rain", (int r) => L.F("ability.a_rain.preview", Scale(r, 30f, 15f).ToString("0")));
			Tip("a_leap", (int r) => L.F("ability.a_leap.preview", FrenzyTime(r).ToString("0"), Mathf.RoundToInt(FrenzyDamage(r) * 100f)));
			Tip("m_blast", (int r) => L.F("ability.m_blast.preview", Scale(r, 35f, 20f).ToString("0")));
			Tip("m_well", (int r) => L.F("ability.m_well.preview", ((0.3f + 0.1f * (float)r) * 100f).ToString("0")));
			Tip("r_step", (int r) => L.F("ability.r_step.preview", ((0.2f + 0.05f * (float)r) * 100f).ToString("0"), 5 + r));
			Tip("r_venom", (int r) => L.F("ability.r_venom.preview", Scale(r, 60f, 30f).ToString("0"), Scale(r, 15f, 8f).ToString("0")));
			foreach (Ability item in All)
			{
				if (!item.Active && item.Row == 4)
				{
					item.MaxRank = 3;
				}
			}
		}
	}
	public static class Floaters
	{
		private class F
		{
			public Vector3 Pos;

			public string Text;

			public Color Color;

			public int Size;

			public float T0;

			public float Dur;
		}

		public static readonly Color CritColor = new Color(1f, 0.82f, 0.25f);

		public static readonly Color ExecuteColor = new Color(1f, 0.4f, 0.35f);

		public static readonly Color OpeningColor = new Color(1f, 0.65f, 0.3f);

		public static readonly Color XpColor = new Color(0.55f, 0.75f, 1f);

		private static readonly List<F> list = new List<F>();

		private static readonly Dictionary<string, float> lastShown = new Dictionary<string, float>();

		private static GUIStyle style;

		public static void Add(Vector3 pos, string text, Color color, int size = 18, float dur = 1.2f, string throttleKey = null, float throttle = 0f)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if (throttleKey != null)
			{
				if (lastShown.TryGetValue(throttleKey, out var value) && Time.time - value < throttle)
				{
					return;
				}
				lastShown[throttleKey] = Time.time;
				if (lastShown.Count > 200)
				{
					lastShown.Clear();
				}
			}
			list.Add(new F
			{
				Pos = pos,
				Text = text,
				Color = color,
				Size = size,
				T0 = Time.time,
				Dur = dur
			});
			if (list.Count > 40)
			{
				list.RemoveAt(0);
			}
		}

		public static void Draw(float s)
		{
			//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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			if (list.Count == 0)
			{
				return;
			}
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return;
			}
			if (style == null)
			{
				style = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)4,
					fontStyle = (FontStyle)1
				};
			}
			Rect val2 = default(Rect);
			for (int num = list.Count - 1; num >= 0; num--)
			{
				F f = list[num];
				float num2 = (Time.time - f.T0) / f.Dur;
				if (num2 >= 1f)
				{
					list.RemoveAt(num);
				}
				else
				{
					Vector3 val = main.WorldToScreenPoint(f.Pos + Vector3.up * (num2 * 1.4f));
					if (!(val.z <= 0f))
					{
						float num3 = val.x / s;
						float num4 = ((float)Screen.height - val.y) / s;
						float num5 = 1f + 0.35f * Mathf.Clamp01(1f - num2 * 7f);
						style.fontSize = Mathf.RoundToInt((float)f.Size * num5);
						float num6 = 1f - num2 * num2;
						((Rect)(ref val2))..ctor(num3 - 150f, num4 - 20f, 300f, 40f);
						style.normal.textColor = new Color(0f, 0f, 0f, 0.85f * num6);
						GUI.Label(new Rect(((Rect)(ref val2)).x + 1.5f, ((Rect)(ref val2)).y + 1.5f, ((Rect)(ref val2)).width, ((Rect)(ref val2)).height), f.Text, style);
						style.normal.textColor = new Color(f.Color.r, f.Color.g, f.Color.b, num6);
						GUI.Label(val2, f.Text, style);
					}
				}
			}
		}
	}
	public static class Icons
	{
		private class Canvas
		{
			private readonly Color[] px = (Color[])(object)new Color[4096];

			private void Plot(int x, int y, Color c, float a)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_006d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0080: Unknown result type (might be due to invalid IL or missing references)
				//IL_0089: Unknown result type (might be due to invalid IL or missing references)
				//IL_008f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
				if (x >= 0 && y >= 0 && x < 64 && y < 64)
				{
					a *= c.a;
					if (!(a <= 0f))
					{
						int num = y * 64 + x;
						Color val = px[num];
						float num2 = a + val.a * (1f - a);
						float num3 = 1f / num2;
						px[num] = new Color((c.r * a + val.r * val.a * (1f - a)) * num3, (c.g * a + val.g * val.a * (1f - a)) * num3, (c.b * a + val.b * val.a * (1f - a)) * num3, num2);
					}
				}
			}

			public void Disc(float cx, float cy, float r, Color c)
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				for (int i = (int)(cy - r - 1f); (float)i <= cy + r + 1f; i++)
				{
					for (int j = (int)(cx - r - 1f); (float)j <= cx + r + 1f; j++)
					{
						Plot(j, i, c, Mathf.Clamp01(r - Vector2.Distance(new Vector2((float)j + 0.5f, (float)i + 0.5f), new Vector2(cx, cy)) + 0.5f));
					}
				}
			}

			public void Ring(float cx, float cy, float r, float th, Color c)
			{
				//IL_0024: 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_0039: Unknown result type (might be due to invalid IL or missing references)
				for (int i = (int)(cy - r - th); (float)i <= cy + r + th; i++)
				{
					for (int j = (int)(cx - r - th); (float)j <= cx + r + th; j++)
					{
						float num = Vector2.Distance(new Vector2((float)j + 0.5f, (float)i + 0.5f), new Vector2(cx, cy));
						Plot(j, i, c, Mathf.Clamp01(th * 0.5f - Mathf.Abs(num - r) + 0.5f));
					}
				}
			}

			public void Line(float x0, float y0, float x1, float y1, float th, Color c)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_0058: Unknown result type (might be due to invalid IL or missing references)
				//IL_0059: Unknown result type (might be due to invalid IL or missing references)
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_006d: Unknown result type (might be due to invalid IL or missing references)
				//IL_006f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
				Vector2 val = default(Vector2);
				((Vector2)(ref val))..ctor(x0, y0);
				Vector2 val2 = new Vector2(x1, y1) - val;
				float sqrMagnitude = ((Vector2)(ref val2)).sqrMagnitude;
				Vector2 val3 = default(Vector2);
				for (int i = 0; i < 64; i++)
				{
					for (int j = 0; j < 64; j++)
					{
						((Vector2)(ref val3))..ctor((float)j + 0.5f, (float)i + 0.5f);
						float num = ((sqrMagnitude > 0f) ? Mathf.Clamp01(Vector2.Dot(val3 - val, val2) / sqrMagnitude) : 0f);
						float num2 = Vector2.Distance(val3, val + val2 * num);
						float num3 = Mathf.Clamp01(th * 0.5f - num2 + 0.5f);
						if (num3 > 0f)
						{
							Plot(j, i, c, num3);
						}
					}
				}
			}

			public void Tri(float x0, float y0, float x1, float y1, float x2, float y2, Color c)
			{
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0043: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				//IL_004d: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_0058: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
				Vector2 val = default(Vector2);
				((Vector2)(ref val))..ctor(x0, y0);
				Vector2 val2 = default(Vector2);
				((Vector2)(ref val2))..ctor(x1, y1);
				Vector2 val3 = default(Vector2);
				((Vector2)(ref val3))..ctor(x2, y2);
				for (int i = 0; i < 64; i++)
				{
					for (int j = 0; j < 64; j++)
					{
						Vector2 p = new Vector2((float)j + 0.5f, (float)i + 0.5f);
						float num = Sign(p, val, val2);
						float num2 = Sign(p, val2, val3);
						float num3 = Sign(p, val3, val);
						bool flag = num < 0f || num2 < 0f || num3 < 0f;
						bool flag2 = num > 0f || num2 > 0f || num3 > 0f;
						if (!(flag && flag2))
						{
							Plot(j, i, c, 1f);
						}
					}
				}
			}

			private static float Sign(Vector2 p, Vector2 a, Vector2 b)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				return (p.x - b.x) * (a.y - b.y) - (a.x - b.x) * (p.y - b.y);
			}

			public Texture2D ToTexture()
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Expected O, but got Unknown
				Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false)
				{
					filterMode = (FilterMode)1,
					wrapMode = (TextureWrapMode)1
				};
				val.SetPixels(px);
				val.Apply();
				return val;
			}
		}

		private const int N = 64;

		private static readonly Dictionary<string, Texture2D> cache = new Dictionary<string, Texture2D>();

		public static Color Accent(RpgClass c)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			return (Color)(c switch
			{
				RpgClass.Warrior => new Color(0.88f, 0.34f, 0.28f), 
				RpgClass.Archer => new Color(0.4f, 0.76f, 0.38f), 
				RpgClass.Mage => new Color(0.38f, 0.6f, 1f), 
				RpgClass.Rogue => new Color(0.72f, 0.45f, 0.92f), 
				_ => new Color(0.8f, 0.7f, 0.4f), 
			});
		}

		public static Texture2D ForAbility(Ability a)
		{
			return Get(a.Glyph, a.Class);
		}

		public static Texture2D ForClass(RpgClass c)
		{
			return (Texture2D)(c switch
			{
				RpgClass.Warrior => Get("w_iron", c), 
				RpgClass.Archer => Get("a_rain", c), 
				RpgClass.Mage => Get("m_arcana", c), 
				_ => Get("r_step", c), 
			});
		}

		private static Texture2D Get(string id, RpgClass cls)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return Build(id, Accent(cls));
		}

		public static Texture2D ForGlyph(string glyph, Color accent)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return Build(glyph, accent);
		}

		private static Texture2D Build(string id, Color accent)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			string key = id + "#" + ColorUtility.ToHtmlStringRGB(accent);
			if (cache.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			Canvas canvas = new Canvas();
			canvas.Disc(32f, 32f, 31f, new Color(accent.r * 0.28f, accent.g * 0.28f, accent.b * 0.28f, 1f));
			canvas.Ring(32f, 32f, 29.5f, 3f, accent);
			Glyph(canvas, id, Color.Lerp(accent, Color.white, 0.75f));
			value = canvas.ToTexture();
			cache[key] = value;
			return value;
		}

		private static void Glyph(Canvas cv, string id, Color L)
		{
			//IL_082a: Unknown result type (might be due to invalid IL or missing references)
			//IL_084f: Unknown result type (might be due to invalid IL or missing references)
			//IL_09c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_09e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a00: Unknown result type (might be due to invalid IL or missing references)
			//IL_0442: Unknown result type (might be due to invalid IL or missing references)
			//IL_0467: Unknown result type (might be due to invalid IL or missing references)
			//IL_0487: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_060b: Unknown result type (might be due to invalid IL or missing references)
			//IL_062b: Unknown result type (might be due to invalid IL or missing references)
			//IL_064b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0661: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b20: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b36: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b56: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b76: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b96: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bb6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a8d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ab2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0866: Unknown result type (might be due to invalid IL or missing references)
			//IL_088b: Unknown result type (might be due to invalid IL or missing references)
			//IL_08ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0928: Unknown result type (might be due to invalid IL or missing references)
			//IL_094d: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0809: Unknown result type (might be due to invalid IL or missing references)
			//IL_08d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_08f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0911: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ac9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0adf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b04: Unknown result type (might be due to invalid IL or missing references)
			//IL_0678: Unknown result type (might be due to invalid IL or missing references)
			//IL_067e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0698: Unknown result type (might be due to invalid IL or missing references)
			//IL_069e: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_06cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_06fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0711: Unknown result type (might be due to invalid IL or missing references)
			//IL_050d: Unknown result type (might be due to invalid IL or missing references)
			//IL_052d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bd7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bf7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c17: Unknown result type (might be due to invalid IL or missing references)
			//IL_0732: Unknown result type (might be due to invalid IL or missing references)
			//IL_0752: Unknown result type (might be due to invalid IL or missing references)
			//IL_0772: Unknown result type (might be due to invalid IL or missing references)
			//IL_0792: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_096e: Unknown result type (might be due to invalid IL or missing references)
			//IL_098e: Unknown result type (might be due to invalid IL or missing references)
			//IL_09a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_0344: Unknown result type (might be due to invalid IL or missing references)
			//IL_036a: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_054e: Unknown result type (might be due to invalid IL or missing references)
			//IL_056e: Unknown result type (might be due to invalid IL or missing references)
			//IL_058e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a6c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0417: Unknown result type (might be due to invalid IL or missing references)
			if (id == null)
			{
				return;
			}
			switch (id.Length)
			{
			case 7:
				switch (id[0])
				{
				case 'w':
					if (id == "w_shock")
					{
						cv.Ring(32f, 32f, 13f, 3.5f, L);
						cv.Ring(32f, 32f, 21f, 2.5f, L);
						cv.Disc(32f, 32f, 5f, L);
					}
					break;
				case 'a':
					if (id == "a_endur")
					{
						cv.Tri(32f, 48f, 17f, 20f, 47f, 20f, L);
						cv.Line(20f, 15f, 44f, 15f, 4f, L);
					}
					break;
				case 'm':
					if (id == "m_blast")
					{
						cv.Line(38f, 52f, 26f, 33f, 5f, L);
						cv.Line(26f, 33f, 38f, 31f, 5f, L);
						cv.Line(38f, 31f, 26f, 12f, 5f, L);
					}
					break;
				case 'r':
					if (id == "r_venom")
					{
						cv.Disc(24f, 30f, 10f, L);
						cv.Disc(39f, 30f, 11f, L);
						cv.Disc(31f, 40f, 10f, L);
						cv.Disc(31f, 23f, 8f, L);
					}
					break;
				}
				break;
			case 6:
				switch (id[4])
				{
				case 'n':
					if (id == "w_wind")
					{
						cv.Line(32f, 17f, 32f, 47f, 7f, L);
						cv.Line(17f, 32f, 47f, 32f, 7f, L);
					}
					break;
				case 'o':
					if (id == "w_iron")
					{
						cv.Tri(19f, 44f, 45f, 44f, 32f, 14f, L);
						cv.Line(19f, 46f, 45f, 46f, 9f, L);
					}
					break;
				case 'i':
					if (id == "a_rain")
					{
						float[] array = new float[3] { -12f, 0f, 12f };
						foreach (float num4 in array)
						{
							cv.Line(32f + num4 + 6f, 50f, 32f + num4 - 6f, 22f, 3f, L);
							cv.Tri(32f + num4 - 11f, 27f, 32f + num4 - 1f, 27f, 32f + num4 - 6f, 15f, L);
						}
					}
					break;
				case 'a':
					if (id == "a_leap")
					{
						cv.Line(12f, 32f, 48f, 32f, 5f, L);
						cv.Tri(54f, 32f, 42f, 22f, 42f, 42f, L);
						cv.Line(12f, 32f, 6f, 24f, 4f, L);
						cv.Line(12f, 32f, 6f, 40f, 4f, L);
						cv.Line(20f, 32f, 14f, 24f, 4f, L);
						cv.Line(20f, 32f, 14f, 40f, 4f, L);
					}
					break;
				case 'l':
					if (id == "m_well")
					{
						cv.Disc(32f, 25f, 11f, L);
						cv.Tri(21.5f, 29f, 42.5f, 29f, 32f, 51f, L);
					}
					break;
				case 'e':
					if (id == "r_step")
					{
						cv.Disc(19f, 32f, 7f, Fade(L, 0.35f));
						cv.Disc(32f, 32f, 7.5f, Fade(L, 0.65f));
						cv.Disc(45f, 32f, 8f, L);
					}
					break;
				}
				break;
			case 8:
				switch (id[0])
				{
				case 'm':
					if (id == "m_arcana")
					{
						cv.Line(32f, 11f, 32f, 53f, 3f, L);
						cv.Line(11f, 32f, 53f, 32f, 3f, L);
						cv.Line(17f, 17f, 47f, 47f, 3f, L);
						cv.Line(17f, 47f, 47f, 17f, 3f, L);
						cv.Disc(32f, 32f, 8f, L);
					}
					break;
				case 'r':
					if (id == "r_reflex")
					{
						cv.Line(14f, 41f, 50f, 41f, 4f, L);
						cv.Line(9f, 32f, 43f, 32f, 4f, L);
						cv.Line(16f, 23f, 49f, 23f, 4f, L);
					}
					break;
				}
				break;
			case 4:
				switch (id[3])
				{
				case 'r':
					if (id == "star")
					{
						cv.Line(32f, 10f, 32f, 54f, 4f, L);
						cv.Line(10f, 32f, 54f, 32f, 4f, L);
						cv.Line(17f, 17f, 47f, 47f, 3f, L);
						cv.Line(47f, 17f, 17f, 47f, 3f, L);
						cv.Disc(32f, 32f, 6f, L);
					}
					break;
				case 'k':
					if (id == "pick")
					{
						cv.Line(32f, 10f, 32f, 54f, 5f, L);
						cv.Line(12f, 42f, 32f, 50f, 5f, L);
						cv.Line(52f, 42f, 32f, 50f, 5f, L);
					}
					break;
				case 'f':
					if (id == "leaf")
					{
						cv.Disc(32f, 30f, 14f, L);
						cv.Tri(32f, 52f, 18f, 32f, 46f, 32f, L);
						cv.Line(32f, 52f, 32f, 60f, 3f, L);
					}
					break;
				case 'l':
					if (id == "bowl")
					{
						cv.Tri(12f, 38f, 52f, 38f, 32f, 16f, L);
						cv.Line(26f, 46f, 26f, 56f, 3f, L);
						cv.Line(38f, 46f, 38f, 56f, 3f, L);
					}
					break;
				case 'h':
					if (id == "fish")
					{
						cv.Disc(28f, 32f, 13f, L);
						cv.Tri(38f, 32f, 54f, 44f, 54f, 20f, L);
					}
					break;
				case 'w':
					if (id == "snow")
					{
						float[] array = new float[3] { 0f, 60f, 120f };
						for (int i = 0; i < array.Length; i++)
						{
							float num = array[i] * ((float)Math.PI / 180f);
							float num2 = Mathf.Cos(num) * 19f;
							float num3 = Mathf.Sin(num) * 19f;
							cv.Line(32f - num2, 32f - num3, 32f + num2, 32f + num3, 3.5f, L);
						}
					}
					break;
				case 'e':
					if (id == "fire")
					{
						cv.Disc(32f, 26f, 11f, L);
						cv.Tri(22f, 31f, 42f, 31f, 32f, 54f, L);
					}
					break;
				case 't':
					if (id == "crit")
					{
						cv.Ring(32f, 32f, 13f, 3f, L);
						cv.Disc(32f, 32f, 3.5f, L);
						cv.Line(32f, 9f, 32f, 21f, 3f, L);
						cv.Line(32f, 43f, 32f, 55f, 3f, L);
						cv.Line(9f, 32f, 21f, 32f, 3f, L);
						cv.Line(43f, 32f, 55f, 32f, 3f, L);
					}
					break;
				}
				break;
			case 5:
				switch (id[0])
				{
				case 's':
					if (id == "sword")
					{
						cv.Line(17f, 17f, 46f, 46f, 5f, L);
						cv.Line(17f, 36f, 36f, 17f, 5f, L);
						cv.Disc(46f, 46f, 3f, L);
					}
					break;
				case 'c':
					if (id == "clock")
					{
						cv.Ring(32f, 32f, 17f, 3.5f, L);
						cv.Line(32f, 32f, 32f, 44f, 3f, L);
						cv.Line(32f, 32f, 41f, 32f, 3f, L);
					}
					break;
				case 'h':
					if (id == "heart")
					{
						cv.Disc(24f, 37f, 9f, L);
						cv.Disc(40f, 37f, 9f, L);
						cv.Tri(15.5f, 33f, 48.5f, 33f, 32f, 12f, L);
					}
					break;
				}
				break;
			case 3:
				if (id == "axe")
				{
					cv.Line(22f, 12f, 40f, 52f, 5f, L);
					cv.Tri(38f, 54f, 56f, 42f, 36f, 30f, L);
				}
				break;
			}
		}

		private static Color Fade(Color c, float a)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			return new Color(c.r, c.g, c.b, a);
		}
	}
	public static class L
	{
		private const string Fallback = "English";

		private static Dictionary<string, string> english;

		private static Dictionary<string, string> current;

		private static string lang = "";

		private static float nextCheck;

		private static string PluginDir => Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Translations");

		private static string UserDir => Path.Combine(Paths.ConfigPath, Path.Combine("ValheimReforged", "Translations"));

		private static string GameLanguage()
		{
			try
			{
				return (Localization.instance != null) ? Localization.instance.GetSelectedLanguage() : "English";
			}
			catch
			{
				return "English";
			}
		}

		private static void Ensure()
		{
			if (english == null)
			{
				english = LoadEmbeddedEnglish();
				Overlay(english, Path.Combine(PluginDir, "English.yml"));
				Overlay(english, Path.Combine(UserDir, "English.yml"));
				current = english;
				try
				{
					Directory.CreateDirectory(UserDir);
				}
				catch
				{
				}
			}
			if (Time.realtimeSinceStartup < nextCheck)
			{
				return;
			}
			nextCheck = Time.realtimeSinceStartup + 1f;
			string text = GameLanguage();
			if (text == lang)
			{
				return;
			}
			lang = text;
			if (text == "English")
			{
				current = english;
				return;
			}
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			bool flag = Overlay(dictionary, Path.Combine(PluginDir, text + ".yml"));
			flag |= Overlay(dictionary, Path.Combine(UserDir, text + ".yml"));
			if (!flag)
			{
				flag = TryRelated(dictionary, text);
			}
			current = dictionary;
			if (flag)
			{
				Plugin.Log.LogInfo((object)("Translation loaded: " + text + " (" + dictionary.Count + " entries)"));
			}
			else
			{
				Plugin.Log.LogInfo((object)("No translation for '" + text + "'; using English. Copy English.yml to " + Path.Combine(UserDir, text + ".yml") + " and translate the values to add it."));
			}
		}

		private static bool TryRelated(Dictionary<string, string> into, string g)
		{
			int num = g.IndexOf('_');
			string text = ((num > 0) ? g.Substring(0, num) : g);
			string[] array = new string[2] { PluginDir, UserDir };
			foreach (string path in array)
			{
				try
				{
					if (!Directory.Exists(path))
					{
						continue;
					}
					string[] files = Directory.GetFiles(path, text + "*.yml");
					foreach (string path2 in files)
					{
						if (Overlay(into, path2))
						{
							Plugin.Log.LogInfo((object)("Using related translation " + Path.GetFileName(path2) + " for " + g));
							return true;
						}
					}
				}
				catch
				{
				}
			}
			return false;
		}

		private static Dictionary<string, string> LoadEmbeddedEnglish()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			try
			{
				using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("English.yml");
				if (stream != null)
				{
					using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8);
					Parse(streamReader.ReadToEnd(), dictionary);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not read embedded English.yml: " + ex.Message));
			}
			return dictionary;
		}

		private static bool Overlay(Dictionary<string, string> into, string path)
		{
			try
			{
				if (!File.Exists(path))
				{
					return false;
				}
				Parse(File.ReadAllText(path, Encoding.UTF8), into);
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not read " + path + ": " + ex.Message));
				return false;
			}
		}

		private static void Parse(string text, Dictionary<string, string> into)
		{
			string[] array = text.Split(new char[1] { '\n' });
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim(new char[1] { '\r' }).Trim();
				if (text2.Length != 0 && text2[0] != '#')
				{
					int num = text2.IndexOf(':');
					if (num > 0)
					{
						string key = text2.Substring(0, num).Trim();
						string v = text2.Substring(num + 1).Trim();
						into[key] = Unquote(v);
					}
				}
			}
		}

		private static string Unquote(string v)
		{
			if (v.Length >= 2 && v[0] == '"' && v[v.Length - 1] == '"')
			{
				StringBuilder stringBuilder = new StringBuilder();
				for (int i = 1; i < v.Length - 1; i++)
				{
					char c = v[i];
					if (c == '\\' && i + 1 < v.Length - 1)
					{
						char c2 = v[++i];
						stringBuilder.Append(c2 switch
						{
							't' => '\t', 
							'n' => '\n', 
							_ => c2, 
						});
					}
					else
					{
						stringBuilder.Append(c);
					}
				}
				return stringBuilder.ToString();
			}
			if (v.Length >= 2 && v[0] == '\'' && v[v.Length - 1] == '\'')
			{
				return v.Substring(1, v.Length - 2).Replace("''", "'");
			}
			return v;
		}

		public static bool Has(string key)
		{
			Ensure();
			if (current == null || !current.ContainsKey(key))
			{
				return english.ContainsKey(key);
			}
			return true;
		}

		public static string T(string key)
		{
			Ensure();
			if (current != null && current.TryGetValue(key, out var value))
			{
				return value;
			}
			if (english.TryGetValue(key, out value))
			{
				return value;
			}
			return key;
		}

		public static string F(string key, params object[] args)
		{
			string text = T(key);
			try
			{
				return string.Format(text, args);
			}
			catch (FormatException)
			{
				return text;
			}
		}
	}
	public interface ISynced
	{
		string Key { get; }

		string Serialize();

		void SetServer(string value);

		void ClearServer();

		bool ApplyLocal(string value);
	}
	public class SyncedEntry<T> : ISynced
	{
		private readonly ConfigEntry<T> local;

		private readonly string key;

		private bool hasServer;

		private T server;

		public T Value
		{
			get
			{
				if (!hasServer || !Net.IsRemoteClient)
				{
					return local.Value;
				}
				return server;
			}
		}

		public string Key => key;

		public SyncedEntry(ConfigFile cfg, string section, string name, T defaultValue, string description)
		{
			local = cfg.Bind<T>(section, name, defaultValue, description + " [synced from the server]");
			key = section + "." + name;
			Net.All.Add(this);
			local.SettingChanged += delegate
			{
				Net.PushToServer(key, Serialize());
			};
		}

		public string Serialize()
		{
			return Convert.ToString(local.Value, CultureInfo.InvariantCulture);
		}

		public void SetServer(string value)
		{
			try
			{
				server = (T)Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture);
				hasServer = true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Bad synced value for " + key + ": " + ex.Message));
			}
		}

		public void ClearServer()
		{
			hasServer = false;
		}

		public bool ApplyLocal(string value)
		{
			try
			{
				T val = (T)Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture);
				if (!object.Equals(local.Value, val))
				{
					local.Value = val;
				}
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Bad value for " + key + ": " + ex.Message));
				return false;
			}
		}
	}
	public static class Net
	{
		public static readonly List<ISynced> All = new List<ISynced>();

		public static ConfigEntry<bool> LockConfiguration;

		public static bool ServerLocked;

		public static bool IsRemoteClient
		{
			get
			{
				if ((Object)(object)ZNet.instance != (Object)null)
				{
					return !ZNet.instance.IsServer();
				}
				return false;
			}
		}

		public static void Hook(ConfigFile cfg)
		{
			cfg.SettingChanged += delegate
			{
				if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
				{
					BroadcastConfig();
				}
			};
		}

		public static void BroadcastConfig()
		{
			try
			{
				foreach (ZNetPeer peer in ZNet.instance.GetPeers())
				{
					if (peer != null && peer.IsReady())
					{
						SendConfig(peer.m_rpc);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not broadcast settings: " + ex.Message));
			}
		}

		public static void PushToServer(string key, string value)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			try
			{
				if (IsRemoteClient && ServerLocked && !((Object)(object)ZNet.instance == (Object)null))
				{
					ZRpc serverRPC = ZNet.instance.GetServerRPC();
					if (serverRPC == null)
					{
						Plugin.Log.LogWarning((object)("No server connection to send " + key));
						return;
					}
					Plugin.Log.LogInfo((object)("Sending " + key + " = " + value + " to the server (applied only if you are an admin)"));
					ZPackage val = new ZPackage();
					val.Write(key);
					val.Write(value);
					serverRPC.Invoke("VR_SetConfig", new object[1] { val });
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not send setting to the server: " + ex.Message));
			}
		}

		public static void RPC_SetConfig(ZRpc rpc, ZPackage pkg)
		{
			string text = pkg.ReadString();
			string text2 = pkg.ReadString();
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			string hostName = rpc.GetSocket().GetHostName();
			if (!ZNet.instance.IsAdmin(hostName))
			{
				Plugin.Log.LogWarning((object)("Rejected setting change " + text + " from non-admin " + hostName));
				return;
			}
			foreach (ISynced item in All)
			{
				if (item.Key == text)
				{
					if (item.ApplyLocal(text2))
					{
						Plugin.Log.LogInfo((object)("Admin " + hostName + " changed " + text + " = " + text2));
					}
					break;
				}
			}
		}

		public static void ClearServer()
		{
			foreach (ISynced item in All)
			{
				item.ClearServer();
			}
		}

		public static void SendConfig(ZRpc rpc)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			bool flag = LockConfiguration == null || LockConfiguration.Value;
			val.Write(flag);
			val.Write(flag ? All.Count : 0);
			if (flag)
			{
				foreach (ISynced item in All)
				{
					val.Write(item.Key);
					val.Write(item.Serialize());
				}
			}
			rpc.Invoke("VR_Config", new object[1] { val });
			ZPackage val2 = new ZPackage();
			val2.Write(flag ? NodeConfig.ServerText() : "");
			rpc.Invoke("VR_Nodes", new object[1] { val2 });
		}

		public static void RPC_Nodes(ZRpc rpc, ZPackage pkg)
		{
			NodeConfig.SetServer(pkg.ReadString());
		}

		public static void RPC_Config(ZRpc rpc, ZPackage pkg)
		{
			bool num = (ServerLocked = pkg.ReadBool());
			int num2 = pkg.ReadInt();
			if (!num)
			{
				ClearServer();
				Talents.Dirty = true;
				Plugin.Log.LogInfo((object)"Server does not lock the configuration; using local settings.");
				return;
			}
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			for (int i = 0; i < num2; i++)
			{
				dictionary[pkg.ReadString()] = pkg.ReadString();
			}
			foreach (ISynced item in All)
			{
				if (dictionary.TryGetValue(item.Key, out var value))
				{
					item.SetServer(value);
				}
			}
			Talents.Dirty = true;
			Plugin.Log.LogInfo((object)("Server settings received (" + dictionary.Count + " values)."));
		}

		public static void RPC_KillXp(long sender, float maxHealth, bool boss, Vector3 pos)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			KillRewards.Grant(maxHealth, boss, pos);
		}
	}
	public static class KillRewards
	{
		public static void Grant(float maxHealth, bool boss, Vector3 pos)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			RpgData data = Plugin.Data;
			Player localPlayer = Player.m_localPlayer;
			if (data != null && !((Object)(object)localPlayer == (Object)null) && data.Class != RpgClass.None)
			{
				float num = maxHealth * 0.5f * Plugin.XpMultiplier.Value * (1f + Stats.Get(Eff.Experience));
				if (boss)
				{
					num *= 3f;
				}
				int num2 = Mathf.Max(1, Mathf.RoundToInt(num));
				data.AddXp(num2);
				if (Plugin.ShowXpFloater.Value)
				{
					Floaters.Add(pos + Vector3.up * 1.2f, "+" + num2 + " XP", Floaters.XpColor, 15, 1.6f);
				}
				float num3 = Stats.Get(Eff.KillHeal);
				if (num3 > 0f)
				{
					((Character)localPlayer).Heal(((Character)localPlayer).GetMaxHealth() * num3, true);
				}
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
	internal static class NetConnect
	{
		private static void Postfix(ZNetPeer peer)
		{
			peer.m_rpc.Register<ZPackage>("VR_Config", (Action<ZRpc, ZPackage>)Net.RPC_Config);
			peer.m_rpc.Register<ZPackage>("VR_Nodes", (Action<ZRpc, ZPackage>)Net.RPC_Nodes);
			peer.m_rpc.Register<ZPackage>("VR_SetConfig", (Action<ZRpc, ZPackage>)Net.RPC_SetConfig);
			if (Net.IsRemoteClient)
			{
				Net.ClearServer();
				NodeConfig.ClearServer();
				Net.ServerLocked = false;
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
	internal static class NetPeerInfo
	{
		private static void Postfix(ZNet __instance, ZRpc rpc)
		{
			if (!__instance.IsServer())
			{
				return;
			}
			try
			{
				Net.SendConfig(rpc);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not send settings to a peer: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(Game), "Start")]
	internal static class NetGameStart
	{
		private static void Postfix()
		{
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.Register<float, bool, Vector3>("VR_KillXp", (Action<long, float, bool, Vector3>)Net.RPC_KillXp);
			}
		}
	}
	public static class NodeConfig
	{
		private static readonly Dictionary<string, float> defaults = new Dictionary<string, float>();

		private static Dictionary<string, float> local = new Dictionary<string, float>();

		private static Dictionary<string, float> server = new Dictionary<string, float>();

		private static bool hasServer;

		private static DateTime stamp;

		private static float nextCheck;

		public static string FilePath => Path.Combine(Paths.ConfigPath, Path.Combine("ValheimReforged", "Nodes.yml"));

		private static string SkillKey(Ability a, string field)
		{
			return "skill." + a.Id + "." + field;
		}

		private static string TalentKey(TNode n, string field)
		{
			return "talent." + n.Id + "." + field;
		}

		private static string PerkKey(TalentPerk p)
		{
			return "perk." + p;
		}

		public static void Init()
		{
			try
			{
				foreach (Ability item in Abilities.All)
				{
					defaults[SkillKey(item, "maxRank")] = item.MaxRank;
					defaults[SkillKey(item, "cost")] = item.Cost;
					if (item.Active)
					{
						defaults[SkillKey(item, "cooldown")] = item.Cooldown;
						defaults[SkillKey(item, "power")] = item.Power;
					}
					else
					{
						defaults[SkillKey(item, "value")] = item.PerRank;
					}
				}
				foreach (TNode item2 in Talents.All)
				{
					if (!item2.IsOrigin)
					{
						defaults[TalentKey(item2, "cost")] = item2.Cost;
						defaults[TalentKey(item2, "maxRank")] = item2.MaxRank;
						defaults[TalentKey(item2, "power")] = item2.Power;
					}
				}
				foreach (TalentPerk value in Enum.GetValues(typeof(TalentPerk)))
				{
					if (value != TalentPerk.None)
					{
						defaults[PerkKey(value)] = Talents.PerkValue(value);
					}
				}
				LoadLocal();
				WriteFile();
				Apply(local);
				Plugin.Log.LogInfo((object)("Node settings: " + FilePath + " (" + defaults.Count + " values)"));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("NodeConfig.Init: " + ex.Message));
			}
		}

		private static Dictionary<string, float> Parse(string text)
		{
			Dictionary<string, float> dictionary = new Dictionary<string, float>();
			string[] array = text.Split(new char[1] { '\n' });
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim(new char[1] { '\r' }).Trim();
				if (text2.Length != 0 && text2[0] != '#')
				{
					int num = text2.IndexOf(':');
					if (num > 0 && float.TryParse(text2.Substring(num + 1).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
					{
						dictionary[text2.Substring(0, num).Trim()] = result;
					}
				}
			}
			return dictionary;
		}

		private static void LoadLocal()
		{
			local = new Dictionary<string, float>();
			if (File.Exists(FilePath))
			{
				local = Parse(File.ReadAllText(FilePath, Encoding.UTF8));
				stamp = File.GetLastWriteTimeUtc(FilePath);
			}
		}

		private static string Num(float v)
		{
			return v.ToString("0.#####", CultureInfo.InvariantCulture);
		}

		private static void WriteFile()
		{
			StringBuilder sb = new StringBuilder();
			Action<string> line = delegate(string s)
			{
				sb.Append(s).Append('\n');
			};
			Action<string> action = delegate(string k)
			{
				if (!local.TryGetValue(k, out var value))
				{
					value = defaults[k];
				}
				line(k + ": " + Num(value));
			};
			line("# Valheim Reforged - values of every node. Edit the numbers and save; the game applies them while running.");
			line("# With LockConfiguration = true on the server, the server's file overrides every client.");
			line("#");
			line("# skill.<id>.maxRank / cost    ranks the node can have / skill points per rank");
			line("# skill.<id>.value             passive: bonus per rank (0.02 = 2%; flat amount for health/stamina/eitr)");
			line("# skill.<id>.cooldown / power  active: cooldown in seconds / damage and effect multiplier");
			line("# talent.<id>.cost / maxRank / power   talent points per rank / ranks / multiplier of the node's bonuses");
			line("# perk.<name>                  strength per rank of each branch keystone effect");
			line("");
			RpgClass[] array = new RpgClass[4]
			{
				RpgClass.Warrior,
				RpgClass.Archer,
				RpgClass.Mage,
				RpgClass.Rogue
			};
			for (int num = 0; num < array.Length; num++)
			{
				RpgClass c = array[num];
				line("# ===== " + c.ToString() + " skills =====");
				foreach (Ability item in Abilities.For(c))
				{
					line("# " + item.Id + (item.Active ? "  (active)" : "  (passive)"));
					action(SkillKey(item, "maxRank"));
					action(SkillKey(item, "cost"));
					if (item.Active)
					{
						action(SkillKey(item, "cooldown"));
						action(SkillKey(item, "power"));
					}
					else
					{
						action(SkillKey(item, "value"));
					}
				}
				line("");
			}
			line("# ===== keystone perks =====");
			foreach (TalentPerk value2 in Enum.GetValues(typeof(TalentPerk)))
			{
				if (value2 != TalentPerk.None)
				{
					action(PerkKey(value2));
				}
			}
			line("");
			string text = null;
			foreach (TNode item2 in Talents.All)
			{
				if (!item2.IsOrigin)
				{
					if (item2.Group != text)
					{
						text = item2.Group;
						line("");
						line("# ===== talents: " + text + " =====");
					}
					line("# " + item2.Id + "  (" + item2.Tier.ToString() + ")");
					action(TalentKey(item2, "cost"));
					action(TalentKey(item2, "maxRank"));
					action(TalentKey(item2, "power"));
				}
			}
			Directory.CreateDirectory(Path.GetDirectoryName(FilePath));
			string text2 = sb.ToString();
			if (!File.Exists(FilePath) || File.ReadAllText(FilePath, Encoding.UTF8).Replace("\r\n", "\n") != text2)
			{
				File.WriteAllText(FilePath, text2.Replace("\n", "\r\n"), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
			}
			stamp = File.GetLastWriteTimeUtc(FilePath);
		}

		private static void Apply(Dictionary<string, float> map)
		{
			Func<string, float> func = delegate(string k)
			{
				if (map.TryGetValue(k, out var value))
				{
					return value;
				}
				return (!defaults.TryGetValue(k, out value)) ? 0f : value;
			};
			foreach (Ability item in Abilities.All)
			{
				item.MaxRank = Math.Max(1, (int)Math.Round(func(SkillKey(item, "maxRank"))));
				item.Cost = Math.Max(1, (int)Math.Round(func(SkillKey(item, "cost"))));
				if (item.Active)
				{
					item.Cooldown = Math.Max(0f, func(SkillKey(item, "cooldown")));
					item.Power = Math.Max(0f, func(SkillKey(item, "power")));
				}
				else
				{
					item.PerRank = func(SkillKey(item, "value"));
				}
			}
			foreach (TNode item2 in Talents.All)
			{
				if (!item2.IsOrigin)
				{
					item2.CostOverride = Math.Max(1, (int)Math.Round(func(TalentKey(item2, "cost"))));
					item2.MaxRankOverride = Math.Max(1, (int)Math.Round(func(TalentKey(item2, "maxRank"))));
					item2.Power = Math.Max(0f, func(TalentKey(item2, "power")));
				}
			}
			foreach (TalentPerk value2 in Enum.GetValues(typeof(TalentPerk)))
			{
				if (value2 != TalentPerk.None)
				{
					Talents.PerkOver[value2] = func(PerkKey(value2));
				}
			}
			Talents.Dirty = true;
		}

		public static void Tick()
		{
			if (Time.realtimeSinceStartup < nextCheck)
			{
				return;
			}
			nextCheck = Time.realtimeSinceStartup + 2f;
			try
			{
				if (!File.Exists(FilePath))
				{
					WriteFile();
				}
				else if (!(File.GetLastWriteTimeUtc(FilePath) == stamp))
				{
					LoadLocal();
					if (!hasServer || !Net.IsRemoteClient)
					{
						Apply(local);
					}
					if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
					{
						Net.BroadcastConfig();
					}
					Plugin.Log.LogInfo((object)"Node settings reloaded.");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("NodeConfig.Tick: " + ex.Message));
			}
		}

		public static string ServerText()
		{
			try
			{
				return File.Exists(FilePath) ? File.ReadAllText(FilePath, Encoding.UTF8) : "";
			}
			catch
			{
				return "";
			}
		}

		public static void SetServer(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				ClearServer();
				return;
			}
			server = Parse(text);
			hasServer = true;
			Apply(server);
			Plugin.Log.LogInfo((object)("Node settings received from the server (" + server.Count + " values)."));
		}

		public static void ClearServer()
		{
			if (hasServer)
			{
				hasServer = false;
				Apply(local);
			}
		}
	}
	[BepInPlugin("com.yeyian.valheimreforged", "Reforged Classes", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public static ManualLogSource Log;

		public static RpgData Data;

		public static SyncedEntry<int> MaxLevel;

		public static SyncedEntry<int> PointsPerLevel;

		public static SyncedEntry<int> TalentPointsPerLevel;

		public static SyncedEntry<int> TalentPointsPerBoss;

		public static SyncedEntry<int> TranscendMax;

		public static SyncedEntry<int> TalentPointsPerTranscend;

		public static SyncedEntry<float> XpMultiplier;

		public static SyncedEntry<float> XpBase;

		public static SyncedEntry<float> XpExponent;

		public static SyncedEntry<float> TalentPower;

		public static SyncedEntry<float> AbilityDamage;

		public static SyncedEntry<bool> DisableVanillaSkillGain;

		public static SyncedEntry<bool> AllowRefund;

		public static ConfigEntry<bool> ShowXpFloater;

		public static ConfigEntry<bool> ShowCombatText;

		public static ConfigEntry<KeyCode> MenuKey;

		public static ConfigEntry<float> HudX;

		public static ConfigEntry<float> HudY;

		public static ConfigEntry<KeyCode>[] AbilityKeys = new ConfigEntry<KeyCode>[2];

		private float regenTimer;

		private void Awake()
		{
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Net.LockConfiguration = ((BaseUnityPlugin)this).Config.Bind<bool>("Servidor", "LockConfiguration", true, "Server only. When true, this server's settings override the clients' (sent on connect and whenever this file changes). When false, every client uses its own settings.");
			Net.Hook(((BaseUnityPlugin)this).Config);
			MaxLevel = new SyncedEntry<int>(((BaseUnityPlugin)this).Config, "Progressão", "MaxLevel", 50, "Maximum character level");
			PointsPerLevel = new SyncedEntry<int>(((BaseUnityPlugin)this).Config, "Progressão", "PointsPerLevel", 1, "Skill points per level");
			TalentPointsPerLevel = new SyncedEntry<int>(((BaseUnityPlugin)this).Config, "Progressão", "TalentPointsPerLevel", 1, "Talent tree points per level");
			TalentPointsPerBoss = new SyncedEntry<int>(((BaseUnityPlugin)this).Config, "Progressão", "TalentPointsPerBoss", 3, "Talent tree points per defeated boss");
			TranscendMax = new SyncedEntry<int>(((BaseUnityPlugin)this).Config, "Transcendência", "MaxTranscendences", 10, "How many times a character can transcend at the maximum level (0 disables transcendence)");
			TalentPointsPerTranscend = new SyncedEntry<int>(((BaseUnityPlugin)this).Config, "Transcendência", "TalentPointsPerTranscendence", 10, "Extra talent points granted for each transcendence");
			XpMultiplier = new SyncedEntry<float>(((BaseUnityPlugin)this).Config, "Progressão", "XpMultiplier", 1f, "XP multiplier per kill");
			XpBase = new SyncedEntry<float>(((BaseUnityPlugin)this).Config, "Progressão", "XpBase", 90f, "XP needed to go from level 1 to 2; each next level needs XpBase * level ^ XpExponent");
			XpExponent = new SyncedEntry<float>(((BaseUnityPlugin)this).Config, "Progressão", "XpExponent", 1.3f, "How fast the XP needed per level grows");
			TalentPower = new SyncedEntry<float>(((BaseUnityPlugin)this).Config, "Equilíbrio", "TalentPower", 1f, "Multiplier applied to every bonus of the Talents tab");
			AbilityDamage = new SyncedEntry<float>(((BaseUnityPlugin)this).Config, "Equilíbrio", "AbilityDamage", 1f, "Multiplier applied to the damage of active abilities");
			DisableVanillaSkillGain = new SyncedEntry<bool>(((BaseUnityPlugin)this).Config, "Progressão", "DisableVanillaSkillGain", defaultValue: true, "Disables skill gain by use; skills scale with the character level instead");
			AllowRefund = new SyncedEntry<bool>(((BaseUnityPlugin)this).Config, "Progressão", "AllowRefund", defaultValue: true, "Allows refunding talent points with Ctrl+click (free)");
			ShowXpFloater = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "ShowXpFloater", true, "Shows gained XP as floating text over the slain monster");
			ShowCombatText = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "ShowCombatText", true, "Shows floating text for critical hits, execute and opening bonuses");
			HudX = ((BaseUnityPlugin)this).Config.Bind<float>("Interface", "HudX", 250f, "Distance in pixels (at 1080p) from the left edge of the screen to the level medallion; the ability slots follow it");
			HudY = ((BaseUnityPlugin)this).Config.Bind<float>("Interface", "HudY", 116f, "Distance in pixels (at 1080p) from the bottom edge of the screen to the top of the ability slots");
			MenuKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Teclas", "Menu", (KeyCode)107, "Opens the RPG panel");
			KeyCode[] array = (KeyCode[])(object)new KeyCode[2]
			{
				(KeyCode)118,
				(KeyCode)98
			};
			for (int i = 0; i < 2; i++)
			{
				AbilityKeys[i] = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Teclas", "Ability" + (i + 1), array[i], "Skill bar active ability, slot " + (i + 1));
			}
			NodeConfig.Init();
			new Harmony("com.yeyian.valheimreforged").PatchAll();
		}

		public static void LevelBonus(RpgClass c, int level, out float hp, out float stamina, out float eitr)
		{
			int num = level - 1;
			hp = (stamina = (eitr = 0f));
			switch (c)
			{
			case RpgClass.Warrior:
				hp = (float)num * 4f;
				stamina = (float)num * 1f;
				break;
			case RpgClass.Archer:
				hp = (float)num * 2f;
				stamina = (float)num * 1.5f;
				break;
			case RpgClass.Mage:
				hp = (float)num * 1f;
				eitr = (float)num * 3f;
				break;
			case RpgClass.Rogue:
				hp = (float)num * 2f;
				stamina = (float)num * 2f;
				break;
			}
		}

		private void Update()
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			NodeConfig.Tick();
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				Data = null;
				return;
			}
			if (Data == null)
			{
				Data = RpgData.Load(localPlayer);
			}
			regenTimer += Time.deltaTime;
			if (regenTimer >= 1f && Data.Class != RpgClass.None)
			{
				regenTimer = 0f;
				float num = Stats.Get(Eff.HealthRegen);
				float num2 = Stats.Get(Eff.StaminaRegen);
				float num3 = Stats.Get(Eff.EitrRegen);
				if (num > 0f && ((Character)localPlayer).GetHealth() < ((Character)localPlayer).GetMaxHealth())
				{
					((Character)localPlayer).Heal(num, false);
				}
				if (num2 > 0f)
				{
					((Character)localPlayer).AddStamina(num2);
				}
				if (num3 > 0f)
				{
					((Character)localPlayer).AddEitr(num3);
				}
			}
			if (Ui.Open && Input.GetKeyDown((KeyCode)27))
			{
				Ui.Open = false;
			}
			else if (Input.GetKeyDown(MenuKey.Value) && !Ui.BlockedByOtherUi())
			{
				Ui.Open = !Ui.Open;
			}
			if (Ui.Open || Ui.BlockedByOtherUi() || Data.Class == RpgClass.None)
			{
				return;
			}
			for (int i = 0; i < 2; i++)
			{
				if (Input.GetKeyDown(AbilityKeys[i].Value))
				{
					Abilities.Cast(localPlayer, Data, i);
				}
			}
		}

		private void FixedUpdate()
		{
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				Dash.Step(Player.m_localPlayer);
			}
		}

		private void OnGUI()
		{
			Ui.Draw();
		}
	}
	[HarmonyPatch(typeof(Character), "OnDeath")]
	internal static class KillXp
	{
		private static void Postfix(Character __instance)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			if (__instance is Player)
			{
				return;
			}
			HitData value = Traverse.Create((object)__instance).Field("m_lastHit").GetValue<HitData>();
			Player val = (Player)((value != null) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			float maxHealth = __instance.GetMaxHealth();
			bool flag = __instance.IsBoss();
			Vector3 centerPoint = __instance.GetCenterPoint();
			if ((Object)(object)val == (Object)(object)Player.m_localPlayer)
			{
				KillRewards.Grant(maxHealth, flag, centerPoint);
				return;
			}
			ZNetView component = ((Component)val).GetComponent<ZNetView>();
			if (ZRoutedRpc.instance != null && (Object)(object)component != (Object)null && component.GetZDO() != null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(component.GetZDO().GetOwner(), "VR_KillXp", new object[3] { maxHealth, flag, centerPoint });
			}
		}
	}
	[HarmonyPatch(typeof(Skills), "RaiseSkill")]
	internal static class NoSkillGain
	{
		internal static bool Prefix()
		{
			return !Plugin.DisableVanillaSkillGain.Value;
		}
	}
	[HarmonyPatch(typeof(Skill), "Raise")]
	internal static class NoSkillRaise
	{
		private static bool Prefix(ref bool __result)
		{
			if (!NoSkillGain.Prefix())
			{
				__result = false;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Skills), "GetSkillLevel")]
	internal static class SkillFollowsLevel
	{
		internal static bool Primary(RpgClass c, SkillType t)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Invalid comparison between Unknown and I4
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Invalid comparison between Unknown and I4
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Invalid comparison between Unknown and I4
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Invalid comparison between Unknown and I4
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Invalid comparison between Unknown and I4
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Invalid comparison between Unknown and I4
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Invalid comparison between Unknown and I4
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Invalid comparison between Unknown and I4
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Invalid comparison between Unknown and I4
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Invalid comparison between Unknown and I4
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Invalid comparison between Unknown and I4
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			switch (c)
			{
			case RpgClass.Warrior:
				if ((int)t != 1 && (int)t != 7 && (int)t != 3 && (int)t != 4)
				{
					return (int)t == 6;
				}
				return true;
			case RpgClass.Archer:
				if ((int)t != 8 && (int)t != 14 && (int)t != 5)
				{
					return (int)t == 100;
				}
				return true;
			case RpgClass.Mage:
				if ((int)t != 9)
				{
					return (int)t == 10;
				}
				return true;
			case RpgClass.Rogue:
				if ((int)t != 2 && (int)t != 101 && (int)t != 11)
				{
					return (int)t == 102;
				}
				return true;
			default:
				return false;
			}
		}

		private static void Postfix(Skills __instance, SkillType skillType, ref float __result)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Invalid comparison between Unknown and I4
			RpgData data = Plugin.Data;
			Player localPlayer = Player.m_localPlayer;
			if (data != null && !((Object)(object)localPlayer == (Object)null) && data.Class != RpgClass.None && Plugin.DisableVanillaSkillGain.Value && !((Object)(object)((Character)localPlayer).GetSkills() != (Object)(object)__instance))
			{
				float num = (float)data.Level / (float)Plugin.MaxLevel.Value;
				float num2 = (Primary(data.Class, skillType) ? 1f : 0.5f);
				float num3 = Mathf.Max(__result, Mathf.Floor(num * num2 * 100f));
				if ((int)skillType == 104)
				{
					num3 += Stats.Get(Eff.FishingSkill);
				}
				__result = num3;
			}
		}
	}
	[HarmonyPatch(typeof(SkillsDialog), "Setup")]
	internal static class SkillsDialogNote
	{
		private static Transform Deep(Transform t, string name)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			foreach (Transform item in t)
			{
				Transform val = item;
				if (((Object)val).name == name)
				{
					return val;
				}
				Transform val2 = Deep(val, name);
				if ((Object)(object)val2 != (Object)null)
				{
					return val2;
				}
			}
			return null;
		}

		private static void Postfix(SkillsDialog __instance)
		{
			try
			{
				if (Plugin.Data == null || Plugin.Data.Class == RpgClass.None || !Plugin.DisableVanillaSkillGain.Value)
				{
					return;
				}
				IList value = Traverse.Create((object)__instance).Field("m_elements").GetValue<IList>();
				if (value != null)
				{
					foreach (object item in value)
					{
						GameObject val = (GameObject)((item is GameObject) ? item : null);
						Transform val2 = (((Object)(object)val != (Object)null) ? Deep(val.transform, "currentlevel") : null);
						if ((Object)(object)val2 != (Object)null)
						{
							((Component)val2).gameObject.SetActive(false);
						}
					}
				}
				object value2 = Traverse.Create((object)__instance).Field("m_totalSkillText").GetValue<object>();
				if (value2 != null)
				{
					PropertyInfo property = value2.GetType().GetProperty("text");
					if (property != null)
					{
						property.SetValue(value2, L.T("skills.dialog_note"), null);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("SkillsDialogNote: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(Player), "GetTotalFoodValue")]
	internal static class ClassStats
	{
		private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr)
		{
			RpgData data = Plugin.Data;
			if (data != null && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && data.Class != RpgClass.None)
			{
				Plugin.LevelBonus(data.Class, data.Level, out var hp2, out var stamina2, out var eitr2);
				hp += hp2;
				stamina += stamina2;
				eitr += eitr2;
				hp += Stats.Get(Eff.MaxHealth);
				stamina += Stats.Get(Eff.MaxStamina);
				eitr += Stats.Get(Eff.MaxEitr);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "GetEquipmentMovementModifier")]
	internal static class RogueSpeed
	{
		private static void Postfix(Player __instance, ref float __result)
		{
			if (Plugin.Data != null && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				__result += Stats.Get(Eff.MoveSpeed);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "Damage")]
	internal static class DamageModifiers
	{
		private static void Prefix(Character __instance, HitData hit)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected I4, but got Unknown
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Invalid comparison between Unknown and I4
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || Plugin.Data == null || Plugin.Data.Class == RpgClass.None || hit == null || (Object)(object)hit.GetAttacker() != (Object)(object)localPlayer)
			{
				return;
			}
			float num = 1f + Stats.Get(Eff.Damage);
			SkillType skill = hit.m_skill;
			switch (skill - 1)
			{
			case 0:
			case 1:
			case 2:
			case 3:
			case 4:
			case 6:
			case 10:
				num += Stats.Get(Eff.MeleeDamage);
				break;
			case 7:
			case 13:
				num += Stats.Get(Eff.RangedDamage);
				break;
			case 8:
			case 9:
				num += Stats.Get(Eff.MagicDamage);
				break;
			}
			num += TalentPerks.WeaponBonus(hit.m_skill);
			num *= TalentPerks.DamageMultiplier(localPlayer, __instance, hit);
			if ((int)hit.m_skill == 10)
			{
				int num2 = Talents.PerkRank(TalentPerk.Siphon);
				if (num2 > 0)
				{
					((Character)localPlayer).AddEitr(Talents.PerkValue(TalentPerk.Siphon) * (float)num2);
				}
			}
			float healthPercentage = __instance.GetHealthPercentage();
			float num3 = Stats.Get(Eff.Execute);
			float num4 = Stats.Get(Eff.Opening);
			Vector3 val = ((hit.m_point != Vector3.zero) ? hit.m_point : __instance.GetCenterPoint());
			int instanceID = ((Object)__instance).GetInstanceID();
			if (healthPercentage < 0.3f && num3 > 0f)
			{
				num += num3;
				if (Plugin.ShowCombatText.Value)
				{
					Floaters.Add(val + Vector3.up * 0.5f, L.T("combat.execute"), Floaters.ExecuteColor, 16, 1f, "ex" + instanceID, 0.8f);
				}
			}
			if (healthPercentage > 0.8f && num4 > 0f)
			{
				num += num4;
				if (Plugin.ShowCombatText.Value)
				{
					Floaters.Add(val + Vector3.up * 0.5f, L.T("combat.opening"), Floaters.OpeningColor, 16, 1f, "op" + instanceID, 0.8f);
				}
			}
			bool num5 = Random.value < Stats.Get(Eff.Crit);
			if (num5)
			{
				num *= 1.75f;
			}
			if (num != 1f)
			{
				((DamageTypes)(ref hit.m_damage)).Modify(num);
			}
			if (num5 && Plugin.ShowCombatText.Value)
			{
				Floaters.Add(val + Vector3.up * 0.2f, L.F("combat.crit", Mathf.RoundToInt(hit.GetTotalDamage())), Floaters.CritColor, 22);
			}
			float num6 = Stats.Get(Eff.LifeSteal);
			if (num6 > 0f)
			{
				((Character)localPlayer).Heal(Mathf.Min(hit.GetTotalDamage() * num6, ((Character)localPlayer).GetMaxHealth() * 0.25f), false);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UseStamina")]
	internal static class StaminaCostPatch
	{
		private static void Prefix(Player __instance, ref float __0)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && Plugin.Data != null)
			{
				float num = Mathf.Min(0.6f, Stats.Get(Eff.StaminaCost));
				if (num > 0f)
				{
					__0 *= 1f - num;
				}
				int num2 = (((Character)__instance).IsSwimming() ? Talents.PerkRank(TalentPerk.Swimmer) : 0);
				if (num2 > 0)
				{
					__0 *= Mathf.Max(0.1f, 1f - Talents.PerkValue(TalentPerk.Swimmer) * (float)num2 / 100f);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Skills), "LowerAllSkills")]
	internal static class NoSkillLossOnDeath
	{
		private static bool Prefix()
		{
			return !Plugin.DisableVanillaSkillGain.Value;
		}
	}
	[HarmonyPatch(typeof(Character), "RPC_Damage")]
	internal static class VictimModifiers
	{
		private static void Prefix(Character __instance, HitData hit)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)__instance != (Object)(object)localPlayer) && !((Object)(object)localPlayer == (Object)null) && Plugin.Data != null && Plugin.Data.Class != RpgClass.None && hit != null)
			{
				float num = Mathf.Min(0.8f, Stats.Get(Eff.Resist));
				if (num > 0f)
				{
					((DamageTypes)(ref hit.m_damage)).Modify(1f - num);
				}
				float num2 = Mathf.Min(0.75f, Stats.Get(Eff.ElementalResist));
				if (num2 > 0f)
				{
					hit.m_damage.m_fire *= 1f - num2;
					hit.m_damage.m_frost *= 1f - num2;
					hit.m_damage.m_lightning *= 1f - num2;
					hit.m_damage.m_poison *= 1f - num2;
					hit.m_damage.m_spirit *= 1f - num2;
				}
			}
		}
	}
	public enum RpgClass
	{
		None,
		Warrior,
		Archer,
		Mage,
		Rogue
	}
	public class RpgData
	{
		private const string Key = "VR_Data";

		public int Level = 1;

		public long Xp;

		public RpgClass Class;

		public int Points;

		public int Trans;

		public readonly Dictionary<string, int> Ranks = new Dictionary<string, int>();

		public readonly Dictionary<string, int> TalentRanks = new Dictionary<string, int>();

		public readonly string[] Slots = new string[2];

		public int TalentBank => Trans * Plugin.TalentPointsPerTranscend.Value;

		public bool CanTranscend
		{
			get
			{
				if (Class != RpgClass.None && Level >= Plugin.MaxLevel.Value)
				{
					return Trans < Plugin.TranscendMax.Value;
				}
				return false;
			}
		}

		public static long XpForNext(int level)
		{
			return (long)((double)Plugin.XpBase.Value * Math.Pow(level, Plugin.XpExponent.Value));
		}

		public int TalentRank(string id)
		{
			if (!TalentRanks.TryGetValue(id, out var value))
			{
				return 0;
			}
			return value;
		}

		public string BuyTalent(TNode n)
		{
			if (n.IsOrigin)
			{
				return null;
			}
			if (TalentRank(n.Id) >= n.MaxRank)
			{
				return L.T("ui.rank_max");
			}
			if (TalentRank(n.Id) == 0 && !Talents.IsAvailable(n, this))
			{
				return L.T("msg.talent_neighbor");
			}
			if (Talents.Available(this) < n.Cost)
			{
				return L.F("msg.talent_points_needed", n.Cost);
			}
			TalentRanks[n.Id] = TalentRank(n.Id) + 1;
			Talents.Dirty = true;
			Save();
			return null;
		}

		public string RefundTalent(TNode n)
		{
			if (TalentRank(n.Id) == 0)
			{
				return L.T("msg.nothing_refund");
			}
			if (!Talents.CanRefund(n, this))
			{
				return L.T("msg.would_disconnect");
			}
			int num = TalentRank(n.Id);
			if (num == 1)
			{
				TalentRanks.Remove(n.Id);
			}
			else
			{
				TalentRanks[n.Id] = num - 1;
			}
			Talents.Dirty = true;
			Save();
			return null;
		}

		public void RespecTalents()
		{
			TalentRanks.Clear();
			Talents.Dirty = true;
			Save();
		}

		public int Rank(string id)
		{
			if (!Ranks.TryGetValue(id, out var value))
			{
				return 0;
			}
			return value;
		}

		public void AddXp(long amount)
		{
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			if (Class != RpgClass.None && amount > 0)
			{
				Xp += amount;
				int level = Level;
				int points = Points;
				while (Level < Plugin.MaxLevel.Value && Xp >= XpForNext(Level))
				{
					Xp -= XpForNext(Level);
					Level++;
					Points += Plugin.PointsPerLevel.Value;
				}
				if (Level > level && (Object)(object)Player.m_localPlayer != (Object)null)
				{
					((Character)Player.m_localPlayer).Message((MessageType)2, L.F("msg.level_up", Level, Points - points, (Level - level) * Plugin.TalentPointsPerLevel.Value), 0, (Sprite)null, false);
					Vfx.LevelUp(((Component)Player.m_localPlayer).transform.position);
				}
				if (Level >= Plugin.MaxLevel.Value)
				{
					Xp = 0L;
				}
				Save();
			}
		}

		public void Transcend()
		{
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			if (!CanTranscend)
			{
				Plugin.Log.LogInfo((object)("Transcend refused: class=" + Class.ToString() + " level=" + Level + "/" + Plugin.MaxLevel.Value + " transcendences=" + Trans + "/" + Plugin.TranscendMax.Value));
				return;
			}
			Trans++;
			Level = 1;
			Xp = 0L;
			Points = 0;
			Ranks.Clear();
			TalentRanks.Clear();
			for (int i = 0; i < Slots.Length; i++)
			{
				Slots[i] = null;
			}
			Buffs.Clear();
			Talents.Dirty = true;
			Save();
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				((Character)localPlayer).Message((MessageType)2, L.F("msg.transcended", Trans, Plugin.TalentPointsPerTranscend.Value), 0, (Sprite)null, false);
				Vfx.LevelUp(((Component)localPlayer).transform.position);
			}
		}

		public void ChooseClass(RpgClass c)
		{
			if (Class == RpgClass.None)
			{
				Class = c;
				Save();
			}
		}

		public bool Available(Ability a)
		{
			if (a.Parent != null)
			{
				return Rank(a.Parent) > 0;
			}
			return true;
		}

		public bool Spend(Ability a)
		{
			if (Points < a.Cost || Rank(a.Id) >= a.MaxRank || !Available(a))
			{
				return false;
			}
			Points -= a.Cost;
			Ranks[a.Id] = Rank(a.Id) + 1;
			if (a.Active)
			{
				AutoEquip(a.Id);
			}
			Save();
			return true;
		}

		public void SpendAll(Ability a)
		{
			while (Spend(a))
			{
			}
		}

		public string Refund(Ability a)
		{
			int num = Rank(a.Id);
			if