Decompiled source of SpecialAttack v1.2.5

SpecialAttackPlugin.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("SpecialAttackPlugin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SpecialAttackPlugin")]
[assembly: AssemblyTitle("SpecialAttackPlugin")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace SpecialAttackPlugin;

internal static class AdrenalineOnHit
{
	internal static void Grant(string techniqueName, Character attacker, Character target, float baseAmount)
	{
		if (Plugin.AdrenalineOnHitEnable.Value && !((Object)(object)attacker == (Object)null) && !((Object)(object)target == (Object)null) && !(baseAmount <= 0f) && (BaseAI.IsEnemy(attacker, target) || ((Object)(object)target.GetBaseAI() != (Object)null && target.GetBaseAI().IsAggravatable())))
		{
			float num = baseAmount * target.m_enemyAdrenalineMultiplier;
			if (!(num <= 0f))
			{
				attacker.AddAdrenaline(num);
			}
		}
	}
}
internal static class AftershockCooldown
{
	private sealed class State
	{
		public double ReadyAt;

		public float Duration;

		public Sprite Icon;
	}

	private static readonly ConditionalWeakTable<Character, State> _states = new ConditionalWeakTable<Character, State>();

	internal static bool IsOnCooldown(Character c)
	{
		if (!_states.TryGetValue(c, out var value))
		{
			return false;
		}
		double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble);
		return num < value.ReadyAt;
	}

	internal static bool TryConsume(Character c, float cooldown, Sprite icon = null)
	{
		if (cooldown <= 0f)
		{
			return true;
		}
		State value = _states.GetValue(c, (Character _) => new State());
		double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble);
		if (num < value.ReadyAt)
		{
			return false;
		}
		value.ReadyAt = num + (double)cooldown;
		value.Duration = cooldown;
		value.Icon = icon;
		return true;
	}

	internal static bool CollectEntry(Character c, out CooldownEntry entry)
	{
		entry = default(CooldownEntry);
		if (!_states.TryGetValue(c, out var value))
		{
			return false;
		}
		double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble);
		float num2 = (float)Math.Max(0.0, value.ReadyAt - num);
		if (num2 <= 0f)
		{
			return false;
		}
		entry = new CooldownEntry
		{
			Icon = value.Icon,
			Remaining = num2,
			Duration = value.Duration
		};
		return true;
	}
}
internal static class AftershockFilter
{
	internal static bool Matches(ItemData weapon)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Invalid comparison between Unknown and I4
		if (weapon?.m_shared == null)
		{
			return false;
		}
		SharedData shared = weapon.m_shared;
		if ((int)shared.m_itemType != 14)
		{
			return false;
		}
		string text = shared.m_secondaryAttack?.m_attackAnimation ?? "";
		if (text.IndexOf("sledge", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("slam", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return true;
		}
		string text2 = shared.m_name ?? "";
		if (text2.IndexOf("sledge", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return true;
		}
		string text3 = (((Object)(object)weapon.m_dropPrefab != (Object)null) ? ((Object)weapon.m_dropPrefab).name : "");
		return text3.StartsWith("SledgeGold", StringComparison.OrdinalIgnoreCase);
	}

	internal static bool HasNoSecondaryAnim(ItemData weapon)
	{
		return string.IsNullOrEmpty(weapon?.m_shared?.m_secondaryAttack?.m_attackAnimation);
	}
}
internal static class AftershockSystem
{
	private static readonly Collider[] _hitBuf = (Collider[])(object)new Collider[64];

	private static readonly HashSet<GameObject> _hitSet = new HashSet<GameObject>();

	private static int _maskChars;

	private static int _maskTerrain;

	private static bool _pending;

	private static Player _pendingPlayer;

	private static ItemData _pendingWeapon;

	private static Attack _pendingAttack;

	private static Vector3 _pendingForward;

	private static readonly string[] _waveVfxNames = new string[3] { "vfx_sledge_iron_hit", "sledge_aoe", "fx_goblinbrute_groundslam" };

	private static bool _vfxWarningLogged;

	private static readonly HashSet<string> _allowedVfxNames = new HashSet<string> { "Cloud", "vfx_troll_rock_destroyed", "waves" };

	private static int GetMaskChars()
	{
		if (_maskChars == 0)
		{
			_maskChars = LayerMask.GetMask(new string[9] { "character", "character_net", "character_ghost", "hitbox", "character_noenv", "vehicle", "piece", "piece_nonsolid", "Default" });
		}
		return _maskChars;
	}

	private static int GetMaskTerrain()
	{
		if (_maskTerrain == 0)
		{
			_maskTerrain = LayerMask.GetMask(new string[1] { "terrain" });
		}
		return _maskTerrain;
	}

	internal static bool TryInterceptSA(Humanoid humanoid)
	{
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Expected O, but got Unknown
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0238: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.AsEnable.Value)
		{
			return false;
		}
		ItemData currentWeapon = humanoid.GetCurrentWeapon();
		if (!AftershockFilter.Matches(currentWeapon))
		{
			return false;
		}
		if (!AftershockFilter.HasNoSecondaryAnim(currentWeapon))
		{
			return false;
		}
		Character val = (Character)humanoid;
		if (!val.IsOwner())
		{
			return false;
		}
		Player val2 = (Player)(object)((humanoid is Player) ? humanoid : null);
		if ((Object)(object)val2 == (Object)null)
		{
			return false;
		}
		if ((int)Plugin.SpecialKey.Value != 0 && !SpecialInput.Active)
		{
			return false;
		}
		if (Plugin.AsMinSkillLevel.Value > 0f && ((Character)val2).GetSkillLevel((SkillType)3) < Plugin.AsMinSkillLevel.Value)
		{
			return false;
		}
		if (AftershockCooldown.IsOnCooldown(val) || SkillLimitSystem.ShouldBlock(val, "Aftershock"))
		{
			return false;
		}
		Attack val3 = currentWeapon.m_shared?.m_secondaryAttack;
		float num = val3?.m_attackStamina ?? 0f;
		if (num > 0f && !val.HaveStamina(num))
		{
			return false;
		}
		float num2 = val3?.m_attackEitr ?? 0f;
		if (num2 > 0f && !val.HaveEitr(num2))
		{
			return false;
		}
		SharedData shared = currentWeapon.m_shared;
		Sprite icon = ((shared != null && shared.m_icons?.Length > 0) ? currentWeapon.m_shared.m_icons[0] : null);
		if (!AftershockCooldown.TryConsume(val, Plugin.AsCooldown.Value, icon))
		{
			return false;
		}
		if (num > 0f)
		{
			((Character)val2).UseStamina(num);
		}
		if (num2 > 0f)
		{
			((Character)val2).UseEitr(num2);
		}
		TriggerNow(val2, currentWeapon, null, ((Component)val).transform.forward);
		return true;
	}

	internal static void QueueTrigger(Humanoid humanoid, Attack attack)
	{
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Expected O, but got Unknown
		//IL_00df: 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)
		if (!Plugin.AsEnable.Value)
		{
			return;
		}
		ItemData currentWeapon = humanoid.GetCurrentWeapon();
		if (!AftershockFilter.Matches(currentWeapon) || AftershockFilter.HasNoSecondaryAnim(currentWeapon))
		{
			return;
		}
		Character val = (Character)humanoid;
		if (val.IsOwner())
		{
			Player val2 = (Player)(object)((humanoid is Player) ? humanoid : null);
			if (!((Object)(object)val2 == (Object)null) && (!(Plugin.AsMinSkillLevel.Value > 0f) || !(((Character)val2).GetSkillLevel((SkillType)3) < Plugin.AsMinSkillLevel.Value)) && !AftershockCooldown.IsOnCooldown(val) && !SkillLimitSystem.ShouldBlock(val, "Aftershock"))
			{
				_pending = true;
				_pendingPlayer = val2;
				_pendingWeapon = currentWeapon;
				_pendingAttack = attack;
				_pendingForward = ((Component)val).transform.forward;
			}
		}
	}

	internal static void ExecuteIfQueued(Humanoid humanoid)
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Expected O, but got Unknown
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		if (_pending && (object)humanoid == _pendingPlayer)
		{
			_pending = false;
			Character c = (Character)_pendingPlayer;
			float value = Plugin.AsCooldown.Value;
			SharedData shared = _pendingWeapon.m_shared;
			if (AftershockCooldown.TryConsume(c, value, (shared != null && shared.m_icons?.Length > 0) ? _pendingWeapon.m_shared.m_icons[0] : null))
			{
				TriggerNow(_pendingPlayer, _pendingWeapon, _pendingAttack, _pendingForward);
			}
		}
	}

	internal static int ComputeWaveCount(float skillLevel)
	{
		int result = 1;
		if (skillLevel >= Plugin.AsShockLevel2.Value)
		{
			result = 2;
		}
		if (skillLevel >= Plugin.AsShockLevel3.Value)
		{
			result = 3;
		}
		if (skillLevel >= Plugin.AsShockLevel4.Value)
		{
			result = 4;
		}
		if (skillLevel >= Plugin.AsShockLevel5.Value)
		{
			result = 5;
		}
		return result;
	}

