Decompiled source of SpecialAttack v1.2.1

SpecialAttackPlugin.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;
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 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_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: 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 ?? "";
		return text2.IndexOf("sledge", StringComparison.OrdinalIgnoreCase) >= 0;
	}
}
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 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 void QueueTrigger(Humanoid humanoid, Attack attack)
	{
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Expected O, but got Unknown
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0165: 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))
		{
			if (currentWeapon?.m_shared != null)
			{
				SharedData shared = currentWeapon.m_shared;
				Plugin.Log.LogInfo((object)string.Format("[AS] Filter MISS | wep={0} itemType={1} skill={2} secAnim={3}", shared.m_name, shared.m_itemType, shared.m_skillType, shared.m_secondaryAttack?.m_attackAnimation ?? "null"));
			}
			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))
			{
				_pending = true;
				_pendingPlayer = val2;
				_pendingWeapon = currentWeapon;
				_pendingAttack = attack;
				_pendingForward = ((Component)val).transform.forward;
				Plugin.Log.LogInfo((object)$"[AS] Queued | wep={currentWeapon.m_shared.m_name} dir={_pendingForward}");
			}
		}
	}

	internal static void ExecuteIfQueued(Humanoid humanoid)
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Expected O, but got Unknown
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: 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_00f4: Unknown result type (might be due to invalid IL or missing references)
		if (_pending && (object)humanoid == _pendingPlayer)
		{
			_pending = false;
			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 (AftershockCooldown.TryConsume(c, Plugin.AsCooldown.Value, icon))
			{
				SaVfx.PlayAdrenaline1(((Component)_pendingPlayer).transform.position);
				GameObject gameObject = ((Component)_pendingPlayer).gameObject;
				AftershockController aftershockController = gameObject.AddComponent<AftershockController>();
				aftershockController.Initialize(_pendingPlayer, _pendingWeapon, _pendingAttack, _pendingForward);
				Plugin.Log.LogInfo((object)("[AS] Triggered (OnAttackTrigger) | wep=" + _pendingWeapon.m_shared.m_name));
			}
		}
	}

	internal static void ApplyWave(Player player, ItemData weapon, Attack attack, int waveIndex, Vector3 attackForward, Vector3 startPosition)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Expected O, but got Unknown
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: 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_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: 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_009a: 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_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_025f: Unknown result type (might be due to invalid IL or missing references)
		//IL_021c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
		Character val = (Character)player;
		if ((Object)(object)val == (Object)null || val.IsDead())
		{
			return;
		}
		float num = 1f - Mathf.Clamp01(Plugin.AsWaveDecay.Value);
		float num2 = ((waveIndex <= 0) ? 1f : Mathf.Pow(num, (float)waveIndex));
		float num3 = Plugin.AsRadius.Value * num2;
		float value = Plugin.AsForwardStep.Value;
		float dmgFactor = Plugin.AsDamageFactor.Value * num2;
		float randomSkillFactor = val.GetRandomSkillFactor((SkillType)3);
		Vector3 val2 = startPosition + attackForward * (value * (float)(waveIndex + 1));
		val2.y = GetGroundY(val2, startPosition.y) + 0.3f;
		Quaternion rotation = ((((Vector3)(ref attackForward)).sqrMagnitude > 0.001f) ? Quaternion.LookRotation(attackForward) : Quaternion.identity);
		SpawnWaveVFX(weapon, attack, val2, rotation, num2);
		_hitSet.Clear();
		int num4 = Physics.OverlapSphereNonAlloc(val2, num3, _hitBuf, GetMaskChars(), (QueryTriggerInteraction)0);
		int num5 = 0;
		Vector3 val3 = Vector3.zero;
		for (int i = 0; i < num4; i++)
		{
			Collider val4 = _hitBuf[i];
			if ((Object)(object)val4 == (Object)null)
			{
				continue;
			}
			GameObject val5 = Projectile.FindHitObject(val4);
			if ((Object)(object)val5 == (Object)null || !_hitSet.Add(val5))
			{
				continue;
			}
			Character componentInParent = val5.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, val2, dmgFactor, randomSkillFactor);
					val3 += componentInParent.GetCenterPoint();
					num5++;
				}
			}
			else
			{
				IDestructible componentInParent2 = val5.GetComponentInParent<IDestructible>();
				if (componentInParent2 != null && !(componentInParent2 is Character))
				{
					ApplyDestructibleHit(val, componentInParent2, weapon, val2, dmgFactor, randomSkillFactor);
					num5++;
				}
			}
		}
		Plugin.Log.LogInfo((object)$"[AS] Wave {waveIndex} | origin={val2} radius={num3:F2} hits={num5} scale={num2:F2}");
	}

	private static void SpawnWaveVFX(ItemData weapon, Attack attack, Vector3 origin, Quaternion rotation, float scale)
	{
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: 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_0060: 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);
					Plugin.Log.LogInfo((object)$"[AS VFX] spawned={text} scale={scale:F2}");
					return;
				}
			}
		}
		if (attack != null && attack.m_triggerEffect?.m_effectPrefabs?.Length > 0)
		{
			attack.m_triggerEffect.Create(origin, rotation, (Transform)null, scale, -1, default(ZDOID));
		}
		else
		{
			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)
		{
			string name = ((Object)((Component)val).gameObject).name;
			bool flag = name switch
			{
				"vfx_Splosh (1)" => Plugin.AfterVfx_Splosh.Value, 
				"vfx_troll_rock_destroyed" => Plugin.AfterVfx_TrollRock.Value, 
				"Cloud" => Plugin.AfterVfx_Cloud.Value, 
				"waves" => Plugin.AfterVfx_Waves.Value, 
				_ => true, 
			};
			((Component)val).gameObject.SetActive(flag);
			Plugin.Log.LogInfo((object)$"[SA-VFX] PS={name} active={flag}");
		}
	}

	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, Vector3 origin, float dmgFactor, 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_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: 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_0087: 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_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
		DamageTypes damage = weapon.GetDamage();
		((DamageTypes)(ref damage)).Modify(dmgFactor * skillFactor);
		HitData val = new HitData();
		val.m_damage = damage;
		val.m_skill = (SkillType)3;
		val.m_pushForce = Plugin.AsPushForce.Value * ((dmgFactor > 0f) ? Mathf.Sqrt(dmgFactor) : 0f);
		val.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);
	}

	private static void ApplyDestructibleHit(Character attacker, IDestructible target, ItemData weapon, Vector3 origin, float dmgFactor, 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(dmgFactor * 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 _startPosition;

	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_003a: 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_0049: 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);
		_startPosition = ((Component)(Character)player).transform.position;
		_nextWave = 0;
		_totalWaves = Mathf.Max(1, Plugin.AsWaves.Value);
		_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, _forwardDir, _startPosition);
			_nextWave++;
			float num = Mathf.Max(0f, Plugin.AsInterval.Value);
			_nextWaveTime += num;
			if (num > 0f)
			{
				break;
			}
		}
		if (_nextWave >= _totalWaves)
		{
			Object.Destroy((Object)(object)this);
		}
	}
}
internal static class ChargeSlashCooldown
{
	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 ChargeSlashFilter
{
	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 ChargeSlashSystem
{
	private static bool _multiplyNext;

	private static float _chargeTime;

	private static ZDOID _zdoid;

	private static bool _allowSlash;

	internal static bool AllowSlash => _allowSlash;

	internal static void StartCharging(Humanoid humanoid)
	{
		//IL_0002: 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_0026: Expected O, but got Unknown
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		GameObject gameObject = ((Component)humanoid).gameObject;
		if (!((Object)(object)gameObject.GetComponent<ChargeSlashController>() != (Object)null))
		{
			Character val = (Character)humanoid;
			_zdoid = val.GetZDOID();
			ChargeSlashController chargeSlashController = gameObject.AddComponent<ChargeSlashController>();
			chargeSlashController.Begin(humanoid, humanoid.GetCurrentWeapon());
			Plugin.Log.LogInfo((object)"[CS] 충전 시작");
		}
	}

	internal static bool FireSlash(Humanoid humanoid, float chargeTime)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		_multiplyNext = true;
		_chargeTime = chargeTime;
		_allowSlash = true;
		bool flag = ((Character)humanoid).StartAttack((Character)null, true);
		_allowSlash = false;
		if (!flag)
		{
			_multiplyNext = false;
		}
		Plugin.Log.LogInfo((object)$"[CS] 슬래시 발동 — 충전 {chargeTime:F2}s, ok={flag}");
		return flag;
	}

	internal static void ClearPending()
	{
		_multiplyNext = false;
	}

	internal static void TryHandleDamage(Character target, ref HitData hit)
	{
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Invalid comparison between Unknown and I4
		//IL_0082: 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_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		if (Plugin.CsEnable.Value && _multiplyNext && !((Object)(object)target == (Object)null) && !target.IsPlayer() && (int)hit.m_skill == 1 && !(((DamageTypes)(ref hit.m_damage)).GetTotalDamage() <= 0f) && !(hit.m_attacker != _zdoid))
		{
			_multiplyNext = false;
			float value = Plugin.CsMaxChargeTime.Value;
			float num = ((value > 0f) ? Mathf.Clamp01(_chargeTime / value) : 1f);
			float num2 = Mathf.Lerp(1f, Plugin.CsDamageMult.Value, num);
			((DamageTypes)(ref hit.m_damage)).Modify(num2);
			SaVfx.PlayAdrenaline1(((Object)(object)Player.m_localPlayer != (Object)null) ? ((Component)Player.m_localPlayer).transform.position : ((Component)target).transform.position);
			Plugin.Log.LogInfo((object)$"[CS] 슬래시 ×{num2:F2} (충전 {_chargeTime:F2}s / {value:F1}s)");
			SpawnHitVfx(hit.m_point);
		}
	}

	private static void SpawnHitVfx(Vector3 point)
	{
		//IL_005c: 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)
		string value = Plugin.CsHitVfxName.Value;
		if (!string.IsNullOrEmpty(value) && !((Object)(object)ZNetScene.instance == (Object)null))
		{
			GameObject prefab = ZNetScene.instance.GetPrefab(value);
			if ((Object)(object)prefab == (Object)null)
			{
				Plugin.Log.LogWarning((object)("[CS] VFX 프리팹 없음: " + value));
			}
			else
			{
				Object.Instantiate<GameObject>(prefab, point, Quaternion.identity);
			}
		}
	}
}
internal sealed class ChargeSlashController : MonoBehaviour
{
	private static readonly FieldInfo _secHoldField = AccessTools.Field(typeof(Player), "m_secondaryAttackHold");

