Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of IncreaseDifficultyMod v0.7.1
plugins/IncreaseDifficultyMod/IncreaseDifficultyMod.dll
Decompiled 13 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net.Sockets; 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.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using IncreaseHardMod.Drones; using IncreaseHardMod.Economy; using IncreaseHardMod.Gear; using IncreaseHardMod.Modifiers; using IncreaseHardMod.Networking; using IncreaseHardMod.Patches.Effects; using IncreaseHardMod.Quests; using IncreaseHardMod.Upgrades; 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 TMPro; using UnityEngine; using UnityEngine.AI; using UnityEngine.Events; 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: AssemblyCompany("IncreaseDifficultyMod")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.7.1.0")] [assembly: AssemblyInformationalVersion("0.7.1+b0a316b1a3b744519027bf7a5194e965bded0d66")] [assembly: AssemblyProduct("IncreaseDifficultyMod")] [assembly: AssemblyTitle("IncreaseDifficultyMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.7.1.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; } } 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_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Expected O, but got Unknown //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Expected O, but got Unknown //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Expected O, but got Unknown //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Expected O, but got Unknown //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Expected O, but got Unknown Dictionary<ConfigDefinition, string> orphans = typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(cfg) as Dictionary<ConfigDefinition, string>; 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 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 => 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) { 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)) * Stat(StatAxis.EnemyHealth); } 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<int> SpreadUpgradesCount; 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<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<int> PingAnywhereBasePrice; public static ConfigEntry<int> PingInfoBasePrice; public static ConfigEntry<bool> ItemUnstuckEnabled; public static ConfigEntry<bool> ValuableRelocateStuck; public static ConfigEntry<float> ValuableStuckSeconds; public static ConfigEntry<bool> ValuableInvulnerableUntilGrab; 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<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<int> InventorySlotBasePrice; 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> 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<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<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> 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> PhotonHudEnabled; public static ConfigEntry<string> PhotonHudRegions; 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<float> TruckSellFraction; public static ConfigEntry<bool> PlayerUpgradesEnabled; public static ConfigEntry<float> StaminaPercentPerLevel; public static ConfigEntry<int> StaminaMaxLevel; public static ConfigEntry<int> StaminaBasePrice; public static ConfigEntry<float> RegenPercentPerLevel; public static ConfigEntry<float> RegenMaxHpFraction; public static ConfigEntry<int> RegenMaxLevel; public static ConfigEntry<int> RegenBasePrice; public static ConfigEntry<int> DeathProtectMaxCharges; public static ConfigEntry<int> DeathProtectBasePrice; public static ConfigEntry<float> GunBatteryPercentPerLevel; public static ConfigEntry<int> GunBatteryMaxLevel; public static ConfigEntry<int> GunBatteryBasePrice; public static ConfigEntry<float> DroneBatteryPercentPerLevel; public static ConfigEntry<int> DroneBatteryMaxLevel; public static ConfigEntry<int> DroneBatteryBasePrice; public static ConfigEntry<float> AutoscanRangePerLevel; public static ConfigEntry<int> AutoscanMaxLevel; public static ConfigEntry<float> AutoscanInterval; public static ConfigEntry<int> AutoscanBasePrice; public static ConfigEntry<int> MapBasePrice; public static ConfigEntry<float> MapZoomFovLevel7; public static ConfigEntry<float> MapZoomFovLevel8; public static ConfigEntry<KeyCode> MapZoomInKey; public static ConfigEntry<KeyCode> MapZoomOutKey; public static ConfigEntry<float> MapZoomStep; public static ConfigEntry<bool> MapSuiteReplacesVanilla; 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<int> ShopDuplicatesExtra; public static ConfigEntry<bool> DiagnosticDisablePatches; public static ConfigEntry<bool> DiagnosticDisableRuntimeObjects; private const string HideFromRepoConfig = "HideFromREPOConfig"; private static Dictionary<string, float> _perEnemyHealthMax = new Dictionary<string, float>(); 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 => "Upgrade pickups are scattered around; usable only back in the 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.", _ => $"The '{m}' surprise modifier.", }; } private static void BindModules(ConfigFile cfg) { 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", "Moon phases advance every MoonLevelsPerPhase levels instead of every 5 (slows the moon-based difficulty)."); 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 keep a surprise modifier, level economy or shop economy from ever being rolled again this run. 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). 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) to block a surprise modifier. Scaled by how harmful it is and by depth."); 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.02f, 0f, 0.5f, "Valuable value growth per level (compounding). 0.02 = x1.02 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 a level can have."); MoonLevelsPerPhase = BindInt(cfg, "Level Scaling", "MoonLevelsPerPhase", 15, 5, 60, "With ScaleMoon on: levels per moon phase (vanilla is 5)."); 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."); 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."); 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."); 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)."); 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."); PhotonHudEnabled = Module(cfg, "Photon HUD", "Enabled", def: false, "PhotonHud", "OPT-IN DIAGNOSTIC (default off). Show a small overlay on the main menu with reachability/latency to Photon region name servers. Leave this OFF for normal play: it TCP-probes the same Photon name servers the game uses, and that connection churn can stall REPO's own 'pick best region' step (regions spin forever / stuck loading online). Only enable it briefly when you're actively diagnosing a connection problem."); } 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 typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(cfg) as Dictionary<ConfigDefinition, string>; } public static void Init(ConfigFile cfg) { //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Expected O, but got Unknown //IL_04bd: Unknown result type (might be due to invalid IL or missing references) //IL_04c7: Expected O, but got Unknown //IL_0cc9: Unknown result type (might be due to invalid IL or missing references) //IL_0cd3: Expected O, but got Unknown BindModules(cfg); DiagnosticDisablePatches = cfg.Bind<bool>("Diagnostics", "DisablePatches", false, "DIAGNOSTIC (default off). If true, skip ALL Harmony gameplay patches. Used only to isolate whether the mod's patches interfere with Photon connecting. Leave off for normal play."); DiagnosticDisableRuntimeObjects = cfg.Bind<bool>("Diagnostics", "DisableRuntimeObjects", false, "DIAGNOSTIC (default off). If true, skip creating the mod's runtime menu/HUD objects (networking, timer, ping, Photon HUD). Used only to isolate whether they interfere with Photon connecting. Leave off for normal play."); 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. Steps = max(0, (levelsCompleted - RampStartLevel) / RampLevelsPerStep), using integer division. 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, Loom:1, Cleanup Crew:1.5, Tick:1.5", 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 (Elsa/Loom are excluded by default). 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.1f, 0f, 2f, "Extra enemy attack damage per level past the ramp start. 0.10 = +10% 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.75f, 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.1f, 0f, 2f, "Extra extraction quota per level past the ramp start. 0.10 = +10% 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."); SpreadUpgradesCount = BindInt(cfg, "Modifier Tuning", "SpreadUpgradesCount", 3, 0, 10, "SpreadUpgrades: how many upgrade item pickups to scatter across the special level. They can't be used on that level, only once back in the truck."); 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", "LevelTimerSeconds", 300f, 30f, 1200f, "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", "LevelTimerKillBonus", 10f, 0f, 120f, "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", "LevelTimerQuotaBonus", 60f, 0f, 300f, "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."); PingAnywhereBasePrice = BindInt(cfg, "Ping", "PingAnywhereBasePrice", 6000, 0, 1000000, "Ping Anywhere upgrade: approximate shop price (unlocks Location pings on any surface / through walls)."); PingInfoBasePrice = BindInt(cfg, "Ping", "PingInfoBasePrice", 6000, 0, 1000000, "Ping Info upgrade: approximate shop price (your pings reveal value / rarity / exact names)."); 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."); 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 start hidden and do not automatically open with Tab."); 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."); 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", 350, 50, 2000, "Total damage a fully charged Defence DRONE can absorb for the player it is attached to."); DefenceItemAbsorb = BindInt(cfg, "Gear", "DefenceItemAbsorb", 3500, 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", 45f, 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", 20f, 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", 25, 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, "Total poison damage over the full duration."); 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", 60, 10, 100, "Firearm damage frozen enemies take, in percent of normal."); 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."); InventorySlotBasePrice = BindInt(cfg, "Player Upgrades", "InventorySlotBasePrice", 15000, 1000, 500000, "Approximate first Inventory Slot upgrade price. Four levels, each adds one slot; maximum seven slots total."); 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."); PhotonHudRegions = cfg.Bind<string>("Photon HUD", "Regions", "ns=ns.photonengine.io, exitgames=ns.exitgames.com", new ConfigDescription("Comma-separated 'label=host' (or 'label=host:port') pairs to TCP-probe for the HUD. Default probes the Photon name servers (port 443) — the endpoint the game contacts when connecting with an empty/best region, which is where 'stuck loading online' usually hangs.", (AcceptableValueBase)null, new object[1] { "HideFromREPOConfig" })); 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%)."); ShopDuplicatesExtra = BindInt(cfg, "Shop", "DuplicatesExtra", 0, 0, 10, "Allow the same item (e.g. a gun) to appear more than once in a single shop by adding this many extra copies of each item to the shop pool. 0 = vanilla (usually one of each)."); TruckHealPercentPerLevel = BindFloat(cfg, "Truck Upgrades", "HealPercentPerLevel", 0.25f, 0f, 0.95f, "Heal Power: each level closes this fraction of the remaining bonus gap towards 2x healing. Multiplier = 2 - (1-p)^level. At p=0.25, levels 1/2/3 give 1.25x/1.4375x/1.5781x healing."); TruckHealMaxLevel = BindInt(cfg, "Truck Upgrades", "HealMaxLevel", 3, 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", "ChargePercentPerLevel", 0.2f, 0f, 0.95f, "Charge Efficiency: multiply remaining energy-pool drain by (1-p) per level, with a 5% minimum. At p=0.20, levels 1/2/3 spend 80%/64%/51.2% of normal energy."); TruckChargeMaxLevel = BindInt(cfg, "Truck Upgrades", "ChargeMaxLevel", 3, 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."); 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%."); StaminaPercentPerLevel = BindFloat(cfg, "Player Upgrades", "StaminaPercentPerLevel", 0.05f, 0.01f, 0.5f, "Slower Stamina Use: sprint energy drain multiplier per level, compounding: each level multiplies the drain by (1 - value). 0.05 = each level keeps 95% of the drain; it approaches zero but never reaches it."); StaminaMaxLevel = BindInt(cfg, "Player Upgrades", "StaminaMaxLevel", 5, 1, 20, "Slower Stamina Use: maximum purchasable level."); StaminaBasePrice = BindInt(cfg, "Player Upgrades", "StaminaBasePrice", 4000, 0, 1000000, "Slower Stamina Use: approximate shop price (at one player, before the game's own scaling)."); RegenPercentPerLevel = BindFloat(cfg, "Player Upgrades", "RegenPercentPerLevel", 0.000667f, 0.0005f, 0.05f, "HP Regen: fraction of MAX HP healed per SECOND, per level. 0.000667 = about 0.07%/s per level (~1 HP every 15s at level 1 for a 100 HP player)."); RegenMaxHpFraction = BindFloat(cfg, "Player Upgrades", "RegenMaxHpFraction", 0.3f, 0.05f, 1f, "HP Regen: stops once current HP reaches this fraction of max HP. 0.30 = regen only fills up to 30% of max HP."); RegenMaxLevel = BindInt(cfg, "Player Upgrades", "RegenMaxLevel", 3, 1, 20, "HP Regen: maximum purchasable level."); RegenBasePrice = BindInt(cfg, "Player Upgrades", "RegenBasePrice", 20000, 0, 1000000, "HP Regen: approximate shop price of the first level (very expensive)."); DeathProtectMaxCharges = BindInt(cfg, "Player Upgrades", "DeathProtectMaxCharges", 1, 1, 9, "Death Protection: max charges you can stockpile at once. Each charge saves you from one lethal hit (survive at 1 HP) and is consumed on use; re-buy to restore."); DeathProtectBasePrice = BindInt(cfg, "Player Upgrades", "DeathProtectBasePrice", 50000, 0, 1000000, "Death Protection: approximate shop price per charge (very-very expensive)."); GunBatteryPercentPerLevel = BindFloat(cfg, "Player Upgrades", "GunBatteryPercentPerLevel", 0.05f, 0.01f, 0.5f, "Gun Battery Life: extra effective battery life per level (shared by the Bullet/Laser/Tranq gun upgrades). 0.05 = +5%/level; capped at +100% total."); GunBatteryMaxLevel = BindInt(cfg, "Player Upgrades", "GunBatteryMaxLevel", 20, 1, 100, "Gun Battery Life: maximum purchasable level (20 x 5% = +100%)."); GunBatteryBasePrice = BindInt(cfg, "Player Upgrades", "GunBatteryBasePrice", 6000, 0, 1000000, "Gun Battery Life: approximate shop price of the first level (each gun type is a separate upgrade)."); DroneBatteryPercentPerLevel = BindFloat(cfg, "Player Upgrades", "DroneBatteryPercentPerLevel", 0.05f, 0.01f, 0.5f, "Drone Battery Life: extra effective battery life per level. 0.05 = +5%/level; capped at +100% total."); DroneBatteryMaxLevel = BindInt(cfg, "Player Upgrades", "DroneBatteryMaxLevel", 20, 1, 100, "Drone Battery Life: maximum purchasable level (20 x 5% = +100%)."); DroneBatteryBasePrice = BindInt(cfg, "Player Upgrades", "DroneBatteryBasePrice", 6000, 0, 1000000, "Drone Battery Life: approximate shop price of the first level."); AutoscanRangePerLevel = BindFloat(cfg, "Player Upgrades", "AutoscanRangePerLevel", 5f, 1f, 30f, "Autoscan: scan radius added per level, in metres. Discovers valuables and native discoverable items for the team. 5 = level 1 scans 5m, level 2 scans 10m."); AutoscanMaxLevel = BindInt(cfg, "Player Upgrades", "AutoscanMaxLevel", 5, 1, 20, "Autoscan: maximum purchasable level."); AutoscanInterval = BindFloat(cfg, "Player Upgrades", "AutoscanInterval", 1f, 0.1f, 10f, "Autoscan: seconds between scans. Lower = discovers valuables faster but costs more CPU."); AutoscanBasePrice = BindInt(cfg, "Player Upgrades", "AutoscanBasePrice", 8000, 0, 1000000, "Autoscan: approximate shop price of the first level."); MapBasePrice = BindInt(cfg, "Player Upgrades", "MapBasePrice", 15000, 0, 1000000, "Map Suite: approximate shop price of the FIRST level (very expensive). A single upgrade with 10 levels, each unlocking a map feature: L1-5 live counts + quota path, L6 team pings on the map, L7-8 zoom out, L9 cosmetic-box tracker, L10 monster dots."); MapZoomFovLevel7 = BindFloat(cfg, "Player Upgrades", "MapZoomFovLevel7", 62f, 50f, 120f, "Map Suite L7: camera field-of-view used while the map is open (higher = more zoomed out, see more of the level at once). Vanilla map view is 50."); MapZoomFovLevel8 = BindFloat(cfg, "Player Upgrades", "MapZoomFovLevel8", 74f, 50f, 120f, "Map Suite L8: camera field-of-view while the map is open once level 8 is reached (higher = even more zoomed out)."); MapZoomInKey = cfg.Bind<KeyCode>("Player Upgrades", "MapZoomInKey", (KeyCode)45, "Map Suite L7+: key to zoom the map view IN (lower FOV) while the map is open. Also accepts Keypad Minus and '['."); MapZoomOutKey = cfg.Bind<KeyCode>("Player Upgrades", "MapZoomOutKey", (KeyCode)61, "Map Suite L7+: key to zoom the map view OUT (higher FOV) while the map is open. Also accepts Keypad Plus and ']'."); MapZoomStep = BindFloat(cfg, "Player Upgrades", "MapZoomStep", 6f, 1f, 30f, "Map Suite L7+: how much field-of-view each zoom-hotkey press adds/removes on top of the level's default FOV."); MapSuiteReplacesVanilla = cfg.Bind<bool>("Player Upgrades", "MapSuiteReplacesVanilla", true, "Remove the vanilla 'Map Player Count' upgrade from the shop so Map Suite replaces it (Map Suite already includes live player counts)."); SpecialLevelChancePercent = BindInt(cfg, "Surprises", "SpecialLevelChancePercent", 40, 0, 100, "Percent chance (0-100) that any eligible level becomes a special level with modifiers."); ModifiersPerLevelMin = BindInt(cfg, "Surprises", "ModifiersPerLevelMin", 1, 0, 10, "Minimum number of modifiers a special level rolls."); ModifiersPerLevelMax = BindInt(cfg, "Surprises", "ModifiersPerLevelMax", 2, 0, 10, "Maximum number of modifiers a special level rolls."); SurprisesStartLevel = BindInt(cfg, "Surprises", "StartLevel", 1, 0, 30, "Levels completed before special levels can appear. 1 = from the 2nd level onward."); foreach (ModifierType value in Enum.GetValues(typeof(ModifierType))) { if (value != ModifierType.None) { ModifierEnabled[value] = cfg.Bind<bool>("Surprise Modifiers", value.ToString(), true, ModifierDescription(value) + " Toggle whether it can be rolled on special levels."); } } foreach (StatModifier item in StatModifiers.All) { StatModifierEnabled[item.Id] = cfg.Bind<bool>("Surprise Modifiers", item.Name, true, item.Description + " Toggle whether it can be rolled on special levels."); } RebuildPerEnemyCaps(); EnemyHealthMaxPerEnemy.SettingChanged += delegate { RebuildPerEnemyCaps(); }; } private static void RebuildPerEnemyCaps() { Dictionary<string, float> dictionary = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase); string[] array = EnemyHealthMaxPerEnemy.Value.Split(','); foreach (string text in array) { int num = text.LastIndexOf(':'); if (num > 0) { string text2 = text.Substring(0, num).Trim(); string s = text.Substring(num + 1).Trim(); if (text2.Length != 0 && float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && !float.IsNaN(result) && !float.IsInfinity(result) && result >= 1f) { dictionary[text2] = result; } } } _perEnemyHealthMax = dictionary; } public static float HealthMaxForEnemy(string enemyName) { if (enemyName != null && _perEnemyHealthMax.TryGetValue(enemyName, out var value)) { return value; } return EnemyHealthMax.Value; } } public static class PluginInfo { public const string PLUGIN_GUID = "com.kubai.increasehardmod"; public const string PLUGIN_NAME = "IncreaseDifficultyMod"; public const string PLUGIN_VERSION = "0.7.1"; } [BepInPlugin("com.kubai.increasehardmod", "IncreaseDifficultyMod", "0.7.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private readonly Harmony _harmony = new Harmony("com.kubai.increasehardmod"); private static GameObject _runtimeObject; public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)$"[Build] DLL={typeof(Plugin).Assembly.Location}; MVID={typeof(Plugin).Module.ModuleVersionId}"); ModConfig.Init(((BaseUnityPlugin)this).Config); if (ModConfig.DiagnosticDisablePatches.Value) { Log.LogWarning((object)"[Diagnostics] DisablePatches=true — skipping ALL Harmony patches."); } else { Type[] types = typeof(Plugin).Assembly.GetTypes(); foreach (Type type in types) { if (type.IsDefined(typeof(HarmonyPatch), inherit: true)) { try { _harmony.CreateClassProcessor(type).Patch(); } catch (Exception ex) { Log.LogError((object)("Patch " + type.FullName + " failed: " + ex.Message)); } } } } StaminaUpgrade.Register(); HpRegenUpgrade.Register(); DeathProtectionUpgrade.Register(); BatteryLifeUpgrade.Register(); AutoscanUpgrade.Register(); MapUpgrade.Register(); InventorySlotsUpgrade.Register(); PingUpgrades.Register(); TruckUpgrades.Register(); if (ModConfig.DiagnosticDisableRuntimeObjects.Value) { Log.LogWarning((object)"[Diagnostics] DisableRuntimeObjects=true — skipping runtime menu/HUD objects."); } else { SceneManager.sceneLoaded += OnSceneLoaded; EnsureRuntimeObject(); } Log.LogInfo((object)"IncreaseDifficultyMod v0.7.1 loaded."); } private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { EnsureRuntimeObject(); } private static void EnsureRuntimeObject() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown if (!((Object)(object)_runtimeObject != (Object)null)) { GameObject val = new GameObject("IncreaseHardMod_Runtime"); val.AddComponent<ModNetwork>(); val.AddComponent<InventorySlotsUpgrade.Controller>(); val.AddComponent<VoiceRecoveryController>(); val.AddComponent<TruckUpgrades.SellController>(); val.AddComponent<PhotonHud>(); val.AddComponent<PingHud>(); val.AddComponent<LevelInfoHud>(); val.AddComponent<SpectatorMapHud>(); val.AddComponent<QuestHud>(); val.AddComponent<RoundResultsHud>(); val.AddComponent<BlackMarketHud>(); val.AddComponent<ItemUnstuckController>(); val.AddComponent<ServerInfoHud>(); val.AddComponent<ShoppingListHud>(); val.AddComponent<MapVoteController>(); val.AddComponent<HpRegenUpgrade.RegenController>(); val.AddComponent<AutoscanUpgrade.ScanController>(); val.AddComponent<MapUpgrade.MapController>(); val.AddComponent<MapUpgrade.MarkerController>(); Object.DontDestroyOnLoad((Object)(object)val); _runtimeObject = val; Log.LogInfo((object)$"[Init] Runtime object created (scene-load): active={val.activeInHierarchy}, components={val.GetComponents<Component>().Length}."); } } } internal sealed class SpectatorMapConfig { internal ConfigEntry<bool> Enabled; internal ConfigEntry<KeyCode> HoldKey; internal ConfigEntry<float> ScreenFraction; internal static SpectatorMapConfig Bind(ConfigFile cfg) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Expected O, but got Unknown //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Expected O, but got Unknown //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Expected O, but got Unknown //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Expected O, but got Unknown //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Expected O, but got Unknown //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Expected O, but got Unknown //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Expected O, but got Unknown //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Expected O, but got Unknown //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Expected O, but got Unknown //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Expected O, but got Unknown Dictionary<ConfigDefinition, string> dictionary = typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(cfg) as Dictionary<ConfigDefinition, string>; ConfigDefinition val = new ConfigDefinition("Modules", "SpectatorMap"); ConfigDefinition val2 = new ConfigDefinition("Spectator Map", "HoldKey"); bool flag = cfg.ContainsKey(val) || (dictionary?.ContainsKey(val) ?? false); bool flag2 = cfg.ContainsKey(val2) || (dictionary?.ContainsKey(val2) ?? false); bool? flag3 = LegacyEnabled(cfg, dictionary, "DeadMapAccess", "Dead Map Access"); bool? flag4 = LegacyEnabled(cfg, dictionary, "SpectatorMinimap", "Spectator Minimap"); bool value = (!flag3.HasValue && !flag4.HasValue) || flag3 == true || flag4 == true; string text = Raw(cfg, dictionary, new ConfigDefinition("Spectator Minimap", "HoldKey")); bool saveOnConfigSet = cfg.SaveOnConfigSet; cfg.SaveOnConfigSet = false; SpectatorMapConfig spectatorMapConfig; try { spectatorMapConfig = new SpectatorMapConfig { Enabled = cfg.Bind<bool>(val, true, new ConfigDescription("Map for dead/spectating players. Follows the spectator camera. Normal map key or hold key opens it; arrows pan, map zoom keys change scale, Home restores follow.", (AcceptableValueBase)null, Array.Empty<object>())), HoldKey = cfg.Bind<KeyCode>(val2, (KeyCode)9, new ConfigDescription("Hold this key while dead to show the spectator map. The game's normal map binding also works.", (AcceptableValueBase)null, Array.Empty<object>())), ScreenFraction = cfg.Bind<float>("Spectator Map", "ScreenFraction", 0.8f, new ConfigDescription("Map size relative to reference screen height. 0.8 = a large map.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 0.9f), Array.Empty<object>())) }; if (!flag) { spectatorMapConfig.Enabled.Value = value; } if (!flag2 && !string.IsNullOrEmpty(text)) { ((ConfigEntryBase)spectatorMapConfig.HoldKey).SetSerializedValue(text); } ConfigDefinition[] array = (ConfigDefinition[])(object)new ConfigDefinition[7] { new ConfigDefinition("Modules", "DeadMapAccess"), new ConfigDefinition("Modules", "SpectatorMinimap"), new ConfigDefinition("Dead Map Access", "Enabled"), new ConfigDefinition("Spectator Minimap", "Enabled"), new ConfigDefinition("Spectator Minimap", "HoldKey"), new ConfigDefinition("Spectator Minimap", "ToggleKey"), new ConfigDefinition("Spectator Minimap", "Scale") }; foreach (ConfigDefinition val3 in array) { cfg.Remove(val3); dictionary?.Remove(val3); } } finally { cfg.SaveOnConfigSet = saveOnConfigSet; } if (saveOnConfigSet) { cfg.Save(); } return spectatorMapConfig; } private static bool? LegacyEnabled(ConfigFile cfg, Dictionary<ConfigDefinition, string> orphans, string module, string section) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown if (!bool.TryParse(Raw(cfg, orphans, new ConfigDefinition("Modules", module)) ?? Raw(cfg, orphans, new ConfigDefinition(section, "Enabled")), out var result)) { return null; } return result; } private static string Raw(ConfigFile cfg, Dictionary<ConfigDefinition, string> orphans, ConfigDefinition key) { if (cfg.ContainsKey(key)) { return cfg[key].GetSerializedValue(); } if (orphans == null || !orphans.TryGetValue(key, out var value)) { return null; } return value; } } } namespace IncreaseHardMod.Visuals { internal static class ArtModelReader { internal static ArtModel Parse(string json, string key) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown ArtModel artModel = JsonConvert.DeserializeObject<ArtModel>(json, new JsonSerializerSettings { TypeNameHandling = (TypeNameHandling)0, MetadataPropertyHandling = (MetadataPropertyHandling)2, MaxDepth = 64 }); if (artModel == null || artModel.version != 1 || artModel.fps <= 0 || artModel.frames <= 0 || artModel.parts == null || artModel.parts.Length == 0) { throw new InvalidDataException("Invalid item art header: " + key); } ArtPart[] parts = artModel.parts; foreach (ArtPart artPart in parts) { if (artPart == null || artPart.vertices == null || artPart.vertices.Length == 0 || artPart.normals == null || artPart.normals.Length != artPart.vertices.Length || artPart.uv == null || artPart.uv.Length != artPart.vertices.Length || artPart.triangles == null || artPart.triangles.Length % 3 != 0 || artPart.rest == null || artPart.samples == null || (artPart.samples.Length != 0 && artPart.samples.Length != artModel.frames)) { throw new InvalidDataException("Invalid item art geometry: " + key + "/" + artPart?.name); } int[] triangles = artPart.triangles; foreach (int num in triangles) { if (num < 0 || num >= artPart.vertices.Length) { throw new InvalidDataException("Invalid triangle index: " + key + "/" + artPart.name); } } } return artModel; } } [Serializable] internal sealed class ArtModel { public int version; public int fps; public int frames; public ArtPart[] parts; } [Serializable] internal sealed class ArtPart { public string name; public string texture; public Vector3[] vertices; public Vector3[] normals; public Vector2[] uv; public int[] triangles; public Color color; public ArtPose rest; public ArtPose[] samples; } [Serializable] internal sealed class ArtPose { public Vector3 position; public Vector3 scale; public Quaternion rotation; } internal static class DonorVisuals { private static Mesh _empty; internal static void RemoveGeometry(IEnumerable<Renderer> donors) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown if ((Object)(object)_empty == (Object)null) { _empty = new Mesh { name = "IHM Empty Donor Geometry" }; } foreach (Renderer donor in donors) { if (!((Object)(object)donor == (Object)null)) { MeshFilter component = ((Component)donor).GetComponent<MeshFilter>(); if ((Object)(object)component != (Object)null) { component.sharedMesh = _empty; } SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((donor is SkinnedMeshRenderer) ? donor : null); if (val != null) { val.sharedMesh = _empty; } donor.enabled = false; donor.forceRenderingOff = true; } } } } internal sealed class EnemyStatusVisual : MonoBehaviour { private sealed class FrostSlot { public Renderer Renderer; public Material[] Original; public Material[] Iced; } private Enemy _enemy; private Renderer[] _body; private float _poisonUntil; private float _iceUntil; private ParticleSystem _cloud; private static Material _cloudMaterial; private bool _iceApplied; private readonly List<FrostSlot> _frost = new List<FrostSlot>(); private bool Alive { get { if ((Object)(object)_enemy != (Object)null && ((Behaviour)_enemy).isActiveAndEnabled) { if (_enemy.HasHealth && !((Object)(object)_enemy.Health == (Object)null)) { if (!_enemy.Health.dead) { return _enemy.Health.healthCurrent > 0; } return false; } return true; } return false; } } internal static void Apply(Enemy enemy, byte kind, float seconds) { if (!((Object)(object)enemy == (Object)null) && ((Behaviour)enemy).isActiveAndEnabled && kind <= 1 && !float.IsNaN(seconds) && !float.IsInfinity(seconds) && !(seconds <= 0f)) { EnemyStatusVisual enemyStatusVisual = ((Component)enemy).GetComponent<EnemyStatusVisual>(); if ((Object)(object)enemyStatusVisual == (Object)null) { enemyStatusVisual = ((Component)enemy).gameObject.AddComponent<EnemyStatusVisual>(); } ((Behaviour)enemyStatusVisual).enabled = true; if (kind == 0) { enemyStatusVisual._poisonUntil = Time.time + Mathf.Min(seconds, 600f); } else { enemyStatusVisual._iceUntil = Time.time + Mathf.Min(seconds, 600f); } } } private void Awake() { _enemy = ((Component)this).GetComponent<Enemy>(); Transform val = ((_enemy.HasHealth && (Object)(object)_enemy.Health != (Object)null) ? _enemy.Health.meshParent : null); Renderer[] componentsInChildren = ((Component)(((Object)(object)val != (Object)null) ? val : ((Component)this).transform)).GetComponentsInChildren<Renderer>(true); List<Renderer> list = new List<Renderer>(); Renderer[] array = componentsInChildren; foreach (Renderer val2 in array) { if ((val2 is MeshRenderer || val2 is SkinnedMeshRenderer) ? true : false) { list.Add(val2); } } _body = list.ToArray(); } private Bounds BodyBounds() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = default(Bounds); ((Bounds)(ref bounds))..ctor(((Component)this).transform.position + Vector3.up * 0.5f, Vector3.one * 0.5f); bool flag = false; Renderer[] body = _body; foreach (Renderer val in body) { if (!((Object)(object)val == (Object)null) && val.enabled && ((Component)val).gameObject.activeInHierarchy) { if (!flag) { bounds = val.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val.bounds); } } } return bounds; } private void LateUpdate() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) if (!Alive) { ((Behaviour)this).enabled = false; return; } bool flag = Time.time < _poisonUntil; if (flag && (Object)(object)_cloud == (Object)null) { CreateCloud(); } if ((Object)(object)_cloud != (Object)null) { Bounds val = BodyBounds(); ((Component)_cloud).transform.position = ((Bounds)(ref val)).center - Vector3.up * ((Bounds)(ref val)).extents.y * 0.25f; EmissionModule emission = _cloud.emission; ((EmissionModule)(ref emission)).enabled = flag; if (flag && !_cloud.isPlaying) { _cloud.Play(); } if (!flag && !_cloud.IsAlive()) { Object.Destroy((Object)(object)((Component)_cloud).gameObject); _cloud = null; } } if (Time.time < _iceUntil) { if (!_iceApplied) { ApplyFrost(); } float num = 0.15f + Mathf.Sin(Time.time * 2.5f) * 0.025f; foreach (FrostSlot item in _frost) { Material[] iced = item.Iced; foreach (Material val2 in iced) { if (!((Object)(object)val2 == (Object)null)) { if (val2.HasProperty("_Color")) { val2.SetColor("_Color", new Color(0.32f, 0.67f, 1f)); } if (val2.HasProperty("_BaseColor")) { val2.SetColor("_BaseColor", new Color(0.32f, 0.67f, 1f)); } if (val2.HasProperty("_EmissionColor")) { val2.SetColor("_EmissionColor", new Color(0.1f, 0.38f, 0.8f) * num); } } } } } else if (_iceApplied) { RestoreFrost(); } if (!flag && (Object)(object)_cloud == (Object)null && !_iceApplied) { ((Behaviour)this).enabled = false; } } private void CreateCloud() { //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Expected O, but got Unknown //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown if ((Object)(object)_cloudMaterial == (Object)null) { Shader val = Shader.Find("Particles/Standard Unlit") ?? Shader.Find("Legacy Shaders/Particles/Alpha Blended") ?? Shader.Find("Sprites/Default"); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"[Art] No supported poison particle shader in this game build."); _poisonUntil = 0f; return; } _cloudMaterial = new Material(val) { name = "IHM Poison Mist", renderQueue = 3000 }; _cloudMaterial.mainTexture = (Texture)(object)UpgradeIcons.LoadTexture("poison_puff.png"); _cloudMaterial.SetInt("_SrcBlend", 5); _cloudMaterial.SetInt("_DstBlend", 10); _cloudMaterial.SetInt("_ZWrite", 0); _cloudMaterial.EnableKeyword("_ALPHABLEND_ON"); } GameObject val2 = new GameObject("IHM Poison Cloud"); val2.transform.SetParent(((Component)this).transform, false); _cloud = val2.AddComponent<ParticleSystem>(); _cloud.Stop(true, (ParticleSystemStopBehavior)0); Bounds val3 = BodyBounds(); Vector3 extents = ((Bounds)(ref val3)).extents; float num = Mathf.Clamp(((Vector3)(ref extents)).magnitude * 0.45f, 0.22f, 1.1f); MainModule main = _cloud.main; ((MainModule)(ref main)).loop = true; ((MainModule)(ref main)).playOnAwake = false; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(0.7f, 1.3f); ((MainModule)(ref main)).startSpeed = new MinMaxCurve(0.08f, 0.26f); ((MainModule)(ref main)).startSize = new MinMaxCurve(num * 0.65f, num); ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.66f, 0.83f, 0.33f, 0.45f)); ((MainModule)(ref main)).maxParticles = 36; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; ShapeModule shape = _cloud.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)0; ((ShapeModule)(ref shape)).radius = num * 0.65f; EmissionModule emission = _cloud.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(12f); VelocityOverLifetimeModule velocityOverLifetime = _cloud.velocityOverLifetime; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).enabled = true; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).space = (ParticleSystemSimulationSpace)1; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).y = MinMaxCurve.op_Implicit(0.22f); ColorOverLifetimeModule colorOverLifetime = _cloud.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true; Gradient val4 = new Gradient(); val4.SetKeys((GradientColorKey[])(object)new GradientColorKey[2] { new GradientColorKey(Color.white, 0f), new GradientColorKey(Color.white, 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[3] { new GradientAlphaKey(0f, 0f), new GradientAlphaKey(1f, 0.2f), new GradientAlphaKey(0f, 1f) }); ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = MinMaxGradient.op_Implicit(val4); ParticleSystemRenderer component = val2.GetComponent<ParticleSystemRenderer>(); ((Renderer)component).sharedMaterial = _cloudMaterial; ((Renderer)component).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)component).receiveShadows = false; _cloud.Play(); } private void ApplyFrost() { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_0087: Expected O, but got Unknown _iceApplied = true; Texture2D val = UpgradeIcons.LoadTexture("ice_frost.png"); Renderer[] body = _body; foreach (Renderer val2 in body) { if ((Object)(object)val2 == (Object)null) { continue; } Material[] sharedMaterials = val2.sharedMaterials; Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; for (int j = 0; j < sharedMaterials.Length; j++) { if (!((Object)(object)sharedMaterials[j] == (Object)null)) { int num = j; Material val3 = new Material(sharedMaterials[j]) { name = "IHM Frost " + ((Object)sharedMaterials[j]).name }; Material val4 = val3; array[num] = val3; Material val5 = val4; if (val5.HasProperty("_MainTex")) { val5.SetTexture("_MainTex", (Texture)(object)val); } if (val5.HasProperty("_BaseMap")) { val5.SetTexture("_BaseMap", (Texture)(object)val); } if (val5.HasProperty("_Glossiness")) { val5.SetFloat("_Glossiness", 0.8f); } if (val5.HasProperty("_Smoothness")) { val5.SetFloat("_Smoothness", 0.8f); } if (val5.HasProperty("_Metallic")) { val5.SetFloat("_Metallic", 0.2f); } if (val5.HasProperty("_EmissionMap")) { val5.SetTexture("_EmissionMap", (Texture)(object)val); } val5.EnableKeyword("_EMISSION"); } } _frost.Add(new FrostSlot { Renderer = val2, Original = sharedMaterials, Iced = array }); val2.sharedMaterials = array; } } private void RestoreFrost() { foreach (FrostSlot item in _frost) { if ((Object)(object)item.Renderer != (Object)null) { Material[] sharedMaterials = item.Renderer.sharedMaterials; for (int i = 0; i < sharedMaterials.Length && i < item.Iced.Length; i++) { if ((Object)(object)sharedMaterials[i] == (Object)(object)item.Iced[i]) { sharedMaterials[i] = item.Original[i]; } } item.Renderer.sharedMaterials = sharedMaterials; } Material[] iced = item.Iced; foreach (Material val in iced) { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } } _frost.Clear(); _iceApplied = false; } private void Clear() { _poisonUntil = (_iceUntil = 0f); if ((Object)(object)_cloud != (Object)null) { Object.Destroy((Object)(object)((Component)_cloud).gameObject); _cloud = null; } RestoreFrost(); } private void OnDisable() { Clear(); } private void OnDestroy() { Clear(); } } internal sealed class FrostCoating { private sealed class Slot { internal Renderer Renderer; internal Material[] Original; internal Material[] Iced; } private readonly List<Slot> _slots = new List<Slot>(); internal void Apply(Renderer[] renderers) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_0091: Expected O, but got Unknown if (_slots.Count > 0) { return; } Texture2D val = UpgradeIcons.LoadTexture("ice_frost.png"); foreach (Renderer val2 in renderers) { if (!(val2 is MeshRenderer) && !(val2 is SkinnedMeshRenderer)) { continue; } Material[] sharedMaterials = val2.sharedMaterials; Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; for (int j = 0; j < sharedMaterials.Length; j++) { if (!((Object)(object)sharedMaterials[j] == (Object)null)) { int num = j; Material val3 = new Material(sharedMaterials[j]) { name = "IHM Player Frost " + ((Object)sharedMaterials[j]).name }; Material val4 = val3; array[num] = val3; Material val5 = val4; if (val5.HasProperty("_MainTex")) { val5.SetTexture("_MainTex", (Texture)(object)val); } if (val5.HasProperty("_BaseMap")) { val5.SetTexture("_BaseMap", (Texture)(object)val); } if (val5.HasProperty("_Glossiness")) { val5.SetFloat("_Glossiness", 0.8f); } if (val5.HasProperty("_Smoothness")) { val5.SetFloat("_Smoothness", 0.8f); } if (val5.HasProperty("_EmissionMap")) { val5.SetTexture("_EmissionMap", (Texture)(object)val); } val5.EnableKeyword("_EMISSION"); } } _slots.Add(new Slot { Renderer = val2, Original = sharedMaterials, Iced = array }); val2.sharedMaterials = array; } Tick(); } internal void Tick() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) foreach (Slot slot in _slots) { Material[] iced = slot.Iced; foreach (Material val in iced) { if (!((Object)(object)val == (Object)null)) { if (val.HasProperty("_Color")) { val.SetColor("_Color", new Color(0.32f, 0.67f, 1f)); } if (val.HasProperty("_BaseColor")) { val.SetColor("_BaseColor", new Color(0.32f, 0.67f, 1f)); }