Decompiled source of WeaponArts v0.14.1

WeaponArts.dll

Decompiled 2 days 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 UnityEngine;

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

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

	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> Bonus;

		public ConfigEntry<float> Linger;

		public ConfigEntry<int> Shots;

		public ConfigEntry<float> Regen;

		public bool Heal1H;

		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 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(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;
	}

	[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 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.14.1";

	private const int MaxErrors = 25;

	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 string SyncRpc = "j1ga.weaponarts.config";

	private const int SyncVersion = 1;

	private const float ReapplyInterval = 0.25f;

	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 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 EffectList _shamanCast;

	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> _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 GUIStyle _nameStyle;

	private GUIStyle _descStyle;

	private GUIStyle _shadowStyle;

	private int _styleSize = -1;

	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.");
		_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 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_03df: Unknown result type (might be due to invalid IL or missing references)
		//IL_041d: 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");
		AddHeal("Mend", "Исцеление", "булава 1H: хил только союзникам", skill9, 1, 50f, 30f, 10f, 40f, 16f, 65f, 8f, self: false).En("Mend", "1H mace: heal allies only").Heal1H = true;
		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))
			{
				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_018e: 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 = Mathf.Clamp01(WeaponTotalDamage(currentWeapon) / Mathf.Max(1f, Sv(_cfgRefWeaponDamage)));
		float skillFactor = ((Character)p).GetSkillFactor(art.Skill);
		float num2 = PowerScale(num, skillFactor);
		float p2 = 0.5f * num + 0.5f * skillFactor;
		if (value2 > 0f)
		{
			if (art.UsesEitr)
			{
				((Character)p).UseEitr(value2);
			}
			else
			{
				((Character)p).UseStamina(value2);
			}
		}
		string text;
		if (art.Kind == ArtKind.AoEHeal)
		{
			text = art.Name + " (" + DoHeal(p, art, p2) + ")";
		}
		else if (art.Kind == ArtKind.AoEBurst)
		{
			text = art.Name + " (" + DoBurst(p, art, currentWeapon, num2) + ")";
		}
		else
		{
			float num3 = Sv(art.Mag);
			float num4 = ((art.Kind == ArtKind.DamageMult || art.Kind == ArtKind.Stagger) ? (1f + (num3 - 1f) * num2) : (num3 * num2));
			float num5 = Mathf.Clamp(skillFactor * Sv(_cfgSkillDurationScale) * (0.5f + 0.5f * num), 0f, 0.5f);
			float num6 = Mathf.Max(6f, Sv(art.Win)) * (1f + num5);
			ZDO val = OwnZdo((Character)(object)p);
			if (val != null)
			{
				val.Set(ZdoArt, art.Hash, false);
				val.Set(ZdoUntil, NowTicks() + (long)(num6 * 10000000f));
				val.Set(ZdoPower, num4);
			}
			_activeUntil[art.Id] = time + num6;
			if (art.Kind == ArtKind.Berserk)
			{
				_berserkUntil = time + num6;
				_berserkReduction = Mathf.Clamp(num4, 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);
				text = art.Name + "! " + _shotsLeft[art.Id] + L(" shots (up to ", " выстр. (до ") + FormatTime(num6) + L("s)", "с)");
			}
			else
			{
				text = art.Name + "! " + FormatTime(num6) + L("s", "с");
			}
			Debug("Activated " + art.Id + ": power " + num4.ToString("0.00") + ", window " + FormatTime(num6) + "s");
		}
		_cooldownUntil[art.Id] = time + 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, text);
		Debug("Activated " + art.Id + " (tier " + FormatTime(num) + ", 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_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)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: 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))
			{
				HealChar((Character)(object)val, num3);
				try
				{
					PlayHealHit(a, (Character)(object)val);
				}
				catch (Exception e)
				{
					Fail("heal hit fx", e);
				}
				num5++;
			}
		}
		Debug(a.Id + ": heal " + FormatTime(num3) + " to " + num5 + " (roll " + FormatTime(num) + "-" + FormatTime(num2) + ")");
		return num5;
	}

	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_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Expected O, but got Unknown
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Instance = this;
			BindConfig();
			BindTauntConfig();
			BindProxyConfig();
			BindSyncConfig();
			BindBleedConfig();
			BindEffectsConfig();
			BindHudConfig();
			BindReflection();
			BuildArts();
			RegisterCommands();
			_harmony = new Harmony("j1ga.weaponarts");
			_harmony.PatchAll(typeof(WeaponArtsPlugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Concat("Weapon Arts 0.14.1 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()
	{
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		if (_disabledByErrors || !_cfgEnabled.Value)
		{
			return;
		}
		try
		{
			if (_syncDirty)
			{
				FlushSync();
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !((Character)localPlayer).IsDead())
			{
				if (ShortcutPressed(_cfgKey.Value) && !BlockedByUI())
				{
					TryActivate(localPlayer);
				}
				TauntTick(localPlayer, Time.time);
				BerserkTick(localPlayer, Time.time);
				GcdOnSwap(localPlayer, Time.time);
				UpdateProxies(localPlayer, Time.time);
				BleedTick(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;
	}

	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", "GuardianPower", "Visual on taunt, attached to the tank. 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", "fx_guardstone_activate", "Visual for Rally (sledge heal) instead of the one above: ShamanHeal (the greydwarf shaman heal, green particles) 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", "ShamanHeal", "Visual for Mend (mace heal): ShamanHeal (the greydwarf shaman heal: green particles around you and on each healed ally), or anything HealVisual takes.");
		_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 ResolveShaman()
	{
		//IL_0239: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: 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, "vfx_greydwarf_shaman_pray");
		AddPrefab(list, "sfx_greydwarf_shaman_heal");
		_shamanCast = new EffectList();
		_shamanCast.m_effectPrefabs = list.ToArray();
		Debug("Shaman heal visual: aoe " + (((Object)(object)_shamanAoe != (Object)null) ? ((Object)_shamanAoe).name : "none") + ", " + list.Count + " cast 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 bool UseShaman(Art a)
	{
		if (a == null || a.Kind != ArtKind.AoEHeal)
		{
			return false;
		}
		string text = ((a.Heal1H ? _cfgMendVisual.Value : _cfgHealVisual.Value) ?? "").Trim();
		if (!text.Equals("ShamanHeal", StringComparison.OrdinalIgnoreCase))
		{
			return false;
		}
		ResolveShaman();
		if (!((Object)(object)_shamanAoe != (Object)null))
		{
			if (_shamanCast != null)
			{
				return _shamanCast.HasEffects();
			}
			return false;
		}
		return true;
	}

	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)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)target == (Object)null) && UseShaman(a) && _shamanHit != null)
		{
			Play(_shamanHit, target.GetCenterPoint(), ((Component)target).transform.rotation, ((Component)target).transform, target.GetZDOID());
		}
	}

	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_002c: 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_0043: 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_005f: Unknown result type (might be due to invalid IL or missing references)
		if (a != null)
		{
			if (UseShaman(a))
			{
				PlayEffects(actor, _cfgArtSound.Value, "None", null);
				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, value.BerserkRegen);
				}
			}
			if (_cfgProxyAnnounceReady.Value && !value.ReadyAnnounced && value.CooldownUntil > 0f && now >= value.CooldownUntil)
			{
				value.ReadyAnnounced = true;
				Announce(value.Name + ": " + value.ArtName + L(" ready", " готово"));
			}
		}
		_proxyScratch.Clear();
		foreach (KeyValuePair<ZDOID, Proxy> proxy in _proxies)
		{
			if (now - proxy.Value.LastSeen > 120f)
			{
				_proxyScratch.Add(proxy.Key);
			}
		}
		for (int i = 0; i < _proxyScratch.Count; i++)
		{
			_proxies.Remove(_proxyScratch[i]);
		}
	}

	private void MarkSelf(Player local, float now)
	{
		if (!(now < _nextMark))
		{
			_nextMark = now + 1f;
			ZDO val = OwnZdo((Character)(object)local);
			if (val != null && val.GetInt(ModMarkHash, 0) != 1)
			{
				val.Set(ModMarkHash, 1, false);
			}
		}
	}

	private static bool HasMod(ZDO zdo)
	{
		if (zdo != null)
		{
			return zdo.GetInt(ModMarkHash, 0) != 0;
		}
		return false;
	}

	private Proxy GetOrAdd(Player p, ZDO zdo, float now)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: 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_0048: Unknown result type (might be due to invalid IL or missing references)
		ZDOID zDOID = ((Character)p).GetZDOID();
		if (!_proxies.TryGetValue(zDOID, out var value))
		{
			value = new Proxy();
			value.Id = zDOID;
			value.Name = p.GetPlayerName();
			value.LastEmoteId = zdo.GetInt(ZDOVars.s_emoteID, 0);
			_proxies[zDOID] = value;
		}
		value.LastSeen = now;
		return value;
	}

	private void PollProxies(Player local, float now)
	{
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		string text = (_cfgProxyEmote.Value ?? "").Trim();
		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)local)
			{
				continue;
			}
			ZDO val2 = OwnZdo((Character)(object)val);
			if (val2 == null || HasMod(val2))
			{
				continue;
			}
			bool flag = !_proxies.ContainsKey(((Character)val).GetZDOID());
			Proxy orAdd = GetOrAdd(val, val2, now);
			if (flag || text.Length == 0)
			{
				continue;
			}
			int num = val2.GetInt(ZDOVars.s_emoteID, 0);
			if (num != orAdd.LastEmoteId)
			{
				orAdd.LastEmoteId = num;
				string a = val2.GetString(ZDOVars.s_emote, "");
				if (string.Equals(a, text, StringComparison.OrdinalIgnoreCase))
				{
					TryActivateProxy(val, val2, orAdd, now, "emote");
				}
			}
		}
	}

	private void OnChat(long senderId, Type type, string text)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Invalid comparison between Unknown and I4
		if (!ProxyOn || (int)type == 3 || text == null)
		{
			return;
		}
		string a = text.Trim();
		string text2 = (_cfgProxyChat.Value ?? "").Trim();
		string text3 = (_cfgProxyQuery.Value ?? "").Trim();
		bool flag = text2.Length > 0 && string.Equals(a, text2, StringComparison.OrdinalIgnoreCase);
		bool flag2 = text3.Length > 0 && string.Equals(a, text3, StringComparison.OrdinalIgnoreCase);
		if (!flag && !flag2)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		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)localPlayer || ((Character)val).GetOwner() != senderId)
			{
				continue;
			}
			ZDO val2 = OwnZdo((Character)(object)val);
			if (val2 != null && !HasMod(val2))
			{
				Proxy orAdd = GetOrAdd(val, val2, Time.time);
				if (flag2)
				{
					ReplyQuery(val, val2, orAdd);
				}
				else
				{
					TryActivateProxy(val, val2, orAdd, Time.time, "chat");
				}
			}
			break;
		}
	}

	private static ItemData ProtoItem(int hash)
	{
		GameObject val = ((hash != 0 && (Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(hash) : null);
		ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null);
		if (!((Object)(object)val2 != (Object)null))
		{
			return null;
		}
		return val2.m_itemData;
	}

	private Art ResolveProxyArt(ZDO zdo, out bool taunt, out ItemData item, out int quality)
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Invalid comparison between Unknown and I4
		taunt = false;
		item = null;
		quality = 1;
		ItemData val = ProtoItem(zdo.GetInt(ZDOVars.s_leftItem, 0));
		if (val != null && val.m_shared != null && (int)val.m_shared.m_itemType == 5)
		{
			string text = Ss(_cfgShieldMode);
			if (text == "None" || text == "AnyShield" || val.m_shared.m_timedBlockBonus <= Sv(_cfgTowerParry))
			{
				taunt = true;
				item = val;
				quality = zdo.GetInt(ZDOVars.s_leftItemQuality, 1);
				return null;
			}
		}
		item = ProtoItem(zdo.GetInt(ZDOVars.s_rightItem, 0));
		quality = zdo.GetInt(ZDOVars.s_rightItemQuality, 1);
		return ArtFor(item);
	}

	private void TryActivateProxy(Player p, ZDO zdo, Proxy px, float now, string how)
	{
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		if (!IsProviderFor(p))
		{
			Debug("proxy for " + px.Name + " (" + how + "): provider is elsewhere");
			return;
		}
		if (now < px.CooldownUntil)
		{
			Announce(px.Name + L(": cooldown ", ": КД ") + Mathf.CeilToInt(px.CooldownUntil - now) + L("s", "с"));
			return;
		}
		bool taunt;
		ItemData item;
		int quality;
		Art art = ResolveProxyArt(zdo, out taunt, out item, out quality);
		float num = Mathf.Clamp01(_cfgProxySkill.Value / 100f);
		if (taunt)
		{
			float num2 = ((item != null && item.m_shared != null) ? (item.m_shared.m_blockPower + (float)Mathf.Max(0, quality - 1) * item.m_shared.m_blockPowerPerLevel) : 0f);
			float num3 = Mathf.Clamp01(num2 / Mathf.Max(1f, Sv(_cfgTauntRefBlock)));
			float num4 = Mathf.Clamp(num * Sv(_cfgSkillDurationScale) * (0.5f + 0.5f * num3), 0f, 0.5f);
			px.TauntReduction = Mathf.Clamp(Mathf.Lerp(Sv(_cfgTauntReductionBase), Sv(_cfgTauntReductionBest), 0.8f * num3 + 0.2f * num), 0f, 0.9f);
			px.TauntUntil = now + Mathf.Max(6f, Sv(_cfgTauntDuration)) * (1f + num4);
			px.NextReapply = now + 0.25f;
			px.SinceMs = WorldMs();
			px.ArtName = L("Taunt", "Таунт");
			px.TauntCount = ApplyTauntHold((Character)(object)p, px.TauntUntil, Sv(_cfgTauntRadius), px.SinceMs);
			try
			{
				PlayActivationEffects((Humanoid)(object)p, (item != null && item.m_shared != null) ? item.m_shared.m_blockEffect : null);
			}
			catch (Exception e)
			{
				Fail("proxy effects", e);
			}
			px.CooldownUntil = now + _cfgTauntCooldown.Value * _cfgProxyCooldownFactor.Value;
			px.ReadyAnnounced = false;
			Announce(L("Taunt for ", "Таунт за ") + px.Name + ": " + px.TauntCount + L(" monsters", " мобов"));
			return;
		}
		if (art == null)
		{
			Announce(px.Name + L(": no art for this weapon", ": нет активки для оружия"));
			return;
		}
		px.ArtName = art.Name;
		float num5 = Mathf.Clamp01(TotalDamage(item.GetDamage(quality, 0f)) / Mathf.Max(1f, Sv(_cfgRefWeaponDamage)));
		float num6 = PowerScale(num5, num);
		float p2 = 0.5f * num5 + 0.5f * num;
		if (art.Kind == ArtKind.AoEHeal)
		{
			int num7 = DoHeal(p, art, p2);
			Announce(art.Name + L(" for ", " за ") + px.Name + " (" + num7 + ")");
		}
		else if (art.Kind == ArtKind.AoEBurst)
		{
			int num8 = DoBurst(p, art, item, num6);
			Announce(art.Name + L(" for ", " за ") + px.Name + " (" + num8 + ")");
		}
		else
		{
			float num9 = ((art.Kind == ArtKind.DamageMult || art.Kind == ArtKind.Stagger) ? (1f + (Sv(art.Mag) - 1f) * num6) : (Sv(art.Mag) * num6));
			float num10 = Mathf.Clamp(num * Sv(_cfgSkillDurationScale) * (0.5f + 0.5f * num5), 0f, 0.5f);
			float num11 = Mathf.Max(6f, Sv(art.Win)) * (1f + num10);
			if (art.Shots != null)
			{
				num11 = Mathf.Min(num11, 10f);
			}
			if (art.Kind == ArtKind.Berserk)
			{
				px.BerserkUntil = now + num11;
				px.BerserkReduction = Mathf.Clamp(num9, 0f, 0.8f);
				px.BerserkRegen = ((art.Regen != null) ? Sv(art.Regen) : 0f);
				px.NextRegen = now + 1f;
				px.ArtHash = 0;
			}
			else
			{
				px.ArtHash = art.Hash;
				px.ArtPower = num9;
			}
			px.ArtUntil = now + num11;
			Announce(art.Name + L(" for ", " за ") + px.Name + ": " + num11.ToString("0") + L("s", "с"));
		}
		try
		{
			PlayArtEffects((Humanoid)(object)p, art);
		}
		catch (Exception e2)
		{
			Fail("proxy art effects", e2);
		}
		px.CooldownUntil = now + art.Cd.Value * _cfgProxyCooldownFactor.Value;
		px.ReadyAnnounced = false;
	}

	private void ReplyQuery(Player p, ZDO zdo, Proxy px)
	{
		bool taunt;
		ItemData item;
		int quality;
		Art art = ResolveProxyArt(zdo, out taunt, out item, out quality);
		string text = (taunt ? L("Taunt", "Таунт") : ((art != null) ? art.Name : L("no art", "нет активки")));
		string text2 = (taunt ? L("pull monsters + damage reduction", "стянуть мобов + резист") : ((art != null) ? art.Desc : ""));
		float time = Time.time;
		string text3 = ((time < px.TauntUntil || time < px.ArtUntil) ? L("active", "активна") : ((time < px.CooldownUntil) ? (L("cooldown ", "КД ") + Mathf.CeilToInt(px.CooldownUntil - time) + L("s", "с")) : L("ready", "готова")));
		Announce(px.Name + ": " + text + " — " + text3 + ((text2.Length > 0) ? (" (" + text2 + ")") : ""));
	}

	private void Announce(string text)
	{
		if (_cfgProxyAnnounce.Value && !((Object)(object)Chat.instance == (Object)null))
		{
			Chat.instance.SendText((Type)1, text);
		}
	}

	internal bool ProxyWindowArt(Character attacker, out int hash, out float power)
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		hash = 0;
		power = 0f;
		if ((Object)(object)attacker == (Object)null || _proxies.Count == 0)
		{
			return false;
		}
		if (!_proxies.TryGetValue(attacker.GetZDOID(), out var value) || value.ArtHash == 0 || Time.time >= value.ArtUntil)
		{
			return false;
		}
		hash = value.ArtHash;
		power = value.ArtPower;
		return true;
	}

	private void ReduceProxyHit(Character victim, HitData hit)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)victim == (Object)null || !victim.IsPlayer() || (Object)(object)victim == (Object)(object)Player.m_localPlayer || !_proxies.TryGetValue(victim.GetZDOID(), out var value))
		{
			return;
		}
		Character attacker = hit.GetAttacker();
		if ((Object)(object)attacker == (Object)null)
		{
			return;
		}
		if (Time.time < value.BerserkUntil && !attacker.IsPlayer() && value.BerserkReduction > 0f)
		{
			hit.ApplyModifier(1f - value.BerserkReduction);
		}
		if (!(Time.time >= value.TauntUntil) && _tainted.TryGetValue(attacker.GetZDOID(), out var value2) && !(value2.Target != value.Id) && !(Time.time >= value2.Until))
		{
			float num = Mathf.Clamp(value.TauntReduction, 0f, 0.9f);
			if (num > 0f)
			{
				hit.ApplyModifier(1f - num);
			}
		}
	}

	private void BindSyncConfig()
	{
		_cfgSync = ((BaseUnityPlugin)this).Config.Bind<bool>("10 Sync", "SyncConfig", true, "The server sends its balance settings to every client with the mod on connect and on change; the client uses them while connected. Off on the server: everyone uses their own file. No effect on a client. Proxy settings and local pacing are never synced.");
		((BaseUnityPlugin)this).Config.SettingChanged += delegate
		{
			_syncDirty = true;
		};
	}

	private static string CompKey(ConfigDefinition d)
	{
		return d.Section + "\u0001" + d.Key;
	}

	internal float Sv(ConfigEntry<float> e)
	{
		if (_serverSynced && _serverByKey.TryGetValue(CompKey(((ConfigEntryBase)e).Definition), out var value) && value is float)
		{
			return (float)value;
		}
		return e.Value;
	}

	internal bool Sb(ConfigEntry<bool> e)
	{
		if (_serverSynced && _serverByKey.TryGetValue(CompKey(((ConfigEntryBase)e).Definition), out var value) && value is bool)
		{
			return (bool)value;
		}
		return e.Value;
	}

	internal string Ss(ConfigEntry<string> e)
	{
		if (_serverSynced && _serverByKey.TryGetValue(CompKey(((ConfigEntryBase)e).Definition), out var value) && value is string)
		{
			return (string)value;
		}
		return e.Value;
	}

	private void RegisterRpc()
	{
		if (ZRoutedRpc.instance != null)
		{
			ZRoutedRpc.instance.Register<ZPackage>("j1ga.weaponarts.config", (Action<long, ZPackage>)OnConfigPacket);
		}
	}

	private void FlushSync()
	{
		_syncDirty = false;
		ZNet instance = ZNet.instance;
		if (!((Object)(object)instance == (Object)null) && instance.IsServer() && _cfgSync.Value && ZRoutedRpc.instance != null && instance.GetPeers().Count != 0)
		{
			SendConfig(0L);
			Debug("settings sent to " + instance.GetPeers().Count + " peers");
		}
	}

	private ZPackage BuildPacket()
	{
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Expected O, but got Unknown
		List<ConfigDefinition> list = new List<ConfigDefinition>();
		foreach (ConfigDefinition key in ((BaseUnityPlugin)this).Config.Keys)
		{
			if (key.Section == null || !key.Section.StartsWith("09 Proxy"))
			{
				ConfigEntryBase val = ((BaseUnityPlugin)this).Config[key];
				Type settingType = val.SettingType;
				if (settingType == typeof(float) || settingType == typeof(bool) || settingType == typeof(string))
				{
					list.Add(key);
				}
			}
		}
		ZPackage val2 = new ZPackage();
		val2.Write(1);
		val2.Write(list.Count);
		for (int i = 0; i < list.Count; i++)
		{
			ConfigDefinition val3 = list[i];
			ConfigEntryBase val4 = ((BaseUnityPlugin)this).Config[val3];
			Type settingType2 = val4.SettingType;
			int num = ((settingType2 == typeof(float)) ? 1 : ((settingType2 == typeof(bool)) ? 2 : 3));
			val2.Write(num);
			val2.Write(CompKey(val3));
			switch (num)
			{
			case 1:
				val2.Write((float)val4.BoxedValue);
				break;
			case 2:
				val2.Write((bool)val4.BoxedValue);
				break;
			default:
				val2.Write((string)(val4.BoxedValue ?? ""));
				break;
			}
		}
		return val2;
	}

	private void SendConfig(long target)
	{
		ZRoutedRpc.instance.InvokeRoutedRPC(target, "j1ga.weaponarts.config", new object[1] { BuildPacket() });
	}

	private void OnPeerInfo(ZNet znet, ZRpc rpc)
	{
		if (!znet.IsServer() || !_cfgSync.Value || rpc == null)
		{
			return;
		}
		foreach (ZNetPeer peer in znet.GetPeers())
		{
			if (peer != null && peer.m_rpc == rpc)
			{
				if (peer.m_uid != 0)
				{
					((MonoBehaviour)this).StartCoroutine(SendConfigLater(peer.m_uid));
				}
				break;
			}
		}
	}

	private IEnumerator SendConfigLater(long uid)
	{
		yield return (object)new WaitForSeconds(1f);
		ZNet znet = ZNet.instance;
		if ((Object)(object)znet == (Object)null || !znet.IsServer() || ZRoutedRpc.instance == null || !_cfgSync.Value)
		{
			yield break;
		}
		ZNetPeer peer = znet.GetPeer(uid);
		if (peer != null)
		{
			try
			{
				SendConfig(uid);
				Debug("settings sent to " + peer.m_playerName);
			}
			catch (Exception e)
			{
				Fail("send config", e);
			}
		}
	}

	private void OnConfigPacket(long sender, ZPackage pkg)
	{
		try
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null || instance.IsServer() || pkg == null)
			{
				return;
			}
			ZNetPeer serverPeer = instance.GetServerPeer();
			if (serverPeer == null || sender != serverPeer.m_uid)
			{
				return;
			}
			int num = pkg.ReadInt();
			if (num != 1)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Server config packet version " + num + " != " + 1 + "; using local settings."));
				return;
			}
			int num2 = pkg.ReadInt();
			if (num2 < 0 || num2 > 5000)
			{
				return;
			}
			Dictionary<string, object> dictionary = new Dictionary<string, object>();
			for (int i = 0; i < num2; i++)
			{
				int num3 = pkg.ReadInt();
				string key = pkg.ReadString();
				switch (num3)
				{
				case 1:
					dictionary[key] = pkg.ReadSingle();
					break;
				case 2:
					dictionary[key] = pkg.ReadBool();
					break;
				default:
					dictionary[key] = pkg.ReadString();
					break;
				}
			}
			_serverByKey.Clear();
			foreach (KeyValuePair<string, object> item in dictionary)
			{
				_serverByKey[item.Key] = item.Value;
			}
			_serverSynced = true;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Balance settings received from the server (" + dictionary.Count + " values)."));
		}
		catch (Exception e)
		{
			Fail("config packet", e);
		}
	}

	private void ClearServerValues()
	{
		_serverSynced = false;
		_serverByKey.Clear();
	}

	private static long WorldMs()
	{
		ZNet instance = ZNet.instance;
		if (!((Object)(object)instance != (Object)null))
		{
			ret