Decompiled source of YoureCold v1.1.8

YoureCold.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace YoureCold;

[BepInPlugin("com.marccunningham.yourecold", "You're Cold", "1.1.7")]
[BepInProcess("valheim.exe")]
public sealed class YoureColdPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "com.marccunningham.yourecold";

	public const string PluginName = "You're Cold";

	public const string PluginVersion = "1.1.7";

	private const float MinimumTemperature = 0f;

	private const float MaximumTemperature = 100f;

	private const float ComfortMidpoint = 50f;

	private const float MinimumTickInterval = 0.1f;

	private const float MaximumElapsedMultiplier = 3f;

	private const float TorchTravelComfortCeiling = 76f;

	private const float MinimumHandTorchTravelWarmthPerSecond = 0.22f;

	private const float ArmorInsulationReferenceValue = 110f;

	private const float HudReferenceWidth = 2048f;

	private const float HudReferenceHeight = 1152f;

	private const float CompactHudReferenceLeft = 247f;

	private const float CompactHudReferenceBottom = 118f;

	private const float CompactHudReferenceWidth = 221f;

	private const float CompactHudReferenceHeight = 62f;

	private ConfigEntry<bool> modEnabled;

	private ConfigEntry<KeyCode> diagnosticKey;

	private ConfigEntry<KeyCode> sessionToggleKey;

	private ConfigEntry<float> tickInterval;

	private ConfigEntry<float> startingTemperature;

	private ConfigEntry<string> difficultyPreset;

	private ConfigEntry<string> lastAppliedDifficultyPreset;

	private ConfigEntry<bool> showHud;

	private ConfigEntry<bool> hideHudWithCtrlF3;

	private ConfigEntry<bool> useCompactSurvivalHud;

	private ConfigEntry<bool> debugLogging;

	private ConfigEntry<bool> enableLowTemperatureWarning;

	private ConfigEntry<float> lowTemperatureWarningThreshold;

	private ConfigEntry<float> lowTemperatureWarningRepeatSeconds;

	private ConfigEntry<float> lowTemperatureWarningVolume;

	private ConfigEntry<string> lowTemperatureWarningFile;

	private ConfigEntry<float> safeRecoveryRate;

	private ConfigEntry<float> nearFireWarmingRate;

	private ConfigEntry<float> wetCoolingRate;

	private ConfigEntry<float> coldEnvironmentCoolingRate;

	private ConfigEntry<float> freezingEnvironmentCoolingRate;

	private ConfigEntry<float> mountainCoolingRate;

	private ConfigEntry<float> deepNorthCoolingRate;

	private ConfigEntry<float> nightCoolingRate;

	private ConfigEntry<float> swimmingCoolingRate;

	private ConfigEntry<float> shelterCoolingMultiplier;

	private ConfigEntry<float> severeColdThreshold;

	private ConfigEntry<float> staminaDrainAtZero;

	private ConfigEntry<float> emergencyStaminaReserve;

	private ConfigEntry<float> freezingDamagePerSecond;

	private ConfigEntry<bool> enableArmorInsulation;

	private ConfigEntry<float> maximumArmorInsulation;

	private ConfigEntry<bool> enableTorchWarmth;

	private ConfigEntry<float> torchWarmingRate;

	private ConfigEntry<bool> enableOverheating;

	private ConfigEntry<float> overheatThreshold;

	private ConfigEntry<float> overheatStaminaDrainAtMax;

	private ConfigEntry<float> overheatExhaustionChance;

	private ConfigEntry<bool> enableColdSurvivalDrive;

	private ConfigEntry<float> coldSurvivalDriveTriggerTemperature;

	private ConfigEntry<float> coldSurvivalDriveDurationSeconds;

	private ConfigEntry<float> coldSurvivalDriveDrainMultiplier;

	private ConfigEntry<float> coldSurvivalDriveResetTemperature;

	private bool coldSurvivalDriveActive;

	private float coldSurvivalDriveTimeRemaining;

	private bool wasAboveColdSurvivalDriveResetPoint = true;

	private float temperature;

	private float tickTimer;

	private bool runtimeEnabled = true;

	private SurvivalSnapshot lastSnapshot;

	private bool hasSnapshot;

	private string pluginDirectory;

	private Component lowTemperatureAudioSource;

	private object lowTemperatureWarningClip;

	private bool lowTemperatureWarningLoadStarted;

	private bool wasBelowWarningThreshold;

	private float nextLowTemperatureWarningTime;

	private GUIStyle compactTemperatureHeaderStyle;

	private GUIStyle compactTemperatureDetailStyle;

	private bool hudHiddenByCtrlF3;

	private void RemoveLegacyHudResizeConfigEntries()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Expected O, but got Unknown
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Expected O, but got Unknown
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Expected O, but got Unknown
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Expected O, but got Unknown
		((BaseUnityPlugin)this).Config.Remove(new ConfigDefinition("HUD Layout Editor", "ToggleBodyTempLayoutEditorKey"));
		((BaseUnityPlugin)this).Config.Remove(new ConfigDefinition("HUD Layout", "CompactBodyTempXNormalized"));
		((BaseUnityPlugin)this).Config.Remove(new ConfigDefinition("HUD Layout", "CompactBodyTempYNormalized"));
		((BaseUnityPlugin)this).Config.Remove(new ConfigDefinition("HUD Layout", "CompactBodyTempWidthNormalized"));
		((BaseUnityPlugin)this).Config.Remove(new ConfigDefinition("HUD Layout", "CompactBodyTempHeightNormalized"));
		((BaseUnityPlugin)this).Config.Save();
	}

	private void Awake()
	{
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Expected O, but got Unknown
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Expected O, but got Unknown
		pluginDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
		modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Set false to disable the entire cold system, including temperature changes and penalties.");
		diagnosticKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "DiagnosticKey", (KeyCode)290, "Writes one diagnostic line to BepInEx/LogOutput.log.");
		sessionToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "SessionToggleKey", (KeyCode)291, "Emergency session toggle. This stops or restarts the cold system without removing the DLL.");
		tickInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "TickIntervalSeconds", 1f, "How often the mod updates temperature. Lower values are smoother but use more CPU.");
		startingTemperature = ((BaseUnityPlugin)this).Config.Bind<float>("General", "StartingTemperature", 50f, new ConfigDescription("Temperature used when Valheim starts. 50 is the comfortable middle ground between cold and hot. Temperature is not saved between sessions in V0.1.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
		difficultyPreset = ((BaseUnityPlugin)this).Config.Bind<string>("Difficulty", "Preset", "Medium", new ConfigDescription("Pick a difficulty from the dropdown. This one setting tunes every cold rate, penalty, armor insulation, torch warmth, overheating, and Cold Survival Drive value together for a balanced experience. Change this, then restart Valheim (or use a layout/session toggle) to apply it. Hand-tune individual values afterward if you want a custom mix.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[4] { "Easy", "Medium", "Hard", "Extreme" }), Array.Empty<object>()));
		lastAppliedDifficultyPreset = ((BaseUnityPlugin)this).Config.Bind<string>("Difficulty", "LastAppliedPreset", "Medium", "Internal preset tracking. Leave this alone; it records the last difficulty preset applied.");
		showHud = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "ShowTemperatureBar", true, "Set false to hide only the Body Temp HUD while the cold system continues running.");
		hideHudWithCtrlF3 = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "HideHudWithCtrlF3", true, "When enabled, Ctrl+F3 hides or restores this mod's HUD along with Valheim's HUD toggle. The cold system keeps running.");
		useCompactSurvivalHud = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "UseCompactSurvivalHud", true, "Places the compact Body Temp panel beneath Nourishment and directly left of the Tired meter.");
		enableLowTemperatureWarning = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "EnableLowTemperatureWarning", true, "Plays the supplied cold-warning sound once when body temperature falls below the threshold, then only at a spaced interval while it remains low.");
		lowTemperatureWarningThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "LowTemperatureWarningThreshold", 40f, "Body temperature threshold that starts the low-temperature warning.");
		lowTemperatureWarningRepeatSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "LowTemperatureWarningRepeatSeconds", 150f, "Minimum number of real-time seconds between low-temperature warning repeats while temperature stays below the threshold.");
		lowTemperatureWarningVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "LowTemperatureWarningVolume", 0.55f, "Volume for the external cold-warning sound.");
		lowTemperatureWarningFile = ((BaseUnityPlugin)this).Config.Bind<string>("Audio", "LowTemperatureWarningFile", "cold breath.mp3", "MP3 filename expected in assets/audio beside the You're Cold DLL. The supplied default is cold breath.mp3.");
		debugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLogging", false, "Writes one temperature line every update to LogOutput.log. Keep this off unless testing.");
		safeRecoveryRate = ((BaseUnityPlugin)this).Config.Bind<float>("Rates", "SafeRecoveryPerSecond", 0.4f, "Temperature recovered each second when dry, safe and not losing heat. V1.1.3 uses slower, steadier recovery so ordinary warmth feels gradual rather than instant.");
		nearFireWarmingRate = ((BaseUnityPlugin)this).Config.Bind<float>("Rates", "NearFireWarmingPerSecond", 0.85f, "Temperature gained each second near Valheim's campfire/heat area. A campfire now restores comfort over roughly a minute, rather than in seconds.");
		wetCoolingRate = ((BaseUnityPlugin)this).Config.Bind<float>("Rates", "WetCoolingPerSecond", 0.035f, "Extra temperature lost each second while the player has Valheim's Wet status. Tuned for longer, fairer rain and exposed-boat travel.");
		coldEnvironmentCoolingRate = ((BaseUnityPlugin)this).Config.Bind<float>("Rates", "ColdEnvironmentCoolingPerSecond", 0.045f, "Temperature lost each second when Valheim reports a cold environment. Tuned for a gradual, readable temperature fall.");
		freezingEnvironmentCoolingRate = ((BaseUnityPlugin)this).Config.Bind<float>("Rates", "FreezingEnvironmentCoolingPerSecond", 0.1f, "Temperature lost each second when Valheim reports a freezing environment. Freezing remains serious, but no longer drains the meter in moments.");
		mountainCoolingRate = ((BaseUnityPlugin)this).Config.Bind<float>("Rates", "MountainCoolingPerSecond", 0.07f, "Extra temperature lost each second in the Mountain biome.");
		deepNorthCoolingRate = ((BaseUnityPlugin)this).Config.Bind<float>("Rates", "DeepNorthCoolingPerSecond", 0.14f, "Extra temperature lost each second in the Deep North biome.");
		nightCoolingRate = ((BaseUnityPlugin)this).Config.Bind<float>("Rates", "NightCoolingPerSecond", 0.02f, "Extra temperature lost each second at night.");
		swimmingCoolingRate = ((BaseUnityPlugin)this).Config.Bind<float>("Rates", "SwimmingCoolingPerSecond", 0.15f, "Temperature lost each second while swimming. Swimming remains the fastest cooling route, but now gives a fair escape window instead of emptying the meter in seconds.");
		shelterCoolingMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Rates", "ShelterCoolingMultiplier", 0.3f, "Multiplier applied to cooling while sheltered. 0.30 means shelter reduces cooling by 70 percent.");
		severeColdThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Penalties", "SevereColdThreshold", 15f, "Below this temperature, the player slowly loses stamina.");
		staminaDrainAtZero = ((BaseUnityPlugin)this).Config.Bind<float>("Penalties", "StaminaDrainAtZeroPerSecond", 0.8f, "Stamina removed per second at 0 temperature. The drain scales from zero at SevereColdThreshold.");
		emergencyStaminaReserve = ((BaseUnityPlugin)this).Config.Bind<float>("Safety", "EmergencyStaminaReserve", 12f, "Cold never directly spends stamina below this reserve. Conditions can still make escape difficult, but cold alone cannot erase the last usable burst of stamina.");
		freezingDamagePerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Penalties", "FreezingDamageAtZeroPerSecond", 0.25f, "Health removed per second at 0 temperature. This is deliberately mild in V0.1 for safe testing.");
		enableArmorInsulation = ((BaseUnityPlugin)this).Config.Bind<bool>("Armor Insulation", "EnableArmorInsulation", true, "Equipped armor and capes reduce how fast you lose heat. Better, later-game armor sets insulate more, mirroring real game progression from Rags up to Ashlands-tier gear.");
		maximumArmorInsulation = ((BaseUnityPlugin)this).Config.Bind<float>("Armor Insulation", "MaximumArmorInsulationPercent", 70f, "The most that armor alone can reduce cooling by, as a percent. 70 means a fully-armored, late-game player loses heat 70 percent slower than someone in rags. Armor only slows heat loss; it never warms you up on its own.");
		enableTorchWarmth = ((BaseUnityPlugin)this).Config.Bind<bool>("Torch Warmth", "EnableTorchWarmth", true, "Holding a lit Torch in either hand provides a small amount of warmth, like standing near a small personal flame.");
		torchWarmingRate = ((BaseUnityPlugin)this).Config.Bind<float>("Torch Warmth", "TorchWarmingPerSecond", 0.22f, "Temperature gained each second while holding a hand torch. It actively warms travel and boat journeys toward the Warm band, then holds safely below overheating. It does not work while swimming.");
		enableOverheating = ((BaseUnityPlugin)this).Config.Bind<bool>("Overheating", "EnableOverheating", true, "Adds a high-temperature debuff for prolonged heavy exertion or fire exposure, similar in spirit to real-world heat exhaustion. Off by default behavior is mild; intended as a light realism touch, not a hard punishment.");
		overheatThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Overheating", "OverheatThreshold", 95f, "Temperature above which overheating penalties begin.");
		overheatStaminaDrainAtMax = ((BaseUnityPlugin)this).Config.Bind<float>("Overheating", "OverheatStaminaDrainAtMaxPerSecond", 0.15f, "Stamina removed per second at maximum temperature from overheating. Scales from zero at OverheatThreshold, mirroring the cold-side stamina drain.");
		overheatExhaustionChance = ((BaseUnityPlugin)this).Config.Bind<float>("Overheating", "OverheatExhaustionChancePerMinute", 0f, "Reserved for future use. Currently has no effect; overheating only drains stamina, kept mild and non-lethal by design.");
		enableColdSurvivalDrive = ((BaseUnityPlugin)this).Config.Bind<bool>("Cold Survival Drive", "EnableColdSurvivalDrive", true, "When you drop to a dangerously low temperature, Cold Survival Drive kicks in: a temporary grace period that sharply reduces stamina and health drain so you have a real chance to reach shelter instead of being punished for one bad call. It is a safety net, not a way to ignore the cold long-term.");
		coldSurvivalDriveTriggerTemperature = ((BaseUnityPlugin)this).Config.Bind<float>("Cold Survival Drive", "TriggerTemperature", 8f, "Temperature at or below which Cold Survival Drive activates.");
		coldSurvivalDriveDurationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Cold Survival Drive", "DurationSeconds", 60f, "How long the grace period lasts once triggered, in real seconds.");
		coldSurvivalDriveDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Cold Survival Drive", "DrainMultiplier", 0.25f, "Cold stamina and health drain are multiplied by this while the grace period is active. 0.25 means drain is reduced by 75 percent.");
		coldSurvivalDriveResetTemperature = ((BaseUnityPlugin)this).Config.Bind<float>("Cold Survival Drive", "ResetTemperature", 25f, "Temperature you need to recover to before Cold Survival Drive can trigger again. Prevents it from re-triggering every few seconds while you hover near the threshold.");
		RemoveLegacyHudResizeConfigEntries();
		temperature = 50f;
		MigrateLegacyDefaultsToNormal();
		MigrateV1_1_3RealisticTemperaturePacing();
		MigrateV1_1_4TorchTravelWarmth();
		MigrateV1_1_6HandTorchTravelWarmth();
		ApplyDifficultyPresetIfChanged();
		((MonoBehaviour)this).StartCoroutine(LoadLowTemperatureWarningAudio());
		((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Cold 1.1.7 loaded. V1.1.7 keeps the compact Body Temp status line clear of the lower border. V1.1.6 makes a hand-held torch reliably warm exposed travel and boat journeys toward the Warm band, without entering overheating. The compact Body Temp status line keeps its extra vertical room. F9 writes a diagnostic line. F10 safely toggles the cold system for this session. God mode blocks all cold health damage. Armor insulation, torch warmth, overheating and Cold Survival Drive are active per the " + difficultyPreset.Value + " preset."));
	}

	private void Update()
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		if (TryToggleHudWithCtrlF3())
		{
			return;
		}
		if (Input.GetKeyDown(diagnosticKey.Value))
		{
			WriteDiagnostic();
		}
		if (Input.GetKeyDown(sessionToggleKey.Value))
		{
			runtimeEnabled = !runtimeEnabled;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Cold session toggle: " + (runtimeEnabled ? "ON" : "OFF") + "."));
		}
		if (!runtimeEnabled || !modEnabled.Value)
		{
			return;
		}
		float num = Mathf.Max(0.1f, tickInterval.Value);
		tickTimer += Time.deltaTime;
		if (tickTimer < num)
		{
			return;
		}
		float elapsedSeconds = Mathf.Min(tickTimer, num * 3f);
		tickTimer = 0f;
		try
		{
			Tick(elapsedSeconds);
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("You're Cold update failed: " + ex));
		}
	}

	private void Tick(float elapsedSeconds)
	{
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null))
		{
			SurvivalSnapshot snapshot = (lastSnapshot = ReadSnapshot(localPlayer));
			hasSnapshot = true;
			TemperatureSettings settings = ReadTemperatureSettings();
			float temperatureRate = TemperatureRules.GetTemperatureRate(snapshot, settings);
			float num = temperature + temperatureRate * elapsedSeconds;
			if (snapshot.IsHoldingTorch && !snapshot.IsSwimming && !snapshot.IsNearFire && settings.TorchWarmingRate > 0f)
			{
				float num2 = Mathf.Max(0.22f, settings.TorchWarmingRate);
				num = ((!(temperature < 76f)) ? Mathf.Max(76f, num) : Mathf.Min(76f, temperature + num2 * elapsedSeconds));
			}
			temperature = Mathf.Clamp(num, 0f, 100f);
			UpdateColdSurvivalDrive(elapsedSeconds);
			ApplyColdPenalties(localPlayer, elapsedSeconds);
			ApplyOverheatPenalties(localPlayer, elapsedSeconds);
			UpdateLowTemperatureWarning();
			if (debugLogging.Value)
			{
				ManualLogSource logger = ((BaseUnityPlugin)this).Logger;
				string[] obj = new string[12]
				{
					"Temperature=",
					temperature.ToString("0.0"),
					", rate=",
					temperatureRate.ToString("0.00"),
					"/s, drive=",
					coldSurvivalDriveActive.ToString(),
					", armor=",
					null,
					null,
					null,
					null,
					null
				};
				float armorValue = snapshot.ArmorValue;
				obj[7] = armorValue.ToString("0");
				obj[8] = ", torch=";
				bool isHoldingTorch = snapshot.IsHoldingTorch;
				obj[9] = isHoldingTorch.ToString();
				obj[10] = ", ";
				obj[11] = snapshot.ToDiagnosticText();
				logger.LogInfo((object)string.Concat(obj));
			}
		}
	}

	private SurvivalSnapshot ReadSnapshot(Player player)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Invalid comparison between Unknown and I4
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Invalid comparison between Unknown and I4
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		SEMan sEMan = ((Character)player).GetSEMan();
		Biome currentBiome = player.GetCurrentBiome();
		bool isWet = sEMan != null && sEMan.HaveStatusEffect(SEMan.s_statusEffectWet);
		bool flag = sEMan != null && sEMan.HaveStatusEffect(SEMan.s_statusEffectCampFire);
		bool flag2 = (Object)(object)EffectArea.IsPointInsideArea(((Component)player).transform.position, (Type)1, 0f) != (Object)null;
		return new SurvivalSnapshot(((Character)player).IsSwimming(), player.InShelter(), isWet, flag || flag2, EnvMan.IsCold(), EnvMan.IsFreezing(), EnvMan.IsNight(), (currentBiome & 4) > 0, (currentBiome & 0x40) > 0, currentBiome, IsHoldingHandTorch(player), GetTotalArmorValue(player));
	}

	private static float GetTotalArmorValue(Player player)
	{
		try
		{
			MethodInfo method = ((object)player).GetType().GetMethod("GetBodyArmor", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);
			if (method != null && method.Invoke(player, null) is float num)
			{
				return Mathf.Max(0f, num);
			}
		}
		catch
		{
		}
		return 0f;
	}

	private static bool IsHoldingHandTorch(Player player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return false;
		}
		if (!IsTorchItem(ReadHeldItem(player, "GetRightItem")) && !IsTorchItem(ReadHeldItem(player, "GetLeftItem")) && !IsTorchItem(ReadHeldItem(player, "GetCurrentWeapon")) && !IsTorchItem(ReadHeldItem(player, "m_rightItem")))
		{
			return IsTorchItem(ReadHeldItem(player, "m_leftItem"));
		}
		return true;
	}

	private static ItemData ReadHeldItem(Player player, string memberName)
	{
		if ((Object)(object)player == (Object)null || string.IsNullOrEmpty(memberName))
		{
			return null;
		}
		Type type = ((object)player).GetType();
		while (type != null)
		{
			try
			{
				MethodInfo method = type.GetMethod(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
				if (method != null)
				{
					object? obj = method.Invoke(player, null);
					return (ItemData)((obj is ItemData) ? obj : null);
				}
				FieldInfo field = type.GetField(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					object? value = field.GetValue(player);
					return (ItemData)((value is ItemData) ? value : null);
				}
			}
			catch
			{
			}
			type = type.BaseType;
		}
		return null;
	}

	private static bool IsTorchItem(ItemData item)
	{
		if (item == null)
		{
			return false;
		}
		string value = ((item.m_shared != null) ? item.m_shared.m_name : string.Empty);
		string value2 = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : string.Empty);
		if (!ContainsTorchName(value))
		{
			return ContainsTorchName(value2);
		}
		return true;
	}

	private static bool ContainsTorchName(string value)
	{
		if (string.IsNullOrEmpty(value))
		{
			return false;
		}
		if (value.IndexOf("torch", StringComparison.OrdinalIgnoreCase) < 0)
		{
			return value.IndexOf("lantern", StringComparison.OrdinalIgnoreCase) >= 0;
		}
		return true;
	}

	private TemperatureSettings ReadTemperatureSettings()
	{
		return new TemperatureSettings(Mathf.Max(0f, safeRecoveryRate.Value), Mathf.Max(0f, nearFireWarmingRate.Value), Mathf.Max(0f, wetCoolingRate.Value), Mathf.Max(0f, coldEnvironmentCoolingRate.Value), Mathf.Max(0f, freezingEnvironmentCoolingRate.Value), Mathf.Max(0f, mountainCoolingRate.Value), Mathf.Max(0f, deepNorthCoolingRate.Value), Mathf.Max(0f, nightCoolingRate.Value), Mathf.Max(0f, swimmingCoolingRate.Value), Mathf.Clamp(shelterCoolingMultiplier.Value, 0f, 1f), enableTorchWarmth.Value ? Mathf.Max(0f, torchWarmingRate.Value) : 0f, enableArmorInsulation.Value ? Mathf.Clamp01(maximumArmorInsulation.Value / 100f) : 0f, 110f);
	}

	private void ApplyColdPenalties(Player player, float elapsedSeconds)
	{
		float num = Mathf.Clamp(severeColdThreshold.Value, 0.01f, 100f);
		float num2 = (coldSurvivalDriveActive ? Mathf.Clamp01(coldSurvivalDriveDrainMultiplier.Value) : 1f);
		if (temperature <= num)
		{
			float num3 = 1f - temperature / num;
			float num4 = Mathf.Max(0f, staminaDrainAtZero.Value) * num3 * elapsedSeconds * num2;
			float num5 = Mathf.Clamp(emergencyStaminaReserve.Value, 0f, 50f);
			float num6 = Mathf.Max(0f, player.GetStamina() - num5);
			if (num4 > 0f && num6 > 0f)
			{
				((Character)player).UseStamina(Mathf.Min(num4, num6));
			}
		}
		if (temperature <= 0.01f)
		{
			float healthDamage = Mathf.Max(0f, freezingDamagePerSecond.Value) * elapsedSeconds * num2;
			ApplyNonLethalFreezingDamage(player, healthDamage);
		}
	}

	private static void ApplyNonLethalFreezingDamage(Player player, float healthDamage)
	{
		if (!((Object)(object)player == (Object)null) && !(healthDamage <= 0f) && !IsGodModeActive(player) && !(((Character)player).GetHealth() <= 1f))
		{
			float num = Mathf.Max(0f, ((Character)player).GetHealth() - 1f);
			if (num > 0f)
			{
				((Character)player).UseHealth(Mathf.Min(healthDamage, num));
			}
		}
	}

	private static bool IsGodModeActive(Player player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return false;
		}
		try
		{
			Type type = ((object)player).GetType();
			MethodInfo method = type.GetMethod("InGodMode", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			if (method != null && method.ReturnType == typeof(bool))
			{
				object obj = method.Invoke(method.IsStatic ? null : player, null);
				if (obj is bool && (bool)obj)
				{
					return true;
				}
			}
			FieldInfo field = type.GetField("m_godMode", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null && field.FieldType == typeof(bool))
			{
				object value = field.GetValue(field.IsStatic ? null : player);
				if (value is bool && (bool)value)
				{
					return true;
				}
			}
			PropertyInfo property = type.GetProperty("GodMode", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null && property.PropertyType == typeof(bool) && property.CanRead)
			{
				MethodInfo getMethod = property.GetGetMethod(nonPublic: true);
				object value2 = property.GetValue((getMethod != null && getMethod.IsStatic) ? null : player, null);
				if (value2 is bool && (bool)value2)
				{
					return true;
				}
			}
		}
		catch
		{
		}
		return false;
	}

	private void ApplyOverheatPenalties(Player player, float elapsedSeconds)
	{
		if (!enableOverheating.Value)
		{
			return;
		}
		float num = Mathf.Clamp(overheatThreshold.Value, 0f, 99.99f);
		if (!(temperature <= num))
		{
			float num2 = (temperature - num) / Mathf.Max(0.01f, 100f - num);
			float num3 = Mathf.Max(0f, overheatStaminaDrainAtMax.Value) * num2 * elapsedSeconds;
			if (num3 > 0f && player.GetStamina() > 0f)
			{
				((Character)player).UseStamina(Mathf.Min(num3, player.GetStamina()));
			}
		}
	}

	private void UpdateColdSurvivalDrive(float elapsedSeconds)
	{
		if (!enableColdSurvivalDrive.Value)
		{
			coldSurvivalDriveActive = false;
			coldSurvivalDriveTimeRemaining = 0f;
			return;
		}
		float num = Mathf.Clamp(coldSurvivalDriveResetTemperature.Value, 0f, 100f);
		float num2 = Mathf.Min(coldSurvivalDriveTriggerTemperature.Value, num - 0.01f);
		num2 = Mathf.Clamp(num2, 0f, 100f);
		if (temperature >= num)
		{
			wasAboveColdSurvivalDriveResetPoint = true;
		}
		if (coldSurvivalDriveActive)
		{
			coldSurvivalDriveTimeRemaining -= elapsedSeconds;
			if (coldSurvivalDriveTimeRemaining <= 0f)
			{
				coldSurvivalDriveActive = false;
				coldSurvivalDriveTimeRemaining = 0f;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"You're Cold: Cold Survival Drive has ended. Find warmth soon.");
			}
		}
		else if (wasAboveColdSurvivalDriveResetPoint && temperature <= num2)
		{
			coldSurvivalDriveActive = true;
			wasAboveColdSurvivalDriveResetPoint = false;
			coldSurvivalDriveTimeRemaining = Mathf.Max(1f, coldSurvivalDriveDurationSeconds.Value);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Cold: Cold Survival Drive activated. Cold drain reduced for " + coldSurvivalDriveTimeRemaining.ToString("0") + "s, find shelter or fire."));
		}
	}

	private void MigrateLegacyDefaultsToNormal()
	{
		if (Mathf.Abs(safeRecoveryRate.Value - 0.25f) < 0.001f && Mathf.Abs(wetCoolingRate.Value - 0.35f) < 0.001f && Mathf.Abs(coldEnvironmentCoolingRate.Value - 0.3f) < 0.001f && Mathf.Abs(freezingEnvironmentCoolingRate.Value - 0.65f) < 0.001f && Mathf.Abs(mountainCoolingRate.Value - 0.25f) < 0.001f && Mathf.Abs(deepNorthCoolingRate.Value - 0.45f) < 0.001f && Mathf.Abs(nightCoolingRate.Value - 0.12f) < 0.001f && Mathf.Abs(swimmingCoolingRate.Value - 3f) < 0.001f && Mathf.Abs(shelterCoolingMultiplier.Value - 0.45f) < 0.001f && Mathf.Abs(severeColdThreshold.Value - 25f) < 0.001f && Mathf.Abs(staminaDrainAtZero.Value - 3f) < 0.001f)
		{
			ApplyDifficultyPreset("Medium");
			((BaseUnityPlugin)this).Config.Save();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"You're Cold: migrated untouched legacy cold defaults to the balanced Medium preset.");
		}
	}

	private void MigrateV1_1_3RealisticTemperaturePacing()
	{
		if (Mathf.Abs(safeRecoveryRate.Value - 0.35f) < 0.001f && Mathf.Abs(nearFireWarmingRate.Value - 6f) < 0.001f && Mathf.Abs(wetCoolingRate.Value - 0.2f) < 0.001f && Mathf.Abs(coldEnvironmentCoolingRate.Value - 0.18f) < 0.001f && Mathf.Abs(freezingEnvironmentCoolingRate.Value - 0.35f) < 0.001f && Mathf.Abs(mountainCoolingRate.Value - 0.15f) < 0.001f && Mathf.Abs(deepNorthCoolingRate.Value - 0.3f) < 0.001f && Mathf.Abs(nightCoolingRate.Value - 0.08f) < 0.001f && Mathf.Abs(swimmingCoolingRate.Value - 2f) < 0.001f && Mathf.Abs(torchWarmingRate.Value - 1.4f) < 0.001f)
		{
			ApplyDifficultyPreset("Medium");
			lastAppliedDifficultyPreset.Value = "Medium";
			((BaseUnityPlugin)this).Config.Save();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"You're Cold: applied V1.1.3 realistic temperature pacing to untouched Medium settings.");
		}
	}

	private void MigrateV1_1_4TorchTravelWarmth()
	{
		float value = torchWarmingRate.Value;
		if (Mathf.Abs(value - 0.06f) < 0.001f)
		{
			torchWarmingRate.Value = 0.14f;
		}
		else if (Mathf.Abs(value - 0.08f) < 0.001f)
		{
			torchWarmingRate.Value = 0.16f;
		}
		else if (Mathf.Abs(value - 0.05f) < 0.001f)
		{
			torchWarmingRate.Value = 0.11f;
		}
		else
		{
			if (!(Mathf.Abs(value - 0.04f) < 0.001f))
			{
				return;
			}
			torchWarmingRate.Value = 0.09f;
		}
		((BaseUnityPlugin)this).Config.Save();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"You're Cold: applied V1.1.4 torch travel-warmth update.");
	}

	private void MigrateV1_1_6HandTorchTravelWarmth()
	{
		float value = torchWarmingRate.Value;
		if (Mathf.Abs(value - 0.14f) < 0.001f || Mathf.Abs(value - 0.16f) < 0.001f || Mathf.Abs(value - 0.11f) < 0.001f || Mathf.Abs(value - 0.09f) < 0.001f)
		{
			torchWarmingRate.Value = 0.22f;
			((BaseUnityPlugin)this).Config.Save();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"You're Cold: applied V1.1.6 hand-torch travel warmth.");
		}
	}

	private void ApplyDifficultyPresetIfChanged()
	{
		string text = NormalizeDifficultyPreset(difficultyPreset.Value);
		if (!string.Equals(difficultyPreset.Value, text, StringComparison.OrdinalIgnoreCase))
		{
			difficultyPreset.Value = text;
		}
		if (!string.Equals(lastAppliedDifficultyPreset.Value, text, StringComparison.OrdinalIgnoreCase))
		{
			ApplyDifficultyPreset(text);
			lastAppliedDifficultyPreset.Value = text;
			((BaseUnityPlugin)this).Config.Save();
			((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Cold: applied " + text + " difficulty preset."));
		}
	}

	private static string NormalizeDifficultyPreset(string value)
	{
		if (string.Equals(value, "Easy", StringComparison.OrdinalIgnoreCase))
		{
			return "Easy";
		}
		if (string.Equals(value, "Hard", StringComparison.OrdinalIgnoreCase))
		{
			return "Hard";
		}
		if (string.Equals(value, "Extreme", StringComparison.OrdinalIgnoreCase))
		{
			return "Extreme";
		}
		return "Medium";
	}

	private void ApplyDifficultyPreset(string preset)
	{
		switch (preset)
		{
		case "Easy":
			safeRecoveryRate.Value = 0.24f;
			nearFireWarmingRate.Value = 1.05f;
			wetCoolingRate.Value = 0.02f;
			coldEnvironmentCoolingRate.Value = 0.03f;
			freezingEnvironmentCoolingRate.Value = 0.07f;
			mountainCoolingRate.Value = 0.045f;
			deepNorthCoolingRate.Value = 0.09f;
			nightCoolingRate.Value = 0.012f;
			swimmingCoolingRate.Value = 0.1f;
			shelterCoolingMultiplier.Value = 0.22f;
			severeColdThreshold.Value = 10f;
			staminaDrainAtZero.Value = 0.45f;
			emergencyStaminaReserve.Value = 14f;
			freezingDamagePerSecond.Value = 0.15f;
			maximumArmorInsulation.Value = 80f;
			torchWarmingRate.Value = 0.22f;
			overheatThreshold.Value = 92f;
			overheatStaminaDrainAtMax.Value = 0.3f;
			coldSurvivalDriveTriggerTemperature.Value = 10f;
			coldSurvivalDriveDurationSeconds.Value = 75f;
			coldSurvivalDriveDrainMultiplier.Value = 0.15f;
			coldSurvivalDriveResetTemperature.Value = 25f;
			break;
		case "Hard":
			safeRecoveryRate.Value = 0.14f;
			nearFireWarmingRate.Value = 0.7f;
			wetCoolingRate.Value = 0.055f;
			coldEnvironmentCoolingRate.Value = 0.075f;
			freezingEnvironmentCoolingRate.Value = 0.16f;
			mountainCoolingRate.Value = 0.12f;
			deepNorthCoolingRate.Value = 0.22f;
			nightCoolingRate.Value = 0.035f;
			swimmingCoolingRate.Value = 0.22f;
			shelterCoolingMultiplier.Value = 0.42f;
			severeColdThreshold.Value = 20f;
			staminaDrainAtZero.Value = 1.15f;
			emergencyStaminaReserve.Value = 10f;
			freezingDamagePerSecond.Value = 0.32f;
			maximumArmorInsulation.Value = 60f;
			torchWarmingRate.Value = 0.22f;
			overheatThreshold.Value = 85f;
			overheatStaminaDrainAtMax.Value = 0.65f;
			coldSurvivalDriveTriggerTemperature.Value = 6f;
			coldSurvivalDriveDurationSeconds.Value = 45f;
			coldSurvivalDriveDrainMultiplier.Value = 0.35f;
			coldSurvivalDriveResetTemperature.Value = 22f;
			break;
		case "Extreme":
			safeRecoveryRate.Value = 0.1f;
			nearFireWarmingRate.Value = 0.55f;
			wetCoolingRate.Value = 0.075f;
			coldEnvironmentCoolingRate.Value = 0.1f;
			freezingEnvironmentCoolingRate.Value = 0.22f;
			mountainCoolingRate.Value = 0.16f;
			deepNorthCoolingRate.Value = 0.3f;
			nightCoolingRate.Value = 0.05f;
			swimmingCoolingRate.Value = 0.3f;
			shelterCoolingMultiplier.Value = 0.58f;
			severeColdThreshold.Value = 25f;
			staminaDrainAtZero.Value = 1.35f;
			emergencyStaminaReserve.Value = 8f;
			freezingDamagePerSecond.Value = 0.42f;
			maximumArmorInsulation.Value = 45f;
			torchWarmingRate.Value = 0.22f;
			overheatThreshold.Value = 82f;
			overheatStaminaDrainAtMax.Value = 0.8f;
			coldSurvivalDriveTriggerTemperature.Value = 4f;
			coldSurvivalDriveDurationSeconds.Value = 30f;
			coldSurvivalDriveDrainMultiplier.Value = 0.45f;
			coldSurvivalDriveResetTemperature.Value = 20f;
			break;
		default:
			safeRecoveryRate.Value = 0.18f;
			nearFireWarmingRate.Value = 0.85f;
			wetCoolingRate.Value = 0.035f;
			coldEnvironmentCoolingRate.Value = 0.045f;
			freezingEnvironmentCoolingRate.Value = 0.1f;
			mountainCoolingRate.Value = 0.07f;
			deepNorthCoolingRate.Value = 0.14f;
			nightCoolingRate.Value = 0.02f;
			swimmingCoolingRate.Value = 0.15f;
			shelterCoolingMultiplier.Value = 0.3f;
			severeColdThreshold.Value = 15f;
			staminaDrainAtZero.Value = 0.8f;
			emergencyStaminaReserve.Value = 12f;
			freezingDamagePerSecond.Value = 0.25f;
			maximumArmorInsulation.Value = 70f;
			torchWarmingRate.Value = 0.22f;
			overheatThreshold.Value = 88f;
			overheatStaminaDrainAtMax.Value = 0.5f;
			coldSurvivalDriveTriggerTemperature.Value = 8f;
			coldSurvivalDriveDurationSeconds.Value = 60f;
			coldSurvivalDriveDrainMultiplier.Value = 0.25f;
			coldSurvivalDriveResetTemperature.Value = 25f;
			break;
		}
	}

	private void WriteDiagnostic()
	{
		if (!hasSnapshot)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"You're Cold: no player temperature snapshot has been collected yet.");
			return;
		}
		float temperatureRate = TemperatureRules.GetTemperatureRate(lastSnapshot, ReadTemperatureSettings());
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Diagnostic: temperature=" + temperature.ToString("0.0") + "/100, rate=" + temperatureRate.ToString("0.00") + "/s, drive=" + coldSurvivalDriveActive + (coldSurvivalDriveActive ? (" (" + coldSurvivalDriveTimeRemaining.ToString("0") + "s left)") : string.Empty) + ", " + lastSnapshot.ToDiagnosticText()));
	}

	private void OnGUI()
	{
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_021f: Unknown result type (might be due to invalid IL or missing references)
		//IL_022b: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
		if (!runtimeEnabled || !modEnabled.Value || !showHud.Value || IsHudHiddenByCtrlF3() || (Object)(object)Player.m_localPlayer == (Object)null)
		{
			return;
		}
		if (!useCompactSurvivalHud.Value)
		{
			DrawLegacyTemperatureHud();
			return;
		}
		Rect compactHudRect = GetCompactHudRect();
		float compactHudContentScale = GetCompactHudContentScale(compactHudRect);
		float num = Mathf.Max(1f, ((Rect)(ref compactHudRect)).width - 8f * compactHudContentScale);
		EnsureCompactHudStyles(compactHudContentScale);
		Color color = GUI.color;
		GUI.color = new Color(0f, 0f, 0f, 0.84f);
		GUI.DrawTexture(compactHudRect, (Texture)(object)Texture2D.whiteTexture);
		GUI.color = new Color(0.78f, 0.72f, 0.53f, 0.68f);
		GUI.DrawTexture(new Rect(((Rect)(ref compactHudRect)).x, ((Rect)(ref compactHudRect)).y, ((Rect)(ref compactHudRect)).width, 1f * compactHudContentScale), (Texture)(object)Texture2D.whiteTexture);
		GUI.DrawTexture(new Rect(((Rect)(ref compactHudRect)).x, ((Rect)(ref compactHudRect)).yMax - 1f * compactHudContentScale, ((Rect)(ref compactHudRect)).width, 1f * compactHudContentScale), (Texture)(object)Texture2D.whiteTexture);
		GUI.DrawTexture(new Rect(((Rect)(ref compactHudRect)).x, ((Rect)(ref compactHudRect)).y, 1f * compactHudContentScale, ((Rect)(ref compactHudRect)).height), (Texture)(object)Texture2D.whiteTexture);
		GUI.DrawTexture(new Rect(((Rect)(ref compactHudRect)).xMax - 1f * compactHudContentScale, ((Rect)(ref compactHudRect)).y, 1f * compactHudContentScale, ((Rect)(ref compactHudRect)).height), (Texture)(object)Texture2D.whiteTexture);
		GUI.color = Color.white;
		GUI.Label(new Rect(((Rect)(ref compactHudRect)).x + 7f * compactHudContentScale, ((Rect)(ref compactHudRect)).y + 4f * compactHudContentScale, ((Rect)(ref compactHudRect)).width - 14f * compactHudContentScale, 16f * compactHudContentScale), "Body Temp " + temperature.ToString("0") + "%", compactTemperatureHeaderStyle);
		Rect trackRect = default(Rect);
		((Rect)(ref trackRect))..ctor(((Rect)(ref compactHudRect)).x + 4f * compactHudContentScale, ((Rect)(ref compactHudRect)).y + 24f * compactHudContentScale, num, 14f * compactHudContentScale);
		DrawTemperatureGradientTrack(trackRect);
		GUI.color = GetTemperatureColor(temperature);
		string text = GetTemperatureLabel(temperature);
		if (coldSurvivalDriveActive)
		{
			text = text + " - Drive " + Mathf.CeilToInt(coldSurvivalDriveTimeRemaining) + "s";
		}
		GUI.Label(new Rect(((Rect)(ref compactHudRect)).x + 7f * compactHudContentScale, ((Rect)(ref compactHudRect)).y + 37f * compactHudContentScale, ((Rect)(ref compactHudRect)).width - 14f * compactHudContentScale, 21f * compactHudContentScale), text, compactTemperatureDetailStyle);
		GUI.color = color;
	}

	private void DrawTemperatureGradientTrack(Rect trackRect)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		float num = ((Rect)(ref trackRect)).width / 24f;
		GUI.color = new Color(0f, 0f, 0f, 0.56f);
		GUI.DrawTexture(trackRect, (Texture)(object)Texture2D.whiteTexture);
		for (int i = 0; i < 24; i++)
		{
			GUI.color = GetGradientColor(((float)i + 0.5f) / 24f * 100f);
			GUI.DrawTexture(new Rect(((Rect)(ref trackRect)).x + (float)i * num, ((Rect)(ref trackRect)).y, num + 0.5f, ((Rect)(ref trackRect)).height), (Texture)(object)Texture2D.whiteTexture);
		}
		float num2 = Mathf.Clamp01(temperature / 100f);
		DrawGaugeNeedle(Mathf.Clamp(((Rect)(ref trackRect)).x + ((Rect)(ref trackRect)).width * num2, ((Rect)(ref trackRect)).x + 1f, ((Rect)(ref trackRect)).xMax - 1f), trackRect);
	}

	private static void DrawGaugeNeedle(float centerX, Rect trackRect)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: 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)
		float num = Mathf.Min(2f, ((Rect)(ref trackRect)).height * 0.18f);
		float num2 = Mathf.Max(3f, ((Rect)(ref trackRect)).height * 0.45f);
		Color color = GUI.color;
		GUI.color = new Color(1f, 0.84f, 0.3f, 1f);
		GUI.DrawTexture(new Rect(centerX - 1f, ((Rect)(ref trackRect)).y - num, 2f, ((Rect)(ref trackRect)).height + num * 2f), (Texture)(object)Texture2D.whiteTexture);
		GUI.DrawTexture(new Rect(centerX - num2 * 0.5f, ((Rect)(ref trackRect)).y - num, num2, num), (Texture)(object)Texture2D.whiteTexture);
		GUI.DrawTexture(new Rect(centerX - num2 * 0.5f, ((Rect)(ref trackRect)).yMax, num2, num), (Texture)(object)Texture2D.whiteTexture);
		GUI.color = color;
	}

	private static Color GetGradientColor(float value)
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		float num = Mathf.Clamp01(value / 100f);
		Color val = new Color(0.2f, 0.45f, 0.95f, 1f);
		Color val2 = default(Color);
		((Color)(ref val2))..ctor(1f, 0.55f, 0.1f, 1f);
		return Color.Lerp(val, val2, num);
	}

	private void DrawLegacyTemperatureHud()
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		float num = ((float)Screen.width - 220f) * 0.5f;
		float num2 = (float)Screen.height - 118f;
		Color color = GUI.color;
		DrawTemperatureGradientTrack(new Rect(num + 2f, num2 + 2f, 216f, 14f));
		GUI.color = Color.white;
		GUI.Label(new Rect(num, num2 - 21f, 220f, 20f), "Temperature: " + temperature.ToString("0") + "% - " + GetTemperatureLabel(temperature));
		GUI.color = color;
	}

	private static float GetCompactHudScale()
	{
		return Mathf.Max(0.7f, Mathf.Min((float)Screen.width / 2048f, (float)Screen.height / 1152f));
	}

	private Rect GetCompactHudRect()
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		float compactHudScale = GetCompactHudScale();
		float num = 221f * compactHudScale;
		float num2 = 62f * compactHudScale;
		float num3 = 247f * compactHudScale;
		float num4 = (float)Screen.height - 180f * compactHudScale;
		return new Rect(num3, num4, num, num2);
	}

	private float GetCompactHudContentScale(Rect panelRect)
	{
		float compactHudScale = GetCompactHudScale();
		float num = 221f * compactHudScale;
		float num2 = 62f * compactHudScale;
		float num3 = Mathf.Min(((Rect)(ref panelRect)).width / num, ((Rect)(ref panelRect)).height / num2);
		return Mathf.Max(0.55f, compactHudScale * Mathf.Clamp(num3, 0.55f, 3f));
	}

	private bool IsHudHiddenByCtrlF3()
	{
		if (hideHudWithCtrlF3 != null && hideHudWithCtrlF3.Value)
		{
			return hudHiddenByCtrlF3;
		}
		return false;
	}

	private bool TryToggleHudWithCtrlF3()
	{
		if (!IsCtrlF3Pressed())
		{
			return false;
		}
		if (hideHudWithCtrlF3 == null || !hideHudWithCtrlF3.Value)
		{
			return true;
		}
		hudHiddenByCtrlF3 = !hudHiddenByCtrlF3;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Cold: Ctrl+F3 HUD " + (hudHiddenByCtrlF3 ? "hidden." : "restored.")));
		return true;
	}

	private static bool IsCtrlF3Pressed()
	{
		if (Input.GetKeyDown((KeyCode)284))
		{
			if (!Input.GetKey((KeyCode)306))
			{
				return Input.GetKey((KeyCode)305);
			}
			return true;
		}
		return false;
	}

	private void EnsureCompactHudStyles(float scale)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Expected O, but got Unknown
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Expected O, but got Unknown
		if (compactTemperatureHeaderStyle == null)
		{
			compactTemperatureHeaderStyle = new GUIStyle(GUI.skin.label);
			compactTemperatureHeaderStyle.fontStyle = (FontStyle)0;
			compactTemperatureHeaderStyle.wordWrap = false;
			compactTemperatureHeaderStyle.clipping = (TextClipping)1;
			compactTemperatureHeaderStyle.alignment = (TextAnchor)0;
		}
		if (compactTemperatureDetailStyle == null)
		{
			compactTemperatureDetailStyle = new GUIStyle(GUI.skin.label);
			compactTemperatureDetailStyle.wordWrap = false;
			compactTemperatureDetailStyle.clipping = (TextClipping)1;
			compactTemperatureDetailStyle.alignment = (TextAnchor)0;
		}
		compactTemperatureHeaderStyle.fontSize = Mathf.Max(10, Mathf.RoundToInt(12f * scale));
		compactTemperatureDetailStyle.fontSize = Mathf.Max(9, Mathf.RoundToInt(10.5f * scale));
	}

	private void UpdateLowTemperatureWarning()
	{
		if (enableLowTemperatureWarning.Value && lowTemperatureWarningClip != null)
		{
			float num = Mathf.Clamp(lowTemperatureWarningThreshold.Value, 1f, 100f);
			float num2 = Mathf.Min(100f, num + 2f);
			if (temperature >= num2)
			{
				wasBelowWarningThreshold = false;
			}
			else if (!(temperature > num) && (!wasBelowWarningThreshold || Time.unscaledTime >= nextLowTemperatureWarningTime) && TryPlayOneShot(lowTemperatureWarningClip, Mathf.Clamp01(lowTemperatureWarningVolume.Value)))
			{
				wasBelowWarningThreshold = true;
				nextLowTemperatureWarningTime = Time.unscaledTime + Mathf.Max(30f, lowTemperatureWarningRepeatSeconds.Value);
			}
		}
	}

	private IEnumerator LoadLowTemperatureWarningAudio()
	{
		if (!lowTemperatureWarningLoadStarted)
		{
			lowTemperatureWarningLoadStarted = true;
			string path = (string.IsNullOrWhiteSpace(lowTemperatureWarningFile.Value) ? "cold breath.mp3" : lowTemperatureWarningFile.Value.Trim());
			string path2 = Path.Combine(pluginDirectory ?? string.Empty, "assets", "audio", path);
			yield return ((MonoBehaviour)this).StartCoroutine(LoadExternalMp3(path2, delegate(object clip)
			{
				lowTemperatureWarningClip = clip;
			}, "cold warning"));
		}
	}

	private IEnumerator LoadExternalMp3(string path, Action<object> onLoaded, string label)
	{
		object request;
		object operation;
		if (string.IsNullOrEmpty(path) || !File.Exists(path))
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Cold: " + label + " audio file was not found at " + path));
		}
		else if (TryBeginExternalMp3Request(path, label, out request, out operation))
		{
			yield return operation;
			CompleteExternalMp3Request(request, onLoaded, label);
		}
	}

	private bool TryBeginExternalMp3Request(string path, string label, out object request, out object operation)
	{
		request = null;
		operation = null;
		try
		{
			Type type = FindRuntimeType("UnityEngine.Networking.UnityWebRequestMultimedia");
			if (type == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Cold: UnityWebRequestMultimedia was unavailable; could not load " + label + " audio."));
				return false;
			}
			MethodInfo methodInfo = null;
			MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (methodInfo2.Name == "GetAudioClip" && methodInfo2.GetParameters().Length == 2)
				{
					methodInfo = methodInfo2;
					break;
				}
			}
			if (methodInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Cold: no compatible GetAudioClip method was found for " + label + " audio."));
				return false;
			}
			object obj = Enum.Parse(methodInfo.GetParameters()[1].ParameterType, "MPEG");
			request = methodInfo.Invoke(null, new object[2]
			{
				new Uri(path).AbsoluteUri,
				obj
			});
			if (request == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Cold: could not create the request for " + label + " audio."));
				return false;
			}
			MethodInfo method = request.GetType().GetMethod("SendWebRequest", Type.EmptyTypes);
			if (method == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Cold: no SendWebRequest method was found for " + label + " audio."));
				DisposeRequest(request);
				request = null;
				return false;
			}
			operation = method.Invoke(request, null);
			if (operation == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Cold: SendWebRequest returned no operation for " + label + " audio."));
				DisposeRequest(request);
				request = null;
				return false;
			}
			return true;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Cold: could not start loading " + label + " audio. " + ex.Message));
			DisposeRequest(request);
			request = null;
			operation = null;
			return false;
		}
	}

	private void CompleteExternalMp3Request(object request, Action<object> onLoaded, string label)
	{
		try
		{
			if (request == null)
			{
				return;
			}
			PropertyInfo property = request.GetType().GetProperty("error", BindingFlags.Instance | BindingFlags.Public);
			string text = ((property != null) ? (property.GetValue(request, null) as string) : null);
			if (!string.IsNullOrEmpty(text))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Cold: failed to load " + label + " audio. " + text));
				return;
			}
			PropertyInfo property2 = request.GetType().GetProperty("downloadHandler", BindingFlags.Instance | BindingFlags.Public);
			object obj = ((property2 != null) ? property2.GetValue(request, null) : null);
			PropertyInfo propertyInfo = obj?.GetType().GetProperty("audioClip", BindingFlags.Instance | BindingFlags.Public);
			object obj2 = ((propertyInfo != null) ? propertyInfo.GetValue(obj, null) : null);
			if (obj2 == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Cold: the " + label + " MP3 decoded without an AudioClip."));
				return;
			}
			onLoaded?.Invoke(obj2);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Cold: loaded " + label + " audio from " + Path.GetFileName(GetRequestUrl(request)) + "."));
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Cold: could not finish loading " + label + " audio. " + ex.Message));
		}
		finally
		{
			DisposeRequest(request);
		}
	}

	private static string GetRequestUrl(object request)
	{
		if (request == null)
		{
			return string.Empty;
		}
		try
		{
			PropertyInfo property = request.GetType().GetProperty("url", BindingFlags.Instance | BindingFlags.Public);
			string text = ((property != null) ? (property.GetValue(request, null) as string) : null);
			return string.IsNullOrEmpty(text) ? string.Empty : text;
		}
		catch
		{
			return string.Empty;
		}
	}

	private static void DisposeRequest(object request)
	{
		if (request is IDisposable disposable)
		{
			disposable.Dispose();
		}
	}

	private bool TryPlayOneShot(object clip, float volume)
	{
		if (clip == null)
		{
			return false;
		}
		Component val = EnsureLowTemperatureAudioSource();
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		try
		{
			MethodInfo[] methods = ((object)val).GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name == "PlayOneShot" && methodInfo.GetParameters().Length == 2)
				{
					methodInfo.Invoke(val, new object[2] { clip, volume });
					return true;
				}
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Cold: failed to play low-temperature warning. " + ex.Message));
		}
		return false;
	}

	private Component EnsureLowTemperatureAudioSource()
	{
		if ((Object)(object)lowTemperatureAudioSource != (Object)null)
		{
			return lowTemperatureAudioSource;
		}
		Type type = FindRuntimeType("UnityEngine.AudioSource");
		if (type == null)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"You're Cold: Unity AudioSource was unavailable.");
			return null;
		}
		lowTemperatureAudioSource = ((Component)this).gameObject.GetComponent(type);
		if ((Object)(object)lowTemperatureAudioSource == (Object)null)
		{
			lowTemperatureAudioSource = ((Component)this).gameObject.AddComponent(type);
		}
		if ((Object)(object)lowTemperatureAudioSource != (Object)null)
		{
			SetAudioProperty(lowTemperatureAudioSource, "playOnAwake", false);
			SetAudioProperty(lowTemperatureAudioSource, "spatialBlend", 0f);
			SetAudioProperty(lowTemperatureAudioSource, "loop", false);
		}
		return lowTemperatureAudioSource;
	}

	private static void SetAudioProperty(Component source, string name, object value)
	{
		if (!((Object)(object)source == (Object)null))
		{
			PropertyInfo property = ((object)source).GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public);
			if (property != null && property.CanWrite)
			{
				property.SetValue(source, value, null);
			}
		}
	}

	private static Type FindRuntimeType(string fullName)
	{
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		for (int i = 0; i < assemblies.Length; i++)
		{
			Type type = assemblies[i].GetType(fullName, throwOnError: false);
			if (type != null)
			{
				return type;
			}
		}
		string text = null;
		if (string.Equals(fullName, "UnityEngine.AudioSource", StringComparison.Ordinal))
		{
			text = "UnityEngine.AudioModule";
		}
		else if (fullName.StartsWith("UnityEngine.Networking.", StringComparison.Ordinal))
		{
			text = "UnityEngine.UnityWebRequestAudioModule";
		}
		if (!string.IsNullOrEmpty(text))
		{
			try
			{
				Assembly assembly = Assembly.Load(text);
				Type type2 = ((assembly != null) ? assembly.GetType(fullName, throwOnError: false) : null);
				if (type2 != null)
				{
					return type2;
				}
			}
			catch
			{
			}
		}
		return null;
	}

	private void OnDestroy()
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Expected O, but got Unknown
		if (lowTemperatureWarningClip is Object)
		{
			Object.Destroy((Object)lowTemperatureWarningClip);
		}
	}

	private static Color GetTemperatureColor(float value)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		if (value > 70f)
		{
			return new Color(0.25f, 0.85f, 0.35f, 1f);
		}
		if (value > 40f)
		{
			return new Color(0.95f, 0.78f, 0.2f, 1f);
		}
		if (value > 15f)
		{
			return new Color(1f, 0.45f, 0.12f, 1f);
		}
		return new Color(0.85f, 0.15f, 0.15f, 1f);
	}

	private static string GetTemperatureLabel(float value)
	{
		if (value > 70f)
		{
			return "Warm";
		}
		if (value > 40f)
		{
			return "Chilly";
		}
		if (value > 15f)
		{
			return "Cold";
		}
		return "Freezing";
	}
}
internal struct SurvivalSnapshot
{
	public readonly bool IsSwimming;