	internal static Vector3 ComputeOrigin(Vector3 startPosition, Vector3 forward)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = ((((Vector3)(ref forward)).sqrMagnitude > 0.001f) ? ((Vector3)(ref forward)).normalized : Vector3.forward);
		Vector3 val2 = startPosition + val * Plugin.AsImpactOffset.Value;
		val2.y = GetGroundY(val2, startPosition.y) + 0.3f;
		return val2;
	}

	private static void TriggerNow(Player player, ItemData weapon, Attack attack, Vector3 forward)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		SaVfx.PlayAdrenaline1(((Component)player).transform.position);
		GameObject gameObject = ((Component)player).gameObject;
		AftershockController aftershockController = gameObject.AddComponent<AftershockController>();
		aftershockController.Initialize(player, weapon, attack, forward);
	}

	internal static void ApplyWave(Player player, ItemData weapon, Attack attack, int waveIndex, Vector3 origin, Vector3 facingDir)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Expected O, but got Unknown
		//IL_009c: 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_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_0194: Unknown result type (might be due to invalid IL or missing references)
		Character val = (Character)player;
		if ((Object)(object)val == (Object)null || val.IsDead())
		{
			return;
		}
		int num = waveIndex + 1;
		float num2 = Mathf.Clamp01((float)(num - 1) / 4f);
		float num3 = Mathf.Lerp(Plugin.AsScaleFirst.Value, Plugin.AsScaleLast.Value, num2);
		float dmgScale = Mathf.Lerp(Plugin.AsDamageFirst.Value, Plugin.AsDamageLast.Value, num2);
		float num4 = Plugin.AsRadius.Value * num3;
		float randomSkillFactor = val.GetRandomSkillFactor((SkillType)3);
		Quaternion rotation = ((((Vector3)(ref facingDir)).sqrMagnitude > 0.001f) ? Quaternion.LookRotation(facingDir) : Quaternion.identity);
		SpawnWaveVFX(weapon, attack, origin, rotation, num3);
		_hitSet.Clear();
		int num5 = Physics.OverlapSphereNonAlloc(origin, num4, _hitBuf, GetMaskChars(), (QueryTriggerInteraction)0);
		for (int i = 0; i < num5; i++)
		{
			Collider val2 = _hitBuf[i];
			if ((Object)(object)val2 == (Object)null)
			{
				continue;
			}
			GameObject val3 = Projectile.FindHitObject(val2);
			if ((Object)(object)val3 == (Object)null || !_hitSet.Add(val3))
			{
				continue;
			}
			Character componentInParent = val3.GetComponentInParent<Character>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				if (!componentInParent.IsPlayer() && componentInParent != val && !componentInParent.IsDead() && BaseAI.IsEnemy(val, componentInParent) && !componentInParent.InDodge() && !componentInParent.IsDebugFlying())
				{
					ApplyHit(val, componentInParent, weapon, attack, origin, dmgScale, randomSkillFactor);
				}
				continue;
			}
			IDestructible componentInParent2 = val3.GetComponentInParent<IDestructible>();
			if (componentInParent2 != null && !(componentInParent2 is Character))
			{
				ApplyDestructibleHit(val, componentInParent2, weapon, origin, dmgScale, randomSkillFactor);
			}
		}
	}

	private static void SpawnWaveVFX(ItemData weapon, Attack attack, Vector3 origin, Quaternion rotation, float scale)
	{
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)ZNetScene.instance != (Object)null)
		{
			string[] waveVfxNames = _waveVfxNames;
			foreach (string text in waveVfxNames)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(text);
				if (!((Object)(object)prefab == (Object)null))
				{
					GameObject val = Object.Instantiate<GameObject>(prefab, origin, rotation);
					val.transform.localScale = Vector3.one * scale;
					ScaleParticleSystems(val, scale);
					Aoe[] componentsInChildren = val.GetComponentsInChildren<Aoe>(true);
					foreach (Aoe val2 in componentsInChildren)
					{
						Object.Destroy((Object)(object)val2);
					}
					ApplyVfxToggles(val);
					return;
				}
			}
		}
		if (attack != null && attack.m_triggerEffect?.m_effectPrefabs?.Length > 0)
		{
			attack.m_triggerEffect.Create(origin, rotation, (Transform)null, scale, -1, default(ZDOID));
		}
		else if (!_vfxWarningLogged)
		{
			_vfxWarningLogged = true;
			Plugin.Log.LogWarning((object)"[AS VFX] NO VFX");
		}
	}

	private static void ApplyVfxToggles(GameObject obj)
	{
		ParticleSystem[] componentsInChildren = obj.GetComponentsInChildren<ParticleSystem>(true);
		foreach (ParticleSystem val in componentsInChildren)
		{
			((Component)val).gameObject.SetActive(_allowedVfxNames.Contains(((Object)((Component)val).gameObject).name));
		}
	}

	private static void ScaleParticleSystems(GameObject obj, float scale)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: 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)
		if (Mathf.Approximately(scale, 1f))
		{
			return;
		}
		ParticleSystem[] componentsInChildren = obj.GetComponentsInChildren<ParticleSystem>(true);
		foreach (ParticleSystem val in componentsInChildren)
		{
			MainModule main = val.main;
			if (((MainModule)(ref main)).startSize3D)
			{
				((MainModule)(ref main)).startSizeX = ScaleCurve(((MainModule)(ref main)).startSizeX, scale);
				((MainModule)(ref main)).startSizeY = ScaleCurve(((MainModule)(ref main)).startSizeY, scale);
				((MainModule)(ref main)).startSizeZ = ScaleCurve(((MainModule)(ref main)).startSizeZ, scale);
			}
			else
			{
				((MainModule)(ref main)).startSize = ScaleCurve(((MainModule)(ref main)).startSize, scale);
			}
			((MainModule)(ref main)).startSpeed = ScaleCurve(((MainModule)(ref main)).startSpeed, scale);
			ShapeModule shape = val.shape;
			if (((ShapeModule)(ref shape)).enabled)
			{
				((ShapeModule)(ref shape)).radius = ((ShapeModule)(ref shape)).radius * scale;
				((ShapeModule)(ref shape)).scale = ((ShapeModule)(ref shape)).scale * scale;
				((ShapeModule)(ref shape)).position = ((ShapeModule)(ref shape)).position * scale;
			}
			TrailModule trails = val.trails;
			if (((TrailModule)(ref trails)).enabled)
			{
				((TrailModule)(ref trails)).widthOverTrail = ScaleCurve(((TrailModule)(ref trails)).widthOverTrail, scale);
			}
			ParticleSystemRenderer component = ((Component)val).GetComponent<ParticleSystemRenderer>();
			if ((Object)(object)component != (Object)null)
			{
				component.lengthScale *= scale;
				component.velocityScale *= scale;
			}
		}
	}

	private static MinMaxCurve ScaleCurve(MinMaxCurve curve, float scale)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: 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_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected I4, but got Unknown
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		ParticleSystemCurveMode mode = ((MinMaxCurve)(ref curve)).mode;
		ParticleSystemCurveMode val = mode;
		switch ((int)val)
		{
		case 0:
			((MinMaxCurve)(ref curve)).constant = ((MinMaxCurve)(ref curve)).constant * scale;
			break;
		case 3:
			((MinMaxCurve)(ref curve)).constantMin = ((MinMaxCurve)(ref curve)).constantMin * scale;
			((MinMaxCurve)(ref curve)).constantMax = ((MinMaxCurve)(ref curve)).constantMax * scale;
			break;
		case 1:
		case 2:
			((MinMaxCurve)(ref curve)).curveMultiplier = ((MinMaxCurve)(ref curve)).curveMultiplier * scale;
			break;
		}
		return curve;
	}

	private static float GetGroundY(Vector3 pos, float fallback)
	{
		//IL_0001: 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_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		RaycastHit val = default(RaycastHit);
		if (Physics.Raycast(new Vector3(pos.x, pos.y + 10f, pos.z), Vector3.down, ref val, 25f, GetMaskTerrain(), (QueryTriggerInteraction)1))
		{
			return ((RaycastHit)(ref val)).point.y;
		}
		return fallback;
	}

	private static void ApplyHit(Character attacker, Character target, ItemData weapon, Attack attack, Vector3 origin, float dmgScale, float skillFactor)
	{
		//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)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Expected O, but got Unknown
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: 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_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
		DamageTypes damage = weapon.GetDamage();
		((DamageTypes)(ref damage)).Modify(dmgScale * skillFactor);
		HitData val = new HitData();
		val.m_damage = damage;
		val.m_skill = (SkillType)3;
		val.m_pushForce = weapon.m_shared.m_attackForce;
		val.m_staggerMultiplier = attack?.m_staggerMultiplier ?? 1f;
		val.m_blockable = false;
		val.m_dodgeable = false;
		val.m_skillRaiseAmount = 0f;
		val.m_point = target.GetCenterPoint();
		Vector3 val2 = target.GetCenterPoint() - origin;
		val2.y = 0f;
		val.m_dir = ((((Vector3)(ref val2)).sqrMagnitude > 0.001f) ? ((Vector3)(ref val2)).normalized : ((Component)attacker).transform.forward);
		val.SetAttacker(attacker);
		target.Damage(val);
		AdrenalineOnHit.Grant("Aftershock", attacker, target, attack?.m_attackAdrenaline ?? 0f);
	}

	private static void ApplyDestructibleHit(Character attacker, IDestructible target, ItemData weapon, Vector3 origin, float dmgScale, float skillFactor)
	{
		//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)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Expected O, but got Unknown
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: 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_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: 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_00ad: Unknown result type (might be due to invalid IL or missing references)
		DamageTypes damage = weapon.GetDamage();
		((DamageTypes)(ref damage)).Modify(dmgScale * skillFactor);
		HitData val = new HitData();
		val.m_damage = damage;
		val.m_skill = (SkillType)3;
		val.m_pushForce = 0f;
		val.m_blockable = false;
		val.m_dodgeable = false;
		val.m_skillRaiseAmount = 0f;
		Component val2 = (Component)(object)((target is Component) ? target : null);
		val.m_point = (((Object)(object)val2 != (Object)null) ? val2.transform.position : origin);
		Vector3 val3 = val.m_point - origin;
		val3.y = 0f;
		val.m_dir = ((((Vector3)(ref val3)).sqrMagnitude > 0.001f) ? ((Vector3)(ref val3)).normalized : ((Component)attacker).transform.forward);
		val.SetAttacker(attacker);
		target.Damage(val);
	}
}
internal sealed class AftershockController : MonoBehaviour
{
	private Player _player;

	private ItemData _weapon;

	private Attack _attack;

	private Vector3 _forwardDir;

	private Vector3 _origin;

	private int _nextWave;

	private float _nextWaveTime;

	private int _totalWaves;

	internal void Initialize(Player player, ItemData weapon, Attack attack, Vector3 attackForward)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Expected O, but got Unknown
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		_player = player;
		_weapon = weapon;
		_attack = attack;
		_forwardDir = ((((Vector3)(ref attackForward)).sqrMagnitude > 0.001f) ? ((Vector3)(ref attackForward)).normalized : Vector3.forward);
		Character val = (Character)player;
		_origin = AftershockSystem.ComputeOrigin(((Component)val).transform.position, _forwardDir);
		float level = SkillLevelResolver.GetLevel(player, weapon, (SkillType)3);
		_totalWaves = AftershockSystem.ComputeWaveCount(level);
		_nextWave = 0;
		_nextWaveTime = Time.time;
		((Behaviour)this).enabled = true;
	}

	private void Update()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_player == (Object)null || ((Character)_player).IsDead())
		{
			Object.Destroy((Object)(object)this);
			return;
		}
		while (_nextWave < _totalWaves && Time.time >= _nextWaveTime)
		{
			AftershockSystem.ApplyWave(_player, _weapon, _attack, _nextWave, _origin, _forwardDir);
			_nextWave++;
			float num = Mathf.Max(0f, Plugin.AsShockInterval.Value);
			_nextWaveTime += num;
			if (num > 0f)
			{
				break;
			}
		}
		if (_nextWave >= _totalWaves)
		{
			Object.Destroy((Object)(object)this);
		}
	}
}
internal sealed class ArrowEmbedTracker : MonoBehaviour
{
	private Character _ch;

