using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using CrestsEvolve.Core.Balance; using CrestsEvolve.Core.Events; using CrestsEvolve.Core.State; using CrestsEvolve.Core.Tools; using CrestsEvolve.Core.UI; using CrestsEvolve.Features; using CrestsEvolve.Features.StatusIcons; using CrestsEvolve.Features.Tools; using CrestsEvolve.Features.Tools.Blue; using CrestsEvolve.Features.Tools.Yellow; using CrestsEvolve.GameInterop; using CrestsEvolve.GameInterop.Patches; using CrestsEvolve.ToolsAscension.Bootstrap; using CrestsEvolve.ToolsAscension.Features.Tools; using GlobalEnums; using GlobalSettings; using HarmonyLib; using HutongGames.PlayMaker; using HutongGames.PlayMaker.Actions; using Microsoft.CodeAnalysis; using Silksong.FsmUtil; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("CrestsEvolve.Core.Tests")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("CrestsEvolve.ToolsAscension")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+757e75a2d4534028308600b7117b47c56eb48037")] [assembly: AssemblyProduct("CrestsEvolve.ToolsAscension")] [assembly: AssemblyTitle("CrestsEvolve.ToolsAscension")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } internal static class IsExternalInit { } } namespace CrestsEvolve.GameInterop { public sealed class CogflyAutoReleaseRunner : MonoBehaviour { private const float Interval = 1f; private float _timer; private void Update() { _timer += Time.deltaTime; if (!(_timer < 1f)) { _timer = 0f; CogflyAutoReleasePatch.Tick(); } } } public sealed class CogflySpawner { public const string PrefabName = "Clockwork Hatchling"; public const string ToolName = "Cogwork Flier"; public const string AltToolName = "Cogfly"; private readonly ManualLogSource _log; private GameObject? _prefab; private AssetBundle? _bundle; private FieldInfo? _toolSourceField; private bool _warnedResolve; private bool _warnedSpawn; private bool _warnedToolSource; private bool _warnedCount; private bool _bundleLoadFailed; private bool _loggedSpawn; public CogflySpawner(ManualLogSource log) { _log = log ?? throw new ArgumentNullException("log"); _toolSourceField = AccessTools.Field(typeof(ClockworkHatchling), "toolSource"); } public void OnSceneChanged() { if ((Object)(object)_bundle == (Object)null) { _prefab = null; } } public void Tick() { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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_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) HeroController instance = HeroController.instance; if ((Object)(object)instance == (Object)null) { return; } ToolItem val = ToolItemManager.GetToolByName("Cogwork Flier") ?? ToolItemManager.GetToolByName("Cogfly"); if ((Object)(object)val == (Object)null) { return; } int toolStorageAmount = ToolItemManager.GetToolStorageAmount(val); int num = CountActive(); if (!CogflyAutoReleaseRules.ShouldRelease(num, toolStorageAmount)) { return; } GameObject val2 = ResolvePrefab(val); if ((Object)(object)val2 == (Object)null) { if (!_warnedResolve) { _warnedResolve = true; _log.LogWarning((object)"[CogflySpawner] 'Clockwork Hatchling' prefab not resolved; auto-release disabled."); } return; } try { Vector3 val3 = ((Component)instance).transform.position + new Vector3(1.5f, 1f, 0f); GameObject val4 = ObjectPoolExtensions.Spawn(val2, val3, Quaternion.identity); if (!((Object)(object)val4 == (Object)null)) { val4.SetActive(true); ClockworkHatchling component = val4.GetComponent(); if ((Object)(object)component != (Object)null && _toolSourceField != null) { _toolSourceField.SetValue(component, val); } else if (!_warnedToolSource) { _warnedToolSource = true; _log.LogWarning((object)"[CogflySpawner] hatchling prefab missing ClockworkHatchling/toolSource; tool association skipped."); } if (!_loggedSpawn) { _loggedSpawn = true; _log.LogInfo((object)$"[CogflySpawner] spawned '{((Object)val4).name}' (active {num + 1}/{toolStorageAmount})."); } } } catch (Exception ex) { if (!_warnedSpawn) { _warnedSpawn = true; _log.LogWarning((object)("[CogflySpawner] spawn failed: " + ex.Message)); } } } private int CountActive() { try { return Object.FindObjectsByType((FindObjectsSortMode)0).Count((ClockworkHatchling h) => (Object)(object)h != (Object)null && (IsCogflyHatchling(h) || _toolSourceField == null)); } catch (Exception ex) { if (!_warnedCount) { _warnedCount = true; _log.LogWarning((object)("[CogflySpawner] hatchling count failed: " + ex.Message)); } return 0; } } private bool IsCogflyHatchling(ClockworkHatchling hatchling) { if (_toolSourceField == null) { return true; } try { object? value = _toolSourceField.GetValue(hatchling); ToolItem val = (ToolItem)((value is ToolItem) ? value : null); return (Object)(object)val != (Object)null && (string.Equals(val.name, "Cogwork Flier", StringComparison.Ordinal) || string.Equals(val.name, "Cogfly", StringComparison.Ordinal)); } catch { return true; } } private GameObject? ResolvePrefab(ToolItem tool) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_prefab != (Object)null) { return _prefab; } _prefab = tool.Usage.ThrowPrefab; if ((Object)(object)_prefab != (Object)null) { return _prefab; } _prefab = LoadViaAddressables(); if ((Object)(object)_prefab == (Object)null) { _prefab = LoadViaLoadedBundles(); } if ((Object)(object)_prefab == (Object)null) { _prefab = LoadViaBundleFile(); } return _prefab; } private GameObject? LoadViaAddressables() { try { Type type = (from a in AppDomain.CurrentDomain.GetAssemblies() select a.GetType("UnityEngine.AddressableAssets.Addressables", throwOnError: false)).FirstOrDefault((Type t) => t != null); if (type == null) { return null; } MethodInfo[] array = (from m in type.GetMethods(BindingFlags.Static | BindingFlags.Public) where m.Name == "LoadAssetAsync" && m.IsGenericMethodDefinition && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(string) select m).Take(2).ToArray(); if (array.Length != 1) { return null; } object obj = array[0].MakeGenericMethod(typeof(GameObject)).Invoke(null, new object[1] { "Clockwork Hatchling" }); if (obj == null) { return null; } object? obj2 = obj.GetType().GetMethod("WaitForCompletion", Type.EmptyTypes)?.Invoke(obj, null); return (GameObject?)((obj2 is GameObject) ? obj2 : null); } catch (Exception ex) { _log.LogWarning((object)("[CogflySpawner] Addressables load failed: " + ex.Message)); return null; } } private GameObject? LoadViaLoadedBundles() { try { foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles()) { if (!((Object)(object)allLoadedAssetBundle == (Object)null)) { GameObject val = allLoadedAssetBundle.LoadAsset("Clockwork Hatchling"); if ((Object)(object)val != (Object)null) { return val; } } } } catch (Exception ex) { _log.LogWarning((object)("[CogflySpawner] loaded-bundle search failed: " + ex.Message)); } return null; } private GameObject? LoadViaBundleFile() { if (_bundleLoadFailed) { return null; } try { string text = Path.Combine(Application.streamingAssetsPath, "aa", "StandaloneWindows64", "herodynamic_assets_all.bundle"); if (!File.Exists(text)) { return null; } if ((Object)(object)_bundle == (Object)null) { _bundle = AssetBundle.LoadFromFile(text); } AssetBundle? bundle = _bundle; return (bundle != null) ? bundle.LoadAsset("Clockwork Hatchling") : null; } catch (Exception ex) { _bundleLoadFailed = true; _log.LogWarning((object)("[CogflySpawner] bundle load failed: " + ex.Message)); return null; } } } public static class ReserveBindBridge { public static Func? IsEquipped { get; set; } = () => false; public static Func? TryRestore { get; set; } = () => false; public static Func? TryRepairTool { get; set; } } public sealed class RevengeCrystalSpawner { public const string PrefabName = "Revenge Crystal Hornet"; public const string PrefabPath = "Assets/Prefabs/Heroes/Tools/Revenge Crystal Hornet.prefab"; public const string SpawnQueueGroupPath = "Assets/Data Assets/Spawn Queue Groups/Revenge Crystal Hornet.asset"; private const int MaxSpawnPerCall = 3; private const int SpawnQueueGroupLimit = 3; private const float SecondsBetweenStatueSpawns = 0.1f; private readonly ManualLogSource _log; private GameObject? _prefab; private AssetBundle? _prefabBundle; private AssetBundle? _spawnQueueGroupBundle; private bool _groupLimitRaised; private bool _disabled; private bool _warnedResolve; private bool _warnedSpawn; private bool _warnedBundleSearch; private bool _prefabBundleLoadFailed; private bool _spawnQueueGroupLoadFailed; public RevengeCrystalSpawner(ManualLogSource log) { _log = log ?? throw new ArgumentNullException("log"); } public void OnSceneChanged() { if ((Object)(object)_prefabBundle == (Object)null && (Object)(object)_spawnQueueGroupBundle == (Object)null) { _prefab = null; } _groupLimitRaised = false; _disabled = false; } public void Spawn(int count) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) if (count <= 0 || _disabled) { return; } EnsureGroupLimit(); HeroController instance = HeroController.instance; if ((Object)(object)instance == (Object)null) { _log.LogDebug((object)"[RevengeCrystalSpawner] spawn skipped: HeroController.instance is null."); return; } GameObject val = ResolvePrefab(); if ((Object)(object)val == (Object)null) { if (!_warnedResolve) { _warnedResolve = true; _log.LogWarning((object)"[RevengeCrystalSpawner] Revenge Crystal Hornet prefab not resolved; Revenge Crystal white/L2-L3 spawn disabled."); } return; } Vector3 position = ((Component)instance).transform.position; int num = Math.Min(count, 3); _log.LogInfo((object)$"[RevengeCrystalSpawner] spawning {num} statue(s) from '{((Object)val).name}'."); for (int i = 0; i < num; i++) { try { GameObject val2 = ObjectPoolExtensions.Spawn(val, position, Quaternion.identity); if ((Object)(object)val2 != (Object)null) { val2.SetActive(true); BindHero(val2, ((Component)instance).gameObject); ResetStatueFsm(val2); } } catch (Exception ex) { if (!_warnedSpawn) { _warnedSpawn = true; _log.LogWarning((object)("[RevengeCrystalSpawner] spawn failed: " + ex.Message)); } } } } public void SpawnStaggered(int count) { if (count <= 0 || _disabled) { return; } EnsureGroupLimit(); HeroController instance = HeroController.instance; if ((Object)(object)instance == (Object)null) { _log.LogDebug((object)"[RevengeCrystalSpawner] staggered spawn skipped: HeroController.instance is null."); return; } GameObject val = ResolvePrefab(); if ((Object)(object)val == (Object)null) { if (!_warnedResolve) { _warnedResolve = true; _log.LogWarning((object)"[RevengeCrystalSpawner] Revenge Crystal Hornet prefab not resolved; staggered spawn disabled."); } } else { int num = Math.Min(count, 3); _log.LogInfo((object)$"[RevengeCrystalSpawner] spawning {num} staggered statue(s) from '{((Object)val).name}'."); ((MonoBehaviour)instance).StartCoroutine(SpawnStaggeredRoutine(instance, val, num)); } } private IEnumerator SpawnStaggeredRoutine(HeroController hero, GameObject prefab, int amount) { Vector3 offset = default(Vector3); for (int i = 0; i < amount; i++) { if (i > 0) { yield return (object)new WaitForSeconds(0.1f); } try { GameObject val = ObjectPoolExtensions.Spawn(prefab, ((Component)hero).transform.position, Quaternion.identity); if ((Object)(object)val != (Object)null) { val.SetActive(true); BindHero(val, ((Component)hero).gameObject); ResetStatueFsm(val); ((Vector3)(ref offset))..ctor((float)(i + 1) * 0.6f, (i % 2 == 0) ? 0.5f : (-0.5f), 0f); val.AddComponent().Init(((Component)hero).transform, offset); } } catch (Exception ex) { if (!_warnedSpawn) { _warnedSpawn = true; _log.LogWarning((object)("[RevengeCrystalSpawner] staggered spawn failed: " + ex.Message)); } } } } private GameObject? ResolvePrefab() { if ((Object)(object)_prefab != (Object)null) { return _prefab; } if (_disabled) { return null; } _prefab = LoadViaAddressables(); if ((Object)(object)_prefab == (Object)null) { _prefab = FindUniqueRuntimeObject(); } if ((Object)(object)_prefab == (Object)null) { _prefab = LoadViaAssetBundle(); } if ((Object)(object)_prefab != (Object)null) { _log.LogInfo((object)("[RevengeCrystalSpawner] prefab resolved: " + ((Object)_prefab).name)); } return _prefab; } private GameObject? LoadViaAddressables() { try { string[] array = new string[2] { "Assets/Prefabs/Heroes/Tools/Revenge Crystal Hornet.prefab", "Revenge Crystal Hornet" }; foreach (string key in array) { object? obj = LoadAddressableObject(typeof(GameObject), key); GameObject val = (GameObject)((obj is GameObject) ? obj : null); if ((Object)(object)val != (Object)null && LooksLikeStatuePrefab(val)) { return val; } } return null; } catch (Exception ex) { _log.LogWarning((object)("[RevengeCrystalSpawner] Addressables load failed for 'Revenge Crystal Hornet': " + ex.Message)); return null; } } private object? LoadAddressableObject(Type assetType, string key) { try { Type type = (from a in AppDomain.CurrentDomain.GetAssemblies() select a.GetType("UnityEngine.AddressableAssets.Addressables", throwOnError: false)).FirstOrDefault((Type t) => t != null); if (type == null) { return null; } MethodInfo[] array = (from m in type.GetMethods(BindingFlags.Static | BindingFlags.Public) where m.Name == "LoadAssetAsync" && m.IsGenericMethodDefinition && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(string) select m).Take(2).ToArray(); if (array.Length != 1) { return null; } object obj = array[0].MakeGenericMethod(assetType).Invoke(null, new object[1] { key }); if (obj == null) { return null; } MethodInfo method = obj.GetType().GetMethod("WaitForCompletion", Type.EmptyTypes); if (method == null) { return null; } return method.Invoke(obj, null); } catch (Exception ex) { _log.LogWarning((object)("[RevengeCrystalSpawner] Addressables load failed for '" + key + "': " + ex.Message)); return null; } } private void EnsureGroupLimit() { if (_groupLimitRaised) { return; } try { List list = ResolveSpawnQueueGroups(); if (list.Count == 0) { return; } FieldInfo field = typeof(SpawnQueueGroup).GetField("groupLimit", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { _log.LogWarning((object)"[RevengeCrystalSpawner] SpawnQueueGroup.groupLimit field not found."); return; } foreach (SpawnQueueGroup item in list) { field.SetValue(item, 3); } _groupLimitRaised = true; _log.LogInfo((object)($"[RevengeCrystalSpawner] SpawnQueueGroup.groupLimit raised to {3} " + $"({list.Count} instance(s)).")); } catch (Exception ex) { _log.LogWarning((object)("[RevengeCrystalSpawner] failed to raise SpawnQueueGroup.groupLimit: " + ex.Message)); } } private List ResolveSpawnQueueGroups() { List list = new List(); try { SpawnQueueGroup[] array = Resources.FindObjectsOfTypeAll(); foreach (SpawnQueueGroup val in array) { if ((Object)(object)val != (Object)null && ((Object)val).name == "Revenge Crystal Hornet") { list.Add(val); } } } catch (Exception ex) { if (!_warnedBundleSearch) { _warnedBundleSearch = true; _log.LogWarning((object)("[RevengeCrystalSpawner] runtime SpawnQueueGroup search failed: " + ex.Message)); } } if (list.Count > 0) { return list; } try { foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles()) { if (!((Object)(object)allLoadedAssetBundle == (Object)null)) { SpawnQueueGroup val2 = allLoadedAssetBundle.LoadAsset("Assets/Data Assets/Spawn Queue Groups/Revenge Crystal Hornet.asset"); if ((Object)(object)val2 == (Object)null) { val2 = allLoadedAssetBundle.LoadAsset("Revenge Crystal Hornet"); } if ((Object)(object)val2 != (Object)null) { list.Add(val2); break; } } } } catch (Exception ex2) { if (!_warnedBundleSearch) { _warnedBundleSearch = true; _log.LogWarning((object)("[RevengeCrystalSpawner] loaded-bundle SpawnQueueGroup search failed: " + ex2.Message)); } } if (list.Count > 0) { return list; } object? obj = LoadAddressableObject(typeof(SpawnQueueGroup), "Revenge Crystal Hornet"); SpawnQueueGroup val3 = (SpawnQueueGroup)((obj is SpawnQueueGroup) ? obj : null); if (val3 != null) { list.Add(val3); return list; } if (_spawnQueueGroupLoadFailed) { return list; } try { string text = Path.Combine(Application.streamingAssetsPath, "aa", "StandaloneWindows64", "dataassets_assets_assets", "dataassets", "spawnqueuegroups.bundle"); if (!File.Exists(text)) { return list; } AssetBundle val4 = _spawnQueueGroupBundle; if ((Object)(object)val4 == (Object)null) { val4 = FindLoadedBundle(Path.GetFileName(text)); if ((Object)(object)val4 == (Object)null) { val4 = AssetBundle.LoadFromFile(text); } _spawnQueueGroupBundle = val4; } if ((Object)(object)val4 == (Object)null) { _spawnQueueGroupLoadFailed = true; return list; } SpawnQueueGroup val5 = val4.LoadAsset("Assets/Data Assets/Spawn Queue Groups/Revenge Crystal Hornet.asset"); if ((Object)(object)val5 != (Object)null) { list.Add(val5); } } catch (Exception ex3) { _spawnQueueGroupLoadFailed = true; _log.LogWarning((object)("[RevengeCrystalSpawner] SpawnQueueGroup bundle load failed: " + ex3.Message)); } return list; } private GameObject? LoadViaAssetBundle() { if (_prefabBundleLoadFailed) { return null; } try { string text = Path.Combine(Application.streamingAssetsPath, "aa", "StandaloneWindows64", "localpoolprefabs_assets_shared.bundle"); if (!File.Exists(text)) { return null; } AssetBundle val = _prefabBundle; if ((Object)(object)val == (Object)null) { val = FindLoadedBundle(Path.GetFileName(text)); if ((Object)(object)val == (Object)null) { val = AssetBundle.LoadFromFile(text); } _prefabBundle = val; } if ((Object)(object)val == (Object)null) { _prefabBundleLoadFailed = true; return null; } GameObject val2 = val.LoadAsset("Assets/Prefabs/Heroes/Tools/Revenge Crystal Hornet.prefab"); return ((Object)(object)val2 != (Object)null && LooksLikeStatuePrefab(val2)) ? val2 : null; } catch (Exception ex) { _prefabBundleLoadFailed = true; _log.LogWarning((object)("[RevengeCrystalSpawner] AssetBundle load failed: " + ex.Message)); return null; } } private AssetBundle? FindLoadedBundle(string fileName) { try { foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles()) { if ((Object)(object)allLoadedAssetBundle != (Object)null && string.Equals(((Object)allLoadedAssetBundle).name, fileName, StringComparison.OrdinalIgnoreCase)) { return allLoadedAssetBundle; } } string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName); foreach (AssetBundle allLoadedAssetBundle2 in AssetBundle.GetAllLoadedAssetBundles()) { if ((Object)(object)allLoadedAssetBundle2 != (Object)null && ((Object)allLoadedAssetBundle2).name.IndexOf(fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase) >= 0) { return allLoadedAssetBundle2; } } } catch (Exception ex) { if (!_warnedBundleSearch) { _warnedBundleSearch = true; _log.LogWarning((object)("[RevengeCrystalSpawner] loaded-bundle search failed: " + ex.Message)); } } return null; } private static bool LooksLikeStatuePrefab(GameObject candidate) { if ((Object)(object)candidate == (Object)null) { return false; } PlayMakerFSM component = candidate.GetComponent(); if ((Object)(object)component == (Object)null) { return false; } if (!string.Equals(component.FsmName, "FSM", StringComparison.Ordinal)) { return false; } if (component.FsmVariables.FindFsmGameObject("Form Antic Pt") == null) { return component.FsmVariables.FindFsmGameObject("Enemy Damager") != null; } return true; } private GameObject? FindUniqueRuntimeObject() { try { GameObject[] array = (from g in Resources.FindObjectsOfTypeAll() where (Object)(object)g != (Object)null && ((Object)g).name == "Revenge Crystal Hornet" select g).Take(2).ToArray(); if (array.Length == 1) { return array[0]; } if (array.Length > 1) { _disabled = true; _log.LogWarning((object)"[RevengeCrystalSpawner] multiple 'Revenge Crystal Hornet' objects found; spawn disabled (ambiguous)."); } return null; } catch (Exception ex) { _log.LogWarning((object)("[RevengeCrystalSpawner] runtime object search failed: " + ex.Message)); return null; } } private static void BindHero(GameObject spawned, GameObject hero) { if ((Object)(object)spawned == (Object)null || (Object)(object)hero == (Object)null) { return; } PlayMakerFSM component = spawned.GetComponent(); if (!((Object)(object)component == (Object)null)) { FsmGameObject val = component.FsmVariables.FindFsmGameObject("Hero") ?? FsmVariables.GlobalVariables.FindFsmGameObject("Hero"); if (val != null) { val.Value = hero; } } } private static void ResetStatueFsm(GameObject statue) { if ((Object)(object)statue == (Object)null) { return; } PlayMakerFSM component = statue.GetComponent(); if ((Object)(object)component == (Object)null) { return; } try { ((object)component).GetType().GetMethod("SetState", new Type[1] { typeof(string) })?.Invoke(component, new object[1] { "Init Wait" }); } catch (Exception ex) { Debug.LogWarning((object)("[RevengeCrystalSpawner] FSM reset failed: " + ex.Message)); } } } public sealed class RevengeCrystalStatueOffsetter : MonoBehaviour { private Transform? _hero; private Vector3 _offset; public void Init(Transform hero, Vector3 offset) { //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) _hero = hero; _offset = offset; ((MonoBehaviour)this).StartCoroutine(ApplyOffsetAfterAppear()); } private IEnumerator ApplyOffsetAfterAppear() { yield return (object)new WaitForSeconds(1.3f); if ((Object)(object)_hero != (Object)null) { ((Component)this).transform.position = _hero.position + _offset; } } } public sealed class ShellSatchelRepairRunner : MonoBehaviour { private sealed class Entry { public ToolItem? Tool; public float ReadyTime; } private const float RepairDelaySeconds = 2f; private static readonly List Pending = new List(); private static bool _warned; public static void Schedule(ToolItem tool) { if ((Object)(object)tool == (Object)null) { return; } foreach (Entry item in Pending) { if ((Object)(object)item.Tool == (Object)(object)tool) { item.ReadyTime = Time.time + 2f; return; } } Pending.Add(new Entry { Tool = tool, ReadyTime = Time.time + 2f }); } public static void CancelAll() { Pending.Clear(); } private void Update() { for (int num = Pending.Count - 1; num >= 0; num--) { Entry entry = Pending[num]; if ((Object)(object)entry.Tool == (Object)null) { Pending.RemoveAt(num); } else if (!(Time.time < entry.ReadyTime)) { Pending.RemoveAt(num); TryRepair(entry.Tool); } } } private static void TryRepair(ToolItem tool) { //IL_0020: 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) try { if (ShellSatchelAutoRepairPatch.IsLevelActive(ShellSatchelAutoRepairPatch.GetLevel?.Invoke("Shell Satchel") ?? 0) && (int)tool.Type == 0 && tool.SavedData.AmountLeft <= 0) { tool.CollectFree(ToolItemManager.GetToolStorageAmount(tool)); ToolItemStatesLiquid val = (ToolItemStatesLiquid)(object)((tool is ToolItemStatesLiquid) ? tool : null); if (val != null) { val.RefillRefills(false); } } } catch (Exception ex) { if (!_warned) { _warned = true; Debug.LogWarning((object)("[ShellSatchelRepair] repair failed: " + ex.Message)); } } } } public sealed class ToolEquipRefreshBridge : MonoBehaviour { private GameEventHub? _events; private ToolEquipIconDriver? _driver; public void Initialize(GameEventHub events, ToolEquipIconDriver driver) { _events = events; _driver = driver; events.CrestChanged += OnCrestChanged; events.SceneChanged += OnSceneChanged; } private void OnDestroy() { if (_events != null) { _events.CrestChanged -= OnCrestChanged; _events.SceneChanged -= OnSceneChanged; } } private void OnCrestChanged(CrestChangedEvent e) { ((MonoBehaviour)this).StartCoroutine(RefreshNextFrame()); } private void OnSceneChanged(string scene) { ((MonoBehaviour)this).StartCoroutine(RefreshNextFrame()); } private IEnumerator RefreshNextFrame() { yield return null; _driver?.Refresh(); } } } namespace CrestsEvolve.GameInterop.Patches { public static class BellBindSkillShieldPatch { private sealed class ActionCache { public bool Stored; public bool OriginalEnabled; } private sealed class SkillShieldMarker : MonoBehaviour { } private sealed class BindBellGateMarker : MonoBehaviour { } private sealed class EndBellBindShieldAction : FsmStateAction { public override void OnEnter() { try { EndShield(); } catch (Exception ex) { WarnOnce(ex); } ((FsmStateAction)this).Finish(); } } public static readonly string[] SkillShieldEvents = new string[4] { "NEEDLE THROW", "THREAD SPHERE", "PARRY", "SILK BOMB" }; private static readonly string[] EndStates = new string[4] { "N Throw Recover", "Special End", "Cancel All", "Cancel Frame" }; public static Func? IsEquippedInWhiteSlot; private static ManualLogSource? _log; private static bool _warned; private static FieldInfo? _bellBindFsmField; private static readonly List _patchedSpecials = new List(); private static readonly List _patchedBind = new List(); private static readonly ConditionalWeakTable _bindBellCache = new ConditionalWeakTable(); public static void Configure(ManualLogSource log) { _log = log; _warned = false; _bellBindFsmField = AccessTools.Field(typeof(HeroController), "bellBindFSM"); _patchedSpecials.Clear(); _patchedBind.Clear(); } public static bool ShouldTriggerSkillShield(string? eventName) { if (eventName != null) { return Array.IndexOf(SkillShieldEvents, eventName) >= 0; } return false; } public static void OnSkillEvent(PlayMakerFSM __instance, string eventName) { try { if (ShouldTriggerSkillShield(eventName) && !((Object)(object)__instance == (Object)null) && !(__instance.FsmName != "Silk Specials")) { Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Bell Bind")) { ActivateShield(); } } } catch (Exception ex) { WarnOnce(ex); } } public static void OnFsmStart(PlayMakerFSM __instance) { if ((Object)(object)__instance == (Object)null || __instance.Fsm == null || (Object)(object)((Component)__instance).gameObject == (Object)null || !((Object)((Component)__instance).gameObject).name.StartsWith("Hero_Hornet", StringComparison.Ordinal)) { return; } try { if (__instance.FsmName == "Silk Specials") { InstallSkillEndActions(__instance); } else if (__instance.FsmName == "Spell Control") { InstallBindBellGate(__instance); } } catch (Exception ex) { WarnOnce(ex); } } public static void RefreshAll() { for (int num = _patchedBind.Count - 1; num >= 0; num--) { PlayMakerFSM val = _patchedBind[num]; if ((Object)(object)val == (Object)null) { _patchedBind.RemoveAt(num); } else { ApplyBindBellGate(val); } } } public static void RestoreAll() { foreach (PlayMakerFSM item in _patchedBind) { if (!((Object)(object)item == (Object)null)) { ApplyBindBellGate(item, forceInactive: true); } } _patchedBind.Clear(); _patchedSpecials.Clear(); } private static void ActivateShield() { PlayMakerFSM val = ResolveBellBindFsm(); if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { ((Component)val).gameObject.SetActive(true); ManualLogSource? log = _log; if (log != null) { log.LogDebug((object)"[BellBindSkillShield] white-slot skill shield activated."); } } } private static void EndShield() { PlayMakerFSM val = ResolveBellBindFsm(); if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeSelf) { val.SendEvent("DISAPPEAR"); ManualLogSource? log = _log; if (log != null) { log.LogDebug((object)"[BellBindSkillShield] white-slot skill shield ended (DISAPPEAR)."); } } } private static PlayMakerFSM? ResolveBellBindFsm() { if (_bellBindFsmField == null) { return null; } HeroController instance = HeroController.instance; if ((Object)(object)instance == (Object)null) { return null; } object? value = _bellBindFsmField.GetValue(instance); return (PlayMakerFSM?)((value is PlayMakerFSM) ? value : null); } private static void InstallSkillEndActions(PlayMakerFSM fsm) { if ((Object)(object)((Component)fsm).GetComponent() != (Object)null) { return; } int num = 0; string[] endStates = EndStates; foreach (string text in endStates) { FsmState state = FsmUtil.GetState(fsm, text); if (state != null) { FsmUtil.InsertAction(state, state.Actions.Length, (FsmStateAction)(object)new EndBellBindShieldAction()); num++; } } if (num == 0) { WarnOnce(new InvalidOperationException("Silk Specials FSM end states not found (N Throw Recover/Special End/Cancel All/Cancel Frame); skill shield end disabled.")); return; } ((Component)fsm).gameObject.AddComponent(); _patchedSpecials.Add(fsm); ManualLogSource? log = _log; if (log != null) { log.LogInfo((object)$"[BellBindSkillShield] Silk Specials FSM hook installed ({num} end state(s))."); } } private static void InstallBindBellGate(PlayMakerFSM fsm) { if ((Object)(object)((Component)fsm).GetComponent() != (Object)null) { ApplyBindBellGate(fsm); return; } if (!FindBindBellActivation(fsm)) { WarnOnce(new InvalidOperationException("Spell Control | Bind Bell? ActivateGameObject(Bind Bell, true) not found; bind-release gate disabled.")); return; } ((Component)fsm).gameObject.AddComponent(); _patchedBind.Add(fsm); ApplyBindBellGate(fsm); ManualLogSource? log = _log; if (log != null) { log.LogInfo((object)"[BellBindSkillShield] Spell Control | Bind Bell? gate installed (white-slot bind no shield)."); } } private static bool FindBindBellActivation(PlayMakerFSM fsm) { FsmState[] fsmStates = fsm.FsmStates; foreach (FsmState val in fsmStates) { if (val.Name != "Bind Bell?") { continue; } FsmStateAction[] actions = val.Actions; for (int j = 0; j < actions.Length; j++) { if (IsBindBellActivation(actions[j])) { return true; } } } return false; } private static bool IsBindBellActivation(FsmStateAction action) { ActivateGameObject val = (ActivateGameObject)(object)((action is ActivateGameObject) ? action : null); if (val != null && val.activate != null && val.activate.Value && val.gameObject != null && val.gameObject.GameObject != null) { return string.Equals(((NamedVariable)val.gameObject.GameObject).Name, "Bind Bell", StringComparison.Ordinal); } return false; } private static void ApplyBindBellGate(PlayMakerFSM fsm, bool forceInactive = false) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown try { bool flag = !forceInactive && IsEquippedInWhiteSlot != null && IsEquippedInWhiteSlot("Bell Bind"); FsmState[] fsmStates = fsm.FsmStates; foreach (FsmState val in fsmStates) { if (val.Name != "Bind Bell?") { continue; } FsmStateAction[] actions = val.Actions; foreach (FsmStateAction val2 in actions) { if (IsBindBellActivation(val2)) { ActionCache orCreateValue = _bindBellCache.GetOrCreateValue((ActivateGameObject)val2); if (!orCreateValue.Stored) { orCreateValue.Stored = true; orCreateValue.OriginalEnabled = val2.Enabled; } val2.Enabled = !flag && orCreateValue.OriginalEnabled; } } } } catch (Exception ex) { WarnOnce(ex); } } private static void WarnOnce(Exception ex) { if (!_warned) { _warned = true; ManualLogSource? log = _log; if (log != null) { log.LogWarning((object)("[BellBindSkillShield] disabled: " + ex.GetType().Name + ": " + ex.Message)); } } } } public static class BlueToolEffectPatches { private sealed class WispCooldownCache { public float Min; public float Max; } private sealed class SlashScaleCache { public Vector3 Original; } private const int SilkMaxCapacity = 36; public static Func? GetLevel; public static Func? IsEquippedInWhiteSlot; public static Action? SpawnRevengeCrystals; public static Action? AddExtraBlueHealth; private static ManualLogSource? _log; private static bool _warned; private static FieldInfo? _moss1Hits; private static FieldInfo? _moss2Hits; private static FieldInfo? _lavaCooldown; private static FieldInfo? _taggedDamage; private static FieldInfo? _wispCooldownField; private static FieldInfo? _minMaxStartField; private static FieldInfo? _minMaxEndField; private static FieldInfo? _queuedAutoThrowTool; private static FieldInfo? _willThrowTool; private static MethodInfo? _resetMaggotCharm; private static FieldInfo? _heroCState; private static FieldInfo? _whipLashing; private static FieldInfo? _luckyDiceShieldedHits; private static object? _zeroMinMaxFloat; private static double _pendingPoisonMultiplier = 1.0; private static double _pendingSilkMultiplier = 1.0; private static int _quickSlingRemaining; private static int _revengeHealthBefore = -1; private static int _lastLoggedCompassCap = -1; private static ToolItem? _quickSlingTool; private static FieldInfo? _quickeningTimeLeft; private static FieldInfo? _imbuementTimeLeft; private static FieldInfo? _nailAttackBaseScale; private static string? _pendingWhiteSlotTool; private static double _pendingWhiteSlotMultiplier = 1.0; private static readonly ConditionalWeakTable _wispCooldownCache = new ConditionalWeakTable(); private static readonly ConditionalWeakTable _slashScales = new ConditionalWeakTable(); public static bool IsDiceCritWindow { get; private set; } public static void Configure(ManualLogSource log) { _log = log; _moss1Hits = AccessTools.Field(typeof(HeroController), "mossCreep1Hits"); _moss2Hits = AccessTools.Field(typeof(HeroController), "mossCreep2Hits"); _lavaCooldown = AccessTools.Field(typeof(HeroController), "lavaBellCooldownTimeLeft"); _taggedDamage = AccessTools.Field(typeof(TagDamageTaker), "taggedDamage"); _wispCooldownField = AccessTools.Field(typeof(HeroWispLantern), "wispSpawnCooldown"); Type type = Type.GetType("TeamCherry.SharedUtils.MinMaxFloat, TeamCherry.SharedUtils"); if (type != null) { _minMaxStartField = AccessTools.Field(type, "Start"); _minMaxEndField = AccessTools.Field(type, "End"); try { _zeroMinMaxFloat = Activator.CreateInstance(type); if (_zeroMinMaxFloat != null && _minMaxStartField != null && _minMaxEndField != null) { _minMaxStartField.SetValue(_zeroMinMaxFloat, 0f); _minMaxEndField.SetValue(_zeroMinMaxFloat, 0f); } } catch (Exception ex) { _log.LogWarning((object)("[BlueToolEffects] MinMaxFloat zero instance creation failed: " + ex.Message)); } } _queuedAutoThrowTool = AccessTools.Field(typeof(HeroController), "queuedAutoThrowTool"); _willThrowTool = AccessTools.Field(typeof(HeroController), "willThrowTool"); _quickeningTimeLeft = AccessTools.Field(typeof(HeroController), "quickeningTimeLeft"); _imbuementTimeLeft = AccessTools.Field(typeof(HeroNailImbuement), "imbuementTimeLeft"); _nailAttackBaseScale = AccessTools.Field(typeof(NailAttackBase), "scale"); _resetMaggotCharm = AccessTools.Method(typeof(HeroController), "ResetMaggotCharm", (Type[])null, (Type[])null); _heroCState = AccessTools.Field(typeof(HeroController), "cState"); _whipLashing = ((_heroCState == null) ? null : AccessTools.Field(_heroCState.FieldType, "whipLashing")); _luckyDiceShieldedHits = AccessTools.Field(typeof(HeroController), "luckyDiceShieldedHits"); ClearQuickSling(); ClearPendingWhiteSlot(); _revengeHealthBefore = -1; } public static double GetDamageMultiplier(string toolName) { return EffectsFor(toolName).DamageMultiplier; } public static bool ShouldApplyEffectDamagePrefix(bool hasRepresentingTool) { return !hasRepresentingTool; } public static bool IsShellSatchelWhiteFixedCostActive() { return ShouldApplyShellSatchelWhiteFixedCost(IsEquippedInWhiteSlot?.Invoke("Shell Satchel") ?? false, EffectsFor("Shell Satchel").ShellSatchelWhiteFixedShardCost); } public static bool IsCompassEquippedAnywhere() { if (!Gameplay.CompassTool.Status.IsEquipped) { return IsEquippedInWhiteSlot?.Invoke("Compass") ?? false; } return true; } public static bool IsCompassAbsoluteStorageActive(ToolItem tool) { if ((Object)(object)tool != (Object)null) { return ShouldApplyCompassAbsoluteStorage(IsCompassEquippedAnywhere(), GetLevel?.Invoke("Compass") ?? 0, tool.name); } return false; } public static bool IsCogworkStorageTool(string toolName) { if (!string.Equals(toolName, "Cogwork Flier", StringComparison.Ordinal)) { return string.Equals(toolName, "Cogfly", StringComparison.Ordinal); } return true; } public static bool ShouldApplyShellSatchelWhiteFixedCost(bool inWhiteSlot, bool effectEnabled) { return inWhiteSlot && effectEnabled; } public static bool ShouldApplyCompassAbsoluteStorage(bool compassEquipped, int level, string toolName) { if (compassEquipped && level >= 2) { return IsCogworkStorageTool(toolName); } return false; } public static bool ShouldForceDiceLucky(bool diceEquipped, int level, bool inCritWindow) { return diceEquipped && level >= 2 && inCritWindow; } public static void LongneedleSlashPrefix(NailAttackBase __instance) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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) if (((ToolBase)Gameplay.LongNeedleTool).IsEquipped) { ToolEffectSpec toolEffectSpec = EffectsFor("Longneedle"); if (!(toolEffectSpec.NailLengthMultiplier <= 1.0) || !(toolEffectSpec.NailWidthMultiplier <= 1.0) || !(toolEffectSpec.NailWhiteLengthMultiplier <= 1.0)) { _slashScales.Remove(__instance); Vector3 original = (Vector3)((_nailAttackBaseScale != null) ? ((Vector3)(_nailAttackBaseScale.GetValue(__instance) ?? ((object)Vector3.one))) : ((Component)__instance).transform.localScale); _slashScales.Add(__instance, new SlashScaleCache { Original = original }); } } } public static void LongneedleSlashPostfix(NailAttackBase __instance) { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) if (!((ToolBase)Gameplay.LongNeedleTool).IsEquipped) { return; } ToolEffectSpec toolEffectSpec = EffectsFor("Longneedle"); if ((!(toolEffectSpec.NailLengthMultiplier <= 1.0) || !(toolEffectSpec.NailWidthMultiplier <= 1.0) || !(toolEffectSpec.NailWhiteLengthMultiplier <= 1.0)) && _slashScales.TryGetValue(__instance, out SlashScaleCache value)) { _slashScales.Remove(__instance); double num = toolEffectSpec.NailLengthMultiplier; double num2 = toolEffectSpec.NailWidthMultiplier; if (IsWitchCrest()) { num += toolEffectSpec.WitchNailLengthBonus; num2 += toolEffectSpec.WitchNailWidthBonus; } num *= toolEffectSpec.NailWhiteLengthMultiplier; ((Component)__instance).transform.localScale = new Vector3(value.Original.x * (float)num, value.Original.y * (float)num2, value.Original.z); } } public static void WispLanternEquipsChangedPostfix(HeroWispLantern __instance) { ToolEffectSpec toolEffectSpec = EffectsFor("Wisp Lantern"); if (!Gameplay.WispLanternTool.Status.IsEquipped || toolEffectSpec.WispSpawnIntervalSeconds <= 0f) { RestoreWispCooldown(__instance); } else { SetWispCooldown(__instance, toolEffectSpec.WispSpawnIntervalSeconds); } } public static bool TakeSilkWispPrefix(int amount, SilkTakeSource source) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 if ((int)source == 1) { return !EffectsFor("Wisp Lantern").WispNoSilkCost; } return true; } public static void SilkSkillCostPostfix(PlayerData __instance, ref int __result) { if (Gameplay.FleaCharmTool.IsEquippedHud) { ToolEffectSpec toolEffectSpec = EffectsFor("Flea Charm"); if (toolEffectSpec.SilkSkillCost > 0 && (toolEffectSpec.SilkSkillCostNoHealthGate || __instance.health >= __instance.CurrentMaxHealth)) { __result = toolEffectSpec.SilkSkillCost; } } } public static void NailChargeTimePostfix(HeroController __instance, ref float __result) { ApplyNailChargeFactor(__instance, ref __result, __instance.NAIL_CHARGE_TIME); } public static void NailChargeBeginTimePostfix(HeroController __instance, ref float __result) { ApplyNailChargeFactor(__instance, ref __result, __instance.NAIL_CHARGE_BEGIN_TIME); } public static void SilkGainPrefix(HeroController __instance, HitInstance hitInstance) { //IL_0029: 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_0031: Invalid comparison between Unknown and I4 if (ToolItemManager.IsToolEquipped("Pinstress Tool")) { ToolEffectSpec toolEffectSpec = EffectsFor("Pinstress Tool"); if (toolEffectSpec.ChargeSilkMultiplier > 1.0 && (int)hitInstance.AttackType == 16) { _pendingSilkMultiplier = toolEffectSpec.ChargeSilkMultiplier; } } } public static void AddSilkPrefix(ref int amount) { if (!(_pendingSilkMultiplier <= 1.0)) { amount = (int)Math.Round((double)amount * _pendingSilkMultiplier); _pendingSilkMultiplier = 1.0; } } public static void WandererCritMultiplierPostfix(ref float __result) { if (Gameplay.CompassTool.Status.IsEquipped) { ToolEffectSpec toolEffectSpec = EffectsFor("Compass"); if (toolEffectSpec.CritMultiplierBonus > 0.0) { __result += (float)toolEffectSpec.CritMultiplierBonus; } } } public static void ZapDamageMultPostfix(ref float __result) { if (Gameplay.ZapImbuementTool.Status.IsEquipped) { ToolEffectSpec toolEffectSpec = EffectsFor("Zap Imbuement"); double num = toolEffectSpec.SilkSkillDamageBonus; if (toolEffectSpec.SilkSkillDamageWhiteBonus) { num += 0.25; } if (num > 0.0) { __result += (float)num; } } } public static void SilkRegenMaxPostfix(PlayerData __instance, ref int __result) { if (Gameplay.WhiteRingTool.Status.IsEquipped) { ToolEffectSpec toolEffectSpec = EffectsFor("White Ring"); int num = ((toolEffectSpec.SilkRegenCapBonus <= 0) ? 1 : toolEffectSpec.SilkRegenCapBonus); __result += num - 1; } } public static void WhiteRingSpeedMultiplierPostfix(ref float __result) { if (Gameplay.WhiteRingTool.Status.IsEquipped) { ToolEffectSpec toolEffectSpec = EffectsFor("White Ring"); double num = ((toolEffectSpec.SilkRegenSpeedFactor > 0.0) ? toolEffectSpec.SilkRegenSpeedFactor : 1.35); __result *= (float)(1.35 / num); } } public static bool SilkSpoolSetRegenPrefix(SilkSpool __instance, int amount, bool isUpgraded) { if (amount != 0) { return true; } Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot == null || !isEquippedInWhiteSlot("White Ring")) { return true; } return !EffectsFor("White Ring").SilkRegenNoResetOnChange; } public static void SilkMaxPostfix(PlayerData __instance, ref int __result) { if (Gameplay.SpoolExtenderTool.Status.IsEquipped) { ToolEffectSpec toolEffectSpec = EffectsFor("Spool Extender"); int num = ((toolEffectSpec.SilkCapBonus > 0) ? toolEffectSpec.SilkCapBonus : 3); if (toolEffectSpec.SilkCapWhiteDouble) { num *= 2; } __result = Math.Min(__instance.CurrentSilkMaxBasic + num, 36); } } public static void DrawSpoolPrefix(ref int maxOffset) { try { PlayerData instance = PlayerData.instance; if (instance != null) { int num = instance.CurrentSilkMax - instance.CurrentSilkMaxBasic; if (num > 0) { maxOffset += num; } } } catch (Exception ex) { WarnOnce(ex); } } public static void BrollyHitPrefix(ref HitInstance hitInstance) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (IsBrollyHit(hitInstance) && Gameplay.BrollySpikeTool.Status.IsEquipped && ShouldApplyEffectDamagePrefix((Object)(object)hitInstance.RepresentingTool != (Object)null)) { ToolEffectSpec toolEffectSpec = EffectsFor("Brolly Spike"); if (!(toolEffectSpec.DamageMultiplier <= 1.0)) { hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * toolEffectSpec.DamageMultiplier); } } } public static void BrollyHitPostfix(HitInstance hitInstance) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (!IsBrollyHit(hitInstance)) { return; } Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Brolly Spike") && EffectsFor("Brolly Spike").BrollyWhiteSilk) { HeroController instance = HeroController.instance; if ((Object)(object)instance != (Object)null) { instance.AddSilk(1, false, (SilkAddSource)0); } } } public static void DazzleHitPrefix(ref HitInstance hitInstance) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (!IsDazzleHit(hitInstance)) { return; } ToolDefinition toolDefinition = FindDazzleDefinition(); if (!(toolDefinition == null) && ShouldApplyEffectDamagePrefix((Object)(object)hitInstance.RepresentingTool != (Object)null)) { ToolEffectSpec toolEffectSpec = EffectsFor(toolDefinition.Name); if (!(toolEffectSpec.DamageMultiplier <= 1.0)) { hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * toolEffectSpec.DamageMultiplier); } } } public static void DazzleWhiteTakeDamagePostfix(HeroController __instance) { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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_00d3: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null) { return; } ToolDefinition toolDefinition = FindDazzleDefinition(); if (toolDefinition == null) { return; } Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot == null || !isEquippedInWhiteSlot(toolDefinition.Name) || !EffectsFor(toolDefinition.Name).DazzleWhiteOnHit) { return; } try { GameObject val = ReadDazzleFlashPrefab((PlayMakerFSM?)(((Object)(object)__instance.spellControl != (Object)null) ? ((object)__instance.spellControl) : ((object)((IEnumerable)((Component)__instance).GetComponents()).FirstOrDefault((Func)((PlayMakerFSM f) => (Object)(object)f != (Object)null && (f.FsmName == "Bind" || f.FsmName == "Spell Control"))))), toolDefinition.Name == "Dazzle Bind Upgraded"); if (!((Object)(object)val == (Object)null)) { Vector3 val2 = ((Component)__instance).transform.position + new Vector3(0f, 0f, -0.21f); ObjectPoolExtensions.Spawn(val, val2, Quaternion.identity); } } catch (Exception ex) { WarnOnce(ex); } } public static void RevengeCrystalTakeDamagePrefix(HeroController __instance) { _revengeHealthBefore = -1; if (!((Object)(object)__instance == (Object)null)) { PlayerData playerData = __instance.playerData; if (playerData != null) { _revengeHealthBefore = playerData.health + playerData.healthBlue; } } } public static void RevengeCrystalTakeDamagePostfix(HeroController __instance) { if ((Object)(object)__instance == (Object)null) { return; } try { PlayerData playerData = __instance.playerData; if (playerData == null) { return; } int revengeHealthBefore = _revengeHealthBefore; _revengeHealthBefore = -1; if (revengeHealthBefore >= 0 && playerData.health + playerData.healthBlue < revengeHealthBefore) { string text = "Revenge Crystal"; ToolEffectSpec toolEffectSpec = EffectsFor(text); bool equipped = ToolItemManager.IsToolEquipped(text); bool inWhiteSlot = IsEquippedInWhiteSlot?.Invoke(text) ?? false; int effectiveLevel = GetLevel?.Invoke(text) ?? 0; int revengeCrystalCount = toolEffectSpec.RevengeCrystalCount; bool num = RevengeCrystalRules.ShouldSpawnExtras(equipped, inWhiteSlot, effectiveLevel, revengeCrystalCount); int num2 = RevengeCrystalRules.ExtraCount(revengeCrystalCount); if (num && num2 > 0) { SpawnRevengeCrystals?.Invoke(num2); } } } catch (Exception ex) { WarnOnce(ex); } } public static void RevengeCrystalSpecialDamagePostfix(HeroController __instance) { if ((Object)(object)__instance == (Object)null) { return; } try { string text = "Revenge Crystal"; ToolEffectSpec toolEffectSpec = EffectsFor(text); bool equipped = ToolItemManager.IsToolEquipped(text); bool inWhiteSlot = IsEquippedInWhiteSlot?.Invoke(text) ?? false; int effectiveLevel = GetLevel?.Invoke(text) ?? 0; int revengeCrystalCount = toolEffectSpec.RevengeCrystalCount; bool num = RevengeCrystalRules.ShouldSpawnExtras(equipped, inWhiteSlot, effectiveLevel, revengeCrystalCount); int num2 = RevengeCrystalRules.ExtraCount(revengeCrystalCount); if (num && num2 > 0) { SpawnRevengeCrystals?.Invoke(num2); } } catch (Exception ex) { WarnOnce(ex); } } public static void ShardsAddPrefix(PlayerData __instance, ref int amount) { if (amount > 0 && ToolItemManager.IsToolEquipped("Bone Necklace")) { ToolEffectSpec toolEffectSpec = EffectsFor("Bone Necklace"); if (!(toolEffectSpec.ShardValueMultiplier <= 1.0)) { amount = (int)Math.Round((double)amount * toolEffectSpec.ShardValueMultiplier); } } } public static void GeoAddPrefix(HeroController __instance, ref int amount) { if (amount > 0 && ToolItemManager.IsToolEquipped("Rosary Magnet")) { ToolEffectSpec toolEffectSpec = EffectsFor("Rosary Magnet"); if (!(toolEffectSpec.GeoValueMultiplier <= 1.0)) { amount = (int)Math.Round((double)amount * toolEffectSpec.GeoValueMultiplier); } } } public static void MaxFallVelocityPostfix(HeroController __instance, ref float __result) { if (Gameplay.WeightedAnkletTool.Status.IsEquipped) { ToolEffectSpec toolEffectSpec = EffectsFor("Weighted Anklet"); if (!(toolEffectSpec.FallSpeedBonusPercent <= 0.0)) { __result = __instance.MAX_FALL_VELOCITY * (float)(1.0 + toolEffectSpec.FallSpeedBonusPercent); } } } public static void WeightedKnockbackMultPostfix(ref float __result) { if (Gameplay.WeightedAnkletTool.Status.IsEquipped && (GetLevel?.Invoke("Weighted Anklet") ?? 0) >= 2) { __result = (float)EffectsFor("Weighted Anklet").KnockbackMultiplier; } } public static void WeightedInvulnMultPostfix(ref float __result) { if (Gameplay.WeightedAnkletTool.Status.IsEquipped && (GetLevel?.Invoke("Weighted Anklet") ?? 0) >= 2) { __result = (float)EffectsFor("Weighted Anklet").InvulnMultiplier; } } public static void BarbedWireDealtMultPostfix(ref float __result) { if (Gameplay.BarbedWireTool.Status.IsEquipped && (GetLevel?.Invoke("Barbed Wire") ?? 0) >= 2) { __result = (float)EffectsFor("Barbed Wire").BarbedWireDamageDealtMultiplier; } } public static void BarbedWireTakenMultPostfix(ref float __result) { if (Gameplay.BarbedWireTool.Status.IsEquipped) { Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Barbed Wire") && EffectsFor("Barbed Wire").BarbedWireWhiteNoDamageTakenMultiplier) { __result = 1f; } else if ((GetLevel?.Invoke("Barbed Wire") ?? 0) >= 2) { __result = (float)EffectsFor("Barbed Wire").BarbedWireDamageTakenMultiplier; } } } public static void DeadPurseHoldPercentPostfix(ref float __result) { if (Gameplay.DeadPurseTool.Status.IsEquipped && (GetLevel?.Invoke("Dead Mans Purse") ?? 0) >= 2) { __result = (float)EffectsFor("Dead Mans Purse").DeadPurseHoldPercent; } } public static void CocoonBrokenMinOneCocoonPrefix(HeroController __instance) { try { if (Gameplay.DeadPurseTool.Status.IsEquipped && (GetLevel?.Invoke("Dead Mans Purse") ?? 0) >= 3 && EffectsFor("Dead Mans Purse").DeadPurseMinOneCocoon) { PlayerData val = __instance.playerData ?? PlayerData.instance; if (val != null && val.HeroCorpseMoneyPool == 0 && val.geo > 0) { val.geo--; val.HeroCorpseMoneyPool = 1; } } } catch (Exception ex) { WarnOnce(ex); } } public static void CompassStoragePostfix(ToolItem __instance, ref int __result) { if ((Object)(object)__instance == (Object)null || !IsCompassEquippedAnywhere()) { return; } int num = GetLevel?.Invoke("Compass") ?? 0; if (num < 2 || !IsCogworkStorageTool(__instance.name)) { return; } __result = ((num >= 3) ? 12 : 8); if (__result != _lastLoggedCompassCap) { _lastLoggedCompassCap = __result; ManualLogSource? log = _log; if (log != null) { log.LogInfo((object)$"[CompassStorage] cogfly capacity -> {__result} (level {num})."); } } } public static void ToolReplenishCostPostfix(ref int __result) { Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Shell Satchel") && EffectsFor("Shell Satchel").ShellSatchelWhiteFixedShardCost) { __result = 1; } } public static void ReplenishUsageMultiplierPostfix(ref float __result) { Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Shell Satchel") && EffectsFor("Shell Satchel").ShellSatchelWhiteFixedShardCost) { __result = 1f; } } public static void LuckyDiceThresholdPostfix(int hits, ref int __result) { if (Gameplay.LuckyDiceTool.Status.IsEquipped) { int num = GetLevel?.Invoke("Magnetite Dice") ?? 0; if (num >= 2) { int num2 = ((num >= 3) ? 8 : 4); __result = Math.Min(hits * num2, num2 * 5); } } } public static void LuckyDiceTakeDamagePrefix(HeroController __instance, ref int __state) { __state = ((_luckyDiceShieldedHits != null && (Object)(object)__instance != (Object)null) ? ((int)(_luckyDiceShieldedHits.GetValue(__instance) ?? ((object)0))) : 0); } public static void LuckyDiceTakeDamagePostfix(HeroController __instance, HazardType hazardType, int __state) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 if ((Object)(object)__instance == (Object)null || __state <= 0 || (int)hazardType != 1) { return; } Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot == null || !isEquippedInWhiteSlot("Magnetite Dice") || !EffectsFor("Magnetite Dice").LuckyDiceWhiteNoReset || _luckyDiceShieldedHits == null) { return; } try { if ((int)(_luckyDiceShieldedHits.GetValue(__instance) ?? ((object)0)) == 0) { _luckyDiceShieldedHits.SetValue(__instance, __state); } } catch (Exception ex) { WarnOnce(ex); } } public static void IsWandererLuckyDicePostfix(HeroController __instance, ref bool __result) { if (!__result && !((Object)(object)__instance == (Object)null) && !__instance.cState.isMaggoted && ShouldForceDiceLucky(Gameplay.LuckyDiceTool.Status.IsEquipped, GetLevel?.Invoke("Magnetite Dice") ?? 0, IsDiceCritWindow)) { __result = true; } } public static void DoDamagePrefix(GameObject target, bool isFirstHit) { if (ShouldForceDiceLucky(Gameplay.LuckyDiceTool.Status.IsEquipped, GetLevel?.Invoke("Magnetite Dice") ?? 0, inCritWindow: true)) { IsDiceCritWindow = true; } } public static void DoDamagePostfix(GameObject target, bool isFirstHit) { IsDiceCritWindow = false; } public static void DoDamageFinalizer(GameObject target, bool isFirstHit, Exception __exception) { IsDiceCritWindow = false; } public static void WandererCritChanceDicePostfix(ref float __result) { if (Gameplay.LuckyDiceTool.Status.IsEquipped && (GetLevel?.Invoke("Magnetite Dice") ?? 0) >= 2) { ToolEffectSpec toolEffectSpec = EffectsFor("Magnetite Dice"); double num = toolEffectSpec.LuckyDiceCritChance; HeroController instance = HeroController.instance; if ((Object)(object)instance != (Object)null && ((ToolBase)Gameplay.WandererCrest).IsEquipped && instance.playerData != null && instance.playerData.silk >= 9) { num += toolEffectSpec.LuckyDiceWandererCritBonus; } __result = (float)num; } } public static void GetLuckModifierDicePostfix(ref float __result) { if (Gameplay.LuckyDiceTool.Status.IsEquipped && (GetLevel?.Invoke("Magnetite Dice") ?? 0) >= 2) { __result = 1f; } } public static void MusicianRangeMultPostfix(ref float __result) { if (Gameplay.MusicianCharmTool.Status.IsEquipped && (GetLevel?.Invoke("Musician Charm") ?? 0) >= 2) { __result = (float)EffectsFor("Musician Charm").MusicianRangeMultiplier; } } public static void MusicianDrainTimeMultPostfix(ref float __result) { if (Gameplay.MusicianCharmTool.Status.IsEquipped && (GetLevel?.Invoke("Musician Charm") ?? 0) >= 2) { __result = (float)EffectsFor("Musician Charm").MusicianSongTimeMultiplier; } } public static void SilkDrainDisabledPostfix(ref bool __result) { Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Sprintmaster") && EffectsFor("Sprintmaster").SprintmasterWhiteNoSilkCost) { __result = true; } } public static void ThiefSmallGeoIncreasePostfix(ref float __result) { ApplyThiefGeoIncrease(ref __result, (ToolEffectSpec fx) => fx.ThiefSmallGeoIncrease); } public static void ThiefMedGeoIncreasePostfix(ref float __result) { ApplyThiefGeoIncrease(ref __result, (ToolEffectSpec fx) => fx.ThiefMedGeoIncrease); } public static void ThiefLargeGeoIncreasePostfix(ref float __result) { ApplyThiefGeoIncrease(ref __result, (ToolEffectSpec fx) => fx.ThiefLargeGeoIncrease); } public static void ThiefGeoLossPostfix(ref object __result) { Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Thief Charm") && EffectsFor("Thief Charm").ThiefWhiteNoLoss && _zeroMinMaxFloat != null) { __result = _zeroMinMaxFloat; } } public static void ThiefGeoLossLooseChancePostfix(ref float __result) { Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Thief Charm") && EffectsFor("Thief Charm").ThiefWhiteNoLoss) { __result = 0f; } } public static bool TakeSilkClawlinePrefix(HeroController __instance, int amount, SilkTakeSource source) { Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot == null || !isEquippedInWhiteSlot("Thief Claw")) { return true; } if (!EffectsFor("Thief Claw").ClawlineNoSilkCost) { return true; } try { object obj = _heroCState?.GetValue(__instance); if (obj != null && _whipLashing != null && (bool)(_whipLashing.GetValue(obj) ?? ((object)false))) { return false; } } catch (Exception ex) { WarnOnce(ex); } return true; } public static void ThrowToolPrefix(HeroController __instance, bool isAutoThrow) { try { if (!Gameplay.QuickSlingTool.Status.IsEquipped) { Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot == null || !isEquippedInWhiteSlot("Quick Sling")) { goto IL_0033; } } if (!ToolItemManager.IsCustomToolOverride) { object? obj = _willThrowTool?.GetValue(__instance); ToolItem val = (ToolItem)((obj is ToolItem) ? obj : null); if ((Object)(object)val == (Object)null) { _quickSlingRemaining = 0; _quickSlingTool = null; return; } ToolEffectSpec toolEffectSpec = EffectsFor("Quick Sling"); int num = ((toolEffectSpec.QuickSlingThrowCount > 0) ? toolEffectSpec.QuickSlingThrowCount : 2); if (QuickSlingWhiteSlotRules.ShouldApplyWhiteSlotModifier(toolEffectSpec, IsEquippedInWhiteSlot?.Invoke("Quick Sling") ?? false, val.name)) { _quickSlingRemaining = 0; _quickSlingTool = null; if (!isAutoThrow) { _pendingWhiteSlotTool = val.name; _pendingWhiteSlotMultiplier = (string.Equals(val.name, "Lifeblood Syringe", StringComparison.Ordinal) ? ((double)QuickSlingWhiteSlotRules.SyringeBlueHealth(toolEffectSpec)) : QuickSlingWhiteSlotRules.DurationMultiplier(toolEffectSpec)); } } else if (QuickSlingWhiteSlotRules.ShouldStartThrowChain(isWhiteSlotModifiedTool: false, num)) { _quickSlingTool = val; if (!isAutoThrow) { _quickSlingRemaining = num - 1; } } else { _quickSlingRemaining = 0; _quickSlingTool = null; } return; } goto IL_0033; IL_0033: _quickSlingRemaining = 0; _quickSlingTool = null; } catch (Exception ex) { WarnOnce(ex); } } public static void ThrowToolPostfix(HeroController __instance, bool isAutoThrow) { try { if (_quickSlingRemaining <= 0) { return; } if (!Gameplay.QuickSlingTool.Status.IsEquipped) { Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot == null || !isEquippedInWhiteSlot("Quick Sling")) { goto IL_0040; } } if (!ToolItemManager.IsCustomToolOverride) { if (isAutoThrow) { object? obj = _willThrowTool?.GetValue(__instance); if ((Object)((obj is ToolItem) ? obj : null) != (Object)null) { _quickSlingRemaining = 0; _quickSlingTool = null; _queuedAutoThrowTool?.SetValue(__instance, false); } else if (_quickSlingRemaining > 1 && (Object)(object)_quickSlingTool != (Object)null) { _quickSlingRemaining--; _willThrowTool?.SetValue(__instance, _quickSlingTool); _queuedAutoThrowTool?.SetValue(__instance, true); } else { _quickSlingRemaining = 0; _quickSlingTool = null; } } return; } goto IL_0040; IL_0040: _quickSlingRemaining = 0; _quickSlingTool = null; } catch (Exception ex) { WarnOnce(ex); } } public static void ThrowToolEndPostfix(HeroController __instance) { if (_quickSlingRemaining <= 0) { _quickSlingTool = null; } } public static void ActivateQuickeningPostfix(HeroController __instance) { if (_pendingWhiteSlotTool != "Flea Brew" || _quickeningTimeLeft == null) { return; } try { if (!(_pendingWhiteSlotMultiplier <= 1.0)) { float num = (float)(_quickeningTimeLeft.GetValue(__instance) ?? ((object)0f)); _quickeningTimeLeft.SetValue(__instance, num * (float)_pendingWhiteSlotMultiplier); } } catch (Exception ex) { WarnOnce(ex); } finally { ClearPendingWhiteSlot(); } } public static void NailImbuementSetElementPostfix(HeroNailImbuement __instance) { if (_pendingWhiteSlotTool != "Flintstone" || _imbuementTimeLeft == null) { return; } try { if (!(_pendingWhiteSlotMultiplier <= 1.0)) { float num = (float)(_imbuementTimeLeft.GetValue(__instance) ?? ((object)0f)); _imbuementTimeLeft.SetValue(__instance, num * (float)_pendingWhiteSlotMultiplier); } } catch (Exception ex) { WarnOnce(ex); } finally { ClearPendingWhiteSlot(); } } public static void OnToolUsed(ToolUsedEvent toolUsed) { if (!(_pendingWhiteSlotTool != "Lifeblood Syringe") && string.Equals(toolUsed.ToolName, "Lifeblood Syringe", StringComparison.Ordinal)) { int num = Math.Max(1, (int)Math.Round(_pendingWhiteSlotMultiplier)); int num2 = Math.Max(0, num - 1); if (num2 > 0) { AddExtraBlueHealth?.Invoke(num2); } ClearPendingWhiteSlot(); } } private static void ClearPendingWhiteSlot() { _pendingWhiteSlotTool = null; _pendingWhiteSlotMultiplier = 1.0; } private static void ClearQuickSling(HeroController? hero = null) { bool flag = _quickSlingRemaining > 0 || (Object)(object)_quickSlingTool != (Object)null; _quickSlingRemaining = 0; _quickSlingTool = null; if ((Object)(object)hero == (Object)null || !flag) { return; } try { _queuedAutoThrowTool?.SetValue(hero, false); } catch (Exception ex) { WarnOnce(ex); } } public static bool AddToMaggotCharmTimerPrefix() { return !MaggotImmuneActive(); } public static bool DidMaggotCharmHitPrefix() { return !MaggotImmuneActive(); } public static bool IsMaggotRepairOnHealActive() { if (ToolItemManager.IsToolEquipped("Maggot Charm")) { return EffectsFor("Maggot Charm").MaggotRepairOnHeal; } return false; } public static bool IsMaggotRepairOnKillActive() { Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Maggot Charm")) { return EffectsFor("Maggot Charm").MaggotRepairOnKill; } return false; } public static void ResetMaggotCharmNow() { HeroController instance = HeroController.instance; if ((Object)(object)instance == (Object)null || _resetMaggotCharm == null) { return; } try { _resetMaggotCharm.Invoke(instance, null); } catch (Exception ex) { WarnOnce(ex); } } public static bool DoMossToolHitPrefix(HeroController __instance) { try { PlayerData instance = PlayerData.instance; if (instance == null || instance.health <= 0 || instance.silk >= instance.CurrentSilkMax) { return true; } if (HandleMossTool(__instance, Gameplay.MossCreep1Tool, _moss1Hits, 1)) { return false; } if (HandleMossTool(__instance, Gameplay.MossCreep2Tool, _moss2Hits, 2)) { return false; } } catch (Exception ex) { WarnOnce(ex); } return true; } public static bool HeroTakeDamagePrefix(HeroController __instance, ref int damageAmount, HazardType hazardType, DamagePropertyFlags damagePropertyFlags) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) try { if (HealUninterruptibleActive(__instance)) { return false; } ToolDefinition toolDefinition = ToolCatalog.Find("Lava Charm"); if (toolDefinition != null && ((int)hazardType == 4 || (damagePropertyFlags & 4) != 0)) { int level = GetLevel?.Invoke("Lava Charm") ?? 0; bool inWhiteSlot = IsEquippedInWhiteSlot?.Invoke("Lava Charm") ?? false; if (toolDefinition.ResolveEffects(level, inWhiteSlot).LavaDamageImmune) { damageAmount = 0; } } ToolDefinition toolDefinition2 = ToolCatalog.Find("Weighted Anklet"); if (toolDefinition2 != null) { int level2 = GetLevel?.Invoke("Weighted Anklet") ?? 0; bool inWhiteSlot2 = IsEquippedInWhiteSlot?.Invoke("Weighted Anklet") ?? false; if (toolDefinition2.ResolveEffects(level2, inWhiteSlot2).TwoDamageToOne && damageAmount == 2) { damageAmount = 1; } } } catch (Exception ex) { WarnOnce(ex); } return true; } public static bool CanBeGrabbedPrefix(HeroController __instance, bool ignoreParryState, ref bool __result) { if (HealUninterruptibleActive(__instance)) { __result = false; return false; } return true; } public static bool CanBeBarnacleGrabbedPrefix(HeroController __instance, ref bool __result) { if (HealUninterruptibleActive(__instance)) { __result = false; return false; } return true; } private static bool HealUninterruptibleActive(HeroController hero) { if ((Object)(object)hero == (Object)null || hero.cState == null) { return false; } if (!hero.cState.focusing && !hero.cState.isBinding) { return false; } Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot == null || !isEquippedInWhiteSlot("Bone Necklace")) { return false; } return EffectsFor("Bone Necklace").HealUninterruptible; } public static void UseLavaBellPostfix(HeroController __instance) { try { ToolDefinition toolDefinition = ToolCatalog.Find("Lava Charm"); if (!(toolDefinition == null)) { int level = GetLevel?.Invoke("Lava Charm") ?? 0; bool inWhiteSlot = IsEquippedInWhiteSlot?.Invoke("Lava Charm") ?? false; int lavaCooldownSeconds = toolDefinition.ResolveEffects(level, inWhiteSlot).LavaCooldownSeconds; if (lavaCooldownSeconds > 0) { _lavaCooldown?.SetValue(__instance, (float)lavaCooldownSeconds); } } } catch (Exception ex) { WarnOnce(ex); } } public static bool TakeFrostDamagePrefix() { return !ColdDebuffImmune(); } public static bool AddFrostPrefix() { return !ColdDebuffImmune(); } public static bool SetFrostAmountPrefix() { return !ColdDebuffImmune(); } public static void DamageTagOnHitPrefix(DamageTag __instance) { if ((Object)(object)__instance == (Object)(object)Gameplay.PoisonPouchDamageTag) { _pendingPoisonMultiplier = (GetLevel?.Invoke("Poison Pouch") ?? 0) switch { 2 => 2.0, 3 => 3.0, _ => 1.0, }; } } public static void HealthManagerApplyTagDamagePrefix(ref DamageTagInstance damageTagInstance) { if (_pendingPoisonMultiplier > 1.0) { damageTagInstance.amount = (int)Math.Round((double)damageTagInstance.amount * _pendingPoisonMultiplier); _pendingPoisonMultiplier = 1.0; } } public static void TagDamageTakerAddDamageTagToStackPostfix(TagDamageTaker __instance, DamageTag damageTag, int hitAmountOverride) { if (hitAmountOverride <= 0 || (Object)(object)damageTag != (Object)(object)Gameplay.PoisonPouchDamageTag) { return; } ToolDefinition toolDefinition = ToolCatalog.Find("Poison Pouch"); if (toolDefinition == null) { return; } int level = GetLevel?.Invoke("Poison Pouch") ?? 0; bool inWhiteSlot = IsEquippedInWhiteSlot?.Invoke("Poison Pouch") ?? false; if (!toolDefinition.ResolveEffects(level, inWhiteSlot).PoisonStacking) { return; } try { if (_taggedDamage?.GetValue(__instance) is Dictionary dictionary && dictionary.TryGetValue(damageTag, out var value)) { DamageTagInfo obj = value; obj.HitsLeft += hitAmountOverride; } } catch (Exception ex) { WarnOnce(ex); } } private static bool HandleMossTool(HeroController hero, ToolItem tool, FieldInfo? hitsField, int silk) { if ((Object)(object)tool == (Object)null) { return false; } string name = tool.name; if (!WhiteToolSystem.IsEquippedAnywhere(name)) { return false; } int num = GetLevel?.Invoke(name) ?? 0; bool flag = IsEquippedInWhiteSlot?.Invoke(name) ?? false; ToolEffectSpec toolEffectSpec = ToolCatalog.Find(name)?.ResolveEffects(num, flag) ?? ToolEffectSpec.None; if (num == 0 && !flag) { return false; } int num2 = MossRules.PerHitSpools(toolEffectSpec.MossSpoolsPerHit, silk); if (toolEffectSpec.MossSilkPerWhiteHit > 0) { hero.AddSilk(toolEffectSpec.MossSilkPerWhiteHit, false, (SilkAddSource)1); hitsField?.SetValue(hero, 0); GameCameras.instance.silkSpool.SetMossState(0, 1); ManualLogSource? log = _log; if (log != null) { log.LogDebug((object)($"[Moss][probe] tool={name} level={num} white={flag} " + $"branch=white-direct silk={toolEffectSpec.MossSilkPerWhiteHit}")); } return true; } int num3 = (int)(hitsField?.GetValue(hero) ?? ((object)0)) + 1; if (num3 >= 2) { hitsField?.SetValue(hero, 0); hero.AddSilk(num2, false, (SilkAddSource)1); ManualLogSource? log2 = _log; if (log2 != null) { log2.LogDebug((object)($"[Moss][probe] tool={name} level={num} white={flag} " + $"branch=convert silk={num2}")); } } else { hitsField?.SetValue(hero, num3); GameCameras.instance.silkSpool.SetMossState(1, num2); ManualLogSource? log3 = _log; if (log3 != null) { log3.LogDebug((object)($"[Moss][probe] tool={name} level={num} white={flag} " + $"branch=spools count={num2}")); } } return true; } private static bool ColdDebuffImmune() { ToolDefinition toolDefinition = ToolCatalog.Find("Lava Charm"); if (toolDefinition == null) { return false; } int level = GetLevel?.Invoke("Lava Charm") ?? 0; bool inWhiteSlot = IsEquippedInWhiteSlot?.Invoke("Lava Charm") ?? false; return toolDefinition.ResolveEffects(level, inWhiteSlot).ColdDebuffImmune; } public static ToolEffectSpec EffectsFor(string toolName) { ToolDefinition toolDefinition = ToolCatalog.Find(toolName); if (toolDefinition == null) { return ToolEffectSpec.None; } int level = GetLevel?.Invoke(toolName) ?? 0; bool inWhiteSlot = IsEquippedInWhiteSlot?.Invoke(toolName) ?? false; return toolDefinition.ResolveEffects(level, inWhiteSlot); } private static bool IsWitchCrest() { return string.Equals(HeroController.instance?.playerData?.CurrentCrestID, "Witch", StringComparison.OrdinalIgnoreCase); } private static bool IsBrollyHit(HitInstance hit) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_0036: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)hit.RepresentingTool != (Object)null && string.Equals(hit.RepresentingTool.name, "Brolly Spike", StringComparison.Ordinal)) { return true; } if ((Object)(object)hit.Source != (Object)null) { return ((Object)hit.Source).name.IndexOf("Brolly", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private static bool IsDazzleHit(HitInstance hit) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)hit.RepresentingTool != (Object)null && (string.Equals(hit.RepresentingTool.name, "Dazzle Bind", StringComparison.Ordinal) || string.Equals(hit.RepresentingTool.name, "Dazzle Bind Upgraded", StringComparison.Ordinal))) { return true; } if ((Object)(object)hit.Source != (Object)null) { return ((Object)hit.Source).name.IndexOf("dazzle", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } public static bool IsBellBindSource(string? toolName, string? sourceName) { if (!string.IsNullOrEmpty(toolName) && string.Equals(toolName, "Bell Bind", StringComparison.Ordinal)) { return true; } if (!string.IsNullOrEmpty(sourceName)) { if (sourceName.IndexOf("bell", StringComparison.OrdinalIgnoreCase) < 0) { return sourceName.IndexOf("shield", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } return false; } private static bool IsBellBindHit(HitInstance hit) { //IL_0000: 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) ToolItem representingTool = hit.RepresentingTool; string toolName = ((representingTool != null) ? representingTool.name : null); GameObject source = hit.Source; return IsBellBindSource(toolName, (source != null) ? ((Object)source).name : null); } public static void BellBindHitPrefix(ref HitInstance hitInstance) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (IsBellBindHit(hitInstance) && ToolItemManager.IsToolEquipped("Bell Bind") && ShouldApplyEffectDamagePrefix((Object)(object)hitInstance.RepresentingTool != (Object)null)) { ToolEffectSpec toolEffectSpec = EffectsFor("Bell Bind"); if (!(toolEffectSpec.DamageMultiplier <= 1.0)) { hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * toolEffectSpec.DamageMultiplier); } } } private static ToolDefinition? FindDazzleDefinition() { string text = DazzleWhiteRules.SelectDefinitionName(WhiteToolSystem.IsEquippedAnywhere("Dazzle Bind Upgraded"), WhiteToolSystem.IsEquippedAnywhere("Dazzle Bind")); if (text != null) { return ToolCatalog.Find(text); } return null; } private static GameObject? ReadDazzleFlashPrefab(PlayMakerFSM? bindFsm, bool isUpgraded) { if ((Object)(object)bindFsm == (Object)null) { return null; } FsmState state = FsmUtil.GetState(bindFsm, "Dazzle?"); if (state == null) { return null; } string text = (isUpgraded ? "Dazzle Flash Upgraded" : "Dazzle Flash"); FsmStateAction[] actions = state.Actions; foreach (FsmStateAction obj in actions) { SetGameObject val = (SetGameObject)(object)((obj is SetGameObject) ? obj : null); if (val != null && val.variable != null && ((NamedVariable)val.variable).Name == text && val.gameObject != null) { return val.gameObject.Value; } } return null; } private static bool MaggotImmuneActive() { if (ToolItemManager.IsToolEquipped("Maggot Charm")) { return EffectsFor("Maggot Charm").MaggotImmune; } return false; } private static void ApplyNailChargeFactor(HeroController hero, ref float result, float baseValue) { if (ToolItemManager.IsToolEquipped("Pinstress Tool")) { ToolEffectSpec toolEffectSpec = EffectsFor("Pinstress Tool"); if (!(toolEffectSpec.NailChargeTimeFactor <= 0.0) && !(toolEffectSpec.NailChargeTimeFactor >= 1.0)) { result = (float)((double)baseValue * toolEffectSpec.NailChargeTimeFactor); } } } private static void SetWispCooldown(HeroWispLantern instance, float seconds) { if (_wispCooldownField == null || _minMaxStartField == null || _minMaxEndField == null) { return; } try { if (!_wispCooldownCache.TryGetValue(instance, out WispCooldownCache value)) { object value2 = _wispCooldownField.GetValue(instance); value = new WispCooldownCache { Min = (float)_minMaxStartField.GetValue(value2), Max = (float)_minMaxEndField.GetValue(value2) }; _wispCooldownCache.Add(instance, value); } object value3 = _wispCooldownField.GetValue(instance); _minMaxStartField.SetValue(value3, seconds); _minMaxEndField.SetValue(value3, seconds); _wispCooldownField.SetValue(instance, value3); } catch (Exception ex) { WarnOnce(ex); } } private static void RestoreWispCooldown(HeroWispLantern instance) { if (_wispCooldownField == null || _minMaxStartField == null || _minMaxEndField == null || !_wispCooldownCache.TryGetValue(instance, out WispCooldownCache value)) { return; } try { object value2 = _wispCooldownField.GetValue(instance); _minMaxStartField.SetValue(value2, value.Min); _minMaxEndField.SetValue(value2, value.Max); _wispCooldownField.SetValue(instance, value2); } catch (Exception ex) { WarnOnce(ex); } } private static void ApplyThiefGeoIncrease(ref float result, Func selector) { if (Gameplay.ThiefCharmTool.Status.IsEquipped && (GetLevel?.Invoke("Thief Charm") ?? 0) >= 2) { double num = selector(EffectsFor("Thief Charm")); if (num > 0.0) { result = (float)num; } } } private static void WarnOnce(Exception ex) { if (!_warned) { _warned = true; ManualLogSource? log = _log; if (log != null) { log.LogWarning((object)("[BlueToolEffects] patch failed: " + ex.Message)); } } } } public static class CogflyAutoReleasePatch { public static Func? IsEnabled; public static CogflySpawner? Spawner; public static void Tick() { Func? isEnabled = IsEnabled; if (isEnabled != null && isEnabled() && Spawner != null) { Spawner.Tick(); } } public static void OnSceneChanged() { Spawner?.OnSceneChanged(); } } public static class FlintBrewStackBridge { public static Func? IsActive; public static FlintBrewStackState FlintState { get; } = new FlintBrewStackState(); public static FlintBrewStackState BrewState { get; } = new FlintBrewStackState(); public static bool IsEnabled => IsActive?.Invoke() ?? false; } public static class FlintBrewStackPatch { private static FieldRef? _imbuementTimeLeftRef; private static FieldRef? _quickeningTimeLeftRef; private static bool _warned; public static void Configure(ManualLogSource log) { _warned = false; _imbuementTimeLeftRef = AccessTools.FieldRefAccess("imbuementTimeLeft"); _quickeningTimeLeftRef = AccessTools.FieldRefAccess("quickeningTimeLeft"); } public static void SetElementPrefix(HeroNailImbuement __instance, ref float __state) { __state = ((_imbuementTimeLeftRef != null) ? _imbuementTimeLeftRef.Invoke(__instance) : 0f); } public static void SetElementPostfix(HeroNailImbuement __instance, NailElements element, float __state) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 if (!FlintBrewStackBridge.IsEnabled) { return; } if ((int)element == 0) { FlintBrewStackBridge.FlintState.Reset(); } else { if ((int)element != 1) { return; } try { float num = FlintBrewStackBridge.FlintState.AddUse(); if (num > 0f && _imbuementTimeLeftRef != null) { _imbuementTimeLeftRef.Invoke(__instance) = __state + num; } } catch (Exception ex) { WarnOnce(ex); } } } public static void ActivateQuickeningPrefix(HeroController __instance, ref float __state) { __state = ((_quickeningTimeLeftRef != null) ? _quickeningTimeLeftRef.Invoke(__instance) : 0f); } public static void ActivateQuickeningPostfix(HeroController __instance, float __state) { if (!FlintBrewStackBridge.IsEnabled) { return; } try { float num = FlintBrewStackBridge.BrewState.AddUse(); if (num > 0f && _quickeningTimeLeftRef != null) { _quickeningTimeLeftRef.Invoke(__instance) = __state + num; } } catch (Exception ex) { WarnOnce(ex); } } public static void StopQuickeningPostfix(HeroController __instance) { if (FlintBrewStackBridge.IsEnabled) { FlintBrewStackBridge.BrewState.Reset(); } } public static void QuickAttackSpeedMultPostfix(HeroControllerConfig __instance, ref float __result) { if (FlintBrewStackBridge.IsEnabled && FlintBrewStackBridge.BrewState.Stacks > 1) { HeroController instance = HeroController.instance; if (!((Object)(object)instance == (Object)null) && instance.Config == __instance && instance.IsUsingQuickening) { __result *= FlintBrewStackBridge.BrewState.Stacks; } } } public static void QuickAttackCooldownTimePostfix(HeroControllerConfig __instance, ref float __result) { if (FlintBrewStackBridge.IsEnabled && FlintBrewStackBridge.BrewState.Stacks > 1) { HeroController instance = HeroController.instance; if (!((Object)(object)instance == (Object)null) && instance.Config == __instance && instance.IsUsingQuickening && __result > 0f) { __result /= FlintBrewStackBridge.BrewState.Stacks; } } } public static void HitPrefix(ref HitInstance hitInstance) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Invalid comparison between Unknown and I4 if (FlintBrewStackBridge.IsEnabled && FlintBrewStackBridge.FlintState.Stacks > 1 && !((Object)(object)hitInstance.NailImbuement == (Object)null)) { HeroController instance = HeroController.instance; if (!((Object)(object)((instance != null) ? instance.NailImbuement : null) == (Object)null) && (int)instance.NailImbuement.CurrentElement == 1 && hitInstance.NailImbuement == instance.NailImbuement.CurrentImbuement) { hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * (double)FlintBrewStackBridge.FlintState.Stacks); } } } private static void WarnOnce(Exception ex) { if (!_warned) { _warned = true; Debug.LogWarning((object)("[FlintBrewStack] patch failed: " + ex.Message)); } } } public static class FracturedMaskBreakPatch { public static void Prefix(PlayerData __instance, ref int __state) { __state = ReadAmountLeft(); } public static void Postfix(PlayerData __instance, int __state) { //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_005f: 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) if (__state <= 0 || ReadAmountLeft() != 0) { return; } Func isEquipped = FracturedMaskBridge.IsEquipped; if (isEquipped == null || !isEquipped()) { return; } Func tryRepair = FracturedMaskBridge.TryRepair; if (tryRepair == null || !tryRepair()) { return; } ToolItem fracturedMaskTool = Gameplay.FracturedMaskTool; if (!((Object)(object)fracturedMaskTool == (Object)null)) { Data savedData = fracturedMaskTool.SavedData; savedData.AmountLeft = ToolItemManager.GetToolStorageAmount(fracturedMaskTool); if (savedData.AmountLeft <= 0) { savedData.AmountLeft = 1; } fracturedMaskTool.SavedData = savedData; EventRegister.SendEvent(EventRegisterEvents.HealthUpdate, (GameObject)null); } } private static int ReadAmountLeft() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) try { ToolItem fracturedMaskTool = Gameplay.FracturedMaskTool; return ((Object)(object)fracturedMaskTool != (Object)null) ? fracturedMaskTool.SavedData.AmountLeft : 0; } catch (Exception ex) { Debug.LogWarning((object)("[FracturedMask] AmountLeft read failed: " + ex.Message)); return -1; } } } public static class MagnetiteDiceMagnetPatch { private sealed class MagnetDelayCache { public bool Stored; public float StartDelayMin; public float StartDelayMax; public float AttractDelayMin; public float AttractDelayMax; public float StartMoveDuration; } public static Func? GetLevel; public static Func? IsEquippedInWhiteSlot; private static ManualLogSource? _log; private static bool _warned; private static FieldInfo? _startDelayField; private static FieldInfo? _attractDelayField; private static FieldInfo? _startMoveDurationField; private static FieldInfo? _minMaxStartField; private static FieldInfo? _minMaxEndField; private static readonly ConditionalWeakTable _cache = new ConditionalWeakTable(); public static void Configure(ManualLogSource log) { _log = log; _warned = false; _startDelayField = AccessTools.Field(typeof(CurrencyObjectBase), "magnetStartDelay"); _attractDelayField = AccessTools.Field(typeof(CurrencyObjectBase), "magnetAttractDelay"); _startMoveDurationField = AccessTools.Field(typeof(CurrencyObjectBase), "magnetStartMoveDuration"); Type type = Type.GetType("TeamCherry.SharedUtils.MinMaxFloat, TeamCherry.SharedUtils"); if (type != null) { _minMaxStartField = AccessTools.Field(type, "Start"); _minMaxEndField = AccessTools.Field(type, "End"); } } public static void OnToolEquipsUpdatedPrefix(CurrencyObjectBase __instance) { try { if ((Object)(object)__instance == (Object)null) { return; } int num = GetLevel?.Invoke("Magnetite Dice") ?? 0; bool num2 = num >= 2 && Gameplay.LuckyDiceTool.Status.IsEquipped; ToolEffectSpec toolEffectSpec = ToolCatalog.Find("Magnetite Dice")?.ResolveEffects(num, inWhiteSlot: false) ?? ToolEffectSpec.None; MagnetDelayCache orCreateValue = _cache.GetOrCreateValue(__instance); if (!orCreateValue.Stored) { orCreateValue.Stored = true; orCreateValue.StartDelayMin = ReadMin(_startDelayField, __instance); orCreateValue.StartDelayMax = ReadMax(_startDelayField, __instance); orCreateValue.AttractDelayMin = ReadMin(_attractDelayField, __instance); orCreateValue.AttractDelayMax = ReadMax(_attractDelayField, __instance); orCreateValue.StartMoveDuration = ((_startMoveDurationField != null) ? ((float)(_startMoveDurationField.GetValue(__instance) ?? ((object)0f))) : 0f); } if (!num2) { Restore(__instance, orCreateValue); } else if (toolEffectSpec.LuckyDiceMagnetInstant) { WriteMinMax(_startDelayField, __instance, 0f, 0f); WriteMinMax(_attractDelayField, __instance, 0f, 0f); if (_startMoveDurationField != null) { _startMoveDurationField.SetValue(__instance, 0f); } } else { double luckyDiceMagnetDelayFactor = toolEffectSpec.LuckyDiceMagnetDelayFactor; if (luckyDiceMagnetDelayFactor > 0.0 && luckyDiceMagnetDelayFactor < 1.0) { WriteMinMax(_startDelayField, __instance, orCreateValue.StartDelayMin * (float)luckyDiceMagnetDelayFactor, orCreateValue.StartDelayMax * (float)luckyDiceMagnetDelayFactor); WriteMinMax(_attractDelayField, __instance, orCreateValue.AttractDelayMin * (float)luckyDiceMagnetDelayFactor, orCreateValue.AttractDelayMax * (float)luckyDiceMagnetDelayFactor); } } } catch (Exception ex) { WarnOnce(ex); } } public static void MagnetToolIsEquippedPostfix(CurrencyObjectBase __instance, ref bool __result) { if (!__result && __instance is ShellShard) { Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Rosary Magnet")) { __result = true; } } } private static void Restore(CurrencyObjectBase instance, MagnetDelayCache cache) { WriteMinMax(_startDelayField, instance, cache.StartDelayMin, cache.StartDelayMax); WriteMinMax(_attractDelayField, instance, cache.AttractDelayMin, cache.AttractDelayMax); if (_startMoveDurationField != null) { _startMoveDurationField.SetValue(instance, cache.StartMoveDuration); } } private static float ReadMin(FieldInfo? field, CurrencyObjectBase instance) { if (field == null || _minMaxStartField == null) { return 0f; } object value = field.GetValue(instance); if (value != null) { return (float)(_minMaxStartField.GetValue(value) ?? ((object)0f)); } return 0f; } private static float ReadMax(FieldInfo? field, CurrencyObjectBase instance) { if (field == null || _minMaxEndField == null) { return 0f; } object value = field.GetValue(instance); if (value != null) { return (float)(_minMaxEndField.GetValue(value) ?? ((object)0f)); } return 0f; } private static void WriteMinMax(FieldInfo? field, CurrencyObjectBase instance, float min, float max) { if (!(field == null) && !(_minMaxStartField == null) && !(_minMaxEndField == null)) { object value = field.GetValue(instance); if (value != null) { _minMaxStartField.SetValue(value, min); _minMaxEndField.SetValue(value, max); } } } private static void WarnOnce(Exception ex) { if (!_warned) { _warned = true; ManualLogSource? log = _log; if (log != null) { log.LogWarning((object)("[MagnetiteDice] magnet patch disabled: " + ex.GetType().Name + ": " + ex.Message)); } } } } public static class MultibindFsmPatch { private sealed class ActionValueCache { public bool Stored; public bool IsInt; public bool IsFloat; public int OriginalInt; public float OriginalFloat; } private sealed class MultibindFsmMarker : MonoBehaviour { } public static Func? GetLevel; public static Func? IsEquippedInWhiteSlot; public static Func? IsEquipped; private static ManualLogSource? _log; private static bool _warned; private static readonly List _patched = new List(); private static readonly ConditionalWeakTable _cache = new ConditionalWeakTable(); public static void Configure(ManualLogSource log) { _log = log; _warned = false; } public static void OnFsmStart(PlayMakerFSM __instance) { if ((Object)(object)__instance == (Object)null || __instance.Fsm == null) { return; } string fsmName = __instance.FsmName; if ((fsmName != "Bind" && fsmName != "Spell Control") || (Object)(object)((Component)__instance).gameObject == (Object)null || !((Object)((Component)__instance).gameObject).name.StartsWith("Hero_Hornet", StringComparison.Ordinal)) { return; } if ((Object)(object)((Component)__instance).GetComponent() != (Object)null) { ApplyValues(__instance); return; } if (FsmUtil.GetState(__instance, "Multi Bind") == null || FsmUtil.GetState(__instance, "Witch Bind") == null) { WarnOnce(new InvalidOperationException(string.Format("Bind FSM states missing: Multi Bind={0}, ", FsmUtil.GetState(__instance, "Multi Bind") != null) + string.Format("Witch Bind={0}", FsmUtil.GetState(__instance, "Witch Bind") != null))); return; } ((Component)__instance).gameObject.AddComponent(); _patched.Add(__instance); ApplyValues(__instance); ManualLogSource? log = _log; if (log != null) { log.LogInfo((object)"[Multibind] Bind FSM hooks installed (Multi Bind / Witch Bind)."); } } public static void RefreshAll() { for (int num = _patched.Count - 1; num >= 0; num--) { PlayMakerFSM val = _patched[num]; if ((Object)(object)val == (Object)null) { _patched.RemoveAt(num); } else { ApplyValues(val); } } } public static void RestoreAll() { foreach (PlayMakerFSM item in _patched) { if (!((Object)(object)item == (Object)null)) { ApplyValues(item, forceInactive: true); } } _patched.Clear(); } public static void RageHealCapPostfix(HeroController __instance, ref int __result) { ApplyHealCap(__instance, ref __result); } public static void WitchHealCapPostfix(HeroController __instance, ref int __result) { ApplyHealCap(__instance, ref __result); } private static void ApplyHealCap(HeroController hero, ref int result) { if (!((Object)(object)hero == (Object)null) && ToolItemManager.IsToolEquipped("Multibind") && GetLevel != null) { MultibindValues multibindValues = MultibindValuesResolver.Resolve(GetLevel("Multibind"), IsEquippedInWhiteSlot?.Invoke("Multibind") ?? false); if (multibindValues.BeastWitchHealCap > result) { result = multibindValues.BeastWitchHealCap; } } } private static void ApplyValues(PlayMakerFSM fsm, bool forceInactive = false) { try { int level = ((!forceInactive && GetLevel != null) ? GetLevel("Multibind") : 0); bool flag = !forceInactive && IsEquippedInWhiteSlot != null && IsEquippedInWhiteSlot("Multibind"); bool equipped = !forceInactive && IsEquipped != null && IsEquipped("Multibind"); bool active = ToolLevelGate.ShouldApply(level, flag, equipped); MultibindValues multibindValues = MultibindValuesResolver.Resolve(level, flag); FsmState state = FsmUtil.GetState(fsm, "Multi Bind"); FsmStateAction[] actions; if (state != null) { actions = state.Actions; foreach (FsmStateAction val in actions) { SetIntValue val2 = (SetIntValue)(object)((val is SetIntValue) ? val : null); if (val2 != null) { if (val2.intVariable != null && ((NamedVariable)val2.intVariable).Name == "Heal Amount") { ApplyInt((FsmStateAction)(object)val2, active, multibindValues.HealPerSegment); } else if (val2.intVariable != null && ((NamedVariable)val2.intVariable).Name == "Bind Amount") { ApplyInt((FsmStateAction)(object)val2, active, multibindValues.SegmentCount); } } else { SetFloatValue val3 = (SetFloatValue)(object)((val is SetFloatValue) ? val : null); if (val3 != null && val3.floatVariable != null && ((NamedVariable)val3.floatVariable).Name == "Bind Time") { ApplyFloat((FsmStateAction)(object)val3, active, multibindValues.SegmentSeconds); } } } } FsmState state2 = FsmUtil.GetState(fsm, "Witch Bind"); if (state2 == null) { return; } actions = state2.Actions; foreach (FsmStateAction obj in actions) { ConvertBoolToInt val4 = (ConvertBoolToInt)(object)((obj is ConvertBoolToInt) ? obj : null); if (val4 != null && val4.boolVariable != null && ((NamedVariable)val4.boolVariable).Name == "Is Multibind Equipped") { ApplyInt((FsmStateAction)(object)val4, active, multibindValues.HealPerSegment); } } } catch (Exception ex) { WarnOnce(ex); } } private static void ApplyInt(FsmStateAction action, bool active, int newValue) { ActionValueCache orCreateValue = _cache.GetOrCreateValue(action); orCreateValue.IsInt = true; if (!orCreateValue.Stored) { orCreateValue.Stored = true; orCreateValue.OriginalInt = ReadInt(action); } WriteInt(action, active ? newValue : orCreateValue.OriginalInt); } private static void ApplyFloat(FsmStateAction action, bool active, float newValue) { ActionValueCache orCreateValue = _cache.GetOrCreateValue(action); orCreateValue.IsFloat = true; if (!orCreateValue.Stored) { orCreateValue.Stored = true; orCreateValue.OriginalFloat = ReadFloat(action); } WriteFloat(action, active ? newValue : orCreateValue.OriginalFloat); } private static int ReadInt(FsmStateAction action) { SetIntValue val = (SetIntValue)(object)((action is SetIntValue) ? action : null); if (val != null && val.intValue != null) { return val.intValue.Value; } ConvertBoolToInt val2 = (ConvertBoolToInt)(object)((action is ConvertBoolToInt) ? action : null); if (val2 != null && val2.trueValue != null) { return val2.trueValue.Value; } return 0; } private static void WriteInt(FsmStateAction action, int value) { SetIntValue val = (SetIntValue)(object)((action is SetIntValue) ? action : null); if (val != null && val.intValue != null) { val.intValue.Value = value; } ConvertBoolToInt val2 = (ConvertBoolToInt)(object)((action is ConvertBoolToInt) ? action : null); if (val2 != null && val2.trueValue != null) { val2.trueValue.Value = value; } } private static float ReadFloat(FsmStateAction action) { SetFloatValue val = (SetFloatValue)(object)((action is SetFloatValue) ? action : null); if (val == null || val.floatValue == null) { return 0f; } return val.floatValue.Value; } private static void WriteFloat(FsmStateAction action, float value) { SetFloatValue val = (SetFloatValue)(object)((action is SetFloatValue) ? action : null); if (val != null && val.floatValue != null) { val.floatValue.Value = value; } } private static void WarnOnce(Exception ex) { if (!_warned) { _warned = true; ManualLogSource? log = _log; if (log != null) { log.LogWarning((object)("[Multibind] FSM hook disabled: " + ex.GetType().Name + ": " + ex.Message)); } } } } public static class QuickbindFsmPatch { private sealed class FloatCache { public bool Stored; public float Original; } private sealed class QuickbindFsmMarker : MonoBehaviour { } public static Func? GetLevel; public static Func? IsEquippedInWhiteSlot; public static Func? IsEquipped; private static ManualLogSource? _log; private static bool _warned; private static readonly List _patched = new List(); private static readonly ConditionalWeakTable _cache = new ConditionalWeakTable(); public static void Configure(ManualLogSource log) { _log = log; _warned = false; } public static void OnFsmStart(PlayMakerFSM __instance) { if ((Object)(object)__instance == (Object)null || __instance.Fsm == null) { return; } string fsmName = __instance.FsmName; if ((fsmName != "Bind" && fsmName != "Spell Control") || (Object)(object)((Component)__instance).gameObject == (Object)null || !((Object)((Component)__instance).gameObject).name.StartsWith("Hero_Hornet", StringComparison.Ordinal)) { return; } if ((Object)(object)((Component)__instance).GetComponent() != (Object)null) { ApplyValues(__instance); return; } if (FsmUtil.GetState(__instance, "Quick Bind?") == null) { WarnOnce(new InvalidOperationException("Bind FSM state 'Quick Bind?' missing.")); return; } ((Component)__instance).gameObject.AddComponent(); _patched.Add(__instance); ApplyValues(__instance); ManualLogSource? log = _log; if (log != null) { log.LogInfo((object)"[Quickbind] Bind FSM hook installed (Quick Bind? multiply)."); } } public static void RefreshAll() { for (int num = _patched.Count - 1; num >= 0; num--) { PlayMakerFSM val = _patched[num]; if ((Object)(object)val == (Object)null) { _patched.RemoveAt(num); } else { ApplyValues(val); } } } public static void RestoreAll() { foreach (PlayMakerFSM item in _patched) { if (!((Object)(object)item == (Object)null)) { ApplyValues(item, forceInactive: true); } } _patched.Clear(); } private static void ApplyValues(PlayMakerFSM fsm, bool forceInactive = false) { try { int level = ((!forceInactive && GetLevel != null) ? GetLevel("Quickbind") : 0); bool flag = !forceInactive && IsEquippedInWhiteSlot != null && IsEquippedInWhiteSlot("Quickbind"); bool equipped = !forceInactive && IsEquipped != null && IsEquipped("Quickbind"); bool flag2 = ToolLevelGate.ShouldApply(level, flag, equipped); QuickbindValues quickbindValues = QuickbindValuesResolver.Resolve(level, flag); FsmState state = FsmUtil.GetState(fsm, "Quick Bind?"); if (state == null) { return; } FsmStateAction[] actions = state.Actions; foreach (FsmStateAction obj in actions) { FloatMultiply val = (FloatMultiply)(object)((obj is FloatMultiply) ? obj : null); if (val != null && val.floatVariable != null && ((NamedVariable)val.floatVariable).Name == "Bind Time") { FloatCache orCreateValue = _cache.GetOrCreateValue((FsmStateAction)(object)val); if (!orCreateValue.Stored) { orCreateValue.Stored = true; orCreateValue.Original = ((val.multiplyBy != null) ? val.multiplyBy.Value : 0.6f); } if (val.multiplyBy != null) { val.multiplyBy.Value = (flag2 ? ((float)quickbindValues.DurationFactor) : orCreateValue.Original); } } } } catch (Exception ex) { WarnOnce(ex); } } private static void WarnOnce(Exception ex) { if (!_warned) { _warned = true; ManualLogSource? log = _log; if (log != null) { log.LogWarning((object)("[Quickbind] FSM hook disabled: " + ex.GetType().Name + ": " + ex.Message)); } } } } public static class ReserveBindFreeBindPatch { public static void Prefix(ToolItem __instance, ref Data __state) { //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) __state = __instance.SavedData; } public static void Postfix(ToolItem __instance, Data value, Data __state) { //IL_0000: 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) if (__state.AmountLeft <= 0 || value.AmountLeft != 0 || !string.Equals(__instance.name, "Reserve Bind", StringComparison.Ordinal)) { return; } Func? isEquipped = ReserveBindBridge.IsEquipped; if (isEquipped != null && isEquipped()) { Func? tryRestore = ReserveBindBridge.TryRestore; if (tryRestore != null && tryRestore()) { __instance.CollectFree(1); } } } } public static class ScuttlebraceAirDashPatch { public static Func? IsEquippedInWhiteSlot; private static FieldRef? _airDashedRef; private static int _airDashCount; private static bool _warned; public static void Configure(ManualLogSource log) { _warned = false; _airDashedRef = AccessTools.FieldRefAccess("airDashed"); _airDashCount = 0; } public static void CanDashPrefix(HeroController __instance, ref bool __state) { __state = ReadAirDashed(__instance); if (ShouldOverride(__instance)) { SetAirDashed(__instance, value: false); } } public static void CanDashPostfix(HeroController __instance, bool __state) { if (__state != ReadAirDashed(__instance)) { SetAirDashed(__instance, __state); } } public static void HeroDashPostfix(HeroController __instance) { if (!((Object)(object)__instance == (Object)null) && __instance.cState != null) { Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot != null && isEquippedInWhiteSlot("Scuttlebrace") && !__instance.cState.onGround && !__instance.cState.wallSliding) { _airDashCount++; } } } public static void ResetAirMovesPostfix(HeroController __instance) { _airDashCount = 0; } private static bool ShouldOverride(HeroController hero) { if ((Object)(object)hero == (Object)null || hero.cState == null) { return false; } Func? isEquippedInWhiteSlot = IsEquippedInWhiteSlot; if (isEquippedInWhiteSlot == null || !isEquippedInWhiteSlot("Scuttlebrace")) { return false; } bool inAir = !hero.cState.onGround && !hero.cState.wallSliding; return ScuttlebraceAirDashRules.ShouldAllowSecondAirDash(equipped: true, inAir, ReadAirDashed(hero), _airDashCount); } private static bool ReadAirDashed(HeroController hero) { if (_airDashedRef != null) { return _airDashedRef.Invoke(hero); } return false; } private static void SetAirDashed(HeroController hero, bool value) { if (_airDashedRef != null) { _airDashedRef.Invoke(hero) = value; } } private static void WarnOnce(Exception ex) { if (!_warned) { _warned = true; Debug.LogWarning((object)("[ScuttlebraceAirDash] patch failed: " + ex.Message)); } } } public static class ShellSatchelAutoRepairPatch { public static Func? GetLevel; public static Func? IsEquipped; private static bool _warned; public static void Configure(ManualLogSource log) { _warned = false; } public static bool IsLevelActive(int level) { Func? isEquipped = IsEquipped; if (isEquipped != null && isEquipped()) { return level == 2; } return false; } public static void Prefix(ToolItem __instance, ref Data __state) { //IL_0016: 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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) __state = (Data)(((Object)(object)__instance != (Object)null) ? __instance.SavedData : default(Data)); } public static void Postfix(ToolItem __instance, Data value, Data __state) { //IL_000b: 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_003e: Unknown result type (might be due to invalid IL or missing references) try { if (!((Object)(object)__instance == (Object)null) && __state.AmountLeft > 0 && value.AmountLeft == 0 && IsLevelActive(GetLevel?.Invoke("Shell Satchel") ?? 0) && (int)__instance.Type == 0) { ShellSatchelRepairRunner.Schedule(__instance); } } catch (Exception ex) { if (!_warned) { _warned = true; Debug.LogWarning((object)("[ShellSatchelAutoRepair] patch failed: " + ex.Message)); } } } } public static class ShellSatchelShardCostPatch { public static Func? GetLevel; public static Func? IsEquipped; private static bool _warned; public static void Configure(ManualLogSource log) { _warned = false; } public static bool IsLevelActive(int level) { Func? isEquipped = IsEquipped; if (isEquipped != null && isEquipped()) { return level == 3; } return false; } public static void Prefix(ToolItem __instance, ref Data value) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_0085: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)__instance == (Object)null || !IsLevelActive(GetLevel?.Invoke("Shell Satchel") ?? 0) || (int)__instance.Type != 0) { return; } Data savedData = __instance.SavedData; if (value.AmountLeft >= savedData.AmountLeft) { return; } int toolStorageAmount = ToolItemManager.GetToolStorageAmount(__instance); if (toolStorageAmount <= 0) { return; } float fullRepairCost = (float)Gameplay.ToolReplenishCost * __instance.ReplenishUsageMultiplier; int num = ShellSatchelShardCostRules.PerUseShardCost(toolStorageAmount, fullRepairCost); PlayerData instance = PlayerData.instance; if (instance != null) { value.AmountLeft = savedData.AmountLeft; if (instance.ShellShards >= num) { instance.TakeShards(num); } } } catch (Exception ex) { if (!_warned) { _warned = true; Debug.LogWarning((object)("[ShellSatchelShardCost] patch failed: " + ex.Message)); } } } } public static class SprintmasterFsmPatch { private sealed class SpeedCache { public bool Stored; public float BothFalse; public float OneTrue; public float BothTrue; } private sealed class SprintmasterFsmMarker : MonoBehaviour { } public static Func? GetLevel; public static Func? IsEquipped; private static ManualLogSource? _log; private static bool _warned; private static readonly List _patched = new List(); private static readonly ConditionalWeakTable _cache = new ConditionalWeakTable(); public static void Configure(ManualLogSource log) { _log = log; _warned = false; } public static void OnFsmStart(PlayMakerFSM __instance) { if ((Object)(object)__instance == (Object)null || __instance.Fsm == null) { return; } string fsmName = __instance.FsmName; if ((fsmName != "Sprint" && fsmName != "Init") || (Object)(object)((Component)__instance).gameObject == (Object)null || !((Object)((Component)__instance).gameObject).name.StartsWith("Hero_Hornet", StringComparison.Ordinal)) { return; } if ((Object)(object)((Component)__instance).GetComponent() != (Object)null) { ApplyValues(__instance); } else if (HasSprintmasterActions(__instance)) { ((Component)__instance).gameObject.AddComponent(); _patched.Add(__instance); ApplyValues(__instance); ManualLogSource? log = _log; if (log != null) { log.LogInfo((object)("[Sprintmaster] FSM hook installed (" + fsmName + " speed actions).")); } } } public static void RefreshAll() { for (int num = _patched.Count - 1; num >= 0; num--) { PlayMakerFSM val = _patched[num]; if ((Object)(object)val == (Object)null) { _patched.RemoveAt(num); } else { ApplyValues(val); } } } public static void RestoreAll() { foreach (PlayMakerFSM item in _patched) { if (!((Object)(object)item == (Object)null)) { ApplyValues(item, forceInactive: true); } } _patched.Clear(); } private static bool HasSprintmasterActions(PlayMakerFSM fsm) { FsmState[] fsmStates = fsm.FsmStates; for (int i = 0; i < fsmStates.Length; i++) { FsmStateAction[] actions = fsmStates[i].Actions; foreach (FsmStateAction obj in actions) { ConvertDoubleBoolToFloat val = (ConvertDoubleBoolToFloat)(object)((obj is ConvertDoubleBoolToFloat) ? obj : null); if (val != null && val.boolVariable2 != null && ((NamedVariable)val.boolVariable2).Name == "Sprintmaster Active") { return true; } } } return false; } private static void ApplyValues(PlayMakerFSM fsm, bool forceInactive = false) { try { int level = ((!forceInactive && GetLevel != null) ? GetLevel("Sprintmaster") : 0); bool num = string.Equals(fsm.FsmName, "Sprint", StringComparison.Ordinal); bool equipped = !forceInactive && IsEquipped != null && IsEquipped("Sprintmaster"); bool flag = ToolLevelGate.ShouldApply(level, white: false, equipped); ToolEffectSpec toolEffectSpec = ToolCatalog.Find("Sprintmaster")?.ResolveEffects(level, inWhiteSlot: false) ?? ToolEffectSpec.None; double num2 = (num ? toolEffectSpec.SprintmasterSpeedMultiplier : toolEffectSpec.SprintmasterScuttleSpeedMultiplier); int level2 = ((!forceInactive && GetLevel != null) ? GetLevel("Scuttlebrace") : 0); bool equipped2 = !forceInactive && IsEquipped != null && IsEquipped("Scuttlebrace"); bool flag2 = ToolLevelGate.ShouldApply(level2, white: false, equipped2); ToolEffectSpec toolEffectSpec2 = ToolCatalog.Find("Scuttlebrace")?.ResolveEffects(level2, inWhiteSlot: false) ?? ToolEffectSpec.None; double num3 = ((!num && flag2) ? toolEffectSpec2.ScuttleSpeedMultiplier : 0.0); FsmState[] fsmStates = fsm.FsmStates; for (int i = 0; i < fsmStates.Length; i++) { FsmStateAction[] actions = fsmStates[i].Actions; foreach (FsmStateAction obj in actions) { ConvertDoubleBoolToFloat val = (ConvertDoubleBoolToFloat)(object)((obj is ConvertDoubleBoolToFloat) ? obj : null); if (val != null && val.boolVariable2 != null && !(((NamedVariable)val.boolVariable2).Name != "Sprintmaster Active") && val.oneTrueValue != null && val.bothFalseValue != null) { SpeedCache orCreateValue = _cache.GetOrCreateValue(val); if (!orCreateValue.Stored) { orCreateValue.Stored = true; orCreateValue.BothFalse = val.bothFalseValue.Value; orCreateValue.OneTrue = val.oneTrueValue.Value; orCreateValue.BothTrue = val.bothTrueValue.Value; } double num4 = ((flag && num2 > 0.0) ? num2 : 1.0) * ((num3 > 0.0) ? num3 : 1.0); val.bothFalseValue.Value = ((num3 > 0.0) ? (orCreateValue.BothFalse * (float)num3) : orCreateValue.BothFalse); if (flag && num2 > 0.0) { val.oneTrueValue.Value = orCreateValue.BothFalse * (float)num4; val.bothTrueValue.Value = orCreateValue.BothFalse * (float)num4; } else if (num3 > 0.0) { val.oneTrueValue.Value = orCreateValue.OneTrue * (float)num3; val.bothTrueValue.Value = orCreateValue.BothTrue * (float)num3; } else { val.oneTrueValue.Value = orCreateValue.OneTrue; val.bothTrueValue.Value = orCreateValue.BothTrue; } } } } } catch (Exception ex) { WarnOnce(ex); } } private static void WarnOnce(Exception ex) { if (!_warned) { _warned = true; ManualLogSource? log = _log; if (log != null) { log.LogWarning((object)("[Sprintmaster] FSM hook disabled: " + ex.GetType().Name + ": " + ex.Message)); } } } } public static class ToolEquipsDiagnosticsPatches { private static ManualLogSource? _log; public static void Configure(ManualLogSource log) { _log = log; } public static void SetCurrentCrestPostfix(InventoryToolCrestList __instance, InventoryToolCrest crest, bool doScroll, bool doSave) { if (_log != null && !((Object)(object)crest == (Object)null)) { ToolCrest crestData = crest.CrestData; object obj = ((crestData != null) ? crestData.name : null); if (obj == null) { GameObject gameObject = ((Component)crest).gameObject; obj = ((gameObject != null) ? ((Object)gameObject).name : null) ?? "unknown"; } string text = (string)obj; ToolEquipsSnapshot.Log(_log, "inventory-set-crest:" + text); } } public static void GetEquippedForSlotsPostfix(InventoryToolCrest __instance) { if (_log != null && !((Object)(object)__instance == (Object)null)) { ToolCrest crestData = __instance.CrestData; object obj = ((crestData != null) ? crestData.name : null); if (obj == null) { GameObject gameObject = ((Component)__instance).gameObject; obj = ((gameObject != null) ? ((Object)gameObject).name : null) ?? "unknown"; } string text = (string)obj; ToolEquipsSnapshot.Log(_log, "inventory-load-slots:" + text); } } } public static class ToolUpgradePatches { public static Func? Resolve; public static Action? ToolUsed; private static ManualLogSource? _log; private static bool _warned; public static void Configure(ManualLogSource log) { _log = log; } public static void HitDamagePrefix(ref HitInstance hitInstance) { ToolItem representingTool = hitInstance.RepresentingTool; if (!((Object)(object)representingTool == (Object)null)) { double num = 1.0; ToolUpgradeModifiers toolUpgradeModifiers = ResolveFor(representingTool); if (toolUpgradeModifiers != null) { num *= toolUpgradeModifiers.DamageMultiplier; } num *= BlueToolEffectPatches.GetDamageMultiplier(representingTool.name); if (!(num <= 1.0)) { hitInstance.DamageDealt = (int)Math.Round((double)hitInstance.DamageDealt * num); } } } public static void GetToolStorageAmountPostfix(ToolItem __instance, ref int __result) { if (!BlueToolEffectPatches.IsCompassAbsoluteStorageActive(__instance)) { ToolUpgradeModifiers toolUpgradeModifiers = ResolveFor(__instance); if (!(toolUpgradeModifiers == null)) { __result = ToolUpgradeService.ApplyAmmoCapacity(__result, toolUpgradeModifiers); } } } public static void ReplenishUsageMultiplierPostfix(ToolItem __instance, ref float __result) { if (!BlueToolEffectPatches.IsShellSatchelWhiteFixedCostActive()) { ToolUpgradeModifiers toolUpgradeModifiers = ResolveFor(__instance); if (!(toolUpgradeModifiers == null)) { __result *= (float)toolUpgradeModifiers.CostMultiplier; } } } public static void UsageCooldownPostfix(ToolItem __instance, ref UsageOptions __result) { ToolUpgradeModifiers toolUpgradeModifiers = ResolveFor(__instance); if (!(toolUpgradeModifiers == null) && !(__result.ThrowCooldown <= 0f)) { __result.ThrowCooldown *= (float)toolUpgradeModifiers.CooldownMultiplier; } } public unsafe static void ReportBoundAttackToolUsedPostfix(AttackToolBinding binding) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) try { ToolItem boundAttackTool = ToolItemManager.GetBoundAttackTool(binding, (ToolEquippedReadSource)0); if ((Object)(object)boundAttackTool != (Object)null) { ToolUsed?.Invoke(boundAttackTool.name, ((object)(*(AttackToolBinding*)(&binding))/*cast due to .constrained prefix*/).ToString()); } } catch (Exception ex) { WarnOnce(ex); } } private static ToolUpgradeModifiers? ResolveFor(ToolItem tool) { if ((Object)(object)tool == (Object)null || Resolve == null) { return null; } try { return Resolve(tool); } catch (Exception ex) { WarnOnce(ex); return null; } } private static void WarnOnce(Exception ex) { if (!_warned) { _warned = true; ManualLogSource? log = _log; if (log != null) { log.LogWarning((object)("[ToolUpgrade] patch resolve failed: " + ex.Message)); } } } } public static class WallclingJumpPatch { public static Func? GetLevel; public static Func? IsEquippedInWhiteSlot; private static FieldRef? _doubleJumpStepsRef; private static double _jumpMultiplier = 1.0; private static bool _warned; public static void Configure(ManualLogSource log) { _warned = false; _doubleJumpStepsRef = AccessTools.FieldRefAccess("doubleJump_steps"); _jumpMultiplier = 1.0; } public static bool IsWallclingEquipped() { if (!ToolItemManager.IsToolEquipped("Wallcling")) { return IsEquippedInWhiteSlot?.Invoke("Wallcling") ?? false; } return true; } public static double GetJumpMultiplier() { if (!IsWallclingEquipped()) { return 1.0; } return WallclingJumpRules.JumpMultiplier(EffectsFor("Wallcling")); } public static void HeroJumpPostfix(HeroController __instance) { _jumpMultiplier = GetJumpMultiplier(); } public static void DoWallJumpPrefix(HeroController __instance) { _jumpMultiplier = 1.0; } public static void DoDoubleJumpPrefix(HeroController __instance) { _jumpMultiplier = GetJumpMultiplier(); } public static void JumpPostfix(HeroController __instance) { if (!(_jumpMultiplier <= 1.0)) { ScaleVerticalVelocity(__instance, _jumpMultiplier); } } public static void DoDoubleJumpPostfix(HeroController __instance) { if (!(_jumpMultiplier <= 1.0)) { ScaleVerticalVelocity(__instance, _jumpMultiplier); } } public static void DoubleJumpPostfix(HeroController __instance) { if (_jumpMultiplier <= 1.0 || _doubleJumpStepsRef == null) { return; } try { if (_doubleJumpStepsRef.Invoke(__instance) > __instance.DOUBLE_JUMP_FALL_STEPS) { ScaleVerticalVelocity(__instance, _jumpMultiplier); } } catch (Exception ex) { WarnOnce(ex); } } private static ToolEffectSpec EffectsFor(string toolName) { return ToolCatalog.Find(toolName)?.ResolveEffects(GetLevel?.Invoke(toolName) ?? 0, IsEquippedInWhiteSlot?.Invoke(toolName) ?? false) ?? ToolEffectSpec.None; } private static void ScaleVerticalVelocity(HeroController hero, double multiplier) { //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_0030: 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_0053: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)hero == (Object)null) && !((Object)(object)hero.Body == (Object)null) && !(multiplier <= 1.0)) { Vector2 linearVelocity = hero.Body.linearVelocity; if (!(linearVelocity.y <= 0f)) { hero.Body.linearVelocity = new Vector2(linearVelocity.x, linearVelocity.y * (float)multiplier); } } } private static void WarnOnce(Exception ex) { if (!_warned) { _warned = true; Debug.LogWarning((object)("[WallclingJump] patch failed: " + ex.Message)); } } } public static class WallclingTripleJumpPatch { public static Func? IsEquippedInWhiteSlot; private static FieldInfo? _jumpedStepsField; private static FieldInfo? _doubleJumpStepsField; private static FieldInfo? _doubleJumpedField; private static FieldInfo? _onDoubleJumpedField; private static MethodInfo? _jumpMethod; private static bool _tripleJumpConsumed; private static bool _warned; public static void Configure(ManualLogSource log) { _warned = false; _jumpedStepsField = AccessTools.Field(typeof(HeroController), "jumped_steps"); _doubleJumpStepsField = AccessTools.Field(typeof(HeroController), "doubleJump_steps"); _doubleJumpedField = AccessTools.Field(typeof(HeroController), "doubleJumped"); _onDoubleJumpedField = AccessTools.Field(typeof(HeroController), "OnDoubleJumped"); _jumpMethod = AccessTools.Method(typeof(HeroController), "Jump", Type.EmptyTypes, (Type[])null); } public static bool StartFloatPrefix(HeroController __instance) { if ((Object)(object)__instance == (Object)null) { return true; } bool flag = IsEquippedInWhiteSlot?.Invoke("Wallcling") ?? false; if (!flag) { return true; } bool flag2 = ReadBool(_doubleJumpedField, __instance); if (!flag2) { _tripleJumpConsumed = false; return true; } if (WallclingTripleJumpRules.ShouldPerformTripleJump(flag, flag2, _tripleJumpConsumed)) { _tripleJumpConsumed = true; return !PerformTripleJump(__instance); } return true; } public static void DoDoubleJumpPrefix(HeroController __instance) { _tripleJumpConsumed = false; } private static bool PerformTripleJump(HeroController __instance) { //IL_005e: 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_0083: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) try { if (__instance.cState != null && __instance.cState.inUpdraft) { return false; } if (__instance.cState != null && __instance.cState.jumping) { _jumpMethod?.Invoke(__instance, null); } if ((Object)(object)__instance.doubleJumpEffectPrefab != (Object)null) { ObjectPoolExtensions.Spawn(__instance.doubleJumpEffectPrefab, ((Component)__instance).transform, Vector3.zero); } if ((Object)(object)__instance.Body != (Object)null) { Vector2 linearVelocity = __instance.Body.linearVelocity; if (linearVelocity.y < 0f - __instance.MAX_FALL_VELOCITY_DJUMP) { __instance.Body.linearVelocity = new Vector2(linearVelocity.x, 0f - __instance.MAX_FALL_VELOCITY_DJUMP); } } __instance.ShuttleCockCancel(); __instance.ResetLook(); if (__instance.cState != null) { __instance.cState.jumping = false; __instance.cState.doubleJumping = true; __instance.cState.downSpikeRecovery = false; } __instance.AnimCtrl.AllowDoubleJumpReEntry(); SetInt(_jumpedStepsField, __instance, Math.Max(ReadInt(_jumpedStepsField, __instance), __instance.JUMP_STEPS_MIN)); SetInt(_doubleJumpStepsField, __instance, 0); SetBool(_doubleJumpedField, __instance, value: true); __instance.ResetHardLandingTimer(); (_onDoubleJumpedField?.GetValue(__instance) as Action)?.Invoke(); double jumpMultiplier = WallclingJumpPatch.GetJumpMultiplier(); if (jumpMultiplier > 1.0 && (Object)(object)__instance.Body != (Object)null) { Vector2 linearVelocity2 = __instance.Body.linearVelocity; if (linearVelocity2.y > 0f) { __instance.Body.linearVelocity = new Vector2(linearVelocity2.x, linearVelocity2.y * (float)jumpMultiplier); } } return true; } catch (Exception ex) { WarnOnce(ex); return false; } } private static bool ReadBool(FieldInfo? field, HeroController hero) { if (field != null) { return (bool)(field.GetValue(hero) ?? ((object)false)); } return false; } private static int ReadInt(FieldInfo? field, HeroController hero) { if (!(field != null)) { return 0; } return (int)(field.GetValue(hero) ?? ((object)0)); } private static void SetInt(FieldInfo? field, HeroController hero, int value) { if (field != null) { field.SetValue(hero, value); } } private static void SetBool(FieldInfo? field, HeroController hero, bool value) { if (field != null) { field.SetValue(hero, value); } } private static void WarnOnce(Exception ex) { if (!_warned) { _warned = true; Debug.LogWarning((object)("[WallclingTripleJump] patch failed: " + ex.Message)); } } } public static class WhiteBuffAttackIntervalPatch { public static Func? IsActive { get; set; } public static double IntervalFactor { get; set; } = 0.58; public static void Postfix(ref float __result) { Func? isActive = IsActive; if (isActive != null && isActive() && !(__result <= 0f)) { __result = (float)((double)__result * IntervalFactor); } } } public static class WhiteBuffDamagePatch { public static Func? IsVoidHeartActive { get; set; } public static Func? IsKingsoulActive { get; set; } public static Func? IsWeaversongActive { get; set; } public static double VoidHeartMultiplier { get; set; } = 1.5; public static double KingsoulMultiplier { get; set; } = 1.5; public static double WeaversongMultiplier { get; set; } = 1.5; public static void HitPrefix(ref HitInstance hitInstance) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) double num = WhiteBuffDamageRules.ComputeMultiplier(hitInstance, IsVoidHeartActive?.Invoke() ?? false, VoidHeartMultiplier, IsKingsoulActive?.Invoke() ?? false, KingsoulMultiplier, IsWeaversongActive?.Invoke() ?? false, WeaversongMultiplier); if (!(num <= 1.0)) { hitInstance.DamageDealt = WhiteBuffDamageRules.ScaleDamage(hitInstance.DamageDealt, num); } } } public static class WhiteToolDisplayNamePatch { public static void DisplayNamePostfix(InventoryItemTool __instance, ref string __result) { ToolItem val = ((__instance != null) ? ((InventoryItemToolBase)__instance).ItemData : null); if (!((Object)(object)val == (Object)null)) { string text = WhiteToolDisplayText.ResolveName(val.name, __result); if (text != null) { __result = text; } } } public static void DescriptionPostfix(InventoryItemTool __instance, ref string __result) { ToolItem val = ((__instance != null) ? ((InventoryItemToolBase)__instance).ItemData : null); if (!((Object)(object)val == (Object)null)) { string text = WhiteToolDisplayText.ResolveDescription(val.name, __result); if (text != null) { __result = text; } } } } } namespace CrestsEvolve.Features { public sealed class ToolUpgradeFeature : IDisposable { private readonly ManualLogSource _log; private readonly GameEventHub _events; private readonly IGameApi _game; private readonly ToolUpgradeService _service; private readonly ToolLevelService _levels; private readonly ToolUpgradeBalanceOptions _options; public ToolUpgradeFeature(ManualLogSource log, GameEventHub events, IGameApi game, ToolUpgradeService service, ToolLevelService levels, ToolUpgradeBalanceOptions options) { _log = log; _events = events; _game = game; _service = service; _levels = levels; _options = options; } public void Start() { _events.BenchRested += OnBenchRested; _events.PlayerDied += OnPlayerDied; _events.SceneChanged += OnSceneChanged; _events.CrestChanged += OnCrestChanged; _log.LogInfo((object)$"Tool upgrade feature started (enabled={_options.Enabled})."); } public bool SetLevel(string toolId, int level) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) if (!_options.Enabled || !_service.Enabled) { return false; } int num = Math.Clamp(level, 1, 3); _levels.SetLevel(toolId, num); if (!_service.SetLevel(toolId, num - 1)) { return false; } ToolUpgradeModifiers toolUpgradeModifiers = ResolveFor(toolId); _log.LogInfo((object)($"Tool upgrade changed: tool={toolId}, color={toolUpgradeModifiers.Color}, level={num}, " + $"damage=×{toolUpgradeModifiers.DamageMultiplier:F2}, ammo=×{toolUpgradeModifiers.AmmoMultiplier:F2}, " + $"cost=×{toolUpgradeModifiers.CostMultiplier:F2}, cooldown=×{toolUpgradeModifiers.CooldownMultiplier:F2}")); return true; } public ToolUpgradeModifiers ResolveFor(string toolId) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) ToolColorKind color = default(ToolColorKind); if (_game.TryGetToolColor(toolId, ref color)) { return _service.Resolve(toolId, color); } _log.LogWarning((object)("Tool color unresolved for '" + toolId + "'; returning identity modifiers.")); return ToolUpgradeModifiers.Identity(toolId, (ToolColorKind)3); } private void OnBenchRested() { Reset((ResetReason)1, _options.ResetOnBench); } private void OnPlayerDied() { Reset((ResetReason)3, _options.ResetOnDeath); } private void OnSceneChanged(string scene) { Reset((ResetReason)5, _options.ResetOnSceneChange); } private void OnCrestChanged(CrestChangedEvent e) { Reset((ResetReason)0, _options.ResetOnCrestSwitch); } private void Reset(ResetReason reason, bool allowed) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (allowed && _service.Enabled) { int num = _service.ResetLevels(reason); int num2 = _levels.ResetLevels(); if (num > 0 || num2 > 0) { _log.LogInfo((object)$"Tool upgrade levels reset ({num} upgrade / {num2} hud) on {reason}."); } } } public void Dispose() { _events.BenchRested -= OnBenchRested; _events.PlayerDied -= OnPlayerDied; _events.SceneChanged -= OnSceneChanged; _events.CrestChanged -= OnCrestChanged; } } } namespace CrestsEvolve.Features.Tools { public static class BlueTools { public static readonly IReadOnlyList All = new ToolDefinition[23] { DazzleBindTool.Definition, DazzleBindUpgradedTool.Definition, MosscreepTool1.Definition, MosscreepTool2.Definition, FleaCharmTool.Definition, FracturedMaskTool.Definition, QuickbindTool.Definition, LongneedleTool.Definition, LavaCharmTool.Definition, RevengeCrystalTool.Definition, MultibindTool.Definition, PinstressTool.Definition, PoisonPouchTool.Definition, QuickSlingTool.Definition, ReserveBindTool.Definition, BrollySpikeTool.Definition, ThiefClawTool.Definition, SpoolExtenderTool.Definition, ZapImbuementTool.Definition, BellBindTool.Definition, WhiteRingTool.Definition, WispLanternTool.Definition, MaggotCharmTool.Definition }; } public static class CogflyAutoReleaseRules { public static bool ShouldRelease(int activeCount, int capacity) { if (capacity > 0) { return activeCount < capacity; } return false; } } public sealed class DiceToolState { public const string ToolName = "Magnetite Dice"; private readonly StatusIconLedger _ledger; private readonly Func _isWhiteMode; private readonly Func _isDiceEquipped; private readonly Func _isIoniaEquipped; private readonly Func _isWandererCrest; private readonly Func _blockChance; private readonly Func _critChance; private readonly Func _effectiveCritChance; public DiceToolState(StatusIconLedger ledger, Func isWhiteMode, Func isDiceEquipped, Func isIoniaEquipped, Func isWandererCrest, Func blockChance, Func critChance, Func effectiveCritChance) { _ledger = ledger; _isWhiteMode = isWhiteMode; _isDiceEquipped = isDiceEquipped; _isIoniaEquipped = isIoniaEquipped; _isWandererCrest = isWandererCrest; _blockChance = blockChance; _critChance = critChance; _effectiveCritChance = effectiveCritChance; } public void Tick() { string text = ToolCatalog.IconKey("Magnetite Dice"); if (_isIoniaEquipped()) { int num = (_isWandererCrest() ? Math.Min(12, (int)Math.Floor(Math.Max(0f, _effectiveCritChance()) * 100f)) : 0); _ledger.SetMax(text, "tool-equip", 12); _ledger.SetVisible(text, "tool-equip", true); _ledger.Set(text, "tool-equip", num); _ledger.SetColorOverride(text, "tool-equip", "#FFFFFF"); } else { bool flag = _isWhiteMode(); int num2 = (flag ? 12 : 8); int num3 = (flag ? Math.Min(num2, (int)Math.Floor(Math.Max(0f, _critChance()) / 1f)) : Math.Min(num2, (int)Math.Floor(Math.Max(0f, _blockChance()) / 5f))); bool flag2 = _isDiceEquipped(); _ledger.SetMax(text, "tool-equip", num2); _ledger.SetVisible(text, "tool-equip", flag2); _ledger.Set(text, "tool-equip", flag2 ? num3 : 0); _ledger.SetColorOverride(text, "tool-equip", (flag2 && flag) ? "#FFFFFF" : null); } } } public sealed class FlintBrewStackState { public const int MaxStacks = 3; public const float BonusSecondsPerUseAtCap = 5f; public int Stacks { get; private set; } public float BonusSeconds { get; private set; } public event Action? Changed; public float AddUse() { if (Stacks < 3) { Stacks++; this.Changed?.Invoke(); return 0f; } BonusSeconds += 5f; this.Changed?.Invoke(); return 5f; } public void Reset() { Stacks = 0; BonusSeconds = 0f; this.Changed?.Invoke(); } } public sealed record MultibindValues(int SegmentCount, int HealPerSegment, float SegmentSeconds, int BeastWitchHealCap); public static class MultibindValuesResolver { public static MultibindValues Resolve(int level, bool inWhiteSlot) { ToolEffectSpec toolEffectSpec = ToolCatalog.Find("Multibind")?.ResolveEffects(level, inWhiteSlot) ?? ToolEffectSpec.None; return new MultibindValues((toolEffectSpec.MultibindSegmentCount > 0) ? toolEffectSpec.MultibindSegmentCount : 2, (toolEffectSpec.MultibindWhiteHealPerSegment > 0) ? toolEffectSpec.MultibindWhiteHealPerSegment : ((toolEffectSpec.MultibindHealPerSegment > 0) ? toolEffectSpec.MultibindHealPerSegment : 2), (toolEffectSpec.MultibindSegmentSeconds > 0f) ? toolEffectSpec.MultibindSegmentSeconds : 0.8f, (toolEffectSpec.MultibindBeastWitchHealCap > 0) ? toolEffectSpec.MultibindBeastWitchHealCap : 4); } } public sealed record QuickbindValues(double DurationFactor); public static class QuickbindValuesResolver { public static QuickbindValues Resolve(int level, bool inWhiteSlot) { ToolEffectSpec toolEffectSpec = ToolCatalog.Find("Quickbind")?.ResolveEffects(level, inWhiteSlot) ?? ToolEffectSpec.None; double num = ((toolEffectSpec.QuickBindDurationFactor > 0.0) ? toolEffectSpec.QuickBindDurationFactor : 0.6); if (toolEffectSpec.QuickBindWhiteExtra) { num *= 0.6; } return new QuickbindValues((num < 0.05) ? 0.05 : num); } } public static class QuickSlingWhiteSlotRules { public const int BaseThrowCount = 2; public const int DefaultSyringeBlueHealth = 2; public static bool IsWhiteSlotModifiedTool(string toolName) { if (!string.Equals(toolName, "Flintstone", StringComparison.Ordinal) && !string.Equals(toolName, "Flea Brew", StringComparison.Ordinal)) { return string.Equals(toolName, "Lifeblood Syringe", StringComparison.Ordinal); } return true; } public static bool ShouldApplyWhiteSlotModifier(ToolEffectSpec quickSlingEffects, bool quickSlingInWhiteSlot, string toolName) { if (quickSlingEffects != null && quickSlingEffects.QuickSlingWhiteSlotModifier && quickSlingInWhiteSlot) { return IsWhiteSlotModifiedTool(toolName); } return false; } public static double DurationMultiplier(ToolEffectSpec quickSlingEffects) { if (quickSlingEffects == null) { return 1.0; } if (quickSlingEffects.QuickSlingDurationMultiplier > 0.0) { return quickSlingEffects.QuickSlingDurationMultiplier; } if (quickSlingEffects.QuickSlingThrowCount > 0) { return quickSlingEffects.QuickSlingThrowCount; } return 2.0; } public static int SyringeBlueHealth(ToolEffectSpec quickSlingEffects) { if (!(quickSlingEffects != null) || quickSlingEffects.QuickSlingSyringeBlueHealth <= 0) { return (int)Math.Round(DurationMultiplier(quickSlingEffects ?? ToolEffectSpec.None)); } return quickSlingEffects.QuickSlingSyringeBlueHealth; } public static bool ShouldStartThrowChain(bool isWhiteSlotModifiedTool, int throwCount) { if (!isWhiteSlotModifiedTool) { return throwCount > 2; } return false; } } public static class ScuttlebraceAirDashRules { public static bool ShouldAllowSecondAirDash(bool equipped, bool inAir, bool alreadyAirDashed, int airDashCount) { if (equipped && inAir && alreadyAirDashed) { return airDashCount < 2; } return false; } } public static class ShellSatchelShardCostRules { public static int PerUseShardCost(int capacity, float fullRepairCost) { if (capacity <= 0) { return 1; } float num = fullRepairCost / (float)capacity; return Math.Max(1, (int)Math.Ceiling(num)); } } public static class ToolCatalog { public static readonly IReadOnlyList All = BlueTools.All.Concat(WhiteTools.All).Concat(YellowTools.All).ToArray(); public const string YellowColor = "#E8C14A"; public const string BlueColor = "#5A9BD6"; public const string WhiteColor = "#FFFFFF"; public static string ColorHex(string toolName) { object obj = WhiteTools.RingColorHexFor(toolName); if (obj == null) { if (!BlueTools.All.Any((ToolDefinition t) => t.Name == toolName)) { if (!WhiteTools.All.Any((ToolDefinition t) => t.Name == toolName)) { return "#E8C14A"; } return "#FFFFFF"; } obj = "#5A9BD6"; } return (string)obj; } public static ToolDefinition? Find(string toolName) { return All.FirstOrDefault((ToolDefinition t) => string.Equals(t.Name, toolName, StringComparison.Ordinal)); } public static string IconKey(string toolName) { return "tool." + toolName.Replace(' ', '_'); } } public sealed record ToolDefinition(string Name, bool IsBlue, string? Level2Effect = null, string? Level3Effect = null, string? Level1Effect = null, ToolEffectSpec? Level2Effects = null, ToolEffectSpec? Level3Effects = null, ToolEffectSpec? WhiteSlotEffects = null) { public ToolEffectSpec ResolveEffects(int level, bool inWhiteSlot) { ToolEffectSpec toolEffectSpec = (ToolEffectSpec)((level switch { 2 => Level2Effects, 3 => Level3Effects, _ => null, }) ?? ToolEffectSpec.None); if (!inWhiteSlot || !(WhiteSlotEffects != null)) { return toolEffectSpec; } return ToolEffectSpec.Merge(toolEffectSpec, WhiteSlotEffects); } } public sealed record ToolEffectsOptions(string DiceExclusiveCrest, float DiceBlockChancePercent, float DiceCritChancePercent); public static class ToolEffectsBinder { public static ToolEffectsOptions Bind(ConfigFile config, ManualLogSource log) { ToolEffectsOptions toolEffectsOptions = new ToolEffectsOptions(config.Bind("Tools.Dice", "ExclusiveCrest", "wanderer", "Crest that turns Magnetite Dice white (crit mode).").Value, config.Bind("Tools.Dice", "BlockChancePercent", 40f, "Yellow dice block chance in percent (8/8 = 40%).").Value, config.Bind("Tools.Dice", "CritChancePercent", 12f, "White dice crit chance in percent (12/12 = 12%).").Value); log.LogDebug((object)("[Tools] dice config bound: crest=" + toolEffectsOptions.DiceExclusiveCrest)); return toolEffectsOptions; } } public sealed record ToolEffectSpec(int MossSpoolsPerHit = 0, int MossSilkPerWhiteHit = 0, double DamageMultiplier = 1.0, int LavaCooldownSeconds = -1, bool LavaDamageImmune = false, bool ColdDebuffImmune = false, bool HealUninterruptible = false, bool PoisonStacking = false, double NailLengthMultiplier = 1.0, double NailWidthMultiplier = 1.0, double WitchNailLengthBonus = 0.0, double WitchNailWidthBonus = 0.0, double NailWhiteLengthMultiplier = 1.0, float WispSpawnIntervalSeconds = 0f, bool WispNoSilkCost = false, int SilkSkillCost = 0, bool SilkSkillCostNoHealthGate = false, double NailChargeTimeFactor = 1.0, double ChargeSilkMultiplier = 1.0, double CritMultiplierBonus = 0.0, bool CrossColorSlots = false, int QuickSlingThrowCount = 0, bool QuickSlingWhiteSlotModifier = false, double QuickSlingDurationMultiplier = 0.0, int QuickSlingSyringeBlueHealth = 0, bool MaggotImmune = false, bool MaggotRepairOnHeal = false, bool MaggotRepairOnKill = false, double ClawlineDamageMultiplier = 1.0, bool ClawlineNoSilkCost = false, double SilkSkillDamageBonus = 0.0, bool SilkSkillDamageWhiteBonus = false, int MultibindSegmentCount = 0, float MultibindSegmentSeconds = 0f, int MultibindHealPerSegment = 0, int MultibindWhiteHealPerSegment = 0, int MultibindBeastWitchHealCap = 0, int SilkRegenCapBonus = 0, double SilkRegenSpeedFactor = 0.0, bool SilkRegenNoResetOnChange = false, bool BrollyWhiteSilk = false, double QuickBindDurationFactor = 0.0, bool QuickBindWhiteExtra = false, int SilkCapBonus = 0, bool SilkCapWhiteDouble = false, bool DazzleWhiteOnHit = false, int RevengeCrystalCount = 0, bool RevengeWhiteOnHeal = false, int ReserveFreeBindCharges = 0, bool ReserveWhiteKillRepair = false, double ShardValueMultiplier = 1.0, bool ShardInstantPickup = false, double GeoValueMultiplier = 1.0, bool RosaryMagnetWhiteShards = false, double FallSpeedBonusPercent = 0.0, double KnockbackMultiplier = 0.0, double InvulnMultiplier = 0.0, bool TwoDamageToOne = false, double BarbedWireDamageDealtMultiplier = 1.0, double BarbedWireDamageTakenMultiplier = 0.0, bool BarbedWireWhiteNoDamageTakenMultiplier = false, double DeadPurseHoldPercent = 0.0, bool DeadPurseMinOneCocoon = false, bool DeadPurseWhiteFlintBrewStack = false, bool DeadPurseWhiteCogflyAutoRelease = false, int ShellSatchelCogworkFlierCap = 0, bool ShellSatchelWhiteFixedShardCost = false, bool ShellSatchelL2AutoRepair = false, bool ShellSatchelL3ShardCost = false, int LuckyDiceBlockPerHit = 0, bool LuckyDiceWhiteNoReset = false, double LuckyDiceCritChance = 0.0, double LuckyDiceWandererCritBonus = 0.0, double LuckyDiceMagnetDelayFactor = 0.0, bool LuckyDiceMagnetInstant = false, double ScuttleSpeedMultiplier = 0.0, bool ScuttleWhiteAirDoubleDash = false, double WallclingJumpHeightMultiplier = 1.0, bool WallclingWhiteTripleJump = false, double MusicianRangeMultiplier = 0.0, double MusicianSongTimeMultiplier = 0.0, bool MusicianWhiteNoSilkCost = false, double SprintmasterSpeedMultiplier = 0.0, double SprintmasterScuttleSpeedMultiplier = 0.0, bool SprintmasterWhiteNoSilkCost = false, double ThiefSmallGeoIncrease = 0.0, double ThiefMedGeoIncrease = 0.0, double ThiefLargeGeoIncrease = 0.0, bool ThiefWhiteNoLoss = false, bool SkillCastShield = false) { public static ToolEffectSpec None { get; } = new ToolEffectSpec(); public static ToolEffectSpec Merge(ToolEffectSpec a, ToolEffectSpec b) { return new ToolEffectSpec(Math.Max(a.MossSpoolsPerHit, b.MossSpoolsPerHit), Math.Max(a.MossSilkPerWhiteHit, b.MossSilkPerWhiteHit), Math.Max(a.DamageMultiplier, b.DamageMultiplier), Math.Max(a.LavaCooldownSeconds, b.LavaCooldownSeconds), a.LavaDamageImmune || b.LavaDamageImmune, a.ColdDebuffImmune || b.ColdDebuffImmune, a.HealUninterruptible || b.HealUninterruptible, a.PoisonStacking || b.PoisonStacking, Math.Max(a.NailLengthMultiplier, b.NailLengthMultiplier), Math.Max(a.NailWidthMultiplier, b.NailWidthMultiplier), Math.Max(a.WitchNailLengthBonus, b.WitchNailLengthBonus), Math.Max(a.WitchNailWidthBonus, b.WitchNailWidthBonus), Math.Max(a.NailWhiteLengthMultiplier, b.NailWhiteLengthMultiplier), MinOrFloat(a.WispSpawnIntervalSeconds, b.WispSpawnIntervalSeconds), a.WispNoSilkCost || b.WispNoSilkCost, Math.Max(a.SilkSkillCost, b.SilkSkillCost), a.SilkSkillCostNoHealthGate || b.SilkSkillCostNoHealthGate, MinOr(a.NailChargeTimeFactor, b.NailChargeTimeFactor), Math.Max(a.ChargeSilkMultiplier, b.ChargeSilkMultiplier), Math.Max(a.CritMultiplierBonus, b.CritMultiplierBonus), a.CrossColorSlots || b.CrossColorSlots, Math.Max(a.QuickSlingThrowCount, b.QuickSlingThrowCount), a.QuickSlingWhiteSlotModifier || b.QuickSlingWhiteSlotModifier, Math.Max(a.QuickSlingDurationMultiplier, b.QuickSlingDurationMultiplier), Math.Max(a.QuickSlingSyringeBlueHealth, b.QuickSlingSyringeBlueHealth), a.MaggotImmune || b.MaggotImmune, a.MaggotRepairOnHeal || b.MaggotRepairOnHeal, a.MaggotRepairOnKill || b.MaggotRepairOnKill, Math.Max(a.ClawlineDamageMultiplier, b.ClawlineDamageMultiplier), a.ClawlineNoSilkCost || b.ClawlineNoSilkCost, Math.Max(a.SilkSkillDamageBonus, b.SilkSkillDamageBonus), a.SilkSkillDamageWhiteBonus || b.SilkSkillDamageWhiteBonus, Math.Max(a.MultibindSegmentCount, b.MultibindSegmentCount), MinOrFloat(a.MultibindSegmentSeconds, b.MultibindSegmentSeconds), Math.Max(a.MultibindHealPerSegment, b.MultibindHealPerSegment), Math.Max(a.MultibindWhiteHealPerSegment, b.MultibindWhiteHealPerSegment), Math.Max(a.MultibindBeastWitchHealCap, b.MultibindBeastWitchHealCap), Math.Max(a.SilkRegenCapBonus, b.SilkRegenCapBonus), Math.Max(a.SilkRegenSpeedFactor, b.SilkRegenSpeedFactor), a.SilkRegenNoResetOnChange || b.SilkRegenNoResetOnChange, a.BrollyWhiteSilk || b.BrollyWhiteSilk, MinOr(a.QuickBindDurationFactor, b.QuickBindDurationFactor), a.QuickBindWhiteExtra || b.QuickBindWhiteExtra, Math.Max(a.SilkCapBonus, b.SilkCapBonus), a.SilkCapWhiteDouble || b.SilkCapWhiteDouble, a.DazzleWhiteOnHit || b.DazzleWhiteOnHit, Math.Max(a.RevengeCrystalCount, b.RevengeCrystalCount), a.RevengeWhiteOnHeal || b.RevengeWhiteOnHeal, Math.Max(a.ReserveFreeBindCharges, b.ReserveFreeBindCharges), a.ReserveWhiteKillRepair || b.ReserveWhiteKillRepair, Math.Max(a.ShardValueMultiplier, b.ShardValueMultiplier), a.ShardInstantPickup || b.ShardInstantPickup, Math.Max(a.GeoValueMultiplier, b.GeoValueMultiplier), a.RosaryMagnetWhiteShards || b.RosaryMagnetWhiteShards, Math.Max(a.FallSpeedBonusPercent, b.FallSpeedBonusPercent), Math.Max(a.KnockbackMultiplier, b.KnockbackMultiplier), Math.Max(a.InvulnMultiplier, b.InvulnMultiplier), a.TwoDamageToOne || b.TwoDamageToOne, Math.Max(a.BarbedWireDamageDealtMultiplier, b.BarbedWireDamageDealtMultiplier), Math.Max(a.BarbedWireDamageTakenMultiplier, b.BarbedWireDamageTakenMultiplier), a.BarbedWireWhiteNoDamageTakenMultiplier || b.BarbedWireWhiteNoDamageTakenMultiplier, Math.Max(a.DeadPurseHoldPercent, b.DeadPurseHoldPercent), a.DeadPurseMinOneCocoon || b.DeadPurseMinOneCocoon, a.DeadPurseWhiteFlintBrewStack || b.DeadPurseWhiteFlintBrewStack, a.DeadPurseWhiteCogflyAutoRelease || b.DeadPurseWhiteCogflyAutoRelease, Math.Max(a.ShellSatchelCogworkFlierCap, b.ShellSatchelCogworkFlierCap), a.ShellSatchelWhiteFixedShardCost || b.ShellSatchelWhiteFixedShardCost, a.ShellSatchelL2AutoRepair || b.ShellSatchelL2AutoRepair, a.ShellSatchelL3ShardCost || b.ShellSatchelL3ShardCost, Math.Max(a.LuckyDiceBlockPerHit, b.LuckyDiceBlockPerHit), a.LuckyDiceWhiteNoReset || b.LuckyDiceWhiteNoReset, Math.Max(a.LuckyDiceCritChance, b.LuckyDiceCritChance), Math.Max(a.LuckyDiceWandererCritBonus, b.LuckyDiceWandererCritBonus), Math.Max(a.LuckyDiceMagnetDelayFactor, b.LuckyDiceMagnetDelayFactor), a.LuckyDiceMagnetInstant || b.LuckyDiceMagnetInstant, Math.Max(a.ScuttleSpeedMultiplier, b.ScuttleSpeedMultiplier), a.ScuttleWhiteAirDoubleDash || b.ScuttleWhiteAirDoubleDash, Math.Max(a.WallclingJumpHeightMultiplier, b.WallclingJumpHeightMultiplier), a.WallclingWhiteTripleJump || b.WallclingWhiteTripleJump, Math.Max(a.MusicianRangeMultiplier, b.MusicianRangeMultiplier), Math.Max(a.MusicianSongTimeMultiplier, b.MusicianSongTimeMultiplier), a.MusicianWhiteNoSilkCost || b.MusicianWhiteNoSilkCost, Math.Max(a.SprintmasterSpeedMultiplier, b.SprintmasterSpeedMultiplier), Math.Max(a.SprintmasterScuttleSpeedMultiplier, b.SprintmasterScuttleSpeedMultiplier), a.SprintmasterWhiteNoSilkCost || b.SprintmasterWhiteNoSilkCost, Math.Max(a.ThiefSmallGeoIncrease, b.ThiefSmallGeoIncrease), Math.Max(a.ThiefMedGeoIncrease, b.ThiefMedGeoIncrease), Math.Max(a.ThiefLargeGeoIncrease, b.ThiefLargeGeoIncrease), a.ThiefWhiteNoLoss || b.ThiefWhiteNoLoss, a.SkillCastShield || b.SkillCastShield); } private static double MinOr(double a, double b) { if (!(a <= 0.0)) { if (!(b <= 0.0)) { return Math.Min(a, b); } return a; } return b; } private static float MinOrFloat(float a, float b) { if (!(a <= 0f)) { if (!(b <= 0f)) { return Math.Min(a, b); } return a; } return b; } [CompilerGenerated] private ToolEffectSpec(ToolEffectSpec original) { MossSpoolsPerHit = original.MossSpoolsPerHit; MossSilkPerWhiteHit = original.MossSilkPerWhiteHit; DamageMultiplier = original.DamageMultiplier; LavaCooldownSeconds = original.LavaCooldownSeconds; LavaDamageImmune = original.LavaDamageImmune; ColdDebuffImmune = original.ColdDebuffImmune; HealUninterruptible = original.HealUninterruptible; PoisonStacking = original.PoisonStacking; NailLengthMultiplier = original.NailLengthMultiplier; NailWidthMultiplier = original.NailWidthMultiplier; WitchNailLengthBonus = original.WitchNailLengthBonus; WitchNailWidthBonus = original.WitchNailWidthBonus; NailWhiteLengthMultiplier = original.NailWhiteLengthMultiplier; WispSpawnIntervalSeconds = original.WispSpawnIntervalSeconds; WispNoSilkCost = original.WispNoSilkCost; SilkSkillCost = original.SilkSkillCost; SilkSkillCostNoHealthGate = original.SilkSkillCostNoHealthGate; NailChargeTimeFactor = original.NailChargeTimeFactor; ChargeSilkMultiplier = original.ChargeSilkMultiplier; CritMultiplierBonus = original.CritMultiplierBonus; CrossColorSlots = original.CrossColorSlots; QuickSlingThrowCount = original.QuickSlingThrowCount; QuickSlingWhiteSlotModifier = original.QuickSlingWhiteSlotModifier; QuickSlingDurationMultiplier = original.QuickSlingDurationMultiplier; QuickSlingSyringeBlueHealth = original.QuickSlingSyringeBlueHealth; MaggotImmune = original.MaggotImmune; MaggotRepairOnHeal = original.MaggotRepairOnHeal; MaggotRepairOnKill = original.MaggotRepairOnKill; ClawlineDamageMultiplier = original.ClawlineDamageMultiplier; ClawlineNoSilkCost = original.ClawlineNoSilkCost; SilkSkillDamageBonus = original.SilkSkillDamageBonus; SilkSkillDamageWhiteBonus = original.SilkSkillDamageWhiteBonus; MultibindSegmentCount = original.MultibindSegmentCount; MultibindSegmentSeconds = original.MultibindSegmentSeconds; MultibindHealPerSegment = original.MultibindHealPerSegment; MultibindWhiteHealPerSegment = original.MultibindWhiteHealPerSegment; MultibindBeastWitchHealCap = original.MultibindBeastWitchHealCap; SilkRegenCapBonus = original.SilkRegenCapBonus; SilkRegenSpeedFactor = original.SilkRegenSpeedFactor; SilkRegenNoResetOnChange = original.SilkRegenNoResetOnChange; BrollyWhiteSilk = original.BrollyWhiteSilk; QuickBindDurationFactor = original.QuickBindDurationFactor; QuickBindWhiteExtra = original.QuickBindWhiteExtra; SilkCapBonus = original.SilkCapBonus; SilkCapWhiteDouble = original.SilkCapWhiteDouble; DazzleWhiteOnHit = original.DazzleWhiteOnHit; RevengeCrystalCount = original.RevengeCrystalCount; RevengeWhiteOnHeal = original.RevengeWhiteOnHeal; ReserveFreeBindCharges = original.ReserveFreeBindCharges; ReserveWhiteKillRepair = original.ReserveWhiteKillRepair; ShardValueMultiplier = original.ShardValueMultiplier; ShardInstantPickup = original.ShardInstantPickup; GeoValueMultiplier = original.GeoValueMultiplier; RosaryMagnetWhiteShards = original.RosaryMagnetWhiteShards; FallSpeedBonusPercent = original.FallSpeedBonusPercent; KnockbackMultiplier = original.KnockbackMultiplier; InvulnMultiplier = original.InvulnMultiplier; TwoDamageToOne = original.TwoDamageToOne; BarbedWireDamageDealtMultiplier = original.BarbedWireDamageDealtMultiplier; BarbedWireDamageTakenMultiplier = original.BarbedWireDamageTakenMultiplier; BarbedWireWhiteNoDamageTakenMultiplier = original.BarbedWireWhiteNoDamageTakenMultiplier; DeadPurseHoldPercent = original.DeadPurseHoldPercent; DeadPurseMinOneCocoon = original.DeadPurseMinOneCocoon; DeadPurseWhiteFlintBrewStack = original.DeadPurseWhiteFlintBrewStack; DeadPurseWhiteCogflyAutoRelease = original.DeadPurseWhiteCogflyAutoRelease; ShellSatchelCogworkFlierCap = original.ShellSatchelCogworkFlierCap; ShellSatchelWhiteFixedShardCost = original.ShellSatchelWhiteFixedShardCost; ShellSatchelL2AutoRepair = original.ShellSatchelL2AutoRepair; ShellSatchelL3ShardCost = original.ShellSatchelL3ShardCost; LuckyDiceBlockPerHit = original.LuckyDiceBlockPerHit; LuckyDiceWhiteNoReset = original.LuckyDiceWhiteNoReset; LuckyDiceCritChance = original.LuckyDiceCritChance; LuckyDiceWandererCritBonus = original.LuckyDiceWandererCritBonus; LuckyDiceMagnetDelayFactor = original.LuckyDiceMagnetDelayFactor; LuckyDiceMagnetInstant = original.LuckyDiceMagnetInstant; ScuttleSpeedMultiplier = original.ScuttleSpeedMultiplier; ScuttleWhiteAirDoubleDash = original.ScuttleWhiteAirDoubleDash; WallclingJumpHeightMultiplier = original.WallclingJumpHeightMultiplier; WallclingWhiteTripleJump = original.WallclingWhiteTripleJump; MusicianRangeMultiplier = original.MusicianRangeMultiplier; MusicianSongTimeMultiplier = original.MusicianSongTimeMultiplier; MusicianWhiteNoSilkCost = original.MusicianWhiteNoSilkCost; SprintmasterSpeedMultiplier = original.SprintmasterSpeedMultiplier; SprintmasterScuttleSpeedMultiplier = original.SprintmasterScuttleSpeedMultiplier; SprintmasterWhiteNoSilkCost = original.SprintmasterWhiteNoSilkCost; ThiefSmallGeoIncrease = original.ThiefSmallGeoIncrease; ThiefMedGeoIncrease = original.ThiefMedGeoIncrease; ThiefLargeGeoIncrease = original.ThiefLargeGeoIncrease; ThiefWhiteNoLoss = original.ThiefWhiteNoLoss; SkillCastShield = original.SkillCastShield; } } public sealed class ToolExclusiveCrests { private readonly Dictionary _map = new Dictionary(StringComparer.Ordinal); public ToolExclusiveCrests(string diceCrestId) { _map["Magnetite Dice"] = diceCrestId; } public void Bind(string toolName, string crestId) { _map[toolName] = crestId; } public bool IsExclusiveActive(string toolName, string currentCrestId) { if (_map.TryGetValue(toolName, out string value)) { return string.Equals(value, currentCrestId, StringComparison.OrdinalIgnoreCase); } return false; } } public static class ToolLevelGate { public static bool ShouldApply(int level, bool white, bool equipped) { if (equipped) { return level >= 2 || white; } return false; } } public sealed class ToolLevelService { private readonly Dictionary _levels = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _offsets = new Dictionary(StringComparer.Ordinal); private readonly Dictionary> _toolOffsets = new Dictionary>(StringComparer.Ordinal); public int TemporaryOffset { get { int num = 0; foreach (int value in _offsets.Values) { num += value; } foreach (Dictionary value2 in _toolOffsets.Values) { foreach (int value3 in value2.Values) { num += value3; } } return num; } } public event Action? LevelChanged; public event Action? Changed; public int GetLevel(string toolName) { if (!_levels.TryGetValue(toolName, out var value)) { return 1; } return value; } public int GetOffset(string source) { if (string.IsNullOrWhiteSpace(source)) { throw new ArgumentException("Offset source is required.", "source"); } if (!_offsets.TryGetValue(source, out var value)) { return 0; } return value; } public void SetOffset(string source, int offset) { if (string.IsNullOrWhiteSpace(source)) { throw new ArgumentException("Offset source is required.", "source"); } int num = Math.Clamp(offset, 0, 3); if (!_offsets.TryGetValue(source, out var value) || value != num) { _offsets[source] = num; this.Changed?.Invoke(); } } public void ClearOffset(string source) { if (string.IsNullOrWhiteSpace(source)) { throw new ArgumentException("Offset source is required.", "source"); } if (_offsets.Remove(source)) { this.Changed?.Invoke(); } } public void SetOffsetForTool(string source, string toolName, int offset) { if (string.IsNullOrWhiteSpace(source)) { throw new ArgumentException("Offset source is required.", "source"); } if (string.IsNullOrWhiteSpace(toolName)) { throw new ArgumentException("Tool name is required.", "toolName"); } if (!_toolOffsets.TryGetValue(source, out Dictionary value)) { value = new Dictionary(StringComparer.Ordinal); _toolOffsets[source] = value; } int num = Math.Clamp(offset, 0, 3); if (!value.TryGetValue(toolName, out var value2) || value2 != num) { value[toolName] = num; this.Changed?.Invoke(); } } public void ClearOffsetForTool(string source, string toolName) { if (!string.IsNullOrWhiteSpace(source) && !string.IsNullOrWhiteSpace(toolName) && _toolOffsets.TryGetValue(source, out Dictionary value) && value.Remove(toolName)) { if (value.Count == 0) { _toolOffsets.Remove(source); } this.Changed?.Invoke(); } } public void ClearToolOffsets(string source) { if (!string.IsNullOrWhiteSpace(source) && _toolOffsets.Remove(source)) { this.Changed?.Invoke(); } } public int EffectiveLevel(string toolName) { return Math.Clamp(GetLevel(toolName) + TotalOffsetFor(toolName), 1, 3); } public void SetLevel(string toolName, int level) { int num = Math.Clamp(level, 1, 3); if (!_levels.TryGetValue(toolName, out var value) || value != num) { _levels[toolName] = num; this.LevelChanged?.Invoke(toolName, num); this.Changed?.Invoke(); } } public int ResetLevels() { if (_levels.Count == 0) { return 0; } int count = _levels.Count; _levels.Clear(); Action? action = this.Changed; if (action != null) { action(); return count; } return count; } private int TotalOffsetFor(string toolName) { int num = 0; foreach (int value2 in _offsets.Values) { num += value2; } foreach (Dictionary value3 in _toolOffsets.Values) { if (value3.TryGetValue(toolName, out var value)) { num += value; } } return num; } } public static class WallclingJumpRules { public static double JumpMultiplier(ToolEffectSpec fx) { if (!(fx != null) || !(fx.WallclingJumpHeightMultiplier > 1.0)) { return 1.0; } return fx.WallclingJumpHeightMultiplier; } } public static class WallclingTripleJumpRules { public static bool ShouldPerformTripleJump(bool equipped, bool doubleJumped, bool alreadyPerformed) { if (equipped && doubleJumped) { return !alreadyPerformed; } return false; } } public static class WhiteBuffDamageRules { private static readonly string[] SkillSourceKeywords = new string[4] { "Wave", "Rune", "Charge Slash", "Bind" }; public static bool IsNeedleHit(HitInstance hit) { //IL_0000: 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_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: Invalid comparison between Unknown and I4 //IL_0019: 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_0021: Invalid comparison between Unknown and I4 //IL_0023: 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_002a: Invalid comparison between Unknown and I4 if (hit.IsHeroDamage) { if ((int)hit.AttackType != 0 && (int)hit.AttackType != 1 && (int)hit.AttackType != 16) { return (int)hit.AttackType == 6; } return true; } return false; } public static bool IsSkillHit(HitInstance hit) { //IL_0000: 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_0011: Invalid comparison between Unknown and I4 //IL_0013: 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_001b: Invalid comparison between Unknown and I4 //IL_001f: 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) if (!hit.IsHeroDamage) { return false; } if ((int)hit.AttackType == 2 || (int)hit.AttackType == 16) { return true; } return IsSkillSourceName((hit.Source != null) ? ((Object)hit.Source).name : string.Empty); } public static bool IsSkillSourceName(string? sourceName) { if (string.IsNullOrEmpty(sourceName)) { return false; } string[] skillSourceKeywords = SkillSourceKeywords; foreach (string value in skillSourceKeywords) { if (sourceName.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } public static bool IsToolHit(HitInstance hit) { //IL_0000: 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) if (hit.IsHeroDamage) { return hit.RepresentingTool != null; } return false; } public static double ComputeMultiplier(HitInstance hit, bool needleBuffActive, double needleMultiplier, bool skillBuffActive, double skillMultiplier, bool toolBuffActive, double toolMultiplier) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) double num = 1.0; if (needleBuffActive && needleMultiplier > 1.0 && IsNeedleHit(hit)) { num *= needleMultiplier; } if (skillBuffActive && skillMultiplier > 1.0 && IsSkillHit(hit)) { num *= skillMultiplier; } if (toolBuffActive && toolMultiplier > 1.0 && IsToolHit(hit)) { num *= toolMultiplier; } return num; } public static int ScaleDamage(int damage, double multiplier) { if (!(multiplier <= 1.0)) { return (int)Math.Round((double)damage * multiplier); } return damage; } } public sealed record WhiteBuffOptions(bool Enabled, double VoidHeartNeedleDamageMultiplier, double KingsoulSkillDamageMultiplier, double WeaversongToolDamageMultiplier, double HivebloodAttackIntervalFactor) { public static WhiteBuffOptions Bind(ConfigFile config, ManualLogSource log) { bool value = config.Bind("WhiteBuffs", "Enabled", true, "Master switch for the four white-slot white-tool enhancements.").Value; double value2 = config.Bind("WhiteBuffs", "VoidHeartNeedleDamageMultiplier", 1.5, "Void Heart white slot: needle damage multiplier (Nail/Generic/Heavy/SharpShadow).").Value; double value3 = config.Bind("WhiteBuffs", "KingsoulSkillDamageMultiplier", 1.5, "Kingsoul white slot: skill damage multiplier (Spell/Heavy + Wave/Rune/Charge Slash/Bind).").Value; double value4 = config.Bind("WhiteBuffs", "WeaversongToolDamageMultiplier", 1.5, "Weaversong white slot: tool damage multiplier (HitInstance.RepresentingTool != null).").Value; double value5 = config.Bind("WhiteBuffs", "HivebloodAttackIntervalFactor", 0.58, "Hiveblood white slot: attack cycle interval multiplier (0.58 = -42%).").Value; return Clamp(new WhiteBuffOptions(value, value2, value3, value4, value5), log); } public static WhiteBuffOptions Clamp(WhiteBuffOptions options, ManualLogSource? log = null) { double num = ((options.VoidHeartNeedleDamageMultiplier < 1.0) ? 1.0 : options.VoidHeartNeedleDamageMultiplier); double num2 = ((options.KingsoulSkillDamageMultiplier < 1.0) ? 1.0 : options.KingsoulSkillDamageMultiplier); double num3 = ((options.WeaversongToolDamageMultiplier < 1.0) ? 1.0 : options.WeaversongToolDamageMultiplier); double num4 = ((options.HivebloodAttackIntervalFactor <= 0.0 || options.HivebloodAttackIntervalFactor > 1.0) ? 0.58 : options.HivebloodAttackIntervalFactor); if ((num != options.VoidHeartNeedleDamageMultiplier || num2 != options.KingsoulSkillDamageMultiplier || num3 != options.WeaversongToolDamageMultiplier || num4 != options.HivebloodAttackIntervalFactor) && log != null) { log.LogWarning((object)"[WhiteBuffs] invalid multiplier values clamped to safe defaults."); } return options with { VoidHeartNeedleDamageMultiplier = num, KingsoulSkillDamageMultiplier = num2, WeaversongToolDamageMultiplier = num3, HivebloodAttackIntervalFactor = num4 }; } } public sealed class WhiteCharmLevelDriver : IDisposable { public const string OffsetSource = "white-charm"; public const string KingsoulOffsetSource = "white-charm-kingsoul"; public const string WeaversongOffsetSource = "white-charm-weaversong"; public const string VoidHeartOffsetSource = "white-charm-void-heart"; public const string HivebloodOffsetSource = "white-charm-hiveblood"; private readonly ManualLogSource _log; private readonly GameEventHub _events; private readonly ToolLevelService _levels; private readonly Func _isEquipped; private bool _started; private bool _warned; public WhiteCharmLevelDriver(ManualLogSource log, GameEventHub events, ToolLevelService levels, Func isEquipped) { _log = log; _events = events; _levels = levels; _isEquipped = isEquipped; } public void Start() { if (!_started) { _started = true; _events.ToolEquipsChanged += Refresh; _events.SceneChanged += OnSceneChanged; _events.CrestChanged += OnCrestChanged; Refresh(); } } public void Dispose() { _started = false; _events.ToolEquipsChanged -= Refresh; _events.SceneChanged -= OnSceneChanged; _events.CrestChanged -= OnCrestChanged; _levels.ClearToolOffsets("white-charm-kingsoul"); _levels.ClearToolOffsets("white-charm-weaversong"); _levels.ClearToolOffsets("white-charm-void-heart"); _levels.ClearToolOffsets("white-charm-hiveblood"); } private void OnSceneChanged(string scene) { Refresh(); } private void OnCrestChanged(CrestChangedEvent e) { Refresh(); } private void Refresh() { bool flag = SafeEquipped("Kingsoul"); bool flag2 = SafeEquipped("Weaversong"); bool flag3 = SafeEquipped("Void Heart"); bool flag4 = SafeEquipped("Hiveblood"); _levels.ClearToolOffsets("white-charm-kingsoul"); _levels.ClearToolOffsets("white-charm-weaversong"); _levels.ClearToolOffsets("white-charm-void-heart"); _levels.ClearToolOffsets("white-charm-hiveblood"); if (flag) { foreach (ToolDefinition item in BlueTools.All) { _levels.SetOffsetForTool("white-charm-kingsoul", item.Name, 1); } } if (flag3) { foreach (ToolDefinition item2 in BlueTools.All) { _levels.SetOffsetForTool("white-charm-void-heart", item2.Name, 1); } } if (flag2) { foreach (ToolDefinition item3 in YellowTools.All) { _levels.SetOffsetForTool("white-charm-weaversong", item3.Name, 1); } } if (flag4) { foreach (ToolDefinition item4 in YellowTools.All) { _levels.SetOffsetForTool("white-charm-hiveblood", item4.Name, 1); } } _log.LogDebug((object)($"[WhiteCharmLevel] kingsoul={flag}, voidHeart={flag3} (blue +1 each), " + $"weaversong={flag2}, hiveblood={flag4} (yellow +1 each).")); } private bool SafeEquipped(string name) { try { return _isEquipped(name); } catch (Exception ex) { if (!_warned) { _warned = true; _log.LogWarning((object)("[WhiteCharmLevel] equip query failed (" + name + "): " + ex.Message)); } return false; } } } public static class WhiteToolDisplayText { private static readonly IReadOnlyDictionary Names = BuildNames(); private static readonly IReadOnlyDictionary Descriptions = BuildDescriptions(); public static string? ResolveName(string? toolName, string current) { if (toolName == null || !Names.TryGetValue(toolName, out string value)) { return null; } if (!NeedsOverride(current, toolName, toolName + "Desc")) { return null; } return value; } public static string? ResolveDescription(string? toolName, string current) { if (toolName == null || !Descriptions.TryGetValue(toolName, out string value)) { return null; } if (!NeedsOverride(current, toolName, toolName + "Desc")) { return null; } return value; } private static bool NeedsOverride(string current, string toolName, string descriptionKey) { if (string.IsNullOrWhiteSpace(current)) { return true; } if (current.Contains("Mods.local", StringComparison.OrdinalIgnoreCase)) { return true; } if (string.Equals(current.Trim(), toolName, StringComparison.OrdinalIgnoreCase)) { return true; } return string.Equals(current.Trim(), descriptionKey, StringComparison.OrdinalIgnoreCase); } private static IReadOnlyDictionary BuildNames() { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (TextEntry entry in IoniaDescription.Entries) { if (!entry.Key.EndsWith("Desc", StringComparison.Ordinal)) { dictionary[entry.Key] = entry.Text; } } return dictionary; } private static IReadOnlyDictionary BuildDescriptions() { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (TextEntry entry in IoniaDescription.Entries) { if (entry.Key.EndsWith("Desc", StringComparison.Ordinal)) { dictionary[entry.Key.Substring(0, entry.Key.Length - "Desc".Length)] = entry.Text; } } return dictionary; } } public static class WhiteTools { public const string IoniaName = "Ionia"; public static readonly IReadOnlyList HiddenFromHud = WhiteToolCatalog.HiddenFromHud; public static readonly IReadOnlyList Specs = WhiteToolCatalog.PassiveTools; public static readonly IReadOnlyList All = BuildAll(); public static bool IsWhiteTool(string toolName) { return WhiteToolCatalog.IsWhiteTool(toolName); } public static bool IsWhiteToolIconKey(string key) { return All.Any((ToolDefinition t) => t.Name != "Ionia" && ToolCatalog.IconKey(t.Name) == key); } public static bool IsHiddenFromHud(string toolName) { return HiddenFromHud.Contains(toolName, StringComparer.Ordinal); } public static string? RingColorHexFor(string toolName) { return WhiteToolCatalog.RingColorHexFor(toolName); } private static IReadOnlyList BuildAll() { List list = new List(); foreach (WhiteToolSpec item in WhiteToolCatalog.All) { list.Add(new ToolDefinition(item.Name, IsBlue: false, (item.Name == "Ionia") ? "White tool: used for white dice display and gates all crest passives." : ("White tool: " + item.Name))); } return list; } } public static class YellowTools { public static readonly IReadOnlyList All = new ToolDefinition[13] { WallclingTool.Definition, BarbedWireTool.Definition, CompassTool.Definition, DeadMansPurseTool.Definition, RosaryMagnetTool.Definition, MagnetiteDiceTool.Definition, ScuttlebraceTool.Definition, BoneNecklaceTool.Definition, ShellSatchelTool.Definition, SprintmasterTool.Definition, MusicianCharmTool.Definition, ThiefCharmTool.Definition, WeightedAnkletTool.Definition }; } } namespace CrestsEvolve.Features.Tools.Yellow { public static class BarbedWireTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Barbed Wire", IsBlue: false, "针刺伤害+50%并取整;受到的几乎所有伤害翻2倍(×3)。/ 只影响针刺本身,不影响丝技能。", "针刺伤害+100%并取整;受到的几乎所有伤害翻4倍(×5)。/ 只影响针刺本身,不影响丝技能。", "针刺(含蓄力斩)伤害+25%并取整:基础5/9/13/17/21→6/11/16/21/26;受到的几乎所有伤害翻倍(虚空伤害固定为2格、山风寒冷伤害不翻倍)。/ 只影响针刺本身,不影响丝技能。", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.5, 3.0), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 2.0, 5.0), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: true)); } public static class BoneNecklaceTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Bone Necklace", IsBlue: false, "每个获取的碎片价值*2", "每个获取的碎片价值*4", "敌人掉落的碎片数量+25%(向上取整)", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 2.0), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 4.0), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: true)); } public static class CompassTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Compass", IsBlue: false, "齿轮蜂数量上限变为8。", "齿轮蜂数量上限变为12。", "地图界面显示Hornet当前位置标记", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 8), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 12), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: true)); } public static class DeadMansPurseTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Dead Mans Purse", IsBlue: false, "死亡时保留75%念珠(四舍五入到整数)。", "死亡时保留99%念珠(四舍五入到整数,最少给茧内留下1颗)。", "死亡时保留一半念珠(四舍五入到整数),其余留在茧中;并允许念珠炮(Rosary Cannon)在死亡之间重新装填。", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.75), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.99, DeadPurseMinOneCocoon: true), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: true, DeadPurseWhiteCogflyAutoRelease: true)); } public static class MagnetiteDiceTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Magnetite Dice", IsBlue: false, "每次受击累计+4%格挡率,成功格挡后重置为0%,上限20%;佩戴任意纹章暴击率+4%(漫游者+9丝线再+2%),并大幅加快磁石胸针触发(吸引延迟减半)。", "每次受击累计+8%格挡率,成功格挡后重置为0%,上限40%;佩戴任意纹章暴击率+8%(漫游者+9丝线再+2%),并使磁石胸针瞬间触发,念珠瞬间飞回。", "每次受击累计+2.02%格挡率,成功格挡后重置为0%,上限10.1%;格挡时仍受击退。/ 搭配漫游者纹章时暴击率由2%提升至2.2%,并加快磁石胸针触发。", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 4, LuckyDiceWhiteNoReset: false, 0.04, 0.02, 0.5), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 8, LuckyDiceWhiteNoReset: false, 0.08, 0.02, 0.0, LuckyDiceMagnetInstant: true), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: true)); } public static class MusicianCharmTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Musician Charm", IsBlue: false, "影响范围+50%,敌人/NPC唱歌时间+2.5~5秒。", "影响范围+100%,敌人/NPC唱歌时间+5~10秒。", "Needolin(蛛琴)影响范围+25%,敌人/NPC唱歌时间+1.25~2.5秒;并为琴声添加独立音轨层。", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: false, 0.0, 0.0, 0.0, LuckyDiceMagnetInstant: false, 0.0, ScuttleWhiteAirDoubleDash: false, 1.0, WallclingWhiteTripleJump: false, 1.5, 2.0), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: false, 0.0, 0.0, 0.0, LuckyDiceMagnetInstant: false, 0.0, ScuttleWhiteAirDoubleDash: false, 1.0, WallclingWhiteTripleJump: false, 2.0, 4.0), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: false, 0.0, 0.0, 0.0, LuckyDiceMagnetInstant: false, 0.0, ScuttleWhiteAirDoubleDash: false, 1.0, WallclingWhiteTripleJump: false, 0.0, 0.0, MusicianWhiteNoSilkCost: true)); } public static class RosaryMagnetTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Rosary Magnet", IsBlue: false, "每个获取的念珠价值*2", "每个获取的念珠价值*4", "将敌人掉落或念珠宝箱散落的念珠吸向Hornet", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 2.0), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 4.0), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: true)); } public static class ScuttlebraceTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Scuttlebrace", IsBlue: false, "爬行速度+25%。", "爬行速度+75%。", "下+冲刺(DOWN+SPRINT)向后快速爬行撤退,可空中多次使用;Hitbox变矮变宽,部分攻击可从头顶飞过;敌人招架窗口内使用有特殊闪避动画。/ 爬行速度约步行+80%;搭配丝速脚环时爬行速度再+26%。", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: false, 0.0, 0.0, 0.0, LuckyDiceMagnetInstant: false, 1.25), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: false, 0.0, 0.0, 0.0, LuckyDiceMagnetInstant: false, 1.75), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: false, 0.0, 0.0, 0.0, LuckyDiceMagnetInstant: false, 0.0, ScuttleWhiteAirDoubleDash: true)); } public static class ShellSatchelTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Shell Satchel", IsBlue: false, "红色工具消耗完后2秒自动补充修复。", "红色工具使用时不消耗数量,改为按比例向上取整消耗碎片。", "Steel Soul 模式专属(替换亡虫囊):红工具容量增加(数值随工具袋等级);卸下壳囊或更换纹章后多余工具消失,重新装备需用碎片重新制作。", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: true), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: true), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: true)); } public static class SprintmasterTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Sprintmaster", IsBlue: false, "地面冲刺/疾跑速度+100%(原版+50%等比放大);搭配迅捷脊锁时其爬行速度+54%。", "地面冲刺/疾跑速度+150%;搭配迅捷脊锁时其爬行速度+81%。", "地面冲刺/疾跑速度+34%;约每6秒疾跑消耗1缕丝线(中断4秒内续跑会累计计时);空中无加成也不消耗;搭配迅捷脊锁时其爬行速度+27%。", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: false, 0.0, 0.0, 0.0, LuckyDiceMagnetInstant: false, 0.0, ScuttleWhiteAirDoubleDash: false, 1.0, WallclingWhiteTripleJump: false, 0.0, 0.0, MusicianWhiteNoSilkCost: false, 2.0, 1.54), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: false, 0.0, 0.0, 0.0, LuckyDiceMagnetInstant: false, 0.0, ScuttleWhiteAirDoubleDash: false, 1.0, WallclingWhiteTripleJump: false, 0.0, 0.0, MusicianWhiteNoSilkCost: false, 2.5, 1.81), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: false, 0.0, 0.0, 0.0, LuckyDiceMagnetInstant: false, 0.0, ScuttleWhiteAirDoubleDash: false, 1.0, WallclingWhiteTripleJump: false, 0.0, 0.0, MusicianWhiteNoSilkCost: false, 0.0, 0.0, SprintmasterWhiteNoSilkCost: true)); } public static class ThiefCharmTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Thief Charm", IsBlue: false, "敌人掉落念珠增加:普通念珠+80%、壳念珠+60%、珍珠+40%。", "敌人掉落念珠增加:普通念珠+160%、壳念珠+120%、珍珠+80%。", "敌人掉落念珠增加:普通念珠+40%、壳念珠+30%、珍珠+20%(向上取整,掉落呈白色高亮)。/ 受击时30%概率损失3–5%持有念珠(上限10–20颗);多段攻击按整体30%概率、损失6–10%(上限15–30颗);部分损失掉在地上可捡回。窃蝇不会主动攻击Hornet。", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: false, 0.0, 0.0, 0.0, LuckyDiceMagnetInstant: false, 0.0, ScuttleWhiteAirDoubleDash: false, 1.0, WallclingWhiteTripleJump: false, 0.0, 0.0, MusicianWhiteNoSilkCost: false, 0.0, 0.0, SprintmasterWhiteNoSilkCost: false, 0.8, 0.6, 0.4), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: false, 0.0, 0.0, 0.0, LuckyDiceMagnetInstant: false, 0.0, ScuttleWhiteAirDoubleDash: false, 1.0, WallclingWhiteTripleJump: false, 0.0, 0.0, MusicianWhiteNoSilkCost: false, 0.0, 0.0, SprintmasterWhiteNoSilkCost: false, 1.6, 1.2, 0.8), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: false, 0.0, 0.0, 0.0, LuckyDiceMagnetInstant: false, 0.0, ScuttleWhiteAirDoubleDash: false, 1.0, WallclingWhiteTripleJump: false, 0.0, 0.0, MusicianWhiteNoSilkCost: false, 0.0, 0.0, SprintmasterWhiteNoSilkCost: false, 0.0, 0.0, 0.0, ThiefWhiteNoLoss: true)); } public static class WallclingTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Wallcling", IsBlue: false, "跳跃高度+25%(地面/空中)。", "跳跃高度+50%(地面/空中)。", "攀墙(Cling Grip)时不再下滑,可固定在墙上;松开移动输入即取消。/ 高处坠落贴墙会先滑一小段再停住。", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: false, 0.0, 0.0, 0.0, LuckyDiceMagnetInstant: false, 0.0, ScuttleWhiteAirDoubleDash: false, 1.25), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: false, 0.0, 0.0, 0.0, LuckyDiceMagnetInstant: false, 0.0, ScuttleWhiteAirDoubleDash: false, 1.5), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: false, 0.0, 0.0, 0.0, LuckyDiceMagnetInstant: false, 0.0, ScuttleWhiteAirDoubleDash: false, 1.0, WallclingWhiteTripleJump: true)); } public static class WeightedAnkletTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Weighted Anklet", IsBlue: false, "后退距离减75%;受伤无敌+60%;最大下落速度+52%", "后退距离为0;受伤无敌+90%;最大下落速度+78%", "受击/针刺命中后退距离减半;受伤无敌+30%;最大下落速度+26%", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.52, 0.25, 1.6), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.78, 0.0, 1.9), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: true)); } } namespace CrestsEvolve.Features.Tools.Blue { public static class BellBindTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Bell Bind", IsBlue: true, "伤害*2", "伤害*3", "治疗期间受击免疫该次伤害,并造成范围伤害;击退与治疗取消仍生效", new ToolEffectSpec(0, 0, 2.0), new ToolEffectSpec(0, 0, 3.0), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: false, 1.0, ShardInstantPickup: false, 1.0, RosaryMagnetWhiteShards: false, 0.0, 0.0, 0.0, TwoDamageToOne: false, 1.0, 0.0, BarbedWireWhiteNoDamageTakenMultiplier: false, 0.0, DeadPurseMinOneCocoon: false, DeadPurseWhiteFlintBrewStack: false, DeadPurseWhiteCogflyAutoRelease: false, 0, ShellSatchelWhiteFixedShardCost: false, ShellSatchelL2AutoRepair: false, ShellSatchelL3ShardCost: false, 0, LuckyDiceWhiteNoReset: false, 0.0, 0.0, 0.0, LuckyDiceMagnetInstant: false, 0.0, ScuttleWhiteAirDoubleDash: false, 1.0, WallclingWhiteTripleJump: false, 0.0, 0.0, MusicianWhiteNoSilkCost: false, 0.0, 0.0, SprintmasterWhiteNoSilkCost: false, 0.0, 0.0, 0.0, ThiefWhiteNoLoss: false, SkillCastShield: true)); } public static class BrollySpikeTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Brolly Spike", IsBlue: true, "伤害*2", "伤害*3", "激活落披风/流浪者披风时绕身旋转斩击,伤害8+1/13+1/18+1/22+1/27+1(随制作包/针刺等级)", new ToolEffectSpec(0, 0, 2.0), new ToolEffectSpec(0, 0, 3.0), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: true)); } public static class DazzleBindTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Dazzle Bind", IsBlue: true, "伤害*2", "伤害*3", "治疗(Bind)后周围爆发闪光,命中伤害11/18/24/31/37 + 2次×5范围伤害", new ToolEffectSpec(0, 0, 2.0), new ToolEffectSpec(0, 0, 3.0), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: true)); } public static class DazzleBindUpgradedTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Dazzle Bind Upgraded", IsBlue: true, "伤害*2", "伤害*3", "治疗(Bind)后造成15/24/33/42/51 + 2次×8范围伤害(双生爪镜)", new ToolEffectSpec(0, 0, 2.0), new ToolEffectSpec(0, 0, 3.0), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: true)); } public static class DazzleWhiteRules { public const string BaseName = "Dazzle Bind"; public const string UpgradedName = "Dazzle Bind Upgraded"; public static string? SelectDefinitionName(bool upgradedEquipped, bool baseEquipped) { if (!upgradedEquipped) { if (!baseEquipped) { return null; } return "Dazzle Bind"; } return "Dazzle Bind Upgraded"; } } public static class FleaCharmTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Flea Charm", IsBlue: true, "降为2缕", "降为1缕", "满血时丝技能消耗由4缕降为3缕", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 2), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 1), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: true)); } public static class FracturedMaskTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Fractured Mask", IsBlue: true, "待实现", "待实现", "原版效果(未修饰)"); } public static class LavaCharmTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Lava Charm", IsBlue: true, "热地板/热墙安全时间在原本约0.7秒基础上额外+7秒;触发保护后进入1秒冷却", "火焰/岩浆类伤害为0;热地板/热墙上不会受到伤害", "火焰/岩浆类伤害减半;热地板/热墙安全时间额外+2秒;触发保护后5秒冷却", new ToolEffectSpec(0, 0, 1.0, 1), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: true), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: true)); } public static class LongneedleTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Longneedle", IsBlue: true, "针刺攻击判定长度+40%、宽度+15%(下劈范围同样增加);女巫纹章下特殊倍率:长度×9%、宽度×43%", "针刺攻击判定长度+60%、宽度+22.5%(下劈范围同样增加);女巫纹章下特殊倍率:长度×13.5%、宽度×69.5%", "针刺攻击判定长度+20%、宽度+7.5%(下劈范围同样增加);女巫纹章下特殊倍率:长度×4.5%、宽度×26.5%", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.4, 1.15, 0.09, 0.43), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.6, 1.225, 0.135, 0.695), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.2)); } public static class MaggotCharmTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Maggot Charm", IsBlue: true, "花环在治疗后修复", "花环不会损坏", "免疫3次泥虫感染(HUD花环递减);坐椅子或获得新面具后完全修复", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: true), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: true), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: true)); } public static class MosscreepTool1 { public static ToolDefinition Definition { get; } = new ToolDefinition("Mosscreep Tool 1", IsBlue: true, "每次受击在丝线轴生成2个绿色丝球", "每次受击在丝线轴生成4个绿色丝球", "每次受击在丝线轴生成1个绿色丝球,累计2次受击转化为1缕完整丝线", new ToolEffectSpec(2), new ToolEffectSpec(4), new ToolEffectSpec(0, 1)); } public static class MosscreepTool2 { public static ToolDefinition Definition { get; } = new ToolDefinition("Mosscreep Tool 2", IsBlue: true, "每次受击在丝线轴生成4个绿色丝球", "每次受击在丝线轴生成8个绿色丝球", "每次受击生成2个绿色丝球,累计2次受击转化为2缕完整丝线", new ToolEffectSpec(4), new ToolEffectSpec(8), new ToolEffectSpec(0, 2)); } public static class MossRules { public static int PerHitSpools(int configuredPerHit, int baseSilk) { if (configuredPerHit <= 0) { return baseSilk; } return configuredPerHit; } public static int WhiteDirectSilk(int configuredWhite) { return Math.Max(0, configuredWhite); } } public static class MultibindTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Multibind", IsBlue: true, "3段动画,共回6格,每段动画0.6秒;野兽女巫治疗上限变为6格", "4段动画,共回8格,每段动画0.5秒;野兽女巫治疗上限变为8格", "治疗(Bind)变为2段动画,每段0.8秒、各回复2格面具,共4格(原版3格);野兽纹章狂暴治疗上限变为4格", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 3, 0.6f, 2, 0, 6), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 4, 0.5f, 2, 0, 8), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 3)); } public static class PinstressTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Pinstress Tool", IsBlue: true, "蓄力时间-60%", "蓄力时间-80%", "蓄力斩(Needle Strike)蓄力时间-40%", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 0.4), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 0.2), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 3.0)); } public static class PoisonPouchTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Poison Pouch", IsBlue: true, "伤害*2", "伤害*3", "大部分红工具命中附加中毒:持续2跳,每跳伤害随制作包为1/2/2/3/3;重复命中刷新中毒时间", new ToolEffectSpec(0, 0, 2.0), new ToolEffectSpec(0, 0, 3.0), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: true)); } public static class QuickbindTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Quickbind", IsBlue: true, "治疗(Bind)速度+80%;同时加快野兽纹章、女巫纹章的治疗", "治疗(Bind)速度+120%;同时加快野兽纹章、女巫纹章的治疗", "治疗(Bind)速度+40%;同时加快野兽纹章、女巫纹章的治疗", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.2), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.1), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: true)); } public static class QuickSlingTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Quick Sling", IsBlue: true, "一次投掷3个红工具", "一次投掷4个红工具", "一次投掷2个红工具,同时消耗2弹药;不影响燧石板、跳蚤酿造、等离子药瓶", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 3, QuickSlingWhiteSlotModifier: false, 3.0, 3), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 4, QuickSlingWhiteSlotModifier: false, 4.0, 4), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: true, 2.0, 2)); } public static class ReserveBindTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Reserve Bind", IsBlue: true, "免费治疗2次", "免费治疗3次", "免费治疗一次:消耗储备而不消耗丝线轴上的丝线;用完后须坐椅子恢复", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 2), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 3), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: false, 0, ReserveWhiteKillRepair: true)); } public static class RevengeCrystalRules { public static bool ShouldSpawnExtras(bool equipped, bool inWhiteSlot, int effectiveLevel, int configuredCount) { if (equipped && effectiveLevel >= 2) { return configuredCount >= 2; } return false; } public static int ExtraCount(int configuredCount) { return Math.Max(0, configuredCount - 1); } } public static class RevengeCrystalTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Revenge Crystal", IsBlue: true, "生成2冰像", "生成3冰像", "受击后延迟生成冰像,敌人接触或被Hornet攻击命中时爆炸(伤害10/16/22/28/34)", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 2), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 3), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: false, DazzleWhiteOnHit: false, 0, RevengeWhiteOnHeal: true)); } public sealed class RevengeCrystalWhiteSlotDriver : IDisposable { public const string ToolName = "Revenge Crystal"; private readonly ManualLogSource _log; private readonly GameEventHub _events; private readonly Func _isBindHeal; private readonly Func _isEquippedInWhiteSlot; private readonly Func _effectsFor; private readonly Action _spawn; private bool _started; private bool _warned; public RevengeCrystalWhiteSlotDriver(ManualLogSource log, GameEventHub events, Func isBindHeal, Func isEquippedInWhiteSlot, Func effectsFor, Action spawn) { _log = log ?? throw new ArgumentNullException("log"); _events = events ?? throw new ArgumentNullException("events"); _isBindHeal = isBindHeal ?? throw new ArgumentNullException("isBindHeal"); _isEquippedInWhiteSlot = isEquippedInWhiteSlot ?? throw new ArgumentNullException("isEquippedInWhiteSlot"); _effectsFor = effectsFor ?? throw new ArgumentNullException("effectsFor"); _spawn = spawn ?? throw new ArgumentNullException("spawn"); } public void Start() { if (!_started) { _started = true; _events.HealResolved += OnHealResolved; } } public void Dispose() { _started = false; _events.HealResolved -= OnHealResolved; } private void OnHealResolved(HealEvent e) { if (!_started) { return; } try { bool flag = _isEquippedInWhiteSlot("Revenge Crystal"); bool revengeWhiteOnHeal = _effectsFor("Revenge Crystal").RevengeWhiteOnHeal; if (e.Requested > 0 && flag && revengeWhiteOnHeal && _isBindHeal(e.SourceTag)) { _spawn(1); } } catch (Exception ex) { WarnOnce(ex); } } private void WarnOnce(Exception ex) { if (!_warned) { _warned = true; _log.LogWarning((object)("[RevengeCrystalWhiteSlot] trigger failed: " + ex.Message)); } } } public static class SpoolExtenderTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Spool Extender", IsBlue: true, "丝线轴上限+6缕", "丝线轴上限+9缕", "丝线轴上限+3缕(即使尚未拾取茧也生效)", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 6), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 9), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: false, BrollyWhiteSilk: false, 0.0, QuickBindWhiteExtra: false, 0, SilkCapWhiteDouble: true)); } public static class ThiefClawTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Thief Claw", IsBlue: true, "伤害=基础针刺伤害的0.5倍", "伤害=基础针刺伤害", "丝线爪击(Clawline)增加第三段攻击:伤害=基础针刺伤害的0.25倍,同时偷取敌人念珠与碎片", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 2.0), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 4.0), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: true)); } public static class WhiteRingTool { public static ToolDefinition Definition { get; } = new ToolDefinition("White Ring", IsBlue: true, "丝线被动再生速度+70%;可再生的丝线上限+2缕", "丝线被动再生速度+105%;可再生的丝线上限+3缕", "丝线被动再生速度+35%;可再生的丝线上限+1缕", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 2, 1.7), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 3, 2.05), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: false, 0, 0f, 0, 0, 0, 0, 0.0, SilkRegenNoResetOnChange: true)); } public static class WispLanternTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Wisp Lantern", IsBlue: true, "每2秒召唤一个", "每1秒召唤一个", "附近有敌人时每4秒消耗1缕丝线召唤一个Wisp自动攻击", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 2f), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 1f), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: true)); } public static class ZapImbuementTool { public static ToolDefinition Definition { get; } = new ToolDefinition("Zap Imbuement", IsBlue: true, "丝技能伤害+50%(仅主伤害倍率)", "丝技能伤害+75%(仅主伤害倍率)", "丝技能伤害+25%(仅主伤害倍率),并按技能附加电击tick", new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.25), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.5), new ToolEffectSpec(0, 0, 1.0, -1, LavaDamageImmune: false, ColdDebuffImmune: false, HealUninterruptible: false, PoisonStacking: false, 1.0, 1.0, 0.0, 0.0, 1.0, 0f, WispNoSilkCost: false, 0, SilkSkillCostNoHealthGate: false, 1.0, 1.0, 0.0, CrossColorSlots: false, 0, QuickSlingWhiteSlotModifier: false, 0.0, 0, MaggotImmune: false, MaggotRepairOnHeal: false, MaggotRepairOnKill: false, 1.0, ClawlineNoSilkCost: false, 0.0, SilkSkillDamageWhiteBonus: true)); } } namespace CrestsEvolve.Features.StatusIcons { public sealed class FlintBrewStackHudDriver : IDisposable { public const string FlintKey = "tool.flintstone.stack"; public const string FlintOwner = "tool-flintstone"; public const string BrewKey = "tool.fleabrew.stack"; public const string BrewOwner = "tool-fleabrew"; private readonly ManualLogSource _log; private readonly GameEventHub _events; private readonly StatusIconLedger _ledger; private readonly FlintBrewStackState _state; private readonly string _key; private readonly string _owner; private bool _started; private bool _warned; public FlintBrewStackHudDriver(ManualLogSource log, GameEventHub events, StatusIconLedger ledger, FlintBrewStackState state, string key, string owner) { _log = log ?? throw new ArgumentNullException("log"); _events = events ?? throw new ArgumentNullException("events"); _ledger = ledger ?? throw new ArgumentNullException("ledger"); _state = state ?? throw new ArgumentNullException("state"); _key = key ?? throw new ArgumentNullException("key"); _owner = owner ?? throw new ArgumentNullException("owner"); } public void Start() { if (!_started) { _started = true; _events.BenchRested += OnReset; _events.SceneChanged += OnSceneChanged; _events.ToolEquipsChanged += OnReset; _state.Changed += OnStateChanged; Write(); } } public void Refresh() { if (_started) { Write(); } } public void Dispose() { if (!_started) { return; } _started = false; _events.BenchRested -= OnReset; _events.SceneChanged -= OnSceneChanged; _events.ToolEquipsChanged -= OnReset; _state.Changed -= OnStateChanged; _state.Reset(); try { _ledger.SetVisible(_key, _owner, false); _ledger.Set(_key, _owner, 0); _ledger.SetText(_key, _owner, (string)null); } catch (Exception ex) { WarnOnce(ex); } } private void OnReset() { _state.Reset(); } private void OnSceneChanged(string scene) { _state.Reset(); } private void OnStateChanged() { Write(); } private void Write() { try { bool flag = _state.Stacks > 0; _ledger.SetMax(_key, _owner, 3); _ledger.SetVisible(_key, _owner, flag); _ledger.Set(_key, _owner, _state.Stacks); _ledger.SetColorOverride(_key, _owner, flag ? "#FFFFFF" : null); _ledger.SetText(_key, _owner, flag ? _state.Stacks.ToString() : null); } catch (Exception ex) { WarnOnce(ex); } } private void WarnOnce(Exception ex) { if (!_warned) { _warned = true; _log.LogWarning((object)("[FlintBrewStackHud] write failed: " + ex.Message)); } } } public sealed class FracturedMaskHudDriver : IDisposable { public const string ToolName = "Fractured Mask"; public const string IconOwner = "tool-equip"; private readonly ManualLogSource _log; private readonly GameEventHub _events; private readonly StatusIconLedger _ledger; private readonly FracturedMaskOptions _options; private readonly Func _isEquipped; private readonly ToolLevelService _levels; private readonly Func _isInWhiteSlot; private readonly Func _getHealth; private readonly HealthGatedChargeState _state = new HealthGatedChargeState(); private bool _started; private bool _warnedEquip; private bool _warnedWhiteSlot; private bool _warnedHealth; public FracturedMaskHudDriver(ManualLogSource log, GameEventHub events, StatusIconLedger ledger, FracturedMaskOptions options, Func isEquipped, ToolLevelService levels, Func isInWhiteSlot, Func getHealth) { _log = log; _events = events; _ledger = ledger; _options = options; _isEquipped = isEquipped; _levels = levels; _isInWhiteSlot = isInWhiteSlot; _getHealth = getHealth ?? throw new ArgumentNullException("getHealth"); } public void Start() { if (!_started && _options.Enabled) { _started = true; _events.ToolEquipsChanged += OnToolEquipsChanged; _events.BenchRested += OnBenchRested; _events.EnemyKilled += OnEnemyKilled; _events.HealthChanged += OnHealthChanged; _levels.Changed += OnLevelsChanged; OnToolEquipsChanged(); } } public bool TryRepair() { if (!_started) { return false; } bool result = _state.TryBreak(); Write(); return result; } public void Dispose() { if (_started) { _started = false; _events.ToolEquipsChanged -= OnToolEquipsChanged; _events.BenchRested -= OnBenchRested; _events.EnemyKilled -= OnEnemyKilled; _events.HealthChanged -= OnHealthChanged; _levels.Changed -= OnLevelsChanged; _state.Reset(); string text = ToolIconDefaults.ToolKey("Fractured Mask"); _ledger.SetVisible(text, "tool-equip", false); _ledger.Set(text, "tool-equip", 0); _ledger.SetColorOverride(text, "tool-equip", (string)null); } } private void OnToolEquipsChanged() { if (SafeEquipped()) { _state.SetInitial(); } else { _state.Reset(); } RefreshHealthGate(); Write(); } private void OnBenchRested() { if (SafeEquipped()) { _state.SetInitial(); } RefreshHealthGate(); Write(); } private void OnEnemyKilled(EnemyKilledEvent e) { if (SafeEquipped() && SafeWhiteSlot()) { _state.OnEnemyKilledInWhiteSlot(); Write(); } } private void OnLevelsChanged() { if (SafeEquipped()) { _state.SetInitial(); } RefreshHealthGate(); Write(); } private void OnHealthChanged(HealthChangedEvent e) { RefreshHealthGateAndWrite(); } private void RefreshHealthGateAndWrite() { RefreshHealthGate(); Write(); } private void Write() { string text = ToolIconDefaults.ToolKey("Fractured Mask"); bool flag = SafeEquipped(); _ledger.SetMax(text, "tool-equip", _state.Max); _ledger.SetVisible(text, "tool-equip", flag && _state.Charges > 0); _ledger.Set(text, "tool-equip", flag ? _state.Charges : 0); _ledger.SetColorOverride(text, "tool-equip", flag ? "#B33A3A" : null); } private void RefreshHealthGate() { try { _state.SetHealth(_getHealth()); } catch (Exception ex) { if (!_warnedHealth) { _warnedHealth = true; _log.LogWarning((object)("[FracturedMask] health query failed: " + ex.Message)); } } } private bool SafeEquipped() { try { return _isEquipped(); } catch (Exception ex) { if (!_warnedEquip) { _warnedEquip = true; _log.LogWarning((object)("[FracturedMask] equip query failed: " + ex.Message)); } return false; } } private bool SafeWhiteSlot() { try { return _isInWhiteSlot(); } catch (Exception ex) { if (!_warnedWhiteSlot) { _warnedWhiteSlot = true; _log.LogWarning((object)("[FracturedMask] white-slot query failed: " + ex.Message)); } return false; } } } public sealed record FracturedMaskOptions(bool Enabled); public static class FracturedMaskBinder { public static FracturedMaskOptions Bind(ConfigFile config, ManualLogSource log) { FracturedMaskOptions fracturedMaskOptions = new FracturedMaskOptions(config.Bind("FracturedMask", "Enabled", true, "Enable the Fractured Mask HUD charges and auto-repair (max 3, or 6 while at 1 health).").Value); log.LogDebug((object)$"[FracturedMask] config bound: enabled={fracturedMaskOptions.Enabled}"); return fracturedMaskOptions; } } public sealed class ReserveBindHudDriver : IDisposable { public const string ToolName = "Reserve Bind"; public const string IconOwner = "tool-equip"; private readonly ManualLogSource _log; private readonly GameEventHub _events; private readonly StatusIconLedger _ledger; private readonly ReserveBindOptions _options; private readonly Func _isEquipped; private readonly ToolLevelService _levels; private readonly Func _isInWhiteSlot; private readonly Func _getHealth; private readonly HealthGatedChargeState _state = new HealthGatedChargeState(); private bool _started; private bool _warnedEquip; private bool _warnedWhiteSlot; private bool _warnedHealth; public ReserveBindHudDriver(ManualLogSource log, GameEventHub events, StatusIconLedger ledger, ReserveBindOptions options, Func isEquipped, ToolLevelService levels, Func isInWhiteSlot, Func getHealth) { _log = log; _events = events; _ledger = ledger; _options = options; _isEquipped = isEquipped; _levels = levels; _isInWhiteSlot = isInWhiteSlot; _getHealth = getHealth ?? throw new ArgumentNullException("getHealth"); } public void Start() { if (!_started && _options.Enabled) { _started = true; _events.ToolEquipsChanged += OnToolEquipsChanged; _events.BenchRested += OnBenchRested; _events.EnemyKilled += OnEnemyKilled; _events.HealthChanged += OnHealthChanged; _levels.Changed += OnLevelsChanged; OnToolEquipsChanged(); } } public bool TryRestore() { if (!_started) { return false; } bool result = _state.TryUseFreeBind(); Write(); return result; } public void Dispose() { if (_started) { _started = false; _events.ToolEquipsChanged -= OnToolEquipsChanged; _events.BenchRested -= OnBenchRested; _events.EnemyKilled -= OnEnemyKilled; _events.HealthChanged -= OnHealthChanged; _levels.Changed -= OnLevelsChanged; _state.Reset(); string text = ToolIconDefaults.ToolKey("Reserve Bind"); _ledger.SetVisible(text, "tool-equip", false); _ledger.Set(text, "tool-equip", 0); } } private void OnToolEquipsChanged() { if (SafeEquipped()) { _state.SetInitial(); } else { _state.Reset(); } RefreshHealthGate(); Write(); } private void OnBenchRested() { if (SafeEquipped()) { _state.SetInitial(); } RefreshHealthGate(); Write(); } private void OnEnemyKilled(EnemyKilledEvent e) { if (!SafeEquipped() || !SafeWhiteSlot()) { return; } _state.OnEnemyKilledInWhiteSlot(); Write(); try { ReserveBindBridge.TryRepairTool?.Invoke(); } catch (Exception ex) { if (!_warnedWhiteSlot) { _warnedWhiteSlot = true; _log.LogWarning((object)("[ReserveBind] white-slot tool repair failed: " + ex.Message)); } } } private void OnLevelsChanged() { if (SafeEquipped()) { _state.SetInitial(); } RefreshHealthGate(); Write(); } private void OnHealthChanged(HealthChangedEvent e) { RefreshHealthGate(); Write(); } private void Write() { string text = ToolIconDefaults.ToolKey("Reserve Bind"); bool flag = SafeEquipped(); _ledger.SetMax(text, "tool-equip", _state.Max); _ledger.SetVisible(text, "tool-equip", flag); _ledger.Set(text, "tool-equip", flag ? _state.Charges : 0); _ledger.SetColorOverride(text, "tool-equip", (string)null); } private void RefreshHealthGate() { try { _state.SetHealth(_getHealth()); } catch (Exception ex) { if (!_warnedHealth) { _warnedHealth = true; _log.LogWarning((object)("[ReserveBind] health query failed: " + ex.Message)); } } } private bool SafeEquipped() { try { return _isEquipped(); } catch (Exception ex) { if (!_warnedEquip) { _warnedEquip = true; _log.LogWarning((object)("[ReserveBind] equip query failed: " + ex.Message)); } return false; } } private bool SafeWhiteSlot() { try { return _isInWhiteSlot(); } catch (Exception ex) { if (!_warnedWhiteSlot) { _warnedWhiteSlot = true; _log.LogWarning((object)("[ReserveBind] white-slot query failed: " + ex.Message)); } return false; } } } public sealed record ReserveBindOptions(bool Enabled); public static class ReserveBindBinder { public static ReserveBindOptions Bind(ConfigFile config, ManualLogSource log) { ReserveBindOptions reserveBindOptions = new ReserveBindOptions(config.Bind("ReserveBind", "Enabled", true, "Enable Reserve Bind extra free-bind restores (L2=1, L3=2) and white-slot kill charge.").Value); log.LogDebug((object)$"[ReserveBind] config bound: enabled={reserveBindOptions.Enabled}"); return reserveBindOptions; } } public sealed class ToolEquipIconDriver : IDisposable { private readonly ManualLogSource _log; private readonly GameEventHub _events; private readonly StatusIconLedger _ledger; private readonly Func _isEquipped; private readonly Func _isEquippedInWhiteSlot; private readonly ToolLevelService _levels; private readonly ToolExclusiveCrests _exclusive; private readonly Func _currentCrestId; private readonly IReadOnlyList _tools; private string _currentCrest = ""; private bool _warnedNotReady; public ToolEquipIconDriver(ManualLogSource log, GameEventHub events, StatusIconLedger ledger, Func isEquipped, Func? isEquippedInWhiteSlot, ToolLevelService levels, ToolExclusiveCrests exclusive, Func currentCrestId) { _log = log; _events = events; _ledger = ledger; _isEquipped = isEquipped; _isEquippedInWhiteSlot = isEquippedInWhiteSlot ?? ((Func)((string _) => false)); _levels = levels; _exclusive = exclusive; _currentCrestId = currentCrestId; _tools = ToolIconDefaults.ToolIcons; } public void Start() { _events.ToolEquipsChanged += Refresh; _events.CrestChanged += OnCrestChanged; _levels.Changed += Refresh; _currentCrest = _currentCrestId(); Refresh(); } public void Dispose() { _events.ToolEquipsChanged -= Refresh; _events.CrestChanged -= OnCrestChanged; _levels.Changed -= Refresh; } private void OnCrestChanged(CrestChangedEvent e) { _currentCrest = e.Current; Refresh(); } public void Refresh() { foreach (ToolIconDefaults.ToolIconDefault tool in _tools) { if (tool.ToolName == "Magnetite Dice" || tool.ToolName == "Fractured Mask" || tool.ToolName == "Reserve Bind") { continue; } if (tool.ToolName == "Fury of the Fallen") { string text = ToolIconDefaults.ToolKey(tool.ToolName); _ledger.SetVisible(text, "tool-equip", false); _ledger.Set(text, "tool-equip", 0); _ledger.SetColorOverride(text, "tool-equip", (string)null); continue; } bool flag = false; try { flag = _isEquipped(tool.ToolName); } catch (Exception ex) { if (!_warnedNotReady) { _warnedNotReady = true; _log.LogWarning((object)("[ToolEquipIconDriver] tool manager not ready yet; retrying on next equip event. " + ex.Message)); } break; } string text2 = ToolIconDefaults.ToolKey(tool.ToolName); bool flag2 = WhiteTools.IsWhiteTool(tool.ToolName); bool flag3 = false; try { flag3 = _isEquippedInWhiteSlot(tool.ToolName); } catch (Exception ex2) { if (!_warnedNotReady) { _warnedNotReady = true; _log.LogWarning((object)("[ToolEquipIconDriver] white-slot query failed for " + tool.ToolName + ": " + ex2.Message)); } } int num = (flag2 ? _levels.GetLevel(tool.ToolName) : _levels.EffectiveLevel(tool.ToolName)); bool flag4 = _exclusive.IsExclusiveActive(tool.ToolName, _currentCrest); bool flag5 = flag && (flag2 || flag3 || num >= 2 || flag4); _ledger.SetVisible(text2, "tool-equip", flag5); _ledger.Set(text2, "tool-equip", flag5 ? Math.Max(1, num) : 0); _ledger.SetColorOverride(text2, "tool-equip", (flag5 && (flag4 || (flag3 && !flag2))) ? "#FFFFFF" : null); } } } public static class ToolIconDefaults { public sealed record ToolIconDefault(string ToolName, string ColorHex); public static readonly IReadOnlyList ToolIcons = (from t in ToolCatalog.All where !WhiteTools.IsHiddenFromHud(t.Name) select new ToolIconDefault(t.Name, ToolCatalog.ColorHex(t.Name))).ToArray(); public static string ToolKey(string toolName) { return "tool." + toolName.Replace(' ', '_'); } public static Dictionary CreateEntries() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (ToolIconDefault toolIcon in ToolIcons) { string key = ToolKey(toolIcon.ToolName); int num = ((toolIcon.ToolName == "Magnetite Dice") ? 12 : (WhiteTools.IsWhiteTool(toolIcon.ToolName) ? 1 : 3)); dictionary[key] = new StatusIconEntryOptions(true, num, toolIcon.ColorHex, "game:tool:" + toolIcon.ToolName, "#FFFFFF"); } return dictionary; } } public sealed class WhiteBuffIconDriver : IStatusIconDriver, IDisposable { public sealed record WhiteBuffIconEntry(string Key, string ToolName, string TextureFile); public const string IconOwner = "white-buff"; public static readonly IReadOnlyList Entries = new WhiteBuffIconEntry[4] { new WhiteBuffIconEntry("white.void-heart", "Void Heart", "Unbreakable_Strength.png"), new WhiteBuffIconEntry("white.kingsoul", "Kingsoul", "Shaman_Stone.png"), new WhiteBuffIconEntry("white.weaversong", "Weaversong", "Gathering_Swarm.png"), new WhiteBuffIconEntry("white.hiveblood", "Hiveblood", "Quick_Slash.png") }; private readonly ManualLogSource _log; private readonly StatusIconLedger _ledger; private readonly GameEventHub _events; private readonly Func _isActive; private bool _started; public WhiteBuffIconDriver(ManualLogSource log, StatusIconLedger ledger, GameEventHub events, Func isActive) { _log = log ?? throw new ArgumentNullException("log"); _ledger = ledger ?? throw new ArgumentNullException("ledger"); _events = events ?? throw new ArgumentNullException("events"); _isActive = isActive ?? throw new ArgumentNullException("isActive"); } public void Start(string currentCrestId) { if (!_started) { _started = true; _events.ToolEquipsChanged += OnChanged; _events.SceneChanged += OnSceneChanged; _events.CrestChanged += OnCrestChanged; Refresh(); } } public void Dispose() { if (!_started) { return; } _started = false; _events.ToolEquipsChanged -= OnChanged; _events.SceneChanged -= OnSceneChanged; _events.CrestChanged -= OnCrestChanged; foreach (WhiteBuffIconEntry entry in Entries) { _ledger.SetVisible(entry.Key, "white-buff", false); _ledger.Set(entry.Key, "white-buff", 0); _ledger.SetColorOverride(entry.Key, "white-buff", (string)null); } } private void OnChanged() { Refresh(); } private void OnSceneChanged(string scene) { Refresh(); } private void OnCrestChanged(CrestChangedEvent e) { Refresh(); } private void Refresh() { foreach (WhiteBuffIconEntry entry in Entries) { bool flag = SafeActive(entry.ToolName); _ledger.SetVisible(entry.Key, "white-buff", flag); _ledger.Set(entry.Key, "white-buff", flag ? 1 : 0); _ledger.SetMax(entry.Key, "white-buff", 1); _ledger.SetColorOverride(entry.Key, "white-buff", flag ? "#FFFFFF" : null); } } private bool SafeActive(string toolName) { try { return _isActive(toolName); } catch (Exception ex) { _log.LogWarning((object)("[WhiteBuffIcons] gate query failed (" + toolName + "): " + ex.Message)); return false; } } } } namespace CrestsEvolve.Core.Tools { public sealed record ToolUpgradeModifiers(string ToolId, ToolColorKind Color, int Level, double DamageMultiplier, double AmmoMultiplier, double CostMultiplier, double CooldownMultiplier) { public static ToolUpgradeModifiers Identity(string toolId, ToolColorKind color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return new ToolUpgradeModifiers(toolId, color, 0, 1.0, 1.0, 1.0, 1.0); } [CompilerGenerated] public void Deconstruct(out string ToolId, out ToolColorKind Color, out int Level, out double DamageMultiplier, out double AmmoMultiplier, out double CostMultiplier, out double CooldownMultiplier) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected I4, but got Unknown ToolId = this.ToolId; Color = (ToolColorKind)(int)this.Color; Level = this.Level; DamageMultiplier = this.DamageMultiplier; AmmoMultiplier = this.AmmoMultiplier; CostMultiplier = this.CostMultiplier; CooldownMultiplier = this.CooldownMultiplier; } } public sealed class ToolUpgradeService { private readonly ToolUpgradeBalanceOptions _options; private readonly double _safetyMaxDamageMultiplier; private readonly Dictionary _levels = new Dictionary(StringComparer.Ordinal); private long _revision; public long Revision => _revision; public bool Enabled => _options.Enabled; public ToolUpgradeService(ToolUpgradeBalanceOptions options, double safetyMaxDamageMultiplier) { _options = options ?? throw new ArgumentNullException("options"); _safetyMaxDamageMultiplier = safetyMaxDamageMultiplier; } public int GetLevel(string toolId) { if (string.IsNullOrWhiteSpace(toolId)) { throw new ArgumentException("Tool id is required.", "toolId"); } if (!_levels.TryGetValue(toolId, out var value)) { return 0; } return value; } public bool SetLevel(string toolId, int level) { if (string.IsNullOrWhiteSpace(toolId)) { throw new ArgumentException("Tool id is required.", "toolId"); } if (level < 0) { throw new ArgumentOutOfRangeException("level"); } int num = Math.Min(level, MaxLevelForAnyColor()); if (_levels.TryGetValue(toolId, out var value) && value == num) { return false; } _levels[toolId] = num; _revision++; return true; } public int ResetLevels(ResetReason reason) { int count = _levels.Count; if (count == 0) { return 0; } _levels.Clear(); _revision++; return count; } public ToolUpgradeModifiers Resolve(string toolId, ToolColorKind color) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(toolId)) { throw new ArgumentException("Tool id is required.", "toolId"); } if (!_options.Enabled) { return ToolUpgradeModifiers.Identity(toolId, color); } ToolColorUpgradeOptions val = _options.For(color); if (!val.Enabled) { return ToolUpgradeModifiers.Identity(toolId, color); } int num = Math.Clamp(GetLevel(toolId), 0, val.MaxLevel); double val2 = Math.Pow(val.DamageMultiplierPerLevel, num); val2 = Math.Min(val2, Math.Max(1.0, Math.Min(_options.MaxDamageMultiplier, _safetyMaxDamageMultiplier))); double val3 = Math.Pow(val.AmmoMultiplierPerLevel, num); val3 = Math.Min(val3, Math.Max(1.0, _options.MaxAmmoMultiplier)); double val4 = Math.Pow(val.CostMultiplierPerLevel, num); val4 = Math.Max(val4, Math.Clamp(_options.MinCostMultiplier, 0.0, 1.0)); double val5 = Math.Pow(val.CooldownMultiplierPerLevel, num); val5 = Math.Max(val5, Math.Clamp(_options.MinCooldownMultiplier, 0.0, 1.0)); return new ToolUpgradeModifiers(toolId, color, num, val2, val3, val4, val5); } public static double ApplyDamage(double baseDamage, ToolUpgradeModifiers modifiers) { if (baseDamage < 0.0) { throw new ArgumentOutOfRangeException("baseDamage"); } return baseDamage * modifiers.DamageMultiplier; } public static int ApplyAmmoCapacity(int baseCapacity, ToolUpgradeModifiers modifiers) { if (baseCapacity < 0) { throw new ArgumentOutOfRangeException("baseCapacity"); } return (int)Math.Round((double)baseCapacity * modifiers.AmmoMultiplier); } public static int ApplyCost(int baseCost, ToolUpgradeModifiers modifiers) { if (baseCost < 0) { throw new ArgumentOutOfRangeException("baseCost"); } if (baseCost == 0) { return 0; } int val = (int)Math.Round((double)baseCost * modifiers.CostMultiplier); return Math.Max(1, val); } public static double ApplyCooldown(double baseCooldown, ToolUpgradeModifiers modifiers) { if (baseCooldown < 0.0) { throw new ArgumentOutOfRangeException("baseCooldown"); } return baseCooldown * modifiers.CooldownMultiplier; } private int MaxLevelForAnyColor() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) int num = 0; ToolColorKind[] array = new ToolColorKind[4]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); ToolColorKind[] array2 = (ToolColorKind[])(object)array; foreach (ToolColorKind val in array2) { num = Math.Max(num, _options.For(val).MaxLevel); } return num; } } } namespace CrestsEvolve.Core.State { public sealed class HealthGatedChargeState { public const int NormalMax = 3; public const int LowHealthMax = 6; public const int Initial = 3; public int Charges { get; private set; } public int Max { get; private set; } = 3; public void SetInitial() { Charges = 3; Max = 3; } public void SetHealth(int health) { Max = ((health == 1) ? 6 : 3); if (Charges > Max) { Charges = Max; } } public bool TryBreak() { if (Charges <= 1) { Charges = 0; return false; } Charges--; return true; } public bool TryUseFreeBind() { if (Charges <= 0) { return false; } Charges--; return true; } public void OnEnemyKilledInWhiteSlot() { Charges = Math.Min(Max, Charges + 1); } public void Reset() { Charges = 0; Max = 3; } } } namespace CrestsEvolve.ToolsAscension { [BepInPlugin("local.crestsevolve.toolsascension", "TOOLS ASCENSION", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "local.crestsevolve.toolsascension"; public const string PluginName = "TOOLS ASCENSION"; public const string PluginVersion = "0.1.0"; private Harmony? _harmony; private ToolsBootstrap? _bootstrap; private void Awake() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown _harmony = new Harmony("local.crestsevolve.toolsascension"); _bootstrap = new ToolsBootstrap(((BaseUnityPlugin)this).Logger, ((BaseUnityPlugin)this).Config, _harmony); _bootstrap.Start(); } private void OnDestroy() { _bootstrap?.Dispose(); Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } } namespace CrestsEvolve.ToolsAscension.Features.Tools { public static class ToolDescriptionText { private static readonly Dictionary WhiteSlotTexts = new Dictionary(StringComparer.OrdinalIgnoreCase) { ["Bell Bind"] = "释放技能时触发护盾(丝之矛/灵丝风暴/十字绣/符文之怒,收招结束);白槽时缚丝不再释放护盾", ["Brolly Spike"] = "旋转斩击回丝", ["Dazzle Bind"] = "受击触发闪光", ["Dazzle Bind Upgraded"] = "受击触发闪光", ["Flea Charm"] = "无需满血也减耗", ["Fractured Mask"] = "白槽击杀+1充能(上限6)", ["Lava Charm"] = "抵御寒冷debuff", ["Longneedle"] = "命中框长度再×1.20", ["Maggot Charm"] = "击杀修复花环", ["Mosscreep Tool 1"] = "受击直接产丝1缕", ["Mosscreep Tool 2"] = "受击直接产丝2缕", ["Multibind"] = "每段治疗3格", ["Pinstress Tool"] = "蓄力回丝×3", ["Poison Pouch"] = "重复命中叠加中毒时间", ["Quick Sling"] = "修饰工具单次动作增强(持续×2、药瓶+2蓝/紫血)", ["Quickbind"] = "额外加快治疗", ["Reserve Bind"] = "白槽击杀+1充能并修复", ["Revenge Crystal"] = "Bind实际回血生成1冰像", ["Spool Extender"] = "丝线上限翻倍", ["Thief Claw"] = "爪击免丝", ["White Ring"] = "再生不因变化重置", ["Wisp Lantern"] = "召唤免丝", ["Zap Imbuement"] = "丝技能伤害再+25%", ["Barbed Wire"] = "受击伤害不再翻倍", ["Bone Necklace"] = "治疗时不可选中、不能被打断", ["Compass"] = "蓝↔黄工具互装", ["Dead Mans Purse"] = "燧石板叠层/齿轮蜂自动释放", ["Magnetite Dice"] = "格挡率不因成功格挡重置", ["Musician Charm"] = "琴声免丝", ["Rosary Magnet"] = "吸引碎片", ["Scuttlebrace"] = "空中二段冲刺", ["Shell Satchel"] = "固定碎片成本", ["Sprintmaster"] = "疾跑免丝", ["Thief Charm"] = "受击不掉念珠", ["Wallcling"] = "三段跳", ["Weighted Anklet"] = "2伤变1伤" }; public static string? Build(ToolDefinition def) { if (def == null) { return null; } StringBuilder stringBuilder = new StringBuilder(); AppendLine(stringBuilder, "L2", def.Level2Effect); AppendLine(stringBuilder, "L3", def.Level3Effect); AppendLine(stringBuilder, "LX", WhiteSlotTexts.TryGetValue(def.Name, out string value) ? value : null); if (stringBuilder.Length != 0) { return stringBuilder.ToString(); } return null; } private static void AppendLine(StringBuilder sb, string label, string? text) { if (!string.IsNullOrWhiteSpace(text) && !string.Equals(text.Trim(), "待实现", StringComparison.Ordinal)) { if (sb.Length > 0) { sb.Append('\n'); } sb.Append(label).Append(':').Append(text.Trim()); } } } } namespace CrestsEvolve.ToolsAscension.Bootstrap { public sealed class ToolsBootstrap : IDisposable { private sealed class ToolIconAdapter : IStatusIconDriver, IDisposable { private readonly ToolEquipIconDriver _toolEquip; private readonly FracturedMaskHudDriver _fracturedMask; private readonly ReserveBindHudDriver _reserveBind; public ToolIconAdapter(ToolEquipIconDriver toolEquip, FracturedMaskHudDriver fracturedMask, ReserveBindHudDriver reserveBind) { _toolEquip = toolEquip; _fracturedMask = fracturedMask; _reserveBind = reserveBind; } public void Start(string currentCrestId) { _toolEquip.Start(); _fracturedMask.Start(); _reserveBind.Start(); } public void Dispose() { _toolEquip.Dispose(); _fracturedMask.Dispose(); _reserveBind.Dispose(); } } private readonly ManualLogSource _log; private readonly ConfigFile _config; private readonly Harmony _harmony; private ToolLevelService? _toolLevels; private ToolUpgradeService? _toolUpgradeService; private ToolUpgradeFeature? _toolUpgradeFeature; private WhiteCharmLevelDriver? _whiteCharmLevels; private WhiteBuffIconDriver? _whiteBuffIcons; private DiceToolState? _dice; private ToolEquipIconDriver? _toolEquipDriver; private FracturedMaskHudDriver? _fracturedMask; private ReserveBindHudDriver? _reserveBind; private RevengeCrystalSpawner? _revengeCrystalSpawner; private RevengeCrystalWhiteSlotDriver? _revengeWhiteDriver; private FlintBrewStackHudDriver? _flintBrewStackHud; private FlintBrewStackHudDriver? _fleabrewStackHud; private CogflySpawner? _cogflySpawner; private GameObject? _cogflyTickGo; private GameObject? _shellRepairGo; private GameObject? _toolEquipBridgeGo; private readonly List _patchedMethods = new List(); private Action? _maggotHealRepair; private Action? _maggotKillRepair; private bool _disposed; public ToolsBootstrap(ManualLogSource log, ConfigFile config, Harmony harmony) { _log = log; _config = config; _harmony = harmony; } public void Start() { //IL_057a: Unknown result type (might be due to invalid IL or missing references) //IL_0584: Expected O, but got Unknown FoundationServices services = FoundationServices.Current; if (services == null) { _log.LogWarning((object)"[ToolsAscension] foundation not loaded; tools disabled."); return; } FoundationServices obj = services; BalanceOptions obj2 = services.Balance.$(); obj2.set_Tools(BalanceBinder.BindTools(_config)); obj.Balance = obj2; RegisterToolDescriptions(); ToolEffectsOptions toolOptions = ToolEffectsBinder.Bind(_config, _log); FracturedMaskOptions options = FracturedMaskBinder.Bind(_config, _log); ReserveBindOptions options2 = ReserveBindBinder.Bind(_config, _log); _toolLevels = new ToolLevelService(); _toolUpgradeService = new ToolUpgradeService(services.Balance.Tools.Upgrades, services.Balance.Safety.MaxDamageMultiplier); _toolUpgradeFeature = new ToolUpgradeFeature(_log, services.Events, services.Game, _toolUpgradeService, _toolLevels, services.Balance.Tools.Upgrades); _toolUpgradeFeature.Start(); _whiteCharmLevels = new WhiteCharmLevelDriver(_log, services.Events, _toolLevels, (string name) => WhiteToolSystem.IsEquippedAnywhere(name)); _whiteCharmLevels.Start(); WhiteBuffOptions whiteBuffOptions = WhiteBuffOptions.Bind(_config, _log); Func isVoidHeartBuffActive = () => whiteBuffOptions.Enabled && WhiteToolSystem.IsEquippedInWhiteSlot("Void Heart"); Func isKingsoulBuffActive = () => whiteBuffOptions.Enabled && WhiteToolSystem.IsEquippedInWhiteSlot("Kingsoul"); Func isWeaversongBuffActive = () => whiteBuffOptions.Enabled && WhiteToolSystem.IsEquippedInWhiteSlot("Weaversong"); Func isHivebloodBuffActive = () => whiteBuffOptions.Enabled && WhiteToolSystem.IsEquippedInWhiteSlot("Hiveblood"); Func isActive = (string toolName) => toolName switch { "Void Heart" => isVoidHeartBuffActive(), "Kingsoul" => isKingsoulBuffActive(), "Weaversong" => isWeaversongBuffActive(), "Hiveblood" => isHivebloodBuffActive(), _ => false, }; ToolExclusiveCrests exclusive = new ToolExclusiveCrests(toolOptions.DiceExclusiveCrest); Func isIoniaEquipped = delegate { try { return WhiteToolSystem.IsEquippedAnywhere("Ionia"); } catch { return false; } }; bool critProbeLogged = false; _dice = new DiceToolState(services.StatusLedger, () => string.Equals(services.Game.CurrentCrestId, toolOptions.DiceExclusiveCrest, StringComparison.OrdinalIgnoreCase), () => ToolItemManager.IsToolEquipped("Magnetite Dice"), isIoniaEquipped, () => string.Equals(services.Game.CurrentCrestId, "wanderer", StringComparison.OrdinalIgnoreCase), () => toolOptions.DiceBlockChancePercent, () => toolOptions.DiceCritChancePercent, delegate { HeroController instance = HeroController.instance; float num = (((Object)(object)instance != (Object)null) ? (Gameplay.WandererCritChance * instance.GetLuckModifier()) : 0f); if (!critProbeLogged && (Object)(object)instance != (Object)null) { critProbeLogged = true; _log.LogInfo((object)($"[WandererRune][probe] effectiveCritChance={num} " + $"(WandererCritChance={Gameplay.WandererCritChance}, luck={instance.GetLuckModifier()})")); } return num; }); StatusIconTextureService.IsWhiteToolIconKey = (string key) => WhiteTools.IsWhiteToolIconKey(key); RegisterIcons(services); _whiteBuffIcons = new WhiteBuffIconDriver(_log, services.StatusLedger, services.Events, isActive); _toolEquipDriver = new ToolEquipIconDriver(_log, services.Events, services.StatusLedger, (string name) => ToolItemManager.IsToolEquipped(name), (string name) => WhiteToolSystem.IsEquippedInWhiteSlot(name), _toolLevels, exclusive, () => services.Game.CurrentCrestId); _fracturedMask = new FracturedMaskHudDriver(_log, services.Events, services.StatusLedger, options, () => ToolItemManager.IsToolEquipped("Fractured Mask"), _toolLevels, () => WhiteToolSystem.IsEquippedInWhiteSlot("Fractured Mask"), () => services.Game.CurrentHealth); _fracturedMask.Start(); FracturedMaskBridge.IsEquipped = () => ToolItemManager.IsToolEquipped("Fractured Mask"); FracturedMaskBridge.TryRepair = () => _fracturedMask.TryRepair(); _reserveBind = new ReserveBindHudDriver(_log, services.Events, services.StatusLedger, options2, () => ToolItemManager.IsToolEquipped("Reserve Bind"), _toolLevels, () => WhiteToolSystem.IsEquippedInWhiteSlot("Reserve Bind"), () => services.Game.CurrentHealth); _reserveBind.Start(); ReserveBindBridge.IsEquipped = () => ToolItemManager.IsToolEquipped("Reserve Bind"); ReserveBindBridge.TryRestore = () => _reserveBind.TryRestore(); ReserveBindBridge.TryRepairTool = delegate { //IL_0017: Unknown result type (might be due to invalid IL or missing references) ToolItem toolByName = ToolItemManager.GetToolByName("Reserve Bind"); if ((Object)(object)toolByName == (Object)null) { return false; } if (toolByName.SavedData.AmountLeft > 0) { return false; } toolByName.CollectFree(1); return true; }; services.StatusIcons.RegisterDriver((IStatusIconDriver)(object)new ToolIconAdapter(_toolEquipDriver, _fracturedMask, _reserveBind)); services.StatusIcons.RegisterDriver((IStatusIconDriver)(object)_whiteBuffIcons); services.StatusIcons.AddTick((Action)delegate { _dice.Tick(); }); services.StatusIcons.Start(services.Game.CurrentCrestId); _toolEquipBridgeGo = new GameObject("CrestsEvolveToolEquipRefresh"); Object.DontDestroyOnLoad((Object)(object)_toolEquipBridgeGo); _toolEquipBridgeGo.AddComponent().Initialize(services.Events, _toolEquipDriver); InstallToolUpgradePatches(services); InstallBlueToolPatches(services); InstallFsmPatches(services); InstallMiscPatches(); InstallDeadPurseShellSatchelSystems(services); InstallWhiteBuffPatches(whiteBuffOptions, isVoidHeartBuffActive, isKingsoulBuffActive, isWeaversongBuffActive, isHivebloodBuffActive); _log.LogInfo((object)"[ToolsAscension] tools wired."); } private void RegisterIcons(FoundationServices services) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown Dictionary dictionary = ToolIconDefaults.CreateEntries(); Dictionary dictionary2 = new Dictionary(StringComparer.Ordinal); foreach (KeyValuePair item in dictionary) { StatusIconEntryOptions val = StatusIconBinder.BindIcon(_config, "UI.StatusIcons." + item.Key, item.Key, item.Value); dictionary2[item.Key] = val; services.StatusIcons.RegisterIcon(new StatusIconDefinition(item.Key, "tool-equip", val.Max)); } RegisterStackIcon(services, dictionary2, "tool.flintstone.stack", "tool-flintstone", "game:tool:Flintstone"); RegisterStackIcon(services, dictionary2, "tool.fleabrew.stack", "tool-fleabrew", "game:tool:Flea Brew"); RegisterWhiteBuffIcons(services, dictionary2); services.StatusOptions.RegisterIconOptions((IEnumerable>)dictionary2); } private void RegisterWhiteBuffIcons(FoundationServices services, Dictionary entries) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown foreach (WhiteBuffIconDriver.WhiteBuffIconEntry entry in WhiteBuffIconDriver.Entries) { StatusIconEntryOptions val = new StatusIconEntryOptions(true, 1, "#FFFFFF", entry.TextureFile, "#FFFFFF"); StatusIconEntryOptions value = StatusIconBinder.BindIcon(_config, "UI.StatusIcons." + entry.Key, entry.Key, val); entries[entry.Key] = value; services.StatusIcons.RegisterIcon(new StatusIconDefinition(entry.Key, "white-buff", 1)); } } private void RegisterStackIcon(FoundationServices services, Dictionary entries, string key, string owner, string texture) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown StatusIconEntryOptions val = new StatusIconEntryOptions(true, 3, "#FFFFFF", texture, "#FFFFFF"); StatusIconEntryOptions value = StatusIconBinder.BindIcon(_config, "UI.StatusIcons." + key, key, val); entries[key] = value; services.StatusIcons.RegisterIcon(new StatusIconDefinition(key, owner, 3)); } private void RegisterToolDescriptions() { foreach (ToolDefinition item in BlueTools.All) { ToolDescriptionRegistry.Register(item.Name, ToolDescriptionText.Build(item)); } foreach (ToolDefinition item2 in YellowTools.All) { ToolDescriptionRegistry.Register(item2.Name, ToolDescriptionText.Build(item2)); } } private void UnregisterToolDescriptions() { foreach (ToolDefinition item in BlueTools.All) { ToolDescriptionRegistry.Register(item.Name, (string)null); } foreach (ToolDefinition item2 in YellowTools.All) { ToolDescriptionRegistry.Register(item2.Name, (string)null); } } private void InstallToolUpgradePatches(FoundationServices services) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Expected O, but got Unknown //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Expected O, but got Unknown //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Expected O, but got Unknown //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Expected O, but got Unknown //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Expected O, but got Unknown //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Expected O, but got Unknown ToolUpgradePatches.Configure(_log); ToolUpgradePatches.Resolve = delegate(ToolItem tool) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)tool == (Object)null) { return (ToolUpgradeModifiers?)null; } ToolColorKind color = default(ToolColorKind); return (!services.Game.TryGetToolColor(tool.name, ref color)) ? null : _toolUpgradeService.Resolve(tool.name, color); }; ToolUpgradePatches.ToolUsed = delegate(string toolId, string binding) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown services.Events.PublishToolUsed(new ToolUsedEvent(toolId, binding)); }; MethodInfo methodInfo = AccessTools.Method(typeof(HealthManager), "Hit", new Type[1] { typeof(HitInstance) }, (Type[])null); if (methodInfo != null) { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ToolUpgradePatches), "HitDamagePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo); } MethodInfo methodInfo2 = AccessTools.Method(typeof(ToolItemManager), "GetToolStorageAmount", (Type[])null, (Type[])null); if (methodInfo2 != null) { _harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(ToolUpgradePatches), "GetToolStorageAmountPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(BlueToolEffectPatches), "CompassStoragePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo2); } MethodInfo methodInfo3 = AccessTools.PropertyGetter(typeof(ToolItem), "ReplenishUsageMultiplier"); if (methodInfo3 != null) { _harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(ToolUpgradePatches), "ReplenishUsageMultiplierPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(BlueToolEffectPatches), "ReplenishUsageMultiplierPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo3); } string[] array = new string[4] { "ToolItemBasic", "ToolItemLerpStates", "ToolItemStates", "ToolItemStatesLiquid" }; for (int num = 0; num < array.Length; num++) { Type type = AccessTools.TypeByName(array[num]); if (!(type == null)) { MethodInfo methodInfo4 = AccessTools.PropertyGetter(type, "ThrowCooldown"); if (methodInfo4 != null) { _harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(typeof(ToolUpgradePatches), "UsageCooldownPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo4); } } } MethodInfo methodInfo5 = AccessTools.Method(typeof(ToolItemManager), "ReportBoundAttackToolUsed", (Type[])null, (Type[])null); if (methodInfo5 != null) { _harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, new HarmonyMethod(typeof(ToolUpgradePatches), "ReportBoundAttackToolUsedPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo5); } } private void InstallBlueToolPatches(FoundationServices services) { //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Expected O, but got Unknown //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Expected O, but got Unknown //IL_02bf: Expected O, but got Unknown //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Expected O, but got Unknown //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Expected O, but got Unknown //IL_036e: Unknown result type (might be due to invalid IL or missing references) //IL_0383: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Unknown result type (might be due to invalid IL or missing references) //IL_03a4: Expected O, but got Unknown //IL_03a4: Expected O, but got Unknown //IL_03a4: Expected O, but got Unknown //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_03f9: Expected O, but got Unknown //IL_0411: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_0433: Expected O, but got Unknown //IL_0433: Expected O, but got Unknown //IL_044b: Unknown result type (might be due to invalid IL or missing references) //IL_0459: Expected O, but got Unknown //IL_0471: Unknown result type (might be due to invalid IL or missing references) //IL_0486: Unknown result type (might be due to invalid IL or missing references) //IL_0493: Expected O, but got Unknown //IL_0493: Expected O, but got Unknown //IL_04ec: Unknown result type (might be due to invalid IL or missing references) //IL_04fa: Expected O, but got Unknown //IL_0542: Unknown result type (might be due to invalid IL or missing references) //IL_0550: Expected O, but got Unknown //IL_0598: Unknown result type (might be due to invalid IL or missing references) //IL_05ad: Unknown result type (might be due to invalid IL or missing references) //IL_05ba: Expected O, but got Unknown //IL_05ba: Expected O, but got Unknown //IL_094c: Unknown result type (might be due to invalid IL or missing references) //IL_095a: Expected O, but got Unknown //IL_09a3: Unknown result type (might be due to invalid IL or missing references) //IL_09b0: Expected O, but got Unknown //IL_09f8: Unknown result type (might be due to invalid IL or missing references) //IL_0a06: Expected O, but got Unknown //IL_0a4f: Unknown result type (might be due to invalid IL or missing references) //IL_0a5c: Expected O, but got Unknown //IL_0b88: Unknown result type (might be due to invalid IL or missing references) //IL_0b9d: Unknown result type (might be due to invalid IL or missing references) //IL_0baa: Expected O, but got Unknown //IL_0baa: Expected O, but got Unknown //IL_0bf3: Unknown result type (might be due to invalid IL or missing references) //IL_0c00: Expected O, but got Unknown //IL_0c67: Unknown result type (might be due to invalid IL or missing references) //IL_0c75: Expected O, but got Unknown //IL_0c8e: Unknown result type (might be due to invalid IL or missing references) //IL_0c9c: Expected O, but got Unknown //IL_0ce3: Unknown result type (might be due to invalid IL or missing references) //IL_0cf0: Expected O, but got Unknown //IL_0e71: Unknown result type (might be due to invalid IL or missing references) //IL_0e86: Unknown result type (might be due to invalid IL or missing references) //IL_0e93: Expected O, but got Unknown //IL_0e93: Expected O, but got Unknown BlueToolEffectPatches.Configure(_log); BlueToolEffectPatches.GetLevel = (string name) => _toolLevels.EffectiveLevel(name); BlueToolEffectPatches.IsEquippedInWhiteSlot = (string name) => WhiteToolSystem.IsEquippedInWhiteSlot(name); services.Events.ToolUsed += BlueToolEffectPatches.OnToolUsed; _revengeCrystalSpawner = new RevengeCrystalSpawner(_log); services.Events.SceneChanged += delegate { _revengeCrystalSpawner?.OnSceneChanged(); }; BlueToolEffectPatches.SpawnRevengeCrystals = delegate(int count) { _revengeCrystalSpawner?.SpawnStaggered(count); }; _revengeWhiteDriver = new RevengeCrystalWhiteSlotDriver(_log, services.Events, (string tag) => IsBindHealSource(tag), (string name) => WhiteToolSystem.IsEquippedInWhiteSlot(name), BlueToolEffectPatches.EffectsFor, delegate(int count) { _revengeCrystalSpawner?.Spawn(count); }); _revengeWhiteDriver.Start(); BlueToolEffectPatches.AddExtraBlueHealth = delegate(int amount) { if (amount <= 0) { return; } try { GameManager instance = GameManager.instance; if (!((Object)(object)instance == (Object)null)) { for (int i = 0; i < amount; i++) { instance.AddBlueHealthQueued(); } } } catch (Exception ex) { _log.LogWarning((object)("[BlueToolEffects] AddExtraBlueHealth failed: " + ex.Message)); } }; WhiteSlotToolFilterPatch.IsCompassWhiteActive = () => WhiteToolSystem.IsEquippedInWhiteSlot("Compass"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(PlayerData), "CurrentSilkRegenMax"), "SilkRegenMaxPostfix", "CurrentSilkRegenMax"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "WhiteRingSilkRegenTimeMultiplier"), "WhiteRingSpeedMultiplierPostfix", "WhiteRingSilkRegenTimeMultiplier"); PatchBluePrefix(AccessTools.Method(typeof(SilkSpool), "SetRegen", (Type[])null, (Type[])null), "SilkSpoolSetRegenPrefix", "SilkSpool.SetRegen"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(PlayerData), "CurrentSilkMax"), "SilkMaxPostfix", "CurrentSilkMax"); MethodInfo methodInfo = AccessTools.Method(typeof(SilkSpool), "DrawSpool", new Type[1] { typeof(int) }, (Type[])null); if (methodInfo != null) { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(BlueToolEffectPatches), "DrawSpoolPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo); } MethodInfo methodInfo2 = AccessTools.Method(typeof(HealthManager), "Hit", new Type[1] { typeof(HitInstance) }, (Type[])null); if (methodInfo2 != null) { _harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(BlueToolEffectPatches), "BrollyHitPrefix", (Type[])null), new HarmonyMethod(typeof(BlueToolEffectPatches), "BrollyHitPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(BlueToolEffectPatches), "DazzleHitPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(BlueToolEffectPatches), "BellBindHitPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo2); } MethodInfo methodInfo3 = AccessTools.Method(typeof(DamageEnemies), "DoDamage", new Type[2] { typeof(GameObject), typeof(bool) }, (Type[])null); if (methodInfo3 != null) { _harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(BlueToolEffectPatches), "DoDamagePrefix", (Type[])null), new HarmonyMethod(typeof(BlueToolEffectPatches), "DoDamagePostfix", (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(BlueToolEffectPatches), "DoDamageFinalizer", (Type[])null), (HarmonyMethod)null); _patchedMethods.Add(methodInfo3); } MethodInfo methodInfo4 = AccessTools.Method(typeof(HeroController), "TakeDamage", (Type[])null, (Type[])null); if (methodInfo4 != null) { _harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(typeof(BlueToolEffectPatches), "DazzleWhiteTakeDamagePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(BlueToolEffectPatches), "RevengeCrystalTakeDamagePrefix", (Type[])null), new HarmonyMethod(typeof(BlueToolEffectPatches), "RevengeCrystalTakeDamagePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(BlueToolEffectPatches), "HeroTakeDamagePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(BlueToolEffectPatches), "LuckyDiceTakeDamagePrefix", (Type[])null), new HarmonyMethod(typeof(BlueToolEffectPatches), "LuckyDiceTakeDamagePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo4); } MethodInfo methodInfo5 = AccessTools.Method(typeof(HeroController), "CanBeGrabbed", new Type[1] { typeof(bool) }, (Type[])null); if (methodInfo5 != null) { _harmony.Patch((MethodBase)methodInfo5, new HarmonyMethod(typeof(BlueToolEffectPatches), "CanBeGrabbedPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo5); } MethodInfo methodInfo6 = AccessTools.Method(typeof(HeroController), "CanBeBarnacleGrabbed", (Type[])null, (Type[])null); if (methodInfo6 != null) { _harmony.Patch((MethodBase)methodInfo6, new HarmonyMethod(typeof(BlueToolEffectPatches), "CanBeBarnacleGrabbedPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo6); } MethodInfo methodInfo7 = AccessTools.Method(typeof(HeroController), "DoSpecialDamage", (Type[])null, (Type[])null); if (methodInfo7 != null) { _harmony.Patch((MethodBase)methodInfo7, new HarmonyMethod(typeof(BlueToolEffectPatches), "RevengeCrystalTakeDamagePrefix", (Type[])null), new HarmonyMethod(typeof(BlueToolEffectPatches), "RevengeCrystalSpecialDamagePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo7); } PatchBluePrefix(AccessTools.Method(typeof(PlayerData), "AddShards", (Type[])null, (Type[])null), "ShardsAddPrefix", "AddShards"); PatchBluePrefix(AccessTools.Method(typeof(HeroController), "AddGeo", (Type[])null, (Type[])null), "GeoAddPrefix", "AddGeo"); PatchBluePostfix(AccessTools.Method(typeof(HeroController), "GetMaxFallVelocity", (Type[])null, (Type[])null), "MaxFallVelocityPostfix", "GetMaxFallVelocity"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "WeightedAnkletDmgKnockbackMult"), "WeightedKnockbackMultPostfix", "WeightedAnkletDmgKnockbackMult"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "WeightedAnkletDmgInvulnMult"), "WeightedInvulnMultPostfix", "WeightedAnkletDmgInvulnMult"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "BarbedWireDamageDealtMultiplier"), "BarbedWireDealtMultPostfix", "BarbedWireDamageDealtMultiplier"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "BarbedWireDamageTakenMultiplier"), "BarbedWireTakenMultPostfix", "BarbedWireDamageTakenMultiplier"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "DeadPurseHoldPercent"), "DeadPurseHoldPercentPostfix", "DeadPurseHoldPercent"); PatchBluePrefix(AccessTools.Method(typeof(HeroController), "CocoonBroken", new Type[2] { typeof(bool), typeof(bool) }, (Type[])null), "CocoonBrokenMinOneCocoonPrefix", "CocoonBroken"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "ToolReplenishCost"), "ToolReplenishCostPostfix", "ToolReplenishCost"); PatchBluePostfix(AccessTools.Method(typeof(HeroController), "GetLuckyDiceShieldThreshold", (Type[])null, (Type[])null), "LuckyDiceThresholdPostfix", "GetLuckyDiceShieldThreshold"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(HeroController), "IsWandererLucky"), "IsWandererLuckyDicePostfix", "IsWandererLucky"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "WandererCritChance"), "WandererCritChanceDicePostfix", "WandererCritChance"); PatchBluePostfix(AccessTools.Method(typeof(HeroController), "GetLuckModifier", (Type[])null, (Type[])null), "GetLuckModifierDicePostfix", "GetLuckModifier"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "MusicianCharmNeedolinRangeMult"), "MusicianRangeMultPostfix", "MusicianCharmNeedolinRangeMult"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "MusicianCharmSilkDrainTimeMult"), "MusicianDrainTimeMultPostfix", "MusicianCharmSilkDrainTimeMult"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(CheatManager), "IsSilkDrainDisabled"), "SilkDrainDisabledPostfix", "IsSilkDrainDisabled"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "ThiefCharmGeoSmallIncrease"), "ThiefSmallGeoIncreasePostfix", "ThiefCharmGeoSmallIncrease"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "ThiefCharmGeoMedIncrease"), "ThiefMedGeoIncreasePostfix", "ThiefCharmGeoMedIncrease"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "ThiefCharmGeoLargeIncrease"), "ThiefLargeGeoIncreasePostfix", "ThiefCharmGeoLargeIncrease"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "ThiefCharmGeoLoss"), "ThiefGeoLossPostfix", "ThiefCharmGeoLoss"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "ThiefCharmGeoLossLooseChance"), "ThiefGeoLossLooseChancePostfix", "ThiefCharmGeoLossLooseChance"); InstallWallclingAndTripleJumpPatches(services); MethodInfo methodInfo8 = AccessTools.Method(typeof(CurrencyObjectBase), "OnToolEquipsUpdated", (Type[])null, (Type[])null); if (methodInfo8 != null) { _harmony.Patch((MethodBase)methodInfo8, new HarmonyMethod(typeof(MagnetiteDiceMagnetPatch), "OnToolEquipsUpdatedPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo8); } MethodInfo methodInfo9 = AccessTools.Method(typeof(CurrencyObjectBase), "MagnetToolIsEquipped", (Type[])null, (Type[])null); if (methodInfo9 != null) { _harmony.Patch((MethodBase)methodInfo9, (HarmonyMethod)null, new HarmonyMethod(typeof(MagnetiteDiceMagnetPatch), "MagnetToolIsEquippedPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo9); } MethodInfo methodInfo10 = AccessTools.Method(typeof(HeroController), "DoMossToolHit", (Type[])null, (Type[])null); if (methodInfo10 != null) { _harmony.Patch((MethodBase)methodInfo10, new HarmonyMethod(typeof(BlueToolEffectPatches), "DoMossToolHitPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo10); } MethodInfo methodInfo11 = AccessTools.Method(typeof(HeroController), "UseLavaBell", (Type[])null, (Type[])null); if (methodInfo11 != null) { _harmony.Patch((MethodBase)methodInfo11, (HarmonyMethod)null, new HarmonyMethod(typeof(BlueToolEffectPatches), "UseLavaBellPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo11); } PatchBluePrefix(AccessTools.Method(typeof(HeroController), "TakeFrostDamage", (Type[])null, (Type[])null), "TakeFrostDamagePrefix", "TakeFrostDamage"); PatchBluePrefix(AccessTools.Method(typeof(HeroController), "AddFrost", (Type[])null, (Type[])null), "AddFrostPrefix", "AddFrost"); PatchBluePrefix(AccessTools.Method(typeof(HeroController), "SetFrostAmount", (Type[])null, (Type[])null), "SetFrostAmountPrefix", "SetFrostAmount"); PatchBluePrefix(AccessTools.Method(typeof(DamageTag), "OnHit", (Type[])null, (Type[])null), "DamageTagOnHitPrefix", "DamageTag.OnHit"); PatchBluePrefix(AccessTools.Method(typeof(HealthManager), "ApplyTagDamage", (Type[])null, (Type[])null), "HealthManagerApplyTagDamagePrefix", "ApplyTagDamage"); PatchBluePostfix(AccessTools.Method(typeof(TagDamageTaker), "AddDamageTagToStack", (Type[])null, (Type[])null), "TagDamageTakerAddDamageTagToStackPostfix", "AddDamageTagToStack"); MethodInfo methodInfo12 = AccessTools.Method(typeof(NailAttackBase), "OnSlashStarting", (Type[])null, (Type[])null); if (methodInfo12 != null) { _harmony.Patch((MethodBase)methodInfo12, new HarmonyMethod(typeof(BlueToolEffectPatches), "LongneedleSlashPrefix", (Type[])null), new HarmonyMethod(typeof(BlueToolEffectPatches), "LongneedleSlashPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo12); } MethodInfo methodInfo13 = AccessTools.Method(typeof(HeroWispLantern), "OnEquipsChanged", (Type[])null, (Type[])null); if (methodInfo13 != null) { _harmony.Patch((MethodBase)methodInfo13, (HarmonyMethod)null, new HarmonyMethod(typeof(BlueToolEffectPatches), "WispLanternEquipsChangedPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo13); } MethodInfo methodInfo14 = AccessTools.Method(typeof(HeroController), "TakeSilk", new Type[2] { typeof(int), typeof(SilkTakeSource) }, (Type[])null); if (methodInfo14 != null) { _harmony.Patch((MethodBase)methodInfo14, new HarmonyMethod(typeof(BlueToolEffectPatches), "TakeSilkWispPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)methodInfo14, new HarmonyMethod(typeof(BlueToolEffectPatches), "TakeSilkClawlinePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo14); } MethodInfo methodInfo15 = AccessTools.PropertyGetter(typeof(PlayerData), "SilkSkillCost"); if (methodInfo15 != null) { _harmony.Patch((MethodBase)methodInfo15, (HarmonyMethod)null, new HarmonyMethod(typeof(BlueToolEffectPatches), "SilkSkillCostPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo15); } PatchBluePostfix(AccessTools.PropertyGetter(typeof(HeroController), "CurrentNailChargeTime"), "NailChargeTimePostfix", "CurrentNailChargeTime"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(HeroController), "CurrentNailChargeBeginTime"), "NailChargeBeginTimePostfix", "CurrentNailChargeBeginTime"); PatchBluePrefix(AccessTools.Method(typeof(HeroController), "SilkGain", new Type[1] { typeof(HitInstance) }, (Type[])null), "SilkGainPrefix", "SilkGain"); PatchBluePrefix(AccessTools.Method(typeof(HeroController), "AddSilk", new Type[4] { typeof(int), typeof(bool), typeof(SilkAddSource), typeof(bool) }, (Type[])null), "AddSilkPrefix", "AddSilk"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "WandererCritMultiplier"), "WandererCritMultiplierPostfix", "WandererCritMultiplier"); PatchBluePostfix(AccessTools.PropertyGetter(typeof(Gameplay), "ZapDamageMult"), "ZapDamageMultPostfix", "ZapDamageMult"); MethodInfo methodInfo16 = AccessTools.Method(typeof(HeroController), "ThrowTool", new Type[1] { typeof(bool) }, (Type[])null); if (methodInfo16 != null) { _harmony.Patch((MethodBase)methodInfo16, new HarmonyMethod(typeof(BlueToolEffectPatches), "ThrowToolPrefix", (Type[])null), new HarmonyMethod(typeof(BlueToolEffectPatches), "ThrowToolPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo16); } PatchBluePostfix(AccessTools.Method(typeof(HeroController), "ThrowToolEnd", (Type[])null, (Type[])null), "ThrowToolEndPostfix", "ThrowToolEnd"); PatchBluePostfix(AccessTools.Method(typeof(HeroController), "ActivateQuickening", (Type[])null, (Type[])null), "ActivateQuickeningPostfix", "ActivateQuickening"); PatchBluePostfix(AccessTools.Method(typeof(HeroNailImbuement), "SetElement", (Type[])null, (Type[])null), "NailImbuementSetElementPostfix", "HeroNailImbuement.SetElement"); PatchBluePrefix(AccessTools.Method(typeof(HeroController), "AddToMaggotCharmTimer", (Type[])null, (Type[])null), "AddToMaggotCharmTimerPrefix", "AddToMaggotCharmTimer"); PatchBluePrefix(AccessTools.Method(typeof(HeroController), "DidMaggotCharmHit", (Type[])null, (Type[])null), "DidMaggotCharmHitPrefix", "DidMaggotCharmHit"); _maggotHealRepair = delegate { if (BlueToolEffectPatches.IsMaggotRepairOnHealActive()) { BlueToolEffectPatches.ResetMaggotCharmNow(); } }; _maggotKillRepair = delegate { if (BlueToolEffectPatches.IsMaggotRepairOnKillActive()) { BlueToolEffectPatches.ResetMaggotCharmNow(); } }; services.Events.HealResolved += _maggotHealRepair; services.Events.EnemyKilled += _maggotKillRepair; } private static bool IsBindHealSource(string? sourceTag) { try { HeroController instance = HeroController.instance; if ((Object)(object)instance != (Object)null && instance.cState != null && (instance.cState.focusing || instance.cState.isBinding)) { return true; } } catch { } if (sourceTag != null) { return sourceTag.IndexOf("bind", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private void InstallWallclingAndTripleJumpPatches(FoundationServices services) { //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Expected O, but got Unknown //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Expected O, but got Unknown //IL_01fd: Expected O, but got Unknown //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Expected O, but got Unknown //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Expected O, but got Unknown //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Expected O, but got Unknown //IL_0322: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Expected O, but got Unknown //IL_0344: Expected O, but got Unknown //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03ac: Expected O, but got Unknown //IL_03f9: Unknown result type (might be due to invalid IL or missing references) //IL_0406: Expected O, but got Unknown WallclingJumpPatch.Configure(_log); WallclingJumpPatch.GetLevel = (string name) => _toolLevels.EffectiveLevel(name); WallclingJumpPatch.IsEquippedInWhiteSlot = (string name) => WhiteToolSystem.IsEquippedInWhiteSlot(name); WallclingTripleJumpPatch.Configure(_log); WallclingTripleJumpPatch.IsEquippedInWhiteSlot = (string name) => WhiteToolSystem.IsEquippedInWhiteSlot(name); ScuttlebraceAirDashPatch.Configure(_log); ScuttlebraceAirDashPatch.IsEquippedInWhiteSlot = (string name) => WhiteToolSystem.IsEquippedInWhiteSlot(name); MethodInfo methodInfo = AccessTools.Method(typeof(HeroController), "HeroJump", Type.EmptyTypes, (Type[])null); if (methodInfo != null) { _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(WallclingJumpPatch), "HeroJumpPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo); } MethodInfo methodInfo2 = AccessTools.Method(typeof(HeroController), "Jump", Type.EmptyTypes, (Type[])null); if (methodInfo2 != null) { _harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(WallclingJumpPatch), "JumpPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo2); } MethodInfo methodInfo3 = AccessTools.Method(typeof(HeroController), "DoWallJump", Type.EmptyTypes, (Type[])null); if (methodInfo3 != null) { _harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(WallclingJumpPatch), "DoWallJumpPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo3); } MethodInfo methodInfo4 = AccessTools.Method(typeof(HeroController), "DoDoubleJump", Type.EmptyTypes, (Type[])null); if (methodInfo4 != null) { _harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(WallclingTripleJumpPatch), "DoDoubleJumpPrefix", (Type[])null), new HarmonyMethod(typeof(WallclingJumpPatch), "DoDoubleJumpPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(WallclingJumpPatch), "DoDoubleJumpPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo4); } MethodInfo methodInfo5 = AccessTools.Method(typeof(HeroController), "DoubleJump", Type.EmptyTypes, (Type[])null); if (methodInfo5 != null) { _harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, new HarmonyMethod(typeof(WallclingJumpPatch), "DoubleJumpPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo5); } MethodInfo methodInfo6 = AccessTools.Method(typeof(HeroController), "StartFloat", Type.EmptyTypes, (Type[])null); if (methodInfo6 != null) { _harmony.Patch((MethodBase)methodInfo6, new HarmonyMethod(typeof(WallclingTripleJumpPatch), "StartFloatPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo6); } MethodInfo methodInfo7 = AccessTools.Method(typeof(HeroController), "CanDash", Type.EmptyTypes, (Type[])null); if (methodInfo7 != null) { _harmony.Patch((MethodBase)methodInfo7, new HarmonyMethod(typeof(ScuttlebraceAirDashPatch), "CanDashPrefix", (Type[])null), new HarmonyMethod(typeof(ScuttlebraceAirDashPatch), "CanDashPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo7); } MethodInfo methodInfo8 = AccessTools.Method(typeof(HeroController), "HeroDash", new Type[1] { typeof(bool) }, (Type[])null); if (methodInfo8 != null) { _harmony.Patch((MethodBase)methodInfo8, (HarmonyMethod)null, new HarmonyMethod(typeof(ScuttlebraceAirDashPatch), "HeroDashPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo8); } MethodInfo methodInfo9 = AccessTools.Method(typeof(HeroController), "ResetAirMoves", Type.EmptyTypes, (Type[])null); if (methodInfo9 != null) { _harmony.Patch((MethodBase)methodInfo9, (HarmonyMethod)null, new HarmonyMethod(typeof(ScuttlebraceAirDashPatch), "ResetAirMovesPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo9); } } private void InstallFsmPatches(FoundationServices services) { //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Expected O, but got Unknown //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Expected O, but got Unknown //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Expected O, but got Unknown //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Expected O, but got Unknown //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Expected O, but got Unknown MultibindFsmPatch.Configure(_log); MultibindFsmPatch.GetLevel = (string name) => _toolLevels.EffectiveLevel(name); MultibindFsmPatch.IsEquippedInWhiteSlot = (string name) => WhiteToolSystem.IsEquippedInWhiteSlot(name); MultibindFsmPatch.IsEquipped = (string name) => ToolItemManager.IsToolEquipped(name); QuickbindFsmPatch.Configure(_log); QuickbindFsmPatch.GetLevel = (string name) => _toolLevels.EffectiveLevel(name); QuickbindFsmPatch.IsEquippedInWhiteSlot = (string name) => WhiteToolSystem.IsEquippedInWhiteSlot(name); QuickbindFsmPatch.IsEquipped = (string name) => ToolItemManager.IsToolEquipped(name); SprintmasterFsmPatch.Configure(_log); SprintmasterFsmPatch.GetLevel = (string name) => _toolLevels.EffectiveLevel(name); SprintmasterFsmPatch.IsEquipped = (string name) => ToolItemManager.IsToolEquipped(name); MagnetiteDiceMagnetPatch.Configure(_log); MagnetiteDiceMagnetPatch.GetLevel = (string name) => _toolLevels.EffectiveLevel(name); MagnetiteDiceMagnetPatch.IsEquippedInWhiteSlot = (string name) => WhiteToolSystem.IsEquippedInWhiteSlot(name); BellBindSkillShieldPatch.Configure(_log); BellBindSkillShieldPatch.IsEquippedInWhiteSlot = (string name) => WhiteToolSystem.IsEquippedInWhiteSlot(name); MethodInfo methodInfo = AccessTools.Method(typeof(PlayMakerFSM), "Start", (Type[])null, (Type[])null); if (methodInfo != null) { _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(MultibindFsmPatch), "OnFsmStart", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(QuickbindFsmPatch), "OnFsmStart", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(SprintmasterFsmPatch), "OnFsmStart", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(BellBindSkillShieldPatch), "OnFsmStart", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo); } MethodInfo methodInfo2 = AccessTools.Method(typeof(PlayMakerFSM), "SendEvent", new Type[1] { typeof(string) }, (Type[])null); if (methodInfo2 != null) { _harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(BellBindSkillShieldPatch), "OnSkillEvent", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo2); } PatchBluePostfix(AccessTools.Method(typeof(HeroController), "GetRageModeHealCap", (Type[])null, (Type[])null), typeof(MultibindFsmPatch), "RageHealCapPostfix", "GetRageModeHealCap"); PatchBluePostfix(AccessTools.Method(typeof(HeroController), "GetWitchHealCap", (Type[])null, (Type[])null), typeof(MultibindFsmPatch), "WitchHealCapPostfix", "GetWitchHealCap"); services.Events.ToolEquipsChanged += OnFsmRefresh; services.Events.CrestChanged += OnFsmRefresh; services.Events.SceneChanged += OnFsmRefresh; } private void InstallMiscPatches() { //IL_0063: 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_0085: Expected O, but got Unknown //IL_0085: Expected O, but got Unknown //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown //IL_00e9: Expected O, but got Unknown //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Expected O, but got Unknown //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(PlayerData), "TakeHealth", new Type[3] { typeof(int), typeof(bool), typeof(bool) }, (Type[])null); if (methodInfo != null) { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(FracturedMaskBreakPatch), "Prefix", (Type[])null), new HarmonyMethod(typeof(FracturedMaskBreakPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo); } MethodInfo methodInfo2 = AccessTools.PropertySetter(typeof(ToolItem), "SavedData"); if (methodInfo2 != null) { _harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(ReserveBindFreeBindPatch), "Prefix", (Type[])null), new HarmonyMethod(typeof(ReserveBindFreeBindPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo2); } MethodInfo methodInfo3 = AccessTools.PropertyGetter(typeof(InventoryItemTool), "DisplayName"); if (methodInfo3 != null) { _harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(WhiteToolDisplayNamePatch), "DisplayNamePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo3); } else { _log.LogWarning((object)"[WhiteToolDisplay] InventoryItemTool.get_DisplayName not found; white tool page names fallback disabled."); } MethodInfo methodInfo4 = AccessTools.PropertyGetter(typeof(InventoryItemTool), "Description"); if (methodInfo4 != null) { _harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(typeof(WhiteToolDisplayNamePatch), "DescriptionPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo4); } else { _log.LogWarning((object)"[WhiteToolDisplay] InventoryItemTool.get_Description not found; white tool page descriptions fallback disabled."); } } private void InstallWhiteBuffPatches(WhiteBuffOptions options, Func isVoidHeartActive, Func isKingsoulActive, Func isWeaversongActive, Func isHivebloodActive) { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Expected O, but got Unknown WhiteBuffDamagePatch.IsVoidHeartActive = isVoidHeartActive; WhiteBuffDamagePatch.IsKingsoulActive = isKingsoulActive; WhiteBuffDamagePatch.IsWeaversongActive = isWeaversongActive; WhiteBuffDamagePatch.VoidHeartMultiplier = options.VoidHeartNeedleDamageMultiplier; WhiteBuffDamagePatch.KingsoulMultiplier = options.KingsoulSkillDamageMultiplier; WhiteBuffDamagePatch.WeaversongMultiplier = options.WeaversongToolDamageMultiplier; WhiteBuffAttackIntervalPatch.IsActive = isHivebloodActive; WhiteBuffAttackIntervalPatch.IntervalFactor = options.HivebloodAttackIntervalFactor; MethodInfo methodInfo = AccessTools.Method(typeof(HealthManager), "Hit", new Type[1] { typeof(HitInstance) }, (Type[])null); if (methodInfo != null) { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(WhiteBuffDamagePatch), "HitPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo); } else { _log.LogWarning((object)"[WhiteBuffs] HealthManager.Hit not found; white buff damage multipliers disabled."); } MethodInfo[] array = new MethodInfo[5] { AccessTools.PropertyGetter(typeof(HeroControllerConfig), "AttackDuration"), AccessTools.PropertyGetter(typeof(HeroControllerConfig), "AttackRecoveryTime"), AccessTools.PropertyGetter(typeof(HeroControllerConfig), "AttackCooldownTime"), AccessTools.PropertyGetter(typeof(HeroControllerConfig), "QuickAttackCooldownTime"), AccessTools.PropertyGetter(typeof(HeroControllerConfigWarrior), "QuickAttackCooldownTime") }; foreach (MethodInfo methodInfo2 in array) { if (!(methodInfo2 == null)) { _harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(WhiteBuffAttackIntervalPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo2); } } } private void InstallDeadPurseShellSatchelSystems(FoundationServices services) { //IL_00e6: 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) //IL_0108: Expected O, but got Unknown //IL_0108: Expected O, but got Unknown //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Expected O, but got Unknown //IL_0172: Expected O, but got Unknown //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Expected O, but got Unknown //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Expected O, but got Unknown //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Expected O, but got Unknown //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Expected O, but got Unknown //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Expected O, but got Unknown //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Expected O, but got Unknown //IL_0439: Unknown result type (might be due to invalid IL or missing references) //IL_0443: Expected O, but got Unknown //IL_04d7: Unknown result type (might be due to invalid IL or missing references) //IL_04ec: Unknown result type (might be due to invalid IL or missing references) //IL_04f9: Expected O, but got Unknown //IL_04f9: Expected O, but got Unknown //IL_0512: Unknown result type (might be due to invalid IL or missing references) //IL_0520: Expected O, but got Unknown FlintBrewStackPatch.Configure(_log); FlintBrewStackBridge.IsActive = () => WhiteToolSystem.IsEquippedInWhiteSlot("Dead Mans Purse"); _flintBrewStackHud = new FlintBrewStackHudDriver(_log, services.Events, services.StatusLedger, FlintBrewStackBridge.FlintState, "tool.flintstone.stack", "tool-flintstone"); _flintBrewStackHud.Start(); _fleabrewStackHud = new FlintBrewStackHudDriver(_log, services.Events, services.StatusLedger, FlintBrewStackBridge.BrewState, "tool.fleabrew.stack", "tool-fleabrew"); _fleabrewStackHud.Start(); MethodInfo methodInfo = AccessTools.Method(typeof(HeroNailImbuement), "SetElement", new Type[1] { typeof(NailElements) }, (Type[])null); if (methodInfo != null) { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(FlintBrewStackPatch), "SetElementPrefix", (Type[])null), new HarmonyMethod(typeof(FlintBrewStackPatch), "SetElementPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo); } MethodInfo methodInfo2 = AccessTools.Method(typeof(HeroController), "ActivateQuickening", Type.EmptyTypes, (Type[])null); if (methodInfo2 != null) { _harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(FlintBrewStackPatch), "ActivateQuickeningPrefix", (Type[])null), new HarmonyMethod(typeof(FlintBrewStackPatch), "ActivateQuickeningPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo2); } MethodInfo methodInfo3 = AccessTools.Method(typeof(HeroController), "StopQuickening", Type.EmptyTypes, (Type[])null); if (methodInfo3 != null) { _harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(FlintBrewStackPatch), "StopQuickeningPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo3); } MethodInfo methodInfo4 = AccessTools.PropertyGetter(typeof(HeroControllerConfig), "QuickAttackSpeedMult"); if (methodInfo4 != null) { _harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(typeof(FlintBrewStackPatch), "QuickAttackSpeedMultPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo4); } MethodInfo methodInfo5 = AccessTools.PropertyGetter(typeof(HeroControllerConfig), "QuickAttackCooldownTime"); if (methodInfo5 != null) { _harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, new HarmonyMethod(typeof(FlintBrewStackPatch), "QuickAttackCooldownTimePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo5); } MethodInfo methodInfo6 = AccessTools.PropertyGetter(typeof(HeroControllerConfigWarrior), "QuickAttackCooldownTime"); if (methodInfo6 != null) { _harmony.Patch((MethodBase)methodInfo6, (HarmonyMethod)null, new HarmonyMethod(typeof(FlintBrewStackPatch), "QuickAttackCooldownTimePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo6); } MethodInfo methodInfo7 = AccessTools.Method(typeof(HealthManager), "Hit", new Type[1] { typeof(HitInstance) }, (Type[])null); if (methodInfo7 != null) { _harmony.Patch((MethodBase)methodInfo7, new HarmonyMethod(typeof(FlintBrewStackPatch), "HitPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo7); } _cogflySpawner = new CogflySpawner(_log); CogflyAutoReleasePatch.Spawner = _cogflySpawner; CogflyAutoReleasePatch.IsEnabled = () => WhiteToolSystem.IsEquippedInWhiteSlot("Dead Mans Purse") && (ToolItemManager.IsToolEquipped("Cogwork Flier") || ToolItemManager.IsToolEquipped("Cogfly")); _cogflyTickGo = new GameObject("CrestsEvolveCogflyAutoRelease"); Object.DontDestroyOnLoad((Object)(object)_cogflyTickGo); _cogflyTickGo.AddComponent(); services.Events.SceneChanged += OnCogflySceneChanged; ShellSatchelAutoRepairPatch.Configure(_log); ShellSatchelAutoRepairPatch.GetLevel = (string name) => _toolLevels.EffectiveLevel(name); ShellSatchelAutoRepairPatch.IsEquipped = () => ToolItemManager.IsToolEquipped("Shell Satchel"); ShellSatchelShardCostPatch.Configure(_log); ShellSatchelShardCostPatch.GetLevel = (string name) => _toolLevels.EffectiveLevel(name); ShellSatchelShardCostPatch.IsEquipped = () => ToolItemManager.IsToolEquipped("Shell Satchel"); _shellRepairGo = new GameObject("CrestsEvolveShellSatchelRepair"); Object.DontDestroyOnLoad((Object)(object)_shellRepairGo); _shellRepairGo.AddComponent(); services.Events.SceneChanged += OnShellSatchelReset; services.Events.ToolEquipsChanged += OnShellSatchelReset; services.Events.BenchRested += OnShellSatchelReset; MethodInfo methodInfo8 = AccessTools.PropertySetter(typeof(ToolItem), "SavedData"); if (methodInfo8 != null) { _harmony.Patch((MethodBase)methodInfo8, new HarmonyMethod(typeof(ShellSatchelAutoRepairPatch), "Prefix", (Type[])null), new HarmonyMethod(typeof(ShellSatchelAutoRepairPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)methodInfo8, new HarmonyMethod(typeof(ShellSatchelShardCostPatch), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(methodInfo8); } } private void OnCogflySceneChanged(string scene) { CogflyAutoReleasePatch.OnSceneChanged(); } private void OnShellSatchelReset() { ShellSatchelRepairRunner.CancelAll(); } private void OnShellSatchelReset(string scene) { ShellSatchelRepairRunner.CancelAll(); } private void PatchBluePrefix(MethodBase? method, string patchMethodName, string featureName) { PatchBluePrefix(method, typeof(BlueToolEffectPatches), patchMethodName, featureName); } private void PatchBluePrefix(MethodBase? method, Type patchType, string patchMethodName, string featureName) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown if (method == null) { _log.LogWarning((object)("[BlueToolEffects] " + featureName + " not found; related effect disabled.")); return; } _harmony.Patch(method, new HarmonyMethod(patchType, patchMethodName, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(method); } private void PatchBluePostfix(MethodBase? method, string patchMethodName, string featureName) { PatchBluePostfix(method, typeof(BlueToolEffectPatches), patchMethodName, featureName); } private void PatchBluePostfix(MethodBase? method, Type patchType, string patchMethodName, string featureName) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown if (method == null) { _log.LogWarning((object)("[BlueToolEffects] " + featureName + " not found; related effect disabled.")); return; } _harmony.Patch(method, (HarmonyMethod)null, new HarmonyMethod(patchType, patchMethodName, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patchedMethods.Add(method); } private void OnFsmRefresh() { OnFsmRefreshCore(); } private void OnFsmRefresh(CrestChangedEvent e) { OnFsmRefreshCore(); } private void OnFsmRefresh(string scene) { OnFsmRefreshCore(); } private static void OnFsmRefreshCore() { MultibindFsmPatch.RefreshAll(); QuickbindFsmPatch.RefreshAll(); SprintmasterFsmPatch.RefreshAll(); BellBindSkillShieldPatch.RefreshAll(); } public void Dispose() { if (_disposed) { return; } _disposed = true; FoundationServices current = FoundationServices.Current; if (current != null) { current.Events.ToolUsed -= BlueToolEffectPatches.OnToolUsed; current.Events.ToolEquipsChanged -= OnFsmRefresh; current.Events.CrestChanged -= OnFsmRefresh; current.Events.SceneChanged -= OnFsmRefresh; if (_maggotHealRepair != null) { current.Events.HealResolved -= _maggotHealRepair; } if (_maggotKillRepair != null) { current.Events.EnemyKilled -= _maggotKillRepair; } current.Events.SceneChanged -= OnCogflySceneChanged; current.Events.SceneChanged -= OnShellSatchelReset; current.Events.ToolEquipsChanged -= OnShellSatchelReset; current.Events.BenchRested -= OnShellSatchelReset; } if ((Object)(object)_toolEquipBridgeGo != (Object)null) { Object.Destroy((Object)(object)_toolEquipBridgeGo); } if ((Object)(object)_cogflyTickGo != (Object)null) { Object.Destroy((Object)(object)_cogflyTickGo); } if ((Object)(object)_shellRepairGo != (Object)null) { Object.Destroy((Object)(object)_shellRepairGo); } ShellSatchelRepairRunner.CancelAll(); _flintBrewStackHud?.Dispose(); _fleabrewStackHud?.Dispose(); FlintBrewStackBridge.FlintState.Reset(); FlintBrewStackBridge.BrewState.Reset(); _revengeWhiteDriver?.Dispose(); _reserveBind?.Dispose(); _fracturedMask?.Dispose(); _toolEquipDriver?.Dispose(); _whiteBuffIcons?.Dispose(); _whiteBuffIcons = null; _whiteCharmLevels?.Dispose(); _toolUpgradeFeature?.Dispose(); UnregisterToolDescriptions(); BellBindSkillShieldPatch.RestoreAll(); BlueToolEffectPatches.AddExtraBlueHealth = null; BlueToolEffectPatches.SpawnRevengeCrystals = null; BlueToolEffectPatches.GetLevel = null; BlueToolEffectPatches.IsEquippedInWhiteSlot = null; BellBindSkillShieldPatch.IsEquippedInWhiteSlot = null; WallclingJumpPatch.GetLevel = null; WallclingJumpPatch.IsEquippedInWhiteSlot = null; WallclingTripleJumpPatch.IsEquippedInWhiteSlot = null; ScuttlebraceAirDashPatch.IsEquippedInWhiteSlot = null; FlintBrewStackBridge.IsActive = null; CogflyAutoReleasePatch.IsEnabled = null; CogflyAutoReleasePatch.Spawner = null; ShellSatchelAutoRepairPatch.GetLevel = null; ShellSatchelAutoRepairPatch.IsEquipped = null; ShellSatchelShardCostPatch.GetLevel = null; ShellSatchelShardCostPatch.IsEquipped = null; WhiteSlotToolFilterPatch.IsCompassWhiteActive = null; ToolUpgradePatches.Resolve = null; ToolUpgradePatches.ToolUsed = null; WhiteBuffDamagePatch.IsVoidHeartActive = null; WhiteBuffDamagePatch.IsKingsoulActive = null; WhiteBuffDamagePatch.IsWeaversongActive = null; WhiteBuffDamagePatch.VoidHeartMultiplier = 1.5; WhiteBuffDamagePatch.KingsoulMultiplier = 1.5; WhiteBuffDamagePatch.WeaversongMultiplier = 1.5; WhiteBuffAttackIntervalPatch.IsActive = null; WhiteBuffAttackIntervalPatch.IntervalFactor = 0.58; StatusIconTextureService.IsWhiteToolIconKey = null; FracturedMaskBridge.IsEquipped = null; FracturedMaskBridge.TryRepair = null; ReserveBindBridge.IsEquipped = null; ReserveBindBridge.TryRestore = null; ReserveBindBridge.TryRepairTool = null; foreach (MethodBase patchedMethod in _patchedMethods) { _harmony.Unpatch(patchedMethod, (HarmonyPatchType)0, _harmony.Id); } _patchedMethods.Clear(); } } }