Decompiled source of Elins PEAK v0.4.7

BepInEx/plugins/Elins_PEAK/PEAKUsageSkills.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using PEAKLib.UI;
using PEAKLib.UI.Elements;
using PEAKUsageSkills.Config;
using PEAKUsageSkills.Core;
using PEAKUsageSkills.Diagnostics;
using PEAKUsageSkills.Effects;
using PEAKUsageSkills.GameAdapters;
using PEAKUsageSkills.GameAdapters.Patches;
using PEAKUsageSkills.Localization;
using PEAKUsageSkills.Persistence;
using PEAKUsageSkills.Tracking;
using PEAKUsageSkills.UI;
using Peak.Afflictions;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Zorro.Core.Serizalization;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PEAKUsageSkills")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.4.7.0")]
[assembly: AssemblyInformationalVersion("0.4.7+ff2a3c774b0d6323303de590055096131c3b177a")]
[assembly: AssemblyProduct("PEAKUsageSkills")]
[assembly: AssemblyTitle("PEAKUsageSkills")]
[assembly: AssemblyVersion("0.4.7.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PEAKUsageSkills
{
	[BepInPlugin("com.chiseled.peak.usageskills", "Elin's PEAK", "0.4.7")]
	[BepInProcess("PEAK.exe")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.chiseled.peak.usageskills";

		public const string PluginName = "Elin's PEAK";

		public const string PluginVersion = "0.4.7";

		private Harmony? harmony;

		internal static UsageSkillsConfig Settings { get; private set; }

		internal static RunStateAdapter RunState { get; private set; }

		internal static ProgressionService Progression { get; private set; }

		internal static EffectService Effects { get; private set; }

		internal static DiagnosticHub? Diagnostics { get; private set; }

		internal static ManualLogSource ModLog { get; private set; }

		private void Awake()
		{
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Expected O, but got Unknown
			ModLog = ((BaseUnityPlugin)this).Logger;
			Settings = new UsageSkillsConfig(((BaseUnityPlugin)this).Config);
			LocalizationService.Initialize(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? Paths.PluginPath);
			RunState = new RunStateAdapter(Settings);
			SaveStore store = new SaveStore(((BaseUnityPlugin)this).Logger);
			Progression = new ProgressionService(Settings, store, ((BaseUnityPlugin)this).Logger, RunState);
			Effects = new EffectService(Settings, Progression, RunState);
			Diagnostics = new DiagnosticHub(((BaseUnityPlugin)this).Logger, Settings, RunState, Progression, Effects);
			Progression.LevelChanged += OnSkillLevelChanged;
			harmony = new Harmony("com.chiseled.peak.usageskills");
			PatchAllFailSoft(Assembly.GetExecutingAssembly());
			((Component)this).gameObject.AddComponent<ActivitySampler>();
			((Component)this).gameObject.AddComponent<InventorySkillController>();
			((Component)this).gameObject.AddComponent<DebugOverlay>();
			PauseMenuIntegration.Register();
			SceneManager.sceneLoaded += OnSceneLoaded;
			InspectPatchHealth();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Elin's PEAK 0.4.7 loaded. Save levels are player-owned; Airport XP is disabled and anti-farming policy is deferred for the first runtime pass.");
		}

		private void Update()
		{
			Progression.Tick();
			Diagnostics?.Tick();
		}

		private void OnApplicationQuit()
		{
			Progression.Flush();
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			Progression.LevelChanged -= OnSkillLevelChanged;
			PauseMenuIntegration.Unregister();
			LocalizationService.Shutdown();
			Progression.Flush();
			Harmony? obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}

		private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			Progression.Flush();
			ModLog.LogInfo((object)$"[UsageSkills:Scene] loaded={((Scene)(ref scene)).name} mode={mode} xpEligible={RunState.IsExperienceEligible}");
		}

		private static void OnSkillLevelChanged(SkillId skillId, int level)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if (skillId == SkillId.Strength && Settings.DebugAllSkillLevelOverride.Value < 0)
			{
				WeightPatch.RefreshLocalWeight($"StrengthLevel:{level}");
				InventorySkillService.EnsureBackpackCapacity(InventorySkillService.TryGetEquippedBackpackData(Character.localCharacter, out var backpackType), backpackType, $"StrengthLevel:{level}");
			}
		}

		private static void InspectPatchHealth()
		{
			RecordHook("StaminaCapacity", typeof(Character), "GetMaxStamina");
			RecordHook("PassOutThreshold", typeof(CharacterAfflictions), "get_shouldPassOut");
			RecordHook("PassOutRecovery", typeof(Character), "HandlePassedOut");
			RecordHook("StaminaCost", typeof(Character), "UseStamina");
			RecordHook("StaminaRegen", typeof(Character), "UpdateVariablesFixed");
			RecordHook("StaminaHud", typeof(StaminaBar), "Update");
			RecordHook("Weight", typeof(CharacterAfflictions), "UpdateWeight");
			RecordHook("WallClimbing", typeof(CharacterClimbing), "GetRequestedPostition");
			RecordHook("RopeClimbing", typeof(CharacterRopeHandling), "Update");
			RecordHook("VineClimbing", typeof(CharacterVineClimbing), "FixedUpdate");
			RecordHook("Athletics", typeof(CharacterMovement), "GetMovementForce");
			RecordHook("Agility", typeof(CharacterMovement), "JumpRpc");
			RecordHook("NormalFalls", typeof(CharacterMovement), "CheckFallDamage");
			RecordHook("WallFalls", typeof(CharacterClimbing), "CheckFallDamage");
			RecordHook("Afflictions", typeof(CharacterAfflictions), "AddStatus");
			RecordHook("ConditionRecovery", typeof(CharacterAfflictions), "SubtractStatus");
			RecordHook("Petrification", typeof(CharacterAfflictions), "AddPetrify", new Type[1] { typeof(int) });
			RecordHook("BackpackInventory", typeof(BackpackData), "DeserializeValue");
			RecordHook("BackpackWheel", typeof(BackpackWheel), "InitWheel");
			RecordHook("WetGrip", typeof(WindChillZone), "ApplyStatus");
		}

		private void PatchAllFailSoft(Assembly assembly)
		{
			Type[] types = assembly.GetTypes();
			Array.Sort(types, (Type left, Type right) => string.CompareOrdinal(left.FullName, right.FullName));
			Type[] array = types;
			foreach (Type type in array)
			{
				if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0)
				{
					try
					{
						harmony.CreateClassProcessor(type).Patch();
					}
					catch (Exception arg)
					{
						((BaseUnityPlugin)this).Logger.LogError((object)$"[UsageSkills:Patch] Failed patch class {type.FullName}; its adapter will remain disabled. {arg}");
					}
				}
			}
		}

		private static void RecordHook(string adapter, Type type, string methodName, Type[]? parameterTypes = null)
		{
			MethodInfo methodInfo = ((parameterTypes == null) ? AccessTools.Method(type, methodName, (Type[])null, (Type[])null) : AccessTools.Method(type, methodName, parameterTypes, (Type[])null));
			int num;
			if (methodInfo != null)
			{
				Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
				num = ((patchInfo != null && patchInfo.Owners.Contains("com.chiseled.peak.usageskills")) ? 1 : 0);
			}
			else
			{
				num = 0;
			}
			bool healthy = (byte)num != 0;
			string hook = ((parameterTypes == null) ? (type.FullName + "." + methodName) : (type.FullName + "." + methodName + "(" + string.Join(",", Array.ConvertAll(parameterTypes, (Type value) => value.Name)) + ")"));
			Diagnostics?.RecordPatchHealth(adapter, healthy, hook);
		}
	}
}
namespace PEAKUsageSkills.UI
{
	internal sealed class DebugOverlay : MonoBehaviour
	{
		private GUIStyle? labelStyle;