	private bool _recovered;

	private readonly List<GameObject> _visuals = new List<GameObject>();

	private readonly Dictionary<Player, int> _hitCounts = new Dictionary<Player, int>();

	private readonly Dictionary<Player, ItemData> _hitAmmoSample = new Dictionary<Player, ItemData>();

	private void Awake()
	{
		_ch = ((Component)this).GetComponent<Character>();
	}

	internal void AddVisual(GameObject go)
	{
		if ((Object)(object)go == (Object)null)
		{
			return;
		}
		_visuals.Add(go);
		int num = Mathf.Max(1, Plugin.ArEmbedMax.Value);
		while (_visuals.Count > num)
		{
			GameObject val = _visuals[0];
			_visuals.RemoveAt(0);
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)val);
			}
		}
	}

	internal void RegisterHit(Player player, ItemData ammo)
	{
		if (!((Object)(object)player == (Object)null))
		{
			_hitCounts.TryGetValue(player, out var value);
			_hitCounts[player] = value + 1;
			if (ammo != null)
			{
				_hitAmmoSample[player] = ammo;
			}
		}
	}

	internal void TryRecover()
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: 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)
		if (_recovered)
		{
			return;
		}
		_recovered = true;
		Vector3 position = ((Component)this).transform.position;
		foreach (KeyValuePair<Player, int> hitCount in _hitCounts)
		{
			Player key = hitCount.Key;
			int value = hitCount.Value;
			if ((Object)(object)key == (Object)null || value <= 0)
			{
				continue;
			}
			float skillLevel = ((Character)key).GetSkillLevel((SkillType)8);
			float num = Mathf.Clamp01(skillLevel / 100f);
			float num2 = Mathf.Lerp(Plugin.ArRecoverChancePercentLv0.Value, Plugin.ArRecoverChancePercentLv100.Value, num);
			float num3 = Mathf.Clamp01(num2 / 100f);
			_hitAmmoSample.TryGetValue(key, out var value2);
			for (int i = 0; i < value; i++)
			{
				if (Random.value <= num3)
				{
					ArrowEmbedSystem.SpawnArrowItem(value2, position);
				}
			}
		}
	}

	private void OnDestroy()
	{
		foreach (GameObject visual in _visuals)
		{
			if ((Object)(object)visual != (Object)null)
			{
				Object.Destroy((Object)(object)visual);
			}
		}
		_visuals.Clear();
	}
}
internal static class ArrowEmbedSystem
{
	internal static void OnProjectileHit(Projectile proj, Collider collider, Vector3 hitPoint, bool water)
	{
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
		if (water || (Object)(object)proj == (Object)null || (Object)(object)collider == (Object)null)
		{
			return;
		}
		ItemData weapon = ProjectileAccess.GetWeapon(proj);
		if (!HuntersVolleyFilter.Matches(weapon))
		{
			return;
		}
		Character owner = ProjectileAccess.GetOwner(proj);
		Player val = (Player)(object)((owner is Player) ? owner : null);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		ItemData ammo = ProjectileAccess.GetAmmo(proj);
		GameObject val2 = Projectile.FindHitObject(collider);
		Character val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponentInParent<Character>() : null);
		if ((Object)(object)val3 != (Object)null)
		{
			ArrowEmbedTracker arrowEmbedTracker = ((Component)val3).gameObject.GetComponent<ArrowEmbedTracker>();
			if ((Object)(object)arrowEmbedTracker == (Object)null)
			{
				arrowEmbedTracker = ((Component)val3).gameObject.AddComponent<ArrowEmbedTracker>();
			}
			arrowEmbedTracker.RegisterHit(val, ammo);
			if (Plugin.ArEmbedEnable.Value)
			{
				GameObject val4 = CreateArrowVisual(proj, hitPoint, val3);
				if ((Object)(object)val4 != (Object)null)
				{
					arrowEmbedTracker.AddVisual(val4);
				}
			}
			return;
		}
		float skillLevel = ((Character)val).GetSkillLevel((SkillType)8);
		float num = Mathf.Clamp01(skillLevel / 100f);
		float num2 = Mathf.Lerp(Plugin.ArMissRecoverChancePercentLv0.Value, Plugin.ArMissRecoverChancePercentLv100.Value, num);
		float num3 = Mathf.Clamp01(num2 / 100f);
		if (!(Random.value <= num3))
		{
			return;
		}
		if ((Object)(object)proj != (Object)null && (Object)(object)((Component)proj).gameObject != (Object)null)
		{
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				ZNetScene.instance.Destroy(((Component)proj).gameObject);
			}
			else
			{
				Object.Destroy((Object)(object)((Component)proj).gameObject);
			}
		}
		SpawnArrowItem(ammo, hitPoint);
	}

	internal static bool SpawnArrowItem(ItemData ammo, Vector3 pos)
	{
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)ammo?.m_dropPrefab == (Object)null || (Object)(object)ZNetScene.instance == (Object)null)
		{
			return false;
		}
		try
		{
			GameObject prefab = ZNetScene.instance.GetPrefab(((Object)ammo.m_dropPrefab).name);
			if ((Object)(object)prefab == (Object)null)
			{
				return false;
			}
			GameObject val = Object.Instantiate<GameObject>(prefab, pos + Vector3.up * 0.1f, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f));
			ItemDrop component = val.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			component.m_itemData.m_stack = 1;
			component.m_itemData.m_quality = ammo.m_quality;
			return true;
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("[AR] 화살 드롭 실패: " + ex.Message));
			return false;
		}
	}

	private static GameObject CreateArrowVisual(Projectile proj, Vector3 hitPoint, Character target)
	{
		//IL_0028: 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_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: 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_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		GameObject visualChild = GetVisualChild(((Component)proj).gameObject);
		if ((Object)(object)visualChild == (Object)null)
		{
			return null;
		}
		Vector3 forward = ((Component)proj).transform.forward;
		Vector3 val;
		if (!(((Vector3)(ref forward)).sqrMagnitude > 0.01f))
		{
			val = Vector3.forward;
		}
		else
		{
			forward = ((Component)proj).transform.forward;
			val = ((Vector3)(ref forward)).normalized;
		}
		Vector3 val2 = val;
		Vector3 val3 = hitPoint + val2 * Mathf.Max(0f, Plugin.ArEmbedDepth.Value);
		GameObject val4 = Object.Instantiate<GameObject>(visualChild, val3, ((Component)proj).transform.rotation);
		Collider[] componentsInChildren = val4.GetComponentsInChildren<Collider>(true);
		foreach (Collider val5 in componentsInChildren)
		{
			val5.enabled = false;
		}
		WeaponBoneAttach.Attach(val4, target, hitPoint, ((Component)target).transform);
		return val4;
	}

	private static GameObject GetVisualChild(GameObject prefab)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		foreach (Transform item in prefab.transform)
		{
			Transform val = item;
			if ((Object)(object)((Component)val).GetComponentInChildren<Renderer>(true) != (Object)null)
			{
				return ((Component)val).gameObject;
			}
		}
		Renderer componentInChildren = prefab.GetComponentInChildren<Renderer>(true);
		return ((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).gameObject : null;
	}
}
[HarmonyPatch(typeof(Projectile), "OnHit")]
internal static class Patch_ProjectileOnHit_ArrowEmbed
{
	private static void Postfix(Projectile __instance, Collider collider, Vector3 hitPoint, bool water)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		ArrowEmbedSystem.OnProjectileHit(__instance, collider, hitPoint, water);
	}
}
[HarmonyPatch(typeof(Character), "OnDeath")]
internal static class Patch_CharacterOnDeath_ArrowEmbed
{
	private static void Prefix(Character __instance)
	{
		((Component)__instance).GetComponent<ArrowEmbedTracker>()?.TryRecover();
	}
}
internal static class QuadSlashCooldown
{
	private sealed class State
	{
		public double ReadyAt;

		public float Duration;

		public Sprite Icon;
	}

	private static readonly ConditionalWeakTable<Character, State> _states = new ConditionalWeakTable<Character, State>();

	internal static bool IsOnCooldown(Character c)
	{
		if (!_states.TryGetValue(c, out var value))
		{
			return false;
		}
		double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble);
		return num < value.ReadyAt;
	}

	internal static bool TryConsume(Character c, float cooldown, Sprite icon = null)
	{
		if (cooldown <= 0f)
		{
			return true;
		}
		State value = _states.GetValue(c, (Character _) => new State());
		double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble);
		if (num < value.ReadyAt)
		{
			return false;
		}
		value.ReadyAt = num + (double)cooldown;
		value.Duration = cooldown;
		value.Icon = icon;
		return true;
	}

	internal static bool CollectEntry(Character c, out CooldownEntry entry)
	{
		entry = default(CooldownEntry);
		if (!_states.TryGetValue(c, out var value))
		{
			return false;
		}
		double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble);
		float num2 = (float)Math.Max(0.0, value.ReadyAt - num);
		if (num2 <= 0f)
		{
			return false;
		}
		entry = new CooldownEntry
		{
			Icon = value.Icon,
			Remaining = num2,
			Duration = value.Duration
		};
		return true;
	}
}
internal static class QuadSlashFilter
{
	internal static bool Matches(ItemData weapon)
	{
		if (weapon?.m_shared == null || (Object)(object)weapon.m_dropPrefab == (Object)null)
		{
			return false;
		}
		string name = ((Object)weapon.m_dropPrefab).name;
		return name.Equals("THSwordKrom", StringComparison.OrdinalIgnoreCase) || name.IndexOf("claymore", StringComparison.OrdinalIgnoreCase) >= 0 || name.StartsWith("THSwordGold", StringComparison.OrdinalIgnoreCase) || name.Equals("THSwordWood", StringComparison.OrdinalIgnoreCase) || name.StartsWith("THSwordSlayer", StringComparison.OrdinalIgnoreCase);
	}
}
internal static class QuadSlashVfx
{
	private static Material _trailMat;

