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 _states = new ConditionalWeakTable(); 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 _hitSet = new HashSet(); 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.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(); 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(); 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(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(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(); 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 _states = new ConditionalWeakTable(); 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() != (Object)null)) { Character val = (Character)humanoid; _zdoid = val.GetZDOID(); ChargeSlashController chargeSlashController = gameObject.AddComponent(); 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(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 _states = new ConditionalWeakTable(); 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(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() ?? ((Component)val2).GetComponentInChildren(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(); 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(true); if (componentsInChildren.Length == 0) { Plugin.Log.LogWarning((object)"[QS-VFX] 무기 모델에 MeleeWeaponTrail 없음"); return; } List list = new List(); List list2 = new List(); 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(); 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(); 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(); if ((Object)(object)component != (Object)null) { ((MonoBehaviour)component).StopAllCoroutines(); component.ForceCleanup(); } QuadSlashController quadSlashController = component ?? gameObject.AddComponent(); 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(); _animator = (Animator)((_fZsyncAnimator != null && (Object)(object)componentInChildren != (Object)null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)((Component)humanoid).GetComponentInChildren())); _animEvent = ((Component)humanoid).GetComponentInChildren(); 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() : 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() != (Object)(Character)localPlayer) { return; } QuadSlashController component = ((Component)localPlayer).GetComponent(); 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(); 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(); 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 _states = new ConditionalWeakTable(); 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(); if ((Object)(object)component != (Object)null) { ((MonoBehaviour)component).StopAllCoroutines(); component.ForceCleanup(); } CounterUpperController counterUpperController = component ?? gameObject.AddComponent(); 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(); _animator = (Animator)((_fZsyncAnimator != null && (Object)(object)_zsync != (Object)null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)((Component)humanoid).GetComponentInChildren())); ((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(); 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(); 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 _states = new ConditionalWeakTable(); 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 _thrown = new ConditionalWeakTable(); private static readonly Collider[] _hitBuf = (Collider[])(object)new Collider[64]; private static readonly HashSet _hitSet = new HashSet(); 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(); 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(val2, val5, Quaternion.LookRotation(val6)); Projectile component = val8.GetComponent(); IProjectile component2 = val8.GetComponent(); 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(); 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(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.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(true); foreach (MeshRenderer val in componentsInChildren) { MeshFilter component = ((Component)val).GetComponent(); 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(); val3.sharedMesh = component.sharedMesh; MeshRenderer val4 = val2.AddComponent(); ((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(itemData.m_dropPrefab, pos, Quaternion.identity); ItemDrop component = val.GetComponent(); 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()?.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() : 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(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 _states = new ConditionalWeakTable(); 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() ?? ((Component)target).gameObject.AddComponent(); 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()); 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 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 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 list = new List(); HashSet hashSet = new HashSet(); 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 EnableBattleHammer; internal static ConfigEntry Cooldown; internal static ConfigEntry LoopStart; internal static ConfigEntry LoopEnd; internal static ConfigEntry AnimationSpeed; internal static ConfigEntry BattleHammerMoveSpeedFactor; internal static ConfigEntry SkillRaiseFactor; internal static ConfigEntry SsMinSkillLevel; internal static ConfigEntry KcEnable; internal static ConfigEntry KcCooldown; internal static ConfigEntry KcMinSkillLevel; internal static ConfigEntry KcPushFactor; internal static ConfigEntry KcMaxChainTargets; internal static ConfigEntry KcCollisionRadius; internal static ConfigEntry KcChainDecay; internal static ConfigEntry KcChainDamageFactor; internal static ConfigEntry LsEnable; internal static ConfigEntry LsCooldown; internal static ConfigEntry LsMinSkillLevel; internal static ConfigEntry LsLaunchHeight; internal static ConfigEntry LsDamageFactor; internal static ConfigEntry LsLandingRadius; internal static ConfigEntry SaEnable; internal static ConfigEntry SaCooldown; internal static ConfigEntry SaMinSkillLevel; internal static ConfigEntry SaChargeTime; internal static ConfigEntry SaChargeSpeedFactor; internal static ConfigEntry SaAggroResetRadius; internal static ConfigEntry SaBackstabBonus; internal static ConfigEntry AsEnable; internal static ConfigEntry AsCooldown; internal static ConfigEntry AsMinSkillLevel; internal static ConfigEntry AsWaves; internal static ConfigEntry AsInterval; internal static ConfigEntry AsWaveDecay; internal static ConfigEntry AsForwardStep; internal static ConfigEntry AsRadius; internal static ConfigEntry AsDamageFactor; internal static ConfigEntry AsPushForce; internal static ConfigEntry QsEnable; internal static ConfigEntry QsCooldown; internal static ConfigEntry QsMinSkillLevel; internal static ConfigEntry QsAnimSpeed1; internal static ConfigEntry QsAnimSpeed2; internal static ConfigEntry QsAnimSpeed3; internal static ConfigEntry QsAnimSpeed4; internal static ConfigEntry QsDamage1; internal static ConfigEntry QsDamage2; internal static ConfigEntry QsDamage3; internal static ConfigEntry QsDamage4; internal static ConfigEntry CuEnable; internal static ConfigEntry CuCooldown; internal static ConfigEntry CuMinSkillLevel; internal static ConfigEntry CuDuckTime; internal static ConfigEntry CuCounterMult; internal static ConfigEntry CuUppercutSpeed; internal static ConfigEntry CuDodgeTime; internal static ConfigEntry IbEnable; internal static ConfigEntry IbCooldown; internal static ConfigEntry IbMinSkillLevel; internal static ConfigEntry IbDamageFactor; internal static ConfigEntry IbPushFactor; internal static ConfigEntry IbRadius; internal static ConfigEntry IbThrowSpeed; internal static ConfigEntry IbSpinSpeed; internal static ConfigEntry ScEnable; internal static ConfigEntry ScCooldown; internal static ConfigEntry ScMinSkillLevel; internal static ConfigEntry ScChainWindow; internal static ConfigEntry ScAnimSpeed; internal static ConfigEntry ScDamage1; internal static ConfigEntry ScDamage2; internal static ConfigEntry ScDamage3; internal static ConfigEntry SpEnable; internal static ConfigEntry SpCooldown; internal static ConfigEntry SpMinSkillLevel; internal static ConfigEntry SpSpeedFactor; internal static ConfigEntry SpPinDuration; internal static ConfigEntry SpPullRange; internal static ConfigEntry SpPullRestoreTime; internal static ConfigEntry TtEnable; internal static ConfigEntry TtCooldown; internal static ConfigEntry TtMinSkillLevel; internal static ConfigEntry TtStaggerMultiplier; internal static ConfigEntry TtAnimSpeed; internal static ConfigEntry TtRange; internal static ConfigEntry CsEnable; internal static ConfigEntry CsCooldown; internal static ConfigEntry CsMinSkillLevel; internal static ConfigEntry CsMaxChargeTime; internal static ConfigEntry CsDamageMult; internal static ConfigEntry CsHitVfxName; internal static ConfigEntry HudX; internal static ConfigEntry HudY; internal static ConfigEntry SpecialKey; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; EnableBattleHammer = ((BaseUnityPlugin)this).Config.Bind("SpinningSweep", "EnableBattleHammer", true, "배틀해머류 — Clubs + TwoHandedWeapon (슬렛지해머 제외)"); Cooldown = ((BaseUnityPlugin)this).Config.Bind("SpinningSweep", "Cooldown", 8f, "쿨타임 (초)"); LoopStart = ((BaseUnityPlugin)this).Config.Bind("SpinningSweep", "LoopStart", 0.4f, "루프 시작 normalizedTime (0~1)"); LoopEnd = ((BaseUnityPlugin)this).Config.Bind("SpinningSweep", "LoopEnd", 0.6f, "루프 종료 normalizedTime (0~1)"); AnimationSpeed = ((BaseUnityPlugin)this).Config.Bind("SpinningSweep", "AnimationSpeed", 1f, "애니메이션 재생 속도"); BattleHammerMoveSpeedFactor = ((BaseUnityPlugin)this).Config.Bind("SpinningSweep", "BattleHammerMoveSpeedFactor", 0.3f, "배틀해머 스피닝 중 이동속도 배율"); SkillRaiseFactor = ((BaseUnityPlugin)this).Config.Bind("SpinningSweep", "SkillRaiseFactor", 0.25f, "루프 1회당 스킬 경험치 배율"); SsMinSkillLevel = ((BaseUnityPlugin)this).Config.Bind("SpinningSweep", "MinSkillLevel", 0f, "스킬 발동 최소 레벨 (0~100, 0 = 제한 없음)"); KcEnable = ((BaseUnityPlugin)this).Config.Bind("KnockbackChain", "Enable", true, "비무장(주먹) 세컨드 공격 — 킥으로 적을 날리고 연쇄 넉백 발동"); KcCooldown = ((BaseUnityPlugin)this).Config.Bind("KnockbackChain", "Cooldown", 12f, "쿨타임 (초)"); KcPushFactor = ((BaseUnityPlugin)this).Config.Bind("KnockbackChain", "PushFactor", 2.5f, "킥의 넉백 배율 (기본 push force 대비)"); KcMaxChainTargets = ((BaseUnityPlugin)this).Config.Bind("KnockbackChain", "MaxChainTargets", 3, "연쇄 넉백 최대 대상 수 (0 = 연쇄 없음)"); KcCollisionRadius = ((BaseUnityPlugin)this).Config.Bind("KnockbackChain", "CollisionRadius", 3f, "연쇄 감지 반지름 (미터)"); KcChainDecay = ((BaseUnityPlugin)this).Config.Bind("KnockbackChain", "ChainDecay", 0.6f, "연쇄당 넉백 감쇠율 (0~1)"); KcChainDamageFactor = ((BaseUnityPlugin)this).Config.Bind("KnockbackChain", "ChainDamageFactor", 0.5f, "연쇄 충돌 데미지 배율 (원본 킥 데미지 대비, 0 = 데미지 없음)"); KcMinSkillLevel = ((BaseUnityPlugin)this).Config.Bind("KnockbackChain", "MinSkillLevel", 0f, "스킬 발동 최소 레벨 — Unarmed (0~100, 0 = 제한 없음)"); LsEnable = ((BaseUnityPlugin)this).Config.Bind("LaunchSlam", "Enable", true, "1H 클럽(철퇴류) 세컨더리 — 적을 공중으로 띄우고 착지 시 AOE 데미지"); LsCooldown = ((BaseUnityPlugin)this).Config.Bind("LaunchSlam", "Cooldown", 10f, "쿨타임 (초)"); LsLaunchHeight = ((BaseUnityPlugin)this).Config.Bind("LaunchSlam", "LaunchHeight", 4f, "띄우는 높이 (미터)"); LsDamageFactor = ((BaseUnityPlugin)this).Config.Bind("LaunchSlam", "DamageFactor", 0.5f, "착지 AOE 데미지 배율"); LsLandingRadius = ((BaseUnityPlugin)this).Config.Bind("LaunchSlam", "LandingRadius", 3f, "착지 AOE 반경 (미터)"); LsMinSkillLevel = ((BaseUnityPlugin)this).Config.Bind("LaunchSlam", "MinSkillLevel", 0f, "스킬 발동 최소 레벨 — Clubs (0~100, 0 = 제한 없음)"); SaEnable = ((BaseUnityPlugin)this).Config.Bind("SneakAmbush", "Enable", true, "나이프(단검류) 세컨더리 — 은신 중 홀드로 충전 → 어그로 리셋 + 백스탭 창 활성화"); SaCooldown = ((BaseUnityPlugin)this).Config.Bind("SneakAmbush", "Cooldown", 15f, "쿨타임 (초)"); SaChargeTime = ((BaseUnityPlugin)this).Config.Bind("SneakAmbush", "ChargeTime", 2f, "최대 충전 시간 (초, Sneak 0 기준)"); SaChargeSpeedFactor = ((BaseUnityPlugin)this).Config.Bind("SneakAmbush", "ChargeSpeedFactor", 2f, "Sneak 100 레벨 시 충전 속도 배율 (기본 1×, 최대 이 값×)"); SaAggroResetRadius = ((BaseUnityPlugin)this).Config.Bind("SneakAmbush", "AggroResetRadius", 10f, "어그로 리셋 반경 (미터, 0 = 리셋 없음)"); SaBackstabBonus = ((BaseUnityPlugin)this).Config.Bind("SneakAmbush", "BackstabBonus", 3f, "백스탭 보너스 배율 (기존 무기 백스탭 배율에 곱함)"); SaMinSkillLevel = ((BaseUnityPlugin)this).Config.Bind("SneakAmbush", "MinSkillLevel", 0f, "스킬 발동 최소 레벨 — Knives (0~100, 0 = 제한 없음)"); AsEnable = ((BaseUnityPlugin)this).Config.Bind("Aftershock", "Enable", true, "슬레지해머(2H 해머) 세컨더리 — 전방 충격파"); AsCooldown = ((BaseUnityPlugin)this).Config.Bind("Aftershock", "Cooldown", 15f, "쿨타임 (초)"); AsWaves = ((BaseUnityPlugin)this).Config.Bind("Aftershock", "Waves", 3, "충격파 웨이브 수"); AsInterval = ((BaseUnityPlugin)this).Config.Bind("Aftershock", "Interval", 0.5f, "웨이브 간격 (초)"); AsWaveDecay = ((BaseUnityPlugin)this).Config.Bind("Aftershock", "WaveDecay", 0.2f, "웨이브마다 데미지 감쇠율 (0.2 = 20% 감소)"); AsForwardStep = ((BaseUnityPlugin)this).Config.Bind("Aftershock", "ForwardStep", 3f, "웨이브마다 전진 거리 (미터)"); AsRadius = ((BaseUnityPlugin)this).Config.Bind("Aftershock", "Radius", 4f, "각 웨이브 히트 반경 (미터)"); AsDamageFactor = ((BaseUnityPlugin)this).Config.Bind("Aftershock", "DamageFactor", 1.5f, "기본 무기 데미지에 곱할 배율"); AsPushForce = ((BaseUnityPlugin)this).Config.Bind("Aftershock", "PushForce", 8f, "넉백 힘"); AsMinSkillLevel = ((BaseUnityPlugin)this).Config.Bind("Aftershock", "MinSkillLevel", 0f, "스킬 발동 최소 레벨 — Clubs (0~100, 0 = 제한 없음)"); QsEnable = ((BaseUnityPlugin)this).Config.Bind("QuadSlash", "Enable", true, "클레이모어류 SA → 4연 베기 활성화"); QsCooldown = ((BaseUnityPlugin)this).Config.Bind("QuadSlash", "Cooldown", 12f, "쿨타임 (초)"); QsAnimSpeed1 = ((BaseUnityPlugin)this).Config.Bind("QuadSlash", "AnimSpeed1", 2.5f, "베기1 애니메이션 속도 배율"); QsAnimSpeed2 = ((BaseUnityPlugin)this).Config.Bind("QuadSlash", "AnimSpeed2", 2.5f, "베기2 애니메이션 속도 배율"); QsAnimSpeed3 = ((BaseUnityPlugin)this).Config.Bind("QuadSlash", "AnimSpeed3", 2.5f, "베기3 애니메이션 속도 배율"); QsAnimSpeed4 = ((BaseUnityPlugin)this).Config.Bind("QuadSlash", "AnimSpeed4", 2f, "베기4(피니셔) 애니메이션 속도 배율"); QsDamage1 = ((BaseUnityPlugin)this).Config.Bind("QuadSlash", "Damage1", 1f, "베기1 데미지 배율"); QsDamage2 = ((BaseUnityPlugin)this).Config.Bind("QuadSlash", "Damage2", 1f, "베기2 데미지 배율"); QsDamage3 = ((BaseUnityPlugin)this).Config.Bind("QuadSlash", "Damage3", 1f, "베기3 데미지 배율"); QsDamage4 = ((BaseUnityPlugin)this).Config.Bind("QuadSlash", "Damage4", 1.5f, "베기4(피니셔) 데미지 배율"); QsMinSkillLevel = ((BaseUnityPlugin)this).Config.Bind("QuadSlash", "MinSkillLevel", 0f, "발동 최소 Swords 레벨 (0~100, 0 = 제한 없음)"); CuEnable = ((BaseUnityPlugin)this).Config.Bind("CounterUpper", "Enable", true, "Fist 계열 SA → 더킹+어퍼컷 활성화"); CuCooldown = ((BaseUnityPlugin)this).Config.Bind("CounterUpper", "Cooldown", 10f, "쿨타임 (초)"); CuDuckTime = ((BaseUnityPlugin)this).Config.Bind("CounterUpper", "DuckTime", 0.4f, "더킹(회피 i-frame) 유지 시간 (초)"); CuCounterMult = ((BaseUnityPlugin)this).Config.Bind("CounterUpper", "CounterMult", 2.5f, "회피 성공 시 어퍼컷 데미지 배율"); CuUppercutSpeed = ((BaseUnityPlugin)this).Config.Bind("CounterUpper", "UppercutSpeed", 1.4f, "어퍼컷 애니메이션 속도 배율 (1.0=기본)"); CuDodgeTime = ((BaseUnityPlugin)this).Config.Bind("CounterUpper", "DodgeDisplayTime", 0.25f, "더킹 dodge 애니메이션 표시 시간 (초, CuDuckTime 이하)"); CuMinSkillLevel = ((BaseUnityPlugin)this).Config.Bind("CounterUpper", "MinSkillLevel", 0f, "발동 최소 Unarmed 레벨 (0~100, 0 = 제한 없음)"); IbEnable = ((BaseUnityPlugin)this).Config.Bind("ImpactBurst", "Enable", true, "2H 도끼(배틀액스류) 세컨더리 — 도끼 투척 후 착탄 AOE 버스트"); IbCooldown = ((BaseUnityPlugin)this).Config.Bind("ImpactBurst", "Cooldown", 12f, "쿨타임 (초)"); IbDamageFactor = ((BaseUnityPlugin)this).Config.Bind("ImpactBurst", "DamageFactor", 0.75f, "AOE 데미지 배율"); IbPushFactor = ((BaseUnityPlugin)this).Config.Bind("ImpactBurst", "PushFactor", 4f, "AOE 넉백 배율"); IbRadius = ((BaseUnityPlugin)this).Config.Bind("ImpactBurst", "Radius", 4f, "AOE 반경 (미터)"); IbThrowSpeed = ((BaseUnityPlugin)this).Config.Bind("ImpactBurst", "ThrowSpeed", 30f, "투척 속도 (m/s)"); IbSpinSpeed = ((BaseUnityPlugin)this).Config.Bind("ImpactBurst", "SpinSpeed", 360f, "던져진 도끼 회전 속도 (도/초)"); IbMinSkillLevel = ((BaseUnityPlugin)this).Config.Bind("ImpactBurst", "MinSkillLevel", 0f, "스킬 발동 최소 레벨 — Axes (0~100, 0 = 제한 없음)"); ScEnable = ((BaseUnityPlugin)this).Config.Bind("SwordChain", "Enable", true, "한손검 세컨더리 — 쿨타임 완충 시 3타 체인 공격"); ScCooldown = ((BaseUnityPlugin)this).Config.Bind("SwordChain", "Cooldown", 10f, "쿨타임 (초)"); ScChainWindow = ((BaseUnityPlugin)this).Config.Bind("SwordChain", "ChainWindow", 0.8f, "다음 체인 공격 발동 허용 시간 (초)"); ScAnimSpeed = ((BaseUnityPlugin)this).Config.Bind("SwordChain", "AnimSpeed", 1.4f, "체인 공격 애니메이션 속도 배율 (1.0 = 기본)"); ScDamage1 = ((BaseUnityPlugin)this).Config.Bind("SwordChain", "Damage1", 1.2f, "1타(특수공격) 데미지 배율"); ScDamage2 = ((BaseUnityPlugin)this).Config.Bind("SwordChain", "Damage2", 1.4f, "2타 데미지 배율"); ScDamage3 = ((BaseUnityPlugin)this).Config.Bind("SwordChain", "Damage3", 2f, "3타(피니셔) 데미지 배율"); ScMinSkillLevel = ((BaseUnityPlugin)this).Config.Bind("SwordChain", "MinSkillLevel", 0f, "스킬 발동 최소 레벨 — Swords (0~100, 0 = 제한 없음)"); SpEnable = ((BaseUnityPlugin)this).Config.Bind("SpearPin", "Enable", true, "스피어(창류) 세컨더리 — 창이 몬스터에 박혀 이동속도 제한"); SpCooldown = ((BaseUnityPlugin)this).Config.Bind("SpearPin", "Cooldown", 18f, "쿨타임 (초)"); SpSpeedFactor = ((BaseUnityPlugin)this).Config.Bind("SpearPin", "SpeedFactor", 0.35f, "핀됐을 때 몬스터 이동속도 배율 (0.1~1.0)"); SpPinDuration = ((BaseUnityPlugin)this).Config.Bind("SpearPin", "PinDuration", 8f, "핀 지속 시간 (초) — 만료 시 창이 아이템으로 떨어짐"); SpPullRange = ((BaseUnityPlugin)this).Config.Bind("SpearPin", "PullRange", 3f, "창 뽑기 가능 거리 (미터)"); SpPullRestoreTime = ((BaseUnityPlugin)this).Config.Bind("SpearPin", "PullRestoreTime", 3f, "뽑은 후 이동속도 점진 회복 시간 (초)"); SpMinSkillLevel = ((BaseUnityPlugin)this).Config.Bind("SpearPin", "MinSkillLevel", 0f, "스킬 발동 최소 레벨 — Spears (0~100, 0 = 제한 없음)"); TtEnable = ((BaseUnityPlugin)this).Config.Bind("TripleThrust", "Enable", true, "Atgeir류 3연 찌르기 활성화"); TtCooldown = ((BaseUnityPlugin)this).Config.Bind("TripleThrust", "Cooldown", 12f, "쿨타임 (초)"); TtMinSkillLevel = ((BaseUnityPlugin)this).Config.Bind("TripleThrust", "MinSkillLevel", 0f, "발동 최소 Polearms 레벨 (0 = 제한 없음)"); TtStaggerMultiplier = ((BaseUnityPlugin)this).Config.Bind("TripleThrust", "StaggerMultiplier", 2.5f, "히트당 스태거 추가 배율 (자연 스태거 외 추가분, 높을수록 스태거 빠르게 적립)"); TtAnimSpeed = ((BaseUnityPlugin)this).Config.Bind("TripleThrust", "AnimSpeed", 2.5f, "3연타 중 애니메이션 재생 속도 배율"); TtRange = ((BaseUnityPlugin)this).Config.Bind("TripleThrust", "Range", 3.5f, "스태거 보너스 적용 범위 (미터)"); CsEnable = ((BaseUnityPlugin)this).Config.Bind("ChargeSlash", "Enable", true, "바스타드소드 차지슬래시 활성화"); CsCooldown = ((BaseUnityPlugin)this).Config.Bind("ChargeSlash", "Cooldown", 20f, "쿨타임 (초)"); CsMaxChargeTime = ((BaseUnityPlugin)this).Config.Bind("ChargeSlash", "MaxChargeTime", 1f, "최대 충전 시간 (초) — 이 시간을 채우면 게이지 100%"); CsDamageMult = ((BaseUnityPlugin)this).Config.Bind("ChargeSlash", "DamageMult", 3f, "최대 충전 시 데미지 배율 (최소 1× → 최대 N×)"); CsHitVfxName = ((BaseUnityPlugin)this).Config.Bind("ChargeSlash", "HitVfxName", "", "히트 VFX 프리팹 이름 (예: vfx_HitSparks). 빈 값이면 VFX 없음"); CsMinSkillLevel = ((BaseUnityPlugin)this).Config.Bind("ChargeSlash", "MinSkillLevel", 0f, "스킬 발동 최소 레벨 — Swords (0~100, 0 = 제한 없음)"); HudX = ((BaseUnityPlugin)this).Config.Bind("Hud", "HudX", 0.5f, "쿨타임 HUD X 위치 (0=왼쪽, 1=오른쪽)"); HudY = ((BaseUnityPlugin)this).Config.Bind("Hud", "HudY", 0.15f, "쿨타임 HUD Y 위치 (0=아래, 1=위)"); SpecialKey = ((BaseUnityPlugin)this).Config.Bind("General", "SpecialAttackKey", (KeyCode)0, "특수 공격 발동 키 (KeyCode). None이면 기존 세컨더리 공격 키로 발동. 키를 지정하면 세컨더리 공격키는 기존 바닐라 공격으로만 동작함."); _harmony.PatchAll(); Log.LogInfo((object)"SpecialAttack 1.0.0 로드 완료"); } private void OnDestroy() { _harmony.UnpatchSelf(); } } internal static class SpecialInput { internal static bool Active; internal static bool BlockMeleeDamage; internal static void TriggerFromKey(Humanoid humanoid) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) Active = true; if (!((Character)humanoid).StartAttack((Character)null, true)) { Active = false; } } } internal static class SpecialCooldownHelper { internal static bool IsOnCooldown(Character ch, ItemData weapon) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Invalid comparison between Unknown and I4 if (weapon?.m_shared == null) { return false; } CooldownEntry entry; if (WeaponFilter.Matches(weapon)) { return SpinningSweepCooldown.CollectEntry(ch, out entry); } if ((int)weapon.m_shared.m_skillType == 11 && (Object)(object)weapon.m_dropPrefab == (Object)null) { return KnockbackChainCooldown.CollectEntry(out entry); } if (CounterUpperFilter.Matches(weapon)) { return CounterUpperCooldown.CollectEntry(ch, out entry); } if (LaunchSlamFilter.Matches(weapon)) { return LaunchSlamCooldown.CollectEntry(ch, out entry); } if (SneakAmbushFilter.Matches(weapon)) { return SneakAmbushCooldown.CollectEntry(ch, out entry); } if (AftershockFilter.Matches(weapon)) { return AftershockCooldown.CollectEntry(ch, out entry); } if (ChargeSlashFilter.Matches(weapon)) { return ChargeSlashCooldown.IsOnCooldown(ch); } if (QuadSlashFilter.Matches(weapon)) { return QuadSlashCooldown.CollectEntry(ch, out entry); } if (ImpactBurstFilter.Matches(weapon)) { return ImpactBurstCooldown.CollectEntry(ch, out entry); } if (SwordChainFilter.Matches(weapon)) { return SwordChainCooldown.IsOnCooldown(ch); } if (SpearPinFilter.Matches(weapon)) { return SpearPinCooldown.CollectEntry(ch, out entry); } if (TripleThrustFilter.Matches(weapon)) { return TripleThrustCooldown.CollectEntry(ch, out entry); } return false; } } internal static class ValheimAccess { internal static readonly FieldInfo AttackWeaponField = AccessTools.Field(typeof(Attack), "m_weapon"); internal static readonly FieldInfo HumanoidCurrentAttackField = AccessTools.Field(typeof(Humanoid), "m_currentAttack"); internal static readonly MethodInfo AttackGetOriginMethod = AccessTools.Method(typeof(Attack), "GetAttackOrigin", (Type[])null, (Type[])null); internal static ItemData GetWeapon(Attack attack) { object? obj = AttackWeaponField?.GetValue(attack); return (ItemData)((obj is ItemData) ? obj : null); } internal static Attack GetCurrentAttack(Humanoid h) { object? obj = HumanoidCurrentAttackField?.GetValue(h); return (Attack)((obj is Attack) ? obj : null); } internal static Transform GetAttackOrigin(Attack attack) { object? obj = AttackGetOriginMethod?.Invoke(attack, null); return (Transform)((obj is Transform) ? obj : null); } } internal struct CooldownEntry { internal Sprite Icon; internal float Remaining; internal float Duration; internal bool IsCharging; } internal static class SpinningSweepCooldown { private sealed class State { public double ReadyAt; public float Duration; public Sprite Icon; } private static readonly ConditionalWeakTable _states = new ConditionalWeakTable(); 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 KnockbackChainCooldown { private static double _readyAt; private static float _duration; private static Sprite _icon; internal static bool TryConsume(float cooldown, Sprite icon = null) { if (cooldown <= 0f) { return true; } double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble); if (num < _readyAt) { return false; } _readyAt = num + (double)cooldown; _duration = cooldown; _icon = icon; return true; } internal static bool CollectEntry(out CooldownEntry entry) { entry = default(CooldownEntry); double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble); float num2 = (float)Math.Max(0.0, _readyAt - num); if (num2 <= 0f) { return false; } entry = new CooldownEntry { Icon = _icon, Remaining = num2, Duration = _duration }; return true; } } internal static class CooldownHud { private sealed class Slot { internal GameObject Root; internal Image Bg; internal Image Icon; internal Image Overlay; internal TMP_Text Label; internal bool IsValid => (Object)(object)Root != (Object)null && (Object)(object)Bg != (Object)null && (Object)(object)Icon != (Object)null && (Object)(object)Overlay != (Object)null && (Object)(object)Label != (Object)null; internal void Set(CooldownEntry e) { //IL_0014: 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_0151: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) Root.SetActive(true); ((Graphic)Bg).color = BgFilled; Icon.sprite = e.Icon; ((Behaviour)Icon).enabled = (Object)(object)e.Icon != (Object)null; if ((Object)(object)e.Icon != (Object)null) { ((Graphic)Icon).color = Color.white; } ((Behaviour)Overlay).enabled = true; if (e.IsCharging) { float fillAmount = ((e.Duration > 0.001f) ? Mathf.Clamp01(e.Remaining / e.Duration) : 0f); Overlay.fillAmount = fillAmount; ((Graphic)Overlay).color = new Color(0.2f, 0.9f, 0.2f, 0.55f); int num = Mathf.FloorToInt(e.Remaining); Label.text = num.ToString(); } else { float fillAmount2 = ((e.Duration > 0.001f) ? Mathf.Clamp01(e.Remaining / e.Duration) : 0f); Overlay.fillAmount = fillAmount2; ((Graphic)Overlay).color = new Color(0f, 0f, 0f, 0.58f); int num2 = Mathf.CeilToInt(e.Remaining); Label.text = ((num2 >= 60) ? $"{Mathf.CeilToInt((float)num2 / 60f)}m" : num2.ToString()); } } internal void Hide() { if ((Object)(object)Root != (Object)null && Root.activeSelf) { Root.SetActive(false); } } } private static readonly Color BgFilled = new Color(0f, 0f, 0f, 0.48f); private static readonly Color BgEmpty = new Color(0f, 0f, 0f, 0.2f); private const float SlotSize = 42f; private const float SlotGap = 4f; private const int MaxSlots = 8; private static GameObject _root; private static RectTransform _rootRect; private static readonly List _slots = new List(); private static readonly List _entries = new List(); private static bool _built; internal static void Update(Player player) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown if ((Object)(object)player == (Object)null || player != Player.m_localPlayer || (Object)(object)Hud.instance == (Object)null || (Object)(object)Hud.instance.m_rootObject == (Object)null) { HideAll(); return; } CollectEntries((Character)player); if (_entries.Count == 0) { HideAll(); return; } EnsureHud(); if (!_built) { return; } ApplyPosition(); _root.SetActive(true); for (int i = 0; i < _slots.Count; i++) { if (i < _entries.Count) { _slots[i].Set(_entries[i]); } else { _slots[i].Hide(); } } } private static void CollectEntries(Character ch) { _entries.Clear(); if (SpinningSweepCooldown.CollectEntry(ch, out var entry)) { _entries.Add(entry); } if (KnockbackChainCooldown.CollectEntry(out var entry2)) { _entries.Add(entry2); } if (CounterUpperCooldown.CollectEntry(ch, out var entry3)) { _entries.Add(entry3); } if (LaunchSlamCooldown.CollectEntry(ch, out var entry4)) { _entries.Add(entry4); } if (QuadSlashCooldown.CollectEntry(ch, out var entry5)) { _entries.Add(entry5); } if (SneakAmbushCooldown.CollectEntry(ch, out var entry6)) { _entries.Add(entry6); } if (AftershockCooldown.CollectEntry(ch, out var entry7)) { _entries.Add(entry7); } if (ImpactBurstCooldown.CollectEntry(ch, out var entry8)) { _entries.Add(entry8); } if (SpearPinCooldown.CollectEntry(ch, out var entry9)) { _entries.Add(entry9); } if (SwordChainCooldown.CollectEntry(ch, out var entry10)) { _entries.Add(entry10); } if (TripleThrustCooldown.CollectEntry(ch, out var entry11)) { _entries.Add(entry11); } if (ChargeSlashCooldown.CollectEntry(ch, out var entry12)) { _entries.Add(entry12); } } private static void HideAll() { if ((Object)(object)_root != (Object)null && _root.activeSelf) { _root.SetActive(false); } } private static void EnsureHud() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) if (_built && (Object)(object)_root != (Object)null && _slots.Count > 0 && _slots[0].IsValid) { return; } Reset(); TMP_Text val = ResolveFontSource(); if (!((Object)(object)val == (Object)null)) { _root = new GameObject("SA_CooldownHud"); _root.SetActive(false); _root.transform.SetParent(Hud.instance.m_rootObject.transform, false); _rootRect = _root.AddComponent(); _rootRect.anchorMin = Vector2.zero; _rootRect.anchorMax = Vector2.zero; _rootRect.pivot = new Vector2(0f, 0.5f); HorizontalLayoutGroup val2 = _root.AddComponent(); ((HorizontalOrVerticalLayoutGroup)val2).spacing = 4f; ((HorizontalOrVerticalLayoutGroup)val2).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)val2).childForceExpandHeight = false; ContentSizeFitter val3 = _root.AddComponent(); val3.horizontalFit = (FitMode)2; val3.verticalFit = (FitMode)2; for (int i = 0; i < 8; i++) { _slots.Add(CreateSlot(_root.transform, val)); } _built = true; } } private static void Reset() { if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); } _root = null; _rootRect = null; _slots.Clear(); _built = false; } private static void ApplyPosition() { //IL_003f: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_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) if (!((Object)(object)_rootRect == (Object)null)) { Transform parent = ((Transform)_rootRect).parent; RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); ? val2; if (!((Object)(object)val != (Object)null)) { val2 = new Vector2((float)Screen.width, (float)Screen.height); } else { Rect rect = val.rect; val2 = ((Rect)(ref rect)).size; } Vector2 val3 = (Vector2)val2; _rootRect.anchoredPosition = new Vector2(val3.x * Mathf.Clamp01(Plugin.HudX.Value), val3.y * Mathf.Clamp01(Plugin.HudY.Value)); } } private static Slot CreateSlot(Transform parent, TMP_Text font) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0034: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: 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_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Expected O, but got Unknown //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0160: 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) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Expected O, but got Unknown //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("SA_Slot"); val.transform.SetParent(parent, false); val.SetActive(false); RectTransform val2 = val.AddComponent(); val2.sizeDelta = new Vector2(42f, 42f); LayoutElement val3 = val.AddComponent(); val3.preferredWidth = 42f; val3.preferredHeight = 42f; Image val4 = val.AddComponent(); ((Graphic)val4).color = BgEmpty; ((Graphic)val4).raycastTarget = false; GameObject val5 = new GameObject("Icon"); val5.transform.SetParent(val.transform, false); RectTransform val6 = val5.AddComponent(); val6.anchorMin = new Vector2(0.5f, 0.5f); val6.anchorMax = new Vector2(0.5f, 0.5f); val6.pivot = new Vector2(0.5f, 0.5f); val6.sizeDelta = new Vector2(36f, 36f); Image val7 = val5.AddComponent(); val7.preserveAspect = true; ((Graphic)val7).raycastTarget = false; GameObject val8 = new GameObject("Overlay"); val8.transform.SetParent(val.transform, false); RectTransform val9 = val8.AddComponent(); val9.anchorMin = Vector2.zero; val9.anchorMax = Vector2.one; Vector2 offsetMin = (val9.offsetMax = Vector2.zero); val9.offsetMin = offsetMin; Image val10 = val8.AddComponent(); ((Graphic)val10).color = new Color(0f, 0f, 0f, 0.58f); val10.type = (Type)3; val10.fillMethod = (FillMethod)4; val10.fillOrigin = 2; val10.fillClockwise = false; ((Graphic)val10).raycastTarget = false; GameObject val11 = new GameObject("Text"); val11.transform.SetParent(val.transform, false); RectTransform val12 = val11.AddComponent(); val12.anchorMin = Vector2.zero; val12.anchorMax = Vector2.one; offsetMin = (val12.offsetMax = Vector2.zero); val12.offsetMin = offsetMin; TextMeshProUGUI val13 = val11.AddComponent(); ((TMP_Text)val13).font = font.font; ((TMP_Text)val13).fontSharedMaterial = font.fontSharedMaterial; ((TMP_Text)val13).alignment = (TextAlignmentOptions)514; ((Graphic)val13).color = Color.white; ((TMP_Text)val13).fontSize = 14f; ((TMP_Text)val13).fontStyle = (FontStyles)1; ((TMP_Text)val13).richText = false; ((Graphic)val13).raycastTarget = false; Shadow val14 = val11.AddComponent(); val14.effectColor = new Color(0f, 0f, 0f, 0.9f); val14.effectDistance = new Vector2(1f, -1f); return new Slot { Root = val, Bg = val4, Icon = val7, Overlay = val10, Label = (TMP_Text)(object)val13 }; } private static TMP_Text ResolveFontSource() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown if ((Object)(object)Hud.instance == (Object)null) { return null; } TMP_Text val = (TMP_Text)Hud.instance.m_hoverName; if (HasFont(val)) { return val; } if (HasFont(Hud.instance.m_pieceDescription)) { return Hud.instance.m_pieceDescription; } TMP_Text[] componentsInChildren = Hud.instance.m_rootObject.GetComponentsInChildren(true); foreach (TMP_Text val2 in componentsInChildren) { if (HasFont(val2)) { return val2; } } return null; } private static bool HasFont(TMP_Text t) { return (Object)(object)t != (Object)null && (Object)(object)t.font != (Object)null; } } internal enum WeaponGroup { None, BattleHammer } internal static class WeaponFilter { internal static WeaponGroup GetGroup(ItemData weapon) { if ((Object)(object)weapon?.m_dropPrefab == (Object)null || weapon.m_shared == null) { return WeaponGroup.None; } SharedData shared = weapon.m_shared; string name = ((Object)weapon.m_dropPrefab).name; if (Plugin.EnableBattleHammer.Value && IsBattleHammer(shared, name)) { return WeaponGroup.BattleHammer; } return WeaponGroup.None; } internal static bool Matches(ItemData weapon) { return GetGroup(weapon) != WeaponGroup.None; } private static bool IsBattleHammer(SharedData s, string prefab) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 return (int)s.m_skillType == 3 && (int)s.m_itemType == 14 && !prefab.StartsWith("Sledge", StringComparison.OrdinalIgnoreCase); } } internal static class SpinningSweepSystem { internal static bool TryStart(Humanoid humanoid, Attack attack) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)humanoid == (Object)null || attack == null) { return false; } Character val = (Character)humanoid; if (!val.IsOwner()) { return false; } ItemData currentWeapon = humanoid.GetCurrentWeapon(); WeaponGroup weaponGroup = WeaponFilter.GetGroup(currentWeapon); if (weaponGroup == WeaponGroup.None) { return false; } GameObject gameObject = ((Component)humanoid).gameObject; SpinningSweepController spinningSweepController = gameObject.GetComponent(); if ((Object)(object)spinningSweepController != (Object)null && spinningSweepController.IsActive) { if (!spinningSweepController.MatchesWeapon(currentWeapon)) { spinningSweepController.StopAfterCurrentAttack(); return false; } spinningSweepController.AttachAttack(attack, currentWeapon); return true; } Player val2 = (Player)(object)((humanoid is Player) ? humanoid : null); if ((Object)(object)val2 != (Object)null && Plugin.SsMinSkillLevel.Value > 0f && ((Character)val2).GetSkillLevel((SkillType)3) < Plugin.SsMinSkillLevel.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 (!SpinningSweepCooldown.TryConsume(val, Plugin.Cooldown.Value, icon)) { return false; } if ((Object)(object)spinningSweepController == (Object)null) { spinningSweepController = gameObject.AddComponent(); } spinningSweepController.Begin(humanoid, attack, currentWeapon, weaponGroup); SaVfx.PlayAdrenaline1(((Component)val).transform.position); return true; } internal static void UpdateInput(Player player, bool secondaryHold, bool primaryHold) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player == (Object)null)) { ((Component)player).GetComponent()?.UpdateInput(secondaryHold, primaryHold); } } internal static bool StartRepeatAttack(Humanoid h) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return ((Character)h).StartAttack((Character)null, true); } } internal sealed class SpinningSweepController : MonoBehaviour { private static readonly int AttackTagHash = ZSyncAnimation.GetHash("attack"); private Humanoid _humanoid; private ItemData _weapon; private WeaponGroup _weaponGroup; private Attack _currentAttack; private Animator _animator; private ZSyncAnimation _zanim; private Attack _skillRaiseAttack; private float _nextRepeatTime; private float _originalAnimatorSpeed = 1f; private float _originalRaiseSkillAmount; private int _loopStateHash; private int _lastLoopFrame = -1; private int _startedFrame; private bool _stopRequested; private bool _cancelArmed; private bool _primaryCancelArmed; private bool _lastSecondaryHold = true; private bool _lastPrimaryHold; private bool _hasOriginalAnimatorSpeed; private bool _hasOriginalRaiseSkillAmount; private bool _speedApplied; private bool _initialLoopStartApplied; private bool _loopRearmed = true; internal bool IsActive => !_stopRequested && _weapon != null; internal void Begin(Humanoid humanoid, Attack attack, ItemData weapon, WeaponGroup group) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) _humanoid = humanoid; _weapon = weapon; _weaponGroup = group; _animator = ((Component)humanoid).GetComponentInChildren(); _zanim = ((Character)humanoid).GetZAnim(); _startedFrame = Time.frameCount; _stopRequested = false; _cancelArmed = false; _primaryCancelArmed = false; _lastSecondaryHold = true; _lastPrimaryHold = false; _currentAttack = null; AttachAttack(attack, weapon); ((Behaviour)this).enabled = true; } internal bool MatchesWeapon(ItemData weapon) { if (_weapon == weapon) { return true; } if ((Object)(object)_weapon?.m_dropPrefab != (Object)null && (Object)(object)weapon?.m_dropPrefab != (Object)null) { return ((Object)_weapon.m_dropPrefab).name == ((Object)weapon.m_dropPrefab).name; } return false; } internal void AttachAttack(Attack attack, ItemData weapon) { bool flag = _currentAttack != attack; _currentAttack = attack; _weapon = weapon; if (flag) { _loopStateHash = 0; _lastLoopFrame = -1; _initialLoopStartApplied = false; _loopRearmed = true; } ApplyMovementFactors(attack); ApplySkillRaiseFactor(attack); ApplyAnimationSpeed(); _nextRepeatTime = Time.time; } internal void UpdateInput(bool secondaryHold, bool primaryHold) { if (!IsActive) { return; } UpdatePrimaryCancel(primaryHold); if (!IsActive) { return; } if (!secondaryHold) { _cancelArmed = Time.frameCount > _startedFrame + 1; _lastSecondaryHold = false; return; } bool flag = !_lastSecondaryHold; _lastSecondaryHold = true; if (_cancelArmed && flag) { StopAfterCurrentAttack(); } } private void UpdatePrimaryCancel(bool primaryHold) { if (!primaryHold) { _primaryCancelArmed = Time.frameCount > _startedFrame + 1; _lastPrimaryHold = false; return; } bool flag = !_lastPrimaryHold; _lastPrimaryHold = true; if (_primaryCancelArmed && flag) { StopAfterCurrentAttack(); } } internal void StopAfterCurrentAttack() { _stopRequested = 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 Character val = (Character)_humanoid; if ((Object)(object)_humanoid == (Object)null || _weapon == null || val.IsDead() || !val.IsOwner()) { Object.Destroy((Object)(object)this); return; } Attack currentAttack = ValheimAccess.GetCurrentAttack(_humanoid); if (currentAttack != null && val.InAttack()) { if (currentAttack == _currentAttack) { ApplyMovementFactors(currentAttack); if (ShouldKeepLooping()) { TryUpdateSeamlessLoop(currentAttack); } } } else if (_stopRequested || !MatchesWeapon(_humanoid.GetCurrentWeapon())) { Object.Destroy((Object)(object)this); } else if (!(Time.time < _nextRepeatTime) && !val.IsStaggering() && !val.InAttack()) { if (!CanPayCost(out var _)) { Object.Destroy((Object)(object)this); } else if (!SpinningSweepSystem.StartRepeatAttack(_humanoid)) { _nextRepeatTime = Time.time + 0.05f; } } } private bool ShouldKeepLooping() { return !_stopRequested && (Object)(object)_humanoid != (Object)null && MatchesWeapon(_humanoid.GetCurrentWeapon()); } private bool TryUpdateSeamlessLoop(Attack activeAttack) { //IL_0040: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_humanoid == (Object)null || _weapon == null) { return false; } if ((Object)(object)_animator == (Object)null) { _animator = ((Component)_humanoid).GetComponentInChildren(); } if ((Object)(object)_zanim == (Object)null) { _zanim = ((Character)_humanoid).GetZAnim(); } if ((Object)(object)_animator == (Object)null) { return false; } AnimatorStateInfo attackState = GetAttackState(_animator); if (!IsAttackState(attackState)) { return false; } if (_loopStateHash == 0 && ((AnimatorStateInfo)(ref attackState)).fullPathHash != 0) { _loopStateHash = ((AnimatorStateInfo)(ref attackState)).fullPathHash; } float value = Plugin.LoopStart.Value; float value2 = Plugin.LoopEnd.Value; if (!_initialLoopStartApplied) { _initialLoopStartApplied = true; if (((AnimatorStateInfo)(ref attackState)).normalizedTime < value) { SeekTo(attackState, value); _loopRearmed = false; return true; } } if (!TryRearmLoop(attackState, value2)) { return true; } if (((AnimatorStateInfo)(ref attackState)).normalizedTime < value2 || _lastLoopFrame == Time.frameCount) { return false; } if (!CanPayCost(out var _)) { _stopRequested = true; return false; } PayCost(activeAttack); _lastLoopFrame = Time.frameCount; SeekTo(attackState, value); _loopRearmed = false; return true; } private bool TryRearmLoop(AnimatorStateInfo state, float loopEnd) { if (_loopRearmed) { return true; } if (((AnimatorStateInfo)(ref state)).normalizedTime < loopEnd) { _loopRearmed = true; return true; } return false; } private void SeekTo(AnimatorStateInfo state, float t) { if (!((Object)(object)_animator == (Object)null)) { int num = ((_loopStateHash != 0) ? _loopStateHash : ((AnimatorStateInfo)(ref state)).fullPathHash); if (num != 0) { SweepTrailResetSystem.ClearTrails(_currentAttack); _animator.Play(num, 0, t); } } } private static AnimatorStateInfo GetAttackState(Animator a) { //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_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_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 (a.IsInTransition(0)) { AnimatorStateInfo nextAnimatorStateInfo = a.GetNextAnimatorStateInfo(0); if (IsAttackState(nextAnimatorStateInfo)) { return nextAnimatorStateInfo; } } return a.GetCurrentAnimatorStateInfo(0); } private static bool IsAttackState(AnimatorStateInfo s) { return ((AnimatorStateInfo)(ref s)).fullPathHash != 0 && ((AnimatorStateInfo)(ref s)).tagHash == AttackTagHash; } private bool CanPayCost(out string reason) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown reason = ""; SharedData val = _weapon?.m_shared; Attack val2 = val?.m_secondaryAttack; if (val2 == null) { reason = "no secondary"; return false; } Character val3 = (Character)_humanoid; float num = Mathf.Max(0f, val.m_useDurabilityDrain); if (num > 0f && _weapon.m_durability + 0.001f < num) { reason = "durability"; return false; } float num2 = Mathf.Max(0f, val2.m_attackStamina); if (num2 > 0f && !val3.HaveStamina(num2)) { reason = "stamina"; return false; } float num3 = Mathf.Max(0f, val2.m_attackEitr); if (num3 > 0f && !val3.HaveEitr(num3)) { reason = "eitr"; return false; } float num4 = Mathf.Max(0f, val2.m_attackHealth); if (num4 > 0f && !val3.HaveHealth(num4) && val2.m_attackHealthLowBlockUse) { reason = "health"; return false; } return true; } private void PayCost(Attack activeAttack) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) Character val = (Character)_humanoid; if ((Object)(object)val == (Object)null || _weapon?.m_shared == null) { return; } Attack secondaryAttack = _weapon.m_shared.m_secondaryAttack; if (secondaryAttack != null) { float num = Mathf.Max(0f, secondaryAttack.m_attackStamina); if (num > 0f) { val.UseStamina(num); } float num2 = Mathf.Max(0f, secondaryAttack.m_attackEitr); if (num2 > 0f) { val.UseEitr(num2); } float num3 = Mathf.Max(0f, secondaryAttack.m_attackHealth); if (num3 > 0f) { val.UseHealth(Mathf.Max(0f, Mathf.Min(val.GetHealth() - 1f, num3))); } Transform attackOrigin = ValheimAccess.GetAttackOrigin(activeAttack); if ((Object)(object)attackOrigin != (Object)null) { _weapon.m_shared.m_startEffect.Create(attackOrigin.position, ((Component)_humanoid).transform.rotation, attackOrigin, 1f, -1); activeAttack.m_startEffect.Create(attackOrigin.position, ((Component)_humanoid).transform.rotation, attackOrigin, 1f, -1); } val.AddNoise(activeAttack.m_attackStartNoise); } } private void ApplyMovementFactors(Attack attack) { attack.m_speedFactor = Plugin.BattleHammerMoveSpeedFactor.Value; attack.m_speedFactorRotation = 1f; } private void ApplySkillRaiseFactor(Attack attack) { if (_skillRaiseAttack != attack) { RestoreSkillRaise(); _skillRaiseAttack = attack; _originalRaiseSkillAmount = attack.m_raiseSkillAmount; _hasOriginalRaiseSkillAmount = true; } attack.m_raiseSkillAmount = _originalRaiseSkillAmount * Mathf.Max(0f, Plugin.SkillRaiseFactor.Value); } private void RestoreSkillRaise() { if (_hasOriginalRaiseSkillAmount && _skillRaiseAttack != null) { _skillRaiseAttack.m_raiseSkillAmount = _originalRaiseSkillAmount; _skillRaiseAttack = null; _hasOriginalRaiseSkillAmount = false; } } private void ApplyAnimationSpeed() { //IL_0048: 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) float value = Plugin.AnimationSpeed.Value; if (Mathf.Approximately(value, 1f)) { return; } if ((Object)(object)_animator == (Object)null && (Object)(object)_humanoid != (Object)null) { _animator = ((Component)_humanoid).GetComponentInChildren(); } if ((Object)(object)_zanim == (Object)null && (Object)(object)_humanoid != (Object)null) { _zanim = ((Character)_humanoid).GetZAnim(); } if (!((Object)(object)_animator == (Object)null)) { if (!_hasOriginalAnimatorSpeed) { _originalAnimatorSpeed = _animator.speed; _hasOriginalAnimatorSpeed = true; } ZSyncAnimation zanim = _zanim; if (zanim != null) { zanim.SetSpeed(value); } _animator.speed = value; _speedApplied = true; } } private void RestoreAnimationSpeed() { if (_speedApplied && !((Object)(object)_animator == (Object)null)) { ZSyncAnimation zanim = _zanim; if (zanim != null) { zanim.SetSpeed(_originalAnimatorSpeed); } _animator.speed = _originalAnimatorSpeed; _speedApplied = false; } } private void OnDestroy() { SweepTrailResetSystem.ClearTrails(_currentAttack); RestoreSkillRaise(); RestoreAnimationSpeed(); } } internal static class SweepTrailResetSystem { private static readonly FieldInfo _visEquipField = AccessTools.Field(typeof(Attack), "m_visEquipment"); private static readonly FieldInfo _rightItemField = AccessTools.Field(typeof(VisEquipment), "m_rightItemInstance"); private static readonly FieldInfo _trailMeshField = AccessTools.Field(typeof(MeleeWeaponTrail), "m_trailMesh"); private static readonly FieldInfo _emitTimeField = AccessTools.Field(typeof(MeleeWeaponTrail), "_emitTime"); private static readonly FieldInfo _lastPosField = AccessTools.Field(typeof(MeleeWeaponTrail), "m_lastPosition"); private static readonly FieldInfo _baseField = AccessTools.Field(typeof(MeleeWeaponTrail), "_base"); private static readonly FieldInfo _tipField = AccessTools.Field(typeof(MeleeWeaponTrail), "_tip"); private static readonly FieldInfo[] _listFields = new FieldInfo[8] { AccessTools.Field(typeof(MeleeWeaponTrail), "m_points"), AccessTools.Field(typeof(MeleeWeaponTrail), "m_smoothedPoints"), AccessTools.Field(typeof(MeleeWeaponTrail), "m_smoothBaseList"), AccessTools.Field(typeof(MeleeWeaponTrail), "m_smoothTipList"), AccessTools.Field(typeof(MeleeWeaponTrail), "m_newVertices"), AccessTools.Field(typeof(MeleeWeaponTrail), "m_newUV"), AccessTools.Field(typeof(MeleeWeaponTrail), "m_newColors"), AccessTools.Field(typeof(MeleeWeaponTrail), "m_newTriangles") }; internal static void ClearTrails(Attack attack) { if (attack == null) { return; } object? obj = _visEquipField?.GetValue(attack); VisEquipment val = (VisEquipment)((obj is VisEquipment) ? obj : null); if ((Object)(object)val == (Object)null) { return; } object? obj2 = _rightItemField?.GetValue(val); GameObject val2 = (GameObject)((obj2 is GameObject) ? obj2 : null); if (!((Object)(object)val2 == (Object)null)) { MeleeWeaponTrail[] componentsInChildren = val2.GetComponentsInChildren(true); foreach (MeleeWeaponTrail trail in componentsInChildren) { ClearTrail(trail); } } } private static void ClearTrail(MeleeWeaponTrail trail) { //IL_0109: 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_00f7: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)trail == (Object)null) { return; } FieldInfo[] listFields = _listFields; for (int i = 0; i < listFields.Length; i++) { if (listFields[i]?.GetValue(trail) is IList list) { list.Clear(); } } object? obj = _trailMeshField?.GetValue(trail); Mesh val = (Mesh)((obj is Mesh) ? obj : null); if (val != null) { val.Clear(); } _emitTimeField?.SetValue(trail, 0f); if (_lastPosField != null) { object? obj2 = _baseField?.GetValue(trail); Transform val2 = (Transform)((obj2 is Transform) ? obj2 : null); object? obj3 = _tipField?.GetValue(trail); Transform val3 = (Transform)((obj3 is Transform) ? obj3 : null); _lastPosField.SetValue(trail, ((Object)(object)val2 != (Object)null) ? val2.position : (((Object)(object)val3 != (Object)null) ? val3.position : Vector3.zero)); } } } internal static class KnockbackChainSystem { private static bool _pendingSecondary; private static ZDOID _pendingAttacker; private static readonly int _charMask = LayerMask.GetMask(new string[3] { "character", "character_net", "character_ghost" }); internal static readonly Collider[] _overlapBuffer = (Collider[])(object)new Collider[32]; private static readonly FieldInfo _critHitEffectsField = AccessTools.Field(typeof(Character), "m_critHitEffects"); internal static bool IsApplyingChainDamage { get; private set; } private static void SpawnStaggerHitVfx(Character target, Vector3 point, Vector3 dir) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) object? obj = _critHitEffectsField?.GetValue(target); EffectList val = (EffectList)((obj is EffectList) ? obj : null); if (val != null) { Quaternion val2 = ((((Vector3)(ref dir)).sqrMagnitude > 0.001f) ? Quaternion.LookRotation(dir) : ((Component)target).transform.rotation); val.Create(point, val2, ((Component)target).transform, 1f, -1); } } internal static void OnSecondaryStarted(Humanoid humanoid) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Invalid comparison between Unknown and I4 //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.KcEnable.Value) { return; } ItemData currentWeapon = humanoid.GetCurrentWeapon(); if (currentWeapon != null && (int)(currentWeapon.m_shared?.m_skillType).GetValueOrDefault() == 11 && !((Object)(object)currentWeapon.m_dropPrefab != (Object)null)) { Player val = (Player)(object)((humanoid is Player) ? humanoid : null); if (!((Object)(object)val != (Object)null) || !(Plugin.KcMinSkillLevel.Value > 0f) || !(((Character)val).GetSkillLevel((SkillType)11) < Plugin.KcMinSkillLevel.Value)) { _pendingSecondary = 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: 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_01df: Expected O, but got Unknown if (IsApplyingChainDamage || !_pendingSecondary || !Plugin.KcEnable.Value || hit.m_attacker != _pendingAttacker || hit.m_pushForce <= 0f || ((DamageTypes)(ref hit.m_damage)).GetTotalDamage() <= 0f) { return; } _pendingSecondary = false; object obj; if (!((Object)(object)Player.m_localPlayer != (Object)null)) { obj = null; } else { ItemData currentWeapon = ((Humanoid)Player.m_localPlayer).GetCurrentWeapon(); obj = ((currentWeapon != null && currentWeapon.m_shared?.m_icons?.Length > 0) ? ((Humanoid)Player.m_localPlayer).GetCurrentWeapon().m_shared.m_icons[0] : null); } Sprite icon = (Sprite)obj; if (!KnockbackChainCooldown.TryConsume(Plugin.KcCooldown.Value, icon)) { return; } if ((Object)(object)Player.m_localPlayer != (Object)null) { SaVfx.PlayAdrenaline1(((Component)Player.m_localPlayer).transform.position); } float num = hit.m_pushForce * Mathf.Max(0f, Plugin.KcPushFactor.Value); hit.m_pushForce = num; if (Plugin.KcMaxChainTargets.Value > 0) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { GameObject gameObject = ((Component)localPlayer).gameObject; KnockbackChainLauncher knockbackChainLauncher = gameObject.GetComponent() ?? gameObject.AddComponent(); knockbackChainLauncher.Launch((Character)localPlayer, target, hit.m_dir, num, hit.m_damage); } } } internal static void ApplyChainPush(Character attacker, Character target, Vector3 dir, float pushForce, DamageTypes baseDamage, float damageScale) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016a: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0134: 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 ((Object)(object)target == (Object)null || target.IsDead() || target == attacker || !target.IsOwner()) { return; } IsApplyingChainDamage = true; try { HitData val = new HitData(); val.m_pushForce = pushForce; val.m_attacker = attacker.GetZDOID(); val.m_skill = (SkillType)11; val.m_dir = dir; float num = Mathf.Max(0f, Plugin.KcChainDamageFactor.Value) * damageScale; if (num > 0f) { val.m_damage.m_blunt = baseDamage.m_blunt * num; val.m_damage.m_slash = baseDamage.m_slash * num; val.m_damage.m_pierce = baseDamage.m_pierce * num; val.m_damage.m_chop = baseDamage.m_chop * num; val.m_damage.m_pickaxe = baseDamage.m_pickaxe * num; val.m_damage.m_fire = baseDamage.m_fire * num; val.m_damage.m_frost = baseDamage.m_frost * num; val.m_damage.m_lightning = baseDamage.m_lightning * num; val.m_damage.m_poison = baseDamage.m_poison * num; val.m_damage.m_spirit = baseDamage.m_spirit * num; } Vector3 centerPoint = target.GetCenterPoint(); target.Damage(val); SpawnStaggerHitVfx(target, centerPoint, dir); } finally { IsApplyingChainDamage = false; } } internal static int FindNearby(Vector3 center, float radius) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return Physics.OverlapSphereNonAlloc(center, radius, _overlapBuffer, _charMask, (QueryTriggerInteraction)2); } } internal sealed class KnockbackChainLauncher : MonoBehaviour { private Character _attacker; private Character _target; private Vector3 _dir; private float _push; private float _fireAt; private DamageTypes _baseDamage; internal void Launch(Character attacker, Character target, Vector3 dir, float push, DamageTypes baseDamage) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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) _attacker = attacker; _target = target; _dir = dir; _push = push * Plugin.KcChainDecay.Value; _baseDamage = baseDamage; _fireAt = Time.time + 0.35f; ((Behaviour)this).enabled = true; } private void Update() { if (!(Time.time < _fireAt)) { DoChain(_target, _push, 1f, new HashSet { _attacker, _target }, 0); Object.Destroy((Object)(object)this); } } private void DoChain(Character source, float power, float damageScale, HashSet visited, int depth) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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) //IL_00bc: 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_00c2: 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_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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_00f5: Unknown result type (might be due to invalid IL or missing references) int value = Plugin.KcMaxChainTargets.Value; if (depth >= value || power < 0.05f || (Object)(object)source == (Object)null || source.IsDead()) { return; } Vector3 centerPoint = source.GetCenterPoint(); int num = KnockbackChainSystem.FindNearby(centerPoint, Plugin.KcCollisionRadius.Value); for (int i = 0; i < num; i++) { if (visited.Count - 2 + depth >= value) { break; } Collider val = KnockbackChainSystem._overlapBuffer[i]; KnockbackChainSystem._overlapBuffer[i] = null; if ((Object)(object)val == (Object)null) { continue; } Character componentInParent = ((Component)val).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null) && !visited.Contains(componentInParent) && !componentInParent.IsDead()) { visited.Add(componentInParent); Vector3 val2 = componentInParent.GetCenterPoint() - centerPoint; Vector3 normalized = ((Vector3)(ref val2)).normalized; if (!(Vector3.Dot(normalized, _dir) < -0.25f)) { KnockbackChainSystem.ApplyChainPush(_attacker, componentInParent, normalized, power, _baseDamage, damageScale); DoChain(componentInParent, power * Plugin.KcChainDecay.Value, damageScale * Plugin.KcChainDecay.Value, visited, depth + 1); } } } } } [HarmonyPatch(typeof(Humanoid), "GetTimeSinceLastAttack")] internal static class Patch_TimeSinceLastAttack { private static void Postfix(Humanoid __instance, ref float __result) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) SpinningSweepController component = ((Component)__instance).GetComponent(); if (component != null && component.IsActive) { __result = 999f; } } } [HarmonyPatch(typeof(Humanoid), "StartAttack")] internal static class Patch_StartAttack { private static bool Prefix(Humanoid __instance, bool secondaryAttack, ref bool __result) { //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Expected O, but got Unknown //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) if (!secondaryAttack) { return true; } if (TripleThrustSystem.TryInterceptSA(__instance)) { __result = false; return false; } if (QuadSlashSystem.TryInterceptSA(__instance)) { __result = false; return false; } if (CounterUpperSystem.TryInterceptSA(__instance)) { __result = false; return false; } if (!Plugin.CsEnable.Value) { return true; } if (!(__instance is Player) || (object)__instance != Player.m_localPlayer) { return true; } ItemData currentWeapon = __instance.GetCurrentWeapon(); if (!ChargeSlashFilter.Matches(currentWeapon)) { SharedData val = currentWeapon?.m_shared; string text = (((Object)(object)currentWeapon?.m_dropPrefab != (Object)null) ? ((Object)currentWeapon.m_dropPrefab).name : "null"); Plugin.Log.LogInfo((object)$"[CS-DIAG] Filter MISS | prefab={text} itemType={val?.m_itemType} skill={val?.m_skillType} name={val?.m_name}"); return true; } if (ChargeSlashSystem.AllowSlash) { return true; } Character c = (Character)__instance; GameObject gameObject = ((Component)__instance).gameObject; ChargeSlashController component = gameObject.GetComponent(); if ((Object)(object)component == (Object)null) { if (ChargeSlashCooldown.IsOnCooldown(c)) { Plugin.Log.LogInfo((object)"[CS-DIAG] Prefix: 쿨타임 중 → 일반 공격 허용"); return true; } if ((int)Plugin.SpecialKey.Value != 0 && !SpecialInput.Active) { Plugin.Log.LogInfo((object)$"[CS-DIAG] Prefix: 커스텀 키 모드, SpecialInput.Active=false → 일반 공격 허용 (SpecialKey={Plugin.SpecialKey.Value})"); return true; } if (Plugin.CsMinSkillLevel.Value > 0f) { Player val2 = (Player)(object)((__instance is Player) ? __instance : null); if ((Object)(object)val2 != (Object)null && ((Character)val2).GetSkillLevel((SkillType)1) < Plugin.CsMinSkillLevel.Value) { return true; } } ChargeSlashSystem.StartCharging(__instance); __result = false; return false; } __result = false; return false; } private static void Postfix(Humanoid __instance, bool secondaryAttack, bool __result, Attack ___m_currentAttack) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Invalid comparison between Unknown and I4 if (!secondaryAttack) { return; } bool active = SpecialInput.Active; SpecialInput.Active = false; if (!__result || ((int)Plugin.SpecialKey.Value != 0 && !active)) { return; } if (___m_currentAttack != null) { SpinningSweepSystem.TryStart(__instance, ___m_currentAttack); } KnockbackChainSystem.OnSecondaryStarted(__instance); LaunchSlamSystem.OnSecondaryStarted(__instance); ImpactBurstSystem.QueueTrigger(__instance); SpearPinSystem.QueueTrigger(__instance); SwordChainSystem.OnSecondaryStarted(__instance, ___m_currentAttack); AftershockSystem.QueueTrigger(__instance, ___m_currentAttack); if ((int)Plugin.SpecialKey.Value > 0 && active) { ItemData currentWeapon = __instance.GetCurrentWeapon(); if (AftershockFilter.Matches(currentWeapon) || ImpactBurstFilter.Matches(currentWeapon)) { SpecialInput.BlockMeleeDamage = true; } } } } [HarmonyPatch(typeof(Humanoid), "OnAttackTrigger")] internal static class Patch_OnAttackTrigger { private static void Postfix(Humanoid __instance) { SpecialInput.BlockMeleeDamage = false; QuadSlashSystem.ExecuteIfQueued(__instance); AftershockSystem.ExecuteIfQueued(__instance); ImpactBurstSystem.ExecuteIfQueued(__instance); TripleThrustSystem.ExecuteIfQueued(__instance); } } [HarmonyPatch(typeof(Attack), "DoMeleeAttack")] internal static class Patch_DoMeleeAttack { private static bool Prefix() { return !SpecialInput.BlockMeleeDamage; } } [HarmonyPatch(typeof(Character), "Damage")] internal static class Patch_CharacterDamage { private static void Prefix(Character __instance, ref HitData hit) { KnockbackChainSystem.TryApply(__instance, ref hit); LaunchSlamSystem.TryApply(__instance, ref hit); SneakAmbushSystem.TryApplyChargeDamage(__instance, ref hit); SwordChainSystem.TryApplyChainDamage(__instance, ref hit); ChargeSlashSystem.TryHandleDamage(__instance, ref hit); } } [HarmonyPatch(typeof(Attack), "Start")] internal static class Patch_AttackStart { private static void Prefix(Attack __instance, Humanoid character, ref float timeSinceLastAttack) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)character == (Object)null)) { SwordChainSystem.TryInjectChainLevel(character, __instance, ref timeSinceLastAttack); QuadSlashController component = ((Component)character).GetComponent(); if ((Object)(object)component != (Object)null) { component.InjectAnimOverride(__instance, ref timeSinceLastAttack); } } } private static void Postfix(Attack __instance, Humanoid character) { //IL_000f: 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)character == (Object)null)) { QuadSlashController component = ((Component)character).GetComponent(); if ((Object)(object)component != (Object)null && component.IsActive) { component.RestoreAnimOverride(); component.OverrideAnimTrigger(__instance); } CounterUpperController component2 = ((Component)character).GetComponent(); if ((Object)(object)component2 != (Object)null && component2.IsActive && component2.IsFiringNext) { component2.OverrideAnimTrigger(__instance); } } } } [HarmonyPatch(typeof(Projectile), "OnHit")] internal static class Patch_ProjectileOnHit { private static void Postfix(Projectile __instance, Collider collider, Vector3 hitPoint, bool water) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) ImpactBurstSystem.TryTriggerOnHit(__instance, hitPoint, water); Character hitCharacter = null; if ((Object)(object)collider != (Object)null) { GameObject val = Projectile.FindHitObject(collider); hitCharacter = ((val != null) ? val.GetComponentInParent() : null); } SpearPinSystem.TryTriggerOnHit(__instance, hitPoint, water, hitCharacter); } } [HarmonyPatch(typeof(Player), "Update")] internal static class Patch_PlayerUpdate { private static void Postfix(Player __instance) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) Character val = (Character)__instance; if (!val.IsOwner()) { return; } bool secondaryHold = ZInput.GetButton("SecondaryAttack") || ZInput.GetButton("JoySecondaryAttack"); bool primaryHold = ZInput.GetButton("Attack") || ZInput.GetButton("JoyAttack"); SpinningSweepSystem.UpdateInput(__instance, secondaryHold, primaryHold); SneakAmbushSystem.UpdatePlayer(__instance); SpearPinSystem.UpdatePullInteraction(__instance); KeyCode value = Plugin.SpecialKey.Value; if ((int)value != 0 && Input.GetKeyDown(value) && !val.InAttack() && !val.IsStaggering()) { ItemData currentWeapon = ((Humanoid)__instance).GetCurrentWeapon(); if (!SneakAmbushFilter.Matches(currentWeapon) && !SpecialCooldownHelper.IsOnCooldown(val, currentWeapon)) { SpecialInput.TriggerFromKey((Humanoid)(object)__instance); } } CooldownHud.Update(__instance); SneakChargeBar.Update(__instance); ChargeSlashBar.Update(__instance); } } internal static class ChargeSlashBar { private static GameObject _root; private static Image _fill; private static TMP_Text _label; private static bool _built; private const float BarW = 200f; private const float BarH = 18f; private const float BarY = 155f; internal static void Update(Player player) { //IL_0045: 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) if ((Object)(object)player == (Object)null || player != Player.m_localPlayer || (Object)(object)Hud.instance == (Object)null || (Object)(object)Hud.instance.m_rootObject == (Object)null) { Hide(); return; } ChargeSlashController component = ((Component)player).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsCharging) { Hide(); return; } EnsureBar(); if (_built) { float chargeRatio = component.ChargeRatio; RectTransform rectTransform = ((Graphic)_fill).rectTransform; rectTransform.anchorMax = new Vector2(chargeRatio, 1f); int num = Mathf.RoundToInt(chargeRatio * 100f); _label.text = $"CHARGE {num}%"; _root.SetActive(true); } } private static void Hide() { if ((Object)(object)_root != (Object)null && _root.activeSelf) { _root.SetActive(false); } } private static void EnsureBar() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Expected O, but got Unknown //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Expected O, but got Unknown //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Expected O, but got Unknown //IL_03a9: Unknown result type (might be due to invalid IL or missing references) //IL_03c0: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Unknown result type (might be due to invalid IL or missing references) //IL_03e1: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Unknown result type (might be due to invalid IL or missing references) if (_built && (Object)(object)_root != (Object)null) { return; } TMP_Text val = null; if ((Object)(object)Hud.instance != (Object)null) { val = (TMP_Text)Hud.instance.m_hoverName; if ((Object)(object)val == (Object)null || (Object)(object)val.font == (Object)null) { val = Hud.instance.m_pieceDescription; } if ((Object)(object)val == (Object)null || (Object)(object)val.font == (Object)null) { TMP_Text[] componentsInChildren = Hud.instance.m_rootObject.GetComponentsInChildren(true); foreach (TMP_Text val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null && (Object)(object)val2.font != (Object)null) { val = val2; break; } } } } if (!((Object)(object)val == (Object)null) && !((Object)(object)val.font == (Object)null)) { _root = new GameObject("CS_ChargeBar"); _root.SetActive(false); _root.transform.SetParent(Hud.instance.m_rootObject.transform, false); RectTransform val3 = _root.AddComponent(); val3.anchorMin = new Vector2(0.5f, 0f); val3.anchorMax = new Vector2(0.5f, 0f); val3.pivot = new Vector2(0.5f, 0f); val3.sizeDelta = new Vector2(200f, 38f); val3.anchoredPosition = new Vector2(0f, 155f); GameObject val4 = new GameObject("Label"); val4.transform.SetParent(_root.transform, false); RectTransform val5 = val4.AddComponent(); val5.anchorMin = new Vector2(0f, 1f); val5.anchorMax = new Vector2(1f, 1f); val5.pivot = new Vector2(0.5f, 0f); val5.sizeDelta = new Vector2(0f, 20f); val5.anchoredPosition = Vector2.zero; TextMeshProUGUI val6 = val4.AddComponent(); ((TMP_Text)val6).font = val.font; ((TMP_Text)val6).fontSharedMaterial = val.fontSharedMaterial; ((TMP_Text)val6).alignment = (TextAlignmentOptions)514; ((Graphic)val6).color = new Color(1f, 0.75f, 0.2f, 1f); ((TMP_Text)val6).fontSize = 13f; ((TMP_Text)val6).fontStyle = (FontStyles)1; ((TMP_Text)val6).richText = false; ((Graphic)val6).raycastTarget = false; _label = (TMP_Text)(object)val6; GameObject val7 = new GameObject("Bg"); val7.transform.SetParent(_root.transform, false); RectTransform val8 = val7.AddComponent(); val8.anchorMin = Vector2.zero; val8.anchorMax = new Vector2(1f, 0f); val8.pivot = Vector2.zero; val8.sizeDelta = new Vector2(0f, 18f); val8.anchoredPosition = Vector2.zero; Image val9 = val7.AddComponent(); ((Graphic)val9).color = new Color(0f, 0f, 0f, 0.6f); ((Graphic)val9).raycastTarget = false; GameObject val10 = new GameObject("Fill"); val10.transform.SetParent(val7.transform, false); RectTransform val11 = val10.AddComponent(); val11.anchorMin = Vector2.zero; val11.anchorMax = new Vector2(0f, 1f); val11.pivot = Vector2.zero; Vector2 offsetMin = (val11.offsetMax = Vector2.zero); val11.offsetMin = offsetMin; _fill = val10.AddComponent(); ((Graphic)_fill).color = new Color(1f, 0.55f, 0.05f, 0.9f); ((Graphic)_fill).raycastTarget = false; _built = true; } } } internal static class SneakChargeBar { private static GameObject _root; private static Image _fill; private static TMP_Text _label; private static bool _built; private const float BarW = 200f; private const float BarH = 18f; private const float BarY = 120f; internal static void Update(Player player) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || player != Player.m_localPlayer || (Object)(object)Hud.instance == (Object)null || (Object)(object)Hud.instance.m_rootObject == (Object)null) { Hide(); return; } if (!SneakAmbushSystem.CollectChargeEntry((Character)player, out var entry)) { Hide(); return; } EnsureBar(); if (_built) { float num = ((entry.Duration > 0.001f) ? Mathf.Clamp01(entry.Remaining / entry.Duration) : 0f); RectTransform rectTransform = ((Graphic)_fill).rectTransform; rectTransform.anchorMax = new Vector2(num, 1f); int num2 = Mathf.RoundToInt(num * 100f); _label.text = $"SNEAK {num2}%"; _root.SetActive(true); } } private static void Hide() { if ((Object)(object)_root != (Object)null && _root.activeSelf) { _root.SetActive(false); } } private static void EnsureBar() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Expected O, but got Unknown //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Expected O, but got Unknown //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Expected O, but got Unknown //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_03ac: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_03c8: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) //IL_03ce: Unknown result type (might be due to invalid IL or missing references) //IL_03d6: Unknown result type (might be due to invalid IL or missing references) //IL_0403: Unknown result type (might be due to invalid IL or missing references) if (_built && (Object)(object)_root != (Object)null) { return; } TMP_Text val = null; if ((Object)(object)Hud.instance != (Object)null) { val = (TMP_Text)Hud.instance.m_hoverName; if ((Object)(object)val == (Object)null || (Object)(object)val.font == (Object)null) { val = Hud.instance.m_pieceDescription; } if ((Object)(object)val == (Object)null || (Object)(object)val.font == (Object)null) { TMP_Text[] componentsInChildren = Hud.instance.m_rootObject.GetComponentsInChildren(true); foreach (TMP_Text val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null && (Object)(object)val2.font != (Object)null) { val = val2; break; } } } } if (!((Object)(object)val == (Object)null) && !((Object)(object)val.font == (Object)null)) { _root = new GameObject("SA_ChargeBar"); _root.SetActive(false); _root.transform.SetParent(Hud.instance.m_rootObject.transform, false); RectTransform val3 = _root.AddComponent(); val3.anchorMin = new Vector2(0.5f, 0f); val3.anchorMax = new Vector2(0.5f, 0f); val3.pivot = new Vector2(0.5f, 0f); val3.sizeDelta = new Vector2(200f, 38f); val3.anchoredPosition = new Vector2(0f, 120f); GameObject val4 = new GameObject("Label"); val4.transform.SetParent(_root.transform, false); RectTransform val5 = val4.AddComponent(); val5.anchorMin = new Vector2(0f, 1f); val5.anchorMax = new Vector2(1f, 1f); val5.pivot = new Vector2(0.5f, 0f); val5.sizeDelta = new Vector2(0f, 20f); val5.anchoredPosition = Vector2.zero; TextMeshProUGUI val6 = val4.AddComponent(); ((TMP_Text)val6).font = val.font; ((TMP_Text)val6).fontSharedMaterial = val.fontSharedMaterial; ((TMP_Text)val6).alignment = (TextAlignmentOptions)514; ((Graphic)val6).color = Color.white; ((TMP_Text)val6).fontSize = 13f; ((TMP_Text)val6).fontStyle = (FontStyles)1; ((TMP_Text)val6).richText = false; ((Graphic)val6).raycastTarget = false; _label = (TMP_Text)(object)val6; GameObject val7 = new GameObject("Bg"); val7.transform.SetParent(_root.transform, false); RectTransform val8 = val7.AddComponent(); val8.anchorMin = Vector2.zero; val8.anchorMax = new Vector2(1f, 0f); val8.pivot = Vector2.zero; val8.sizeDelta = new Vector2(0f, 18f); val8.anchoredPosition = Vector2.zero; Image val9 = val7.AddComponent(); ((Graphic)val9).color = new Color(0f, 0f, 0f, 0.6f); ((Graphic)val9).raycastTarget = false; GameObject val10 = new GameObject("Fill"); val10.transform.SetParent(val7.transform, false); RectTransform val11 = val10.AddComponent(); val11.anchorMin = Vector2.zero; val11.anchorMax = new Vector2(0f, 1f); val11.pivot = Vector2.zero; Vector2 offsetMin = (val11.offsetMax = Vector2.zero); val11.offsetMin = offsetMin; _fill = val10.AddComponent(); ((Graphic)_fill).color = new Color(0.2f, 0.85f, 0.3f, 0.85f); ((Graphic)_fill).raycastTarget = false; _built = true; } } } internal static class SneakAmbushCooldown { private sealed class State { public double ReadyAt; public float Duration; public Sprite Icon; } private static readonly ConditionalWeakTable _states = new ConditionalWeakTable(); 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 SneakAmbushFilter { 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 if (weapon?.m_shared == null) { return false; } SharedData shared = weapon.m_shared; if ((int)shared.m_skillType == 2) { return true; } string text = (((Object)(object)weapon.m_dropPrefab != (Object)null) ? ((Object)weapon.m_dropPrefab).name : (shared.m_name ?? "")); return text.IndexOf("knife", StringComparison.OrdinalIgnoreCase) >= 0; } } internal static class SneakAmbushSystem { private static readonly FieldInfo _crouchToggledField = AccessTools.Field(typeof(Player), "m_crouchToggled"); private static readonly MethodInfo _setAlertedMethod = AccessTools.Method(typeof(BaseAI), "SetAlerted", new Type[1] { typeof(bool) }, (Type[])null); private static float _chargeProgress; private static int _diagFrame; private static int _lastUpdateFrame = -1; private static bool _initLogged; private static bool GetCrouching(Player player) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (_crouchToggledField != null) { object value = _crouchToggledField.GetValue(player); bool flag = default(bool); int num; if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } return ((Character)player).IsCrouching(); } internal static bool CollectChargeEntry(Character c, out CooldownEntry entry) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) entry = default(CooldownEntry); if (_chargeProgress <= 0f) { return false; } if ((Object)(object)Player.m_localPlayer == (Object)null) { return false; } ItemData currentWeapon = ((Humanoid)Player.m_localPlayer).GetCurrentWeapon(); Sprite icon = ((currentWeapon != null && currentWeapon.m_shared?.m_icons?.Length > 0) ? currentWeapon.m_shared.m_icons[0] : null); float skillLevel = c.GetSkillLevel((SkillType)101); float num = Mathf.Lerp(1f, Mathf.Max(1f, Plugin.SaChargeSpeedFactor.Value), skillLevel / 100f); float num2 = Plugin.SaChargeTime.Value / num; entry = new CooldownEntry { Icon = icon, Remaining = _chargeProgress * num2, Duration = num2, IsCharging = true }; return true; } internal static void UpdatePlayer(Player player) { //IL_00d4: 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_00ee: Expected O, but got Unknown if (!_initLogged) { _initLogged = true; ManualLogSource log = Plugin.Log; string arg = ((player != null) ? ((Object)player).name : null) ?? "null"; Player localPlayer = Player.m_localPlayer; log.LogInfo((object)string.Format("[SA-INIT] UpdatePlayer 첫 호출 player={0} local={1} enable={2}", arg, ((localPlayer != null) ? ((Object)localPlayer).name : null) ?? "null", Plugin.SaEnable?.Value)); } if (!Plugin.SaEnable.Value || player != Player.m_localPlayer) { return; } int frameCount = Time.frameCount; if (frameCount == _lastUpdateFrame) { return; } _lastUpdateFrame = frameCount; bool crouching = GetCrouching(player); ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon(); bool flag = SneakAmbushFilter.Matches(currentWeapon); Character val = (Character)player; bool flag2 = SneakAmbushCooldown.IsOnCooldown(val); bool flag3 = Plugin.SaMinSkillLevel.Value <= 0f || val.GetSkillLevel((SkillType)2) >= Plugin.SaMinSkillLevel.Value; _diagFrame++; if (_diagFrame >= 120) { _diagFrame = 0; string text = currentWeapon?.m_shared?.m_name ?? "none"; Plugin.Log.LogInfo((object)$"[SA-DIAG] crouch={crouching} knife={flag} cd={flag2} skillOk={flag3} weapon={text} crouchField={_crouchToggledField != null}"); } if (crouching && flag && !flag2 && flag3) { float skillLevel = val.GetSkillLevel((SkillType)101); float num = Mathf.Lerp(1f, Mathf.Max(1f, Plugin.SaChargeSpeedFactor.Value), skillLevel / 100f); float num2 = Plugin.SaChargeTime.Value / num; float chargeProgress = _chargeProgress; _chargeProgress = Mathf.Min(1f, _chargeProgress + Time.deltaTime / num2); if (chargeProgress < 1f && _chargeProgress >= 1f) { Plugin.Log.LogInfo((object)"[SA] Fully charged!"); } } else if (_chargeProgress > 0f) { Plugin.Log.LogInfo((object)$"[SA] Charge reset (crouch={crouching} knife={flag} cd={flag2})"); _chargeProgress = 0f; } } internal static void TryApplyChargeDamage(Character target, ref HitData hit) { //IL_0069: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Invalid comparison between Unknown and I4 //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Expected O, but got Unknown //IL_01fa: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.SaEnable.Value || (Object)(object)target == (Object)null || target.IsPlayer() || _chargeProgress <= 0.01f) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } ZDOID zDOID = ((Character)localPlayer).GetZDOID(); if ((zDOID != ZDOID.None && hit.m_attacker != zDOID) || (int)hit.m_skill != 2 || ((DamageTypes)(ref hit.m_damage)).GetTotalDamage() <= 0f) { return; } ItemData currentWeapon = ((Humanoid)localPlayer).GetCurrentWeapon(); if (!SneakAmbushFilter.Matches(currentWeapon) || !GetCrouching(localPlayer)) { return; } BaseAI baseAI = target.GetBaseAI(); if (!((Object)(object)baseAI == (Object)null) && !baseAI.IsAlerted()) { float num = Mathf.Lerp(1f, Plugin.SaBackstabBonus.Value, _chargeProgress); float chargeProgress = _chargeProgress; _chargeProgress = 0f; Character val = (Character)localPlayer; Sprite icon = ((currentWeapon != null && currentWeapon.m_shared?.m_icons?.Length > 0) ? currentWeapon.m_shared.m_icons[0] : null); SneakAmbushCooldown.TryConsume(val, Plugin.SaCooldown.Value, icon); float value = Plugin.SaAggroResetRadius.Value; if (value > 0f) { ResetAggroInRadius(val, ((Component)val).transform.position, value); } ((DamageTypes)(ref hit.m_damage)).Modify(num); Plugin.Log.LogInfo((object)$"[SA] Charge {chargeProgress * 100f:F0}% → x{num:F2} on {((Object)target).name}"); } } private static void ResetAggroInRadius(Character self, Vector3 center, float radius) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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) int num = 0; foreach (Character allCharacter in Character.GetAllCharacters()) { if ((Object)(object)allCharacter == (Object)null || allCharacter == self || !BaseAI.IsEnemy(self, allCharacter)) { continue; } Vector3 val = ((Component)allCharacter).transform.position - center; val.y = 0f; if (!(((Vector3)(ref val)).magnitude > radius)) { BaseAI baseAI = allCharacter.GetBaseAI(); if ((Object)(object)baseAI != (Object)null) { _setAlertedMethod?.Invoke(baseAI, new object[1] { false }); } num++; } } Plugin.Log.LogInfo((object)$"[SA] Aggro reset: {num} enemies"); } } internal static class SaVfx { internal static void PlayAdrenaline1(Vector3 pos) { //IL_0030: 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) if (!((Object)(object)ZNetScene.instance == (Object)null)) { GameObject prefab = ZNetScene.instance.GetPrefab("fx_Adrenaline1"); if (!((Object)(object)prefab == (Object)null)) { Object.Instantiate(prefab, pos, Quaternion.identity); } } } } internal static class SpearPinCooldown { private sealed class State { public double ReadyAt; public float Duration; public Sprite Icon; } private static readonly ConditionalWeakTable _states = new ConditionalWeakTable(); 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 SpearPinFilter { internal static bool Matches(ItemData weapon) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 if (weapon?.m_shared == null) { return false; } return (int)weapon.m_shared.m_skillType == 5; } } internal sealed class SpearPinEffect : MonoBehaviour { internal static readonly List ActiveList = new List(); private Character _target; private float _originalSpeed; private float _originalRunSpeed; private GameObject _spearVisual; private Player _source; private ItemData _weapon; private float _remainingTime; private float _speedFactor; private float _pullRestoreTime; private bool _isBeingPulled; private float _pullRestoreTimer; private bool _dropSpawned; private Vector3 _lastVisualWorldPos; internal bool IsBeingPulled => _isBeingPulled; internal void Initialize(Character target, float duration, float speedFactor, GameObject spearVisual, Player source, ItemData weapon, float pullRestoreTime) { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) _target = target; _remainingTime = duration; _speedFactor = Mathf.Clamp(speedFactor, 0.05f, 1f); _originalSpeed = target.m_speed; _originalRunSpeed = target.m_runSpeed; _spearVisual = spearVisual; _source = source; _weapon = weapon; _pullRestoreTime = Mathf.Max(0.1f, pullRestoreTime); target.m_speed *= _speedFactor; target.m_runSpeed *= _speedFactor; if ((Object)(object)_spearVisual != (Object)null) { _lastVisualWorldPos = _spearVisual.transform.position; } } private void OnEnable() { ActiveList.Add(this); } private void OnDisable() { ActiveList.Remove(this); } private void OnDestroy() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) ActiveList.Remove(this); RestoreSpeed(); if (!_dropSpawned && _lastVisualWorldPos != Vector3.zero) { SpawnItemDrop(_lastVisualWorldPos); } } private void Update() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_spearVisual != (Object)null) { _lastVisualWorldPos = _spearVisual.transform.position; } if ((Object)(object)_target == (Object)null || _target.IsDead()) { Remove(dropSpear: true); } else if (_isBeingPulled) { _pullRestoreTimer -= Time.deltaTime; float num = 1f - Mathf.Clamp01(_pullRestoreTimer / _pullRestoreTime); float num2 = Mathf.Lerp(_speedFactor, 1f, num); _target.m_speed = _originalSpeed * num2; _target.m_runSpeed = _originalRunSpeed * num2; if (_pullRestoreTimer <= 0f) { Remove(dropSpear: false); } } else { _remainingTime -= Time.deltaTime; if (_remainingTime <= 0f) { Remove(dropSpear: true); } } } internal void StartPull() { if (!_isBeingPulled) { _isBeingPulled = true; _pullRestoreTimer = _pullRestoreTime; if ((Object)(object)_spearVisual != (Object)null) { Object.Destroy((Object)(object)_spearVisual); _spearVisual = null; } TryReturnWeapon(); } } private void TryReturnWeapon() { if ((Object)(object)_source == (Object)null || (Object)(object)_weapon?.m_dropPrefab == (Object)null) { return; } try { ((Humanoid)_source).GetInventory().AddItem(((Object)_weapon.m_dropPrefab).name, 1, _weapon.m_quality, _weapon.m_variant, 0L, "", false); Plugin.Log.LogInfo((object)("[SP] 창 반환: " + _weapon.m_shared.m_name + " → 인벤토리")); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[SP] 창 반환 실패: " + ex.Message)); } } private void Remove(bool dropSpear) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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) RestoreSpeed(); Vector3 pos = (((Object)(object)_spearVisual != (Object)null) ? _spearVisual.transform.position : ((Component)this).transform.position); if ((Object)(object)_spearVisual != (Object)null) { Object.Destroy((Object)(object)_spearVisual); _spearVisual = null; } if (dropSpear) { SpawnItemDrop(pos); } if ((Object)(object)this != (Object)null) { Object.Destroy((Object)(object)this); } } private void RestoreSpeed() { if (!((Object)(object)_target == (Object)null) && !_target.IsDead()) { _target.m_speed = _originalSpeed; _target.m_runSpeed = _originalRunSpeed; } } private void SpawnItemDrop(Vector3 pos) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_00a6: Unknown result type (might be due to invalid IL or missing references) if (_dropSpawned) { return; } _dropSpawned = true; if ((Object)(object)_weapon?.m_dropPrefab == (Object)null || (Object)(object)ZNetScene.instance == (Object)null) { return; } try { GameObject prefab = ZNetScene.instance.GetPrefab(((Object)_weapon.m_dropPrefab).name); if (!((Object)(object)prefab == (Object)null)) { GameObject val = Object.Instantiate(prefab, pos + Vector3.up * 0.3f, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f)); ItemDrop component = val.GetComponent(); if ((Object)(object)component != (Object)null) { component.m_itemData.m_stack = 1; component.m_itemData.m_quality = _weapon.m_quality; component.m_itemData.m_durability = _weapon.m_durability; } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[SP] 드롭 실패: " + ex.Message)); } } } internal static class SpearPinSystem { private static readonly FieldInfo _projWeaponField = AccessTools.Field(typeof(Projectile), "m_weapon"); private static readonly FieldInfo _projOwnerField = AccessTools.Field(typeof(Projectile), "m_owner"); private static bool _pending; private static Player _pendingPlayer; private static ItemData _pendingWeapon; private static int _pullMsgFrame; private const int PullMsgInterval = 90; internal static bool IsPending => _pending; internal static Player PendingPlayer => _pendingPlayer; internal static void QueueTrigger(Humanoid humanoid) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown if (!Plugin.SpEnable.Value) { return; } ItemData currentWeapon = humanoid.GetCurrentWeapon(); if (!SpearPinFilter.Matches(currentWeapon)) { return; } Character val = (Character)humanoid; if (val.IsOwner()) { Player val2 = (Player)(object)((humanoid is Player) ? humanoid : null); if (!((Object)(object)val2 == (Object)null) && (!(Plugin.SpMinSkillLevel.Value > 0f) || !(((Character)val2).GetSkillLevel((SkillType)5) < Plugin.SpMinSkillLevel.Value)) && !SpearPinCooldown.CollectEntry(val, out var _)) { _pending = true; _pendingPlayer = val2; _pendingWeapon = currentWeapon; Plugin.Log.LogInfo((object)("[SP] Queued | wep=" + currentWeapon.m_shared.m_name)); } } } internal static void TryTriggerOnHit(Projectile projectile, Vector3 hitPoint, bool water, Character hitCharacter) { //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown //IL_0141: 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) //IL_019a: Unknown result type (might be due to invalid IL or missing references) if (water || (Object)(object)projectile == (Object)null || !_pending || (Object)(object)hitCharacter == (Object)null) { return; } object? obj = _projOwnerField?.GetValue(projectile); Character val = (Character)((obj is Character) ? obj : null); if ((object)val != _pendingPlayer) { return; } object? obj2 = _projWeaponField?.GetValue(projectile); ItemData val2 = (ItemData)((obj2 is ItemData) ? obj2 : null); if (val2 == null || !SpearPinFilter.Matches(val2)) { return; } _pending = false; if ((Object)(object)((Component)hitCharacter).GetComponent() != (Object)null) { Plugin.Log.LogInfo((object)("[SP] 이미 핀 중: " + ((Object)hitCharacter).name)); return; } Character c = (Character)_pendingPlayer; SharedData shared = val2.m_shared; Sprite icon = ((shared != null && shared.m_icons?.Length > 0) ? val2.m_shared.m_icons[0] : null); if (SpearPinCooldown.TryConsume(c, Plugin.SpCooldown.Value, icon)) { GameObject spearVisual = CreateSpearVisual(val2, hitPoint, ((Component)hitCharacter).transform, SpearPin_Patch_ProjectileOnHit_Prefix.LastImpactDir); SpearPinEffect spearPinEffect = ((Component)hitCharacter).gameObject.AddComponent(); spearPinEffect.Initialize(hitCharacter, Plugin.SpPinDuration.Value, Plugin.SpSpeedFactor.Value, spearVisual, _pendingPlayer, val2, Plugin.SpPullRestoreTime.Value); SaVfx.PlayAdrenaline1(((Component)_pendingPlayer).transform.position); Plugin.Log.LogInfo((object)$"[SP] 핀 적용: {((Object)hitCharacter).name} | dur={Plugin.SpPinDuration.Value:F1}s spd={Plugin.SpSpeedFactor.Value:F2}x"); } } private static GameObject CreateSpearVisual(ItemData weapon, Vector3 hitPoint, Transform parentTransform, Vector3 impactDir) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_0081: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)weapon?.m_dropPrefab == (Object)null) { return null; } GameObject visualChild = GetVisualChild(weapon.m_dropPrefab); if ((Object)(object)visualChild == (Object)null) { Plugin.Log.LogWarning((object)("[SP] 비주얼 자식 없음: " + ((Object)weapon.m_dropPrefab).name)); return null; } Quaternion val = ((((Vector3)(ref impactDir)).sqrMagnitude > 0.01f) ? Quaternion.LookRotation(-impactDir) : Quaternion.identity); GameObject val2 = Object.Instantiate(visualChild, hitPoint, val); Collider[] componentsInChildren = val2.GetComponentsInChildren(true); foreach (Collider val3 in componentsInChildren) { val3.enabled = false; } val2.transform.SetParent(parentTransform, true); return val2; } private static GameObject GetVisualChild(GameObject prefab) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown foreach (Transform item in prefab.transform) { Transform val = item; if ((Object)(object)((Component)val).GetComponentInChildren(true) != (Object)null) { return ((Component)val).gameObject; } } Renderer componentInChildren = prefab.GetComponentInChildren(true); return ((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).gameObject : null; } internal static void UpdatePullInteraction(Player player) { //IL_00bc: 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) if (!Plugin.SpEnable.Value || SpearPinEffect.ActiveList.Count == 0) { return; } float value = Plugin.SpPullRange.Value; SpearPinEffect spearPinEffect = null; float num = float.MaxValue; for (int num2 = SpearPinEffect.ActiveList.Count - 1; num2 >= 0; num2--) { SpearPinEffect spearPinEffect2 = SpearPinEffect.ActiveList[num2]; if ((Object)(object)spearPinEffect2 == (Object)null) { SpearPinEffect.ActiveList.RemoveAt(num2); } else if (!spearPinEffect2.IsBeingPulled) { Character component = ((Component)spearPinEffect2).GetComponent(); if (!((Object)(object)component == (Object)null) && !component.IsDead()) { float num3 = Vector3.Distance(((Component)player).transform.position, ((Component)component).transform.position); if (num3 < value && num3 < num) { num = num3; spearPinEffect = spearPinEffect2; } } } } if ((Object)(object)spearPinEffect == (Object)null) { return; } if (Time.frameCount - _pullMsgFrame > 90) { _pullMsgFrame = Time.frameCount; if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, "창 뽑기 [E]", 0, (Sprite)null, false); } } if (ZInput.GetButtonDown("Use") || ZInput.GetButtonDown("JoyUse")) { spearPinEffect.StartPull(); Plugin.Log.LogInfo((object)"[SP] 창 뽑기 실행"); } } } [HarmonyPatch(typeof(Projectile), "OnHit")] internal static class SpearPin_Patch_ProjectileOnHit_Prefix { private static readonly FieldInfo _projWeaponField = AccessTools.Field(typeof(Projectile), "m_weapon"); private static readonly FieldInfo _projOwnerField = AccessTools.Field(typeof(Projectile), "m_owner"); private static readonly FieldInfo _projVelField = AccessTools.Field(typeof(Projectile), "m_vel"); internal static Vector3 LastImpactDir = Vector3.forward; [HarmonyPriority(600)] private static void Prefix(Projectile __instance, Collider collider, bool water) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (_projVelField?.GetValue(__instance) is Vector3 val && ((Vector3)(ref val)).sqrMagnitude > 0.01f) { LastImpactDir = ((Vector3)(ref val)).normalized; } if (water || !SpearPinSystem.IsPending || (Object)(object)collider == (Object)null) { return; } object? obj = _projOwnerField?.GetValue(__instance); Character val2 = (Character)((obj is Character) ? obj : null); if ((object)val2 != SpearPinSystem.PendingPlayer) { return; } object? obj2 = _projWeaponField?.GetValue(__instance); ItemData weapon = (ItemData)((obj2 is ItemData) ? obj2 : null); if (SpearPinFilter.Matches(weapon)) { GameObject val3 = Projectile.FindHitObject(collider); Character val4 = ((val3 != null) ? val3.GetComponentInParent() : null); if (!((Object)(object)val4 == (Object)null) && !val4.IsPlayer() && !val4.IsDead()) { __instance.m_respawnItemOnHit = false; __instance.m_spawnItem = null; __instance.m_spawnOnTtl = false; } } } } internal static class SwordChainCooldown { private sealed class State { public double ReadyAt; public float Duration; public Sprite Icon; } private static readonly ConditionalWeakTable _states = new ConditionalWeakTable(); 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 SwordChainFilter { 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_003c: 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 != 3) { return false; } GameObject dropPrefab = weapon.m_dropPrefab; string text = ((dropPrefab != null) ? ((Object)dropPrefab).name : null) ?? string.Empty; if (text.IndexOf("warpike", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } return true; } } internal static class SwordChainSystem { internal static float PendingDamageMultiplier; private static ZDOID _chainAttackerZdoid; internal static void OnSecondaryStarted(Humanoid humanoid, Attack currentAttack) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.ScEnable.Value || currentAttack == null) { return; } ItemData currentWeapon = humanoid.GetCurrentWeapon(); if (!SwordChainFilter.Matches(currentWeapon)) { return; } Character val = (Character)humanoid; if (!val.IsOwner() || !(humanoid is Player)) { return; } if (Plugin.ScMinSkillLevel.Value > 0f) { Player val2 = (Player)(object)((humanoid is Player) ? humanoid : null); if ((Object)(object)val2 != (Object)null && ((Character)val2).GetSkillLevel((SkillType)1) < Plugin.ScMinSkillLevel.Value) { return; } } if (!SwordChainCooldown.IsOnCooldown(val)) { SharedData shared = currentWeapon.m_shared; Sprite icon = ((shared != null && shared.m_icons?.Length > 0) ? currentWeapon.m_shared.m_icons[0] : null); if (SwordChainCooldown.TryConsume(val, Plugin.ScCooldown.Value, icon)) { SaVfx.PlayAdrenaline1(((Component)humanoid).transform.position); PendingDamageMultiplier = Plugin.ScDamage1.Value; _chainAttackerZdoid = val.GetZDOID(); GameObject gameObject = ((Component)humanoid).gameObject; SwordChainController swordChainController = gameObject.GetComponent() ?? gameObject.AddComponent(); swordChainController.Begin(humanoid, currentWeapon); Plugin.Log.LogInfo((object)("[SC] Chain started | wep=" + currentWeapon.m_shared.m_name)); } } } internal static void TryInjectChainLevel(Humanoid humanoid, Attack attack, ref float timeSinceLastAttack) { //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) Component val = (Component)humanoid; SwordChainController swordChainController = (((int)val != 0) ? val.GetComponent() : null); if (!((Object)(object)swordChainController == (Object)null) && swordChainController.IsActive) { swordChainController.TryInject(humanoid, attack, ref timeSinceLastAttack); } } internal static void TryApplyChainDamage(Character target, ref HitData hit) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Invalid comparison between Unknown and I4 //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (!(PendingDamageMultiplier <= 0f) && Plugin.ScEnable.Value && !((Object)(object)target == (Object)null) && !target.IsPlayer() && (int)hit.m_skill == 1 && !(hit.m_attacker != _chainAttackerZdoid) && !(((DamageTypes)(ref hit.m_damage)).GetTotalDamage() <= 0f)) { float pendingDamageMultiplier = PendingDamageMultiplier; PendingDamageMultiplier = 0f; if (!Mathf.Approximately(pendingDamageMultiplier, 1f)) { ((DamageTypes)(ref hit.m_damage)).Modify(pendingDamageMultiplier); } Plugin.Log.LogInfo((object)$"[SC] ChainDamage x{pendingDamageMultiplier:F2} on {((Object)target).name}"); } } internal static void ClearPending() { PendingDamageMultiplier = 0f; } } internal sealed class SwordChainController : MonoBehaviour { private static readonly FieldInfo _chainLevelField = AccessTools.Field(typeof(Attack), "m_currentAttackCainLevel"); private Humanoid _humanoid; private ItemData _weapon; private int _stage; private float _nextStageAt; private bool _waitingForAttackEnd; private bool _wasInAttack; private Animator _animator; private ZSyncAnimation _zanim; private float _originalAnimSpeed = 1f; private bool _speedApplied; internal bool IsActive => _stage > 0 && _stage < 3; internal void Begin(Humanoid humanoid, ItemData weapon) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) _humanoid = humanoid; _weapon = weapon; _stage = 1; _waitingForAttackEnd = true; _wasInAttack = false; _nextStageAt = Time.time + 3f; ((Behaviour)this).enabled = true; _animator = ((Component)humanoid).GetComponentInChildren(); _zanim = ((Character)humanoid).GetZAnim(); ReapplyAnimSpeed(); } internal void TryInject(Humanoid humanoid, Attack attack, ref float timeSinceLastAttack) { if (!IsActive) { return; } if (!SwordChainFilter.Matches(humanoid.GetCurrentWeapon())) { Object.Destroy((Object)(object)this); return; } int num = ((_stage == 1) ? 1 : 2); _chainLevelField?.SetValue(attack, num); timeSinceLastAttack = 0f; SwordChainSystem.PendingDamageMultiplier = ((num == 1) ? Plugin.ScDamage2.Value : Plugin.ScDamage3.Value); Plugin.Log.LogInfo((object)$"[SC] Inject chainLevel={num} (stage={_stage})"); _stage++; if (_stage >= 3) { _waitingForAttackEnd = false; _wasInAttack = false; _nextStageAt = Time.time + 3f; RestoreAnimSpeed(); } else { _waitingForAttackEnd = true; _wasInAttack = false; _nextStageAt = Time.time + 3f; ReapplyAnimSpeed(); } } private void ReapplyAnimSpeed() { float value = Plugin.ScAnimSpeed.Value; if (!Mathf.Approximately(value, 1f) && !((Object)(object)_animator == (Object)null)) { if (!_speedApplied) { _originalAnimSpeed = _animator.speed; _speedApplied = true; } ZSyncAnimation zanim = _zanim; if (zanim != null) { zanim.SetSpeed(value); } _animator.speed = value; } } private void MaintainAnimSpeed() { if (_speedApplied) { float value = Plugin.ScAnimSpeed.Value; if (!Mathf.Approximately(value, 1f) && (Object)(object)_animator != (Object)null) { _animator.speed = value; } } } private void RestoreAnimSpeed() { if (_speedApplied) { _speedApplied = false; ZSyncAnimation zanim = _zanim; if (zanim != null) { zanim.SetSpeed(_originalAnimSpeed); } if ((Object)(object)_animator != (Object)null) { _animator.speed = _originalAnimSpeed; } } } private void Update() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown if ((Object)(object)_humanoid == (Object)null || _weapon == null) { Object.Destroy((Object)(object)this); return; } Character val = (Character)_humanoid; if (val.IsDead() || !val.IsOwner()) { Object.Destroy((Object)(object)this); } else if (_stage >= 3) { RestoreAnimSpeed(); if (Time.time > _nextStageAt) { Object.Destroy((Object)(object)this); } } else { if (!IsActive) { return; } if (_waitingForAttackEnd) { if (val.InAttack()) { if (!_wasInAttack) { ReapplyAnimSpeed(); } _wasInAttack = true; MaintainAnimSpeed(); return; } if (!_wasInAttack) { if (Time.time > _nextStageAt) { Plugin.Log.LogInfo((object)$"[SC] Timeout waiting for attack start (stage={_stage})"); Object.Destroy((Object)(object)this); } return; } _wasInAttack = false; _waitingForAttackEnd = false; _nextStageAt = Time.time + Plugin.ScChainWindow.Value; Plugin.Log.LogInfo((object)$"[SC] Attack ended, opening chain window (stage={_stage})"); } if (Time.time < _nextStageAt) { if (val.IsStaggering() || !SwordChainFilter.Matches(_humanoid.GetCurrentWeapon())) { Object.Destroy((Object)(object)this); } else { val.StartAttack((Character)null, false); } } else { Plugin.Log.LogInfo((object)$"[SC] Chain window expired (stage={_stage})"); Object.Destroy((Object)(object)this); } } } private void OnDestroy() { RestoreAnimSpeed(); SwordChainSystem.ClearPending(); Plugin.Log.LogInfo((object)$"[SC] Controller destroyed at stage={_stage}"); } } internal static class TripleThrustCooldown { private sealed class State { public double ReadyAt; public float Duration; public Sprite Icon; } private static readonly ConditionalWeakTable _states = new ConditionalWeakTable(); 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 TripleThrustFilter { 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_0030: Invalid comparison between Unknown and I4 if (weapon?.m_shared == null) { return false; } SharedData shared = weapon.m_shared; return (int)shared.m_skillType == 4 && (int)shared.m_itemType == 14; } } internal static class TripleThrustSystem { 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.TtEnable.Value) { return false; } ItemData currentWeapon = humanoid.GetCurrentWeapon(); if (!TripleThrustFilter.Matches(currentWeapon)) { return false; } Character val = (Character)humanoid; if (!val.IsOwner()) { return false; } Player val2 = (Player)(object)((humanoid is Player) ? humanoid : null); if ((Object)(object)val2 == (Object)null) { return false; } if ((int)Plugin.SpecialKey.Value != 0 && !SpecialInput.Active) { return false; } if (Plugin.TtMinSkillLevel.Value > 0f && ((Character)val2).GetSkillLevel((SkillType)4) < Plugin.TtMinSkillLevel.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 (!TripleThrustCooldown.TryConsume(val, Plugin.TtCooldown.Value, icon)) { return false; } SaVfx.PlayAdrenaline1(((Component)val2).transform.position); TripleThrustController.Begin(humanoid, currentWeapon); Plugin.Log.LogInfo((object)"[TT] SA 차단 → 3연 PA 시작"); return true; } internal static void ExecuteIfQueued(Humanoid humanoid) { GetActiveController(humanoid)?.OnAttackTriggered(); } internal static TripleThrustController GetActiveController(Humanoid h) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) TripleThrustController component = ((Component)h).GetComponent(); return ((Object)(object)component != (Object)null && component.IsActive) ? component : null; } } internal sealed class TripleThrustController : MonoBehaviour { private Humanoid _humanoid; private ItemData _weapon; private Animator _animator; private float _savedAnimSpeed; private int _hitsLeft; internal bool IsActive => _hitsLeft > 0; internal static TripleThrustController Begin(Humanoid humanoid, ItemData weapon) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) GameObject gameObject = ((Component)humanoid).gameObject; TripleThrustController component = gameObject.GetComponent(); if ((Object)(object)component != (Object)null) { ((MonoBehaviour)component).StopAllCoroutines(); component.RestoreAnimSpeed(); } TripleThrustController tripleThrustController = component ?? gameObject.AddComponent(); tripleThrustController.Setup(humanoid, weapon); return tripleThrustController; } private void Setup(Humanoid humanoid, ItemData weapon) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) _humanoid = humanoid; _weapon = weapon; _hitsLeft = 3; _animator = ((Component)humanoid).GetComponentInChildren(); if ((Object)(object)_animator != (Object)null) { _savedAnimSpeed = _animator.speed; _animator.speed = Plugin.TtAnimSpeed.Value; } ((MonoBehaviour)this).StartCoroutine(FireFirstPA()); } 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) { _hitsLeft--; if (_hitsLeft > 0) { ((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 && ch.InAttack()) { yield return null; } if ((Object)(object)_humanoid != (Object)null && _hitsLeft > 0 && (Object)(object)ch != (Object)null && !ch.IsDead()) { ((Character)_humanoid).StartAttack((Character)null, false); } } private void Update() { if (IsActive && !((Object)(object)_animator == (Object)null)) { _animator.speed = Plugin.TtAnimSpeed.Value; } } private void Finish() { RestoreAnimSpeed(); Object.Destroy((Object)(object)this); } private void OnDestroy() { RestoreAnimSpeed(); } internal void RestoreAnimSpeed() { if ((Object)(object)_animator != (Object)null && _savedAnimSpeed > 0f) { _animator.speed = _savedAnimSpeed; } } } [HarmonyPatch(typeof(Character), "Damage")] internal static class TripleThrust_Patch_Damage { private static void Prefix(Character __instance, ref HitData hit) { //IL_0014: 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_0033: 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())) { TripleThrustController component = ((Component)Player.m_localPlayer).GetComponent(); if (!((Object)(object)component == (Object)null) && component.IsActive) { HitData obj = hit; obj.m_staggerMultiplier *= Plugin.TtStaggerMultiplier.Value; } } } }