	private Humanoid _humanoid;

	private ItemData _weapon;

	private float _chargeTimer;

	private bool _releasing;

	private float _releaseTime;

	private int _diagFrame;

	internal bool IsCharging => !_releasing;

	internal float ChargeTime => _chargeTimer;

	internal float MaxCharge => Plugin.CsMaxChargeTime.Value;

	internal float ChargeRatio
	{
		get
		{
			float maxCharge = MaxCharge;
			return (maxCharge > 0f) ? Mathf.Clamp01(_chargeTimer / maxCharge) : 1f;
		}
	}

	private bool IsSecondaryHeld()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Invalid comparison between Unknown and I4
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		KeyCode value = Plugin.SpecialKey.Value;
		if ((int)value > 0)
		{
			return Input.GetKey(value);
		}
		Humanoid humanoid = _humanoid;
		Player val = (Player)(object)((humanoid is Player) ? humanoid : null);
		if (val != null && _secHoldField != null)
		{
			return (bool)_secHoldField.GetValue(val);
		}
		return ZInput.GetButton("SecondaryAttack") || ZInput.GetButton("JoySecondaryAttack");
	}

	internal void Begin(Humanoid h, ItemData w)
	{
		_humanoid = h;
		_weapon = w;
		_chargeTimer = 0f;
		_releasing = false;
		_releaseTime = 0f;
		((Behaviour)this).enabled = true;
	}