	private static bool _searched;

	private static readonly FieldInfo _trailMatField = AccessTools.Field(typeof(MeleeWeaponTrail), "m_trailMaterial") ?? AccessTools.Field(typeof(MeleeWeaponTrail), "m_material") ?? AccessTools.Field(typeof(MeleeWeaponTrail), "_material");

	private static readonly FieldInfo _rightItemField = AccessTools.Field(typeof(VisEquipment), "m_rightItemInstance");

	internal static Material GetDvergrMat()
	{
		if (_searched)
		{
			return _trailMat;
		}
		_searched = true;
		ZNetScene instance = ZNetScene.instance;
		GameObject val = ((instance != null) ? instance.GetPrefab("BattleaxeDvergr_TW") : null);
		if ((Object)(object)val == (Object)null)
		{
			Plugin.Log.LogWarning((object)"[QS-VFX] BattleaxeDvergr_TW 프리팹 없음");
			return null;
		}
		MeleeWeaponTrail[] componentsInChildren = val.GetComponentsInChildren<MeleeWeaponTrail>(true);
		foreach (MeleeWeaponTrail val2 in componentsInChildren)
		{
			if (_trailMatField != null)
			{
				object? value = _trailMatField.GetValue(val2);
				Material val3 = (Material)((value is Material) ? value : null);
				if ((Object)(object)val3 != (Object)null)
				{
					_trailMat = val3;
					return _trailMat;
				}
			}
			Renderer val4 = ((Component)val2).GetComponent<Renderer>() ?? ((Component)val2).GetComponentInChildren<Renderer>(true);
			if ((Object)(object)((val4 != null) ? val4.sharedMaterial : null) != (Object)null)
			{
				_trailMat = val4.sharedMaterial;
				return _trailMat;
			}
		}
		Plugin.Log.LogWarning((object)"[QS-VFX] Dvergr trail 머티리얼 접근 실패 — VFX 생략");
		return null;
	}

	internal static void Apply(Humanoid humanoid, out Material[] saved, out Renderer[] renderers)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		saved = null;
		renderers = null;
		Material dvergrMat = GetDvergrMat();
		if ((Object)(object)dvergrMat == (Object)null)
		{
			return;
		}
		VisEquipment component = ((Component)humanoid).GetComponent<VisEquipment>();
		if ((Object)(object)component == (Object)null)
		{
			return;
		}
		object? obj = _rightItemField?.GetValue(component);
		GameObject val = (GameObject)((obj is GameObject) ? obj : null);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		MeleeWeaponTrail[] componentsInChildren = val.GetComponentsInChildren<MeleeWeaponTrail>(true);
		if (componentsInChildren.Length == 0)
		{
			Plugin.Log.LogWarning((object)"[QS-VFX] 무기 모델에 MeleeWeaponTrail 없음");
			return;
		}
		List<Material> list = new List<Material>();
		List<Renderer> list2 = new List<Renderer>();
		MeleeWeaponTrail[] array = componentsInChildren;
		foreach (MeleeWeaponTrail val2 in array)
		{
			if (_trailMatField != null)
			{
				object? value = _trailMatField.GetValue(val2);
				Material val3 = (Material)((value is Material) ? value : null);
				if ((Object)(object)val3 != (Object)null)
				{
					_trailMatField.SetValue(val2, dvergrMat);
					list.Add(val3);
					list2.Add(null);
					continue;
				}
			}
			Renderer component2 = ((Component)val2).GetComponent<Renderer>();
			if (!((Object)(object)component2 == (Object)null))
			{
				list.Add(component2.sharedMaterial);
				list2.Add(component2);
				component2.sharedMaterial = dvergrMat;
			}
		}
		saved = list.ToArray();
		renderers = list2.ToArray();
	}

	internal static void Restore(Material[] saved, Renderer[] renderers)
	{
		if (saved == null || renderers == null)
		{
			return;
		}
		int num = Math.Min(saved.Length, renderers.Length);
		for (int i = 0; i < num; i++)
		{
			if ((Object)(object)renderers[i] != (Object)null)
			{
				renderers[i].sharedMaterial = saved[i];
			}
			else if (!((Object)(object)saved[i] != (Object)null))
			{
			}
		}
	}
}
internal static class QuadSlashSystem
{
	internal static bool TryInterceptSA(Humanoid humanoid)
	{
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Expected O, but got Unknown
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.QsEnable.Value)
		{
			return false;
		}
		ItemData currentWeapon = humanoid.GetCurrentWeapon();
		if (!QuadSlashFilter.Matches(currentWeapon))
		{
			return false;
		}
		Character val = (Character)humanoid;
		if (!val.IsOwner())
		{
			return false;
		}
		Player val2 = (Player)(object)((humanoid is Player) ? humanoid : null);
		if (val2 == null)
		{
			return false;
		}
		if ((int)Plugin.SpecialKey.Value != 0 && !SpecialInput.Active)
		{
			return false;
		}
		if (Plugin.QsMinSkillLevel.Value > 0f && ((Character)val2).GetSkillLevel((SkillType)1) < Plugin.QsMinSkillLevel.Value)
		{
			return false;
		}
		if (QuadSlashCooldown.IsOnCooldown(val) || SkillLimitSystem.ShouldBlock(val, "QuadSlash"))
		{
			return false;
		}
		Attack val3 = currentWeapon.m_shared?.m_secondaryAttack;
		float num = val3?.m_attackStamina ?? 0f;
		if (num > 0f && !val.HaveStamina(num))
		{
			return false;
		}
		float num2 = val3?.m_attackEitr ?? 0f;
		if (num2 > 0f && !val.HaveEitr(num2))
		{
			return false;
		}
		SharedData shared = currentWeapon.m_shared;
		Sprite icon = ((shared != null && shared.m_icons?.Length > 0) ? currentWeapon.m_shared.m_icons[0] : null);
		if (!QuadSlashCooldown.TryConsume(val, Plugin.QsCooldown.Value, icon))
		{
			return false;
		}
		SaVfx.PlayAdrenaline1(((Component)val2).transform.position);
		QuadSlashController.Begin(humanoid, currentWeapon, ComputeAllowedHits(val2, currentWeapon));
		return true;
	}

	private static int ComputeAllowedHits(Player player, ItemData weapon)
	{
		float level = SkillLevelResolver.GetLevel(player, weapon, (SkillType)1);
		if (level >= Plugin.QsHitLevel4.Value)
		{
			return 4;
		}
		if (level >= Plugin.QsHitLevel3.Value)
		{
			return 3;
		}
		if (level >= Plugin.QsHitLevel2.Value)
		{
			return 2;
		}
		return 1;
	}

	internal static void ExecuteIfQueued(Humanoid humanoid)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		QuadSlashController component = ((Component)humanoid).GetComponent<QuadSlashController>();
		if ((Object)(object)component != (Object)null && component.IsActive)
		{
			component.OnAttackTriggered();
		}
	}
}
internal sealed class QuadSlashController : MonoBehaviour
{
	private static readonly FieldInfo _fChainLevels = AccessTools.Field(typeof(Attack), "m_attackChainLevels");

	private static readonly FieldInfo _fCurrentLevel = AccessTools.Field(typeof(Attack), "m_currentAttackCainLevel");

	private static readonly FieldInfo _fAnimBase = AccessTools.Field(typeof(Attack), "m_attackAnimation");

	private static readonly FieldInfo _fZsyncAnimator = AccessTools.Field(typeof(ZSyncAnimation), "m_animator");

	private static readonly FieldInfo _fAnimChain = AccessTools.Field(typeof(CharacterAnimEvent), "m_chain");

	private Humanoid _humanoid;

	private ItemData _weapon;

	private Animator _animator;

	private CharacterAnimEvent _animEvent;

	private float _savedAnimSpeed;

	private int _hitsLeft;

	private int _currentHit;

	internal bool IsFiringNext;

	private Material[] _savedTrailMats;

	private Renderer[] _trailRenderers;

	private static string _cachedBattleaxeTrigger;

	private static bool _battleaxeTriggerSearched;

	internal bool IsActive => _hitsLeft > 0;

	internal int CurrentHit => _currentHit;

