Decompiled source of VoidFiendPassiveAndBuffs v0.2.3

plugins/VoidFiendUnstableTouch.dll

Decompiled 14 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates;
using EntityStates.VoidSurvivor;
using EntityStates.VoidSurvivor.CorruptMode;
using EntityStates.VoidSurvivor.Weapon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using RoR2;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.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 VoidFiendUnstableTouch
{
	internal sealed class AbilityBuffs : IDisposable
	{
		private static AbilityBuffs active;

		private readonly Harmony patches = new Harmony("local.voidfiend.unstabletouch.abilities");

		private readonly AbilityEffects effects = new AbilityEffects();

		private readonly Func<BuffOptions> options;

		private readonly ManualLogSource logger;

		private readonly MethodInfo fixedAgeGetter;

		internal AbilityBuffs(Func<BuffOptions> options, ManualLogSource logger)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			//IL_0101: Expected O, but got Unknown
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Expected O, but got Unknown
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Expected O, but got Unknown
			this.options = options;
			this.logger = logger;
			try
			{
				MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ChargeMegaBlaster), "OnEnter", (Type[])null, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(VoidBlinkBase), "OnExit", (Type[])null, (Type[])null);
				MethodInfo methodInfo3 = AccessTools.DeclaredMethod(typeof(CorruptMode), "OnEnter", (Type[])null, (Type[])null);
				fixedAgeGetter = AccessTools.PropertyGetter(typeof(EntityState), "fixedAge");
				if (methodInfo == null || methodInfo2 == null || methodInfo3 == null || fixedAgeGetter == null)
				{
					throw new MissingMethodException("Void Fiend ability states changed.");
				}
				active = this;
				patches.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(AbilityBuffs), "BeginCharge", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(AbilityBuffs), "RestoreCharge", (Type[])null), (HarmonyMethod)null);
				patches.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(AbilityBuffs), "EndTrespass", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				patches.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(AbilityBuffs), "EnterCorruption", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Run.onRunDestroyGlobal += OnRunEnd;
			}
			catch
			{
				Dispose();
				throw;
			}
		}

		internal float? ConsumeFollowupChance(CharacterBody body)
		{
			BuffOptions buffOptions = options();
			return effects.ConsumeFollowupChance(body, Time.fixedTime, buffOptions);
		}

		private static void BeginCharge(ChargeMegaBlaster __instance, out float __state)
		{
			__state = __instance.baseDuration;
			if (active != null)
			{
				__state = AbilityEffects.BeforeCharge(__instance, active.options().ChargeSpeedBonusPercent);
			}
		}

		private static Exception RestoreCharge(ChargeMegaBlaster __instance, float __state, Exception __exception)
		{
			__instance.baseDuration = __state;
			return __exception;
		}

		private static void EndTrespass(VoidBlinkBase __instance)
		{
			AbilityBuffs abilityBuffs = active;
			if (abilityBuffs != null)
			{
				BuffOptions buffOptions = abilityBuffs.options();
				if (abilityBuffs.effects.AfterTrespass(__instance, buffOptions, (float)abilityBuffs.fixedAgeGetter.Invoke(__instance, null)) && buffOptions.LogEvents)
				{
					abilityBuffs.logger.LogInfo((object)("Trespass primed one " + buffOptions.FollowupChancePercent + "% Collapse roll for " + buffOptions.HitWindowSeconds + " seconds."));
				}
			}
		}

		private static void EnterCorruption(CorruptMode __instance)
		{
			AbilityBuffs abilityBuffs = active;
			if (abilityBuffs != null)
			{
				BuffOptions buffOptions = abilityBuffs.options();
				int num = abilityBuffs.effects.OnCorruption(__instance, buffOptions);
				if (num > 0 && buffOptions.LogEvents)
				{
					abilityBuffs.logger.LogInfo((object)("Transformation pulse applied Collapse to " + num + " enemies."));
				}
			}
		}

		private void OnRunEnd(Run run)
		{
			effects.Clear();
		}

		public void Dispose()
		{
			Run.onRunDestroyGlobal -= OnRunEnd;
			patches.UnpatchSelf();
			effects.Clear();
			if (active == this)
			{
				active = null;
			}
		}
	}
	internal sealed class BuffOptions
	{
		internal float ChargeSpeedBonusPercent = 10f;

		internal bool TrespassEnabled = true;

		internal float FollowupChancePercent = 50f;

		internal float HitWindowSeconds = 5f;

		internal bool PulseEnabled = true;

		internal float PulseRadius = 10f;

		internal bool LogEvents;
	}
	internal sealed class AbilityEffects
	{
		private sealed class Window
		{
			internal float Expires;
		}

		private sealed class Handled
		{
		}

		private ConditionalWeakTable<CharacterBody, Window> windows = new ConditionalWeakTable<CharacterBody, Window>();

		private ConditionalWeakTable<object, Handled> blinkExits = new ConditionalWeakTable<object, Handled>();

		private ConditionalWeakTable<object, Handled> corruptEntries = new ConditionalWeakTable<object, Handled>();

		internal static float BeforeCharge(ChargeMegaBlaster state, float bonusPercent)
		{
			float baseDuration = state.baseDuration;
			CharacterBody val = (Object.op_Implicit((Object)(object)((EntityState)state).outer) ? ((Component)((EntityState)state).outer).GetComponent<CharacterBody>() : null);
			VoidSurvivorController val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<VoidSurvivorController>() : null);
			if (Object.op_Implicit((Object)(object)val2) && !val2.isCorrupted && ValidPositive(baseDuration) && ValidPositive(bonusPercent))
			{
				state.baseDuration = baseDuration / (1f + Math.Min(100f, bonusPercent) / 100f);
			}
			return baseDuration;
		}

		internal bool AfterTrespass(VoidBlinkBase state, BuffOptions options, float fixedAge)
		{
			CharacterBody val = (Object.op_Implicit((Object)(object)((EntityState)state).outer) ? ((Component)((EntityState)state).outer).GetComponent<CharacterBody>() : null);
			if (!NetworkServer.active || !options.TrespassEnabled || !ValidPositive(options.HitWindowSeconds) || !ValidPositive(options.FollowupChancePercent) || !Object.op_Implicit((Object)(object)((EntityState)state).outer) || ((EntityState)state).outer.destroying || !(fixedAge >= state.duration) || !LivingFiend(val) || blinkExits.TryGetValue(state, out var _))
			{
				return false;
			}
			blinkExits.Add(state, new Handled());
			windows.Remove(val);
			windows.Add(val, new Window
			{
				Expires = Time.fixedTime + Math.Min(30f, options.HitWindowSeconds)
			});
			return true;
		}

		internal bool TryConsume(CharacterBody body, float now, bool enabled)
		{
			if (!Object.op_Implicit((Object)(object)body) || !windows.TryGetValue(body, out var value))
			{
				return false;
			}
			windows.Remove(body);
			if (enabled && LivingFiend(body) && !float.IsNaN(now) && !float.IsInfinity(now))
			{
				return now < value.Expires;
			}
			return false;
		}

		internal float? ConsumeFollowupChance(CharacterBody body, float now, BuffOptions options)
		{
			bool enabled = options.TrespassEnabled && ValidPositive(options.HitWindowSeconds) && ValidPositive(options.FollowupChancePercent);
			if (!TryConsume(body, now, enabled))
			{
				return null;
			}
			return Math.Min(100f, options.FollowupChancePercent);
		}

		internal int OnCorruption(CorruptMode state, BuffOptions options)
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Invalid comparison between Unknown and I4
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			CharacterBody val = (Object.op_Implicit((Object)(object)((EntityState)state).outer) ? ((Component)((EntityState)state).outer).GetComponent<CharacterBody>() : null);
			if (!NetworkServer.active || !options.PulseEnabled || !ValidPositive(options.PulseRadius) || !LivingFiend(val) || !((Component)val).GetComponent<VoidSurvivorController>().isCorrupted || !Object.op_Implicit((Object)(object)((EntityState)state).outer) || ((EntityState)state).outer.destroying || corruptEntries.TryGetValue(state, out var _))
			{
				return 0;
			}
			corruptEntries.Add(state, new Handled());
			if (!Object.op_Implicit((Object)(object)val.teamComponent))
			{
				return 0;
			}
			float num = Math.Min(30f, options.PulseRadius);
			float num2 = num * num;
			TeamMask enemyTeams = TeamMask.GetEnemyTeams(val.teamComponent.teamIndex);
			int num3 = 0;
			foreach (CharacterBody item in new List<CharacterBody>(CharacterBody.readOnlyInstancesList))
			{
				if (Object.op_Implicit((Object)(object)item) && !((Object)(object)item == (Object)(object)val) && Object.op_Implicit((Object)(object)item.healthComponent) && item.healthComponent.alive && Object.op_Implicit((Object)(object)item.teamComponent) && item.teamComponent.teamIndex != val.teamComponent.teamIndex && (int)item.teamComponent.teamIndex != 0 && (int)item.teamComponent.teamIndex != -1 && ((TeamMask)(ref enemyTeams)).HasTeam(item.teamComponent.teamIndex))
				{
					Vector3 val2 = item.corePosition - val.corePosition;
					if (((Vector3)(ref val2)).sqrMagnitude <= num2 && TouchEffect.Inflict(val, item.healthComponent, null, default(ProcChainMask)))
					{
						num3++;
					}
				}
			}
			return num3;
		}

		internal void Clear()
		{
			windows = new ConditionalWeakTable<CharacterBody, Window>();
			blinkExits = new ConditionalWeakTable<object, Handled>();
			corruptEntries = new ConditionalWeakTable<object, Handled>();
		}

		private static bool LivingFiend(CharacterBody body)
		{
			if (Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.healthComponent) && body.healthComponent.alive)
			{
				return Object.op_Implicit((Object)(object)((Component)body).GetComponent<VoidSurvivorController>());
			}
			return false;
		}

		private static bool ValidPositive(float value)
		{
			if (value > 0f)
			{
				return !float.IsInfinity(value);
			}
			return false;
		}
	}
	[BepInPlugin("local.voidfiend.unstabletouch", "Void Fiend Passive and Buffs", "0.2.3")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "local.voidfiend.unstabletouch";

		private static Plugin instance;

		private ConfigEntry<float> normalChance;

		private ConfigEntry<float> corruptedChance;

		private ConfigEntry<float> chargeSpeedBonus;

		private ConfigEntry<float> hitWindow;

		private ConfigEntry<float> pulseRadius;

		private ConfigEntry<float> followupChance;

		private ConfigEntry<bool> logProcs;

		private ConfigEntry<bool> trespassEnabled;

		private ConfigEntry<bool> pulseEnabled;

		private Harmony presentation;

		private AbilityBuffs abilities;

		private Func<CharacterBody, float?> consumeFollowupChance;

		private void Awake()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Expected O, but got Unknown
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Expected O, but got Unknown
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Expected O, but got Unknown
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: Expected O, but got Unknown
			instance = this;
			normalChance = ((BaseUnityPlugin)this).Config.Bind<float>("Passive", "NormalChancePercent", 3f, new ConfigDescription("Collapse chance in normal form, multiplied by the attack proc coefficient. Zero disables this form.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			corruptedChance = ((BaseUnityPlugin)this).Config.Bind<float>("Passive", "CorruptedChancePercent", 7f, new ConfigDescription("Collapse chance in corrupted form, multiplied by the attack proc coefficient. Zero disables this form.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			chargeSpeedBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Flood", "ChargeSpeedBonusPercent", 10f, new ConfigDescription("Normal Flood charges this percent faster, on top of attack speed. 10 means charge time divided by 1.1. Zero disables the buff.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			trespassEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Trespass", "GuaranteedCollapseEnabled", true, "Legacy setting name: enables the Trespass follow-up Collapse roll, which is no longer guaranteed. The first eligible hit consumes the roll even if it fails. Does not stack.");
			followupChance = ((BaseUnityPlugin)this).Config.Bind<float>("Trespass", "FollowupChancePercent", 50f, new ConfigDescription("Base Collapse chance on the first eligible hit after Trespass. Replaces the passive roll on that hit, and is consumed on success or failure. Uses normal attacker luck; not multiplied by proc coefficient. Zero disables the follow-up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			hitWindow = ((BaseUnityPlugin)this).Config.Bind<float>("Trespass", "HitWindowSeconds", 5f, new ConfigDescription("Seconds after completing Trespass to use the follow-up Collapse roll. Zero disables it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>()));
			pulseEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Transformation", "PulseEnabled", true, "Entering corrupted mode applies one Collapse stack to each nearby enemy.");
			pulseRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Transformation", "PulseRadiusMetres", 10f, new ConfigDescription("Transformation pulse radius in metres, measured between body centres. Zero disables the pulse.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>()));
			logProcs = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogProcs", false, "Log successful Collapse applications, Trespass primes, and transformation pulses for testing.");
			try
			{
				abilities = new AbilityBuffs(CurrentOptions, ((BaseUnityPlugin)this).Logger);
				consumeFollowupChance = abilities.ConsumeFollowupChance;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Ability buffs unavailable; Unstable Touch remains active: " + ex));
			}
			GlobalEventManager.onServerDamageDealt += OnDamage;
			try
			{
				presentation = new Harmony("local.voidfiend.unstabletouch.tooltip");
				MethodInfo methodInfo = AccessTools.Method(typeof(Language), "GetLocalizedStringByToken", new Type[1] { typeof(string) }, (Type[])null);
				if (methodInfo == null)
				{
					throw new MissingMethodException("Language.GetLocalizedStringByToken");
				}
				presentation.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "Describe", (Type[])null)
				{
					priority = 0
				}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			catch (Exception ex2)
			{
				Harmony obj = presentation;
				if (obj != null)
				{
					obj.UnpatchSelf();
				}
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Skill tooltips unavailable; gameplay remains active: " + ex2));
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Void Fiend Passive and Buffs 0.2.3 loaded: " + normalChance.Value + "% normal / " + corruptedChance.Value + "% corrupted Collapse; Trespass follow-up " + followupChance.Value + "%; ability buffs " + ((abilities != null) ? "active" : "unavailable") + "."));
		}

		private BuffOptions CurrentOptions()
		{
			return new BuffOptions
			{
				ChargeSpeedBonusPercent = chargeSpeedBonus.Value,
				TrespassEnabled = trespassEnabled.Value,
				FollowupChancePercent = followupChance.Value,
				HitWindowSeconds = hitWindow.Value,
				PulseEnabled = pulseEnabled.Value,
				PulseRadius = pulseRadius.Value,
				LogEvents = logProcs.Value
			};
		}

		private void OnDamage(DamageReport report)
		{
			if (TouchEffect.Apply(report, normalChance.Value, corruptedChance.Value, consumeFollowupChance) && logProcs.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Void Fiend Passive and Buffs applied Collapse to " + ((Object)report.victimBody).name));
			}
		}

		private static void Describe(string __0, ref string __result)
		{
			if (Object.op_Implicit((Object)(object)instance) && TooltipText.IsSupported(__0))
			{
				__result = TooltipText.Describe(__0, __result, instance.normalChance.Value, instance.corruptedChance.Value, (instance.abilities != null) ? instance.CurrentOptions() : null);
			}
		}

		private void OnDestroy()
		{
			GlobalEventManager.onServerDamageDealt -= OnDamage;
			consumeFollowupChance = null;
			abilities?.Dispose();
			Harmony obj = presentation;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			if ((Object)(object)instance == (Object)(object)this)
			{
				instance = null;
			}
		}
	}
	internal static class TooltipText
	{
		private static string Number(float value)
		{
			return value.ToString("0.##", CultureInfo.InvariantCulture);
		}

		internal static bool IsSupported(string token)
		{
			switch (token)
			{
			default:
				return token == "VOIDSURVIVOR_UTILITY_UPRADE_TOOLTIP";
			case "VOIDSURVIVOR_PASSIVE_DESCRIPTION":
			case "VOIDSURVIVOR_SECONDARY_DESCRIPTION":
			case "VOIDSURVIVOR_UTILITY_DESCRIPTION":
				return true;
			}
		}

		internal static string Describe(string token, string original, float normal, float corrupted, BuffOptions buffs)
		{
			string text = original;
			if (token == "VOIDSURVIVOR_PASSIVE_DESCRIPTION")
			{
				text = Append(text, normal, corrupted);
				if (buffs != null && buffs.PulseEnabled && buffs.PulseRadius > 0f)
				{
					text = Add(text, "Transformation Pulse", "Entering corrupted mode inflicts <style=cIsVoid>1 Collapse stack</style> on each enemy within <style=cIsUtility>" + Number(buffs.PulseRadius) + "m</style>. Occurs once per transformation.");
				}
			}
			if (buffs == null)
			{
				return text;
			}
			if (token == "VOIDSURVIVOR_SECONDARY_DESCRIPTION" && buffs.ChargeSpeedBonusPercent > 0f)
			{
				text = Add(text, "Faster Flood", "Normal-form Flood charges <style=cIsUtility>" + Number(buffs.ChargeSpeedBonusPercent) + "% faster</style>, in addition to attack speed.");
			}
			if ((token == "VOIDSURVIVOR_UTILITY_DESCRIPTION" || token == "VOIDSURVIVOR_UTILITY_UPRADE_TOOLTIP") && buffs.TrespassEnabled && buffs.HitWindowSeconds > 0f && buffs.FollowupChancePercent > 0f)
			{
				text = Add(text, "Void Follow-through", "After completing Trespass in either form, your next successful hit within <style=cIsUtility>" + Number(buffs.HitWindowSeconds) + "s</style> has a <style=cIsDamage>" + Number(buffs.FollowupChancePercent) + "% chance</style> to inflict <style=cIsVoid>1 Collapse stack</style>. Consumed on success or failure. Requires a positive proc coefficient; chance uses normal luck and is not scaled by that coefficient. Damage-over-time cannot consume it. Refreshes instead of stacking; replaces the passive roll on that hit.");
			}
			return text;
		}

		private static string Add(string original, string title, string description)
		{
			string text = "<style=cIsVoid>" + title + "</style>";
			if (original != null && original.Contains(text))
			{
				return original;
			}
			return original + "\n\n" + text + ": " + description;
		}

		internal static string Append(string original, float normal, float corrupted)
		{
			if (normal <= 0f && corrupted <= 0f)
			{
				return original;
			}
			return Add(original, "Unstable Touch", "Hits have a <style=cIsDamage>" + Number(normal) + "%</style> chance to inflict <style=cIsVoid>Collapse</style> in normal form, or <style=cIsDamage>" + Number(corrupted) + "%</style> while corrupted. Chance scales with the attack's proc coefficient. Collapse cannot trigger itself.");
		}
	}
	internal static class TouchEffect
	{
		internal static bool Apply(DamageReport report, float normalChance, float corruptedChance, Func<CharacterBody, float?> consumeFollowupChance = null)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Invalid comparison between Unknown and I4
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkServer.active || report?.damageInfo == null)
			{
				return false;
			}
			DamageInfo damageInfo = report.damageInfo;
			if (damageInfo.rejected || damageInfo.delayedDamageSecondHalf || !(report.damageDealt > 0f) || (int)damageInfo.dotIndex != -1 || ((ProcChainMask)(ref damageInfo.procChainMask)).HasProc((ProcType)19) || !Object.op_Implicit((Object)(object)report.attackerBody) || !Object.op_Implicit((Object)(object)report.victim) || !report.victim.alive || !Object.op_Implicit((Object)(object)report.victimBody) || (Object)(object)report.attackerBody == (Object)(object)report.victimBody || report.attackerTeamIndex == report.victimTeamIndex)
			{
				return false;
			}
			CharacterBody attackerBody = report.attackerBody;
			VoidSurvivorController component = ((Component)attackerBody).GetComponent<VoidSurvivorController>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return false;
			}
			if (Chance(100f, damageInfo.procCoefficient) <= 0f)
			{
				return false;
			}
			if (DotController.GetDotDef((DotIndex)8) == null)
			{
				return false;
			}
			float? num = consumeFollowupChance?.Invoke(attackerBody);
			float num2 = (num.HasValue ? Chance(num.Value, 1f) : Chance(component.isCorrupted ? corruptedChance : normalChance, damageInfo.procCoefficient));
			if (num2 <= 0f || !Util.CheckRoll(num2, attackerBody.master))
			{
				return false;
			}
			return Inflict(attackerBody, report.victim, damageInfo.inflictedHurtbox, damageInfo.procChainMask);
		}

		internal static bool Inflict(CharacterBody attacker, HealthComponent victim, HurtBox hurtbox, ProcChainMask mask)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkServer.active || !Object.op_Implicit((Object)(object)attacker) || !Object.op_Implicit((Object)(object)victim) || !victim.alive)
			{
				return false;
			}
			DotDef dotDef = DotController.GetDotDef((DotIndex)8);
			if (dotDef == null)
			{
				return false;
			}
			((ProcChainMask)(ref mask)).AddProc((ProcType)19);
			DotController.InflictDot(((Component)victim).gameObject, ((Component)attacker).gameObject, hurtbox, mask, (DotIndex)8, dotDef.interval, 1f, (uint?)null);
			return true;
		}

		internal static float Chance(float configuredPercent, float coefficient)
		{
			if (float.IsNaN(configuredPercent) || float.IsInfinity(configuredPercent) || float.IsNaN(coefficient) || float.IsInfinity(coefficient) || configuredPercent <= 0f || coefficient <= 0f)
			{
				return 0f;
			}
			return (float)Math.Min(100.0, Math.Min(100.0, configuredPercent) * (double)coefficient);
		}
	}
}