Decompiled source of BadItemRehabilitation v1.1.1

BadItemAcademy.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HG.Reflection;
using IL.RoR2;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using MonoMod.Utils;
using R2API;
using R2API.Utils;
using RoR2;
using RoR2.ContentManagement;
using RoR2.Items;
using RoR2.Orbs;
using RoR2.Projectile;
using RoR2BepInExPack.GameAssetPathsBetter;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Networking;
using UnityEngine.ResourceManagement.AsyncOperations;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: OptIn]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("BadItemAcademy")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BadItemAcademy")]
[assembly: AssemblyTitle("BadItemAcademy")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace BadItemAcademy;

[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
[R2APISubmoduleDependency(new string[] { "ContentAddition" })]
[BepInPlugin("com.BadItemCouncil.BadItemRehabilitation", "BadItemRehabilitation", "1.1.1")]
public class BadItemAcademyPlugin : BaseUnityPlugin
{
	private enum ScreamingInternally
	{
		Brfalse,
		Brtrue,
		Blt,
		Bne,
		Ble
	}

	public static PluginInfo PInfo;

	public const string guid = "com.BadItemCouncil.BadItemRehabilitation";

	public const string teamName = "BadItemCouncil";

	public const string modName = "BadItemRehabilitation";

	public const string version = "1.1.1";

	private static AssetBundle _mainAssetBundle;

	public static BuffDef AegisFortificationBuff;

	internal static float _AegisConversionInterval = 1f;

	internal static float _AegisConversionRate = 1f;

	internal static float _AegisRemovalRate = 1f;

	internal static float _AegisForceConversionThreshold = 0.05f;

	internal static int _AegisMaxFortificationStacks = 100;

	internal static float _AegisMaxStatBonusBase = 0.2f;

	internal static float _AegisMaxStatBonusStack = 0.1f;

	internal static bool _AegisRevertHealingReduction = true;

	internal static bool _AegisUseFortification = true;

	internal static float incomingHealingCache = 0f;

	internal static float modifiedHealingCache = 0f;

	internal static float barrierDecayedCache = 0f;

	internal static bool _ChangeNkuhanaHealthCalculation = true;

	internal static bool _ShouldBenthicWeighSelection = true;

	internal static bool _InvertBenthicWeightedSelection = true;

	internal static bool _BiasBenthicWeightedSelection = true;

	internal static bool _PoolHealingBeforeModifiers = true;

	internal static bool _PoolHealingAfterIncrease = false;

	internal static float _NkuhanaDamageMultiplier = 3.5f;

	internal static float _NkuhanaProcCoefficient = 1f;

	internal static float _NkuhanaMaxRange = 80f;

	internal static float _VoidBandDamageMult = 2f;

	internal static float _VoidBandProcCoeff = 2f;

	public static AssetBundle mainAssetBundle
	{
		get
		{
			if ((Object)(object)_mainAssetBundle == (Object)null)
			{
				_mainAssetBundle = Assets.LoadAssetBundle("baditemrehab");
			}
			return _mainAssetBundle;
		}
		set
		{
			_mainAssetBundle = value;
		}
	}

	private void Awake()
	{
		PInfo = ((BaseUnityPlugin)this).Info;
		Bindings.Init();
		RehabNkuhanas();
		RehabSingularityBand();
		RehabBenthic();
		RehabAegis();
		Bindings.Save();
	}

	public static AssetReferenceT<T> LoadAsync<T>(string guid, Action<T> callback) where T : Object
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		AssetReferenceT<T> val = new AssetReferenceT<T>(guid);
		AsyncOperationHandle<T> handle2 = AssetAsyncReferenceManager<T>.LoadAsset(val, (AsyncReferenceHandleUnloadType)2);
		if (callback == null)
		{
			return val;
		}
		if (handle2.IsDone)
		{
			onCompleted(handle2);
			return val;
		}
		handle2.Completed += onCompleted;
		return val;
		void onCompleted(AsyncOperationHandle<T> handle)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			if (handle.Result == null || (int)handle.Status != 1)
			{
				Debug.LogError((object)$"Failed to load asset [{handle.DebugName}] : {handle.OperationException}");
			}
			else
			{
				callback(handle.Result);
			}
		}
	}

	public static void DebugBreakpoint(string methodName, int breakpointNumber = -1)
	{
		string text = "(BadItemRehabilitation) " + methodName + " IL hook failed!";
		if (breakpointNumber >= 0)
		{
			text += $" (breakpoint {breakpointNumber})";
		}
		Debug.LogError((object)text);
	}

	public static void RehabAegis()
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Expected O, but got Unknown
		//IL_0144: Unknown result type (might be due to invalid IL or missing references)
		//IL_014e: Expected O, but got Unknown
		//IL_0156: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: Expected O, but got Unknown
		AegisFortificationBuff = ScriptableObject.CreateInstance<BuffDef>();
		((Object)AegisFortificationBuff).name = "bdBarrierFortification";
		AegisFortificationBuff.iconSprite = mainAssetBundle.LoadAsset<Sprite>("Assets/Textures/Icons/Buff/aegisbarrier.png");
		AegisFortificationBuff.buffColor = Color.white;
		AegisFortificationBuff.canStack = true;
		AegisFortificationBuff.isDebuff = false;
		AegisFortificationBuff.stackingDisplayMethod = (StackingDisplayMethod)1;
		ContentAddition.AddBuffDef(AegisFortificationBuff);
		RecalculateStatsAPI.GetStatCoefficients += new StatHookEventHandler(AegisStatCoefficients);
		LanguageAPI.Add("ITEM_BARRIERONOVERHEAL_PICKUP", "Healing past full grants you a temporary barrier. Decayed barrier boosts all damage stats.");
		LanguageAPI.Add("ITEM_BARRIERONOVERHEAL_DESC", "Healing past full grants you a <style=cIsHealing>temporary barrier</style> for <style=cIsHealing>50% <style=cStack>(+50% per stack)</style></style> of the amount you <style=cIsHealing>healed</style>. " + ((!Bindings.AegisUseFortification.Value) ? "" : ($"Every <style=cIsHealing>{Bindings.AegisForceConversionThreshold.Value * 100f}%</style> barrier that decays is converted into " + "<style=cIsDamage>Fortification</style>, increasing damage, attack speed, and critical strike chance " + $"by up to <style=cIsDamage>{Bindings.AegisMaxStatBonusBase.Value * 100f}%</style> " + $"<style=cStack>(+{Bindings.AegisMaxStatBonusStack.Value * 100f}% per stack)</style>. " + "<style=cIsDamage>Fortification</style> is lost when taking damage.")));
		HealthComponent.ServerFixedUpdate += new Manipulator(HealthComponent_ServerFixedUpdate_CumulateBarrierDecay);
		HealthComponent.Heal += new Manipulator(HealthComponent_Heal_OverhealToBarrier);
	}

	private static void AegisStatCoefficients(CharacterBody sender, StatHookEventArgs args)
	{
		if (Bindings.AegisUseFortification.Value)
		{
			Inventory inventory = sender.inventory;
			int num = ((inventory != null) ? inventory.GetItemCountEffective(Items.BarrierOnOverHeal) : 0);
			int buffCount = sender.GetBuffCount(AegisFortificationBuff);
			if (buffCount > 0 && num > 0)
			{
				float num2 = Bindings.AegisMaxStatBonusBase.Value + Bindings.AegisMaxStatBonusStack.Value * (float)(num - 1);
				float num3 = num2 * ((float)buffCount / (float)Bindings.AegisMaxFortificationStacks.Value);
				args.damageMultAdd += num3;
				args.attackSpeedMultAdd += num3;
				args.critAdd += num3 * 100f;
			}
		}
	}

	private static void HealthComponent_Heal_OverhealToBarrier(ILContext il)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Expected O, but got Unknown
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		ILCursor val = new ILCursor(il);
		int modifiedHealingLoc = 2;
		if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
		{
			(Instruction x) => ILPatternMatchingExt.MatchLdfld<ItemCounts>(x, "increaseHealing")
		}) || !val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
		{
			(Instruction x) => ILPatternMatchingExt.MatchStarg(x, 1)
		}))
		{
			DebugBreakpoint("HealthComponent_Heal_OverhealToBarrier", 1);
			val.Index = 0;
		}
		else
		{
			int index = val.Index;
			val.Index = index + 1;
		}
		val.Emit(OpCodes.Ldarg_1);
		val.EmitDelegate<Action<float>>((Action<float>)delegate(float incomingHealing)
		{
			incomingHealingCache = incomingHealing;
		});
		if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[2]
		{
			(Instruction x) => ILPatternMatchingExt.MatchLdarg(x, 1),
			(Instruction x) => ILPatternMatchingExt.MatchStloc(x, ref modifiedHealingLoc)
		}))
		{
			DebugBreakpoint("HealthComponent_Heal_OverhealToBarrier", 2);
			return;
		}
		val.Emit(OpCodes.Ldloc, modifiedHealingLoc);
		val.EmitDelegate<Action<float>>((Action<float>)delegate(float modifiedHealing)
		{
			modifiedHealingCache = modifiedHealing;
		});
		if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
		{
			(Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt<HealthComponent>(x, "AddBarrier")
		}) || !val.TryGotoPrev((MoveType)2, new Func<Instruction, bool>[1]
		{
			(Instruction x) => ILPatternMatchingExt.MatchLdloc(x, modifiedHealingLoc)
		}))
		{
			DebugBreakpoint("HealthComponent_Heal_OverhealToBarrier", 3);
			return;
		}
		val.EmitDelegate<Func<float, float>>((Func<float, float>)delegate(float healingRemainder)
		{
			if (healingRemainder == 0f || modifiedHealingCache == 0f || !Bindings.AegisRevertHealingReduction.Value)
			{
				return healingRemainder;
			}
			if (healingRemainder == modifiedHealingCache)
			{
				return incomingHealingCache;
			}
			float num = incomingHealingCache / modifiedHealingCache;
			return (num <= 1f) ? healingRemainder : (healingRemainder * num);
		});
	}

	private static void HealthComponent_ServerFixedUpdate_CumulateBarrierDecay(ILContext il)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Expected O, but got Unknown
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		ILCursor val = new ILCursor(il);
		if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
		{
			(Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt<HealthComponent>(x, "set_Networkbarrier")
		}))
		{
			DebugBreakpoint("HealthComponent_ServerFixedUpdate_CumulateBarrierDecay", 1);
			return;
		}
		val.Emit(OpCodes.Ldarg_0);
		val.EmitDelegate<Func<float, HealthComponent, float>>((Func<float, HealthComponent, float>)delegate(float newBarrier, HealthComponent self)
		{
			barrierDecayedCache = self.barrier - newBarrier;
			return newBarrier;
		});
		int index = val.Index;
		val.Index = index + 1;
		val.Emit(OpCodes.Ldarg_0);
		val.EmitDelegate<Action<HealthComponent>>((Action<HealthComponent>)delegate(HealthComponent self)
		{
			if (self.itemCounts.barrierOnOverHeal > 0 && NetworkServer.active && Bindings.AegisUseFortification.Value)
			{
				AegisItemBehavior component = ((Component)self.body).GetComponent<AegisItemBehavior>();
				if ((Object)(object)component != (Object)null && ((BaseItemBodyBehavior)component).stack > 0)
				{
					component.OnBarrierDecayed(barrierDecayedCache);
				}
			}
		});
	}

	public static void RehabBenthic()
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Expected O, but got Unknown
		if (Bindings.ShouldBenthicWeighSelection.Value)
		{
			CharacterMaster.TryCloverVoidUpgrades += new Manipulator(CloverWeightedSelection);
		}
	}

	public static void CloverWeightedSelection(ILContext il)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Expected O, but got Unknown
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		ILCursor val = new ILCursor(il);
		if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
		{
			(Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, "RoR2.Util", "ShuffleList")
		}))
		{
			DebugBreakpoint("CloverWeightedSelection");
			return;
		}
		val.Remove();
		val.Emit(OpCodes.Ldarg_0);
		val.EmitDelegate<Action<List<ItemIndex>, Xoroshiro128Plus, CharacterMaster>>((Action<List<ItemIndex>, Xoroshiro128Plus, CharacterMaster>)delegate(List<ItemIndex> itemList, Xoroshiro128Plus rng, CharacterMaster master)
		{
			CreateShuffledListFromWeightedSelection(ref itemList, rng, master);
		});
	}

	public static void CreateShuffledListFromWeightedSelection(ref List<ItemIndex> list, Xoroshiro128Plus rng, CharacterMaster master)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Invalid comparison between Unknown and I4
		//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)master.inventory == (Object)null || master.inventory.GetItemCountEffective(Items.CloverVoid.itemIndex) <= 0 || list == null || list.Count < 0)
		{
			return;
		}
		int totalItemCountOfTier = master.inventory.GetTotalItemCountOfTier((ItemTier)0);
		int totalItemCountOfTier2 = master.inventory.GetTotalItemCountOfTier((ItemTier)1);
		if (totalItemCountOfTier + totalItemCountOfTier2 == 0)
		{
			Debug.Log((object)"Could not create a Benthic weighted selection: No Tier 1/2 Items");
			return;
		}
		WeightedSelection<ItemIndex> val = new WeightedSelection<ItemIndex>(list.Count);
		foreach (ItemIndex item in list)
		{
			ItemDef itemDef = ItemCatalog.GetItemDef(item);
			if ((Object)(object)itemDef == (Object)null || !itemDef.canRemove)
			{
				continue;
			}
			int num = 1;
			ItemTier tier = itemDef.tier;
			ItemTier val2 = tier;
			if ((int)val2 != 0)
			{
				if ((int)val2 != 1)
				{
					continue;
				}
				num = totalItemCountOfTier / (totalItemCountOfTier + totalItemCountOfTier2);
			}
			else
			{
				num = totalItemCountOfTier2 / (totalItemCountOfTier + totalItemCountOfTier2);
			}
			int itemCountEffective = master.inventory.GetItemCountEffective(item);
			float num2 = 1 / itemCountEffective;
			float num3 = (Bindings.InvertBenthicWeightedSelection.Value ? num2 : ((float)itemCountEffective));
			if (Bindings.BiasBenthicWeightedSelection.Value)
			{
				num3 *= (float)num;
			}
			val.AddChoice(item, num3);
		}
		list = new List<ItemIndex>(val.Count);
		for (int i = 0; i < list.Count; i++)
		{
			if (val.Count <= 0)
			{
				break;
			}
			if (val.totalWeight == 0f)
			{
				break;
			}
			int num4 = val.EvaluateToChoiceIndex(rng.nextNormalizedFloat);
			if (num4 < val.Count)
			{
				list[i] = val.choices[num4].value;
				val.ModifyChoiceWeight(num4, 0f);
			}
		}
	}

	public static void RehabNkuhanas()
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Expected O, but got Unknown
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Expected O, but got Unknown
		if (Bindings.PoolHealingBeforeModifiers.Value)
		{
			HealthComponent.Heal += new Manipulator(HealthComponent_Heal_Pooling);
		}
		HealthComponent.ServerFixedUpdate += new Manipulator(NkuhanasBuff);
		LanguageAPI.Add("ITEM_NOVAONHEAL_DESC", "Store <style=cIsHealing>100%</style> <style=cStack>(+100% per stack)</style> of healing as <style=cIsHealing>Soul Energy</style>. After your <style=cIsHealing>Soul Energy</style> reaches <style=cIsHealing>10%</style> of your " + (Bindings.ChangeNkuhanaHealthCalculation.Value ? "<style=cIsHealing>base health</style>, " : "<style=cIsHealing>maximum health</style>, ") + $"<style=cIsDamage>fire a skull</style> that deals <style=cIsDamage>{Bindings.NkuhanaDamageMultiplier.Value * 100f}%</style> " + "of your <style=cIsHealing>Soul Energy</style> as <style=cIsDamage>damage</style>.");
	}

	public static void NkuhanasBuff(ILContext il)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Expected O, but got Unknown
		ILCursor val = new ILCursor(il);
		bool flag = val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
		{
			(Instruction x) => ILPatternMatchingExt.MatchLdfld<HealthComponent>(x, "devilOrbHealPool")
		});
		int index = val.Index;
		BuffNkuhanaDamage(val);
		if (Bindings.ChangeNkuhanaHealthCalculation.Value)
		{
			val.Index = index;
			FixNkuahanHealth(val);
		}
		val.Index = index;
		BuffNkuhanaRange(val);
		val.Index = index;
		BuffNkuhanaProcCoefficient(val);
	}

	public static void BuffNkuhanaProcCoefficient(ILCursor c)
	{
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		int index = 9;
		if (!c.TryGotoNext((MoveType)2, new Func<Instruction, bool>[2]
		{
			(Instruction x) => ILPatternMatchingExt.MatchNewobj<DevilOrb>(x),
			(Instruction x) => ILPatternMatchingExt.MatchStloc(x, ref index)
		}))
		{
			DebugBreakpoint("BuffNkuhanaProcCoefficient");
			return;
		}
		c.Emit(OpCodes.Ldloc, index);
		c.EmitDelegate<Action<DevilOrb>>((Action<DevilOrb>)delegate(DevilOrb devilOrb)
		{
			devilOrb.procCoefficient = Bindings.NkuhanaProcCoefficient.Value;
		});
	}

	public static void BuffNkuhanaRange(ILCursor c)
	{
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		float num = default(float);
		if (!c.TryGotoNext((MoveType)0, new Func<Instruction, bool>[2]
		{
			(Instruction x) => ILPatternMatchingExt.MatchLdcR4(x, ref num),
			(Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt<DevilOrb>(x, "PickNextTarget")
		}))
		{
			DebugBreakpoint("BuffNkuhanaRange");
			return;
		}
		c.Remove();
		c.Emit(OpCodes.Ldc_R4, Bindings.NkuhanaMaxRange.Value);
	}

	public static void FixNkuahanHealth(ILCursor c)
	{
		if (!c.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
		{
			(Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt<HealthComponent>(x, "get_fullCombinedHealth")
		}))
		{
			DebugBreakpoint("FixNkuahanHealth");
			return;
		}
		c.Remove();
		c.EmitDelegate<Func<HealthComponent, float>>((Func<HealthComponent, float>)delegate(HealthComponent hc)
		{
			CharacterBody body = hc.body;
			if (!Object.op_Implicit((Object)(object)body))
			{
				return hc.fullCombinedHealth;
			}
			float num = body.level - 1f;
			return body.baseMaxHealth + body.baseMaxShield + (body.levelMaxHealth + body.levelMaxShield) * num;
		});
	}

	public static void BuffNkuhanaDamage(ILCursor c)
	{
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		if (!c.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
		{
			(Instruction x) => ILPatternMatchingExt.MatchStfld<DevilOrb>(x, "damageValue")
		}))
		{
			DebugBreakpoint("BuffNkuhanaDamage");
			return;
		}
		c.Index -= 2;
		c.Remove();
		c.Emit(OpCodes.Ldc_R4, Bindings.NkuhanaDamageMultiplier.Value);
	}

	public static void HealthComponent_Heal_Pooling(ILContext il)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Expected O, but got Unknown
		ILCursor val = new ILCursor(il);
		ILLabel val2 = val.DefineLabel();
		ILLabel target = val.DefineLabel();
		int num3 = default(int);
		if (!val.TryGotoNext((MoveType)0, new Func<Instruction, bool>[3]
		{
			(Instruction x) => ILPatternMatchingExt.MatchLdarg(x, ref num3),
			(Instruction X) => ILPatternMatchingExt.MatchLdflda<HealthComponent>(X, "itemCounts"),
			(Instruction x) => ILPatternMatchingExt.MatchLdfld<ItemCounts>(x, "increaseHealing")
		}))
		{
			DebugBreakpoint("HealthComponent_Heal_Pooling");
			return;
		}
		if (!Bindings.PoolHealingAfterIncrease.Value || !val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
		{
			(Instruction x) => ILPatternMatchingExt.MatchBle(x, ref target)
		}))
		{
			if (Bindings.PoolHealingAfterIncrease.Value)
			{
				Debug.Log((object)"(BadItemRehabilitation) Error: PoolHealingAfterIncrease is true, but failed to find label. Falling back to [PoolHealingAfterIncrease=false] label.");
			}
			val.MarkLabel(target);
		}
		val2 = target;
		int count = 1;
		int count2 = 1;
		GetOpinionLabels(val, target, out var poolStart, out var poolEnd);
		HyperSwap(val, target, poolStart, poolEnd, out var newEnd, out var newStart, out var newTarget);
		target = newTarget;
		RedirectAllBranchesToLabel(val, poolEnd, newEnd, count, ScreamingInternally.Brtrue);
		RedirectAllBranchesToLabel(val, poolEnd, newEnd, count2, ScreamingInternally.Ble);
		int count3 = 1;
		int count4 = 2;
		int num = 1;
		int num2 = 1;
		GetCorpsebloomLabels(val, target, out poolStart, out poolEnd);
		HyperSwap(val, target, poolStart, poolEnd, out newEnd, out newStart, out newTarget);
		RedirectAllBranchesToLabel(val, poolEnd, newEnd, count3, ScreamingInternally.Brtrue);
		RedirectAllBranchesToLabel(val, poolEnd, newEnd, count4);
		RedirectAllBranchesToLabel(val, poolStart, newStart, 1, ScreamingInternally.Blt);
		RedirectAllBranchesToLabel(val, poolStart, newStart, 1, ScreamingInternally.Bne);
		Debug.Log((object)"bia redirecting branches before target to acknowledge inserted code. true search");
		RedirectAllBranchesToLabel(val, val2, newTarget, 1);
		Extensions.RecalculateILOffsets(val.Method);
	}

	public static void HyperSwap(ILCursor c, ILLabel target, ILLabel poolStart, ILLabel poolEnd, out ILLabel newEnd, out ILLabel newStart, out ILLabel newTarget)
	{
		SwapLabel(c, poolEnd, target, out newEnd);
		SwapLabel(c, poolStart, poolEnd, out newStart);
		SwapLabel(c, target, poolStart, out newTarget);
	}

	public static void GetOpinionLabels(ILCursor c, ILLabel target, out ILLabel poolStart, out ILLabel poolEnd)
	{
		poolStart = c.DefineLabel();
		poolEnd = c.DefineLabel();
		Debug.Log((object)"bia opinion");
		c.Index = 0;
		int num = default(int);
		if (!c.TryGotoNext((MoveType)0, new Func<Instruction, bool>[3]
		{
			(Instruction x) => ILPatternMatchingExt.MatchLdarg(x, ref num),
			(Instruction X) => ILPatternMatchingExt.MatchLdflda<HealthComponent>(X, "itemCounts"),
			(Instruction x) => ILPatternMatchingExt.MatchLdfld<ItemCounts>(x, "novaOnHeal")
		}))
		{
			DebugBreakpoint("GetOpinionLabels", 1);
			return;
		}
		c.MarkLabel(poolStart);
		if (!c.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
		{
			(Instruction x) => ILPatternMatchingExt.MatchStfld<HealthComponent>(x, "devilOrbHealPool")
		}))
		{
			DebugBreakpoint("GetOpinionLabels", 2);
		}
		else
		{
			c.MarkLabel(poolEnd);
		}
	}

	public static void GetCorpsebloomLabels(ILCursor c, ILLabel target, out ILLabel poolStart, out ILLabel poolEnd)
	{
		poolStart = c.DefineLabel();
		poolEnd = c.DefineLabel();
		Debug.Log((object)"bia corpsebloom");
		c.Index = 0;
		if (!c.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
		{
			(Instruction x) => ILPatternMatchingExt.MatchLdfld<HealthComponent>(x, "repeatHealComponent")
		}))
		{
			DebugBreakpoint("GetCorpsebloomLabels", 1);
			return;
		}
		ILLabel end = c.DefineLabel();
		int num = default(int);
		if (!c.TryGotoPrev((MoveType)0, new Func<Instruction, bool>[2]
		{
			(Instruction x) => ILPatternMatchingExt.MatchLdarg(x, ref num),
			(Instruction x) => ILPatternMatchingExt.MatchBrfalse(x, ref end)
		}))
		{
			DebugBreakpoint("GetCorpsebloomLabels", 2);
			return;
		}
		poolEnd = end;
		c.MarkLabel(poolStart);
	}

	private static void SwapLabel(ILCursor c, ILLabel location, ILLabel destination, out ILLabel newLabel)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		c.GotoLabel(location, (MoveType)0, false);
		c.Emit(OpCodes.Br, (object)destination);
		int index = c.Index;
		c.Index = index - 1;
		newLabel = c.DefineLabel();
		c.MarkLabel(newLabel);
	}

	private static void RedirectAllBranchesToLabel(ILCursor c, ILLabel labelOld, ILLabel labelNew, int count, ScreamingInternally screamingInternally = ScreamingInternally.Brfalse)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_0195: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
		if (count <= 0)
		{
			return;
		}
		c.GotoLabel(labelOld, (MoveType)0, false);
		bool flag = true;
		ILLabel val5 = default(ILLabel);
		ILLabel val2 = default(ILLabel);
		ILLabel val4 = default(ILLabel);
		ILLabel val3 = default(ILLabel);
		ILLabel val6 = default(ILLabel);
		for (int i = 0; i < count; i++)
		{
			OpCode val = OpCodes.Nop;
			switch (screamingInternally)
			{
			default:
				flag = false;
				break;
			case ScreamingInternally.Brfalse:
				val = OpCodes.Brfalse_S;
				flag = c.TryGotoPrev((MoveType)0, new Func<Instruction, bool>[1]
				{
					(Instruction x) => ILPatternMatchingExt.MatchBrfalse(x, ref val5)
				});
				break;
			case ScreamingInternally.Brtrue:
				val = OpCodes.Brtrue_S;
				flag = c.TryGotoPrev((MoveType)0, new Func<Instruction, bool>[1]
				{
					(Instruction x) => ILPatternMatchingExt.MatchBrtrue(x, ref val2)
				});
				break;
			case ScreamingInternally.Blt:
				val = OpCodes.Blt_S;
				flag = c.TryGotoPrev((MoveType)0, new Func<Instruction, bool>[1]
				{
					(Instruction x) => ILPatternMatchingExt.MatchBlt(x, ref val4)
				});
				break;
			case ScreamingInternally.Bne:
				val = OpCodes.Bne_Un_S;
				flag = c.TryGotoPrev((MoveType)0, new Func<Instruction, bool>[1]
				{
					(Instruction x) => ILPatternMatchingExt.MatchBneUn(x, ref val3)
				});
				break;
			case ScreamingInternally.Ble:
				val = OpCodes.Ble_S;
				flag = c.TryGotoPrev((MoveType)0, new Func<Instruction, bool>[1]
				{
					(Instruction x) => ILPatternMatchingExt.MatchBle(x, ref val6)
				});
				break;
			}
			if (!flag)
			{
				Debug.Log((object)"bia redirect exiting");
				break;
			}
			c.Remove();
			c.Emit(val, (object)labelNew);
			int index = c.Index;
			c.Index = index - 1;
			OpCode opCode = c.Prev.OpCode;
			Debug.Log((object)((object)(OpCode)(ref opCode)).ToString());
		}
	}

	public static void RehabSingularityBand()
	{
		BadItemAcademyPlugin.LoadAsync<GameObject>(RoR2_DLC1_ElementalRingVoid.ElementalRingVoidBlackHole_prefab, (Action<GameObject>)delegate(GameObject prefab)
		{
			ProjectileExplosion component = prefab.GetComponent<ProjectileExplosion>();
			if (Object.op_Implicit((Object)(object)component))
			{
				component.blastProcCoefficient = Bindings.VoidBandProcCoeff.Value;
				component.blastDamageCoefficient = Bindings.VoidBandDamageMult.Value;
			}
		});
		LanguageAPI.Add("ITEM_ELEMENTALRINGVOID_DESC", "Hits that deal <style=cIsDamage>more than 400% damage</style> also fire a black hole that <style=cIsUtility>draws enemies within 15m into its center</style>. Lasts <style=cIsUtility>5</style> seconds before collapsing, " + $"dealing <style=cIsDamage>{100f * Bindings.VoidBandDamageMult.Value}%</style> " + $"<style=cStack>(+{100f * Bindings.VoidBandDamageMult.Value} per stack)</style> TOTAL damage. " + "Recharges every <style=cIsUtility>20</style> seconds. <style=cIsVoid>Corrupts all Runald's and Kjaro's Bands</style>.");
	}
}
public class AegisItemBehavior : BaseItemBodyBehavior, IOnTakeDamageServerReceiver
{
	public float decayedBarrierCumulative = 0f;