	private void Update()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Expected O, but got Unknown
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Expected O, but got Unknown
		//IL_0178: Unknown result type (might be due to invalid IL or missing references)
		Character val = (Character)_humanoid;
		if ((Object)(object)_humanoid == (Object)null || val.IsDead() || !val.IsOwner())
		{
			Object.Destroy((Object)(object)this);
		}
		else if (!ChargeSlashFilter.Matches(_humanoid.GetCurrentWeapon()))
		{
			Plugin.Log.LogWarning((object)$"[CS-DIAG] 무기 필터 실패 → 컨트롤러 종료 (timer={_chargeTimer:F3})");
			Object.Destroy((Object)(object)this);
		}
		else if (val.IsStaggering())
		{
			Object.Destroy((Object)(object)this);
		}
		else if (!_releasing)
		{
			_chargeTimer = Mathf.Min(_chargeTimer + Time.deltaTime, MaxCharge);
			bool flag = IsSecondaryHeld();
			_diagFrame++;
			if (_diagFrame % 10 == 0)
			{
				Plugin.Log.LogInfo((object)$"[CS-DIAG] timer={_chargeTimer:F3} held={flag} secHoldField={_secHoldField != null}");
			}
			if (_chargeTimer > 0.2f && !flag)
			{
				_releasing = true;
				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);
					ChargeSlashCooldown.TryConsume(c, Plugin.CsCooldown.Value, icon);
				}
				bool flag2 = ChargeSlashSystem.FireSlash(_humanoid, _chargeTimer);
				_releaseTime = Time.time + 0.5f;
				if (!flag2)
				{
					Plugin.Log.LogInfo((object)"[CS] 슬래시 실패");
					Object.Destroy((Object)(object)this);
				}
			}
		}
		else if (Time.time > _releaseTime && !val.InAttack())
		{
			Object.Destroy((Object)(object)this);
		}
	}

	private void OnDestroy()
	{
		if (!_releasing)
		{
			ChargeSlashSystem.ClearPending();
		}
		Plugin.Log.LogInfo((object)$"[CS] 컨트롤러 종료 (충전 {_chargeTimer:F2}s, releasing={_releasing})");
	}
}
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 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;
	}
}
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;
					Plugin.Log.LogInfo((object)"[QS-VFX] Dvergr trail mat 캐시 완료");
					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;
				Plugin.Log.LogInfo((object)"[QS-VFX] Dvergr trail renderer mat 캐시 완료");
				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_0147: 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;
		}
		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);
		Plugin.Log.LogInfo((object)"[QS] SA 차단 → 4연 베기 시작");
		return true;
	}

	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)
	{
		//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);
		return quadSlashController;
	}

	private void Setup(Humanoid humanoid, ItemData weapon)
	{
		//IL_001e: 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_0064: Unknown result type (might be due to invalid IL or missing references)
		_humanoid = humanoid;
		_weapon = weapon;
		_hitsLeft = 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);
		Plugin.Log.LogInfo((object)string.Format("[QS-Speed] animator={0} savedSpeed={1} speed0={2}", ((Object)(object)_animator != (Object)null) ? ((Object)_animator).name : "NULL", _savedAnimSpeed, GetSpeed(0)));
		((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;
			}
			Plugin.Log.LogInfo((object)string.Format("[QS-Speed] hit={0} speed={1} animator.speed(after)={2}", _currentHit, speed, ((Object)(object)_animator != (Object)null) ? _animator.speed.ToString("F2") : "NULL"));
			((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;
		}
		if (_currentHit == 0)
		{
			Plugin.Log.LogInfo((object)$"[QS-Anim] animBase='{text}' chainLevels={num} naturalLevel={num2}");
		}
		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))
		{
			Plugin.Log.LogInfo((object)$"[QS-Anim] hit={_currentHit} {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);
		Plugin.Log.LogInfo((object)$"[QS-Anim] battleaxe trigger 캐시: '{_cachedBattleaxeTrigger}' (chainLevels={num})");
		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 SpinkickFilter
{
	internal static bool Matches(ItemData weapon)
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Invalid comparison between Unknown and I4
		if (weapon?.m_shared == null || (Object)(object)weapon.m_dropPrefab == (Object)null)
		{
			return false;
		}
		if ((int)weapon.m_shared.m_skillType != 11)
		{
			return false;
		}
		string name = ((Object)weapon.m_dropPrefab).name;
		return name.IndexOf("Fist", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Claw", StringComparison.OrdinalIgnoreCase) >= 0;
	}
}
internal static class SpinkickCooldown
{
	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 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 SpinkickSystem
{
	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_01c1: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.CuEnable.Value)
		{
			return false;
		}
		ItemData currentWeapon = humanoid.GetCurrentWeapon();
		if (!SpinkickFilter.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.CuMinSkillLevel.Value > 0f && ((Character)val2).GetSkillLevel((SkillType)11) < Plugin.CuMinSkillLevel.Value)
		{
			return false;
		}
		SharedData shared = currentWeapon.m_shared;
		Sprite icon = ((shared != null && shared.m_icons?.Length > 0) ? currentWeapon.m_shared.m_icons[0] : null);
		if (!SpinkickCooldown.TryConsume(val, Plugin.CuCooldown.Value, icon))
		{
			return false;
		}
		float valueOrDefault = (currentWeapon.m_shared?.m_secondaryAttack?.m_attackStamina).GetValueOrDefault();
		if (valueOrDefault > 0f)
		{
			((Character)val2).UseStamina(valueOrDefault);
			Plugin.Log.LogInfo((object)$"[CU] SA 스태미나 {valueOrDefault} 소모");
		}
		SaVfx.PlayAdrenaline1(((Component)val2).transform.position);
		SpinkickController.Begin(humanoid, currentWeapon);
		Plugin.Log.LogInfo((object)"[CU] SA 차단 → 스핀킥 시작");
		return true;
	}
}
internal sealed class SpinkickController : MonoBehaviour
{
	private static readonly FieldInfo _fInDodge = AccessTools.Field(typeof(Player), "m_inDodge");

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

	private static readonly FieldInfo _fBody = AccessTools.Field(typeof(Character), "m_body");

	private static readonly FieldInfo _fLookDir = AccessTools.Field(typeof(Character), "m_lookDir");

	private static readonly int _charMask = LayerMask.GetMask(new string[3] { "character", "character_net", "character_ghost" });

	private Humanoid _humanoid;

	private Player _player;

	private Animator _animator;

	private ItemData _weapon;

	internal bool IsActive;

	internal bool IsInDuck;

	private Quaternion _startRotation;

	private static int _runCounter;

	private PlayableGraph _activeGraph;

	private bool _graphRootMotionOrig;

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

	private void Setup(Humanoid humanoid, ItemData weapon)
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Expected O, but got Unknown
		//IL_004c: 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_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: 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_006c: 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_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_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: 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_00cf: Unknown result type (might be due to invalid IL or missing references)
		_humanoid = humanoid;
		_player = (Player)(object)((humanoid is Player) ? humanoid : null);
		_weapon = weapon;
		IsActive = true;
		Vector3 val = ((_fLookDir?.GetValue((object?)(Character)humanoid) is Vector3 val2) ? val2 : ((Component)humanoid).transform.forward);
		Vector3 val3 = default(Vector3);
		((Vector3)(ref val3))..ctor(val.x, 0f, val.z);
		_startRotation = ((((Vector3)(ref val3)).sqrMagnitude > 0.001f) ? Quaternion.LookRotation(((Vector3)(ref val3)).normalized) : ((Component)humanoid).transform.rotation);
		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>()));
		((MonoBehaviour)this).StartCoroutine(SpinkickCoroutine());
	}

	private IEnumerator SpinkickCoroutine()
	{
		IsInDuck = false;
		int runId = ++_runCounter;
		yield return (object)new WaitForSeconds(0.05f);
		if ((Object)(object)_humanoid == (Object)null || !IsActive)
		{
			yield break;
		}
		Character ch = (Character)_humanoid;
		IsInDuck = true;
		yield return null;
		AnimationClip spClip = SpinkickLoader.GetClip();
		bool graphActive = false;
		PlayableGraph graph = default(PlayableGraph);
		bool origRootMotion = (Object)(object)_animator != (Object)null && _animator.applyRootMotion;
		if ((Object)(object)spClip != (Object)null && (Object)(object)_animator != (Object)null)
		{
			try
			{
				_animator.applyRootMotion = true;
				graph = PlayableGraph.Create("SpinkickGraph");
				((PlayableGraph)(ref graph)).SetTimeUpdateMode((DirectorUpdateMode)1);
				AnimationLayerMixerPlayable layerMixer = AnimationLayerMixerPlayable.Create(graph, 2);
				AnimatorControllerPlayable ctrlPlayable = AnimatorControllerPlayable.Create(graph, _animator.runtimeAnimatorController);
				((PlayableGraph)(ref graph)).Connect<AnimatorControllerPlayable, AnimationLayerMixerPlayable>(ctrlPlayable, 0, layerMixer, 0);
				PlayableExtensions.SetInputWeight<AnimationLayerMixerPlayable>(layerMixer, 0, 0f);
				((AnimationLayerMixerPlayable)(ref layerMixer)).SetLayerAdditive(0u, false);
				AnimationClipPlayable clipPlayable = AnimationClipPlayable.Create(graph, spClip);
				((PlayableGraph)(ref graph)).Connect<AnimationClipPlayable, AnimationLayerMixerPlayable>(clipPlayable, 0, layerMixer, 1);
				PlayableExtensions.SetInputWeight<AnimationLayerMixerPlayable>(layerMixer, 1, 1f);
				((AnimationLayerMixerPlayable)(ref layerMixer)).SetLayerAdditive(1u, false);
				AnimationPlayableOutput output = AnimationPlayableOutput.Create(graph, "SpinkickOut", _animator);
				PlayableOutputExtensions.SetSourcePlayable<AnimationPlayableOutput, AnimationLayerMixerPlayable>(output, layerMixer);
				PlayableOutputExtensions.SetWeight<AnimationPlayableOutput>(output, 1f);
				float animSpeed = Mathf.Max(0.1f, Plugin.CuSpinkickAnimSpeed.Value);
				PlayableExtensions.SetSpeed<Playable>(AnimationClipPlayable.op_Implicit(clipPlayable), (double)animSpeed);
				((PlayableGraph)(ref graph)).Play();
				graphActive = true;
				_activeGraph = graph;
				_graphRootMotionOrig = origRootMotion;
				Plugin.Log.LogInfo((object)($"[CU-Trace #{runId}] GRAPH_START t={Time.time:F3}" + $" clip={((Object)spClip).name}({spClip.length:F2}s) speed={animSpeed:F2}"));
			}
			catch (Exception ex)
			{
				Exception ex2 = ex;
				Plugin.Log.LogWarning((object)("[CU] PlayableGraph 실패: " + ex2.GetType().Name + ": " + ex2.Message));
				_animator.applyRootMotion = origRootMotion;
			}
		}
		float animSpeedFinal = (graphActive ? Mathf.Max(0.1f, Plugin.CuSpinkickAnimSpeed.Value) : 1f);
		float clipLen = (((Object)(object)spClip != (Object)null) ? spClip.length : 0f);
		float realClipDur = ((clipLen > 0f) ? (clipLen / animSpeedFinal) : 0.5f);
		float hitDelay = Mathf.Max(0f, Plugin.CuSpinkickHitFraction.Value * realClipDur);
		((MonoBehaviour)this).StartCoroutine(DelayedDirectDamage(hitDelay));
		float cutoff = Mathf.Clamp(Plugin.CuSpinkickCutoff.Value, 0.05f, 1f);
		if (cutoff < Plugin.CuSpinkickHitFraction.Value)
		{
			Plugin.Log.LogWarning((object)($"[CU-#{runId}] 경고: Cutoff({cutoff:F2}) < HitFraction({Plugin.CuSpinkickHitFraction.Value:F2})" + " → 타격 전에 기술이 종료됩니다."));
		}
		float clipEndTime = Time.time + realClipDur * cutoff;
		Plugin.Log.LogInfo((object)($"[CU-Trace #{runId}] CUTOFF_SET cutoff={cutoff:F2} realDur={realClipDur:F3}s" + $" clipEndAt={clipEndTime:F3} (현재={Time.time:F3})"));
		object? obj = _fBody?.GetValue((object?)(Character)_humanoid);
		Rigidbody body = (Rigidbody)((obj is Rigidbody) ? obj : null);
		Plugin.Log.LogInfo((object)$"[CU-Lock] body null={(Object)(object)body == (Object)null}");
		while (Time.time < clipEndTime && IsActive && !ch.InDodge())
		{
			try
			{
				Transform tf = ((Component)_humanoid).transform;
				tf.rotation = _startRotation;
				if ((Object)(object)body != (Object)null)
				{
					body.rotation = _startRotation;
				}
			}
			catch (Exception ex3)
			{
				Plugin.Log.LogWarning((object)("[CU-Lock] 예외: " + ex3.GetType().Name + ": " + ex3.Message));
			}
			yield return null;
		}
		Plugin.Log.LogInfo((object)$"[CU-Trace #{runId}] CUTOFF_REACHED t={Time.time:F3} → 기술 즉시 종료");
		if (ch.InDodge())
		{
			Plugin.Log.LogInfo((object)$"[CU-Trace #{runId}] 닷지 감지 → 루프 조기 종료 t={Time.time:F3}");
		}
		if (graphActive && ((PlayableGraph)(ref graph)).IsValid())
		{
			_animator.applyRootMotion = origRootMotion;
			((PlayableGraph)(ref graph)).Destroy();
			_activeGraph = default(PlayableGraph);
			Plugin.Log.LogInfo((object)$"[CU-Trace #{runId}] GRAPH_END t={Time.time:F3}");
		}
		IsInDuck = false;
		Plugin.Log.LogInfo((object)$"[CU-Trace #{runId}] LOCK_RELEASED IsInDuck=false t={Time.time:F3}");
		IsActive = false;
		Plugin.Log.LogInfo((object)$"[CU-Trace #{runId}] SKILL_ENDED IsActive=false t={Time.time:F3} (이동/방향 잠금 해제, 다음 공격 가능)");
	}

	private IEnumerator DelayedDirectDamage(float delay)
	{
		if (delay > 0f)
		{
			yield return (object)new WaitForSeconds(delay);
		}
		if (!IsActive || (Object)(object)_humanoid == (Object)null || _weapon == null)
		{
			yield break;
		}
		Character character = (Character)_humanoid;
		Attack sa = _weapon.m_shared.m_secondaryAttack;
		SkillType skillType = _weapon.m_shared.m_skillType;
		DamageTypes dmg = _weapon.GetDamage();
		if (!Mathf.Approximately(sa.m_damageMultiplier, 1f))
		{
			((DamageTypes)(ref dmg)).Modify(sa.m_damageMultiplier);
		}
		float skillFactor = character.GetRandomSkillFactor(skillType);
		float levelFactor = 1f + (float)Mathf.Max(0, character.GetLevel() - 1) * 0.5f;
		((DamageTypes)(ref dmg)).Modify(skillFactor * levelFactor);
		if (!Mathf.Approximately(Plugin.CuSpinkickDamageMult.Value, 1f))
		{
			((DamageTypes)(ref dmg)).Modify(Plugin.CuSpinkickDamageMult.Value);
		}
		float pushForce = _weapon.m_shared.m_attackForce * skillFactor * sa.m_forceMultiplier;
		float range = Mathf.Max(0.5f, sa.m_attackRange);
		Vector3 center = ((Component)_humanoid).transform.position + Vector3.up * 0.8f;
		Collider[] buffer = (Collider[])(object)new Collider[16];
		int n = Physics.OverlapSphereNonAlloc(center, range, buffer, _charMask, (QueryTriggerInteraction)2);
		HashSet<int> visited = new HashSet<int>();
		int hitCount = 0;
		for (int i = 0; i < n; i++)
		{
			if ((Object)(object)buffer[i] == (Object)null)
			{
				continue;
			}
			Character ch = ((Component)buffer[i]).GetComponentInParent<Character>();
			if (!((Object)(object)ch == (Object)null) && (object)ch != _humanoid && !ch.IsDead() && visited.Add(((Object)ch).GetInstanceID()))
			{
				HitData hit = new HitData();
				hit.m_damage = dmg;
				hit.m_attacker = character.GetZDOID();
				hit.m_skill = skillType;
				hit.m_skillLevel = character.GetSkillLevel(skillType);
				hit.m_skillRaiseAmount = sa.m_raiseSkillAmount;
				hit.m_toolTier = (short)_weapon.m_shared.m_toolTier;
				hit.m_pushForce = pushForce;
				hit.m_backstabBonus = _weapon.m_shared.m_backstabBonus;
				hit.m_dodgeable = _weapon.m_shared.m_dodgeable;
				hit.m_blockable = _weapon.m_shared.m_blockable;
				hit.m_point = ch.GetCenterPoint();
				HitData obj = hit;
				Vector3 val = ch.GetCenterPoint() - center;
				obj.m_dir = ((Vector3)(ref val)).normalized;
				hit.m_hitType = (HitType)2;
				hit.SetAttacker(character);
				if ((Object)(object)_weapon.m_shared.m_attackStatusEffect != (Object)null)
				{
					hit.m_statusEffectHash = _weapon.m_shared.m_attackStatusEffect.NameHash();
				}
				character.GetSEMan().ModifyAttack(skillType, ref hit);
				ch.Damage(hit);
				EffectList efx = _weapon.m_shared.m_hitEffect;
				if (efx != null && efx.HasEffects())
				{
					efx.Create(hit.m_point, Quaternion.LookRotation(-hit.m_dir), ((Component)ch).transform, 1f, -1, default(ZDOID));
				}
				hitCount++;
			}
		}
		Plugin.Log.LogInfo((object)($"[CU-Hit] 직접 데미지 t={Time.time:F3}" + $" range={range:F1} skill={skillFactor:F2} dmg≈{((DamageTypes)(ref dmg)).GetTotalDamage():F1} 적={hitCount}"));
	}

	internal void ForceCleanup()
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		IsActive = false;
		IsInDuck = false;
		((MonoBehaviour)this).StopAllCoroutines();
		if (((PlayableGraph)(ref _activeGraph)).IsValid())
		{
			if ((Object)(object)_animator != (Object)null)
			{
				_animator.applyRootMotion = _graphRootMotionOrig;
			}
			((PlayableGraph)(ref _activeGraph)).Destroy();
			_activeGraph = default(PlayableGraph);
			Plugin.Log.LogInfo((object)"[CU] ForceCleanup: activeGraph 긴급 제거");
		}
		if ((Object)(object)_player != (Object)null)
		{
			_fInDodge?.SetValue(_player, false);
		}
	}

	private void OnDestroy()
	{
		ForceCleanup();
	}
}
[HarmonyPatch(typeof(Humanoid), "GetAttackSpeedFactorMovement")]
internal static class Spinkick_Patch_MoveSpeed
{
	private static void Postfix(Humanoid __instance, ref float __result)
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		if ((object)__instance == Player.m_localPlayer)
		{
			SpinkickController component = ((Component)Player.m_localPlayer).GetComponent<SpinkickController>();
			if (!((Object)(object)component == (Object)null) && component.IsActive)
			{
				__result = Mathf.Min(__result, Plugin.CuSpinkickMoveFactor.Value);
			}
		}
	}
}
[HarmonyPatch(typeof(Humanoid), "GetAttackSpeedFactorRotation")]
internal static class Spinkick_Patch_TurnSpeed
{
	private static void Postfix(Humanoid __instance, ref float __result)
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		if ((object)__instance == Player.m_localPlayer)
		{
			SpinkickController component = ((Component)Player.m_localPlayer).GetComponent<SpinkickController>();
			if (!((Object)(object)component == (Object)null) && component.IsActive)
			{
				__result = Mathf.Min(__result, Plugin.CuSpinkickTurnFactor.Value);
			}
		}
	}
}
[HarmonyPatch(typeof(Character), "Damage")]
internal static class Spinkick_Patch_DodgeDetect
{
	private static bool Prefix(Character __instance, HitData hit)
	{
		//IL_002f: 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_0064: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)Player.m_localPlayer == (Object)null)
		{
			return true;
		}
		if ((object)__instance != Player.m_localPlayer)
		{
			return true;
		}
		SpinkickController component = ((Component)Player.m_localPlayer).GetComponent<SpinkickController>();
		if ((Object)(object)component == (Object)null || !component.IsInDuck)
		{
			return true;
		}
		if (hit.m_attacker == ((Character)Player.m_localPlayer).GetZDOID())
		{
			return true;
		}
		Plugin.Log.LogInfo((object)$"[CU-Dodge] Damage 차단 t={Time.time:F3}");
		return false;
	}
}
internal static class SpinkickLoader
{
	private static AnimationClip _clip;