		private void OnGUI()
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.Settings.EnableMod.Value && Plugin.Settings.ShowDebugOverlay.Value && Plugin.Diagnostics != null)
			{
				if (labelStyle == null)
				{
					labelStyle = new GUIStyle(GUI.skin.label)
					{
						fontSize = 14,
						wordWrap = false,
						richText = false,
						alignment = (TextAnchor)0
					};
					labelStyle.normal.textColor = Color.white;
				}
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(18f, 18f, 820f, 420f);
				GUI.Box(val, GUIContent.none);
				GUILayout.BeginArea(new Rect(((Rect)(ref val)).x + 12f, ((Rect)(ref val)).y + 10f, ((Rect)(ref val)).width - 24f, ((Rect)(ref val)).height - 20f));
				GUILayout.Label(Plugin.Diagnostics.BuildOverlayText(), labelStyle, Array.Empty<GUILayoutOption>());
				GUILayout.EndArea();
			}
		}
	}
	internal static class PauseMenuIntegration
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Action <0>__OnLanguageChanged;

			public static BuilderDelegate <1>__BuildPauseMenu;
		}

		private const string RootObjectName = "UI_PEAKUsageSkills_ReleasePanels";

		private const float PanelWidth = 390f;

		private const float HeaderHeight = 56f;

		private const float RowHeight = 32f;

		private static readonly Color MainPanelColor = new Color(0.66f, 0.09f, 0.15f, 1f);

		private static readonly Color ResiliencyPanelColor = new Color(0.08f, 0.3f, 0.68f, 1f);

		private static RectTransform? activeRoot;

		private static readonly SkillId[] MainSkills = new SkillId[10]
		{
			SkillId.Strength,
			SkillId.Endurance,
			SkillId.WallClimbing,
			SkillId.RopeClimbing,
			SkillId.VineClimbing,
			SkillId.Athletics,
			SkillId.Agility,
			SkillId.Vitality,
			SkillId.WetGrip,
			SkillId.ClimbingTenacity
		};

		private static readonly SkillId[] ResiliencySkills = new SkillId[8]
		{
			SkillId.Toxicology,
			SkillId.ColdTolerance,
			SkillId.HeatTolerance,
			SkillId.DrowsyTolerance,
			SkillId.SporeTolerance,
			SkillId.HungerTolerance,
			SkillId.CurseTolerance,
			SkillId.PetrificationResistance
		};

		public static void Register()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			LocalizationService.LanguageChanged += OnLanguageChanged;
			object obj = <>O.<1>__BuildPauseMenu;
			if (obj == null)
			{
				BuilderDelegate val = BuildPauseMenu;
				<>O.<1>__BuildPauseMenu = val;
				obj = (object)val;
			}
			MenuAPI.AddToPauseMenu((BuilderDelegate)obj);
		}

		public static void Unregister()
		{
			LocalizationService.LanguageChanged -= OnLanguageChanged;
			activeRoot = null;
		}

		private static void BuildPauseMenu(Transform parent)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			RemoveLegacyControls(parent);
			Transform val = parent.Find("UI_PEAKUsageSkills_ReleasePanels");
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
			RectTransform component = new GameObject("UI_PEAKUsageSkills_ReleasePanels", new Type[2]
			{
				typeof(RectTransform),
				typeof(SkillPanelRefresher)
			}).GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = Vector2.zero;
			component.offsetMax = Vector2.zero;
			activeRoot = component;
			BuildSection(component, "Main", LocalizationService.Get("section.main"), MainSkills, MainPanelColor, new Vector2(24f, -88f), alignRight: false);
			BuildSection(component, "Resiliency", LocalizationService.Get("section.resiliency"), ResiliencySkills, ResiliencyPanelColor, new Vector2(24f, -88f - SectionHeight(MainSkills.Length) - 18f), alignRight: false);
			SkillTooltip.Create(component);
			Refresh(component);
			Plugin.ModLog.LogInfo((object)"[UsageSkills:UI] release skill panels built; values refresh once when the pause UI opens");
		}

		private static void BuildSection(RectTransform root, string sectionName, string title, SkillId[] skills, Color panelColor, Vector2 offset, bool alignRight)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			PeakMenuButton val = MenuAPI.CreatePauseMenuButton(title);
			((Object)((Component)val).gameObject).name = "UI_PEAKUsageSkills_Section_" + sectionName;
			RectTransform component = ((Component)val).GetComponent<RectTransform>();
			((Transform)component).SetParent((Transform)(object)root, false);
			Vector2 anchorMin = (component.anchorMax = (alignRight ? new Vector2(1f, 1f) : new Vector2(0f, 1f)));
			component.anchorMin = anchorMin;
			component.pivot = (alignRight ? new Vector2(1f, 1f) : new Vector2(0f, 1f));
			component.anchoredPosition = offset;
			component.sizeDelta = new Vector2(390f, SectionHeight(skills.Length));
			LayoutElement component2 = ((Component)val).GetComponent<LayoutElement>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.ignoreLayout = true;
			}
			ConfigurePanelGraphics(val, panelColor);
			Button[] componentsInChildren = ((Component)val).GetComponentsInChildren<Button>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				((Behaviour)componentsInChildren[i]).enabled = false;
			}
			TextMeshProUGUI[] componentsInChildren2 = ((Component)val).GetComponentsInChildren<TextMeshProUGUI>(true);
			foreach (TextMeshProUGUI val3 in componentsInChildren2)
			{
				if (string.Equals(((TMP_Text)val3).text, title, StringComparison.OrdinalIgnoreCase))
				{
					((TMP_Text)val3).rectTransform.anchorMin = new Vector2(0f, 1f);
					((TMP_Text)val3).rectTransform.anchorMax = new Vector2(1f, 1f);
					((TMP_Text)val3).rectTransform.pivot = new Vector2(0.5f, 1f);
					((TMP_Text)val3).rectTransform.anchoredPosition = new Vector2(0f, -8f);
					((TMP_Text)val3).rectTransform.sizeDelta = new Vector2(-20f, 32f);
					((TMP_Text)val3).fontSize = 26f;
					break;
				}
			}
			for (int j = 0; j < skills.Length; j++)
			{
				BuildSkillRow(component, skills[j], j, alignRight);
			}
		}

		private static void BuildSkillRow(RectTransform panel, SkillId skillId, int index, bool openTooltipLeft)
		{
			//IL_0044: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: 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_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("UI_PEAKUsageSkills_" + skillId, new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(SkillHoverTarget)
			});
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent((Transform)(object)panel, false);
			component.anchorMin = new Vector2(0f, 1f);
			component.anchorMax = new Vector2(1f, 1f);
			component.pivot = new Vector2(0.5f, 1f);
			component.anchoredPosition = new Vector2(0f, -56f - (float)index * 32f);
			component.sizeDelta = new Vector2(-24f, 32f);
			((Graphic)val.GetComponent<Image>()).color = new Color(1f, 1f, 1f, 0.001f);
			PeakText obj = MenuAPI.CreateText(string.Empty, "Text");
			((Component)obj).transform.SetParent((Transform)(object)component, false);
			RectTransform component2 = ((Component)obj).GetComponent<RectTransform>();
			obj.SetFontSize(24f);
			Fill(component2, Vector2.zero, Vector2.zero);
			((TMP_Text)obj.TextMesh).alignment = (TextAlignmentOptions)4097;
			((TMP_Text)obj.TextMesh).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)obj.TextMesh).overflowMode = (TextOverflowModes)0;
			((Graphic)obj.TextMesh).raycastTarget = false;
			((TMP_Text)obj.TextMesh).richText = false;
			SkillHoverTarget component3 = val.GetComponent<SkillHoverTarget>();
			component3.Skill = skillId;
			component3.OpenTooltipLeft = openTooltipLeft;
		}

		internal static void Refresh(RectTransform root)
		{
			//IL_009a: 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)
			RefreshSectionTitle(root, "Main", "section.main");
			RefreshSectionTitle(root, "Resiliency", "section.resiliency");
			foreach (SkillId value in Enum.GetValues(typeof(SkillId)))
			{
				Transform? obj = FindDeep((Transform)(object)root, "UI_PEAKUsageSkills_" + value);
				object obj2;
				if (obj == null)
				{
					obj2 = null;
				}
				else
				{
					Transform obj3 = obj.Find("Text");
					obj2 = ((obj3 != null) ? ((Component)obj3).GetComponent<PeakText>() : null);
				}
				PeakText val = (PeakText)obj2;
				if ((Object)(object)val != (Object)null)
				{
					val.SetText(GetSkillText(value));
					Fill(((Component)val).GetComponent<RectTransform>(), Vector2.zero, Vector2.zero);
				}
			}
		}

		private static void RefreshSectionTitle(RectTransform root, string sectionName, string localizationKey)
		{
			Transform? obj = FindDeep((Transform)(object)root, "UI_PEAKUsageSkills_Section_" + sectionName);
			PeakMenuButton obj2 = ((obj != null) ? ((Component)obj).GetComponent<PeakMenuButton>() : null);
			if (obj2 != null)
			{
				obj2.SetText(LocalizationService.Get(localizationKey));
			}
		}

		private static void OnLanguageChanged()
		{
			SkillTooltip.Hide();
			if ((Object)(object)activeRoot != (Object)null)
			{
				Refresh(activeRoot);
			}
		}

		internal static string GetTooltipText(SkillId skillId)
		{
			int level = Plugin.Progression.GetLevel(skillId);
			switch (skillId)
			{
			case SkillId.Strength:
			{
				float value = (1f - SkillMath.AnchoredReductionMultiplier(level, Plugin.Settings.StrengthReductionPerLevel.Value)) * 100f;
				return LocalizationService.Get("tooltip.strength", LocalizationService.FormatNumber(value, 1), InventorySkillService.ExtraBackpackSlots);
			}
			case SkillId.Endurance:
				return LocalizationService.Get("tooltip.endurance", LocalizationService.FormatNumber((float)level * 0.5f, 1), LocalizationService.FormatNumber((float)level * 0.1f, 1));
			case SkillId.WallClimbing:
				return ClimbingTooltip(LocalizationService.Get("term.wall"), level, Plugin.Settings.WallSpeedPerLevel.Value, Plugin.Settings.WallCostReductionPerLevel.Value);
			case SkillId.RopeClimbing:
				return ClimbingTooltip(LocalizationService.Get("term.rope"), level, Plugin.Settings.RopeSpeedPerLevel.Value, Plugin.Settings.RopeCostEfficiencyPerLevel.Value);
			case SkillId.VineClimbing:
			{
				float value = (1f - SkillMath.AnchoredReductionMultiplier(level, Plugin.Settings.VineCostEfficiencyPerLevel.Value)) * 100f;
				return LocalizationService.Get("tooltip.vine", LocalizationService.FormatNumber((float)level * 0.3f, 1), LocalizationService.FormatNumber(value, 1));
			}
			case SkillId.Athletics:
			{
				float value = (1f - SkillMath.AnchoredReductionMultiplier(level, Plugin.Settings.AthleticsSprintEfficiencyPerLevel.Value)) * 100f;
				return LocalizationService.Get("tooltip.athletics", LocalizationService.FormatNumber(value, 1));
			}
			case SkillId.Agility:
			{
				float value = (1f - SkillMath.AnchoredReductionMultiplier(level, Plugin.Settings.AgilityJumpEfficiencyPerLevel.Value)) * 100f;
				return LocalizationService.Get("tooltip.agility", LocalizationService.FormatNumber((float)level * 0.15f, 1), LocalizationService.FormatNumber(value, 1));
			}
			case SkillId.Vitality:
				return ReductionTooltip(LocalizationService.Get("term.fall_injury"), level, Plugin.Settings.VitalityFallReductionPerLevel.Value);
			case SkillId.WetGrip:
				return ReductionTooltip(LocalizationService.Get("term.wet_grip_penalty"), level, Plugin.Settings.WetGripReductionPerLevel.Value);
			case SkillId.ClimbingTenacity:
				return ReductionTooltip(LocalizationService.Get("term.tenacity_penalty"), level, Plugin.Settings.ClimbingTenacityReductionPerLevel.Value);
			case SkillId.Toxicology:
			case SkillId.ColdTolerance:
			case SkillId.HeatTolerance:
			case SkillId.DrowsyTolerance:
			case SkillId.SporeTolerance:
				return ToleranceTooltip(LocalizationService.SkillName(skillId), level, hasNaturalRecovery: true);
			case SkillId.HungerTolerance:
			case SkillId.CurseTolerance:
				return ToleranceTooltip(LocalizationService.SkillName(skillId), level, hasNaturalRecovery: false);
			case SkillId.PetrificationResistance:
				return ToleranceTooltip(LocalizationService.SkillName(skillId), level, hasNaturalRecovery: false);
			default:
				return LocalizationService.SkillName(skillId);
			}
		}

		private static string ClimbingTooltip(string kind, int level, float speedRate, float costRate)
		{
			float value = (1f - SkillMath.AnchoredReductionMultiplier(level, costRate)) * 100f;
			return LocalizationService.Get("tooltip.climbing", kind, LocalizationService.FormatNumber(speedRate * 100f, 1), LocalizationService.FormatNumber((float)level * speedRate * 100f, 1), LocalizationService.FormatNumber(value, 1));
		}

		private static string ReductionTooltip(string effect, int level, float rate)
		{
			float value = (1f - SkillMath.AnchoredReductionMultiplier(level, rate)) * 100f;
			return LocalizationService.Get("tooltip.reduction", effect, LocalizationService.FormatNumber(rate * 100f, 2), LocalizationService.FormatNumber(value, 1));
		}

		private static string ToleranceTooltip(string condition, int level, bool hasNaturalRecovery)
		{
			float value = (1f - SkillMath.AnchoredReductionMultiplier(level, Plugin.Settings.ConditionResistancePerLevel.Value)) * 100f;
			string text = (hasNaturalRecovery ? LocalizationService.Get("tooltip.natural_recovery", LocalizationService.FormatNumber((float)level * Plugin.Settings.ConditionRecoveryPerLevel.Value * 100f, 1)) : "");
			return LocalizationService.Get("tooltip.tolerance", condition, LocalizationService.FormatNumber(value, 1), text);
		}

		private static string GetSkillText(SkillId skillId)
		{
			int level = Plugin.Progression.GetLevel(skillId);
			int num = ((level < Plugin.Progression.MaximumLevel) ? SkillMath.ExperienceProgressPercent(Plugin.Progression.GetExperience(skillId), Plugin.Progression.GetExperienceToNextLevel(skillId)) : 0);
			return string.Format("{0} {1} {2:00}.{3:00}", LocalizationService.SkillName(skillId), LocalizationService.Get("level.abbreviation"), level, num);
		}

		private static float SectionHeight(int rowCount)
		{
			return 56f + (float)rowCount * 32f + 16f;
		}

		private static void ConfigurePanelGraphics(PeakMenuButton panel, Color color)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			panel.SetColor(color, true);
			Stretch(((Graphic)panel.Panel).rectTransform);
			((Graphic)panel.Panel).raycastTarget = false;
			((Transform)((Graphic)panel.Panel).rectTransform).SetAsFirstSibling();
			ConfigureBorder(((Graphic)panel.BorderTop).rectTransform, top: true);
			ConfigureBorder(((Graphic)panel.BorderBottom).rectTransform, top: false);
			((Graphic)panel.BorderTop).raycastTarget = false;
			((Graphic)panel.BorderBottom).raycastTarget = false;
		}

		private static void Stretch(RectTransform rect)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = Vector2.zero;
			rect.anchorMax = Vector2.one;
			rect.pivot = new Vector2(0.5f, 0.5f);
			rect.anchoredPosition = Vector2.zero;
			rect.sizeDelta = Vector2.zero;
		}

		private static void Fill(RectTransform rect, Vector2 minimumInset, Vector2 maximumInset)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = Vector2.zero;
			rect.anchorMax = Vector2.one;
			rect.pivot = new Vector2(0.5f, 0.5f);
			rect.offsetMin = minimumInset;
			rect.offsetMax = maximumInset;
		}

		private static void ConfigureBorder(RectTransform border, bool top)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = border.rect;
			float num = Mathf.Max(3f, ((Rect)(ref rect)).height);
			border.anchorMin = new Vector2(0f, top ? 1f : 0f);
			border.anchorMax = new Vector2(1f, top ? 1f : 0f);
			border.pivot = new Vector2(0.5f, top ? 1f : 0f);
			border.anchoredPosition = Vector2.zero;
			border.sizeDelta = new Vector2(0f, num);
		}

		internal static string WrapTooltipText(string message, int maximumLineLength = 58)
		{
			if (ContainsCjk(message))
			{
				int num = Math.Max(32, maximumLineLength - 14);
				StringBuilder stringBuilder = new StringBuilder(message.Length + 8);
				int num2 = 0;
				foreach (char c in message)
				{
					if (c == '\n')
					{
						stringBuilder.Append(c);
						num2 = 0;
						continue;
					}
					int num3 = ((!IsCjk(c)) ? 1 : 2);
					if (num2 > 0 && num2 + num3 > num)
					{
						stringBuilder.Append('\n');
						num2 = 0;
						if (char.IsWhiteSpace(c))
						{
							continue;
						}
					}
					stringBuilder.Append(c);
					num2 += num3;
				}
				return stringBuilder.ToString();
			}
			string[] array = message.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
			StringBuilder stringBuilder2 = new StringBuilder(message.Length + 8);
			int num4 = 0;
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (num4 > 0 && num4 + 1 + text.Length > maximumLineLength)
				{
					stringBuilder2.Append('\n');
					num4 = 0;
				}
				if (num4 > 0)
				{
					stringBuilder2.Append(' ');
					num4++;
				}
				stringBuilder2.Append(text);
				num4 += text.Length;
			}
			return stringBuilder2.ToString();
		}

		private static bool ContainsCjk(string value)
		{
			for (int i = 0; i < value.Length; i++)
			{
				if (IsCjk(value[i]))
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsCjk(char character)
		{
			if ((character < '\u3040' || character > 'ヿ') && (character < '㐀' || character > '鿿'))
			{
				if (character >= '가')
				{
					return character <= '\ud7af';
				}
				return false;
			}
			return true;
		}

		private static void RemoveLegacyControls(Transform parent)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			string[] array = new string[3] { "UI_MainMenuButton_PEAKUsageSkills", "UI_MainMenuButton_PEAKUsageSkillsTestLevel", "UI_MainMenuButton_PEAKUsageSkillsReset" };
			foreach (string text in array)
			{
				Transform val = parent.Find(text);
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)val).gameObject);
				}
			}
			List<GameObject> list = new List<GameObject>();
			foreach (Transform item in parent)
			{
				Transform val2 = item;
				if (((Object)val2).name.StartsWith("UI_MainMenuButton_PEAKUsageSkillsStatus_", StringComparison.Ordinal))
				{
					list.Add(((Component)val2).gameObject);
				}
			}
			foreach (GameObject item2 in list)
			{
				Object.Destroy((Object)(object)item2);
			}
		}

		private static Transform? FindDeep(Transform root, string objectName)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			foreach (Transform item in root)
			{
				Transform val = item;
				if (((Object)val).name == objectName)
				{
					return val;
				}
				Transform val2 = FindDeep(val, objectName);
				if ((Object)(object)val2 != (Object)null)
				{
					return val2;
				}
			}
			return null;
		}
	}
	internal sealed class SkillPanelRefresher : MonoBehaviour
	{
		private void OnEnable()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			PauseMenuIntegration.Refresh((RectTransform)((Component)this).transform);
		}
	}
	internal sealed class SkillHoverTarget : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler
	{
		public SkillId Skill { get; set; }

		public bool OpenTooltipLeft { get; set; }

		public void OnPointerEnter(PointerEventData eventData)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			SkillTooltip.Show((RectTransform)((Component)this).transform, PauseMenuIntegration.GetTooltipText(Skill), OpenTooltipLeft);
		}

		public void OnPointerExit(PointerEventData eventData)
		{
			SkillTooltip.Hide();
		}
	}
	internal sealed class SkillTooltip : MonoBehaviour
	{
		private static SkillTooltip? instance;

		private RectTransform rect;

		private PeakText text;

		public static void Create(RectTransform parent)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: 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_0155: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("UI_PEAKUsageSkills_Tooltip", new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(SkillTooltip)
			});
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent((Transform)(object)parent, false);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			component.anchorMax = val2;
			component.anchorMin = val2;
			component.pivot = new Vector2(0f, 0.5f);
			component.sizeDelta = new Vector2(500f, 124f);
			((Graphic)val.GetComponent<Image>()).color = new Color(0.035f, 0.035f, 0.04f, 0.94f);
			PeakText val3 = MenuAPI.CreateText(string.Empty, "Text");
			((Component)val3).transform.SetParent((Transform)(object)component, false);
			RectTransform component2 = ((Component)val3).GetComponent<RectTransform>();
			val3.SetFontSize(21f);
			component2.anchorMin = Vector2.zero;
			component2.anchorMax = Vector2.one;
			component2.offsetMin = new Vector2(12f, 8f);
			component2.offsetMax = new Vector2(-12f, -8f);
			((TMP_Text)val3.TextMesh).alignment = (TextAlignmentOptions)4097;
			((TMP_Text)val3.TextMesh).textWrappingMode = (TextWrappingModes)1;
			((TMP_Text)val3.TextMesh).overflowMode = (TextOverflowModes)3;
			((Graphic)val3.TextMesh).raycastTarget = false;
			SkillTooltip component3 = val.GetComponent<SkillTooltip>();
			component3.rect = component;
			component3.text = val3;
			instance = component3;
			val.SetActive(false);
		}

		public static void Show(RectTransform target, string message, bool openLeft)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)instance == (Object)null))
			{
				((Component)instance).gameObject.SetActive(true);
				instance.text.SetText(PauseMenuIntegration.WrapTooltipText(message));
				RectTransform component = ((Component)instance.text).GetComponent<RectTransform>();
				component.anchorMin = Vector2.zero;
				component.anchorMax = Vector2.one;
				component.offsetMin = new Vector2(12f, 8f);
				component.offsetMax = new Vector2(-12f, -8f);
				Vector3[] array = (Vector3[])(object)new Vector3[4];
				target.GetWorldCorners(array);
				instance.rect.pivot = new Vector2(openLeft ? 1f : 0f, 0.5f);
				((Transform)instance.rect).position = (openLeft ? array[1] : array[2]) + Vector3.right * (openLeft ? (-16f) : 16f);
				((Transform)instance.rect).SetAsLastSibling();
			}
		}

		public static void Hide()
		{
			if ((Object)(object)instance != (Object)null)
			{
				((Component)instance).gameObject.SetActive(false);
			}
		}
	}
}
namespace PEAKUsageSkills.Tracking
{
	internal sealed class ActivitySampler : MonoBehaviour
	{
		private const float SampleInterval = 0.2f;

