Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SpecialAttack v1.2.5
SpecialAttackPlugin.dll
Decompiled 4 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Splatform; using TMPro; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("SpecialAttackPlugin")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SpecialAttackPlugin")] [assembly: AssemblyTitle("SpecialAttackPlugin")] [assembly: AssemblyVersion("1.0.0.0")] namespace SpecialAttackPlugin; internal static class AdrenalineOnHit { internal static void Grant(string techniqueName, Character attacker, Character target, float baseAmount) { if (Plugin.AdrenalineOnHitEnable.Value && !((Object)(object)attacker == (Object)null) && !((Object)(object)target == (Object)null) && !(baseAmount <= 0f) && (BaseAI.IsEnemy(attacker, target) || ((Object)(object)target.GetBaseAI() != (Object)null && target.GetBaseAI().IsAggravatable()))) { float num = baseAmount * target.m_enemyAdrenalineMultiplier; if (!(num <= 0f)) { attacker.AddAdrenaline(num); } } } } internal static class AftershockCooldown { private sealed class State { public double ReadyAt; public float Duration; public Sprite Icon; } private static readonly ConditionalWeakTable<Character, State> _states = new ConditionalWeakTable<Character, State>(); internal static bool IsOnCooldown(Character c) { if (!_states.TryGetValue(c, out var value)) { return false; } double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble); return num < value.ReadyAt; } internal static bool TryConsume(Character c, float cooldown, Sprite icon = null) { if (cooldown <= 0f) { return true; } State value = _states.GetValue(c, (Character _) => new State()); double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble); if (num < value.ReadyAt) { return false; } value.ReadyAt = num + (double)cooldown; value.Duration = cooldown; value.Icon = icon; return true; } internal static bool CollectEntry(Character c, out CooldownEntry entry) { entry = default(CooldownEntry); if (!_states.TryGetValue(c, out var value)) { return false; } double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble); float num2 = (float)Math.Max(0.0, value.ReadyAt - num); if (num2 <= 0f) { return false; } entry = new CooldownEntry { Icon = value.Icon, Remaining = num2, Duration = value.Duration }; return true; } } internal static class AftershockFilter { internal static bool Matches(ItemData weapon) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 if (weapon?.m_shared == null) { return false; } SharedData shared = weapon.m_shared; if ((int)shared.m_itemType != 14) { return false; } string text = shared.m_secondaryAttack?.m_attackAnimation ?? ""; if (text.IndexOf("sledge", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("slam", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } string text2 = shared.m_name ?? ""; if (text2.IndexOf("sledge", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } string text3 = (((Object)(object)weapon.m_dropPrefab != (Object)null) ? ((Object)weapon.m_dropPrefab).name : ""); return text3.StartsWith("SledgeGold", StringComparison.OrdinalIgnoreCase); } internal static bool HasNoSecondaryAnim(ItemData weapon) { return string.IsNullOrEmpty(weapon?.m_shared?.m_secondaryAttack?.m_attackAnimation); } } internal static class AftershockSystem { private static readonly Collider[] _hitBuf = (Collider[])(object)new Collider[64]; private static readonly HashSet<GameObject> _hitSet = new HashSet<GameObject>(); private static int _maskChars; private static int _maskTerrain; private static bool _pending; private static Player _pendingPlayer; private static ItemData _pendingWeapon; private static Attack _pendingAttack; private static Vector3 _pendingForward; private static readonly string[] _waveVfxNames = new string[3] { "vfx_sledge_iron_hit", "sledge_aoe", "fx_goblinbrute_groundslam" }; private static bool _vfxWarningLogged; private static readonly HashSet<string> _allowedVfxNames = new HashSet<string> { "Cloud", "vfx_troll_rock_destroyed", "waves" }; private static int GetMaskChars() { if (_maskChars == 0) { _maskChars = LayerMask.GetMask(new string[9] { "character", "character_net", "character_ghost", "hitbox", "character_noenv", "vehicle", "piece", "piece_nonsolid", "Default" }); } return _maskChars; } private static int GetMaskTerrain() { if (_maskTerrain == 0) { _maskTerrain = LayerMask.GetMask(new string[1] { "terrain" }); } return _maskTerrain; } internal static bool TryInterceptSA(Humanoid humanoid) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.AsEnable.Value) { return false; } ItemData currentWeapon = humanoid.GetCurrentWeapon(); if (!AftershockFilter.Matches(currentWeapon)) { return false; } if (!AftershockFilter.HasNoSecondaryAnim(currentWeapon)) { return false; } Character val = (Character)humanoid; if (!val.IsOwner()) { return false; } Player val2 = (Player)(object)((humanoid is Player) ? humanoid : null); if ((Object)(object)val2 == (Object)null) { return false; } if ((int)Plugin.SpecialKey.Value != 0 && !SpecialInput.Active) { return false; } if (Plugin.AsMinSkillLevel.Value > 0f && ((Character)val2).GetSkillLevel((SkillType)3) < Plugin.AsMinSkillLevel.Value) { return false; } if (AftershockCooldown.IsOnCooldown(val) || SkillLimitSystem.ShouldBlock(val, "Aftershock")) { return false; } Attack val3 = currentWeapon.m_shared?.m_secondaryAttack; float num = val3?.m_attackStamina ?? 0f; if (num > 0f && !val.HaveStamina(num)) { return false; } float num2 = val3?.m_attackEitr ?? 0f; if (num2 > 0f && !val.HaveEitr(num2)) { return false; } SharedData shared = currentWeapon.m_shared; Sprite icon = ((shared != null && shared.m_icons?.Length > 0) ? currentWeapon.m_shared.m_icons[0] : null); if (!AftershockCooldown.TryConsume(val, Plugin.AsCooldown.Value, icon)) { return false; } if (num > 0f) { ((Character)val2).UseStamina(num); } if (num2 > 0f) { ((Character)val2).UseEitr(num2); } TriggerNow(val2, currentWeapon, null, ((Component)val).transform.forward); return true; } internal static void QueueTrigger(Humanoid humanoid, Attack attack) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.AsEnable.Value) { return; } ItemData currentWeapon = humanoid.GetCurrentWeapon(); if (!AftershockFilter.Matches(currentWeapon) || AftershockFilter.HasNoSecondaryAnim(currentWeapon)) { return; } Character val = (Character)humanoid; if (val.IsOwner()) { Player val2 = (Player)(object)((humanoid is Player) ? humanoid : null); if (!((Object)(object)val2 == (Object)null) && (!(Plugin.AsMinSkillLevel.Value > 0f) || !(((Character)val2).GetSkillLevel((SkillType)3) < Plugin.AsMinSkillLevel.Value)) && !AftershockCooldown.IsOnCooldown(val) && !SkillLimitSystem.ShouldBlock(val, "Aftershock")) { _pending = true; _pendingPlayer = val2; _pendingWeapon = currentWeapon; _pendingAttack = attack; _pendingForward = ((Component)val).transform.forward; } } } internal static void ExecuteIfQueued(Humanoid humanoid) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) if (_pending && (object)humanoid == _pendingPlayer) { _pending = false; Character c = (Character)_pendingPlayer; float value = Plugin.AsCooldown.Value; SharedData shared = _pendingWeapon.m_shared; if (AftershockCooldown.TryConsume(c, value, (shared != null && shared.m_icons?.Length > 0) ? _pendingWeapon.m_shared.m_icons[0] : null)) { TriggerNow(_pendingPlayer, _pendingWeapon, _pendingAttack, _pendingForward); } } } internal static int ComputeWaveCount(float skillLevel) { int result = 1; if (skillLevel >= Plugin.AsShockLevel2.Value) { result = 2; } if (skillLevel >= Plugin.AsShockLevel3.Value) { result = 3; } if (skillLevel >= Plugin.AsShockLevel4.Value) { result = 4; } if (skillLevel >= Plugin.AsShockLevel5.Value) { result = 5; } return result; } internal static Vector3 ComputeOrigin(Vector3 startPosition, Vector3 forward) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((((Vector3)(ref forward)).sqrMagnitude > 0.001f) ? ((Vector3)(ref forward)).normalized : Vector3.forward); Vector3 val2 = startPosition + val * Plugin.AsImpactOffset.Value; val2.y = GetGroundY(val2, startPosition.y) + 0.3f; return val2; } private static void TriggerNow(Player player, ItemData weapon, Attack attack, Vector3 forward) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) SaVfx.PlayAdrenaline1(((Component)player).transform.position); GameObject gameObject = ((Component)player).gameObject; AftershockController aftershockController = gameObject.AddComponent<AftershockController>(); aftershockController.Initialize(player, weapon, attack, forward); } internal static void ApplyWave(Player player, ItemData weapon, Attack attack, int waveIndex, Vector3 origin, Vector3 facingDir) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) Character val = (Character)player; if ((Object)(object)val == (Object)null || val.IsDead()) { return; } int num = waveIndex + 1; float num2 = Mathf.Clamp01((float)(num - 1) / 4f); float num3 = Mathf.Lerp(Plugin.AsScaleFirst.Value, Plugin.AsScaleLast.Value, num2); float dmgScale = Mathf.Lerp(Plugin.AsDamageFirst.Value, Plugin.AsDamageLast.Value, num2); float num4 = Plugin.AsRadius.Value * num3; float randomSkillFactor = val.GetRandomSkillFactor((SkillType)3); Quaternion rotation = ((((Vector3)(ref facingDir)).sqrMagnitude > 0.001f) ? Quaternion.LookRotation(facingDir) : Quaternion.identity); SpawnWaveVFX(weapon, attack, origin, rotation, num3); _hitSet.Clear(); int num5 = Physics.OverlapSphereNonAlloc(origin, num4, _hitBuf, GetMaskChars(), (QueryTriggerInteraction)0); for (int i = 0; i < num5; i++) { Collider val2 = _hitBuf[i]; if ((Object)(object)val2 == (Object)null) { continue; } GameObject val3 = Projectile.FindHitObject(val2); if ((Object)(object)val3 == (Object)null || !_hitSet.Add(val3)) { continue; } Character componentInParent = val3.GetComponentInParent<Character>(); if ((Object)(object)componentInParent != (Object)null) { if (!componentInParent.IsPlayer() && componentInParent != val && !componentInParent.IsDead() && BaseAI.IsEnemy(val, componentInParent) && !componentInParent.InDodge() && !componentInParent.IsDebugFlying()) { ApplyHit(val, componentInParent, weapon, attack, origin, dmgScale, randomSkillFactor); } continue; } IDestructible componentInParent2 = val3.GetComponentInParent<IDestructible>(); if (componentInParent2 != null && !(componentInParent2 is Character)) { ApplyDestructibleHit(val, componentInParent2, weapon, origin, dmgScale, randomSkillFactor); } } } private static void SpawnWaveVFX(ItemData weapon, Attack attack, Vector3 origin, Quaternion rotation, float scale) { //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNetScene.instance != (Object)null) { string[] waveVfxNames = _waveVfxNames; foreach (string text in waveVfxNames) { GameObject prefab = ZNetScene.instance.GetPrefab(text); if (!((Object)(object)prefab == (Object)null)) { GameObject val = Object.Instantiate<GameObject>(prefab, origin, rotation); val.transform.localScale = Vector3.one * scale; ScaleParticleSystems(val, scale); Aoe[] componentsInChildren = val.GetComponentsInChildren<Aoe>(true); foreach (Aoe val2 in componentsInChildren) { Object.Destroy((Object)(object)val2); } ApplyVfxToggles(val); return; } } } if (attack != null && attack.m_triggerEffect?.m_effectPrefabs?.Length > 0) { attack.m_triggerEffect.Create(origin, rotation, (Transform)null, scale, -1, default(ZDOID)); } else if (!_vfxWarningLogged) { _vfxWarningLogged = true; Plugin.Log.LogWarning((object)"[AS VFX] NO VFX"); } } private static void ApplyVfxToggles(GameObject obj) { ParticleSystem[] componentsInChildren = obj.GetComponentsInChildren<ParticleSystem>(true); foreach (ParticleSystem val in componentsInChildren) { ((Component)val).gameObject.SetActive(_allowedVfxNames.Contains(((Object)((Component)val).gameObject).name)); } } private static void ScaleParticleSystems(GameObject obj, float scale) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) if (Mathf.Approximately(scale, 1f)) { return; } ParticleSystem[] componentsInChildren = obj.GetComponentsInChildren<ParticleSystem>(true); foreach (ParticleSystem val in componentsInChildren) { MainModule main = val.main; if (((MainModule)(ref main)).startSize3D) { ((MainModule)(ref main)).startSizeX = ScaleCurve(((MainModule)(ref main)).startSizeX, scale); ((MainModule)(ref main)).startSizeY = ScaleCurve(((MainModule)(ref main)).startSizeY, scale); ((MainModule)(ref main)).startSizeZ = ScaleCurve(((MainModule)(ref main)).startSizeZ, scale); } else { ((MainModule)(ref main)).startSize = ScaleCurve(((MainModule)(ref main)).startSize, scale); } ((MainModule)(ref main)).startSpeed = ScaleCurve(((MainModule)(ref main)).startSpeed, scale); ShapeModule shape = val.shape; if (((ShapeModule)(ref shape)).enabled) { ((ShapeModule)(ref shape)).radius = ((ShapeModule)(ref shape)).radius * scale; ((ShapeModule)(ref shape)).scale = ((ShapeModule)(ref shape)).scale * scale; ((ShapeModule)(ref shape)).position = ((ShapeModule)(ref shape)).position * scale; } TrailModule trails = val.trails; if (((TrailModule)(ref trails)).enabled) { ((TrailModule)(ref trails)).widthOverTrail = ScaleCurve(((TrailModule)(ref trails)).widthOverTrail, scale); } ParticleSystemRenderer component = ((Component)val).GetComponent<ParticleSystemRenderer>(); if ((Object)(object)component != (Object)null) { component.lengthScale *= scale; component.velocityScale *= scale; } } } private static MinMaxCurve ScaleCurve(MinMaxCurve curve, float scale) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected I4, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) ParticleSystemCurveMode mode = ((MinMaxCurve)(ref curve)).mode; ParticleSystemCurveMode val = mode; switch ((int)val) { case 0: ((MinMaxCurve)(ref curve)).constant = ((MinMaxCurve)(ref curve)).constant * scale; break; case 3: ((MinMaxCurve)(ref curve)).constantMin = ((MinMaxCurve)(ref curve)).constantMin * scale; ((MinMaxCurve)(ref curve)).constantMax = ((MinMaxCurve)(ref curve)).constantMax * scale; break; case 1: case 2: ((MinMaxCurve)(ref curve)).curveMultiplier = ((MinMaxCurve)(ref curve)).curveMultiplier * scale; break; } return curve; } private static float GetGroundY(Vector3 pos, float fallback) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) RaycastHit val = default(RaycastHit); if (Physics.Raycast(new Vector3(pos.x, pos.y + 10f, pos.z), Vector3.down, ref val, 25f, GetMaskTerrain(), (QueryTriggerInteraction)1)) { return ((RaycastHit)(ref val)).point.y; } return fallback; } private static void ApplyHit(Character attacker, Character target, ItemData weapon, Attack attack, Vector3 origin, float dmgScale, float skillFactor) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) DamageTypes damage = weapon.GetDamage(); ((DamageTypes)(ref damage)).Modify(dmgScale * skillFactor); HitData val = new HitData(); val.m_damage = damage; val.m_skill = (SkillType)3; val.m_pushForce = weapon.m_shared.m_attackForce; val.m_staggerMultiplier = attack?.m_staggerMultiplier ?? 1f; val.m_blockable = false; val.m_dodgeable = false; val.m_skillRaiseAmount = 0f; val.m_point = target.GetCenterPoint(); Vector3 val2 = target.GetCenterPoint() - origin; val2.y = 0f; val.m_dir = ((((Vector3)(ref val2)).sqrMagnitude > 0.001f) ? ((Vector3)(ref val2)).normalized : ((Component)attacker).transform.forward); val.SetAttacker(attacker); target.Damage(val); AdrenalineOnHit.Grant("Aftershock", attacker, target, attack?.m_attackAdrenaline ?? 0f); } private static void ApplyDestructibleHit(Character attacker, IDestructible target, ItemData weapon, Vector3 origin, float dmgScale, float skillFactor) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) DamageTypes damage = weapon.GetDamage(); ((DamageTypes)(ref damage)).Modify(dmgScale * skillFactor); HitData val = new HitData(); val.m_damage = damage; val.m_skill = (SkillType)3; val.m_pushForce = 0f; val.m_blockable = false; val.m_dodgeable = false; val.m_skillRaiseAmount = 0f; Component val2 = (Component)(object)((target is Component) ? target : null); val.m_point = (((Object)(object)val2 != (Object)null) ? val2.transform.position : origin); Vector3 val3 = val.m_point - origin; val3.y = 0f; val.m_dir = ((((Vector3)(ref val3)).sqrMagnitude > 0.001f) ? ((Vector3)(ref val3)).normalized : ((Component)attacker).transform.forward); val.SetAttacker(attacker); target.Damage(val); } } internal sealed class AftershockController : MonoBehaviour { private Player _player; private ItemData _weapon; private Attack _attack; private Vector3 _forwardDir; private Vector3 _origin; private int _nextWave; private float _nextWaveTime; private int _totalWaves; internal void Initialize(Player player, ItemData weapon, Attack attack, Vector3 attackForward) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) _player = player; _weapon = weapon; _attack = attack; _forwardDir = ((((Vector3)(ref attackForward)).sqrMagnitude > 0.001f) ? ((Vector3)(ref attackForward)).normalized : Vector3.forward); Character val = (Character)player; _origin = AftershockSystem.ComputeOrigin(((Component)val).transform.position, _forwardDir); float level = SkillLevelResolver.GetLevel(player, weapon, (SkillType)3); _totalWaves = AftershockSystem.ComputeWaveCount(level); _nextWave = 0; _nextWaveTime = Time.time; ((Behaviour)this).enabled = true; } private void Update() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_player == (Object)null || ((Character)_player).IsDead()) { Object.Destroy((Object)(object)this); return; } while (_nextWave < _totalWaves && Time.time >= _nextWaveTime) { AftershockSystem.ApplyWave(_player, _weapon, _attack, _nextWave, _origin, _forwardDir); _nextWave++; float num = Mathf.Max(0f, Plugin.AsShockInterval.Value); _nextWaveTime += num; if (num > 0f) { break; } } if (_nextWave >= _totalWaves) { Object.Destroy((Object)(object)this); } } } internal sealed class ArrowEmbedTracker : MonoBehaviour { private Character _ch; private bool _recovered; private readonly List<GameObject> _visuals = new List<GameObject>(); private readonly Dictionary<Player, int> _hitCounts = new Dictionary<Player, int>(); private readonly Dictionary<Player, ItemData> _hitAmmoSample = new Dictionary<Player, ItemData>(); private void Awake() { _ch = ((Component)this).GetComponent<Character>(); } internal void AddVisual(GameObject go) { if ((Object)(object)go == (Object)null) { return; } _visuals.Add(go); int num = Mathf.Max(1, Plugin.ArEmbedMax.Value); while (_visuals.Count > num) { GameObject val = _visuals[0]; _visuals.RemoveAt(0); if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } } internal void RegisterHit(Player player, ItemData ammo) { if (!((Object)(object)player == (Object)null)) { _hitCounts.TryGetValue(player, out var value); _hitCounts[player] = value + 1; if (ammo != null) { _hitAmmoSample[player] = ammo; } } } internal void TryRecover() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) if (_recovered) { return; } _recovered = true; Vector3 position = ((Component)this).transform.position; foreach (KeyValuePair<Player, int> hitCount in _hitCounts) { Player key = hitCount.Key; int value = hitCount.Value; if ((Object)(object)key == (Object)null || value <= 0) { continue; } float skillLevel = ((Character)key).GetSkillLevel((SkillType)8); float num = Mathf.Clamp01(skillLevel / 100f); float num2 = Mathf.Lerp(Plugin.ArRecoverChancePercentLv0.Value, Plugin.ArRecoverChancePercentLv100.Value, num); float num3 = Mathf.Clamp01(num2 / 100f); _hitAmmoSample.TryGetValue(key, out var value2); for (int i = 0; i < value; i++) { if (Random.value <= num3) { ArrowEmbedSystem.SpawnArrowItem(value2, position); } } } } private void OnDestroy() { foreach (GameObject visual in _visuals) { if ((Object)(object)visual != (Object)null) { Object.Destroy((Object)(object)visual); } } _visuals.Clear(); } } internal static class ArrowEmbedSystem { internal static void OnProjectileHit(Projectile proj, Collider collider, Vector3 hitPoint, bool water) { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) if (water || (Object)(object)proj == (Object)null || (Object)(object)collider == (Object)null) { return; } ItemData weapon = ProjectileAccess.GetWeapon(proj); if (!HuntersVolleyFilter.Matches(weapon)) { return; } Character owner = ProjectileAccess.GetOwner(proj); Player val = (Player)(object)((owner is Player) ? owner : null); if ((Object)(object)val == (Object)null) { return; } ItemData ammo = ProjectileAccess.GetAmmo(proj); GameObject val2 = Projectile.FindHitObject(collider); Character val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponentInParent<Character>() : null); if ((Object)(object)val3 != (Object)null) { ArrowEmbedTracker arrowEmbedTracker = ((Component)val3).gameObject.GetComponent<ArrowEmbedTracker>(); if ((Object)(object)arrowEmbedTracker == (Object)null) { arrowEmbedTracker = ((Component)val3).gameObject.AddComponent<ArrowEmbedTracker>(); } arrowEmbedTracker.RegisterHit(val, ammo); if (Plugin.ArEmbedEnable.Value) { GameObject val4 = CreateArrowVisual(proj, hitPoint, val3); if ((Object)(object)val4 != (Object)null) { arrowEmbedTracker.AddVisual(val4); } } return; } float skillLevel = ((Character)val).GetSkillLevel((SkillType)8); float num = Mathf.Clamp01(skillLevel / 100f); float num2 = Mathf.Lerp(Plugin.ArMissRecoverChancePercentLv0.Value, Plugin.ArMissRecoverChancePercentLv100.Value, num); float num3 = Mathf.Clamp01(num2 / 100f); if (!(Random.value <= num3)) { return; } if ((Object)(object)proj != (Object)null && (Object)(object)((Component)proj).gameObject != (Object)null) { if ((Object)(object)ZNetScene.instance != (Object)null) { ZNetScene.instance.Destroy(((Component)proj).gameObject); } else { Object.Destroy((Object)(object)((Component)proj).gameObject); } } SpawnArrowItem(ammo, hitPoint); } internal static bool SpawnArrowItem(ItemData ammo, Vector3 pos) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ammo?.m_dropPrefab == (Object)null || (Object)(object)ZNetScene.instance == (Object)null) { return false; } try { GameObject prefab = ZNetScene.instance.GetPrefab(((Object)ammo.m_dropPrefab).name); if ((Object)(object)prefab == (Object)null) { return false; } GameObject val = Object.Instantiate<GameObject>(prefab, pos + Vector3.up * 0.1f, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f)); ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { return false; } component.m_itemData.m_stack = 1; component.m_itemData.m_quality = ammo.m_quality; return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("[AR] 화살 드롭 실패: " + ex.Message)); return false; } } private static GameObject CreateArrowVisual(Projectile proj, Vector3 hitPoint, Character target) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) GameObject visualChild = GetVisualChild(((Component)proj).gameObject); if ((Object)(object)visualChild == (Object)null) { return null; } Vector3 forward = ((Component)proj).transform.forward; Vector3 val; if (!(((Vector3)(ref forward)).sqrMagnitude > 0.01f)) { val = Vector3.forward; } else { forward = ((Component)proj).transform.forward; val = ((Vector3)(ref forward)).normalized; } Vector3 val2 = val; Vector3 val3 = hitPoint + val2 * Mathf.Max(0f, Plugin.ArEmbedDepth.Value); GameObject val4 = Object.Instantiate<GameObject>(visualChild, val3, ((Component)proj).transform.rotation); Collider[] componentsInChildren = val4.GetComponentsInChildren<Collider>(true); foreach (Collider val5 in componentsInChildren) { val5.enabled = false; } WeaponBoneAttach.Attach(val4, target, hitPoint, ((Component)target).transform); return val4; } private static GameObject GetVisualChild(GameObject prefab) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown foreach (Transform item in prefab.transform) { Transform val = item; if ((Object)(object)((Component)val).GetComponentInChildren<Renderer>(true) != (Object)null) { return ((Component)val).gameObject; } } Renderer componentInChildren = prefab.GetComponentInChildren<Renderer>(true); return ((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).gameObject : null; } } [HarmonyPatch(typeof(Projectile), "OnHit")] internal static class Patch_ProjectileOnHit_ArrowEmbed { private static void Postfix(Projectile __instance, Collider collider, Vector3 hitPoint, bool water) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) ArrowEmbedSystem.OnProjectileHit(__instance, collider, hitPoint, water); } } [HarmonyPatch(typeof(Character), "OnDeath")] internal static class Patch_CharacterOnDeath_ArrowEmbed { private static void Prefix(Character __instance) { ((Component)__instance).GetComponent<ArrowEmbedTracker>()?.TryRecover(); } } internal static class QuadSlashCooldown { private sealed class State { public double ReadyAt; public float Duration; public Sprite Icon; } private static readonly ConditionalWeakTable<Character, State> _states = new ConditionalWeakTable<Character, State>(); internal static bool IsOnCooldown(Character c) { if (!_states.TryGetValue(c, out var value)) { return false; } double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble); return num < value.ReadyAt; } internal static bool TryConsume(Character c, float cooldown, Sprite icon = null) { if (cooldown <= 0f) { return true; } State value = _states.GetValue(c, (Character _) => new State()); double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble); if (num < value.ReadyAt) { return false; } value.ReadyAt = num + (double)cooldown; value.Duration = cooldown; value.Icon = icon; return true; } internal static bool CollectEntry(Character c, out CooldownEntry entry) { entry = default(CooldownEntry); if (!_states.TryGetValue(c, out var value)) { return false; } double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble); float num2 = (float)Math.Max(0.0, value.ReadyAt - num); if (num2 <= 0f) { return false; } entry = new CooldownEntry { Icon = value.Icon, Remaining = num2, Duration = value.Duration }; return true; } } internal static class QuadSlashFilter { internal static bool Matches(ItemData weapon) { if (weapon?.m_shared == null || (Object)(object)weapon.m_dropPrefab == (Object)null) { return false; } string name = ((Object)weapon.m_dropPrefab).name; return name.Equals("THSwordKrom", StringComparison.OrdinalIgnoreCase) || name.IndexOf("claymore", StringComparison.OrdinalIgnoreCase) >= 0 || name.StartsWith("THSwordGold", StringComparison.OrdinalIgnoreCase) || name.Equals("THSwordWood", StringComparison.OrdinalIgnoreCase) || name.StartsWith("THSwordSlayer", StringComparison.OrdinalIgnoreCase); } } internal static class QuadSlashVfx { private static Material _trailMat; private static bool _searched; private static readonly FieldInfo _trailMatField = AccessTools.Field(typeof(MeleeWeaponTrail), "m_trailMaterial") ?? AccessTools.Field(typeof(MeleeWeaponTrail), "m_material") ?? AccessTools.Field(typeof(MeleeWeaponTrail), "_material"); private static readonly FieldInfo _rightItemField = AccessTools.Field(typeof(VisEquipment), "m_rightItemInstance"); internal static Material GetDvergrMat() { if (_searched) { return _trailMat; } _searched = true; ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.GetPrefab("BattleaxeDvergr_TW") : null); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"[QS-VFX] BattleaxeDvergr_TW 프리팹 없음"); return null; } MeleeWeaponTrail[] componentsInChildren = val.GetComponentsInChildren<MeleeWeaponTrail>(true); foreach (MeleeWeaponTrail val2 in componentsInChildren) { if (_trailMatField != null) { object? value = _trailMatField.GetValue(val2); Material val3 = (Material)((value is Material) ? value : null); if ((Object)(object)val3 != (Object)null) { _trailMat = val3; return _trailMat; } } Renderer val4 = ((Component)val2).GetComponent<Renderer>() ?? ((Component)val2).GetComponentInChildren<Renderer>(true); if ((Object)(object)((val4 != null) ? val4.sharedMaterial : null) != (Object)null) { _trailMat = val4.sharedMaterial; return _trailMat; } } Plugin.Log.LogWarning((object)"[QS-VFX] Dvergr trail 머티리얼 접근 실패 — VFX 생략"); return null; } internal static void Apply(Humanoid humanoid, out Material[] saved, out Renderer[] renderers) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) saved = null; renderers = null; Material dvergrMat = GetDvergrMat(); if ((Object)(object)dvergrMat == (Object)null) { return; } VisEquipment component = ((Component)humanoid).GetComponent<VisEquipment>(); if ((Object)(object)component == (Object)null) { return; } object? obj = _rightItemField?.GetValue(component); GameObject val = (GameObject)((obj is GameObject) ? obj : null); if ((Object)(object)val == (Object)null) { return; } MeleeWeaponTrail[] componentsInChildren = val.GetComponentsInChildren<MeleeWeaponTrail>(true); if (componentsInChildren.Length == 0) { Plugin.Log.LogWarning((object)"[QS-VFX] 무기 모델에 MeleeWeaponTrail 없음"); return; } List<Material> list = new List<Material>(); List<Renderer> list2 = new List<Renderer>(); MeleeWeaponTrail[] array = componentsInChildren; foreach (MeleeWeaponTrail val2 in array) { if (_trailMatField != null) { object? value = _trailMatField.GetValue(val2); Material val3 = (Material)((value is Material) ? value : null); if ((Object)(object)val3 != (Object)null) { _trailMatField.SetValue(val2, dvergrMat); list.Add(val3); list2.Add(null); continue; } } Renderer component2 = ((Component)val2).GetComponent<Renderer>(); if (!((Object)(object)component2 == (Object)null)) { list.Add(component2.sharedMaterial); list2.Add(component2); component2.sharedMaterial = dvergrMat; } } saved = list.ToArray(); renderers = list2.ToArray(); } internal static void Restore(Material[] saved, Renderer[] renderers) { if (saved == null || renderers == null) { return; } int num = Math.Min(saved.Length, renderers.Length); for (int i = 0; i < num; i++) { if ((Object)(object)renderers[i] != (Object)null) { renderers[i].sharedMaterial = saved[i]; } else if (!((Object)(object)saved[i] != (Object)null)) { } } } } internal static class QuadSlashSystem { internal static bool TryInterceptSA(Humanoid humanoid) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.QsEnable.Value) { return false; } ItemData currentWeapon = humanoid.GetCurrentWeapon(); if (!QuadSlashFilter.Matches(currentWeapon)) { return false; } Character val = (Character)humanoid; if (!val.IsOwner()) { return false; } Player val2 = (Player)(object)((humanoid is Player) ? humanoid : null); if (val2 == null) { return false; } if ((int)Plugin.SpecialKey.Value != 0 && !SpecialInput.Active) { return false; } if (Plugin.QsMinSkillLevel.Value > 0f && ((Character)val2).GetSkillLevel((SkillType)1) < Plugin.QsMinSkillLevel.Value) { return false; } if (QuadSlashCooldown.IsOnCooldown(val) || SkillLimitSystem.ShouldBlock(val, "QuadSlash")) { return false; } Attack val3 = currentWeapon.m_shared?.m_secondaryAttack; float num = val3?.m_attackStamina ?? 0f; if (num > 0f && !val.HaveStamina(num)) { return false; } float num2 = val3?.m_attackEitr ?? 0f; if (num2 > 0f && !val.HaveEitr(num2)) { return false; } SharedData shared = currentWeapon.m_shared; Sprite icon = ((shared != null && shared.m_icons?.Length > 0) ? currentWeapon.m_shared.m_icons[0] : null); if (!QuadSlashCooldown.TryConsume(val, Plugin.QsCooldown.Value, icon)) { return false; } SaVfx.PlayAdrenaline1(((Component)val2).transform.position); QuadSlashController.Begin(humanoid, currentWeapon, ComputeAllowedHits(val2, currentWeapon)); return true; } private static int ComputeAllowedHits(Player player, ItemData weapon) { float level = SkillLevelResolver.GetLevel(player, weapon, (SkillType)1); if (level >= Plugin.QsHitLevel4.Value) { return 4; } if (level >= Plugin.QsHitLevel3.Value) { return 3; } if (level >= Plugin.QsHitLevel2.Value) { return 2; } return 1; } internal static void ExecuteIfQueued(Humanoid humanoid) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) QuadSlashController component = ((Component)humanoid).GetComponent<QuadSlashController>(); if ((Object)(object)component != (Object)null && component.IsActive) { component.OnAttackTriggered(); } } } internal sealed class QuadSlashController : MonoBehaviour { private static readonly FieldInfo _fChainLevels = AccessTools.Field(typeof(Attack), "m_attackChainLevels"); private static readonly FieldInfo _fCurrentLevel = AccessTools.Field(typeof(Attack), "m_currentAttackCainLevel"); private static readonly FieldInfo _fAnimBase = AccessTools.Field(typeof(Attack), "m_attackAnimation"); private static readonly FieldInfo _fZsyncAnimator = AccessTools.Field(typeof(ZSyncAnimation), "m_animator"); private static readonly FieldInfo _fAnimChain = AccessTools.Field(typeof(CharacterAnimEvent), "m_chain"); private Humanoid _humanoid; private ItemData _weapon; private Animator _animator; private CharacterAnimEvent _animEvent; private float _savedAnimSpeed; private int _hitsLeft; private int _currentHit; internal bool IsFiringNext; private Material[] _savedTrailMats; private Renderer[] _trailRenderers; private static string _cachedBattleaxeTrigger; private static bool _battleaxeTriggerSearched; internal bool IsActive => _hitsLeft > 0; internal int CurrentHit => _currentHit; internal static QuadSlashController Begin(Humanoid humanoid, ItemData weapon, int maxHits) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) GameObject gameObject = ((Component)humanoid).gameObject; QuadSlashController component = gameObject.GetComponent<QuadSlashController>(); if ((Object)(object)component != (Object)null) { ((MonoBehaviour)component).StopAllCoroutines(); component.ForceCleanup(); } QuadSlashController quadSlashController = component ?? gameObject.AddComponent<QuadSlashController>(); quadSlashController.Setup(humanoid, weapon, maxHits); return quadSlashController; } private void Setup(Humanoid humanoid, ItemData weapon, int maxHits) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) _humanoid = humanoid; _weapon = weapon; _hitsLeft = Mathf.Clamp(maxHits, 1, 4); _currentHit = 0; ZSyncAnimation componentInChildren = ((Component)humanoid).GetComponentInChildren<ZSyncAnimation>(); _animator = (Animator)((_fZsyncAnimator != null && (Object)(object)componentInChildren != (Object)null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)((Component)humanoid).GetComponentInChildren<Animator>())); _animEvent = ((Component)humanoid).GetComponentInChildren<CharacterAnimEvent>(); if ((Object)(object)_animator != (Object)null) { _savedAnimSpeed = _animator.speed; _animator.speed = GetSpeed(0); } QuadSlashVfx.Apply(humanoid, out _savedTrailMats, out _trailRenderers); ((MonoBehaviour)this).StartCoroutine(FireFirstPA()); } private float GetSpeed(int hit) { if (1 == 0) { } float result = hit switch { 0 => Plugin.QsAnimSpeed1.Value, 1 => Plugin.QsAnimSpeed2.Value, 2 => Plugin.QsAnimSpeed3.Value, _ => Plugin.QsAnimSpeed4.Value, }; if (1 == 0) { } return result; } private IEnumerator FireFirstPA() { yield return null; if ((Object)(object)_humanoid != (Object)null && _hitsLeft > 0) { ((Character)_humanoid).StartAttack((Character)null, false); } } internal void OnAttackTriggered() { if (_hitsLeft <= 0) { return; } _hitsLeft--; _currentHit++; if (_hitsLeft > 0) { float speed = GetSpeed(_currentHit); if ((Object)(object)_animator != (Object)null) { _animator.speed = speed; } ((MonoBehaviour)this).StartCoroutine(FireNextPA()); } else { Finish(); } } private IEnumerator FireNextPA() { Character ch = (Character)_humanoid; float timeout = Time.time + 2f; while ((Object)(object)ch != (Object)null && !ch.IsDead() && Time.time < timeout) { if (!ch.InAttack()) { if ((Object)(object)_humanoid != (Object)null && _hitsLeft > 0) { ch.StartAttack((Character)null, false); } break; } if ((Object)(object)_animEvent != (Object)null && _fAnimChain != null && (bool)_fAnimChain.GetValue(_animEvent) && (Object)(object)_humanoid != (Object)null && _hitsLeft > 0) { IsFiringNext = true; ch.StartAttack((Character)null, false); IsFiringNext = false; break; } yield return null; } } internal void InjectAnimOverride(Attack attack, ref float timeSinceLastAttack) { timeSinceLastAttack = 0f; } internal void OverrideAnimTrigger(Attack attack) { if ((Object)(object)_animator == (Object)null) { return; } string text = ((_fAnimBase != null) ? ((string)_fAnimBase.GetValue(attack)) : attack.m_attackAnimation); int num = ((_fChainLevels != null) ? ((int)_fChainLevels.GetValue(attack)) : 0); int num2 = ((_fCurrentLevel != null) ? ((int)_fCurrentLevel.GetValue(attack)) : 0); if (string.IsNullOrEmpty(text)) { return; } string text2 = ((num > 1) ? (text + num2) : text); string text3; if (_currentHit == 3) { text3 = GetBattleaxeLastTrigger() ?? (text + ((num > 1) ? (num - 1).ToString() : "")); } else { if (num <= 1) { Plugin.Log.LogWarning((object)$"[QS-Anim] chainLevels={num} ≤ 1, 애니메이션 순서 제어 불가 (베기 {_currentHit + 1})"); return; } int currentHit = _currentHit; if (1 == 0) { } int num3 = currentHit switch { 0 => Mathf.Min(1, num - 1), 1 => 0, 2 => Mathf.Min(1, num - 1), _ => num - 1, }; if (1 == 0) { } int num4 = num3; text3 = text + num4; } if (!(text2 == text3)) { _animator.ResetTrigger(text2); _animator.SetTrigger(text3); } } private static string GetBattleaxeLastTrigger() { if (_battleaxeTriggerSearched) { return _cachedBattleaxeTrigger; } ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.GetPrefab("BattleaxeDvergr_TW") : null); if ((Object)(object)val == (Object)null) { return null; } _battleaxeTriggerSearched = true; Attack val2 = ((val != null) ? val.GetComponent<ItemDrop>() : null)?.m_itemData?.m_shared?.m_attack; if (val2 == null || string.IsNullOrEmpty(val2.m_attackAnimation)) { Plugin.Log.LogWarning((object)"[QS-Anim] BattleaxeDvergr_TW m_attack 미발견 — 배틀액스 AA4 스킵"); return null; } int num = ((_fChainLevels != null) ? ((int)_fChainLevels.GetValue(val2)) : 0); string text = ((_fAnimBase != null) ? ((string)_fAnimBase.GetValue(val2)) : val2.m_attackAnimation); _cachedBattleaxeTrigger = ((num > 1) ? (text + (num - 1)) : text); return _cachedBattleaxeTrigger; } internal void RestoreAnimOverride() { } private void Update() { if (IsActive && !((Object)(object)_animator == (Object)null)) { _animator.speed = GetSpeed(_currentHit); } } private void Finish() { ForceCleanup(); Object.Destroy((Object)(object)this); } private void OnDestroy() { ForceCleanup(); } internal void ForceCleanup() { IsFiringNext = false; RestoreAnimSpeed(); RestoreAnimOverride(); QuadSlashVfx.Restore(_savedTrailMats, _trailRenderers); _savedTrailMats = null; _trailRenderers = null; } internal void RestoreAnimSpeed() { if ((Object)(object)_animator != (Object)null && _savedAnimSpeed > 0f) { _animator.speed = _savedAnimSpeed; } } internal float GetCurrentSpeed() { return GetSpeed(_currentHit); } } internal static class QuadSlash_CharAnimHelper { internal static readonly FieldInfo FAnimator = AccessTools.Field(typeof(CharacterAnimEvent), "m_animator"); internal static void RestoreSpeed(CharacterAnimEvent instance) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)((Component)instance).GetComponentInParent<Character>() != (Object)(Character)localPlayer) { return; } QuadSlashController component = ((Component)localPlayer).GetComponent<QuadSlashController>(); if (!((Object)(object)component == (Object)null) && component.IsActive) { object? obj = FAnimator?.GetValue(instance); Animator val = (Animator)((obj is Animator) ? obj : null); if ((Object)(object)val != (Object)null) { val.speed = component.GetCurrentSpeed(); } } } } [HarmonyPatch(typeof(CharacterAnimEvent), "CustomFixedUpdate")] internal static class QuadSlash_Patch_CharAnimFixedUpdate { private static void Postfix(CharacterAnimEvent __instance) { QuadSlash_CharAnimHelper.RestoreSpeed(__instance); } } [HarmonyPatch(typeof(CharacterAnimEvent), "Speed")] internal static class QuadSlash_Patch_CharAnimSpeed { private static void Postfix(CharacterAnimEvent __instance) { QuadSlash_CharAnimHelper.RestoreSpeed(__instance); } } [HarmonyPatch(typeof(Player), "HaveQueuedChain")] internal static class QuadSlash_Patch_HaveQueuedChain { private static void Postfix(Player __instance, ref bool __result) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (!__result) { QuadSlashController component = ((Component)__instance).GetComponent<QuadSlashController>(); if ((Object)(object)component != (Object)null && component.IsActive && component.IsFiringNext) { __result = true; } } } } [HarmonyPatch(typeof(Character), "Damage")] internal static class QuadSlash_Patch_Damage { private static void Prefix(Character __instance, ref HitData hit) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null || hit.m_attacker != ((Character)Player.m_localPlayer).GetZDOID()) { return; } QuadSlashController component = ((Component)Player.m_localPlayer).GetComponent<QuadSlashController>(); if (!((Object)(object)component == (Object)null) && component.IsActive) { int currentHit = component.CurrentHit; if (1 == 0) { } float num = currentHit switch { 0 => Plugin.QsDamage1.Value, 1 => Plugin.QsDamage2.Value, 2 => Plugin.QsDamage3.Value, _ => Plugin.QsDamage4.Value, }; if (1 == 0) { } float num2 = num; if (!Mathf.Approximately(num2, 1f)) { ((DamageTypes)(ref hit.m_damage)).Modify(num2); } } } } internal static class ConcussionBlowCooldown { private sealed class State { public double ReadyAt; public float Duration; public Sprite Icon; } private static readonly ConditionalWeakTable<Character, State> _states = new ConditionalWeakTable<Character, State>(); internal static bool IsOnCooldown(Character c) { if (!_states.TryGetValue(c, out var value)) { return false; } double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble); return num < value.ReadyAt; } internal static bool TryConsume(Character c, float cooldown, Sprite icon = null) { if (cooldown <= 0f) { return true; } State value = _states.GetValue(c, (Character _) => new State()); double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble); if (num < value.ReadyAt) { return false; } value.ReadyAt = num + (double)cooldown; value.Duration = cooldown; value.Icon = icon; return true; } internal static bool CollectEntry(Character c, out CooldownEntry entry) { entry = default(CooldownEntry); if (!_states.TryGetValue(c, out var value)) { return false; } double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble); float num2 = (float)Math.Max(0.0, value.ReadyAt - num); if (num2 <= 0f) { return false; } entry = new CooldownEntry { Icon = value.Icon, Remaining = num2, Duration = value.Duration }; return true; } } internal static class ConcussionBlowFilter { internal static bool Matches(ItemData weapon) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 if (weapon?.m_shared == null) { return false; } SharedData shared = weapon.m_shared; return (int)shared.m_skillType == 3 && (int)shared.m_itemType == 3; } } internal static class ConcussionBlowSystem { private static bool _pending; private static ZDOID _pendingAttacker; private static bool _appliedAny; internal static void OnSecondaryStarted(Humanoid humanoid, Attack attack) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.CbEnable.Value) { return; } ItemData currentWeapon = humanoid.GetCurrentWeapon(); if (!ConcussionBlowFilter.Matches(currentWeapon)) { return; } Player val = (Player)(object)((humanoid is Player) ? humanoid : null); if (!((Object)(object)val != (Object)null) || !(Plugin.CbMinSkillLevel.Value > 0f) || !(((Character)val).GetSkillLevel((SkillType)3) < Plugin.CbMinSkillLevel.Value)) { Character val2 = (Character)humanoid; if (!ConcussionBlowCooldown.IsOnCooldown(val2) && !SkillLimitSystem.ShouldBlock(val2, "ConcussionBlow")) { _pending = true; _pendingAttacker = val2.GetZDOID(); _appliedAny = false; } } } internal static void OnSwingProcessed() { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) if (_pending && _appliedAny) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { Character c = (Character)localPlayer; ItemData currentWeapon = ((Humanoid)localPlayer).GetCurrentWeapon(); Sprite icon = ((currentWeapon != null && currentWeapon.m_shared?.m_icons?.Length > 0) ? currentWeapon.m_shared.m_icons[0] : null); ConcussionBlowCooldown.TryConsume(c, Plugin.CbCooldown.Value, icon); SaVfx.PlayAdrenaline1(((Component)localPlayer).transform.position); } } _pending = false; _pendingAttacker = ZDOID.None; _appliedAny = false; } internal static void CancelPending() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) _pending = false; _pendingAttacker = ZDOID.None; _appliedAny = false; } internal static void TryApply(Character target, ref HitData hit) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.CbEnable.Value || !_pending || hit.m_attacker != _pendingAttacker || (Object)(object)target == (Object)null || target.IsDead() || ((DamageTypes)(ref hit.m_damage)).GetTotalDamage() <= 0f) { return; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && (object)target != localPlayer && CreatureClassification.Classify(target) != CreatureTier.Boss) { ItemData currentWeapon = ((Humanoid)localPlayer).GetCurrentWeapon(); float requiredLevel = CreatureClassification.GetRequiredLevel(target); float level = SkillLevelResolver.GetLevel(localPlayer, currentWeapon, (SkillType)3); if (!(level < requiredLevel)) { target.Stagger(hit.m_dir); ConcussionBlowStun.Apply(target); _appliedAny = true; } } } } internal static class ConcussionBlowStun { private sealed class State { public double StunnedUntil; public bool SpeedAdjusted; public float OriginalSpeed = 1f; public bool NeedsRecalc; } private static readonly ConditionalWeakTable<Character, State> _states = new ConditionalWeakTable<Character, State>(); private static readonly List<WeakReference> _tracked = new List<WeakReference>(); private static readonly FieldInfo f_animator = AccessTools.Field(typeof(Character), "m_animator"); private static Animator GetAnimator(Character c) { object? value = f_animator.GetValue(c); return (Animator)((value is Animator) ? value : null); } internal static void Apply(Character target) { if ((Object)(object)target == (Object)null || CreatureClassification.Classify(target) == CreatureTier.Boss) { return; } float value = Plugin.CbStunDuration.Value; if (!(value <= 0f)) { double num = Now(); State value2; bool flag = !_states.TryGetValue(target, out value2); State value3 = _states.GetValue(target, (Character _) => new State()); value3.StunnedUntil = num + (double)value; value3.NeedsRecalc = true; if (flag) { _tracked.Add(new WeakReference(target)); } } } private static bool TryFindStaggerState(Animator animator, out int layer, out AnimatorStateInfo info, out bool isNext) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) int layerCount = animator.layerCount; for (int i = 0; i < layerCount; i++) { AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(i); if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsTag("stagger")) { layer = i; info = currentAnimatorStateInfo; isNext = false; return true; } if (animator.IsInTransition(i)) { AnimatorStateInfo nextAnimatorStateInfo = animator.GetNextAnimatorStateInfo(i); if (((AnimatorStateInfo)(ref nextAnimatorStateInfo)).IsTag("stagger")) { layer = i; info = nextAnimatorStateInfo; isNext = true; return true; } } } layer = -1; info = default(AnimatorStateInfo); isNext = false; return false; } internal static bool IsStunned(Character target) { if ((Object)(object)target == (Object)null || target.IsDead()) { return false; } if (!_states.TryGetValue(target, out var value)) { return false; } return Now() < value.StunnedUntil; } private static double Now() { return ((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble; } internal static void Tick() { for (int num = _tracked.Count - 1; num >= 0; num--) { object? target = _tracked[num].Target; Character val = (Character)((target is Character) ? target : null); State value; if ((Object)(object)val == (Object)null) { _tracked.RemoveAt(num); } else if (!_states.TryGetValue(val, out value)) { _tracked.RemoveAt(num); } else { double num2 = Now(); bool flag = num2 < value.StunnedUntil; bool flag2 = val.IsDead(); if (!flag || flag2) { if (value.SpeedAdjusted) { Animator animator = GetAnimator(val); if ((Object)(object)animator != (Object)null) { animator.speed = value.OriginalSpeed; } } _states.Remove(val); _tracked.RemoveAt(num); } else { Animator animator2 = GetAnimator(val); if (!((Object)(object)animator2 == (Object)null)) { if (TryFindStaggerState(animator2, out var _, out var info, out var _)) { if (value.NeedsRecalc) { float length = ((AnimatorStateInfo)(ref info)).length; float num3 = ((AnimatorStateInfo)(ref info)).normalizedTime % 1f; if (num3 < 0f) { num3 = 0f; } float num4 = Mathf.Max(0f, length * (1f - num3)); float num5 = Mathf.Max(0.01f, (float)(value.StunnedUntil - num2)); if (!value.SpeedAdjusted) { value.OriginalSpeed = animator2.speed; value.SpeedAdjusted = true; } float speed = Mathf.Clamp(num4 / num5, 0.05f, 1f); animator2.speed = speed; value.NeedsRecalc = false; } } else if (value.SpeedAdjusted) { animator2.speed = value.OriginalSpeed; value.SpeedAdjusted = false; } } } } } } } public static class ConcussionBlowApi { public static bool IsStunned(Character target) { return ConcussionBlowStun.IsStunned(target); } } [HarmonyPatch(typeof(Character), "CanMove")] internal static class Patch_CharacterCanMove_ConcussionStun { private static void Postfix(Character __instance, ref bool __result) { if (__result && ConcussionBlowStun.IsStunned(__instance)) { __result = false; } } } [HarmonyPatch(typeof(Character), "StartAttack")] internal static class Patch_CharacterStartAttack_ConcussionStun { private static bool Prefix(Character __instance, ref bool __result) { if (ConcussionBlowStun.IsStunned(__instance)) { __result = false; return false; } return true; } } internal enum CreatureTier { Small, Large, Boss } internal static class CreatureClassification { private static readonly HashSet<string> VanillaCreaturePrefabs = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Abomination", "Asksvin", "Asksvin_hatchling", "Bat", "Bjorn", "Blob", "BlobElite", "BlobFrost", "BlobLava", "BlobTar", "Boar", "Boar_piggy", "BogWitchKvastur", "BogWitch_Camp", "Bonemass", "BonemawSerpent", "Charred_Archer", "Charred_Archer_Fader", "Charred_Mage", "Charred_Melee", "Charred_Melee_Dyrnwyn", "Charred_Melee_Fader", "Charred_Twitcher", "Charred_Twitcher_Summoned", "Chicken", "Deathsquito", "Deer", "Dragon", "Draugr", "Draugr_Elite", "Draugr_Ranged", "Dverger", "DvergerAshlands", "DvergerMage", "DvergerMageFire", "DvergerMageIce", "DvergerMageSupport", "Eikthyr", "Fader", "FallenValkyrie", "Fenring", "Fenring_Cultist", "Fenring_Cultist_Hildir", "Fenring_Cultist_Hildir_nochest", "Ghost", "Gjall", "Goblin", "GoblinArcher", "GoblinBrute", "GoblinBruteBros", "GoblinBruteBros_nochest", "GoblinBrute_Hildir", "GoblinKing", "GoblinShaman", "GoblinShaman_Hildir", "GoblinShaman_Hildir_nochest", "Goblin_Gem", "Greydwarf", "Greydwarf_Elite", "Greydwarf_Shaman", "Greyling", "Hare", "Hatchling", "Hen", "Hive", "Leech", "Leech_cave", "Lox", "Lox_Calf", "Morgen", "Morgen_NonSleeping", "Neck", "Seeker", "SeekerBrood", "SeekerBrute", "SeekerQueen", "Serpent", "Skeleton", "Skeleton_Friendly", "Skeleton_Hildir", "Skeleton_Hildir_nochest", "Skeleton_NoArcher", "Skeleton_Poison", "StoneGolem", "Surtling", "TentaRoot", "TheHive", "Tick", "Troll", "Troll_Summoned", "Ulv", "Unbjorn", "Volture", "Wolf", "Wolf_cub", "Wraith", "gd_king" }; private static bool _exported; internal static string GetPrefabName(Character c) { GameObject val = (((Object)(object)c != (Object)null) ? ((Component)c).gameObject : null); return ((Object)(object)val != (Object)null) ? StripClone(((Object)val).name) : string.Empty; } private static string StripClone(string name) { return name.EndsWith("(Clone)", StringComparison.Ordinal) ? name.Substring(0, name.Length - "(Clone)".Length) : name; } private static HashSet<string> ParseCsv(string csv) { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrWhiteSpace(csv)) { return hashSet; } string[] array = csv.Split(new char[1] { ',' }); foreach (string text in array) { string text2 = text.Trim(); if (text2.Length > 0) { hashSet.Add(text2); } } return hashSet; } internal static CreatureTier Classify(Character c) { if ((Object)(object)c == (Object)null) { return CreatureTier.Small; } if (c.IsBoss()) { return CreatureTier.Boss; } string prefabName = GetPrefabName(c); if (prefabName.Length > 0) { if (ParseCsv(Plugin.CbExtraBosses.Value).Contains(prefabName)) { return CreatureTier.Boss; } if (ParseCsv(Plugin.CbLargeMonsters.Value).Contains(prefabName)) { return CreatureTier.Large; } } return CreatureTier.Small; } internal static float GetRequiredLevel(Character c) { CreatureTier creatureTier = Classify(c); CreatureTier creatureTier2 = creatureTier; if (creatureTier2 == CreatureTier.Large) { return Plugin.CbLargeLevel.Value; } return Plugin.CbSmallLevel.Value; } internal static void ExportIfNeeded() { //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) if (_exported || !Plugin.CbExportCreatureList.Value || (Object)(object)ZNetScene.instance == (Object)null) { return; } _exported = true; try { string text = Path.Combine(Paths.ConfigPath, "SpecialAttack_CreatureList.txt"); List<string> list = new List<string> { "PrefabName\tDisplayName\tIsBoss\tMaxHealth\tMass\tHeight\tVanilla\tTier" }; foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { if ((Object)(object)prefab == (Object)null) { continue; } Character component = prefab.GetComponent<Character>(); if (!((Object)(object)component == (Object)null)) { string text2 = StripClone(((Object)prefab).name); string name = component.m_name; bool boss = component.m_boss; float health = component.m_health; Rigidbody component2 = prefab.GetComponent<Rigidbody>(); float num = (((Object)(object)component2 != (Object)null) ? component2.mass : 0f); Collider componentInChildren = prefab.GetComponentInChildren<Collider>(); float num2; if (!((Object)(object)componentInChildren != (Object)null)) { num2 = 0f; } else { Bounds bounds = componentInChildren.bounds; num2 = ((Bounds)(ref bounds)).size.y; } float num3 = num2; bool flag = VanillaCreaturePrefabs.Contains(text2); CreatureTier creatureTier = Classify(component); list.Add($"{text2}\t{name}\t{boss}\t{health:F0}\t{num:F1}\t{num3:F2}\t" + string.Format("{0}\t{1}", flag ? "바닐라" : "모드", creatureTier)); } } File.WriteAllLines(text, list); Plugin.Log.LogInfo((object)("[ConcussionBlow] 크리처 목록 저장: " + text)); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[ConcussionBlow] 크리처 목록 저장 실패: " + ex.Message)); } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class Patch_ZNetSceneAwake_CreatureExport { private static void Postfix() { CreatureClassification.ExportIfNeeded(); } } internal static class CrescentWaveTuning { internal const float ColorR = 0.45f; internal const float ColorG = 0.8f; internal const float ColorB = 1f; internal const float Range = 30f; internal const float Speed = 30f; internal const float SpawnHeight = 1.3f; internal const float SpawnForward = 0.5f; internal const float TiltAngle = 40f; internal const float VisualScale = 2f; internal const float HitWidth = 4f; internal const float HitSlashScale = 0.1f; internal const float MaxPitch = 60f; } internal static class CrescentWaveCooldown { private sealed class State { public double ReadyAt; public float Duration; public Sprite Icon; } private static readonly ConditionalWeakTable<Character, State> _states = new ConditionalWeakTable<Character, State>(); internal static bool IsOnCooldown(Character c) { if (!_states.TryGetValue(c, out var value)) { return false; } double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble); return num < value.ReadyAt; } internal static bool TryConsume(Character c, float cooldown, Sprite icon = null) { if (cooldown <= 0f) { return true; } State value = _states.GetValue(c, (Character _) => new State()); double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble); if (num < value.ReadyAt) { return false; } value.ReadyAt = num + (double)cooldown; value.Duration = cooldown; value.Icon = icon; return true; } internal static bool CollectEntry(Character c, out CooldownEntry entry) { entry = default(CooldownEntry); if (!_states.TryGetValue(c, out var value)) { return false; } double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : Time.timeAsDouble); float num2 = (float)Math.Max(0.0, value.ReadyAt - num); if (num2 <= 0f) { return false; } entry = new CooldownEntry { Icon = value.Icon, Remaining = num2, Duration = value.Duration }; return true; } } internal static class CrescentWaveFilter { internal static bool Matches(ItemData weapon) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Invalid comparison between Unknown and I4 if (weapon?.m_shared == null) { return false; } SharedData shared = weapon.m_shared; if ((int)shared.m_skillType != 1) { return false; } if ((int)shared.m_itemType != 14) { return false; } string text = (((Object)(object)weapon.m_dropPrefab != (Object)null) ? ((Object)weapon.m_dropPrefab).name : ""); return text.IndexOf("bastard", StringComparison.OrdinalIgnoreCase) >= 0; } } internal static class CrescentWaveSystem { private static bool _pending; private static Player _pendingPlayer; private static ItemData _pendingWeapon; internal static void QueueTrigger(Humanoid humanoid) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown if (!Plugin.CwEnable.Value) { return; } ItemData currentWeapon = humanoid.GetCurrentWeapon(); if (!CrescentWaveFilter.Matches(currentWeapon)) { return; } Character val = (Character)humanoid; if (val.IsOwner()) { Player val2 = (Player)(object)((humanoid is Player) ? humanoid : null); if (!((Object)(object)val2 == (Object)null) && (!(Plugin.CwMinSkillLevel.Value > 0f) || !(((Character)val2).GetSkillLevel((SkillType)1) < Plugin.CwMinSkillLevel.Value)) && !CrescentWaveCooldown.IsOnCooldown(val) && !SkillLimitSystem.ShouldBlock(val, "CrescentWave")) { _pending = true; _pendingPlayer = val2; _pendingWeapon = currentWeapon; } } } internal static void ExecuteIfQueued(Humanoid humanoid) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown if (!_pending || (object)humanoid != _pendingPlayer) { return; } _pending = false; Material trailMaterialOrWarn = CrescentWaveVisual.GetTrailMaterialOrWarn(_pendingPlayer, _pendingWeapon); if (!((Object)(object)trailMaterialOrWarn == (Object)null)) { Character c = (Character)_pendingPlayer; SharedData shared = _pendingWeapon.m_shared; Sprite icon = ((shared != null && shared.m_icons?.Length > 0) ? _pendingWeapon.m_shared.m_icons[0] : null); if (CrescentWaveCooldown.TryConsume(c, Plugin.CwCooldown.Value, icon)) { Fire(_pendingPlayer, _pendingWeapon, trailMaterialOrWarn); } } } private static void Fire(Player player, ItemData weapon, Material material) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) Character val = (Character)player; Vector3 forward = ((Component)val).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f) { forward = Vector3.forward; } ((Vector3)(ref forward)).Normalize(); Vector3 origin = ((Component)val).transform.position + Vector3.up * 1.3f + forward * 0.5f; Vector3 direction = CrescentWaveAim.ComputeAimDirection(origin, forward); float randomSkillFactor = val.GetRandomSkillFactor((SkillType)1); DamageTypes damage = weapon.GetDamage(); ((DamageTypes)(ref damage)).Modify(randomSkillFactor); float slash = ((DamageTypes)(ref damage)).GetTotalDamage() * Mathf.Max(0f, Plugin.CwDamageMult.Value); damage.m_damage = 0f; damage.m_blunt = 0f; damage.m_pierce = 0f; damage.m_chop = 0f; damage.m_pickaxe = 0f; damage.m_fire = 0f; damage.m_frost = 0f; damage.m_lightning = 0f; damage.m_poison = 0f; damage.m_spirit = 0f; damage.m_slash = slash; float pushForce = weapon.m_shared?.m_attackForce ?? 0f; SpawnProjectile(val, origin, direction, damage, pushForce, weapon, material); float level = SkillLevelResolver.GetLevel(player, weapon, (SkillType)1); int num = ResolveShotCountForLevel(level); if (num > 1) { GameObject gameObject = ((Component)player).gameObject; CrescentWaveController component = gameObject.GetComponent<CrescentWaveController>(); if ((Object)(object)component != (Object)null) { component.CancelRemaining("이전체인재시작"); } CrescentWaveController crescentWaveController = gameObject.AddComponent<CrescentWaveController>(); crescentWaveController.Begin(player, origin, direction, damage, pushForce, weapon, material, level, num, Mathf.Max(0f, Plugin.CwChainInterval.Value)); } } private static int ResolveShotCountForLevel(float level) { int result = 1; if (level >= Plugin.CwLv1.Value) { result = Plugin.CwCount1.Value; } if (level >= Plugin.CwLv2.Value) { result = Plugin.CwCount2.Value; } if (level >= Plugin.CwLv3.Value) { result = Plugin.CwCount3.Value; } if (level >= Plugin.CwLv4.Value) { result = Plugin.CwCount4.Value; } return result; } internal static void SpawnProjectile(Character ch, Vector3 origin, Vector3 direction, DamageTypes dmg, float pushForce, ItemData weapon, Material material) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("CrescentWave"); val.transform.position = origin; val.transform.rotation = Quaternion.LookRotation(direction); CrescentWaveProjectile crescentWaveProjectile = val.AddComponent<CrescentWaveProjectile>(); crescentWaveProjectile.Initialize(ch, dmg, direction, pushForce, weapon, material); CrescentWaveVisual.Attach(val, material); } } internal sealed class CrescentWaveController : MonoBehaviour { private static readonly MethodInfo _mIsTeleporting = AccessTools.Method(typeof(Character), "IsTeleporting", (Type[])null, (Type[])null); private static readonly Func<Character, bool> _isTeleporting = ((_mIsTeleporting != null) ? AccessTools.MethodDelegate<Func<Character, bool>>(_mIsTeleporting, (object)null, true) : null); private Player _player; private Vector3 _origin; private Vector3 _direction; private DamageTypes _damage; private float _pushForce; private ItemData _weapon; private Material _material; private float _level; private int _targetCount; private int _firedCount; private float _interval; private Vector3 _lastCheckPos; private Coroutine _routine; internal void Begin(Player player, Vector3 origin, Vector3 direction, DamageTypes damage, float pushForce, ItemData weapon, Material material, float level, int targetCount, float interval) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) _player = player; _origin = origin; _direction = direction; _damage = damage; _pushForce = pushForce; _weapon = weapon; _material = material; _level = level; _targetCount = targetCount; _firedCount = 1; _interval = interval; _lastCheckPos = ((Component)player).transform.position; _routine = ((MonoBehaviour)this).StartCoroutine(RunChain()); } private IEnumerator RunChain() { string stopReason = "완료"; while (_firedCount < _targetCount) { if (_interval > 0f) { yield return (object)new WaitForSeconds(_interval); } else { yield return null; } if (!CanContinue(ref stopReason)) { break; } CrescentWaveSystem.SpawnProjectile((Character)(object)_player, _origin, _direction, _damage, _pushForce, _weapon, _material); _firedCount++; } if ((Object)(object)this != (Object)null) { Object.Destroy((Object)(object)this); } } private bool CanContinue(ref string stopReason) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_player == (Object)null) { stopReason = "플레이어없음"; return false; } Character val = (Character)_player; if ((Object)(object)val == (Object)null || val.IsDead()) { stopReason = "사망"; return false; } if (val.IsStaggering()) { stopReason = "스태거"; return false; } if (!CrescentWaveFilter.Matches(((Humanoid)_player).GetCurrentWeapon())) { stopReason = "무기교체"; return false; } if (_isTeleporting != null && _isTeleporting(val)) { stopReason = "순간이동"; return false; } Vector3 position = ((Component)_player).transform.position; Vector3 val2 = position - _lastCheckPos; if (((Vector3)(ref val2)).sqrMagnitude > 9f) { stopReason = "순간이동(위치이상)"; return false; } _lastCheckPos = position; return true; } internal void CancelRemaining(string reason) { if (_routine != null) { ((MonoBehaviour)this).StopCoroutine(_routine); _routine = null; } if ((Object)(object)this != (Object)null) { Object.Destroy((Object)(object)this); } } private void OnDestroy() { if (_routine != null) { ((MonoBehaviour)this).StopCoroutine(_routine); } } } internal static class CrescentWaveAim { private static int _aimMask; private static int GetAimMask() { if (_aimMask == 0) { _aimMask = LayerMask.GetMask(new string[12] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "terrain", "character", "character_net", "character_ghost", "hitbox", "character_noenv", "vehicle" }); } return _aimMask; } internal static Vector3 ComputeAimDirection(Vector3 origin, Vector3 bodyForward) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) GameCamera instance = GameCamera.instance; if ((Object)(object)instance == (Object)null) { return bodyForward; } Vector3 position = ((Component)instance).transform.position; Vector3 forward = ((Component)instance).transform.forward; float num = Mathf.Max(1f, 30f); RaycastHit val2 = default(RaycastHit); Vector3 val = (Physics.Raycast(position, forward, ref val2, num, GetAimMask(), (QueryTriggerInteraction)1) ? ((RaycastHit)(ref val2)).point : (position + forward * num)); Vector3 val3 = val - origin; Vector3 dir = ((Vector3.Dot(val3, bodyForward) <= 0f || ((Vector3)(ref val3)).magnitude < 3f) ? forward : ((Vector3)(ref val3)).normalized); dir = ClampPitch(dir, 60f); return (((Vector3)(ref dir)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref dir)).normalized : bodyForward; } private static Vector3 ClampPitch(Vector3 dir, float maxPitchDegrees) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) Vector3 forward = default(Vector3); ((Vector3)(ref forward))..ctor(dir.x, 0f, dir.z); if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f) { forward = Vector3.forward; } ((Vector3)(ref forward)).Normalize(); float y = dir.y; Vector3 val = new Vector3(dir.x, 0f, dir.z); float num = Mathf.Atan2(y, ((Vector3)(ref val)).magnitude) * 57.29578f; float num2 = Mathf.Clamp(num, 0f - maxPitchDegrees, maxPitchDegrees); float num3 = num2 * ((float)Math.PI / 180f); return forward * Mathf.Cos(num3) + Vector3.up * Mathf.Sin(num3); } } internal sealed class CrescentWaveProjectile : MonoBehaviour { private static readonly Collider[] _hitBuf = (Collider[])(object)new Collider[32]; private static int _maskChars; private Character _attacker; private DamageTypes _damage; private Vector3 _direction; private float _pushForce; private float _traveled; private ItemData _weapon; private Material _material; private float _lastHitSoundTime = float.NegativeInfinity; private readonly HashSet<Character> _hitTargets = new HashSet<Character>(); private static int GetMaskChars() { if (_maskChars == 0) { _maskChars = LayerMask.GetMask(new string[5] { "character", "character_net", "character_ghost", "hitbox", "character_noenv" }); } return _maskChars; } internal void Initialize(Character attacker, DamageTypes damage, Vector3 direction, float pushForce, ItemData weapon, Material material) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) _attacker = attacker; _damage = damage; _direction = direction; _pushForce = pushForce; _weapon = weapon; _material = material; _traveled = 0f; } private void FixedUpdate() { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_attacker == (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } float num = Mathf.Max(0f, 30f); float num2 = Mathf.Max(0.01f, 30f); float num3 = Mathf.Min(num2 * Time.fixedDeltaTime, num - _traveled); if (num3 <= 0f) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Vector3 position = ((Component)this).transform.position; Vector3 val = position + _direction * num3; CheckHits(position, val, num3); ((Component)this).transform.position = val; _traveled += num3; if (_traveled >= num) { Object.Destroy((Object)(object)((Component)this).gameObject); } } private void CheckHits(Vector3 prevPos, Vector3 nextPos, float step) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) Vector3 val = (prevPos + nextPos) * 0.5f; Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(Mathf.Max(0.1f, 4f) * 0.5f, Mathf.Max(0.1f, Plugin.CwHitHeight.Value) * 0.5f, step * 0.5f + 0.1f); Quaternion val3 = Quaternion.LookRotation(_direction); int num = Physics.OverlapBoxNonAlloc(val, val2, _hitBuf, val3, GetMaskChars(), (QueryTriggerInteraction)0); for (int i = 0; i < num; i++) { Collider val4 = _hitBuf[i]; if (!((Object)(object)val4 == (Object)null)) { Character componentInParent = ((Component)val4).GetComponentInParent<Character>(); if (!((Object)(object)componentInParent == (Object)null) && componentInParent != _attacker && !componentInParent.IsDead() && !componentInParent.IsPlayer() && BaseAI.IsEnemy(_attacker, componentInParent) && !componentInParent.InDodge() && !componentInParent.IsDebugFlying() && _hitTargets.Add(componentInParent)) { ApplyHit(componentInParent, val); } } } } private void ApplyHit(Character target, Vector3 origin) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) /