Decompiled source of SpecialAttack v1.1.0

plugins/SpecialAttackPlugin.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
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.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[2] { "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_0241: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: 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_01d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01da: 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 != 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)
				{
					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_00f9: 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_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: 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)
		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);
					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);
		}
		else
		{
			Plugin.Log.LogWarning((object)"[AS VFX] NO VFX");
		}
	}

	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 CounterUpperFilter
{
	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 CounterUpperCooldown
{
	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 CounterUpperSystem
{
	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_0148: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.CuEnable.Value)
		{
			return false;
		}
		ItemData currentWeapon = humanoid.GetCurrentWeapon();
		if (!CounterUpperFilter.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 (!CounterUpperCooldown.TryConsume(val, Plugin.CuCooldown.Value, icon))
		{
			return false;
		}
		SaVfx.PlayAdrenaline1(((Component)val2).transform.position);
		CounterUpperController.Begin(humanoid, currentWeapon);
		Plugin.Log.LogInfo((object)"[CU] SA 차단 → 더킹+어퍼컷 시작");
		return true;
	}
}
internal sealed class CounterUpperController : MonoBehaviour
{
	private static readonly FieldInfo _fInDodge = AccessTools.Field(typeof(Player), "m_inDodge");

	private static readonly FieldInfo _fDodgeInvincible = AccessTools.Field(typeof(Player), "m_dodgeInvincible");

	private static readonly FieldInfo _fDodgeInvincCached = AccessTools.Field(typeof(Player), "m_dodgeInvincibleCached");

	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 int _hashDodge = Animator.StringToHash("dodge");

	private const string UppercutTrigger = "RightPowerUppercut_TW";

	private Humanoid _humanoid;

	private Player _player;

	private Animator _animator;

	private ZSyncAnimation _zsync;

	internal bool IsActive;

	internal bool IsInDuck;

	internal bool CounterReady;

	internal bool IsFiringNext;

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

	private void Setup(Humanoid humanoid, ItemData weapon)
	{
		//IL_001d: 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)
		_humanoid = humanoid;
		_player = (Player)(object)((humanoid is Player) ? humanoid : null);
		IsActive = true;
		_zsync = ((Component)humanoid).GetComponentInChildren<ZSyncAnimation>();
		_animator = (Animator)((_fZsyncAnimator != null && (Object)(object)_zsync != (Object)null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)((Component)humanoid).GetComponentInChildren<Animator>()));
		((MonoBehaviour)this).StartCoroutine(DuckThenUppercut());
	}

	private IEnumerator DuckThenUppercut()
	{
		IsInDuck = false;
		CounterReady = false;
		if ((Object)(object)_player != (Object)null)
		{
			Animator animator = _animator;
			if (animator != null)
			{
				animator.SetTrigger(_hashDodge);
			}
			_fInDodge?.SetValue(_player, true);
			IsInDuck = true;
			Plugin.Log.LogInfo((object)"[CU] 더킹 시작");
		}
		yield return (object)new WaitForSeconds(Plugin.CuDodgeTime.Value);
		_fInDodge?.SetValue(_player, false);
		float remaining = Plugin.CuDuckTime.Value - Plugin.CuDodgeTime.Value;
		if (remaining > 0f)
		{
			yield return (object)new WaitForSeconds(remaining);
		}
		if ((Object)(object)_player != (Object)null)
		{
			IsInDuck = false;
			Plugin.Log.LogInfo((object)$"[CU] 더킹 종료 — counter={CounterReady}");
		}
		yield return (object)new WaitForSeconds(0.05f);
		if ((Object)(object)_humanoid == (Object)null || !IsActive)
		{
			yield break;
		}
		Character ch = (Character)_humanoid;
		IsFiringNext = true;
		bool started = ch.StartAttack((Character)null, false);
		IsFiringNext = false;
		Plugin.Log.LogInfo((object)$"[CU] 어퍼컷 StartAttack={started}");
		if (started)
		{
			yield return null;
			while (ch.InAttack())
			{
				if ((Object)(object)_zsync != (Object)null)
				{
					_zsync.SetSpeed(Plugin.CuUppercutSpeed.Value);
				}
				yield return null;
			}
			ZSyncAnimation zsync = _zsync;
			if (zsync != null)
			{
				zsync.SetSpeed(1f);
			}
		}
		IsActive = false;
	}

	internal void OverrideAnimTrigger(Attack attack)
	{
		if ((Object)(object)_zsync == (Object)null || !IsActive)
		{
			return;
		}
		string text = ((_fAnimBase != null) ? ((string)_fAnimBase.GetValue(attack)) : null);
		if (!string.IsNullOrEmpty(text) && (Object)(object)_animator != (Object)null)
		{
			_animator.ResetTrigger(text);
			for (int i = 0; i < 4; i++)
			{
				_animator.ResetTrigger(text + i);
			}
		}
		_zsync.SetTrigger("RightPowerUppercut_TW");
		Plugin.Log.LogInfo((object)string.Format("[CU-Anim] → {0} (animBase={1} counter={2})", "RightPowerUppercut_TW", text, CounterReady));
	}

	internal void ForceCleanup()
	{
		IsActive = false;
		IsInDuck = false;
		IsFiringNext = false;
		CounterReady = false;
		ZSyncAnimation zsync = _zsync;
		if (zsync != null)
		{
			zsync.SetSpeed(1f);
		}
		if ((Object)(object)_player != (Object)null)
		{
			_fInDodge?.SetValue(_player, false);
		}
	}

	private void OnDestroy()
	{
		ForceCleanup();
	}
}
[HarmonyPatch(typeof(Character), "Damage")]
internal static class CounterUpper_Patch_DodgeDetect
{
	private static void Prefix(Character __instance, HitData hit)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)Player.m_localPlayer == (Object)null) && (object)__instance == Player.m_localPlayer)
		{
			CounterUpperController component = ((Component)Player.m_localPlayer).GetComponent<CounterUpperController>();
			if (!((Object)(object)component == (Object)null) && component.IsInDuck && !(hit.m_attacker == ((Character)Player.m_localPlayer).GetZDOID()))
			{
				hit.m_damage.m_damage = 0f;
				hit.m_damage.m_blunt = 0f;
				hit.m_damage.m_slash = 0f;
				hit.m_damage.m_pierce = 0f;
				hit.m_damage.m_chop = 0f;
				hit.m_damage.m_pickaxe = 0f;
				hit.m_damage.m_fire = 0f;
				hit.m_damage.m_frost = 0f;
				hit.m_damage.m_lightning = 0f;
				hit.m_damage.m_poison = 0f;
				hit.m_damage.m_spirit = 0f;
				component.CounterReady = true;
				Plugin.Log.LogInfo((object)"[CU] 카운터 판정 성공 — 피격 차단");
			}
		}
	}
}
[HarmonyPatch(typeof(Character), "RPC_Damage")]
internal static class CounterUpper_Patch_ApplyMult
{
	private static void Prefix(Character __instance, long sender, 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()))
		{
			CounterUpperController component = ((Component)Player.m_localPlayer).GetComponent<CounterUpperController>();
			if (!((Object)(object)component == (Object)null) && component.IsActive && component.CounterReady && !Mathf.Approximately(Plugin.CuCounterMult.Value, 1f))
			{
				((DamageTypes)(ref hit.m_damage)).Modify(Plugin.CuCounterMult.Value);
				component.CounterReady = false;
				Plugin.Log.LogInfo((object)$"[CU] 카운터 데미지 ×{Plugin.CuCounterMult.Value}");
			}
		}
	}
}
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)
		//IL_004c: 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_0093: 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)
		if ((Object)(object)target == (Object)null || (Object)(object)attacker == (Object)null || target.IsDead() || ((DamageTypes)(ref landingDamage)).GetTotalDamage() <= 0f)
		{
			return;
		}
		Vector3 position = ((Component)target).transform.position;
		float value = Plugin.LsLandingRadius.Value;
		List<Character> list = GatherLandingTargets(target, attacker, position, value);
		if (list.Count == 0)
		{
			return;
		}
		IsApplyingLandingDamage = true;
		try
		{
			foreach (Character item in list)
			{
				ApplyLandingHit(item, attacker, sourceHit, landingDamage, position);
			}
		}
		finally
		{
			IsApplyingLandingDamage = false;
		}
	}

	private static List<Character> GatherLandingTargets(Character source, Character attacker, Vector3 origin, float radius)
	{
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		List<Character> list = new List<Character>();
		HashSet<Character> hashSet = new HashSet<Character>();
		if (!source.IsDead())
		{
			hashSet.Add(source);
			list.Add(source);
		}
		if (radius <= 0f)
		{
			return list;
		}
		foreach (Character allCharacter in Character.GetAllCharacters())
		{
			if (!((Object)(object)allCharacter == (Object)null) && !allCharacter.IsDead() && allCharacter != source && allCharacter != attacker && hashSet.Add(allCharacter) && (BaseAI.IsEnemy(attacker, allCharacter) || (attacker.IsPlayer() && (Object)(object)allCharacter.GetBaseAI() != (Object)null && allCharacter.GetBaseAI().IsAggravatable())))
			{
				Vector3 val = allCharacter.GetCenterPoint() - origin;
				val.y = 0f;
				if (((Vector3)(ref val)).magnitude <= radius)
				{
					list.Add(allCharacter);
				}
			}
		}
		return list;
	}

	private static void ApplyLandingHit(Character target, Character attacker, HitData sourceHit, DamageTypes landingDamage, Vector3 origin)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_009d: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)target == (Object)null) && !target.IsDead())
		{
			HitData val = sourceHit.Clone();
			val.m_damage = ((DamageTypes)(ref landingDamage)).Clone();
			val.m_pushForce = 0f;
			val.m_staggerMultiplier = 0f;
			val.m_skillRaiseAmount = 0f;
			val.m_blockable = false;
			val.m_dodgeable = false;
			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 : Vector3.down);
			val.m_hitCollider = null;
			val.SetAttacker(attacker);
			target.Damage(val);
		}
	}
}
internal sealed class LaunchSlamLandingTracker : MonoBehaviour
{
	private Character _target;