	private static bool _attempted;

	internal static AnimationClip GetClip()
	{
		if (_attempted)
		{
			return _clip;
		}
		_attempted = true;
		using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("SpecialAttackPlugin.Assets.spinkick");
		if (stream == null)
		{
			Plugin.Log.LogWarning((object)"[Spinkick] EmbeddedResource 없음: SpecialAttackPlugin.Assets.spinkick");
			return null;
		}
		byte[] array = new byte[stream.Length];
		stream.Read(array, 0, array.Length);
		AssetBundle val = AssetBundle.LoadFromMemory(array);
		if ((Object)(object)val == (Object)null)
		{
			Plugin.Log.LogWarning((object)"[Spinkick] AssetBundle 로드 실패");
			return null;
		}
		AnimationClip[] array2 = val.LoadAllAssets<AnimationClip>();
		_clip = ((array2.Length != 0) ? array2[0] : null);
		val.Unload(false);
		if ((Object)(object)_clip == (Object)null)
		{
			Plugin.Log.LogWarning((object)"[Spinkick] 번들에 AnimationClip이 없음");
		}
		else
		{
			Plugin.Log.LogInfo((object)$"[Spinkick] 클립 로드 성공: {((Object)_clip).name} ({_clip.length:F2}s)");
		}
		return _clip;
	}
}
internal static class ImpactBurstCooldown
{
	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 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 ImpactBurstFilter
{
	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 != 7)
		{
			return false;
		}
		if ((int)shared.m_itemType != 14)
		{
			return false;
		}
		GameObject dropPrefab = weapon.m_dropPrefab;
		string text = ((dropPrefab != null) ? ((Object)dropPrefab).name : null) ?? string.Empty;
		return text.IndexOf("battleaxe", StringComparison.OrdinalIgnoreCase) >= 0;
	}
}
internal static class ImpactBurstSystem
{
	private sealed class ThrownState
	{
		public Character Attacker;