	public readonly bool IsSheltered;

	public readonly bool IsWet;

	public readonly bool IsNearFire;

	public readonly bool IsCold;

	public readonly bool IsFreezing;

	public readonly bool IsNight;

	public readonly bool IsMountain;

	public readonly bool IsDeepNorth;

	public readonly Biome Biome;

	public readonly bool IsHoldingTorch;

	public readonly float ArmorValue;

	public SurvivalSnapshot(bool isSwimming, bool isSheltered, bool isWet, bool isNearFire, bool isCold, bool isFreezing, bool isNight, bool isMountain, bool isDeepNorth, Biome biome, bool isHoldingTorch, float armorValue)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		IsSwimming = isSwimming;
		IsSheltered = isSheltered;
		IsWet = isWet;
		IsNearFire = isNearFire;
		IsCold = isCold;
		IsFreezing = isFreezing;
		IsNight = isNight;
		IsMountain = isMountain;
		IsDeepNorth = isDeepNorth;
		Biome = biome;
		IsHoldingTorch = isHoldingTorch;
		ArmorValue = armorValue;
	}

	public string ToDiagnosticText()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		string[] obj = new string[24]
		{
			"biome=",
			((object)Biome/*cast due to .constrained prefix*/).ToString(),
			", swimming=",
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null
		};
		bool isSwimming = IsSwimming;
		obj[3] = isSwimming.ToString();
		obj[4] = ", sheltered=";
		isSwimming = IsSheltered;
		obj[5] = isSwimming.ToString();
		obj[6] = ", wet=";
		isSwimming = IsWet;
		obj[7] = isSwimming.ToString();
		obj[8] = ", nearFire=";
		isSwimming = IsNearFire;
		obj[9] = isSwimming.ToString();
		obj[10] = ", cold=";
		isSwimming = IsCold;
		obj[11] = isSwimming.ToString();
		obj[12] = ", freezing=";
		isSwimming = IsFreezing;
		obj[13] = isSwimming.ToString();
		obj[14] = ", night=";
		isSwimming = IsNight;
		obj[15] = isSwimming.ToString();
		obj[16] = ", mountain=";
		isSwimming = IsMountain;
		obj[17] = isSwimming.ToString();
		obj[18] = ", deepNorth=";
		isSwimming = IsDeepNorth;
		obj[19] = isSwimming.ToString();
		obj[20] = ", torch=";
		isSwimming = IsHoldingTorch;
		obj[21] = isSwimming.ToString();
		obj[22] = ", armor=";
		float armorValue = ArmorValue;
		obj[23] = armorValue.ToString("0");
		return string.Concat(obj);
	}
}
internal struct TemperatureSettings
{
	public readonly float SafeRecoveryRate;

