Decompiled source of WeaponArts v0.16.0

WeaponArts.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace WeaponArts;

[BepInPlugin("j1ga.weaponarts", "Weapon Arts", "0.16.0")]
public class WeaponArtsPlugin : BaseUnityPlugin
{
	internal enum ArtKind
	{
		DamageMult,
		Dot,
		Stagger,
		Vampirism,
		AoEHeal,
		AoEBurst,
		Pierce,
		Bleed,
		Expose,
		Berserk,
		Legion
	}

	internal class Art
	{
		public string Id;

		public int Hash;

		public string NameRu;

		public string DescRu;

		public string NameEn;

		public string DescEn;

		public ArtKind Kind;

		public SkillType Skill;

		public int Hand;

		public bool UsesEitr;

		public ConfigEntry<float> Mag;

		public ConfigEntry<float> Win;

		public ConfigEntry<float> Cd;

		public ConfigEntry<float> Cost;

		public ConfigEntry<float> Radius;

		public ConfigEntry<float> HLo0;

		public ConfigEntry<float> HLo1;

		public ConfigEntry<float> HHi0;

		public ConfigEntry<float> HHi1;

		public bool IncludeSelf;

		public ConfigEntry<float> Angle;

		public ConfigEntry<float> Bonus;

		public ConfigEntry<float> Linger;

		public ConfigEntry<int> Shots;

		public ConfigEntry<float> Regen;

		public bool Heal1H;

		public ConfigEntry<bool> HealTamed;

		public ConfigEntry<float> HpCost;

		public ConfigEntry<int> Count;

		public ConfigEntry<string> StaffCds;

		public ConfigEntry<float> CdShareMin;

		public string Name => L(NameEn ?? NameRu, NameRu);

		public string Desc => L(DescEn ?? DescRu, DescRu);

		public Art En(string name, string desc)
		{
			NameEn = name;
			DescEn = desc;
			return this;
		}
	}

	private struct Bleed
	{
		public float Dps;

		public float Until;

		public ZDOID Attacker;
	}

	private enum ShamanVisual
	{
		None,
		Heal,
		Spray
	}

	private class HitState
	{
		public Art Art;

		public float Hp;

		public float Before;

		public float After;
	}