	private Character _attacker;

	private HitData _sourceHit;

	private DamageTypes _landingDamage = default(DamageTypes);

	private float _startTime;

	private float _startHeight;

	private float _targetApexHeight;

	private bool _hasBeenAirborne;

	internal void Initialize(Character target, Character attacker, HitData sourceHit, DamageTypes landingDamage, float launchHeight)
	{
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		if (_sourceHit == null || !(((DamageTypes)(ref landingDamage)).GetTotalDamage() <= ((DamageTypes)(ref _landingDamage)).GetTotalDamage()))
		{
			Plugin.Log.LogInfo((object)$"[LS] Tracker Initialize: target={((target != null) ? ((Object)target).name : null)} startY={((target != null) ? new float?(((Component)target).transform.position.y) : ((float?)null)):F2}");
			_target = target;
			_attacker = attacker;
			_sourceHit = sourceHit.Clone();
			_landingDamage = ((DamageTypes)(ref landingDamage)).Clone();
			_targetApexHeight = ((Component)target).transform.position.y + Mathf.Max(0f, launchHeight);
			_startTime = Time.time;
			_startHeight = ((Component)target).transform.position.y;
			_hasBeenAirborne = false;
			((Behaviour)this).enabled = true;
		}
	}

	private void Update()
	{
		//IL_00b0: 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_0155: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_target == (Object)null || (Object)(object)_attacker == (Object)null || _target.IsDead())
		{
			Object.Destroy((Object)(object)this);
			return;
		}
		if (Time.time - _startTime > 3f)
		{
			Plugin.Log.LogInfo((object)$"[LS] Tracker timeout. airborne={_hasBeenAirborne} y={((Component)_target).transform.position.y:F2} startY={_startHeight:F2}");
			Object.Destroy((Object)(object)this);
			return;
		}
		float y = ((Component)_target).transform.position.y;
		if (y > _startHeight + 0.5f)
		{
			_hasBeenAirborne = true;
		}
		if (_hasBeenAirborne && !(Time.time - _startTime < 0.2f) && y <= _startHeight + 0.5f)
		{
			Plugin.Log.LogInfo((object)$"[LS] Landing! y={y:F2} startY={_startHeight:F2}");
			LaunchSlamSystem.ApplyLandingDamage(_target, _attacker, _sourceHit, _landingDamage);
			Object.Destroy((Object)(object)this);
		}
	}
}
[BepInPlugin("com.specialattack.plugin", "SpecialAttack", "1.0.0")]
[BepInProcess("valheim.exe")]
public class Plugin : BaseUnityPlugin
{
	public const string GUID = "com.specialattack.plugin";