		public ItemData WeaponData;

		public HitData HitData;
	}

	private static readonly ConditionalWeakTable<Projectile, ThrownState> _thrown = new ConditionalWeakTable<Projectile, ThrownState>();

	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 bool _pending;

	private static Player _pendingPlayer;

	private static ItemData _pendingWeapon;

	private static GameObject _cachedCarrier;

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

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

	internal static void QueueTrigger(Humanoid humanoid)
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Expected O, but got Unknown
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.IbEnable.Value)
		{
			return;
		}
		ItemData currentWeapon = humanoid.GetCurrentWeapon();
		if (!ImpactBurstFilter.Matches(currentWeapon))
		{
			return;
		}
		Character val = (Character)humanoid;
		if (!val.IsOwner())
		{
			return;
		}
		Player val2 = (Player)(object)((humanoid is Player) ? humanoid : null);
		if (!((Object)(object)val2 == (Object)null) && (!(Plugin.IbMinSkillLevel.Value > 0f) || !(((Character)val2).GetSkillLevel((SkillType)7) < Plugin.IbMinSkillLevel.Value)) && !ImpactBurstCooldown.CollectEntry(val, out var _))
		{
			_pending = true;
			_pendingPlayer = val2;
			_pendingWeapon = currentWeapon;
			Animator componentInChildren = ((Component)humanoid).GetComponentInChildren<Animator>();
			ZSyncAnimation zAnim = val.GetZAnim();
			if (zAnim != null)
			{
				zAnim.SetTrigger("OverheadSlashBattleaxe");
			}
			if (componentInChildren != null)
			{
				componentInChildren.CrossFade("OverheadSlashBattleaxe", 0.1f, 0, 0f);
			}
			Plugin.Log.LogInfo((object)("[IB] Queued | wep=" + currentWeapon.m_shared.m_name));
		}
	}

	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_00b4: 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 && (object)humanoid == _pendingPlayer)
		{
			_pending = false;
			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 (ImpactBurstCooldown.TryConsume(c, Plugin.IbCooldown.Value, icon))
			{
				SaVfx.PlayAdrenaline1(((Component)_pendingPlayer).transform.position);
				SpawnThrowProjectile(_pendingPlayer, _pendingWeapon);
			}
		}
	}

	private static void SpawnThrowProjectile(Player player, ItemData weapon)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Expected O, but got Unknown
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: 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_0097: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Expected O, but got Unknown
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: 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_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: 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_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		Character val = (Character)player;
		GameObject val2 = FindCarrierPrefab();
		if ((Object)(object)val2 == (Object)null)
		{
			Plugin.Log.LogWarning((object)"[IB] 캐리어 프로젝타일 없음 — 빌드 후 재시작 필요");
			return;
		}
		ItemData val3 = weapon.Clone();
		val3.m_equipped = false;
		((Humanoid)player).UnequipItem(weapon, false);
		((Humanoid)player).GetInventory().RemoveItem(weapon);
		Vector3 val4 = (((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform.forward : ((Component)val).transform.forward);
		Vector3 val5 = val.GetEyePoint() + val4 * 0.6f;
		Vector3 val6 = val4;
		float value = Plugin.IbThrowSpeed.Value;
		HitData val7 = new HitData();
		val7.m_damage = val3.GetDamage();
		val7.m_skill = (SkillType)7;
		val7.m_pushForce = val3.m_shared.m_attackForce;
		val7.m_blockable = false;
		val7.m_dodgeable = false;
		val7.m_skillRaiseAmount = 0f;
		val7.SetAttacker(val);
		GameObject val8 = Object.Instantiate<GameObject>(val2, val5, Quaternion.LookRotation(val6));
		Projectile component = val8.GetComponent<Projectile>();
		IProjectile component2 = val8.GetComponent<IProjectile>();
		if ((Object)(object)component == (Object)null || component2 == null)
		{
			Object.Destroy((Object)(object)val8);
			((Humanoid)player).GetInventory().AddItem(val3);
			Plugin.Log.LogWarning((object)"[IB] Projectile 컴포넌트 없음 — 무기 복원");
			return;
		}
		ApplyWeaponVisual(val8, val3);
		component2.Setup(val, val6 * value, 0f, val7, val3, (ItemData)null);
		component.m_respawnItemOnHit = false;
		component.m_spawnItem = null;
		component.m_spawnOnTtl = false;
		component.m_ttl = Mathf.Max(component.m_ttl, 8f);
		_thrown.Remove(component);
		_thrown.Add(component, new ThrownState
		{
			Attacker = val,
			WeaponData = val3,
			HitData = val7
		});
		Plugin.Log.LogInfo((object)("[IB] Thrown | wep=" + val3.m_shared.m_name + " prefab=" + ((Object)val2).name));
	}

	internal static void TryTriggerOnHit(Projectile projectile, Vector3 hitPoint, bool water)
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: 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_005d: 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_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)projectile == (Object)null) && _thrown.TryGetValue(projectile, out var value))
		{
			_thrown.Remove(projectile);
			if (!((Object)(object)value.Attacker == (Object)null) && !value.Attacker.IsDead())
			{
				Vector3 pos = (water ? (hitPoint + Vector3.up * 1f) : (hitPoint + Vector3.up * 0.3f));
				DropWeaponItem(value.WeaponData, pos);
				projectile.m_spawnOnTtl = false;
				SpawnBurstVFX(hitPoint);
				ApplyBurst(value, hitPoint);
				Plugin.Log.LogInfo((object)$"[IB] Burst | origin={hitPoint} radius={Plugin.IbRadius.Value:F2}");
			}
		}
	}

	private static void ApplyBurst(ThrownState state, Vector3 origin)
	{
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		float num = Mathf.Max(0f, Plugin.IbRadius.Value);
		float dmgFactor = Mathf.Max(0f, Plugin.IbDamageFactor.Value);
		float pushFactor = Mathf.Max(0f, Plugin.IbPushFactor.Value);
		if (num <= 0f)
		{
			return;
		}
		_hitSet.Clear();
		int num2 = Physics.OverlapSphereNonAlloc(origin, num, _hitBuf, GetMaskChars(), (QueryTriggerInteraction)0);
		for (int i = 0; i < num2; i++)
		{
			Collider val = _hitBuf[i];
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			GameObject val2 = Projectile.FindHitObject(val);
			if (!((Object)(object)val2 == (Object)null) && _hitSet.Add(val2))
			{
				Character componentInParent = val2.GetComponentInParent<Character>();
				if (!((Object)(object)componentInParent == (Object)null) && componentInParent != state.Attacker && !componentInParent.IsDead() && BaseAI.IsEnemy(state.Attacker, componentInParent) && !componentInParent.InDodge() && !componentInParent.IsDebugFlying())
				{
					ApplyHit(state, componentInParent, origin, dmgFactor, pushFactor);
				}
			}
		}
	}

	private static void ApplyHit(ThrownState state, Character target, Vector3 origin, float dmgFactor, float pushFactor)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Expected O, but got Unknown
		//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)
		//IL_003c: 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_0080: 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_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: 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_00bf: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
		DamageTypes damage = ((DamageTypes)(ref state.HitData.m_damage)).Clone();
		if (!Mathf.Approximately(dmgFactor, 1f))
		{
			((DamageTypes)(ref damage)).Modify(dmgFactor);
		}
		HitData val = new HitData();
		val.m_damage = damage;
		val.m_skill = (SkillType)7;
		val.m_pushForce = state.HitData.m_pushForce * pushFactor;
		val.m_staggerMultiplier = 1f;
		val.m_blockable = false;
		val.m_dodgeable = false;
		val.m_skillRaiseAmount = 0f;
		val.m_point = target.GetCenterPoint();
		Vector3 val2 = Vector3.ProjectOnPlane(target.GetCenterPoint() - origin, Vector3.up);
		val.m_dir = ((((Vector3)(ref val2)).sqrMagnitude > 0.001f) ? ((Vector3)(ref val2)).normalized : ((Component)state.Attacker).transform.forward);
		val.SetAttacker(state.Attacker);
		target.Damage(val);
	}

	private static void ApplyWeaponVisual(GameObject projGo, ItemData weapon)
	{
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Expected O, but got Unknown
		//IL_0069: 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_008b: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)weapon?.m_dropPrefab == (Object)null))
		{
			Renderer[] componentsInChildren = projGo.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				val.enabled = false;
			}
			GameObject val2 = new GameObject("IB_WeaponVisual");
			val2.transform.SetParent(projGo.transform);
			val2.transform.localPosition = Vector3.zero;
			val2.transform.localRotation = Quaternion.identity;
			val2.transform.localScale = Vector3.one;
			CopyMeshRenderers(weapon.m_dropPrefab, val2.transform);
			ImpactBurstWeaponSpin impactBurstWeaponSpin = val2.AddComponent<ImpactBurstWeaponSpin>();
			impactBurstWeaponSpin.Initialize(Plugin.IbSpinSpeed.Value);
		}
	}

	private static void CopyMeshRenderers(GameObject source, Transform parent)
	{
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Expected O, but got Unknown
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		MeshRenderer[] componentsInChildren = source.GetComponentsInChildren<MeshRenderer>(true);
		foreach (MeshRenderer val in componentsInChildren)
		{
			MeshFilter component = ((Component)val).GetComponent<MeshFilter>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)component.sharedMesh == (Object)null))
			{
				GameObject val2 = new GameObject(((Object)((Component)val).gameObject).name);
				val2.transform.SetParent(parent);
				val2.transform.localPosition = source.transform.InverseTransformPoint(((Component)val).transform.position);
				val2.transform.localRotation = Quaternion.Inverse(source.transform.rotation) * ((Component)val).transform.rotation;
				val2.transform.localScale = ((Component)val).transform.lossyScale;
				MeshFilter val3 = val2.AddComponent<MeshFilter>();
				val3.sharedMesh = component.sharedMesh;
				MeshRenderer val4 = val2.AddComponent<MeshRenderer>();
				((Renderer)val4).sharedMaterials = ((Renderer)val).sharedMaterials;
			}
		}
	}

	private static void DropWeaponItem(ItemData itemData, Vector3 pos)
	{
		//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)
		if (!((Object)(object)itemData?.m_dropPrefab == (Object)null))
		{
			GameObject val = Object.Instantiate<GameObject>(itemData.m_dropPrefab, pos, Quaternion.identity);
			ItemDrop component = val.GetComponent<ItemDrop>();
			if (!((Object)(object)component == (Object)null))
			{
				component.m_itemData = itemData.Clone();
				component.m_itemData.m_stack = 1;
				component.m_itemData.m_equipped = false;
			}
		}
	}

	private static GameObject FindCarrierPrefab()
	{
		if ((Object)(object)_cachedCarrier != (Object)null)
		{
			return _cachedCarrier;
		}
		if ((Object)(object)ObjectDB.instance != (Object)null)
		{
			string[] array = new string[6] { "SpearFlint", "SpearBronze", "SpearChitin", "SpearWolfFang", "SpearElderbark", "Spear" };
			foreach (string text in array)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text);
				GameObject val = ((itemPrefab == null) ? null : itemPrefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_secondaryAttack?.m_attackProjectile);
				if ((Object)(object)val != (Object)null)
				{
					_cachedCarrier = val;
					Plugin.Log.LogInfo((object)("[IB] 캐리어: " + ((Object)val).name + " (" + text + " secondary)"));
					return _cachedCarrier;
				}
			}
		}
		if ((Object)(object)ZNetScene.instance != (Object)null)
		{
			string[] array2 = new string[3] { "projectile_spear", "projectile_spear_chitin", "projectile_knife" };
			foreach (string text2 in array2)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(text2);
				if ((Object)(object)((prefab != null) ? prefab.GetComponent<Projectile>() : null) != (Object)null)
				{
					_cachedCarrier = prefab;
					Plugin.Log.LogInfo((object)("[IB] 캐리어: " + text2 + " (ZNetScene)"));
					return _cachedCarrier;
				}
			}
		}
		return null;
	}

	private static void SpawnBurstVFX(Vector3 origin)
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)ZNetScene.instance == (Object)null)
		{
			return;
		}
		string[] vfxNames = _vfxNames;
		foreach (string text in vfxNames)
		{
			GameObject prefab = ZNetScene.instance.GetPrefab(text);
			if (!((Object)(object)prefab == (Object)null))
			{
				Object.Instantiate<GameObject>(prefab, origin, Quaternion.identity);
				Plugin.Log.LogInfo((object)("[IB VFX] " + text));
				break;
			}
		}
	}
}
internal sealed class ImpactBurstWeaponSpin : MonoBehaviour
{
	private float _spinSpeed;