	[HarmonyPatch(typeof(MonsterAI), "UpdateTarget")]
	private static class MonsterAI_UpdateTarget_Patch
	{
		private static void Postfix(MonsterAI __instance)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			WeaponArtsPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || instance._tainted.Count == 0 || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			try
			{
				Character component = ((Component)__instance).GetComponent<Character>();
				if (!((Object)(object)component == (Object)null))
				{
					Character val = instance.HeldTarget(component.GetZDOID());
					if (!((Object)(object)val == (Object)null) && !val.IsDead() && (Object)(object)((BaseAI)__instance).GetTargetCreature() != (Object)(object)val)
					{
						instance.ForceTarget(__instance, val);
					}
				}
			}
			catch (Exception e)
			{
				instance.Fail("UpdateTarget", e);
			}
		}
	}

	[HarmonyPatch(typeof(Character), "RPC_Damage")]
	private static class Character_RPC_Damage_Patch
	{
		private static void Prefix(Character __instance, HitData hit, out HitState __state)
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			__state = null;
			if (s_bleedTick)
			{
				s_penActive = true;
				s_penFraction = 1f;
				return;
			}
			s_penActive = false;
			WeaponArtsPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || !instance.Active || (Object)(object)__instance == (Object)null || hit == null)
			{
				return;
			}
			try
			{
				if (instance.TauntActive && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
				{
					float num = Mathf.Clamp(instance._tauntReduction, 0f, 0.9f);
					if (num > 0f)
					{
						hit.ApplyModifier(1f - num);
					}
				}
				if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && instance.BerserkActive)
				{
					float berserkReduction = instance.BerserkReduction;
					if (berserkReduction > 0f)
					{
						hit.ApplyModifier(1f - berserkReduction);
					}
				}
				if (__instance.IsPlayer())
				{
					return;
				}
				Character attacker = hit.GetAttacker();
				if ((Object)(object)attacker == (Object)null || !attacker.IsPlayer())
				{
					return;
				}
				float before = TotalDamage(hit.m_damage);
				bool flag = __instance.IsBoss();
				float num2 = (flag ? instance.Sv(instance._cfgBossFactor) : 1f);
				float num3 = instance.ExposedFraction(__instance);
				if (num3 > 0f)
				{
					hit.ApplyModifier(1f + num3);
				}
				if (!instance.AttackerArt(attacker, out var a, out var power))
				{
					if (num3 > 0f && instance._cfgDebug.Value)
					{
						__state = new HitState();
						__state.Hp = __instance.GetHealth();
						__state.Before = before;
						__state.After = TotalDamage(hit.m_damage);
					}
					return;
				}
				switch (a.Kind)
				{
				case ArtKind.DamageMult:
					hit.ApplyModifier(1f + (power - 1f) * num2);
					break;
				case ArtKind.Dot:
				{
					ref DamageTypes damage = ref hit.m_damage;
					damage.m_poison += power * num2;
					break;
				}
				case ArtKind.Bleed:
					instance.RegisterBleed(__instance, power * num2, hit.m_attacker);
					break;
				case ArtKind.Stagger:
					if (!flag)
					{
						hit.m_staggerMultiplier = Mathf.Max(hit.m_staggerMultiplier, 100f);
					}
					break;
				case ArtKind.Pierce:
					s_penActive = true;
					s_penFraction = Mathf.Clamp(power * num2, 0f, 0.95f);
					if (a.Bonus != null)
					{
						hit.ApplyModifier(1f + instance.Sv(a.Bonus) * num2);
					}
					break;
				case ArtKind.Expose:
					instance.MarkExposed(__instance, Mathf.Clamp(power * num2, 0f, 1f), instance.Sv(a.Linger));
					break;
				}
				if (a.Kind == ArtKind.Vampirism || instance._cfgDebug.Value)
				{
					__state = new HitState();
					__state.Art = a;
					__state.Hp = __instance.GetHealth();
					__state.Before = before;
					__state.After = TotalDamage(hit.m_damage);
				}
			}
			catch (Exception e)
			{
				instance.Fail("RPC_Damage", e);
			}
		}

		private static void Finalizer()
		{
			s_penActive = false;
		}

		private static void Postfix(Character __instance, HitData hit, HitState __state)
		{
			s_penActive = false;
			WeaponArtsPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || __state == null || (Object)(object)__instance == (Object)null || hit == null)
			{
				return;
			}
			try
			{
				float num = __state.Hp - __instance.GetHealth();
				Art art = __state.Art;
				instance.Debug("hit " + ((Object)__instance).name + " by " + ((art != null) ? art.Id : "-") + ": damage " + __state.Before.ToString("0.0") + " -> " + __state.After.ToString("0.0") + " (x" + ((__state.Before > 0f) ? (__state.After / __state.Before) : 1f).ToString("0.00") + "), hp lost " + num.ToString("0.0") + ", exposed " + instance.ExposedFraction(__instance).ToString("0.00") + ", staggering " + __instance.IsStaggering());
				if (art == null || art.Kind != ArtKind.Vampirism || num <= 0f)
				{
					return;
				}
				Character attacker = hit.GetAttacker();
				if ((Object)(object)attacker == (Object)null || !instance.AttackerArt(attacker, out var a, out var power) || a.Kind != ArtKind.Vampirism || power <= 0f)
				{
					return;
				}
				float num2 = (__instance.IsBoss() ? instance.Sv(instance._cfgBossFactor) : 1f);
				float num3 = num * power * num2;
				if (num3 <= 0f)
				{
					return;
				}
				ZNetView component = ((Component)attacker).GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.IsValid())
				{
					if (component.IsOwner())
					{
						attacker.Heal(num3, false);
						return;
					}
					component.InvokeRPC(component.GetZDO().GetOwner(), "RPC_Heal", new object[2] { num3, false });
				}
			}
			catch (Exception e)
			{
				instance.Fail("RPC_Damage.post", e);
			}
		}
	}

	[HarmonyPatch(typeof(HitData), "ApplyResistance")]
	private static class HitData_ApplyResistance_Patch
	{
		private static void Prefix(HitData __instance, out DamageTypes __state)
		{
			//IL_0002: 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)
			__state = __instance.m_damage;
		}

		private static void Postfix(HitData __instance, DamageTypes __state)
		{
			if (s_penActive && !(WeaponArtsPlugin.s_penFraction <= 0f))
			{
				float s_penFraction = WeaponArtsPlugin.s_penFraction;
				__instance.m_damage.m_blunt = Restore(__state.m_blunt, __instance.m_damage.m_blunt, s_penFraction);
				__instance.m_damage.m_slash = Restore(__state.m_slash, __instance.m_damage.m_slash, s_penFraction);
				__instance.m_damage.m_pierce = Restore(__state.m_pierce, __instance.m_damage.m_pierce, s_penFraction);
				__instance.m_damage.m_fire = Restore(__state.m_fire, __instance.m_damage.m_fire, s_penFraction);
				__instance.m_damage.m_frost = Restore(__state.m_frost, __instance.m_damage.m_frost, s_penFraction);
				__instance.m_damage.m_lightning = Restore(__state.m_lightning, __instance.m_damage.m_lightning, s_penFraction);
				__instance.m_damage.m_poison = Restore(__state.m_poison, __instance.m_damage.m_poison, s_penFraction);
				__instance.m_damage.m_spirit = Restore(__state.m_spirit, __instance.m_damage.m_spirit, s_penFraction);
			}
		}

		private static float Restore(float before, float after, float f)
		{
			if (after <= 0f || after >= before)
			{
				return after;
			}
			return after + (before - after) * f;
		}
	}

	[HarmonyPatch(typeof(Projectile), "Setup")]
	private static class Projectile_Setup_Patch
	{
		private static void Postfix(Character owner, ItemData item)
		{
			WeaponArtsPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)owner == (Object)null || (Object)(object)owner != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			try
			{
				instance.OnLocalShot(item);
			}
			catch (Exception e)
			{
				instance.Fail("Projectile.Setup", e);
			}
		}
	}

	[HarmonyPatch(typeof(Player), "TeleportTo")]
	private static class Player_TeleportTo_Patch
	{
		private static void Prefix(Player __instance, out bool __state)
		{
			__state = (Object)(object)__instance != (Object)null && ((Character)__instance).IsTeleporting();
		}

		private static void Postfix(Player __instance, Vector3 pos, Quaternion rot, bool distantTeleport, bool __state)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			WeaponArtsPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || !instance.Active || __state || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !((Character)__instance).IsTeleporting())
			{
				return;
			}
			try
			{
				instance.OnLocalTeleport(__instance, pos, rot, distantTeleport);
			}
			catch (Exception e)
			{
				instance.Fail("TeleportTo", e);
			}
		}
	}

	[HarmonyPatch(typeof(Tameable), "UpdateSummon")]
	private static class Tameable_UpdateSummon_Patch
	{
		private static bool Prefix(Tameable __instance)
		{
			WeaponArtsPlugin instance = Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				return !instance.SummonHeld(__instance);
			}
			return true;
		}
	}

	[HarmonyPatch(typeof(Tameable), "Interact")]
	private static class Tameable_Interact_Patch
	{
		private static void Postfix(Tameable __instance, Humanoid user, bool hold)
		{
			WeaponArtsPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || !instance.Active)
			{
				return;
			}
			try
			{
				instance.HoldInteract(__instance, user, hold);
			}
			catch (Exception e)
			{
				instance.Fail("dismiss", e);
			}
		}
	}

	[HarmonyPatch(typeof(Tameable), "GetHoverText")]
	private static class Tameable_GetHoverText_Patch
	{
		private static void Postfix(Tameable __instance, ref string __result)
		{
			WeaponArtsPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || !instance.Active)
			{
				return;
			}
			try
			{
				string text = instance.DismissHint(__instance);
				if (text != null)
				{
					__result += text;
				}
			}
			catch (Exception e)
			{
				instance.Fail("dismiss hint", e);
			}
		}
	}

	[HarmonyPatch(typeof(MonsterAI), "UpdateAI")]
	private static class MonsterAI_UpdateAI_Patch
	{
		private static void Postfix(MonsterAI __instance)
		{
			WeaponArtsPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || !instance.Active)
			{
				return;
			}
			try
			{
				instance.YieldMove(__instance);
			}
			catch (Exception e)
			{
				instance.Fail("step aside", e);
			}
		}
	}

	[HarmonyPatch(typeof(Chat), "OnNewChatMessage")]
	private static class Chat_OnNewChatMessage_Patch
	{
		private static void Postfix(long senderID, Type type, string text)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			WeaponArtsPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || !instance.Active)
			{
				return;
			}
			try
			{
				instance.OnChat(senderID, type, text);
			}
			catch (Exception e)
			{
				instance.Fail("chat", e);
			}
		}
	}

	[HarmonyPatch(typeof(Character), "Damage")]
	private static class Character_Damage_Patch
	{
		private static void Prefix(Character __instance, HitData hit)
		{
			WeaponArtsPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || hit == null || instance._proxies.Count == 0)
			{
				return;
			}
			try
			{
				instance.ReduceProxyHit(__instance, hit);
			}
			catch (Exception e)
			{
				instance.Fail("Damage", e);
			}
		}
	}

	private class Proxy
	{
		public ZDOID Id;

		public string Name;

		public int LastEmoteId;

		public float LastSeen;

		public float CooldownUntil;

		public bool ReadyAnnounced;

		public string ArtName = "";

		public int ArtHash;

		public float ArtUntil;

		public float ArtPower;

		public float TauntUntil;

		public float TauntReduction;

		public int TauntCount;

		public float NextReapply;

		public long SinceMs;

		public float BerserkUntil;

		public float BerserkReduction;

		public float BerserkRegen;

		public float NextRegen;
	}

	private class Yield
	{
		public Vector3 To;

		public float Until;
	}

	[HarmonyPatch(typeof(ZNet), "Awake")]
	private static class ZNet_Awake_Patch
	{
		private static void Postfix()
		{
			WeaponArtsPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			try
			{
				instance.RegisterRpc();
			}
			catch (Exception e)
			{
				instance.Fail("ZNet.Awake", e);
			}
		}
	}

	[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
	private static class ZNet_RPC_PeerInfo_Patch
	{
		private static void Postfix(ZNet __instance, ZRpc rpc)
		{
			WeaponArtsPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || instance._disabledByErrors)
			{
				return;
			}
			try
			{
				instance.OnPeerInfo(__instance, rpc);
			}
			catch (Exception e)
			{
				instance.Fail("ZNet.RPC_PeerInfo", e);
			}
		}
	}

	[HarmonyPatch(typeof(ZNet), "OnDestroy")]
	private static class ZNet_OnDestroy_Patch
	{
		private static void Postfix()
		{
			WeaponArtsPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			try
			{
				((MonoBehaviour)instance).StopAllCoroutines();
				instance.ClearServerValues();
			}
			catch (Exception e)
			{
				instance.Fail("ZNet.OnDestroy", e);
			}
		}
	}

	private struct Hold
	{
		public float Until;

		public ZDOID Target;

		public long Since;
	}

	private struct AiSettings
	{
		public MonsterAI Ai;

		public float CircleInterval;

		public bool Circulate;

		public bool CirculateFlying;
	}

	private const float ConeCloseRange = 2f;

	private const float ShotGrace = 2.5f;

	internal const float MinWindow = 6f;

	public const string Guid = "j1ga.weaponarts";

	public const string Name = "Weapon Arts";

	public const string Version = "0.16.0";

	private const int MaxErrors = 25;

	private const string ShamanHelp = "ShamanHeal (the greydwarf shaman's heal: green flames around you), ShamanSpray (the greydwarf shaman's green spray, cast forward)";

	private const string VisualHelp = "None; GuardianPower (the forsaken-power activation flash); or a registered prefab name, e.g. fx_eikthyr_stomp, fx_Adrenaline1, fx_guardstone_activate, vfx_perfectblock, fx_gjall_taunt.";

	private const float ProxyForgetAfter = 120f;

	private const float ProxyShotWindow = 10f;

	private const float TurretSpacing = 2.5f;

	private const float YieldTime = 1.2f;

	private const float YieldMinSpeed = 2f;

	private const float YieldMaxSpeed = 30f;

	private const float CarryGrace = 10f;

	private const string SyncRpc = "j1ga.weaponarts.config";

	private const int SyncVersion = 1;

	private const float ReapplyInterval = 0.25f;

	private const string HudObjectName = "WeaponArts";

	private readonly List<Art> _arts = new List<Art>();

	private readonly Dictionary<int, Art> _artByHash = new Dictionary<int, Art>();

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

	private float _berserkUntil;

	private float _berserkReduction;

	private float _berserkRegen;

	private float _berserkNextTick;

	internal static readonly int ZdoExposedUntil = StringExtensionMethods.GetStableHashCode("j1ga.weaponarts.exposed.until");

	internal static readonly int ZdoExposed = StringExtensionMethods.GetStableHashCode("j1ga.weaponarts.exposed");

	private readonly Dictionary<string, int> _shotsLeft = new Dictionary<string, int>();

	internal static bool s_bleedTick;

	private ConfigEntry<float> _cfgBleedSeconds;

	private ConfigEntry<float> _cfgBleedInterval;

	private readonly Dictionary<ZDOID, Bleed> _bleeds = new Dictionary<ZDOID, Bleed>();

	private readonly List<ZDOID> _bleedScratch = new List<ZDOID>();

	private float _nextBleedTick;

	private ConfigEntry<bool> _cfgEnabled;

	private ConfigEntry<bool> _cfgDebug;

	private ConfigEntry<KeyboardShortcut> _cfgKey;

	private ConfigEntry<bool> _cfgShowHud;

	private static ConfigEntry<string> _cfgLanguage;

	private ConfigEntry<float> _cfgGlobalCooldown;

	private ConfigEntry<float> _cfgBossFactor;

	private ConfigEntry<float> _cfgSkillPowerScale;

	private ConfigEntry<float> _cfgTierPowerScale;

	private ConfigEntry<float> _cfgSkillDurationScale;

	private ConfigEntry<float> _cfgRefWeaponDamage;

	public static WeaponArtsPlugin Instance;

	private Harmony _harmony;

	internal static readonly int ZdoArt = StringExtensionMethods.GetStableHashCode("j1ga.weaponarts.art");

	internal static readonly int ZdoUntil = StringExtensionMethods.GetStableHashCode("j1ga.weaponarts.until");

	internal static readonly int ZdoPower = StringExtensionMethods.GetStableHashCode("j1ga.weaponarts.power");

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

	private float _gcdUntil;

	private string _lastArtId = "";

	private float _lastActivated;

	private int _errorCount;

	private bool _disabledByErrors;

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

	private float _keyHeldSince = -1f;

	private bool _keyHoldDone;

	private string _lastLoadout = "";

	private ConfigEntry<string> _cfgTauntSound;

	private ConfigEntry<string> _cfgTauntVisual;

	private readonly HashSet<string> _warnedEffects = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private ConfigEntry<string> _cfgArtSound;

	private ConfigEntry<string> _cfgArtVisual;

	private ConfigEntry<string> _cfgHealVisual;

	private ConfigEntry<string> _cfgMendVisual;

	private ConfigEntry<string> _cfgMendAnimation;

	private ConfigEntry<bool> _cfgAllyHealVisual;

	private EffectList _shamanCast;

	private EffectList _shamanSpray;

	private EffectList _shamanHit;

	private GameObject _shamanAoe;

	private bool _shamanResolved;

	private static readonly FieldInfo s_zanim = AccessTools.Field(typeof(Character), "m_zanim");

	internal static bool s_penActive;

	internal static float s_penFraction;

	private ConfigEntry<bool> _cfgProxy;

	private ConfigEntry<string> _cfgProxyProvider;

	private ConfigEntry<string> _cfgProxyEmote;

	private ConfigEntry<string> _cfgProxyChat;

	private ConfigEntry<string> _cfgProxyQuery;

	private ConfigEntry<float> _cfgProxySkill;

	private ConfigEntry<float> _cfgProxyCooldownFactor;

	private ConfigEntry<bool> _cfgProxyAnnounce;

	private ConfigEntry<bool> _cfgProxyAnnounceReady;

	private static readonly int ModMarkHash = StringExtensionMethods.GetStableHashCode("j1ga.weaponarts.mod");

	private float _nextMark;

	private readonly Dictionary<ZDOID, Proxy> _proxies = new Dictionary<ZDOID, Proxy>();

	private readonly List<ZDOID> _proxyScratch = new List<ZDOID>();

	private float _nextProxyPoll;

	private ConfigEntry<bool> _cfgSummonTeleport;

	private ConfigEntry<bool> _cfgSummonCarry;

	private ConfigEntry<bool> _cfgSummonYield;

	private ConfigEntry<bool> _cfgSummonPassThrough;

	private ConfigEntry<bool> _cfgSummonYieldOthers;

	private ConfigEntry<bool> _cfgSummonPassThroughOthers;

	private ConfigEntry<bool> _cfgSummonDismiss;

	private ConfigEntry<float> _cfgSummonDismissHold;

	private ConfigEntry<float> _cfgSummonYieldDistance;

	private ConfigEntry<float> _cfgSummonYieldStep;

	private ConfigEntry<float> _cfgSummonTeleportDistance;

	private ConfigEntry<float> _cfgSummonTeleportHeight;

	private ConfigEntry<float> _cfgSummonTeleportCombatDistance;

	private ConfigEntry<string> _cfgSummonTeleportVisual;

	private float _legionCooldown;

	private readonly Dictionary<SharedData, SpawnAbility> _summonOf = new Dictionary<SharedData, SpawnAbility>();

	private Tameable _holdTame;

	private float _holdStart;

	private float _holdLast;

	private float _nextSummonCheck;

	private readonly Dictionary<MonsterAI, Yield> _yield = new Dictionary<MonsterAI, Yield>();

	private float _nextYieldCheck;

	private float _nextPassCheck;

	private readonly Dictionary<Player, Vector3> _lastPos = new Dictionary<Player, Vector3>();

	private float _lastPosTime;

	private readonly HashSet<Character> _passThrough = new HashSet<Character>();

	private Player _passPlayer;

	private readonly HashSet<ZDOID> _carried = new HashSet<ZDOID>();

	private float _carryUntil;

	private ConfigEntry<bool> _cfgSync;

	private bool _syncDirty;

	private bool _serverSynced;

	private readonly Dictionary<string, object> _serverByKey = new Dictionary<string, object>();

	private FieldInfo _fiTargetCreature;

	private FieldInfo _fiTargetStatic;

	private FieldInfo _fiLastKnownTargetPos;

	private FieldInfo _fiBeenAtLastPos;

	private FieldInfo _fiTimeSinceSensed;

	private MethodInfo _miSetAlerted;

	private MethodInfo _miGetBlocker;

	private ConfigEntry<string> _cfgShieldMode;

	private ConfigEntry<float> _cfgTowerParry;

	private ConfigEntry<float> _cfgTauntRadius;

	private ConfigEntry<float> _cfgTauntDuration;

	private ConfigEntry<float> _cfgTauntCooldown;

	private ConfigEntry<float> _cfgTauntStamina;

	private ConfigEntry<float> _cfgTauntReductionBase;

	private ConfigEntry<float> _cfgTauntReductionBest;

	private ConfigEntry<float> _cfgTauntRefBlock;

	private ConfigEntry<bool> _cfgTauntBosses;

	private ConfigEntry<bool> _cfgTauntTamed;

	private ConfigEntry<bool> _cfgTauntAggravate;

	private ConfigEntry<bool> _cfgTauntChargeStraight;

	private ConfigEntry<float> _cfgTauntSkillGain;

	private ConfigEntry<float> _cfgTauntSkillCap;

	private readonly Dictionary<ZDOID, Hold> _tainted = new Dictionary<ZDOID, Hold>();

	private readonly List<ZDOID> _tauntScratch = new List<ZDOID>();

	private static readonly int HoldByHash = StringExtensionMethods.GetStableHashCode("j1ga.weaponarts.holdby");

	private static readonly int HoldUntilHash = StringExtensionMethods.GetStableHashCode("j1ga.weaponarts.holduntil");

	private static readonly int HoldSinceHash = StringExtensionMethods.GetStableHashCode("j1ga.weaponarts.holdsince");

	private readonly Dictionary<ZDOID, AiSettings> _straight = new Dictionary<ZDOID, AiSettings>();

	private float _tauntUntil;

	private float _tauntCdUntil;

	private float _tauntNextReapply;

	private float _tauntReduction;

	private long _tauntSinceMs;

	private int _tauntCount;

	private ConfigEntry<float> _cfgHudX;

	private ConfigEntry<float> _cfgHudY;

	private ConfigEntry<int> _cfgHudFont;

	private Hud _labelHud;

	private RectTransform _label;

	private TextMeshProUGUI _nameText;

	private TextMeshProUGUI _descText;

	private float _labelX = -1f;

	private float _labelY = -1f;

	private int _labelFont = -1;

	private static readonly Color Grey = new Color(0.8f, 0.8f, 0.8f);

	private static readonly Color Green = new Color(0.6f, 1f, 0.6f);

	private static readonly Color Amber = new Color(1f, 0.85f, 0.3f);

	private static readonly Color DescColor = new Color(0.8f, 0.8f, 0.76f);

	internal bool BerserkActive => Time.time < _berserkUntil;

	internal float BerserkReduction
	{
		get
		{
			if (!BerserkActive)
			{
				return 0f;
			}
			return _berserkReduction;
		}
	}

	private bool Active
	{
		get
		{
			if (!_disabledByErrors)
			{
				return Sb(_cfgEnabled);
			}
			return false;
		}
	}

	private bool ProxyOn => _cfgProxy.Value;

	private bool TauntActive
	{
		get
		{
			if (Active)
			{
				return Time.time < _tauntUntil;
			}
			return false;
		}
	}

	private bool CanForceTarget
	{
		get
		{
			if (_fiTargetCreature != null && _fiTargetStatic != null && _fiLastKnownTargetPos != null && _fiBeenAtLastPos != null)
			{
				return _fiTimeSinceSensed != null;
			}
			return false;
		}
	}

	private Art Add(string id, string name, string desc, ArtKind kind, SkillType skill, int hand, float mag, float win, float cd, float cost, bool eitr)
	{
		//IL_0030: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Expected O, but got Unknown
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Expected O, but got Unknown
		//IL_015b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0165: Expected O, but got Unknown
		//IL_0193: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Expected O, but got Unknown
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d5: Expected O, but got Unknown
		//IL_0123: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Expected O, but got Unknown
		Art art = new Art();
		art.Id = id;
		art.Hash = StringExtensionMethods.GetStableHashCode(id);
		art.NameRu = name;
		art.DescRu = desc;
		art.Kind = kind;
		art.Skill = skill;
		art.Hand = hand;
		art.UsesEitr = eitr;
		string text = "03 Arts - " + id;
		art.Mag = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Magnitude", mag, "Base strength at skill 0 with the weakest weapon (grows with TierPowerBonus/SkillPowerBonus). Damage arts: multiplier; DoT: poison/bleed per hit; lifesteal: fraction; pierce: fraction of resistance ignored; expose: extra damage taken by the target; stagger: unused (every hit staggers).");
		if (kind == ArtKind.Pierce)
		{
			art.Bonus = ((BaseUnityPlugin)this).Config.Bind<float>(text, "DamageBonus", 0.225f, new ConfigDescription("Extra damage on top of the resistance ignore (0.15 = +15%), so the art matters on unresisting targets too.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), new object[0]));
		}
		if (kind == ArtKind.Berserk)
		{
			art.Regen = ((BaseUnityPlugin)this).Config.Bind<float>(text, "RegenPerSecond", 10f, new ConfigDescription("HP restored per second while berserk (fixed, not scaled by tier/skill).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), new object[0]));
		}
		if (kind == ArtKind.Expose)
		{
			art.Linger = ((BaseUnityPlugin)this).Config.Bind<float>(text, "ExposeSeconds", 8f, new ConfigDescription("Seconds a struck target stays exposed (takes more damage from everyone).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), new object[0]));
		}
		art.Win = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Window", win, new ConfigDescription("Seconds the art lasts (before skill/tier scaling; +50% cap).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(6f, 30f), new object[0]));
		art.Cd = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Cooldown", cd, new ConfigDescription("Seconds before reuse.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 600f), new object[0]));
		art.Cost = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Cost", cost, new ConfigDescription("Stamina (or eitr) spent.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), new object[0]));
		_arts.Add(art);
		_artByHash[art.Hash] = art;
		return art;
	}

	private Art AddHeal(string id, string name, string desc, SkillType skill, int hand, float cd, float cost, float lo0, float lo1, float hi0, float hi1, float radius, bool self)
	{
		//IL_002f: 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_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Expected O, but got Unknown
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Expected O, but got Unknown
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Expected O, but got Unknown
		Art art = new Art();
		art.Id = id;
		art.Hash = StringExtensionMethods.GetStableHashCode(id);
		art.NameRu = name;
		art.DescRu = desc;
		art.Kind = ArtKind.AoEHeal;
		art.Skill = skill;
		art.Hand = hand;
		art.IncludeSelf = self;
		string text = "03 Arts - " + id;
		art.Cd = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Cooldown", cd, new ConfigDescription("Seconds before reuse.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 600f), new object[0]));
		art.Cost = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Cost", cost, new ConfigDescription("Stamina spent.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), new object[0]));
		art.Radius = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Radius", radius, new ConfigDescription("Heal radius, m.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 40f), new object[0]));
		art.HLo0 = ((BaseUnityPlugin)this).Config.Bind<float>(text, "HealLoMin", lo0, "Lower bound of the heal roll at min tier/skill.");
		art.HLo1 = ((BaseUnityPlugin)this).Config.Bind<float>(text, "HealLoMax", lo1, "Lower bound at max tier/skill.");
		art.HHi0 = ((BaseUnityPlugin)this).Config.Bind<float>(text, "HealHiMin", hi0, "Upper bound of the heal roll at min tier/skill.");
		art.HHi1 = ((BaseUnityPlugin)this).Config.Bind<float>(text, "HealHiMax", hi1, "Upper bound at max tier/skill.");
		art.HealTamed = ((BaseUnityPlugin)this).Config.Bind<bool>(text, "HealTamed", true, "Also heal tamed creatures and staff summons in range (anyone's). They get the same share of their max health as the heal is of the healer's (60 HP of your 200 = 30% of theirs). They are not counted in the number shown.");
		_arts.Add(art);
		_artByHash[art.Hash] = art;
		return art;
	}

	private Art AddBurst(string id, string name, string desc, SkillType skill, int hand, float mag, float cd, float cost, float radius)
	{
		//IL_002f: 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_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Expected O, but got Unknown
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Expected O, but got Unknown
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Expected O, but got Unknown
		Art art = new Art();
		art.Id = id;
		art.Hash = StringExtensionMethods.GetStableHashCode(id);
		art.NameRu = name;
		art.DescRu = desc;
		art.Kind = ArtKind.AoEBurst;
		art.Skill = skill;
		art.Hand = hand;
		string text = "03 Arts - " + id;
		art.Mag = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Magnitude", mag, "Damage as a fraction of weapon damage (1.3 = 130%).");
		art.Cd = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Cooldown", cd, new ConfigDescription("Seconds before reuse.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 600f), new object[0]));
		art.Cost = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Cost", cost, new ConfigDescription("Stamina spent.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), new object[0]));
		art.Radius = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Radius", radius, new ConfigDescription("Burst radius, m.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), new object[0]));
		_arts.Add(art);
		_artByHash[art.Hash] = art;
		return art;
	}

	private Art AddLegion(string id, string name, string desc, SkillType skill, float cd, float eitr, float hp, int count)
	{
		//IL_0030: 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_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Expected O, but got Unknown
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Expected O, but got Unknown
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Expected O, but got Unknown
		//IL_017e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0188: Expected O, but got Unknown
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Expected O, but got Unknown
		Art art = new Art();
		art.Id = id;
		art.Hash = StringExtensionMethods.GetStableHashCode(id);
		art.NameRu = name;
		art.DescRu = desc;
		art.Kind = ArtKind.Legion;
		art.Skill = skill;
		art.Hand = 0;
		art.UsesEitr = true;
		string text = "03 Arts - " + id;
		art.Cd = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Cooldown", cd, new ConfigDescription("Seconds before reuse.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 600f), new object[0]));
		art.Cost = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Cost", eitr, new ConfigDescription("Eitr spent.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), new object[0]));
		art.HpCost = ((BaseUnityPlugin)this).Config.Bind<float>(text, "HealthCost", hp, new ConfigDescription("Share of max health spent (0.3 = 30%); the art is refused if it would leave you at 1 HP or less.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.9f), new object[0]));
		if (count > 0)
		{
			art.Count = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Count", count, new ConfigDescription("Creatures per activation, for staves whose creatures are timed (Staff of the Wild roots).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), new object[0]));
		}
		else
		{
			art.StaffCds = ((BaseUnityPlugin)this).Config.Bind<string>(text, "StaffCooldowns", "StaffSkeleton:150, StaffSpiritCaller:150, StaffRedTroll:150", "Cooldown after summoning a full squad, by staff prefab (set a stronger staff higher); Cooldown for a staff not listed. Bringing back part of the squad costs that share of it.");
			art.CdShareMin = ((BaseUnityPlugin)this).Config.Bind<float>(text, "MinCooldownShare", 0.3f, new ConfigDescription("Least share of that cooldown any use costs - all of it when nobody was missing and the art only healed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[0]));
		}
		_arts.Add(art);
		_artByHash[art.Hash] = art;
		return art;
	}

	private void BuildArts()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: 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_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: 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_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: 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_0064: 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_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0159: Unknown result type (might be due to invalid IL or missing references)
		//IL_0196: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0211: Unknown result type (might be due to invalid IL or missing references)
		//IL_024f: Unknown result type (might be due to invalid IL or missing references)
		//IL_028e: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ec: Expected O, but got Unknown
		//IL_0317: Unknown result type (might be due to invalid IL or missing references)
		//IL_0321: Expected O, but got Unknown
		//IL_0327: Unknown result type (might be due to invalid IL or missing references)
		//IL_032b: Unknown result type (might be due to invalid IL or missing references)
		//IL_032f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0341: Unknown result type (might be due to invalid IL or missing references)
		//IL_038d: 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)
		//IL_0421: Expected O, but got Unknown
		//IL_0436: Unknown result type (might be due to invalid IL or missing references)
		//IL_046d: Unknown result type (might be due to invalid IL or missing references)
		//IL_04a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e3: Unknown result type (might be due to invalid IL or missing references)
		SkillType skill = (SkillType)1;
		SkillType skill2 = (SkillType)7;
		SkillType skill3 = (SkillType)5;
		SkillType skill4 = (SkillType)4;
		SkillType skill5 = (SkillType)2;
		SkillType skill6 = (SkillType)11;
		SkillType skill7 = (SkillType)8;
		SkillType skill8 = (SkillType)14;
		Add("Onslaught", "Натиск", "меч 2H: +урон по цели", ArtKind.DamageMult, skill, 2, 1.525f, 6f, 43f, 30f, eitr: false).En("Onslaught", "2H sword: more damage to the target");
		Add("Bloodthirst", "Кровожадность", "меч 1H: вампиризм с урона", ArtKind.Vampirism, skill, 1, 0.3f, 6f, 48f, 25f, eitr: false).En("Bloodthirst", "1H sword: lifesteal from damage dealt");
		Add("Berserk", "Берсерк", "боевой топор: меньше урона по себе + реген HP", ArtKind.Berserk, skill2, 2, 0.375f, 10f, 54f, 30f, eitr: false).En("Berserk", "battleaxe: take less damage + regenerate HP");
		Add("Bleed", "Кровотечение", "топор 1H: физический DoT (обходит броню)", ArtKind.Bleed, skill2, 1, 12f, 6f, 32f, 25f, eitr: false).En("Bleed", "1H axe: physical damage over time");
		Add("Rend", "Рассечение", "копьё: цель уязвима (+урон от всех)", ArtKind.Expose, skill3, 1, 0.3f, 6f, 38f, 30f, eitr: false).En("Rend", "spear: the target is exposed (more damage from everyone)");
		Add("Impale", "Пронзание", "пика: сильный игнор сопротивлений + урон", ArtKind.Pierce, skill3, 2, 0.95f, 6f, 48f, 30f, eitr: false).En("Impale", "pike: strong resistance ignore + damage");
		Add("Crushing", "Дробящий", "атгейр: каждый удар вгоняет в стаггер", ArtKind.Stagger, skill4, 0, 1f, 6f, 48f, 30f, eitr: false).En("Crushing", "atgeir: every hit staggers");
		Add("Envenom", "Отравление", "ножи: сильный яд на ударах", ArtKind.Dot, skill5, 0, 18f, 6f, 32f, 25f, eitr: false).En("Envenom", "knives: strong poison on hits");
		Add("Fury", "Ярость", "кулаки: крит на каждом ударе", ArtKind.DamageMult, skill6, 0, 2f, 6f, 43f, 25f, eitr: false).En("Fury", "fists: a critical hit on every blow");
		Art art = Add("Focus", "Фокус", "лук: следующие выстрелы критуют", ArtKind.DamageMult, skill7, 0, 2.5f, 22.5f, 48f, 20f, eitr: false).En("Focus", "bow: the next shots are critical");
		Art art2 = Add("PiercingBolts", "Бронебой", "арбалет: болты игнорят сопротивления + урон", ArtKind.Pierce, skill8, 0, 0.9f, 22.5f, 48f, 20f, eitr: false).En("Piercing Bolts", "crossbow: bolts ignore resistances + damage");
		art.Shots = ((BaseUnityPlugin)this).Config.Bind<int>("03 Arts - Focus", "Shots", 3, new ConfigDescription("The art lasts this many shots (Window is the time cap).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), new object[0]));
		art2.Shots = ((BaseUnityPlugin)this).Config.Bind<int>("03 Arts - PiercingBolts", "Shots", 3, new ConfigDescription("The art lasts this many shots (Window is the time cap).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), new object[0]));
		SkillType skill9 = (SkillType)3;
		SkillType skill10 = (SkillType)9;
		SkillType skill11 = (SkillType)10;
		AddHeal("Rally", "Клич", "кувалда 2H: хил себе и союзникам", skill9, 2, 60f, 40f, 15f, 60f, 25f, 100f, 10f, self: true).En("Rally", "2H sledge: heal yourself and allies");
		Art art3 = AddHeal("Mend", "Исцеление", "булава 1H: хил союзникам перед собой", skill9, 1, 50f, 30f, 10f, 40f, 16f, 65f, 12f, self: false).En("Mend", "1H mace: heal the allies in front of you");
		art3.Heal1H = true;
		art3.Angle = ((BaseUnityPlugin)this).Config.Bind<float>("03 Arts - Mend", "Angle", 90f, new ConfigDescription("Width of the cone the heal reaches, degrees (Radius is its length); on activation you turn to the camera, so it points where you look. Allies within " + 2f + " m count from any side. 360 = all around.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(30f, 360f), new object[0]));
		AddLegion("LegionBlood", "Легион", "посох призыва: весь отряд сразу, хил призванным", skill11, 150f, 0f, 0.3f, 0).En("Legion", "summoning staff: the whole squad at once, heals your summons");
		AddLegion("Overgrowth", "Буйный рост", "посох дикости: несколько корней у ближайшего врага", skill10, 40f, 30f, 0f, 3).En("Overgrowth", "staff of the wild: several roots at the nearest enemy");
		Add("EitrSurgeElem", "Вспышка эйтра", "посох стихий: +магический урон", ArtKind.DamageMult, skill10, 0, 1.6f, 6f, 60f, 30f, eitr: true).En("Eitr Surge", "elemental staff: more magic damage");
		Add("EitrSurgeBlood", "Вспышка эйтра", "посох крови: +магический урон", ArtKind.DamageMult, skill11, 0, 1.6f, 6f, 60f, 30f, eitr: true).En("Eitr Surge", "blood staff: more magic damage");
	}

	private static int HandOf(ItemType t)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Invalid comparison between Unknown and I4
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Invalid comparison between Unknown and I4
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Invalid comparison between Unknown and I4
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Invalid comparison between Unknown and I4
		if ((int)t == 3)
		{
			return 1;
		}
		if ((int)t == 14 || (int)t == 22 || (int)t == 20)
		{
			return 2;
		}
		return 0;
	}

	internal Art ArtFor(ItemData weapon)
	{
		//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_001f: 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)
		if (weapon == null || weapon.m_shared == null)
		{
			return null;
		}
		SkillType skillType = weapon.m_shared.m_skillType;
		int num = HandOf(weapon.m_shared.m_itemType);
		for (int i = 0; i < _arts.Count; i++)
		{
			Art art = _arts[i];
			if (art.Skill == skillType && (art.Hand == 0 || art.Hand == num) && (art.Kind != ArtKind.Legion || !((Object)(object)SummonOf(weapon) == (Object)null)))
			{
				return art;
			}
		}
		return null;
	}

	internal Art CurrentArt(Player p)
	{
		if ((Object)(object)p == (Object)null)
		{
			return null;
		}
		return ArtFor(((Humanoid)p).GetCurrentWeapon());
	}

	internal static float TotalDamage(DamageTypes d)
	{
		return d.m_blunt + d.m_slash + d.m_pierce + d.m_fire + d.m_frost + d.m_lightning + d.m_poison + d.m_spirit;
	}

	private static float WeaponTotalDamage(ItemData w)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		if (w != null)
		{
			return TotalDamage(w.GetDamage());
		}
		return 0f;
	}

	internal bool AttackerArt(Character attacker, out Art a, out float power)
	{
		a = null;
		power = 0f;
		if ((Object)(object)attacker == (Object)null)
		{
			return false;
		}
		int hash = 0;
		ZDO val = OwnZdo(attacker);
		if (val != null)
		{
			hash = val.GetInt(ZdoArt, 0);
			if (hash != 0)
			{
				long num = val.GetLong(ZdoUntil, 0L);
				if (num == 0 || NowTicks() >= num)
				{
					hash = 0;
				}
				else
				{
					power = val.GetFloat(ZdoPower, 0f);
				}
			}
		}
		if (hash == 0 && !ProxyWindowArt(attacker, out hash, out power))
		{
			return false;
		}
		if (_artByHash.TryGetValue(hash, out a))
		{
			return power > 0f;
		}
		return false;
	}

	private void TryActivate(Player p)
	{
		//IL_021e: Unknown result type (might be due to invalid IL or missing references)
		if (TauntShieldEquipped(p))
		{
			ActivateTaunt(p);
			return;
		}
		ItemData currentWeapon = ((Humanoid)p).GetCurrentWeapon();
		Art art = ArtFor(currentWeapon);
		if (art == null)
		{
			Message(p, L("No art for this weapon", "Нет активки для этого оружия"));
			return;
		}
		float time = Time.time;
		if (time < _gcdUntil)
		{
			Message(p, L("Global cooldown: ", "Общий КД: ") + Mathf.CeilToInt(_gcdUntil - time) + L("s", "с"));
			return;
		}
		if (_cooldownUntil.TryGetValue(art.Id, out var value) && time < value)
		{
			Message(p, art.Name + L(": cooldown ", ": КД ") + Mathf.CeilToInt(value - time) + L("s", "с"));
			return;
		}
		float value2 = art.Cost.Value;
		if (value2 > 0f && !(art.UsesEitr ? ((Character)p).HaveEitr(value2) : ((Character)p).HaveStamina(value2)))
		{
			Message(p, art.Name + (art.UsesEitr ? L(": not enough eitr", ": не хватает эйтра") : L(": not enough stamina", ": не хватает стамины")));
			return;
		}
		float num = ((art.HpCost != null) ? (art.HpCost.Value * ((Character)p).GetMaxHealth()) : 0f);
		if (num > 0f && ((Character)p).GetHealth() - num < 1f)
		{
			Message(p, art.Name + L(": not enough health", ": не хватает здоровья"));
			return;
		}
		if (art.Kind == ArtKind.Legion)
		{
			string text = LegionBlocked(p, currentWeapon);
			if (text != null)
			{
				Message(p, art.Name + ": " + text);
				return;
			}
		}
		float num2 = Mathf.Clamp01(WeaponTotalDamage(currentWeapon) / Mathf.Max(1f, Sv(_cfgRefWeaponDamage)));
		float skillFactor = ((Character)p).GetSkillFactor(art.Skill);
		float num3 = PowerScale(num2, skillFactor);
		float p2 = 0.5f * num2 + 0.5f * skillFactor;
		if (value2 > 0f)
		{
			if (art.UsesEitr)
			{
				((Character)p).UseEitr(value2);
			}
			else
			{
				((Character)p).UseStamina(value2);
			}
		}
		if (num > 0f)
		{
			((Character)p).UseHealth(num);
		}
		if (art.Angle != null && Sv(art.Angle) < 360f)
		{
			p.FaceLookDirection();
		}
		string text2;
		if (art.Kind == ArtKind.AoEHeal)
		{
			text2 = art.Name + " (" + DoHeal(p, art, p2) + ")";
		}
		else if (art.Kind == ArtKind.AoEBurst)
		{
			text2 = art.Name + " (" + DoBurst(p, art, currentWeapon, num3) + ")";
		}
		else if (art.Kind == ArtKind.Legion)
		{
			text2 = art.Name + " (" + DoLegion(p, art, currentWeapon) + ")";
		}
		else
		{
			float num4 = Sv(art.Mag);
			float num5 = ((art.Kind == ArtKind.DamageMult || art.Kind == ArtKind.Stagger) ? (1f + (num4 - 1f) * num3) : (num4 * num3));
			float num6 = Mathf.Clamp(skillFactor * Sv(_cfgSkillDurationScale) * (0.5f + 0.5f * num2), 0f, 0.5f);
			float num7 = Mathf.Max(6f, Sv(art.Win)) * (1f + num6);
			ZDO val = OwnZdo((Character)(object)p);
			if (val != null)
			{
				val.Set(ZdoArt, art.Hash, false);
				val.Set(ZdoUntil, NowTicks() + (long)(num7 * 10000000f));
				val.Set(ZdoPower, num5);
			}
			_activeUntil[art.Id] = time + num7;
			if (art.Kind == ArtKind.Berserk)
			{
				_berserkUntil = time + num7;
				_berserkReduction = Mathf.Clamp(num5, 0f, 0.8f);
				_berserkRegen = ((art.Regen != null) ? Sv(art.Regen) : 0f);
				_berserkNextTick = time + 1f;
			}
			if (art.Shots != null)
			{
				_shotsLeft[art.Id] = Mathf.Max(1, art.Shots.Value);
				text2 = art.Name + "! " + _shotsLeft[art.Id] + L(" shots (up to ", " выстр. (до ") + FormatTime(num7) + L("s)", "с)");
			}
			else
			{
				text2 = art.Name + "! " + FormatTime(num7) + L("s", "с");
			}
			Debug("Activated " + art.Id + ": power " + num5.ToString("0.00") + ", window " + FormatTime(num7) + "s");
		}
		_cooldownUntil[art.Id] = time + ((art.Kind == ArtKind.Legion) ? _legionCooldown : art.Cd.Value);
		_gcdUntil = time + _cfgGlobalCooldown.Value;
		_lastArtId = art.Id;
		_lastActivated = time;
		try
		{
			PlayArtEffects((Humanoid)(object)p, art);
		}
		catch (Exception e)
		{
			Fail("art effects", e);
		}
		Message(p, text2);
		Debug("Activated " + art.Id + " (tier " + FormatTime(num2) + ", skill " + FormatTime(skillFactor) + ")");
	}

	private int DoHeal(Player p, Art a, float p01)
	{
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		float num = Sv(a.HLo0) + (Sv(a.HLo1) - Sv(a.HLo0)) * p01;
		float num2 = Sv(a.HHi0) + (Sv(a.HHi1) - Sv(a.HHi0)) * p01;
		if (num2 < num)
		{
			num2 = num;
		}
		float num3 = Random.Range(num, num2);
		float num4 = Sv(a.Radius) * Sv(a.Radius);
		Vector3 position = ((Component)p).transform.position;
		int num5 = 0;
		List<Player> allPlayers = Player.GetAllPlayers();
		for (int i = 0; i < allPlayers.Count; i++)
		{
			Player val = allPlayers[i];
			if ((Object)(object)val == (Object)null || ((Character)val).IsDead() || ((Object)(object)val == (Object)(object)p && !a.IncludeSelf))
			{
				continue;
			}
			Vector3 val2 = ((Component)val).transform.position - position;
			if (!(((Vector3)(ref val2)).sqrMagnitude > num4) && InCone(p, a, (Character)(object)val))
			{
				HealChar((Character)(object)val, num3);
				try
				{
					PlayHealHit(a, (Character)(object)val, (Character)(object)p);
				}
				catch (Exception e)
				{
					Fail("heal hit fx", e);
				}
				num5++;
			}
		}
		int num6 = 0;
		if (a.HealTamed != null && Sb(a.HealTamed))
		{
			List<Character> allCharacters = Character.GetAllCharacters();
			for (int j = 0; j < allCharacters.Count; j++)
			{
				Character val3 = allCharacters[j];
				if ((Object)(object)val3 == (Object)null || val3.IsPlayer() || val3.IsDead() || !val3.IsTamed())
				{
					continue;
				}
				Vector3 val4 = ((Component)val3).transform.position - position;
				if (!(((Vector3)(ref val4)).sqrMagnitude > num4) && InCone(p, a, val3) && !(val3.GetHealth() >= val3.GetMaxHealth()))
				{
					HealChar(val3, num3 / Mathf.Max(1f, ((Character)p).GetMaxHealth()) * val3.GetMaxHealth());
					try
					{
						PlayHealHit(a, val3, (Character)(object)p);
					}
					catch (Exception e2)
					{
						Fail("heal hit fx", e2);
					}
					num6++;
				}
			}
		}
		Debug(a.Id + ": heal " + FormatTime(num3) + " to " + num5 + " players, " + num6 + " tamed (roll " + FormatTime(num) + "-" + FormatTime(num2) + ")");
		return num5;
	}

	private bool InCone(Player p, Art a, Character q)
	{
		//IL_0027: 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_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		if (a.Angle == null)
		{
			return true;
		}
		float num = Sv(a.Angle);
		if (num >= 360f)
		{
			return true;
		}
		Vector3 val = ((Component)q).transform.position - ((Component)p).transform.position;
		val.y = 0f;
		if (((Vector3)(ref val)).sqrMagnitude <= 4f)
		{
			return true;
		}
		Vector3 forward = ((Component)p).transform.forward;
		forward.y = 0f;
		return Vector3.Angle(forward, val) <= num * 0.5f;
	}

	private static void HealChar(Character c, float amt)
	{
		if ((Object)(object)c == (Object)null || amt <= 0f)
		{
			return;
		}
		ZNetView component = ((Component)c).GetComponent<ZNetView>();
		if (!((Object)(object)component == (Object)null) && component.IsValid())
		{
			if (component.IsOwner())
			{
				c.Heal(amt, true);
				return;
			}
			component.InvokeRPC(component.GetZDO().GetOwner(), "RPC_Heal", new object[2] { amt, true });
		}
	}

	private int DoBurst(Player p, Art a, ItemData weapon, float s)
	{
		//IL_0035: 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_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Expected O, but got Unknown
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		if (weapon == null)
		{
			return 0;
		}
		float num = Sv(a.Mag) * s;
		float num2 = Sv(a.Radius) * Sv(a.Radius);
		Vector3 position = ((Component)p).transform.position;
		int num3 = 0;
		List<Character> allCharacters = Character.GetAllCharacters();
		for (int i = 0; i < allCharacters.Count; i++)
		{
			Character val = allCharacters[i];
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)p) && !val.IsPlayer() && !val.IsDead() && !val.IsTamed())
			{
				Vector3 val2 = ((Component)val).transform.position - position;
				if (!(((Vector3)(ref val2)).sqrMagnitude > num2))
				{
					float num4 = (val.IsBoss() ? Sv(_cfgBossFactor) : 1f);
					HitData val3 = new HitData();
					val3.m_damage = weapon.GetDamage();
					val3.ApplyModifier(num * num4);
					val3.SetAttacker((Character)(object)p);
					val3.m_point = ((Component)val).transform.position;
					Vector3 val4 = ((Component)val).transform.position - position;
					val3.m_dir = ((Vector3)(ref val4)).normalized;
					val.Damage(val3);
					num3++;
				}
			}
		}
		return num3;
	}

	internal float CooldownLeft(Art a)
	{
		if (!_cooldownUntil.TryGetValue(a.Id, out var value))
		{
			return 0f;
		}
		return value - Time.time;
	}

	internal float ActiveLeft(Art a)
	{
		if (!_activeUntil.TryGetValue(a.Id, out var value))
		{
			return 0f;
		}
		return value - Time.time;
	}

	private void BerserkTick(Player p, float now)
	{
		if (!(now >= _berserkUntil) && !(_berserkRegen <= 0f) && !(now < _berserkNextTick))
		{
			_berserkNextTick = now + 1f;
			((Character)p).Heal(_berserkRegen, true);
			Debug("Berserk: +" + FormatTime(_berserkRegen) + " HP, " + FormatTime(_berserkUntil - now) + "s left");
		}
	}

	internal void MarkExposed(Character c, float fraction, float seconds)
	{
		ZDO val = OwnZdo(c);
		if (val != null && !(fraction <= 0f))
		{
			long num = NowTicks();
			float num2 = ((val.GetLong(ZdoExposedUntil, 0L) > num) ? val.GetFloat(ZdoExposed, 0f) : 0f);
			val.Set(ZdoExposed, Mathf.Max(num2, fraction));
			val.Set(ZdoExposedUntil, num + (long)(seconds * 10000000f));
		}
	}

	internal float ExposedFraction(Character c)
	{
		ZDO val = OwnZdo(c);
		if (val == null || val.GetLong(ZdoExposedUntil, 0L) <= NowTicks())
		{
			return 0f;
		}
		return Mathf.Clamp(val.GetFloat(ZdoExposed, 0f), 0f, 1f);
	}

	internal int ShotsLeft(Art a)
	{
		if (a == null || a.Shots == null || !(ActiveLeft(a) > 0f) || !_shotsLeft.TryGetValue(a.Id, out var value))
		{
			return 0;
		}
		return value;
	}

	internal void OnLocalShot(ItemData weapon)
	{
		Art art = ArtFor(weapon);
		if (art == null || art.Shots == null || ActiveLeft(art) <= 0f || !_shotsLeft.TryGetValue(art.Id, out var value) || value <= 0)
		{
			return;
		}
		value--;
		_shotsLeft[art.Id] = value;
		Debug(art.Id + ": shot, " + value + " left");
		if (value <= 0)
		{
			float num = Mathf.Min(ActiveLeft(art), 2.5f);
			_activeUntil[art.Id] = Time.time + num;
			ZDO val = OwnZdo((Character)(object)Player.m_localPlayer);
			if (val != null && val.GetInt(ZdoArt, 0) == art.Hash)
			{
				val.Set(ZdoUntil, NowTicks() + (long)(num * 10000000f));
			}
		}
	}

	private void BindBleedConfig()
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Expected O, but got Unknown
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Expected O, but got Unknown
		_cfgBleedSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("05 Bleed", "BleedSeconds", 6f, new ConfigDescription("How long a bleed keeps ticking after the last hit that applied it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), new object[0]));
		_cfgBleedInterval = ((BaseUnityPlugin)this).Config.Bind<float>("05 Bleed", "TickInterval", 1f, new ConfigDescription("Seconds between bleed ticks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 5f), new object[0]));
	}

	internal void RegisterBleed(Character victim, float dps, ZDOID attacker)
	{
		//IL_0035: 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_0042: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)victim == (Object)null) && !(dps <= 0f))
		{
			Bleed value = default(Bleed);
			value.Dps = dps;
			value.Until = Time.time + Sv(_cfgBleedSeconds);
			value.Attacker = attacker;
			_bleeds[victim.GetZDOID()] = value;
		}
	}

	private void BleedTick(float now)
	{
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: 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_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Expected O, but got Unknown
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//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)
		if (_bleeds.Count == 0 || now < _nextBleedTick)
		{
			return;
		}
		float num = Mathf.Max(0.25f, _cfgBleedInterval.Value);
		_nextBleedTick = now + num;
		_bleedScratch.Clear();
		foreach (KeyValuePair<ZDOID, Bleed> bleed in _bleeds)
		{
			ZDOID key = bleed.Key;
			Bleed value = bleed.Value;
			Character val = ProxyTankChar(key);
			if ((Object)(object)val == (Object)null || val.IsDead() || now >= value.Until)
			{
				_bleedScratch.Add(key);
				continue;
			}
			ZNetView component = ((Component)val).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner())
			{
				HitData val2 = new HitData();
				val2.m_damage.m_slash = value.Dps * num;
				val2.m_attacker = value.Attacker;
				val2.m_point = ((Component)val).transform.position;
				val2.m_dir = Vector3.up;
				s_bleedTick = true;
				try
				{
					val.Damage(val2);
				}
				finally
				{
					s_bleedTick = false;
				}
			}
		}
		for (int i = 0; i < _bleedScratch.Count; i++)
		{
			_bleeds.Remove(_bleedScratch[i]);
		}
	}

	private void RegisterCommands()
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Expected O, but got Unknown
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		new ConsoleCommand("weaponarts", "Weapon Arts. 'weaponarts status' - current art and state; 'weaponarts list' - all arts", (ConsoleEvent)delegate(ConsoleEventArgs args)
		{
			RunCommand(args);
		}, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}

	private static void Say(ConsoleEventArgs args, string text)
	{
		if (args != null && (Object)(object)args.Context != (Object)null)
		{
			args.Context.AddString(text);
		}
	}

	private void RunCommand(ConsoleEventArgs args)
	{
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			string text = ((args.Args.Length > 1) ? args.Args[1].ToLowerInvariant() : "");
			if (text == "list")
			{
				StringBuilder stringBuilder = new StringBuilder();
				for (int i = 0; i < _arts.Count; i++)
				{
					Art art = _arts[i];
					stringBuilder.Append(art.Id).Append(" [").Append(art.Skill)
						.Append((art.Hand == 1) ? " 1H" : ((art.Hand == 2) ? " 2H" : ""))
						.Append("]: ")
						.Append(art.Desc)
						.Append("\n");
				}
				Say(args, stringBuilder.ToString());
			}
			else if (text == "status")
			{
				if (_disabledByErrors)
				{
					Say(args, "Weapon Arts is inert after errors.");
					return;
				}
				Player localPlayer = Player.m_localPlayer;
				Art art2 = CurrentArt(localPlayer);
				if (art2 == null)
				{
					Say(args, "No art for the current weapon.");
					return;
				}
				float num = CooldownLeft(art2);
				Say(args, art2.Name + " (" + art2.Id + "): " + ((num > 0f) ? ("cooldown " + Mathf.CeilToInt(num) + "s") : "ready") + ". " + art2.Desc);
			}
			else
			{
				Say(args, "weaponarts status | list");
			}
		}
		catch (Exception ex)
		{
			Say(args, "weaponarts: " + ex.Message);
			Fail("command", ex);
		}
	}

	internal static string L(string en, string ru)
	{
		string text = ((_cfgLanguage != null) ? _cfgLanguage.Value : "Auto");
		if (text == "Russian")
		{
			return ru;
		}
		if (text == "English")
		{
			return en;
		}
		try
		{
			Localization instance = Localization.instance;
			return (instance != null && instance.GetSelectedLanguage() == "Russian") ? ru : en;
		}
		catch
		{
			return en;
		}
	}

	private void BindConfig()
	{
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Expected O, but got Unknown
		//IL_0114: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Expected O, but got Unknown
		//IL_0153: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Expected O, but got Unknown
		//IL_0192: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Expected O, but got Unknown
		//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01db: Expected O, but got Unknown
		//IL_0210: Unknown result type (might be due to invalid IL or missing references)
		//IL_021a: Expected O, but got Unknown
		//IL_024f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0259: Expected O, but got Unknown
		_cfgEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("01 General", "Enabled", true, "Master switch.");
		_cfgDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("01 General", "Debug", false, "Log every activation and applied effect.");
		_cfgKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("01 General", "AbilityKey", new KeyboardShortcut((KeyCode)99, (KeyCode[])(object)new KeyCode[0]), "Key that triggers the art of the currently equipped weapon.");
		_cfgShowHud = ((BaseUnityPlugin)this).Config.Bind<bool>("01 General", "ShowHud", true, "Show the current art and its state at the bottom of the screen.");
		_cfgLanguage = ((BaseUnityPlugin)this).Config.Bind<string>("01 General", "Language", "Auto", new ConfigDescription("Language of the HUD, messages and proxy chat lines. Auto = the game's language (Russian if the game is in Russian, else English). Local, never taken from the server.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "Auto", "English", "Russian" }), new object[0]));
		_cfgGlobalCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("02 Balance", "GlobalCooldown", 30f, new ConfigDescription("Seconds after any activation during which no art can fire (stops weapon-swap spam). Shown in the HUD and on weapon swap.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), new object[0]));
		_cfgBossFactor = ((BaseUnityPlugin)this).Config.Bind<float>("02 Balance", "BossEffectFactor", 0.5f, new ConfigDescription("Multiplier of art strength against bosses. Crowd control does not apply to bosses regardless (vanilla immunity).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[0]));
		_cfgSkillPowerScale = ((BaseUnityPlugin)this).Config.Bind<float>("02 Balance", "SkillPowerBonus", 0.25f, new ConfigDescription("Extra art strength at weapon skill 100 (0.25 = +25%). The art's Magnitude is the floor (skill 0, weakest weapon).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), new object[0]));
		_cfgTierPowerScale = ((BaseUnityPlugin)this).Config.Bind<float>("02 Balance", "TierPowerBonus", 0.25f, new ConfigDescription("Extra art strength from a full-tier weapon (see RefWeaponDamage). Adds to SkillPowerBonus.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), new object[0]));
		_cfgSkillDurationScale = ((BaseUnityPlugin)this).Config.Bind<float>("02 Balance", "SkillDurationScale", 0.5f, new ConfigDescription("Extra art duration from skill+tier, capped at +50% (4s -> max 6s).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.5f), new object[0]));
		_cfgRefWeaponDamage = ((BaseUnityPlugin)this).Config.Bind<float>("02 Balance", "RefWeaponDamage", 100f, new ConfigDescription("Weapon base damage that counts as full tier (tierNorm = weaponDamage / this, capped 1).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 400f), new object[0]));
	}

	private float PowerScale(float tierNorm, float skill)
	{
		return 1f + Sv(_cfgTierPowerScale) * tierNorm + Sv(_cfgSkillPowerScale) * skill;
	}

	private void Awake()
	{
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Expected O, but got Unknown
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Instance = this;
			BindConfig();
			BindTauntConfig();
			BindProxyConfig();
			BindSyncConfig();
			BindBleedConfig();
			BindEffectsConfig();
			BindHudConfig();
			BindSummonConfig();
			BindReflection();
			BuildArts();
			MigrateConfig();
			RegisterCommands();
			_harmony = new Harmony("j1ga.weaponarts");
			_harmony.PatchAll(typeof(WeaponArtsPlugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Concat("Weapon Arts 0.16.0 loaded. Key: ", _cfgKey.Value, "."));
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Awake failed, mod is inert: " + ex));
			_disabledByErrors = true;
		}
	}

	private void OnDestroy()
	{
		try
		{
			ReleaseAllStraight();
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("OnDestroy: " + ex.Message));
		}
		if ((Object)(object)Instance == (Object)(object)this)
		{
			Instance = null;
		}
	}

	private void Update()
	{
		if (_disabledByErrors || !_cfgEnabled.Value)
		{
			return;
		}
		try
		{
			if (_syncDirty)
			{
				FlushSync();
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !((Character)localPlayer).IsDead())
			{
				ArtKeyTick(localPlayer, Time.time);
				TauntTick(localPlayer, Time.time);
				BerserkTick(localPlayer, Time.time);
				GcdOnSwap(localPlayer, Time.time);
				UpdateProxies(localPlayer, Time.time);
				BleedTick(Time.time);
				CarryTick(localPlayer, Time.time);
				SummonFollowTick(localPlayer, Time.time);
				SummonYieldTick(localPlayer, Time.time);
			}
		}
		catch (Exception e)
		{
			Fail("Update", e);
		}
	}

	internal static long NowTicks()
	{
		ZNet instance = ZNet.instance;
		if (!((Object)(object)instance != (Object)null))
		{
			return DateTime.UtcNow.Ticks;
		}
		return instance.GetTime().Ticks;
	}

	internal static ZDO OwnZdo(Character c)
	{
		if ((Object)(object)c == (Object)null)
		{
			return null;
		}
		ZNetView component = ((Component)c).GetComponent<ZNetView>();
		if (!((Object)(object)component != (Object)null) || !component.IsValid())
		{
			return null;
		}
		return component.GetZDO();
	}

	private static bool BlockedByUI()
	{
		if ((Object)(object)Chat.instance != (Object)null && Chat.instance.IsChatDialogWindowVisible())
		{
			return true;
		}
		if (Console.IsVisible())
		{
			return true;
		}
		if (TextInput.IsVisible())
		{
			return true;
		}
		if (Menu.IsVisible())
		{
			return true;
		}
		if (InventoryGui.IsVisible())
		{
			return true;
		}
		if (StoreGui.IsVisible())
		{
			return true;
		}
		if ((Object)(object)Minimap.instance != (Object)null && Minimap.IsOpen())
		{
			return true;
		}
		return false;
	}

	private static bool ShortcutPressed(KeyboardShortcut shortcut)
	{
		//IL_0002: 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_0035: 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_003c: Unknown result type (might be due to invalid IL or missing references)
		if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0)
		{
			return false;
		}
		IInputSystem current = UnityInput.Current;
		if (current == null || !current.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey))
		{
			return false;
		}
		foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
		{
			if (!current.GetKey(modifier))
			{
				return false;
			}
		}
		return true;
	}

	private void ArtKeyTick(Player p, float now)
	{
		//IL_0006: 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_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		if (ShortcutPressed(_cfgKey.Value) && !BlockedByUI())
		{
			if (CanDismissSquad(p))
			{
				_keyHeldSince = now;
				_keyHoldDone = false;
			}
			else
			{
				TryActivate(p);
			}
		}
		if (_keyHeldSince < 0f)
		{
			return;
		}
		IInputSystem current = UnityInput.Current;
		if (current != null)
		{
			KeyboardShortcut value = _cfgKey.Value;
			if (current.GetKey(((KeyboardShortcut)(ref value)).MainKey))
			{
				if (!_keyHoldDone && now - _keyHeldSince >= Sv(_cfgSummonDismissHold))
				{
					_keyHoldDone = true;
					DismissSquad(p);
				}
				return;
			}
		}
		if (!_keyHoldDone)
		{
			TryActivate(p);
		}
		_keyHeldSince = -1f;
	}

	internal static string FormatTime(float seconds)
	{
		return Mathf.Max(0f, seconds).ToString("0.0", CultureInfo.InvariantCulture);
	}

	private void GcdOnSwap(Player p, float now)
	{
		ItemData currentWeapon = ((Humanoid)p).GetCurrentWeapon();
		string text = ((currentWeapon != null && currentWeapon.m_shared != null) ? currentWeapon.m_shared.m_name : "") + (TauntShieldEquipped(p) ? "+shield" : "");
		if (!(text == _lastLoadout))
		{
			_lastLoadout = text;
			if (now < _gcdUntil)
			{
				Message(p, L("Global cooldown: ", "Общий КД: ") + Mathf.CeilToInt(_gcdUntil - now) + L("s", "с"));
			}
		}
	}

	internal float GcdLeft()
	{
		return _gcdUntil - Time.time;
	}

	private void Message(Player p, string text)
	{
		if ((Object)(object)p != (Object)null)
		{
			((Character)p).Message((MessageType)2, text, 0, (Sprite)null, false);
		}
	}

	private void Debug(string text)
	{
		if (_cfgDebug.Value)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)text);
		}
	}

	private void Fail(string where, Exception e)
	{
		string text = where + ": " + e.GetType().Name + ": " + e.Message;
		if (_loggedErrors.Add(text))
		{
			((BaseUnityPlugin)this).Logger.LogError((object)(text + "\n" + e.StackTrace));
		}
		if (++_errorCount >= 25 && !_disabledByErrors)
		{
			_disabledByErrors = true;
			((BaseUnityPlugin)this).Logger.LogError((object)"Too many errors, Weapon Arts is now inert until the game restarts.");
		}
	}

	private void BindEffectsConfig()
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Expected O, but got Unknown
		_cfgTauntSound = ((BaseUnityPlugin)this).Config.Bind<string>("06 Taunt Effects", "Sound", "Perfect", new ConfigDescription("Sound on taunt: Block (the shield's own block effect), Perfect (perfect-block sparks), None.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "Block", "Perfect", "None" }), new object[0]));
		_cfgTauntVisual = ((BaseUnityPlugin)this).Config.Bind<string>("06 Taunt Effects", "Visual", "fx_guardstone_activate", "Visual on taunt, attached to the tank (fx_guardstone_activate = the ward's transparent dome). None; GuardianPower (the forsaken-power activation flash); or a registered prefab name, e.g. fx_eikthyr_stomp, fx_Adrenaline1, fx_guardstone_activate, vfx_perfectblock, fx_gjall_taunt.");
		_cfgArtSound = ((BaseUnityPlugin)this).Config.Bind<string>("07 Art Effects", "Sound", "Perfect", new ConfigDescription("Sound when a weapon art is activated: Perfect (perfect-block sparks), None.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "Perfect", "None" }), new object[0]));
		_cfgArtVisual = ((BaseUnityPlugin)this).Config.Bind<string>("07 Art Effects", "Visual", "GuardianPower", "Visual when a weapon art is activated, attached to you. None; GuardianPower (the forsaken-power activation flash); or a registered prefab name, e.g. fx_eikthyr_stomp, fx_Adrenaline1, fx_guardstone_activate, vfx_perfectblock, fx_gjall_taunt.");
		_cfgHealVisual = ((BaseUnityPlugin)this).Config.Bind<string>("07 Art Effects", "HealVisual", "ShamanHeal", "Visual for Rally (sledge heal) instead of the one above: ShamanHeal (the greydwarf shaman's heal: green flames around you), ShamanSpray (the greydwarf shaman's green spray, cast forward) or None; GuardianPower (the forsaken-power activation flash); or a registered prefab name, e.g. fx_eikthyr_stomp, fx_Adrenaline1, fx_guardstone_activate, vfx_perfectblock, fx_gjall_taunt.");
		_cfgMendVisual = ((BaseUnityPlugin)this).Config.Bind<string>("07 Art Effects", "MendVisual", "ShamanSpray", "Visual for Mend (mace heal): ShamanHeal (the greydwarf shaman's heal: green flames around you), ShamanSpray (the greydwarf shaman's green spray, cast forward) or anything HealVisual takes.");
		_cfgAllyHealVisual = ((BaseUnityPlugin)this).Config.Bind<bool>("07 Art Effects", "AllyHealVisual", true, "With ShamanHeal or ShamanSpray: every healed ally also gets the shaman's green heal flames, so everyone sees who was healed.");
		_cfgMendAnimation = ((BaseUnityPlugin)this).Config.Bind<string>("07 Art Effects", "MendAnimation", "StaffShield", "Player animation for Mend: the attack animation of this item prefab (StaffShield = the staff-of-protection cast), a raw animator trigger name, or None.");
	}

	private void MigrateConfig()
	{
		ConfigEntry<int> val = ((BaseUnityPlugin)this).Config.Bind<int>("01 General", "ConfigVersion", 1, "Internal: which defaults this file has been updated to. Do not edit.");
		if (val.Value >= 2)
		{
			return;
		}
		if (_cfgTauntVisual.Value == "GuardianPower")
		{
			_cfgTauntVisual.Value = "fx_guardstone_activate";
		}
		if (_cfgHealVisual.Value == "fx_guardstone_activate")
		{
			_cfgHealVisual.Value = "ShamanHeal";
		}
		if (_cfgMendVisual.Value == "ShamanHeal")
		{
			_cfgMendVisual.Value = "ShamanSpray";
		}
		foreach (Art art in _arts)
		{
			if (art.Id == "Mend" && Mathf.Approximately(art.Radius.Value, 8f))
			{
				art.Radius.Value = 12f;
			}
		}
		val.Value = 2;
	}

	private void ResolveShaman()
	{
		//IL_022e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0238: Expected O, but got Unknown
		//IL_029e: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a8: Expected O, but got Unknown
		if (_shamanResolved || (Object)(object)ZNetScene.instance == (Object)null)
		{
			return;
		}
		_shamanResolved = true;
		List<EffectData> list = new List<EffectData>();
		GameObject prefab = ZNetScene.instance.GetPrefab("Greydwarf_Shaman");
		Humanoid val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Humanoid>() : null);
		if ((Object)(object)val != (Object)null && val.m_defaultItems != null)
		{
			GameObject[] defaultItems = val.m_defaultItems;
			foreach (GameObject val2 in defaultItems)
			{
				ItemDrop val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val3 == (Object)null || ((Object)val2).name.IndexOf("heal", StringComparison.OrdinalIgnoreCase) < 0)
				{
					continue;
				}
				SharedData shared = val3.m_itemData.m_shared;
				Attack attack = shared.m_attack;
				AddEffects(list, shared.m_startEffect);
				AddEffects(list, shared.m_triggerEffect);
				if (attack != null)
				{
					AddEffects(list, attack.m_startEffect);
					AddEffects(list, attack.m_triggerEffect);
					if ((Object)(object)attack.m_spawnOnTrigger != (Object)null && (Object)(object)attack.m_spawnOnTrigger.GetComponent<Aoe>() != (Object)null)
					{
						_shamanAoe = attack.m_spawnOnTrigger;
					}
					if (attack.m_hitEffect != null && attack.m_hitEffect.HasEffects())
					{
						_shamanHit = attack.m_hitEffect;
					}
				}
				Debug("Shaman heal item " + ((Object)val2).name + ": spawn " + ((attack != null && (Object)(object)attack.m_spawnOnTrigger != (Object)null) ? ((Object)attack.m_spawnOnTrigger).name : "-"));
				break;
			}
		}
		if ((Object)(object)_shamanAoe == (Object)null)
		{
			_shamanAoe = ZNetScene.instance.GetPrefab("shaman_heal_aoe");
		}
		Aoe val4 = (((Object)(object)_shamanAoe != (Object)null) ? _shamanAoe.GetComponent<Aoe>() : null);
		if ((Object)(object)val4 != (Object)null)
		{
			if (_shamanHit == null && val4.m_hitEffects != null && val4.m_hitEffects.HasEffects())
			{
				_shamanHit = val4.m_hitEffects;
			}
		}
		else
		{
			_shamanAoe = null;
		}
		AddPrefab(list, "sfx_greydwarf_shaman_heal");
		_shamanCast = new EffectList();
		_shamanCast.m_effectPrefabs = list.ToArray();
		List<EffectData> list2 = new List<EffectData>();
		AddPrefab(list2, "vfx_greydwarf_shaman_pray");
		AddPrefab(list2, "sfx_greydwarf_shaman_heal");
		foreach (EffectData item in list2)
		{
			item.m_inheritParentRotation = true;
		}
		_shamanSpray = new EffectList();
		_shamanSpray.m_effectPrefabs = list2.ToArray();
		Debug("Shaman visuals: aoe " + (((Object)(object)_shamanAoe != (Object)null) ? ((Object)_shamanAoe).name : "none") + ", " + list.Count + " heal cast effects, " + list2.Count + " spray effects, hit " + (_shamanHit != null));
		if ((Object)(object)_shamanAoe == (Object)null && list.Count == 0)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Shaman heal visual not found; heals use HealVisual.");
		}
	}

	private static void AddEffects(List<EffectData> to, EffectList from)
	{
		if (from == null || from.m_effectPrefabs == null)
		{
			return;
		}
		EffectData[] effectPrefabs = from.m_effectPrefabs;
		foreach (EffectData val in effectPrefabs)
		{
			if (val != null && (Object)(object)val.m_prefab != (Object)null && val.m_enabled)
			{
				to.Add(val);
			}
		}
	}

	private static void AddPrefab(List<EffectData> to, string name)
	{
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Expected O, but got Unknown
		GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(name) : null);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		foreach (EffectData item in to)
		{
			if ((Object)(object)item.m_prefab == (Object)(object)val)
			{
				return;
			}
		}
		EffectData val2 = new EffectData();
		val2.m_prefab = val;
		val2.m_enabled = true;
		val2.m_attach = true;
		to.Add(val2);
	}

	private ShamanVisual ShamanOf(Art a)
	{
		if (a == null || a.Kind != ArtKind.AoEHeal)
		{
			return ShamanVisual.None;
		}
		string text = ((a.Heal1H ? _cfgMendVisual.Value : _cfgHealVisual.Value) ?? "").Trim();
		ShamanVisual shamanVisual = (text.Equals("ShamanHeal", StringComparison.OrdinalIgnoreCase) ? ShamanVisual.Heal : (text.Equals("ShamanSpray", StringComparison.OrdinalIgnoreCase) ? ShamanVisual.Spray : ShamanVisual.None));
		if (shamanVisual == ShamanVisual.None)
		{
			return shamanVisual;
		}
		ResolveShaman();
		if (shamanVisual == ShamanVisual.Heal && (Object)(object)_shamanAoe == (Object)null && (_shamanCast == null || !_shamanCast.HasEffects()))
		{
			return ShamanVisual.None;
		}
		if (shamanVisual == ShamanVisual.Spray && (_shamanSpray == null || !_shamanSpray.HasEffects()))
		{
			return ShamanVisual.None;
		}
		return shamanVisual;
	}

	private void SpawnShamanAoe(Vector3 pos, Quaternion rot)
	{
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: 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_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		Aoe val = (((Object)(object)_shamanAoe != (Object)null) ? _shamanAoe.GetComponent<Aoe>() : null);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		bool hitCharacters = val.m_hitCharacters;
		bool hitProps = val.m_hitProps;
		bool hitTerrain = val.m_hitTerrain;
		bool hitOwner = val.m_hitOwner;
		DamageTypes damage = val.m_damage;
		string statusEffect = val.m_statusEffect;
		string statusEffectIfBoss = val.m_statusEffectIfBoss;
		string statusEffectIfPlayer = val.m_statusEffectIfPlayer;
		GameObject spawnOnHitTerrain = val.m_spawnOnHitTerrain;
		GameObject chainObj = val.m_chainObj;
		float damageSelf = val.m_damageSelf;
		try
		{
			val.m_hitCharacters = false;
			val.m_hitProps = false;
			val.m_hitTerrain = false;
			val.m_hitOwner = false;
			val.m_damage = default(DamageTypes);
			val.m_statusEffect = "";
			val.m_statusEffectIfBoss = "";
			val.m_statusEffectIfPlayer = "";
			val.m_spawnOnHitTerrain = null;
			val.m_chainObj = null;
			val.m_damageSelf = 0f;
			Object.Instantiate<GameObject>(_shamanAoe, pos, rot);
		}
		finally
		{
			val.m_hitCharacters = hitCharacters;
			val.m_hitProps = hitProps;
			val.m_hitTerrain = hitTerrain;
			val.m_hitOwner = hitOwner;
			val.m_damage = damage;
			val.m_statusEffect = statusEffect;
			val.m_statusEffectIfBoss = statusEffectIfBoss;
			val.m_statusEffectIfPlayer = statusEffectIfPlayer;
			val.m_spawnOnHitTerrain = spawnOnHitTerrain;
			val.m_chainObj = chainObj;
			val.m_damageSelf = damageSelf;
		}
	}

	private void PlayHealHit(Art a, Character target, Character caster)
	{
		//IL_0062: 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_0039: 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_0050: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)target == (Object)null) && !((Object)(object)target == (Object)(object)caster) && _cfgAllyHealVisual.Value && ShamanOf(a) != ShamanVisual.None)
		{
			if (_shamanHit != null)
			{
				Play(_shamanHit, target.GetCenterPoint(), ((Component)target).transform.rotation, ((Component)target).transform, target.GetZDOID());
			}
			else
			{
				SpawnShamanAoe(((Component)target).transform.position, ((Component)target).transform.rotation);
			}
		}
	}

	private void PlayMendAnimation(Humanoid actor, Art a)
	{
		if (a == null || !a.Heal1H || (Object)(object)actor != (Object)(object)Player.m_localPlayer)
		{
			return;
		}
		string text = (_cfgMendAnimation.Value ?? "").Trim();
		if (text.Length != 0 && !text.Equals("None", StringComparison.OrdinalIgnoreCase))
		{
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(text) : null);
			ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 != (Object)null && val2.m_itemData.m_shared.m_attack != null)
			{
				text = val2.m_itemData.m_shared.m_attack.m_attackAnimation;
			}
			ZSyncAnimation val3 = (ZSyncAnimation)((s_zanim != null) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val3 != (Object)null && !string.IsNullOrEmpty(text))
			{
				val3.SetTrigger(text);
			}
		}
	}

	private void PlayActivationEffects(Humanoid tank, EffectList blockEffect)
	{
		PlayEffects(tank, _cfgTauntSound.Value, _cfgTauntVisual.Value, blockEffect);
	}

	private void PlayArtEffects(Humanoid actor, Art a)
	{
		//IL_005f: 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_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: 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_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		if (a == null)
		{
			return;
		}
		ShamanVisual shamanVisual = ShamanOf(a);
		if (shamanVisual != ShamanVisual.None)
		{
			PlayEffects(actor, _cfgArtSound.Value, "None", null);
			if (shamanVisual == ShamanVisual.Spray)
			{
				Play(_shamanSpray, ((Character)actor).GetCenterPoint(), ((Component)actor).transform.rotation, ((Component)actor).transform, ((Character)actor).GetZDOID());
			}
			else
			{
				Play(_shamanCast, ((Character)actor).GetCenterPoint(), ((Component)actor).transform.rotation, ((Component)actor).transform, ((Character)actor).GetZDOID());
				SpawnShamanAoe(((Component)actor).transform.position, ((Component)actor).transform.rotation);
			}
			PlayMendAnimation(actor, a);
		}
		else
		{
			string visual = ((a.Kind == ArtKind.AoEHeal) ? _cfgHealVisual.Value : _cfgArtVisual.Value);
			PlayEffects(actor, _cfgArtSound.Value, visual, null);
			PlayMendAnimation(actor, a);
		}
	}

	private void PlayEffects(Humanoid actor, string sound, string visual, EffectList blockEffect)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: 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_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: 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_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_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: 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_00ac: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)actor == (Object)null))
		{
			Vector3 centerPoint = ((Character)actor).GetCenterPoint();
			Quaternion rotation = ((Component)actor).transform.rotation;
			ZDOID zDOID = ((Character)actor).GetZDOID();
			sound = sound ?? "";
			if (sound.Equals("Block", StringComparison.OrdinalIgnoreCase) && blockEffect != null && blockEffect.HasEffects())
			{
				Play(blockEffect, centerPoint, rotation, null, zDOID);
			}
			else if (!sound.Equals("None", StringComparison.OrdinalIgnoreCase))
			{
				Play(actor.m_perfectBlockEffect, centerPoint, rotation, null, zDOID);
			}
			visual = (visual ?? "").Trim();
			if (visual.Length != 0 && !visual.Equals("None", StringComparison.OrdinalIgnoreCase))
			{
				Play(VisualEffects(visual), centerPoint, rotation, ((Component)actor).transform, zDOID);
			}
		}
	}

	private static void Play(EffectList list, Vector3 pos, Quaternion rot, Transform parent, ZDOID id)
	{
		//IL_000d: 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_0016: Unknown result type (might be due to invalid IL or missing references)
		if (list != null && list.HasEffects())
		{
			list.Create(pos, rot, parent, 1f, -1, id);
		}
	}

	private EffectList VisualEffects(string name)
	{
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Expected O, but got Unknown
		//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Expected O, but got Unknown
		if (name.Equals("GuardianPower", StringComparison.OrdinalIgnoreCase))
		{
			ObjectDB instance = ObjectDB.instance;
			StatusEffect val = (((Object)(object)instance != (Object)null) ? instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode("GP_Eikthyr")) : null);
			if ((Object)(object)val != (Object)null && val.m_startEffects != null && val.m_startEffects.HasEffects())
			{
				return val.m_startEffects;
			}
			if (_warnedEffects.Add(name))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"GP_Eikthyr has no start effects in this build; no taunt visual.");
			}
			return null;
		}
		GameObject val2 = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(name) : null);
		if ((Object)(object)val2 == (Object)null)
		{
			if (_warnedEffects.Add(name))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Visual effect prefab '" + name + "' is not registered; no taunt visual. Try GuardianPower, fx_eikthyr_stomp, fx_Adrenaline1, fx_guardstone_activate, vfx_perfectblock or fx_gjall_taunt."));
			}
			return null;
		}
		EffectData val3 = new EffectData();
		val3.m_prefab = val2;
		val3.m_enabled = true;
		val3.m_attach = true;
		val3.m_inheritParentRotation = true;
		EffectList val4 = new EffectList();
		val4.m_effectPrefabs = (EffectData[])(object)new EffectData[1] { val3 };
		return val4;
	}

	private void BindProxyConfig()
	{
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Expected O, but got Unknown
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0117: Expected O, but got Unknown
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0156: Expected O, but got Unknown
		_cfgProxy = ((BaseUnityPlugin)this).Config.Bind<bool>("09 Proxy", "Enabled", false, "Run arts for players WITHOUT the mod near you: they play the trigger emote (or say the trigger word) and this client applies the art of their equipped weapon/shield on their behalf. Players with the mod act for themselves.");
		_cfgProxyProvider = ((BaseUnityPlugin)this).Config.Bind<string>("09 Proxy", "Provider", "Nearby", new ConfigDescription("Which modded client acts for a modless player. Nearby = of the modded players near enough to own the monsters, the host else the lowest session id (works on a dedicated server). Host = only the hosting player.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "Nearby", "Host" }), new object[0]));
		_cfgProxyEmote = ((BaseUnityPlugin)this).Config.Bind<string>("09 Proxy", "TriggerEmote", "challenge", "Vanilla emote that triggers the art (e.g. /challenge). Empty: off.");
		_cfgProxyChat = ((BaseUnityPlugin)this).Config.Bind<string>("09 Proxy", "TriggerChat", "art", "Exact chat word that triggers the art for its sender. Empty: off.");
		_cfgProxyQuery = ((BaseUnityPlugin)this).Config.Bind<string>("09 Proxy", "QueryWord", "art?", "Exact chat word a modless player types to be told their art and its state. Empty: off.");
		_cfgProxySkill = ((BaseUnityPlugin)this).Config.Bind<float>("09 Proxy", "SkillForModless", 25f, new ConfigDescription("Weapon skill assumed for players without the mod (their real skill is not visible).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), new object[0]));
		_cfgProxyCooldownFactor = ((BaseUnityPlugin)this).Config.Bind<float>("09 Proxy", "CooldownFactor", 1.5f, new ConfigDescription("Their cooldown is the art's cooldown times this (no stamina/eitr is spent for them).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), new object[0]));
		_cfgProxyAnnounce = ((BaseUnityPlugin)this).Config.Bind<bool>("09 Proxy", "Announce", true, "Say the result in chat (they have no HUD).");
		_cfgProxyAnnounceReady = ((BaseUnityPlugin)this).Config.Bind<bool>("09 Proxy", "AnnounceReady", true, "Say in chat when their art comes off cooldown.");
	}

	private bool IsProviderFor(Player p)
	{
		long num = ProviderFor(p);
		if (num != 0)
		{
			return num == ZDOMan.GetSessionID();
		}
		return false;
	}

	private long ProviderFor(Player p)
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: 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_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		ZNet instance = ZNet.instance;
		if ((Object)(object)instance == (Object)null || (Object)(object)p == (Object)null)
		{
			return 0L;
		}
		if (_cfgProxyProvider.Value == "Host")
		{
			if (!instance.IsServer())
			{
				return 0L;
			}
			return ZDOMan.GetSessionID();
		}
		Player localPlayer = Player.m_localPlayer;
		Vector3 position = ((Component)p).transform.position;
		long num = 0L;
		bool flag = false;
		List<Player> allPlayers = Player.GetAllPlayers();
		for (int i = 0; i < allPlayers.Count; i++)
		{
			Player val = allPlayers[i];
			if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)p)
			{
				continue;
			}
			ZNetView component = ((Component)val).GetComponent<ZNetView>();
			ZDO val2 = (((Object)(object)component != (Object)null) ? component.GetZDO() : null);
			if (val2 != null && (!((Object)(object)val != (Object)(object)localPlayer) || HasMod(val2)) && ZNetScene.InActiveArea(position, ZoneSystem.GetZone(((Component)val).transform.position)))
			{
				long owner = val2.GetOwner();
				bool flag2 = IsHostSession(instance, owner);
				if (num == 0 || (flag2 && !flag) || (flag2 == flag && owner < num))
				{
					num = owner;
					flag = flag2;
				}
			}
		}
		return num;
	}

	private static bool IsHostSession(ZNet znet, long uid)
	{
		if (znet.IsServer())
		{
			return uid == ZDOMan.GetSessionID();
		}
		ZNetPeer serverPeer = znet.GetServerPeer();
		if (serverPeer != null)
		{
			return uid == serverPeer.m_uid;
		}
		return false;
	}

	internal Character ProxyTankChar(ZDOID id)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)ZNetScene.instance == (Object)null || ((ZDOID)(ref id)).IsNone())
		{
			return null;
		}
		GameObject val = ZNetScene.instance.FindInstance(id);
		if (!((Object)(object)val != (Object)null))
		{
			return null;
		}
		return val.GetComponent<Character>();
	}

	private void UpdateProxies(Player local, float now)
	{
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_020d: Unknown result type (might be due to invalid IL or missing references)
		MarkSelf(local, now);
		if (!ProxyOn)
		{
			if (_proxies.Count > 0)
			{
				_proxies.Clear();
			}
			return;
		}
		if (now >= _nextProxyPoll)
		{
			_nextProxyPoll = now + 0.25f;
			PollProxies(local, now);
		}
		foreach (Proxy value in _proxies.Values)
		{
			if (now < value.TauntUntil && now >= value.NextReapply)
			{
				value.NextReapply = now + 0.25f;
				Character val = ProxyTankChar(value.Id);
				if ((Object)(object)val != (Object)null && !val.IsDead())
				{
					value.TauntCount = ApplyTauntHold(val, value.TauntUntil, Sv(_cfgTauntRadius), value.SinceMs);
				}
			}
			if (now < value.BerserkUntil && value.BerserkRegen > 0f && now >= value.NextRegen)
			{
				value.NextRegen = now + 1f;
				Character val2 = ProxyTankChar(value.Id);
				if ((Object)(object)val2 != (Object)null && !val2.IsDead())
				{
					HealChar(val2,