	public const string NAME = "SpecialAttack";

	public const string VERSION = "1.0.0";

	private readonly Harmony _harmony = new Harmony("com.specialattack.plugin");

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> EnableBattleHammer;

	internal static ConfigEntry<float> Cooldown;

	internal static ConfigEntry<float> LoopStart;

	internal static ConfigEntry<float> LoopEnd;

	internal static ConfigEntry<float> AnimationSpeed;

	internal static ConfigEntry<float> BattleHammerMoveSpeedFactor;

	internal static ConfigEntry<float> SkillRaiseFactor;

	internal static ConfigEntry<float> SsMinSkillLevel;

	internal static ConfigEntry<bool> KcEnable;

	internal static ConfigEntry<float> KcCooldown;

	internal static ConfigEntry<float> KcMinSkillLevel;

	internal static ConfigEntry<float> KcPushFactor;

	internal static ConfigEntry<int> KcMaxChainTargets;

	internal static ConfigEntry<float> KcCollisionRadius;

	internal static ConfigEntry<float> KcChainDecay;

	internal static ConfigEntry<float> KcChainDamageFactor;

	internal static ConfigEntry<bool> LsEnable;

	internal static ConfigEntry<float> LsCooldown;

	internal static ConfigEntry<float> LsMinSkillLevel;

