Decompiled source of Altar of the Pack v0.1.2

plugins/WolfShrine/WolfShrine.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("WolfShrine")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.2.0")]
[assembly: AssemblyInformationalVersion("0.1.2")]
[assembly: AssemblyProduct("WolfShrine")]
[assembly: AssemblyTitle("WolfShrine")]
[assembly: AssemblyVersion("0.1.2.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace WolfShrine
{
	internal static class BlessedWolves
	{
		internal sealed class Growth
		{
			internal Character Source;

			internal Character Adult;

			internal float Factor;

			internal float Fraction;

			internal Vector3 Position;
		}

		internal const string BonusKey = "wolfshrine.health";

		internal const string BirthKey = "wolfshrine.birth";

		internal const string OriginKey = "wolfshrine.origin";

		[ThreadStatic]
		internal static Growth? Growing;

		internal static bool FromShrine(Character? character)
		{
			if (character == null || !IsWolf(character))
			{
				return false;
			}
			ZNetView component = ((Component)character).GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)component) && component.IsValid())
			{
				if (!component.GetZDO().GetBool("wolfshrine.origin", false) && !(component.GetZDO().GetFloat("wolfshrine.health", 0f) >= 1f))
				{
					return component.GetZDO().GetString("wolfshrine.birth", "").Length > 0;
				}
				return true;
			}
			return false;
		}

		internal static bool IsWolf(Character character)
		{
			if (Object.op_Implicit((Object)(object)character))
			{
				if (!(((Object)character).name == "Wolf") && !(((Object)character).name == "Wolf(Clone)") && !(((Object)character).name == "Wolf_cub"))
				{
					return ((Object)character).name == "Wolf_cub(Clone)";
				}
				return true;
			}
			return false;
		}

		internal static float Bonus(Character character)
		{
			if (!IsWolf(character))
			{
				return 1f;
			}
			ZNetView component = ((Component)character).GetComponent<ZNetView>();
			float num = ((Object.op_Implicit((Object)(object)component) && component.IsValid()) ? component.GetZDO().GetFloat("wolfshrine.health", 1f) : 1f);
			if (!(num >= 1f) || !(num <= 10f) || float.IsNaN(num))
			{
				return 1f;
			}
			return num;
		}

		internal static void Mark(Character character, float factor)
		{
			ZNetView component = ((Component)character).GetComponent<ZNetView>();
			if (!IsWolf(character) || !Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner())
			{
				throw new InvalidOperationException("Shrine wolf is not a valid owned wolf.");
			}
			component.GetZDO().Set("wolfshrine.health", factor);
			component.GetZDO().Set("wolfshrine.origin", true);
		}
	}
	[HarmonyPatch(typeof(Character), "GetMaxHealthBase")]
	internal static class ShrineWolfHealth
	{
		private static void Postfix(Character __instance, ref float __result)
		{
			__result = RitualPolicy.Health(__result, BlessedWolves.Bonus(__instance));
		}
	}
	[HarmonyPatch(typeof(Growup), "GrowUpdate")]
	internal static class PreserveShrineGrowth
	{
		private static void Prefix(Growup __instance, out BlessedWolves.Growth? __state)
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			__state = BlessedWolves.Growing;
			Character component = ((Component)__instance).GetComponent<Character>();
			ZNetView component2 = ((Component)__instance).GetComponent<ZNetView>();
			float factor = (Object.op_Implicit((Object)(object)component) ? BlessedWolves.Bonus(component) : 1f);
			if (BlessedWolves.FromShrine(component))
			{
				__instance.m_inheritTame = true;
			}
			BlessedWolves.Growing = ((Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component2) && component2.IsValid() && component2.IsOwner() && BlessedWolves.FromShrine(component)) ? new BlessedWolves.Growth
			{
				Source = component,
				Factor = factor,
				Fraction = Mathf.Clamp01(component.GetHealthPercentage()),
				Position = ((Component)component).transform.position
			} : null);
		}

		private static void Finalizer(BlessedWolves.Growth? __state)
		{
			BlessedWolves.Growing = __state;
		}
	}
	[HarmonyPatch(typeof(Character), "SetLevel")]
	internal static class InheritShrineHealth
	{
		private static void Prefix(Character __instance)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			BlessedWolves.Growth growing = BlessedWolves.Growing;
			if (growing != null && !((Object)(object)__instance == (Object)(object)growing.Source) && BlessedWolves.IsWolf(__instance) && !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<Growup>()))
			{
				Vector3 val = ((Component)__instance).transform.position - growing.Position;
				if (!(((Vector3)(ref val)).sqrMagnitude > 4f) && (!Object.op_Implicit((Object)(object)growing.Adult) || !((Object)(object)growing.Adult != (Object)(object)__instance)))
				{
					BlessedWolves.Mark(__instance, growing.Factor);
					growing.Adult = __instance;
				}
			}
		}

		private static void Postfix(Character __instance)
		{
			BlessedWolves.Growth growing = BlessedWolves.Growing;
			if (growing != null && (Object)(object)growing.Adult == (Object)(object)__instance)
			{
				__instance.SetHealth(__instance.GetMaxHealth() * growing.Fraction);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerController), "TakeInput")]
	internal static class ShrinePopupController
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(PlayerController __instance, ref bool __result)
		{
			if (WolfAltar.PopupOpen && (Object)(object)((Component)__instance).GetComponent<Player>() == (Object)(object)Player.m_localPlayer)
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "TakeInput")]
	internal static class ShrinePopupPlayer
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(Player __instance, ref bool __result)
		{
			if (WolfAltar.PopupOpen && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(Piece), "CanBeRemoved")]
	internal static class KeepActiveAltar
	{
		private static bool Prefix(Piece __instance, ref bool __result)
		{
			WolfAltar component = ((Component)__instance).GetComponent<WolfAltar>();
			if (!Object.op_Implicit((Object)(object)component) || !component.Busy)
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[BepInPlugin("com.jason.wolfshrine", "Altar of the Pack", "0.1.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Id = "com.jason.wolfshrine";

		public const string Version = "0.1.2";

		internal static ManualLogSource Log;

		internal static ConfigEntry<string>[] Recipes;

		internal static ConfigEntry<float> HealthBonus;

		internal static ConfigEntry<float> RitualSeconds;

		internal static ConfigEntry<float> Cooldown;

		private Harmony patches;

		private void Awake()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Expected O, but got Unknown
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ConfigurationManagerAttributes val = new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			};
			Recipes = new ConfigEntry<string>[3]
			{
				((BaseUnityPlugin)this).Config.Bind<string>("Offerings", "ZeroStar", "WolfMeat:5,WolfPelt:2,BoneFragments:5", new ConfigDescription("0-star cub offering, exact prefab:amount pairs. Server synchronized.", (AcceptableValueBase)null, new object[1] { val })),
				((BaseUnityPlugin)this).Config.Bind<string>("Offerings", "OneStar", "WolfMeat:10,WolfPelt:4,WolfFang:2,TrophyWolf:1,Silver:2", new ConfigDescription("1-star cub offering.", (AcceptableValueBase)null, new object[1] { val })),
				((BaseUnityPlugin)this).Config.Bind<string>("Offerings", "TwoStar", "WolfMeat:20,WolfPelt:8,WolfFang:5,TrophyWolf:2,Silver:5", new ConfigDescription("2-star cub offering.", (AcceptableValueBase)null, new object[1] { val }))
			};
			HealthBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "ShrineWolfHealthMultiplier", 3f, new ConfigDescription("Health relative to an ordinary wolf of the same star tier. Stored on each shrine-born cub; follows it into adulthood. Damage unchanged; wild/bred wolves unchanged.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), new object[1] { val }));
			RitualSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "RitualSeconds", 6f, new ConfigDescription("Delay before the cub appears; blocked exits wait without consuming again.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), new object[1] { val }));
			Cooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "CooldownSeconds", 60f, new ConfigDescription("Per-shrine cooldown after birth.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3600f), new object[1] { val }));
			patches = new Harmony("com.jason.wolfshrine");
			patches.PatchAll();
			PrefabManager.OnVanillaPrefabsAvailable += ShrinePrefab.Register;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Altar of the Pack 0.1.2 loaded: born-tame 0/1/2-star cubs; default 3x health through adulthood.");
		}

		private void OnDestroy()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= ShrinePrefab.Register;
			Harmony obj = patches;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}

		private void Update()
		{
			if (WolfAltar.PopupOpen && (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !UnifiedPopup.IsVisible()))
			{
				WolfAltar.PopupOpen = false;
			}
			WolfUnlock.Update();
		}
	}
	internal static class RitualPolicy
	{
		internal const int MaxTier = 2;

		internal static bool Tier(int tier)
		{
			if (tier >= 0)
			{
				return tier <= 2;
			}
			return false;
		}

		internal static int Level(int tier)
		{
			if (!Tier(tier))
			{
				throw new ArgumentOutOfRangeException("tier");
			}
			return tier + 1;
		}

		internal static float Health(float native, float factor)
		{
			float num = native * factor;
			if (!(native > 0f) || !(factor >= 1f) || !(factor <= 10f) || float.IsNaN(num) || float.IsInfinity(num))
			{
				return native;
			}
			return num;
		}

		internal static Dictionary<string, int>? Recipe(string value)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
			string[] array = value.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Trim().Split(new char[1] { ':' });
				if (array2.Length != 2 || array2[0].Length == 0 || array2[0].Any((char c) => !char.IsLetterOrDigit(c) && c != '_') || !int.TryParse(array2[1], NumberStyles.None, CultureInfo.InvariantCulture, out var result) || result < 1 || result > 999 || dictionary.ContainsKey(array2[0]))
				{
					return null;
				}
				dictionary.Add(array2[0], result);
			}
			if (dictionary.Count <= 0 || dictionary.Count > 12)
			{
				return null;
			}
			return dictionary;
		}

		internal static int[]? Debit(string[] identities, int[] amounts, IReadOnlyDictionary<string, int> costs)
		{
			if (identities.Length != amounts.Length || amounts.Any((int a) => a <= 0) || costs.Count == 0 || costs.Any<KeyValuePair<string, int>>((KeyValuePair<string, int> p) => p.Key.Length == 0 || p.Value <= 0))
			{
				return null;
			}
			int[] array = new int[amounts.Length];
			foreach (KeyValuePair<string, int> cost in costs)
			{
				int num = cost.Value;
				for (int num2 = 0; num2 < identities.Length; num2++)
				{
					if (num <= 0)
					{
						break;
					}
					if (identities[num2] == cost.Key)
					{
						num -= (array[num2] = Math.Min(amounts[num2], num));
					}
				}
				if (num > 0)
				{
					return null;
				}
			}
			return array;
		}

		internal static bool CanReserve(bool owner, bool access, bool alive, double distanceSquared, int tier, bool pending, double cooldown, double lease, double now)
		{
			if (owner && access && alive && distanceSquared >= 0.0 && distanceSquared <= 16.0 && Tier(tier) && !pending && cooldown <= now)
			{
				return lease <= now;
			}
			return false;
		}
	}
	internal static class ShrinePrefab
	{
		internal const string Name = "WolfShrine_AltarOfThePack";

		internal static void Register()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			//IL_033e: Unknown result type (might be due to invalid IL or missing references)
			//IL_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: 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_0454: Unknown result type (might be due to invalid IL or missing references)
			//IL_0466: Unknown result type (might be due to invalid IL or missing references)
			//IL_047b: Unknown result type (might be due to invalid IL or missing references)
			//IL_049a: Unknown result type (might be due to invalid IL or missing references)
			PrefabManager.OnVanillaPrefabsAvailable -= Register;
			try
			{
				GameObject prefab = PrefabManager.Instance.GetPrefab("TrophyWolf");
				GameObject prefab2 = PrefabManager.Instance.GetPrefab("Wolf_cub");
				if (!Object.op_Implicit((Object)(object)prefab) || !Object.op_Implicit((Object)(object)prefab2) || !Object.op_Implicit((Object)(object)prefab2.GetComponent<Character>()) || !Object.op_Implicit((Object)(object)prefab2.GetComponent<Growup>()))
				{
					throw new InvalidOperationException("Native wolf cub/trophy prefabs are missing.");
				}
				PieceConfig val = new PieceConfig();
				val.Name = "Altar of the Pack";
				val.Description = "Unlock by taming a wolf, or petting an existing ordinary tame wolf. Offer wolf remains to summon a born-tamed, hardy wolf cub. All three star tiers available. Use to review; alternate use changes the selected tier.";
				val.PieceTable = "Hammer";
				val.Category = "Crafting";
				val.CraftingStation = "";
				val.Requirements = (RequirementConfig[])(object)new RequirementConfig[3]
				{
					new RequirementConfig("Stone", 20, 0, true),
					new RequirementConfig("Silver", 5, 0, true),
					new RequirementConfig("TrophyWolf", 1, 0, true)
				};
				CustomPiece val2 = new CustomPiece("WolfShrine_AltarOfThePack", "stone_floor_2x2", val);
				GameObject piecePrefab = val2.PiecePrefab;
				piecePrefab.GetComponent<Piece>().m_icon = prefab.GetComponent<ItemDrop>().m_itemData.GetIcon();
				piecePrefab.GetComponent<Piece>().m_craftingStation = null;
				piecePrefab.GetComponent<Piece>().m_groundOnly = false;
				WearNTear component = piecePrefab.GetComponent<WearNTear>();
				MeshFilter val3 = ((Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.m_new)) ? component.m_new : piecePrefab).GetComponentsInChildren<MeshFilter>(true).Where(delegate(MeshFilter f)
				{
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					//IL_0025: Unknown result type (might be due to invalid IL or missing references)
					//IL_0028: 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_0044: Unknown result type (might be due to invalid IL or missing references)
					//IL_0047: Unknown result type (might be due to invalid IL or missing references)
					//IL_005e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0063: Unknown result type (might be due to invalid IL or missing references)
					//IL_0066: Unknown result type (might be due to invalid IL or missing references)
					if (Object.op_Implicit((Object)(object)f.sharedMesh) && Object.op_Implicit((Object)(object)((Component)f).GetComponent<MeshRenderer>()))
					{
						Bounds bounds = f.sharedMesh.bounds;
						if (((Bounds)(ref bounds)).size.x > 0.001f)
						{
							bounds = f.sharedMesh.bounds;
							if (((Bounds)(ref bounds)).size.y > 0.001f)
							{
								bounds = f.sharedMesh.bounds;
								return ((Bounds)(ref bounds)).size.z > 0.001f;
							}
						}
					}
					return false;
				}).OrderByDescending(delegate(MeshFilter f)
				{
					//IL_0006: Unknown result type (might be due to invalid IL or missing references)
					//IL_000b: Unknown result type (might be due to invalid IL or missing references)
					//IL_000e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					Bounds bounds = f.sharedMesh.bounds;
					Vector3 size = ((Bounds)(ref bounds)).size;
					return ((Vector3)(ref size)).sqrMagnitude;
				})
					.FirstOrDefault();
				if (Object.op_Implicit((Object)(object)val3))
				{
					StoneBlock(piecePrefab.transform, "Hewn altar body", val3, new Vector3(0f, 0.48f, 0f), new Vector3(1.42f, 0.52f, 1.04f), 0.72f);
					StoneBlock(piecePrefab.transform, "Offering capstone", val3, new Vector3(0f, 0.79f, -0.04f), new Vector3(1.66f, 0.18f, 1.25f), 0.8f);
					StoneBlock(piecePrefab.transform, "Wolf headstone", val3, new Vector3(0f, 1.18f, 0.43f), new Vector3(1.16f, 1.05f, 0.25f), 0.66f);
				}
				else
				{
					Plugin.Log.LogWarning((object)"Native stone mesh unavailable; retaining native altar base instead of preventing shrine registration.");
				}
				object obj = prefab.transform.Find("attach");
				if (obj == null)
				{
					obj = prefab.transform.Find("visual");
					if (obj == null)
					{
						Renderer componentInChildren = prefab.GetComponentInChildren<Renderer>(true);
						obj = ((componentInChildren != null) ? ((Component)componentInChildren).transform : null);
					}
				}
				if (!Object.op_Implicit((Object)obj))
				{
					throw new InvalidOperationException("Wolf trophy has no safe detachable visual.");
				}
				GameObject val4 = Object.Instantiate<GameObject>(((Component)obj).gameObject, piecePrefab.transform, false);
				((Object)val4).name = "Shrine wolf trophy";
				val4.transform.localPosition = new Vector3(0f, Object.op_Implicit((Object)(object)val3) ? 1.28f : 0.6f, 0.19f);
				val4.transform.localRotation = Quaternion.Euler(0f, 180f, 0f);
				val4.transform.localScale = Vector3.one * 0.65f;
				MonoBehaviour[] componentsInChildren = val4.GetComponentsInChildren<MonoBehaviour>(true);
				for (int num = 0; num < componentsInChildren.Length; num++)
				{
					Object.DestroyImmediate((Object)(object)componentsInChildren[num]);
				}
				Collider[] componentsInChildren2 = val4.GetComponentsInChildren<Collider>(true);
				for (int num = 0; num < componentsInChildren2.Length; num++)
				{
					Object.DestroyImmediate((Object)(object)componentsInChildren2[num]);
				}
				Rigidbody[] componentsInChildren3 = val4.GetComponentsInChildren<Rigidbody>(true);
				for (int num = 0; num < componentsInChildren3.Length; num++)
				{
					Object.DestroyImmediate((Object)(object)componentsInChildren3[num]);
				}
				Renderer[] componentsInChildren4 = val4.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer obj2 in componentsInChildren4)
				{
					obj2.sharedMaterials = obj2.sharedMaterials.Select((Material m) => Matte(m, 1f)).ToArray();
				}
				val4.SetActive(true);
				if (Object.op_Implicit((Object)(object)val3))
				{
					Runes(piecePrefab.transform);
				}
				GameObject val5 = new GameObject("Shrine light");
				val5.transform.SetParent(piecePrefab.transform, false);
				val5.transform.localPosition = new Vector3(0f, 1.05f, -0.48f);
				Light obj3 = val5.AddComponent<Light>();
				obj3.color = new Color(0.16f, 0.42f, 0.66f);
				obj3.range = 1.6f;
				obj3.intensity = 0.12f;
				piecePrefab.AddComponent<WolfAltar>();
				if (!PieceManager.Instance.AddPiece(val2))
				{
					throw new InvalidOperationException("Shrine piece registration rejected.");
				}
				Plugin.Log.LogInfo((object)"Registered Altar of the Pack in Hammer/Crafting: wolf-taming unlock, no crafting station; native Wolf_cub verified.");
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Wolf shrine registration failed; no ritual is available. {arg}");
			}
		}

		private static Material Matte(Material source, float shade)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_003a: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)source))
			{
				return source;
			}
			Material val = new Material(source)
			{
				name = "WolfShrine matte " + ((Object)source).name
			};
			if (val.HasProperty("_Color"))
			{
				Color color = val.GetColor("_Color");
				val.SetColor("_Color", new Color(color.r * shade, color.g * shade, color.b * shade, color.a));
			}
			if (val.HasProperty("_EmissionColor"))
			{
				val.SetColor("_EmissionColor", Color.black);
			}
			if (val.HasProperty("_Glossiness"))
			{
				val.SetFloat("_Glossiness", 0.08f);
			}
			if (val.HasProperty("_Metallic"))
			{
				val.SetFloat("_Metallic", 0f);
			}
			val.DisableKeyword("_EMISSION");
			return val;
		}

		private static void StoneBlock(Transform parent, string name, MeshFilter source, Vector3 centre, Vector3 size, float shade)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			Mesh sharedMesh = source.sharedMesh;
			Bounds bounds = sharedMesh.bounds;
			if (((Bounds)(ref bounds)).size.x <= 0.001f || ((Bounds)(ref bounds)).size.y <= 0.001f || ((Bounds)(ref bounds)).size.z <= 0.001f)
			{
				throw new InvalidOperationException("Native stone mesh has invalid bounds.");
			}
			GameObject val = new GameObject(name)
			{
				layer = ((Component)parent).gameObject.layer
			};
			val.transform.SetParent(parent, false);
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(size.x / ((Bounds)(ref bounds)).size.x, size.y / ((Bounds)(ref bounds)).size.y, size.z / ((Bounds)(ref bounds)).size.z);
			val.transform.localScale = val2;
			val.transform.localPosition = centre - Vector3.Scale(((Bounds)(ref bounds)).center, val2);
			val.AddComponent<MeshFilter>().sharedMesh = sharedMesh;
			((Renderer)val.AddComponent<MeshRenderer>()).sharedMaterials = ((Renderer)((Component)source).GetComponent<MeshRenderer>()).sharedMaterials.Select((Material m) => Matte(m, shade)).ToArray();
			val.AddComponent<MeshCollider>().sharedMesh = sharedMesh;
		}

		private static void Runes(Transform parent)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			//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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00b9: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: 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_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			Shader val = Shader.Find("Unlit/Color") ?? Shader.Find("Sprites/Default");
			if (!Object.op_Implicit((Object)(object)val))
			{
				Plugin.Log.LogWarning((object)"Rune shader unavailable; retaining the stone/trophy altar without rune inlays.");
				return;
			}
			Material sharedMaterial = new Material(val)
			{
				name = "WolfShrine muted blue rune",
				color = new Color(0.12f, 0.48f, 0.64f)
			};
			Vector2[][] array = new Vector2[4][]
			{
				(Vector2[])(object)new Vector2[4]
				{
					new Vector2(0f, 0f),
					new Vector2(0f, 0.18f),
					new Vector2(0.08f, 0.14f),
					new Vector2(0f, 0.1f)
				},
				(Vector2[])(object)new Vector2[4]
				{
					new Vector2(0f, 0f),
					new Vector2(0f, 0.18f),
					new Vector2(0.08f, 0.15f),
					new Vector2(0.08f, 0f)
				},
				(Vector2[])(object)new Vector2[3]
				{
					new Vector2(0f, 0f),
					new Vector2(0f, 0.18f),
					new Vector2(0.08f, 0.12f)
				},
				(Vector2[])(object)new Vector2[6]
				{
					new Vector2(0f, 0f),
					new Vector2(0f, 0.18f),
					new Vector2(0.08f, 0.18f),
					new Vector2(0f, 0.18f),
					new Vector2(0f, 0.1f),
					new Vector2(0.06f, 0.1f)
				}
			};
			for (int i = 0; i < array.Length; i++)
			{
				GameObject val2 = new GameObject("Carved pack rune " + i)
				{
					layer = ((Component)parent).gameObject.layer
				};
				val2.transform.SetParent(parent, false);
				LineRenderer val3 = val2.AddComponent<LineRenderer>();
				val3.useWorldSpace = false;
				((Renderer)val3).sharedMaterial = sharedMaterial;
				val3.widthMultiplier = 0.018f;
				val3.positionCount = array[i].Length;
				((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)val3).receiveShadows = false;
				for (int j = 0; j < array[i].Length; j++)
				{
					val3.SetPosition(j, new Vector3(-0.45f + (float)i * 0.28f + array[i][j].x, 0.46f + array[i][j].y, -0.545f));
				}
			}
		}
	}
	public sealed class WolfAltar : MonoBehaviour, Hoverable, Interactable
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static PopupButtonCallback <>9__35_1;

			public static Func<string, bool> <>9__37_0;

			public static Func<KeyValuePair<string, int>, string> <>9__38_0;

			public static Func<ItemData, int> <>9__40_0;

			public static Func<ItemData, int> <>9__42_0;

			public static Func<ItemData, int> <>9__42_1;

			internal void <Interact>b__35_1()
			{
				UnifiedPopup.Pop();
				PopupOpen = false;
			}

			internal bool <ValidRecipe>b__37_0(string id)
			{
				if (Object.op_Implicit((Object)(object)ObjectDB.instance))
				{
					return Object.op_Implicit((Object)(object)ObjectDB.instance.GetItemPrefab(id));
				}
				return false;
			}

			internal string <CostText>b__38_0(KeyValuePair<string, int> pair)
			{
				GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab(pair.Key) : null);
				ItemDrop val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<ItemDrop>() : null);
				return pair.Value + " " + (Object.op_Implicit((Object)(object)val2) ? Localization.instance.Localize(val2.m_itemData.m_shared.m_name) : pair.Key);
			}

			internal int <Offer>b__40_0(ItemData i)
			{
				return i.m_stack;
			}

			internal int <Commit>b__42_0(ItemData i)
			{
				return i.m_stack;
			}

			internal int <Commit>b__42_1(ItemData i)
			{
				return i.m_stack;
			}

			internal void <.cctor>b__53_0(Inventory inventory)
			{
				AccessTools.MethodDelegate<Action<Inventory, bool, bool>>(AccessTools.Method(typeof(Inventory), "Changed", (Type[])null, (Type[])null), (object)null, true)(inventory, arg2: false, arg3: false);
			}
		}

		internal static bool PopupOpen;

		private const string Lease = "ws_lease";

		private const string Holder = "ws_holder";

		private const string Expiry = "ws_expiry";

		private const string LeaseTier = "ws_lease_tier";

		private const string Pending = "ws_pending";

		private const string Due = "ws_due";

		private const string Star = "ws_star";

		private const string Bonus = "ws_bonus";

		private const string Paid = "ws_paid";

		private const string Next = "ws_next";

		private static readonly Func<PrivateArea, bool> WardEnabled = AccessTools.MethodDelegate<Func<PrivateArea, bool>>(AccessTools.Method(typeof(PrivateArea), "IsEnabled", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<PrivateArea, Vector3, float, bool> WardInside = AccessTools.MethodDelegate<Func<PrivateArea, Vector3, float, bool>>(AccessTools.Method(typeof(PrivateArea), "IsInside", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<PrivateArea, long, bool> WardPermitted = AccessTools.MethodDelegate<Func<PrivateArea, long, bool>>(AccessTools.Method(typeof(PrivateArea), "IsPermitted", (Type[])null, (Type[])null), (object)null, true);

		private ZNetView view;

		private int selectedTier;

		private string request = "";

		private bool answered;

		private bool granted;

		private bool requesting;

		private long expectedOwner;

		private float nextBirthCheck;

		private readonly HashSet<string> seen = new HashSet<string>();

		private readonly Queue<string> history = new Queue<string>();

		private static readonly Action<Inventory> InventoryChanged = delegate(Inventory inventory)
		{
			AccessTools.MethodDelegate<Action<Inventory, bool, bool>>(AccessTools.Method(typeof(Inventory), "Changed", (Type[])null, (Type[])null), (object)null, true)(inventory, arg2: false, arg3: false);
		};

		private static double Now => (double)ZNet.instance.GetTime().Ticks / 10000000.0;

		internal bool Busy
		{
			get
			{
				if (Object.op_Implicit((Object)(object)view) && view.IsValid())
				{
					if (view.GetZDO().GetString("ws_pending", "").Length <= 0)
					{
						return TimeAt(view.GetZDO(), "ws_expiry") > Now;
					}
					return true;
				}
				return false;
			}
		}

		private static double TimeAt(ZDO data, string key)
		{
			return (double)data.GetLong(key, 0L) / 10000000.0;
		}

		private static void SetTime(ZDO data, string key, double time)
		{
			data.Set(key, (long)(time * 10000000.0));
		}

		private void Awake()
		{
			view = ((Component)this).GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)view) && view.IsValid())
			{
				view.Register<string, int>("WS_Reserve", (Action<long, string, int>)Reserve);
				view.Register<string, bool>("WS_Granted", (Action<long, string, bool>)Response);
				WearNTear component = ((Component)this).GetComponent<WearNTear>();
				if (Object.op_Implicit((Object)(object)component))
				{
					component.m_onDestroyed = (Action)Delegate.Combine(component.m_onDestroyed, new Action(RefundDestroyed));
				}
			}
		}

		public string GetHoverName()
		{
			return "Altar of the Pack";
		}

		public float GetHoverOffset()
		{
			return 1f;
		}

		public string GetHoverText()
		{
			if (!Object.op_Implicit((Object)(object)view) || !view.IsValid())
			{
				return GetHoverName();
			}
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && !WolfUnlock.Has(Player.m_localPlayer))
			{
				return "Altar of the Pack\nTame a wolf, or pet an existing ordinary tame wolf, to unlock this shrine.";
			}
			ZDO zDO = view.GetZDO();
			if (zDO.GetString("ws_pending", "").Length > 0)
			{
				return GetHoverName() + "\nRitual in progress — keep the space beside the shrine clear.";
			}
			double num = TimeAt(zDO, "ws_next") - Now;
			string text = ((num > 0.0) ? $"\nResting: {Math.Ceiling(num)} seconds" : "");
			return Localization.instance.Localize($"Altar of the Pack — {selectedTier}-star cub\nBorn tamed; {Plugin.HealthBonus.Value:0.#}× health through adulthood.\n{CostText(selectedTier)}{text}\n[<color=yellow>$KEY_Use</color>] Review offering\n[<color=yellow>$KEY_AltPlace + $KEY_Use</color>] Next star tier");
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			return false;
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Expected O, but got Unknown
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Expected O, but got Unknown
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Expected O, but got Unknown
			if (hold || (Object)(object)user != (Object)(object)Player.m_localPlayer || !Object.op_Implicit((Object)(object)view) || !view.IsValid() || PopupOpen || requesting)
			{
				return false;
			}
			if (alt)
			{
				selectedTier = (selectedTier + 1) % 3;
				return true;
			}
			Player player = Player.m_localPlayer;
			if (!WolfUnlock.Has(player))
			{
				Tell("Tame a wolf, or pet an existing ordinary tame wolf, before using the shrine.");
				return true;
			}
			if (!Access(player) || Busy || TimeAt(view.GetZDO(), "ws_next") > Now)
			{
				Tell("The shrine is busy, resting or ward-protected.");
				return true;
			}
			int tier = selectedTier;
			string recipe = Plugin.Recipes[tier].Value;
			if (!ValidRecipe(recipe))
			{
				Tell("This offering configuration is invalid; nothing consumed.");
				return true;
			}
			PopupOpen = true;
			string text = $"Summon one born-tamed {tier}-star wolf cub?\n\nOffering from your inventory:\n{CostText(tier)}\n\nShrine-born wolves have {Plugin.HealthBonus.Value:0.#}× normal health for their star tier, including adulthood. Damage is unchanged.\n\nThe ritual takes {Plugin.RitualSeconds.Value:0} seconds.";
			PopupButtonCallback val = delegate
			{
				UnifiedPopup.Pop();
				PopupOpen = false;
				if (Object.op_Implicit((Object)(object)this))
				{
					((MonoBehaviour)this).StartCoroutine(Offer(player, tier, recipe));
				}
			};
			object obj = <>c.<>9__35_1;
			if (obj == null)
			{
				PopupButtonCallback val2 = delegate
				{
					UnifiedPopup.Pop();
					PopupOpen = false;
				};
				<>c.<>9__35_1 = val2;
				obj = (object)val2;
			}
			UnifiedPopup.Push((PopupBase)new YesNoPopup("Altar of the Pack", text, val, (PopupButtonCallback)obj, false, true));
			return true;
		}

		private static string ItemId(ItemData item)
		{
			if (!Object.op_Implicit((Object)(object)item.m_dropPrefab))
			{
				return "";
			}
			return Utils.GetPrefabName(item.m_dropPrefab);
		}

		private static bool ValidRecipe(string text)
		{
			return RitualPolicy.Recipe(text)?.Keys.All((string id) => Object.op_Implicit((Object)(object)ObjectDB.instance) && Object.op_Implicit((Object)(object)ObjectDB.instance.GetItemPrefab(id))) ?? false;
		}

		private static string CostText(int tier)
		{
			Dictionary<string, int> dictionary = RitualPolicy.Recipe(Plugin.Recipes[tier].Value);
			if (dictionary == null)
			{
				return "Invalid offering configuration";
			}
			return string.Join(", ", dictionary.Select(delegate(KeyValuePair<string, int> pair)
			{
				GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab(pair.Key) : null);
				ItemDrop val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<ItemDrop>() : null);
				return pair.Value + " " + (Object.op_Implicit((Object)(object)val2) ? Localization.instance.Localize(val2.m_itemData.m_shared.m_name) : pair.Key);
			}));
		}

		private bool Access(Player player)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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)
			if (Object.op_Implicit((Object)(object)player) && WolfUnlock.Has(player) && !((Character)player).IsDead())
			{
				Vector3 val = ((Component)player).transform.position - ((Component)this).transform.position;
				if (!(((Vector3)(ref val)).sqrMagnitude > 16f))
				{
					bool flag = false;
					bool flag2 = false;
					PrivateArea[] array = Object.FindObjectsByType<PrivateArea>((FindObjectsSortMode)0);
					foreach (PrivateArea val2 in array)
					{
						if (WardEnabled(val2) && WardInside(val2, ((Component)this).transform.position, 0f))
						{
							if (((Component)val2).GetComponent<Piece>().GetCreator() == player.GetPlayerID() || WardPermitted(val2, player.GetPlayerID()))
							{
								flag = true;
							}
							else
							{
								flag2 = true;
							}
						}
					}
					if (!flag)
					{
						return !flag2;
					}
					return true;
				}
			}
			return false;
		}

		private IEnumerator Offer(Player player, int tier, string reviewedRecipe)
		{
			if (requesting || !Object.op_Implicit((Object)(object)player) || !Access(player) || !ValidRecipe(reviewedRecipe) || Plugin.Recipes[tier].Value != reviewedRecipe)
			{
				yield break;
			}
			Dictionary<string, int> costs = RitualPolicy.Recipe(reviewedRecipe);
			ItemData[] source = ((Humanoid)player).GetInventory().GetAllItems().ToArray();
			if (RitualPolicy.Debit(source.Select(ItemId).ToArray(), source.Select((ItemData i) => i.m_stack).ToArray(), costs) == null)
			{
				Tell("You do not have the complete offering in your inventory.");
				yield break;
			}
			if (!SpawnPoint(out var _))
			{
				Tell("Clear dry ground beside the shrine before offering.");
				yield break;
			}
			requesting = true;
			WolfAltar wolfAltar = this;
			WolfAltar wolfAltar2 = this;
			bool flag = false;
			wolfAltar2.granted = false;
			wolfAltar.answered = flag;
			request = Guid.NewGuid().ToString("N");
			expectedOwner = view.GetZDO().GetOwner();
			double started = Time.realtimeSinceStartupAsDouble;
			try
			{
				if (view.IsOwner())
				{
					Reserve(ZNet.GetUID(), request, tier);
				}
				else
				{
					view.InvokeRPC("WS_Reserve", new object[2] { request, tier });
				}
				while (Object.op_Implicit((Object)(object)view) && view.IsValid() && !answered && Time.realtimeSinceStartupAsDouble - started < 5.0)
				{
					yield return null;
				}
				if (!Object.op_Implicit((Object)(object)view) || !view.IsValid() || !answered || !granted)
				{
					Tell("The shrine is busy or did not answer. Nothing consumed.");
					yield break;
				}
				while (Object.op_Implicit((Object)(object)view) && view.IsValid() && (!view.IsOwner() || view.GetZDO().GetString("ws_lease", "") != request) && Time.realtimeSinceStartupAsDouble - started < 5.0)
				{
					yield return null;
				}
				if (!Object.op_Implicit((Object)(object)view) || !view.IsValid() || !view.IsOwner() || !Access(player) || !OwnLease() || Plugin.Recipes[tier].Value != reviewedRecipe)
				{
					Tell("The offering changed or the reservation expired. Nothing consumed.");
				}
				else
				{
					Commit(player, tier, reviewedRecipe, costs);
				}
			}
			finally
			{
				WolfAltar wolfAltar3 = this;
				if (Object.op_Implicit((Object)(object)wolfAltar3.view) && wolfAltar3.view.IsValid() && wolfAltar3.view.IsOwner() && wolfAltar3.view.GetZDO().GetString("ws_lease", "") == wolfAltar3.request)
				{
					wolfAltar3.view.GetZDO().Set("ws_lease", "");
					wolfAltar3.view.GetZDO().Set("ws_expiry", 0L);
				}
				wolfAltar3.requesting = false;
			}
		}

		private bool OwnLease()
		{
			if (view.IsOwner() && view.GetZDO().GetString("ws_lease", "") == request && view.GetZDO().GetLong("ws_holder", 0L) == ZNet.GetUID())
			{
				return TimeAt(view.GetZDO(), "ws_expiry") - Now > 1.0;
			}
			return false;
		}

		private void Commit(Player player, int tier, string recipe, Dictionary<string, int> costs)
		{
			ZDO zDO = view.GetZDO();
			if (!OwnLease() || zDO.GetInt("ws_lease_tier", 0) != tier || zDO.GetString("ws_pending", "").Length > 0 || TimeAt(zDO, "ws_next") > Now || !SpawnPoint(out var _))
			{
				Tell("Shrine conditions changed. Nothing consumed.");
				return;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			ItemData[] array = inventory.GetAllItems().ToArray();
			int[] array2 = RitualPolicy.Debit(array.Select(ItemId).ToArray(), array.Select((ItemData i) => i.m_stack).ToArray(), costs);
			if (array2 == null)
			{
				Tell("Your offering is incomplete. Nothing consumed.");
				return;
			}
			int[] array3 = array.Select((ItemData i) => i.m_stack).ToArray();
			try
			{
				for (int num = 0; num < array.Length; num++)
				{
					if (array2[num] > 0 && !inventory.RemoveItem(array[num], array2[num]))
					{
						throw new InvalidOperationException("Offering debit failed.");
					}
				}
				zDO.Set("ws_star", tier);
				zDO.Set("ws_bonus", Plugin.HealthBonus.Value);
				zDO.Set("ws_paid", recipe);
				SetTime(zDO, "ws_due", Now + (double)Plugin.RitualSeconds.Value);
				zDO.Set("ws_pending", request);
				Tell($"The pack answers: a tamed {tier}-star cub is coming.");
			}
			catch (Exception arg)
			{
				zDO.Set("ws_pending", "");
				List<ItemData> allItems = inventory.GetAllItems();
				allItems.Clear();
				for (int num2 = 0; num2 < array.Length; num2++)
				{
					array[num2].m_stack = array3[num2];
					allItems.Add(array[num2]);
				}
				try
				{
					InventoryChanged(inventory);
				}
				catch (Exception arg2)
				{
					Plugin.Log.LogError((object)$"Restored offering inventory callback failed: {arg2}");
				}
				Plugin.Log.LogError((object)$"Offering failed; inventory restored before birth. {arg}");
				Tell("Offering failed; check inventory and logs.");
			}
		}

		private void Reserve(long sender, string token, int tier)
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			if (!view.IsOwner() || token == null || !Guid.TryParseExact(token, "N", out var _))
			{
				return;
			}
			if (!seen.Add(token))
			{
				Reply(sender, token, success: false);
				return;
			}
			history.Enqueue(token);
			if (history.Count > 256)
			{
				seen.Remove(history.Dequeue());
			}
			Player val = ((IEnumerable<Player>)Player.GetAllPlayers()).FirstOrDefault((Func<Player, bool>)((Player p) => Object.op_Implicit((Object)(object)p) && Object.op_Implicit((Object)(object)((Component)p).GetComponent<ZNetView>()) && ((Component)p).GetComponent<ZNetView>().IsValid() && ((Component)p).GetComponent<ZNetView>().GetZDO().GetOwner() == sender));
			ZDO zDO = view.GetZDO();
			int num;
			if (Object.op_Implicit((Object)(object)val))
			{
				bool access = Access(val);
				bool alive = !((Character)val).IsDead();
				Vector3 point = ((Component)val).transform.position - ((Component)this).transform.position;
				if (RitualPolicy.CanReserve(owner: true, access, alive, ((Vector3)(ref point)).sqrMagnitude, tier, zDO.GetString("ws_pending", "").Length > 0, TimeAt(zDO, "ws_next"), TimeAt(zDO, "ws_expiry"), Now) && ValidRecipe(Plugin.Recipes[tier].Value))
				{
					num = (SpawnPoint(out point) ? 1 : 0);
					goto IL_013c;
				}
			}
			num = 0;
			goto IL_013c;
			IL_013c:
			bool flag = (byte)num != 0;
			if (flag)
			{
				zDO.Set("ws_lease", token);
				zDO.Set("ws_holder", sender);
				zDO.Set("ws_lease_tier", tier);
				SetTime(zDO, "ws_expiry", Now + 12.0);
				if (sender != ZNet.GetUID())
				{
					zDO.SetOwner(sender);
					ZDOMan.instance.ForceSendZDO(sender, zDO.m_uid);
				}
			}
			Reply(sender, token, flag);
		}

		private void Reply(long sender, string token, bool success)
		{
			if (sender == ZNet.GetUID())
			{
				Response(sender, token, success);
				return;
			}
			view.InvokeRPC(sender, "WS_Granted", new object[2] { token, success });
		}

		private void Response(long sender, string token, bool success)
		{
			if (token == request && sender == expectedOwner && !answered)
			{
				answered = true;
				granted = success;
			}
		}

		private void Update()
		{
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)view) || !view.IsValid() || !Object.op_Implicit((Object)(object)ZNet.instance))
			{
				return;
			}
			ZDO zDO = view.GetZDO();
			bool flag = zDO.GetString("ws_pending", "").Length > 0;
			Light componentInChildren = ((Component)this).GetComponentInChildren<Light>();
			if (Object.op_Implicit((Object)(object)componentInChildren))
			{
				componentInChildren.intensity = (flag ? (0.26f + Mathf.Sin(Time.time * 4f) * 0.04f) : 0.12f);
			}
			if (!view.IsOwner() || !flag || Now < TimeAt(zDO, "ws_due") || Time.unscaledTime < nextBirthCheck)
			{
				return;
			}
			nextBirthCheck = Time.unscaledTime + 2f;
			string token = zDO.GetString("ws_pending", "");
			int num = zDO.GetInt("ws_star", 0);
			if (!RitualPolicy.Tier(num))
			{
				Plugin.Log.LogError((object)"Invalid pending wolf tier; ritual held for inspection.");
				return;
			}
			try
			{
				Character val = ((IEnumerable<Character>)Character.GetAllCharacters()).FirstOrDefault((Func<Character, bool>)((Character c) => Object.op_Implicit((Object)(object)c) && Object.op_Implicit((Object)(object)((Component)c).GetComponent<ZNetView>()) && ((Component)c).GetComponent<ZNetView>().IsValid() && ((Component)c).GetComponent<ZNetView>().GetZDO().GetString("wolfshrine.birth", "") == token));
				if (!Object.op_Implicit((Object)(object)val))
				{
					if (!SpawnPoint(out var point))
					{
						return;
					}
					GameObject prefab = ZNetScene.instance.GetPrefab("Wolf_cub");
					if (!Object.op_Implicit((Object)(object)prefab))
					{
						throw new InvalidOperationException("Wolf_cub is unavailable.");
					}
					GameObject val2 = Object.Instantiate<GameObject>(prefab, point, ((Component)this).transform.rotation);
					try
					{
						val = val2.GetComponent<Character>();
						ZNetView component = val2.GetComponent<ZNetView>();
						if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner())
						{
							throw new InvalidOperationException("Spawned cub is not a valid owned Character.");
						}
						component.GetZDO().Set("wolfshrine.birth", token);
					}
					catch
					{
						ZNetScene.instance.Destroy(val2);
						throw;
					}
				}
				BlessedWolves.Mark(val, zDO.GetFloat("ws_bonus", 3f));
				val.SetTamed(true);
				val.SetLevel(RitualPolicy.Level(num));
				val.SetHealth(val.GetMaxHealth());
				if (!val.IsTamed())
				{
					throw new InvalidOperationException("Cub taming has not been acknowledged; ritual remains pending.");
				}
				Growup component2 = ((Component)val).GetComponent<Growup>();
				if (Object.op_Implicit((Object)(object)component2))
				{
					component2.m_inheritTame = true;
				}
				SetTime(zDO, "ws_next", Now + (double)Plugin.Cooldown.Value);
				zDO.Set("ws_pending", "");
				Plugin.Log.LogInfo((object)$"Shrine cub born: {num} stars, tamed={val.IsTamed()}, maxHealth={val.GetMaxHealth()}, multiplier={BlessedWolves.Bonus(val)}.");
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Wolf ritual is pending and will retry without charging again: {arg}");
			}
		}

		private bool SpawnPoint(out Vector3 point)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: 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_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: 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_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			int mask = LayerMask.GetMask(new string[4] { "terrain", "piece", "Default", "static_solid" });
			int mask2 = LayerMask.GetMask(new string[6] { "piece", "Default", "static_solid", "character", "character_net", "character_ghost" });
			RaycastHit val = default(RaycastHit);
			for (int i = 0; i < 12; i++)
			{
				float num = (float)i * (float)Math.PI / 6f;
				if (Physics.Raycast(((Component)this).transform.position + new Vector3(Mathf.Sin(num), 0f, Mathf.Cos(num)) * 2.5f + Vector3.up * 2f, Vector3.down, ref val, 4f, mask, (QueryTriggerInteraction)1) && !(Mathf.Abs(((RaycastHit)(ref val)).point.y - ((Component)this).transform.position.y) > 1.5f) && (!Object.op_Implicit((Object)(object)ZoneSystem.instance) || !(((RaycastHit)(ref val)).point.y < ZoneSystem.instance.m_waterLevel + 0.1f)))
				{
					point = ((RaycastHit)(ref val)).point + Vector3.up * 0.1f;
					if (!Physics.CheckCapsule(point + Vector3.up * 0.5f, point + Vector3.up * 0.9f, 0.35f, mask2, (QueryTriggerInteraction)1))
					{
						return true;
					}
				}
			}
			point = Vector3.zero;
			return false;
		}

		private void RefundDestroyed()
		{
			try
			{
				RefundOffering();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Destroyed shrine refund was incomplete; preserve the world/player backup and logs. {arg}");
			}
		}

		private void RefundOffering()
		{
			//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_011d: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)view) || !view.IsValid() || !view.IsOwner())
			{
				return;
			}
			ZDO zDO = view.GetZDO();
			string token = zDO.GetString("ws_pending", "");
			if (token.Length == 0 || Character.GetAllCharacters().Any((Character c) => Object.op_Implicit((Object)(object)c) && Object.op_Implicit((Object)(object)((Component)c).GetComponent<ZNetView>()) && ((Component)c).GetComponent<ZNetView>().IsValid() && ((Component)c).GetComponent<ZNetView>().GetZDO().GetString("wolfshrine.birth", "") == token))
			{
				return;
			}
			Dictionary<string, int> dictionary = RitualPolicy.Recipe(zDO.GetString("ws_paid", ""));
			zDO.Set("ws_pending", "");
			if (dictionary == null)
			{
				Plugin.Log.LogError((object)"Destroyed shrine has an invalid paid offering record; preserve the backup.");
				return;
			}
			foreach (KeyValuePair<string, int> item in dictionary)
			{
				ItemData itemData = ObjectDB.instance.GetItemPrefab(item.Key).GetComponent<ItemDrop>().m_itemData;
				int num = item.Value;
				while (num > 0)
				{
					int num2 = Math.Min(num, itemData.m_shared.m_maxStackSize);
					ItemDrop.DropItem(itemData.Clone(), num2, ((Component)this).transform.position + Vector3.up, Quaternion.identity);
					num -= num2;
				}
			}
			Plugin.Log.LogInfo((object)"Destroyed active shrine dropped its pending offering as ordinary items.");
		}

		private static void Tell(string message)
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false);
			}
		}
	}
	internal static class WolfUnlock
	{
		internal const string Key = "wolfshrine.wolf_tamed";

		private static readonly Dictionary<ZDOID, bool> observed = new Dictionary<ZDOID, bool>();

		private static Player current = null;

		private static float nextScan;

		private static readonly Action<Player> KnownRecipes = AccessTools.MethodDelegate<Action<Player>>(AccessTools.Method(typeof(Player), "UpdateKnownRecipesList", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Action<Player> AvailablePieces = AccessTools.MethodDelegate<Action<Player>>(AccessTools.Method(typeof(Player), "UpdateAvailablePiecesList", (Type[])null, (Type[])null), (object)null, true);

		internal static bool Has(Player player)
		{
			if (!Object.op_Implicit((Object)(object)player))
			{
				return false;
			}
			if ((Object)(object)player == (Object)(object)Player.m_localPlayer)
			{
				if (player.m_customData.TryGetValue("wolfshrine.wolf_tamed", out var value))
				{
					return value == "1";
				}
				return false;
			}
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)component) && component.IsValid())
			{
				return component.GetZDO().GetBool("wolfshrine.wolf_tamed", false);
			}
			return false;
		}

		internal static bool OrdinaryTame(Character wolf)
		{
			if (BlessedWolves.IsWolf(wolf) && wolf.IsTamed())
			{
				return !BlessedWolves.FromShrine(wolf);
			}
			return false;
		}

		internal static void Credit(Player player)
		{
			if (Object.op_Implicit((Object)(object)player) && !((Object)(object)player != (Object)(object)Player.m_localPlayer) && !Has(player))
			{
				player.m_customData["wolfshrine.wolf_tamed"] = "1";
				Synchronize(player);
				KnownRecipes(player);
				AvailablePieces(player);
				((Character)player).Message((MessageType)2, "Altar of the Pack unlocked — your bond with wolves is remembered.", 0, (Sprite)null, false);
				Plugin.Log.LogInfo((object)"Wolf-taming progression unlocked for the local character.");
			}
		}

		private static void Synchronize(Player player)
		{
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)component) && component.IsValid() && component.IsOwner() && component.GetZDO().GetBool("wolfshrine.wolf_tamed", false) != Has(player))
			{
				component.GetZDO().Set("wolfshrine.wolf_tamed", Has(player));
			}
		}

		internal static void Update()
		{
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: 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_0133: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)current != (Object)(object)localPlayer)
			{
				current = localPlayer;
				observed.Clear();
				nextScan = 0f;
			}
			if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)ZNet.instance))
			{
				return;
			}
			Synchronize(localPlayer);
			if (Has(localPlayer) || ((Character)localPlayer).IsDead() || Time.unscaledTime < nextScan)
			{
				return;
			}
			nextScan = Time.unscaledTime + 0.5f;
			HashSet<ZDOID> hashSet = new HashSet<ZDOID>();
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if (!BlessedWolves.IsWolf(allCharacter) || BlessedWolves.FromShrine(allCharacter))
				{
					continue;
				}
				Vector3 val2 = ((Component)allCharacter).transform.position - ((Component)localPlayer).transform.position;
				if (((Vector3)(ref val2)).sqrMagnitude > 900f)
				{
					continue;
				}
				ZNetView component = ((Component)allCharacter).GetComponent<ZNetView>();
				if (Object.op_Implicit((Object)(object)component) && component.IsValid())
				{
					ZDOID uid = component.GetZDO().m_uid;
					hashSet.Add(uid);
					bool flag = allCharacter.IsTamed();
					if (observed.TryGetValue(uid, out var value) && !value && flag && (Object)(object)Player.GetClosestPlayer(((Component)allCharacter).transform.position, 30f) == (Object)(object)localPlayer)
					{
						Credit(localPlayer);
					}
					observed[uid] = flag;
				}
			}
			foreach (ZDOID item in new List<ZDOID>(observed.Keys))
			{
				if (!hashSet.Contains(item))
				{
					observed.Remove(item);
				}
			}
		}

		internal static bool IsShrine(Piece piece)
		{
			if (Object.op_Implicit((Object)(object)piece))
			{
				return Utils.GetPrefabName(((Component)piece).gameObject) == "WolfShrine_AltarOfThePack";
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Tameable), "Interact")]
	internal static class RecognizeExistingWolf
	{
		private static void Postfix(Tameable __instance, Humanoid user, bool hold, bool __result)
		{
			if (!hold && __result && (Object)(object)user == (Object)(object)Player.m_localPlayer && WolfUnlock.OrdinaryTame(((Component)__instance).GetComponent<Character>()))
			{
				WolfUnlock.Credit(Player.m_localPlayer);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
	{
		typeof(Piece),
		typeof(RequirementMode)
	})]
	internal static class WolfShrineBuildKnowledge
	{
		private static void Postfix(Player __instance, Piece piece, ref bool __result)
		{
			if (WolfUnlock.IsShrine(piece) && !WolfUnlock.Has(__instance))
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch]
	internal static class WolfShrinePlacementGate
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.Method(typeof(Player), "TryPlacePiece", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(Player), "PlacePiece", (Type[])null, (Type[])null);
		}

		private static bool Prefix(Player __instance, Piece __0)
		{
			if (!WolfUnlock.IsShrine(__0) || WolfUnlock.Has(__instance))
			{
				return true;
			}
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				((Character)__instance).Message((MessageType)2, "Tame a wolf, or pet an existing ordinary tame wolf, to unlock this shrine.", 0, (Sprite)null, false);
			}
			return false;
		}
	}
}