	internal void Initialize(float spinSpeed)
	{
		_spinSpeed = spinSpeed;
	}

	private void Update()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		((Component)this).transform.Rotate(Vector3.right, _spinSpeed * Time.deltaTime, (Space)1);
	}
}
internal static class LaunchSlamCooldown
{
	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 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 LaunchSlamFilter
{
	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 LaunchSlamSystem
{
	internal const float MinAirTime = 0.2f;

	internal const float LandingTimeout = 3f;

	private static bool _pending;

	private static ZDOID _pendingAttacker;

	private static readonly FieldInfo _bodyField = AccessTools.Field(typeof(Character), "m_body");

	internal static bool IsApplyingLandingDamage { get; private set; }

	internal static void OnSecondaryStarted(Humanoid humanoid)
	{
		//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_007c: Unknown result type (might be due to invalid IL or missing references)
		if (Plugin.LsEnable.Value && LaunchSlamFilter.Matches(humanoid.GetCurrentWeapon()))
		{
			Player val = (Player)(object)((humanoid is Player) ? humanoid : null);
			if (!((Object)(object)val != (Object)null) || !(Plugin.LsMinSkillLevel.Value > 0f) || !(((Character)val).GetSkillLevel((SkillType)3) < Plugin.LsMinSkillLevel.Value))
			{
				_pending = true;
				_pendingAttacker = ((Character)humanoid).GetZDOID();
			}
		}
	}

	internal static void TryApply(Character target, ref HitData hit)
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Expected O, but got Unknown
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: Unknown result type (might be due to invalid IL or missing references)
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
		if (IsApplyingLandingDamage || !_pending || !Plugin.LsEnable.Value || hit.m_attacker != _pendingAttacker || ((DamageTypes)(ref hit.m_damage)).GetTotalDamage() <= 0f || (Object)(object)target == (Object)null || target.IsDead())
		{
			return;
		}
		_pending = false;
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return;
		}
		Character val = (Character)localPlayer;
		if (target == val)
		{
			return;
		}
		ItemData currentWeapon = ((Humanoid)localPlayer).GetCurrentWeapon();
		Sprite icon = ((currentWeapon != null && currentWeapon.m_shared?.m_icons?.Length > 0) ? currentWeapon.m_shared.m_icons[0] : null);
		if (!LaunchSlamCooldown.TryConsume(val, Plugin.LsCooldown.Value, icon))
		{
			return;
		}
		float num = Mathf.Max(0f, Plugin.LsLaunchHeight.Value);
		if (!(num <= 0f))
		{
			DamageTypes landingDamage = ((DamageTypes)(ref hit.m_damage)).Clone();
			((DamageTypes)(ref landingDamage)).Modify(Mathf.Max(0f, Plugin.LsDamageFactor.Value));
			if (!(((DamageTypes)(ref landingDamage)).GetTotalDamage() <= 0f) && TryLaunchTarget(target, num))
			{
				hit.m_pushForce = 0f;
				LaunchSlamLandingTracker launchSlamLandingTracker = ((Component)target).GetComponent<LaunchSlamLandingTracker>() ?? ((Component)target).gameObject.AddComponent<LaunchSlamLandingTracker>();
				launchSlamLandingTracker.Initialize(target, val, hit, landingDamage, num);
				SaVfx.PlayAdrenaline1(((Component)val).transform.position);
			}
		}
	}

	private static bool TryLaunchTarget(Character target, float liftHeight)
	{
		//IL_0060: 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_008b: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
		if (!target.IsOwner())
		{
			return false;
		}
		object? obj = _bodyField?.GetValue(target);
		Rigidbody val = (Rigidbody)(((obj is Rigidbody) ? obj : null) ?? ((Component)target).GetComponent<Rigidbody>());
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		if (val.isKinematic)
		{
			val.isKinematic = false;
		}
		float num = Mathf.Abs(Physics.gravity.y) * 25f;
		float num2 = Mathf.Sqrt(2f * num * liftHeight);
		Vector3 linearVelocity = val.linearVelocity;
		linearVelocity.y = Mathf.Max(linearVelocity.y, num2);
		val.linearVelocity = linearVelocity;
		return true;
	}

	internal static void ApplyLandingDamage(Character target, Character attacker, HitData sourceHit, DamageTypes landingDamage)
	{
		//IL_0047: Unknown result type (might be due to invalid IL or missing references