	internal static ConfigEntry<float> LsLaunchHeight;

	internal static ConfigEntry<float> LsDamageFactor;

	internal static ConfigEntry<float> LsLandingRadius;

	internal static ConfigEntry<bool> SaEnable;

	internal static ConfigEntry<float> SaCooldown;

	internal static ConfigEntry<float> SaMinSkillLevel;

	internal static ConfigEntry<float> SaChargeTime;

	internal static ConfigEntry<float> SaChargeSpeedFactor;

	internal static ConfigEntry<float> SaAggroResetRadius;

	internal static ConfigEntry<float> SaBackstabBonus;

	internal static ConfigEntry<bool> AsEnable;

	internal static ConfigEntry<float> AsCooldown;

	internal static ConfigEntry<float> AsMinSkillLevel;

	internal static ConfigEntry<int> AsWaves;

	internal static ConfigEntry<float> AsInterval;

	internal static ConfigEntry<float> AsWaveDecay;

	internal static ConfigEntry<float> AsForwardStep;

	internal static ConfigEntry<float> AsRadius;

	internal static ConfigEntry<float> AsDamageFactor;

	internal static ConfigEntry<float> AsPushForce;

	internal static ConfigEntry<bool> QsEnable;

	internal static ConfigEntry<float> QsCooldown;

	internal static ConfigEntry<float> QsMinSkillLevel;

	internal static ConfigEntry<float> QsAnimSpeed1;

	internal static ConfigEntry<float> QsAnimSpeed2;

	internal static ConfigEntry<float> QsAnimSpeed3;

	internal static ConfigEntry<float> QsAnimSpeed4;

	internal static ConfigEntry<float> QsDamage1;

	internal static ConfigEntry<float> QsDamage2;

	internal static ConfigEntry<float> QsDamage3;

	internal static ConfigEntry<float> QsDamage4;

	internal static ConfigEntry<bool> CuEnable;

	internal static ConfigEntry<float> CuCooldown;

	internal static ConfigEntry<float> CuMinSkillLevel;

	internal static ConfigEntry<float> CuDuckTime;

	internal static ConfigEntry<float> CuCounterMult;

	internal static ConfigEntry<float> CuUppercutSpeed;

	internal static ConfigEntry<float> CuDodgeTime;

	internal static ConfigEntry<bool> IbEnable;

	internal static ConfigEntry<float> IbCooldown;

	internal static ConfigEntry<float> IbMinSkillLevel;

	internal static ConfigEntry<float> IbDamageFactor;

	internal static ConfigEntry<float> IbPushFactor;

	internal static ConfigEntry<float> IbRadius;

	internal static ConfigEntry<float> IbThrowSpeed;

	internal static ConfigEntry<float> IbSpinSpeed;

	internal static ConfigEntry<bool> ScEnable;

	internal stati