	private float aegisConversionStopwatch = 0f;

	private bool isAtFullFortification = false;

	public HealthComponent healthComponent => ((BaseItemBodyBehavior)this).body.healthComponent;

	[ItemDefAssociation(useOnServer = true, useOnClient = false)]
	private static ItemDef GetItemDef()
	{
		return Items.BarrierOnOverHeal;
	}

	private static BuffDef GetBuffDef()
	{
		return BadItemAcademyPlugin.AegisFortificationBuff;
	}

	private void Start()
	{
		if (!Bindings.AegisUseFortification.Value)
		{
			return;
		}
		CharacterBody body = ((BaseItemBodyBehavior)this).body;
		if (body != null)
		{
			HealthComponent obj = body.healthComponent;
			if (obj != null)
			{
				obj.AddOnTakeDamageServerReceiver((IOnTakeDamageServerReceiver)(object)this);
			}
		}
	}

	private void OnDestroy()
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		CharacterBody body = ((BaseItemBodyBehavior)this).body;
		if (body != null)
		{
			HealthComponent obj = body.healthComponent;
			if (obj != null)
			{
				obj.RemoveOnTakeDamageServerReceiver((IOnTakeDamageServerReceiver)(object)this);
			}
		}
		((BaseItemBodyBehavior)this).body.SetBuffCount(GetBuffDef().buffIndex, 0);
	}

	public void CumulateBarrierDecay(HealthComponent healthComponent, float barrierDecayed)
	{
		if ((Object)(object)healthComponent == (Object)(object)this.healthComponent)
		{
			OnBarrierDecayed(barrierDecayed);
		}
	}

	public void OnBarrierDecayed(float barrierDecayed)
	{
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Unknown result type (might be due to invalid IL or missing references)
		if (isAtFullFortification)
		{
			return;
		}
		decayedBarrierCumulative += barrierDecayed * Bindings.AegisConversionRate.Value;
		aegisConversionStopwatch += Time.fixedDeltaTime;
		if (healthComponent.barrier <= float.Epsilon || decayedBarrierCumulative >= healthComponent.fullCombinedHealth * Bindings.AegisForceConversionThreshold.Value || aegisConversionStopwatch >= Bindings.AegisConversionInterval.Value)
		{
			aegisConversionStopwatch = 0f;
			int num = 0;
			if (healthComponent.barrier <= float.Epsilon)
			{
				num = Mathf.CeilToInt(100f * decayedBarrierCumulative / healthComponent.fullCombinedHealth);
				decayedBarrierCumulative = 0f;
			}
			else
			{
				float num2 = healthComponent.fullCombinedHealth / 100f;
				num = Mathf.FloorToInt(decayedBarrierCumulative / num2);
				decayedBarrierCumulative -= num2 * (float)num;
			}
			int buffCount = ((BaseItemBodyBehavior)this).body.GetBuffCount(GetBuffDef().buffIndex);
			int num3 = buffCount + num;
			if (num3 >= Bindings.AegisMaxFortificationStacks.Value)
			{
				num3 = Bindings.AegisMaxFortificationStacks.Value;
				isAtFullFortification = true;
			}
			((BaseItemBodyBehavior)this).body.SetBuffCount(GetBuffDef().buffIndex, num3);
		}
	}

	public void OnTakeDamageServer(DamageReport damageReport)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Invalid comparison between Unknown and I4
		//IL_0068: 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)
		if ((int)damageReport.damageInfo.damageType.damageType == 2048)
		{
			return;
		}
		CharacterBody victimBody = damageReport.victimBody;
		HealthComponent val = ((victimBody != null) ? victimBody.healthComponent : null);
		CharacterBody victimBody2 = damageReport.victimBody;
		if (!((Object)(object)((victimBody2 != null) ? victimBody2.healthComponent : null) == (Object)null))
		{
			CharacterBody body = ((BaseItemBodyBehavior)this).body;
			int num = ((body != null) ? body.GetBuffCount(GetBuffDef().buffIndex) : 0);
			if (num != 0)
			{
				float num2 = damageReport.combinedHealthBeforeDamage - val.combinedHealth;
				int num3 = Mathf.FloorToInt(100f * num2 * Bindings.AegisRemovalRate.Value / val.fullCombinedHealth);
				damageReport.victimBody.SetBuffCount(GetBuffDef().buffIndex, Mathf.Max(num - num3, 0));
				isAtFullFortification = false;
			}
		}
	}
}
public static class Assets
{
	internal static Dictionary<string, AssetBundle> loadedBundles = new Dictionary<string, AssetBundle>();

