Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SparkleMercTweaks v1.19.0
plugins/SparkleMercTweaks.dll
Decompiled 11 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using EntityStates; using EntityStates.Merc; using HarmonyLib; using Microsoft.CodeAnalysis; using R2API; using RoR2; using RoR2.Projectile; using RoR2.Skills; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("SparkleMercTweaks")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SparkleMercTweaks")] [assembly: AssemblyTitle("SparkleMercTweaks")] [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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SparkleMercTweaks { public static class EvisZeroArmorDouble { private static ConfigEntry<bool> _enable; private static ConfigEntry<float> _multiplier; private static ManualLogSource _log; private static float _lastLogAt = -999f; private static int _appliedHits; private static bool _diagnoseLogged; private static FieldInfo _damageInfoField; public static void Init(ConfigFile cfg, ManualLogSource log) { _log = log; _damageInfoField = AccessTools.Field(typeof(HealthComponent), "damageInfo"); _enable = cfg.Bind<bool>("EvisZeroArmorDouble", "EnableDoubleDamage", true, "剔除内脏是否对护甲 <= 0 的目标造成双倍伤害。true = 启用,false = 原版行为。"); _multiplier = cfg.Bind<float>("EvisZeroArmorDouble", "DoubleDamageMultiplier", 2f, "对护甲 <= 0 的目标的伤害倍率。2 = 双倍伤害,1 = 原版。"); Log((LogLevel)16, "剔除内脏「零/负护甲双倍伤害」已载入:" + (IsEnabled() ? "已启用" : "已禁用(只剩半径改动)")); } public static bool IsEnabled() { if (_enable != null) { return _enable.Value; } return true; } public static string Summary() { string text = ((_enable != null && _enable.Value) ? "开" : "关"); float num = ((_multiplier == null) ? 2f : _multiplier.Value); return " [零护甲双倍:" + text + ((num <= 0f) ? "" : (" x" + num.ToString("0.##"))) + "]"; } public static void Patch(Harmony harmony) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown MethodBase methodBase = AccessTools.Method(typeof(HealthComponent), "TakeDamageProcess", (Type[])null, (Type[])null); if (methodBase == null) { Log((LogLevel)2, "双倍伤害补丁失败:找不到 HealthComponent.TakeDamageProcess。"); return; } HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(EvisZeroArmorDouble), "TakeDamageProcessPrefix", (Type[])null, (Type[])null)); harmony.Patch(methodBase, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log((LogLevel)16, "补丁已挂载:HealthComponent.TakeDamageProcess <- TakeDamageProcessPrefix()(零/负护甲双倍伤害)"); MethodBase methodBase2 = AccessTools.Method(typeof(Evis), "OnEnter", (Type[])null, (Type[])null); if (methodBase2 != null) { harmony.Patch(methodBase2, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(EvisZeroArmorDouble), "EvisOnEnterPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log((LogLevel)16, "补丁已挂载:Evis.OnEnter <- EvisOnEnterPostfix()(状态机自检)"); } else { Log((LogLevel)4, "自检补丁未挂载:找不到 EntityStates.Merc.Evis.OnEnter。"); } } public static void EvisOnEnterPostfix(Evis __instance) { if (_diagnoseLogged || __instance == null) { return; } _diagnoseLogged = true; try { object member = GetMember(__instance, "characterBody"); CharacterBody val = (CharacterBody)((member is CharacterBody) ? member : null); if ((Object)(object)val == (Object)null) { Log((LogLevel)4, "状态自检失败:Evis.OnEnter 里取 characterBody 为空,「双倍伤害」判定会永远不触发。"); return; } Component[] components = ((Component)val).GetComponents<Component>(); int num = 0; string text = "n/a"; if (components != null) { foreach (Component obj in components) { EntityStateMachine val2 = (EntityStateMachine)(object)((obj is EntityStateMachine) ? obj : null); if (!((Object)(object)val2 == (Object)null)) { num++; if (num == 1) { object member2 = GetMember(val2, "state"); text = ((member2 == null) ? "null" : member2.GetType().Name); } } } } Log((LogLevel)16, "状态自检:当前状态 = " + text + ",角色身上 EntityStateMachine 数量 = " + num + "(找不到的话「双倍伤害」不会生效,把这个数字发我即可定位)。"); } catch (Exception ex) { Log((LogLevel)4, "状态自检异常:" + ex.GetType().Name + " " + ex.Message); } } public static void TakeDamageProcessPrefix(HealthComponent __instance, ref DamageInfo damageInfo) { try { if (!IsEnabled()) { return; } float num = ((_multiplier == null) ? 2f : _multiplier.Value); if (num <= 0f || num == 1f || (Object)(object)__instance == (Object)null || (Object)(object)damageInfo.attacker == (Object)null) { return; } CharacterBody component = damageInfo.attacker.GetComponent<CharacterBody>(); if ((Object)(object)component == (Object)null || !IsEvisAttacker(component)) { return; } float num2 = TargetArmor(__instance); if (num2 > 0f) { return; } float damage = damageInfo.damage; damageInfo.damage = damage * num; if (_damageInfoField != null) { try { _damageInfoField.SetValue(__instance, damageInfo); } catch { } } _appliedHits++; if (Time.time - _lastLogAt >= 3f) { _lastLogAt = Time.time; Log((LogLevel)16, "剔除内脏「零护甲双倍伤害」已生效:目标护甲 " + num2.ToString("0.##") + "(<= 0)→ 伤害由 " + damage.ToString("0.##") + " 变为 " + damageInfo.damage.ToString("0.##") + "(x" + num.ToString("0.##") + ")。"); } } catch (Exception ex) { Log((LogLevel)4, "双倍伤害结算异常(已忽略):" + ex.GetType().Name + " " + ex.Message); } } private static bool IsEvisAttacker(CharacterBody attackerBody) { if ((Object)(object)attackerBody == (Object)null) { return false; } Component[] components = ((Component)attackerBody).GetComponents<Component>(); if (components == null) { return false; } foreach (Component obj in components) { EntityStateMachine val = (EntityStateMachine)(object)((obj is EntityStateMachine) ? obj : null); if ((Object)(object)val == (Object)null) { continue; } try { if (val.state is Evis) { return true; } } catch { } } return false; } private static float TargetArmor(HealthComponent healthComponent) { float num = 0f; if ((Object)(object)healthComponent == (Object)null) { return num; } if ((Object)(object)healthComponent.body != (Object)null) { num = healthComponent.body.armor; } FieldInfo fieldInfo = AccessTools.Field(typeof(HealthComponent), "adaptiveArmorValue"); if (fieldInfo != null) { try { num += Convert.ToSingle(fieldInfo.GetValue(healthComponent)); } catch { } } return num; } private static object GetMember(object instance, string memberName) { if (instance == null) { return null; } Type type = instance.GetType(); try { FieldInfo fieldInfo = AccessTools.Field(type, memberName); if (fieldInfo != null) { return fieldInfo.GetValue(instance); } PropertyInfo propertyInfo = AccessTools.Property(type, memberName); if (propertyInfo != null && propertyInfo.CanRead) { return propertyInfo.GetValue(instance, null); } } catch { return null; } return null; } private static void Log(LogLevel level, string message) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (_log != null) { _log.Log(level, (object)("[SparkleMercTweaks] " + message)); } } } public static class MercBodyStatsTweaks { private const string MercBodyPrefabName = "MercBody"; private const string MercBodyNameToken = "MERC_BODY_NAME"; private static ConfigEntry<bool> _enable; private static ConfigEntry<float> _baseRegen; private static ConfigEntry<float> _levelRegen; private static ManualLogSource _log; private static bool _logged; private static float _originalBaseRegen = -1f; private static float _originalLevelRegen = -1f; private static bool _errorLogged; public static void Init(ConfigFile cfg, ManualLogSource logger) { _log = logger; _enable = cfg.Bind<bool>("BodyStats", "Enable", true, "是否改动雇佣兵的生命恢复。关掉则完全保持原版(基础 1/s,每级 +0.2/s)。"); _baseRegen = cfg.Bind<float>("BodyStats", "BaseRegen", 2.5f, "雇佣兵的「基础生命恢复」(每秒回复量,不含等级成长)。原版是 1。\n填 0 或负数 = 不改这项。"); _levelRegen = cfg.Bind<float>("BodyStats", "LevelRegen", 0.5f, "雇佣兵「每升一级」额外获得的生命恢复(每秒)。原版是 0.2。\n填 0 或负数 = 不改这项。"); } public static void Patch(Harmony harmony) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown if (_enable != null && _enable.Value) { MethodInfo methodInfo = null; try { methodInfo = AccessTools.Method(typeof(CharacterBody), "RecalculateStats", (Type[])null, (Type[])null); } catch (Exception ex) { Log((LogLevel)2, "生命恢复改动未生效:反射拿不到 CharacterBody.RecalculateStats():" + ex.Message); return; } if (methodInfo == null) { Log((LogLevel)2, "生命恢复改动未生效:找不到 CharacterBody.RecalculateStats()。"); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(MercBodyStatsTweaks), "RecalculateStatsPrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log((LogLevel)16, "补丁已挂载:CharacterBody.RecalculateStats() <- RecalculateStatsPrefix()(雇佣兵生命恢复 MercBody)"); } } public static string Summary() { if (_enable == null || !_enable.Value) { return " [生命恢复:原版]"; } float num = ((_baseRegen == null) ? 2.5f : _baseRegen.Value); float num2 = ((_levelRegen == null) ? 0.5f : _levelRegen.Value); return " [生命恢复:" + num.ToString("0.##") + "/s 每级+" + num2.ToString("0.##") + "]"; } public static void RecalculateStatsPrefix(CharacterBody __instance) { if (_enable == null || !_enable.Value || (Object)(object)__instance == (Object)null || !IsMerc(__instance)) { return; } try { float num = ((_baseRegen == null) ? 2.5f : _baseRegen.Value); float num2 = ((_levelRegen == null) ? 0.5f : _levelRegen.Value); if (!_logged) { _logged = true; _originalBaseRegen = __instance.baseRegen; _originalLevelRegen = __instance.levelRegen; Log((LogLevel)16, "雇佣兵原版生命恢复基准:基础 " + _originalBaseRegen.ToString("0.##") + "/s、每级 +" + _originalLevelRegen.ToString("0.##") + "/s;将覆写为基础 " + ((num > 0f) ? num.ToString("0.##") : _originalBaseRegen.ToString("0.##")) + "/s、每级 +" + ((num2 > 0f) ? num2.ToString("0.##") : _originalLevelRegen.ToString("0.##")) + "/s。"); } if (num > 0f && Math.Abs(__instance.baseRegen - num) > 0.0001f) { __instance.baseRegen = num; } if (num2 > 0f && Math.Abs(__instance.levelRegen - num2) > 0.0001f) { __instance.levelRegen = num2; } } catch (Exception ex) { if (!_errorLogged) { _errorLogged = true; Log((LogLevel)4, "雇佣兵生命恢复覆写异常:" + ex.GetType().Name + " " + ex.Message); } } } private static bool IsMerc(CharacterBody body) { string baseNameToken = body.baseNameToken; if (!string.IsNullOrEmpty(baseNameToken) && baseNameToken.IndexOf("MERC", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (!string.IsNullOrEmpty(((Object)body).name)) { return ((Object)body).name.StartsWith("MercBody", StringComparison.OrdinalIgnoreCase); } return false; } private static void Log(LogLevel level, string message) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (_log != null) { _log.Log(level, (object)("[SparkleMercTweaks] " + message)); } } } public static class MercEvisTweak { private const string FallbackToken = "MERC_SPECIAL_DESCRIPTION"; private const string DescriptionZh = "向前冲锋并斩击最近的敌人,重复造成<style=cIsDamage>110%的伤害</style>。这个伤害对<style=cIsUtility>无护甲</style>目标<style=cIsDamage>翻倍</style>。过程中<style=cIsUtility>无法被攻击</style>。"; internal static ConfigEntry<float> RadiusMultiplier; internal static ConfigEntry<bool> OverrideSkillDescription; private static ManualLogSource _log; private static bool _evisCaptured; private static float _baseEvisMaxRadius; private static bool _dashCaptured; private static float _baseDashOverlapRadius; private static bool _capturedLogged; private static bool _tokenProbed; public static void Init(ConfigFile config, ManualLogSource logger) { _log = logger; RadiusMultiplier = config.Bind<float>("Eviscerate", "RadiusMultiplier", 1.5f, "剔除内脏的判定半径与伤害半径的放大倍率。1.5 = 扩大 50%(原版 1.0)。\n同时作用于两处:连续斩击的索敌 / 伤害半径,以及起手突进的判定半径。"); OverrideSkillDescription = config.Bind<bool>("Eviscerate", "OverrideSkillDescription", true, "是否把游戏内「剔除内脏」的技能说明改成与实际效果一致的描述。\n关掉则显示原版文本。改完需要重启游戏。"); } public static void ApplyRadii() { float num = RadiusMultiplier.Value; if (num <= 0f) { num = 1f; } ApplyEvisRadius(num); ApplyDashRadius(num); LogCapturedOnce(); } private static void ApplyEvisRadius(float mult) { float maxRadius = Evis.maxRadius; if (!_evisCaptured) { if (!(maxRadius > 0f)) { return; } _baseEvisMaxRadius = maxRadius; _evisCaptured = true; } Evis.maxRadius = _baseEvisMaxRadius * mult; } private static void ApplyDashRadius(float mult) { float overlapSphereRadius = EvisDash.overlapSphereRadius; if (!_dashCaptured) { if (!(overlapSphereRadius > 0f)) { return; } _baseDashOverlapRadius = overlapSphereRadius; _dashCaptured = true; } EvisDash.overlapSphereRadius = _baseDashOverlapRadius * mult; } private static void LogCapturedOnce() { if (!_capturedLogged && _evisCaptured && _dashCaptured) { _capturedLogged = true; Log((LogLevel)16, "剔除内脏原版半径已记录:斩击半径 " + _baseEvisMaxRadius.ToString("0.##") + ",突进判定半径 " + _baseDashOverlapRadius.ToString("0.##") + ",放大后分别为 " + (_baseEvisMaxRadius * RadiusMultiplier.Value).ToString("0.##") + " / " + (_baseDashOverlapRadius * RadiusMultiplier.Value).ToString("0.##")); } } public static void ApplyLanguage() { if (OverrideSkillDescription.Value) { LanguageAPI.Add("MERC_SPECIAL_DESCRIPTION", "向前冲锋并斩击最近的敌人,重复造成<style=cIsDamage>110%的伤害</style>。这个伤害对<style=cIsUtility>无护甲</style>目标<style=cIsDamage>翻倍</style>。过程中<style=cIsUtility>无法被攻击</style>。", "en"); LanguageAPI.Add("MERC_SPECIAL_DESCRIPTION", "向前冲锋并斩击最近的敌人,重复造成<style=cIsDamage>110%的伤害</style>。这个伤害对<style=cIsUtility>无护甲</style>目标<style=cIsDamage>翻倍</style>。过程中<style=cIsUtility>无法被攻击</style>。", "zh-CN"); } } public static void ProbeToken() { if (_tokenProbed || !OverrideSkillDescription.Value) { return; } GameObject val = BodyCatalog.FindBodyPrefab("MercBody"); if ((Object)(object)val == (Object)null) { return; } SkillLocator component = val.GetComponent<SkillLocator>(); if ((Object)(object)component == (Object)null || (Object)(object)component.special == (Object)null || (Object)(object)component.special.skillFamily == (Object)null) { return; } _tokenProbed = true; Variant[] variants = component.special.skillFamily.variants; if (variants == null) { return; } for (int i = 0; i < variants.Length; i++) { SkillDef skillDef = variants[i].skillDef; if ((Object)(object)skillDef == (Object)null || string.IsNullOrEmpty(skillDef.skillDescriptionToken)) { continue; } string text = null; try { text = ((SerializableEntityStateType)(ref skillDef.activationState)).typeName; } catch (Exception ex) { Log((LogLevel)4, "读取激活状态失败 " + skillDef.skillNameToken + ":" + ex.Message); continue; } if (string.IsNullOrEmpty(text) || text.IndexOf("Merc.Evis", StringComparison.Ordinal) < 0) { Log((LogLevel)16, "跳过雇佣兵 R 槽位的其它技能:" + skillDef.skillNameToken + "(激活状态 " + text + ",游戏内显示名 " + Language.GetString(skillDef.skillNameToken) + ")"); continue; } string skillDescriptionToken = skillDef.skillDescriptionToken; Log((LogLevel)16, "发现剔除内脏的技能说明 token: " + skillDescriptionToken + "(技能名 " + skillDef.skillNameToken + ",游戏内显示名 " + Language.GetString(skillDef.skillNameToken) + ")"); if (!string.Equals(skillDescriptionToken, "MERC_SPECIAL_DESCRIPTION", StringComparison.Ordinal)) { LanguageAPI.Add(skillDescriptionToken, "向前冲锋并斩击最近的敌人,重复造成<style=cIsDamage>110%的伤害</style>。这个伤害对<style=cIsUtility>无护甲</style>目标<style=cIsDamage>翻倍</style>。过程中<style=cIsUtility>无法被攻击</style>。", "en"); LanguageAPI.Add(skillDescriptionToken, "向前冲锋并斩击最近的敌人,重复造成<style=cIsDamage>110%的伤害</style>。这个伤害对<style=cIsUtility>无护甲</style>目标<style=cIsDamage>翻倍</style>。过程中<style=cIsUtility>无法被攻击</style>。", "zh-CN"); } } } public static string Summary() { return "剔除内脏(雇佣兵 R):判定半径与伤害半径 x" + RadiusMultiplier.Value.ToString("0.##") + "(每次挥砍只打 1 名敌人),对护甲 <= 0 的目标双倍伤害。" + (OverrideSkillDescription.Value ? "技能说明已更新。" : "技能说明保持原版。"); } private static void Log(LogLevel level, string message) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (_log != null) { _log.Log(level, (object)message); } } } public static class MercExposeCripple { private const uint ApplyMercExposeFlag = 8388608u; private const float VanillaBonusMultiplier = 3.5f; private static ConfigEntry<bool> _enabled; private static ConfigEntry<float> _duration; private static ConfigEntry<bool> _requireMercAttacker; private static ConfigEntry<float> _bonusMultiplier; private static ManualLogSource _log; private static BuffDef _exposeDef; private static BuffDef _crippleDef; private static bool _appliedLogged; private static float _lastLogAt = -999f; public static void Init(ConfigFile cfg, ManualLogSource logger) { _log = logger; _enabled = cfg.Bind<bool>("MercExpose", "ApplyCripple", true, "雇佣兵消耗敌人身上的「暴露」时,是否改为给这名敌人挂「残废」(降低移动速度和护甲)。\ntrue = 消耗暴露的那一下附带残废,false = 不挂残废。"); _duration = cfg.Bind<float>("MercExpose", "CrippleDuration", 3f, "「残废」的持续时间(秒)。3 = 3 秒。"); _requireMercAttacker = cfg.Bind<bool>("MercExpose", "RequireMercAttacker", true, "是否只在攻击者是雇佣兵时才挂残废。true = 只有雇佣兵消耗暴露才触发;\nfalse = 任何人(含队友、召唤物)消耗暴露都会触发。"); _bonusMultiplier = cfg.Bind<float>("MercExpose", "ExposeDamageBonusMultiplier", 0f, "消耗暴露时那笔「额外伤害」的系数(以攻击者的面板伤害 damage 为基数,是加值不是乘法)。\n0 = 取消原版那 350% 的额外伤害(默认);3.5 = 保持原版;其它值自行调整。\n改这一项需要重启游戏才生效(它在补丁里被写死进 IL)。"); } public static string Summary() { string text = " [暴露:消耗时"; text = text + ((_bonusMultiplier == null) ? 0f : _bonusMultiplier.Value).ToString("0.##") + "倍额外伤害"; if (_enabled == null || !_enabled.Value) { return text + "/无残废]"; } return text + "/残废 " + ((_duration == null) ? 2f : _duration.Value).ToString("0.##") + "秒]"; } public static void Patch(Harmony harmony) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_008c: Expected O, but got Unknown //IL_008c: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(HealthComponent), "TakeDamageProcess", (Type[])null, (Type[])null); if (methodInfo == null) { Log((LogLevel)2, "「暴露消耗改造」补丁失败:找不到 HealthComponent.TakeDamageProcess。"); return; } MethodInfo methodInfo2 = AccessTools.Method(typeof(MercExposeCripple), "CrippleExposedPrefix", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(MercExposeCripple), "CrippleExposedPostfix", (Type[])null, (Type[])null); MethodInfo methodInfo4 = AccessTools.Method(typeof(MercExposeCripple), "ExposeBonusTranspiler", (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), new HarmonyMethod(methodInfo3), new HarmonyMethod(methodInfo4), (HarmonyMethod)null, (HarmonyMethod)null); Log((LogLevel)16, "补丁已挂载:HealthComponent.TakeDamageProcess <- CrippleExposedPrefix/Postfix + ExposeBonusTranspiler(消耗暴露:取消额外伤害、改挂残废)"); } public static void CrippleExposedPrefix(HealthComponent __instance, DamageInfo damageInfo, ref bool __state) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) __state = false; try { if (_enabled == null || !_enabled.Value || (Object)(object)__instance == (Object)null) { return; } CharacterBody body = __instance.body; if (!((Object)(object)body == (Object)null)) { BuffDef val = ResolveBuff(ref _exposeDef, "MercExpose"); if (!((Object)(object)val == (Object)null) && body.HasBuff(val.buffIndex) && IsMercAttacker(damageInfo.attacker)) { __state = true; } } } catch (Exception ex) { Log((LogLevel)4, "「暴露消耗改造」Prefix 异常(已忽略):" + ex.GetType().Name + " " + ex.Message); } } public static void CrippleExposedPostfix(HealthComponent __instance, DamageInfo damageInfo, bool __state) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected I4, but got Unknown if (!__state) { return; } try { if ((Object)(object)__instance == (Object)null || damageInfo.rejected) { return; } CharacterBody body = __instance.body; if ((Object)(object)body == (Object)null) { return; } BuffDef val = ResolveBuff(ref _crippleDef, "Cripple"); if ((Object)(object)val == (Object)null) { return; } float num = ((_duration == null) ? 2f : _duration.Value); if (!(num <= 0f)) { body.AddTimedBuff(val, num); if (!_appliedLogged) { _appliedLogged = true; Log((LogLevel)16, "「消耗暴露」已触发:目标被挂上 " + num.ToString("0.##") + " 秒残废(Cripple,BuffIndex " + (int)val.buffIndex + ")。"); } else { LogThrottled("「消耗暴露」已触发:挂上 " + num.ToString("0.##") + " 秒残废。"); } } } catch (Exception ex) { Log((LogLevel)4, "「暴露消耗改造」Postfix 异常(已忽略):" + ex.GetType().Name + " " + ex.Message); } } public static IEnumerable<CodeInstruction> ExposeBonusTranspiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); float num = ((_bonusMultiplier == null) ? 0f : _bonusMultiplier.Value); bool flag = false; int num2 = 0; for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; FieldInfo fieldInfo = val.operand as FieldInfo; if (fieldInfo != null && string.Equals(fieldInfo.Name, "MercExpose", StringComparison.Ordinal)) { flag = true; } else if (flag && !(val.opcode != OpCodes.Ldc_R4) && val.operand is float && !(Mathf.Abs((float)val.operand - 3.5f) > 0.0001f)) { val.operand = num; flag = false; num2++; } } if (num2 == 1) { Log((LogLevel)16, "暴露额外伤害已改写:" + 3.5f.ToString("0.##") + " → " + num.ToString("0.##") + "(0 = 取消那 350% 加成,改为挂残废;暴露消耗与冷却缩减保持原版)。"); } else { Log((LogLevel)4, "暴露额外伤害改写异常:命中 " + num2 + " 处(预期 1 处),伤害加成可能仍是原版的 " + 3.5f.ToString("0.##") + " 倍。请把这条日志连同游戏版本一起反馈。"); } return list; } private static bool IsMercAttacker(GameObject attacker) { if (_requireMercAttacker != null && !_requireMercAttacker.Value) { return true; } if ((Object)(object)attacker == (Object)null) { return false; } CharacterBody component = attacker.GetComponent<CharacterBody>(); if ((Object)(object)component != (Object)null && !string.IsNullOrEmpty(component.baseNameToken) && component.baseNameToken.IndexOf("MERC", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } return ((Object)attacker).name.StartsWith("MercBody", StringComparison.OrdinalIgnoreCase); } private static BuffDef ResolveBuff(ref BuffDef cache, string keyword) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Invalid comparison between Unknown and I4 //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected I4, but got Unknown //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Expected I4, but got Unknown if ((Object)(object)cache != (Object)null) { return cache; } string[] array = new string[4] { "bd" + keyword, keyword, "RoR2/Base/Buffs/bd" + keyword + ".asset", "RoR2/Base/Buffs/bd" + keyword }; for (int i = 0; i < array.Length; i++) { BuffIndex val = BuffCatalog.FindBuffIndex(array[i]); if ((int)val > 0) { BuffDef buffDef = BuffCatalog.GetBuffDef(val); if ((Object)(object)buffDef != (Object)null) { cache = buffDef; Log((LogLevel)16, "BuffDef 已定位:" + keyword + " 按名字 " + array[i] + " 命中,BuffIndex " + (int)val + "。"); return buffDef; } } } BuffDef[] allBuffDefs = GetAllBuffDefs(); if (allBuffDefs != null) { foreach (BuffDef val2 in allBuffDefs) { if (!((Object)(object)val2 == (Object)null) && !string.IsNullOrEmpty(((Object)val2).name) && ((Object)val2).name.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) >= 0) { cache = val2; Log((LogLevel)16, "BuffDef 已定位:" + keyword + " 按资产名 " + ((Object)val2).name + " 命中,BuffIndex " + (int)val2.buffIndex + "。"); return val2; } } } Log((LogLevel)4, "BuffDef 定位失败:" + keyword + ",相关功能不会生效。已扫描的 BuffDef 数量:" + ((allBuffDefs == null) ? "null" : allBuffDefs.Length.ToString()) + ",前 40 个资产名:"); if (allBuffDefs != null) { for (int k = 0; k < allBuffDefs.Length && k < 40; k++) { if (!((Object)(object)allBuffDefs[k] == (Object)null)) { Log((LogLevel)4, " [" + k + "] " + (string.IsNullOrEmpty(((Object)allBuffDefs[k]).name) ? "(空)" : ((Object)allBuffDefs[k]).name)); } } } return null; } private static BuffDef[] GetAllBuffDefs() { FieldInfo fieldInfo = AccessTools.Field(typeof(BuffCatalog), "buffDefs"); if (fieldInfo == null) { Log((LogLevel)4, "BuffDef 定位失败:反射拿不到 BuffCatalog.buffDefs。"); return null; } return fieldInfo.GetValue(null) as BuffDef[]; } private static void LogThrottled(string message) { if (!(Time.time - _lastLogAt < 3f)) { _lastLogAt = Time.time; Log((LogLevel)16, message); } } private static void Log(LogLevel level, string message) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (_log != null) { _log.Log(level, (object)("[SparkleMercTweaks] " + message)); } } } public static class MercSecondaryTweaks { private const string WhirlwindDescriptionToken = "MERC_SECONDARY_DESCRIPTION"; private const string UppercutDescriptionToken = "MERC_SECONDARY_ALT1_DESCRIPTION"; private const string WhirlwindDescription = "快速横斩两次,每次造成<style=cIsDamage>350%的伤害</style>,若位于空中,则改为<style=cIsUtility>竖斩</style>。"; private const string UppercutDescription = "跳起并释放一个上挑斩,造成<style=cIsDamage>700%的伤害</style>并<style=cIsUtility>击飞敌人</style>。"; private static readonly string[] WhirlwindTypeNames = new string[3] { "EntityStates.Merc.WhirlwindBase", "EntityStates.Merc.WhirlwindGround", "EntityStates.Merc.WhirlwindAir" }; private static ConfigEntry<float> _whirlwindCoefficient; private static ConfigEntry<float> _uppercutCoefficient; private static ConfigEntry<bool> _overrideDescription; private static ManualLogSource _log; private static int _whirlwindPatched; private static bool _whirlwindLogged; private static float _whirlwindOriginal = -1f; private static bool _whirlwindErrorLogged; private static FieldInfo _uppercutField; private static bool _uppercutLogged; private static float _uppercutOriginal = -1f; public static void Init(ConfigFile cfg, ManualLogSource logger) { _log = logger; _whirlwindCoefficient = cfg.Bind<float>("Whirlwind", "DamageCoefficient", 3.5f, "旋风斩每段挥砍的伤害系数(百分比)。3.5 = 350%(原版是 2 = 200%),段数仍是原版的 2 段。\n填 0 或负数 = 不改这项,保持原版 200%。"); _uppercutCoefficient = cfg.Bind<float>("Uppercut", "DamageCoefficient", 7f, "升雷的单段伤害系数(百分比)。7 = 700%,原版是 5.5(550%)。\n填 0 或负数 = 不改这项,保持原版 550%。"); _overrideDescription = cfg.Bind<bool>("Secondary", "OverrideSkillDescription", true, "是否把游戏内「旋风斩 / 升雷」的技能说明改成与实际效果一致的描述。关掉则显示原版文本。"); _uppercutField = FindStaticFloatField("EntityStates.Merc.Uppercut", "升雷"); } public static void Patch(Harmony harmony) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(MercSecondaryTweaks), "WhirlwindOnEnterPostfix", (Type[])null, (Type[])null); string[] whirlwindTypeNames = WhirlwindTypeNames; foreach (string text in whirlwindTypeNames) { Type type = AccessTools.TypeByName(text); if (!(type == null)) { MethodInfo methodInfo2 = AccessTools.Method(type, "OnEnter", (Type[])null, (Type[])null); if (!(methodInfo2 == null) && !(methodInfo2.DeclaringType != type)) { harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _whirlwindPatched++; Log((LogLevel)16, "补丁已挂载:" + text + ".OnEnter() <- WhirlwindOnEnterPostfix()(旋风斩每段伤害系数覆写)"); } } } if (_whirlwindPatched == 0) { Log((LogLevel)2, "旋风斩伤害改动未生效:三个 Whirlwind 类里都没找到可挂的 OnEnter()。"); } } public static string Summary() { float num = ((_whirlwindCoefficient == null) ? 3.5f : _whirlwindCoefficient.Value); float num2 = ((_uppercutCoefficient == null) ? 7f : _uppercutCoefficient.Value); return " [旋风斩:" + ((num > 0f) ? ((num * 100f).ToString("0") + "%") : "原版 200%") + "] [升雷:" + ((num2 > 0f) ? ((num2 * 100f).ToString("0") + "%") : "原版 550%") + "]"; } public static void ApplyLanguage() { if (_overrideDescription != null && _overrideDescription.Value) { LanguageAPI.Add("MERC_SECONDARY_DESCRIPTION", "快速横斩两次,每次造成<style=cIsDamage>350%的伤害</style>,若位于空中,则改为<style=cIsUtility>竖斩</style>。", "en"); LanguageAPI.Add("MERC_SECONDARY_DESCRIPTION", "快速横斩两次,每次造成<style=cIsDamage>350%的伤害</style>,若位于空中,则改为<style=cIsUtility>竖斩</style>。", "zh-CN"); LanguageAPI.Add("MERC_SECONDARY_ALT1_DESCRIPTION", "跳起并释放一个上挑斩,造成<style=cIsDamage>700%的伤害</style>并<style=cIsUtility>击飞敌人</style>。", "en"); LanguageAPI.Add("MERC_SECONDARY_ALT1_DESCRIPTION", "跳起并释放一个上挑斩,造成<style=cIsDamage>700%的伤害</style>并<style=cIsUtility>击飞敌人</style>。", "zh-CN"); } } public static void ApplyCoefficients() { float target = ((_uppercutCoefficient == null) ? 7f : _uppercutCoefficient.Value); ApplyStatic(_uppercutField, target, "升雷", ref _uppercutLogged, ref _uppercutOriginal); } public static void WhirlwindOnEnterPostfix(object __instance) { float num = ((_whirlwindCoefficient == null) ? 3.5f : _whirlwindCoefficient.Value); if (num <= 0f || __instance == null) { return; } Type type = __instance.GetType(); try { FieldInfo fieldInfo = AccessTools.Field(type, "baseDamageCoefficient"); FieldInfo fieldInfo2 = AccessTools.Field(type, "overlapAttack"); if (fieldInfo == null || fieldInfo2 == null) { return; } float num2 = Convert.ToSingle(fieldInfo.GetValue(__instance)); if (num2 <= 0f) { return; } object? value = fieldInfo2.GetValue(__instance); OverlapAttack val = (OverlapAttack)((value is OverlapAttack) ? value : null); if (val != null) { if (!_whirlwindLogged) { _whirlwindLogged = true; _whirlwindOriginal = num2; Log((LogLevel)16, "旋风斩原版伤害系数基准 = " + num2.ToString("0.##") + "(= " + (num2 * 100f).ToString("0") + "%),将覆写为 " + num.ToString("0.##") + "(= " + (num * 100f).ToString("0") + "%)。"); } if (Mathf.Abs(num2 - num) > 0.0001f) { val.damage = val.damage / num2 * num; fieldInfo.SetValue(__instance, num); } } } catch (Exception ex) { if (!_whirlwindErrorLogged) { _whirlwindErrorLogged = true; Log((LogLevel)4, "旋风斩伤害覆写异常:" + ex.GetType().Name + " " + ex.Message); } } } private static void ApplyStatic(FieldInfo field, float target, string label, ref bool logged, ref float original) { if (field == null || target <= 0f) { return; } try { float num = Convert.ToSingle(field.GetValue(null)); if (!(num <= 0f)) { if (!logged) { logged = true; original = num; Log((LogLevel)16, label + "原版伤害系数基准 = " + num.ToString("0.##") + "(= " + (num * 100f).ToString("0") + "%),将覆写为 " + target.ToString("0.##") + "(= " + (target * 100f).ToString("0") + "%)。"); } if (Mathf.Abs(num - target) > 0.0001f) { field.SetValue(null, target); } } } catch (Exception ex) { Log((LogLevel)4, label + "伤害系数覆写异常(已忽略):" + ex.GetType().Name + " " + ex.Message); } } private static FieldInfo FindStaticFloatField(string typeName, string label) { Type type = AccessTools.TypeByName(typeName); if (type == null) { Log((LogLevel)4, label + "伤害改动未生效:找不到类型 " + typeName + "。"); return null; } FieldInfo fieldInfo = AccessTools.Field(type, "baseDamageCoefficient"); if (fieldInfo == null) { Log((LogLevel)4, label + "伤害改动未生效:反射拿不到 " + typeName + ".baseDamageCoefficient。"); } return fieldInfo; } private static void Log(LogLevel level, string message) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (_log != null) { _log.Log(level, (object)("[SparkleMercTweaks] " + message)); } } } public static class MercSlicingWindsTweak { private const string BladeName = "EvisProjectile"; private const string WindName = "EvisOverlapProjectile"; private const string AltDescriptionToken = "MERC_SPECIAL_ALT1_DESCRIPTION"; private const uint ApplyMercExposeFlag = 8388608u; private const string AltDescriptionZh = "发射一片斩击风暴,在击中敌人时<style=cIsUtility>暴露</style>周围最多<style=cIsDamage>3名敌人</style>,并重复造成<style=cIsDamage>100%伤害</style>。"; private static ConfigEntry<float> _speedMultiplier; private static ConfigEntry<bool> _scaleHitCount; private static ConfigEntry<bool> _removeExpose; private static ConfigEntry<bool> _exposeOnFirstHit; private static ConfigEntry<float> _bladeRadiusMultiplier; private static ConfigEntry<float> _windRadiusMultiplier; private static ConfigEntry<bool> _overrideDescription; private static ManualLogSource _log; private static int _castId; private static readonly Dictionary<int, int> _exposeCast = new Dictionary<int, int>(); private static readonly Dictionary<int, float> _exposeAt = new Dictionary<int, float>(); private const float SameCastWindow = 6f; private static FieldInfo _speedField; private static MethodInfo _setForwardSpeed; private static FieldInfo _fireFrequencyField; private static FieldInfo _resetIntervalField; private static FieldInfo _attackField; private static FieldInfo _hitboxOriginalScalesField; private static FieldInfo _hitboxTransformsField; private static FieldInfo _projDamageTypeField; private static FieldInfo _overlapDamageTypeField; private static FieldInfo _damageInfoTypeField; private static FieldInfo _comboDamageTypeField; private static FieldInfo _healthDamageInfoField; private static float _baseSpeed = -1f; private static float _baseFireFrequency = -1f; private static float _baseResetInterval = -1f; private static Vector3 _baseColliderSize = new Vector3(-1f, -1f, -1f); private static bool _baselineLogged; private static bool _exposeDiagnosed; private static bool _exposeClearedLogged; private static bool _exposeAppliedLogged; private static float _lastLogAt = -999f; public static void Init(ConfigFile cfg, ManualLogSource logger) { _log = logger; _speedMultiplier = cfg.Bind<float>("SlicingWinds", "ProjectileSpeedMultiplier", 2f, "「裂片之风」刀刃射弹的飞行速度倍率。2 = 翻倍(原版 90),1 = 原版。"); _scaleHitCount = cfg.Bind<bool>("SlicingWinds", "ScaleHitCountWithAttackSpeed", true, "「裂片之风」的伤害段数是否随攻击速度缩放:段数 = 原版 8 段 x 角色攻击速度倍率。\n关掉则保持原版的固定 8 段。"); _removeExpose = cfg.Bind<bool>("SlicingWinds", "RemoveExpose", true, "是否移除「裂片之风」原版的「暴露」效果(原版是最后一次打击才给敌人挂暴露)。\ntrue = 清掉原版那次暴露(配合 ApplyExposeOnFirstHit 就变成首次命中暴露),false = 完全保留原版。"); _exposeOnFirstHit = cfg.Bind<bool>("SlicingWinds", "ApplyExposeOnFirstHit", true, "「裂片之风」是否改为首次命中就给敌人挂「暴露」:每次施法对每个敌人只挂一次。\ntrue = 第一下就暴露(与原版「最后一下才暴露」不同),false = 不额外施加。"); _bladeRadiusMultiplier = cfg.Bind<float>("SlicingWinds", "BladeRadiusMultiplier", 2f, "「裂片之风」刀刃本体飞行时的判定范围倍率(改的是 BoxCollider 尺寸)。\n2 = 扩大 100%,1.5 = 扩大 50%,1 = 原版。"); _windRadiusMultiplier = cfg.Bind<float>("SlicingWinds", "WindRadiusMultiplier", 1.25f, "「裂片之风」风场的伤害判定范围倍率(改的是 ProjectileOverlapAttack 的 HitBox 缩放)。\n1.25 = 扩大 25%,1.5 = 扩大 50%,1 = 原版。"); _overrideDescription = cfg.Bind<bool>("SlicingWinds", "OverrideSkillDescription", true, "是否把游戏内「裂片之风」的技能说明改成与实际效果一致的描述。\n关掉则显示原版文本。改完需要重启游戏。"); _speedField = AccessTools.Field(typeof(ProjectileSimple), "desiredForwardSpeed"); _setForwardSpeed = AccessTools.Method(typeof(ProjectileSimple), "SetForwardSpeed", (Type[])null, (Type[])null); _fireFrequencyField = AccessTools.Field(typeof(ProjectileOverlapAttack), "fireFrequency"); _resetIntervalField = AccessTools.Field(typeof(ProjectileOverlapAttack), "resetInterval"); _attackField = AccessTools.Field(typeof(ProjectileOverlapAttack), "attack"); _hitboxOriginalScalesField = AccessTools.Field(typeof(ProjectileOverlapAttack), "HitboxOriginalScales"); _hitboxTransformsField = AccessTools.Field(typeof(ProjectileOverlapAttack), "HitboxTransforms"); _projDamageTypeField = AccessTools.Field(typeof(ProjectileDamage), "damageType"); _damageInfoTypeField = AccessTools.Field(typeof(DamageInfo), "damageType"); _healthDamageInfoField = AccessTools.Field(typeof(HealthComponent), "damageInfo"); if (_damageInfoTypeField != null) { _comboDamageTypeField = AccessTools.Field(_damageInfoTypeField.FieldType, "damageType"); } if (_attackField != null) { _overlapDamageTypeField = AccessTools.Field(_attackField.FieldType, "damageType"); } if (_speedField == null) { Log((LogLevel)2, "字段定位失败:ProjectileSimple.desiredForwardSpeed,速度调整不会生效。"); } if (_setForwardSpeed == null) { Log((LogLevel)2, "方法定位失败:ProjectileSimple.SetForwardSpeed,速度调整不会生效。"); } if (_fireFrequencyField == null || _resetIntervalField == null) { Log((LogLevel)2, "字段定位失败:ProjectileOverlapAttack.fireFrequency / resetInterval,段数调整不会生效。"); } if (_hitboxOriginalScalesField == null || _hitboxTransformsField == null) { Log((LogLevel)2, "字段定位失败:ProjectileOverlapAttack.HitboxOriginalScales / HitboxTransforms,判定范围不会生效。"); } if (_comboDamageTypeField == null) { Log((LogLevel)2, "字段定位失败:DamageTypeCombo.damageType,移除「暴露」不会生效。"); } } public static string Summary() { float num = ((_speedMultiplier == null) ? 2f : _speedMultiplier.Value); string text = ((_scaleHitCount == null || _scaleHitCount.Value) ? "随攻速" : "固定"); bool num2 = _exposeOnFirstHit != null && _exposeOnFirstHit.Value; bool flag = _removeExpose == null || _removeExpose.Value; string text2 = (num2 ? "首击暴露" : (flag ? "无暴露" : "原版暴露")); float num3 = ((_bladeRadiusMultiplier == null) ? 2f : _bladeRadiusMultiplier.Value); float num4 = ((_windRadiusMultiplier == null) ? 1.25f : _windRadiusMultiplier.Value); return " [裂片之风:速度 x" + num.ToString("0.##") + " 段数" + text + " 判定 刀刃x" + num3.ToString("0.##") + "/风场x" + num4.ToString("0.##") + " " + text2 + "]"; } public static void ApplyLanguage() { if (_overrideDescription != null && _overrideDescription.Value) { LanguageAPI.Add("MERC_SPECIAL_ALT1_DESCRIPTION", "发射一片斩击风暴,在击中敌人时<style=cIsUtility>暴露</style>周围最多<style=cIsDamage>3名敌人</style>,并重复造成<style=cIsDamage>100%伤害</style>。", "en"); LanguageAPI.Add("MERC_SPECIAL_ALT1_DESCRIPTION", "发射一片斩击风暴,在击中敌人时<style=cIsUtility>暴露</style>周围最多<style=cIsDamage>3名敌人</style>,并重复造成<style=cIsDamage>100%伤害</style>。", "zh-CN"); } } public static void Patch(Harmony harmony) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(ProjectileSimple), "Start", (Type[])null, (Type[])null); if (methodInfo == null) { Log((LogLevel)2, "「裂片之风」补丁失败:找不到 ProjectileSimple.Start。"); } else { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(MercSlicingWindsTweak), "BladeStartPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log((LogLevel)16, "补丁已挂载:ProjectileSimple.Start <- BladeStartPostfix()(裂片之风刀刃提速 + 判定放大)"); } MethodInfo methodInfo2 = AccessTools.Method(typeof(ProjectileOverlapAttack), "Start", (Type[])null, (Type[])null); if (methodInfo2 == null) { Log((LogLevel)2, "「裂片之风」补丁失败:找不到 ProjectileOverlapAttack.Start。"); } else { harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(MercSlicingWindsTweak), "WindStartPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log((LogLevel)16, "补丁已挂载:ProjectileOverlapAttack.Start <- WindStartPostfix()(裂片之风段数随攻速 + 去原版暴露 + 判定放大)"); } MethodInfo methodInfo3 = AccessTools.Method(typeof(HealthComponent), "TakeDamageProcess", (Type[])null, (Type[])null); if (methodInfo3 == null) { Log((LogLevel)2, "「裂片之风」补丁失败:找不到 HealthComponent.TakeDamageProcess(暴露时机控制)。"); return; } harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(AccessTools.Method(typeof(MercSlicingWindsTweak), "ExposeControlPrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log((LogLevel)16, "补丁已挂载:HealthComponent.TakeDamageProcess <- ExposeControlPrefix()(裂片之风首击暴露)"); } public static void BladeStartPostfix(ProjectileSimple __instance) { try { if ((Object)(object)__instance == (Object)null) { return; } GameObject gameObject = ((Component)__instance).gameObject; if ((Object)(object)gameObject == (Object)null || !((Object)gameObject).name.StartsWith("EvisProjectile", StringComparison.Ordinal) || (Object)(object)gameObject.GetComponent<ProjectileExplosion>() == (Object)null) { return; } _castId++; if (_speedField != null && _setForwardSpeed != null) { float baseSpeed = Convert.ToSingle(_speedField.GetValue(__instance)); if (_baseSpeed < 0f) { _baseSpeed = baseSpeed; } float num = ((_speedMultiplier == null) ? 1f : _speedMultiplier.Value); if (num <= 0f) { num = 1f; } float num2 = _baseSpeed * num; _speedField.SetValue(__instance, num2); _setForwardSpeed.Invoke(__instance, new object[1] { num2 }); } ScaleBladeCollider(gameObject); } catch (Exception ex) { Log((LogLevel)4, "「裂片之风」刀刃处理异常(已忽略):" + ex.GetType().Name + " " + ex.Message); } } private static void ScaleBladeCollider(GameObject go) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_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_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) float num = ((_bladeRadiusMultiplier == null) ? 2f : _bladeRadiusMultiplier.Value); if (num <= 0f) { num = 1f; } BoxCollider component = go.GetComponent<BoxCollider>(); if ((Object)(object)component != (Object)null) { if (_baseColliderSize.x < 0f) { _baseColliderSize = component.size; } component.size = _baseColliderSize * num; string[] obj = new string[7] { "「裂片之风」刀刃判定范围:原版 ", ((Vector3)(ref _baseColliderSize)).ToString("0.##"), " → ", null, null, null, null }; Vector3 size = component.size; obj[3] = ((Vector3)(ref size)).ToString("0.##"); obj[4] = "(x"; obj[5] = num.ToString("0.##"); obj[6] = ")。"; LogThrottled(string.Concat(obj)); return; } SphereCollider component2 = go.GetComponent<SphereCollider>(); if ((Object)(object)component2 != (Object)null) { if (_baseColliderSize.x < 0f) { _baseColliderSize = new Vector3(component2.radius, component2.radius, component2.radius); } component2.radius = _baseColliderSize.x * num; } } public static void WindStartPostfix(ProjectileOverlapAttack __instance) { try { if ((Object)(object)__instance == (Object)null) { return; } GameObject gameObject = ((Component)__instance).gameObject; if ((Object)(object)gameObject == (Object)null || !((Object)gameObject).name.StartsWith("EvisOverlapProjectile", StringComparison.Ordinal)) { return; } if (_fireFrequencyField != null && _resetIntervalField != null) { float baseFireFrequency = Convert.ToSingle(_fireFrequencyField.GetValue(__instance)); float baseResetInterval = Convert.ToSingle(_resetIntervalField.GetValue(__instance)); if (_baseFireFrequency < 0f) { _baseFireFrequency = baseFireFrequency; } if (_baseResetInterval < 0f) { _baseResetInterval = baseResetInterval; } if (_scaleHitCount == null || _scaleHitCount.Value) { float ownerAttackSpeed = GetOwnerAttackSpeed(gameObject); float num = _baseFireFrequency * ownerAttackSpeed; if (num < 0.5f) { num = 0.5f; } float num2 = _baseResetInterval / ownerAttackSpeed; if (num2 <= 0f) { num2 = 1f / num; } _fireFrequencyField.SetValue(__instance, num); _resetIntervalField.SetValue(__instance, num2); LogThrottled("「裂片之风」段数随攻击速度生效:攻击速度 x" + ownerAttackSpeed.ToString("0.##") + ",原版 " + _baseFireFrequency.ToString("0.##") + " 段 → 本次 " + num.ToString("0.##") + " 段(重置间隔 " + _baseResetInterval.ToString("0.###") + " → " + num2.ToString("0.###") + ")。"); } } RemoveExposeFromWind(__instance); ScaleWindHitboxes(__instance); LogBaselineOnce(); } catch (Exception ex) { Log((LogLevel)4, "「裂片之风」风场处理异常(已忽略):" + ex.GetType().Name + " " + ex.Message); } } private static void RemoveExposeFromWind(ProjectileOverlapAttack instance) { if (_removeExpose == null || !_removeExpose.Value) { return; } ProjectileDamage component = ((Component)instance).GetComponent<ProjectileDamage>(); uint num = 0u; if ((Object)(object)component != (Object)null && _projDamageTypeField != null) { object value = _projDamageTypeField.GetValue(component); num = ComboDamageTypeValue(value); if (ClearExposeFlag(value)) { _projDamageTypeField.SetValue(component, value); } } if (_attackField != null && _overlapDamageTypeField != null) { object value2 = _attackField.GetValue(instance); if (value2 != null) { object value3 = _overlapDamageTypeField.GetValue(value2); if (num == 0) { num = ComboDamageTypeValue(value3); } if (ClearExposeFlag(value3)) { _overlapDamageTypeField.SetValue(value2, value3); } } } if (!_exposeDiagnosed) { _exposeDiagnosed = true; bool flag = (num & 0x800000) != 0; Log((LogLevel)16, "「裂片之风」风场伤害类型诊断:damageType = " + num + ",是否带「暴露」标志(" + 8388608u + ")= " + (flag ? "是" : "否") + "。已按配置处理。"); } } private static void ScaleWindHitboxes(ProjectileOverlapAttack instance) { //IL_008a: 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) if (_hitboxOriginalScalesField == null || _hitboxTransformsField == null) { return; } float num = ((_windRadiusMultiplier == null) ? 1.25f : _windRadiusMultiplier.Value); if (num <= 0f) { num = 1f; } Vector3[] array = _hitboxOriginalScalesField.GetValue(instance) as Vector3[]; Transform[] array2 = _hitboxTransformsField.GetValue(instance) as Transform[]; if (array == null || array2 == null) { Log((LogLevel)4, "「裂片之风」判定范围:HitboxOriginalScales / HitboxTransforms 取不到,跳过放大。"); return; } for (int i = 0; i < array2.Length && i < array.Length; i++) { if (!((Object)(object)array2[i] == (Object)null)) { array2[i].localScale = array[i] * num; } } LogThrottled("「裂片之风」风场判定范围:HitBox 数量 " + array2.Length + ",缩放 x" + num.ToString("0.##") + "。"); } public static void ExposeControlPrefix(HealthComponent __instance, ref DamageInfo damageInfo) { //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown try { bool num = _removeExpose == null || _removeExpose.Value; bool flag = _exposeOnFirstHit != null && _exposeOnFirstHit.Value; if (!num && !flag) { return; } GameObject inflictor = damageInfo.inflictor; if ((Object)(object)inflictor == (Object)null) { return; } string name = ((Object)inflictor).name; if ((!name.StartsWith("EvisProjectile", StringComparison.Ordinal) && !name.StartsWith("EvisOverlapProjectile", StringComparison.Ordinal)) || _damageInfoTypeField == null || _comboDamageTypeField == null) { return; } bool flag2 = IsFirstHitOfCast(__instance); bool flag3 = flag && flag2; object obj = damageInfo; object value = _damageInfoTypeField.GetValue(obj); if (flag3 ? SetExposeFlag(value) : ClearExposeFlag(value)) { _damageInfoTypeField.SetValue(obj, value); damageInfo = (DamageInfo)obj; } if (_healthDamageInfoField != null && (Object)(object)__instance != (Object)null) { object value2 = _healthDamageInfoField.GetValue(__instance); object value3 = _damageInfoTypeField.GetValue(value2); if (flag3 ? SetExposeFlag(value3) : ClearExposeFlag(value3)) { _damageInfoTypeField.SetValue(value2, value3); _healthDamageInfoField.SetValue(__instance, value2); } } if (flag3 && !_exposeAppliedLogged) { _exposeAppliedLogged = true; Log((LogLevel)16, "「裂片之风」首击暴露已生效:本次伤害来自 " + name + ",已给目标加上「暴露」(ApplyMercExpose)。本次施法序号 " + _castId + "。"); } else if (!flag3 && !flag2 && !_exposeClearedLogged) { _exposeClearedLogged = true; Log((LogLevel)16, "「裂片之风」后续伤害段已清掉「暴露」标志位(本次施法只暴露一次)。"); } } catch (Exception ex) { Log((LogLevel)4, "「裂片之风」暴露控制异常(已忽略):" + ex.GetType().Name + " " + ex.Message); } } private static bool IsFirstHitOfCast(HealthComponent victim) { if ((Object)(object)victim == (Object)null) { return false; } int instanceID = ((Object)victim).GetInstanceID(); float time = Time.time; int value; bool num = _exposeCast.TryGetValue(instanceID, out value); float value2; float num2 = (_exposeAt.TryGetValue(instanceID, out value2) ? value2 : (-999f)); int num3; if (num && value == _castId) { num3 = ((time - num2 > 6f) ? 1 : 0); if (num3 == 0) { goto IL_007a; } } else { num3 = 1; } _exposeCast[instanceID] = _castId; _exposeAt[instanceID] = time; PruneExposeRecords(); goto IL_007a; IL_007a: return (byte)num3 != 0; } private static void PruneExposeRecords() { if (_exposeCast.Count < 64) { return; } List<int> list = new List<int>(); foreach (KeyValuePair<int, int> item in _exposeCast) { if (item.Value != _castId) { list.Add(item.Key); } } for (int i = 0; i < list.Count; i++) { _exposeCast.Remove(list[i]); _exposeAt.Remove(list[i]); } } private static uint ComboDamageTypeValue(object combo) { if (combo == null || _comboDamageTypeField == null) { return 0u; } try { return Convert.ToUInt32(_comboDamageTypeField.GetValue(combo)); } catch (Exception) { return 0u; } } private static bool ClearExposeFlag(object combo) { if (combo == null || _comboDamageTypeField == null) { return false; } uint num; try { num = Convert.ToUInt32(_comboDamageTypeField.GetValue(combo)); } catch (Exception) { return false; } if ((num & 0x800000) == 0) { return false; } _comboDamageTypeField.SetValue(combo, Enum.ToObject(_comboDamageTypeField.FieldType, num & 0xFF7FFFFFu)); return true; } private static bool SetExposeFlag(object combo) { if (combo == null || _comboDamageTypeField == null) { return false; } uint num; try { num = Convert.ToUInt32(_comboDamageTypeField.GetValue(combo)); } catch (Exception) { return false; } if ((num & 0x800000) != 0) { return false; } _comboDamageTypeField.SetValue(combo, Enum.ToObject(_comboDamageTypeField.FieldType, num | 0x800000)); return true; } private static float GetOwnerAttackSpeed(GameObject projectile) { ProjectileController component = projectile.GetComponent<ProjectileController>(); if ((Object)(object)component == (Object)null || (Object)(object)component.owner == (Object)null) { return 1f; } CharacterBody component2 = component.owner.GetComponent<CharacterBody>(); if ((Object)(object)component2 == (Object)null) { return 1f; } float num = component2.attackSpeed; if (num < 0.1f) { num = 0.1f; } return num; } private static void LogBaselineOnce() { if (!_baselineLogged && !(_baseFireFrequency < 0f)) { _baselineLogged = true; Log((LogLevel)16, "「裂片之风」原版数值已记录:风场段数 " + _baseFireFrequency.ToString("0.##") + " 段/秒(重置间隔 " + _baseResetInterval.ToString("0.###") + ")" + ((_baseSpeed >= 0f) ? (",刀刃速度 " + _baseSpeed.ToString("0.##")) : "") + "。"); } } private static void LogThrottled(string message) { if (!(Time.time - _lastLogAt < 3f)) { _lastLogAt = Time.time; Log((LogLevel)16, message); } } private static void Log(LogLevel level, string message) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (_log != null) { _log.Log(level, (object)("[SparkleMercTweaks] " + message)); } } } public static class MercUtilityTweaks { private const string BlindingAssaultDescriptionToken = "MERC_UTILITY_DESCRIPTION"; private const string FocusedAssaultDescriptionToken = "MERC_UTILITY_ALT1_DESCRIPTION"; private const string BlindingAssaultDescription = "<style=cIsUtility>眩晕</style>。向前连续冲锋并造成<style=cIsDamage>400%的伤害</style>,最多<style=cIsDamage>3</style>次。"; private const string FocusedAssaultDescription = "<style=cIsUtility>眩晕</style>。向前冲锋并在<style=cIsDamage>1秒</style>后造成<style=cIsDamage>800%的伤害</style>并<style=cIsUtility>暴露</style>敌人。"; private static ConfigEntry<float> _blindingCoefficient; private static ConfigEntry<bool> _removeHitRequirement; private static ConfigEntry<float> _focusedCoefficient; private static ConfigEntry<bool> _overrideDescription; private static ManualLogSource _log; private static FieldInfo _assaulterStaticField; private static bool _assaulterStaticLogged; private static float _assaulterStaticOriginal = -1f; private static bool _focusedLogged; private static bool _blindingLogged; private static bool _dashGrantedLogged; public static void Init(ConfigFile cfg, ManualLogSource logger) { _log = logger; _blindingCoefficient = cfg.Bind<float>("BlindingAssault", "DamageCoefficient", 4f, "「盲目突击」每段冲刺的伤害系数(百分比)。4 = 400%(原版是 3 = 300%)。\n填 0 或负数 = 不改这项,保持原版 300%。"); _removeHitRequirement = cfg.Bind<bool>("BlindingAssault", "RemoveHitRequirement", true, "是否移除「必须命中敌人才能进行下一段突击」的限制。\ntrue = 不管有没有打中都给下一段(原版只有命中才追加充能),false = 保持原版。"); _focusedCoefficient = cfg.Bind<float>("FocusedAssault", "DamageCoefficient", 8f, "「凝神一击」的伤害系数(百分比)。8 = 800%(原版是 7 = 700%)。\n填 0 或负数 = 不改这项,保持原版 700%。"); _overrideDescription = cfg.Bind<bool>("Utility", "OverrideSkillDescription", true, "是否把游戏内「盲目突击 / 凝神一击」的技能说明改成与实际效果一致的描述。关掉则显示原版文本。"); Type type = AccessTools.TypeByName("EntityStates.Merc.Assaulter"); if (type != null) { _assaulterStaticField = AccessTools.Field(type, "damageCoefficient"); } if (_assaulterStaticField == null) { Log((LogLevel)4, "盲目突击静态伤害系数取不到(EntityStates.Merc.Assaulter.damageCoefficient),只改 Assaulter2 的实例系数;通常不影响效果。"); } } public static string Summary() { float num = ((_blindingCoefficient == null) ? 4f : _blindingCoefficient.Value); float num2 = ((_focusedCoefficient == null) ? 8f : _focusedCoefficient.Value); return string.Concat(string.Concat(" [盲目突击:" + ((num > 0f) ? ((num * 100f).ToString("0") + "%") : "原版 300%") + "]", " [凝神一击:", (num2 > 0f) ? ((num2 * 100f).ToString("0") + "%") : "原版 700%", "]"), (_removeHitRequirement == null || _removeHitRequirement.Value) ? " [突击:免命中续段]" : ""); } public static void ApplyLanguage() { if (_overrideDescription != null && _overrideDescription.Value) { LanguageAPI.Add("MERC_UTILITY_DESCRIPTION", "<style=cIsUtility>眩晕</style>。向前连续冲锋并造成<style=cIsDamage>400%的伤害</style>,最多<style=cIsDamage>3</style>次。", "en"); LanguageAPI.Add("MERC_UTILITY_DESCRIPTION", "<style=cIsUtility>眩晕</style>。向前连续冲锋并造成<style=cIsDamage>400%的伤害</style>,最多<style=cIsDamage>3</style>次。", "zh-CN"); LanguageAPI.Add("MERC_UTILITY_ALT1_DESCRIPTION", "<style=cIsUtility>眩晕</style>。向前冲锋并在<style=cIsDamage>1秒</style>后造成<style=cIsDamage>800%的伤害</style>并<style=cIsUtility>暴露</style>敌人。", "en"); LanguageAPI.Add("MERC_UTILITY_ALT1_DESCRIPTION", "<style=cIsUtility>眩晕</style>。向前冲锋并在<style=cIsDamage>1秒</style>后造成<style=cIsDamage>800%的伤害</style>并<style=cIsUtility>暴露</style>敌人。", "zh-CN"); } } public static void ApplyCoefficients() { if (_assaulterStaticField == null) { return; } float num = ((_blindingCoefficient == null) ? 4f : _blindingCoefficient.Value); if (num <= 0f) { return; } try { float num2 = Convert.ToSingle(_assaulterStaticField.GetValue(null)); if (!(num2 <= 0f)) { if (!_assaulterStaticLogged) { _assaulterStaticLogged = true; _assaulterStaticOriginal = num2; Log((LogLevel)16, "盲目突击静态伤害系数基准 = " + num2.ToString("0.##") + "(= " + (num2 * 100f).ToString("0") + "%),将覆写为 " + num.ToString("0.##") + "。"); } if (Mathf.Abs(num2 - num) > 0.0001f) { _assaulterStaticField.SetValue(null, num); } } } catch (Exception ex) { Log((LogLevel)4, "盲目突击静态伤害系数覆写异常(已忽略):" + ex.GetType().Name + " " + ex.Message); } } public static void Patch(Harmony harmony) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown PatchInstance(harmony, "EntityStates.Merc.FocusedAssaultDash", "FocusedAssaultDamagePrefix", "凝神一击伤害系数"); PatchInstance(harmony, "EntityStates.Merc.Assaulter2", "BlindingAssaultDamagePrefix", "盲目突击伤害系数"); Type type = AccessTools.TypeByName("EntityStates.Merc.Assaulter2"); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "OnEnter", (Type[])null, (Type[])null)); if (methodInfo == null) { Log((LogLevel)2, "「免命中续段」补丁失败:找不到 EntityStates.Merc.Assaulter2.OnEnter。"); return; } try { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(MercUtilityTweaks), "Assaulter2OnEnterPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log((LogLevel)16, "补丁已挂载:Assaulter2.OnEnter <- Assaulter2OnEnterPostfix()(盲目突击免命中续段)"); } catch (Exception ex) { Log((LogLevel)2, "「免命中续段」补丁挂载失败:" + ex.GetType().Name + " " + ex.Message); } } private static void PatchInstance(Harmony harmony, string typeName, string prefixName, string label) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown Type type = AccessTools.TypeByName(typeName); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "AuthorityModifyOverlapAttack", (Type[])null, (Type[])null)); if (methodInfo == null) { Log((LogLevel)2, label + "补丁失败:找不到 " + typeName + ".AuthorityModifyOverlapAttack。"); return; } try { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(MercUtilityTweaks), prefixName, (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log((LogLevel)16, "补丁已挂载:" + typeName + ".AuthorityModifyOverlapAttack <- " + prefixName + "()(" + label + ")"); } catch (Exception ex) { Log((LogLevel)2, label + "补丁挂载失败:" + ex.GetType().Name + " " + ex.Message); } } public static void FocusedAssaultDamagePrefix(object __instance) { ApplyInstanceCoefficient(__instance, _focusedCoefficient, 8f, "凝神一击", ref _focusedLogged); } public static void BlindingAssaultDamagePrefix(object __instance) { ApplyInstanceCoefficient(__instance, _blindingCoefficient, 4f, "盲目突击", ref _blindingLogged); } public static void Assaulter2OnEnterPostfix(object __instance) { try { if (_removeHitRequirement == null || !_removeHitRequirement.Value || __instance == null) { return; } FieldInfo fieldInfo = AccessTools.Field(__instance.GetType(), "grantAnotherDash"); if (!(fieldInfo == null)) { fieldInfo.SetValue(__instance, true); if (!_dashGrantedLogged) { _dashGrantedLogged = true; Log((LogLevel)16, "盲目突击「免命中续段」已生效:冲刺开始即视为可追加下一段(原版要命中才给,grantAnotherDash = true)。"); } } } catch (Exception ex) { Log((LogLevel)4, "盲目突击「免命中续段」异常(已忽略):" + ex.GetType().Name + " " + ex.Message); } } private static void ApplyInstanceCoefficient(object instance, ConfigEntry<float> entry, float fallback, string label, ref bool logged) { try { float num = entry?.Value ?? fallback; if (num <= 0f || instance == null) { return; } FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), "damageCoefficient"); if (fieldInfo == null) { return; } float num2 = Convert.ToSingle(fieldInfo.GetValue(instance)); if (!(num2 <= 0f)) { if (!logged) { logged = true; Log((LogLevel)16, label + "原版伤害系数基准 = " + num2.ToString("0.##") + "(= " + (num2 * 100f).ToString("0") + "%),将覆写为 " + num.ToString("0.##") + "(= " + (num * 100f).ToString("0") + "%)。"); } if (Mathf.Abs(num2 - num) > 0.0001f) { fieldInfo.SetValue(instance, num); } } } catch (Exception ex) { Log((LogLevel)4, label + "伤害系数覆写异常(已忽略):" + ex.GetType().Name + " " + ex.Message); } } private static void Log(LogLevel level, string message) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (_log != null) { _log.Log(level, (object)("[SparkleMercTweaks] " + message)); } } } [BepInPlugin("com.sparkletwilight.sparklemerctweaks", "SparkleMercTweaks", "1.19.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class SparkleMercTweaksPlugin : BaseUnityPlugin { public const string PluginGUID = "com.sparkletwilight.sparklemerctweaks"; public const string PluginName = "SparkleMercTweaks"; public const string PluginVersion = "1.19.0"; public void Awake() { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown //IL_00b8: Expected O, but got Unknown MercEvisTweak.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); MercEvisTweak.ApplyLanguage(); MercSlicingWindsTweak.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); MercSlicingWindsTweak.ApplyLanguage(); MercSecondaryTweaks.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); MercSecondaryTweaks.ApplyLanguage(); MercUtilityTweaks.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); MercUtilityTweaks.ApplyLanguage(); MercBodyStatsTweaks.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); Harmony val = new Harmony("com.sparkletwilight.sparklemerctweaks"); EvisZeroArmorDouble.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); EvisZeroArmorDouble.Patch(val); MercSlicingWindsTweak.Patch(val); MercExposeCripple.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); MercExposeCripple.Patch(val); MercUtilityTweaks.Patch(val); MercSecondaryTweaks.Patch(val); MercBodyStatsTweaks.Patch(val); ((BaseUnityPlugin)this).Logger.LogInfo((object)("SparkleMercTweaks v1.19.0 已加载。" + MercEvisTweak.Summary() + EvisZeroArmorDouble.Summary() + MercSlicingWindsTweak.Summary() + MercExposeCripple.Summary() + MercSecondaryTweaks.Summary() + MercUtilityTweaks.Summary() + MercBodyStatsTweaks.Summary())); } public void Update() { MercEvisTweak.ApplyRadii(); MercSecondaryTweaks.ApplyCoefficients(); MercUtilityTweaks.ApplyCoefficients(); MercEvisTweak.ProbeToken(); } } }