		private Character? sampledCharacter;

		private Vector3 lastPosition;

		private float lastSampleTime;

		private bool hasPosition;

		private void Update()
		{
			//IL_0043: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_045f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0465: Unknown result type (might be due to invalid IL or missing references)
			//IL_046b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0470: Unknown result type (might be due to invalid IL or missing references)
			if (Time.unscaledTime - lastSampleTime < 0.2f)
			{
				return;
			}
			lastSampleTime = Time.unscaledTime;
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter == (Object)null || !Plugin.RunState.IsGameplayScene)
			{
				ResetSample(localCharacter);
				return;
			}
			Vector3 center = localCharacter.Center;
			if ((Object)(object)sampledCharacter != (Object)(object)localCharacter || !hasPosition)
			{
				sampledCharacter = localCharacter;
				lastPosition = center;
				hasPosition = true;
				return;
			}
			Vector3 val = center - lastPosition;
			lastPosition = center;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (Plugin.Diagnostics != null)
			{
				Plugin.Diagnostics.Metrics.LastPhysicalMovementDistance = magnitude;
			}
			if (magnitude > 5f)
			{
				Plugin.Diagnostics?.RecordRejected(SkillId.Strength, "TeleportDelta", magnitude);
				Plugin.Diagnostics?.RecordRejected(SkillId.WallClimbing, "TeleportDelta", magnitude);
				Plugin.Diagnostics?.RecordRejected(SkillId.RopeClimbing, "TeleportDelta", magnitude);
				Plugin.Diagnostics?.RecordRejected(SkillId.VineClimbing, "TeleportDelta", magnitude);
				Plugin.Diagnostics?.RecordRejected(SkillId.Athletics, "TeleportDelta", magnitude);
				Plugin.Diagnostics?.RecordRejected(SkillId.WetGrip, "TeleportDelta", magnitude);
				Plugin.Diagnostics?.RecordRejected(SkillId.ClimbingTenacity, "TeleportDelta", magnitude);
				Plugin.Diagnostics?.RecordRejected(SkillId.HungerTolerance, "TeleportDelta", magnitude);
				return;
			}
			if (magnitude >= 0.01f)
			{
				float num = Plugin.Diagnostics?.Metrics.RawWeight ?? 0f;
				if (num >= 0.025f)
				{
					double work = num * magnitude;
					Plugin.Progression.AwardWork(SkillId.Strength, work, Plugin.Settings.StrengthXpPerWork.Value, localCharacter.data.isClimbingAnything ? "WeightedClimbing" : "WeightedMovement");
				}
				CharacterRefs refs = localCharacter.refs;
				float? obj;
				if (refs == null)
				{
					obj = null;
				}
				else
				{
					CharacterAfflictions afflictions = refs.afflictions;
					obj = ((afflictions != null) ? new float?(afflictions.GetCurrentStatus((STATUSTYPE)1)) : ((float?)null));
				}
				float? num2 = obj;
				double num3 = SkillMath.HungerMovementWork(num2.GetValueOrDefault(), magnitude, Plugin.Settings.HungerTrainingThreshold.Value);
				if (num3 > 0.0)
				{
					Plugin.Progression.AwardWork(SkillId.HungerTolerance, num3, Plugin.Settings.HungerMovementXpPerWork.Value, "HungryMovement");
				}
			}
			bool num4 = localCharacter.data.isClimbing && !localCharacter.data.isRopeClimbing && !localCharacter.data.isVineClimbing;
			bool flag = (Object)(object)localCharacter.input != (Object)null && ((Vector2)(ref localCharacter.input.movementInput)).sqrMagnitude >= 0.01f;
			float num5 = ((num4 && flag) ? magnitude : 0f);
			float num6 = ((localCharacter.data.isRopeClimbing && flag) ? magnitude : 0f);
			float num7 = ((localCharacter.data.isVineClimbing && flag) ? magnitude : 0f);
			if (Plugin.Diagnostics != null)
			{
				Plugin.Diagnostics.Metrics.LastWallVerticalDelta = num5;
				Plugin.Diagnostics.Metrics.LastRopeVerticalDelta = num6;
				Plugin.Diagnostics.Metrics.LastVineVerticalDelta = num7;
			}
			if (num5 >= 0.005f)
			{
				if (Plugin.Diagnostics != null)
				{
					Plugin.Diagnostics.Metrics.SessionWallVerticalDistance += num5;
				}
				Plugin.Progression.AwardWork(SkillId.WallClimbing, num5, Plugin.Settings.WallClimbingXpPerMeter.Value, "IntentionalWallDistance");
				float num8 = Mathf.Clamp01(localCharacter.data.slippy);
				if (num8 > 0.001f)
				{
					Plugin.Progression.AwardWork(SkillId.WetGrip, num5 * num8, Plugin.Settings.WetGripXpPerMeter.Value, "SlipperyWallDistance");
				}
				if (localCharacter.GetTotalStamina() < 0.2f)
				{
					Plugin.Progression.AwardWork(SkillId.ClimbingTenacity, num5, Plugin.Settings.ClimbingTenacityXpPerMeter.Value, "LowStaminaWallDistance");
				}
			}
			if (num6 >= 0.005f)
			{
				Plugin.Progression.AwardWork(SkillId.RopeClimbing, num6, Plugin.Settings.RopeClimbingXpPerMeter.Value, "IntentionalRopeDistance");
			}
			if (num7 >= 0.005f)
			{
				Plugin.Progression.AwardWork(SkillId.VineClimbing, num7, Plugin.Settings.VineClimbingXpPerMeter.Value, "IntentionalVineDistance");
			}
			Vector2 val2 = new Vector2(val.x, val.z);
			float magnitude2 = ((Vector2)(ref val2)).magnitude;
			if (localCharacter.data.isGrounded && !localCharacter.data.isClimbingAnything && (Object)(object)localCharacter.input != (Object)null && ((Vector2)(ref localCharacter.input.movementInput)).sqrMagnitude >= 0.01f && magnitude2 >= 0.01f)
			{
				Plugin.Progression.AwardWork(SkillId.Athletics, magnitude2, localCharacter.data.isSprinting ? Plugin.Settings.AthleticsSprintXpPerMeter.Value : Plugin.Settings.AthleticsXpPerMeter.Value, localCharacter.data.isSprinting ? "GroundSprinting" : "GroundMovement");
			}
		}