	internal static AssetBundle LoadAssetBundle(string bundleName)
	{
		if (loadedBundles.ContainsKey(bundleName))
		{
			return loadedBundles[bundleName];
		}
		AssetBundle val = null;
		val = AssetBundle.LoadFromFile(Path.Combine(Path.GetDirectoryName(BadItemAcademyPlugin.PInfo.Location), bundleName));
		loadedBundles[bundleName] = val;
		return val;
	}
}
public static class Bindings
{
	internal static ConfigFile CustomConfigFile { get; set; }

	internal static ConfigEntry<bool> PoolHealingBeforeModifiers { get; set; }

	internal static ConfigEntry<bool> PoolHealingAfterIncrease { get; set; }

	internal static ConfigEntry<float> VoidBandDamageMult { get; set; }

	internal static ConfigEntry<float> VoidBandProcCoeff { get; set; }

	internal static ConfigEntry<float> NkuhanaDamageMultiplier { get; set; }

	internal static ConfigEntry<float> NkuhanaProcCoefficient { get; set; }

	internal static ConfigEntry<float> NkuhanaMaxRange { get; set; }

	internal static ConfigEntry<bool> ChangeNkuhanaHealthCalculation { get; set; }

	internal static ConfigEntry<bool> ShouldBenthicWeighSelection { get; set; }