	internal static QuadSlashController Begin(Humanoid humanoid, ItemData weapon, int maxHits)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		GameObject gameObject = ((Component)humanoid).gameObject;
		QuadSlashController component = gameObject.GetComponent<QuadSlashController>();
		if ((Object)(object)component != (Object)null)
		{
			((MonoBehaviour)component).StopAllCoroutines();
			component.ForceCleanup();
		}
		QuadSlashController quadSlashController = component ?? gameObject.AddComponent<QuadSlashController>();
		quadSlashController.Setup(humanoid, weapon, maxHits);
		return quadSlashController;
	}

	private void Setup(Humanoid humanoid, ItemData weapon, int maxHits)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		_humanoid = humanoid;
		_weapon = weapon;
		_hitsLeft = Mathf.Clamp(maxHits, 1, 4);
		_currentHit = 0;
		ZSyncAnimation componentInChildren = ((Component)humanoid).GetComponentInChildren<ZSyncAnimation>();
		_animator = (Animator)((_fZsyncAnimator != null && (Object)(object)componentInChildren != (Object)null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)((Component)humanoid).GetComponentInChildren<Animator>()));
		_animEvent = ((Component)humanoid).GetComponentInChildren<CharacterAnimEvent>();
		if ((Object)(object)_animator != (Object)null)
		{
			_savedAnimSpeed = _animator.speed;
			_animator.speed = GetSpeed(0);
		}
		QuadSlashVfx.Apply(humanoid, out _savedTrailMats, out _trailRenderers);
		((MonoBehaviour)this).StartCoroutine(FireFirstPA());
	}

	private float GetSpeed(int hit)
	{
		if (1 == 0)
		{
		}
		float result = hit switch
		{
			0 => Plugin.QsAnimSpeed1.Value, 
			1 => Plugin.QsAnimSpeed2.Value, 
			2 => Plugin.QsAnimSpeed3.Value, 
			_ => Plugin.QsAnimSpeed4.Value, 
		};
		if (1 == 0)
		{
		}
		return result;
	}

	private IEnumerator FireFirstPA()
	{
		yield return null;
		if ((Object)(object)_humanoid != (Object)null && _hitsLeft > 0)
		{
			((Character)_humanoid).StartAttack((Character)null, false);
		}
	}

	internal void OnAttackTriggered()
	{
		if (_hitsLeft <= 0)
		{
			return;
		}
		_hitsLeft--;
		_currentHit++;
		if (_hitsLeft > 0)
		{
			float speed = GetSpeed(_currentHit);
			if ((Object)(object)_animator != (Object)null)
			{
				_animator.speed = speed;
			}
			((MonoBehaviour)this).StartCoroutine(FireNextPA());
		}
		else
		{
			Finish();
		}
	}

	private IEnumerator FireNextPA()
	{
		Character ch = (Character)_humanoid;
		float timeout = Time.time + 2f;
		while ((Object)(object)ch != (Object)null && !ch.IsDead() && Time.time < timeout)
		{
			if (!ch.InAttack())
			{
				if ((Object)(object)_humanoid != (Object)null && _hitsLeft > 0)
				{
					ch.StartAttack((Character)null, false);
				}
				break;
			}
			if ((Object)(object)_animEvent != (Object)null && _fAnimChain != null && (bool)_fAnimChain.GetValue(_animEvent) && (Object)(object)_humanoid != (Object)null && _hitsLeft > 0)
			{
				IsFiringNext = true;
				ch.StartAttack((Character)null, false);
				IsFiringNext = false;
				break;
			}
			yield return null;
		}
	}

	internal void InjectAnimOverride(Attack attack, ref float timeSinceLastAttack)
	{
		timeSinceLastAttack = 0f;
	}

	internal void OverrideAnimTrigger(Attack attack)
	{
		if ((Object)(object)_animator == (Object)null)
		{
			return;
		}
		string text = ((_fAnimBase != null) ? ((string)_fAnimBase.GetValue(attack)) : attack.m_attackAnimation);
		int num = ((_fChainLevels != null) ? ((int)_fChainLevels.GetValue(attack)) : 0);
		int num2 = ((_fCurrentLevel != null) ? ((int)_fCurrentLevel.GetValue(attack)) : 0);
		if (string.IsNullOrEmpty(text))
		{
			return;
		}
		string text2 = ((num > 1) ? (text + num2) : text);
		string text3;
		if (_currentHit == 3)
		{
			text3 = GetBattleaxeLastTrigger() ?? (text + ((num > 1) ? (num - 1).ToString() : ""));
		}
		else
		{
			if (num <= 1)
			{
				Plugin.Log.LogWarning((object)$"[QS-Anim] chainLevels={num} ≤ 1, 애니메이션 순서 제어 불가 (베기 {_currentHit + 1})");
				return;
			}
			int currentHit = _currentHit;
			if (1 == 0)
			{
			}
			int num3 = currentHit switch
			{
				0 => Mathf.Min(1, num - 1), 
				1 => 0, 
				2 => Mathf.Min(1, num - 1), 
				_ => num - 1, 
			};
			if (1 == 0)
			{
			}
			int num4 = num3;
			text3 = text + num4;
		}
		if (!(text2 == text3))
		{
			_animator.ResetTrigger(text2);
			_animator.SetTrigger(text3);
		}
	}

	private static string GetBattleaxeLastTrigger()
	{
		if (_battleaxeTriggerSearched)
		{
			return _cachedBattleaxeTrigger;
		}
		ZNetScene instance = ZNetScene.instance;
		GameObject val = ((instance != null) ? instance.GetPrefab("BattleaxeDvergr_TW") : null);
		if ((Object)(object)val == (Object)null)
		{
			return null;
		}
		_battleaxeTriggerSearched = true;
		Attack val2 = ((val != null) ? val.GetComponent<ItemDrop>() : null)?.m_itemData?.m_shared?.m_attack;
		if (val2 == null || string.IsNullOrEmpty(val2.m_attackAnimation))
		{
			Plugin.Log.LogWarning((object)"[QS-Anim] BattleaxeDvergr_TW m_attack 미발견 — 배틀액스 AA4 스킵");
			return null;
		}
		int num = ((_fChainLevels != null) ? ((int)_fChainLevels.GetValue(val2)) : 0);
		string text = ((_fAnimBase != null) ? ((string)_fAnimBase.GetValue(val2)) : val2.m_attackAnimation);
		_cachedBattleaxeTrigger = ((num > 1) ? (text + (num - 1)) : text);
		return _cachedBattleaxeTrigger;
	}

	internal void RestoreAnimOverride()
	{
	}

	private void Update()
	{
		if (IsActive && !((Object)(object)_animator == (Object)null))
		{
			_animator.speed = GetSpeed(_currentHit);
		}
	}

	private void Finish()
	{
		ForceCleanup();
		Object.Destroy((Object)(object)this);
	}

	private void OnDestroy()
	{
		ForceCleanup();
	}

	internal void ForceCleanup()
	{
		IsFiringNext = false;
		RestoreAnimSpeed();
		RestoreAnimOverride();
		QuadSlashVfx.Restore(_savedTrailMats, _trailRenderers);
		_savedTrailMats = null;
		_trailRenderers = null;
	}

	internal void RestoreAnimSpeed()
	{
		if ((Object)(object)_animator != (Object)null && _savedAnimSpeed > 0f)
		{
			_animator.speed = _savedAnimSpeed;
		}
	}

	internal float GetCurrentSpeed()
	{
		return GetSpeed(_currentHit);
	}
}
internal static class QuadSlash_CharAnimHelper
{
	internal static readonly FieldInfo FAnimator = AccessTools.Field(typeof(CharacterAnimEvent), "m_animator");

	internal static void RestoreSpeed(CharacterAnimEvent instance)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Expected O, but got Unknown
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || (Object)(object)((Component)instance).GetComponentInParent<Character>() != (Object)(Character)localPlayer)
		{
			return;
		}
		QuadSlashController component = ((Component)localPlayer).GetComponent<QuadSlashController>();
		if (!((Object)(object)component == (Object)null) && component.IsActive)
		{
			object? obj = FAnimator?.GetValue(instance);
			Animator val = (Animator)((obj is Animator) ? obj : null);
			if ((Object)(object)val != (Object)null)
			{
				val.speed = component.GetCurrentSpeed();
			}
		}
	}
}
[HarmonyPatch(typeof(CharacterAnimEvent), "CustomFixedUpdate")]
internal static class QuadSlash_Patch_CharAnimFixedUpdate
{
	private static void Postfix(CharacterAnimEvent __instance)
	{
		QuadSlash_CharAnimHelper.RestoreSpeed(__instance);
	}
}
[HarmonyPatch(typeof(CharacterAnimEvent), "Speed")]
internal static class QuadSlash_Patch_CharAnimSpeed
{
	private static void Postfix(CharacterAnimEvent __instance)
	{
		QuadSlash_CharAnimHelper.RestoreSpeed(__instance);
	}
}
[HarmonyPatch(typeof(Player), "HaveQueuedChain")]
internal static class QuadSlash_Patch_HaveQueuedChain
{
	private static void Postfix(Player __instance, ref bool __result)
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		if (!__result)
		{
			QuadSlashController component = ((Component)__instance).GetComponent<QuadSlashController>();
			if ((Object)(object)component != (Object)null && component.IsActive && component.IsFiringNext)
			{
				__result = true;
			}
		}
	}
}
[HarmonyPatch(typeof(Character), "Damage")]
internal static class QuadSlash_Patch_Damage
{
	private static void Prefix(Character __instance, ref HitData hit)
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)Player.m_localPlayer == (Object)null || hit.m_attacker != ((Character)Player.m_localPlayer).GetZDOID())
		{
			return;
		}
		QuadSlashController component = ((Component)Player.m_localPlayer).GetComponent<QuadSlashController>();
		if (!((Object)(object)component == (Object)null) && component.IsActive)
		{
			int currentHit = component.CurrentHit;
			if (1 == 0)
			{
			}
			float num = currentHit switch
			{
				0 => Plugin.QsDamage1.Value, 
				1 => Plugin.QsDamage2.Value, 
				2 => Plugin.QsDamage3.Value, 
				_ => Plugin.QsDamage4.Value, 
			};
			if (1 == 0)
			{
			}
			float num2 = num;
			if (!Mathf.Approximately(num2, 1f))
			{
				((DamageTypes)(ref hit.m_damage)).Modify(num2);
			}
		}
	}
}
internal static class ConcussionBlowCooldown
{
	private sealed class State
	{
		public double ReadyAt;

		public float Duration;

		public Sprite Icon;
	}

	private static readonly ConditionalWeakTable<Character, State> _states = new ConditionalWeakTable<Character, State>();

	internal static bool IsOnCooldown(Character c)
	{
		if (!_states.TryGetValue(c, out var value))
		{
			return false;
		}
		double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble);
		return num < value.ReadyAt;
	}

	internal static bool TryConsume(Character c, float cooldown, Sprite icon = null)
	{
		if (cooldown <= 0f)
		{
			return true;
		}
		State value = _states.GetValue(c, (Character _) => new State());
		double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble);
		if (num < value.ReadyAt)
		{
			return false;
		}
		value.ReadyAt = num + (double)cooldown;
		value.Duration = cooldown;
		value.Icon = icon;
		return true;
	}

	internal static bool CollectEntry(Character c, out CooldownEntry entry)
	{
		entry = default(CooldownEntry);
		if (!_states.TryGetValue(c, out var value))
		{
			return false;
		}
		double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble);
		float num2 = (float)Math.Max(0.0, value.ReadyAt - num);
		if (num2 <= 0f)
		{
			return false;
		}
		entry = new CooldownEntry
		{
			Icon = value.Icon,
			Remaining = num2,
			Duration = value.Duration
		};
		return true;
	}
}
internal static class ConcussionBlowFilter
{
	internal static bool Matches(ItemData weapon)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Invalid comparison between Unknown and I4
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Invalid comparison between Unknown and I4
		if (weapon?.m_shared == null)
		{
			return false;
		}
		SharedData shared = weapon.m_shared;
		return (int)shared.m_skillType == 3 && (int)shared.m_itemType == 3;
	}
}
internal static class ConcussionBlowSystem
{
	private static bool _pending;

	private static ZDOID _pendingAttacker;

	private static bool _appliedAny;