		private void ResetSample(Character? character)
		{
			sampledCharacter = character;
			hasPosition = false;
			if (Plugin.Diagnostics != null)
			{
				Plugin.Diagnostics.Metrics.LastWallVerticalDelta = 0f;
				Plugin.Diagnostics.Metrics.LastRopeVerticalDelta = 0f;
				Plugin.Diagnostics.Metrics.LastVineVerticalDelta = 0f;
			}
		}
	}
}
namespace PEAKUsageSkills.Persistence
{
	internal sealed class ProgressionSave
	{
		public int SchemaVersion { get; set; } = 1;

		public DateTime LastSavedUtc { get; set; } = DateTime.UtcNow;

		public Dictionary<string, SkillSave> Skills { get; set; } = new Dictionary<string, SkillSave>(StringComparer.Ordinal);
	}
	internal sealed class SkillSave
	{
		public int Level { get; set; } = 1;

		public double Experience { get; set; }

		public double LifetimeWork { get; set; }
	}
	internal sealed class SaveStore
	{
		private const int MaximumBackups = 5;

		private readonly ManualLogSource log;

		private readonly string saveDirectory;

		private readonly string savePath;

		private readonly string backupDirectory;

		public SaveStore(ManualLogSource log)
		{
			this.log = log;
			saveDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "LandCrab", "PEAK", "PEAKUsageSkills");
			savePath = Path.Combine(saveDirectory, "progression.json");
			backupDirectory = Path.Combine(saveDirectory, "backups");
		}

		public ProgressionSave Load()
		{
			Directory.CreateDirectory(saveDirectory);
			Directory.CreateDirectory(backupDirectory);
			if (TryLoad(savePath, out ProgressionSave save))
			{
				log.LogInfo((object)("Loaded usage-skill progression from " + savePath));
				return save;
			}
			foreach (string item in GetBackupsNewestFirst())
			{
				if (TryLoad(item, out save))
				{
					log.LogWarning((object)("Recovered usage-skill progression from backup " + item));
					return save;
				}
			}
			log.LogInfo((object)"No valid usage-skill save found; starting new progression.");
			return new ProgressionSave();
		}

		public void Save(ProgressionSave save)
		{
			Directory.CreateDirectory(saveDirectory);
			Directory.CreateDirectory(backupDirectory);
			save.LastSavedUtc = DateTime.UtcNow;
			string text = savePath + ".tmp";
			string contents = JsonConvert.SerializeObject((object)save, (Formatting)1);
			File.WriteAllText(text, contents);
			if (File.Exists(savePath))
			{
				string destinationBackupFileName = Path.Combine(backupDirectory, $"progression-{DateTime.UtcNow:yyyyMMdd-HHmmss-fff}.json");
				File.Replace(text, savePath, destinationBackupFileName, ignoreMetadataErrors: true);
			}
			else
			{
				File.Move(text, savePath);
			}
			CleanupBackups();
		}

		private bool TryLoad(string path, out ProgressionSave? save)
		{
			save = null;
			if (!File.Exists(path))
			{
				return false;
			}
			try
			{
				save = JsonConvert.DeserializeObject<ProgressionSave>(File.ReadAllText(path));
				return save != null && save.SchemaVersion == 1 && save.Skills != null;
			}
			catch (Exception ex)
			{
				log.LogWarning((object)("Could not load progression file " + path + ": " + ex.Message));
				return false;
			}
		}

		private IEnumerable<string> GetBackupsNewestFirst()
		{
			if (!Directory.Exists(backupDirectory))
			{
				return Array.Empty<string>();
			}
			return Directory.GetFiles(backupDirectory, "progression-*.json").OrderByDescending(File.GetLastWriteTimeUtc);
		}

		private void CleanupBackups()
		{
			string[] array = GetBackupsNewestFirst().ToArray();
			for (int i = 5; i < array.Length; i++)
			{
				try
				{
					File.Delete(array[i]);
				}
				catch (Exception ex)
				{
					log.LogWarning((object)("Could not remove old progression backup " + array[i] + ": " + ex.Message));
				}
			}
		}
	}
}
namespace PEAKUsageSkills.Localization
{
	internal static class LocalizationService
	{
		private sealed class LocaleDefinition
		{
			public string FileName { get; }

			public Language[] Languages { get; }

			public LocaleDefinition(string fileName, params Language[] languages)
			{
				FileName = fileName;
				Languages = languages;
			}
		}

		private const string TranslationIndexPrefix = "ELINS_PEAK_";

