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 SparkleBanditTweaks v3.8.0
plugins/SparkleBanditTweaks.dll
Decompiled 6 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using EntityStates; using EntityStates.Bandit2; using EntityStates.Bandit2.Weapon; using HarmonyLib; using Microsoft.CodeAnalysis; using On.RoR2; using R2API; using RoR2; 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("BanditSmokeBombSpeed")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("BanditSmokeBombSpeed")] [assembly: AssemblyTitle("BanditSmokeBombSpeed")] [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 BanditSmokeBombSpeed { public static class BanditSecondaryTweak { [CompilerGenerated] private static class <>O { public static hook_OnHitEnemy <0>__OnHitEnemy; } private const string ShivDescriptionToken = "BANDIT2_SECONDARY_DESCRIPTION"; private const string AltShivDescriptionToken = "BANDIT2_SECONDARY_ALT_DESCRIPTION"; private const string BanditBodyToken = "BANDIT2_BODY_NAME"; internal static ConfigEntry<bool> BleedOnNonCrit; internal static ConfigEntry<float> BleedDuration; internal static ConfigEntry<float> BleedDamageMultiplier; internal static ConfigEntry<bool> ScaleByProcCoefficient; internal static ConfigEntry<bool> RequireBanditAttacker; internal static ConfigEntry<bool> OverrideSecondaryDescription; private static ManualLogSource _log; private static bool _bleedLogged; private static readonly FieldInfo ComboRawField = AccessTools.Field(typeof(DamageTypeCombo), "damageTypeCombined"); public static void Init(ConfigFile config, ManualLogSource logger) { _log = logger; BleedOnNonCrit = config.Bind<bool>("BanditSecondary", "BleedOnNonCrit", true, "盗贼的两个 M2(锯齿匕首 / 锯齿小刀)在未暴击时造成「流血」(三尖匕首那种)。\n暴击时仍按原版造成「出血」。"); BleedDuration = config.Bind<float>("BanditSecondary", "BleedDuration", 3f, "施加的流血持续多少秒。\n3 = 与原版三尖匕首一致。"); BleedDamageMultiplier = config.Bind<float>("BanditSecondary", "BleedDamageMultiplier", 1f, "流血的伤害倍率。1 = 与原版三尖匕首一致。"); ScaleByProcCoefficient = config.Bind<bool>("BanditSecondary", "ScaleByProcCoefficient", true, "持续时间是否乘以技能的触发系数(原版三尖匕首就是这么算的)。\n关掉则恒定用 BleedDuration 秒。"); RequireBanditAttacker = config.Bind<bool>("BanditSecondary", "RequireBanditAttacker", true, "只处理攻击者是盗贼的命中。关掉则任何带「暴击出血」标记的伤害未暴击都会造成流血。"); OverrideSecondaryDescription = config.Bind<bool>("BanditSecondary", "OverrideSecondaryDescription", true, "是否把两个 M2 的技能说明改成与实际效果一致的文本(在原版文案后补一句未暴击造成流血)。"); } public static void SetupHooks(ManualLogSource logger) { //IL_0016: 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) //IL_0021: Expected O, but got Unknown _log = logger; try { object obj = <>O.<0>__OnHitEnemy; if (obj == null) { hook_OnHitEnemy val = OnHitEnemy; <>O.<0>__OnHitEnemy = val; obj = (object)val; } GlobalEventManager.OnHitEnemy += (hook_OnHitEnemy)obj; Log((LogLevel)16, "钩子已挂载:GlobalEventManager.OnHitEnemy(M2 未暴击流血)"); } catch (Exception ex) { Log((LogLevel)2, "钩子挂载失败:GlobalEventManager.OnHitEnemy —— " + ex.Message); } } private static void OnHitEnemy(orig_OnHitEnemy orig, GlobalEventManager self, DamageInfo damageInfo, GameObject victim) { orig.Invoke(self, damageInfo, victim); try { TryApplyBleed(damageInfo, victim); } catch (Exception ex) { Log((LogLevel)4, "施加流血时出错:" + ex.Message); } } private static void TryApplyBleed(DamageInfo damageInfo, GameObject victim) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (BleedOnNonCrit == null || !BleedOnNonCrit.Value || damageInfo == null || (Object)(object)victim == (Object)null || damageInfo.crit || !HasFlag(damageInfo.damageType, (DamageType)134217728)) { return; } GameObject attacker = damageInfo.attacker; if ((Object)(object)attacker == (Object)null || (RequireBanditAttacker != null && RequireBanditAttacker.Value && !IsBandit(attacker))) { return; } float procCoefficient = damageInfo.procCoefficient; bool flag = ScaleByProcCoefficient == null || ScaleByProcCoefficient.Value; float num = BleedDuration.Value * (flag ? procCoefficient : 1f); if (!(num <= 0f)) { DotController.InflictDot(victim, attacker, damageInfo.inflictedHurtbox, (DotIndex)0, num, BleedDamageMultiplier.Value, (uint?)null); if (!_bleedLogged) { _bleedLogged = true; Log((LogLevel)16, $"M2 未暴击流血已生效:{num:0.##} 秒 ×{BleedDamageMultiplier.Value:0.##}"); } } } private static bool IsBandit(GameObject attacker) { CharacterBody component = attacker.GetComponent<CharacterBody>(); if ((Object)(object)component == (Object)null) { return false; } if (!string.IsNullOrEmpty(component.baseNameToken) && string.Equals(component.baseNameToken, "BANDIT2_BODY_NAME", StringComparison.Ordinal)) { return true; } return (((Object)attacker).name ?? string.Empty).IndexOf("Bandit2", StringComparison.OrdinalIgnoreCase) >= 0; } private static bool HasFlag(DamageTypeCombo combo, DamageType flag) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (ComboRawField == null) { return false; } object obj = combo; object value = ComboRawField.GetValue(obj); if (value == null) { return false; } return (Convert.ToUInt64(value) & (ulong)flag) != 0; } public static void ApplyLanguage() { if (OverrideSecondaryDescription != null && OverrideSecondaryDescription.Value) { string text = "向前突进,挥动匕首,造成<style=cIsDamage>360%的伤害</style>并<style=cIsHealth>流血</style>。暴击则造成<style=cIsHealth>出血</style>。"; string text2 = "掷出一枚小刀,造成<style=cIsDamage>240%的伤害</style>并<style=cIsHealth>流血</style>。暴击则造成<style=cIsHealth>出血</style>。"; LanguageAPI.Add("BANDIT2_SECONDARY_DESCRIPTION", text, "en"); LanguageAPI.Add("BANDIT2_SECONDARY_DESCRIPTION", text, "zh-CN"); LanguageAPI.Add("BANDIT2_SECONDARY_ALT_DESCRIPTION", text2, "en"); LanguageAPI.Add("BANDIT2_SECONDARY_ALT_DESCRIPTION", text2, "zh-CN"); } } public static string Summary() { return "M2 未暴击流血" + (BleedOnNonCrit.Value ? "开启" : "关闭") + $"({BleedDuration.Value:0.##} 秒,×{BleedDamageMultiplier.Value:0.##}," + (ScaleByProcCoefficient.Value ? "按触发系数缩放" : "固定时长") + "," + (RequireBanditAttacker.Value ? "仅限盗贼" : "不限角色") + ");M2 说明" + (OverrideSecondaryDescription.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 DesperadoTweak { private const string DesperadoDescriptionToken = "BANDIT2_SPECIAL_ALT_DESCRIPTION"; private const float VanillaDamagePercent = 600f; private const float VanillaStackBonus = 0.1f; internal static ConfigEntry<float> DesperadoDamagePercent; internal static ConfigEntry<float> StackDamageBonus; internal static ConfigEntry<bool> ApplyStackToPrimary; internal static ConfigEntry<bool> OverrideDesperadoDescription; private static ManualLogSource _log; private static bool _revolverFired; private static bool _skullFired; private static bool _primaryFired; private static readonly PropertyInfo CharacterBodyProperty = AccessTools.Property(typeof(EntityState), "characterBody"); public static void Init(ConfigFile config, ManualLogSource logger) { _log = logger; DesperadoDamagePercent = config.Bind<float>("Desperado", "DesperadoDamagePercent", 800f, "亡命徒与熄灯(两个 R 技能)的基础伤害倍率。800 = 800%,原版两个都是 600。"); StackDamageBonus = config.Bind<float>("Desperado", "StackDamageBonus", 0.05f, "每层「亡命徒」叠层 buff(BanditSkull)提供的伤害加成。\n0.05 = 每层 +5%,原版是 0.1(每层 +10%)。\n总倍率 = 基础倍率 × (1 + 本值 × 层数)。"); ApplyStackToPrimary = config.Bind<bool>("Desperado", "ApplyStackToPrimary", true, "让叠层增伤同时作用于主武器(M1)。\n开启后 迸射(霰弹)和 轰击(步枪)都会吃到同样的每层加成。\n关掉则维持原版行为 —— 只有亡命徒自己吃加成。"); OverrideDesperadoDescription = config.Bind<bool>("Desperado", "OverrideDesperadoDescription", true, "是否把游戏内亡命徒的技能说明改成与实际数值一致的文本。\n文本里的百分比由上面两项配置实时算出,改配置后重启游戏即可同步。\n关掉则显示原版文本(600% / 10%)。"); } public static void Patch(Harmony harmony) { Apply(harmony, typeof(BaseFireSidearmRevolverState), "ModifyBullet", "RevolverPostfix"); Apply(harmony, typeof(FireSidearmSkullRevolver), "ModifyBullet", "SkullRevolverPostfix"); Apply(harmony, typeof(Bandit2FirePrimaryBase), "ModifyBullet", "PrimaryPostfix"); } private static void Apply(Harmony harmony, Type targetType, string targetMethod, string patchMethod) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown string text = targetType.Name + "." + targetMethod; MethodInfo methodInfo = AccessTools.Method(targetType, targetMethod, (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(DesperadoTweak), patchMethod, (Type[])null, (Type[])null); if (methodInfo == null) { Log((LogLevel)2, "补丁失败:找不到目标方法 " + text); return; } if (methodInfo2 == null) { Log((LogLevel)2, "补丁失败:找不到补丁方法 " + patchMethod); return; } try { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log((LogLevel)16, "补丁已挂载:" + text + " ← " + patchMethod + "()"); } catch (Exception ex) { Log((LogLevel)2, "补丁异常:" + text + " —— " + ex.Message); } } public static void ApplyLanguage() { if (OverrideDesperadoDescription.Value) { string text = DesperadoDamagePercent.Value.ToString("0"); string text2 = (StackDamageBonus.Value * 100f).ToString("0.##"); string text3 = "<style=cIsDamage>屠戮者</style>。使用左轮手枪进行射击,造成<style=cIsDamage>" + text + "%的伤害</style>。击败敌人可以<style=cIsDamage>叠加效果</style>,使亡命徒与主武器的伤害提高<style=cIsDamage>" + text2 + "%</style>。"; LanguageAPI.Add("BANDIT2_SPECIAL_ALT_DESCRIPTION", text3, "en"); LanguageAPI.Add("BANDIT2_SPECIAL_ALT_DESCRIPTION", text3, "zh-CN"); } } 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); } } private static CharacterBody BodyOf(EntityState state, BulletAttack bulletAttack) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown if (bulletAttack != null && (Object)(object)bulletAttack.owner != (Object)null) { CharacterBody component = bulletAttack.owner.GetComponent<CharacterBody>(); if ((Object)(object)component != (Object)null) { return component; } } if (state == null) { return null; } if (!(CharacterBodyProperty == null)) { return (CharacterBody)CharacterBodyProperty.GetValue(state); } return null; } private static int StacksOf(CharacterBody body) { if (!((Object)(object)body == (Object)null)) { return body.GetBuffCount(Buffs.BanditSkull); } return 0; } private static float StackMultiplier(CharacterBody body) { return 1f + StackDamageBonus.Value * (float)StacksOf(body); } public static void RevolverPostfix(BulletAttack bulletAttack) { if (bulletAttack != null && DesperadoDamagePercent != null) { if (!_revolverFired) { _revolverFired = true; Log((LogLevel)16, $"左轮倍率补丁已生效:{600f:0}% → {DesperadoDamagePercent.Value:0}%(亡命徒 / 熄灯)"); } bulletAttack.damage *= DesperadoDamagePercent.Value / 600f; } } public static void SkullRevolverPostfix(FireSidearmSkullRevolver __instance, BulletAttack bulletAttack) { if (bulletAttack != null && DesperadoDamagePercent != null) { int num = StacksOf(BodyOf((EntityState)(object)__instance, bulletAttack)); float num2 = 1f + 0.1f * (float)num; float num3 = 1f + StackDamageBonus.Value * (float)num; if (!_skullFired) { _skullFired = true; Log((LogLevel)16, $"亡命徒叠层补丁已生效:每层 +{10f:0}% → +{StackDamageBonus.Value * 100f:0.##}%"); } bulletAttack.damage *= num3 / num2; } } public static void PrimaryPostfix(Bandit2FirePrimaryBase __instance, BulletAttack bulletAttack) { if (bulletAttack != null && ApplyStackToPrimary.Value) { int num = StacksOf(BodyOf((EntityState)(object)__instance, bulletAttack)); if (!_primaryFired) { _primaryFired = true; Log((LogLevel)16, $"M1 叠层补丁已生效:当前 {num} 层,加成 ×{StackMultiplier(BodyOf((EntityState)(object)__instance, bulletAttack)):0.##}"); } bulletAttack.damage *= 1f + StackDamageBonus.Value * (float)num; } } } public static class LightsOutTweak { [CompilerGenerated] private static class <>O { public static hook_Fire <0>__OnBulletFire; public static hook_OnHitEnemy <1>__OnHitEnemy; } private const string LightsOutDescriptionToken = "BANDIT2_SPECIAL_DESCRIPTION"; private const float FireWindow = 0.25f; internal static ConfigEntry<bool> RestoreKillReset; internal static ConfigEntry<bool> DetonateKillReset; internal static ConfigEntry<bool> DetonateBleed; internal static ConfigEntry<float> HemorrhageDamagePercent; internal static ConfigEntry<float> BleedDamagePercent; internal static ConfigEntry<bool> RemoveStacksAfterDetonate; internal static ConfigEntry<bool> StrictSourceCheck; internal static ConfigEntry<bool> OverrideLightsOutDescription; private static ManualLogSource _log; private static float _lastFireTime = float.NegativeInfinity; private static GameObject _lastOwner; private static bool _resolving; private static bool _resetRemovedLogged; private static bool _resetRestoredLogged; private static bool _detonateLogged; private static ulong MarkerBit; private static readonly FieldInfo ComboRawField = AccessTools.Field(typeof(DamageTypeCombo), "damageTypeCombined"); private static readonly FieldInfo DotStackListField = AccessTools.Field(typeof(DotController), "dotStackList"); private static readonly Type DotStackType = typeof(DotController).GetNestedType("DotStack", BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo DotIndexField = ((DotStackType == null) ? null : AccessTools.Field(DotStackType, "dotIndex")); private static readonly MethodInfo RemoveDotStackMethod = AccessTools.Method(typeof(DotController), "RemoveDotStackAtServer", (Type[])null, (Type[])null); public static void Init(ConfigFile config, ManualLogSource logger) { _log = logger; RestoreKillReset = config.Bind<bool>("LightsOut", "RestoreKillResetCooldown", true, "恢复熄灯「击败敌人重置所有能力冷却」的效果(默认开启,即原版行为)。\n关掉它会改成清掉子弹 DamageType 里的 ResetCooldownsOnKill 标记,\n届时「熄灯直接击杀」不再重置冷却(引爆结算的击杀仍可单独控制)。"); DetonateKillReset = config.Bind<bool>("LightsOut", "DetonateKillResetsCooldown", true, "是否让「引爆结算造成的击杀」也触发重置所有技能冷却。\n原理是给结算伤害的 damageType 打上 ResetCooldownsOnKill 标记,\n游戏在 OnCharacterDeath 里检测到这个标记就会对攻击者调用 ResetSkills()。"); DetonateBleed = config.Bind<bool>("LightsOut", "DetonateBleedStacks", true, "开启新的命中效果:清除目标身上所有的出血与流血,并按移除的层数结算一次伤害。"); HemorrhageDamagePercent = config.Bind<float>("LightsOut", "HemorrhageDamagePercent", 2000f, "每移除 1 层「出血」(盗贼 M2 暴击造成的 SuperBleed)造成的伤害百分比。\n2000 = 每层 2000% 基础伤害。"); BleedDamagePercent = config.Bind<float>("LightsOut", "BleedDamagePercent", 240f, "每移除 1 层「流血」(三尖匕首造成的 Bleed)造成的伤害百分比。\n240 = 每层 240% 基础伤害。"); RemoveStacksAfterDetonate = config.Bind<bool>("LightsOut", "RemoveStacksAfterDetonate", true, "结算后是否真的把这些层数移除。关掉的话层数保留,等于白嫖一份伤害。"); StrictSourceCheck = config.Bind<bool>("LightsOut", "StrictSourceCheck", true, "是否额外要求「伤害来源为 Special」才判定为熄灯命中。\n默认开启以避免误伤其他伤害事件;如果发现新效果没触发,可以关掉试试。"); OverrideLightsOutDescription = config.Bind<bool>("LightsOut", "OverrideLightsOutDescription", true, "是否把游戏内熄灯的技能说明改成与实际效果一致的文本。\n关掉则显示原版文本(600% + 重置冷却)。"); } public static void SetupHooks(ManualLogSource logger) { _log = logger; PrepareMarker(); Hook("BulletAttack.Fire", delegate { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown object obj = <>O.<0>__OnBulletFire; if (obj == null) { hook_Fire val = OnBulletFire; <>O.<0>__OnBulletFire = val; obj = (object)val; } BulletAttack.Fire += (hook_Fire)obj; }); Hook("GlobalEventManager.OnHitEnemy", delegate { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown object obj = <>O.<1>__OnHitEnemy; if (obj == null) { hook_OnHitEnemy val = OnHitEnemy; <>O.<1>__OnHitEnemy = val; obj = (object)val; } GlobalEventManager.OnHitEnemy += (hook_OnHitEnemy)obj; }); } private static void PrepareMarker() { if (ComboRawField == null) { Log((LogLevel)4, "熄灯:找不到 DamageTypeCombo.damageTypeCombined,改用时间窗判定命中来源"); return; } Type fieldType = ComboRawField.FieldType; if (fieldType == typeof(ulong)) { MarkerBit = 4611686018427387904uL; Log((LogLevel)16, "熄灯:damageTypeCombined 是 ulong,标记位可用"); } else { MarkerBit = 0uL; Log((LogLevel)4, "熄灯:damageTypeCombined 是 " + fieldType.Name + ",没有空位放标记,改用时间窗判定命中来源"); } } private static void Hook(string label, Action action) { try { action(); Log((LogLevel)16, "钩子已挂载:" + label); } catch (Exception ex) { Log((LogLevel)2, "钩子挂载失败:" + label + " —— " + ex.Message); } } private static void OnBulletFire(orig_Fire orig, BulletAttack self) { MarkLightsOut(self); orig.Invoke(self); } public static void FirePrefix(BulletAttack __instance) { MarkLightsOut(__instance); } private static void MarkLightsOut(BulletAttack self) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) if (self == null || !HasFlag(self.damageType, (DamageType)4)) { return; } if (RestoreKillReset == null || !RestoreKillReset.Value) { DamageTypeCombo combo = self.damageType; ClearFlag(ref combo, (DamageType)4); if (MarkerBit != 0L) { object obj = combo; ulong num = Convert.ToUInt64(ComboRawField.GetValue(obj)) | MarkerBit; ComboRawField.SetValue(obj, Convert.ChangeType(num, ComboRawField.FieldType)); combo = (DamageTypeCombo)obj; } self.damageType = combo; if (!_resetRemovedLogged) { _resetRemovedLogged = true; Log((LogLevel)16, "熄灯:已移除「击败敌人重置冷却」(清掉 ResetCooldownsOnKill 标记)"); } } else if (!_resetRestoredLogged) { _resetRestoredLogged = true; Log((LogLevel)16, "熄灯:保留原版「击败敌人重置冷却」(ResetCooldownsOnKill 标记原样保留)"); } if (MarkerBit != 0L) { DamageTypeCombo damageType = self.damageType; object obj2 = damageType; ulong num2 = Convert.ToUInt64(ComboRawField.GetValue(obj2)) | MarkerBit; ComboRawField.SetValue(obj2, Convert.ChangeType(num2, ComboRawField.FieldType)); damageType = (DamageTypeCombo)obj2; self.damageType = damageType; } _lastFireTime = Time.time; _lastOwner = self.owner; } public static void Patch(Harmony harmony) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(typeof(BulletAttack), "Fire", new Type[0], (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(LightsOutTweak), "FirePrefix", (Type[])null, (Type[])null); if (methodInfo == null) { Log((LogLevel)2, "补丁失败:找不到目标方法 BulletAttack.Fire()"); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log((LogLevel)16, "补丁已挂载:BulletAttack.Fire() ← FirePrefix()"); } catch (Exception ex) { Log((LogLevel)2, "补丁异常:BulletAttack.Fire() —— " + ex.Message); } } private static void OnHitEnemy(orig_OnHitEnemy orig, GlobalEventManager self, DamageInfo damageInfo, GameObject victim) { orig.Invoke(self, damageInfo, victim); if (!_resolving && !((Object)(object)victim == (Object)null) && damageInfo != null && DetonateBleed != null && DetonateBleed.Value && IsLightsOutHit(damageInfo)) { Detonate(damageInfo, victim); } } private static bool IsLightsOutHit(DamageInfo damageInfo) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (Time.time - _lastFireTime > 0.25f) { return false; } if ((Object)(object)_lastOwner == (Object)null || damageInfo.attacker != _lastOwner) { return false; } if (StrictSourceCheck != null && StrictSourceCheck.Value) { bool num = MarkerBit != 0L && (RawOf(damageInfo.damageType) & MarkerBit) != 0; bool flag = HasFlag(damageInfo.damageType, (DamageType)4); if (!num && !flag) { return false; } } return true; } private static void Detonate(DamageInfo sourceInfo, GameObject victim) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Invalid comparison between Unknown and I4 //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Expected O, but got Unknown DotController val = DotController.FindDotController(victim); if ((Object)(object)val == (Object)null || DotStackListField == null || DotIndexField == null || !(DotStackListField.GetValue(val) is IList { Count: not 0 } list)) { return; } int num = 0; int num2 = 0; List<int> list2 = new List<int>(); for (int i = 0; i < list.Count; i++) { object obj = list[i]; if (obj == null) { continue; } object value = DotIndexField.GetValue(obj); if (value != null) { DotIndex val2 = (DotIndex)Convert.ToInt32(value); if ((int)val2 == 6) { num++; list2.Add(i); } else if ((int)val2 == 0) { num2++; list2.Add(i); } } } if (num == 0 && num2 == 0) { return; } GameObject attacker = sourceInfo.attacker; CharacterBody val3 = (((Object)(object)attacker == (Object)null) ? null : attacker.GetComponent<CharacterBody>()); HealthComponent component = victim.GetComponent<HealthComponent>(); if ((Object)(object)val3 == (Object)null || (Object)(object)component == (Object)null) { return; } float num3 = val3.damage * (HemorrhageDamagePercent.Value / 100f * (float)num + BleedDamagePercent.Value / 100f * (float)num2); if (RemoveStacksAfterDetonate != null && RemoveStacksAfterDetonate.Value) { RemoveStacks(val, list2); } if (!_detonateLogged) { _detonateLogged = true; Log((LogLevel)16, $"熄灯引爆已生效:出血 {num} 层 × {HemorrhageDamagePercent.Value:0}% + " + $"流血 {num2} 层 × {BleedDamagePercent.Value:0}% = {num3:0.##} 伤害"); } _resolving = true; try { DamageInfo val4 = new DamageInfo { damage = num3, attacker = attacker, inflictor = attacker, position = victim.transform.position, force = Vector3.zero, crit = false, procCoefficient = 0f, damageColorIndex = (DamageColorIndex)2, damageType = DamageTypeCombo.op_Implicit((DamageType)((DetonateKillReset != null && DetonateKillReset.Value) ? 4 : 0)), procChainMask = default(ProcChainMask) }; component.TakeDamage(val4); } finally { _resolving = false; } } private static void RemoveStacks(DotController controller, List<int> indices) { if (RemoveDotStackMethod == null) { return; } for (int num = indices.Count - 1; num >= 0; num--) { try { RemoveDotStackMethod.Invoke(controller, new object[1] { indices[num] }); } catch (Exception ex) { Log((LogLevel)4, "移除流血层数时出错:" + ex.Message); } } } private static bool HasFlag(DamageTypeCombo combo, DamageType flag) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) return (RawOf(combo) & (ulong)flag) != 0; } private static void ClearFlag(ref DamageTypeCombo combo, DamageType flag) { //IL_0001: 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_001f: 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) ulong num = RawOf(combo) & ~(ulong)flag; if (!(ComboRawField == null)) { object obj = combo; ComboRawField.SetValue(obj, Convert.ChangeType(num, ComboRawField.FieldType)); combo = (DamageTypeCombo)obj; } } private static ulong RawOf(DamageTypeCombo combo) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (ComboRawField == null) { return 0uL; } object obj = combo; object value = ComboRawField.GetValue(obj); if (value != null) { return Convert.ToUInt64(value); } return 0uL; } public static void ApplyLanguage() { if (OverrideLightsOutDescription != null && OverrideLightsOutDescription.Value) { string text = ((DesperadoTweak.DesperadoDamagePercent == null) ? "800" : DesperadoTweak.DesperadoDamagePercent.Value.ToString("0")); string text2 = "<style=cIsDamage>屠戮者</style>。使用左轮手枪进行射击,造成<style=cIsDamage>" + text + "%的伤害</style>。命中时清算目标身上的<style=cIsHealth>出血</style>与<style=cIsHealth>流血</style>。<style=cIsUtility>击败敌人会重置所有技能的冷却时间。</style>"; LanguageAPI.Add("BANDIT2_SPECIAL_DESCRIPTION", text2, "en"); LanguageAPI.Add("BANDIT2_SPECIAL_DESCRIPTION", text2, "zh-CN"); } } public static string Summary() { return "熄灯:击败重置冷却" + (RestoreKillReset.Value ? "保留原版" : "已移除") + ";引爆结算的击杀也重置冷却" + (DetonateKillReset.Value ? "开启" : "关闭") + ";" + string.Format("引爆{0}(出血每层 {1:0}%,", DetonateBleed.Value ? "开启" : "关闭", HemorrhageDamagePercent.Value) + $"流血每层 {BleedDamagePercent.Value:0}%," + "层数" + (RemoveStacksAfterDetonate.Value ? "结算后移除" : "保留") + ");技能描述" + (OverrideLightsOutDescription.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 PrimaryTweak { private const string ShotgunToken = "BANDIT2_PRIMARY_DESCRIPTION"; private const string RifleToken = "BANDIT2_PRIMARY_ALT_DESCRIPTION"; private const int ShotgunPellets = 5; internal static ConfigEntry<float> ShotgunDamagePercent; internal static ConfigEntry<float> VanillaShotgunDamagePercent; internal static ConfigEntry<float> ShotgunProcCoefficient; internal static ConfigEntry<float> RifleDamagePercent; internal static ConfigEntry<float> VanillaRifleDamagePercent; internal static ConfigEntry<bool> OverridePrimaryDescription; private static ManualLogSource _log; private static bool _shotgunLogged; private static bool _rifleLogged; public static void Init(ConfigFile config, ManualLogSource logger) { _log = logger; ShotgunDamagePercent = config.Bind<float>("Primary", "ShotgunDamagePercent", 80f, "迸射(霰弹枪)每颗弹丸的伤害百分比。80 = 每段 80%(原版 100%)。\n一次打出 5 颗,所以满命中是 5 × 80% = 400%。"); VanillaShotgunDamagePercent = config.Bind<float>("Primary", "VanillaShotgunDamagePercent", 100f, "迸射的原版每段伤害百分比,只用来换算缩放比例,一般不用改。"); ShotgunProcCoefficient = config.Bind<float>("Primary", "ShotgunProcCoefficient", 0.75f, "迸射的触发系数(影响道具触发几率)。0.75 = 每颗弹丸 75%。"); RifleDamagePercent = config.Bind<float>("Primary", "RifleDamagePercent", 380f, "轰击(步枪)的伤害百分比。380 = 380%(原版 330%)。"); VanillaRifleDamagePercent = config.Bind<float>("Primary", "VanillaRifleDamagePercent", 330f, "轰击的原版伤害百分比,只用来换算缩放比例,一般不用改。"); OverridePrimaryDescription = config.Bind<bool>("Primary", "OverridePrimaryDescription", true, "是否把两个 M1 的技能说明改成与实际数值一致的文本。\n关掉则显示原版(5x100% / 330%)。"); } public static void Patch(Harmony harmony) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown string text = "Bandit2FirePrimaryBase.ModifyBullet"; MethodInfo methodInfo = AccessTools.Method(typeof(Bandit2FirePrimaryBase), "ModifyBullet", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(PrimaryTweak), "PrimaryPostfix", (Type[])null, (Type[])null); if (methodInfo == null) { Log((LogLevel)2, "补丁失败:找不到目标方法 " + text); return; } try { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log((LogLevel)16, "补丁已挂载:" + text + " ← PrimaryPostfix()"); } catch (Exception ex) { Log((LogLevel)2, "补丁异常:" + text + " —— " + ex.Message); } } public static void PrimaryPostfix(Bandit2FirePrimaryBase __instance, BulletAttack bulletAttack) { if (bulletAttack != null && __instance != null) { if (__instance is FireShotgun2) { ApplyShotgun(bulletAttack); } else if (__instance is Bandit2FireRifle) { ApplyRifle(bulletAttack); } } } private static void ApplyShotgun(BulletAttack bulletAttack) { if (ShotgunDamagePercent != null && VanillaShotgunDamagePercent != null) { if (VanillaShotgunDamagePercent.Value > 0f) { bulletAttack.damage *= ShotgunDamagePercent.Value / VanillaShotgunDamagePercent.Value; } if (ShotgunProcCoefficient != null) { bulletAttack.procCoefficient = ShotgunProcCoefficient.Value; } if (!_shotgunLogged) { _shotgunLogged = true; Log((LogLevel)16, $"M1 迸射补丁已生效:{VanillaShotgunDamagePercent.Value:0}% → " + $"{ShotgunDamagePercent.Value:0}%(×{5} 颗)," + $"触发系数 {((ShotgunProcCoefficient == null) ? 0f : ShotgunProcCoefficient.Value):0.##}"); } } } private static void ApplyRifle(BulletAttack bulletAttack) { if (RifleDamagePercent != null && VanillaRifleDamagePercent != null) { if (VanillaRifleDamagePercent.Value > 0f) { bulletAttack.damage *= RifleDamagePercent.Value / VanillaRifleDamagePercent.Value; } if (!_rifleLogged) { _rifleLogged = true; Log((LogLevel)16, $"M1 轰击补丁已生效:{VanillaRifleDamagePercent.Value:0}% → " + $"{RifleDamagePercent.Value:0}%(触发系数不变)"); } } } public static void ApplyLanguage() { if (OverridePrimaryDescription != null && OverridePrimaryDescription.Value) { string text = $"使用霰弹枪射击,造成<style=cIsDamage>{5}x" + $"{ShotgunDamagePercent.Value:0}%的伤害</style>。最多可发射4发子弹。"; string text2 = $"使用步枪射击,造成<style=cIsDamage>{RifleDamagePercent.Value:0}%的伤害</style>。" + "最多可发射4发子弹。"; LanguageAPI.Add("BANDIT2_PRIMARY_DESCRIPTION", text, "en"); LanguageAPI.Add("BANDIT2_PRIMARY_DESCRIPTION", text, "zh-CN"); LanguageAPI.Add("BANDIT2_PRIMARY_ALT_DESCRIPTION", text2, "en"); LanguageAPI.Add("BANDIT2_PRIMARY_ALT_DESCRIPTION", text2, "zh-CN"); } } public static string Summary() { return $"M1 迸射:每段 {VanillaShotgunDamagePercent.Value:0}% → {ShotgunDamagePercent.Value:0}%" + $"({5} 颗共 {ShotgunDamagePercent.Value * 5f:0}%)," + $"触发系数 {ShotgunProcCoefficient.Value:0.##};" + $"M1 轰击:{VanillaRifleDamagePercent.Value:0}% → {RifleDamagePercent.Value:0}%(系数不变);" + "M1 说明" + (OverridePrimaryDescription.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); } } } [BepInPlugin("com.yourname.banditsmokebombspeed", "BanditSmokeBombSpeed", "3.8.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class SmokeBombSpeedPlugin : BaseUnityPlugin { private class Tracker { public float StartTime; public int LastTier = -1; } public const string PluginGUID = "com.yourname.banditsmokebombspeed"; public const string PluginName = "BanditSmokeBombSpeed"; public const string PluginVersion = "3.8.0"; private const float VanillaBonus = 0.4f; private const string ModeFlat = "Flat"; private const string ModeRelative = "Relative"; private const string SkillDescriptionToken = "BANDIT2_UTILITY_DESCRIPTION"; private const string SkillDescription = "眩晕。造成<style=cIsDamage>120%的伤害</style>,进入<style=cIsUtility>隐身</style>,然后再次造成<style=cIsDamage>120%的伤害</style>。在此期间获得持续衰减的<style=cIsUtility>+150%移动速度</style>。"; internal static ConfigEntry<float> InitialBonus; internal static ConfigEntry<float> DecayInterval; internal static ConfigEntry<float> DecayPerTick; internal static ConfigEntry<float> Duration; internal static ConfigEntry<string> DecayMode; internal static ConfigEntry<bool> OnlyAffectBandit; internal static ConfigEntry<float> SmokeBombDamageCoefficient; internal static ConfigEntry<bool> OverrideSkillDescription; private readonly Dictionary<CharacterBody, Tracker> _trackers = new Dictionary<CharacterBody, Tracker>(); private readonly List<CharacterBody> _toRemove = new List<CharacterBody>(); public void Awake() { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Expected O, but got Unknown //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Expected O, but got Unknown //IL_01c6: Expected O, but got Unknown //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Expected O, but got Unknown InitialBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Smoke Bomb", "InitialBonus", 1.5f, "隐身刚开始的移动速度加成。1.5 = +150%(最终移速为基础值的 2.5 倍)。"); DecayInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Smoke Bomb", "DecayInterval", 0.3f, "每隔多少秒衰减一档。"); DecayPerTick = ((BaseUnityPlugin)this).Config.Bind<float>("Smoke Bomb", "DecayPerTick", 0.15f, "每档减少多少。Flat 模式下 0.15 = 每档减 15 个百分点(+150% → +135% → +120%...);\nRelative 模式下 0.15 = 每档降低 15%(+150% → +127.5% → +108%...)。"); Duration = ((BaseUnityPlugin)this).Config.Bind<float>("Smoke Bomb", "Duration", 3f, "加成总持续时间(秒),与烟雾弹技能持续时间一致。超过后加成归零。"); DecayMode = ((BaseUnityPlugin)this).Config.Bind<string>("Smoke Bomb", "DecayMode", "Flat", new ConfigDescription("衰减方式。Flat = 每档固定减掉 DecayPerTick 的加成值(匀速下降);\nRelative = 每档乘以 (1 - DecayPerTick)(前段掉得快、后段拖尾)。", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "Flat", "Relative" }), Array.Empty<object>())); OnlyAffectBandit = ((BaseUnityPlugin)this).Config.Bind<bool>("Smoke Bomb", "OnlyAffectBandit", true, "开启时只对盗贼生效;关闭时任何获得 CloakSpeed 隐身加速状态的角色都会生效。"); SmokeBombDamageCoefficient = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "SmokeBombDamageCoefficient", 1.2f, "烟雾弹爆炸的伤害系数,按「每段」计。原版是 2.0(每段 200%),改成 1.2 就是每段 120%。\n眩晕不受这个值影响 —— 眩晕来自 damageType 里的 Stun1s,伤害多少都会触发。\n设成 0 则完全不造成伤害。"); OverrideSkillDescription = ((BaseUnityPlugin)this).Config.Bind<bool>("Description", "OverrideSkillDescription", true, "是否把游戏内盗贼 utility 技能(Shift)的说明文本改成与实际效果一致的描述。\n关掉则显示原版文本。改完需要重启游戏。"); DesperadoTweak.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); DesperadoTweak.ApplyLanguage(); LightsOutTweak.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); LightsOutTweak.ApplyLanguage(); LightsOutTweak.SetupHooks(((BaseUnityPlugin)this).Logger); BanditSecondaryTweak.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); BanditSecondaryTweak.ApplyLanguage(); BanditSecondaryTweak.SetupHooks(((BaseUnityPlugin)this).Logger); PrimaryTweak.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); PrimaryTweak.ApplyLanguage(); Harmony val = new Harmony("com.yourname.banditsmokebombspeed"); DesperadoTweak.Patch(val); PrimaryTweak.Patch(val); LightsOutTweak.Patch(val); ApplySkillDescription(); RecalculateStatsAPI.GetStatCoefficients += new StatHookEventHandler(OnGetStatCoefficients); ((BaseUnityPlugin)this).Logger.LogInfo((object)("BanditSmokeBombSpeed v3.8.0 已加载。" + $"移速:起始 +{InitialBonus.Value * 100f:0}%,每 {DecayInterval.Value:0.##} 秒减少 " + $"{DecayPerTick.Value * 100f:0} 个百分点(模式 {DecayMode.Value}),持续 {Duration.Value:0.##} 秒;" + $"烟雾弹伤害系数 {SmokeBombDamageCoefficient.Value * 100f:0}%(原版每段 200%);" + "技能描述" + (OverrideSkillDescription.Value ? "已覆盖" : "保持原版") + "。")); ((BaseUnityPlugin)this).Logger.LogInfo((object)($"R 技能:亡命徒与熄灯的基础倍率都是 {DesperadoTweak.DesperadoDamagePercent.Value:0}%(原版 600%)," + $"亡命徒每层叠层 +{DesperadoTweak.StackDamageBonus.Value * 100f:0.##}%(原版 10%)," + "叠层增伤" + (DesperadoTweak.ApplyStackToPrimary.Value ? "同时作用于 M1(迸射 / 轰击)" : "仅作用于亡命徒") + "。")); ((BaseUnityPlugin)this).Logger.LogInfo((object)LightsOutTweak.Summary()); ((BaseUnityPlugin)this).Logger.LogInfo((object)BanditSecondaryTweak.Summary()); ((BaseUnityPlugin)this).Logger.LogInfo((object)PrimaryTweak.Summary()); } private void ApplySkillDescription() { if (OverrideSkillDescription.Value) { LanguageAPI.Add("BANDIT2_UTILITY_DESCRIPTION", "眩晕。造成<style=cIsDamage>120%的伤害</style>,进入<style=cIsUtility>隐身</style>,然后再次造成<style=cIsDamage>120%的伤害</style>。在此期间获得持续衰减的<style=cIsUtility>+150%移动速度</style>。", "en"); LanguageAPI.Add("BANDIT2_UTILITY_DESCRIPTION", "眩晕。造成<style=cIsDamage>120%的伤害</style>,进入<style=cIsUtility>隐身</style>,然后再次造成<style=cIsDamage>120%的伤害</style>。在此期间获得持续衰减的<style=cIsUtility>+150%移动速度</style>。", "zh-CN"); } } public void Update() { ApplyDamageCoefficient(); ReadOnlyCollection<CharacterBody> readOnlyInstancesList = CharacterBody.readOnlyInstancesList; for (int i = 0; i < readOnlyInstancesList.Count; i++) { CharacterBody val = readOnlyInstancesList[i]; if ((Object)(object)val == (Object)null) { continue; } if (val.HasBuff(Buffs.CloakSpeed) && AppliesTo(val)) { Tracker tracker = EnsureTracker(val); int num = TierOf(Time.time - tracker.StartTime); if (num != tracker.LastTier) { tracker.LastTier = num; val.RecalculateStats(); } } else if (_trackers.ContainsKey(val)) { val.RecalculateStats(); _toRemove.Add(val); } } CleanupCulled(); } private void ApplyDamageCoefficient() { StealthMode.blastAttackDamageCoefficient = SmokeBombDamageCoefficient.Value; } private void OnGetStatCoefficients(CharacterBody body, StatHookEventArgs args) { if (!((Object)(object)body == (Object)null) && body.HasBuff(Buffs.CloakSpeed) && AppliesTo(body)) { args.moveSpeedMultAdd += CurrentBonus(body) - 0.4f; } } private float CurrentBonus(CharacterBody body) { Tracker tracker = EnsureTracker(body); float num = Time.time - tracker.StartTime; if (num >= Duration.Value) { return 0f; } int num2 = (tracker.LastTier = TierOf(num)); float num3 = ((!string.Equals(DecayMode.Value, "Relative", StringComparison.OrdinalIgnoreCase)) ? (InitialBonus.Value - DecayPerTick.Value * (float)num2) : (InitialBonus.Value * Mathf.Pow(1f - DecayPerTick.Value, (float)num2))); if (!(num3 > 0f)) { return 0f; } return num3; } private int TierOf(float elapsed) { float value = DecayInterval.Value; if (value <= 0f) { return 0; } return Mathf.FloorToInt(elapsed / value); } private Tracker EnsureTracker(CharacterBody body) { if (_trackers.TryGetValue(body, out var value) && value != null) { return value; } value = new Tracker { StartTime = Time.time }; _trackers[body] = value; return value; } private void CleanupCulled() { if (_toRemove.Count == 0 && _trackers.Count == 0) { return; } foreach (CharacterBody key in _trackers.Keys) { if ((Object)(object)key == (Object)null) { _toRemove.Add(key); } } for (int i = 0; i < _toRemove.Count; i++) { _trackers.Remove(_toRemove[i]); } _toRemove.Clear(); } private bool AppliesTo(CharacterBody body) { if (OnlyAffectBandit.Value) { return IsBandit(body); } return true; } private static bool IsBandit(CharacterBody body) { if (((Object)body).name != null) { return ((Object)body).name.StartsWith("Bandit2Body", StringComparison.Ordinal); } return false; } } }