	internal static void OnSecondaryStarted(Humanoid humanoid, Attack attack)
	{
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Expected O, but got Unknown
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.CbEnable.Value)
		{
			return;
		}
		ItemData currentWeapon = humanoid.GetCurrentWeapon();
		if (!ConcussionBlowFilter.Matches(currentWeapon))
		{
			return;
		}
		Player val = (Player)(object)((humanoid is Player) ? humanoid : null);
		if (!((Object)(object)val != (Object)null) || !(Plugin.CbMinSkillLevel.Value > 0f) || !(((Character)val).GetSkillLevel((SkillType)3) < Plugin.CbMinSkillLevel.Value))
		{
			Character val2 = (Character)humanoid;
			if (!ConcussionBlowCooldown.IsOnCooldown(val2) && !SkillLimitSystem.ShouldBlock(val2, "ConcussionBlow"))
			{
				_pending = true;
				_pendingAttacker = val2.GetZDOID();
				_appliedAny = false;
			}
		}
	}

	internal static void OnSwingProcessed()
	{
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		if (_pending && _appliedAny)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				Character c = (Character)localPlayer;
				ItemData currentWeapon = ((Humanoid)localPlayer).GetCurrentWeapon();
				Sprite icon = ((currentWeapon != null && currentWeapon.m_shared?.m_icons?.Length > 0) ? currentWeapon.m_shared.m_icons[0] : null);
				ConcussionBlowCooldown.TryConsume(c, Plugin.CbCooldown.Value, icon);
				SaVfx.PlayAdrenaline1(((Component)localPlayer).transform.position);
			}
		}
		_pending = false;
		_pendingAttacker = ZDOID.None;
		_appliedAny = false;
	}

	internal static void CancelPending()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		_pending = false;
		_pendingAttacker = ZDOID.None;
		_appliedAny = false;
	}

	internal static void TryApply(Character target, ref HitData hit)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.CbEnable.Value || !_pending || hit.m_attacker != _pendingAttacker || (Object)(object)target == (Object)null || target.IsDead() || ((DamageTypes)(ref hit.m_damage)).GetTotalDamage() <= 0f)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null) && (object)target != localPlayer && CreatureClassification.Classify(target) != CreatureTier.Boss)
		{
			ItemData currentWeapon = ((Humanoid)localPlayer).GetCurrentWeapon();
			float requiredLevel = CreatureClassification.GetRequiredLevel(target);
			float level = SkillLevelResolver.GetLevel(localPlayer, currentWeapon, (SkillType)3);
			if (!(level < requiredLevel))
			{
				target.Stagger(hit.m_dir);
				ConcussionBlowStun.Apply(target);
				_appliedAny = true;
			}
		}
	}
}
internal static class ConcussionBlowStun
{
	private sealed class State
	{
		public double StunnedUntil;

		public bool SpeedAdjusted;

		public float OriginalSpeed = 1f;

		public bool NeedsRecalc;
	}

	private static readonly ConditionalWeakTable<Character, State> _states = new ConditionalWeakTable<Character, State>();

	private static readonly List<WeakReference> _tracked = new List<WeakReference>();

	private static readonly FieldInfo f_animator = AccessTools.Field(typeof(Character), "m_animator");

	private static Animator GetAnimator(Character c)
	{
		object? value = f_animator.GetValue(c);
		return (Animator)((value is Animator) ? value : null);
	}

	internal static void Apply(Character target)
	{
		if ((Object)(object)target == (Object)null || CreatureClassification.Classify(target) == CreatureTier.Boss)
		{
			return;
		}
		float value = Plugin.CbStunDuration.Value;
		if (!(value <= 0f))
		{
			double num = Now();
			State value2;
			bool flag = !_states.TryGetValue(target, out value2);
			State value3 = _states.GetValue(target, (Character _) => new State());
			value3.StunnedUntil = num + (double)value;
			value3.NeedsRecalc = true;
			if (flag)
			{
				_tracked.Add(new WeakReference(target));
			}
		}
	}

	private static bool TryFindStaggerState(Animator animator, out int layer, out AnimatorStateInfo info, out bool isNext)
	{
		//IL_000f: 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_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: 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_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		int layerCount = animator.layerCount;
		for (int i = 0; i < layerCount; i++)
		{
			AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(i);
			if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsTag("stagger"))
			{
				layer = i;
				info = currentAnimatorStateInfo;
				isNext = false;
				return true;
			}
			if (animator.IsInTransition(i))
			{
				AnimatorStateInfo nextAnimatorStateInfo = animator.GetNextAnimatorStateInfo(i);
				if (((AnimatorStateInfo)(ref nextAnimatorStateInfo)).IsTag("stagger"))
				{
					layer = i;
					info = nextAnimatorStateInfo;
					isNext = true;
					return true;
				}
			}
		}
		layer = -1;
		info = default(AnimatorStateInfo);
		isNext = false;
		return false;
	}

	internal static bool IsStunned(Character target)
	{
		if ((Object)(object)target == (Object)null || target.IsDead())
		{
			return false;
		}
		if (!_states.TryGetValue(target, out var value))
		{
			return false;
		}
		return Now() < value.StunnedUntil;
	}

	private static double Now()
	{
		return ((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble;
	}

	internal static void Tick()
	{
		for (int num = _tracked.Count - 1; num >= 0; num--)
		{
			object? target = _tracked[num].Target;
			Character val = (Character)((target is Character) ? target : null);
			State value;
			if ((Object)(object)val == (Object)null)
			{
				_tracked.RemoveAt(num);
			}
			else if (!_states.TryGetValue(val, out value))
			{
				_tracked.RemoveAt(num);
			}
			else
			{
				double num2 = Now();
				bool flag = num2 < value.StunnedUntil;
				bool flag2 = val.IsDead();
				if (!flag || flag2)
				{
					if (value.SpeedAdjusted)
					{
						Animator animator = GetAnimator(val);
						if ((Object)(object)animator != (Object)null)
						{
							animator.speed = value.OriginalSpeed;
						}
					}
					_states.Remove(val);
					_tracked.RemoveAt(num);
				}
				else
				{
					Animator animator2 = GetAnimator(val);
					if (!((Object)(object)animator2 == (Object)null))
					{
						if (TryFindStaggerState(animator2, out var _, out var info, out var _))
						{
							if (value.NeedsRecalc)
							{
								float length = ((AnimatorStateInfo)(ref info)).length;
								float num3 = ((AnimatorStateInfo)(ref info)).normalizedTime % 1f;
								if (num3 < 0f)
								{
									num3 = 0f;
								}
								float num4 = Mathf.Max(0f, length * (1f - num3));
								float num5 = Mathf.Max(0.01f, (float)(value.StunnedUntil - num2));
								if (!value.SpeedAdjusted)
								{
									value.OriginalSpeed = animator2.speed;
									value.SpeedAdjusted = true;
								}
								float speed = Mathf.Clamp(num4 / num5, 0.05f, 1f);
								animator2.speed = speed;
								value.NeedsRecalc = false;
							}
						}
						else if (value.SpeedAdjusted)
						{
							animator2.speed = value.OriginalSpeed;
							value.SpeedAdjusted = false;
						}
					}
				}
			}
		}
	}
}
public static class ConcussionBlowApi
{
	public static bool IsStunned(Character target)
	{
		return ConcussionBlowStun.IsStunned(target);
	}
}
[HarmonyPatch(typeof(Character), "CanMove")]
internal static class Patch_CharacterCanMove_ConcussionStun
{
	private static void Postfix(Character __instance, ref bool __result)
	{
		if (__result && ConcussionBlowStun.IsStunned(__instance))
		{
			__result = false;
		}
	}
}
[HarmonyPatch(typeof(Character), "StartAttack")]
internal static class Patch_CharacterStartAttack_ConcussionStun
{
	private static bool Prefix(Character __instance, ref bool __result)
	{
		if (ConcussionBlowStun.IsStunned(__instance))
		{
			__result = false;
			return false;
		}
		return true;
	}
}
internal enum CreatureTier
{
	Small,
	Large,
	Boss
}
internal static class CreatureClassification
{
	private static readonly HashSet<string> VanillaCreaturePrefabs = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
	{
		"Abomination", "Asksvin", "Asksvin_hatchling", "Bat", "Bjorn", "Blob", "BlobElite", "BlobFrost", "BlobLava", "BlobTar",
		"Boar", "Boar_piggy", "BogWitchKvastur", "BogWitch_Camp", "Bonemass", "BonemawSerpent", "Charred_Archer", "Charred_Archer_Fader", "Charred_Mage", "Charred_Melee",
		"Charred_Melee_Dyrnwyn", "Charred_Melee_Fader", "Charred_Twitcher", "Charred_Twitcher_Summoned", "Chicken", "Deathsquito", "Deer", "Dragon", "Draugr", "Draugr_Elite",
		"Draugr_Ranged", "Dverger", "DvergerAshlands", "DvergerMage", "DvergerMageFire", "DvergerMageIce", "DvergerMageSupport", "Eikthyr", "Fader", "FallenValkyrie",
		"Fenring", "Fenring_Cultist", "Fenring_Cultist_Hildir", "Fenring_Cultist_Hildir_nochest", "Ghost", "Gjall", "Goblin", "GoblinArcher", "GoblinBrute", "GoblinBruteBros",
		"GoblinBruteBros_nochest", "GoblinBrute_Hildir", "GoblinKing", "GoblinShaman", "GoblinShaman_Hildir", "GoblinShaman_Hildir_nochest", "Goblin_Gem", "Greydwarf", "Greydwarf_Elite", "Greydwarf_Shaman",
		"Greyling", "Hare", "Hatchling", "Hen", "Hive", "Leech", "Leech_cave", "Lox", "Lox_Calf", "Morgen",
		"Morgen_NonSleeping", "Neck", "Seeker", "SeekerBrood", "SeekerBrute", "SeekerQueen", "Serpent", "Skeleton", "Skeleton_Friendly", "Skeleton_Hildir",
		"Skeleton_Hildir_nochest", "Skeleton_NoArcher", "Skeleton_Poison", "StoneGolem", "Surtling", "TentaRoot", "TheHive", "Tick", "Troll", "Troll_Summoned",
		"Ulv", "Unbjorn", "Volture", "Wolf", "Wolf_cub", "Wraith", "gd_king"
	};

	private static bool _exported;

	internal static string GetPrefabName(Character c)
	{
		GameObject val = (((Object)(object)c != (Object)null) ? ((Component)c).gameObject : null);
		return ((Object)(object)val != (Object)null) ? StripClone(((Object)val).name) : string.Empty;
	}

	private static string StripClone(string name)
	{
		return name.EndsWith("(Clone)", StringComparison.Ordinal) ? name.Substring(0, name.Length - "(Clone)".Length) : name;
	}

	private static HashSet<string> ParseCsv(string csv)
	{
		HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
		if (string.IsNullOrWhiteSpace(csv))
		{
			return hashSet;
		}
		string[] array = csv.Split(new char[1] { ',' });
		foreach (string text in array)
		{
			string text2 = text.Trim();
			if (text2.Length > 0)
			{
				hashSet.Add(text2);
			}
		}
		return hashSet;
	}

	internal static CreatureTier Classify(Character c)
	{
		if ((Object)(object)c == (Object)null)
		{
			return CreatureTier.Small;
		}
		if (c.IsBoss())
		{
			return CreatureTier.Boss;
		}
		string prefabName = GetPrefabName(c);
		if (prefabName.Length > 0)
		{
			if (ParseCsv(Plugin.CbExtraBosses.Value).Contains(prefabName))
			{
				return CreatureTier.Boss;
			}
			if (ParseCsv(Plugin.CbLargeMonsters.Value).Contains(prefabName))
			{
				return CreatureTier.Large;
			}
		}
		return CreatureTier.Small;
	}

	internal static float GetRequiredLevel(Character c)
	{
		CreatureTier creatureTier = Classify(c);
		CreatureTier creatureTier2 = creatureTier;
		if (creatureTier2 == CreatureTier.Large)
		{
			return Plugin.CbLargeLevel.Value;
		}
		return Plugin.CbSmallLevel.Value;
	}

	internal static void ExportIfNeeded()
	{
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_011b: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		if (_exported || !Plugin.CbExportCreatureList.Value || (Object)(object)ZNetScene.instance == (Object)null)
		{
			return;
		}
		_exported = true;
		try
		{
			string text = Path.Combine(Paths.ConfigPath, "SpecialAttack_CreatureList.txt");
			List<string> list = new List<string> { "PrefabName\tDisplayName\tIsBoss\tMaxHealth\tMass\tHeight\tVanilla\tTier" };
			foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
			{
				if ((Object)(object)prefab == (Object)null)
				{
					continue;
				}
				Character component = prefab.GetComponent<Character>();
				if (!((Object)(object)component == (Object)null))
				{
					string text2 = StripClone(((Object)prefab).name);
					string name = component.m_name;
					bool boss = component.m_boss;
					float health = component.m_health;
					Rigidbody component2 = prefab.GetComponent<Rigidbody>();
					float num = (((Object)(object)component2 != (Object)null) ? component2.mass : 0f);
					Collider componentInChildren = prefab.GetComponentInChildren<Collider>();
					float num2;
					if (!((Object)(object)componentInChildren != (Object)null))
					{
						num2 = 0f;
					}
					else
					{
						Bounds bounds = componentInChildren.bounds;
						num2 = ((Bounds)(ref bounds)).size.y;
					}
					float num3 = num2;
					bool flag = VanillaCreaturePrefabs.Contains(text2);
					CreatureTier creatureTier = Classify(component);
					list.Add($"{text2}\t{name}\t{boss}\t{health:F0}\t{num:F1}\t{num3:F2}\t" + string.Format("{0}\t{1}", flag ? "바닐라" : "모드", creatureTier));
				}
			}
			File.WriteAllLines(text, list);
			Plugin.Log.LogInfo((object)("[ConcussionBlow] 크리처 목록 저장: " + text));
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("[ConcussionBlow] 크리처 목록 저장 실패: " + ex.Message));
		}
	}
}
[HarmonyPatch(typeof(ZNetScene), "Awake")]
internal static class Patch_ZNetSceneAwake_CreatureExport
{
	private static void Postfix()
	{
		CreatureClassification.ExportIfNeeded();
	}
}
internal static class CrescentWaveTuning
{
	internal const float ColorR = 0.45f;

