Decompiled source of CustomDifficulty v2.1.1

BepInEx\plugins\CustomDifficulty\CustomDifficulty.dll

Decompiled a week ago
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<CustomDifficultyBossProfileData> _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<CustomDifficultyBossProfileData> 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<CustomDifficultyBossProfileData> list = JsonConvert.DeserializeObject<List<CustomDifficultyBossProfileData>>(text);
			_cachedProfiles = list ?? new List<CustomDifficultyBossProfileData>();
			_cachedWriteTimeUtc = dateTime;
			return _cachedProfiles;
		}
		catch (Exception ex)
		{
			CustomDifficultyPlugin.LogWarningSafe("Could not load boss profiles: " + ex.Message);
			return new List<CustomDifficultyBossProfileData>();
		}
	}

	public bool TryFindProfile(GameObject gameObject, out CustomDifficultyBossProfileData profile)
	{
		profile = null;
		if ((Object)(object)gameObject == (Object)null)
		{
			return false;
		}
		List<string> list = CollectObjectNames(gameObject);
		List<CustomDifficultyBossProfileData> 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<string> CollectObjectNames(GameObject gameObject)
	{
		List<string> list = new List<string>();
		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<MonoBehaviour>(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<CustomDifficultyBossProfileData> list = new List<CustomDifficultyBossProfileData>();
		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<CustomDifficultyBossProfileData> 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<KeyCode> _openMenuKey;

	private readonly ConfigEntry<int> _baseDamage;

	private readonly ConfigEntry<int> _baseHealth;

	private readonly ConfigEntry<float> _dropRate;

	private readonly ConfigEntry<float> _damageTakenMultiplier;

	private readonly ConfigEntry<float> _healingMultiplier;

	private readonly ConfigEntry<float> _healingCostMultiplier;

	private readonly ConfigEntry<float> _invincibilityTimeMultiplier;

	private readonly ConfigEntry<float> _skillDamageMultiplier;

	private readonly ConfigEntry<float> _silkSpearDamageMultiplier;

	private readonly ConfigEntry<float> _bossDamageMultiplier;

	private readonly ConfigEntry<float> _commonEnemyDamageMultiplier;

	private readonly ConfigEntry<float> _criticalChance;

	private readonly ConfigEntry<float> _criticalDamageMultiplier;

	private readonly ConfigEntry<float> _environmentalDamageMultiplier;

	private readonly ConfigEntry<float> _bossDamageTakenMultiplier;

	private readonly ConfigEntry<float> _commonEnemyDamageTakenMultiplier;

	private readonly ConfigEntry<float> _enemyHealthMultiplier;

	private readonly ConfigEntry<float> _enemyDamageMultiplier;

	private readonly ConfigEntry<float> _enemySpeedMultiplier;

	private readonly ConfigEntry<float> _enemyAttackCooldownMultiplier;

	private readonly ConfigEntry<float> _enemyAggressionMultiplier;

	private readonly ConfigEntry<float> _bossHealthMultiplier;

	private readonly ConfigEntry<float> _bossSpeedMultiplier;

	private readonly ConfigEntry<float> _bossAttackCooldownMultiplier;

	private readonly ConfigEntry<bool> _bossBrutalMode;

	private readonly ConfigEntry<bool> _disableHealingDuringBoss;

	private readonly ConfigEntry<float> _healingDuringBossMultiplier;

	private readonly ConfigEntry<float> _currencyDropMultiplier;

	private readonly ConfigEntry<float> _itemDropMultiplier;

	private readonly ConfigEntry<float> _shopPriceMultiplier;

	private readonly ConfigEntry<float> _bossRewardMultiplier;

	private readonly ConfigEntry<float> _deathCurrencyLossMultiplier;

	private readonly ConfigEntry<float> _playerSpeedMultiplier;

	private readonly ConfigEntry<float> _jumpHeightMultiplier;

	private readonly ConfigEntry<float> _dashCooldownMultiplier;

	private readonly ConfigEntry<float> _abilityCostMultiplier;

	private readonly ConfigEntry<float> _silkCostMultiplier;

	private readonly ConfigEntry<bool> _oneHitMode;

	private readonly ConfigEntry<bool> _mutatorNoHealing;

	private readonly ConfigEntry<bool> _mutatorLowGravity;

	private readonly ConfigEntry<bool> _mutatorDoubleDamage;

	private readonly ConfigEntry<bool> _mutatorGlassCannon;

	private readonly ConfigEntry<bool> _mutatorFastEnemies;

	private readonly ConfigEntry<bool> _mutatorTankEnemies;

	private readonly ConfigEntry<bool> _mutatorAggressiveEnemies;

	private readonly ConfigEntry<bool> _mutatorRandomizedEnemyHealth;

	private readonly ConfigEntry<bool> _mutatorRichWorld;

	private readonly ConfigEntry<bool> _mutatorPoorWorld;

	private readonly ConfigEntry<bool> _mutatorExpensiveShops;

	private readonly ConfigEntry<bool> _mutatorNoDeathLoss;

	private readonly ConfigEntry<bool> _mutatorBossFrenzy;

	private readonly ConfigEntry<bool> _mutatorNoMercy;

	private readonly ConfigEntry<bool> _mutatorExtendedFights;

	private readonly ConfigEntry<bool> _bossProfilesEnabled;

	private readonly ConfigEntry<bool> _bossProfilesFallbackGlobal;

	private readonly ConfigEntry<bool> _contextBossRulesEnabled;

	private readonly ConfigEntry<bool> _contextExplorationRulesEnabled;

	private readonly ConfigEntry<bool> _contextLowHealthRuleEnabled;

	private readonly ConfigEntry<bool> _contextDeathStreakTrackingEnabled;

	private readonly ConfigEntry<bool> _adaptiveDifficultyEnabled;

	private readonly ConfigEntry<bool> _adaptiveBossAssistEnabled;

	private readonly ConfigEntry<bool> _adaptiveExplorationAssistEnabled;

	private readonly ConfigEntry<bool> _adaptiveEconomyAssistEnabled;

	private readonly ConfigEntry<float> _adaptiveMaxAssist;

	private readonly ConfigEntry<int> _adaptiveApplyMode;

	private DifficultySettings _appliedSettings;

	private DifficultySettings _draftSettings;

	private int _settingsRevision;

	public int SettingsRevision => _settingsRevision;

	public CustomDifficultyConfigManager(BaseUnityPlugin plugin)
	{
		_plugin = plugin;
		_openMenuKey = plugin.Config.Bind<KeyCode>("Menu", "OpenMenuKey", (KeyCode)289, "Open the Custom Difficulty menu.");
		_baseDamage = plugin.Config.Bind<int>("Gameplay", "BaseDamage", 5, "Base character damage.");
		_baseHealth = plugin.Config.Bind<int>("Gameplay", "BaseHealth", 5, "Base maximum health.");
		_dropRate = plugin.Config.Bind<float>("Gameplay", "DropRate", 1f, "Global drop rate multiplier.");
		_damageTakenMultiplier = plugin.Config.Bind<float>("Gameplay", "DamageTakenMultiplier", 1f, "Global incoming damage multiplier.");
		_healingMultiplier = plugin.Config.Bind<float>("Player", "HealingMultiplier", 1f, "Healing amount multiplier.");
		_healingCostMultiplier = plugin.Config.Bind<float>("Player", "HealingCostMultiplier", 1f, "Healing silk cost multiplier.");
		_invincibilityTimeMultiplier = plugin.Config.Bind<float>("Player", "InvincibilityTimeMultiplier", 1f, "Invincibility time after damage.");
		_skillDamageMultiplier = plugin.Config.Bind<float>("Damage", "SkillDamageMultiplier", 1f, "Generic skill damage multiplier.");
		_silkSpearDamageMultiplier = plugin.Config.Bind<float>("Damage", "SilkSpearDamageMultiplier", 1f, "Silk spear damage multiplier.");
		_bossDamageMultiplier = plugin.Config.Bind<float>("Damage", "BossDamageMultiplier", 1f, "Damage dealt against bosses.");
		_commonEnemyDamageMultiplier = plugin.Config.Bind<float>("Damage", "CommonEnemyDamageMultiplier", 1f, "Damage dealt against common enemies.");
		_criticalChance = plugin.Config.Bind<float>("Damage", "CriticalChance", 0f, "Critical hit chance percentage.");
		_criticalDamageMultiplier = plugin.Config.Bind<float>("Damage", "CriticalDamageMultiplier", 2f, "Critical hit damage multiplier.");
		_environmentalDamageMultiplier = plugin.Config.Bind<float>("IncomingDamage", "EnvironmentalDamageMultiplier", 1f, "Environmental damage multiplier.");
		_bossDamageTakenMultiplier = plugin.Config.Bind<float>("IncomingDamage", "BossDamageTakenMultiplier", 1f, "Boss damage taken multiplier.");
		_commonEnemyDamageTakenMultiplier = plugin.Config.Bind<float>("IncomingDamage", "CommonEnemyDamageTakenMultiplier", 1f, "Common enemy damage taken multiplier.");
		_enemyHealthMultiplier = plugin.Config.Bind<float>("Enemies", "EnemyHealthMultiplier", 1f, "Common enemy health multiplier.");
		_enemyDamageMultiplier = plugin.Config.Bind<float>("Enemies", "EnemyDamageMultiplier", 1f, "Common enemy damage multiplier.");
		_enemySpeedMultiplier = plugin.Config.Bind<float>("Enemies", "EnemySpeedMultiplier", 1f, "Reserved enemy speed multiplier.");
		_enemyAttackCooldownMultiplier = plugin.Config.Bind<float>("Enemies", "EnemyAttackCooldownMultiplier", 1f, "Reserved enemy attack cooldown multiplier.");
		_enemyAggressionMultiplier = plugin.Config.Bind<float>("Enemies", "EnemyAggressionMultiplier", 1f, "Reserved enemy aggression multiplier.");
		_bossHealthMultiplier = plugin.Config.Bind<float>("Bosses", "BossHealthMultiplier", 1f, "Boss health multiplier.");
		_bossSpeedMultiplier = plugin.Config.Bind<float>("Bosses", "BossSpeedMultiplier", 1f, "Reserved boss speed multiplier.");
		_bossAttackCooldownMultiplier = plugin.Config.Bind<float>("Bosses", "BossAttackCooldownMultiplier", 1f, "Reserved boss attack cooldown multiplier.");
		_bossBrutalMode = plugin.Config.Bind<bool>("Bosses", "BossBrutalMode", false, "Enable brutal boss adjustments.");
		_disableHealingDuringBoss = plugin.Config.Bind<bool>("Bosses", "DisableHealingDuringBoss", false, "Reduce healing to zero during bosses.");
		_healingDuringBossMultiplier = plugin.Config.Bind<float>("Bosses", "HealingDuringBossMultiplier", 1f, "Healing multiplier during boss fights.");
		_currencyDropMultiplier = plugin.Config.Bind<float>("Drops", "CurrencyDropMultiplier", 1f, "Currency drop multiplier.");
		_itemDropMultiplier = plugin.Config.Bind<float>("Drops", "ItemDropMultiplier", 1f, "Item drop multiplier.");
		_shopPriceMultiplier = plugin.Config.Bind<float>("Economy", "ShopPriceMultiplier", 1f, "Experimental shop price multiplier.");
		_bossRewardMultiplier = plugin.Config.Bind<float>("Economy", "BossRewardMultiplier", 1f, "Experimental boss reward multiplier.");
		_deathCurrencyLossMultiplier = plugin.Config.Bind<float>("Economy", "DeathCurrencyLossMultiplier", 1f, "Reserved death currency loss multiplier.");
		_playerSpeedMultiplier = plugin.Config.Bind<float>("Movement", "PlayerSpeedMultiplier", 1f, "Player speed multiplier.");
		_jumpHeightMultiplier = plugin.Config.Bind<float>("Movement", "JumpHeightMultiplier", 1f, "Jump height multiplier.");
		_dashCooldownMultiplier = plugin.Config.Bind<float>("Movement", "DashCooldownMultiplier", 1f, "Dash cooldown multiplier.");
		_abilityCostMultiplier = plugin.Config.Bind<float>("Movement", "AbilityCostMultiplier", 1f, "Ability cost multiplier.");
		_silkCostMultiplier = plugin.Config.Bind<float>("Movement", "SilkCostMultiplier", 1f, "Silk ability cost multiplier.");
		_oneHitMode = plugin.Config.Bind<bool>("System", "OneHitMode", false, "Enable one hit mode.");
		_mutatorNoHealing = plugin.Config.Bind<bool>("Mutators", "NoHealing", false, "Disable normal healing.");
		_mutatorLowGravity = plugin.Config.Bind<bool>("Mutators", "LowGravity", false, "Slightly increases jump feel through the existing jump hook.");
		_mutatorDoubleDamage = plugin.Config.Bind<bool>("Mutators", "DoubleDamage", false, "Double Hornet outgoing damage.");
		_mutatorGlassCannon = plugin.Config.Bind<bool>("Mutators", "GlassCannon", false, "Large outgoing damage with higher incoming damage.");
		_mutatorFastEnemies = plugin.Config.Bind<bool>("Mutators", "FastEnemies", false, "Experimental enemy speed mutator.");
		_mutatorTankEnemies = plugin.Config.Bind<bool>("Mutators", "TankEnemies", false, "Common enemies effectively take less damage.");
		_mutatorAggressiveEnemies = plugin.Config.Bind<bool>("Mutators", "AggressiveEnemies", false, "Experimental enemy pressure mutator.");
		_mutatorRandomizedEnemyHealth = plugin.Config.Bind<bool>("Mutators", "RandomizedEnemyHealth", false, "Experimental randomized enemy effective health.");
		_mutatorRichWorld = plugin.Config.Bind<bool>("Mutators", "RichWorld", false, "Increase world drops.");
		_mutatorPoorWorld = plugin.Config.Bind<bool>("Mutators", "PoorWorld", false, "Reduce world drops.");
		_mutatorExpensiveShops = plugin.Config.Bind<bool>("Mutators", "ExpensiveShops", false, "Experimental shop price mutator.");
		_mutatorNoDeathLoss = plugin.Config.Bind<bool>("Mutators", "NoDeathLoss", false, "Reserved death-loss mutator stored for future hooks.");
		_mutatorBossFrenzy = plugin.Config.Bind<bool>("Mutators", "BossFrenzy", false, "Boss fights receive extra pressure through safe existing hooks.");
		_mutatorNoMercy = plugin.Config.Bind<bool>("Mutators", "NoMercy", false, "Disable healing during boss fights.");
		_mutatorExtendedFights = plugin.Config.Bind<bool>("Mutators", "ExtendedFights", false, "Bosses effectively take less damage.");
		_bossProfilesEnabled = plugin.Config.Bind<bool>("BossProfiles", "Enabled", false, "Experimental boss profile matching by object or component name.");
		_bossProfilesFallbackGlobal = plugin.Config.Bind<bool>("BossProfiles", "FallbackGlobal", true, "Use global boss settings when a boss profile is not identified.");
		_contextBossRulesEnabled = plugin.Config.Bind<bool>("ContextRules", "BossRulesEnabled", false, "Reserved context rule for boss fights.");
		_contextExplorationRulesEnabled = plugin.Config.Bind<bool>("ContextRules", "ExplorationRulesEnabled", false, "Reserved context rule for exploration.");
		_contextLowHealthRuleEnabled = plugin.Config.Bind<bool>("ContextRules", "LowHealthRuleEnabled", false, "Reserved context rule for low health.");
		_contextDeathStreakTrackingEnabled = plugin.Config.Bind<bool>("ContextRules", "DeathStreakTrackingEnabled", false, "Reserved context rule for repeated deaths.");
		_adaptiveDifficultyEnabled = plugin.Config.Bind<bool>("Adaptive", "Enabled", false, "Enable adaptive difficulty structure. Default is off.");
		_adaptiveBossAssistEnabled = plugin.Config.Bind<bool>("Adaptive", "BossAssist", false, "Reserved adaptive boss assistance.");
		_adaptiveExplorationAssistEnabled = plugin.Config.Bind<bool>("Adaptive", "ExplorationAssist", false, "Reserved adaptive exploration assistance.");
		_adaptiveEconomyAssistEnabled = plugin.Config.Bind<bool>("Adaptive", "EconomyAssist", false, "Reserved adaptive economy assistance.");
		_adaptiveMaxAssist = plugin.Config.Bind<float>("Adaptive", "MaxAssist", 0.25f, "Maximum adaptive assistance from 0.0 to 1.0.");
		_adaptiveApplyMode = plugin.Config.Bind<int>("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<string> Lines = new List<string>();
}
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<string> _favoriteOptionIds;

	private readonly HashSet<string> _favorites = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	public int Count => _favorites.Count;

	public CustomDifficultyFavorites(BaseUnityPlugin plugin)
	{
		_plugin = plugin;
		_favoriteOptionIds = plugin.Config.Bind<string>("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<string> GetAll()
	{
		return new List<string>(_favorites);
	}

	public void ReplaceAll(IEnumerable<string> 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<string> list = JsonConvert.DeserializeObject<List<string>>(_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<string, int> AppliedBaseHealthByProfile = new Dictionary<string, int>();

		public Dictionary<string, int> BonusHealthByProfile = new Dictionary<string, int>();
	}

	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<int, Stack<GameObject>> DamageTargetContexts = new Dictionary<int, Stack<GameObject>>();

	[ThreadStatic]
	private static bool _skipFallbackIncomingDamageScaling;

	private readonly BaseUnityPlugin _plugin;

	private readonly CustomDifficultyConfigManager _configManager;

	private readonly CustomDifficultyBossProfileManager _bossProfileManager;

	private readonly Dictionary<int, int> _appliedBaseHealthByProfile = new Dictionary<int, int>();

	private readonly Dictionary<int, int> _bonusHealthByProfile = new Dictionary<int, int>();

	private readonly Dictionary<int, float> _randomEnemyHealthByTarget = new Dictionary<int, float>();

	private readonly HashSet<string> _reportedBossProfiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private readonly HashSet<int> _trackedHealthProfiles = new HashSet<int>();

	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<GameObject>();
				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<MonoBehaviour>(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<HealthProfileStateFile>(text);
			if (healthProfileStateFile == null)
			{
				return;
			}
			if (healthProfileStateFile.AppliedBaseHealthByProfile != null)
			{
				foreach (KeyValuePair<string, int> item in healthProfileStateFile.AppliedBaseHealthByProfile)
				{
					if (int.TryParse(item.Key, out var result))
					{
						_appliedBaseHealthByProfile[result] = item.Value;
					}
				}
			}
			if (healthProfileStateFile.BonusHealthByProfile == null)
			{
				return;
			}
			foreach (KeyValuePair<string, int> 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<int, int> item in _appliedBaseHealthByProfile)
			{
				healthProfileStateFile.AppliedBaseHealthByProfile[item.Key.ToString()] = item.Value;
			}
			foreach (KeyValuePair<int, int> 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<MethodBase> 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<string> _menuLanguageOverride;

	private readonly Dictionary<string, string> _englishStrings;

	private readonly List<MenuLanguageOption> _availableLanguages;

	private Dictionary<string, string> _currentStrings;

	private string _currentLanguageCode;

	public CustomDifficultyLocalizationManager(BaseUnityPlugin plugin, string localizationDirectory)
	{
		_plugin = plugin;
		_localizationDirectory = localizationDirectory;
		_menuLanguageOverride = plugin.Config.Bind<string>("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<string, string> LoadLanguageFile(string languageCode)
	{
		string path = Path.Combine(_localizationDirectory, languageCode + ".json");
		if (!File.Exists(path))
		{
			return _englishStrings ?? new Dictionary<string, string>();
		}
		try
		{
			string text = File.ReadAllText(path);
			Dictionary<string, string> dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(text);
			return dictionary ?? _englishStrings ?? new Dictionary<string, string>();
		}
		catch
		{
			return _englishStrings ?? new Dictionary<string, string>();
		}
	}

	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<MenuLanguageOption> BuildAvailableLanguages()
	{
		List<MenuLanguageOption> list = new List<MenuLanguageOption>();
		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<MenuOptionDefinition> _allOptions = new List<MenuOptionDefinition>();

	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<MenuOptionDefinition> 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.u