Decompiled source of DeepRunOverhaul v0.10.15

plugins/DeepRunOverhaul/DeepRunOverhaul.dll

Decompiled 12 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using IncreaseHardMod.Challenges;
using IncreaseHardMod.Cosmetics;
using IncreaseHardMod.Courier;
using IncreaseHardMod.Drones;
using IncreaseHardMod.Economy;
using IncreaseHardMod.Gear;
using IncreaseHardMod.Hud;
using IncreaseHardMod.Localization;
using IncreaseHardMod.Modifiers;
using IncreaseHardMod.Monsters;
using IncreaseHardMod.Networking;
using IncreaseHardMod.Patches;
using IncreaseHardMod.Patches.Effects;
using IncreaseHardMod.Quests;
using IncreaseHardMod.Skills;
using IncreaseHardMod.Testing;
using IncreaseHardMod.Upgrades;
using IncreaseHardMod.Valuables;
using IncreaseHardMod.Visuals;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Photon.Pun;
using Photon.Realtime;
using Photon.Voice;
using Photon.Voice.PUN;
using Photon.Voice.Unity;
using REPOLib.Modules;
using REPOLib.Objects.Sdk;
using Steamworks;
using Steamworks.Data;
using TMPro;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Events;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("BepInEx")]
[assembly: IgnoresAccessChecksTo("PhotonUnityNetworking")]
[assembly: IgnoresAccessChecksTo("REPOLib")]
[assembly: AssemblyCompany("DeepRunOverhaul")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.10.15.0")]
[assembly: AssemblyInformationalVersion("0.10.15+481f8a318e6ec0624759e8685f335c8f71a24af5")]
[assembly: AssemblyProduct("DeepRunOverhaul")]
[assembly: AssemblyTitle("DeepRunOverhaul")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.10.15.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 IncreaseHardMod
{
	internal static class CustomItemPrices
	{
		internal const float Multiplier = 0.5f;
	}
	public static class Difficulty
	{
		public static int LevelsCompleted
		{
			get
			{
				if (!((Object)(object)RunManager.instance != (Object)null))
				{
					return 0;
				}
				return RunManager.instance.levelsCompleted;
			}
		}

		public static int Steps
		{
			get
			{
				int num = LevelsCompleted - ModConfig.RampStartLevel.Value;
				if (num <= 0)
				{
					return 0;
				}
				int num2 = ModConfig.RampLevelsPerStep.Value;
				if (num2 < 1)
				{
					num2 = 1;
				}
				return (num + num2 - 1) / num2;
			}
		}

		public static float Multiplier(float perLevel, float max)
		{
			return Mathf.Clamp(1f + perLevel * (float)Steps, 1f, max);
		}

		public static float ReduceMultiplier(float perLevel, float minFactor)
		{
			return Mathf.Clamp(1f - perLevel * (float)Steps, minFactor, 1f);
		}
	}
	internal sealed class EconomicSurpriseConfig
	{
		internal ConfigEntry<int> Chance;

		internal ConfigEntry<int> StartLevel;

		internal static EconomicSurpriseConfig Bind(ConfigFile cfg)
		{
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Expected O, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Expected O, but got Unknown
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Expected O, but got Unknown
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Expected O, but got Unknown
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Expected O, but got Unknown
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Expected O, but got Unknown
			Dictionary<ConfigDefinition, string> orphans = cfg.OrphanedEntries;
			bool flag = Raw("Surprises", "EconomyEventChancePercent") != null;
			bool flag2 = Raw("Surprises", "EconomyStartLevel") != null;
			string text = Raw("Economy", "EventChancePercent");
			string text2 = Raw("Economy", "StartLevel");
			bool result;
			bool flag3 = bool.TryParse(Raw("Modules", "EconomyEvents") ?? Raw("Economy", "Enabled"), out result) && !result;
			bool saveOnConfigSet = cfg.SaveOnConfigSet;
			cfg.SaveOnConfigSet = false;
			EconomicSurpriseConfig economicSurpriseConfig;
			try
			{
				economicSurpriseConfig = new EconomicSurpriseConfig
				{
					Chance = cfg.Bind<int>("Surprises", "EconomyEventChancePercent", 50, new ConfigDescription("Chance per eligible level of an economic surprise changing loot value, quota or extraction pay. Requires Modules/Surprises. 0 disables this category.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())),
					StartLevel = cfg.Bind<int>("Surprises", "EconomyStartLevel", 2, new ConfigDescription("Levels completed before economic surprises can appear. 2 = from the third level. Requires Modules/Surprises.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 30), Array.Empty<object>()))
				};
				if (!flag)
				{
					if (flag3)
					{
						economicSurpriseConfig.Chance.Value = 0;
					}
					else if (text != null)
					{
						((ConfigEntryBase)economicSurpriseConfig.Chance).SetSerializedValue(text);
					}
				}
				if (!flag2 && text2 != null)
				{
					((ConfigEntryBase)economicSurpriseConfig.StartLevel).SetSerializedValue(text2);
				}
				ConfigDefinition[] array = (ConfigDefinition[])(object)new ConfigDefinition[4]
				{
					new ConfigDefinition("Modules", "EconomyEvents"),
					new ConfigDefinition("Economy", "Enabled"),
					new ConfigDefinition("Economy", "EventChancePercent"),
					new ConfigDefinition("Economy", "StartLevel")
				};
				foreach (ConfigDefinition val in array)
				{
					cfg.Remove(val);
					orphans?.Remove(val);
				}
			}
			finally
			{
				cfg.SaveOnConfigSet = saveOnConfigSet;
			}
			if (saveOnConfigSet)
			{
				cfg.Save();
			}
			return economicSurpriseConfig;
			string Raw(string section, string key)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Expected O, but got Unknown
				ConfigDefinition val2 = new ConfigDefinition(section, key);
				if (cfg.ContainsKey(val2))
				{
					return cfg[val2].GetSerializedValue();
				}
				if (orphans == null || !orphans.TryGetValue(val2, out var value))
				{
					return null;
				}
				return value;
			}
		}
	}
	internal static class EnemyBalance
	{
		private static float[] _remote;

		private static Dictionary<string, float> _caps;

		private static Room _room;

		private static int _host;

		private static bool _surprises;

		private const float SurpriseCeiling = 3f;

		private static bool Remote
		{
			get
			{
				if (_remote != null && PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient && _room == PhotonNetwork.CurrentRoom)
				{
					Player masterClient = PhotonNetwork.MasterClient;
					return ((masterClient != null) ? new int?(masterClient.ActorNumber) : ((int?)null)) == _host;
				}
				return false;
			}
		}

		internal static bool Surprises
		{
			get
			{
				if (!Remote)
				{
					return ModConfig.SurprisesEnabled.Value;
				}
				return _surprises;
			}
		}

		internal static float Damage => WithSurprise(Factor(2), Stat(StatAxis.EnemyDamage));

		internal static float Speed => Factor(3) * Stat(StatAxis.EnemySpeed);

		internal static float Respawn => Factor(4) * Stat(StatAxis.EnemyRespawn);

		internal static float LightMass => Factor(5);

		internal static float HeavyMass => Factor(6);

		internal static float PitDamage => Factor(7);

		internal static float Stat(StatAxis axis)
		{
			if (!Surprises)
			{
				return 1f;
			}
			return StatModifiers.Mult(axis);
		}

		internal static float Health(string name)
		{
			return WithSurprise(BaseHealth(name), Stat(StatAxis.EnemyHealth));
		}

		private static float BaseHealth(string name)
		{
			float value;
			float val = ((!Remote) ? ModConfig.HealthMaxForEnemy(name) : ((name != null && _caps.TryGetValue(name, out value)) ? value : _remote[1]));
			return Math.Max(1f, Math.Min(Factor(0), val));
		}

		internal static bool Allows(StatModifier modifier)
		{
			foreach (var (statAxis2, num2) in modifier.Effects)
			{
				if (!(num2 <= 1f))
				{
					if (statAxis2 == StatAxis.EnemyDamage && ExceedsLimit(Factor(2), num2))
					{
						return false;
					}
					if (statAxis2 == StatAxis.EnemyHealth && ExceedsLimit(HighestHealthRamp(), num2))
					{
						return false;
					}
				}
			}
			return true;
		}

		private static float HighestHealthRamp()
		{
			float num = BaseHealth(null);
			foreach (float perEnemyHealthCap in ModConfig.PerEnemyHealthCaps)
			{
				num = Math.Max(num, Math.Min(Factor(0), perEnemyHealthCap));
			}
			return num;
		}

		private static bool ExceedsLimit(float ramp, float factor)
		{
			return ramp * factor > 3f;
		}

		private static float WithSurprise(float ramp, float factor)
		{
			return Math.Min(ramp * factor, Math.Max(ramp, 3f));
		}

		private static float Factor(int index)
		{
			if (Remote)
			{
				return _remote[index];
			}
			return index switch
			{
				0 => ModConfig.ScaleEnemyHealth.Value ? (1f + ModConfig.EnemyHealthPerLevel.Value * (float)Difficulty.Steps) : 1f, 
				1 => ModConfig.EnemyHealthMax.Value, 
				2 => ModConfig.ScaleEnemyDamage.Value ? Difficulty.Multiplier(ModConfig.EnemyDamagePerLevel.Value, ModConfig.EnemyDamageMax.Value) : 1f, 
				3 => ModConfig.ScaleEnemySpeed.Value ? Difficulty.Multiplier(ModConfig.EnemySpeedPerLevel.Value, ModConfig.EnemySpeedMax.Value) : 1f, 
				4 => ModConfig.ScaleEnemyRespawn.Value ? Difficulty.ReduceMultiplier(ModConfig.EnemyRespawnFasterPerLevel.Value, ModConfig.EnemyRespawnMinFactor.Value) : 1f, 
				5 => ModConfig.LightMonsterMaxMass.Value, 
				6 => ModConfig.HeavyMonsterMinMass.Value, 
				_ => ModConfig.MonsterPitDamageFactor.Value, 
			};
		}

		internal static float[] Capture()
		{
			return Enumerable.Range(0, 8).Select(Factor).ToArray();
		}

		internal static string Signature()
		{
			return string.Join("|", from v in Capture()
				select v.ToString("R", CultureInfo.InvariantCulture)) + "|" + ModConfig.EnemyHealthMaxPerEnemy.Value + "|" + ModConfig.SurprisesEnabled.Value;
		}

		internal static bool Apply(float[] factors, string caps, bool surprises)
		{
			if (factors == null || factors.Length != 8 || caps == null || caps.Length > 16384 || factors.Any((float v) => float.IsNaN(v) || float.IsInfinity(v) || v < 0f || v > 1E+09f) || factors[0] < 1f || factors[1] < 1f || factors[2] < 1f || factors[3] < 1f || factors[4] <= 0f || factors[5] <= 0f || factors[6] <= 0f || factors[7] > 5f || PhotonNetwork.MasterClient == null)
			{
				return false;
			}
			Dictionary<string, float> dictionary = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);
			string[] array = caps.Split(',');
			foreach (string text in array)
			{
				int num2 = text.LastIndexOf(':');
				if (num2 > 0)
				{
					string text2 = text.Substring(0, num2).Trim();
					if (text2.Length > 0 && float.TryParse(text.Substring(num2 + 1), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && !float.IsNaN(result) && !float.IsInfinity(result) && result >= 1f)
					{
						dictionary[text2] = result;
					}
				}
			}
			_remote = (float[])factors.Clone();
			_caps = dictionary;
			_room = PhotonNetwork.CurrentRoom;
			_host = PhotonNetwork.MasterClient.ActorNumber;
			_surprises = surprises;
			return true;
		}
	}
	public static class ModConfig
	{
		public static ConfigEntry<bool> VoiceRecoveryEnabled;

		public static ConfigEntry<bool> NetworkDiagnosticsEnabled;

		public static ConfigEntry<KeyCode> AudioRecoveryKey;

		public static ConfigEntry<int> RampStartLevel;

		public static ConfigEntry<int> RampLevelsPerStep;

		public static ConfigEntry<bool> ScaleEnemyHealth;

		public static ConfigEntry<bool> ScaleEnemyDamage;

		public static ConfigEntry<bool> ScaleEnemySpeed;

		public static ConfigEntry<bool> ScaleEnemyRespawn;

		public static ConfigEntry<bool> ScaleQuota;

		public static ConfigEntry<float> EnemyHealthPerLevel;

		public static ConfigEntry<float> EnemyHealthMax;

		public static ConfigEntry<string> EnemyHealthMaxPerEnemy;

		public static ConfigEntry<bool> LogEnemyNames;

		public static ConfigEntry<float> EnemyDamagePerLevel;

		public static ConfigEntry<float> EnemyDamageMax;

		public static ConfigEntry<float> EnemySpeedPerLevel;

		public static ConfigEntry<float> EnemySpeedMax;

		public static ConfigEntry<float> EnemyRespawnFasterPerLevel;

		public static ConfigEntry<float> EnemyRespawnMinFactor;

		public static ConfigEntry<float> QuotaPerLevel;

		public static ConfigEntry<float> QuotaMax;

		public static ConfigEntry<float> QuotaMaxLootFraction;

		public static ConfigEntry<bool> SurprisesEnabled;

		public static ConfigEntry<int> SpecialLevelChancePercent;

		public static ConfigEntry<int> ModifiersPerLevelMin;

		public static ConfigEntry<int> ModifiersPerLevelMax;

		public static ConfigEntry<int> SurprisesStartLevel;

		public static readonly Dictionary<ModifierType, ConfigEntry<bool>> ModifierEnabled = new Dictionary<ModifierType, ConfigEntry<bool>>();

		public static ConfigEntry<float> FragileLootFactor;

		public static ConfigEntry<float> ProtectedLootFactor;

		public static ConfigEntry<float> HeavyLootFactor;

		public static ConfigEntry<float> LightLootFactor;

		public static ConfigEntry<float> LightMonsterMaxMass;

		public static ConfigEntry<float> HeavyMonsterMinMass;

		public static ConfigEntry<float> BiggerSoulDropsFactor;

		public static ConfigEntry<float> MonsterPitDamageFactor;

		public static ConfigEntry<int> ExtraGachaCubesPerSpawn;

		public static ConfigEntry<float> DangerousLootDamageFactor;

		public static ConfigEntry<float> SoulsExplodeHarderFactor;

		public static ConfigEntry<float> ThornyMonstersChance;

		public static ConfigEntry<float> ThornyMonstersMaxReflect;

		public static ConfigEntry<int> SpreadUpgradesCount;

		public static ConfigEntry<int> MysteryBoxCount;

		public static ConfigEntry<int> MysteryBoxMoneyMin;

		public static ConfigEntry<int> MysteryBoxMoneyMax;

		public static ConfigEntry<int> MysteryBoxWeightUpgrade;

		public static ConfigEntry<int> MysteryBoxWeightMoney;

		public static ConfigEntry<int> MysteryBoxWeightWeapon;

		public static ConfigEntry<int> MysteryBoxWeightCostume;

		public static ConfigEntry<bool> CostumeRewardsEnabled;

		public static ConfigEntry<string> SpreadUpgradesAllowed;

		public static ConfigEntry<bool> LogSpreadUpgradeNames;

		public static ConfigEntry<bool> AutoReviveAtCar;

		public static ConfigEntry<float> LevelTimerSeconds;

		public static ConfigEntry<float> LevelTimerKillBonus;

		public static ConfigEntry<float> LevelTimerDeathPenalty;

		public static ConfigEntry<float> LevelTimerQuotaBonus;

		public static ConfigEntry<bool> LateJoinEnabled;

		public static ConfigEntry<bool> PingEnabled;

		public static ConfigEntry<bool> PingUnderglowEnabled;

		public static ConfigEntry<KeyCode> PingKey;

		public static ConfigEntry<float> PingMaxDistance;

		public static ConfigEntry<float> PingDurationSeconds;

		public static ConfigEntry<float> PingMarkerScale;

		public static ConfigEntry<float> PingSoundVolume;

		public static ConfigEntry<int> MaxLocationPings;

		public static ConfigEntry<int> MaxActivePings;

		public static ConfigEntry<bool> ItemUnstuckEnabled;

		public static ConfigEntry<bool> ValuableRelocateStuck;

		public static ConfigEntry<float> ValuableStuckSeconds;

		public static ConfigEntry<bool> ValuableInvulnerableUntilGrab;

		public static ConfigEntry<bool> LootSafetyNetEnabled;

		public static ConfigEntry<bool> ChallengesEnabled;

		public static ConfigEntry<float> ChallengeChancePercent;

		public static ConfigEntry<float> LootSafetyMinPlayerDistance;

		public static ConfigEntry<int> LootSafetyMaxSpawns;

		public static ConfigEntry<bool> LootSafetyRevealOnMap;

		public static ConfigEntry<bool> LootSafetyLog;

		public static ConfigEntry<bool> SpectatorMapEnabled;

		public static ConfigEntry<KeyCode> SpectatorMapHoldKey;

		public static ConfigEntry<float> SpectatorMapScreenFraction;

		public static ConfigEntry<bool> QuestsEnabled;

		public static ConfigEntry<KeyCode> QuestPeekKey;

		public static ConfigEntry<int> QuestsPerLevelMin;

		public static ConfigEntry<int> QuestsPerLevelMax;

		public static ConfigEntry<int> QuestCompletionsPerRank;

		public static ConfigEntry<int> QuestCompletionsAtoS;

		public static ConfigEntry<int> QuestCompletionsStoSS;

		public static ConfigEntry<int> QuestCompletionsSStoSSS;

		public static ConfigEntry<int> QuestMoneyBase;

		public static ConfigEntry<int> QuestSkillPoints;

		public static ConfigEntry<int> QuestSkillPointsHighRank;

		public static ConfigEntry<float> QuestSkillPointChance;

		public static ConfigEntry<float> QuestContractChance;

		public static ConfigEntry<bool> SkillBoxesEnabled;

		public static ConfigEntry<bool> RetryCrystalsEnabled;

		public static ConfigEntry<int> RetryCrystalMin;

		public static ConfigEntry<int> RetryCrystalMax;

		public static ConfigEntry<float> RetryCrystalCharge;

		public static ConfigEntry<int> SkillBoxMin;

		public static ConfigEntry<int> SkillBoxMax;

		public static ConfigEntry<int> SkillBoxWeight0;

		public static ConfigEntry<int> SkillBoxWeight1;

		public static ConfigEntry<int> SkillBoxWeight2;

		public static ConfigEntry<int> SkillBoxWeight3;

		public static ConfigEntry<bool> QuestFunnyEnabled;

		public static ConfigEntry<bool> QuestItemRewardsEnabled;

		public static ConfigEntry<bool> QuestCosmeticRewardsEnabled;

		public static ConfigEntry<bool> QuestExactUpgradeRewardsEnabled;

		public static ConfigEntry<bool> QuestShopItemRewardsEnabled;

		public static ConfigEntry<bool> QuestHealRewardsEnabled;

		public static ConfigEntry<bool> QuestTempStatRewardsEnabled;

		public static ConfigEntry<int> QuestHealAmount;

		public static ConfigEntry<bool> RoundResultsEnabled;

		public static ConfigEntry<float> RoundResultsSeconds;

		public static ConfigEntry<KeyCode> RoundResultsKey;

		public static ConfigEntry<KeyCode> MapVoteHudKey;

		public static ConfigEntry<bool> InventorySlotsEnabled;

		public static ConfigEntry<KeyCode> InventorySlot4Key;

		public static ConfigEntry<KeyCode> InventorySlot5Key;

		public static ConfigEntry<KeyCode> InventorySlot6Key;

		public static ConfigEntry<KeyCode> InventorySlot7Key;

		public static ConfigEntry<bool> DronesEnabled;

		public static ConfigEntry<bool> ScaleMapValue;

		public static ConfigEntry<bool> ScaleEnemyCap;

		public static ConfigEntry<bool> ScaleLevelSize;

		public static ConfigEntry<bool> ScaleExtractions;

		public static ConfigEntry<bool> ScaleMoon;

		public static ConfigEntry<int> EconomyEventChance;

		public static ConfigEntry<int> EconomyStartLevel;

		public static ConfigEntry<int> MapValueStartLevel;

		public static ConfigEntry<int> EnemyCapStartLevel;

		public static ConfigEntry<int> LevelSizeStartLevel;

		public static ConfigEntry<int> ExtractionBonusInterval;

		public static ConfigEntry<int> ExtractionMax;

		public static ConfigEntry<int> MoonLevelsPerPhase;

		public static ConfigEntry<float> MapValuePerLevel;

		public static ConfigEntry<float> MapValueMax;

		public static ConfigEntry<float> EnemyCapPerLevel;

		public static ConfigEntry<float> EnemyCapMax;

		public static ConfigEntry<float> LevelSizePerLevel;

		public static ConfigEntry<float> LevelSizeMax;

		public static ConfigEntry<bool> ShopEconomyEnabled;

		public static ConfigEntry<bool> BlackMarketEnabled;

		public static ConfigEntry<int> ShopEconomyChance;

		public static ConfigEntry<int> BlackMarketModifierPrice;

		public static ConfigEntry<int> BlackMarketEconomyPrice;

		public static ConfigEntry<int> BlackMarketShopEconomyPrice;

		public static ConfigEntry<float> BlackMarketPerLevel;

		public static ConfigEntry<KeyCode> BlackMarketKey;

		public static readonly Dictionary<int, ConfigEntry<bool>> StatModifierEnabled = new Dictionary<int, ConfigEntry<bool>>();

		public static ConfigEntry<bool> GearEnabled;

		public static ConfigEntry<bool> CircletEnabled;

		public static ConfigEntry<bool> HeroAuraEnabled;

		public static ConfigEntry<bool> IceBlockEnabled;

		public static ConfigEntry<bool> UpgradesListScaleEnabled;

		public static ConfigEntry<bool> ArmorEnabled;

		public static ConfigEntry<bool> OverchargeEnabled;

		public static ConfigEntry<bool> TumbleBonusEnabled;

		public static ConfigEntry<bool> FailVoteEnabled;

		public static ConfigEntry<bool> HostRunControlsEnabled;

		public static ConfigEntry<bool> PlayerRestartVoteEnabled;

		public static ConfigEntry<float> ArmorPercentPerLevel;

		public static ConfigEntry<float> ArmorMaxReduction;

		public static ConfigEntry<float> OverchargeBuildupPerLevel;

		public static ConfigEntry<float> OverchargeRecoveryPerLevel;

		public static ConfigEntry<float> TumbleDamagePerLevel;

		public static ConfigEntry<float> TumbleSelfDamageReductionPerLevel;

		public static ConfigEntry<float> TumbleSelfDamageMaxReduction;

		public static ConfigEntry<int> ArmorMaxLevel;

		public static ConfigEntry<int> OverchargeMaxLevel;

		public static ConfigEntry<int> TumbleMaxLevel;

		public static ConfigEntry<float> CircletScale;

		public static ConfigEntry<bool> DefenceOrbEnabled;

		public static ConfigEntry<bool> DefenceDroneEnabled;

		public static ConfigEntry<bool> ProtectionOrbEnabled;

		public static ConfigEntry<bool> PoisonCrossbowEnabled;

		public static ConfigEntry<bool> DecoyGrenadeEnabled;

		public static ConfigEntry<bool> IcePistolEnabled;

		public static ConfigEntry<bool> StickyPistolEnabled;

		public static ConfigEntry<bool> FlameCartEnabled;

		public static ConfigEntry<bool> CustomCartsEnabled;

		public static ConfigEntry<bool> CourierEnabled;

		public static ConfigEntry<int> CourierLook;

		public static ConfigEntry<int> CourierOwned;

		public static ConfigEntry<int> CourierCoins;

		public static ConfigEntry<int> CourierFragments;

		public static ConfigEntry<bool> CourierStarterCoinGiven;

		public static ConfigEntry<bool> CourierDangerIcon;

		public static ConfigEntry<bool> CourierDangerSound;

		public static ConfigEntry<float> CourierCoinChance;

		public static ConfigEntry<KeyCode> CourierMenuKey;

		public static ConfigEntry<int> SoulCartValueCap;

		public static ConfigEntry<float> WideCartWidth;

		public static ConfigEntry<int> FlameDamagePerSecond;

		public static ConfigEntry<int> FlameCartValueCap;

		public static ConfigEntry<int> FlameCartPriceMinK;

		public static ConfigEntry<int> FlameCartPriceMaxK;

		public static ConfigEntry<float> FlameTickSeconds;

		public static ConfigEntry<float> FlameFuelSeconds;

		public static ConfigEntry<float> FlameRange;

		public static ConfigEntry<float> FlameConeAngle;

		public static ConfigEntry<bool> StaffEnabled;

		public static ConfigEntry<bool> NetLauncherEnabled;

		public static ConfigEntry<bool> WingCosmeticsEnabled;

		public static ConfigEntry<bool> SharkCosmeticsEnabled;

		public static ConfigEntry<bool> StarlightCosmeticsEnabled;

		public static ConfigEntry<bool> LegateCosmeticsEnabled;

		public static ConfigEntry<bool> FairyCosmeticsEnabled;

		public static ConfigEntry<bool> GildedCosmeticsEnabled;

		public static ConfigEntry<bool> SeerCosmeticsEnabled;

		public static ConfigEntry<bool> JesterCosmeticsEnabled;

		public static ConfigEntry<bool> BrideCosmeticsEnabled;

		public static ConfigEntry<bool> AngelCosmeticsEnabled;

		public static ConfigEntry<bool> MascotCosmeticsEnabled;

		public static ConfigEntry<bool> MermaidCosmeticsEnabled;

		public static ConfigEntry<bool> DruidCosmeticsEnabled;

		public static ConfigEntry<bool> VampireCosmeticsEnabled;

		public static ConfigEntry<bool> DiverCosmeticsEnabled;

		public static ConfigEntry<bool> ClockworkCosmeticsEnabled;

		public static ConfigEntry<string> CostumeChannelColors;

		public static ConfigEntry<bool> ScreenEffectsEnabled;

		public static ConfigEntry<bool> GuaranteedStrengthEnabled;

		public static ConfigEntry<float> NetSeconds;

		public static ConfigEntry<float> NetBreakChance;

		public static ConfigEntry<int> NetShots;

		public static ConfigEntry<int> StaffDamage;

		public static ConfigEntry<int> StaffMaxTargets;

		public static ConfigEntry<int> StaffCharges;

		public static ConfigEntry<float> StaffRange;

		public static ConfigEntry<float> StaffChainRange;

		public static ConfigEntry<float> StaffAimAngle;

		public static ConfigEntry<float> StaffShockSeconds;

		public static ConfigEntry<float> StaffPlayerDamagePercent;

		public static ConfigEntry<int> DefenceAbsorb;

		public static ConfigEntry<int> ProtectionReductionPercent;

		public static ConfigEntry<float> DefenceIdleDrainPerMinute;

		public static ConfigEntry<int> DefenceItemAbsorb;

		public static ConfigEntry<float> DefenceDroneSeconds;

		public static ConfigEntry<int> PoisonHitDamage;

		public static ConfigEntry<int> PoisonTotalDamage;

		public static ConfigEntry<int> PoisonMaxHpPercent;

		public static ConfigEntry<float> PoisonSeconds;

		public static ConfigEntry<float> IceFreezeSeconds;

		public static ConfigEntry<float> DecoySeconds;

		public static ConfigEntry<float> StickyFreeLiftMass;

		public static ConfigEntry<int> IceGunDamagePercent;

		public static ConfigEntry<int> IceMeleeBonusPercent;

		public static ConfigEntry<bool> EliteMonstersEnabled;

		public static ConfigEntry<bool> NewGrenadesEnabled;

		public static ConfigEntry<bool> ConsumablesEnabled;

		public static ConfigEntry<bool> SickleEnabled;

		public static ConfigEntry<bool> MonstersEnabled;

		public static ConfigEntry<bool> PigEnabled;

		public static ConfigEntry<bool> WitchEnabled;

		public static ConfigEntry<bool> BasiliskEnabled;

		public static ConfigEntry<bool> GorgonEnabled;

		public static ConfigEntry<bool> NagaEnabled;

		public static ConfigEntry<bool> FairyEnabled;

		public static ConfigEntry<bool> TwinsEnabled;

		public static ConfigEntry<float> PigSpawnChance;

		public static ConfigEntry<float> NewMonsterChance;

		public static ConfigEntry<int> MonsterRarity;

		public static ConfigEntry<KeyCode> DodgeKey;

		public static ConfigEntry<bool> GhostEnabled;

		public static ConfigEntry<bool> SilencerEnabled;

		public static ConfigEntry<bool> LinkEnabled;

		public static ConfigEntry<bool> RepairEnabled;

		public static ConfigEntry<float> LinkMaxDistance;

		public static ConfigEntry<float> SilencerNoiseMultiplier;

		public static ConfigEntry<bool> MapVoteEnabled;

		public static ConfigEntry<int> MapVoteChoices;

		public static ConfigEntry<float> MapVoteSeconds;

		public static ConfigEntry<bool> AutoBackupEnabled;

		public static ConfigEntry<bool> TruckUpgradesEnabled;

		public static ConfigEntry<float> TruckHealPercentPerLevel;

		public static ConfigEntry<int> TruckHealMaxLevel;

		public static ConfigEntry<int> TruckHealBaseCost;

		public static ConfigEntry<float> TruckChargePercentPerLevel;

		public static ConfigEntry<int> TruckChargeMaxLevel;

		public static ConfigEntry<int> TruckChargeBaseCost;

		public static ConfigEntry<int> TruckSellCost;

		public static ConfigEntry<int> TeamHaggleCost;

		public static ConfigEntry<int> TeamCrystalCost;

		public static ConfigEntry<int> TeamSpareGunCost;

		public static ConfigEntry<int> TeamSpareMeleeCost;

		public static ConfigEntry<int> TeamSpareDroneCost;

		public static ConfigEntry<int> TeamShelfCost;

		public static ConfigEntry<float> TruckSellFraction;

		public static ConfigEntry<float> TruckSellMaxQuotaShare;

		public static ConfigEntry<bool> PlayerUpgradesEnabled;

		public static ConfigEntry<float> StaminaPercentPerLevel;

		public static ConfigEntry<int> StaminaMaxLevel;

		public static ConfigEntry<float> RegenPercentPerLevel;

		public static ConfigEntry<float> RegenMaxHpFraction;

		public static ConfigEntry<int> RegenMaxLevel;

		public static ConfigEntry<int> DeathProtectMaxCharges;

		public static ConfigEntry<int> DeathProtectBasePrice;

		public static ConfigEntry<float> GunExtraBulletsPerLevel;

		public static ConfigEntry<int> GunExtraBulletsMaxLevel;

		public static ConfigEntry<float> DroneBatteryPercentPerLevel;

		public static ConfigEntry<int> DroneBatteryMaxLevel;

		public static ConfigEntry<float> MeleeDamagePercentPerLevel;

		public static ConfigEntry<int> MeleeDamageMaxLevel;

		public static ConfigEntry<float> GrenadeDamagePercentPerLevel;

		public static ConfigEntry<int> GrenadeDamageMaxLevel;

		public static ConfigEntry<float> AutoscanRangePerLevel;

		public static ConfigEntry<int> AutoscanMaxLevel;

		public static ConfigEntry<float> AutoscanInterval;

		public static ConfigEntry<float> MapZoomFovLevel7;

		public static ConfigEntry<float> MapZoomFovLevel8;

		public static ConfigEntry<KeyCode> MapZoomInKey;

		public static ConfigEntry<KeyCode> BetterMapKey;

		public static ConfigEntry<KeyCode> MapZoomOutKey;

		public static ConfigEntry<float> MapZoomStep;

		public static ConfigEntry<bool> SkillSpendAnywhere;

		public static ConfigEntry<int> SkillRespecCost;

		public static ConfigEntry<int> SkillTradeOffResetCost;

		public static ConfigEntry<int> SkillPointBasePrice;

		public static ConfigEntry<KeyCode> SkillTreeKey;

		public static ConfigEntry<float> SkillRootBonus;

		public static ConfigEntry<float> SkillWeaponDamageMax;

		public static ConfigEntry<float> SkillStatusRootSeconds;

		public static ConfigEntry<float> SkillSecondWindPerLevel;

		public static ConfigEntry<float> SkillSurvivorStamina;

		public static ConfigEntry<float> SkillFlashRange;

		public static ConfigEntry<float> SkillFlashWidthPerLevel;

		public static ConfigEntry<float> SkillFlashBrightnessPerLevel;

		public static ConfigEntry<float> SkillDesperationPerLevel;

		public static ConfigEntry<float> SkillDesperationThreshold;

		public static ConfigEntry<float> SkillHeavyHitterPerLevel;

		public static ConfigEntry<float> SkillMedicPerLevel;

		public static ConfigEntry<float> SkillMedicRadius;

		public static ConfigEntry<float> SkillBatterySaverPerLevel;

		public static ConfigEntry<float> SkillLuckyCrystalBonus;

		public static ConfigEntry<float> SkillCrouchSpeedPerLevel;

		public static ConfigEntry<float> SkillVampireMax;

		public static ConfigEntry<int> SkillLuckyBoxShift;

		public static ConfigEntry<bool> SkillWideViewOn;

		public static ConfigEntry<bool> LevelInfoEnabled;

		public static ConfigEntry<KeyCode> LevelInfoToggleKey;

		public static ConfigEntry<bool> ServerInfoEnabled;

		public static ConfigEntry<bool> ShoppingListEnabled;

		public static ConfigEntry<bool> MorePlayersEnabled;

		public static ConfigEntry<int> MorePlayersMax;

		public static ConfigEntry<bool> ShopPriceScaleEnabled;

		public static ConfigEntry<int> ShopPriceBaselinePlayers;

		public static ConfigEntry<float> ShopPricePerExtraPlayer;

		public static ConfigEntry<bool> SkillPageBonuses;

		public static ConfigEntry<KeyCode> FlashStunKey;

		public static ConfigEntry<float> FlashStunSeconds;

		public static ConfigEntry<float> FlashStunCooldown;

		public static ConfigEntry<int> ShopExtraItems;

		private const string HideFromRepoConfig = "HideFromREPOConfig";

		private const int BalanceRevision = 1;

		private static Dictionary<string, float> _perEnemyHealthMax = new Dictionary<string, float>();

		internal static IEnumerable<float> PerEnemyHealthCaps => _perEnemyHealthMax.Values;

		private static ConfigEntry<int> BindInt(ConfigFile cfg, string section, string key, int def, int min, int max, string desc)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			return cfg.Bind<int>(section, key, def, new ConfigDescription(desc, (AcceptableValueBase)(object)new AcceptableValueRange<int>(min, max), Array.Empty<object>()));
		}

		private static ConfigEntry<float> BindFloat(ConfigFile cfg, string section, string key, float def, float min, float max, string desc)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			return cfg.Bind<float>(section, key, def, new ConfigDescription(desc, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), Array.Empty<object>()));
		}

		internal static string ModifierDescription(ModifierType m)
		{
			return m switch
			{
				ModifierType.FragileLoot => "Loot breaks and loses value more easily.", 
				ModifierType.HeavyLoot => "Loot weighs more, making it harder to haul.", 
				ModifierType.LightLoot => "Loot weighs less, making it easier to haul.", 
				ModifierType.ProtectedLoot => "Loot takes less damage before breaking.", 
				ModifierType.DangerousLoot => "Hazardous valuables deal more damage to players.", 
				ModifierType.ExtraSmallCart => "An extra small cart spawns on the level.", 
				ModifierType.ExtraBigCart => "An extra big cart spawns on the level.", 
				ModifierType.ExtraSouls => "Monsters drop more souls.", 
				ModifierType.SpreadUpgrades => "Up to 6 upgrades on the map. Submit them with a successful quota to receive them in the next truck.", 
				ModifierType.NoMap => "No map until you find a map upgrade pickup.", 
				ModifierType.ReducedPlayerHp => "Everyone starts the level wounded — current HP is cut to a rolled percentage (max HP is untouched, so you can heal back up).", 
				ModifierType.AutoRevive => "Each player gets one automatic revive this level.", 
				ModifierType.MoneyLossOnDeath => "Dying loses a percentage of your collected money.", 
				ModifierType.LevelTimer => "Timed level: kills add time, deaths remove it, quota adds it; at 0 the layout rerolls.", 
				ModifierType.ChangeVoices => "Player voices get swapped or randomized.", 
				ModifierType.MoreGachaCubes => "More gacha/cube valuables spawn.", 
				ModifierType.SoulsExplodeHarder => "Exploding souls deal more damage to players.", 
				ModifierType.BiggerSoulDrops => "Each soul drop is worth more money (value per drop, not count).", 
				ModifierType.MonstersPitTanky => "Monsters take less damage from death pits.", 
				ModifierType.LightMonsters => "Monsters weigh less and yield to a single player's grab without Strength upgrades. Native hold-time, mounted and freeze restrictions still apply.", 
				ModifierType.HeavyMonsters => "All monsters weigh more, so they're hard to shove around.", 
				ModifierType.SilentNight => "Everything players do makes 40% less noise: footsteps, voices and dropped loot alert fewer monsters.", 
				ModifierType.LoudFacility => "The acoustics are terrible: monsters hear every footstep, voice and bump 50% farther away.", 
				ModifierType.GreasedWheels => "Freshly oiled wheels: C.A.R.T.s are much easier to push, even full and uphill.", 
				ModifierType.ShortMemory => "Monsters forget quickly: once they lose sight of you, they give up the chase sooner.", 
				ModifierType.ThornyMonsters => "About half the monsters grew thorns: hitting them with a melee weapon reflects up to 10% of the damage back at you.", 
				ModifierType.MysteryBoxes => "Mystery boxes appear around the map. Drop one monster soul into a box to roll a random upgrade, money, or a weapon/grenade for this level only. Each box takes one soul.", 
				_ => $"The '{m}' surprise modifier.", 
			};
		}

		private static void BindModules(ConfigFile cfg)
		{
			//IL_07db: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e2: Invalid comparison between Unknown and I4
			//IL_0e3d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e43: Expected O, but got Unknown
			//IL_0e89: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e95: Expected O, but got Unknown
			SurprisesEnabled = Module(cfg, "Surprises", "Enabled", def: true, "Surprises", "Master switch for all level surprises, including economic events affecting loot value, quota and extraction pay. Shop price events have their own ShopEconomy switch.");
			ScaleMapValue = Module(cfg, "Level Scaling", "MapValue", def: true, "ScaleMapValue", "Valuables are worth more the deeper the run goes.");
			ScaleEnemyCap = Module(cfg, "Level Scaling", "EnemyCount", def: true, "ScaleEnemyCount", "More monsters spawn per level the deeper the run goes.");
			ScaleLevelSize = Module(cfg, "Level Scaling", "LevelSize", def: true, "ScaleLevelSize", "Levels get more modules (a bigger map) the deeper the run goes.");
			ScaleExtractions = Module(cfg, "Level Scaling", "Extractions", def: true, "ScaleExtractions", "Deeper levels get extra extraction points.");
			ScaleMoon = Module(cfg, "Level Scaling", "Moon", def: false, "ScaleMoon", "Override the moon phase interval with MoonLevelsPerPhase. Recommended: every 5 levels, matching native progression.");
			ShopEconomyEnabled = Module(cfg, "Shop Economy", "Enabled", def: true, "ShopEconomy", "Shop price events: when the run reaches a shop it may get a sale, a tax or an inflation spike that changes item, upgrade, health pack and crystal prices (including this mod's own items and upgrades). Host rolls it.");
			BlackMarketEnabled = Module(cfg, "Black Market", "Enabled", def: true, "BlackMarket", "Black Market: in the shop, pay to make a surprise modifier rarer (down to never) or more common for the rest of the run, and switch what you bought on or off for free; or block a level economy or shop economy. Keyboard driven.");
			PlayerUpgradesEnabled = Module(cfg, "Player Upgrades", "Enabled", def: true, "PlayerUpgrades", "Master switch for the mod's custom per-player upgrades that appear in the normal shop. Requires REPOLib. Takes effect on restart.");
			TruckUpgradesEnabled = Module(cfg, "Truck Upgrades", "Enabled", def: true, "TruckUpgrades", "Enable the team-wide truck upgrades (Heal Power, Charge Efficiency, Loot Cash-In, Haggling, Crystal Stock, Spare Gun / Melee / Drone, Upgrade Shelf). Bought in the normal shop; effects apply for the whole team.");
			ScaleEnemyHealth = Module(cfg, "Scaling", "EnemyHealth", def: true, "ScaleEnemyHealth", "Enemies gain max HP as the run goes deeper. Off disables the depth ramp; level surprises remain independent. Host settings apply to the lobby.");
			ScaleEnemyDamage = Module(cfg, "Scaling", "EnemyDamage", def: true, "ScaleEnemyDamage", "Enemies deal more damage to players as the run goes deeper. Off disables the depth ramp; level surprises remain independent. Host settings apply to the lobby.");
			ScaleEnemySpeed = Module(cfg, "Scaling", "EnemySpeed", def: true, "ScaleEnemySpeed", "Enemies move faster as the run goes deeper. Off disables the depth ramp; level surprises remain independent. Host settings apply to the lobby.");
			ScaleEnemyRespawn = Module(cfg, "Scaling", "EnemyRespawn", def: true, "ScaleEnemyRespawn", "Enemies respawn faster as the run goes deeper. Off disables the depth ramp; level surprises remain independent. Host settings apply to the lobby.");
			ScaleQuota = Module(cfg, "Scaling", "Quota", def: true, "ScaleQuota", "The extraction quota grows as the run goes deeper. Off = vanilla quota (host setting).");
			DronesEnabled = Module(cfg, "Drones", "Enabled", def: true, "Drones", "Add the Ghost, Silencer and Link utility drones to the shop. EVERY player must run this mod with the same setting, otherwise shop items and effects will not match. Takes effect on game restart.");
			GhostEnabled = Module(cfg, "Drones", "GhostEnabled", def: true, "GhostDrone", "Sell the Ghost Drone. Needs Drones/Enabled. Same on every player; applies on game restart.");
			SilencerEnabled = Module(cfg, "Drones", "SilencerEnabled", def: true, "SilencerDrone", "Sell the Silencer Drone. Needs Drones/Enabled. Same on every player; applies on game restart.");
			LinkEnabled = Module(cfg, "Drones", "LinkEnabled", def: true, "LinkDrone", "Sell the Link Drone Set (A + B). Needs Drones/Enabled. Same on every player; applies on game restart.");
			RepairEnabled = Module(cfg, "Drones", "RepairEnabled", def: true, "RepairDrone", "Sell the Repair Drone. Needs Drones/Enabled. Same on every player; applies on game restart.");
			ShopEconomyChance = BindInt(cfg, "Shop Economy", "EventChancePercent", 50, 0, 100, "Chance (percent) that a shop visit gets a price event.");
			BlackMarketKey = cfg.Bind<KeyCode>("Black Market", "Key", (KeyCode)98, "Key that opens the Black Market while you are in the shop.");
			BlackMarketModifierPrice = BindInt(cfg, "Black Market", "ModifierPrice", 35, 1, 5000, "Base price (in the game's K currency) for surprise modifier odds: one step costs 0.2-0.8 of it (more for steps that help the crew: a nasty modifier rarer or a good one more common), scaled by depth. A step back toward normal odds is free.");
			BlackMarketEconomyPrice = BindInt(cfg, "Black Market", "EconomyPrice", 50, 1, 5000, "Base price to block a level economy event.");
			BlackMarketShopEconomyPrice = BindInt(cfg, "Black Market", "ShopEconomyPrice", 65, 1, 5000, "Base price to block a shop economy.");
			BlackMarketPerLevel = BindFloat(cfg, "Black Market", "PricePerLevel", 0.07f, 0f, 1f, "Price growth per level completed (0.07 = +7% per level).");
			EconomicSurpriseConfig economicSurpriseConfig = EconomicSurpriseConfig.Bind(cfg);
			EconomyEventChance = economicSurpriseConfig.Chance;
			EconomyStartLevel = economicSurpriseConfig.StartLevel;
			MapValueStartLevel = BindInt(cfg, "Level Scaling", "MapValueStartLevel", 2, 0, 50, "Levels completed before valuables start gaining value.");
			MapValuePerLevel = BindFloat(cfg, "Level Scaling", "MapValuePerLevel", 0.03f, 0f, 0.5f, "Valuable value growth per level (compounding). 0.03 = x1.03 per level.");
			MapValueMax = BindFloat(cfg, "Level Scaling", "MapValueMax", 3f, 1f, 20f, "Cap on the depth multiplier of valuables' value.");
			EnemyCapStartLevel = BindInt(cfg, "Level Scaling", "EnemyCountStartLevel", 8, 0, 100, "Levels completed before extra monsters appear.");
			EnemyCapPerLevel = BindFloat(cfg, "Level Scaling", "EnemyCountPerLevel", 0.03f, 0f, 1f, "Extra monsters per level past the start, as a fraction of the normal count (0.03 = +3%).");
			EnemyCapMax = BindFloat(cfg, "Level Scaling", "EnemyCountMax", 2f, 1f, 5f, "Cap on the monster count multiplier.");
			LevelSizeStartLevel = BindInt(cfg, "Level Scaling", "LevelSizeStartLevel", 8, 0, 100, "Levels completed before levels start growing.");
			LevelSizePerLevel = BindFloat(cfg, "Level Scaling", "LevelSizePerLevel", 0.03f, 0f, 1f, "Level size growth per level past the start (0.03 = +3% modules and grid).");
			LevelSizeMax = BindFloat(cfg, "Level Scaling", "LevelSizeMax", 1.5f, 1f, 3f, "Cap on the level size multiplier.");
			ExtractionBonusInterval = BindInt(cfg, "Level Scaling", "ExtractionBonusInterval", 10, 1, 50, "One extra extraction point every this many levels.");
			ExtractionMax = BindInt(cfg, "Level Scaling", "ExtractionMax", 5, 1, 8, "Most extraction points (quotas) a level can have, counting the one in the start room. Never fewer than the game itself gives the level.");
			MoonLevelsPerPhase = BindInt(cfg, "Level Scaling", "MoonLevelsPerPhase", 5, 5, 60, "With ScaleMoon on: levels per moon phase. Recommended: 5, matching native progression.");
			GearEnabled = Module(cfg, "Gear", "Enabled", def: true, "ExtraGear", "Add the extra shop gear (Defence/Protection orbs, Defence drone, poison crossbow, decoy grenade, ice pistol, sticky pistol). EVERY player must run this mod with the same settings. Applies on game restart.");
			DefenceOrbEnabled = Module(cfg, "Gear", "DefenceOrbEnabled", def: true, "DefenceOrb", "Sell the Defence Orb.");
			DefenceDroneEnabled = Module(cfg, "Gear", "DefenceDroneEnabled", def: true, "DefenceDrone", "Sell the Defence Drone.");
			ProtectionOrbEnabled = Module(cfg, "Gear", "ProtectionOrbEnabled", def: true, "ProtectionOrb", "Sell the Protection Orb.");
			PoisonCrossbowEnabled = Module(cfg, "Gear", "PoisonCrossbowEnabled", def: true, "PoisonCrossbow", "Sell the Poison Crossbow.");
			DecoyGrenadeEnabled = Module(cfg, "Gear", "DecoyGrenadeEnabled", def: true, "DecoyGrenade", "Sell the Decoy Grenade.");
			NewGrenadesEnabled = Module(cfg, "Gear", "NewGrenadesEnabled", def: true, "NewGrenades", "Sell the Smoke, Cryo and Glue grenades. Every player must use the same setting (shop items must match). Takes effect on restart.");
			ConsumablesEnabled = Module(cfg, "Gear", "ConsumablesEnabled", def: true, "Consumables", "Sell the Antidote, Adrenaline Shot and Repair Kit. Every player must use the same setting (shop items must match). Takes effect on restart.");
			SickleEnabled = Module(cfg, "Gear", "SickleEnabled", def: true, "Sickle", "Sell the Boomerang Sickle. Every player must use the same setting (shop items must match). Takes effect on restart.");
			IcePistolEnabled = Module(cfg, "Gear", "IcePistolEnabled", def: true, "IcePistol", "Sell the Pulse Ice Pistol.");
			StickyPistolEnabled = Module(cfg, "Gear", "StickyPistolEnabled", def: true, "StickyPistol", "Sell the Sticky Pistol.");
			FlameCartEnabled = Module(cfg, "Gear", "FlameCartEnabled", def: true, "FlameCart", "Sell the Flamethrower C.A.R.T. (a wheeled flamethrower turret with a loot storage box).");
			CourierEnabled = Module(cfg, "Courier", "Enabled", def: true, "Courier", "Every player gets a courier pet that follows them, charges and fetches items and can be petted by grabbing it, like Elsa. The host's setting decides.");
			CourierLook = cfg.Bind<int>("Courier", "Look", 0, "Your courier's animal and colours (set from the courier menu; saved here).");
			CourierOwned = cfg.Bind<int>("Courier", "OwnedAnimals", 0, "Courier animals you unlocked from the gacha (bit mask: 1 penguin, 2 chicken, 4 cat, 8 owl, 16 beaver, 32 sheep, 64 cow, 128 dog, 256 fairy, 512 devil, 1024 angel, 2048 dragon, 4096 mermaid, 8192 skeleton, 16384 elemental, 32768 phoenix).");
			CourierCoins = cfg.Bind<int>("Courier", "GachaCoins", 0, "Your gacha coins (found rarely on levels; one pull each).");
			CourierFragments = cfg.Bind<int>("Courier", "CoinHalves", 0, "Half coins from duplicate pulls; two make a coin.");
			CourierStarterCoinGiven = cfg.Bind<bool>("Courier", "StarterCoinGiven", false, "Whether you already got the free starter coin.");
			CourierDangerIcon = cfg.Bind<bool>("Courier", "DangerIcon", true, "Show the red \"!\" over your pets when a monster is near. Only changes your own screen (also in the courier menu: MORE).");
			CourierDangerSound = cfg.Bind<bool>("Courier", "DangerSound", true, "Play the pets' alarm chirp when a monster comes near. Only changes what you hear (also in the courier menu: MORE).");
			CourierCoinChance = BindFloat(cfg, "Courier", "CoinChancePerLevel", 0.3f, 0f, 1f, "HOST: chance that a gacha coin is hidden somewhere on a level.");
			if (Mathf.Approximately(CourierCoinChance.Value, 0.2f))
			{
				CourierCoinChance.Value = 0.3f;
			}
			CourierMenuKey = cfg.Bind<KeyCode>("Courier", "MenuKey", (KeyCode)99, "Opens the courier command menu. Arrow keys move, Enter/Right picks, Left goes back.");
			if ((int)CourierMenuKey.Value == 103)
			{
				CourierMenuKey.Value = (KeyCode)99;
			}
			CustomCartsEnabled = Module(cfg, "Gear", "CustomCartsEnabled", def: true, "CustomCarts", "Sell the Soul C.A.R.T. (small, souls only), the Wide C.A.R.T. and the Double-Decker C.A.R.T.");
			SoulCartValueCap = BindInt(cfg, "Carts", "SoulCartValueCap", 65000, 1000, 65000, "Value of souls the Soul C.A.R.T. hatch can store, up to $65,000.");
			if (SoulCartValueCap.Value == 55000)
			{
				SoulCartValueCap.Value = 65000;
			}
			WideCartWidth = BindFloat(cfg, "Carts", "WideCartWidth", 1.25f, 1f, 1.5f, "How much wider the Wide C.A.R.T. is than the big C.A.R.T. (1.25 = 25% wider). Length is at least " + 1.4f.ToString("0.##", CultureInfo.InvariantCulture) + "x, with extra length at lower widths to retain floor space. Above about 1.3 it may not fit through doorways. Applies after a game restart.");
			FlameDamagePerSecond = BindInt(cfg, "Flamethrower", "DamagePerSecond", 30, 1, 500, "Damage per second dealt to every monster inside the flame, applied in small fast ticks.");
			FlameTickSeconds = BindFloat(cfg, "Flamethrower", "DamageTickSeconds", 0.25f, 0.1f, 2f, "Seconds between flame damage ticks. Smaller = smoother, more immediate damage.");
			FlameFuelSeconds = BindFloat(cfg, "Flamethrower", "FuelSeconds", 60f, 5f, 600f, "Seconds of continuous flame one full battery provides (used whether or not anything is hit).");
			FlameRange = BindFloat(cfg, "Flamethrower", "Range", 7f, 2f, 15f, "Flame reach in metres, in the direction the operator looks.");
			FlameConeAngle = BindFloat(cfg, "Flamethrower", "ConeHalfAngle", 30f, 5f, 80f, "Half-angle of the flame cone in degrees.");
			FlameCartValueCap = BindInt(cfg, "Flamethrower", "CargoValueCap", 25000, 0, 1000000, "Most loot value its storage box (the Hauler's storage system) holds; loot that would exceed it is refused. 0 = the Hauler's own limit.");
			FlameCartPriceMinK = BindInt(cfg, "Flamethrower", "ShopPriceMinK", 50, 1, 5000, "Lowest shop price, in K as the shop shows it (50 = $50K). Shop economy modifiers still apply on top.");
			FlameCartPriceMaxK = BindInt(cfg, "Flamethrower", "ShopPriceMaxK", 80, 1, 5000, "Highest shop price, in K as the shop shows it (80 = $80K).");
			StaffEnabled = Module(cfg, "Gear", "WizardStaffEnabled", def: true, "WizardStaff", "Sell the Wizard Staff (chain-lightning wand).");
			NetLauncherEnabled = Module(cfg, "Gear", "NetLauncherEnabled", def: true, "NetLauncher", "Sell the Net Launcher (roots a monster to the floor).");
			GuaranteedStrengthEnabled = Module(cfg, "Shop", "GuaranteedStrength", def: true, "GuaranteedStrength", "When MoreStandsForShops is installed, the shop always offers at least one Strength (grab strength) upgrade, while the team can still buy it. Host setting.");
			ScreenEffectsEnabled = Module(cfg, "Screen Effects", "Enabled", def: true, "ScreenEffects", "When you are frozen, poisoned, sedated (tranquilized) or netted, show a themed frame around the screen edges and a status card at the left with a time bar. Local only.");
			MascotCosmeticsEnabled = Module(cfg, "Cosmetics", "MascotsEnabled", def: true, "MascotCosmetics", "Add nine modular costume sets: Musketeer Cat, Bomb Bird, Talking Dog, Rabbid Mayhem, Jackal Warden, Panda Dojo, Penguin Captain, Hello Kitty and Chipmunk Hoodie. Tintable in the native cosmetics menu. Everyone needs the same mod version. Takes effect on restart.");
			CostumeChannelColors = cfg.Bind<string>("Cosmetics", "ChannelColors", "", "Your second and accent colours for the mod's costume parts (set with the MAIN / SECOND / ACCENT buttons on the game's colour page; saved here).");
			WingCosmeticsEnabled = Module(cfg, "Cosmetics", "WingsEnabled", def: true, "WingCosmetics", "Add three Rare back-wing cosmetics (Astral Night, Solar Seraph, Prism Chime) to the Body Top slot. Everyone in the lobby needs this setting to see them. Takes effect on restart.");
			SharkCosmeticsEnabled = Module(cfg, "Cosmetics", "PlushSharkEnabled", def: true, "SharkCosmetics", "Add the six-part Plush Shark set: hood (Hat), headphones (Ears), suit with dorsal fin (Body Top), tail (Body Bottom) and two fin sleeves (Arm Right, Arm Left). The blue plush takes the colour you pick in the cosmetics menu. Everyone in the lobby needs this setting to see them. Takes effect on restart.");
			SeerCosmeticsEnabled = Module(cfg, "Cosmetics", "SeerEnabled", def: true, "SeerCosmetics", "Add the Horned Seer set: a hood with crescent horns, chains, crystals and a blindfold (Hat), a black robe with a tattered green shawl and a deer-skull pauldron (Body Top), a long ragged robe with a green veil and crystal chains (Body Bottom) and bell sleeves (Arm Right, Arm Left). The green takes the colour you pick in the cosmetics menu. Takes effect on restart.");
			JesterCosmeticsEnabled = Module(cfg, "Cosmetics", "JesterEnabled", def: true, "JesterCosmetics", "Add the Card Jester set: a three-pointed hat with bells and playing cards (Hat), a smiling porcelain mask (Face Top), a red-and-black doublet with a ruff and peplum (Body Top), wide split trousers (Body Bottom) and puffed sleeves (Arm Right, Arm Left). The red takes the colour you pick in the cosmetics menu. Takes effect on restart.");
			BrideCosmeticsEnabled = Module(cfg, "Cosmetics", "BrideEnabled", def: true, "BrideCosmetics", "Add the Ghost Bride set: a blue rose crown with a tattered veil (Hat), a lace corset (Body Top), a long open satin skirt (Body Bottom), a blue arm and a skeleton arm (Arm Right, Arm Left), a skeleton leg and a blue leg in white boots (Leg Right, Leg Left) and a blue face, lips and jaw (Face Top, Face Bottom, Head Bottom). The lace and satin take the colour you pick in the cosmetics menu; skin, bone and the face keep their own colours. Takes effect on restart.");
			AngelCosmeticsEnabled = Module(cfg, "Cosmetics", "AngelEnabled", def: true, "AngelCosmetics", "Add the Mossy Stone Angel set: a stone veil with a moss crown (Hat), a stone robe with a ruffled collar, with or without tall folded stone wings (Body Top), a long draped robe with moss (Body Bottom) and ruffled sleeves (Arm Right, Arm Left). The stone takes the colour you pick in the cosmetics menu. Takes effect on restart.");
			MermaidCosmeticsEnabled = Module(cfg, "Cosmetics", "MermaidEnabled", def: true, "MermaidCosmetics", "Add the Pearl Mermaid set: a shell crown on long hair (Hat), a shell top with pearls (Body Top), a scale skirt with a fin veil (Body Bottom), fin cuffs with gloves (both arms) and shell boots (both legs). Every part recolours with the game's colour picker.");
			DruidCosmeticsEnabled = Module(cfg, "Cosmetics", "DruidEnabled", def: true, "DruidCosmetics", "Add the Grove Druid set: an antlered mossy hood with amber drops (Hat), a robe under a leaf mantle (Body Top), a leaf skirt with vines, a tabard and a flask (Body Bottom), bark bracers (both arms) and rooted boots (both legs). Every part recolours with the game's colour picker.");
			VampireCosmeticsEnabled = Module(cfg, "Cosmetics", "VampireEnabled", def: true, "VampireCosmetics", "Add the Night Count set: swept pale hair (Hat), a coat with a high collar, bat-wing cape, jabot and ruby (Body Top), striped breeches with a coffin charm (Body Bottom), ruffled sleeves (both arms) and buckled boots (both legs). Every part recolours with the game's colour picker.");
			DiverCosmeticsEnabled = Module(cfg, "Cosmetics", "DiverEnabled", def: true, "DiverCosmetics", "Add the Deep Diver set: a brass helmet with lit portholes (Hat), a canvas suit with an air tank (Body Top), breeches with a lantern and an anchor tabard (Body Bottom), sealed gloves (both arms) and weighted boots (both legs). Every part recolours with the game's colour picker.");
			ClockworkCosmeticsEnabled = Module(cfg, "Cosmetics", "ClockworkEnabled", def: true, "ClockworkCosmetics", "Add the Clockwork Toy set: an inventor's top hat with goggles and gears (Hat), a uniform with epaulettes and a wind-up key (Body Top), striped breeches under coat tails (Body Bottom), banded sleeves (both arms) and piston boots (both legs). Every part recolours with the game's colour picker.");
			GildedCosmeticsEnabled = Module(cfg, "Cosmetics", "GildedEnabled", def: true, "GildedCosmetics", "Add the Gilded Shadow set: a gold-trimmed hood (Hat), a corset with an open coat, spiked shoulders and a necklace (Body Top), a long open veil skirt over shorts with chains and moon pendants (Body Bottom), puff sleeves (Arm Right, Arm Left) and stockings with black boots, one dark and one cream (Leg Right, Leg Left). The brown fabric and the stockings take the colour you pick in the cosmetics menu. Everyone in the lobby needs this setting to see them. Takes effect on restart.");
			FairyCosmeticsEnabled = Module(cfg, "Cosmetics", "FairyEnabled", def: true, "FairyCosmetics", "Add the Petal Fairy set: a pink crop top with choker and flowers (Body Top), the same top with four glowing petal wings (Body Top), a wrap skirt over striped shorts (Body Bottom), off-shoulder sleeves (Arm Right, Arm Left) and striped stockings with slouch boots (Leg Right, Leg Left). The pink fabric, wings and stocking stripes take the colour you pick in the cosmetics menu. Everyone in the lobby needs this setting to see them. Takes effect on restart.");
			LegateCosmeticsEnabled = Module(cfg, "Cosmetics", "LegateEnabled", def: true, "LegateCosmetics", "Add the Legate set: a silver muscle cuirass with baldric and belt (Body Top), the same cuirass with a red mantle and long cape (Body Top), a war skirt of tooled leather strips (Body Bottom) and red leather bracers (Arm Right, Arm Left). The red cloth and leather take the colour you pick in the cosmetics menu. Everyone in the lobby needs this setting to see them. Takes effect on restart.");
			StarlightCosmeticsEnabled = Module(cfg, "Cosmetics", "StarlightEnabled", def: true, "StarlightCosmetics", "Add the seven-part Starlight Gown set: galaxy bodice with choker (Body Top), high-low skirt with lace hems and belt (Body Bottom), lace sleeves (Arm Right, Arm Left), thigh-high galaxy boots (Leg Right, Leg Left) and drop earrings (Ears). The galaxy fabric, its glowing stars, the lace and the gems take the colour you pick in the cosmetics menu. Everyone in the lobby needs this setting to see them. Takes effect on restart.");
			NetSeconds = BindFloat(cfg, "Net Launcher", "RootSeconds", 5f, 1f, 30f, "How long a net pins a monster to the floor. It can still turn and attack anyone in reach.");
			NetBreakChance = BindFloat(cfg, "Net Launcher", "BreakChancePerSecond", 0.12f, 0f, 1f, "Chance each second that the monster tears the net and breaks free early (0.12 = about 45% over 5 seconds).");
			NetShots = BindInt(cfg, "Net Launcher", "Shots", 8, 1, 20, "Nets per full battery (one battery bar per net).");
			StaffDamage = BindInt(cfg, "Wizard Staff", "BoltDamage", 75, 1, 1000, "Total lightning damage per bolt, split evenly between the monsters it strikes (75 = 75 to one, 38 + 37 to two, 25 each to three).");
			StaffRange = BindFloat(cfg, "Wizard Staff", "Range", 7.5f, 1f, 20f, "How far (metres) the first bolt reaches from the staff tip.");
			StaffShockSeconds = BindFloat(cfg, "Wizard Staff", "ShockSeconds", 4f, 0f, 15f, "Everything a bolt strikes is shocked this long: players move 50% slower and recover stamina half as fast; monsters move 50% slower and deal 25% less damage. 0 turns it off.");
			StaffPlayerDamagePercent = BindFloat(cfg, "Wizard Staff", "PlayerDamagePercent", 30f, 0f, 100f, "A bolt aimed straight at a teammate strikes them (and chains to nearby players) for this share of its damage. 0 = shock only, no damage.");
			StaffMaxTargets = BindInt(cfg, "Wizard Staff", "MaxTargets", 3, 1, 10, "Most monsters one bolt can strike, including the first (the chain jumps to the nearest unstruck monster).");
			StaffChainRange = BindFloat(cfg, "Wizard Staff", "ChainRange", 5f, 1f, 20f, "Farthest jump (metres) from one struck monster to the next.");
			StaffAimAngle = BindFloat(cfg, "Wizard Staff", "AimAssistAngle", 20f, 0f, 60f, "If the aim line misses, the bolt still finds a monster within this many degrees of it (0 = exact aim only).");
			StaffCharges = BindInt(cfg, "Wizard Staff", "Charges", 8, 1, 20, "Bolts per full battery (one battery bar per bolt).");
			CircletEnabled = Module(cfg, "Cosmetics", "WingedCircletEnabled", def: true, "WingedCirclet", "Player ping marker: when someone pings a player, a floating winged circlet appears above that player's head for the length of the ping, coloured to match the player's own colour (black, cyan, yellow, green, white, purple or red). Not a cosmetic and not always shown. Local visuals only: each player can turn it off for themselves.");
			Dictionary<ConfigDefinition, string> dictionary = Orphans(cfg);
			ConfigDefinition key = new ConfigDefinition("Ping", "WingedCircletScale");
			bool num = dictionary?.ContainsKey(key) ?? false;
			CircletScale = BindFloat(cfg, "Ping", "WingedCircletScale", 1f, 0.5f, 2f, "Size of the winged circlet shown above a pinged player (1 = default).");
			if (!num && dictionary != null && dictionary.TryGetValue(new ConfigDefinition("Cosmetics", "WingedCircletScale"), out var value))
			{
				((ConfigEntryBase)CircletScale).SetSerializedValue(value);
			}
			IceBlockEnabled = Module(cfg, "Cosmetics", "IceBlockEnabled", def: true, "IceBlock", "Monsters frozen by the Ice Pistol are encased in a see-through block of ice with crystal shards, cold mist and frost sparkles. Local visuals only.");
			HeroAuraEnabled = Module(cfg, "Cosmetics", "HeroAuraEnabled", def: true, "HeroAura", "Give enemy souls a red-purple aura (soft halo, light rays, sparkles and a light) while a ping is on the soul. Local visuals only. Applies on game restart.");
			UpgradesListScaleEnabled = Module(cfg, "HUD", "UpgradesListScaleEnabled", def: true, "UpgradesListScale", "Shrink the native UPGRADES list (names and level numbers together) just enough to fit on screen when a modded run has more upgrades than fit. Short lists stay full size. Local only.");
			FailVoteEnabled = Module(cfg, "Run", "FailVoteEnabled", def: true, "FailVote", "When everyone dies on a level, vote for 15 seconds: [1] restart the level or [2] a random map, instead of going to the death arena. Closes early when everyone has voted; a tie or no votes restarts. HOST-SIDE.");
			HostRunControlsEnabled = Module(cfg, "Run", "HostRunControlsEnabled", def: true, "HostRunControls", "Host-only Esc menu buttons: RESTART LEVEL (on levels) and RETURN TO LOBBY (keeps everyone together; saves first in the shop). Both ask for a second click.");
			PlayerRestartVoteEnabled = cfg.Bind<bool>("Run", "PlayerRestartVoteEnabled", true, "Any player can call a 20-second vote from the Esc menu on a level: [1] restart this map, [2] a random map, [3] keep playing. The level restarts only if more than half of all players vote for a restart; one vote a minute. The host's setting decides (a player who turns it off also hides the button for themself).");
			TestShortcuts.Bind(cfg);
			LateJoinEnabled = Module(cfg, "Late Join", "Enabled", def: true, "LateJoin", "Host keeps the room/lobby joinable during a run/shop/truck (REPO normally seals it at run start) and re-syncs mod state to anyone who connects mid-game.");
			PingEnabled = Module(cfg, "Ping", "Enabled", def: true, "Ping", "Enable the ping system: press the ping key to mark what you're looking at for the whole team.");
			PingUnderglowEnabled = Module(cfg, "Ping", "UnderglowEnabled", def: true, "PingUnderglow", "Pinged loot, items, carts and other physical objects get a neon underglow in the ping colour: coloured light on the floor beneath them for as long as the ping lasts. Local visuals only.");
			ItemUnstuckEnabled = Module(cfg, "Item Unstuck", "Enabled", def: true, "ItemUnstuck", "Master switch for the valuable safety-net features (relocate stuck loot, invulnerable-until-grab, undamaged-value HUD). The relocate/invuln parts are HOST-SIDE (computed by the host).");
			ChallengesEnabled = Module(cfg, "Challenges", "Enabled", def: true, "Challenges", "Run levels may get a challenge shrine: crouch on it to start a timed challenge (wisp escort, target practice, hunt, cull or smash). Winning gives a skill point for everyone, an upgrade or a cosmetic box. Host-side.");
			LootSafetyNetEnabled = Module(cfg, "Loot Safety Net", "Enabled", def: true, "LootSafetyNet", "Host-side: while an extraction point is open and the loot the team can reach is not enough to fill it, spawn more (replaces the game's own top-up, which also counts loot nobody can reach). Everyone gets a notice.");
			SpectatorMapConfig spectatorMapConfig = SpectatorMapConfig.Bind(cfg);
			SpectatorMapEnabled = spectatorMapConfig.Enabled;
			SpectatorMapHoldKey = spectatorMapConfig.HoldKey;
			SpectatorMapScreenFraction = spectatorMapConfig.ScreenFraction;
			RoundResultsEnabled = Module(cfg, "Round Results", "Enabled", def: true, "RoundResults", "After each level show an MVP / OOPS CHAMP screen with per-player stats: loot broken, loot delivered, deaths and revives. Stats are recorded by the host, so the host must run this mod for the board to appear.");
			MapVoteEnabled = Module(cfg, "Map Vote", "Enabled", def: true, "MapVote", "While in the truck lobby, let players vote on the next map from a few random candidates. Whatever is leading when the truck departs is used instead of the game's random pick. Vote with the number keys (or the on-screen buttons). If nobody votes, the game's normal random selection is used, so this is harmless when ignored. HOST-SIDE: the host applies the winning map and syncs it to everyone normally.");
			AutoBackupEnabled = Module(cfg, "Auto Backup Saves", "Enabled", def: true, "AutoBackup", "Create extra snapshots when REPO would delete a run. Snapshots are never pruned. The original checkpoint is always protected, even if this module is disabled. Legacy KeepSaveLoadable and MaxBackupsPerSave settings are ignored.");
			VoiceRecoveryEnabled = Module(cfg, "Voice Recovery", "Enabled", def: true, "VoiceRecovery", "Retry failed local microphone capture up to three times per voice object. Does not override mute or push-to-talk. Restarts voice streams after audio device changes.");
			InventorySlotsEnabled = Module(cfg, "Player Upgrades", "InventorySlotsEnabled", def: true, "InventorySlots", "Sell Inventory Slot upgrades: +1 slot per level, up to seven total slots (four upgrade levels). Requires PlayerUpgrades and REPOLib.");
			MorePlayersEnabled = Module(cfg, "More Players", "Enabled", def: false, "MorePlayers", "Raise the room's max player count above REPO's default of 6. HOST-SIDE: the host's value defines the room cap; joiners don't need this on. Everyone in the lobby should still run the mod to avoid desync.");
			ShopPriceScaleEnabled = Module(cfg, "Shop", "PriceScaleEnabled", def: false, "ShopPriceScale", "Scale shop item prices up with the number of players, so bigger lobbies (which earn more) still feel expensive. HOST-SIDE: prices are computed by the host and synced.");
			ShoppingListEnabled = Module(cfg, "Shopping List", "Enabled", def: false, "ShoppingList", "While in the shop, show a panel listing everything in the cart (yours and your friends'): quantity, name and summed price per item, colour-coded by item type, with a running total vs. your team's currency.");
			LevelInfoEnabled = Module(cfg, "Level Info", "Enabled", def: true, "LevelInfo", "Show a panel on the right side of the screen that logs each level change (run number + name, plus any rolled surprise modifiers).");
			ServerInfoEnabled = Module(cfg, "Server Info", "Enabled", def: true, "ServerInfo", "Show a passive overlay in the lobby/menu with the current Photon region, ping, room code and player count. Reads connection state only — never opens sockets, so it's safe on the main menu.");
		}

		private static ConfigEntry<bool> Module(ConfigFile cfg, string oldSection, string oldKey, bool def, string key, string desc)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			ConfigDefinition val = new ConfigDefinition("Modules", key);
			Dictionary<ConfigDefinition, string> dictionary = Orphans(cfg);
			bool num = dictionary?.ContainsKey(val) ?? false;
			ConfigEntry<bool> val2 = cfg.Bind<bool>(val, def, new ConfigDescription(desc, (AcceptableValueBase)null, Array.Empty<object>()));
			if (!num && dictionary != null && dictionary.TryGetValue(new ConfigDefinition(oldSection, oldKey), out var value))
			{
				((ConfigEntryBase)val2).SetSerializedValue(value);
			}
			return val2;
		}

		private static Dictionary<ConfigDefinition, string> Orphans(ConfigFile cfg)
		{
			return cfg.OrphanedEntries;
		}

		public static void Init(ConfigFile cfg)
		{
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Expected O, but got Unknown
			//IL_05de: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e8: Expected O, but got Unknown
			//IL_1ed3: Unknown result type (might be due to invalid IL or missing references)
			//IL_1eda: Expected O, but got Unknown
			//IL_1f0f: Unknown result type (might be due to invalid IL or missing references)
			//IL_1f19: Expected O, but got Unknown
			//IL_1f39: Unknown result type (might be due to invalid IL or missing references)
			//IL_1f45: Expected O, but got Unknown
			BindModules(cfg);
			NetworkDiagnosticsEnabled = cfg.Bind<bool>("Voice Recovery", "NetworkDiagnostics", false, "Log actual Photon room RTT, jitter and cumulative reliable resends once per minute. Does not change transport or region.");
			AudioRecoveryKey = cfg.Bind<KeyCode>("Voice Recovery", "RecoveryKey", (KeyCode)290, "Hold Left Ctrl and press this key to reset Unity audio and restart voice streams locally. Briefly interrupts sound. None disables the shortcut.");
			RampStartLevel = BindInt(cfg, "General", "RampStartLevel", 4, 0, 30, "Completed-level offset for the difficulty ramp. The first boost lands on the first completed level after RampStartLevel, then one more every RampLevelsPerStep levels (start 1, step 3: boosts at 2, 5, 8 completed levels). With start 4 and step 1, the first boost is at 5 completed levels (the sixth playable level).");
			RampLevelsPerStep = BindInt(cfg, "General", "RampLevelsPerStep", 1, 1, 10, "How many levels of depth make up ONE difficulty step. 1 = stats grow every level; 2 = stats step up only every 2nd level past the start (stretches the ramp).");
			EnemyHealthPerLevel = BindFloat(cfg, "Enemies", "HealthPerLevel", 0.15f, 0f, 2f, "Extra enemy max HP per level past the ramp start. 0.15 = +15% per level (cumulative, additive).");
			EnemyHealthMax = BindFloat(cfg, "Enemies", "HealthMaxMultiplier", 3f, 1f, 20f, "Global upper cap on the depth HP multiplier, before level surprises. Per-enemy overrides take precedence. 3.0 = at most 3x native HP from the depth ramp.");
			EnemyHealthMaxPerEnemy = cfg.Bind<string>("Enemies", "HealthMaxPerEnemy", "Elsa:1.75, Loom:1.75, Trudge:2.25", new ConfigDescription("Per-enemy HP cap overrides. Format: 'Name:multiplier, Name:multiplier'. Names match EnemyParent.enemyName (case-insensitive). A cap of 1 EXCLUDES that enemy from HP scaling. Defaults: Elsa and Loom up to x1.75, Trudge up to x2.25. Unlisted enemies use HealthMaxMultiplier. Enable LogEnemyNames to see exact names.", (AcceptableValueBase)null, new object[1] { "HideFromREPOConfig" }));
			LogEnemyNames = cfg.Bind<bool>("Enemies", "LogEnemyNames", true, "Log each enemy's internal name the first time it spawns, so you can tune HealthMaxPerEnemy.");
			EnemyDamagePerLevel = BindFloat(cfg, "Enemies", "DamagePerLevel", 0.07f, 0f, 2f, "Extra enemy attack damage per level past the ramp start. 0.07 = +7% per level.");
			EnemyDamageMax = BindFloat(cfg, "Enemies", "DamageMaxMultiplier", 3f, 1f, 20f, "Upper cap on the enemy damage multiplier.");
			EnemySpeedPerLevel = BindFloat(cfg, "Enemies", "SpeedPerLevel", 0.06f, 0f, 1f, "Extra enemy movement speed per level past the ramp start. 0.06 = +6% per level.");
			EnemySpeedMax = BindFloat(cfg, "Enemies", "SpeedMaxMultiplier", 1.25f, 1f, 4f, "Upper cap on the enemy speed multiplier. Keep modest; too high makes enemies uncatchable/janky.");
			EnemyRespawnFasterPerLevel = BindFloat(cfg, "Enemies", "RespawnFasterPerLevel", 0.08f, 0f, 1f, "How much shorter the enemy respawn wait gets per level. 0.08 = -8% wait per level.");
			EnemyRespawnMinFactor = BindFloat(cfg, "Enemies", "RespawnMinFactor", 0.3f, 0.05f, 1f, "Floor for the respawn-wait multiplier. 0.3 = respawn wait never drops below 30% of vanilla.");
			QuotaPerLevel = BindFloat(cfg, "Quota", "QuotaPerLevel", 0.07f, 0f, 2f, "Extra extraction quota per level past the ramp start. 0.07 = +7% per level.");
			QuotaMax = BindFloat(cfg, "Quota", "QuotaMaxMultiplier", 5f, 1f, 20f, "Upper cap on the quota multiplier.");
			QuotaMaxLootFraction = BindFloat(cfg, "Quota", "QuotaMaxLootFraction", 0.9f, 0.1f, 1f, "Quota can never exceed this fraction of the total loot value on the level (keeps levels beatable). 0.9 = at most 90%.");
			FragileLootFactor = BindFloat(cfg, "Modifier Tuning", "FragileLootFactor", 2f, 0.1f, 10f, "FragileLoot: multiplies loot fragility. >1 = breaks more easily. 2.0 = twice as fragile.");
			ProtectedLootFactor = BindFloat(cfg, "Modifier Tuning", "ProtectedLootFactor", 0.4f, 0.1f, 10f, "ProtectedLoot: multiplies loot fragility. <1 = harder to break. 0.4 = 60% less fragile.");
			HeavyLootFactor = BindFloat(cfg, "Modifier Tuning", "HeavyLootFactor", 1.75f, 0.1f, 10f, "HeavyLoot: multiplies loot mass. >1 = heavier.");
			LightLootFactor = BindFloat(cfg, "Modifier Tuning", "LightLootFactor", 0.5f, 0.1f, 10f, "LightLoot: multiplies loot mass. <1 = lighter.");
			LightMonsterMaxMass = BindFloat(cfg, "Modifier Tuning", "LightMonsterMaxMass", 3f, 0.1f, 50f, "LightMonsters: cap every monster's mass at this value, including late spawns. A held monster stops fighting the grab so one player without Strength upgrades can lift it. Frozen monsters remain unliftable.");
			HeavyMonsterMinMass = BindFloat(cfg, "Modifier Tuning", "HeavyMonsterMinMass", 7f, 0.1f, 50f, "HeavyMonsters: raise every monster's mass to at least this value (heavier = harder to move).");
			BiggerSoulDropsFactor = BindFloat(cfg, "Modifier Tuning", "BiggerSoulDropsFactor", 2f, 0.1f, 10f, "BiggerSoulDrops: multiplies the money value of each enemy soul drop. 2.0 = each drop worth twice as much. Does not change drop count.");
			MonsterPitDamageFactor = BindFloat(cfg, "Modifier Tuning", "MonsterPitDamageFactor", 0.5f, 0f, 5f, "MonstersPitTanky: multiplies death-pit chip damage dealt to monsters (moon 2+). 0.5 = monsters take half pit damage. Instant-kill pits on early moons are unaffected.");
			ExtraGachaCubesPerSpawn = BindInt(cfg, "Modifier Tuning", "ExtraGachaCubesPerSpawn", 1, 0, 10, "MoreGachaCubes: how many additional cosmetic 'gacha' cubes to spawn per cube the game would normally place. Capped by the level's available spawn spots. 1 = roughly double.");
			DangerousLootDamageFactor = BindFloat(cfg, "Modifier Tuning", "DangerousLootDamageFactor", 2f, 0.1f, 10f, "DangerousLoot: multiplies the damage hazardous valuables (cursed dolls, radioactive cups, barrels, saws, etc.) deal to players. 2.0 = double damage.");
			SoulsExplodeHarderFactor = BindFloat(cfg, "Modifier Tuning", "SoulsExplodeHarderFactor", 2f, 0.1f, 10f, "SoulsExplodeHarder: multiplies the player damage of enemy-soul explosions (moon 4+). 2.0 = double explosion damage.");
			ThornyMonstersChance = BindFloat(cfg, "Modifier Tuning", "ThornyMonstersChance", 0.5f, 0f, 1f, "ThornyMonsters: chance that each monster on the level has thorns. 0.5 = about half of them.");
			ThornyMonstersMaxReflect = BindFloat(cfg, "Modifier Tuning", "ThornyMonstersMaxReflect", 0.1f, 0f, 0.5f, "ThornyMonsters: the most of a melee hit a thorny monster reflects to the attacker. Each thorny monster rolls between a third of this and this.");
			SpreadUpgradesCount = BindInt(cfg, "Modifier Tuning", "SpreadUpgradesCount", 3, 0, 6, "SpreadUpgrades: at most six pickups across the entire map. Submit them with a successful quota to receive them in the next truck.");
			MysteryBoxCount = BindInt(cfg, "Modifier Tuning", "MysteryBoxCount", 3, 1, 8, "MysteryBoxes: how many mystery boxes are placed across the map. They use navigation points, never valuable spawn spots. Each box accepts one soul.");
			MysteryBoxMoneyMin = BindInt(cfg, "Modifier Tuning", "MysteryBoxMoneyMin", 3000, 1000, 100000, "MysteryBoxes: smallest money prize in dollars, before depth scaling. Paid to the team wallet in whole $1K.");
			MysteryBoxMoneyMax = BindInt(cfg, "Modifier Tuning", "MysteryBoxMoneyMax", 9000, 1000, 200000, "MysteryBoxes: largest money prize in dollars, before depth scaling (deeper levels pay a little more).");
			MysteryBoxWeightUpgrade = BindInt(cfg, "Modifier Tuning", "MysteryBoxWeightUpgrade", 35, 0, 100, "MysteryBoxes: relative chance of a random upgrade pickup (maxed upgrades are skipped).");
			MysteryBoxWeightMoney = BindInt(cfg, "Modifier Tuning", "MysteryBoxWeightMoney", 30, 0, 100, "MysteryBoxes: relative chance of a money prize.");
			MysteryBoxWeightCostume = BindInt(cfg, "Modifier Tuning", "MysteryBoxWeightCostume", 15, 0, 100, "MysteryBoxes: relative chance of a costume piece: every player unlocks one of the mod's costume parts they don't own yet.");
			CostumeRewardsEnabled = cfg.Bind<bool>("Quests", "CostumeRewardsEnabled", true, "Costume pieces as rewards: challenge shrines, mystery boxes, special contracts and rank A+ quests can give every player one of the mod's costume parts they don't own yet (a Rare cosmetic token once they own them all).");
			MysteryBoxWeightWeapon = BindInt(cfg, "Modifier Tuning", "MysteryBoxWeightWeapon", 35, 0, 100, "MysteryBoxes: relative chance of a weapon or grenade that only exists on this level (it is not added to your saved items).");
			SpreadUpgradesAllowed = cfg.Bind<string>("Modifier Tuning", "SpreadUpgradesAllowed", "", new ConfigDescription("SpreadUpgrades: comma-separated list of upgrade item names allowed to be scattered (case-insensitive, substring match against the item's internal name). Empty = any upgrade. Enable LogSpreadUpgradeNames to print the exact names to the log.", (AcceptableValueBase)null, new object[1] { "HideFromREPOConfig" }));
			LogSpreadUpgradeNames = cfg.Bind<bool>("Modifier Tuning", "LogSpreadUpgradeNames", false, "Log the internal names of all upgrade items the first time a SpreadUpgrades level generates, so you can fill in SpreadUpgradesAllowed.");
			AutoReviveAtCar = cfg.Bind<bool>("Modifier Tuning", "AutoReviveAtCar", true, "AutoRevive: bring the auto-revived player back at the level's spawn point (the truck/car drop-off) and fully heal them, instead of reviving them on the spot where they died. Still only one auto-revive per player per level.");
			LevelTimerSeconds = BindFloat(cfg, "Modifier Tuning", "LevelTimerStartSeconds", 420f, 30f, 1800f, "LevelTimer: starting countdown in seconds. When it hits 0 the level restarts and rerolls to a fresh layout (progress is not lost, the level is just regenerated).");
			LevelTimerKillBonus = BindFloat(cfg, "Modifier Tuning", "LevelTimerKillSeconds", 60f, 0f, 300f, "LevelTimer: seconds added to the clock for each enemy killed.");
			LevelTimerDeathPenalty = BindFloat(cfg, "Modifier Tuning", "LevelTimerDeathPenalty", 30f, 0f, 300f, "LevelTimer: seconds removed from the clock each time a player dies.");
			LevelTimerQuotaBonus = BindFloat(cfg, "Modifier Tuning", "LevelTimerQuotaSeconds", 120f, 0f, 600f, "LevelTimer: seconds added when an extraction point's quota is completed.");
			PingKey = cfg.Bind<KeyCode>("Ping", "PingKey", (KeyCode)325, "Key/button to place a ping on whatever you're aiming at (default: middle mouse).");
			PingMaxDistance = BindFloat(cfg, "Ping", "MaxDistance", 60f, 5f, 200f, "Maximum distance the ping raycast reaches. Beyond this a ping is placed in mid-air along your aim.");
			PingDurationSeconds = BindFloat(cfg, "Ping", "DurationSeconds", 4f, 1f, 30f, "How long a ping marker stays visible (seconds).");
			PingMarkerScale = BindFloat(cfg, "Ping", "MarkerScale", 1f, 0.5f, 2.5f, "Scale of the large cyan location ring and arrow. Object silhouettes retain their actual size.");
			PingSoundVolume = BindFloat(cfg, "Ping", "SoundVolume", 0.28f, 0f, 1f, "Volume of distinct target-type ping cues through the game's mixer. 0 mutes ping sounds.");
			MaxLocationPings = BindInt(cfg, "Ping", "MaxLocationPings", 3, 1, 20, "Maximum live Location pings a single player can have at once (needs the 'Ping Anywhere' upgrade). Placing more drops your oldest.");
			MaxActivePings = BindInt(cfg, "Ping", "MaxActivePings", 3, 1, 20, "Global anti-flood cap: the most ping markers shown on screen at once (across all players). Placing more drops the oldest.");
			ValuableRelocateStuck = cfg.Bind<bool>("Item Unstuck", "RelocateStuck", true, "Recover valuables embedded in geometry or wedged in a frame while a player tries to pull them free. Uses a collision-checked nearby position or a validated previous safe spot. Host-side.");
			ValuableStuckSeconds = BindFloat(cfg, "Item Unstuck", "StuckSeconds", 6f, 2f, 60f, "Seconds an embedded valuable must remain settled, or a wedged valuable must resist a sustained grab, before a recovery is attempted.");
			ValuableInvulnerableUntilGrab = cfg.Bind<bool>("Item Unstuck", "InvulnerableUntilGrab", true, "Valuables take no damage / lose no value until a player grabs them for the first time (uses the game's own indestructible flag). Host-side.");
			ChallengeChancePercent = BindFloat(cfg, "Challenges", "ShrineChancePercent", 100f, 0f, 100f, "Chance that a run level gets a challenge shrine.");
			LootSafetyMinPlayerDistance = BindFloat(cfg, "Loot Safety Net", "MinPlayerDistance", 20f, 0f, 60f, "New loot prefers spawn spots at least this far (metres) from every player, like the game's own top-up. Closer spots are used only when no far spot is free.");
			LootSafetyMaxSpawns = BindInt(cfg, "Loot Safety Net", "MaxSpawnsPerTopUp", 25, 1, 100, "Most valuables one top-up may spawn.");
			LootSafetyRevealOnMap = cfg.Bind<bool>("Loot Safety Net", "RevealOnMap", true, "Mark the new loot on the map right away so players can find it.");
			LootSafetyLog = cfg.Bind<bool>("Loot Safety Net", "DiagnosticLog", true, "While an extraction point is open, log the loot count against its goal about once a minute, plus every top-up and the loot it did not count.");
			QuestsEnabled = cfg.Bind<bool>("Quests", "Enabled", true, "Enable the quest progression layer: each run level offers 2-3 team quests plus a personal quest, scaled to team size / day / your contract rank. Completing quests advances your rank (F..SSS) and pays money or upgrade items. Team quests are rolled by the host and synced to everyone.");
			QuestPeekKey = cfg.Bind<KeyCode>("Quests", "PeekKey", (KeyCode)106, "Press this key to show/hide the quest tracker (default J). Quests are shown by default; your choice is kept between levels.");
			QuestsPerLevelMin = BindInt(cfg, "Quests", "QuestsPerLevelMin", 2, 1, 5, "Minimum number of TEAM quests offered per level.");
			QuestsPerLevelMax = BindInt(cfg, "Quests", "QuestsPerLevelMax", 3, 1, 5, "Maximum number of TEAM quests offered per level.");
			QuestCompletionsPerRank = BindInt(cfg, "Quests", "CompletionsPerRank", 10, 1, 100, "How many quest completions advance your contract rank by one for the LOWER ranks (F->E->D->C->B->A). 10 = ten quests per step. The top ranks use their own larger requirements below.");
			QuestCompletionsAtoS = BindInt(cfg, "Quests", "CompletionsAtoS", 40, 1, 500, "How many quest completions are required to advance from rank A to rank S.");
			QuestCompletionsStoSS = BindInt(cfg, "Quests", "CompletionsStoSS", 42, 1, 500, "How many quest completions are required to advance from rank S to rank SS.");
			QuestCompletionsSStoSSS = BindInt(cfg, "Quests", "CompletionsSStoSSS", 50, 1, 500, "How many quest completions are required to advance from rank SS to rank SSS.");
			QuestMoneyBase = BindInt(cfg, "Quests", "MoneyRewardBase", 3000, 0, 1000000, "Base money reward for a quest at rank F / one player. It scales up with team size (+25% per extra player), day, and rank.");
			QuestSkillPoints = BindInt(cfg, "Quests", "SkillPointReward", 1, 0, 10, "Skill points every finished quest gives on top of its normal reward. Team quests give them to every player, personal quests to you. 0 = none.");
			QuestSkillPointsHighRank = BindInt(cfg, "Quests", "SkillPointRewardSSPlus", 2, 0, 10, "Skill points a finished quest gives at contract rank SS and SSS instead.");
			QuestSkillPointChance = BindFloat(cfg, "Quests", "SkillPointChance", 0.35f, 0f, 1f, "Chance that a quest comes with skill points at rank F; +5% per contract rank, at most 75%. Funny quests and contracts never give points.");
			QuestContractChance = BindFloat(cfg, "Quests", "ContractChance", 0.35f, 0f, 1f, "Chance per level of a special CONTRACT quest: harder, and it gives every player a level of a quest-only skill tree perk (Contracts page).");
			SkillBoxesEnabled = cfg.Bind<bool>("Skill Boxes", "Enabled", true, "Small glowing boxes on every run level. Walk into one to open it: it gives you 0-3 skill points. Host setting.");
			SkillBoxMin = BindInt(cfg, "Skill Boxes", "MinPerLevel", 1, 0, 5, "Fewest skill boxes placed on a level.");
			SkillBoxMax = BindInt(cfg, "Skill Boxes", "MaxPerLevel", 5, 0, 5, "Most skill boxes placed on a level.");
			SkillBoxWeight0 = BindInt(cfg, "Skill Boxes", "Chance0Points", 65, 0, 100, "Weight of an empty box (0 points). Default 65 of 100.");
			SkillBoxWeight1 = BindInt(cfg, "Skill Boxes", "Chance1Point", 20, 0, 100, "Weight of a 1-point box. Default 20 of 100.");
			SkillBoxWeight2 = BindInt(cfg, "Skill Boxes", "Chance2Points", 10, 0, 100, "Weight of a 2-point box. Default 10 of 100.");
			SkillBoxWeight3 = BindInt(cfg, "Skill Boxes", "Chance3Points", 5, 0, 100, "Weight of a 3-point box. Default 5 of 100.");
			RetryCrystalsEnabled = cfg.Bind<bool>("Battery Crystals", "Enabled", true, "When a level is retried (restart, random map or timer reroll), small battery crystals lie around the map. HP and battery charge carry over between attempts, so walk into a crystal to top up your emptiest battery item. Host setting.");
			RetryCrystalMin = BindInt(cfg, "Battery Crystals", "MinPerLevel", 3, 0, 30, "Fewest battery crystals on a retried level (up to 30).");
			RetryCrystalMax = BindInt(cfg, "Battery Crystals", "MaxPerLevel", 8, 0, 30, "Most battery crystals on a retried level (up to 30; a small map may have room for fewer, they keep 4.5 m apart).");
			RetryCrystalCharge = BindFloat(cfg, "Battery Crystals", "ChargePercent", 20f, 1f, 100f, "Battery charge one crystal adds to the emptiest battery item you hold or carry (20 = about one bar of five).");
			QuestFunnyEnabled = cfg.Bind<bool>("Quests", "FunnyQuests", true, "Allow silly side-quests (talk to yourself, spin around, pay respects...). At most one per level, small cash reward, no skill points.");
			QuestItemRewardsEnabled = cfg.Bind<bool>("Quests", "ItemRewardsEnabled", true, "Allow higher-rank quests (rank C and above) to sometimes pay out a random upgrade item on the level instead of money.");
			QuestCosmeticRewardsEnabled = cfg.Bind<bool>("Quests", "CosmeticRewardsEnabled", true, "Allow higher-rank quests (rank C and above) to sometimes pay out a cosmetic 'gacha' box (a rarity cube to roll a skin) on the level instead of money. Higher ranks bias toward rarer boxes.");
			QuestExactUpgradeRewardsEnabled = cfg.Bind<bool>("Quests", "ExactUpgradeRewardsEnabled", true, "Allow higher-rank quests (rank C and above) to sometimes pay out a SPECIFIC upgrade item (e.g. a Health or Sprint Speed upgrade) on the level instead of money.");
			QuestShopItemRewardsEnabled = cfg.Bind<bool>("Quests", "ShopItemRewardsEnabled", true, "Allow higher-rank quests (rank C and above) to sometimes spawn a random general shop item (grenade, health pack, gun, tool, etc.) on the level instead of money.");
			QuestHealRewardsEnabled = cfg.Bind<bool>("Quests", "HealRewardsEnabled", true, "Allow higher-rank quests (rank C and above) to sometimes heal the whole squad instead of paying money.");
			QuestTempStatRewardsEnabled = cfg.Bind<bool>("Quests", "TempStatRewardsEnabled", true, "Allow higher-rank quests (rank C and above) to sometimes grant every player a TEMPORARY stat buff (stamina/sprint speed/extra jump/grab strength) that lasts only for the current level.");
			QuestHealAmount = BindInt(cfg, "Quests", "HealRewardAmount", 100, 1, 100, "How much HP a squad-heal quest reward restores to each player (capped at each player's max health).");
			RoundResultsSeconds = BindFloat(cfg, "Round Results", "ShowSeconds", 20f, 5f, 60f, "How long the results screen stays up after a level ends.");
			RoundResultsKey = cfg.Bind<KeyCode>("Round Results", "ToggleKey", (KeyCode)288, "Press to dismiss the results screen, or to bring the last results back.");
			DefenceAbsorb = BindInt(cfg, "Gear", "DefenceAbsorb", 450, 50, 2000, "Total damage a fully charged Defence DRONE can absorb for the player it is attached to.");
			DefenceItemAbsorb = BindInt(cfg, "Gear", "DefenceItemAbsorb", 10000, 100, 50000, "Defence ORB (protects loot): value, in dollars, a fully charged orb can absorb from valuables breaking inside its field. The Defence DRONE protects a player instead, see DefenceAbsorb.");
			DefenceDroneSeconds = BindFloat(cfg, "Gear", "DefenceDroneSeconds", 90f, 5f, 600f, "Defence DRONE: seconds from a full battery to empty while it is running, even if the player takes no damage (hits drain it faster).");
			DefenceIdleDrainPerMinute = BindFloat(cfg, "Gear", "DefenceIdleDrainPercentPerMinute", 10f, 0f, 60f, "Slow passive discharge of an active Defence ORB, in percent of battery per minute, applied whether or not it is taking hits (hits drain it further). 20 = about 5 minutes from full.");
			ProtectionReductionPercent = BindInt(cfg, "Gear", "ProtectionReductionPercent", 30, 5, 90, "Damage reduction inside an active Protection Orb.");
			PoisonHitDamage = BindInt(cfg, "Gear", "PoisonHitDamage", 7, 1, 100, "Direct damage of a poison bolt.");
			PoisonTotalDamage = BindInt(cfg, "Gear", "PoisonTotalDamage", 125, 1, 1000, "Smallest total poison damage over the full duration (the max-HP share below wins on tougher monsters).");
			PoisonMaxHpPercent = BindInt(cfg, "Gear", "PoisonMaxHpPercent", 15, 0, 100, "Total poison damage as a percent of the monster's max HP (after depth scaling). A fresh bolt also keeps half of the poison still left. 0 = flat PoisonTotalDamage only.");
			PoisonSeconds = BindFloat(cfg, "Gear", "PoisonSeconds", 15f, 1f, 60f, "Poison duration. Each hit refreshes it to this value (it does not stack).");
			IceFreezeSeconds = BindFloat(cfg, "Gear", "IceFreezeSeconds", 4.5f, 0.5f, 30f, "How long the Ice Pistol freezes a monster or player. Players receive a visible ice coating and movement pause without shot damage, including in the shop. Repeated hits refresh the timer.");
			IceGunDamagePercent = BindInt(cfg, "Gear", "IceGunDamagePercent", 75, 10, 100, "Firearm damage frozen enemies take, in percent of normal.");
			EliteMonstersEnabled = cfg.Bind<bool>("Monsters", "EliteMonsters", true, "From 16 completed levels some monsters roll one elite trait: Armored (30% less damage until stunned), Regenerating (heals after 5 quiet seconds) or Thorned (reflects 10% of melee damage). 10% of monsters at 16 levels, +3% per level, at most 40%. Pings with Monster Threat name the trait. Host setting.");
			MonstersEnabled = cfg.Bind<bool>("Monsters", "Enabled", true, "Let the director spawn the mod's new monsters (Golden Pig, Mischief Fairy, Witch, Basilisk, Hansel and Gretel, Gorgon, Naga Queen). Host setting.");
			PigEnabled = cfg.Bind<bool>("Monsters", "GoldenPig", true, "Golden flying pig (Tier I, neutral). At most one per level, rolled separately. Host setting.");
			WitchEnabled = cfg.Bind<bool>("Monsters", "Witch", true, "Witch (Tier II): fireball and electric levitation. Host setting.");
			BasiliskEnabled = cfg.Bind<bool>("Monsters", "Basilisk", true, "Basilisk (Tier II): ambush constriction and venom bite. Host setting.");
			GorgonEnabled = cfg.Bind<bool>("Monsters", "Gorgon", true, "Gorgon bull (Tier III): charge and death stare. Host setting.");
			NagaEnabled = cfg.Bind<bool>("Monsters", "NagaQueen", true, "Naga Queen (Tier III): sword combos, petrification and bleeding. Host setting.");
			FairyEnabled = cfg.Bind<bool>("Monsters", "MischiefFairy", true, "Mischief Fairy (Tier I, harmless): lifts light valuables out of carts and extraction points and carries them off. Host setting.");
			TwinsEnabled = cfg.Bind<bool>("Monsters", "HanselAndGretel", true, "Hansel and Gretel (Tier II): twins who seize a player between them and throw them. Host setting.");
			PigSpawnChance = BindFloat(cfg, "Monsters", "GoldenPigChance", 0.11f, 0f, 1f, "Chance per level that one Golden Pig appears (design: 10-12%).");
			DodgeKey = cfg.Bind<KeyCode>("Monsters", "DodgeRollKey", (KeyCode)308, "Key for the Dodge Roll perk (hold A or D for the direction). C, G and I are already used by the mod.");
			NewMonsterChance = BindFloat(cfg, "Monsters", "SlotChance", 0.2f, 0f, 1f, "Chance that each enemy slot of a level is filled by one of the mod's monsters of that tier (Fairy; Witch, Basilisk, Hansel and Gretel; Gorgon, Naga Queen) instead of a native one. 0.2 = about one slot in five; 0 = never. The Golden Pig rolls separately. Host setting.");
			MonsterRarity = BindInt(cfg, "Monsters", "Rarity", 100, 1, 100, "Maximum random selection score for each new monster, not a percentage or linear weight. Recommended: 100, matching common native presets. Lower scores can make a monster much rarer when many native candidates compete.");
			IceMeleeBonusPercent = BindInt(cfg, "Gear", "IceMeleeBonusPercent", 35, 0, 300, "Extra melee damage frozen enemies take, in percent.");
			DecoySeconds = BindFloat(cfg, "Gear", "DecoySeconds", 5f, 1f, 30f, "How long the Decoy Grenade attracts monsters once armed.");
			StickyFreeLiftMass = BindFloat(cfg, "Gear", "StickyFreeLiftMass", 10f, 1f, 100f, "Approximate mass (kg) a player with base grab strength can lift freely. The Sticky Pistol can pull things up to what ONE strength level less could lift.");
			LinkMaxDistance = BindFloat(cfg, "Drones", "LinkMaxDistance", 6f, 1f, 12f, "Link drone: maximum distance (metres) between the two attached objects for the cable to connect. The cable fits the gap when it connects.");
			SilencerNoiseMultiplier = BindFloat(cfg, "Drones", "SilencerNoiseMultiplier", 0.08f, 0.01f, 0.35f, "Silencer drone: multiplier applied to the attached target's emitted sound, voice and the radius enemies investigate it from. 0.08 = 8% as loud.");
			InventorySlot4Key = cfg.Bind<KeyCode>("Inventory Slots", "Slot4Key", (KeyCode)52, "Store/retrieve from inventory slot 4.");
			InventorySlot5Key = cfg.Bind<KeyCode>("Inventory Slots", "Slot5Key", (KeyCode)53, "Store/retrieve from inventory slot 5.");
			InventorySlot6Key = cfg.Bind<KeyCode>("Inventory Slots", "Slot6Key", (KeyCode)54, "Store/retrieve from inventory slot 6.");
			InventorySlot7Key = cfg.Bind<KeyCode>("Inventory Slots", "Slot7Key", (KeyCode)55, "Store/retrieve from inventory slot 7.");
			MapVoteHudKey = cfg.Bind<KeyCode>("Map Vote", "ToggleHudKey", (KeyCode)287, "Hide or show the local map-vote HUD without cancelling the vote. Number-key voting continues while hidden.");
			MapVoteChoices = BindInt(cfg, "Map Vote", "Choices", 3, 2, 6, "How many random candidate maps to offer for the vote each lobby.");
			MapVoteSeconds = BindFloat(cfg, "Map Vote", "Seconds", 60f, 10f, 300f, "How long the vote stays open (host-authoritative). It closes early the moment everyone in the lobby has voted. When it closes, the leading map is locked in and used when the truck departs. If nobody votes, the game's normal random selection is used.");
			LevelInfoToggleKey = cfg.Bind<KeyCode>("Level Info", "ToggleKey", (KeyCode)289, "Key to hide/show the level info announcement.");
			MorePlayersMax = BindInt(cfg, "More Players", "MaxPlayers", 6, 2, 20, "Maximum players allowed in the room when More Players is enabled. REPO supports up to 20 internally. Large lobbies are unofficial and may be unstable.");
			ShopPriceBaselinePlayers = BindInt(cfg, "Shop", "PriceBaselinePlayers", 4, 1, 20, "Player count at which prices are unchanged. Each player above this raises prices by PricePerExtraPlayer; at or below it, prices are vanilla.");
			ShopPricePerExtraPlayer = BindFloat(cfg, "Shop", "PricePerExtraPlayer", 0.15f, 0f, 2f, "Extra shop price per player above the baseline. 0.15 = +15% per extra player (e.g. 8 players with baseline 4 = +60%).");
			FlashStunKey = cfg.Bind<KeyCode>("Skill Tree", "FlashStunKey", (KeyCode)102, "Flash Stun perk: flares your flashlight to stun monsters in the beam.");
			FlashStunSeconds = BindFloat(cfg, "Skill Tree", "FlashStunSeconds", 2f, 0.5f, 6f, "How long Flash Stun stuns monsters in the beam. Host setting.");
			FlashStunCooldown = BindFloat(cfg, "Skill Tree", "FlashStunCooldown", 45f, 5f, 300f, "Seconds between Flash Stun uses. Host setting.");
			SkillPageBonuses = cfg.Bind<bool>("Skill Tree", "PageBonuses", true, "Every 5 points spent on a skill tree page's perks give +1 level of its main stats, like a shop upgrade, up to each stat's cap: Combat Power +5, Survival Health +5, Recon Sprint Speed +3, Courier Stamina +5 and Crouch Rest +3, Arsenal Tumble Launch +3, Utility Range +3 and Death Head Battery +5. Host setting.");
			ShopExtraItems = BindInt(cfg, "Shop", "ExtraItems", 4, 0, 20, "Extra different regular items (weapons, tools, drones...) stocked per shop visit on top of the game's 8. Never copies of the same item; they go on free shelf slots, using a bigger free slot when no slot of their own size is left.");
			TruckHealPercentPerLevel = BindFloat(cfg, "Truck Upgrades", "HealBonusPerLevel", 0.05f, 0f, 1f, "Heal Power: the truck heal is multiplied by (1 + p) per level, compounding. Multiplier = (1 + p)^level. At p=0.05, a 35 HP heal becomes 36.75 / 38.59 / 40.52 at levels 1/2/3 (truck heal only).");
			TruckHealMaxLevel = BindInt(cfg, "Truck Upgrades", "HealPowerMaxLevel", 10, 0, 20, "Heal Power: maximum purchasable level.");
			TruckHealBaseCost = BindInt(cfg, "Truck Upgrades", "HealBaseCost", 10000, 0, 1000000, "Heal Power: cost of the first level (grows by CostGrowth each level).");
			TruckChargePercentPerLevel = BindFloat(cfg, "Truck Upgrades", "ChargeReductionPerLevel", 0.05f, 0f, 0.95f, "Charge Efficiency: multiply remaining energy-pool drain by (1-p) per level, compounding like Slower Stamina Use, with a 5% minimum. At p=0.05, levels 1/2/3 spend 95%/90.25%/85.7% of normal energy.");
			TruckChargeMaxLevel = BindInt(cfg, "Truck Upgrades", "ChargePowerMaxLevel", 10, 0, 20, "Charge Efficiency: maximum purchasable level.");
			TruckChargeBaseCost = BindInt(cfg, "Truck Upgrades", "ChargeBaseCost", 10000, 0, 1000000, "Charge Efficiency: cost of the first level (grows by CostGrowth each level).");
			TruckSellCost = BindInt(cfg, "Truck Upgrades", "SellUnlockCost", 50000, 0, 1000000, "Loot Cash-In: one-time cost to unlock selling leftover valuables after all quotas are closed.");
			TeamHaggleCost = BindInt(cfg, "Truck Upgrades", "HagglingCost", 45000, 0, 1000000, "Haggling (whole team, 3 levels): cost of the first level. Each level gives the shopkeeper robot one more discount attempt per shop visit (3 -> 6).");
			TeamCrystalCost = BindInt(cfg, "Truck Upgrades", "CrystalStockCost", 15000, 0, 1000000, "Crystal Stock (whole team, 3 levels): cost of the first level. The shop stocks 6 / 7 / 8 power crystals at once, never more than the truck needs for a full charge.");
			TeamSpareGunCost = BindInt(cfg, "Truck Upgrades", "SpareGunCost", 25000, 0, 1000000, "Spare Gun (whole team, one level): every gun and launcher can be bought one more time.");
			TeamSpareMeleeCost = BindInt(cfg, "Truck Upgrades", "SpareMeleeCost", 15000, 0, 1000000, "Spare Melee (whole team, one level): every melee weapon can be bought one more time.");
			TeamSpareDroneCost = BindInt(cfg, "Truck Upgrades", "SpareDroneCost", 25000, 0, 1000000, "Spare Drone (whole team, one level): every drone can be bought one more time.");
			TeamShelfCost = BindInt(cfg, "Truck Upgrades", "UpgradeShelfCost", 20000, 0, 1000000, "Upgrade Shelf (whole team, 4 levels): cost of the first level. Two more upgrades in the shop per level (up to +8).");
			TruckSellFraction = BindFloat(cfg, "Truck Upgrades", "SellFraction", 0.75f, 0f, 1f, "Loot Cash-In: fraction of a leftover valuable's value returned as currency when sold. 0.75 = 75%.");
			TruckSellMaxQuotaSh