		private static readonly Dictionary<string, string> English = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ "section.main", "MAIN SKILLS" },
			{ "section.resiliency", "RESILIENCY" },
			{ "level.abbreviation", "Lv." },
			{ "skill.strength", "Strength" },
			{ "skill.endurance", "Endurance" },
			{ "skill.wall_climbing", "Wall Climbing" },
			{ "skill.rope_climbing", "Rope Climbing" },
			{ "skill.vine_climbing", "Vine Climbing" },
			{ "skill.athletics", "Athletics" },
			{ "skill.agility", "Agility" },
			{ "skill.vitality", "Vitality" },
			{ "skill.wet_grip", "Wet Grip" },
			{ "skill.climbing_tenacity", "Climbing Tenacity" },
			{ "skill.poison", "Poison" },
			{ "skill.cold", "Cold" },
			{ "skill.heat", "Heat" },
			{ "skill.drowsy", "Drowsy" },
			{ "skill.spores", "Spores" },
			{ "skill.hunger", "Hunger" },
			{ "skill.curse", "Curse" },
			{ "skill.petrification", "Petrification" },
			{ "term.wall", "wall" },
			{ "term.rope", "rope" },
			{ "term.vine", "vine" },
			{ "term.fall_injury", "fall Injury" },
			{ "term.wet_grip_penalty", "rain/slippery climbing pull and wind stamina drain" },
			{ "term.tenacity_penalty", "climbing control, slide, and stamina penalties below 20% stamina" },
			{ "tooltip.strength", "Reduces carried Weight and adds item slots to Backpacks, Fanny Packs, and Jet Packs at levels 20/40/70/120/200. Current: {0}% less Weight, +{1} slots." },
			{ "tooltip.endurance", "Adds 0.5% base stamina and 0.1% regeneration per level. Current: +{0} stamina, +{1}% regeneration." },
			{ "tooltip.vine", "Improves vine speed by 0.3% per level, reduces stamina cost, and retains light slide momentum. Current: +{0}% speed, {1}% less cost." },
			{ "tooltip.athletics", "Improves ground force by 0.1% and sprint force by another 0.2% per level. Current sprint cost reduction: {0}%." },
			{ "tooltip.agility", "Improves jump impulse and very lightly improves air control. Current: +{0}% jump impulse, {1}% less jump cost." },
			{ "tooltip.climbing", "Improves {0} climbing speed by {1}% per level and reduces stamina cost. Current: +{2}% speed, {3}% less cost." },
			{ "tooltip.reduction", "Reduces {0} using the {1}% anchored curve. Current bonus: {2}% reduction." },
			{ "tooltip.tolerance", "Reduces incoming {0}. Current reduction: {1}%.{2} XP comes only from receiving the affliction." },
			{ "tooltip.natural_recovery", " Natural recovery: +{0}%." }
		};

		private static readonly Dictionary<SkillId, string> SkillKeys = new Dictionary<SkillId, string>
		{
			{
				SkillId.Strength,
				"skill.strength"
			},
			{
				SkillId.Endurance,
				"skill.endurance"
			},
			{
				SkillId.WallClimbing,
				"skill.wall_climbing"
			},
			{
				SkillId.RopeClimbing,
				"skill.rope_climbing"
			},
			{
				SkillId.VineClimbing,
				"skill.vine_climbing"
			},
			{
				SkillId.Athletics,
				"skill.athletics"
			},
			{
				SkillId.Agility,
				"skill.agility"
			},
			{
				SkillId.Vitality,
				"skill.vitality"
			},
			{
				SkillId.WetGrip,
				"skill.wet_grip"
			},
			{
				SkillId.ClimbingTenacity,
				"skill.climbing_tenacity"
			},
			{
				SkillId.Toxicology,
				"skill.poison"
			},
			{
				SkillId.ColdTolerance,
				"skill.cold"
			},
			{
				SkillId.HeatTolerance,
				"skill.heat"
			},
			{
				SkillId.DrowsyTolerance,
				"skill.drowsy"
			},
			{
				SkillId.SporeTolerance,
				"skill.spores"
			},
			{
				SkillId.HungerTolerance,
				"skill.hunger"
			},
			{
				SkillId.CurseTolerance,
				"skill.curse"
			},
			{
				SkillId.PetrificationResistance,
				"skill.petrification"
			}
		};

		private static readonly LocaleDefinition[] Locales = new LocaleDefinition[6]
		{
			new LocaleDefinition("fr.json", (Language)1),
			new LocaleDefinition("de.json", (Language)3),
			new LocaleDefinition("es.json", (Language)4, (Language)5),
			new LocaleDefinition("zh-CN.json", (Language)9),
			new LocaleDefinition("ja.json", (Language)11),
			new LocaleDefinition("ko.json", (Language)12)
		};

		private static bool initialized;

		private static bool nativeRegistrationAvailable;

		public static string Locale => GetLocaleCode(LocalizedText.CURRENT_LANGUAGE);

		public static event Action? LanguageChanged;

		public static void Initialize(string pluginDirectory)
		{
			if (initialized)
			{
				Shutdown();
			}
			try
			{
				RegisterEnglish();
				string localizationDirectory = Path.Combine(pluginDirectory, "Localization");
				LocaleDefinition[] locales = Locales;
				foreach (LocaleDefinition locale in locales)
				{
					LoadAndRegister(localizationDirectory, locale);
				}
				LocalizedText.OnLangugageChanged = (Action)Delegate.Combine(LocalizedText.OnLangugageChanged, new Action(OnGameLanguageChanged));
				nativeRegistrationAvailable = true;
				initialized = true;
				Plugin.ModLog.LogInfo((object)$"[UsageSkills:Localization] registered={English.Count} locale={Locale} source=PEAK selector");
			}
			catch (Exception ex)
			{
				nativeRegistrationAvailable = false;
				initialized = false;
				Plugin.ModLog.LogWarning((object)("[UsageSkills:Localization] PEAK localization registration failed; using English. " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		public static void Shutdown()
		{
			if (initialized)
			{
				LocalizedText.OnLangugageChanged = (Action)Delegate.Remove(LocalizedText.OnLangugageChanged, new Action(OnGameLanguageChanged));
				LocalizationService.LanguageChanged = null;
				nativeRegistrationAvailable = false;
				initialized = false;
			}
		}

		public static string Get(string key, params object[] args)
		{
			string value = "";
			if (nativeRegistrationAvailable)
			{
				try
				{
					value = LocalizedText.GetText(GetTranslationIndex(key), false);
				}
				catch (Exception ex)
				{
					Plugin.ModLog.LogWarning((object)("[UsageSkills:Localization] lookup failed key=" + key + "; using English. " + ex.GetType().Name + ": " + ex.Message));
				}
			}
			if (string.IsNullOrEmpty(value) && !English.TryGetValue(key, out value))
			{
				value = key;
			}
			if (args == null || args.Length == 0)
			{
				return value;
			}
			try
			{
				return string.Format(GetFormattingCulture(), value, args);
			}
			catch (FormatException ex2)
			{
				Plugin.ModLog.LogWarning((object)("[UsageSkills:Localization] invalid format key=" + key + " locale=" + Locale + "; using English. " + ex2.Message));
				string value2;
				return English.TryGetValue(key, out value2) ? string.Format(GetFormattingCulture(), value2, args) : value;
			}
		}

		public static string FormatNumber(float value, int decimalPlaces)
		{
			return value.ToString("F" + decimalPlaces, GetFormattingCulture());
		}

		public static string SkillName(SkillId skillId)
		{
			if (!SkillKeys.TryGetValue(skillId, out string value))
			{
				return skillId.ToString();
			}
			return Get(value);
		}

		private static void RegisterEnglish()
		{
			foreach (KeyValuePair<string, string> item in English)
			{
				MenuAPI.CreateLocalization(GetTranslationIndex(item.Key)).AddLocalization(item.Value, (Language)0);
			}
		}

		private static void LoadAndRegister(string localizationDirectory, LocaleDefinition locale)
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			string path = Path.Combine(localizationDirectory, locale.FileName);
			try
			{
				if (!File.Exists(path))
				{
					Plugin.ModLog.LogWarning((object)("[UsageSkills:Localization] missing=" + locale.FileName + "; affected languages use English"));
					return;
				}
				Dictionary<string, string> dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(path));
				if (dictionary == null || dictionary.Count == 0)
				{
					Plugin.ModLog.LogWarning((object)("[UsageSkills:Localization] empty=" + locale.FileName + "; affected languages use English"));
					return;
				}
				int num = 0;
				int num2 = 0;
				foreach (string key in English.Keys)
				{
					if (!dictionary.TryGetValue(key, out var value) || string.IsNullOrWhiteSpace(value))
					{
						num2++;
						continue;
					}
					Language[] languages = locale.Languages;
					foreach (Language val in languages)
					{
						MenuAPI.CreateLocalization(GetTranslationIndex(key)).AddLocalization(value, val);
					}
					num++;
				}
				Plugin.ModLog.LogInfo((object)$"[UsageSkills:Localization] file={locale.FileName} registered={num} missing={num2}");
			}
			catch (Exception ex)
			{
				Plugin.ModLog.LogWarning((object)("[UsageSkills:Localization] failed=" + locale.FileName + "; affected languages use English. " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private static void OnGameLanguageChanged()
		{
			Plugin.ModLog.LogInfo((object)("[UsageSkills:Localization] changed locale=" + Locale));
			try
			{
				LocalizationService.LanguageChanged?.Invoke();
			}
			catch (Exception ex)
			{
				Plugin.ModLog.LogWarning((object)("[UsageSkills:Localization] UI refresh failed after language change. " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private static string GetTranslationIndex(string key)
		{
			return "ELINS_PEAK_" + key.Replace('.', '_').ToUpperInvariant();
		}

		private static CultureInfo GetFormattingCulture()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected I4, but got Unknown
			Language cURRENT_LANGUAGE = LocalizedText.CURRENT_LANGUAGE;
			return (cURRENT_LANGUAGE - 1) switch
			{
				0 => CultureInfo.GetCultureInfo("fr-FR"), 
				2 => CultureInfo.GetCultureInfo("de-DE"), 
				4 => CultureInfo.GetCultureInfo("es-MX"), 
				3 => CultureInfo.GetCultureInfo("es-ES"), 
				8 => CultureInfo.GetCultureInfo("zh-CN"), 
				10 => CultureInfo.GetCultureInfo("ja-JP"), 
				11 => CultureInfo.GetCultureInfo("ko-KR"), 
				_ => CultureInfo.GetCultureInfo("en-US"), 
			};
		}

		private static string GetLocaleCode(Language language)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected I4, but got Unknown
			return (language - 1) switch
			{
				0 => "fr", 
				1 => "it", 
				2 => "de", 
				3 => "es-ES", 
				4 => "es-419", 
				5 => "pt-BR", 
				6 => "ru", 
				7 => "uk", 
				8 => "zh-CN", 
				9 => "zh-TW", 
				10 => "ja", 
				11 => "ko", 
				12 => "pl", 
				13 => "tr", 
				_ => "en", 
			};
		}
	}
}
namespace PEAKUsageSkills.GameAdapters
{
	internal static class ConditionSkillAdapter
	{
		public static bool TryGetToleranceSkill(STATUSTYPE statusType, out SkillId skillId)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected I4, but got Unknown
			switch (statusType - 1)
			{
			case 2:
				skillId = SkillId.Toxicology;
				return true;
			case 1:
				skillId = SkillId.ColdTolerance;
				return true;
			case 7:
				skillId = SkillId.HeatTolerance;
				return true;
			case 5:
				skillId = SkillId.DrowsyTolerance;
				return true;
			case 9:
				skillId = SkillId.SporeTolerance;
				return true;
			case 0:
				skillId = SkillId.HungerTolerance;
				return true;
			case 4:
				skillId = SkillId.CurseTolerance;
				return true;
			case 12:
				skillId = SkillId.PetrificationResistance;
				return true;
			default:
				skillId = SkillId.Strength;
				return false;
			}
		}

		public static bool TryGetRecoveryTolerance(STATUSTYPE statusType, out SkillId skillId)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected I4, but got Unknown
			switch (statusType - 2)
			{
			case 1:
				skillId = SkillId.Toxicology;
				return true;
			case 0:
				skillId = SkillId.ColdTolerance;
				return true;
			case 6:
				skillId = SkillId.HeatTolerance;
				return true;
			case 4:
				skillId = SkillId.DrowsyTolerance;
				return true;
			case 8:
				skillId = SkillId.SporeTolerance;
				return true;
			default:
				skillId = SkillId.Strength;
				return false;
			}
		}
	}
	internal static class InventorySkillService
	{
		private static Character? cachedBackpackCharacter;

		private static ItemInstanceData? cachedBackpackInstance;

		private static BackpackData? cachedBackpackData;

		public static int ExtraBackpackSlots => SkillMath.ExtraBackpackSlots(Plugin.Progression.GetLevel(SkillId.Strength));

		public static bool IsItemStorage(BackpackType backpackType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			if ((int)backpackType != 1 && (int)backpackType != 2)
			{
				return (int)backpackType == 3;
			}
			return true;
		}

		public static int BaseItemSlots(BackpackType backpackType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected I4, but got Unknown
			return (backpackType - 1) switch
			{
				0 => 4, 
				1 => 2, 
				2 => 1, 
				_ => 0, 
			};
		}

		public static int DesiredItemCapacity(BackpackType backpackType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			int num = BaseItemSlots(backpackType);
			if (num != 0)
			{
				return num + ExtraBackpackSlots;
			}
			return 0;
		}

		public static int EnsureBackpackCapacity(BackpackData? data, BackpackType backpackType, string source)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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_00a0: Expected O, but got Unknown
			if (data == null || !IsItemStorage(backpackType))
			{
				return 0;
			}
			ItemSlot[] array = data.itemSlots ?? Array.Empty<ItemSlot>();
			int num = Math.Max(DesiredItemCapacity(backpackType), HighestOccupiedIndex(array) + 1);
			if (array.Length < num)
			{
				Array.Resize(ref array, num);
				data.itemSlots = array;
				Plugin.ModLog.LogInfo((object)($"[UsageSkills:Inventory] {backpackType} item slots expanded to {num} " + $"strength={Plugin.Progression.GetLevel(SkillId.Strength)} source={source}"));
			}
			for (int i = 0; i < array.Length; i++)
			{
				ItemSlot[] array2 = array;
				int num2 = i;
				if (array2[num2] == null)
				{
					array2[num2] = new ItemSlot((byte)i);
				}
			}
			return num;
		}

		public static BackpackData? TryGetEquippedBackpackData(Character? character, out BackpackType backpackType)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected I4, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			backpackType = (BackpackType)(int)((character == null) ? ((BackpackType?)null) : character.player?.backpackSlot?.backpackType).GetValueOrDefault();
			if (((character == null) ? null : character.player?.backpackSlot) == null || ((ItemSlot)character.player.backpackSlot).IsEmpty())
			{
				cachedBackpackCharacter = character;
				cachedBackpackInstance = null;
				cachedBackpackData = null;
				return null;
			}
			if (!IsItemStorage(backpackType))
			{
				cachedBackpackCharacter = character;
				cachedBackpackInstance = ((ItemSlot)character.player.backpackSlot).data;
				cachedBackpackData = null;
				return null;
			}
			ItemInstanceData data = ((ItemSlot)character.player.backpackSlot).data;
			if ((Object)(object)character == (Object)(object)cachedBackpackCharacter && data == cachedBackpackInstance)
			{
				return cachedBackpackData;
			}
			try
			{
				BackpackReference fromEquippedBackpack = BackpackReference.GetFromEquippedBackpack(character);
				cachedBackpackCharacter = character;
				cachedBackpackInstance = data;
				cachedBackpackData = (((BackpackReference)(ref fromEquippedBackpack)).exists ? ((BackpackReference)(ref fromEquippedBackpack)).GetData() : null);
				return cachedBackpackData;
			}
			catch (Exception ex)
			{
				Plugin.ModLog.LogWarning((object)("[UsageSkills:Inventory] backpack lookup failed: " + ex.Message));
				return null;
			}
		}

		private static int HighestOccupiedIndex(ItemSlot[] slots)
		{
			for (int num = slots.Length - 1; num >= 0; num--)
			{
				if (slots[num] != null && !slots[num].IsEmpty())
				{
					return num;
				}
			}
			return -1;
		}
	}
	internal sealed class InventorySkillController : MonoBehaviour
	{
		private BackpackData? lastBackpackData;

		private int lastDesiredCapacity;

		private BackpackType lastBackpackType;

		private void Update()
		{
			//IL_000d: 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_0052: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			BackpackType backpackType;
			BackpackData val = InventorySkillService.TryGetEquippedBackpackData(Character.localCharacter, out backpackType);
			int num = InventorySkillService.DesiredItemCapacity(backpackType);
			if (val != null && (val != lastBackpackData || backpackType != lastBackpackType || num != lastDesiredCapacity || val.itemSlots.Length < num))
			{
				InventorySkillService.EnsureBackpackCapacity(val, backpackType, "Controller");
				lastBackpackData = val;
				lastBackpackType = backpackType;
				lastDesiredCapacity = num;
			}
		}
	}
	internal sealed class RunStateAdapter
	{
		private readonly UsageSkillsConfig config;

		public string ActiveSceneName
		{
			get
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				Scene activeScene = SceneManager.GetActiveScene();
				return ((Scene)(ref activeScene)).name ?? string.Empty;
			}
		}

		public bool IsAirport => ActiveSceneName.IndexOf("airport", StringComparison.OrdinalIgnoreCase) >= 0;

		public bool IsGameplayScene
		{
			get
			{
				if (!IsAirport)
				{
					return (Object)(object)Character.localCharacter != (Object)null;
				}
				return false;
			}
		}

		public bool IsExperienceEligible
		{
			get
			{
				if (!config.EnableMod.Value || !config.EnableExperience.Value || !IsGameplayScene || (Object)(object)Character.localCharacter == (Object)null)
				{
					return false;
				}
				if (!config.EnableXpInCustomRuns.Value)
				{
					return !RunSettings.IsCustomRun;
				}
				return true;
			}
		}

		public RunStateAdapter(UsageSkillsConfig config)
		{
			this.config = config;
		}
	}
}
namespace PEAKUsageSkills.GameAdapters.Patches
{
	[HarmonyPatch(typeof(CharacterClimbing), "GetRequestedPostition")]
	internal static class WallClimbingSpeedPatch
	{
		private struct State
		{
			public bool Applied;

			public float Original;

			public float OriginalSlippy;
		}

		private static void Prefix(CharacterClimbing __instance, Character ___character, out State __state)
		{
			__state = new State
			{
				Applied = false,
				Original = __instance.climbSpeedMod,
				OriginalSlippy = (___character?.data.slippy ?? 0f)
			};
			if (!((Object)(object)___character == (Object)null) && Plugin.Effects.CanApply(___character) && !___character.data.isRopeClimbing && !___character.data.isVineClimbing)
			{
				__instance.climbSpeedMod = __state.Original * Plugin.Effects.WallSpeedMultiplier;
				___character.data.slippy = __state.OriginalSlippy * Plugin.Effects.WetGripPenaltyMultiplier;
				__state.Applied = true;
			}
		}

		private static void Postfix(CharacterClimbing __instance, State __state)
		{
			Restore(__instance, __state);
		}

		private static Exception? Finalizer(CharacterClimbing __instance, State __state, Exception? __exception)
		{
			Restore(__instance, __state);
			return __exception;
		}

		private static void Restore(CharacterClimbing instance, State state)
		{
			if (state.Applied)
			{
				instance.climbSpeedMod = state.Original;
				object? value = AccessTools.Field(typeof(CharacterClimbing), "character").GetValue(instance);
				Character val = (Character)((value is Character) ? value : null);
				if ((Object)(object)val != (Object)null)
				{
					val.data.slippy = state.OriginalSlippy;
				}
			}
		}
	}
	[HarmonyPatch(typeof(CharacterRopeHandling), "Update")]
	internal static class RopeClimbingSpeedPatch
	{
		private struct State
		{
			public bool Applied;

			public float Original;
		}

		private static void Prefix(CharacterRopeHandling __instance, Character ___character, out State __state)
		{
			__state = new State
			{
				Applied = false,
				Original = __instance.climbSpeedMod
			};
			if (!((Object)(object)___character == (Object)null) && ___character.data.isRopeClimbing && Plugin.Effects.CanApply(___character))
			{
				__instance.climbSpeedMod = __state.Original * Plugin.Effects.RopeSpeedMultiplier;
				__state.Applied = true;
			}
		}

		private static Exception? Finalizer(CharacterRopeHandling __instance, State __state, Exception? __exception)
		{
			if (__state.Applied)
			{
				__instance.climbSpeedMod = __state.Original;
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(CharacterVineClimbing), "FixedUpdate")]
	internal static class VineClimbingSpeedPatch
	{
		private struct State
		{
			public bool Applied;

			public float Original;

			public float OriginalSlideDeceleration;
		}

		private static void Prefix(CharacterVineClimbing __instance, Character ___character, out State __state)
		{
			__state = new State
			{
				Applied = false,
				Original = __instance.climbSpeedMod,
				OriginalSlideDeceleration = __instance.slideDeceleration
			};
			if (!((Object)(object)___character == (Object)null) && ___character.data.isVineClimbing && Plugin.Effects.CanApply(___character))
			{
				__instance.climbSpeedMod = __state.Original * Plugin.Effects.VineSpeedMultiplier;
				__instance.slideDeceleration = Mathf.Lerp(__state.OriginalSlideDeceleration, 1f, Plugin.Effects.VineMomentumRetention);
				__state.Applied = true;
			}
		}

		private static Exception? Finalizer(CharacterVineClimbing __instance, State __state, Exception? __exception)
		{
			if (__state.Applied)
			{
				__instance.climbSpeedMod = __state.Original;
				__instance.slideDeceleration = __state.OriginalSlideDeceleration;
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(WindChillZone), "ApplyStatus")]
	internal static class WetGripWindCostPatch
	{
		private static void Prefix(Character character, out float __state)
		{
			__state = character?.refs?.climbing?.climbingStamMinimumMultiplier ?? 1f;
		}

		private static void Postfix(Character character, float __state)
		{
			CharacterClimbing val = character?.refs?.climbing;
			if (!((Object)(object)val == (Object)null) && Plugin.Effects.CanApply(character))
			{
				float climbingStamMinimumMultiplier = val.climbingStamMinimumMultiplier;
				if (climbingStamMinimumMultiplier > Math.Max(1f, __state))
				{
					val.climbingStamMinimumMultiplier = 1f + (climbingStamMinimumMultiplier - 1f) * Plugin.Effects.WetGripPenaltyMultiplier;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Character), "UpdateVariablesFixed")]
	internal static class LowStaminaClimbingControlPatch
	{
		private static void Postfix(Character __instance)
		{
			if (Plugin.Effects.CanApply(__instance) && __instance.data.isClimbing && !(__instance.GetTotalStamina() >= 0.2f))
			{
				float num = Mathf.Clamp01(__instance.data.staminaMod);
				__instance.data.staminaMod = 1f - (1f - num) * Plugin.Effects.ClimbingTenacityPenaltyMultiplier;
			}
		}
	}
	[HarmonyPatch(typeof(CharacterClimbing), "Climbing")]
	internal static class LowStaminaClimbingSlidePatch
	{
		private struct State
		{
			public bool Applied;

			public float Original;
		}

		private static void Prefix(Character ___character, out State __state)
		{
			__state = default(State);
			if (!((Object)(object)___character == (Object)null) && Plugin.Effects.CanApply(___character) && !(___character.data.outOfStaminaClimbingFor <= 0f))
			{
				__state.Original = ___character.data.outOfStaminaClimbingFor;
				___character.data.outOfStaminaClimbingFor = __state.Original * Plugin.Effects.ClimbingTenacityPenaltyMultiplier;
				__state.Applied = true;
			}
		}

		private static Exception? Finalizer(Character ___character, State __state, Exception? __exception)
		{
			if (__state.Applied && (Object)(object)___character != (Object)null)
			{
				___character.data.outOfStaminaClimbingFor = __state.Original;
			}
			return __exception;
		}
	}
	internal static class ExplicitItemStatusScope
	{
		[ThreadStatic]
		private static int depth;

		public static bool Active => depth > 0;

		public static void Enter()
		{
			depth++;
		}

		public static void Exit()
		{
			depth = Math.Max(0, depth - 1);
		}
	}
	internal static class EnvironmentalColdRecoveryScope
	{
		[ThreadStatic]
		private static int depth;

		public static bool Active => depth > 0;

		public static void Enter()
		{
			depth++;
		}

		public static void Exit()
		{
			depth = Math.Max(0, depth - 1);
		}
	}
	[HarmonyPatch(typeof(Action_ModifyStatus), "RunAction")]
	internal static class ExplicitItemStatusScopePatch
	{
		private static void Prefix()
		{
			ExplicitItemStatusScope.Enter();
		}

		private static Exception? Finalizer(Exception? __exception)
		{
			ExplicitItemStatusScope.Exit();
			return __exception;
		}
	}
	internal static class FallScope
	{
		[ThreadStatic]
		private static string? source;

		public static string? Source => source;

		public static void Enter(string value)
		{
			source = value;
		}

		public static void Exit()
		{
			source = null;
		}
	}
	[HarmonyPatch(typeof(CharacterMovement), "CheckFallDamage")]
	internal static class NormalFallScopePatch
	{
		private static void Prefix()
		{
			FallScope.Enter("CharacterMovement");
		}

		private static Exception? Finalizer(Exception? __exception)
		{
			FallScope.Exit();
			return __exception;
		}
	}
	[HarmonyPatch(typeof(CharacterClimbing), "CheckFallDamage")]
	internal static class WallFallScopePatch
	{
		private static void Prefix()
		{
			FallScope.Enter("CharacterClimbing");
		}

		private static Exception? Finalizer(Exception? __exception)
		{
			FallScope.Exit();
			return __exception;
		}
	}
	[HarmonyPatch(typeof(CharacterAfflictions), "AddStatus")]
	internal static class AddStatusPatch
	{
		private struct State
		{
			public bool Local;

			public float Before;

			public float RawRequested;

			public STATUSTYPE StatusType;

			public string Source;

			public bool ToleranceExposure;

			public SkillId ToleranceSkill;

			public bool EnvironmentalColdRecovery;
		}

		private unsafe static void Prefix(CharacterAfflictions __instance, STATUSTYPE statusType, ref float amount, bool fromRPC, out State __state)
		{
			//IL_004a: 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)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Invalid comparison between Unknown and I4
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Invalid comparison between Unknown and I4
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			bool flag = (Object)(object)__instance != (Object)null && (Object)(object)__instance.character != (Object)null && (Object)(object)Character.localCharacter == (Object)(object)__instance.character;
			__state = new State
			{
				Local = flag,
				Before = (flag ? __instance.GetCurrentStatus(statusType) : 0f),
				RawRequested = amount,
				StatusType = statusType,
				Source = (fromRPC ? "AddRPC" : "AddLocal"),
				ToleranceExposure = false,
				ToleranceSkill = SkillId.Strength,
				EnvironmentalColdRecovery = false
			};
			string source = FallScope.Source;
			if (!flag || amount <= 0f)
			{
				return;
			}
			bool flag2 = (int)statusType == 8 && __instance.GetCurrentStatus((STATUSTYPE)2) > 0f;
			if (flag2 && !ExplicitItemStatusScope.Active)
			{
				EnvironmentalColdRecoveryScope.Enter();
				__state.EnvironmentalColdRecovery = true;
			}
			SkillId skillId;
			if ((int)statusType == 0 && source != null)
			{
				float num = amount;
				Plugin.Progression.AwardWork(SkillId.Vitality, num, Plugin.Settings.VitalityXpPerInjury.Value, source);
				if (Plugin.Effects.CanApply(__instance.character))
				{
					amount *= Plugin.Effects.VitalityFallMultiplier;
				}
				__state.Source = "Fall:" + source;
				Plugin.Diagnostics?.RecordFall(num, amount, source);
			}
			else if ((int)statusType == 13)
			{
				__state.Local = false;
			}
			else if (ConditionSkillAdapter.TryGetToleranceSkill(statusType, out skillId))
			{
				__state.ToleranceExposure = true;
				__state.ToleranceSkill = skillId;
				__state.Source = "Exposure:" + ((object)(*(STATUSTYPE*)(&statusType))/*cast due to .constrained prefix*/).ToString();
				if (!flag2 && Plugin.Effects.CanApply(__instance.character))
				{
					amount *= Plugin.Effects.ConditionGainMultiplier(skillId);
				}
			}
		}

		private unsafe static void Postfix(CharacterAfflictions __instance, bool __result, State __state)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (__state.Local)
			{
				float currentStatus = __instance.GetCurrentStatus(__state.StatusType);
				float num = currentStatus - __state.Before;
				if (__state.ToleranceExposure && __state.ToleranceSkill != SkillId.HungerTolerance && __result && num > 0f)
				{
					Plugin.Progression.AwardWork(__state.ToleranceSkill, num, Plugin.Settings.ConditionXpPerStatus.Value, __state.Source);
				}
				Plugin.Diagnostics?.RecordStatusChange(((object)(*(STATUSTYPE*)(&__state.StatusType))/*cast due to .constrained prefix*/).ToString(), __state.RawRequested, num, currentStatus, __state.Source);
			}
		}

		private static Exception? Finalizer(Exception? __exception, State __state)
		{
			if (__state.EnvironmentalColdRecovery)
			{
				EnvironmentalColdRecoveryScope.Exit();
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(CharacterAfflictions), "AddPetrify", new Type[] { typeof(int) })]
	internal static class AddPetrifyPatch
	{
		private struct State
		{
			public bool Local;

			public int Before;

			public int RawRequested;
		}

		private static void Prefix(CharacterAfflictions __instance, ref int petrify, out State __state)
		{
			bool flag = (Object)(object)__instance != (Object)null && (Object)(object)__instance.character != (Object)null && (Object)(object)Character.localCharacter == (Object)(object)__instance.character;
			__state = new State
			{
				Local = flag,
				Before = (flag ? __instance.character.data.petrifyAmount : 0),
				RawRequested = petrify
			};
			if (flag && petrify > 0 && Plugin.Effects.CanApply(__instance.character))
			{
				petrify = Mathf.Max(0, Mathf.RoundToInt((float)petrify * Plugin.Effects.ConditionGainMultiplier(SkillId.PetrificationResistance)));
			}
		}

		private static void Postfix(CharacterAfflictions __instance, State __state)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			if (__state.Local && __state.RawRequested > 0)
			{
				int petrifyAmount = __instance.character.data.petrifyAmount;
				int num = Mathf.Max(0, petrifyAmount - __state.Before);
				if (num > 0)
				{
					Plugin.Progression.AwardWork(SkillId.PetrificationResistance, (double)num / 100.0, Plugin.Settings.ConditionXpPerStatus.Value, "Exposure:Petrify");
				}
				Plugin.Diagnostics?.RecordStatusChange(((object)(STATUSTYPE)13/*cast due to .constrained prefix*/).ToString(), (float)__state.RawRequested / 100f, (float)num / 100f, (float)petrifyAmount / 100f, "Exposure:Petrify");
			}
		}
	}
	[HarmonyPatch(typeof(CharacterAfflictions), "SubtractStatus")]
	internal static class SubtractStatusPatch
	{
		private struct State
		{
			public bool Local;

			public float Before;

			public float Requested;

			public STATUSTYPE StatusType;

			public string Source;

			public bool HasRecoveryTolerance;

			public SkillId RecoveryTolerance;
		}

		private unsafe static void Prefix(CharacterAfflictions __instance, STATUSTYPE statusType, ref float amount, bool fromRPC, bool decreasedNaturally, out State __state)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Invalid comparison between Unknown and I4
			//IL_005c: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			bool flag = (Object)(object)__instance != (Object)null && (Object)(object)__instance.character != (Object)null && (Object)(object)Character.localCharacter == (Object)(object)__instance.character;
			bool flag2 = (int)statusType == 2 && EnvironmentalColdRecoveryScope.Active;
			bool flag3 = decreasedNaturally || flag2;
			__state = new State
			{
				Local = flag,
				Before = (flag ? __instance.GetCurrentStatus(statusType) : 0f),
				Requested = amount,
				StatusType = statusType,
				Source = (flag2 ? "NaturalRecovery:ColdByWarmth" : (decreasedNaturally ? "NaturalRecovery" : (fromRPC ? "SubtractRPC" : "SubtractLocal"))),
				HasRecoveryTolerance = ConditionSkillAdapter.TryGetRecoveryTolerance(statusType, out var skillId),
				RecoveryTolerance = skillId
			};
			if (flag && flag3 && amount > 0f && __state.HasRecoveryTolerance && Plugin.Effects.CanApply(__instance.character))
			{
				amount *= Plugin.Effects.ConditionRecoveryMultiplier(__state.RecoveryTolerance);
				if (!flag2)
				{
					__state.Source = "NaturalRecovery:" + ((object)(*(STATUSTYPE*)(&statusType))/*cast due to .constrained prefix*/).ToString();
				}
			}
		}

		private unsafe static void Postfix(CharacterAfflictions __instance, State __state)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (__state.Local)
			{
				float currentStatus = __instance.GetCurrentStatus(__state.StatusType);
				float actual = currentStatus - __state.Before;
				Plugin.Diagnostics?.RecordStatusChange(((object)(*(STATUSTYPE*)(&__state.StatusType))/*cast due to .constrained prefix*/).ToString(), 0f - __state.Requested, actual, currentStatus, __state.Source);
			}
		}
	}
	[HarmonyPatch(typeof(BackpackData), "DeserializeValue")]
	internal static class BackpackDataDeserializePatch
	{
		private static bool Prefix(BackpackData __instance, BinaryDeserializer deserializer)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_0090: 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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			InventorySyncData val = default(InventorySyncData);
			((InventorySyncData)(ref val)).Deserialize(deserializer);
			SlotData[] array = val.slots ?? Array.Empty<SlotData>();
			int num = array.Length;
			ItemSlot[] itemSlots = __instance.itemSlots;
			int val2 = ((itemSlots != null) ? itemSlots.Length : 0);
			int num2 = Math.Max(num, val2);
			ItemSlot[] array2 = __instance.itemSlots ?? Array.Empty<ItemSlot>();
			if (array2.Length < num2)
			{
				Array.Resize(ref array2, num2);
				__instance.itemSlots = array2;
			}
			Item val5 = default(Item);
			for (int i = 0; i < array2.Length; i++)
			{
				ItemSlot[] array3 = array2;
				int num3 = i;
				if (array3[num3] == null)
				{
					array3[num3] = new ItemSlot((byte)i);
				}
				if (i < num)
				{
					SlotData val3 = array[i];
					Item val4 = (ItemDatabase.TryGetItem(val3.ItemID, ref val5) ? val5 : null);
					array2[i].SetItem(val4, val3.Data);
				}
				else
				{
					array2[i].SetItem((Item)null, (ItemInstanceData)null);
				}
			}
			Plugin.ModLog.LogInfo((object)($"[UsageSkills:Inventory] backpack deserialized serialized={num} " + $"retainedCapacity={array2.Length}"));
			return false;
		}
	}
	[HarmonyPatch(typeof(BackpackWheel), "InitWheel")]
	internal static class BackpackWheelCapacityPatch
	{
		private static void Prefix(BackpackWheel __instance, BackpackReference bp, ref int slotCount, BackpackType backpackType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			if (!InventorySkillService.IsItemStorage(backpackType))
			{
				return;
			}
			BackpackData data = ((BackpackReference)(ref bp)).GetData();
			slotCount = InventorySkillService.EnsureBackpackCapacity(data, backpackType, "WheelOpen");
			int num = Math.Max(slotCount, data.itemSlots.Length) + 1;
			if (__instance.slices.Length < num)
			{
				List<BackpackWheelSlice> list = new List<BackpackWheelSlice>(__instance.slices);
				BackpackWheelSlice val = __instance.slices[Math.Min(1, __instance.slices.Length - 1)];
				while (list.Count < num)
				{
					list.Add(Object.Instantiate<BackpackWheelSlice>(val, ((Component)val).transform.parent));
				}
				__instance.slices = list.ToArray();
			}
			int num2 = slotCount + 1;
			float num3 = 158f + (float)Math.Max(0, num2 - 5) * 20f;
			for (int i = 0; i < num2; i++)
			{
				float num4 = 360f / (float)num2 * (float)i + 158f;
				float num5 = (num4 + 112f) * (MathF.PI / 180f);
				Transform transform = ((Component)__instance.slices[i]).transform;
				transform.localRotation = Quaternion.Euler(0f, 0f, num4);
				transform.localPosition = new Vector3(Mathf.Cos(num5) * num3, Mathf.Sin(num5) * num3, 0f);
			}
		}
	}
	[HarmonyPatch(typeof(BackpackVisuals), "RefreshVisuals")]
	internal static class BackpackVisualCapacityPatch
	{
		private static void Prefix(BackpackVisuals __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			BackpackType backpackType = GetBackpackType(__instance);
			if (!InventorySkillService.IsItemStorage(backpackType))
			{
				return;
			}
			BackpackData backpackData = __instance.GetBackpackData();
			if (backpackData == null || __instance.backpackSlots == null || __instance.backpackSlots.Length == 0)
			{
				return;
			}
			int num = InventorySkillService.EnsureBackpackCapacity(backpackData, backpackType, "BackpackVisuals");
			if (__instance.backpackSlots.Length < num)
			{
				Transform[] backpackSlots = __instance.backpackSlots;
				Transform[] array = (Transform[])(object)new Transform[num];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = backpackSlots[i % backpackSlots.Length];
				}
				__instance.backpackSlots = array;
			}
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			MethodInfo methodInfo = AccessTools.Method(typeof(BackpackVisualCapacityPatch), "GetVisualSlotCount", (Type[])null, (Type[])null);
			for (int i = 0; i + 1 < list.Count; i++)
			{
				if (CodeInstructionExtensions.LoadsConstant(list[i], 4L) && (list[i + 1].opcode == OpCodes.Blt || list[i + 1].opcode == OpCodes.Blt_S))
				{
					list[i].opcode = OpCodes.Ldarg_0;
					list[i].operand = null;
					list.Insert(i + 1, new CodeInstruction(OpCodes.Call, (object)methodInfo));
					break;
				}
			}
			return list;
		}

		private static int GetVisualSlotCount(BackpackVisuals visuals)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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)
			BackpackType backpackType = GetBackpackType(visuals);
			if (!InventorySkillService.IsItemStorage(backpackType))
			{
				return 0;
			}
			return InventorySkillService.EnsureBackpackCapacity(visuals.GetBackpackData(), backpackType, "VisualRefresh");
		}

		private static BackpackType GetBackpackType(BackpackVisuals visuals)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			BackpackOnBackVisuals val = (BackpackOnBackVisuals)(object)((visuals is BackpackOnBackVisuals) ? visuals : null);
			if (val != null)
			{
				return val.backpackType;
			}
			Backpack component = ((Component)visuals).GetComponent<Backpack>();
			if (!((Object)(object)component != (Object)null))
			{
				return (BackpackType)0;
			}
			return component.backpackType;
		}
	}
	[HarmonyPatch(typeof(CharacterMovement), "GetMovementForce")]
	internal static class AthleticsMovementPatch
	{
		private static void Postfix(Character ___character, ref float __result)
		{
			if (!(__result <= 0f) && !((Object)(object)___character == (Object)null) && Plugin.Effects.CanApply(___character) && ___character.data.isGrounded && !___character.data.isClimbingAnything)
			{
				__result *= Plugin.Effects.AthleticsMovementMultiplier;
				if (___character.data.isSprinting)
				{
					__result *= Plugin.Effects.AthleticsSprintMovementMultiplier;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Character), "CalculateWorldMovementDir")]
	internal static class AgilityAirControlPatch
	{
		private struct State
		{
			public bool Applied;

			public float Original;
		}

		private static void Prefix(Character __instance, out State __state)
		{
			__state = default(State);
			CharacterMovement val = __instance.refs?.movement;
			if (!((Object)(object)val == (Object)null) && !__instance.data.isGrounded && !__instance.data.isClimbingAnything && Plugin.Effects.CanApply(__instance))
			{
				__state.Original = val.airMovementTurnSpeed;
				val.airMovementTurnSpeed = __state.Original * Plugin.Effects.AgilityAirControlMultiplier;
				__state.Applied = true;
			}
		}

		private static Exception? Finalizer(Character __instance, State __state, Exception? __exception)
		{
			if (__state.Applied && (Object)(object)__instance?.refs?.movement != (Object)null)
			{
				__instance.refs.movement.airMovementTurnSpeed = __state.Original;
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(CharacterMovement), "JumpRpc")]
	internal static class AgilityJumpAwardPatch
	{
		private static void Prefix(Character ___character, bool isPalJump)
		{
			if (!((Object)(object)___character == (Object)null || (Object)(object)Character.localCharacter != (Object)(object)___character || isPalJump))
			{
				Plugin.Progression.AwardWork(SkillId.Agility, 1.0, Plugin.Settings.AgilityXpPerJump.Value, "ExecutedJump");
			}
		}
	}
	internal static class JumpEffectScope
	{
		[ThreadStatic]
		private static Character? character;

		[ThreadStatic]
		private static int depth;

		public static bool Matches(Character candidate)
		{
			if (depth > 0)
			{
				return (Object)(object)character == (Object)(object)candidate;
			}
			return false;
		}

		public static void Enter(Character value)
		{
			character = value;
			depth++;
		}

		public static void Exit()
		{
			depth = Math.Max(0, depth - 1);
			if (depth == 0)
			{
				character = null;
			}
		}
	}
	[HarmonyPatch]
	internal static class AgilityJumpRoutinePatch
	{
		private struct State
		{
			public CharacterMovement? Movement;

			public float OriginalJumpImpulse;

			public bool Applied;

			public bool ScopeEntered;
		}

		private static readonly FieldInfo MovementCharacterField = AccessTools.Field(typeof(CharacterMovement), "character");

		private static readonly FieldInfo JumpImpulseField = AccessTools.Field(typeof(CharacterMovement), "jumpImpulse");

		private static MethodBase TargetMethod()
		{
			Type type = (typeof(CharacterMovement).GetNestedType("<>c__DisplayClass69_0", BindingFlags.NonPublic) ?? throw new MissingMemberException("CharacterMovement jump display class")).GetNestedType("<<JumpRpc>g__IDoJump|0>d", BindingFlags.NonPublic) ?? throw new MissingMemberException("CharacterMovement jump iterator");
			return AccessTools.Method(type, "MoveNext", (Type[])null, (Type[])null) ?? throw new MissingMethodException(type.FullName, "MoveNext");
		}

		private static void Prefix(object __instance, out State __state)
		{
			__state = default(State);
			object obj = AccessTools.Field(__instance.GetType(), "<>4__this")?.GetValue(__instance);
			object? obj2 = ((obj == null) ? null : AccessTools.Field(obj.GetType(), "<>4__this"))?.GetValue(obj);
			CharacterMovement val = (CharacterMovement)((obj2 is CharacterMovement) ? obj2 : null);
			Character val2 = (Character)(((Object)(object)val == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null) && !((Object)(object)Character.localCharacter != (Object)(object)val2))
			{
				__state.Movement = val;
				JumpEffectScope.Enter(val2);
				__state.ScopeEntered = true;
				if (Plugin.Effects.CanApply(val2))
				{
					__state.OriginalJumpImpulse = (float)JumpImpulseField.GetValue(val);
					JumpImpulseField.SetValue(val, __state.OriginalJumpImpulse * Plugin.Effects.AgilityJumpMultiplier);
					__state.Applied = true;
				}
			}
		}

		private static Exception? Finalizer(State __state, Exception? __exception)
		{
			if (__state.Applied && (Object)(object)__state.Movement != (Object)null)
			{
				JumpImpulseField.SetValue(__state.Movement, __state.OriginalJumpImpulse);
			}
			if (__state.ScopeEntered)
			{
				JumpEffectScope.Exit();
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Character), "GetMaxStamina")]
	internal static class StaminaCapacityPatch
	{
		private static void Postfix(Character __instance, ref float __result)
		{
			if (Plugin.Effects.CanApply(__instance))
			{
				float capacityBonus = Plugin.Effects.EnduranceCapacityMultiplier - 1f;
				CharacterRefs refs = __instance.refs;
				float? obj;
				if (refs == null)
				{
					obj = null;
				}
				else
				{
					CharacterAfflictions afflictions = refs.afflictions;
					obj = ((afflictions != null) ? new float?(afflictions.statusSum) : ((float?)null));
				}
				float? num = obj;
				float valueOrDefault = num.GetValueOrDefault();
				__result = SkillMath.ExpandedStaminaCapacity(__result, valueOrDefault, capacityBonus);
			}
		}
	}
	internal static class EndurancePassOutThreshold
	{
		public static float GetThreshold(Character character)
		{
			if ((Object)(object)character == (Object)null || !Plugin.Effects.CanApply(character))
			{
				return 1f;
			}
			return Math.Max(1f, Plugin.Effects.EnduranceCapacityMultiplier);
		}

		public static IEnumerable<CodeInstruction> ReplaceVanillaThreshold(IEnumerable<CodeInstruction> instructions, MethodBase originalMethod)
		{
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(CharacterAfflictions), "statusSum") ?? AccessTools.Method(typeof(CharacterAfflictions), "get_statusSum", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(EndurancePassOutThreshold), "GetThreshold", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				Plugin.ModLog.LogError((object)("[UsageSkills:PassOut] Could not resolve statusSum getter/threshold method while patching " + originalMethod.Name + "."));
				return list;
			}
			int num = 0;
			for (int i = 1; i < list.Count; i++)
			{
				CodeInstruction val = list[i - 1];
				CodeInstruction val2 = list[i];
				bool num2 = (val.opcode == OpCodes.Call || val.opcode == OpCodes.Callvirt) && object.Equals(val.operand, methodInfo);
				bool flag = val2.opcode == OpCodes.Ldc_R4 && val2.operand is float num3 && Math.Abs(num3 - 1f) < 0.0001f;
				if (num2 && flag)
				{
					val2.opcode = OpCodes.Ldarg_0;
					val2.operand = null;
					list.Insert(i + 1, new CodeInstruction(OpCodes.Call, (object)methodInfo2));
					num++;
					i++;
				}
			}
			if (num == 0)
			{
				Plugin.ModLog.LogError((object)("[UsageSkills:PassOut] No vanilla statusSum vs 1.0 threshold found in " + originalMethod.Name + ". Endurance pass-out scaling will not affect this method."));
			}
			else
			{
				Plugin.ModLog.LogInfo((object)$"[UsageSkills:PassOut] Patched {originalMethod.Name} threshold(s)={num}.");
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(Character), "HandlePassedOut")]
	internal static class EndurancePassOutRecoveryPatch
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
		{
			return EndurancePassOutThreshold.ReplaceVanillaThreshold(instructions, __originalMethod);
		}
	}
	[HarmonyPatch(typeof(Character), "UseStamina")]
	internal static class StaminaCostPatch
	{
		private static void Prefix(Character __instance, ref float usage)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)Character.localCharacter != (Object)(object)__instance || usage <= 0f)
			{
				return;
			}
			float num = usage;
			bool flag = JumpEffectScope.Matches(__instance);
			bool flag2 = __instance.data.isClimbing && !__instance.data.isRopeClimbing && !__instance.data.isVineClimbing;
			string source = (flag ? "Jumping" : (flag2 ? "WallClimbing" : (__instance.data.isRopeClimbing ? "RopeClimbing" : (__instance.data.isVineClimbing ? "VineClimbing" : (__instance.data.isSprinting ? "Sprinting" : "OtherExertion")))));
			if (!__instance.infiniteStam)
			{
				Plugin.Progression.AwardWork(SkillId.Endurance, num, Plugin.Settings.EnduranceXpPerStamina.Value, source);
			}
			if (Plugin.Effects.CanApply(__instance))
			{
				if (flag2)
				{
					usage *= Plugin.Effects.WallCostMultiplier;
					if (__instance.GetTotalStamina() < 0.2f)
					{
						usage *= Plugin.Effects.ClimbingTenacityPenaltyMultiplier;
					}
				}
				else if (__instance.data.isRopeClimbing)
				{
					usage *= Plugin.Effects.RopeCostMultiplier;
				}
				else if (__instance.data.isVineClimb