using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using GlobalEnums; using HarmonyLib; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using TeamCherry.Localization; using UnityEngine; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("0.0.0.0")] namespace CodexMods.CustomDifficulty; internal static class CustomDifficultyAdaptiveSystem { public const int SuggestOnly = 0; public const int ApplyWithConfirmation = 1; public const int ApplyAutomatically = 2; public static string GetApplyModeKey(int mode) { return mode switch { 1 => "adaptive_mode_confirm", 2 => "adaptive_mode_auto", _ => "adaptive_mode_suggest", }; } } internal sealed class CustomDifficultyBossProfileData { public string InternalName = string.Empty; public string DisplayName = string.Empty; public float HealthMultiplier = 1f; public float DamageMultiplier = 1f; public float HornetDamageMultiplier = 1f; public float SpeedMultiplier = 1f; public bool HealingAllowed = true; public bool Enabled; public string Notes = "Reserved until boss identification is safer."; } internal sealed class CustomDifficultyBossProfileManager { private readonly BaseUnityPlugin _plugin; private readonly string _profilePath; private List _cachedProfiles; private DateTime _cachedWriteTimeUtc; public string ProfilePath => _profilePath; public CustomDifficultyBossProfileManager(BaseUnityPlugin plugin) { _plugin = plugin; string text = Path.Combine(Paths.ConfigPath, "CustomDifficulty"); Directory.CreateDirectory(text); _profilePath = Path.Combine(text, "boss-profiles.json"); EnsureProfileFile(); } public List LoadProfiles() { try { DateTime dateTime = (File.Exists(_profilePath) ? File.GetLastWriteTimeUtc(_profilePath) : DateTime.MinValue); if (_cachedProfiles != null && dateTime == _cachedWriteTimeUtc) { return _cachedProfiles; } string text = File.ReadAllText(_profilePath); List list = JsonConvert.DeserializeObject>(text); _cachedProfiles = list ?? new List(); _cachedWriteTimeUtc = dateTime; return _cachedProfiles; } catch (Exception ex) { CustomDifficultyPlugin.LogWarningSafe("Could not load boss profiles: " + ex.Message); return new List(); } } public bool TryFindProfile(GameObject gameObject, out CustomDifficultyBossProfileData profile) { profile = null; if ((Object)(object)gameObject == (Object)null) { return false; } List list = CollectObjectNames(gameObject); List list2 = LoadProfiles(); for (int i = 0; i < list2.Count; i++) { CustomDifficultyBossProfileData customDifficultyBossProfileData = list2[i]; if (customDifficultyBossProfileData == null || !customDifficultyBossProfileData.Enabled || string.IsNullOrWhiteSpace(customDifficultyBossProfileData.InternalName)) { continue; } string text = customDifficultyBossProfileData.InternalName.Trim(); if (string.Equals(text, "manual_boss_id", StringComparison.OrdinalIgnoreCase)) { continue; } for (int j = 0; j < list.Count; j++) { if (list[j].IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) { profile = customDifficultyBossProfileData; return true; } } } return false; } private static List CollectObjectNames(GameObject gameObject) { List list = new List(); try { Transform val = gameObject.transform; while ((Object)(object)val != (Object)null) { if (!string.IsNullOrEmpty(((Object)val).name)) { list.Add(((Object)val).name); } val = val.parent; } } catch { if (!string.IsNullOrEmpty(((Object)gameObject).name)) { list.Add(((Object)gameObject).name); } } try { MonoBehaviour[] componentsInParent = gameObject.GetComponentsInParent(true); foreach (MonoBehaviour val2 in componentsInParent) { if ((Object)(object)val2 != (Object)null) { list.Add(((object)val2).GetType().Name); list.Add(((object)val2).GetType().FullName); } } } catch { } return list; } private void EnsureProfileFile() { if (File.Exists(_profilePath)) { return; } List list = new List(); list.Add(new CustomDifficultyBossProfileData { InternalName = "lace", DisplayName = "Lace", HealthMultiplier = 1.2f, DamageMultiplier = 1.4f, SpeedMultiplier = 1.1f, Enabled = false }); list.Add(new CustomDifficultyBossProfileData { InternalName = "bell_beast", DisplayName = "Bell Beast", HealthMultiplier = 1.6f, DamageMultiplier = 1.2f, HealingAllowed = false, Enabled = false }); list.Add(new CustomDifficultyBossProfileData { InternalName = "manual_boss_id", DisplayName = "Manual Boss Profile", Enabled = false }); List list2 = list; try { File.WriteAllText(_profilePath, JsonConvert.SerializeObject((object)list2, (Formatting)1)); } catch (Exception ex) { CustomDifficultyPlugin.LogWarningSafe("Could not create boss profile file: " + ex.Message); } } } internal sealed class CustomDifficultyConfigManager { private readonly BaseUnityPlugin _plugin; private readonly ConfigEntry _openMenuKey; private readonly ConfigEntry _baseDamage; private readonly ConfigEntry _baseHealth; private readonly ConfigEntry _dropRate; private readonly ConfigEntry _damageTakenMultiplier; private readonly ConfigEntry _healingMultiplier; private readonly ConfigEntry _healingCostMultiplier; private readonly ConfigEntry _invincibilityTimeMultiplier; private readonly ConfigEntry _skillDamageMultiplier; private readonly ConfigEntry _silkSpearDamageMultiplier; private readonly ConfigEntry _bossDamageMultiplier; private readonly ConfigEntry _commonEnemyDamageMultiplier; private readonly ConfigEntry _criticalChance; private readonly ConfigEntry _criticalDamageMultiplier; private readonly ConfigEntry _environmentalDamageMultiplier; private readonly ConfigEntry _bossDamageTakenMultiplier; private readonly ConfigEntry _commonEnemyDamageTakenMultiplier; private readonly ConfigEntry _enemyHealthMultiplier; private readonly ConfigEntry _enemyDamageMultiplier; private readonly ConfigEntry _enemySpeedMultiplier; private readonly ConfigEntry _enemyAttackCooldownMultiplier; private readonly ConfigEntry _enemyAggressionMultiplier; private readonly ConfigEntry _bossHealthMultiplier; private readonly ConfigEntry _bossSpeedMultiplier; private readonly ConfigEntry _bossAttackCooldownMultiplier; private readonly ConfigEntry _bossBrutalMode; private readonly ConfigEntry _disableHealingDuringBoss; private readonly ConfigEntry _healingDuringBossMultiplier; private readonly ConfigEntry _currencyDropMultiplier; private readonly ConfigEntry _itemDropMultiplier; private readonly ConfigEntry _shopPriceMultiplier; private readonly ConfigEntry _bossRewardMultiplier; private readonly ConfigEntry _deathCurrencyLossMultiplier; private readonly ConfigEntry _playerSpeedMultiplier; private readonly ConfigEntry _jumpHeightMultiplier; private readonly ConfigEntry _dashCooldownMultiplier; private readonly ConfigEntry _abilityCostMultiplier; private readonly ConfigEntry _silkCostMultiplier; private readonly ConfigEntry _oneHitMode; private readonly ConfigEntry _mutatorNoHealing; private readonly ConfigEntry _mutatorLowGravity; private readonly ConfigEntry _mutatorDoubleDamage; private readonly ConfigEntry _mutatorGlassCannon; private readonly ConfigEntry _mutatorFastEnemies; private readonly ConfigEntry _mutatorTankEnemies; private readonly ConfigEntry _mutatorAggressiveEnemies; private readonly ConfigEntry _mutatorRandomizedEnemyHealth; private readonly ConfigEntry _mutatorRichWorld; private readonly ConfigEntry _mutatorPoorWorld; private readonly ConfigEntry _mutatorExpensiveShops; private readonly ConfigEntry _mutatorNoDeathLoss; private readonly ConfigEntry _mutatorBossFrenzy; private readonly ConfigEntry _mutatorNoMercy; private readonly ConfigEntry _mutatorExtendedFights; private readonly ConfigEntry _bossProfilesEnabled; private readonly ConfigEntry _bossProfilesFallbackGlobal; private readonly ConfigEntry _contextBossRulesEnabled; private readonly ConfigEntry _contextExplorationRulesEnabled; private readonly ConfigEntry _contextLowHealthRuleEnabled; private readonly ConfigEntry _contextDeathStreakTrackingEnabled; private readonly ConfigEntry _adaptiveDifficultyEnabled; private readonly ConfigEntry _adaptiveBossAssistEnabled; private readonly ConfigEntry _adaptiveExplorationAssistEnabled; private readonly ConfigEntry _adaptiveEconomyAssistEnabled; private readonly ConfigEntry _adaptiveMaxAssist; private readonly ConfigEntry _adaptiveApplyMode; private DifficultySettings _appliedSettings; private DifficultySettings _draftSettings; private int _settingsRevision; public int SettingsRevision => _settingsRevision; public CustomDifficultyConfigManager(BaseUnityPlugin plugin) { _plugin = plugin; _openMenuKey = plugin.Config.Bind("Menu", "OpenMenuKey", (KeyCode)289, "Open the Custom Difficulty menu."); _baseDamage = plugin.Config.Bind("Gameplay", "BaseDamage", 5, "Base character damage."); _baseHealth = plugin.Config.Bind("Gameplay", "BaseHealth", 5, "Base maximum health."); _dropRate = plugin.Config.Bind("Gameplay", "DropRate", 1f, "Global drop rate multiplier."); _damageTakenMultiplier = plugin.Config.Bind("Gameplay", "DamageTakenMultiplier", 1f, "Global incoming damage multiplier."); _healingMultiplier = plugin.Config.Bind("Player", "HealingMultiplier", 1f, "Healing amount multiplier."); _healingCostMultiplier = plugin.Config.Bind("Player", "HealingCostMultiplier", 1f, "Healing silk cost multiplier."); _invincibilityTimeMultiplier = plugin.Config.Bind("Player", "InvincibilityTimeMultiplier", 1f, "Invincibility time after damage."); _skillDamageMultiplier = plugin.Config.Bind("Damage", "SkillDamageMultiplier", 1f, "Generic skill damage multiplier."); _silkSpearDamageMultiplier = plugin.Config.Bind("Damage", "SilkSpearDamageMultiplier", 1f, "Silk spear damage multiplier."); _bossDamageMultiplier = plugin.Config.Bind("Damage", "BossDamageMultiplier", 1f, "Damage dealt against bosses."); _commonEnemyDamageMultiplier = plugin.Config.Bind("Damage", "CommonEnemyDamageMultiplier", 1f, "Damage dealt against common enemies."); _criticalChance = plugin.Config.Bind("Damage", "CriticalChance", 0f, "Critical hit chance percentage."); _criticalDamageMultiplier = plugin.Config.Bind("Damage", "CriticalDamageMultiplier", 2f, "Critical hit damage multiplier."); _environmentalDamageMultiplier = plugin.Config.Bind("IncomingDamage", "EnvironmentalDamageMultiplier", 1f, "Environmental damage multiplier."); _bossDamageTakenMultiplier = plugin.Config.Bind("IncomingDamage", "BossDamageTakenMultiplier", 1f, "Boss damage taken multiplier."); _commonEnemyDamageTakenMultiplier = plugin.Config.Bind("IncomingDamage", "CommonEnemyDamageTakenMultiplier", 1f, "Common enemy damage taken multiplier."); _enemyHealthMultiplier = plugin.Config.Bind("Enemies", "EnemyHealthMultiplier", 1f, "Common enemy health multiplier."); _enemyDamageMultiplier = plugin.Config.Bind("Enemies", "EnemyDamageMultiplier", 1f, "Common enemy damage multiplier."); _enemySpeedMultiplier = plugin.Config.Bind("Enemies", "EnemySpeedMultiplier", 1f, "Reserved enemy speed multiplier."); _enemyAttackCooldownMultiplier = plugin.Config.Bind("Enemies", "EnemyAttackCooldownMultiplier", 1f, "Reserved enemy attack cooldown multiplier."); _enemyAggressionMultiplier = plugin.Config.Bind("Enemies", "EnemyAggressionMultiplier", 1f, "Reserved enemy aggression multiplier."); _bossHealthMultiplier = plugin.Config.Bind("Bosses", "BossHealthMultiplier", 1f, "Boss health multiplier."); _bossSpeedMultiplier = plugin.Config.Bind("Bosses", "BossSpeedMultiplier", 1f, "Reserved boss speed multiplier."); _bossAttackCooldownMultiplier = plugin.Config.Bind("Bosses", "BossAttackCooldownMultiplier", 1f, "Reserved boss attack cooldown multiplier."); _bossBrutalMode = plugin.Config.Bind("Bosses", "BossBrutalMode", false, "Enable brutal boss adjustments."); _disableHealingDuringBoss = plugin.Config.Bind("Bosses", "DisableHealingDuringBoss", false, "Reduce healing to zero during bosses."); _healingDuringBossMultiplier = plugin.Config.Bind("Bosses", "HealingDuringBossMultiplier", 1f, "Healing multiplier during boss fights."); _currencyDropMultiplier = plugin.Config.Bind("Drops", "CurrencyDropMultiplier", 1f, "Currency drop multiplier."); _itemDropMultiplier = plugin.Config.Bind("Drops", "ItemDropMultiplier", 1f, "Item drop multiplier."); _shopPriceMultiplier = plugin.Config.Bind("Economy", "ShopPriceMultiplier", 1f, "Experimental shop price multiplier."); _bossRewardMultiplier = plugin.Config.Bind("Economy", "BossRewardMultiplier", 1f, "Experimental boss reward multiplier."); _deathCurrencyLossMultiplier = plugin.Config.Bind("Economy", "DeathCurrencyLossMultiplier", 1f, "Reserved death currency loss multiplier."); _playerSpeedMultiplier = plugin.Config.Bind("Movement", "PlayerSpeedMultiplier", 1f, "Player speed multiplier."); _jumpHeightMultiplier = plugin.Config.Bind("Movement", "JumpHeightMultiplier", 1f, "Jump height multiplier."); _dashCooldownMultiplier = plugin.Config.Bind("Movement", "DashCooldownMultiplier", 1f, "Dash cooldown multiplier."); _abilityCostMultiplier = plugin.Config.Bind("Movement", "AbilityCostMultiplier", 1f, "Ability cost multiplier."); _silkCostMultiplier = plugin.Config.Bind("Movement", "SilkCostMultiplier", 1f, "Silk ability cost multiplier."); _oneHitMode = plugin.Config.Bind("System", "OneHitMode", false, "Enable one hit mode."); _mutatorNoHealing = plugin.Config.Bind("Mutators", "NoHealing", false, "Disable normal healing."); _mutatorLowGravity = plugin.Config.Bind("Mutators", "LowGravity", false, "Slightly increases jump feel through the existing jump hook."); _mutatorDoubleDamage = plugin.Config.Bind("Mutators", "DoubleDamage", false, "Double Hornet outgoing damage."); _mutatorGlassCannon = plugin.Config.Bind("Mutators", "GlassCannon", false, "Large outgoing damage with higher incoming damage."); _mutatorFastEnemies = plugin.Config.Bind("Mutators", "FastEnemies", false, "Experimental enemy speed mutator."); _mutatorTankEnemies = plugin.Config.Bind("Mutators", "TankEnemies", false, "Common enemies effectively take less damage."); _mutatorAggressiveEnemies = plugin.Config.Bind("Mutators", "AggressiveEnemies", false, "Experimental enemy pressure mutator."); _mutatorRandomizedEnemyHealth = plugin.Config.Bind("Mutators", "RandomizedEnemyHealth", false, "Experimental randomized enemy effective health."); _mutatorRichWorld = plugin.Config.Bind("Mutators", "RichWorld", false, "Increase world drops."); _mutatorPoorWorld = plugin.Config.Bind("Mutators", "PoorWorld", false, "Reduce world drops."); _mutatorExpensiveShops = plugin.Config.Bind("Mutators", "ExpensiveShops", false, "Experimental shop price mutator."); _mutatorNoDeathLoss = plugin.Config.Bind("Mutators", "NoDeathLoss", false, "Reserved death-loss mutator stored for future hooks."); _mutatorBossFrenzy = plugin.Config.Bind("Mutators", "BossFrenzy", false, "Boss fights receive extra pressure through safe existing hooks."); _mutatorNoMercy = plugin.Config.Bind("Mutators", "NoMercy", false, "Disable healing during boss fights."); _mutatorExtendedFights = plugin.Config.Bind("Mutators", "ExtendedFights", false, "Bosses effectively take less damage."); _bossProfilesEnabled = plugin.Config.Bind("BossProfiles", "Enabled", false, "Experimental boss profile matching by object or component name."); _bossProfilesFallbackGlobal = plugin.Config.Bind("BossProfiles", "FallbackGlobal", true, "Use global boss settings when a boss profile is not identified."); _contextBossRulesEnabled = plugin.Config.Bind("ContextRules", "BossRulesEnabled", false, "Reserved context rule for boss fights."); _contextExplorationRulesEnabled = plugin.Config.Bind("ContextRules", "ExplorationRulesEnabled", false, "Reserved context rule for exploration."); _contextLowHealthRuleEnabled = plugin.Config.Bind("ContextRules", "LowHealthRuleEnabled", false, "Reserved context rule for low health."); _contextDeathStreakTrackingEnabled = plugin.Config.Bind("ContextRules", "DeathStreakTrackingEnabled", false, "Reserved context rule for repeated deaths."); _adaptiveDifficultyEnabled = plugin.Config.Bind("Adaptive", "Enabled", false, "Enable adaptive difficulty structure. Default is off."); _adaptiveBossAssistEnabled = plugin.Config.Bind("Adaptive", "BossAssist", false, "Reserved adaptive boss assistance."); _adaptiveExplorationAssistEnabled = plugin.Config.Bind("Adaptive", "ExplorationAssist", false, "Reserved adaptive exploration assistance."); _adaptiveEconomyAssistEnabled = plugin.Config.Bind("Adaptive", "EconomyAssist", false, "Reserved adaptive economy assistance."); _adaptiveMaxAssist = plugin.Config.Bind("Adaptive", "MaxAssist", 0.25f, "Maximum adaptive assistance from 0.0 to 1.0."); _adaptiveApplyMode = plugin.Config.Bind("Adaptive", "ApplyMode", 0, "0=suggest only, 1=confirm, 2=automatic."); _appliedSettings = ReadSettingsFromConfig(); _draftSettings = _appliedSettings.Clone(); } public KeyCode GetOpenMenuKey() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return _openMenuKey.Value; } public DifficultySettings GetAppliedSettings() { return _appliedSettings; } public DifficultySettings GetDraftSettings() { return _draftSettings; } public bool HasUnsavedChanges() { return !_draftSettings.IsEquivalent(_appliedSettings); } public void ResetDraftToApplied() { _draftSettings = _appliedSettings.Clone(); } public void ResetDraftToDefaults() { _draftSettings = DifficultySettings.CreateDefaults(); } public void SetDraftSettings(DifficultySettings settings) { _draftSettings = ((settings != null) ? settings.Clone() : DifficultySettings.CreateDefaults()); _draftSettings.Clamp(); } public void ApplyPresetToDraft(DifficultyPreset preset) { if (preset != DifficultyPreset.Custom) { _draftSettings.ApplyPreset(preset); } } public void ApplyDraft() { _draftSettings.Clamp(); _baseDamage.Value = _draftSettings.BaseDamage; _baseHealth.Value = _draftSettings.BaseHealth; _dropRate.Value = _draftSettings.DropRate; _damageTakenMultiplier.Value = _draftSettings.DamageTakenMultiplier; _healingMultiplier.Value = _draftSettings.HealingMultiplier; _healingCostMultiplier.Value = _draftSettings.HealingCostMultiplier; _invincibilityTimeMultiplier.Value = _draftSettings.InvincibilityTimeMultiplier; _skillDamageMultiplier.Value = _draftSettings.SkillDamageMultiplier; _silkSpearDamageMultiplier.Value = _draftSettings.SilkSpearDamageMultiplier; _bossDamageMultiplier.Value = _draftSettings.BossDamageMultiplier; _commonEnemyDamageMultiplier.Value = _draftSettings.CommonEnemyDamageMultiplier; _criticalChance.Value = _draftSettings.CriticalChance; _criticalDamageMultiplier.Value = _draftSettings.CriticalDamageMultiplier; _environmentalDamageMultiplier.Value = _draftSettings.EnvironmentalDamageMultiplier; _bossDamageTakenMultiplier.Value = _draftSettings.BossDamageTakenMultiplier; _commonEnemyDamageTakenMultiplier.Value = _draftSettings.CommonEnemyDamageTakenMultiplier; _enemyHealthMultiplier.Value = _draftSettings.EnemyHealthMultiplier; _enemyDamageMultiplier.Value = _draftSettings.EnemyDamageMultiplier; _enemySpeedMultiplier.Value = _draftSettings.EnemySpeedMultiplier; _enemyAttackCooldownMultiplier.Value = _draftSettings.EnemyAttackCooldownMultiplier; _enemyAggressionMultiplier.Value = _draftSettings.EnemyAggressionMultiplier; _bossHealthMultiplier.Value = _draftSettings.BossHealthMultiplier; _bossSpeedMultiplier.Value = _draftSettings.BossSpeedMultiplier; _bossAttackCooldownMultiplier.Value = _draftSettings.BossAttackCooldownMultiplier; _bossBrutalMode.Value = _draftSettings.BossBrutalMode; _disableHealingDuringBoss.Value = _draftSettings.DisableHealingDuringBoss; _healingDuringBossMultiplier.Value = _draftSettings.HealingDuringBossMultiplier; _currencyDropMultiplier.Value = _draftSettings.CurrencyDropMultiplier; _itemDropMultiplier.Value = _draftSettings.ItemDropMultiplier; _shopPriceMultiplier.Value = _draftSettings.ShopPriceMultiplier; _bossRewardMultiplier.Value = _draftSettings.BossRewardMultiplier; _deathCurrencyLossMultiplier.Value = _draftSettings.DeathCurrencyLossMultiplier; _playerSpeedMultiplier.Value = _draftSettings.PlayerSpeedMultiplier; _jumpHeightMultiplier.Value = _draftSettings.JumpHeightMultiplier; _dashCooldownMultiplier.Value = _draftSettings.DashCooldownMultiplier; _abilityCostMultiplier.Value = _draftSettings.AbilityCostMultiplier; _silkCostMultiplier.Value = _draftSettings.SilkCostMultiplier; _oneHitMode.Value = _draftSettings.OneHitMode; _mutatorNoHealing.Value = _draftSettings.MutatorNoHealing; _mutatorLowGravity.Value = _draftSettings.MutatorLowGravity; _mutatorDoubleDamage.Value = _draftSettings.MutatorDoubleDamage; _mutatorGlassCannon.Value = _draftSettings.MutatorGlassCannon; _mutatorFastEnemies.Value = _draftSettings.MutatorFastEnemies; _mutatorTankEnemies.Value = _draftSettings.MutatorTankEnemies; _mutatorAggressiveEnemies.Value = _draftSettings.MutatorAggressiveEnemies; _mutatorRandomizedEnemyHealth.Value = _draftSettings.MutatorRandomizedEnemyHealth; _mutatorRichWorld.Value = _draftSettings.MutatorRichWorld; _mutatorPoorWorld.Value = _draftSettings.MutatorPoorWorld; _mutatorExpensiveShops.Value = _draftSettings.MutatorExpensiveShops; _mutatorNoDeathLoss.Value = _draftSettings.MutatorNoDeathLoss; _mutatorBossFrenzy.Value = _draftSettings.MutatorBossFrenzy; _mutatorNoMercy.Value = _draftSettings.MutatorNoMercy; _mutatorExtendedFights.Value = _draftSettings.MutatorExtendedFights; _bossProfilesEnabled.Value = _draftSettings.BossProfilesEnabled; _bossProfilesFallbackGlobal.Value = _draftSettings.BossProfilesFallbackGlobal; _contextBossRulesEnabled.Value = _draftSettings.ContextBossRulesEnabled; _contextExplorationRulesEnabled.Value = _draftSettings.ContextExplorationRulesEnabled; _contextLowHealthRuleEnabled.Value = _draftSettings.ContextLowHealthRuleEnabled; _contextDeathStreakTrackingEnabled.Value = _draftSettings.ContextDeathStreakTrackingEnabled; _adaptiveDifficultyEnabled.Value = _draftSettings.AdaptiveDifficultyEnabled; _adaptiveBossAssistEnabled.Value = _draftSettings.AdaptiveBossAssistEnabled; _adaptiveExplorationAssistEnabled.Value = _draftSettings.AdaptiveExplorationAssistEnabled; _adaptiveEconomyAssistEnabled.Value = _draftSettings.AdaptiveEconomyAssistEnabled; _adaptiveMaxAssist.Value = _draftSettings.AdaptiveMaxAssist; _adaptiveApplyMode.Value = _draftSettings.AdaptiveApplyMode; _plugin.Config.Save(); _appliedSettings = _draftSettings.Clone(); _settingsRevision++; } private DifficultySettings ReadSettingsFromConfig() { DifficultySettings difficultySettings = DifficultySettings.CreateDefaults(); difficultySettings.BaseDamage = _baseDamage.Value; difficultySettings.BaseHealth = _baseHealth.Value; difficultySettings.DropRate = _dropRate.Value; difficultySettings.DamageTakenMultiplier = _damageTakenMultiplier.Value; difficultySettings.HealingMultiplier = _healingMultiplier.Value; difficultySettings.HealingCostMultiplier = _healingCostMultiplier.Value; difficultySettings.InvincibilityTimeMultiplier = _invincibilityTimeMultiplier.Value; difficultySettings.SkillDamageMultiplier = _skillDamageMultiplier.Value; difficultySettings.SilkSpearDamageMultiplier = _silkSpearDamageMultiplier.Value; difficultySettings.BossDamageMultiplier = _bossDamageMultiplier.Value; difficultySettings.CommonEnemyDamageMultiplier = _commonEnemyDamageMultiplier.Value; difficultySettings.CriticalChance = _criticalChance.Value; difficultySettings.CriticalDamageMultiplier = _criticalDamageMultiplier.Value; difficultySettings.EnvironmentalDamageMultiplier = _environmentalDamageMultiplier.Value; difficultySettings.BossDamageTakenMultiplier = _bossDamageTakenMultiplier.Value; difficultySettings.CommonEnemyDamageTakenMultiplier = _commonEnemyDamageTakenMultiplier.Value; difficultySettings.EnemyHealthMultiplier = _enemyHealthMultiplier.Value; difficultySettings.EnemyDamageMultiplier = _enemyDamageMultiplier.Value; difficultySettings.EnemySpeedMultiplier = _enemySpeedMultiplier.Value; difficultySettings.EnemyAttackCooldownMultiplier = _enemyAttackCooldownMultiplier.Value; difficultySettings.EnemyAggressionMultiplier = _enemyAggressionMultiplier.Value; difficultySettings.BossHealthMultiplier = _bossHealthMultiplier.Value; difficultySettings.BossSpeedMultiplier = _bossSpeedMultiplier.Value; difficultySettings.BossAttackCooldownMultiplier = _bossAttackCooldownMultiplier.Value; difficultySettings.BossBrutalMode = _bossBrutalMode.Value; difficultySettings.DisableHealingDuringBoss = _disableHealingDuringBoss.Value; difficultySettings.HealingDuringBossMultiplier = _healingDuringBossMultiplier.Value; difficultySettings.CurrencyDropMultiplier = _currencyDropMultiplier.Value; difficultySettings.ItemDropMultiplier = _itemDropMultiplier.Value; difficultySettings.ShopPriceMultiplier = _shopPriceMultiplier.Value; difficultySettings.BossRewardMultiplier = _bossRewardMultiplier.Value; difficultySettings.DeathCurrencyLossMultiplier = _deathCurrencyLossMultiplier.Value; difficultySettings.PlayerSpeedMultiplier = _playerSpeedMultiplier.Value; difficultySettings.JumpHeightMultiplier = _jumpHeightMultiplier.Value; difficultySettings.DashCooldownMultiplier = _dashCooldownMultiplier.Value; difficultySettings.AbilityCostMultiplier = _abilityCostMultiplier.Value; difficultySettings.SilkCostMultiplier = _silkCostMultiplier.Value; difficultySettings.OneHitMode = _oneHitMode.Value; difficultySettings.MutatorNoHealing = _mutatorNoHealing.Value; difficultySettings.MutatorLowGravity = _mutatorLowGravity.Value; difficultySettings.MutatorDoubleDamage = _mutatorDoubleDamage.Value; difficultySettings.MutatorGlassCannon = _mutatorGlassCannon.Value; difficultySettings.MutatorFastEnemies = _mutatorFastEnemies.Value; difficultySettings.MutatorTankEnemies = _mutatorTankEnemies.Value; difficultySettings.MutatorAggressiveEnemies = _mutatorAggressiveEnemies.Value; difficultySettings.MutatorRandomizedEnemyHealth = _mutatorRandomizedEnemyHealth.Value; difficultySettings.MutatorRichWorld = _mutatorRichWorld.Value; difficultySettings.MutatorPoorWorld = _mutatorPoorWorld.Value; difficultySettings.MutatorExpensiveShops = _mutatorExpensiveShops.Value; difficultySettings.MutatorNoDeathLoss = _mutatorNoDeathLoss.Value; difficultySettings.MutatorBossFrenzy = _mutatorBossFrenzy.Value; difficultySettings.MutatorNoMercy = _mutatorNoMercy.Value; difficultySettings.MutatorExtendedFights = _mutatorExtendedFights.Value; difficultySettings.BossProfilesEnabled = _bossProfilesEnabled.Value; difficultySettings.BossProfilesFallbackGlobal = _bossProfilesFallbackGlobal.Value; difficultySettings.ContextBossRulesEnabled = _contextBossRulesEnabled.Value; difficultySettings.ContextExplorationRulesEnabled = _contextExplorationRulesEnabled.Value; difficultySettings.ContextLowHealthRuleEnabled = _contextLowHealthRuleEnabled.Value; difficultySettings.ContextDeathStreakTrackingEnabled = _contextDeathStreakTrackingEnabled.Value; difficultySettings.AdaptiveDifficultyEnabled = _adaptiveDifficultyEnabled.Value; difficultySettings.AdaptiveBossAssistEnabled = _adaptiveBossAssistEnabled.Value; difficultySettings.AdaptiveExplorationAssistEnabled = _adaptiveExplorationAssistEnabled.Value; difficultySettings.AdaptiveEconomyAssistEnabled = _adaptiveEconomyAssistEnabled.Value; difficultySettings.AdaptiveMaxAssist = _adaptiveMaxAssist.Value; difficultySettings.AdaptiveApplyMode = _adaptiveApplyMode.Value; difficultySettings.Clamp(); return difficultySettings; } } internal static class CustomDifficultyContextRules { public static bool HasAnyRuleEnabled(DifficultySettings settings) { if (settings == null) { return false; } if (!settings.ContextBossRulesEnabled && !settings.ContextExplorationRulesEnabled && !settings.ContextLowHealthRuleEnabled) { return settings.ContextDeathStreakTrackingEnabled; } return true; } } internal sealed class DifficultySummary { public string RatingKey; public float Score; public readonly List Lines = new List(); } internal static class CustomDifficultyDifficultySummary { public static DifficultySummary Build(DifficultySettings settings, CustomDifficultyLocalizationManager localization) { DifficultySettings difficultySettings = DifficultySettings.CreateDefaults(); DifficultySummary difficultySummary = new DifficultySummary(); float num = 0f; num += PercentDelta(settings.DamageTakenMultiplier, difficultySettings.DamageTakenMultiplier) * 1.6f; num += PercentDelta(settings.BossDamageTakenMultiplier, difficultySettings.BossDamageTakenMultiplier) * 1.2f; num += PercentDelta(settings.CommonEnemyDamageTakenMultiplier, difficultySettings.CommonEnemyDamageTakenMultiplier) * 0.9f; num += PercentDelta(settings.EnemyDamageMultiplier, difficultySettings.EnemyDamageMultiplier) * 1f; num += PercentDelta(settings.EnemyHealthMultiplier, difficultySettings.EnemyHealthMultiplier) * 0.8f; num += PercentDelta(settings.BossHealthMultiplier, difficultySettings.BossHealthMultiplier) * 1.4f; num += PercentDelta(settings.ShopPriceMultiplier, difficultySettings.ShopPriceMultiplier) * 0.5f; num -= PercentDelta(settings.BaseHealth, difficultySettings.BaseHealth) * 1.5f; num -= PercentDelta(settings.BaseDamage, difficultySettings.BaseDamage) * 1.2f; num -= PercentDelta(settings.HealingMultiplier, difficultySettings.HealingMultiplier) * 1f; num += PercentDelta(settings.HealingCostMultiplier, difficultySettings.HealingCostMultiplier) * 0.8f; num -= PercentDelta(settings.DropRate, difficultySettings.DropRate) * 0.4f; num -= PercentDelta(settings.CurrencyDropMultiplier, difficultySettings.CurrencyDropMultiplier) * 0.3f; num -= PercentDelta(settings.ItemDropMultiplier, difficultySettings.ItemDropMultiplier) * 0.3f; if (settings.OneHitMode) { num += 120f; } if (settings.MutatorNoHealing) { num += 40f; } if (settings.MutatorGlassCannon) { num += 25f; } if (settings.MutatorBossFrenzy) { num += 30f; } if (settings.MutatorNoMercy) { num += 30f; } if (settings.MutatorExtendedFights || settings.MutatorTankEnemies) { num += 18f; } if (settings.MutatorRichWorld) { num -= 16f; } if (settings.MutatorPoorWorld) { num += 14f; } difficultySummary.Score = num; difficultySummary.RatingKey = GetRatingKey(num, settings); difficultySummary.Lines.Add(localization.Get("summary_player_health") + ": " + FormatIntDelta(settings.BaseHealth, difficultySettings.BaseHealth)); difficultySummary.Lines.Add(localization.Get("summary_damage_taken") + ": " + FormatMultiplierDelta(settings.DamageTakenMultiplier, difficultySettings.DamageTakenMultiplier)); difficultySummary.Lines.Add(localization.Get("summary_hornet_damage") + ": " + FormatIntDelta(settings.BaseDamage, difficultySettings.BaseDamage)); difficultySummary.Lines.Add(localization.Get("summary_bosses") + ": " + DescribeBosses(settings, localization)); difficultySummary.Lines.Add(localization.Get("summary_enemies") + ": " + DescribeEnemies(settings, localization)); difficultySummary.Lines.Add(localization.Get("summary_economy") + ": " + DescribeEconomy(settings, localization)); difficultySummary.Lines.Add(localization.Get("summary_healing") + ": " + DescribeHealing(settings, localization)); difficultySummary.Lines.Add(localization.Get("summary_drops") + ": " + FormatMultiplierDelta(settings.DropRate * settings.CurrencyDropMultiplier * CustomDifficultyMutatorManager.GetDropMultiplier(settings), 1f)); difficultySummary.Lines.Add(localization.Get("summary_mutators") + ": " + CustomDifficultyMutatorManager.CountEnabled(settings)); return difficultySummary; } private static string GetRatingKey(float score, DifficultySettings settings) { if (settings.OneHitMode || score >= 95f) { return "rating_chaotic"; } if (score >= 65f) { return "rating_extreme"; } if (score >= 28f) { return "rating_hard"; } if (score <= -45f) { return "rating_very_easy"; } if (score <= -18f) { return "rating_easy"; } return "rating_normal"; } private static string DescribeBosses(DifficultySettings settings, CustomDifficultyLocalizationManager localization) { float num = settings.BossHealthMultiplier * settings.BossDamageTakenMultiplier; if (settings.BossBrutalMode || settings.MutatorBossFrenzy || settings.MutatorExtendedFights) { num += 0.35f; } return DescribePressure(num, localization); } private static string DescribeEnemies(DifficultySettings settings, CustomDifficultyLocalizationManager localization) { float num = settings.EnemyHealthMultiplier * settings.EnemyDamageMultiplier * settings.CommonEnemyDamageTakenMultiplier; if (settings.MutatorTankEnemies || settings.MutatorAggressiveEnemies) { num += 0.25f; } return DescribePressure(num, localization); } private static string DescribeEconomy(DifficultySettings settings, CustomDifficultyLocalizationManager localization) { float num = settings.CurrencyDropMultiplier * settings.DropRate / Math.Max(0.1f, settings.ShopPriceMultiplier); num *= CustomDifficultyMutatorManager.GetDropMultiplier(settings); num /= Math.Max(0.1f, CustomDifficultyMutatorManager.GetShopPriceMultiplier(settings)); if (num >= 1.35f) { return localization.Get("summary_generous"); } if (num <= 0.75f) { return localization.Get("summary_strict"); } return localization.Get("summary_normal"); } private static string DescribeHealing(DifficultySettings settings, CustomDifficultyLocalizationManager localization) { if (settings.MutatorNoHealing || settings.OneHitMode) { return localization.Get("summary_blocked"); } float num = settings.HealingMultiplier / Math.Max(0.1f, settings.HealingCostMultiplier); if (settings.DisableHealingDuringBoss || settings.MutatorNoMercy) { num *= 0.65f; } if (num >= 1.25f) { return localization.Get("summary_generous"); } if (num <= 0.75f) { return localization.Get("summary_reduced"); } return localization.Get("summary_normal"); } private static string DescribePressure(float value, CustomDifficultyLocalizationManager localization) { if (value >= 1.75f) { return localization.Get("summary_much_harder"); } if (value >= 1.2f) { return localization.Get("summary_slightly_harder"); } if (value <= 0.8f) { return localization.Get("summary_easier"); } return localization.Get("summary_normal"); } private static string FormatMultiplierDelta(float current, float defaults) { float num = (current - defaults) * 100f; if (Math.Abs(num) < 0.1f) { return "x" + current.ToString("0.0") + " (default)"; } return "x" + current.ToString("0.0") + " (" + ((num > 0f) ? "+" : string.Empty) + num.ToString("0") + "%)"; } private static string FormatIntDelta(int current, int defaults) { int num = current - defaults; if (num == 0) { return current + " (default)"; } return current + " (" + ((num > 0) ? "+" : string.Empty) + num + ")"; } private static float PercentDelta(float current, float defaults) { if (Math.Abs(defaults) < 0.001f) { return current * 100f; } return (current - defaults) / defaults * 100f; } private static float PercentDelta(int current, int defaults) { if (defaults == 0) { return (float)current * 100f; } return (float)(current - defaults) / (float)defaults * 100f; } } internal sealed class CustomDifficultyFavorites { private readonly BaseUnityPlugin _plugin; private readonly ConfigEntry _favoriteOptionIds; private readonly HashSet _favorites = new HashSet(StringComparer.OrdinalIgnoreCase); public int Count => _favorites.Count; public CustomDifficultyFavorites(BaseUnityPlugin plugin) { _plugin = plugin; _favoriteOptionIds = plugin.Config.Bind("Menu", "FavoriteOptionIds", "[]", "JSON array with Custom Difficulty menu option ids marked as favorites."); Load(); } public bool IsFavorite(string optionId) { if (!string.IsNullOrEmpty(optionId)) { return _favorites.Contains(optionId); } return false; } public void Toggle(string optionId) { if (!string.IsNullOrEmpty(optionId)) { if (_favorites.Contains(optionId)) { _favorites.Remove(optionId); } else { _favorites.Add(optionId); } Save(); } } public List GetAll() { return new List(_favorites); } public void ReplaceAll(IEnumerable optionIds) { _favorites.Clear(); if (optionIds != null) { foreach (string optionId in optionIds) { if (!string.IsNullOrEmpty(optionId)) { _favorites.Add(optionId); } } } Save(); } private void Load() { _favorites.Clear(); try { List list = JsonConvert.DeserializeObject>(_favoriteOptionIds.Value); if (list == null) { return; } foreach (string item in list) { if (!string.IsNullOrEmpty(item)) { _favorites.Add(item); } } } catch { _favoriteOptionIds.Value = "[]"; _plugin.Config.Save(); } } private void Save() { _favoriteOptionIds.Value = JsonConvert.SerializeObject((object)GetAll()); _plugin.Config.Save(); } } internal sealed class CustomDifficultyGameplayHooks { private sealed class HealthProfileStateFile { public Dictionary AppliedBaseHealthByProfile = new Dictionary(); public Dictionary BonusHealthByProfile = new Dictionary(); } private sealed class HeroRuntimeDefaults { public int HeroControllerId; public float RunSpeed; public float WalkSpeed; public float QuickeningRunSpeed; public float QuickeningWalkSpeed; public float JumpSpeed; public float MinJumpSpeed; public float DashCooldown; public float InvulTime; public float InvulTimeCrossStitch; public float InvulTimeParry; public float InvulTimeQuake; public float InvulTimeSilkDash; } private static readonly FieldInfo MaxHealthField = AccessTools.Field(typeof(PlayerData), "maxHealth"); private static readonly FieldInfo MaxHealthBaseField = AccessTools.Field(typeof(PlayerData), "maxHealthBase"); private static readonly FieldInfo HealthField = AccessTools.Field(typeof(PlayerData), "health"); private static readonly FieldInfo PrevHealthField = AccessTools.Field(typeof(PlayerData), "prevHealth"); private static readonly FieldInfo ProfileIdField = AccessTools.Field(typeof(PlayerData), "profileID"); private static readonly MethodInfo PlayerDataMaxHealthMethod = AccessTools.Method(typeof(PlayerData), "MaxHealth", (Type[])null, (Type[])null); private static readonly MethodInfo HeroControllerMaxHealthKeepBlueMethod = AccessTools.Method(typeof(HeroController), "MaxHealthKeepBlue", (Type[])null, (Type[])null); private static readonly FieldInfo HeroRunSpeedField = AccessTools.Field(typeof(HeroController), "RUN_SPEED"); private static readonly FieldInfo HeroWalkSpeedField = AccessTools.Field(typeof(HeroController), "WALK_SPEED"); private static readonly FieldInfo HeroQuickeningRunSpeedField = AccessTools.Field(typeof(HeroController), "QUICKENING_RUN_SPEED"); private static readonly FieldInfo HeroQuickeningWalkSpeedField = AccessTools.Field(typeof(HeroController), "QUICKENING_WALK_SPEED"); private static readonly FieldInfo HeroJumpSpeedField = AccessTools.Field(typeof(HeroController), "JUMP_SPEED"); private static readonly FieldInfo HeroMinJumpSpeedField = AccessTools.Field(typeof(HeroController), "MIN_JUMP_SPEED"); private static readonly FieldInfo HeroDashCooldownField = AccessTools.Field(typeof(HeroController), "DASH_COOLDOWN"); private static readonly FieldInfo HeroDashCooldownTimerField = AccessTools.Field(typeof(HeroController), "dashCooldownTimer"); private static readonly FieldInfo HeroInvulTimeField = AccessTools.Field(typeof(HeroController), "INVUL_TIME"); private static readonly FieldInfo HeroInvulTimeCrossStitchField = AccessTools.Field(typeof(HeroController), "INVUL_TIME_CROSS_STITCH"); private static readonly FieldInfo HeroInvulTimeParryField = AccessTools.Field(typeof(HeroController), "INVUL_TIME_PARRY"); private static readonly FieldInfo HeroInvulTimeQuakeField = AccessTools.Field(typeof(HeroController), "INVUL_TIME_QUAKE"); private static readonly FieldInfo HeroInvulTimeSilkDashField = AccessTools.Field(typeof(HeroController), "INVUL_TIME_SILKDASH"); private static readonly FieldInfo HeroHarpoonDashCooldownField = AccessTools.Field(typeof(HeroController), "harpoonDashCooldown"); private static readonly FieldInfo DamageEnemiesAttackTypeField = AccessTools.Field(typeof(DamageEnemies), "attackType"); private static readonly FieldInfo DamageEnemiesRepresentingToolField = AccessTools.Field(typeof(DamageEnemies), "representingTool"); private static readonly FieldInfo DamageEnemiesUseNailDamageField = AccessTools.Field(typeof(DamageEnemies), "useNailDamage"); private static readonly FieldInfo DamageEnemiesIsNailAttackField = AccessTools.Field(typeof(DamageEnemies), "isNailAttack"); private static readonly FieldInfo DamageEnemiesDoesNotCriticalHitField = AccessTools.Field(typeof(DamageEnemies), "doesNotCriticalHit"); private static readonly FieldInfo DamageEnemiesSpecialTypeField = AccessTools.Field(typeof(DamageEnemies), "specialType"); private static readonly Dictionary> DamageTargetContexts = new Dictionary>(); [ThreadStatic] private static bool _skipFallbackIncomingDamageScaling; private readonly BaseUnityPlugin _plugin; private readonly CustomDifficultyConfigManager _configManager; private readonly CustomDifficultyBossProfileManager _bossProfileManager; private readonly Dictionary _appliedBaseHealthByProfile = new Dictionary(); private readonly Dictionary _bonusHealthByProfile = new Dictionary(); private readonly Dictionary _randomEnemyHealthByTarget = new Dictionary(); private readonly HashSet _reportedBossProfiles = new HashSet(StringComparer.OrdinalIgnoreCase); private readonly HashSet _trackedHealthProfiles = new HashSet(); private readonly string _stateFilePath; private HeroRuntimeDefaults _heroRuntimeDefaults; private int _lastProfileId = -1; private int _lastSettingsRevision = -1; private int _lastHeroControllerId = -1; private float _lastSyncAt = -99f; private bool _healthUiSynced; private float _lastBossSceneRefreshAt = -99f; private bool _cachedBossSceneActive; public static CustomDifficultyGameplayHooks Instance; public CustomDifficultyGameplayHooks(BaseUnityPlugin plugin, CustomDifficultyConfigManager configManager, CustomDifficultyBossProfileManager bossProfileManager) { _plugin = plugin; _configManager = configManager; _bossProfileManager = bossProfileManager; _stateFilePath = Path.Combine(Paths.ConfigPath, "CustomDifficulty", "profile-health-state.json"); LoadProfileState(); Instance = this; } public void Update() { ApplyHeroRuntimeTuning(); if (PlayerData.HasInstance) { PlayerData instance = PlayerData.instance; int profileId = GetProfileId(instance); int num = (((Object)(object)HeroController.instance != (Object)null) ? ((Object)HeroController.instance).GetInstanceID() : (-1)); bool flag = false; if (profileId != _lastProfileId) { _lastProfileId = profileId; _healthUiSynced = false; flag = true; } if (_lastSettingsRevision != _configManager.SettingsRevision) { _lastSettingsRevision = _configManager.SettingsRevision; _healthUiSynced = false; flag = true; } if (num != _lastHeroControllerId) { _lastHeroControllerId = num; _healthUiSynced = false; _heroRuntimeDefaults = null; flag = true; } if (Time.unscaledTime - _lastSyncAt > 1f) { flag = true; } if (flag) { SyncBaseHealth(instance, force: false); } } } public void ApplyImmediateChanges() { _lastSettingsRevision = _configManager.SettingsRevision; _lastSyncAt = -99f; _lastBossSceneRefreshAt = -99f; _randomEnemyHealthByTarget.Clear(); _reportedBossProfiles.Clear(); if (PlayerData.HasInstance) { SyncBaseHealth(PlayerData.instance, force: true); } ApplyHeroRuntimeTuning(); } public void RegisterPermanentHealthUpgrade(int amount) { if (amount > 0 && PlayerData.HasInstance) { int profileId = GetProfileId(PlayerData.instance); if (_trackedHealthProfiles.Contains(profileId)) { int value = 0; _bonusHealthByProfile.TryGetValue(profileId, out value); _bonusHealthByProfile[profileId] = Math.Max(0, value + amount); SaveProfileState(); } } } public int GetScaledBaseDamage(int vanillaDamage) { DifficultySettings appliedSettings = _configManager.GetAppliedSettings(); int num = 0; if (vanillaDamage > 5) { num = Math.Max(0, (vanillaDamage - 5) / 4); } int val = appliedSettings.BaseDamage + num * 4; return Math.Max(1, Math.Min(99999, val)); } public int ScaleHealingAmount(int amount) { if (amount <= 0) { return amount; } DifficultySettings appliedSettings = _configManager.GetAppliedSettings(); bool flag = IsInBossScene(); if (CustomDifficultyMutatorManager.BlocksHealing(appliedSettings, flag)) { return 0; } float num = appliedSettings.HealingMultiplier; if (flag) { if (appliedSettings.DisableHealingDuringBoss) { return 0; } num *= appliedSettings.HealingDuringBossMultiplier; if (appliedSettings.BossBrutalMode) { num *= 0.75f; } } num *= CustomDifficultyMutatorManager.GetHealingMultiplier(appliedSettings, flag); return RoundScaledAmount(amount, num, allowZero: false); } public int ScaleSilkCost(int amount, string silkTakeSourceName) { if (amount <= 0) { return amount; } DifficultySettings appliedSettings = _configManager.GetAppliedSettings(); float num = 1f; string a = silkTakeSourceName ?? string.Empty; if (string.Equals(a, "ActiveUse", StringComparison.OrdinalIgnoreCase)) { num *= appliedSettings.AbilityCostMultiplier; num *= appliedSettings.SilkCostMultiplier; } else if (string.Equals(a, "Normal", StringComparison.OrdinalIgnoreCase)) { num *= appliedSettings.HealingCostMultiplier; } return RoundScaledAmount(amount, num, allowZero: true); } public int ScaleSkillCost(int amount) { if (amount <= 0) { return amount; } DifficultySettings appliedSettings = _configManager.GetAppliedSettings(); return RoundScaledAmount(amount, appliedSettings.AbilityCostMultiplier * appliedSettings.SilkCostMultiplier, allowZero: true); } public int ScaleFallbackIncomingDamage(int amount) { if (amount <= 0) { return amount; } if (_skipFallbackIncomingDamageScaling) { return amount; } DifficultySettings appliedSettings = _configManager.GetAppliedSettings(); if (appliedSettings.OneHitMode && PlayerData.HasInstance) { return Math.Max(1, GetFieldValue(HealthField, PlayerData.instance)); } float damageTakenMultiplier = appliedSettings.DamageTakenMultiplier; damageTakenMultiplier *= CustomDifficultyMutatorManager.GetIncomingDamageMultiplier(appliedSettings, isBoss: false, isEnvironmental: false); return RoundScaledAmount(amount, damageTakenMultiplier, allowZero: true); } public int ScaleDetailedIncomingDamage(GameObject source, int amount, object hazardType) { if (amount <= 0) { return amount; } DifficultySettings appliedSettings = _configManager.GetAppliedSettings(); if (appliedSettings.OneHitMode && PlayerData.HasInstance) { return Math.Max(1, GetFieldValue(HealthField, PlayerData.instance)); } float num = appliedSettings.DamageTakenMultiplier; bool flag = IsBossGameObject(source); bool flag2 = IsEnvironmentalHazard(source, hazardType); if (flag2) { num *= appliedSettings.EnvironmentalDamageMultiplier; } else if (flag) { if (TryGetBossProfile(source, out var profile)) { num *= Math.Max(0f, profile.DamageMultiplier); } else if (!appliedSettings.BossProfilesEnabled || appliedSettings.BossProfilesFallbackGlobal) { num *= appliedSettings.BossDamageTakenMultiplier; if (appliedSettings.BossBrutalMode) { num *= 1.25f; } } } else { num *= appliedSettings.CommonEnemyDamageTakenMultiplier; num *= appliedSettings.EnemyDamageMultiplier; } num *= CustomDifficultyMutatorManager.GetIncomingDamageMultiplier(appliedSettings, flag, flag2); return RoundScaledAmount(amount, num, allowZero: true); } public int ScaleCurrencyDrop(int amount) { if (amount <= 0) { return amount; } DifficultySettings appliedSettings = _configManager.GetAppliedSettings(); float num = appliedSettings.DropRate * appliedSettings.CurrencyDropMultiplier * CustomDifficultyMutatorManager.GetDropMultiplier(appliedSettings); if (IsInBossScene()) { num *= appliedSettings.BossRewardMultiplier; } return ScaleDropAmount(amount, num, allowZero: true); } public int ScaleCollectableAmount(CollectableItem item, int amount) { if (!ShouldScaleCollectable(item, amount)) { return amount; } DifficultySettings appliedSettings = _configManager.GetAppliedSettings(); return ScaleDropAmount(amount, appliedSettings.DropRate * appliedSettings.ItemDropMultiplier * CustomDifficultyMutatorManager.GetDropMultiplier(appliedSettings), allowZero: false); } public int ScaleOutgoingDamage(DamageEnemies damageSource, GameObject target, int baseDamage) { if ((Object)(object)damageSource == (Object)null || baseDamage <= 0) { return baseDamage; } DifficultySettings appliedSettings = _configManager.GetAppliedSettings(); float num = 1f; bool flag = IsBossGameObject(target); bool flag2 = IsLikelySilkSpear(damageSource); bool flag3 = flag2 || IsLikelySkillDamage(damageSource); if (flag2) { num *= appliedSettings.SilkSpearDamageMultiplier; } else if (flag3) { num *= appliedSettings.SkillDamageMultiplier; } if (flag) { if (TryGetBossProfile(target, out var profile)) { num *= Math.Max(0f, profile.HornetDamageMultiplier); num /= Math.Max(0.1f, profile.HealthMultiplier); } else if (!appliedSettings.BossProfilesEnabled || appliedSettings.BossProfilesFallbackGlobal) { num *= appliedSettings.BossDamageMultiplier; num /= Math.Max(0.1f, appliedSettings.BossHealthMultiplier); if (appliedSettings.BossBrutalMode) { num /= 1.35f; } } } else { num *= appliedSettings.CommonEnemyDamageMultiplier; num /= Math.Max(0.1f, appliedSettings.EnemyHealthMultiplier); if (appliedSettings.MutatorRandomizedEnemyHealth) { num /= GetRandomizedEnemyHealthMultiplier(target); } } num *= CustomDifficultyMutatorManager.GetOutgoingDamageMultiplier(appliedSettings, flag); if (ShouldCriticalHit(damageSource, appliedSettings.CriticalChance)) { num *= appliedSettings.CriticalDamageMultiplier; } return RoundScaledAmount(baseDamage, num, allowZero: true); } public int ScaleShopPrice(int amount) { if (amount <= 0) { return amount; } DifficultySettings appliedSettings = _configManager.GetAppliedSettings(); float multiplier = appliedSettings.ShopPriceMultiplier * CustomDifficultyMutatorManager.GetShopPriceMultiplier(appliedSettings); return RoundScaledAmount(amount, multiplier, allowZero: false); } public void PushDamageTarget(DamageEnemies damageSource, GameObject target) { if (!((Object)(object)damageSource == (Object)null)) { int instanceID = ((Object)damageSource).GetInstanceID(); if (!DamageTargetContexts.TryGetValue(instanceID, out var value)) { value = new Stack(); DamageTargetContexts[instanceID] = value; } value.Push(target); } } public void PopDamageTarget(DamageEnemies damageSource) { if ((Object)(object)damageSource == (Object)null) { return; } int instanceID = ((Object)damageSource).GetInstanceID(); if (DamageTargetContexts.TryGetValue(instanceID, out var value)) { if (value.Count > 0) { value.Pop(); } if (value.Count == 0) { DamageTargetContexts.Remove(instanceID); } } } public GameObject PeekDamageTarget(DamageEnemies damageSource) { if ((Object)(object)damageSource == (Object)null) { return null; } if (!DamageTargetContexts.TryGetValue(((Object)damageSource).GetInstanceID(), out var value) || value.Count == 0) { return null; } return value.Peek(); } private int ScaleDropAmount(int amount, float multiplier, bool allowZero) { float num = (float)amount * multiplier; int num2 = (int)Math.Floor(num); float num3 = num - (float)num2; if (Random.value < num3) { num2++; } if (!allowZero && amount > 0) { return Math.Max(1, num2); } return Math.Max(0, num2); } private static bool ShouldScaleCollectable(CollectableItem item, int amount) { if ((Object)(object)item == (Object)null || amount <= 0) { return false; } if (amount <= 1 && !(item is CollectableItemStack) && !item.DisplayAmount) { return false; } return true; } private void SyncBaseHealth(PlayerData playerData, bool force) { if (playerData == null) { return; } int profileId = GetProfileId(playerData); int value = 5; bool flag = _appliedBaseHealthByProfile.TryGetValue(profileId, out value); int fieldValue = GetFieldValue(MaxHealthBaseField, playerData); int fieldValue2 = GetFieldValue(MaxHealthField, playerData); int fieldValue3 = GetFieldValue(HealthField, playerData); int value2 = 0; _bonusHealthByProfile.TryGetValue(profileId, out value2); int baseHealth = _configManager.GetAppliedSettings().BaseHealth; int num = baseHealth + value2; if (num < 1) { num = 1; } bool flag2 = flag && value == baseHealth && fieldValue == num && fieldValue2 == num; if (!force && flag2 && ((Object)(object)HeroController.instance == (Object)null || _healthUiSynced)) { _lastSyncAt = Time.unscaledTime; return; } int num2 = fieldValue2 - fieldValue3; if (num2 < 0) { num2 = 0; } int num3 = 0; if (fieldValue3 > 0) { num3 = num - num2; if (num3 < 1) { num3 = 1; } if (num3 > num) { num3 = num; } } SetFieldValue(MaxHealthBaseField, playerData, num); SetFieldValue(MaxHealthField, playerData, num); SetFieldValue(HealthField, playerData, num3); SetFieldValue(PrevHealthField, playerData, num3); RefreshHealthUi(playerData, num, num3); _appliedBaseHealthByProfile[profileId] = baseHealth; _trackedHealthProfiles.Add(profileId); SaveProfileState(); EventRegister.SendEvent(EventRegisterEvents.HealthUpdate, (GameObject)null); EventRegister.SendEvent(EventRegisterEvents.UpdateBlueHealth, (GameObject)null); if ((Object)(object)HeroController.instance != (Object)null) { HeroController.instance.UpdateBlueHealth(); } _healthUiSynced = (Object)(object)HeroController.instance != (Object)null && num3 > 0; _lastSyncAt = Time.unscaledTime; } private void ApplyHeroRuntimeTuning() { HeroController instance = HeroController.instance; if ((Object)(object)instance == (Object)null) { return; } EnsureHeroDefaults(instance); if (_heroRuntimeDefaults != null) { DifficultySettings appliedSettings = _configManager.GetAppliedSettings(); float num = appliedSettings.InvincibilityTimeMultiplier; if (appliedSettings.BossBrutalMode && IsInBossScene()) { num *= 0.85f; } SetFloatField(HeroRunSpeedField, instance, _heroRuntimeDefaults.RunSpeed * appliedSettings.PlayerSpeedMultiplier); SetFloatField(HeroWalkSpeedField, instance, _heroRuntimeDefaults.WalkSpeed * appliedSettings.PlayerSpeedMultiplier); SetFloatField(HeroQuickeningRunSpeedField, instance, _heroRuntimeDefaults.QuickeningRunSpeed * appliedSettings.PlayerSpeedMultiplier); SetFloatField(HeroQuickeningWalkSpeedField, instance, _heroRuntimeDefaults.QuickeningWalkSpeed * appliedSettings.PlayerSpeedMultiplier); float num2 = appliedSettings.JumpHeightMultiplier * CustomDifficultyMutatorManager.GetJumpMultiplier(appliedSettings); SetFloatField(HeroJumpSpeedField, instance, _heroRuntimeDefaults.JumpSpeed * num2); SetFloatField(HeroMinJumpSpeedField, instance, _heroRuntimeDefaults.MinJumpSpeed * num2); SetFloatField(HeroDashCooldownField, instance, _heroRuntimeDefaults.DashCooldown * appliedSettings.DashCooldownMultiplier); SetFloatField(HeroInvulTimeField, instance, _heroRuntimeDefaults.InvulTime * num); SetFloatField(HeroInvulTimeCrossStitchField, instance, _heroRuntimeDefaults.InvulTimeCrossStitch * num); SetFloatField(HeroInvulTimeParryField, instance, _heroRuntimeDefaults.InvulTimeParry * num); SetFloatField(HeroInvulTimeQuakeField, instance, _heroRuntimeDefaults.InvulTimeQuake * num); SetFloatField(HeroInvulTimeSilkDashField, instance, _heroRuntimeDefaults.InvulTimeSilkDash * num); } } public void SyncDashCooldownTimer(HeroController hero) { if ((Object)(object)hero == (Object)null || HeroDashCooldownTimerField == null || HeroDashCooldownField == null) { return; } try { HeroDashCooldownTimerField.SetValue(hero, HeroDashCooldownField.GetValue(hero)); } catch { } } public void ScaleHarpoonDashCooldown(HeroController hero) { if ((Object)(object)hero == (Object)null || HeroHarpoonDashCooldownField == null) { return; } try { float num = Convert.ToSingle(HeroHarpoonDashCooldownField.GetValue(hero)); float dashCooldownMultiplier = _configManager.GetAppliedSettings().DashCooldownMultiplier; HeroHarpoonDashCooldownField.SetValue(hero, num * dashCooldownMultiplier); } catch { } } private void EnsureHeroDefaults(HeroController hero) { if (!((Object)(object)hero == (Object)null) && (_heroRuntimeDefaults == null || _heroRuntimeDefaults.HeroControllerId != ((Object)hero).GetInstanceID())) { HeroRuntimeDefaults heroRuntimeDefaults = new HeroRuntimeDefaults(); heroRuntimeDefaults.HeroControllerId = ((Object)hero).GetInstanceID(); heroRuntimeDefaults.RunSpeed = GetFloatField(HeroRunSpeedField, hero, 0f); heroRuntimeDefaults.WalkSpeed = GetFloatField(HeroWalkSpeedField, hero, 0f); heroRuntimeDefaults.QuickeningRunSpeed = GetFloatField(HeroQuickeningRunSpeedField, hero, heroRuntimeDefaults.RunSpeed); heroRuntimeDefaults.QuickeningWalkSpeed = GetFloatField(HeroQuickeningWalkSpeedField, hero, heroRuntimeDefaults.WalkSpeed); heroRuntimeDefaults.JumpSpeed = GetFloatField(HeroJumpSpeedField, hero, 0f); heroRuntimeDefaults.MinJumpSpeed = GetFloatField(HeroMinJumpSpeedField, hero, 0f); heroRuntimeDefaults.DashCooldown = GetFloatField(HeroDashCooldownField, hero, 0f); heroRuntimeDefaults.InvulTime = GetFloatField(HeroInvulTimeField, hero, 0f); heroRuntimeDefaults.InvulTimeCrossStitch = GetFloatField(HeroInvulTimeCrossStitchField, hero, heroRuntimeDefaults.InvulTime); heroRuntimeDefaults.InvulTimeParry = GetFloatField(HeroInvulTimeParryField, hero, heroRuntimeDefaults.InvulTime); heroRuntimeDefaults.InvulTimeQuake = GetFloatField(HeroInvulTimeQuakeField, hero, heroRuntimeDefaults.InvulTime); heroRuntimeDefaults.InvulTimeSilkDash = GetFloatField(HeroInvulTimeSilkDashField, hero, heroRuntimeDefaults.InvulTime); _heroRuntimeDefaults = heroRuntimeDefaults; } } private static void RefreshHealthUi(PlayerData playerData, int desiredMaxHealth, int newHealth) { if (playerData == null || (Object)(object)HeroController.instance == (Object)null || newHealth <= 0) { return; } try { if (HeroControllerMaxHealthKeepBlueMethod != null) { HeroControllerMaxHealthKeepBlueMethod.Invoke(HeroController.instance, null); } else if (PlayerDataMaxHealthMethod != null) { PlayerDataMaxHealthMethod.Invoke(playerData, null); } } catch { } SetFieldValue(MaxHealthBaseField, playerData, desiredMaxHealth); SetFieldValue(MaxHealthField, playerData, desiredMaxHealth); SetFieldValue(HealthField, playerData, newHealth); SetFieldValue(PrevHealthField, playerData, newHealth); } private bool IsInBossScene() { if (Time.unscaledTime - _lastBossSceneRefreshAt < 0.25f) { return _cachedBossSceneActive; } _lastBossSceneRefreshAt = Time.unscaledTime; _cachedBossSceneActive = false; try { if (BossSceneController.IsBossScene) { _cachedBossSceneActive = true; } } catch { _cachedBossSceneActive = false; } return _cachedBossSceneActive; } private bool IsBossGameObject(GameObject gameObject) { if ((Object)(object)gameObject == (Object)null) { return false; } if (HasBossName(((Object)gameObject).name)) { return true; } try { MonoBehaviour[] componentsInParent = gameObject.GetComponentsInParent(true); foreach (MonoBehaviour val in componentsInParent) { if (!((Object)(object)val == (Object)null)) { string name = ((object)val).GetType().Name; if (name.IndexOf("Boss", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } } } catch { } return IsInBossScene(); } private bool TryGetBossProfile(GameObject gameObject, out CustomDifficultyBossProfileData profile) { profile = null; DifficultySettings appliedSettings = _configManager.GetAppliedSettings(); if (!appliedSettings.BossProfilesEnabled || _bossProfileManager == null || (Object)(object)gameObject == (Object)null) { return false; } try { if (_bossProfileManager.TryFindProfile(gameObject, out profile) && profile != null) { ReportBossProfile(profile); return true; } } catch { return false; } return false; } private void ReportBossProfile(CustomDifficultyBossProfileData profile) { if (profile != null) { string text = ((!string.IsNullOrEmpty(profile.DisplayName)) ? profile.DisplayName : profile.InternalName); if (!string.IsNullOrEmpty(text) && !_reportedBossProfiles.Contains(text)) { _reportedBossProfiles.Add(text); CustomDifficultyPlugin.LogInfoSafe("Custom Difficulty boss profile matched: " + text); } } } private float GetRandomizedEnemyHealthMultiplier(GameObject target) { if ((Object)(object)target == (Object)null) { return Random.Range(0.75f, 1.35f); } if (_randomEnemyHealthByTarget.Count > 512) { _randomEnemyHealthByTarget.Clear(); CustomDifficultyPlugin.LogInfoSafe("Custom Difficulty cleared randomized enemy health cache to prevent growth."); } int instanceID = ((Object)target).GetInstanceID(); if (!_randomEnemyHealthByTarget.TryGetValue(instanceID, out var value)) { value = Random.Range(0.75f, 1.35f); _randomEnemyHealthByTarget[instanceID] = value; } return value; } private static bool HasBossName(string name) { if (!string.IsNullOrEmpty(name)) { if (name.IndexOf("Boss", StringComparison.OrdinalIgnoreCase) < 0) { return name.IndexOf("Statue", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } return false; } private static bool IsEnvironmentalHazard(GameObject source, object hazardType) { if ((Object)(object)source == (Object)null) { return true; } string text = ((Object)source).name ?? string.Empty; if (text.IndexOf("spike", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("acid", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("lava", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("hazard", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("thorn", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("trap", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } string text2 = ((hazardType != null) ? hazardType.ToString() : string.Empty); if (text2.IndexOf("spike", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("acid", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("lava", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("hazard", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } return false; } private static bool IsLikelySkillDamage(DamageEnemies damageSource) { string fieldStringValue = GetFieldStringValue(DamageEnemiesAttackTypeField, damageSource); string fieldStringValue2 = GetFieldStringValue(DamageEnemiesRepresentingToolField, damageSource); string fieldStringValue3 = GetFieldStringValue(DamageEnemiesSpecialTypeField, damageSource); if (fieldStringValue.IndexOf("Spell", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (fieldStringValue3.IndexOf("Acid", StringComparison.OrdinalIgnoreCase) >= 0 || fieldStringValue3.IndexOf("Heavy", StringComparison.OrdinalIgnoreCase) >= 0 || fieldStringValue3.IndexOf("Rapid", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (fieldStringValue2.IndexOf("Silk", StringComparison.OrdinalIgnoreCase) >= 0 || fieldStringValue2.IndexOf("Spell", StringComparison.OrdinalIgnoreCase) >= 0 || fieldStringValue2.IndexOf("Bomb", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (!GetFieldBoolValue(DamageEnemiesUseNailDamageField, damageSource, fallback: true)) { return true; } if (!GetFieldBoolValue(DamageEnemiesIsNailAttackField, damageSource, fallback: true)) { return true; } string text = (((Object)(object)((Component)damageSource).gameObject != (Object)null) ? ((Object)((Component)damageSource).gameObject).name : string.Empty); if (text.IndexOf("spell", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("silk", StringComparison.OrdinalIgnoreCase) < 0) { return text.IndexOf("bomb", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static bool IsLikelySilkSpear(DamageEnemies damageSource) { string fieldStringValue = GetFieldStringValue(DamageEnemiesRepresentingToolField, damageSource); string text = (((Object)(object)damageSource != (Object)null && (Object)(object)((Component)damageSource).gameObject != (Object)null) ? ((Object)((Component)damageSource).gameObject).name : string.Empty); if (fieldStringValue.IndexOf("harpoon", StringComparison.OrdinalIgnoreCase) < 0 && fieldStringValue.IndexOf("spear", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("harpoon", StringComparison.OrdinalIgnoreCase) < 0) { return text.IndexOf("spear", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static bool ShouldCriticalHit(DamageEnemies damageSource, float criticalChance) { if ((Object)(object)damageSource == (Object)null || criticalChance <= 0f) { return false; } if (GetFieldBoolValue(DamageEnemiesDoesNotCriticalHitField, damageSource, fallback: false)) { return false; } return Random.value <= criticalChance / 100f; } private static int RoundScaledAmount(int amount, float multiplier, bool allowZero) { int val = (int)Math.Round((float)amount * multiplier, MidpointRounding.AwayFromZero); if (allowZero) { return Math.Max(0, val); } return Math.Max(1, val); } private void LoadProfileState() { if (!File.Exists(_stateFilePath)) { return; } try { string text = File.ReadAllText(_stateFilePath); HealthProfileStateFile healthProfileStateFile = JsonConvert.DeserializeObject(text); if (healthProfileStateFile == null) { return; } if (healthProfileStateFile.AppliedBaseHealthByProfile != null) { foreach (KeyValuePair item in healthProfileStateFile.AppliedBaseHealthByProfile) { if (int.TryParse(item.Key, out var result)) { _appliedBaseHealthByProfile[result] = item.Value; } } } if (healthProfileStateFile.BonusHealthByProfile == null) { return; } foreach (KeyValuePair item2 in healthProfileStateFile.BonusHealthByProfile) { if (int.TryParse(item2.Key, out var result2)) { _bonusHealthByProfile[result2] = Math.Max(0, item2.Value); } } } catch { } } private void SaveProfileState() { try { string directoryName = Path.GetDirectoryName(_stateFilePath); if (!Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } HealthProfileStateFile healthProfileStateFile = new HealthProfileStateFile(); foreach (KeyValuePair item in _appliedBaseHealthByProfile) { healthProfileStateFile.AppliedBaseHealthByProfile[item.Key.ToString()] = item.Value; } foreach (KeyValuePair item2 in _bonusHealthByProfile) { healthProfileStateFile.BonusHealthByProfile[item2.Key.ToString()] = Math.Max(0, item2.Value); } File.WriteAllText(_stateFilePath, JsonConvert.SerializeObject((object)healthProfileStateFile, (Formatting)1)); } catch { } } private static int GetFieldValue(FieldInfo fieldInfo, object instance) { return (int)fieldInfo.GetValue(instance); } private static void SetFieldValue(FieldInfo fieldInfo, object instance, int value) { fieldInfo.SetValue(instance, value); } private static float GetFloatField(FieldInfo fieldInfo, object instance, float fallback) { if (fieldInfo == null || instance == null) { return fallback; } try { object value = fieldInfo.GetValue(instance); if (value == null) { return fallback; } return Convert.ToSingle(value); } catch { return fallback; } } private static void SetFloatField(FieldInfo fieldInfo, object instance, float value) { if (fieldInfo == null || instance == null) { return; } try { if (fieldInfo.FieldType == typeof(float)) { fieldInfo.SetValue(instance, value); } else if (fieldInfo.FieldType == typeof(double)) { fieldInfo.SetValue(instance, (double)value); } else if (fieldInfo.FieldType == typeof(int)) { fieldInfo.SetValue(instance, (int)Math.Round(value)); } } catch { } } private static bool GetFieldBoolValue(FieldInfo fieldInfo, object instance, bool fallback) { if (fieldInfo == null || instance == null) { return fallback; } try { return Convert.ToBoolean(fieldInfo.GetValue(instance)); } catch { return fallback; } } private static string GetFieldStringValue(FieldInfo fieldInfo, object instance) { if (fieldInfo == null || instance == null) { return string.Empty; } try { object value = fieldInfo.GetValue(instance); return (value != null) ? value.ToString() : string.Empty; } catch { return string.Empty; } } private static int GetProfileId(PlayerData playerData) { return (int)ProfileIdField.GetValue(playerData); } public static void BeginDetailedIncomingDamageScaling() { _skipFallbackIncomingDamageScaling = true; } public static void EndDetailedIncomingDamageScaling() { _skipFallbackIncomingDamageScaling = false; } } [HarmonyPatch(typeof(PlayerData), "get_nailDamage")] internal static class CustomDifficultyNailDamagePatch { private static void Postfix(ref int __result) { if (CustomDifficultyGameplayHooks.Instance != null) { __result = CustomDifficultyGameplayHooks.Instance.GetScaledBaseDamage(__result); } } } [HarmonyPatch(typeof(HeroController), "AddHealth", new Type[] { typeof(int) })] internal static class CustomDifficultyHeroHealingPatch { private static void Prefix(ref int amount) { if (CustomDifficultyGameplayHooks.Instance != null) { amount = CustomDifficultyGameplayHooks.Instance.ScaleHealingAmount(amount); } } } [HarmonyPatch(typeof(PlayerData), "TakeHealth", new Type[] { typeof(int), typeof(bool), typeof(bool) })] internal static class CustomDifficultyIncomingDamageFallbackPatch { private static void Prefix(ref int amount) { if (CustomDifficultyGameplayHooks.Instance != null) { amount = CustomDifficultyGameplayHooks.Instance.ScaleFallbackIncomingDamage(amount); } } } [HarmonyPatch(typeof(HeroController), "TakeDamage", new Type[] { typeof(GameObject), typeof(CollisionSide), typeof(int), typeof(HazardType), typeof(DamagePropertyFlags) })] internal static class CustomDifficultyHeroTakeDamagePatch { private static void Prefix(GameObject __0, ref int __2, HazardType __3) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (CustomDifficultyGameplayHooks.Instance != null) { CustomDifficultyGameplayHooks.BeginDetailedIncomingDamageScaling(); __2 = CustomDifficultyGameplayHooks.Instance.ScaleDetailedIncomingDamage(__0, __2, __3); } } private static void Postfix() { CustomDifficultyGameplayHooks.EndDetailedIncomingDamageScaling(); } } [HarmonyPatch(typeof(PlayerData), "AddToMaxHealth", new Type[] { typeof(int) })] internal static class CustomDifficultyMaxHealthUpgradePatch { private static void Postfix(int amount) { if (CustomDifficultyGameplayHooks.Instance != null) { CustomDifficultyGameplayHooks.Instance.RegisterPermanentHealthUpgrade(amount); } } } [HarmonyPatch(typeof(HeroController), "TakeSilk", new Type[] { typeof(int), typeof(SilkTakeSource) })] internal static class CustomDifficultyTakeSilkPatch { private static void Prefix(ref int __0, SilkTakeSource __1) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (CustomDifficultyGameplayHooks.Instance != null) { __0 = CustomDifficultyGameplayHooks.Instance.ScaleSilkCost(__0, ((object)__1).ToString()); } } } [HarmonyPatch(typeof(PlayerData), "get_SilkSkillCost")] internal static class CustomDifficultySilkSkillCostPatch { private static void Postfix(ref int __result) { if (CustomDifficultyGameplayHooks.Instance != null) { __result = CustomDifficultyGameplayHooks.Instance.ScaleSkillCost(__result); } } } [HarmonyPatch(typeof(CurrencyManager), "AddCurrency", new Type[] { typeof(int), typeof(CurrencyType), typeof(bool) })] internal static class CustomDifficultyCurrencyPatch { private static void Prefix(ref int __0) { if (CustomDifficultyGameplayHooks.Instance != null) { __0 = CustomDifficultyGameplayHooks.Instance.ScaleCurrencyDrop(__0); } } } [HarmonyPatch] internal static class CustomDifficultyShopPricePatch { private static IEnumerable TargetMethods() { Type shopItemType = AccessTools.TypeByName("ShopItem"); MethodInfo shopItemCostGetter = ((shopItemType != null) ? AccessTools.PropertyGetter(shopItemType, "Cost") : null); if (shopItemCostGetter != null) { yield return shopItemCostGetter; } Type caravanInfoType = AccessTools.TypeByName("CaravanTroupeHunter+ShopItemInfo"); MethodInfo caravanGetCost = ((caravanInfoType != null) ? AccessTools.Method(caravanInfoType, "GetCost", (Type[])null, (Type[])null) : null); if (caravanGetCost != null) { yield return caravanGetCost; } Type simpleQuestInfoType = AccessTools.TypeByName("SimpleQuestsShopOwner+ShopItemInfo"); MethodInfo simpleQuestGetCost = ((simpleQuestInfoType != null) ? AccessTools.Method(simpleQuestInfoType, "GetCost", (Type[])null, (Type[])null) : null); if (simpleQuestGetCost != null) { yield return simpleQuestGetCost; } } private static void Postfix(ref int __result) { if (CustomDifficultyGameplayHooks.Instance != null) { __result = CustomDifficultyGameplayHooks.Instance.ScaleShopPrice(__result); } } } [HarmonyPatch(typeof(CollectableItem), "Collect", new Type[] { typeof(int), typeof(bool) })] internal static class CustomDifficultyCollectablePatch { private static void Prefix(CollectableItem __instance, ref int __0) { if (CustomDifficultyGameplayHooks.Instance != null) { __0 = CustomDifficultyGameplayHooks.Instance.ScaleCollectableAmount(__instance, __0); } } } [HarmonyPatch(typeof(DamageEnemies), "DoDamage", new Type[] { typeof(GameObject), typeof(bool) })] internal static class CustomDifficultyDamageEnemiesGameObjectPatch { private static void Prefix(DamageEnemies __instance, GameObject __0) { if (CustomDifficultyGameplayHooks.Instance != null) { CustomDifficultyGameplayHooks.Instance.PushDamageTarget(__instance, __0); } } private static void Postfix(DamageEnemies __instance) { if (CustomDifficultyGameplayHooks.Instance != null) { CustomDifficultyGameplayHooks.Instance.PopDamageTarget(__instance); } } } [HarmonyPatch(typeof(DamageEnemies), "DoDamage", new Type[] { typeof(Collider2D), typeof(bool) })] internal static class CustomDifficultyDamageEnemiesColliderPatch { private static void Prefix(DamageEnemies __instance, Collider2D __0) { if (CustomDifficultyGameplayHooks.Instance != null) { CustomDifficultyGameplayHooks.Instance.PushDamageTarget(__instance, ((Object)(object)__0 != (Object)null) ? ((Component)__0).gameObject : null); } } private static void Postfix(DamageEnemies __instance) { if (CustomDifficultyGameplayHooks.Instance != null) { CustomDifficultyGameplayHooks.Instance.PopDamageTarget(__instance); } } } [HarmonyPatch(typeof(DamageEnemies), "TryDoDamage", new Type[] { typeof(Collider2D), typeof(bool) })] internal static class CustomDifficultyTryDamageEnemiesPatch { private static void Prefix(DamageEnemies __instance, Collider2D __0) { if (CustomDifficultyGameplayHooks.Instance != null) { CustomDifficultyGameplayHooks.Instance.PushDamageTarget(__instance, ((Object)(object)__0 != (Object)null) ? ((Component)__0).gameObject : null); } } private static void Postfix(DamageEnemies __instance) { if (CustomDifficultyGameplayHooks.Instance != null) { CustomDifficultyGameplayHooks.Instance.PopDamageTarget(__instance); } } } [HarmonyPatch(typeof(DamageEnemies), "GetDamageDealt")] internal static class CustomDifficultyOutgoingDamagePatch { private static void Postfix(DamageEnemies __instance, ref int __result) { if (CustomDifficultyGameplayHooks.Instance != null) { GameObject target = CustomDifficultyGameplayHooks.Instance.PeekDamageTarget(__instance); __result = CustomDifficultyGameplayHooks.Instance.ScaleOutgoingDamage(__instance, target, __result); } } } [HarmonyPatch(typeof(HeroController), "SetDashCooldownTimer")] internal static class CustomDifficultyDashCooldownPatch { private static void Postfix(HeroController __instance) { if (CustomDifficultyGameplayHooks.Instance != null && !((Object)(object)__instance == (Object)null)) { CustomDifficultyGameplayHooks.Instance.SyncDashCooldownTimer(__instance); } } } [HarmonyPatch(typeof(HeroController), "StartHarpoonDashCooldown")] internal static class CustomDifficultyHarpoonDashCooldownPatch { private static void Postfix(HeroController __instance) { if (CustomDifficultyGameplayHooks.Instance != null && !((Object)(object)__instance == (Object)null)) { CustomDifficultyGameplayHooks.Instance.ScaleHarpoonDashCooldown(__instance); } } } internal sealed class CustomDifficultyLocalizationManager { private sealed class MenuLanguageOption { public string Code; public string DisplayName; public bool AiCreated; } private readonly BaseUnityPlugin _plugin; private readonly string _localizationDirectory; private readonly ConfigEntry _menuLanguageOverride; private readonly Dictionary _englishStrings; private readonly List _availableLanguages; private Dictionary _currentStrings; private string _currentLanguageCode; public CustomDifficultyLocalizationManager(BaseUnityPlugin plugin, string localizationDirectory) { _plugin = plugin; _localizationDirectory = localizationDirectory; _menuLanguageOverride = plugin.Config.Bind("Menu", "MenuLanguage", "auto", "Menu language override. Use 'auto' to follow the game's current language."); _englishStrings = LoadLanguageFile("en"); _availableLanguages = BuildAvailableLanguages(); _currentStrings = _englishStrings; _currentLanguageCode = "en"; UpdateLanguage(force: true); } public void UpdateLanguage(bool force) { string mappedLanguageCode = GetMappedLanguageCode(); if (force || !string.Equals(mappedLanguageCode, _currentLanguageCode, StringComparison.OrdinalIgnoreCase)) { _currentStrings = LoadLanguageFile(mappedLanguageCode); _currentLanguageCode = mappedLanguageCode; } } public void CycleLanguage(int direction) { if (_availableLanguages.Count == 0) { return; } string normalizedOverrideCode = GetNormalizedOverrideCode(); int num = 0; for (int i = 0; i < _availableLanguages.Count; i++) { if (string.Equals(_availableLanguages[i].Code, normalizedOverrideCode, StringComparison.OrdinalIgnoreCase)) { num = i; break; } } num += ((direction >= 0) ? 1 : (-1)); if (num < 0) { num = _availableLanguages.Count - 1; } else if (num >= _availableLanguages.Count) { num = 0; } _menuLanguageOverride.Value = _availableLanguages[num].Code; _plugin.Config.Save(); UpdateLanguage(force: true); } public void ResetLanguageOverride() { _menuLanguageOverride.Value = "auto"; _plugin.Config.Save(); UpdateLanguage(force: true); } public string GetCurrentMenuLanguageDisplayName() { return GetLanguageDisplayName(GetNormalizedOverrideCode()); } public string GetDefaultMenuLanguageDisplayName() { return GetLanguageDisplayName("auto"); } public string Get(string key) { if (_currentStrings != null && _currentStrings.TryGetValue(key, out var value)) { return value; } if (_englishStrings != null && _englishStrings.TryGetValue(key, out value)) { return value; } return key; } private string GetLanguageDisplayName(string code) { if (string.Equals(code, "auto", StringComparison.OrdinalIgnoreCase)) { return Get("language_auto"); } MenuLanguageOption menuLanguageOption = FindLanguageOption(code); if (menuLanguageOption == null) { return code; } if (!menuLanguageOption.AiCreated) { return menuLanguageOption.DisplayName; } return menuLanguageOption.DisplayName + Get("ai_created_suffix"); } private Dictionary LoadLanguageFile(string languageCode) { string path = Path.Combine(_localizationDirectory, languageCode + ".json"); if (!File.Exists(path)) { return _englishStrings ?? new Dictionary(); } try { string text = File.ReadAllText(path); Dictionary dictionary = JsonConvert.DeserializeObject>(text); return dictionary ?? _englishStrings ?? new Dictionary(); } catch { return _englishStrings ?? new Dictionary(); } } private string GetMappedLanguageCode() { string normalizedOverrideCode = GetNormalizedOverrideCode(); if (!string.Equals(normalizedOverrideCode, "auto", StringComparison.OrdinalIgnoreCase)) { return normalizedOverrideCode; } return MapGameLanguageCode(); } private string GetNormalizedOverrideCode() { string value = _menuLanguageOverride.Value; if (string.IsNullOrWhiteSpace(value)) { return "auto"; } for (int i = 0; i < _availableLanguages.Count; i++) { if (string.Equals(_availableLanguages[i].Code, value, StringComparison.OrdinalIgnoreCase)) { return _availableLanguages[i].Code; } } return "auto"; } private MenuLanguageOption FindLanguageOption(string code) { for (int i = 0; i < _availableLanguages.Count; i++) { if (string.Equals(_availableLanguages[i].Code, code, StringComparison.OrdinalIgnoreCase)) { return _availableLanguages[i]; } } return null; } private static List BuildAvailableLanguages() { List list = new List(); list.Add(new MenuLanguageOption { Code = "auto", DisplayName = "Auto", AiCreated = false }); list.Add(new MenuLanguageOption { Code = "pt-BR", DisplayName = "Português (Brasil)", AiCreated = false }); list.Add(new MenuLanguageOption { Code = "en", DisplayName = "English", AiCreated = true }); list.Add(new MenuLanguageOption { Code = "es", DisplayName = "Español", AiCreated = true }); list.Add(new MenuLanguageOption { Code = "fr", DisplayName = "Français", AiCreated = true }); list.Add(new MenuLanguageOption { Code = "de", DisplayName = "Deutsch", AiCreated = true }); list.Add(new MenuLanguageOption { Code = "it", DisplayName = "Italiano", AiCreated = true }); list.Add(new MenuLanguageOption { Code = "ru", DisplayName = "Русский", AiCreated = true }); list.Add(new MenuLanguageOption { Code = "ja", DisplayName = "日本語", AiCreated = true }); list.Add(new MenuLanguageOption { Code = "ko", DisplayName = "한국어", AiCreated = true }); list.Add(new MenuLanguageOption { Code = "zh-CN", DisplayName = "简体中文", AiCreated = true }); list.Add(new MenuLanguageOption { Code = "zh-TW", DisplayName = "繁體中文", AiCreated = true }); return list; } private static string MapGameLanguageCode() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) try { string text = ((object)Language.CurrentLanguage()).ToString(); if (text.StartsWith("FR", StringComparison.OrdinalIgnoreCase)) { return "fr"; } if (text.StartsWith("DE", StringComparison.OrdinalIgnoreCase)) { return "de"; } if (text.StartsWith("IT", StringComparison.OrdinalIgnoreCase)) { return "it"; } if (text.StartsWith("PT", StringComparison.OrdinalIgnoreCase)) { return "pt-BR"; } if (text.StartsWith("ES", StringComparison.OrdinalIgnoreCase)) { return "es"; } if (text.StartsWith("RU", StringComparison.OrdinalIgnoreCase)) { return "ru"; } if (text.StartsWith("JA", StringComparison.OrdinalIgnoreCase)) { return "ja"; } if (text.StartsWith("KO", StringComparison.OrdinalIgnoreCase)) { return "ko"; } if (text.StartsWith("ZH_TW", StringComparison.OrdinalIgnoreCase) || text.StartsWith("ZH_HK", StringComparison.OrdinalIgnoreCase)) { return "zh-TW"; } if (text.StartsWith("ZH", StringComparison.OrdinalIgnoreCase)) { return "zh-CN"; } } catch { } return "en"; } } internal sealed class CustomDifficultyMenuUI { private enum MenuCategory { Summary, Favorites, Player, Damage, Enemies, Bosses, Drops, Economy, Movement, Mutators, Presets, BossProfiles, Context, Adaptive, System } private sealed class MenuOptionDefinition { public string Id; public string LabelKey; public string DescriptionKey; public MenuCategory Category; public CustomDifficultyOptionStatus Status; public bool ActionOption; public bool PresetOption; public bool InfoOption; public DifficultyPreset Preset; } private readonly BaseUnityPlugin _plugin; private readonly CustomDifficultyConfigManager _configManager; private readonly CustomDifficultyLocalizationManager _localizationManager; private readonly CustomDifficultyGameplayHooks _gameplayHooks; private readonly CustomDifficultyFavorites _favorites; private readonly CustomDifficultyPresetManager _presetManager; private readonly CustomDifficultyBossProfileManager _bossProfileManager; private readonly object _inputBlockerToken = new object(); private readonly List _allOptions = new List(); private readonly MenuCategory[] _categories = new MenuCategory[15] { MenuCategory.Summary, MenuCategory.Favorites, MenuCategory.Player, MenuCategory.Damage, MenuCategory.Enemies, MenuCategory.Bosses, MenuCategory.Drops, MenuCategory.Economy, MenuCategory.Movement, MenuCategory.Mutators, MenuCategory.Presets, MenuCategory.BossProfiles, MenuCategory.Context, MenuCategory.Adaptive, MenuCategory.System }; private bool _isOpen; private bool _inputBlocked; private bool _textFieldFocused; private bool _focusSearchRequested; private bool _clearTextFocusRequested; private bool _timeScalePaused; private float _previousTimeScale = 1f; private int _selectedCategoryIndex; private int _selectedOptionIndex; private string _searchText = string.Empty; private string _presetNameInput = "Meu Preset"; private float _lastVerticalInputTime = -99f; private float _lastHorizontalInputTime = -99f; private float _lastCategoryInputTime = -99f; private GUIStyle _titleStyle; private GUIStyle _detailTitleStyle; private GUIStyle _subtitleStyle; private GUIStyle _tabStyle; private GUIStyle _selectedTabStyle; private GUIStyle _rowStyle; private GUIStyle _selectedRowStyle; private GUIStyle _valueStyle; private GUIStyle _descriptionStyle; private GUIStyle _buttonStyle; private GUIStyle _selectedButtonStyle; private GUIStyle _badgeStyle; private GUIStyle _smallInputStyle; public CustomDifficultyMenuUI(BaseUnityPlugin plugin, CustomDifficultyConfigManager configManager, CustomDifficultyLocalizationManager localizationManager, CustomDifficultyGameplayHooks gameplayHooks, CustomDifficultyFavorites favorites, CustomDifficultyPresetManager presetManager, CustomDifficultyBossProfileManager bossProfileManager) { _plugin = plugin; _configManager = configManager; _localizationManager = localizationManager; _gameplayHooks = gameplayHooks; _favorites = favorites; _presetManager = presetManager; _bossProfileManager = bossProfileManager; BuildOptionDefinitions(); } public void Update() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (!_isOpen) { if (Input.GetKeyDown(_configManager.GetOpenMenuKey())) { Open(); } return; } if (_textFieldFocused) { if (Input.GetKeyDown((KeyCode)27)) { _clearTextFocusRequested = true; _textFieldFocused = false; } return; } if (Input.GetKeyDown((KeyCode)27) || Input.GetKeyDown((KeyCode)324) || Input.GetKeyDown(_configManager.GetOpenMenuKey()) || Input.GetKeyDown((KeyCode)331)) { Close(keepDraft: false); return; } if (Input.GetKeyDown((KeyCode)114)) { ResetSelectedOptionToDefault(); } if (Input.GetKeyDown((KeyCode)102)) { ToggleSelectedFavorite(); } if (Input.GetKeyDown((KeyCode)47)) { _focusSearchRequested = true; } HandleCategoryNavigation(); HandleVerticalNavigation(); HandleHorizontalAdjustment(); if (Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271) || Input.GetKeyDown((KeyCode)32) || Input.GetKeyDown((KeyCode)330)) { ExecuteSelectedOption(); } } public void OnGUI() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: 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_0263: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) if (_isOpen) { EnsureStyles(); GUI.depth = -1000; Color color = GUI.color; GUI.color = new Color(0f, 0f, 0f, 0.78f); GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)Texture2D.whiteTexture); GUI.color = color; float num = Mathf.Min(1240f, (float)Screen.width - 72f); float num2 = Mathf.Min(780f, (float)Screen.height - 72f); Rect val = default(Rect); ((Rect)(ref val))..ctor(((float)Screen.width - num) * 0.5f, ((float)Screen.height - num2) * 0.5f, num, num2); DrawPanel(val, new Color(0.05f, 0.07f, 0.08f, 0.96f), new Color(0.87f, 0.77f, 0.45f, 0.45f), 2f); DrawSolidRect(new Rect(((Rect)(ref val)).x + 22f, ((Rect)(ref val)).y + 100f, ((Rect)(ref val)).width - 44f, 1f), new Color(1f, 1f, 1f, 0.08f)); GUI.Label(new Rect(((Rect)(ref val)).x + 28f, ((Rect)(ref val)).y + 14f, ((Rect)(ref val)).width - 560f, 46f), _localizationManager.Get("menu_title"), _titleStyle); GUI.Label(new Rect(((Rect)(ref val)).x + 30f, ((Rect)(ref val)).y + 62f, ((Rect)(ref val)).width - 520f, 34f), GetVisibleCategoryLabel(), _subtitleStyle); DrawSearchBox(val); if (_configManager.HasUnsavedChanges()) { DrawBadge(new Rect(((Rect)(ref val)).x + ((Rect)(ref val)).width - 190f, ((Rect)(ref val)).y + 62f, 160f, 28f), _localizationManager.Get("unsaved"), new Color(0.28f, 0.18f, 0.08f, 0.98f), new Color(0.95f, 0.83f, 0.42f, 0.9f)); } DrawCategoryTabs(val); float num3 = ((Rect)(ref val)).y + 164f; float num4 = ((Rect)(ref val)).height - 222f; float num5 = Mathf.Clamp(((Rect)(ref val)).width * 0.35f, 400f, 460f); Rect listRect = default(Rect); ((Rect)(ref listRect))..ctor(((Rect)(ref val)).x + 24f, num3, ((Rect)(ref val)).width - num5 - 66f, num4); Rect detailRect = default(Rect); ((Rect)(ref detailRect))..ctor(((Rect)(ref listRect)).xMax + 18f, num3, num5, num4); Rect footerRect = default(Rect); ((Rect)(ref footerRect))..ctor(((Rect)(ref val)).x + 24f, ((Rect)(ref val)).y + ((Rect)(ref val)).height - 50f, ((Rect)(ref val)).width - 48f, 30f); DrawCurrentOptions(listRect); DrawDescription(detailRect); DrawFooter(footerRect); if (_focusSearchRequested) { GUI.FocusControl("CDSearch"); _focusSearchRequested = false; } if (_clearTextFocusRequested) { GUI.FocusControl(string.Empty); _clearTextFocusRequested = false; } string nameOfFocusedControl = GUI.GetNameOfFocusedControl(); _textFieldFocused = string.Equals(nameOfFocusedControl, "CDSearch", StringComparison.Ordinal) || string.Equals(nameOfFocusedControl, "CDPresetName", StringComparison.Ordinal); ConsumeUnityGuiInputEvent(); } } public void Shutdown() { _isOpen = false; SetHeroInputBlocked(blocked: false); RestoreGameTime(); } private void DrawSearchBox(Rect panelRect) { //IL_002c: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) GUI.Label(new Rect(((Rect)(ref panelRect)).x + ((Rect)(ref panelRect)).width - 475f, ((Rect)(ref panelRect)).y + 22f, 58f, 28f), _localizationManager.Get("search_label"), _descriptionStyle); GUI.SetNextControlName("CDSearch"); _searchText = GUI.TextField(new Rect(((Rect)(ref panelRect)).x + ((Rect)(ref panelRect)).width - 410f, ((Rect)(ref panelRect)).y + 18f, 230f, 32f), _searchText ?? string.Empty, 32, _smallInputStyle); if (DrawFlatButton(new Rect(((Rect)(ref panelRect)).x + ((Rect)(ref panelRect)).width - 170f, ((Rect)(ref panelRect)).y + 18f, 70f, 32f), _localizationManager.Get("clear_search"), accent: false, highlighted: false)) { _searchText = string.Empty; _clearTextFocusRequested = true; } if (DrawFlatButton(new Rect(((Rect)(ref panelRect)).x + ((Rect)(ref panelRect)).width - 92f, ((Rect)(ref panelRect)).y + 18f, 62f, 32f), _localizationManager.Get("favorites_short"), _categories[_selectedCategoryIndex] == MenuCategory.Favorites, highlighted: false)) { SelectCategory(MenuCategory.Favorites); } } private void Open() { _configManager.ResetDraftToApplied(); _presetManager.RefreshPresets(); _selectedCategoryIndex = 0; _selectedOptionIndex = 0; _isOpen = true; PauseGameTime(); SetHeroInputBlocked(blocked: true); Cursor.visible = true; } private void Close(bool keepDraft) { if (!keepDraft) { _configManager.ResetDraftToApplied(); } _isOpen = false; SetHeroInputBlocked(blocked: false); RestoreGameTime(); Cursor.visible = false; } private void PauseGameTime() { if (!_timeScalePaused) { _previousTimeScale = Time.timeScale; Time.timeScale = 0f; _timeScalePaused = true; } } private void RestoreGameTime() { if (_timeScalePaused) { Time.timeScale = ((_previousTimeScale <= 0f) ? 1f : _previousTimeScale); _timeScalePaused = false; } } private static void ConsumeUnityGuiInputEvent() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 Event current = Event.current; if (current != null && (current.isKey || current.isMouse || (int)current.type == 6)) { current.Use(); } } private void SetHeroInputBlocked(bool blocked) { if ((Object)(object)HeroController.instance == (Object)null) { _inputBlocked = false; } else if (blocked && !_inputBlocked) { HeroController.instance.AddInputBlocker(_inputBlockerToken); _inputBlocked = true; } else if (!blocked && _inputBlocked) { HeroController.instance.RemoveInputBlocker(_inputBlockerToken); _inputBlocked = false; } } private void HandleCategoryNavigation() { int num = 0; if (Input.GetKeyDown((KeyCode)113) || Input.GetKeyDown((KeyCode)280)) { num = -1; } else if (Input.GetKeyDown((KeyCode)101) || Input.GetKeyDown((KeyCode)281) || Input.GetKeyDown((KeyCode)9)) { num = 1; } if (num != 0 && !(Time.unscaledTime - _lastCategoryInputTime < 0.12f)) { _selectedCategoryIndex += num; if (_selectedCategoryIndex < 0) { _selectedCategoryIndex = _categories.Length - 1; } else if (_selectedCategoryIndex >= _categories.Length) { _selectedCategoryIndex = 0; } _selectedOptionIndex = 0; _lastCategoryInputTime = Time.unscaledTime; } } private void HandleVerticalNavigation() { int num = 0; if (Input.GetKeyDown((KeyCode)273) || Input.GetKeyDown((KeyCode)119)) { num = -1; } else if (Input.GetKeyDown((KeyCode)274) || Input.GetKeyDown((KeyCode)115)) { num = 1; } else { float axisSafe = GetAxisSafe("Vertical"); if (Math.Abs(axisSafe) > 0.6f && Time.unscaledTime - _lastVerticalInputTime > 0.18f) { num = ((!(axisSafe > 0f)) ? 1 : (-1)); } } if (num == 0) { return; } List currentOptions = GetCurrentOptions(); if (currentOptions.Count != 0) { _selectedOptionIndex += num; if (_selectedOptionIndex < 0) { _selectedOptionIndex = currentOptions.Count - 1; } else if (_selectedOptionIndex >= currentOptions.Count) { _selectedOptionIndex = 0; } _lastVerticalInputTime = Time.unscaledTime; } } private void HandleHorizontalAdjustment() { MenuOptionDefinition selectedOption = GetSelectedOption(); if (selectedOption == null || selectedOption.ActionOption || selectedOption.PresetOption || selectedOption.InfoOption) { return; } int num = 0; if (Input.GetKeyDown((KeyCode)276) || Input.GetKeyDown((KeyCode)97)) { num = -1; } else if (Input.GetKeyDown((KeyCode)275) || Input.GetKeyDown((KeyCode)100)) { num = 1; } else { float axisSafe = GetAxisSafe("Horizontal"); if (Math.Abs(axisSafe) > 0.6f && Time.unscaledTime - _lastHorizontalInputTime > 0.12f) { num = ((axisSafe > 0f) ? 1 : (-1)); } } if (num != 0) { AdjustOption(selectedOption, num); _lastHorizontalInputTime = Time.unscaledTime; } } private void ExecuteSelectedOption() { MenuOptionDefinition selectedOption = GetSelectedOption(); if (selectedOption == null) { return; } if (!selectedOption.ActionOption && !selectedOption.PresetOption && !selectedOption.InfoOption && IsBooleanOption(selectedOption.Id)) { AdjustOption(selectedOption, 1); } else if (selectedOption.PresetOption) { if (selectedOption.Preset != DifficultyPreset.Custom) { _configManager.ApplyPresetToDraft(selectedOption.Preset); } } else { if (selectedOption.InfoOption) { return; } if (selectedOption.Id == "menu_language") { _localizationManager.CycleLanguage(1); } else if (selectedOption.ActionOption) { if (selectedOption.Id == "action_apply") { ApplyDraft(); } else if (selectedOption.Id == "action_reset_all") { _configManager.ResetDraftToDefaults(); ApplyDraft(); } else if (selectedOption.Id == "action_discard") { _configManager.ResetDraftToApplied(); } else if (selectedOption.Id == "action_close") { Close(keepDraft: false); } else if (selectedOption.Id == "action_reset_category") { ResetCurrentCategoryToDefaults(); } else if (selectedOption.Id == "action_create_preset") { _presetManager.CreatePreset(_presetNameInput); } else if (selectedOption.Id == "action_save_preset") { _presetManager.SaveSelectedPreset(); } else if (selectedOption.Id == "action_load_preset") { _presetManager.LoadSelectedPreset(); } else if (selectedOption.Id == "action_duplicate_preset") { _presetManager.DuplicateSelectedPreset(_presetNameInput); } else if (selectedOption.Id == "action_rename_preset") { _presetManager.RenameSelectedPreset(_presetNameInput); } else if (selectedOption.Id == "action_delete_preset") { _presetManager.DeleteSelectedPreset(); } else if (selectedOption.Id == "action_reset_preset_file") { _presetManager.ResetSelectedPresetToDefaults(); } else if (selectedOption.Id == "action_export_preset") { _presetManager.ExportDraftPreset(_presetNameInput); } else if (selectedOption.Id == "action_import_preset") { _presetManager.ImportLatestPreset(); } else if (selectedOption.Id == "action_reload_presets") { _presetManager.RefreshPresets(); } } } } private void ApplyDraft() { _configManager.ApplyDraft(); _gameplayHooks.ApplyImmediateChanges(); } private void ToggleSelectedFavorite() { MenuOptionDefinition selectedOption = GetSelectedOption(); if (selectedOption != null && !selectedOption.ActionOption && !selectedOption.PresetOption && !selectedOption.InfoOption) { _favorites.Toggle(selectedOption.Id); } } private void ResetSelectedOptionToDefault() { MenuOptionDefinition selectedOption = GetSelectedOption(); if (selectedOption != null && !selectedOption.ActionOption && !selectedOption.PresetOption && !selectedOption.InfoOption) { ResetOptionToDefault(selectedOption.Id); } } private void ResetOptionToDefault(string optionId) { DifficultySettings difficultySettings = DifficultySettings.CreateDefaults(); DifficultySettings draftSettings = _configManager.GetDraftSettings(); switch (optionId) { case "menu_language": _localizationManager.ResetLanguageOverride(); return; case "base_damage": draftSettings.BaseDamage = difficultySettings.BaseDamage; break; case "base_health": draftSettings.BaseHealth = difficultySettings.BaseHealth; break; case "drop_rate": draftSettings.DropRate = difficultySettings.DropRate; break; case "damage_taken": draftSettings.DamageTakenMultiplier = difficultySettings.DamageTakenMultiplier; break; case "healing_multiplier": draftSettings.HealingMultiplier = difficultySettings.HealingMultiplier; break; case "healing_cost_multiplier": draftSettings.HealingCostMultiplier = difficultySettings.HealingCostMultiplier; break; case "invincibility_time_multiplier": draftSettings.InvincibilityTimeMultiplier = difficultySettings.InvincibilityTimeMultiplier; break; case "skill_damage_multiplier": draftSettings.SkillDamageMultiplier = difficultySettings.SkillDamageMultiplier; break; case "silk_spear_damage_multiplier": draftSettings.SilkSpearDamageMultiplier = difficultySettings.SilkSpearDamageMultiplier; break; case "boss_damage_multiplier": draftSettings.BossDamageMultiplier = difficultySettings.BossDamageMultiplier; break; case "common_enemy_damage_multiplier": draftSettings.CommonEnemyDamageMultiplier = difficultySettings.CommonEnemyDamageMultiplier; break; case "critical_chance": draftSettings.CriticalChance = difficultySettings.CriticalChance; break; case "critical_damage_multiplier": draftSettings.CriticalDamageMultiplier = difficultySettings.CriticalDamageMultiplier; break; case "environmental_damage_multiplier": draftSettings.EnvironmentalDamageMultiplier = difficultySettings.EnvironmentalDamageMultiplier; break; case "boss_damage_taken_multiplier": draftSettings.BossDamageTakenMultiplier = difficultySettings.BossDamageTakenMultiplier; break; case "common_enemy_damage_taken_multiplier": draftSettings.CommonEnemyDamageTakenMultiplier = difficultySettings.CommonEnemyDamageTakenMultiplier; break; case "enemy_health_multiplier": draftSettings.EnemyHealthMultiplier = difficultySettings.EnemyHealthMultiplier; break; case "enemy_damage_multiplier": draftSettings.EnemyDamageMultiplier = difficultySettings.EnemyDamageMultiplier; break; case "enemy_speed_multiplier": draftSettings.EnemySpeedMultiplier = difficultySettings.EnemySpeedMultiplier; break; case "enemy_attack_cooldown_multiplier": draftSettings.EnemyAttackCooldownMultiplier = difficultySettings.EnemyAttackCooldownMultiplier; break; case "enemy_aggression_multiplier": draftSettings.EnemyAggressionMultiplier = difficultySettings.EnemyAggressionMultiplier; break; case "boss_health_multiplier": draftSettings.BossHealthMultiplier = difficultySettings.BossHealthMultiplier; break; case "boss_speed_multiplier": draftSettings.BossSpeedMultiplier = difficultySettings.BossSpeedMultiplier; break; case "boss_attack_cooldown_multiplier": draftSettings.BossAttackCooldownMultiplier = difficultySettings.BossAttackCooldownMultiplier; break; case "boss_brutal_mode": draftSettings.BossBrutalMode = difficultySettings.BossBrutalMode; break; case "disable_healing_during_boss": draftSettings.DisableHealingDuringBoss = difficultySettings.DisableHealingDuringBoss; break; case "healing_during_boss_multiplier": draftSettings.HealingDuringBossMultiplier = difficultySettings.HealingDuringBossMultiplier; break; case "currency_drop_multiplier": draftSettings.CurrencyDropMultiplier = difficultySettings.CurrencyDropMultiplier; break; case "item_drop_multiplier": draftSettings.ItemDropMultiplier = difficultySettings.ItemDropMultiplier; break; case "shop_price_multiplier": draftSettings.ShopPriceMultiplier = difficultySettings.ShopPriceMultiplier; break; case "boss_reward_multiplier": draftSettings.BossRewardMultiplier = difficultySettings.BossRewardMultiplier; break; case "death_currency_loss_multiplier": draftSettings.DeathCurrencyLossMultiplier = difficultySettings.DeathCurrencyLossMultiplier; break; case "player_speed_multiplier": draftSettings.PlayerSpeedMultiplier = difficultySettings.PlayerSpeedMultiplier; break; case "jump_height_multiplier": draftSettings.JumpHeightMultiplier = difficultySettings.JumpHeightMultiplier; break; case "dash_cooldown_multiplier": draftSettings.DashCooldownMultiplier = difficultySettings.DashCooldownMultiplier; break; case "ability_cost_multiplier": draftSettings.AbilityCostMultiplier = difficultySettings.AbilityCostMultiplier; break; case "silk_cost_multiplier": draftSettings.SilkCostMultiplier = difficultySettings.SilkCostMultiplier; break; case "one_hit_mode": draftSettings.OneHitMode = difficultySettings.OneHitMode; break; case "mutator_no_healing": draftSettings.MutatorNoHealing = difficultySettings.MutatorNoHealing; break; case "mutator_low_gravity": draftSettings.MutatorLowGravity = difficultySettings.MutatorLowGravity; break; case "mutator_double_damage": draftSettings.MutatorDoubleDamage = difficultySettings.MutatorDoubleDamage; break; case "mutator_glass_cannon": draftSettings.MutatorGlassCannon = difficultySettings.MutatorGlassCannon; break; case "mutator_fast_enemies": draftSettings.MutatorFastEnemies = difficultySettings.MutatorFastEnemies; break; case "mutator_tank_enemies": draftSettings.MutatorTankEnemies = difficultySettings.MutatorTankEnemies; break; case "mutator_aggressive_enemies": draftSettings.MutatorAggressiveEnemies = difficultySettings.MutatorAggressiveEnemies; break; case "mutator_randomized_enemy_health": draftSettings.MutatorRandomizedEnemyHealth = difficultySettings.MutatorRandomizedEnemyHealth; break; case "mutator_rich_world": draftSettings.MutatorRichWorld = difficultySettings.MutatorRichWorld; break; case "mutator_poor_world": draftSettings.MutatorPoorWorld = difficultySettings.MutatorPoorWorld; break; case "mutator_expensive_shops": draftSettings.MutatorExpensiveShops = difficultySettings.MutatorExpensiveShops; break; case "mutator_no_death_loss": draftSettings.MutatorNoDeathLoss = difficultySettings.MutatorNoDeathLoss; break; case "mutator_boss_frenzy": draftSettings.MutatorBossFrenzy = difficultySettings.MutatorBossFrenzy; break; case "mutator_no_mercy": draftSettings.MutatorNoMercy = difficultySettings.MutatorNoMercy; break; case "mutator_extended_fights": draftSettings.MutatorExtendedFights = difficultySettings.MutatorExtendedFights; break; case "boss_profiles_enabled": draftSettings.BossProfilesEnabled = difficultySettings.BossProfilesEnabled; break; case "boss_profiles_fallback_global": draftSettings.BossProfilesFallbackGlobal = difficultySettings.BossProfilesFallbackGlobal; break; case "context_boss_rules": draftSettings.ContextBossRulesEnabled = difficultySettings.ContextBossRulesEnabled; break; case "context_exploration_rules": draftSettings.ContextExplorationRulesEnabled = difficultySettings.ContextExplorationRulesEnabled; break; case "context_low_health_rule": draftSettings.ContextLowHealthRuleEnabled = difficultySettings.ContextLowHealthRuleEnabled; break; case "context_death_streak_tracking": draftSettings.ContextDeathStreakTrackingEnabled = difficultySettings.ContextDeathStreakTrackingEnabled; break; case "adaptive_enabled": draftSettings.AdaptiveDifficultyEnabled = difficultySettings.AdaptiveDifficultyEnabled; break; case "adaptive_boss_assist": draftSettings.AdaptiveBossAssistEnabled = difficultySettings.AdaptiveBossAssistEnabled; break; case "adaptive_exploration_assist": draftSettings.AdaptiveExplorationAssistEnabled = difficultySettings.AdaptiveExplorationAssistEnabled; break; case "adaptive_economy_assist": draftSettings.AdaptiveEconomyAssistEnabled = difficultySettings.AdaptiveEconomyAssistEnabled; break; case "adaptive_max_assist": draftSettings.AdaptiveMaxAssist = difficultySettings.AdaptiveMaxAssist; break; case "adaptive_apply_mode": draftSettings.AdaptiveApplyMode = difficultySettings.AdaptiveApplyMode; break; } draftSettings.Clamp(); } private void ResetCurrentCategoryToDefaults() { MenuCategory menuCategory = _categories[_selectedCategoryIndex]; List list = new List(_allOptions); for (int i = 0; i < list.Count; i++) { MenuOptionDefinition menuOptionDefinition = list[i]; if (menuOptionDefinition.Category == menuCategory && !menuOptionDefinition.ActionOption && !menuOptionDefinition.PresetOption && !menuOptionDefinition.InfoOption) { ResetOptionToDefault(menuOptionDefinition.Id); } } } private void AdjustOption(MenuOptionDefinition option, int direction) { if (option == null) { return; } if (option.Id == "saved_preset_selector") { _presetManager.CycleSelectedPreset(direction); return; } DifficultySettings draftSettings = _configManager.GetDraftSettings(); float num = 1f; float num2 = 1f; if (Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303)) { num = 5f; } if (Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305)) { num2 = 2f; } float num3 = 0.1f * num * num2; int num4 = (int)(1f * num * num2); switch (option.Id) { case "menu_language": _localizationManager.CycleLanguage(direction); return; case "base_damage": draftSettings.BaseDamage += direction * num4; break; case "base_health": draftSettings.BaseHealth += direction * Math.Max(1, num4); break; case "drop_rate": draftSettings.DropRate += (float)direction * num3; break; case "damage_taken": draftSettings.DamageTakenMultiplier += (float)direction * num3; break; case "healing_multiplier": draftSettings.HealingMultiplier += (float)direction * num3; break; case "healing_cost_multiplier": draftSettings.HealingCostMultiplier += (float)direction * num3; break; case "invincibility_time_multiplier": draftSettings.InvincibilityTimeMultiplier += (float)direction * num3; break; case "skill_damage_multiplier": draftSettings.SkillDamageMultiplier += (float)direction * num3; break; case "silk_spear_damage_multiplier": draftSettings.SilkSpearDamageMultiplier += (float)direction * num3; break; case "boss_damage_multiplier": draftSettings.BossDamageMultiplier += (float)direction * num3; break; case "common_enemy_damage_multiplier": draftSettings.CommonEnemyDamageMultiplier += (float)direction * num3; break; case "critical_chance": draftSettings.CriticalChance += (float)direction * Math.Max(1f, num * num2); break; case "critical_damage_multiplier": draftSettings.CriticalDamageMultiplier += (float)direction * num3; break; case "environmental_damage_multiplier": draftSettings.EnvironmentalDamageMultiplier += (float)direction * num3; break; case "boss_damage_taken_multiplier": draftSettings.BossDamageTakenMultiplier += (float)direction * num3; break; case "common_enemy_damage_taken_multiplier": draftSettings.CommonEnemyDamageTakenMultiplier += (float)direction * num3; break; case "enemy_health_multiplier": draftSettings.EnemyHealthMultiplier += (float)direction * num3; break; case "enemy_damage_multiplier": draftSettings.EnemyDamageMultiplier += (float)direction * num3; break; case "enemy_speed_multiplier": draftSettings.EnemySpeedMultiplier += (float)direction * num3; break; case "enemy_attack_cooldown_multiplier": draftSettings.EnemyAttackCooldownMultiplier += (float)direction * num3; break; case "enemy_aggression_multiplier": draftSettings.EnemyAggressionMultiplier += (float)direction * num3; break; case "boss_health_multiplier": draftSettings.BossHealthMultiplier += (float)direction * num3; break; case "boss_speed_multiplier": draftSettings.BossSpeedMultiplier += (float)direction * num3; break; case "boss_attack_cooldown_multiplier": draftSettings.BossAttackCooldownMultiplier += (float)direction * num3; break; case "boss_brutal_mode": draftSettings.BossBrutalMode = !draftSettings.BossBrutalMode; break; case "disable_healing_during_boss": draftSettings.DisableHealingDuringBoss = !draftSettings.DisableHealingDuringBoss; break; case "healing_during_boss_multiplier": draftSettings.HealingDuringBossMultiplier += (float)direction * num3; break; case "currency_drop_multiplier": draftSettings.CurrencyDropMultiplier += (float)direction * num3; break; case "item_drop_multiplier": draftSettings.ItemDropMultiplier += (float)direction * num3; break; case "shop_price_multiplier": draftSettings.ShopPriceMultiplier += (float)direction * num3; break; case "boss_reward_multiplier": draftSettings.BossRewardMultiplier += (float)direction * num3; break; case "death_currency_loss_multiplier": draftSettings.DeathCurrencyLossMultiplier += (float)direction * num3; break; case "player_speed_multiplier": draftSettings.PlayerSpeedMultiplier += (float)direction * num3; break; case "jump_height_multiplier": draftSettings.JumpHeightMultiplier += (float)direction * num3; break; case "dash_cooldown_multiplier": draftSettings.DashCooldownMultiplier += (float)direction * num3; break; case "ability_cost_multiplier": draftSettings.AbilityCostMultiplier += (float)direction * num3; break; case "silk_cost_multiplier": draftSettings.SilkCostMultiplier += (float)direction * num3; break; case "one_hit_mode": draftSettings.OneHitMode = !draftSettings.OneHitMode; break; case "mutator_no_healing": draftSettings.MutatorNoHealing = !draftSettings.MutatorNoHealing; break; case "mutator_low_gravity": draftSettings.MutatorLowGravity = !draftSettings.MutatorLowGravity; break; case "mutator_double_damage": draftSettings.MutatorDoubleDamage = !draftSettings.MutatorDoubleDamage; break; case "mutator_glass_cannon": draftSettings.MutatorGlassCannon = !draftSettings.MutatorGlassCannon; break; case "mutator_fast_enemies": draftSettings.MutatorFastEnemies = !draftSettings.MutatorFastEnemies; break; case "mutator_tank_enemies": draftSettings.MutatorTankEnemies = !draftSettings.MutatorTankEnemies; break; case "mutator_aggressive_enemies": draftSettings.MutatorAggressiveEnemies = !draftSettings.MutatorAggressiveEnemies; break; case "mutator_randomized_enemy_health": draftSettings.MutatorRandomizedEnemyHealth = !draftSettings.MutatorRandomizedEnemyHealth; break; case "mutator_rich_world": draftSettings.MutatorRichWorld = !draftSettings.MutatorRichWorld; break; case "mutator_poor_world": draftSettings.MutatorPoorWorld = !draftSettings.MutatorPoorWorld; break; case "mutator_expensive_shops": draftSettings.MutatorExpensiveShops = !draftSettings.MutatorExpensiveShops; break; case "mutator_no_death_loss": draftSettings.MutatorNoDeathLoss = !draftSettings.MutatorNoDeathLoss; break; case "mutator_boss_frenzy": draftSettings.MutatorBossFrenzy = !draftSettings.MutatorBossFrenzy; break; case "mutator_no_mercy": draftSettings.MutatorNoMercy = !draftSettings.MutatorNoMercy; break; case "mutator_extended_fights": draftSettings.MutatorExtendedFights = !draftSettings.MutatorExtendedFights; break; case "boss_profiles_enabled": draftSettings.BossProfilesEnabled = !draftSettings.BossProfilesEnabled; break; case "boss_profiles_fallback_global": draftSettings.BossProfilesFallbackGlobal = !draftSettings.BossProfilesFallbackGlobal; break; case "context_boss_rules": draftSettings.ContextBossRulesEnabled = !draftSettings.ContextBossRulesEnabled; break; case "context_exploration_rules": draftSettings.ContextExplorationRulesEnabled = !draftSettings.ContextExplorationRulesEnabled; break; case "context_low_health_rule": draftSettings.ContextLowHealthRuleEnabled = !draftSettings.ContextLowHealthRuleEnabled; break; case "context_death_streak_tracking": draftSettings.ContextDeathStreakTrackingEnabled = !draftSettings.ContextDeathStreakTrackingEnabled; break; case "adaptive_enabled": draftSettings.AdaptiveDifficultyEnabled = !draftSettings.AdaptiveDifficultyEnabled; break; case "adaptive_boss_assist": draftSettings.AdaptiveBossAssistEnabled = !draftSettings.AdaptiveBossAssistEnabled; break; case "adaptive_exploration_assist": draftSettings.AdaptiveExplorationAssistEnabled = !draftSettings.AdaptiveExplorationAssistEnabled; break; case "adaptive_economy_assist": draftSettings.AdaptiveEconomyAssistEnabled = !draftSettings.AdaptiveEconomyAssistEnabled; break; case "adaptive_max_assist": draftSettings.AdaptiveMaxAssist += (float)direction * num3; break; case "adaptive_apply_mode": draftSettings.AdaptiveApplyMode += ((direction >= 0) ? 1 : (-1)); if (draftSettings.AdaptiveApplyMode < 0) { draftSettings.AdaptiveApplyMode = 2; } else if (draftSettings.AdaptiveApplyMode > 2) { draftSettings.AdaptiveApplyMode = 0; } break; } draftSettings.Clamp(); } private void DrawCategoryTabs(Rect panelRect) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) float num = 8f; float num2 = ((Rect)(ref panelRect)).x + 24f; float num3 = ((Rect)(ref panelRect)).y + 108f; int num4 = Math.Min(9, _categories.Length); int num5 = _selectedCategoryIndex - num4 / 2; if (num5 < 0) { num5 = 0; } if (num5 + num4 > _categories.Length) { num5 = _categories.Length - num4; } float num6 = (((Rect)(ref panelRect)).width - 48f - num * (float)(num4 - 1)) / (float)num4; Rect rect = default(Rect); for (int i = 0; i < num4; i++) { int num7 = num5 + i; ((Rect)(ref rect))..ctor(num2 + (float)i * (num6 + num), num3, num6, 42f); bool flag = num7 == _selectedCategoryIndex; if (DrawFlatButton(rect, GetCategoryLabel(_categories[num7]), flag, flag, flag ? _selectedTabStyle : _tabStyle)) { _selectedCategoryIndex = num7; _selectedOptionIndex = 0; } } } private void DrawCurrentOptions(Rect listRect) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) DrawPanel(listRect, new Color(0.07f, 0.09f, 0.1f, 0.88f), new Color(1f, 1f, 1f, 0.08f), 1f); List currentOptions = GetCurrentOptions(); int num = 7; int num2 = 0; if (_selectedOptionIndex >= num) { num2 = _selectedOptionIndex - num + 1; } GUI.Label(new Rect(((Rect)(ref listRect)).x + 18f, ((Rect)(ref listRect)).y + 14f, ((Rect)(ref listRect)).width - 120f, 28f), GetVisibleCategoryLabel(), _subtitleStyle); if (currentOptions.Count > 0) { GUI.Label(new Rect(((Rect)(ref listRect)).x + ((Rect)(ref listRect)).width - 88f, ((Rect)(ref listRect)).y + 14f, 60f, 28f), _selectedOptionIndex + 1 + "/" + currentOptions.Count, _valueStyle); } float num3 = ((Rect)(ref listRect)).y + 56f; Rect rowRect = default(Rect); for (int i = 0; i < num; i++) { int num4 = num2 + i; if (num4 >= currentOptions.Count) { break; } MenuOptionDefinition option = currentOptions[num4]; ((Rect)(ref rowRect))..ctor(((Rect)(ref listRect)).x + 14f, num3 + (float)i * 66f, ((Rect)(ref listRect)).width - 28f, 56f); DrawOptionRow(rowRect, option, num4 == _selectedOptionIndex); } } private void DrawOptionRow(Rect rowRect, MenuOptionDefinition option, bool isSelected) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0433: Unknown result type (might be due to invalid IL or missing references) //IL_0441: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_0393: Unknown result type (might be due to invalid IL or missing references) //IL_047f: Unknown result type (might be due to invalid IL or missing references) //IL_0490: Unknown result type (might be due to invalid IL or missing references) //IL_03ad: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) bool flag = IsModifiedOption(option); DrawPanel(rowRect, isSelected ? new Color(0.16f, 0.19f, 0.14f, 0.96f) : (flag ? new Color(0.12f, 0.12f, 0.08f, 0.92f) : new Color(0.09f, 0.11f, 0.12f, 0.9f)), isSelected ? new Color(0.92f, 0.8f, 0.42f, 0.7f) : (flag ? new Color(0.92f, 0.8f, 0.42f, 0.3f) : new Color(1f, 1f, 1f, 0.06f)), 1f); string text = _localizationManager.Get(option.LabelKey); if (_favorites.IsFavorite(option.Id) && !option.ActionOption && !option.PresetOption && !option.InfoOption) { text = "* " + text; } float num = 14f; float num2 = 36f; float num3 = 8f; if (!option.ActionOption && !option.PresetOption && !option.InfoOption) { float num4 = (IsWideValueOption(option.Id) ? 210f : (IsBooleanOption(option.Id) ? 120f : 104f)); float num5 = num2 + num3 + num4 + num3 + num2 + num3 + num2; float num6 = ((Rect)(ref rowRect)).x + ((Rect)(ref rowRect)).width - num - num5; float num7 = num6 - ((Rect)(ref rowRect)).x - 24f - 58f; Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref rowRect)).x + 18f, ((Rect)(ref rowRect)).y + 7f, num7, ((Rect)(ref rowRect)).height - 14f); SelectByClick(rowRect, num6, option); GUI.Label(val, text, isSelected ? _selectedRowStyle : _rowStyle); DrawStatusBadge(new Rect(num6 - 58f, ((Rect)(ref rowRect)).y + 16f, 50f, 22f), option.Status); Rect rect = default(Rect); ((Rect)(ref rect))..ctor(num6, ((Rect)(ref rowRect)).y + 10f, num2, num2); Rect rect2 = default(Rect); ((Rect)(ref rect2))..ctor(((Rect)(ref rect)).xMax + num3, ((Rect)(ref rowRect)).y + 10f, num4, num2); Rect rect3 = default(Rect); ((Rect)(ref rect3))..ctor(((Rect)(ref rect2)).xMax + num3, ((Rect)(ref rowRect)).y + 10f, num2, num2); Rect rect4 = default(Rect); ((Rect)(ref rect4))..ctor(((Rect)(ref rect3)).xMax + num3, ((Rect)(ref rowRect)).y + 10f, num2, num2); if (DrawFlatButton(rect, "<", accent: false, isSelected)) { AdjustOption(option, -1); } DrawValueChip(rect2, GetValueText(option), isSelected); if (DrawFlatButton(rect3, ">", accent: false, isSelected)) { AdjustOption(option, 1); } if (DrawFlatButton(rect4, "R", accent: true, highlighted: false)) { ResetOptionToDefaultByButton(option); } } else if (option.InfoOption) { float num8 = 210f; Rect rect5 = default(Rect); ((Rect)(ref rect5))..ctor(((Rect)(ref rowRect)).x + ((Rect)(ref rowRect)).width - num8 - num, ((Rect)(ref rowRect)).y + 10f, num8, num2); Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(((Rect)(ref rowRect)).x + 18f, ((Rect)(ref rowRect)).y + 7f, ((Rect)(ref rect5)).x - ((Rect)(ref rowRect)).x - 36f, ((Rect)(ref rowRect)).height - 14f); SelectByClick(rowRect, ((Rect)(ref rect5)).x, option); GUI.Label(val2, text, isSelected ? _selectedRowStyle : _rowStyle); DrawValueChip(rect5, GetValueText(option), isSelected); } else { float num9 = 180f; Rect rect6 = default(Rect); ((Rect)(ref rect6))..ctor(((Rect)(ref rowRect)).x + ((Rect)(ref rowRect)).width - num9 - num, ((Rect)(ref rowRect)).y + 10f, num9, num2); Rect val3 = default(Rect); ((Rect)(ref val3))..ctor(((Rect)(ref rowRect)).x + 18f, ((Rect)(ref rowRect)).y + 7f, ((Rect)(ref rect6)).x - ((Rect)(ref rowRect)).x - 90f, ((Rect)(ref rowRect)).height - 14f); SelectByClick(rowRect, ((Rect)(ref rect6)).x, option); GUI.Label(val3, text, isSelected ? _selectedRowStyle : _rowStyle); DrawStatusBadge(new Rect(((Rect)(ref rect6)).x - 58f, ((Rect)(ref rowRect)).y + 16f, 50f, 22f), option.Status); if (DrawFlatButton(rect6, GetValueText(option), accent: true, isSelected)) { List currentOptions = GetCurrentOptions(); _selectedOptionIndex = currentOptions.IndexOf(option); ExecuteSelectedOption(); } } } private void SelectByClick(Rect rowRect, float controlStart, MenuOptionDefinition option) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (GUI.Button(new Rect(((Rect)(ref rowRect)).x + 6f, ((Rect)(ref rowRect)).y + 4f, controlStart - ((Rect)(ref rowRect)).x - 12f, ((Rect)(ref rowRect)).height - 8f), GUIContent.none, GUIStyle.none)) { List currentOptions = GetCurrentOptions(); _selectedOptionIndex = currentOptions.IndexOf(option); } } private void ResetOptionToDefaultByButton(MenuOptionDefinition option) { List currentOptions = GetCurrentOptions(); _selectedOptionIndex = currentOptions.IndexOf(option); ResetSelectedOptionToDefault(); } private void DrawDescription(Rect detailRect) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_03a5: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) DrawPanel(detailRect, new Color(0.07f, 0.09f, 0.1f, 0.9f), new Color(1f, 1f, 1f, 0.08f), 1f); MenuOptionDefinition selectedOption = GetSelectedOption(); if (selectedOption == null) { return; } float num = 18f; float num2 = ((Rect)(ref detailRect)).y + 16f; string text = _localizationManager.Get(selectedOption.LabelKey); Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref detailRect)).x + num, num2, ((Rect)(ref detailRect)).width - num * 2f - 104f, 62f); GUI.Label(val, text, _detailTitleStyle); DrawStatusBadge(new Rect(((Rect)(ref detailRect)).x + ((Rect)(ref detailRect)).width - 108f, num2 + 4f, 86f, 26f), selectedOption.Status); num2 += 72f; if (_categories[_selectedCategoryIndex] == MenuCategory.Presets) { DrawPresetNameBoxAt(detailRect, num, num2); num2 += 72f; } else { string valueText = GetValueText(selectedOption); float num3 = ((IsWideValueOption(selectedOption.Id) || selectedOption.InfoOption) ? Mathf.Min(280f, ((Rect)(ref detailRect)).width - num * 2f) : 132f); DrawValueChip(new Rect(((Rect)(ref detailRect)).x + num, num2, num3, 42f), valueText, highlighted: true); num2 += 58f; } if (selectedOption.Category == MenuCategory.Summary) { DrawInfoCard(new Rect(((Rect)(ref detailRect)).x + num, num2, ((Rect)(ref detailRect)).width - num * 2f, ((Rect)(ref detailRect)).yMax - num2 - 18f), _localizationManager.Get("category_summary"), GetDescriptionText(selectedOption), accent: false); return; } float num4 = ((selectedOption.Category == MenuCategory.Presets) ? 102f : 118f); DrawInfoCard(new Rect(((Rect)(ref detailRect)).x + num, num2, ((Rect)(ref detailRect)).width - num * 2f, num4), _localizationManager.Get("description"), _localizationManager.Get(selectedOption.DescriptionKey), accent: false); num2 += num4 + 12f; if (!selectedOption.ActionOption && !selectedOption.PresetOption && !selectedOption.InfoOption) { DrawInfoCard(new Rect(((Rect)(ref detailRect)).x + num, num2, ((Rect)(ref detailRect)).width - num * 2f, 102f), _localizationManager.Get("label_default"), GetComparisonText(selectedOption), IsModifiedOption(selectedOption)); num2 += 114f; } float num5 = ((Rect)(ref detailRect)).yMax - num2 - 18f; string extraInfoText = GetExtraInfoText(selectedOption); if (!string.IsNullOrEmpty(extraInfoText) && num5 >= 170f) { float num6 = Mathf.Min(128f, num5 * 0.5f); DrawInfoCard(new Rect(((Rect)(ref detailRect)).x + num, num2, ((Rect)(ref detailRect)).width - num * 2f, num6), _localizationManager.Get("label_status"), GetStatusText(selectedOption), selectedOption.Status != CustomDifficultyOptionStatus.Supported); num2 += num6 + 12f; DrawInfoCard(new Rect(((Rect)(ref detailRect)).x + num, num2, ((Rect)(ref detailRect)).width - num * 2f, ((Rect)(ref detailRect)).yMax - num2 - 18f), _localizationManager.Get("info"), extraInfoText, accent: false); } else { DrawInfoCard(new Rect(((Rect)(ref detailRect)).x + num, num2, ((Rect)(ref detailRect)).width - num * 2f, Math.Max(96f, num5)), _localizationManager.Get("label_status"), GetStatusText(selectedOption), selectedOption.Status != CustomDifficultyOptionStatus.Supported); } } private void DrawPresetNameBox(Rect detailRect, float padding) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) DrawPresetNameBoxAt(detailRect, padding, ((Rect)(ref detailRect)).y + 58f); } private void DrawPresetNameBoxAt(Rect detailRect, float padding, float y) { //IL_001e: 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) GUI.Label(new Rect(((Rect)(ref detailRect)).x + padding, y, ((Rect)(ref detailRect)).width - padding * 2f, 22f), _localizationManager.Get("preset_name_input"), _descriptionStyle); GUI.SetNextControlName("CDPresetName"); _presetNameInput = GUI.TextField(new Rect(((Rect)(ref detailRect)).x + padding, y + 24f, ((Rect)(ref detailRect)).width - padding * 2f, 40f), _presetNameInput ?? string.Empty, 48, _smallInputStyle); } private void DrawFooter(Rect footerRect) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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) DrawPanel(footerRect, new Color(0.08f, 0.1f, 0.11f, 0.92f), new Color(1f, 1f, 1f, 0.08f), 1f); GUI.Label(new Rect(((Rect)(ref footerRect)).x + 14f, ((Rect)(ref footerRect)).y + 4f, ((Rect)(ref footerRect)).width - 28f, 22f), _localizationManager.Get("footer_controls_21"), _descriptionStyle); } private bool DrawFlatButton(Rect rect, string text, bool accent, bool highlighted) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return DrawFlatButton(rect, text, accent, highlighted, (highlighted || accent) ? _selectedButtonStyle : _buttonStyle); } private bool DrawFlatButton(Rect rect, string text, bool accent, bool highlighted, GUIStyle textStyle) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: 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_0072: Unknown result type (might be due to invalid IL or missing references) DrawPanel(rect, accent ? new Color(0.24f, 0.18f, 0.08f, 0.98f) : (highlighted ? new Color(0.16f, 0.18f, 0.13f, 0.96f) : new Color(0.12f, 0.13f, 0.14f, 0.92f)), accent ? new Color(0.95f, 0.83f, 0.42f, 0.9f) : (highlighted ? new Color(0.84f, 0.73f, 0.4f, 0.45f) : new Color(1f, 1f, 1f, 0.08f)), 1f); GUI.Label(rect, text, textStyle); return GUI.Button(rect, GUIContent.none, GUIStyle.none); } private void DrawValueChip(Rect rect, string text, bool highlighted) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) DrawPanel(rect, highlighted ? new Color(0.14f, 0.17f, 0.18f, 0.98f) : new Color(0.11f, 0.13f, 0.14f, 0.94f), highlighted ? new Color(0.84f, 0.73f, 0.4f, 0.45f) : new Color(1f, 1f, 1f, 0.08f), 1f); GUI.Label(rect, text, _valueStyle); } private void DrawBadge(Rect rect, string text, Color fillColor, Color borderColor) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) DrawPanel(rect, fillColor, borderColor, 1f); GUI.Label(rect, text, _badgeStyle); } private void DrawStatusBadge(Rect rect, CustomDifficultyOptionStatus status) { //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) Color fillColor = default(Color); ((Color)(ref fillColor))..ctor(0.14f, 0.2f, 0.14f, 0.95f); Color borderColor = default(Color); ((Color)(ref borderColor))..ctor(0.52f, 0.78f, 0.52f, 0.65f); switch (status) { case CustomDifficultyOptionStatus.Experimental: ((Color)(ref fillColor))..ctor(0.33f, 0.24f, 0.08f, 0.96f); ((Color)(ref borderColor))..ctor(0.95f, 0.83f, 0.42f, 0.85f); break; case CustomDifficultyOptionStatus.Reserved: ((Color)(ref fillColor))..ctor(0.12f, 0.16f, 0.24f, 0.96f); ((Color)(ref borderColor))..ctor(0.46f, 0.64f, 0.95f, 0.65f); break; case CustomDifficultyOptionStatus.Unsupported: ((Color)(ref fillColor))..ctor(0.24f, 0.1f, 0.1f, 0.96f); ((Color)(ref borderColor))..ctor(0.95f, 0.42f, 0.42f, 0.65f); break; } DrawBadge(rect, GetStatusShortText(status), fillColor, borderColor); } private void DrawInfoCard(Rect rect, string title, string body, bool accent) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) DrawPanel(rect, accent ? new Color(0.15f, 0.12f, 0.06f, 0.9f) : new Color(0.09f, 0.11f, 0.12f, 0.92f), accent ? new Color(0.84f, 0.73f, 0.4f, 0.45f) : new Color(1f, 1f, 1f, 0.08f), 1f); GUI.Label(new Rect(((Rect)(ref rect)).x + 12f, ((Rect)(ref rect)).y + 7f, ((Rect)(ref rect)).width - 24f, 26f), title, accent ? _selectedButtonStyle : _buttonStyle); GUI.Label(new Rect(((Rect)(ref rect)).x + 12f, ((Rect)(ref rect)).y + 34f, ((Rect)(ref rect)).width - 24f, ((Rect)(ref rect)).height - 42f), body, _descriptionStyle); } private static void DrawPanel(Rect rect, Color fillColor, Color borderColor, float borderThickness) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) DrawSolidRect(rect, fillColor); DrawSolidRect(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width, borderThickness), borderColor); DrawSolidRect(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).yMax - borderThickness, ((Rect)(ref rect)).width, borderThickness), borderColor); DrawSolidRect(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, borderThickness, ((Rect)(ref rect)).height), borderColor); DrawSolidRect(new Rect(((Rect)(ref rect)).xMax - borderThickness, ((Rect)(ref rect)).y, borderThickness, ((Rect)(ref rect)).height), borderColor); } private static void DrawSolidRect(Rect rect, Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_000c: 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) Color color2 = GUI.color; GUI.color = color; GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture); GUI.color = color2; } private void EnsureStyles() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Expected O, but got Unknown //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Expected O, but got Unknown //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Expected O, but got Unknown //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Expected O, but got Unknown //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Expected O, but got Unknown //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Expected O, but got Unknown //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Expected O, but got Unknown //IL_0393: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03ba: Expected O, but got Unknown //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_0423: Unknown result type (might be due to invalid IL or missing references) //IL_042d: Expected O, but got Unknown //IL_044c: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Unknown result type (might be due to invalid IL or missing references) //IL_0473: Expected O, but got Unknown //IL_04c3: Unknown result type (might be due to invalid IL or missing references) //IL_04e0: Unknown result type (might be due to invalid IL or missing references) //IL_04ea: Expected O, but got Unknown //IL_050e: Unknown result type (might be due to invalid IL or missing references) //IL_0523: Unknown result type (might be due to invalid IL or missing references) if (_titleStyle == null) { _titleStyle = new GUIStyle(GUI.skin.label); _titleStyle.fontSize = 32; _titleStyle.fontStyle = (FontStyle)1; _titleStyle.alignment = (TextAnchor)3; _titleStyle.clipping = (TextClipping)1; _titleStyle.normal.textColor = Color.white; } if (_detailTitleStyle == null) { _detailTitleStyle = new GUIStyle(GUI.skin.label); _detailTitleStyle.fontSize = 22; _detailTitleStyle.fontStyle = (FontStyle)1; _detailTitleStyle.alignment = (TextAnchor)0; _detailTitleStyle.wordWrap = true; _detailTitleStyle.clipping = (TextClipping)1; _detailTitleStyle.normal.textColor = new Color(0.96f, 0.94f, 0.88f, 1f); } if (_subtitleStyle == null) { _subtitleStyle = new GUIStyle(GUI.skin.label); _subtitleStyle.fontSize = 22; _subtitleStyle.fontStyle = (FontStyle)1; _subtitleStyle.alignment = (TextAnchor)3; _subtitleStyle.clipping = (TextClipping)1; _subtitleStyle.normal.textColor = new Color(0.96f, 0.94f, 0.88f, 1f); } if (_tabStyle == null) { _tabStyle = new GUIStyle(GUI.skin.label); _tabStyle.fontSize = 15; _tabStyle.fontStyle = (FontStyle)1; _tabStyle.alignment = (TextAnchor)4; _tabStyle.wordWrap = true; _tabStyle.clipping = (TextClipping)1; _tabStyle.normal.textColor = new Color(0.86f, 0.86f, 0.86f, 1f); } if (_selectedTabStyle == null) { _selectedTabStyle = new GUIStyle(_tabStyle); _selectedTabStyle.normal.textColor = new Color(1f, 0.95f, 0.6f, 1f); } if (_rowStyle == null) { _rowStyle = new GUIStyle(GUI.skin.label); _rowStyle.fontSize = 19; _rowStyle.alignment = (TextAnchor)3; _rowStyle.normal.textColor = Color.white; _rowStyle.clipping = (TextClipping)1; } if (_selectedRowStyle == null) { _selectedRowStyle = new GUIStyle(_rowStyle); _selectedRowStyle.normal.textColor = new Color(1f, 0.95f, 0.6f, 1f); } if (_valueStyle == null) { _valueStyle = new GUIStyle(GUI.skin.label); _valueStyle.fontSize = 16; _valueStyle.fontStyle = (FontStyle)1; _valueStyle.alignment = (TextAnchor)4; _valueStyle.clipping = (TextClipping)1; _valueStyle.normal.textColor = new Color(0.97f, 0.95f, 0.9f, 1f); } if (_descriptionStyle == null) { _descriptionStyle = new GUIStyle(GUI.skin.label); _descriptionStyle.fontSize = 15; _descriptionStyle.wordWrap = true; _descriptionStyle.clipping = (TextClipping)1; _descriptionStyle.normal.textColor = new Color(0.88f, 0.88f, 0.88f, 1f); } if (_buttonStyle == null) { _buttonStyle = new GUIStyle(GUI.skin.label); _buttonStyle.fontSize = 16; _buttonStyle.fontStyle = (FontStyle)1; _buttonStyle.alignment = (TextAnchor)4; _buttonStyle.clipping = (TextClipping)1; _buttonStyle.normal.textColor = new Color(0.92f, 0.92f, 0.92f, 1f); } if (_selectedButtonStyle == null) { _selectedButtonStyle = new GUIStyle(_buttonStyle); _selectedButtonStyle.normal.textColor = new Color(1f, 0.95f, 0.6f, 1f); } if (_badgeStyle == null) { _badgeStyle = new GUIStyle(GUI.skin.label); _badgeStyle.fontSize = 11; _badgeStyle.fontStyle = (FontStyle)1; _badgeStyle.alignment = (TextAnchor)4; _badgeStyle.clipping = (TextClipping)1; _badgeStyle.normal.textColor = new Color(0.98f, 0.96f, 0.92f, 1f); } if (_smallInputStyle == null) { _smallInputStyle = new GUIStyle(GUI.skin.textField); _smallInputStyle.fontSize = 15; _smallInputStyle.alignment = (TextAnchor)3; _smallInputStyle.normal.textColor = Color.white; _smallInputStyle.focused.textColor = Color.white; } } private void BuildOptionDefinitions() { AddInfo("summary_rating", MenuCategory.Summary, "summary_rating", "desc_summary_rating"); AddInfo("summary_score", MenuCategory.Summary, "summary_score", "desc_summary_score"); AddInfo("summary_profile", MenuCategory.Summary, "summary_profile", "desc_summary_profile"); AddInfo("summary_mutator_count", MenuCategory.Summary, "summary_mutator_count", "desc_summary_mutator_count"); AddSetting("base_health", MenuCategory.Player, "health", "desc_health"); AddSetting("healing_multiplier", MenuCategory.Player, "healing_multiplier", "desc_healing_multiplier"); AddSetting("healing_cost_multiplier", MenuCategory.Player, "healing_cost_multiplier", "desc_healing_cost_multiplier"); AddSetting("invincibility_time_multiplier", MenuCategory.Player, "invincibility_time_multiplier", "desc_invincibility_time_multiplier"); AddSetting("damage_taken", MenuCategory.Player, "damage_taken", "desc_damage_taken"); AddSetting("environmental_damage_multiplier", MenuCategory.Player, "environmental_damage_multiplier", "desc_environmental_damage_multiplier", CustomDifficultyOptionStatus.Experimental); AddSetting("one_hit_mode", MenuCategory.Player, "one_hit_mode", "desc_one_hit_mode"); AddAction("action_reset_category", MenuCategory.Player, "reset_category", "desc_reset_category"); AddSetting("base_damage", MenuCategory.Damage, "damage", "desc_damage"); AddSetting("skill_damage_multiplier", MenuCategory.Damage, "skill_damage_multiplier", "desc_skill_damage_multiplier"); AddSetting("silk_spear_damage_multiplier", MenuCategory.Damage, "silk_spear_damage_multiplier", "desc_silk_spear_damage_multiplier", CustomDifficultyOptionStatus.Experimental); AddSetting("boss_damage_multiplier", MenuCategory.Damage, "boss_damage_multiplier", "desc_boss_damage_multiplier"); AddSetting("common_enemy_damage_multiplier", MenuCategory.Damage, "common_enemy_damage_multiplier", "desc_common_enemy_damage_multiplier"); AddSetting("critical_chance", MenuCategory.Damage, "critical_chance", "desc_critical_chance", CustomDifficultyOptionStatus.Experimental); AddSetting("critical_damage_multiplier", MenuCategory.Damage, "critical_damage_multiplier", "desc_critical_damage_multiplier", CustomDifficultyOptionStatus.Experimental); AddAction("action_reset_category", MenuCategory.Damage, "reset_category", "desc_reset_category"); AddSetting("enemy_health_multiplier", MenuCategory.Enemies, "enemy_health_multiplier", "desc_enemy_health_multiplier"); AddSetting("enemy_damage_multiplier", MenuCategory.Enemies, "enemy_damage_multiplier", "desc_enemy_damage_multiplier"); AddSetting("common_enemy_damage_taken_multiplier", MenuCategory.Enemies, "common_enemy_damage_taken_multiplier", "desc_common_enemy_damage_taken_multiplier"); AddSetting("enemy_speed_multiplier", MenuCategory.Enemies, "enemy_speed_multiplier", "desc_enemy_speed_multiplier", CustomDifficultyOptionStatus.Reserved); AddSetting("enemy_attack_cooldown_multiplier", MenuCategory.Enemies, "enemy_attack_cooldown_multiplier", "desc_enemy_attack_cooldown_multiplier", CustomDifficultyOptionStatus.Reserved); AddSetting("enemy_aggression_multiplier", MenuCategory.Enemies, "enemy_aggression_multiplier", "desc_enemy_aggression_multiplier", CustomDifficultyOptionStatus.Reserved); AddAction("action_reset_category", MenuCategory.Enemies, "reset_category", "desc_reset_category"); AddSetting("boss_health_multiplier", MenuCategory.Bosses, "boss_health_multiplier", "desc_boss_health_multiplier"); AddSetting("boss_damage_taken_multiplier", MenuCategory.Bosses, "boss_damage_taken_multiplier", "desc_boss_damage_taken_multiplier"); AddSetting("boss_speed_multiplier", MenuCategory.Bosses, "boss_speed_multiplier", "desc_boss_speed_multiplier", CustomDifficultyOptionStatus.Reserved); AddSetting("boss_attack_cooldown_multiplier", MenuCategory.Bosses, "boss_attack_cooldown_multiplier", "desc_boss_attack_cooldown_multiplier", CustomDifficultyOptionStatus.Reserved); AddSetting("boss_brutal_mode", MenuCategory.Bosses, "boss_brutal_mode", "desc_boss_brutal_mode", CustomDifficultyOptionStatus.Experimental); AddSetting("disable_healing_during_boss", MenuCategory.Bosses, "disable_healing_during_boss", "desc_disable_healing_during_boss"); AddSetting("healing_during_boss_multiplier", MenuCategory.Bosses, "healing_during_boss_multiplier", "desc_healing_during_boss_multiplier"); AddAction("action_reset_category", MenuCategory.Bosses, "reset_category", "desc_reset_category"); AddSetting("drop_rate", MenuCategory.Drops, "drop_rate", "desc_drop"); AddSetting("currency_drop_multiplier", MenuCategory.Drops, "currency_drop_multiplier", "desc_currency_drop_multiplier"); AddSetting("item_drop_multiplier", MenuCategory.Drops, "item_drop_multiplier", "desc_item_drop_multiplier"); AddSetting("boss_reward_multiplier", MenuCategory.Drops, "boss_reward_multiplier", "desc_boss_reward_multiplier", CustomDifficultyOptionStatus.Experimental); AddAction("action_reset_category", MenuCategory.Drops, "reset_category", "desc_reset_category"); AddSetting("shop_price_multiplier", MenuCategory.Economy, "shop_price_multiplier", "desc_shop_price_multiplier", CustomDifficultyOptionStatus.Experimental); AddSetting("death_currency_loss_multiplier", MenuCategory.Economy, "death_currency_loss_multiplier", "desc_death_currency_loss_multiplier", CustomDifficultyOptionStatus.Reserved); AddAction("action_reset_category", MenuCategory.Economy, "reset_category", "desc_reset_category"); AddSetting("player_speed_multiplier", MenuCategory.Movement, "player_speed_multiplier", "desc_player_speed_multiplier"); AddSetting("jump_height_multiplier", MenuCategory.Movement, "jump_height_multiplier", "desc_jump_height_multiplier"); AddSetting("dash_cooldown_multiplier", MenuCategory.Movement, "dash_cooldown_multiplier", "desc_dash_cooldown_multiplier"); AddSetting("ability_cost_multiplier", MenuCategory.Movement, "ability_cost_multiplier", "desc_ability_cost_multiplier"); AddSetting("silk_cost_multiplier", MenuCategory.Movement, "silk_cost_multiplier", "desc_silk_cost_multiplier"); AddAction("action_reset_category", MenuCategory.Movement, "reset_category", "desc_reset_category"); AddSetting("one_hit_mode", MenuCategory.Mutators, "mutator_one_hit", "desc_one_hit_mode"); AddSetting("mutator_no_healing", MenuCategory.Mutators, "mutator_no_healing", "desc_mutator_no_healing"); AddSetting("mutator_low_gravity", MenuCategory.Mutators, "mutator_low_gravity", "desc_mutator_low_gravity", CustomDifficultyOptionStatus.Experimental); AddSetting("mutator_double_damage", MenuCategory.Mutators, "mutator_double_damage", "desc_mutator_double_damage"); AddSetting("mutator_glass_cannon", MenuCategory.Mutators, "mutator_glass_cannon", "desc_mutator_glass_cannon"); AddSetting("mutator_fast_enemies", MenuCategory.Mutators, "mutator_fast_enemies", "desc_mutator_fast_enemies", CustomDifficultyOptionStatus.Reserved); AddSetting("mutator_tank_enemies", MenuCategory.Mutators, "mutator_tank_enemies", "desc_mutator_tank_enemies"); AddSetting("mutator_aggressive_enemies", MenuCategory.Mutators, "mutator_aggressive_enemies", "desc_mutator_aggressive_enemies", CustomDifficultyOptionStatus.Experimental); AddSetting("mutator_randomized_enemy_health", MenuCategory.Mutators, "mutator_randomized_enemy_health", "desc_mutator_randomized_enemy_health", CustomDifficultyOptionStatus.Experimental); AddSetting("mutator_rich_world", MenuCategory.Mutators, "mutator_rich_world", "desc_mutator_rich_world"); AddSetting("mutator_poor_world", MenuCategory.Mutators, "mutator_poor_world", "desc_mutator_poor_world"); AddSetting("mutator_expensive_shops", MenuCategory.Mutators, "mutator_expensive_shops", "desc_mutator_expensive_shops", CustomDifficultyOptionStatus.Experimental); AddSetting("mutator_no_death_loss", MenuCategory.Mutators, "mutator_no_death_loss", "desc_mutator_no_death_loss", CustomDifficultyOptionStatus.Reserved); AddSetting("mutator_boss_frenzy", MenuCategory.Mutators, "mutator_boss_frenzy", "desc_mutator_boss_frenzy", CustomDifficultyOptionStatus.Experimental); AddSetting("mutator_no_mercy", MenuCategory.Mutators, "mutator_no_mercy", "desc_mutator_no_mercy"); AddSetting("mutator_extended_fights", MenuCategory.Mutators, "mutator_extended_fights", "desc_mutator_extended_fights"); AddAction("action_reset_category", MenuCategory.Mutators, "reset_category", "desc_reset_category"); AddSetting("saved_preset_selector", MenuCategory.Presets, "saved_preset_selector", "desc_saved_preset_selector"); AddAction("action_create_preset", MenuCategory.Presets, "create_preset", "desc_create_preset"); AddAction("action_save_preset", MenuCategory.Presets, "save_preset", "desc_save_preset"); AddAction("action_load_preset", MenuCategory.Presets, "load_preset", "desc_load_preset"); AddAction("action_duplicate_preset", MenuCategory.Presets, "duplicate_preset", "desc_duplicate_preset"); AddAction("action_rename_preset", MenuCategory.Presets, "rename_preset", "desc_rename_preset"); AddAction("action_delete_preset", MenuCategory.Presets, "delete_preset", "desc_delete_preset"); AddAction("action_reset_preset_file", MenuCategory.Presets, "reset_preset_file", "desc_reset_preset_file"); AddAction("action_export_preset", MenuCategory.Presets, "export_preset", "desc_export_preset"); AddAction("action_import_preset", MenuCategory.Presets, "import_preset", "desc_import_preset"); AddAction("action_reload_presets", MenuCategory.Presets, "reload_presets", "desc_reload_presets"); AddPreset("preset_easy", DifficultyPreset.Easy); AddPreset("preset_normal", DifficultyPreset.Normal); AddPreset("preset_hard", DifficultyPreset.Hard); AddPreset("preset_nightmare", DifficultyPreset.Nightmare); AddPreset("preset_one_hit", DifficultyPreset.OneHit); AddPreset("preset_farm", DifficultyPreset.Farm); AddPreset("preset_custom", DifficultyPreset.Custom); AddSetting("boss_profiles_enabled", MenuCategory.BossProfiles, "boss_profiles_enabled", "desc_boss_profiles_enabled", CustomDifficultyOptionStatus.Experimental); AddSetting("boss_profiles_fallback_global", MenuCategory.BossProfiles, "boss_profiles_fallback_global", "desc_boss_profiles_fallback_global", CustomDifficultyOptionStatus.Experimental); AddInfo("boss_profiles_file", MenuCategory.BossProfiles, "boss_profiles_file", "desc_boss_profiles_file", CustomDifficultyOptionStatus.Experimental); AddSetting("context_boss_rules", MenuCategory.Context, "context_boss_rules", "desc_context_boss_rules", CustomDifficultyOptionStatus.Reserved); AddSetting("context_exploration_rules", MenuCategory.Context, "context_exploration_rules", "desc_context_exploration_rules", CustomDifficultyOptionStatus.Reserved); AddSetting("context_low_health_rule", MenuCategory.Context, "context_low_health_rule", "desc_context_low_health_rule", CustomDifficultyOptionStatus.Reserved); AddSetting("context_death_streak_tracking", MenuCategory.Context, "context_death_streak_tracking", "desc_context_death_streak_tracking", CustomDifficultyOptionStatus.Reserved); AddSetting("adaptive_enabled", MenuCategory.Adaptive, "adaptive_enabled", "desc_adaptive_enabled", CustomDifficultyOptionStatus.Reserved); AddSetting("adaptive_boss_assist", MenuCategory.Adaptive, "adaptive_boss_assist", "desc_adaptive_boss_assist", CustomDifficultyOptionStatus.Reserved); AddSetting("adaptive_exploration_assist", MenuCategory.Adaptive, "adaptive_exploration_assist", "desc_adaptive_exploration_assist", CustomDifficultyOptionStatus.Reserved); AddSetting("adaptive_economy_assist", MenuCategory.Adaptive, "adaptive_economy_assist", "desc_adaptive_economy_assist", CustomDifficultyOptionStatus.Reserved); AddSetting("adaptive_max_assist", MenuCategory.Adaptive, "adaptive_max_assist", "desc_adaptive_max_assist", CustomDifficultyOptionStatus.Reserved); AddSetting("adaptive_apply_mode", MenuCategory.Adaptive, "adaptive_apply_mode", "desc_adaptive_apply_mode", CustomDifficultyOptionStatus.Reserved); AddAction("action_reset_category", MenuCategory.Adaptive, "reset_category", "desc_reset_category"); AddSetting("menu_language", MenuCategory.System, "menu_language", "desc_menu_language"); AddAction("action_apply", MenuCategory.System, "apply", "desc_apply"); AddAction("action_reset_all", MenuCategory.System, "reset", "desc_reset"); AddAction("action_discard", MenuCategory.System, "discard", "desc_discard"); AddAction("action_close", MenuCategory.System, "back", "desc_back"); } private void AddSetting(string id, MenuCategory category, string labelKey, string descriptionKey) { AddSetting(id, category, labelKey, descriptionKey, CustomDifficultyOptionStatus.Supported); } private void AddSetting(string id, MenuCategory category, string labelKey, string descriptionKey, CustomDifficultyOptionStatus status) { MenuOptionDefinition menuOptionDefinition = new MenuOptionDefinition(); menuOptionDefinition.Id = id; menuOptionDefinition.Category = category; menuOptionDefinition.LabelKey = labelKey; menuOptionDefinition.DescriptionKey = descriptionKey; menuOptionDefinition.Status = status; _allOptions.Add(menuOptionDefinition); } private void AddInfo(string id, MenuCategory category, string labelKey, string descriptionKey) { AddInfo(id, category, labelKey, descriptionKey, CustomDifficultyOptionStatus.Supported); } private void AddInfo(string id, MenuCategory category, string labelKey, string descriptionKey, CustomDifficultyOptionStatus status) { MenuOptionDefinition menuOptionDefinition = new MenuOptionDefinition(); menuOptionDefinition.Id = id; menuOptionDefinition.Category = category; menuOptionDefinition.LabelKey = labelKey; menuOptionDefinition.DescriptionKey = descriptionKey; menuOptionDefinition.Status = status; menuOptionDefinition.InfoOption = true; _allOptions.Add(menuOptionDefinition); } private void AddPreset(string labelKey, DifficultyPreset preset) { MenuOptionDefinition menuOptionDefinition = new MenuOptionDefinition(); menuOptionDefinition.Id = labelKey; menuOptionDefinition.Category = MenuCategory.Presets; menuOptionDefinition.LabelKey = labelKey; menuOptionDefinition.DescriptionKey = "desc_" + labelKey; menuOptionDefinition.PresetOption = true; menuOptionDefinition.Preset = preset; menuOptionDefinition.Status = CustomDifficultyOptionStatus.Supported; _allOptions.Add(menuOptionDefinition); } private void AddAction(string id, MenuCategory category, string labelKey, string descriptionKey) { MenuOptionDefinition menuOptionDefinition = new MenuOptionDefinition(); menuOptionDefinition.Id = id; menuOptionDefinition.Category = category; menuOptionDefinition.LabelKey = labelKey; menuOptionDefinition.DescriptionKey = descriptionKey; menuOptionDefinition.ActionOption = true; menuOptionDefinition.Status = CustomDifficultyOptionStatus.Supported; _allOptions.Add(menuOptionDefinition); } private List GetCurrentOptions() { List list = new List(); if (!string.IsNullOrWhiteSpace(_searchText)) { for (int i = 0; i < _allOptions.Count; i++) { if (MatchesSearch(_allOptions[i], _searchText)) { list.Add(_allOptions[i]); } } } else { MenuCategory menuCategory = _categories[_selectedCategoryIndex]; for (int j = 0; j < _allOptions.Count; j++) { MenuOptionDefinition menuOptionDefinition = _allOptions[j]; if (menuCategory == MenuCategory.Favorites) { if (_favorites.IsFavorite(menuOptionDefinition.Id)) { list.Add(menuOptionDefinition); } } else if (menuOptionDefinition.Category == menuCategory) { list.Add(menuOptionDefinition); } } } if (_selectedOptionIndex >= list.Count) { _selectedOptionIndex = Math.Max(0, list.Count - 1); } return list; } private MenuOptionDefinition GetSelectedOption() { List currentOptions = GetCurrentOptions(); if (currentOptions.Count == 0) { return null; } if (_selectedOptionIndex < 0) { _selectedOptionIndex = 0; } if (_selectedOptionIndex >= currentOptions.Count) { _selectedOptionIndex = currentOptions.Count - 1; } return currentOptions[_selectedOptionIndex]; } private bool MatchesSearch(MenuOptionDefinition option, string search) { if (option == null || string.IsNullOrWhiteSpace(search)) { return false; } string value = search.Trim(); if (!ContainsIgnoreCase(option.Id, value) && !ContainsIgnoreCase(_localizationManager.Get(option.LabelKey), value) && !ContainsIgnoreCase(_localizationManager.Get(option.DescriptionKey), value)) { return ContainsIgnoreCase(GetCategoryLabel(option.Category), value); } return true; } private static bool ContainsIgnoreCase(string source, string value) { if (!string.IsNullOrEmpty(source)) { return source.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private string GetVisibleCategoryLabel() { if (!string.IsNullOrWhiteSpace(_searchText)) { return _localizationManager.Get("category_search") + ": " + _searchText; } return GetCategoryLabel(_categories[_selectedCategoryIndex]); } private void SelectCategory(MenuCategory category) { for (int i = 0; i < _categories.Length; i++) { if (_categories[i] == category) { _selectedCategoryIndex = i; _selectedOptionIndex = 0; break; } } } private string GetCategoryLabel(MenuCategory category) { return category switch { MenuCategory.Summary => _localizationManager.Get("category_summary"), MenuCategory.Favorites => _localizationManager.Get("category_favorites"), MenuCategory.Player => _localizationManager.Get("category_player"), MenuCategory.Damage => _localizationManager.Get("category_damage"), MenuCategory.Enemies => _localizationManager.Get("category_enemies"), MenuCategory.Bosses => _localizationManager.Get("category_bosses"), MenuCategory.Drops => _localizationManager.Get("category_drops"), MenuCategory.Economy => _localizationManager.Get("category_economy"), MenuCategory.Movement => _localizationManager.Get("category_movement"), MenuCategory.Mutators => _localizationManager.Get("category_mutators"), MenuCategory.Presets => _localizationManager.Get("category_presets"), MenuCategory.BossProfiles => _localizationManager.Get("category_boss_profiles"), MenuCategory.Context => _localizationManager.Get("category_context"), MenuCategory.Adaptive => _localizationManager.Get("category_adaptive"), MenuCategory.System => _localizationManager.Get("category_system"), _ => category.ToString(), }; } private string GetValueText(MenuOptionDefinition option) { return GetValueText(option, _configManager.GetDraftSettings()); } private string GetValueText(MenuOptionDefinition option, DifficultySettings settings) { DifficultySummary difficultySummary = CustomDifficultyDifficultySummary.Build(settings, _localizationManager); switch (option.Id) { case "summary_rating": return _localizationManager.Get(difficultySummary.RatingKey); case "summary_score": return difficultySummary.Score.ToString("0"); case "summary_profile": if (!CustomDifficultyMutatorManager.IsFarmLike(settings)) { return _localizationManager.Get("summary_custom"); } return _localizationManager.Get("summary_farm"); case "summary_mutator_count": return CustomDifficultyMutatorManager.CountEnabled(settings).ToString(); case "menu_language": return _localizationManager.GetCurrentMenuLanguageDisplayName(); case "saved_preset_selector": return _presetManager.GetSelectedPresetDisplayName(); case "base_damage": return settings.BaseDamage.ToString(); case "base_health": return settings.BaseHealth.ToString(); case "drop_rate": return FormatMultiplier(settings.DropRate); case "damage_taken": return FormatMultiplier(settings.DamageTakenMultiplier); case "healing_multiplier": return FormatMultiplier(settings.HealingMultiplier); case "healing_cost_multiplier": return FormatMultiplier(settings.HealingCostMultiplier); case "invincibility_time_multiplier": return FormatMultiplier(settings.InvincibilityTimeMultiplier); case "skill_damage_multiplier": return FormatMultiplier(settings.SkillDamageMultiplier); case "silk_spear_damage_multiplier": return FormatMultiplier(settings.SilkSpearDamageMultiplier); case "boss_damage_multiplier": return FormatMultiplier(settings.BossDamageMultiplier); case "common_enemy_damage_multiplier": return FormatMultiplier(settings.CommonEnemyDamageMultiplier); case "critical_chance": return settings.CriticalChance.ToString("0") + "%"; case "critical_damage_multiplier": return FormatMultiplier(settings.CriticalDamageMultiplier); case "environmental_damage_multiplier": return FormatMultiplier(settings.EnvironmentalDamageMultiplier); case "boss_damage_taken_multiplier": return FormatMultiplier(settings.BossDamageTakenMultiplier); case "common_enemy_damage_taken_multiplier": return FormatMultiplier(settings.CommonEnemyDamageTakenMultiplier); case "enemy_health_multiplier": return FormatMultiplier(settings.EnemyHealthMultiplier); case "enemy_damage_multiplier": return FormatMultiplier(settings.EnemyDamageMultiplier); case "enemy_speed_multiplier": return FormatMultiplier(settings.EnemySpeedMultiplier); case "enemy_attack_cooldown_multiplier": return FormatMultiplier(settings.EnemyAttackCooldownMultiplier); case "enemy_aggression_multiplier": return FormatMultiplier(settings.EnemyAggressionMultiplier); case "boss_health_multiplier": return FormatMultiplier(settings.BossHealthMultiplier); case "boss_speed_multiplier": return FormatMultiplier(settings.BossSpeedMultiplier); case "boss_attack_cooldown_multiplier": return FormatMultiplier(settings.BossAttackCooldownMultiplier); case "boss_brutal_mode": return FormatBool(settings.BossBrutalMode); case "disable_healing_during_boss": return FormatBool(settings.DisableHealingDuringBoss); case "healing_during_boss_multiplier": return FormatMultiplier(settings.HealingDuringBossMultiplier); case "currency_drop_multiplier": return FormatMultiplier(settings.CurrencyDropMultiplier); case "item_drop_multiplier": return FormatMultiplier(settings.ItemDropMultiplier); case "shop_price_multiplier": return FormatMultiplier(settings.ShopPriceMultiplier); case "boss_reward_multiplier": return FormatMultiplier(settings.BossRewardMultiplier); case "death_currency_loss_multiplier": return FormatMultiplier(settings.DeathCurrencyLossMultiplier); case "player_speed_multiplier": return FormatMultiplier(settings.PlayerSpeedMultiplier); case "jump_height_multiplier": return FormatMultiplier(settings.JumpHeightMultiplier); case "dash_cooldown_multiplier": return FormatMultiplier(settings.DashCooldownMultiplier); case "ability_cost_multiplier": return FormatMultiplier(settings.AbilityCostMultiplier); case "silk_cost_multiplier": return FormatMultiplier(settings.SilkCostMultiplier); case "one_hit_mode": return FormatBool(settings.OneHitMode); case "mutator_no_healing": return FormatBool(settings.MutatorNoHealing); case "mutator_low_gravity": return FormatBool(settings.MutatorLowGravity); case "mutator_double_damage": return FormatBool(settings.MutatorDoubleDamage); case "mutator_glass_cannon": return FormatBool(settings.MutatorGlassCannon); case "mutator_fast_enemies": return FormatBool(settings.MutatorFastEnemies); case "mutator_tank_enemies": return FormatBool(settings.MutatorTankEnemies); case "mutator_aggressive_enemies": return FormatBool(settings.MutatorAggressiveEnemies); case "mutator_randomized_enemy_health": return FormatBool(settings.MutatorRandomizedEnemyHealth); case "mutator_rich_world": return FormatBool(settings.MutatorRichWorld); case "mutator_poor_world": return FormatBool(settings.MutatorPoorWorld); case "mutator_expensive_shops": return FormatBool(settings.MutatorExpensiveShops); case "mutator_no_death_loss": return FormatBool(settings.MutatorNoDeathLoss); case "mutator_boss_frenzy": return FormatBool(settings.MutatorBossFrenzy); case "mutator_no_mercy": return FormatBool(settings.MutatorNoMercy); case "mutator_extended_fights": return FormatBool(settings.MutatorExtendedFights); case "boss_profiles_enabled": return FormatBool(settings.BossProfilesEnabled); case "boss_profiles_fallback_global": return FormatBool(settings.BossProfilesFallbackGlobal); case "boss_profiles_file": return _localizationManager.Get("preset_ready"); case "context_boss_rules": return FormatBool(settings.ContextBossRulesEnabled); case "context_exploration_rules": return FormatBool(settings.ContextExplorationRulesEnabled); case "context_low_health_rule": return FormatBool(settings.ContextLowHealthRuleEnabled); case "context_death_streak_tracking": return FormatBool(settings.ContextDeathStreakTrackingEnabled); case "adaptive_enabled": return FormatBool(settings.AdaptiveDifficultyEnabled); case "adaptive_boss_assist": return FormatBool(settings.AdaptiveBossAssistEnabled); case "adaptive_exploration_assist": return FormatBool(settings.AdaptiveExplorationAssistEnabled); case "adaptive_economy_assist": return FormatBool(settings.AdaptiveEconomyAssistEnabled); case "adaptive_max_assist": return settings.AdaptiveMaxAssist.ToString("0.0"); case "adaptive_apply_mode": return _localizationManager.Get(CustomDifficultyAdaptiveSystem.GetApplyModeKey(settings.AdaptiveApplyMode)); case "preset_custom": return _localizationManager.Get("preset_note_custom"); case "action_apply": return _localizationManager.Get("action_save_short"); case "action_reset_all": return _localizationManager.Get("action_reset_short"); case "action_discard": return _localizationManager.Get("action_discard_short"); case "action_close": return _localizationManager.Get("action_close_short"); default: if (option.PresetOption) { return _localizationManager.Get("preset_ready"); } if (option.ActionOption) { return _localizationManager.Get("run_action"); } return string.Empty; } } private string GetDefaultValueText(MenuOptionDefinition option) { if (option.Id == "menu_language") { return _localizationManager.GetDefaultMenuLanguageDisplayName(); } if (option.Id == "saved_preset_selector") { return _localizationManager.Get("none"); } DifficultySettings difficultySettings = DifficultySettings.CreateDefaults(); difficultySettings.Clamp(); return GetValueText(option, difficultySettings); } private string GetComparisonText(MenuOptionDefinition option) { string valueText = GetValueText(option); string defaultValueText = GetDefaultValueText(option); string deltaText = GetDeltaText(option); string rangeText = GetRangeText(option.Id); string text = _localizationManager.Get("comparison_current") + ": " + valueText + "\n" + _localizationManager.Get("comparison_default") + ": " + defaultValueText; if (!string.IsNullOrEmpty(deltaText)) { string text2 = text; text = text2 + "\n" + _localizationManager.Get("comparison_difference") + ": " + deltaText; } if (!string.IsNullOrEmpty(rangeText)) { string text3 = text; text = text3 + "\n" + _localizationManager.Get("comparison_range") + ": " + rangeText; } return text; } private string GetDeltaText(MenuOptionDefinition option) { DifficultySettings draftSettings = _configManager.GetDraftSettings(); DifficultySettings difficultySettings = DifficultySettings.CreateDefaults(); if (option.Id == "base_damage") { return FormatIntegerDifference(draftSettings.BaseDamage, difficultySettings.BaseDamage); } if (option.Id == "base_health") { return FormatIntegerDifference(draftSettings.BaseHealth, difficultySettings.BaseHealth); } float? numericOptionValue = GetNumericOptionValue(option.Id, draftSettings); float? numericOptionValue2 = GetNumericOptionValue(option.Id, difficultySettings); if (!numericOptionValue.HasValue || !numericOptionValue2.HasValue) { return string.Empty; } return FormatPercentDifference(numericOptionValue.Value, numericOptionValue2.Value); } private float? GetNumericOptionValue(string id, DifficultySettings settings) { return id switch { "drop_rate" => settings.DropRate, "damage_taken" => settings.DamageTakenMultiplier, "healing_multiplier" => settings.HealingMultiplier, "healing_cost_multiplier" => settings.HealingCostMultiplier, "invincibility_time_multiplier" => settings.InvincibilityTimeMultiplier, "skill_damage_multiplier" => settings.SkillDamageMultiplier, "silk_spear_damage_multiplier" => settings.SilkSpearDamageMultiplier, "boss_damage_multiplier" => settings.BossDamageMultiplier, "common_enemy_damage_multiplier" => settings.CommonEnemyDamageMultiplier, "critical_chance" => settings.CriticalChance, "critical_damage_multiplier" => settings.CriticalDamageMultiplier, "environmental_damage_multiplier" => settings.EnvironmentalDamageMultiplier, "boss_damage_taken_multiplier" => settings.BossDamageTakenMultiplier, "common_enemy_damage_taken_multiplier" => settings.CommonEnemyDamageTakenMultiplier, "enemy_health_multiplier" => settings.EnemyHealthMultiplier, "enemy_damage_multiplier" => settings.EnemyDamageMultiplier, "enemy_speed_multiplier" => settings.EnemySpeedMultiplier, "enemy_attack_cooldown_multiplier" => settings.EnemyAttackCooldownMultiplier, "enemy_aggression_multiplier" => settings.EnemyAggressionMultiplier, "boss_health_multiplier" => settings.BossHealthMultiplier, "boss_speed_multiplier" => settings.BossSpeedMultiplier, "boss_attack_cooldown_multiplier" => settings.BossAttackCooldownMultiplier, "healing_during_boss_multiplier" => settings.HealingDuringBossMultiplier, "currency_drop_multiplier" => settings.CurrencyDropMultiplier, "item_drop_multiplier" => settings.ItemDropMultiplier, "shop_price_multiplier" => settings.ShopPriceMultiplier, "boss_reward_multiplier" => settings.BossRewardMultiplier, "death_currency_loss_multiplier" => settings.DeathCurrencyLossMultiplier, "player_speed_multiplier" => settings.PlayerSpeedMultiplier, "jump_height_multiplier" => settings.JumpHeightMultiplier, "dash_cooldown_multiplier" => settings.DashCooldownMultiplier, "ability_cost_multiplier" => settings.AbilityCostMultiplier, "silk_cost_multiplier" => settings.SilkCostMultiplier, "adaptive_max_assist" => settings.AdaptiveMaxAssist, _ => null, }; } private string GetRangeText(string id) { switch (id) { case "base_damage": return 1 + " - " + 99999; case "base_health": return 1 + " - " + 99; case "drop_rate": return FormatMultiplier(0.1f) + " - " + FormatMultiplier(10f); case "critical_chance": return "0% - 100%"; case "adaptive_max_assist": return "0.0 - 1.0"; default: if (!GetNumericOptionValue(id, DifficultySettings.CreateDefaults()).HasValue) { return string.Empty; } return FormatMultiplier(0f) + " - " + FormatMultiplier(10f); } } private string GetDescriptionText(MenuOptionDefinition option) { if (option == null) { return string.Empty; } string text = _localizationManager.Get(option.DescriptionKey); if (option.Id == "summary_rating" || option.Id == "summary_score" || option.Id == "summary_profile" || option.Id == "summary_mutator_count") { DifficultySummary difficultySummary = CustomDifficultyDifficultySummary.Build(_configManager.GetDraftSettings(), _localizationManager); text = text + "\n\n" + string.Join("\n", difficultySummary.Lines.ToArray()); } return text; } private string GetExtraInfoText(MenuOptionDefinition option) { if (option == null) { return string.Empty; } if (option.Category == MenuCategory.Presets || option.Id == "saved_preset_selector") { return _localizationManager.Get("preset_folder") + ": " + _presetManager.PresetDirectory + "\n" + _localizationManager.Get("import_folder") + ": " + _presetManager.ImportDirectory + "\n" + _localizationManager.Get("export_folder") + ": " + _presetManager.ExportDirectory + "\n" + _localizationManager.Get("last_message") + ": " + (_presetManager.LastMessage ?? _localizationManager.Get("none")); } if (option.Category == MenuCategory.BossProfiles) { return _localizationManager.Get("boss_profiles_path") + ": " + _bossProfileManager.ProfilePath; } if (_favorites.IsFavorite(option.Id)) { return _localizationManager.Get("favorite_hint_on"); } return _localizationManager.Get("favorite_hint_off"); } private string GetStatusShortText(CustomDifficultyOptionStatus status) { return status switch { CustomDifficultyOptionStatus.Experimental => _localizationManager.Get("label_experimental_short"), CustomDifficultyOptionStatus.Reserved => _localizationManager.Get("label_reserved_short"), CustomDifficultyOptionStatus.Unsupported => _localizationManager.Get("label_unsupported_short"), _ => _localizationManager.Get("label_supported_short"), }; } private string GetStatusText(MenuOptionDefinition option) { CustomDifficultyOptionStatus customDifficultyOptionStatus = option?.Status ?? CustomDifficultyOptionStatus.Supported; string empty = string.Empty; empty = customDifficultyOptionStatus switch { CustomDifficultyOptionStatus.Experimental => _localizationManager.Get("experimental_note"), CustomDifficultyOptionStatus.Reserved => _localizationManager.Get("reserved_note"), CustomDifficultyOptionStatus.Unsupported => _localizationManager.Get("unsupported_note"), _ => _localizationManager.Get("supported_note"), }; if (option != null && IsDangerousOption(option.Id)) { empty = empty + "\n\n" + _localizationManager.Get("danger_warning"); } return empty; } private bool IsModifiedOption(MenuOptionDefinition option) { if (option == null || option.ActionOption || option.PresetOption || option.InfoOption) { return false; } return !string.Equals(GetValueText(option), GetDefaultValueText(option), StringComparison.Ordinal); } private static bool IsDangerousOption(string id) { switch (id) { case "environmental_damage_multiplier": case "enemy_speed_multiplier": case "enemy_attack_cooldown_multiplier": case "enemy_aggression_multiplier": case "boss_speed_multiplier": case "boss_attack_cooldown_multiplier": case "death_currency_loss_multiplier": case "mutator_low_gravity": case "mutator_fast_enemies": case "mutator_aggressive_enemies": case "mutator_randomized_enemy_health": case "mutator_expensive_shops": case "mutator_no_death_loss": case "mutator_boss_frenzy": case "boss_profiles_enabled": case "boss_profiles_fallback_global": case "boss_profiles_file": case "context_boss_rules": case "context_exploration_rules": case "context_low_health_rule": case "context_death_streak_tracking": case "adaptive_enabled": case "adaptive_boss_assist": case "adaptive_exploration_assist": case "adaptive_economy_assist": case "adaptive_max_assist": case "adaptive_apply_mode": return true; default: return false; } } private static bool IsBooleanOption(string id) { switch (id) { case "boss_brutal_mode": case "disable_healing_during_boss": case "one_hit_mode": case "mutator_no_healing": case "mutator_low_gravity": case "mutator_double_damage": case "mutator_glass_cannon": case "mutator_fast_enemies": case "mutator_tank_enemies": case "mutator_aggressive_enemies": case "mutator_randomized_enemy_health": case "mutator_rich_world": case "mutator_poor_world": case "mutator_expensive_shops": case "mutator_no_death_loss": case "mutator_boss_frenzy": case "mutator_no_mercy": case "mutator_extended_fights": case "boss_profiles_enabled": case "boss_profiles_fallback_global": case "context_boss_rules": case "context_exploration_rules": case "context_low_health_rule": case "context_death_streak_tracking": case "adaptive_enabled": case "adaptive_boss_assist": case "adaptive_exploration_assist": case "adaptive_economy_assist": return true; default: return false; } } private static bool IsWideValueOption(string id) { if (!(id == "menu_language") && !(id == "saved_preset_selector")) { return id == "adaptive_apply_mode"; } return true; } private string FormatMultiplier(float value) { return "x" + value.ToString("0.0"); } private string FormatBool(bool value) { return _localizationManager.Get(value ? "enabled" : "disabled"); } private static string FormatIntegerDifference(int current, int defaults) { int num = current - defaults; if (num == 0) { return "0"; } return ((num > 0) ? "+" : string.Empty) + num; } private static string FormatPercentDifference(float current, float defaults) { if (Math.Abs(defaults) < 0.001f) { return current.ToString("0.0"); } float num = (current - defaults) / defaults * 100f; if (Math.Abs(num) < 0.1f) { return "0%"; } return ((num > 0f) ? "+" : string.Empty) + num.ToString("0") + "%"; } private static float GetAxisSafe(string axisName) { try { return Input.GetAxisRaw(axisName); } catch { return 0f; } } } internal static class CustomDifficultyMutatorManager { public static bool BlocksHealing(DifficultySettings settings, bool isBoss) { if (settings == null) { return false; } if (!settings.MutatorNoHealing) { if (isBoss) { return settings.MutatorNoMercy; } return false; } return true; } public static float GetHealingMultiplier(DifficultySettings settings, bool isBoss) { if (settings == null) { return 1f; } if (BlocksHealing(settings, isBoss)) { return 0f; } if (!isBoss || !settings.MutatorBossFrenzy) { return 1f; } return 0.75f; } public static float GetIncomingDamageMultiplier(DifficultySettings settings, bool isBoss, bool isEnvironmental) { if (settings == null) { return 1f; } float num = 1f; if (settings.MutatorGlassCannon) { num *= 1.75f; } if (isBoss && settings.MutatorBossFrenzy) { num *= 1.25f; } if (!isEnvironmental && !isBoss && settings.MutatorAggressiveEnemies) { num *= 1.15f; } return num; } public static float GetOutgoingDamageMultiplier(DifficultySettings settings, bool isBoss) { if (settings == null) { return 1f; } float num = 1f; if (settings.MutatorDoubleDamage) { num *= 2f; } if (settings.MutatorGlassCannon) { num *= 2.5f; } if (isBoss) { if (settings.MutatorBossFrenzy) { num /= 1.15f; } if (settings.MutatorExtendedFights) { num /= 1.75f; } } else if (settings.MutatorTankEnemies) { num /= 1.5f; } return num; } public static float GetDropMultiplier(DifficultySettings settings) { if (settings == null) { return 1f; } float num = 1f; if (settings.MutatorRichWorld) { num *= 1.75f; } if (settings.MutatorPoorWorld) { num *= 0.5f; } return num; } public static float GetShopPriceMultiplier(DifficultySettings settings) { if (settings == null || !settings.MutatorExpensiveShops) { return 1f; } return 1.75f; } public static float GetDeathCurrencyLossMultiplier(DifficultySettings settings) { if (settings == null || !settings.MutatorNoDeathLoss) { return 1f; } return 0f; } public static float GetJumpMultiplier(DifficultySettings settings) { if (settings == null || !settings.MutatorLowGravity) { return 1f; } return 1.18f; } public static float GetSpeedMultiplier(DifficultySettings settings) { if (settings == null || !settings.MutatorFastEnemies) { return 1f; } return 1.2f; } public static int CountEnabled(DifficultySettings settings) { if (settings == null) { return 0; } int num = 0; num += (settings.OneHitMode ? 1 : 0); num += (settings.MutatorNoHealing ? 1 : 0); num += (settings.MutatorLowGravity ? 1 : 0); num += (settings.MutatorDoubleDamage ? 1 : 0); num += (settings.MutatorGlassCannon ? 1 : 0); num += (settings.MutatorFastEnemies ? 1 : 0); num += (settings.MutatorTankEnemies ? 1 : 0); num += (settings.MutatorAggressiveEnemies ? 1 : 0); num += (settings.MutatorRandomizedEnemyHealth ? 1 : 0); num += (settings.MutatorRichWorld ? 1 : 0); num += (settings.MutatorPoorWorld ? 1 : 0); num += (settings.MutatorExpensiveShops ? 1 : 0); num += (settings.MutatorNoDeathLoss ? 1 : 0); num += (settings.MutatorBossFrenzy ? 1 : 0); num += (settings.MutatorNoMercy ? 1 : 0); return num + (settings.MutatorExtendedFights ? 1 : 0); } public static bool IsFarmLike(DifficultySettings settings) { if (settings == null) { return false; } if (settings.MutatorRichWorld && settings.CurrencyDropMultiplier >= 1.5f) { return settings.DamageTakenMultiplier <= 0.8f; } return false; } } internal enum CustomDifficultyOptionStatus { Supported, Experimental, Reserved, Unsupported } [BepInPlugin("codex.silksong.custom-difficulty", "Custom Difficulty", "2.1.1")] public sealed class CustomDifficultyPlugin : BaseUnityPlugin { public const string PluginGuid = "codex.silksong.custom-difficulty"; public const string PluginName = "Custom Difficulty"; public const string PluginVersion = "2.1.1"; private static CustomDifficultyPlugin _instance; private Harmony _harmony; private CustomDifficultyConfigManager _configManager; private CustomDifficultyLocalizationManager _localizationManager; private CustomDifficultyGameplayHooks _gameplayHooks; private CustomDifficultyFavorites _favorites; private CustomDifficultyPresetManager _presetManager; private CustomDifficultyBossProfileManager _bossProfileManager; private CustomDifficultyMenuUI _menuUi; private void Awake() { //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Expected O, but got Unknown //IL_010a: Unknown result type (might be due to invalid IL or missing references) _instance = this; string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string localizationDirectory = Path.Combine(directoryName, "Localization"); _configManager = new CustomDifficultyConfigManager((BaseUnityPlugin)(object)this); _localizationManager = new CustomDifficultyLocalizationManager((BaseUnityPlugin)(object)this, localizationDirectory); _favorites = new CustomDifficultyFavorites((BaseUnityPlugin)(object)this); _presetManager = new CustomDifficultyPresetManager((BaseUnityPlugin)(object)this, _configManager, _favorites); _bossProfileManager = new CustomDifficultyBossProfileManager((BaseUnityPlugin)(object)this); _gameplayHooks = new CustomDifficultyGameplayHooks((BaseUnityPlugin)(object)this, _configManager, _bossProfileManager); _menuUi = new CustomDifficultyMenuUI((BaseUnityPlugin)(object)this, _configManager, _localizationManager, _gameplayHooks, _favorites, _presetManager, _bossProfileManager); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Custom Difficulty initializing."); try { _harmony = new Harmony("codex.silksong.custom-difficulty"); _harmony.PatchAll(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Harmony patch failure: " + ex)); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Custom Difficulty loaded. Menu key: " + _configManager.GetOpenMenuKey())); } private void Update() { _localizationManager.UpdateLanguage(force: false); _gameplayHooks.Update(); _menuUi.Update(); } private void OnGUI() { _menuUi.OnGUI(); } private void OnDestroy() { if (_menuUi != null) { _menuUi.Shutdown(); } if (_harmony != null) { _harmony.UnpatchSelf(); _harmony = null; } if ((Object)(object)_instance == (Object)(object)this) { _instance = null; } } internal static void LogInfoSafe(string message) { if (!((Object)(object)_instance == (Object)null)) { ((BaseUnityPlugin)_instance).Logger.LogInfo((object)message); } } internal static void LogWarningSafe(string message) { if (!((Object)(object)_instance == (Object)null)) { ((BaseUnityPlugin)_instance).Logger.LogWarning((object)message); } } } internal sealed class CustomDifficultyPresetData { public string Schema = "CustomDifficultyPreset"; public int Version = 2; public string Name = "Custom Preset"; public string LastUpdatedUtc = string.Empty; public DifficultySettings Settings = DifficultySettings.CreateDefaults(); public List FavoriteOptionIds = new List(); public List BossProfiles = new List(); public string Notes = string.Empty; } internal sealed class CustomDifficultyPresetManager { private readonly BaseUnityPlugin _plugin; private readonly CustomDifficultyConfigManager _configManager; private readonly CustomDifficultyFavorites _favorites; private readonly string _presetDirectory; private readonly string _importDirectory; private readonly string _exportDirectory; private readonly List _presetNames = new List(); private int _selectedPresetIndex; public string PresetDirectory => _presetDirectory; public string ImportDirectory => _importDirectory; public string ExportDirectory => _exportDirectory; public string LastMessage { get; private set; } public int Count => _presetNames.Count; public CustomDifficultyPresetManager(BaseUnityPlugin plugin, CustomDifficultyConfigManager configManager, CustomDifficultyFavorites favorites) { _plugin = plugin; _configManager = configManager; _favorites = favorites; string path = Path.Combine(Paths.ConfigPath, "CustomDifficulty"); _presetDirectory = Path.Combine(path, "presets"); _importDirectory = Path.Combine(_presetDirectory, "imports"); _exportDirectory = Path.Combine(_presetDirectory, "exports"); EnsureFolders(); RefreshPresets(); SeedExamplePresetsIfNeeded(); RefreshPresets(); } public string GetSelectedPresetName() { if (_presetNames.Count == 0) { return string.Empty; } if (_selectedPresetIndex < 0) { _selectedPresetIndex = 0; } if (_selectedPresetIndex >= _presetNames.Count) { _selectedPresetIndex = _presetNames.Count - 1; } return _presetNames[_selectedPresetIndex]; } public string GetSelectedPresetDisplayName() { string selectedPresetName = GetSelectedPresetName(); if (!string.IsNullOrEmpty(selectedPresetName)) { return selectedPresetName; } return "None"; } public void CycleSelectedPreset(int direction) { RefreshPresets(); if (_presetNames.Count != 0) { _selectedPresetIndex += ((direction >= 0) ? 1 : (-1)); if (_selectedPresetIndex < 0) { _selectedPresetIndex = _presetNames.Count - 1; } else if (_selectedPresetIndex >= _presetNames.Count) { _selectedPresetIndex = 0; } } } public void RefreshPresets() { EnsureFolders(); string selectedPresetName = GetSelectedPresetName(); _presetNames.Clear(); string[] files = Directory.GetFiles(_presetDirectory, "*.json", SearchOption.TopDirectoryOnly); Array.Sort(files, (IComparer?)StringComparer.OrdinalIgnoreCase); for (int i = 0; i < files.Length; i++) { _presetNames.Add(Path.GetFileNameWithoutExtension(files[i])); } _selectedPresetIndex = 0; if (string.IsNullOrEmpty(selectedPresetName)) { return; } for (int j = 0; j < _presetNames.Count; j++) { if (string.Equals(_presetNames[j], selectedPresetName, StringComparison.OrdinalIgnoreCase)) { _selectedPresetIndex = j; break; } } } public bool CreatePreset(string requestedName) { string name = MakeUniquePresetName(SanitizePresetName(requestedName, "Custom Preset")); return SavePreset(name, _configManager.GetDraftSettings(), selectAfterSave: true); } public bool SaveSelectedPreset() { string text = GetSelectedPresetName(); if (string.IsNullOrEmpty(text)) { text = MakeUniquePresetName("Custom Preset"); } return SavePreset(text, _configManager.GetDraftSettings(), selectAfterSave: true); } public bool LoadSelectedPreset() { string selectedPresetName = GetSelectedPresetName(); if (string.IsNullOrEmpty(selectedPresetName)) { LastMessage = "No preset selected."; return false; } if (!TryReadPreset(GetPresetPath(selectedPresetName), out var preset)) { return false; } _configManager.SetDraftSettings(preset.Settings); if (preset.FavoriteOptionIds != null) { _favorites.ReplaceAll(preset.FavoriteOptionIds); } LastMessage = "Loaded preset: " + selectedPresetName; CustomDifficultyPlugin.LogInfoSafe(LastMessage); return true; } public bool DuplicateSelectedPreset(string requestedName) { string selectedPresetName = GetSelectedPresetName(); if (string.IsNullOrEmpty(selectedPresetName)) { LastMessage = "No preset selected."; return false; } if (!TryReadPreset(GetPresetPath(selectedPresetName), out var preset)) { return false; } string fallback = selectedPresetName + " Copy"; string name = MakeUniquePresetName(SanitizePresetName(requestedName, fallback)); return SavePreset(name, preset.Settings, selectAfterSave: true); } public bool RenameSelectedPreset(string requestedName) { string selectedPresetName = GetSelectedPresetName(); string text = MakeUniquePresetName(SanitizePresetName(requestedName, selectedPresetName + " Renamed")); if (string.IsNullOrEmpty(selectedPresetName)) { LastMessage = "No preset selected."; return false; } string presetPath = GetPresetPath(selectedPresetName); string presetPath2 = GetPresetPath(text); try { File.Move(presetPath, presetPath2); RefreshPresets(); SelectPresetByName(text); LastMessage = "Renamed preset to: " + text; return true; } catch (Exception ex) { LastMessage = "Could not rename preset: " + ex.Message; return false; } } public bool DeleteSelectedPreset() { string selectedPresetName = GetSelectedPresetName(); if (string.IsNullOrEmpty(selectedPresetName)) { LastMessage = "No preset selected."; return false; } try { File.Delete(GetPresetPath(selectedPresetName)); RefreshPresets(); LastMessage = "Deleted preset: " + selectedPresetName; return true; } catch (Exception ex) { LastMessage = "Could not delete preset: " + ex.Message; return false; } } public bool ResetSelectedPresetToDefaults() { string selectedPresetName = GetSelectedPresetName(); if (string.IsNullOrEmpty(selectedPresetName)) { LastMessage = "No preset selected."; return false; } return SavePreset(selectedPresetName, DifficultySettings.CreateDefaults(), selectAfterSave: true); } public bool ExportDraftPreset(string requestedName) { EnsureFolders(); string text = SanitizePresetName(requestedName, "Exported Preset"); string path = text + "-" + DateTime.UtcNow.ToString("yyyyMMdd-HHmmss") + ".json"; string text2 = Path.Combine(_exportDirectory, path); return WritePresetFile(text2, text, _configManager.GetDraftSettings(), "Exported preset: " + text2); } public bool ImportLatestPreset() { EnsureFolders(); string[] files = Directory.GetFiles(_importDirectory, "*.json", SearchOption.TopDirectoryOnly); if (files.Length == 0) { LastMessage = "Put a .json preset in: " + _importDirectory; return false; } Array.Sort(files, (string left, string right) => File.GetLastWriteTimeUtc(right).CompareTo(File.GetLastWriteTimeUtc(left))); if (!TryReadPreset(files[0], out var preset)) { return false; } string text = MakeUniquePresetName(SanitizePresetName(preset.Name, Path.GetFileNameWithoutExtension(files[0]))); if (!SavePreset(text, preset.Settings, selectAfterSave: true)) { return false; } SelectPresetByName(text); LastMessage = "Imported preset: " + text; CustomDifficultyPlugin.LogInfoSafe(LastMessage); return true; } private bool SavePreset(string name, DifficultySettings settings, bool selectAfterSave) { string presetPath = GetPresetPath(name); bool flag = WritePresetFile(presetPath, name, settings, "Saved preset: " + name); if (flag) { RefreshPresets(); if (selectAfterSave) { SelectPresetByName(name); } } return flag; } private bool WritePresetFile(string path, string name, DifficultySettings settings, string successMessage) { try { CustomDifficultyPresetData customDifficultyPresetData = new CustomDifficultyPresetData(); customDifficultyPresetData.Name = name; customDifficultyPresetData.LastUpdatedUtc = DateTime.UtcNow.ToString("o"); customDifficultyPresetData.Settings = ((settings != null) ? settings.Clone() : DifficultySettings.CreateDefaults()); customDifficultyPresetData.Settings.Clamp(); customDifficultyPresetData.FavoriteOptionIds = _favorites.GetAll(); string contents = JsonConvert.SerializeObject((object)customDifficultyPresetData, (Formatting)1); File.WriteAllText(path, contents); LastMessage = successMessage; CustomDifficultyPlugin.LogInfoSafe(LastMessage); return true; } catch (Exception ex) { LastMessage = "Could not write preset: " + ex.Message; CustomDifficultyPlugin.LogWarningSafe(LastMessage); return false; } } private bool TryReadPreset(string path, out CustomDifficultyPresetData preset) { preset = null; try { string text = File.ReadAllText(path); JObject root = JObject.Parse(text); CustomDifficultyPresetData customDifficultyPresetData = new CustomDifficultyPresetData(); JToken tokenIgnoreCase = GetTokenIgnoreCase(root, "Name"); if (tokenIgnoreCase != null) { customDifficultyPresetData.Name = ((object)tokenIgnoreCase).ToString(); } DifficultySettings difficultySettings = DifficultySettings.CreateDefaults(); JToken tokenIgnoreCase2 = GetTokenIgnoreCase(root, "Settings"); if (tokenIgnoreCase2 != null) { JsonConvert.PopulateObject(((object)tokenIgnoreCase2).ToString(), (object)difficultySettings); } else { JsonConvert.PopulateObject(text, (object)difficultySettings); } difficultySettings.Clamp(); customDifficultyPresetData.Settings = difficultySettings; JToken tokenIgnoreCase3 = GetTokenIgnoreCase(root, "FavoriteOptionIds"); if (tokenIgnoreCase3 != null) { customDifficultyPresetData.FavoriteOptionIds = tokenIgnoreCase3.ToObject>() ?? new List(); } JToken tokenIgnoreCase4 = GetTokenIgnoreCase(root, "BossProfiles"); if (tokenIgnoreCase4 != null) { customDifficultyPresetData.BossProfiles = tokenIgnoreCase4.ToObject>() ?? new List(); } preset = customDifficultyPresetData; return true; } catch (Exception ex) { LastMessage = "Invalid preset JSON: " + ex.Message; CustomDifficultyPlugin.LogWarningSafe(LastMessage); return false; } } private void SeedExamplePresetsIfNeeded() { if (_presetNames.Count <= 0) { SavePresetFromBuiltIn("Meu Farm", DifficultyPreset.Farm); SavePresetFromBuiltIn("Boss Rush", DifficultyPreset.Hard); SavePresetFromBuiltIn("Exploracao", DifficultyPreset.Easy); SavePresetFromBuiltIn("One Hit", DifficultyPreset.OneHit); SavePresetFromBuiltIn("Desafio Pessoal", DifficultyPreset.Hard); DifficultySettings difficultySettings = DifficultySettings.CreateDefaults(); difficultySettings.ApplyPreset(DifficultyPreset.Nightmare); difficultySettings.MutatorNoMercy = true; difficultySettings.MutatorBossFrenzy = true; SavePreset("Nightmare No Heal", difficultySettings, selectAfterSave: false); DifficultySettings difficultySettings2 = DifficultySettings.CreateDefaults(); difficultySettings2.MutatorGlassCannon = true; difficultySettings2.MutatorDoubleDamage = true; difficultySettings2.BaseHealth = 3; difficultySettings2.DamageTakenMultiplier = 1.5f; difficultySettings2.Clamp(); SavePreset("Glass Cannon", difficultySettings2, selectAfterSave: false); } } private void SavePresetFromBuiltIn(string name, DifficultyPreset builtInPreset) { DifficultySettings difficultySettings = DifficultySettings.CreateDefaults(); difficultySettings.ApplyPreset(builtInPreset); SavePreset(name, difficultySettings, selectAfterSave: false); } private void SelectPresetByName(string name) { for (int i = 0; i < _presetNames.Count; i++) { if (string.Equals(_presetNames[i], name, StringComparison.OrdinalIgnoreCase)) { _selectedPresetIndex = i; break; } } } private string MakeUniquePresetName(string requestedName) { string text = SanitizePresetName(requestedName, "Custom Preset"); string text2 = text; int num = 2; while (File.Exists(GetPresetPath(text2))) { text2 = text + " " + num; num++; } return text2; } private string GetPresetPath(string presetName) { return Path.Combine(_presetDirectory, SanitizePresetName(presetName, "Custom Preset") + ".json"); } private void EnsureFolders() { Directory.CreateDirectory(_presetDirectory); Directory.CreateDirectory(_importDirectory); Directory.CreateDirectory(_exportDirectory); } private static JToken GetTokenIgnoreCase(JObject root, string name) { if (root == null) { return null; } foreach (JProperty item in root.Properties()) { if (string.Equals(item.Name, name, StringComparison.OrdinalIgnoreCase)) { return item.Value; } } return null; } private static string SanitizePresetName(string requestedName, string fallback) { string text = (string.IsNullOrWhiteSpace(requestedName) ? fallback : requestedName.Trim()); char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char oldChar in invalidFileNameChars) { text = text.Replace(oldChar, '_'); } while (text.IndexOf(" ", StringComparison.Ordinal) >= 0) { text = text.Replace(" ", " "); } if (text.Length > 48) { text = text.Substring(0, 48).Trim(); } if (!string.IsNullOrWhiteSpace(text)) { return text; } return fallback; } } internal enum DifficultyPreset { Custom, Easy, Normal, Hard, Nightmare, OneHit, Farm } internal static class DifficultyConstants { public const int DefaultBaseDamage = 5; public const int MinBaseDamage = 1; public const int MaxBaseDamage = 99999; public const int DefaultBaseHealth = 5; public const int MinBaseHealth = 1; public const int MaxBaseHealth = 99; public const float DefaultDropRate = 1f; public const float DefaultMultiplier = 1f; public const float MinGeneralMultiplier = 0f; public const float MaxGeneralMultiplier = 10f; public const float MinDropRate = 0.1f; public const float MaxDropRate = 10f; public const float MinMovementMultiplier = 0.1f; public const float MaxMovementMultiplier = 3f; public const float MinCooldownMultiplier = 0.1f; public const float MaxCooldownMultiplier = 5f; public const float DefaultCriticalChance = 0f; public const float MinCriticalChance = 0f; public const float MaxCriticalChance = 100f; public const float DefaultCriticalDamageMultiplier = 2f; public const float MinCriticalDamageMultiplier = 1f; public const float MaxCriticalDamageMultiplier = 10f; } internal sealed class DifficultySettings { public int BaseDamage; public int BaseHealth; public float DropRate; public float DamageTakenMultiplier; public float HealingMultiplier; public float HealingCostMultiplier; public float InvincibilityTimeMultiplier; public float SkillDamageMultiplier; public float SilkSpearDamageMultiplier; public float BossDamageMultiplier; public float CommonEnemyDamageMultiplier; public float CriticalChance; public float CriticalDamageMultiplier; public float EnvironmentalDamageMultiplier; public float BossDamageTakenMultiplier; public float CommonEnemyDamageTakenMultiplier; public float EnemyHealthMultiplier; public float EnemyDamageMultiplier; public float EnemySpeedMultiplier; public float EnemyAttackCooldownMultiplier; public float EnemyAggressionMultiplier; public float BossHealthMultiplier; public float BossSpeedMultiplier; public float BossAttackCooldownMultiplier; public bool BossBrutalMode; public bool DisableHealingDuringBoss; public float HealingDuringBossMultiplier; public float CurrencyDropMultiplier; public float ItemDropMultiplier; public float ShopPriceMultiplier; public float BossRewardMultiplier; public float DeathCurrencyLossMultiplier; public float PlayerSpeedMultiplier; public float JumpHeightMultiplier; public float DashCooldownMultiplier; public float AbilityCostMultiplier; public float SilkCostMultiplier; public bool OneHitMode; public bool MutatorNoHealing; public bool MutatorLowGravity; public bool MutatorDoubleDamage; public bool MutatorGlassCannon; public bool MutatorFastEnemies; public bool MutatorTankEnemies; public bool MutatorAggressiveEnemies; public bool MutatorRandomizedEnemyHealth; public bool MutatorRichWorld; public bool MutatorPoorWorld; public bool MutatorExpensiveShops; public bool MutatorNoDeathLoss; public bool MutatorBossFrenzy; public bool MutatorNoMercy; public bool MutatorExtendedFights; public bool BossProfilesEnabled; public bool BossProfilesFallbackGlobal; public bool ContextBossRulesEnabled; public bool ContextExplorationRulesEnabled; public bool ContextLowHealthRuleEnabled; public bool ContextDeathStreakTrackingEnabled; public bool AdaptiveDifficultyEnabled; public bool AdaptiveBossAssistEnabled; public bool AdaptiveExplorationAssistEnabled; public bool AdaptiveEconomyAssistEnabled; public float AdaptiveMaxAssist; public int AdaptiveApplyMode; public static DifficultySettings CreateDefaults() { DifficultySettings difficultySettings = new DifficultySettings(); difficultySettings.BaseDamage = 5; difficultySettings.BaseHealth = 5; difficultySettings.DropRate = 1f; difficultySettings.DamageTakenMultiplier = 1f; difficultySettings.HealingMultiplier = 1f; difficultySettings.HealingCostMultiplier = 1f; difficultySettings.InvincibilityTimeMultiplier = 1f; difficultySettings.SkillDamageMultiplier = 1f; difficultySettings.SilkSpearDamageMultiplier = 1f; difficultySettings.BossDamageMultiplier = 1f; difficultySettings.CommonEnemyDamageMultiplier = 1f; difficultySettings.CriticalChance = 0f; difficultySettings.CriticalDamageMultiplier = 2f; difficultySettings.EnvironmentalDamageMultiplier = 1f; difficultySettings.BossDamageTakenMultiplier = 1f; difficultySettings.CommonEnemyDamageTakenMultiplier = 1f; difficultySettings.EnemyHealthMultiplier = 1f; difficultySettings.EnemyDamageMultiplier = 1f; difficultySettings.EnemySpeedMultiplier = 1f; difficultySettings.EnemyAttackCooldownMultiplier = 1f; difficultySettings.EnemyAggressionMultiplier = 1f; difficultySettings.BossHealthMultiplier = 1f; difficultySettings.BossSpeedMultiplier = 1f; difficultySettings.BossAttackCooldownMultiplier = 1f; difficultySettings.BossBrutalMode = false; difficultySettings.DisableHealingDuringBoss = false; difficultySettings.HealingDuringBossMultiplier = 1f; difficultySettings.CurrencyDropMultiplier = 1f; difficultySettings.ItemDropMultiplier = 1f; difficultySettings.ShopPriceMultiplier = 1f; difficultySettings.BossRewardMultiplier = 1f; difficultySettings.DeathCurrencyLossMultiplier = 1f; difficultySettings.PlayerSpeedMultiplier = 1f; difficultySettings.JumpHeightMultiplier = 1f; difficultySettings.DashCooldownMultiplier = 1f; difficultySettings.AbilityCostMultiplier = 1f; difficultySettings.SilkCostMultiplier = 1f; difficultySettings.OneHitMode = false; difficultySettings.MutatorNoHealing = false; difficultySettings.MutatorLowGravity = false; difficultySettings.MutatorDoubleDamage = false; difficultySettings.MutatorGlassCannon = false; difficultySettings.MutatorFastEnemies = false; difficultySettings.MutatorTankEnemies = false; difficultySettings.MutatorAggressiveEnemies = false; difficultySettings.MutatorRandomizedEnemyHealth = false; difficultySettings.MutatorRichWorld = false; difficultySettings.MutatorPoorWorld = false; difficultySettings.MutatorExpensiveShops = false; difficultySettings.MutatorNoDeathLoss = false; difficultySettings.MutatorBossFrenzy = false; difficultySettings.MutatorNoMercy = false; difficultySettings.MutatorExtendedFights = false; difficultySettings.BossProfilesEnabled = false; difficultySettings.BossProfilesFallbackGlobal = true; difficultySettings.ContextBossRulesEnabled = false; difficultySettings.ContextExplorationRulesEnabled = false; difficultySettings.ContextLowHealthRuleEnabled = false; difficultySettings.ContextDeathStreakTrackingEnabled = false; difficultySettings.AdaptiveDifficultyEnabled = false; difficultySettings.AdaptiveBossAssistEnabled = false; difficultySettings.AdaptiveExplorationAssistEnabled = false; difficultySettings.AdaptiveEconomyAssistEnabled = false; difficultySettings.AdaptiveMaxAssist = 0.25f; difficultySettings.AdaptiveApplyMode = 0; return difficultySettings; } public DifficultySettings Clone() { DifficultySettings difficultySettings = new DifficultySettings(); difficultySettings.BaseDamage = BaseDamage; difficultySettings.BaseHealth = BaseHealth; difficultySettings.DropRate = DropRate; difficultySettings.DamageTakenMultiplier = DamageTakenMultiplier; difficultySettings.HealingMultiplier = HealingMultiplier; difficultySettings.HealingCostMultiplier = HealingCostMultiplier; difficultySettings.InvincibilityTimeMultiplier = InvincibilityTimeMultiplier; difficultySettings.SkillDamageMultiplier = SkillDamageMultiplier; difficultySettings.SilkSpearDamageMultiplier = SilkSpearDamageMultiplier; difficultySettings.BossDamageMultiplier = BossDamageMultiplier; difficultySettings.CommonEnemyDamageMultiplier = CommonEnemyDamageMultiplier; difficultySettings.CriticalChance = CriticalChance; difficultySettings.CriticalDamageMultiplier = CriticalDamageMultiplier; difficultySettings.EnvironmentalDamageMultiplier = EnvironmentalDamageMultiplier; difficultySettings.BossDamageTakenMultiplier = BossDamageTakenMultiplier; difficultySettings.CommonEnemyDamageTakenMultiplier = CommonEnemyDamageTakenMultiplier; difficultySettings.EnemyHealthMultiplier = EnemyHealthMultiplier; difficultySettings.EnemyDamageMultiplier = EnemyDamageMultiplier; difficultySettings.EnemySpeedMultiplier = EnemySpeedMultiplier; difficultySettings.EnemyAttackCooldownMultiplier = EnemyAttackCooldownMultiplier; difficultySettings.EnemyAggressionMultiplier = EnemyAggressionMultiplier; difficultySettings.BossHealthMultiplier = BossHealthMultiplier; difficultySettings.BossSpeedMultiplier = BossSpeedMultiplier; difficultySettings.BossAttackCooldownMultiplier = BossAttackCooldownMultiplier; difficultySettings.BossBrutalMode = BossBrutalMode; difficultySettings.DisableHealingDuringBoss = DisableHealingDuringBoss; difficultySettings.HealingDuringBossMultiplier = HealingDuringBossMultiplier; difficultySettings.CurrencyDropMultiplier = CurrencyDropMultiplier; difficultySettings.ItemDropMultiplier = ItemDropMultiplier; difficultySettings.ShopPriceMultiplier = ShopPriceMultiplier; difficultySettings.BossRewardMultiplier = BossRewardMultiplier; difficultySettings.DeathCurrencyLossMultiplier = DeathCurrencyLossMultiplier; difficultySettings.PlayerSpeedMultiplier = PlayerSpeedMultiplier; difficultySettings.JumpHeightMultiplier = JumpHeightMultiplier; difficultySettings.DashCooldownMultiplier = DashCooldownMultiplier; difficultySettings.AbilityCostMultiplier = AbilityCostMultiplier; difficultySettings.SilkCostMultiplier = SilkCostMultiplier; difficultySettings.OneHitMode = OneHitMode; difficultySettings.MutatorNoHealing = MutatorNoHealing; difficultySettings.MutatorLowGravity = MutatorLowGravity; difficultySettings.MutatorDoubleDamage = MutatorDoubleDamage; difficultySettings.MutatorGlassCannon = MutatorGlassCannon; difficultySettings.MutatorFastEnemies = MutatorFastEnemies; difficultySettings.MutatorTankEnemies = MutatorTankEnemies; difficultySettings.MutatorAggressiveEnemies = MutatorAggressiveEnemies; difficultySettings.MutatorRandomizedEnemyHealth = MutatorRandomizedEnemyHealth; difficultySettings.MutatorRichWorld = MutatorRichWorld; difficultySettings.MutatorPoorWorld = MutatorPoorWorld; difficultySettings.MutatorExpensiveShops = MutatorExpensiveShops; difficultySettings.MutatorNoDeathLoss = MutatorNoDeathLoss; difficultySettings.MutatorBossFrenzy = MutatorBossFrenzy; difficultySettings.MutatorNoMercy = MutatorNoMercy; difficultySettings.MutatorExtendedFights = MutatorExtendedFights; difficultySettings.BossProfilesEnabled = BossProfilesEnabled; difficultySettings.BossProfilesFallbackGlobal = BossProfilesFallbackGlobal; difficultySettings.ContextBossRulesEnabled = ContextBossRulesEnabled; difficultySettings.ContextExplorationRulesEnabled = ContextExplorationRulesEnabled; difficultySettings.ContextLowHealthRuleEnabled = ContextLowHealthRuleEnabled; difficultySettings.ContextDeathStreakTrackingEnabled = ContextDeathStreakTrackingEnabled; difficultySettings.AdaptiveDifficultyEnabled = AdaptiveDifficultyEnabled; difficultySettings.AdaptiveBossAssistEnabled = AdaptiveBossAssistEnabled; difficultySettings.AdaptiveExplorationAssistEnabled = AdaptiveExplorationAssistEnabled; difficultySettings.AdaptiveEconomyAssistEnabled = AdaptiveEconomyAssistEnabled; difficultySettings.AdaptiveMaxAssist = AdaptiveMaxAssist; difficultySettings.AdaptiveApplyMode = AdaptiveApplyMode; return difficultySettings; } public void Clamp() { BaseDamage = Math.Max(1, Math.Min(99999, BaseDamage)); BaseHealth = Math.Max(1, Math.Min(99, BaseHealth)); DropRate = ClampDropRate(DropRate); DamageTakenMultiplier = ClampGeneralMultiplier(DamageTakenMultiplier); HealingMultiplier = ClampGeneralMultiplier(HealingMultiplier); HealingCostMultiplier = ClampGeneralMultiplier(HealingCostMultiplier); InvincibilityTimeMultiplier = ClampGeneralMultiplier(InvincibilityTimeMultiplier); SkillDamageMultiplier = ClampGeneralMultiplier(SkillDamageMultiplier); SilkSpearDamageMultiplier = ClampGeneralMultiplier(SilkSpearDamageMultiplier); BossDamageMultiplier = ClampGeneralMultiplier(BossDamageMultiplier); CommonEnemyDamageMultiplier = ClampGeneralMultiplier(CommonEnemyDamageMultiplier); CriticalChance = ClampCriticalChance(CriticalChance); CriticalDamageMultiplier = ClampCriticalDamageMultiplier(CriticalDamageMultiplier); EnvironmentalDamageMultiplier = ClampGeneralMultiplier(EnvironmentalDamageMultiplier); BossDamageTakenMultiplier = ClampGeneralMultiplier(BossDamageTakenMultiplier); CommonEnemyDamageTakenMultiplier = ClampGeneralMultiplier(CommonEnemyDamageTakenMultiplier); EnemyHealthMultiplier = ClampGeneralMultiplier(EnemyHealthMultiplier); EnemyDamageMultiplier = ClampGeneralMultiplier(EnemyDamageMultiplier); EnemySpeedMultiplier = ClampGeneralMultiplier(EnemySpeedMultiplier); EnemyAttackCooldownMultiplier = ClampCooldownMultiplier(EnemyAttackCooldownMultiplier); EnemyAggressionMultiplier = ClampGeneralMultiplier(EnemyAggressionMultiplier); BossHealthMultiplier = ClampGeneralMultiplier(BossHealthMultiplier); BossSpeedMultiplier = ClampGeneralMultiplier(BossSpeedMultiplier); BossAttackCooldownMultiplier = ClampCooldownMultiplier(BossAttackCooldownMultiplier); HealingDuringBossMultiplier = ClampGeneralMultiplier(HealingDuringBossMultiplier); CurrencyDropMultiplier = ClampGeneralMultiplier(CurrencyDropMultiplier); ItemDropMultiplier = ClampGeneralMultiplier(ItemDropMultiplier); ShopPriceMultiplier = ClampGeneralMultiplier(ShopPriceMultiplier); BossRewardMultiplier = ClampGeneralMultiplier(BossRewardMultiplier); DeathCurrencyLossMultiplier = ClampGeneralMultiplier(DeathCurrencyLossMultiplier); PlayerSpeedMultiplier = ClampMovementMultiplier(PlayerSpeedMultiplier); JumpHeightMultiplier = ClampMovementMultiplier(JumpHeightMultiplier); DashCooldownMultiplier = ClampCooldownMultiplier(DashCooldownMultiplier); AbilityCostMultiplier = ClampGeneralMultiplier(AbilityCostMultiplier); SilkCostMultiplier = ClampGeneralMultiplier(SilkCostMultiplier); AdaptiveMaxAssist = Math.Max(0f, Math.Min(1f, RoundOneDecimal(AdaptiveMaxAssist))); AdaptiveApplyMode = Math.Max(0, Math.Min(2, AdaptiveApplyMode)); } public void ApplyPreset(DifficultyPreset preset) { DifficultySettings difficultySettings = CreateDefaults(); switch (preset) { case DifficultyPreset.Easy: difficultySettings.BaseHealth = 8; difficultySettings.BaseDamage = 8; difficultySettings.DamageTakenMultiplier = 0.7f; difficultySettings.HealingMultiplier = 1.5f; difficultySettings.HealingCostMultiplier = 0.8f; difficultySettings.DropRate = 1.6f; difficultySettings.CurrencyDropMultiplier = 1.5f; difficultySettings.ItemDropMultiplier = 1.4f; difficultySettings.ShopPriceMultiplier = 0.8f; difficultySettings.PlayerSpeedMultiplier = 1.1f; break; case DifficultyPreset.Hard: difficultySettings.BaseHealth = 4; difficultySettings.BaseDamage = 5; difficultySettings.DamageTakenMultiplier = 1.35f; difficultySettings.HealingMultiplier = 0.85f; difficultySettings.DropRate = 0.85f; difficultySettings.EnemyHealthMultiplier = 1.35f; difficultySettings.EnemyDamageMultiplier = 1.2f; difficultySettings.BossHealthMultiplier = 1.5f; difficultySettings.BossDamageTakenMultiplier = 1.2f; difficultySettings.HealingDuringBossMultiplier = 0.75f; break; case DifficultyPreset.Nightmare: difficultySettings.BaseHealth = 3; difficultySettings.BaseDamage = 4; difficultySettings.DamageTakenMultiplier = 1.8f; difficultySettings.HealingMultiplier = 0.5f; difficultySettings.HealingCostMultiplier = 1.5f; difficultySettings.DropRate = 0.6f; difficultySettings.CurrencyDropMultiplier = 0.6f; difficultySettings.ItemDropMultiplier = 0.7f; difficultySettings.ShopPriceMultiplier = 1.5f; difficultySettings.EnemyHealthMultiplier = 1.6f; difficultySettings.EnemyDamageMultiplier = 1.35f; difficultySettings.BossHealthMultiplier = 2f; difficultySettings.BossDamageTakenMultiplier = 1.5f; difficultySettings.BossBrutalMode = true; difficultySettings.HealingDuringBossMultiplier = 0.35f; difficultySettings.InvincibilityTimeMultiplier = 0.8f; break; case DifficultyPreset.OneHit: difficultySettings.OneHitMode = true; difficultySettings.MutatorNoHealing = true; difficultySettings.BaseHealth = 1; difficultySettings.HealingMultiplier = 0f; difficultySettings.HealingDuringBossMultiplier = 0f; break; case DifficultyPreset.Farm: difficultySettings.BaseHealth = 8; difficultySettings.BaseDamage = 9; difficultySettings.DamageTakenMultiplier = 0.5f; difficultySettings.HealingMultiplier = 1.4f; difficultySettings.DropRate = 2.5f; difficultySettings.CurrencyDropMultiplier = 2.75f; difficultySettings.ItemDropMultiplier = 2.25f; difficultySettings.ShopPriceMultiplier = 0.9f; difficultySettings.PlayerSpeedMultiplier = 1.15f; difficultySettings.MutatorRichWorld = true; break; case DifficultyPreset.Custom: return; } CopyFrom(difficultySettings); Clamp(); } public bool IsEquivalent(DifficultySettings other) { if (other == null) { return false; } if (BaseDamage == other.BaseDamage && BaseHealth == other.BaseHealth && FloatsEqual(DropRate, other.DropRate) && FloatsEqual(DamageTakenMultiplier, other.DamageTakenMultiplier) && FloatsEqual(HealingMultiplier, other.HealingMultiplier) && FloatsEqual(HealingCostMultiplier, other.HealingCostMultiplier) && FloatsEqual(InvincibilityTimeMultiplier, other.InvincibilityTimeMultiplier) && FloatsEqual(SkillDamageMultiplier, other.SkillDamageMultiplier) && FloatsEqual(SilkSpearDamageMultiplier, other.SilkSpearDamageMultiplier) && FloatsEqual(BossDamageMultiplier, other.BossDamageMultiplier) && FloatsEqual(CommonEnemyDamageMultiplier, other.CommonEnemyDamageMultiplier) && FloatsEqual(CriticalChance, other.CriticalChance) && FloatsEqual(CriticalDamageMultiplier, other.CriticalDamageMultiplier) && FloatsEqual(EnvironmentalDamageMultiplier, other.EnvironmentalDamageMultiplier) && FloatsEqual(BossDamageTakenMultiplier, other.BossDamageTakenMultiplier) && FloatsEqual(CommonEnemyDamageTakenMultiplier, other.CommonEnemyDamageTakenMultiplier) && FloatsEqual(EnemyHealthMultiplier, other.EnemyHealthMultiplier) && FloatsEqual(EnemyDamageMultiplier, other.EnemyDamageMultiplier) && FloatsEqual(EnemySpeedMultiplier, other.EnemySpeedMultiplier) && FloatsEqual(EnemyAttackCooldownMultiplier, other.EnemyAttackCooldownMultiplier) && FloatsEqual(EnemyAggressionMultiplier, other.EnemyAggressionMultiplier) && FloatsEqual(BossHealthMultiplier, other.BossHealthMultiplier) && FloatsEqual(BossSpeedMultiplier, other.BossSpeedMultiplier) && FloatsEqual(BossAttackCooldownMultiplier, other.BossAttackCooldownMultiplier) && BossBrutalMode == other.BossBrutalMode && DisableHealingDuringBoss == other.DisableHealingDuringBoss && FloatsEqual(HealingDuringBossMultiplier, other.HealingDuringBossMultiplier) && FloatsEqual(CurrencyDropMultiplier, other.CurrencyDropMultiplier) && FloatsEqual(ItemDropMultiplier, other.ItemDropMultiplier) && FloatsEqual(ShopPriceMultiplier, other.ShopPriceMultiplier) && FloatsEqual(BossRewardMultiplier, other.BossRewardMultiplier) && FloatsEqual(DeathCurrencyLossMultiplier, other.DeathCurrencyLossMultiplier) && FloatsEqual(PlayerSpeedMultiplier, other.PlayerSpeedMultiplier) && FloatsEqual(JumpHeightMultiplier, other.JumpHeightMultiplier) && FloatsEqual(DashCooldownMultiplier, other.DashCooldownMultiplier) && FloatsEqual(AbilityCostMultiplier, other.AbilityCostMultiplier) && FloatsEqual(SilkCostMultiplier, other.SilkCostMultiplier) && OneHitMode == other.OneHitMode && MutatorNoHealing == other.MutatorNoHealing && MutatorLowGravity == other.MutatorLowGravity && MutatorDoubleDamage == other.MutatorDoubleDamage && MutatorGlassCannon == other.MutatorGlassCannon && MutatorFastEnemies == other.MutatorFastEnemies && MutatorTankEnemies == other.MutatorTankEnemies && MutatorAggressiveEnemies == other.MutatorAggressiveEnemies && MutatorRandomizedEnemyHealth == other.MutatorRandomizedEnemyHealth && MutatorRichWorld == other.MutatorRichWorld && MutatorPoorWorld == other.MutatorPoorWorld && MutatorExpensiveShops == other.MutatorExpensiveShops && MutatorNoDeathLoss == other.MutatorNoDeathLoss && MutatorBossFrenzy == other.MutatorBossFrenzy && MutatorNoMercy == other.MutatorNoMercy && MutatorExtendedFights == other.MutatorExtendedFights && BossProfilesEnabled == other.BossProfilesEnabled && BossProfilesFallbackGlobal == other.BossProfilesFallbackGlobal && ContextBossRulesEnabled == other.ContextBossRulesEnabled && ContextExplorationRulesEnabled == other.ContextExplorationRulesEnabled && ContextLowHealthRuleEnabled == other.ContextLowHealthRuleEnabled && ContextDeathStreakTrackingEnabled == other.ContextDeathStreakTrackingEnabled && AdaptiveDifficultyEnabled == other.AdaptiveDifficultyEnabled && AdaptiveBossAssistEnabled == other.AdaptiveBossAssistEnabled && AdaptiveExplorationAssistEnabled == other.AdaptiveExplorationAssistEnabled && AdaptiveEconomyAssistEnabled == other.AdaptiveEconomyAssistEnabled && FloatsEqual(AdaptiveMaxAssist, other.AdaptiveMaxAssist)) { return AdaptiveApplyMode == other.AdaptiveApplyMode; } return false; } public static float RoundOneDecimal(float value) { return (float)Math.Round(value * 10f, MidpointRounding.AwayFromZero) / 10f; } private void CopyFrom(DifficultySettings other) { BaseDamage = other.BaseDamage; BaseHealth = other.BaseHealth; DropRate = other.DropRate; DamageTakenMultiplier = other.DamageTakenMultiplier; HealingMultiplier = other.HealingMultiplier; HealingCostMultiplier = other.HealingCostMultiplier; InvincibilityTimeMultiplier = other.InvincibilityTimeMultiplier; SkillDamageMultiplier = other.SkillDamageMultiplier; SilkSpearDamageMultiplier = other.SilkSpearDamageMultiplier; BossDamageMultiplier = other.BossDamageMultiplier; CommonEnemyDamageMultiplier = other.CommonEnemyDamageMultiplier; CriticalChance = other.CriticalChance; CriticalDamageMultiplier = other.CriticalDamageMultiplier; EnvironmentalDamageMultiplier = other.EnvironmentalDamageMultiplier; BossDamageTakenMultiplier = other.BossDamageTakenMultiplier; CommonEnemyDamageTakenMultiplier = other.CommonEnemyDamageTakenMultiplier; EnemyHealthMultiplier = other.EnemyHealthMultiplier; EnemyDamageMultiplier = other.EnemyDamageMultiplier; EnemySpeedMultiplier = other.EnemySpeedMultiplier; EnemyAttackCooldownMultiplier = other.EnemyAttackCooldownMultiplier; EnemyAggressionMultiplier = other.EnemyAggressionMultiplier; BossHealthMultiplier = other.BossHealthMultiplier; BossSpeedMultiplier = other.BossSpeedMultiplier; BossAttackCooldownMultiplier = other.BossAttackCooldownMultiplier; BossBrutalMode = other.BossBrutalMode; DisableHealingDuringBoss = other.DisableHealingDuringBoss; HealingDuringBossMultiplier = other.HealingDuringBossMultiplier; CurrencyDropMultiplier = other.CurrencyDropMultiplier; ItemDropMultiplier = other.ItemDropMultiplier; ShopPriceMultiplier = other.ShopPriceMultiplier; BossRewardMultiplier = other.BossRewardMultiplier; DeathCurrencyLossMultiplier = other.DeathCurrencyLossMultiplier; PlayerSpeedMultiplier = other.PlayerSpeedMultiplier; JumpHeightMultiplier = other.JumpHeightMultiplier; DashCooldownMultiplier = other.DashCooldownMultiplier; AbilityCostMultiplier = other.AbilityCostMultiplier; SilkCostMultiplier = other.SilkCostMultiplier; OneHitMode = other.OneHitMode; MutatorNoHealing = other.MutatorNoHealing; MutatorLowGravity = other.MutatorLowGravity; MutatorDoubleDamage = other.MutatorDoubleDamage; MutatorGlassCannon = other.MutatorGlassCannon; MutatorFastEnemies = other.MutatorFastEnemies; MutatorTankEnemies = other.MutatorTankEnemies; MutatorAggressiveEnemies = other.MutatorAggressiveEnemies; MutatorRandomizedEnemyHealth = other.MutatorRandomizedEnemyHealth; MutatorRichWorld = other.MutatorRichWorld; MutatorPoorWorld = other.MutatorPoorWorld; MutatorExpensiveShops = other.MutatorExpensiveShops; MutatorNoDeathLoss = other.MutatorNoDeathLoss; MutatorBossFrenzy = other.MutatorBossFrenzy; MutatorNoMercy = other.MutatorNoMercy; MutatorExtendedFights = other.MutatorExtendedFights; BossProfilesEnabled = other.BossProfilesEnabled; BossProfilesFallbackGlobal = other.BossProfilesFallbackGlobal; ContextBossRulesEnabled = other.ContextBossRulesEnabled; ContextExplorationRulesEnabled = other.ContextExplorationRulesEnabled; ContextLowHealthRuleEnabled = other.ContextLowHealthRuleEnabled; ContextDeathStreakTrackingEnabled = other.ContextDeathStreakTrackingEnabled; AdaptiveDifficultyEnabled = other.AdaptiveDifficultyEnabled; AdaptiveBossAssistEnabled = other.AdaptiveBossAssistEnabled; AdaptiveExplorationAssistEnabled = other.AdaptiveExplorationAssistEnabled; AdaptiveEconomyAssistEnabled = other.AdaptiveEconomyAssistEnabled; AdaptiveMaxAssist = other.AdaptiveMaxAssist; AdaptiveApplyMode = other.AdaptiveApplyMode; } private static bool FloatsEqual(float a, float b) { return Math.Abs(a - b) < 0.001f; } private static float ClampDropRate(float value) { return Math.Max(0.1f, Math.Min(10f, RoundOneDecimal(value))); } private static float ClampGeneralMultiplier(float value) { return Math.Max(0f, Math.Min(10f, RoundOneDecimal(value))); } private static float ClampMovementMultiplier(float value) { return Math.Max(0.1f, Math.Min(3f, RoundOneDecimal(value))); } private static float ClampCooldownMultiplier(float value) { return Math.Max(0.1f, Math.Min(5f, RoundOneDecimal(value))); } private static float ClampCriticalChance(float value) { return Math.Max(0f, Math.Min(100f, RoundOneDecimal(value))); } private static float ClampCriticalDamageMultiplier(float value) { return Math.Max(1f, Math.Min(10f, RoundOneDecimal(value))); } }