	internal const float ColorG = 0.8f;

	internal const float ColorB = 1f;

	internal const float Range = 30f;

	internal const float Speed = 30f;

	internal const float SpawnHeight = 1.3f;

	internal const float SpawnForward = 0.5f;

	internal const float TiltAngle = 40f;

	internal const float VisualScale = 2f;

	internal const float HitWidth = 4f;

	internal const float HitSlashScale = 0.1f;

	internal const float MaxPitch = 60f;
}
internal static class CrescentWaveCooldown
{
	private sealed class State
	{
		public double ReadyAt;

		public float Duration;

		public Sprite Icon;
	}

	private static readonly ConditionalWeakTable<Character, State> _states = new ConditionalWeakTable<Character, State>();

	internal static bool IsOnCooldown(Character c)
	{
		if (!_states.TryGetValue(c, out var value))
		{
			return false;
		}
		double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble);
		return num < value.ReadyAt;
	}

	internal static bool TryConsume(Character c, float cooldown, Sprite icon = null)
	{
		if (cooldown <= 0f)
		{
			return true;
		}
		State value = _states.GetValue(c, (Character _) => new State());
		double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble);
		if (num < value.ReadyAt)
		{
			return false;
		}
		value.ReadyAt = num + (double)cooldown;
		value.Duration = cooldown;
		value.Icon = icon;
		return true;
	}

	internal static bool CollectEntry(Character c, out CooldownEntry entry)
	{
		entry = default(CooldownEntry);
		if (!_states.TryGetValue(c, out var value))
		{
			return false;
		}
		double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble);
		float num2 = (float)Math.Max(0.0, value.ReadyAt - num);
		if (num2 <= 0f)
		{
			return false;
		}
		entry = new CooldownEntry
		{
			Icon = value.Icon,
			Remaining = num2,
			Duration = value.Duration
		};
		return true;
	}
}
internal static class CrescentWaveFilter
{
	internal static bool Matches(ItemData weapon)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Invalid comparison between Unknown and I4
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Invalid comparison between Unknown and I4
		if (weapon?.m_shared == null)
		{
			return false;
		}
		SharedData shared = weapon.m_shared;
		if ((int)shared.m_skillType != 1)
		{
			return false;
		}
		if ((int)shared.m_itemType != 14)
		{
			return false;
		}
		string text = (((Object)(object)weapon.m_dropPrefab != (Object)null) ? ((Object)weapon.m_dropPrefab).name : "");
		return text.IndexOf("bastard", StringComparison.OrdinalIgnoreCase) >= 0;
	}
}
internal static class CrescentWaveSystem
{
	private static bool _pending;

	private static Player _pendingPlayer;

	private static ItemData _pendingWeapon;

	internal static void QueueTrigger(Humanoid humanoid)
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Expected O, but got Unknown
		if (!Plugin.CwEnable.Value)
		{
			return;
		}
		ItemData currentWeapon = humanoid.GetCurrentWeapon();
		if (!CrescentWaveFilter.Matches(currentWeapon))
		{
			return;
		}
		Character val = (Character)humanoid;
		if (val.IsOwner())
		{
			Player val2 = (Player)(object)((humanoid is Player) ? humanoid : null);
			if (!((Object)(object)val2 == (Object)null) && (!(Plugin.CwMinSkillLevel.Value > 0f) || !(((Character)val2).GetSkillLevel((SkillType)1) < Plugin.CwMinSkillLevel.Value)) && !CrescentWaveCooldown.IsOnCooldown(val) && !SkillLimitSystem.ShouldBlock(val, "CrescentWave"))
			{
				_pending = true;
				_pendingPlayer = val2;
				_pendingWeapon = currentWeapon;
			}
		}
	}

	internal static void ExecuteIfQueued(Humanoid humanoid)
	{
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Expected O, but got Unknown
		if (!_pending || (object)humanoid != _pendingPlayer)
		{
			return;
		}
		_pending = false;
		Material trailMaterialOrWarn = CrescentWaveVisual.GetTrailMaterialOrWarn(_pendingPlayer, _pendingWeapon);
		if (!((Object)(object)trailMaterialOrWarn == (Object)null))
		{
			Character c = (Character)_pendingPlayer;
			SharedData shared = _pendingWeapon.m_shared;
			Sprite icon = ((shared != null && shared.m_icons?.Length > 0) ? _pendingWeapon.m_shared.m_icons[0] : null);
			if (CrescentWaveCooldown.TryConsume(c, Plugin.CwCooldown.Value, icon))
			{
				Fire(_pendingPlayer, _pendingWeapon, trailMaterialOrWarn);
			}
		}
	}

	private static void Fire(Player player, ItemData weapon, Material material)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Expected O, but got Unknown
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: 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_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_014e: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		Character val = (Character)player;
		Vector3 forward = ((Component)val).transform.forward;
		forward.y = 0f;
		if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f)
		{
			forward = Vector3.forward;
		}
		((Vector3)(ref forward)).Normalize();
		Vector3 origin = ((Component)val).transform.position + Vector3.up * 1.3f + forward * 0.5f;
		Vector3 direction = CrescentWaveAim.ComputeAimDirection(origin, forward);
		float randomSkillFactor = val.GetRandomSkillFactor((SkillType)1);
		DamageTypes damage = weapon.GetDamage();
		((DamageTypes)(ref damage)).Modify(randomSkillFactor);
		float slash = ((DamageTypes)(ref damage)).GetTotalDamage() * Mathf.Max(0f, Plugin.CwDamageMult.Value);
		damage.m_damage = 0f;
		damage.m_blunt = 0f;
		damage.m_pierce = 0f;
		damage.m_chop = 0f;
		damage.m_pickaxe = 0f;
		damage.m_fire = 0f;
		damage.m_frost = 0f;
		damage.m_lightning = 0f;
		damage.m_poison = 0f;
		damage.m_spirit = 0f;
		damage.m_slash = slash;
		float pushForce = weapon.m_shared?.m_attackForce ?? 0f;
		SpawnProjectile(val, origin, direction, damage, pushForce, weapon, material);
		float level = SkillLevelResolver.GetLevel(player, weapon, (SkillType)1);
		int num = ResolveShotCountForLevel(level);
		if (num > 1)
		{
			GameObject gameObject = ((Component)player).gameObject;
			CrescentWaveController component = gameObject.GetComponent<CrescentWaveController>();
			if ((Object)(object)component != (Object)null)
			{
				component.CancelRemaining("이전체인재시작");
			}
			CrescentWaveController crescentWaveController = gameObject.AddComponent<CrescentWaveController>();
			crescentWaveController.Begin(player, origin, direction, damage, pushForce, weapon, material, level, num, Mathf.Max(0f, Plugin.CwChainInterval.Value));
		}
	}

	private static int ResolveShotCountForLevel(float level)
	{
		int result = 1;
		if (level >= Plugin.CwLv1.Value)
		{
			result = Plugin.CwCount1.Value;
		}
		if (level >= Plugin.CwLv2.Value)
		{
			result = Plugin.CwCount2.Value;
		}
		if (level >= Plugin.CwLv3.Value)
		{
			result = Plugin.CwCount3.Value;
		}
		if (level >= Plugin.CwLv4.Value)
		{
			result = Plugin.CwCount4.Value;
		}
		return result;
	}

	internal static void SpawnProjectile(Character ch, Vector3 origin, Vector3 direction, DamageTypes dmg, float pushForce, ItemData weapon, Material material)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_0012: 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_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("CrescentWave");
		val.transform.position = origin;
		val.transform.rotation = Quaternion.LookRotation(direction);
		CrescentWaveProjectile crescentWaveProjectile = val.AddComponent<CrescentWaveProjectile>();
		crescentWaveProjectile.Initialize(ch, dmg, direction, pushForce, weapon, material);
		CrescentWaveVisual.Attach(val, material);
	}
}
internal sealed class CrescentWaveController : MonoBehaviour
{
	private static readonly MethodInfo _mIsTeleporting = AccessTools.Method(typeof(Character), "IsTeleporting", (Type[])null, (Type[])null);