	public readonly float NearFireWarmingRate;

	public readonly float WetCoolingRate;

	public readonly float ColdEnvironmentCoolingRate;

	public readonly float FreezingEnvironmentCoolingRate;

	public readonly float MountainCoolingRate;

	public readonly float DeepNorthCoolingRate;

	public readonly float NightCoolingRate;

	public readonly float SwimmingCoolingRate;

	public readonly float ShelterCoolingMultiplier;

	public readonly float TorchWarmingRate;

	public readonly float MaximumArmorInsulationFraction;

	public readonly float ArmorInsulationReferenceValue;

	public TemperatureSettings(float safeRecoveryRate, float nearFireWarmingRate, float wetCoolingRate, float coldEnvironmentCoolingRate, float freezingEnvironmentCoolingRate, float mountainCoolingRate, float deepNorthCoolingRate, float nightCoolingRate, float swimmingCoolingRate, float shelterCoolingMultiplier, float torchWarmingRate, float maximumArmorInsulationFraction, float armorInsulationReferenceValue)
	{
		SafeRecoveryRate = safeRecoveryRate;
		NearFireWarmingRate = nearFireWarmingRate;
		WetCoolingRate = wetCoolingRate;
		ColdEnvironmentCoolingRate = coldEnvironmentCoolingRate;
		FreezingEnvironmentCoolingRate = freezingEnvironmentCoolingRate;
		MountainCoolingRate = mountainCoolingRate;
		DeepNorthCoolingRate = deepNorthCoolingRate;
		NightCoolingRate = nightCoolingRate;
		SwimmingCoolingRate = swimmingCoolingRate;
		ShelterCoolingMultiplier = shelterCoolingMultiplier;
		TorchWarmingRate = torchWarmingRate;
		MaximumArmorInsulationFraction = maximumArmorInsulationFraction;
		ArmorInsulationReferenceValue = armorInsulationReferenceValue;
	}
}
internal static class TemperatureRules
{
	public static float GetTemperatureRate(SurvivalSnapshot snapshot, TemperatureSettings settings)
	{
		float num = 0f;
		if (snapshot.IsSwimming)
		{
			num += settings.SwimmingCoolingRate;
		}
		else
		{
			if (snapshot.IsWet)
			{
				num += settings.WetCoolingRate;
			}
			if (snapshot.IsFreezing)
			{
				num += settings.FreezingEnvironmentCoolingRate;
			}
			else if (snapshot.IsCold)
			{
				num += settings.ColdEnvironmentCoolingRate;
			}
			if (snapshot.IsMountain)
			{
				num += settings.MountainCoolingRate;
			}
			if (snapshot.IsDeepNorth)
			{
				num += settings.DeepNorthCoolingRate;
			}
			if (snapshot.IsNight)
			{
				num += settings.NightCoolingRate;
			}
		}
		if (snapshot.IsSheltered && num > 0f)
		{
			num *= settings.ShelterCoolingMultiplier;
		}
		if (num > 0f && settings.MaximumArmorInsulationFraction > 0f)
		{
			float num2 = Mathf.Clamp01(snapshot.ArmorValue / Mathf.Max(1f, settings.ArmorInsulationReferenceValue));
			float num3 = (snapshot.IsSwimming ? Mathf.Min(settings.MaximumArmorInsulationFraction, 0.2f) : settings.MaximumArmorInsulationFraction);
			float num4 = num2 * num3;
			num *= 1f - num4;
		}
		float num5 = 0f;
		if (snapshot.IsHoldingTorch)
		{
			num5 += settings.TorchWarmingRate;
		}
		if (snapshot.IsNearFire)
		{
			return settings.NearFireWarmingRate + num5 - num;
		}
		float num6 = num5 - num;
		if (num6 <= 0f && num <= 0f)
		{
			return settings.SafeRecoveryRate + num5;
		}
		return num6;
	}
}