Decompiled source of CiCisClimbingAxes v1.1.4

plugins/ClimbingAxesMod/ClimbingAxesMod.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TrinketAndBindingFramework;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ClimbingAxesMod")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ClimbingAxesMod")]
[assembly: AssemblyTitle("ClimbingAxesMod")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 ClimbingAxesMod
{
	[BepInPlugin("com.cicismods.climbingaxes", "Climbing Axes Mod", "1.1.4")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string ItemTag = "climbingaxe";

		public const int StartingDurability = 30;

		public const float RegenIntervalSeconds = 60f;

		public const float HandholdLifetimeSeconds = 0f;

		public const string DurabilityDataKey = "axe_durability";

		public const string PrefabNameRed = "ClimbingAxe_Red";

		public const int StartingDurabilityRed = 10;

		public const float RegenIntervalSecondsRed = 15f;

		public const float BrokenRegenDelaySecondsRed = 60f;

		public const float AxeRange = 4f;

		public const float LodgeDelaySeconds = 0f;

		public const float AxeMinChargeTime = 0.05f;

		public const float AxeChargeDamage = 1f;

		public const float AxeAutoReleaseDelay = 0.5f;

		public const float AxeHitShakeAmount = 0.025f;

		public static readonly Vector3 LodgedAxeEulerOffset = new Vector3(-90f, 180f, -90f);

		public const float LodgedAxeHandleTiltDegrees = 40f;

		public static Item_Object AxeTemplate;

		public static Item_Object RedAxeTemplate;

		public static HandItem ClimbingAxeHandItemTemplate;

		public static ManualLogSource Log;

		public static GameObject AxePrefab;

		public static GameObject AxeBrokenPrefab;

		public static GameObject RedAxePrefab;

		public static GameObject RedAxeBrokenPrefab;

		public static Sprite AxeHandSprite;

		public static Sprite AxeSpriteState2;

		public static Sprite AxeSpriteState3;

		public static Sprite AxeSpriteFinal;

		public static Sprite AxeSpriteBroken;

		public static Sprite AxeRedSpritePristine;

		public static Sprite AxeRedSpriteState2;

		public static Sprite AxeRedSpriteState3;

		public static Sprite AxeRedSpriteFinal;

		public static Sprite AxeRedSpriteBroken;

		public static Texture2D AxeTexture;

		public static Sprite WallRunnerIcon;

		public static Sprite AlpinePuristIcon;

		public static Sprite YellowAxesVendingSprite;

		public static Sprite MendingAxesPerkCardSprite;

		public static Material OutlineMaterial;

		public static Material OutlineMaterialRed;

		public static readonly Vector3 OutlineHaloScale = new Vector3(1.04f, 1.04f, 1.04f);

		public static readonly Vector3 OutlineHaloOffset = Vector3.zero;

		public static readonly List<AudioClip> AxeHitClips = new List<AudioClip>();

		public static AudioClip AxeBreakClip;

		private Harmony _harmony;

		public static readonly HashSet<string> AlpinePuristBlockedPrefabs = new HashSet<string> { "Item_Piton", "Item_AutoPiton", "Item_Piton_Holiday", "Item_Rebar", "Item_Rebar_Explosive", "Item_Rebar_Bone", "Item_RebarRope", "Item_Rebar_Holiday", "Item_RebarRope_Holiday", "Item_Hammer" };

		public static readonly string[] AlpinePuristBlockedPerkSubstrings = new string[3] { "piton", "rebar", "hammer" };

		public static readonly string[] AlpinePuristBlockedPerkNameSubstrings = new string[1] { "hangtight" };

		public const string RedAxePerkId = "cici_red_axes_perk";

		private static Purchase _yellowAxeVendingPurchase;

		private static Perk _redAxePerkAsset;

		public static Item_Object AxeVendingSpawnTemplate;

		private static GameObject _axeVendingSpawnContainer;

		private static readonly Dictionary<Mesh, Mesh> _invertedMeshCache = new Dictionary<Mesh, Mesh>();

		public static bool AlpinePuristActive => IsAlpinePuristActiveNow();

		public static Sprite GetSpriteForDurability(int dur, int maxDur)
		{
			if (dur <= 0)
			{
				return AxeSpriteBroken ?? AxeHandSprite;
			}
			if (dur == 1)
			{
				return AxeSpriteFinal ?? AxeHandSprite;
			}
			if (maxDur <= 0)
			{
				return AxeHandSprite;
			}
			float num = (float)dur / (float)maxDur;
			if (num >= 2f / 3f)
			{
				return AxeHandSprite;
			}
			if (num >= 1f / 3f)
			{
				return AxeSpriteState2 ?? AxeHandSprite;
			}
			return AxeSpriteState3 ?? AxeHandSprite;
		}

		public static Sprite GetSpriteForDurability(Item item)
		{
			int durability = GetDurability(item);
			bool flag = item?.prefabName == "ClimbingAxe_Red";
			int maxDur = (flag ? 10 : 30);
			if (flag)
			{
				return GetRedSpriteForDurability(durability, maxDur);
			}
			return GetSpriteForDurability(durability, maxDur);
		}

		private static Sprite GetRedSpriteForDurability(int dur, int maxDur)
		{
			if (dur <= 0)
			{
				return AxeRedSpriteBroken ?? AxeRedSpritePristine ?? AxeHandSprite;
			}
			if (dur == 1)
			{
				return AxeRedSpriteFinal ?? AxeRedSpritePristine ?? AxeHandSprite;
			}
			if (maxDur <= 0)
			{
				return AxeRedSpritePristine ?? AxeHandSprite;
			}
			float num = (float)dur / (float)maxDur;
			if (num >= 2f / 3f)
			{
				return AxeRedSpritePristine ?? AxeHandSprite;
			}
			if (num >= 1f / 3f)
			{
				return AxeRedSpriteState2 ?? AxeRedSpritePristine ?? AxeHandSprite;
			}
			return AxeRedSpriteState3 ?? AxeRedSpritePristine ?? AxeHandSprite;
		}

		private void Awake()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			WK_Leaderboard_Core.disableLeaderboards = true;
			LoadAssetBundle();
			LoadCustomAudio();
			LoadTrinketIcons();
			_harmony = new Harmony("com.cicismods.climbingaxes");
			_harmony.PatchAll();
			GameObject val = new GameObject("ClimbingAxesMod_Handler");
			((Object)val).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)val);
			val.AddComponent<AxeModHandler>();
			TrinketRegistry.RegisterTrinket("cici_wall_runner", "Wall Runner", "Start with a pair of climbing axes. Alternate hands to scale any surface, whiff a swing to let go.", "Some climbers don't trust pitons.", 1, 0f, 0f, WallRunnerIcon, (Func<List<Item_Object>>)delegate
			{
				try
				{
					EnsureAxeTemplate();
				}
				catch
				{
				}
				return ((Object)(object)AxeTemplate == (Object)null) ? new List<Item_Object>() : new List<Item_Object> { AxeTemplate, AxeTemplate };
			}, (Func<List<Perk>>)null, 0);
			TrinketRegistry.RegisterBinding("cici_alpine_purist", "Alpine Purist", "Start with axes instead of the hammer. Pitons, auto-pitons, rebar, and rebar-ropes do not appear in the world or in vending machines. Related perks are disabled.", "Trust the steel.", 1, 0.5f, 0f, AlpinePuristIcon, (Func<List<Item_Object>>)delegate
			{
				try
				{
					EnsureRedAxeTemplate();
				}
				catch
				{
				}
				return ((Object)(object)RedAxeTemplate == (Object)null) ? new List<Item_Object>() : new List<Item_Object> { RedAxeTemplate, RedAxeTemplate };
			}, (Func<List<Perk>>)null, 0);
		}

		private static bool IsAlpinePuristActiveNow()
		{
			try
			{
				M_Gamemode currentGamemode = CL_GameManager.GetCurrentGamemode();
				if ((Object)(object)currentGamemode == (Object)null)
				{
					return false;
				}
				SaveData saveData = StatManager.saveData;
				List<string> list = ((saveData != null) ? saveData.GetGamemodeTrinkets(currentGamemode.GetGamemodeName(true)) : null);
				if (list == null)
				{
					return false;
				}
				foreach (string item in list)
				{
					if (!string.IsNullOrEmpty(item) && item.ToLowerInvariant().Contains("cici_alpine_purist"))
					{
						return true;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		public static string GetAlpinePuristBestTimeFilePath()
		{
			string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
			return Path.Combine(folderPath, "CiCisMods", "AlpinePurist", "best.txt");
		}

		public static float LoadAlpinePuristBestTime()
		{
			try
			{
				string alpinePuristBestTimeFilePath = GetAlpinePuristBestTimeFilePath();
				if (!File.Exists(alpinePuristBestTimeFilePath))
				{
					return 0f;
				}
				string s = File.ReadAllText(alpinePuristBestTimeFilePath).Trim();
				if (float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
				{
					return (result > 0f) ? result : 0f;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("[AlpinePurist] Load persistent best failed: " + ex.Message));
				}
			}
			return 0f;
		}

		public static void SaveAlpinePuristBestTime(float seconds)
		{
			try
			{
				string alpinePuristBestTimeFilePath = GetAlpinePuristBestTimeFilePath();
				string directoryName = Path.GetDirectoryName(alpinePuristBestTimeFilePath);
				if (!Directory.Exists(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				File.WriteAllText(alpinePuristBestTimeFilePath, seconds.ToString("R", CultureInfo.InvariantCulture));
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("[AlpinePurist] Save persistent best failed: " + ex.Message));
				}
			}
		}

		private void LoadAssetBundle()
		{
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Unknown result type (might be due to invalid IL or missing references)
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string text = Path.Combine(directoryName, "climbingaxemod");
			if (!File.Exists(text))
			{
				Log.LogError((object)("Asset bundle not found at: " + text));
				return;
			}
			AssetBundle val = AssetBundle.LoadFromFile(text);
			if ((Object)(object)val == (Object)null)
			{
				Log.LogError((object)"AssetBundle.LoadFromFile returned null");
				return;
			}
			GameObject[] array = val.LoadAllAssets<GameObject>();
			if (array != null && array.Length != 0)
			{
				AxePrefab = PickByExactName<GameObject>(array, "climbing_axe_new");
				AxeBrokenPrefab = PickByExactName<GameObject>(array, "climbing_axe_new_broken");
				RedAxePrefab = PickByExactName<GameObject>(array, "climbing_axe_red");
				RedAxeBrokenPrefab = PickByExactName<GameObject>(array, "climbing_axe_red_broken");
				if ((Object)(object)AxePrefab == (Object)null)
				{
					AxePrefab = PickPreferredByName<GameObject>(array, "_new") ?? array[0];
				}
				if ((Object)(object)AxeBrokenPrefab == (Object)null)
				{
					Log.LogWarning((object)"[Bundle] climbing_axe_new_broken not found");
				}
				if ((Object)(object)RedAxePrefab == (Object)null)
				{
					Log.LogWarning((object)"[Bundle] climbing_axe_red not found");
				}
				if ((Object)(object)RedAxeBrokenPrefab == (Object)null)
				{
					Log.LogWarning((object)"[Bundle] climbing_axe_red_broken not found");
				}
			}
			else
			{
				Log.LogError((object)"Bundle loaded but contains no GameObject assets");
			}
			Sprite[] array2 = val.LoadAllAssets<Sprite>();
			if (array2 != null && array2.Length != 0)
			{
				AxeSpriteState2 = PickPreferredByName<Sprite>(array2, "_state_2");
				AxeSpriteState3 = PickPreferredByName<Sprite>(array2, "_state_3");
				AxeSpriteFinal = PickPreferredByName<Sprite>(array2, "_state_final");
				AxeSpriteBroken = PickPreferredByName<Sprite>(array2, "_state_broken");
				AxeHandSprite = PickPreferredBy<Sprite>(array2, (Func<Sprite, bool>)((Sprite a) => ((Object)a).name != null && ((Object)a).name.ToLowerInvariant().Contains("_new") && !((Object)a).name.ToLowerInvariant().Contains("_state_"))) ?? PickPreferredByName<Sprite>(array2, "_new") ?? array2[0];
				if ((Object)(object)AxeHandSprite != (Object)null && (Object)(object)AxeHandSprite.texture != (Object)null)
				{
					((Texture)AxeHandSprite.texture).filterMode = (FilterMode)0;
					AxeTexture = AxeHandSprite.texture;
				}
				Sprite[] array3 = (Sprite[])(object)new Sprite[4] { AxeSpriteState2, AxeSpriteState3, AxeSpriteFinal, AxeSpriteBroken };
				foreach (Sprite val2 in array3)
				{
					if ((Object)(object)val2 != (Object)null && (Object)(object)val2.texture != (Object)null)
					{
						((Texture)val2.texture).filterMode = (FilterMode)0;
					}
				}
			}
			if ((Object)(object)AxeHandSprite == (Object)null)
			{
				Texture2D[] array4 = val.LoadAllAssets<Texture2D>();
				if (array4 != null && array4.Length != 0)
				{
					AxeTexture = PickPreferredByName<Texture2D>(array4, "_new") ?? array4[0];
					((Texture)AxeTexture).filterMode = (FilterMode)0;
					AxeHandSprite = Sprite.Create(AxeTexture, new Rect(0f, 0f, (float)((Texture)AxeTexture).width, (float)((Texture)AxeTexture).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
					((Object)AxeHandSprite).name = "ClimbingAxe_HandSprite";
				}
			}
			if ((Object)(object)AxeHandSprite == (Object)null)
			{
				Log.LogWarning((object)"No axe sprite/texture found in bundle");
			}
		}

		private static T PickByExactName<T>(T[] assets, string exact) where T : Object
		{
			if (assets == null)
			{
				return default(T);
			}
			foreach (T val in assets)
			{
				if (!((Object)(object)val == (Object)null) && ((Object)val).name == exact)
				{
					return val;
				}
			}
			return default(T);
		}

		private static T PickPreferredByName<T>(T[] assets, string needle) where T : Object
		{
			if (assets == null)
			{
				return default(T);
			}
			needle = needle.ToLowerInvariant();
			foreach (T val in assets)
			{
				if (!((Object)(object)val == (Object)null) && ((Object)val).name != null && ((Object)val).name.ToLowerInvariant().Contains(needle))
				{
					return val;
				}
			}
			return default(T);
		}

		private static T PickPreferredBy<T>(T[] assets, Func<T, bool> pred) where T : Object
		{
			if (assets == null)
			{
				return default(T);
			}
			foreach (T val in assets)
			{
				if (!((Object)(object)val == (Object)null) && pred(val))
				{
					return val;
				}
			}
			return default(T);
		}

		private void LoadCustomAudio()
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string[] array = new string[2] { "climbingaxe_hit_1.wav", "climbingaxe_hit_2.wav" };
			string[] array2 = array;
			foreach (string filename in array2)
			{
				AudioClip val = TryLoadWav(directoryName, filename);
				if ((Object)(object)val != (Object)null)
				{
					AxeHitClips.Add(val);
				}
			}
			AxeBreakClip = TryLoadWav(directoryName, "climbingaxe_break.wav");
		}

		private void LoadTrinketIcons()
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			WallRunnerIcon = TryLoadSpritePng(directoryName, "cici_wall_runner_icon.png");
			AlpinePuristIcon = TryLoadSpritePng(directoryName, "cici_alpine_purist_icon.png");
			AxeRedSpritePristine = TryLoadSpritePng(directoryName, "climbing_axe_sprite_red.png");
			AxeRedSpriteState2 = TryLoadSpritePng(directoryName, "climbing_axe_sprite_red_state_2.png");
			AxeRedSpriteState3 = TryLoadSpritePng(directoryName, "climbing_axe_sprite_red_state_3.png");
			AxeRedSpriteFinal = TryLoadSpritePng(directoryName, "climbing_axe_sprite_red_state_final.png");
			AxeRedSpriteBroken = TryLoadSpritePng(directoryName, "climbing_axe_sprite_red_state_broken.png");
			YellowAxesVendingSprite = TryLoadSpritePng(directoryName, "Vending_Yellow_Axes.png");
			MendingAxesPerkCardSprite = TryLoadSpritePng(directoryName, "Perk_Card_Mending_Axes.png");
		}

		private Sprite TryLoadSpritePng(string dir, string filename)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			string text = Path.Combine(dir, filename);
			if (!File.Exists(text))
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("Trinket icon not found: " + filename + " (at " + text + ") — will use vanilla fallback"));
				}
				return null;
			}
			try
			{
				byte[] array = File.ReadAllBytes(text);
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!ImageConversion.LoadImage(val, array))
				{
					return null;
				}
				((Texture)val).filterMode = (FilterMode)0;
				((Texture)val).wrapMode = (TextureWrapMode)1;
				Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
				((Object)val2).name = filename;
				Object.DontDestroyOnLoad((Object)(object)val2);
				Object.DontDestroyOnLoad((Object)(object)val);
				return val2;
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("Trinket icon load failed for " + filename + ": " + ex.Message));
				}
				return null;
			}
		}

		private AudioClip TryLoadWav(string dir, string filename)
		{
			string text = Path.Combine(dir, filename);
			if (!File.Exists(text))
			{
				Log.LogWarning((object)("Audio not found: " + filename + " (at " + text + ")"));
				return null;
			}
			try
			{
				AudioClip val = WavLoader.LoadFromFile(text);
				if ((Object)(object)val != (Object)null)
				{
					((Object)val).name = filename;
				}
				return val;
			}
			catch (Exception ex)
			{
				Log.LogError((object)("WAV load failed for " + filename + ": " + ex.Message));
				return null;
			}
		}

		public static void EnsureAxeTemplate()
		{
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: 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)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Expected O, but got Unknown
			if ((Object)(object)AxeTemplate != (Object)null)
			{
				return;
			}
			GameObject val = AxePrefab;
			if ((Object)(object)val == (Object)null)
			{
				val = CL_AssetManager.GetAssetGameObject("Item_Hammer", "");
				if ((Object)(object)val == (Object)null)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)"Neither AxePrefab (bundle) nor Item_Hammer available");
					}
					return;
				}
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"AxePrefab bundle missing — falling back to Item_Hammer clone");
				}
			}
			GameObject val2 = Object.Instantiate<GameObject>(val);
			val2.SetActive(false);
			((Object)val2).name = "ClimbingAxe_Template";
			((Object)val2).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)val2);
			ApplyGameShader(val2, addShimmer: true);
			EnsureHaloOnGameObject(val2);
			ConfigureAsPickup(val2);
			Item_Object val3 = val2.GetComponent<Item_Object>();
			if ((Object)(object)val3 == (Object)null)
			{
				val3 = val2.AddComponent<Item_Object>();
			}
			AxeTemplate = val3;
			if (val3.itemData != null)
			{
				return;
			}
			Item val4 = new Item
			{
				itemName = "Climbing Axe",
				itemTag = "climbingaxe",
				itemTags = new List<string> { "tool", "climbingaxe" },
				prefabName = "ClimbingAxe",
				upDirection = Vector3.up,
				pocketable = true,
				pouchable = true,
				worth = 2,
				inventoryScale = 1f,
				itemWeight = 1f,
				itemAsset = AxeTemplate,
				data = new List<string> { string.Format("{0}={1}", "axe_durability", 30) },
				dataModules = new List<Item_Data>(),
				dataModuleSaves = new List<DataModuleSave>(),
				pickupSounds = new List<AudioClip>(),
				executionModules = new List<ItemExecutionModule>()
			};
			try
			{
				GameObject assetGameObject = CL_AssetManager.GetAssetGameObject("Item_Hammer", "");
				Item_Object val5 = (((Object)(object)assetGameObject != (Object)null) ? assetGameObject.GetComponent<Item_Object>() : null);
				if ((Object)(object)val5?.itemData?.handItemAsset != (Object)null)
				{
					EnsureClimbingAxeHandItemTemplate();
					val4.handItemAsset = ClimbingAxeHandItemTemplate ?? val5.itemData.handItemAsset;
					val4.itemWeight = val5.itemData.itemWeight / 3f;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = Log;
				if (log3 != null)
				{
					log3.LogWarning((object)("Template handItemAsset lookup failed: " + ex.Message));
				}
			}
			val3.itemData = val4;
		}

		public static void EnsureRedAxeTemplate()
		{
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: 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)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: 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)
			//IL_015a: 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_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Expected O, but got Unknown
			if ((Object)(object)RedAxeTemplate != (Object)null)
			{
				return;
			}
			EnsureAxeTemplate();
			GameObject val = RedAxePrefab ?? AxePrefab ?? (((Object)(object)AxeTemplate != (Object)null) ? ((Component)AxeTemplate).gameObject : null);
			if ((Object)(object)val == (Object)null)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)"Red axe template deferred — no source prefab available");
				}
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val);
			val2.SetActive(false);
			((Object)val2).name = "ClimbingAxe_Red_Template";
			((Object)val2).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)val2);
			ApplyGameShader(val2, addShimmer: true);
			if ((Object)(object)OutlineMaterialRed == (Object)null)
			{
				OutlineMaterialRed = TryBuildGameOutlineMaterialRed();
			}
			EnsureHaloOnGameObject(val2, OutlineMaterialRed);
			ConfigureAsPickup(val2);
			Item_Object val3 = val2.GetComponent<Item_Object>();
			if ((Object)(object)val3 == (Object)null)
			{
				val3 = val2.AddComponent<Item_Object>();
			}
			RedAxeTemplate = val3;
			if (val3.itemData != null)
			{
				return;
			}
			Item val4 = new Item
			{
				itemName = "Climbing Axe (Red)",
				itemTag = "climbingaxe",
				itemTags = new List<string> { "tool", "climbingaxe" },
				prefabName = "ClimbingAxe_Red",
				upDirection = Vector3.up,
				pocketable = true,
				pouchable = true,
				worth = 2,
				inventoryScale = 1f,
				itemWeight = 1f,
				itemAsset = RedAxeTemplate,
				data = new List<string> { string.Format("{0}={1}", "axe_durability", 10) },
				dataModules = new List<Item_Data>(),
				dataModuleSaves = new List<DataModuleSave>(),
				pickupSounds = new List<AudioClip>(),
				executionModules = new List<ItemExecutionModule>()
			};
			try
			{
				GameObject assetGameObject = CL_AssetManager.GetAssetGameObject("Item_Hammer", "");
				Item_Object val5 = (((Object)(object)assetGameObject != (Object)null) ? assetGameObject.GetComponent<Item_Object>() : null);
				if ((Object)(object)val5?.itemData?.handItemAsset != (Object)null)
				{
					EnsureClimbingAxeHandItemTemplate();
					val4.handItemAsset = ClimbingAxeHandItemTemplate ?? val5.itemData.handItemAsset;
					val4.itemWeight = val5.itemData.itemWeight / 3f;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("Red axe template handItemAsset lookup failed: " + ex.Message));
				}
			}
			val3.itemData = val4;
		}

		public static void EnsureAxeVendingSpawnTemplate()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			if ((Object)(object)AxeVendingSpawnTemplate != (Object)null && (Object)(object)((Component)AxeVendingSpawnTemplate).gameObject != (Object)null)
			{
				return;
			}
			EnsureAxeTemplate();
			if (!((Object)(object)AxeTemplate == (Object)null))
			{
				if ((Object)(object)_axeVendingSpawnContainer == (Object)null)
				{
					_axeVendingSpawnContainer = new GameObject("CiCiAxeVendingSpawnContainer");
					_axeVendingSpawnContainer.SetActive(false);
					((Object)_axeVendingSpawnContainer).hideFlags = (HideFlags)61;
					Object.DontDestroyOnLoad((Object)(object)_axeVendingSpawnContainer);
				}
				GameObject val = Object.Instantiate<GameObject>(((Component)AxeTemplate).gameObject, _axeVendingSpawnContainer.transform);
				val.SetActive(true);
				((Object)val).name = "ClimbingAxe_VendingSpawnTemplate";
				Item_Object component = val.GetComponent<Item_Object>();
				if ((Object)(object)component != (Object)null && component.itemData == null)
				{
					component.itemData = AxeTemplate.itemData;
				}
				AxeVendingSpawnTemplate = component;
			}
		}

		public static Purchase GetOrBuildYellowAxeVendingPurchase()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			//IL_0094: 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_00a6: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			if (_yellowAxeVendingPurchase != null && (Object)(object)_yellowAxeVendingPurchase.itemObject != (Object)null)
			{
				return _yellowAxeVendingPurchase;
			}
			EnsureAxeVendingSpawnTemplate();
			if ((Object)(object)AxeVendingSpawnTemplate == (Object)null)
			{
				return null;
			}
			List<GameObject> spawnAssets = new List<GameObject>
			{
				((Component)AxeVendingSpawnTemplate).gameObject,
				((Component)AxeVendingSpawnTemplate).gameObject
			};
			_yellowAxeVendingPurchase = new Purchase
			{
				name = "cici_climbing_axe_yellow",
				chance = 1f,
				spawnSettings = new SpawnSettings(),
				itemObject = AxeVendingSpawnTemplate,
				spawnAssets = spawnAssets,
				price = 12,
				purchaseSprite = (YellowAxesVendingSprite ?? WallRunnerIcon ?? AxeHandSprite),
				requiredItemTag = "",
				ignoreUnlocked = true
			};
			return _yellowAxeVendingPurchase;
		}

		public static Perk GetOrBuildRedAxePerkAsset()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Expected O, but got Unknown
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: 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_00f4: Expected O, but got Unknown
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Expected O, but got Unknown
			if ((Object)(object)_redAxePerkAsset != (Object)null)
			{
				return _redAxePerkAsset;
			}
			Perk val = ScriptableObject.CreateInstance<Perk>();
			val.id = "cici_red_axes_perk";
			val.title = "Mending Axes";
			val.description = $"Receive 2 Mending Axes. Fragile but self-repair over time.\n<color=\"grey\">Cost: {23}</color>";
			val.flavorText = "";
			val.perkType = (PerkType)2;
			val.cost = 23;
			val.spawnPool = (PerkPool)0;
			val.useBuff = false;
			val.useBaseBuff = false;
			val.canStack = false;
			val.tags = new List<string> { "basic", "standard" };
			val.flags = new List<string>();
			val.playerTag = new List<string>();
			val.modules = new List<PerkModule>();
			val.spawnSettings = new SpawnSettings();
			val.buff = new BuffContainer
			{
				id = "",
				buffs = new List<Buff>()
			};
			val.baseBuff = new BuffContainer
			{
				id = "",
				buffs = new List<Buff>()
			};
			val.perkCard = MendingAxesPerkCardSprite ?? val.perkCard;
			val.icon = MendingAxesPerkCardSprite ?? AxeRedSpritePristine ?? AxeHandSprite;
			try
			{
				WKAssetDatabase fullCombinedAssetDatabase = CL_AssetManager.GetFullCombinedAssetDatabase();
				if (fullCombinedAssetDatabase?.perkAssets != null)
				{
					foreach (Perk perkAsset in fullCombinedAssetDatabase.perkAssets)
					{
						if ((Object)(object)perkAsset == (Object)null || !((Object)(object)val.perkFrame == (Object)null) || !((Object)(object)perkAsset.perkFrame != (Object)null))
						{
							continue;
						}
						val.perkFrame = perkAsset.perkFrame;
						break;
					}
				}
			}
			catch
			{
			}
			((Object)val).hideFlags = (HideFlags)61;
			((Object)val).name = "Perk_CiCiRedAxes";
			_redAxePerkAsset = val;
			return _redAxePerkAsset;
		}

		public static void EnsureClimbingAxeHandItemTemplate()
		{
			if ((Object)(object)ClimbingAxeHandItemTemplate != (Object)null)
			{
				return;
			}
			HandItem val = null;
			try
			{
				GameObject assetGameObject = CL_AssetManager.GetAssetGameObject("Item_Hammer", "");
				val = (((Object)(object)assetGameObject != (Object)null) ? assetGameObject.GetComponent<Item_Object>() : null)?.itemData?.handItemAsset;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("Hammer HandItem lookup failed during clone: " + ex.Message));
				}
				return;
			}
			if ((Object)(object)val == (Object)null)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"Hammer HandItem_Melee prefab not found — climbing axe HandItem decouple deferred");
				}
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject);
			((Object)val2).name = "ClimbingAxesMod_HandItem";
			val2.SetActive(false);
			((Object)val2).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)val2);
			HandItem component = val2.GetComponent<HandItem>();
			if ((Object)(object)component == (Object)null)
			{
				ManualLogSource log3 = Log;
				if (log3 != null)
				{
					log3.LogWarning((object)"Cloned hammer HandItem prefab has no HandItem component — skipping adoption");
				}
				Object.Destroy((Object)(object)val2);
				return;
			}
			ClimbingAxeHandItemTemplate = component;
			ManualLogSource log4 = Log;
			if (log4 != null)
			{
				log4.LogInfo((object)("[Decouple] ClimbingAxeHandItemTemplate cloned from '" + ((Object)val).name + "' as '" + ((Object)val2).name + "'"));
			}
		}

		internal static void ApplyGameShader(GameObject target, bool addShimmer = false)
		{
			Shader val = Shader.Find("Dark Machine/SHDR_Base") ?? Shader.Find("Unlit/Texture");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = target.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if (((Object)((Component)val2).gameObject).name.StartsWith("ClimbingAxeHalo_"))
				{
					continue;
				}
				Material[] materials = val2.materials;
				for (int j = 0; j < materials.Length; j++)
				{
					if (!((Object)(object)materials[j] == (Object)null))
					{
						Texture val3 = (materials[j].HasProperty("_MainTex") ? materials[j].GetTexture("_MainTex") : null);
						materials[j].shader = val;
						if ((Object)(object)val3 != (Object)null && materials[j].HasProperty("_MainTex"))
						{
							materials[j].SetTexture("_MainTex", val3);
						}
						if (addShimmer)
						{
							ApplyItemShimmer(materials[j]);
						}
					}
				}
				val2.materials = materials;
			}
		}

		public static Material TryBuildGameOutlineMaterial()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			return BuildOutlineMaterial("ClimbingAxesMod_Outline_Yellow", new Color(1f, 0.92f, 0.1f, 1f));
		}

		public static Material TryBuildGameOutlineMaterialRed()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			return BuildOutlineMaterial("ClimbingAxesMod_Outline_Red", new Color(1f, 0.2f, 0.2f, 1f));
		}

		private static Material BuildOutlineMaterial(string name, Color color)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			Shader val = Shader.Find("Dark Machine/SHDR_Outline");
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Material val2 = new Material(val)
			{
				name = name
			};
			if (val2.HasProperty("_Color"))
			{
				val2.SetColor("_Color", color);
			}
			if (val2.HasProperty("_Brightness"))
			{
				val2.SetFloat("_Brightness", 1f);
			}
			Object.DontDestroyOnLoad((Object)(object)val2);
			return val2;
		}

		public static Material PickOutlineMaterialForItem(Item item)
		{
			if (item != null && item.prefabName == "ClimbingAxe_Red")
			{
				if ((Object)(object)OutlineMaterialRed == (Object)null)
				{
					OutlineMaterialRed = TryBuildGameOutlineMaterialRed();
				}
				return OutlineMaterialRed ?? OutlineMaterial;
			}
			if ((Object)(object)OutlineMaterial == (Object)null)
			{
				OutlineMaterial = TryBuildGameOutlineMaterial();
			}
			return OutlineMaterial;
		}

		public static Mesh GetInvertedHullMesh(Mesh source)
		{
			//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_0095: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			if (_invertedMeshCache.TryGetValue(source, out var value))
			{
				return value;
			}
			if (!source.isReadable)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("[Outline] Mesh '" + ((Object)source).name + "' is not readable (Read/Write disabled at import). Halo skipped. Enable Read/Write on the FBX and rebuild the bundle to get the outline glow."));
				}
				_invertedMeshCache[source] = null;
				return null;
			}
			try
			{
				Mesh val = new Mesh
				{
					name = ((Object)source).name + "_Inverted"
				};
				val.indexFormat = source.indexFormat;
				val.vertices = source.vertices;
				val.normals = source.normals;
				val.uv = source.uv;
				val.subMeshCount = source.subMeshCount;
				for (int i = 0; i < source.subMeshCount; i++)
				{
					int[] triangles = source.GetTriangles(i);
					for (int j = 0; j < triangles.Length; j += 3)
					{
						int num = triangles[j + 1];
						triangles[j + 1] = triangles[j + 2];
						triangles[j + 2] = num;
					}
					val.SetTriangles(triangles, i);
				}
				val.RecalculateBounds();
				Object.DontDestroyOnLoad((Object)(object)val);
				_invertedMeshCache[source] = val;
				return val;
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[Outline] Failed to invert mesh '" + ((Object)source).name + "': " + ex.Message + ". Halo skipped."));
				}
				_invertedMeshCache[source] = null;
				return null;
			}
		}

		public static void ApplyItemShimmer(Material m)
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)m == (Object)null))
			{
				if (m.HasProperty("_Shimmer"))
				{
					m.SetFloat("_Shimmer", 1f);
				}
				if (m.HasProperty("_ShimmerFrequency"))
				{
					m.SetFloat("_ShimmerFrequency", 1f);
				}
				if (m.HasProperty("_ShimmerSpeed"))
				{
					m.SetFloat("_ShimmerSpeed", 1f);
				}
				if (m.HasProperty("_ShimmerOver"))
				{
					m.SetFloat("_ShimmerOver", 0f);
				}
				if (m.HasProperty("_ShimmerOffset"))
				{
					m.SetFloat("_ShimmerOffset", 0f);
				}
				if (m.HasProperty("_ShimmerTextureMix"))
				{
					m.SetFloat("_ShimmerTextureMix", 1f);
				}
				if (m.HasProperty("_ShimmerColor"))
				{
					m.SetColor("_ShimmerColor", Color.white);
				}
				if (m.HasProperty("_Shading"))
				{
					m.SetFloat("_Shading", 0.96f);
				}
				if (m.HasProperty("_DitherAmount"))
				{
					m.SetFloat("_DitherAmount", 0.63f);
				}
				if (m.HasProperty("_ROUNDMULT"))
				{
					m.SetFloat("_ROUNDMULT", 1.27f);
				}
				if (m.HasProperty("_Wiggle"))
				{
					m.SetFloat("_Wiggle", 0.0003f);
				}
				if (m.HasProperty("_WiggleFreq"))
				{
					m.SetFloat("_WiggleFreq", 2f);
				}
				if (m.HasProperty("_WiggleSpeed"))
				{
					m.SetFloat("_WiggleSpeed", 5f);
				}
			}
		}

		public static void EnsureHaloOnGameObject(GameObject go, Material outlineOverride = null)
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Expected O, but got Unknown
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)go == (Object)null)
			{
				return;
			}
			if ((Object)(object)OutlineMaterial == (Object)null)
			{
				OutlineMaterial = TryBuildGameOutlineMaterial();
			}
			Material val = outlineOverride ?? OutlineMaterial;
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			MeshRenderer[] componentsInChildren = go.GetComponentsInChildren<MeshRenderer>(true);
			foreach (MeshRenderer val2 in componentsInChildren)
			{
				if ((Object)(object)val2 == (Object)null || ((Object)((Component)val2).gameObject).name.StartsWith("ClimbingAxeHalo_"))
				{
					continue;
				}
				Transform val3 = null;
				foreach (Transform item in ((Component)val2).transform)
				{
					Transform val4 = item;
					if (((Object)val4).name.StartsWith("ClimbingAxeHalo_"))
					{
						val3 = val4;
						break;
					}
				}
				MeshFilter component = ((Component)val2).GetComponent<MeshFilter>();
				if ((Object)(object)component == (Object)null || (Object)(object)component.sharedMesh == (Object)null)
				{
					if ((Object)(object)val3 != (Object)null)
					{
						Object.Destroy((Object)(object)((Component)val3).gameObject);
					}
					continue;
				}
				Mesh invertedHullMesh = GetInvertedHullMesh(component.sharedMesh);
				if ((Object)(object)invertedHullMesh == (Object)null)
				{
					if ((Object)(object)val3 != (Object)null)
					{
						Object.Destroy((Object)(object)((Component)val3).gameObject);
					}
				}
				else if ((Object)(object)val3 != (Object)null)
				{
					MeshFilter component2 = ((Component)val3).GetComponent<MeshFilter>();
					if ((Object)(object)component2 != (Object)null && (Object)(object)component2.sharedMesh != (Object)(object)invertedHullMesh)
					{
						component2.sharedMesh = invertedHullMesh;
					}
					MeshRenderer component3 = ((Component)val3).GetComponent<MeshRenderer>();
					if ((Object)(object)component3 != (Object)null && (Object)(object)((Renderer)component3).sharedMaterial != (Object)(object)val)
					{
						((Renderer)component3).sharedMaterial = val;
					}
				}
				else
				{
					GameObject val5 = new GameObject("ClimbingAxeHalo_" + ((Object)val2).name);
					val5.layer = ((Component)val2).gameObject.layer;
					val5.transform.SetParent(((Component)val2).transform, false);
					val5.transform.localPosition = OutlineHaloOffset;
					val5.transform.localRotation = Quaternion.identity;
					val5.transform.localScale = OutlineHaloScale;
					MeshFilter val6 = val5.AddComponent<MeshFilter>();
					val6.sharedMesh = invertedHullMesh;
					MeshRenderer val7 = val5.AddComponent<MeshRenderer>();
					((Renderer)val7).sharedMaterial = val;
					((Renderer)val7).shadowCastingMode = (ShadowCastingMode)0;
					((Renderer)val7).receiveShadows = false;
					((Renderer)val7).lightProbeUsage = (LightProbeUsage)0;
					((Renderer)val7).reflectionProbeUsage = (ReflectionProbeUsage)0;
				}
			}
		}

		private static void ConfigureAsPickup(GameObject go)
		{
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: 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_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			go.layer = 10;
			Transform[] componentsInChildren = go.GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				((Component)val).gameObject.layer = 10;
			}
			try
			{
				go.tag = "Pickupable";
			}
			catch
			{
			}
			ObjectTagger val2 = go.GetComponent<ObjectTagger>() ?? go.AddComponent<ObjectTagger>();
			if (val2.tags == null)
			{
				val2.tags = new List<string>();
			}
			if (!val2.tags.Contains("Pickupable"))
			{
				val2.tags.Add("Pickupable");
			}
			if (!val2.tags.Contains("Item"))
			{
				val2.tags.Add("Item");
			}
			if ((Object)(object)go.GetComponentInChildren<Collider>() == (Object)null)
			{
				Renderer[] componentsInChildren2 = go.GetComponentsInChildren<Renderer>();
				if (componentsInChildren2.Length != 0)
				{
					Bounds bounds = componentsInChildren2[0].bounds;
					for (int j = 1; j < componentsInChildren2.Length; j++)
					{
						((Bounds)(ref bounds)).Encapsulate(componentsInChildren2[j].bounds);
					}
					BoxCollider val3 = go.AddComponent<BoxCollider>();
					val3.center = go.transform.InverseTransformPoint(((Bounds)(ref bounds)).center);
					val3.size = ((Bounds)(ref bounds)).size;
				}
				else
				{
					BoxCollider val4 = go.AddComponent<BoxCollider>();
					val4.size = new Vector3(0.6f, 0.3f, 0.3f);
				}
			}
			Rigidbody val5 = go.GetComponent<Rigidbody>() ?? go.AddComponent<Rigidbody>();
			val5.mass = 0.4f;
			CL_Prop val6 = go.GetComponent<CL_Prop>();
			if ((Object)(object)val6 == (Object)null)
			{
				val6 = go.AddComponent<CL_Prop>();
			}
			if (val6.hitSounds == null)
			{
				val6.hitSounds = new List<PropAudioEffect>();
			}
			if (val6.dragSounds == null)
			{
				val6.dragSounds = new List<PropAudioEffect>();
			}
			if (val6.breakSounds == null)
			{
				val6.breakSounds = new List<PropAudioEffect>();
			}
			if (val6.unstickSounds == null)
			{
				val6.unstickSounds = new List<PropAudioEffect>();
			}
			if (val6.damageSounds == null)
			{
				val6.damageSounds = new List<PropAudioEffect>();
			}
		}

		public static Item CreateAxeItem()
		{
			//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_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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_004b: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Expected O, but got Unknown
			Item val = new Item
			{
				itemName = "Climbing Axe",
				itemTag = "climbingaxe",
				itemTags = new List<string> { "tool", "climbingaxe" },
				prefabName = "ClimbingAxe",
				upDirection = Vector3.up,
				pocketable = true,
				pouchable = true,
				worth = 2,
				inventoryScale = 1f,
				itemWeight = 1f,
				data = new List<string> { string.Format("{0}={1}", "axe_durability", 30) },
				dataModules = new List<Item_Data>(),
				dataModuleSaves = new List<DataModuleSave>(),
				pickupSounds = new List<AudioClip>(),
				executionModules = new List<ItemExecutionModule>()
			};
			try
			{
				EnsureAxeTemplate();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("Template build deferred: " + ex.Message));
				}
			}
			if ((Object)(object)AxeTemplate != (Object)null)
			{
				val.itemAsset = AxeTemplate;
			}
			AxeModHandler.MarkAxeUsedNow(val);
			try
			{
				EnsureClimbingAxeHandItemTemplate();
				GameObject assetGameObject = CL_AssetManager.GetAssetGameObject("Item_Hammer", "");
				Item_Object val2 = (((Object)(object)assetGameObject != (Object)null) ? assetGameObject.GetComponent<Item_Object>() : null);
				if ((Object)(object)ClimbingAxeHandItemTemplate != (Object)null)
				{
					val.handItemAsset = ClimbingAxeHandItemTemplate;
				}
				else if ((Object)(object)val2?.itemData?.handItemAsset != (Object)null)
				{
					val.handItemAsset = val2.itemData.handItemAsset;
				}
				if (val2?.itemData != null)
				{
					val.itemWeight = val2.itemData.itemWeight / 3f;
				}
			}
			catch (Exception ex2)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("Hammer hand lookup failed: " + ex2.Message));
				}
			}
			return val;
		}

		public static int GetDurability(Item item)
		{
			if (item?.data == null)
			{
				return 0;
			}
			foreach (string datum in item.data)
			{
				if (datum != null && datum.StartsWith("axe_durability=") && int.TryParse(datum.Substring("axe_durability".Length + 1), out var result))
				{
					return result;
				}
			}
			return 0;
		}

		public static void SetDurability(Item item, int value)
		{
			if (item == null)
			{
				return;
			}
			if (item.data == null)
			{
				item.data = new List<string>();
			}
			string text = string.Format("{0}={1}", "axe_durability", value);
			for (int i = 0; i < item.data.Count; i++)
			{
				if (item.data[i] != null && item.data[i].StartsWith("axe_durability="))
				{
					item.data[i] = text;
					return;
				}
			}
			item.data.Add(text);
		}
	}
	[HarmonyPatch(typeof(Item), "GetClone")]
	public static class AxePreserveItemTagPatch
	{
		[HarmonyPostfix]
		public static void Postfix(Item __instance, Item __result)
		{
			if (__instance != null && __result != null)
			{
				__result.itemTag = __instance.itemTag;
			}
		}
	}
	[HarmonyPatch(typeof(Item), "CopyNonDataFromItemAsset")]
	public static class AxeSaveMigrationPatch
	{
		[HarmonyPrefix]
		public static void Prefix(Item __instance)
		{
			if (__instance != null && (__instance.prefabName == "ClimbingAxe" || __instance.prefabName == "ClimbingAxe_Red" || __instance.itemTag == "climbingaxe" || __instance.itemName == "Climbing Axe" || __instance.itemName == "Climbing Axe (Red)"))
			{
				string text = ((__instance.prefabName == "ClimbingAxe_Red" || __instance.itemName == "Climbing Axe (Red)") ? "ClimbingAxe_Red" : "ClimbingAxe");
				if (__instance.prefabName != text)
				{
					__instance.prefabName = text;
				}
				if (__instance.itemTag != "climbingaxe")
				{
					__instance.itemTag = "climbingaxe";
				}
				if (__instance.itemTags == null)
				{
					__instance.itemTags = new List<string>();
				}
				if (!__instance.itemTags.Contains("climbingaxe"))
				{
					__instance.itemTags.Add("climbingaxe");
				}
				if (!__instance.itemTags.Contains("tool"))
				{
					__instance.itemTags.Add("tool");
				}
			}
		}
	}
	public static class AxeLodgeRotationFix
	{
		private static readonly Dictionary<UT_SoftParent, Quaternion> _relativeRotations = new Dictionary<UT_SoftParent, Quaternion>();

		public static void Track(UT_SoftParent soft, Quaternion relativeRotation)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)soft == (Object)null))
			{
				_relativeRotations[soft] = relativeRotation;
			}
		}

		internal static bool TryGet(UT_SoftParent soft, out Quaternion rel)
		{
			return _relativeRotations.TryGetValue(soft, out rel);
		}
	}
	[HarmonyPatch(typeof(UT_SoftParent), "CheckEnable")]
	public static class AxeSoftParentRotationPatch
	{
		[HarmonyPostfix]
		public static void Postfix(UT_SoftParent __instance)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.parent == (Object)null) && AxeLodgeRotationFix.TryGet(__instance, out var rel))
			{
				((Component)__instance).transform.rotation = __instance.parent.rotation * rel;
			}
		}
	}
	[HarmonyPatch(typeof(UI_TrinketPicker), "UpdateTrinketActivation")]
	public static class WallRunnerAlpinePuristMutexPatch
	{
		private static readonly FieldInfo _isLockedField = AccessTools.Field(typeof(UI_TrinketPicker_Icon), "isLocked");

		public static readonly HashSet<UI_TrinketPicker_Icon> MutexLockedIcons = new HashSet<UI_TrinketPicker_Icon>();

		public static readonly Dictionary<Trinket, List<string>> MutexLockReasons = new Dictionary<Trinket, List<string>>();

		private const string TagWallRunner = "cici_wall_runner";

		private const string TagAlpinePurist = "cici_alpine_purist";

		private const string TagCarabiner = "trinket_carabiner";

		private const string TagPitonsAndBeans = "pitonandbean";

		[HarmonyPostfix]
		public static void Postfix(UI_TrinketPicker __instance)
		{
			if ((Object)(object)__instance == (Object)null || _isLockedField == null)
			{
				return;
			}
			MutexLockedIcons.Clear();
			MutexLockReasons.Clear();
			bool flag = false;
			bool flag2 = false;
			bool flag3 = false;
			bool flag4 = false;
			List<string> list = new List<string>();
			foreach (Trinket selectedTrinket in __instance.selectedTrinkets)
			{
				if ((Object)(object)selectedTrinket == (Object)null)
				{
					continue;
				}
				string text = ((Object)selectedTrinket).name?.ToLowerInvariant();
				if (!string.IsNullOrEmpty(text))
				{
					if (text.Contains("cici_wall_runner"))
					{
						flag = true;
						continue;
					}
					if (text.Contains("cici_alpine_purist"))
					{
						flag2 = true;
						continue;
					}
					if (text.Contains("trinket_carabiner"))
					{
						flag3 = true;
						continue;
					}
					if (text.Contains("pitonandbean"))
					{
						flag4 = true;
						continue;
					}
				}
				if (TrinketGrantsAlpinePuristBlocked(selectedTrinket))
				{
					list.Add(string.IsNullOrEmpty(selectedTrinket.title) ? "Unknown" : selectedTrinket.title);
				}
			}
			foreach (UI_TrinketPicker_Icon trinketIcon in __instance.trinketIcons)
			{
				if ((Object)(object)trinketIcon?.trinket == (Object)null)
				{
					continue;
				}
				bool flag5 = !trinketIcon.trinket.IsUnlocked() || trinketIcon.trinket.comingSoon;
				List<string> list2 = new List<string>();
				string text2 = ((Object)trinketIcon.trinket).name?.ToLowerInvariant();
				if (!string.IsNullOrEmpty(text2))
				{
					if (text2.Contains("cici_wall_runner") && flag2)
					{
						list2.Add("Alpine Purist");
					}
					else if (text2.Contains("cici_alpine_purist"))
					{
						if (flag)
						{
							list2.Add("Wall Runner");
						}
						if (flag3)
						{
							list2.Add("Carabiner");
						}
						if (flag4)
						{
							list2.Add("Pitons and Beans");
						}
						foreach (string item in list)
						{
							list2.Add(item);
						}
					}
					else if (text2.Contains("trinket_carabiner") && flag2)
					{
						list2.Add("Alpine Purist");
					}
					else if (text2.Contains("pitonandbean") && flag2)
					{
						list2.Add("Alpine Purist");
					}
				}
				if (flag2 && list2.Count == 0 && TrinketGrantsAlpinePuristBlocked(trinketIcon.trinket))
				{
					list2.Add("Alpine Purist");
				}
				bool flag6 = list2.Count > 0;
				_isLockedField.SetValue(trinketIcon, flag5 || flag6);
				if (flag6)
				{
					MutexLockedIcons.Add(trinketIcon);
					MutexLockReasons[trinketIcon.trinket] = list2;
				}
			}
		}

		private static bool TrinketGrantsAlpinePuristBlocked(Trinket t)
		{
			if ((Object)(object)t == (Object)null)
			{
				return false;
			}
			if (t.itemsToGrant != null)
			{
				for (int i = 0; i < t.itemsToGrant.Count; i++)
				{
					string text = t.itemsToGrant[i]?.itemData?.prefabName;
					if (!string.IsNullOrEmpty(text) && Plugin.AlpinePuristBlockedPrefabs.Contains(text))
					{
						return true;
					}
				}
			}
			if (t.perksToGrant != null)
			{
				for (int j = 0; j < t.perksToGrant.Count; j++)
				{
					Perk val = t.perksToGrant[j];
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					string text2 = val.description?.ToLowerInvariant();
					if (!string.IsNullOrEmpty(text2))
					{
						for (int k = 0; k < Plugin.AlpinePuristBlockedPerkSubstrings.Length; k++)
						{
							if (text2.Contains(Plugin.AlpinePuristBlockedPerkSubstrings[k]))
							{
								return true;
							}
						}
					}
					string text3 = ((Object)val).name?.ToLowerInvariant();
					if (string.IsNullOrEmpty(text3))
					{
						continue;
					}
					for (int l = 0; l < Plugin.AlpinePuristBlockedPerkNameSubstrings.Length; l++)
					{
						if (text3.Contains(Plugin.AlpinePuristBlockedPerkNameSubstrings[l]))
						{
							return true;
						}
					}
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Trinket), "GetLockedDescription")]
	public static class MutexLockedDescriptionOverridePatch
	{
		[HarmonyPrefix]
		public static bool Prefix(Trinket __instance, ref string __result)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			if (!WallRunnerAlpinePuristMutexPatch.MutexLockReasons.TryGetValue(__instance, out var value))
			{
				return true;
			}
			if (value == null || value.Count == 0)
			{
				return true;
			}
			string text = ((((Object)__instance).name == null || !((Object)__instance).name.Contains("cici_wall_runner")) ? (__instance.isBinding ? "red" : "#FF8AFF") : "#FFEB1A");
			string text2 = (__instance.isBinding ? "Binding" : "Trinket");
			string text3 = "<color=" + text + "><shimmer s=0.1>" + __instance.title + "</shimmer></color>";
			string text4 = string.Join(", ", value);
			__result = "<color=grey>Locked " + text2 + ":</color> " + text3 + "\n<color=grey>Conflicts with: " + text4 + "</color>";
			return false;
		}
	}
	[HarmonyPatch(typeof(UI_TrinketPicker_Icon), "Update")]
	public static class MutexLockedIconDarkenPatch
	{
		private static readonly Color MutexLockedColor = new Color(0.95f, 0.45f, 0.1f, 1f);

		[HarmonyPostfix]
		public static void Postfix(UI_TrinketPicker_Icon __instance)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.image == (Object)null) && WallRunnerAlpinePuristMutexPatch.MutexLockedIcons.Contains(__instance))
			{
				((Graphic)__instance.image).color = Color.Lerp(((Graphic)__instance.image).color, MutexLockedColor, Time.unscaledDeltaTime * 15f);
			}
		}
	}
	[HarmonyPatch(typeof(M_Gamemode), "StartFreshGamemode")]
	public static class AlpinePuristActivationLogPatch
	{
		[HarmonyPostfix]
		public static void Postfix(M_Gamemode __instance)
		{
			if (Plugin.AlpinePuristActive)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"[AlpinePurist] Active for this run — climbing tools will be blocked");
				}
			}
		}
	}
	[HarmonyPatch(typeof(Item_Object), "Start")]
	public static class AlpinePuristBanItemSpawnPatch
	{
		[HarmonyPostfix]
		public static void Postfix(Item_Object __instance)
		{
			if (Plugin.AlpinePuristActive && __instance?.itemData != null)
			{
				string prefabName = __instance.itemData.prefabName;
				if (prefabName != null && Plugin.AlpinePuristBlockedPrefabs.Contains(prefabName))
				{
					((Component)__instance).gameObject.SetActive(false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(ENV_VendingMachine), "GenerateOptions")]
	public static class AlpinePuristBanVendingPatch
	{
		[HarmonyPrefix]
		public static void Prefix(ENV_VendingMachine __instance)
		{
			if (!Plugin.AlpinePuristActive || __instance?.purchaseList == null)
			{
				return;
			}
			for (int num = __instance.purchaseList.Count - 1; num >= 0; num--)
			{
				string text = __instance.purchaseList[num]?.itemObject?.itemData?.prefabName;
				if (text != null && Plugin.AlpinePuristBlockedPrefabs.Contains(text))
				{
					__instance.purchaseList.RemoveAt(num);
				}
			}
		}
	}
	[HarmonyPatch(typeof(UI_TrinketPicker), "ReloadTrinkets")]
	public static class AlpinePuristDescriptionRefreshPatch
	{
		public const string BaseDescription = "Start with axes instead of the hammer. Pitons, auto-pitons, rebar, and rebar-ropes do not appear in the world or in vending machines. Related perks are disabled.";

		[HarmonyPostfix]
		public static void Postfix(UI_TrinketPicker __instance)
		{
			Trinket runtimeTrinket = TrinketRegistry.GetRuntimeTrinket("cici_alpine_purist");
			if (!((Object)(object)runtimeTrinket == (Object)null))
			{
				object? obj = AccessTools.Field(typeof(UI_TrinketPicker), "currentGamemode")?.GetValue(__instance);
				M_Gamemode val = (M_Gamemode)(((obj is M_Gamemode) ? obj : null) ?? CL_GameManager.GetBaseGamemode());
				GameStats val2 = ((val == null) ? null : val.GetGamemodeSaveData()?.stats);
				float num = 0f;
				try
				{
					float num2 = ((val2 != null) ? StatManager.GetStatisticFloat(val2, "alpine-purist-best-time") : 0f);
					float num3 = Plugin.LoadAlpinePuristBestTime();
					num = ((num2 > 0f && num3 > 0f) ? Mathf.Min(num2, num3) : ((num2 > 0f) ? num2 : num3));
				}
				catch
				{
				}
				string text = "Start with axes instead of the hammer. Pitons, auto-pitons, rebar, and rebar-ropes do not appear in the world or in vending machines. Related perks are disabled.";
				if (num > 0f)
				{
					text = text + "\n<color=#ffaa44>Best speedrun: " + FormatTime(num) + "</color>";
				}
				runtimeTrinket.description = text;
			}
		}

		private static string FormatTime(float seconds)
		{
			int num = (int)(seconds / 60f);
			float num2 = seconds - (float)num * 60f;
			return $"{num:00}:{num2:00.00}";
		}
	}
	[HarmonyPatch(typeof(App_PerkPage), "GenerateCards")]
	public static class AlpinePuristTerminalPerkFilterPatch
	{
		private static readonly FieldInfo _cardsField = AccessTools.Field(typeof(App_PerkPage), "cards");

		[HarmonyPostfix]
		public static void Postfix(App_PerkPage __instance)
		{
			if (!Plugin.AlpinePuristActive || !(_cardsField?.GetValue(__instance) is List<App_PerkPage_Card> list))
			{
				return;
			}
			for (int num = list.Count - 1; num >= 0; num--)
			{
				App_PerkPage_Card val = list[num];
				if (!((Object)(object)val?.perk == (Object)null) && IsPerkBlockedByAlpinePurist(val.perk, out var reason))
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)("[AlpinePurist] Removed terminal perk card '" + ((Object)val.perk).name + "' (" + reason + ")"));
					}
					((Component)val).gameObject.SetActive(false);
					list.RemoveAt(num);
				}
			}
		}

		public static bool IsPerkBlockedByAlpinePurist(Perk perk, out string reason)
		{
			reason = null;
			if ((Object)(object)perk == (Object)null)
			{
				return false;
			}
			string text = perk.description?.ToLowerInvariant();
			if (!string.IsNullOrEmpty(text))
			{
				string[] alpinePuristBlockedPerkSubstrings = Plugin.AlpinePuristBlockedPerkSubstrings;
				foreach (string text2 in alpinePuristBlockedPerkSubstrings)
				{
					if (text.Contains(text2))
					{
						reason = "description mentions '" + text2 + "'";
						return true;
					}
				}
			}
			string text3 = ((Object)perk).name?.ToLowerInvariant();
			if (!string.IsNullOrEmpty(text3))
			{
				string[] alpinePuristBlockedPerkNameSubstrings = Plugin.AlpinePuristBlockedPerkNameSubstrings;
				foreach (string text4 in alpinePuristBlockedPerkNameSubstrings)
				{
					if (text3.Contains(text4))
					{
						reason = "name matches '" + text4 + "'";
						return true;
					}
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(ENV_VendingMachine), "GenerateOptions")]
	public static class CiciYellowAxeVendingInjectPatch
	{
		public const float YellowAxeVendingChance = 0.05f;

		[HarmonyPostfix]
		public static void Postfix(ENV_VendingMachine __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && __instance.buttons != null && __instance.buttons.Length != 0 && !Plugin.AlpinePuristActive && !(Random.value > 0.05f))
			{
				Purchase orBuildYellowAxeVendingPurchase = Plugin.GetOrBuildYellowAxeVendingPurchase();
				if (orBuildYellowAxeVendingPurchase != null)
				{
					int num = Random.Range(0, __instance.buttons.Length);
					__instance.buttons[num].purchase = orBuildYellowAxeVendingPurchase;
					__instance.buttons[num].available = true;
				}
			}
		}
	}
	[HarmonyPatch(typeof(App_PerkPage), "GenerateCards")]
	public static class CiciRedAxePerkInjectPatch
	{
		public const float MendingAxesPerkChance = 1f / 30f;

		private static readonly FieldInfo _cardsField = AccessTools.Field(typeof(App_PerkPage), "cards");

		[HarmonyPostfix]
		public static void Postfix(App_PerkPage __instance)
		{
			if ((Object)(object)__instance == (Object)null || Plugin.AlpinePuristActive || Random.value > 1f / 30f || !(_cardsField?.GetValue(__instance) is List<App_PerkPage_Card> list) || list.Count == 0)
			{
				return;
			}
			Perk orBuildRedAxePerkAsset = Plugin.GetOrBuildRedAxePerkAsset();
			if ((Object)(object)orBuildRedAxePerkAsset == (Object)null)
			{
				return;
			}
			try
			{
				int index = Random.Range(0, list.Count);
				list[index].Initialize(__instance, orBuildRedAxePerkAsset);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[RedAxePerk] Inject failed: " + ex.Message));
				}
			}
		}
	}
	[HarmonyPatch(typeof(ENT_Player), "AddPerk")]
	public static class CiciRedAxePerkGrantPatch
	{
		[CompilerGenerated]
		private sealed class <GrantRedAxesNextFrame>d__2 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <GrantRedAxesNextFrame>d__2(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					DoGrantRedAxes();
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[HarmonyPostfix]
		public static void Postfix(Perk perk)
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)("[RedAxePerk] AddPerk fired — id='" + perk?.id + "' name='" + ((perk != null) ? ((Object)perk).name : null) + "'"));
			}
			if ((Object)(object)perk == (Object)null || perk.id != "cici_red_axes_perk")
			{
				return;
			}
			AxeModHandler axeModHandler = Object.FindObjectOfType<AxeModHandler>();
			if ((Object)(object)axeModHandler == (Object)null)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"[RedAxePerk] No AxeModHandler in scene — running grant directly");
				}
				DoGrantRedAxes();
			}
			else
			{
				((MonoBehaviour)axeModHandler).StartCoroutine(GrantRedAxesNextFrame());
			}
		}

		private static void DoGrantRedAxes()
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Plugin.EnsureRedAxeTemplate();
			}
			catch
			{
			}
			if ((Object)(object)Plugin.RedAxeTemplate == (Object)null)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"[RedAxePerk] RedAxeTemplate null at grant");
				}
				return;
			}
			Inventory instance = Inventory.instance;
			if ((Object)(object)instance == (Object)null)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"[RedAxePerk] Inventory.instance null at grant");
				}
				return;
			}
			for (int i = 0; i < 2; i++)
			{
				try
				{
					Item clone = Plugin.RedAxeTemplate.itemData.GetClone((Item)null);
					instance.AddItemToInventoryScreen(new Vector3(0.15f * ((float)i - 0.5f), 0.1f, 1f), clone, true, false, true);
				}
				catch (Exception ex)
				{
					ManualLogSource log3 = Plugin.Log;
					if (log3 != null)
					{
						log3.LogWarning((object)("[RedAxePerk] Grant failed: " + ex.Message));
					}
				}
			}
			ManualLogSource log4 = Plugin.Log;
			if (log4 != null)
			{
				log4.LogInfo((object)"[RedAxePerk] Granted 2 red axes after perk purchase");
			}
		}

		[IteratorStateMachine(typeof(<GrantRedAxesNextFrame>d__2))]
		private static IEnumerator GrantRedAxesNextFrame()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <GrantRedAxesNextFrame>d__2(0);
		}
	}
	[HarmonyPatch(typeof(CL_GameManager), "Win")]
	public static class AlpinePuristSpeedrunLogPatch
	{
		private static readonly FieldInfo _gameTimeField = AccessTools.Field(typeof(CL_GameManager), "gameTime");

		public const string SpeedrunStatKey = "alpine-purist-best-time";

		[HarmonyPostfix]
		public static void Postfix(CL_GameManager __instance)
		{
			if (!Plugin.AlpinePuristActive)
			{
				return;
			}
			try
			{
				M_Gamemode currentGamemode = CL_GameManager.GetCurrentGamemode();
				if ((Object)(object)currentGamemode == (Object)null)
				{
					return;
				}
				SaveData saveData = StatManager.saveData;
				List<string> list = ((saveData != null) ? saveData.GetGamemodeTrinkets(currentGamemode.GetGamemodeName(true)) : null);
				if (list == null || list.Count != 1 || !list[0].ToLowerInvariant().Contains("cici_alpine_purist"))
				{
					return;
				}
				if (CommandConsole.hasCheated)
				{
					float num = (float)(_gameTimeField?.GetValue(__instance) ?? ((object)0f));
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)$"[AlpinePurist] Run complete — {num:F2}s BUT cheats were used. Time not saved.");
					}
					return;
				}
				float num2 = (float)(_gameTimeField?.GetValue(__instance) ?? ((object)0f));
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)$"[AlpinePurist] Speedrun complete — {num2:F2}s");
				}
				GameStats val = currentGamemode.GetGamemodeSaveData()?.stats;
				if (val == null)
				{
					return;
				}
				float statisticFloat = StatManager.GetStatisticFloat(val, "alpine-purist-best-time");
				float num3 = Plugin.LoadAlpinePuristBestTime();
				float num4 = ((statisticFloat > 0f && num3 > 0f) ? Mathf.Min(statisticFloat, num3) : ((statisticFloat > 0f) ? statisticFloat : num3));
				bool flag = num4 <= 0f;
				bool flag2 = !flag && num2 < num4;
				if (flag || flag2)
				{
					val.UpdateStatistic("alpine-purist-best-time", (object)num2, (DataType)2, (ModType)0, (DisplayType)4, (ModType)1);
					Plugin.SaveAlpinePuristBestTime(num2);
					if (flag)
					{
						ManualLogSource log3 = Plugin.Log;
						if (log3 != null)
						{
							log3.LogInfo((object)$"[AlpinePurist] First speedrun logged: {num2:F2}s");
						}
					}
					else
					{
						ManualLogSource log4 = Plugin.Log;
						if (log4 != null)
						{
							log4.LogInfo((object)$"[AlpinePurist] New best: {num2:F2}s (prev {num4:F2}s)");
						}
					}
				}
				else
				{
					ManualLogSource log5 = Plugin.Log;
					if (log5 != null)
					{
						log5.LogInfo((object)$"[AlpinePurist] Run time {num2:F2}s (not a best — {num4:F2}s still stands)");
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log6 = Plugin.Log;
				if (log6 != null)
				{
					log6.LogWarning((object)("[AlpinePurist] Speedrun log failed: " + ex.Message));
				}
			}
		}
	}
	[HarmonyPatch(typeof(Trinket), "GetDescription")]
	public static class WallRunnerTitleYellowPatch
	{
		private const string YellowHex = "#FFEB1A";

		[HarmonyPrefix]
		public static bool Prefix(Trinket __instance, ref string __result)
		{
			if (((__instance != null) ? ((Object)__instance).name : null) == null)
			{
				return true;
			}
			if (!((Object)__instance).name.Contains("cici_wall_runner"))
			{
				return true;
			}
			__result = "<color=grey>Trinket:</color> <color=#FFEB1A><shimmer s=0.1>" + __instance.title + "</shimmer>. </color>" + __instance.description + "\n<color=grey>" + __instance.flavorText + "</color>";
			return false;
		}
	}
	[HarmonyPatch(typeof(CL_AssetManager), "GetAssetGameObject")]
	public static class AxeAssetLookupPatch
	{
		[HarmonyPostfix]
		public static void Postfix(string name, ref GameObject __result)
		{
			if ((Object)(object)__result != (Object)null)
			{
				return;
			}
			if (name == "ClimbingAxe")
			{
				try
				{
					Plugin.EnsureAxeTemplate();
				}
				catch
				{
				}
				if ((Object)(object)Plugin.AxeTemplate != (Object)null)
				{
					__result = ((Component)Plugin.AxeTemplate).gameObject;
				}
			}
			else if (name == "ClimbingAxe_Red")
			{
				try
				{
					Plugin.EnsureRedAxeTemplate();
				}
				catch
				{
				}
				if ((Object)(object)Plugin.RedAxeTemplate != (Object)null)
				{
					__result = ((Component)Plugin.RedAxeTemplate).gameObject;
				}
			}
		}
	}
	[HarmonyPatch(typeof(HandItem), "Initialize")]
	public static class AxeRangePatch
	{
		[HarmonyPostfix]
		public static void Postfix(HandItem __instance, Item i)
		{
			if (!(i?.itemTag != "climbingaxe"))
			{
				HandItem_Melee val = (HandItem_Melee)(object)((__instance is HandItem_Melee) ? __instance : null);
				if (val != null)
				{
					val.range = 4f;
					val.canCharge = true;
					val.minimumChargeAttackTime = 0.05f;
					val.chargeAttackDamage = 1f;
				}
			}
		}
	}
	[HarmonyPatch(typeof(HandItem_Melee), "Use")]
	public static class AxeAutoReleasePatch
	{
		[HarmonyPostfix]
		public static void Postfix(HandItem_Melee __instance)
		{
			if (!(((HandItem)(__instance?)).item?.itemTag != "climbingaxe") && !((HandItem)__instance).used && !AxeModHandler.HasPendingAutoRelease(__instance))
			{
				AxeModHandler.ScheduleAutoRelease(__instance, 0.5f);
			}
		}
	}
	[HarmonyPatch(typeof(HandItem_Melee), "Hit")]
	public static class AxeHitPatch
	{
		internal static readonly FieldInfo _hitField = AccessTools.Field(typeof(HandItem_Melee), "hit");

		internal static readonly FieldInfo _hasHitField = AccessTools.Field(typeof(HandItem_Melee), "hasHit");

		internal static readonly FieldInfo _hitTaggerField = AccessTools.Field(typeof(HandItem_Melee), "hitTagger");

		internal static readonly FieldInfo _grabAnywhereHitField = AccessTools.Field(typeof(ENT_Player), "grabAnywhereHit");

		internal static readonly FieldInfo _grabAnywherePositionField = AccessTools.Field(typeof(ENT_Player), "grabAnywherePosition");

		public static bool OurAxeIsHitting;

		public const float RedAxeDamageMultiplier = 1.5f;

		private static bool _damageBoostActive;

		private static float _cachedDamage;

		private static float _cachedChargeDamage;

		[HarmonyPrefix]
		public static void Prefix(HandItem_Melee __instance)
		{
			if (((HandItem)(__instance?)).item?.itemTag == "climbingaxe")
			{
				OurAxeIsHitting = true;
				AxeModHandler.MarkAxeUsedNow(((HandItem)__instance).item);
				if (((HandItem)__instance).item.prefabName == "ClimbingAxe_Red")
				{
					_cachedDamage = __instance.damage;
					_cachedChargeDamage = __instance.chargeAttackDamage;
					__instance.damage = _cachedDamage * 1.5f;
					__instance.chargeAttackDamage = _cachedChargeDamage * 1.5f;
					_damageBoostActive = true;
				}
			}
		}

		[HarmonyPostfix]
		public static void Postfix(HandItem_Melee __instance)
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			if (_damageBoostActive && (Object)(object)__instance != (Object)null)
			{
				__instance.damage = _cachedDamage;
				__instance.chargeAttackDamage = _cachedChargeDamage;
				_damageBoostActive = false;
			}
			bool flag = ((HandItem)(__instance?)).item?.itemTag == "climbingaxe";
			if (flag)
			{
				OurAxeIsHitting = false;
			}
			if (!flag)
			{
				return;
			}
			bool flag2 = (bool)(_hasHitField?.GetValue(__instance) ?? ((object)false));
			RaycastHit hit = (RaycastHit)_hitField.GetValue(__instance);
			object? value = _hitTaggerField.GetValue(__instance);
			ObjectTagger val = (ObjectTagger)((value is ObjectTagger) ? value : null);
			if (flag2 && Plugin.AxeHitClips.Count > 0)
			{
				AudioClip val2 = Plugin.AxeHitClips[Random.Range(0, Plugin.AxeHitClips.Count)];
				if ((Object)(object)val2 != (Object)null)
				{
					AudioSource.PlayClipAtPoint(val2, ((RaycastHit)(ref hit)).point);
				}
			}
			if (flag2)
			{
				try
				{
					CL_CameraControl.Shake(0.025f);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Shake failed: " + ex.Message));
				}
			}
			bool flag3 = flag2;
			if (flag3 && Plugin.GetDurability(((HandItem)__instance).item) <= 0)
			{
				flag3 = false;
			}
			if (flag3 && (Object)(object)((RaycastHit)(ref hit)).collider != (Object)null && (Object)(object)((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent<CL_Handhold>() != (Object)null)
			{
				flag3 = false;
			}
			if (flag3 && (Object)(object)val != (Object)null && val.HasTag("Damageable"))
			{
				flag3 = false;
			}
			if (flag3 && AxeModHandler.HasActiveLodge(__instance))
			{
				flag3 = false;
			}
			if (flag3)
			{
				AxeModHandler.QueuePendingLodge(__instance, hit, 0f);
			}
			else
			{
				AxeModHandler.DislodgeAxe(__instance);
			}
		}

		internal static void DoLodgeNow(HandItem_Melee axe, RaycastHit hit)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			SpawnTempHandhold(axe, hit);
		}

		private static void SpawnTempHandhold(HandItem_Melee axe, RaycastHit hit)
		{
			//IL_05e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0673: Unknown result type (might be due to invalid IL or missing references)
			//IL_068a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0631: Unknown result type (might be due to invalid IL or missing references)
			//IL_0636: Unknown result type (might be due to invalid IL or missing references)
			//IL_063b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0640: Unknown result type (might be due to invalid IL or missing references)
			//IL_0644: Unknown result type (might be due to invalid IL or missing references)
			//IL_0649: Unknown result type (might be due to invalid IL or missing references)
			//IL_0623: Unknown result type (might be due to invalid IL or missing references)
			//IL_064e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0665: Unknown result type (might be due to invalid IL or missing references)
			//IL_065e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0667: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Expected O, but got Unknown
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0403: Unknown result type (might be due to invalid IL or missing references)
			//IL_0408: Unknown result type (might be due to invalid IL or missing references)
			//IL_041c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Unknown result type (might be due to invalid IL or missing references)
			//IL_0426: Unknown result type (might be due to invalid IL or missing references)
			//IL_042b: Unknown result type (might be due to invalid IL or missing references)
			//IL_042f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0434: Unknown result type (might be due to invalid IL or missing references)
			//IL_0453: Unknown result type (might be due to invalid IL or missing references)
			//IL_0458: Unknown result type (might be due to invalid IL or missing references)
			//IL_045d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0462: Unknown result type (might be due to invalid IL or missing references)
			//IL_0467: Unknown result type (might be due to invalid IL or missing references)
			//IL_046c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0471: Unknown result type (might be due to invalid IL or missing references)
			//IL_0478: Unknown result type (might be due to invalid IL or missing references)
			//IL_047a: Unknown result type (might be due to invalid IL or missing references)
			//IL_047f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0481: Unknown result type (might be due to invalid IL or missing references)
			//IL_0483: Unknown result type (might be due to invalid IL or missing references)
			//IL_0485: Unknown result type (might be due to invalid IL or missing references)
			//IL_048a: Unknown result type (might be due to invalid IL or missing references)
			//IL_044a: Unknown result type (might be due to invalid IL or missing references)
			//IL_044f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0509: Unknown result type (might be due to invalid IL or missing references)
			//IL_050b: Unknown result type (might be due to invalid IL or missing references)
			//IL_051e: Unknown result type (might be due to invalid IL or missing references)
			//IL_052d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0541: Unknown result type (might be due to invalid IL or missing references)
			//IL_0588: Unknown result type (might be due to invalid IL or missing references)
			//IL_058d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0599: Unknown result type (might be due to invalid IL or missing references)
			//IL_059e: Unknown result type (might be due to invalid IL or missing references)
			if (AxeModHandler.HasActiveLodge(axe) && AxeModHandler.DislodgeAndReportBreak(axe))
			{
				return;
			}
			ENT_Player playerObject = ENT_Player.playerObject;
			if ((Object)(object)playerObject == (Object)null || ((Hand_Base)axe).hand == null)
			{
				Plugin.Log.LogWarning((object)"SpawnTempHandhold: player or axe.hand is null");
				return;
			}
			int id = ((Hand_Base)axe).hand.id;
			CL_Handhold[] grabAnywhereFakeHandholds = playerObject.grabAnywhereFakeHandholds;
			if (grabAnywhereFakeHandholds == null || grabAnywhereFakeHandholds.Length <= id || (Object)(object)grabAnywhereFakeHandholds[id] == (Object)null)
			{
				Plugin.Log.LogWarning((object)"grabAnywhereFakeHandholds not set up on player");
				return;
			}
			CL_Handhold val = grabAnywhereFakeHandholds[id];
			try
			{
				Transform[] array = _grabAnywhereHitField?.GetValue(playerObject) as Transform[];
				Vector3[] array2 = _grabAnywherePositionField?.GetValue(playerObject) as Vector3[];
				if (array != null)
				{
					array[id] = ((Component)((RaycastHit)(ref hit)).collider).transform;
				}
				if (array2 != null)
				{
					array2[id] = ((Component)((RaycastHit)(ref hit)).collider).transform.InverseTransformPoint(((RaycastHit)(ref hit)).point);
				}
				((Component)val).transform.position = ((RaycastHit)(ref hit)).point;
				((Component)val).transform.rotation = Quaternion.identity;
				((Component)val).gameObject.SetActive(true);
				GameObject val2 = null;
				Vector3 val13;
				try
				{
					GameObject val3 = ((((HandItem)(axe?)).item?.prefabName == "ClimbingAxe_Red") ? Plugin.RedAxePrefab : Plugin.AxePrefab);
					GameObject val4 = val3 ?? Plugin.AxePrefab ?? CL_AssetManager.GetAssetGameObject("Item_Hammer", "");
					if ((Object)(object)val4 != (Object)null)
					{
						GameObject val5 = new GameObject("AxeStuckTemp");
						val5.SetActive(false);
						val2 = Object.Instantiate<GameObject>(val4, val5.transform);
						((Object)val2).name = "ClimbingAxe_LodgedVisual";
						Collider[] componentsInChildren = val2.GetComponentsInChildren<Collider>(true);
						foreach (Collider val6 in componentsInChildren)
						{
							Object.DestroyImmediate((Object)(object)val6);
						}
						Rigidbody[] componentsInChildren2 = val2.GetComponentsInChildren<Rigidbody>(true);
						foreach (Rigidbody val7 in componentsInChildren2)
						{
							Object.DestroyImmediate((Object)(object)val7);
						}
						Item_Object[] componentsInChildren3 = val2.GetComponentsInChildren<Item_Object>(true);
						foreach (Item_Object val8 in componentsInChildren3)
						{
							Object.DestroyImmediate((Object)(object)val8);
						}
						CL_Prop[] componentsInChildren4 = val2.GetComponentsInChildren<CL_Prop>(true);
						foreach (CL_Prop val9 in componentsInChildren4)
						{
							Object.DestroyImmediate((Object)(object)val9);
						}
						CL_Handhold[] componentsInChildren5 = val2.GetComponentsInChildren<CL_Handhold>(true);
						foreach (CL_Handhold val10 in componentsInChildren5)
						{
							Object.DestroyImmediate((Object)(object)val10);
						}
						List<Transform> list = new List<Transform>();
						Transform[] componentsInChildren6 = val2.GetComponentsInChildren<Transform>(true);
						foreach (Transform val11 in componentsInChildren6)
						{
							if (!((Object)(object)val11 == (Object)null) && ((Object)((Component)val11).gameObject).name.StartsWith("Scan_Target"))
							{
								list.Add(val11);
							}
						}
						foreach (Transform item in list)
						{
							if ((Object)(object)item != (Object)null)
							{
								Object.DestroyImmediate((Object)(object)((Component)item).gameObject);
							}
						}
						int layer = LayerMask.NameToLayer("Ignore Raycast");
						Transform[] componentsInChildren7 = val2.GetComponentsInChildren<Transform>(true);
						foreach (Transform val12 in componentsInChildren7)
						{
							((Component)val12).gameObject.layer = layer;
						}
						Plugin.ApplyGameShader(val2);
						Transform currentLevelParentRoot = WorldLoader.GetCurrentLevelParentRoot();
						if ((Object)(object)currentLevelParentRoot != (Object)null)
						{
							val2.transform.SetParent(currentLevelParentRoot, false);
						}
						val2.transform.position = ((RaycastHit)(ref hit)).point + ((RaycastHit)(ref hit)).normal * 0.1f;
						Camera main = Camera.main;
						val13 = Vector3.Cross(((RaycastHit)(ref hit)).normal, Vector3.up);
						Vector3 val14 = ((Vector3)(ref val13)).normalized;
						if (((Vector3)(ref val14)).sqrMagnitude < 0.001f)
						{
							val14 = Vector3.right;
						}
						Quaternion val15 = Quaternion.LookRotation(-((RaycastHit)(ref hit)).normal) * Quaternion.Euler(Plugin.LodgedAxeEulerOffset);
						Quaternion val16 = Quaternion.AngleAxis(40f, val14);
						Quaternion rotation = val16 * val15;
						Transform parent = val2.transform.parent;
						Vector3 val17 = (((Object)(object)parent != (Object)null) ? parent.lossyScale : Vector3.one);
						Vector3 val18 = default(Vector3);
						((Vector3)(ref val18))..ctor((val17.x < 0f) ? (-1f) : 1f, (val17.y < 0f) ? (-1f) : 1f, (val17.z < 0f) ? (-1f) : 1f);
						bool flag = val18 != Vector3.one;
						val2.transform.rotation = rotation;
						val2.transform.localScale = val18;
						float y = ((Component)((RaycastHit)(ref hit)).collider).transform.eulerAngles.y;
						UT_SoftParent val19 = val2.AddComponent<UT_SoftParent>();
						val19.Initialize(((Component)((RaycastHit)(ref hit)).collider).transform);
						if ((Object)(object)val19.parent != (Object)null)
						{
							AxeLodgeRotationFix.Track(val19, Quaternion.Inverse(val19.parent.rotation) * val2.transform.rotation);
						}
						val2.SetActive(true);
						Object.Destroy((Object)(object)val5);
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Stuck-axe visual spawn failed: " + ex.Message));
				}
				val13 = Vector3.ProjectOnPlane(((RaycastHit)(ref hit)).normal, Vector3.up);
				Vector3 wallNormal = ((Vector3)(ref val13)).normalized;
				if (((Vector3)(ref wallNormal)).sqrMagnitude < 0.001f)
				{
					Camera main2 = Camera.main;
					Vector3 val20;
					if (!((Object)(object)main2 != (Object)null))
					{
						val20 = Vector3.forward;
					}
					else
					{
						val13 = Vector3.ProjectOnPlane(((Component)main2).transform.forward, Vector3.up);
						val20 = -((Vector3)(ref val13)).normalized;
					}
					Vector3 val21 = val20;
					wallNormal = ((((Vector3)(ref val21)).sqrMagnitude > 0.001f) ? val21 : Vector3.forward);
				}
				AxeModHandler.RegisterHandhold(axe, ((Component)val).gameObject, val2, wallNormal);
				try
				{
					((Hand_Base)axe).hand.GrabHold(((Component)val).transform, ((RaycastHit)(ref hit)).point, (InteractionInfo)null);
					((Hand_Base)axe).hand.lockHand = true;
				}
				catch (Exception ex2)
				{
					Plugin.Log.LogWarning((object)("GrabHold failed: " + ex2.Message));
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"SpawnTempHandhold failed: {arg}");
			}
		}
	}
	public class AxeModHandler : MonoBehaviour
	{
		private struct ActiveLodge
		{
			public GameObject handhold;

			public GameObject stuckVisual;

			public bool firstPersonHidden;

			public Hand hand;

			public Item axeItem;

			public Vector3 wallNormal;
		}

		private struct PendingLodge
		{
			public float fireAt;

			public RaycastHit hit;
		}

		private struct AxeAppearance
		{
			public bool IsRed;

			public bool IsBroken;
		}

		private struct CachedRender
		{
			public Mesh Mesh;

			public Material[] Materials;
		}

		[CompilerGenerated]
		private sealed class <TopUpAlpinePuristAxesNextFrame>d__31 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public AxeModHandler <>4__this;

			private Inventory <inv>5__1;

			private int <redCount>5__2;

			private int <toAdd>5__3;

			private List<Item>.Enumerator <>s__4;

			private Item <it>5__5;

			private ItemHand[] <>s__6;

			private int <>s__7;

			private ItemHand <hand>5__8;

			private int <i>5__9;

			private Item <clone>5__10;

			private Exception <ex>5__11;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <TopUpAlpinePuristAxesNextFrame>d__31(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<inv>5__1 = null;
				<>s__4 = default(List<Item>.Enumerator);
				<it>5__5 = null;
				<>s__6 = null;
				<hand>5__8 = null;
				<clone>5__10 = null;
				<ex>5__11 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0215: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					try
					{
						Plugin.EnsureRedAxeTemplate();
					}
					catch
					{
					}
					if ((Object)(object)Plugin.RedAxeTemplate == (Object)null)
					{
						return false;
					}
					<inv>5__1 = Inventory.instance;
					if ((Object)(object)<inv>5__1 == (Object)null)
					{
						return false;
					}
					<redCount>5__2 = 0;
					if (<inv>5__1.bagItems != null)
					{
						<>s__4 = <inv>5__1.bagItems.GetEnumerator();
						try
						{
							while (<>s__4.MoveNext())
							{
								<it>5__5 = <>s__4.Current;
								if (IsRedAxe(<it>5__5))
								{
									<redCount>5__2++;
								}
								<it>5__5 = null;
							}
						}
						finally
						{
							((IDisposable)<>s__4).Dispose();
						}
						<>s__4 = default(List<Item>.Enumerator);
					}
					if (<inv>5__1.itemHands != null)
					{
						<>s__6 = <inv>5__1.itemHands;
						for (<>s__7 = 0; <>s__7 < <>s__6.Length; <>s__7++)
						{
							<hand>5__8 = <>s__6[<>s__7];
							if (<hand>5__8 != null && IsRedAxe(<hand>5__8.currentItem))
							{
								<redCount>5__2++;
							}
							<hand>5__8 = null;
						}
						<>s__6 = null;
					}
					<toAdd>5__3 = Math.Max(0, 2 - <redCount>5__2);
					<i>5__9 = 0;
					while (<i>5__9 < <toAdd>5__3)
					{
						try
						{
							<clone>5__10 = Plugin.RedAxeTemplate.itemData.GetClone((Item)null);
							<inv>5__1.AddItemToInventoryScreen(new Vector3(0.15f * ((float)<i>5__9 - 0.5f), 0.1f, 1f), <clone>5__10, true, false, true);
							<clone>5__10 = null;
						}
						catch (Exception ex)
						{
							<ex>5__11 = ex;
							ManualLogSource log = Plugin.Log;
							if (log != null)
							{
								log.LogWarning((object)("[AlpinePurist] Revive top-up failed: " + <ex>5__11.Message));
							}
						}
						<i>5__9++;
					}
					if (<toAdd>5__3 > 0)
					{
						ManualLogSource log2 = Plugin.Log;
						if (log2 != null)
						{
							log2.LogInfo((object)$"[AlpinePurist] Revive top-up — added {<toAdd>5__3} red axe(s)");
						}
					}
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private bool _jumpHookInstalled;

		private bool _wasDead;

		private static readonly FieldInfo _gManDeadField = AccessTools.Field(typeof(CL_GameManager), "dead");

		private static readonly Dictionary<HandItem_Melee, ActiveLodge> _activeLodges = new Dictionary<HandItem_Melee, ActiveLodge>();

		private static readonly Dictionary<HandItem_Melee, PendingLodge> _pendingLodges = new Dictionary<HandItem_Melee, PendingLodge>();

		private static readonly Dictionary<Item, float> _lastUseTime = new Dictionary<Item, float>();

		private float _nextRegenCheck;

		private static readonly MaterialPropertyBlock _mpb = new MaterialPropertyBlock();

		private static readonly int _colorId = Shader.PropertyToID("_Color");

		private static readonly Dictionary<HandItem_Melee, float> _pendingAutoReleases = new Dictionary<HandItem_Melee, float>();

		private static readonly Dictionary<Item_Object, AxeAppearance> _lastAppliedAppearance = new Dictionary<Item_Object, AxeAppearance>();

		private static readonly Dictionary<GameObject, CachedRender> _cachedRenderByPrefab = new Dictionary<GameObject, CachedRender>();

		private void OnEnable()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnCameraPreCull));
		}

		private void OnDisable()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnCameraPreCull));
		}

		private void OnCameraPreCull(Camera cam)
		{
			if (!((Object)(object)cam != (Object)(object)Camera.main))
			{
				UpdateTintAndSlide();
			}
		}

		private void UpdateTintAndSlide()
		{
			ENT_Player playerObject = ENT_Player.playerObject;
			if ((Object)(object)playerObject == (Object)null || playerObject.hands == null)
			{
				return;
			}
			Hand[] hands = playerObject.hands;
			foreach (Hand val in hands)
			{
				if (val == null)
				{
					continue;
				}
				HandItem handItem = val.GetHandItem();
				if (!(handItem?.item?.itemTag != "climbingaxe"))
				{
					Sprite spriteForDurability = Plugin.GetSpriteForDurability(handItem.item);
					SwapHandItemMeshIfNeeded(handItem);
					SwapHandItemWeaponSpriteIfNeeded(handItem, spriteForDurability);
					HandItem_Melee val2 = (HandItem_Melee)(object)((handItem is HandItem_Melee) ? handItem : null);
					if (val2 != null)
					{
						UpdateAimCircleForAxe(playerObject, val2);
					}
					HandItem_Melee val3 = (HandItem_Melee)(object)((handItem is HandItem_Melee) ? handItem : null);
					if (val3 != null && _activeLodges.TryGetValue(val3, out var value) && !((Object)(object)value.handhold != (Object)null))
					{
					}
				}
			}
		}

		public static Vector3 GetWallNormalForHand(Hand hand)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if (hand == null)
			{
				return Vector3.zero;
			}
			foreach (KeyValuePair<HandItem_Melee, ActiveLodge> activeLodge in _activeLodges)
			{
				ActiveLodge value = activeLodge.Value;
				if (!((Object)(object)value.handhold == (Object)null))
				{
					CL_Handhold component = value.handhold.GetComponent<CL_Handhold>();
					if ((Object)(object)hand.handhold == (Object)(object)component)
					{
						return value.wallNormal;
					}
				}
			}
			return Vector3.zero;
		}

		public static void QueuePendingLodge(HandItem_Melee axe, RaycastHit hit, float delay)
		{
			//IL_002c: 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)
			if (!((Object)(object)axe == (Object)null))
			{
				_pendingLodges[axe] = new PendingLodge
				{
					fireAt = Time.time + delay,
					hit = hit
				};
			}
		}

		public static void CancelPendingLodge(HandItem_Melee axe)
		{
			if (!((Object)(object)axe == (Object)null))
			{
				_pendingLodges.Remove(axe);
			}
		}

		public static bool HasActiveLodge(HandItem_Melee axe)
		{
			return (Object)(object)axe != (Object)null && _activeLodges.ContainsKey(axe);
		}

		public static void Ma