	internal static ConfigEntry<bool> InvertBenthicWeightedSelection { get; set; }

	internal static ConfigEntry<bool> BiasBenthicWeightedSelection { get; set; }

	internal static ConfigEntry<float> AegisConversionInterval { get; set; }

	internal static ConfigEntry<float> AegisConversionRate { get; set; }

	internal static ConfigEntry<float> AegisRemovalRate { get; set; }

	internal static ConfigEntry<float> AegisForceConversionThreshold { get; set; }

	internal static ConfigEntry<int> AegisMaxFortificationStacks { get; set; }

	internal static ConfigEntry<float> AegisMaxStatBonusBase { get; set; }

	internal static ConfigEntry<float> AegisMaxStatBonusStack { get; set; }

	internal static ConfigEntry<bool> AegisRevertHealingReduction { get; set; }

	internal static ConfigEntry<bool> AegisUseFortification { get; set; }

	public static void Init()
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected O, but got Unknown
		string text = "Bad Item Rehabilitation : ";
		CustomConfigFile = new ConfigFile(Paths.ConfigPath + "\\BadItemRehabilitation.cfg", true);
		CustomConfigFile.SaveOnConfigSet = false;
		AegisConversionInterval = CustomConfigFile.Bind<float>(text + "Aegis", "Aegis Conversion to Fortification Interval", BadItemAcademyPlugin._AegisConversionInterval, "Determines the rate at which cumulated barrier decay is converted to Fortification. By default, this is made to be a fairly high value in order to reduce the performance cost of changing stats frequently. However, the Force Conversion Threshold makes sure that Fortification is not added too slowly for the changing stats.");
		AegisConversionRate = CustomConfigFile.Bind<float>(text + "Aegis", "Aegis Rate Of Conversion To Fortification", BadItemAcademyPlugin._AegisConversionRate, "Determines the multiplier of barrier converted to Fortification. For example, with a value of 0.5, 100% barrier decay only gives 50% Fortification. ");
		AegisRemovalRate = CustomConfigFile.Bind<float>(text + "Aegis", "Aegis Rate Of Conversion To Fortification", BadItemAcademyPlugin._AegisRemovalRate, "Determines the multiplier of Fortification removal when taking damage, proportional to maximum health. For example, with a value of 2, losing 50% of your max health will take away 100% Fortification. ");
		AegisForceConversionThreshold = CustomConfigFile.Bind<float>(text + "Aegis", "Aegis Force Conversion To Fortification Threshold", BadItemAcademyPlugin._AegisForceConversionThreshold, "Determines the threshold at which cumulated barrier decay is forced to be converted to Fortification, bypassing the cooldown and adding all cumulated barrier to Fortification instantly. This is shown in the item's full description as the minimum value to convert to Fortification. ");
		AegisMaxFortificationStacks = CustomConfigFile.Bind<int>(text + "Aegis", "Aegis Max Fortification Stacks", BadItemAcademyPlugin._AegisMaxFortificationStacks, "Determines the maximum stacks of Fortification required for the full bonus. ");
		AegisMaxStatBonusBase = CustomConfigFile.Bind<float>(text + "Aegis", "Aegis Fortification Max Stat Bonus BASE", BadItemAcademyPlugin._AegisMaxStatBonusBase, "Determines the amount Aegis increases ALL STATS with full Fortification with your first stack of Aegis. Scales linearly, represented as a percent. ");
		AegisMaxStatBonusStack = CustomConfigFile.Bind<float>(text + "Aegis", "Aegis Fortification Max Stat Bonus PER STACK", BadItemAcademyPlugin._AegisMaxStatBonusStack, "Determines the amount Aegis increases ALL STATS with full Fortification with additional stacks of Aegis. Scales linearly, represented as a percent. ");
		AegisRevertHealingReduction = CustomConfigFile.Bind<bool>(text + "Aegis", "Should Aegis Revert Healing Reductions When Converting To Barrier?", BadItemAcademyPlugin._AegisRevertHealingReduction, "Vanilla is FALSE. If set to TRUE, Aegis will revert any healing cuts made by modifiers like Eclipse 5 when applying overheal to barrier.");
		AegisUseFortification = CustomConfigFile.Bind<bool>(text + "Aegis", "Should Aegis Use Fortification?", BadItemAcademyPlugin._AegisUseFortification, "Vanilla is FALSE. If set to TRUE, Aegis will turn all decayed barrier into a stat buff called Fortification. Fortification boosts ALL stats, but is reduced when taking damage by an amount proportional to your max health.");
		ShouldBenthicWeighSelection = CustomConfigFile.Bind<bool>(text + "Benthic Bloom", "Should Benthic Bloom Weigh Selection?", BadItemAcademyPlugin._ShouldBenthicWeighSelection, "Vanilla is FALSE. If set to TRUE, Benthic Bloom will be biased towards selecting item stacks with higher lower values. Otherwise, it will prefer item stacks with higher values. Neither of these options resemble vanilla behavior, but you can choose to configure it anyways!");
		InvertBenthicWeightedSelection = CustomConfigFile.Bind<bool>(text + "Benthic Bloom", "Invert Benthic Bloom Weighted Selection", BadItemAcademyPlugin._InvertBenthicWeightedSelection, "If set to TRUE, Benthic Bloom will be biased towards selecting item stacks with lower values. Otherwise, it will prefer item stacks with higher values. Neither of these options resemble vanilla behavior, so do what you want!");
		BiasBenthicWeightedSelection = CustomConfigFile.Bind<bool>(text + "Benthic Bloom", "Bias Benthic Bloom Weighted Selection", BadItemAcademyPlugin._BiasBenthicWeightedSelection, "If set to TRUE, Benthic Bloom will try to maintain equal ratios of upgrades between Common and Uncommon items. Due to selection weighting, Benthic will more often pick Uncommon-to-Rare upgrades than Common-to-Uncommon due to Uncommon items being harder to stack. This config presents a choice, if you would like to make Benthic adjust its weighted selection to account for the size of your inventory or allow it to choose whatever it wants. Neither of these options resemble vanilla behavior, so do what you want!");
		PoolHealingBeforeModifiers = CustomConfigFile.Bind<bool>(text + "NKuhanas Opinion", "Pool Healing Before Modifiers (Affects Corpsebloom)", BadItemAcademyPlugin._PoolHealingBeforeModifiers, "Vanilla is FALSE. If set to TRUE, Nkuhanas Opinion and Corpsebloom will be changed to pool their healing before other healing modifiers. In Corpsebloom's case, this removes the double dipping effect with Rejuvenation Rack and Eclipse 5.");
		PoolHealingAfterIncrease = CustomConfigFile.Bind<bool>(text + "NKuhanas Opinion", "Pool Healing After Increase (Affects Corpsebloom)", BadItemAcademyPlugin._PoolHealingAfterIncrease, "(Requires Pool Healing Before Modifiers to be TRUE) If set to TRUE, Nkuhanas Opinion and Corpsebloom will be changed to pool after Rejuvenation Rack is applied, but before Eclipse 5. ");
		ChangeNkuhanaHealthCalculation = CustomConfigFile.Bind<bool>(text + "NKuhanas Opinion", "Change NKuhana Base Damage Calculation", BadItemAcademyPlugin._ChangeNkuhanaHealthCalculation, "Vanilla is FALSE. If set to TRUE, Nkuhanas Opinion will calculate the base damage of its attacks by using your survivor's base health (scaled with level) rather than max health. ");
		NkuhanaDamageMultiplier = CustomConfigFile.Bind<float>(text + "NKuhanas Opinion", "NKuhanas Damage Coefficient", BadItemAcademyPlugin._NkuhanaDamageMultiplier, "Vanilla is 2.5. Determines the damage multiplier of skulls fired by healing with NKuhanas Opinion. Represented as a percent. ");
		NkuhanaProcCoefficient = CustomConfigFile.Bind<float>(text + "NKuhanas Opinion", "NKuhanas Proc Coefficient", BadItemAcademyPlugin._NkuhanaProcCoefficient, "Vanilla is 0.2. Determines the proc effectivness of skulls fired by healing with NKuhanas Opinion. ");
		NkuhanaMaxRange = CustomConfigFile.Bind<float>(text + "NKuhanas Opinion", "NKuhanas Max Range", BadItemAcademyPlugin._NkuhanaMaxRange, "Vanilla is 40. Determines the maximum range of skulls fired by healing with NKuhanas Opinion. Represented in meters.");
		VoidBandDamageMult = CustomConfigFile.Bind<float>(text + "Singularity Band", "Void Band Damage Coefficient", BadItemAcademyPlugin._VoidBandDamageMult, "Vanilla is 1. Determines the damage multiplier of the explosion from the black hole created by Singularity Band. Scales linearly, represented as a percent. ");
		VoidBandProcCoeff = CustomConfigFile.Bind<float>(text + "Singularity Band", "Void Band Proc Coefficient", BadItemAcademyPlugin._VoidBandProcCoeff, "Vanilla is 1. Determines the proc effectiveness of the explosion from the black hole created by Singularity Band.");
	}

	public static void Save()
	{
		CustomConfigFile.SaveOnConfigSet = true;
		CustomConfigFile.Save();
	}
}