Decompiled source of SparkleBanditTweaks v3.9.0

plugins/SparkleBanditTweaks.dll

Decompiled 19 minutes ago
using 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<float> RifleSpreadMultiplier;

		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 x 80% = 400%。");
			VanillaShotgunDamagePercent = config.Bind<float>("Primary", "VanillaShotgunDamagePercent", 100f, "迸射的原版每段伤害百分比,只用来换算缩放比例,一般不用改。");
			ShotgunProcCoefficient = config.Bind<float>("Primary", "ShotgunProcCoefficient", 0.7f, "迸射的触发系数(影响道具触发几率)。0.7 = 每颗弹丸 70%。");
			RifleDamagePercent = config.Bind<float>("Primary", "RifleDamagePercent", 380f, "轰击(步枪)的伤害百分比。380 = 380%(原版 330%)。");
			VanillaRifleDamagePercent = config.Bind<float>("Primary", "VanillaRifleDamagePercent", 330f, "轰击的原版伤害百分比,只用来换算缩放比例,一般不用改。");
			RifleSpreadMultiplier = config.Bind<float>("Primary", "RifleSpreadMultiplier", 0.15f, "轰击(步枪)的弹道偏移缩放系数。1 = 保持原版;0.15 = 弹道偏移(含开火后\n准星扩大造成的偏移)降到原版的 15%。数值越小弹道越集中。");
			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(__instance, 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}%(x{5} 颗)," + $"触发系数 {((ShotgunProcCoefficient == null) ? 0f : ShotgunProcCoefficient.Value):0.##}");
				}
			}
		}

		private static void ApplyRifle(Bandit2FirePrimaryBase __instance, BulletAttack bulletAttack)
		{
			if (RifleDamagePercent != null && VanillaRifleDamagePercent != null)
			{
				if (VanillaRifleDamagePercent.Value > 0f)
				{
					bulletAttack.damage *= RifleDamagePercent.Value / VanillaRifleDamagePercent.Value;
				}
				if (RifleSpreadMultiplier != null)
				{
					float value = RifleSpreadMultiplier.Value;
					bulletAttack.minSpread *= value;
					bulletAttack.maxSpread *= value;
					bulletAttack.spreadPitchScale *= value;
					bulletAttack.spreadYawScale *= value;
				}
				Bandit2FireRifle val = (Bandit2FireRifle)(object)((__instance is Bandit2FireRifle) ? __instance : null);
				if (val != null)
				{
					float num = ((RifleSpreadMultiplier != null) ? RifleSpreadMultiplier.Value : 1f);
					((GenericBulletBaseState)val).spreadBloomValue = ((GenericBulletBaseState)val).spreadBloomValue * num;
				}
				if (!_rifleLogged)
				{
					_rifleLogged = true;
					Log((LogLevel)16, $"M1 轰击补丁已生效:{VanillaRifleDamagePercent.Value:0}% -> " + $"{RifleDamagePercent.Value:0}%(触发系数不变)" + ((RifleSpreadMultiplier != null) ? $";弹道偏移 x{RifleSpreadMultiplier.Value:0.##}" : ""));
				}
			}
		}

		public static void ApplyLanguage()
		{
			if (OverridePrimaryDescription != null && OverridePrimaryDescription.Value)
			{
				string text = "使用霰弹枪射击,造成" + 5 + "x" + ShotgunDamagePercent.Value.ToString("0") + "%的伤害。最多可发射4发子弹。";
				string text2 = "使用步枪射击,造成" + RifleDamagePercent.Value.ToString("0") + "%的伤害。";
				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()
		{
			string text = (OverridePrimaryDescription.Value ? "已覆盖" : "保持原版");
			return "M1 迸射:每段 " + VanillaShotgunDamagePercent.Value.ToString("0") + "% -> " + ShotgunDamagePercent.Value.ToString("0") + "%(" + 5 + " 颗共 " + (ShotgunDamagePercent.Value * 5f).ToString("0") + "%),触发系数 " + ShotgunProcCoefficient.Value.ToString("0.##") + ";M1 轰击:" + VanillaRifleDamagePercent.Value.ToString("0") + "% -> " + RifleDamagePercent.Value.ToString("0") + "%,弹道偏移 x" + RifleSpreadMultiplier.Value.ToString("0.##") + ";M1 说明" + text + "。";
		}

		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.9.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.9.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.9.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;
		}
	}
}