	private static readonly Func<Character, bool> _isTeleporting = ((_mIsTeleporting != null) ? AccessTools.MethodDelegate<Func<Character, bool>>(_mIsTeleporting, (object)null, true) : null);

	private Player _player;

	private Vector3 _origin;

	private Vector3 _direction;

	private DamageTypes _damage;

	private float _pushForce;

	private ItemData _weapon;

	private Material _material;

	private float _level;

	private int _targetCount;

	private int _firedCount;

	private float _interval;

	private Vector3 _lastCheckPos;

	private Coroutine _routine;

	internal void Begin(Player player, Vector3 origin, Vector3 direction, DamageTypes damage, float pushForce, ItemData weapon, Material material, float level, int targetCount, float interval)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: 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_0011: 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_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		_player = player;
		_origin = origin;
		_direction = direction;
		_damage = damage;
		_pushForce = pushForce;
		_weapon = weapon;
		_material = material;
		_level = level;
		_targetCount = targetCount;
		_firedCount = 1;
		_interval = interval;
		_lastCheckPos = ((Component)player).transform.position;
		_routine = ((MonoBehaviour)this).StartCoroutine(RunChain());
	}

	private IEnumerator RunChain()
	{
		string stopReason = "완료";
		while (_firedCount < _targetCount)
		{
			if (_interval > 0f)
			{
				yield return (object)new WaitForSeconds(_interval);
			}
			else
			{
				yield return null;
			}
			if (!CanContinue(ref stopReason))
			{
				break;
			}
			CrescentWaveSystem.SpawnProjectile((Character)(object)_player, _origin, _direction, _damage, _pushForce, _weapon, _material);
			_firedCount++;
		}
		if ((Object)(object)this != (Object)null)
		{
			Object.Destroy((Object)(object)this);
		}
	}

	private bool CanContinue(ref string stopReason)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Expected O, but got Unknown
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: 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_00d7: 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_00fb: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_player == (Object)null)
		{
			stopReason = "플레이어없음";
			return false;
		}
		Character val = (Character)_player;
		if ((Object)(object)val == (Object)null || val.IsDead())
		{
			stopReason = "사망";
			return false;
		}
		if (val.IsStaggering())
		{
			stopReason = "스태거";
			return false;
		}
		if (!CrescentWaveFilter.Matches(((Humanoid)_player).GetCurrentWeapon()))
		{
			stopReason = "무기교체";
			return false;
		}
		if (_isTeleporting != null && _isTeleporting(val))
		{
			stopReason = "순간이동";
			return false;
		}
		Vector3 position = ((Component)_player).transform.position;
		Vector3 val2 = position - _lastCheckPos;
		if (((Vector3)(ref val2)).sqrMagnitude > 9f)
		{
			stopReason = "순간이동(위치이상)";
			return false;
		}
		_lastCheckPos = position;
		return true;
	}

	internal void CancelRemaining(string reason)
	{
		if (_routine != null)
		{
			((MonoBehaviour)this).StopCoroutine(_routine);
			_routine = null;
		}
		if ((Object)(object)this != (Object)null)
		{
			Object.Destroy((Object)(object)this);
		}
	}

	private void OnDestroy()
	{
		if (_routine != null)
		{
			((MonoBehaviour)this).StopCoroutine(_routine);
		}
	}
}
internal static class CrescentWaveAim
{
	private static int _aimMask;

	private static int GetAimMask()
	{
		if (_aimMask == 0)
		{
			_aimMask = LayerMask.GetMask(new string[12]
			{
				"Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "terrain", "character", "character_net", "character_ghost", "hitbox",
				"character_noenv", "vehicle"
			});
		}
		return _aimMask;
	}

	internal static Vector3 ComputeAimDirection(Vector3 origin, Vector3 bodyForward)
	{
		//IL_0022: 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_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: 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_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		GameCamera instance = GameCamera.instance;
		if ((Object)(object)instance == (Object)null)
		{
			return bodyForward;
		}
		Vector3 position = ((Component)instance).transform.position;
		Vector3 forward = ((Component)instance).transform.forward;
		float num = Mathf.Max(1f, 30f);
		RaycastHit val2 = default(RaycastHit);
		Vector3 val = (Physics.Raycast(position, forward, ref val2, num, GetAimMask(), (QueryTriggerInteraction)1) ? ((RaycastHit)(ref val2)).point : (position + forward * num));
		Vector3 val3 = val - origin;
		Vector3 dir = ((Vector3.Dot(val3, bodyForward) <= 0f || ((Vector3)(ref val3)).magnitude < 3f) ? forward : ((Vector3)(ref val3)).normalized);
		dir = ClampPitch(dir, 60f);
		return (((Vector3)(ref dir)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref dir)).normalized : bodyForward;
	}

	private static Vector3 ClampPitch(Vector3 dir, float maxPitchDegrees)
	{
		//IL_0003: 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_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: 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_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		Vector3 forward = default(Vector3);
		((Vector3)(ref forward))..ctor(dir.x, 0f, dir.z);
		if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f)
		{
			forward = Vector3.forward;
		}
		((Vector3)(ref forward)).Normalize();
		float y = dir.y;
		Vector3 val = new Vector3(dir.x, 0f, dir.z);
		float num = Mathf.Atan2(y, ((Vector3)(ref val)).magnitude) * 57.29578f;
		float num2 = Mathf.Clamp(num, 0f - maxPitchDegrees, maxPitchDegrees);
		float num3 = num2 * ((float)Math.PI / 180f);
		return forward * Mathf.Cos(num3) + Vector3.up * Mathf.Sin(num3);
	}
}
internal sealed class CrescentWaveProjectile : MonoBehaviour
{
	private static readonly Collider[] _hitBuf = (Collider[])(object)new Collider[32];

	private static int _maskChars;

	private Character _attacker;

	private DamageTypes _damage;

	private Vector3 _direction;

	private float _pushForce;

	private float _traveled;

	private ItemData _weapon;

	private Material _material;

	private float _lastHitSoundTime = float.NegativeInfinity;

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

	private static int GetMaskChars()
	{
		if (_maskChars == 0)
		{
			_maskChars = LayerMask.GetMask(new string[5] { "character", "character_net", "character_ghost", "hitbox", "character_noenv" });
		}
		return _maskChars;
	}

	internal void Initialize(Character attacker, DamageTypes damage, Vector3 direction, float pushForce, ItemData weapon, Material material)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: 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_0011: Unknown result type (might be due to invalid IL or missing references)
		_attacker = attacker;
		_damage = damage;
		_direction = direction;
		_pushForce = pushForce;
		_weapon = weapon;
		_material = material;
		_traveled = 0f;
	}

	private void FixedUpdate()
	{
		//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_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: 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_00ab: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_attacker == (Object)null)
		{
			Object.Destroy((Object)(object)((Component)this).gameObject);
			return;
		}
		float num = Mathf.Max(0f, 30f);
		float num2 = Mathf.Max(0.01f, 30f);
		float num3 = Mathf.Min(num2 * Time.fixedDeltaTime, num - _traveled);
		if (num3 <= 0f)
		{
			Object.Destroy((Object)(object)((Component)this).gameObject);
			return;
		}
		Vector3 position = ((Component)this).transform.position;
		Vector3 val = position + _direction * num3;
		CheckHits(position, val, num3);
		((Component)this).transform.position = val;
		_traveled += num3;
		if (_traveled >= num)
		{
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}
	}

	private void CheckHits(Vector3 prevPos, Vector3 nextPos, float step)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: 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_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: 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_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = (prevPos + nextPos) * 0.5f;
		Vector3 val2 = default(Vector3);
		((Vector3)(ref val2))..ctor(Mathf.Max(0.1f, 4f) * 0.5f, Mathf.Max(0.1f, Plugin.CwHitHeight.Value) * 0.5f, step * 0.5f + 0.1f);
		Quaternion val3 = Quaternion.LookRotation(_direction);
		int num = Physics.OverlapBoxNonAlloc(val, val2, _hitBuf, val3, GetMaskChars(), (QueryTriggerInteraction)0);
		for (int i = 0; i < num; i++)
		{
			Collider val4 = _hitBuf[i];
			if (!((Object)(object)val4 == (Object)null))
			{
				Character componentInParent = ((Component)val4).GetComponentInParent<Character>();
				if (!((Object)(object)componentInParent == (Object)null) && componentInParent != _attacker && !componentInParent.IsDead() && !componentInParent.IsPlayer() && BaseAI.IsEnemy(_attacker, componentInParent) && !componentInParent.InDodge() && !componentInParent.IsDebugFlying() && _hitTargets.Add(componentInParent))
				{
					ApplyHit(componentInParent, val);
				}
			}
		}
	}

	private void ApplyHit(Character target, Vector3 origin)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_00de: 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_0133: Unknown result type (might be due to invalid IL or missing references)
		/