Decompiled source of Lost Scrolls II v0.2.0

LostScrollsII.dll

Decompiled 17 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GUIFramework;
using HarmonyLib;
using LostScrollsII.Companions;
using LostScrollsII.Integration;
using Microsoft.CodeAnalysis;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using ValheimServerGuide.Triggers;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("LostScrollsII")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0+66965495cf4375659e26678c299e75e011841e2f")]
[assembly: AssemblyProduct("LostScrollsII")]
[assembly: AssemblyTitle("LostScrollsII")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LostScrollsII
{
	[BepInPlugin("com.lostscrollsii", "Lost Scrolls II", "0.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.lostscrollsii";

		public const string PluginName = "Lost Scrolls II";

		public const string PluginVersion = "0.2.0";

		private Harmony _harmony;

		public static Plugin Instance { get; private set; }

		public static ManualLogSource Log { get; private set; }

		public static ConfigEntry<KeyCode> CommunionKey { get; private set; }

		public static ConfigEntry<KeyCode> ChoreAssignKey { get; private set; }

		public static ConfigEntry<float> ChoreAssignRadius { get; private set; }

		public static ConfigEntry<KeyCode> DuelSelectKey { get; private set; }

		public static ConfigEntry<KeyCode> StanceCycleKey { get; private set; }

		public static ConfigEntry<KeyCode> InventoryKey { get; private set; }

		public static ConfigEntry<bool> ShowMapPins { get; private set; }

		public static ConfigEntry<int> MapPinIcon { get; private set; }

		private void Awake()
		{
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			CommunionKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Recruitment", "CommunionKey", (KeyCode)103, "Key held while hovering a subdued Dvergr to perform the Communion Rite and recruit it.");
			ChoreAssignKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Chores", "ChoreAssignKey", (KeyCode)104, "Key pressed while hovering a workstation (Smelter-family), a ripe crop, or a tamed animal to assign/unassign the nearest matching-caste companion to that chore.");
			ChoreAssignRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Chores", "ChoreAssignRadius", 10f, "Max distance from the player to look for a recruited companion to assign to a chore.");
			DuelSelectKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Duels", "DuelSelectKey", (KeyCode)106, "Press while hovering your own recruited companion to toggle its duel mode. A duel-mode companion fights other players' duel-mode companions and ignores everyone else.");
			StanceCycleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Companions", "StanceCycleKey", (KeyCode)101, "Press while hovering your companion to cycle its stance: Follow -> Guard -> Standby.");
			InventoryKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Companions", "InventoryKey", (KeyCode)121, "Press while hovering your companion to open its inventory (a chest-like panel that also lets you rename it).");
			ShowMapPins = ((BaseUnityPlugin)this).Config.Bind<bool>("Companions", "ShowMapPins", true, "Show a live minimap pin at each of your own recruited companions. Pins are client-side — other players never see your companions, and you never see theirs.");
			MapPinIcon = ((BaseUnityPlugin)this).Config.Bind<int>("Companions", "MapPinIcon", 3, "Which vanilla map-pin icon (0-4) to use for companion pins.");
			_harmony = new Harmony("com.lostscrollsii");
			_harmony.PatchAll();
			((Component)this).gameObject.AddComponent<CompanionMapPins>();
			((Component)this).gameObject.AddComponent<CompanionInventoryGui>();
			Log.LogInfo((object)"Lost Scrolls II v0.2.0 loaded.");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void Update()
		{
			//IL_0046: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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)
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !TextInput.IsVisible() && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !CompanionInventoryGui.IsTyping)
			{
				if (Input.GetKeyDown(CommunionKey.Value))
				{
					HandleCommunionInput(localPlayer);
				}
				if (Input.GetKeyDown(ChoreAssignKey.Value))
				{
					HandleChoreAssignInput(localPlayer);
				}
				if (Input.GetKeyDown(DuelSelectKey.Value))
				{
					HandleDuelInput(localPlayer);
				}
				if (Input.GetKeyDown(StanceCycleKey.Value))
				{
					HandleStanceCycleInput(localPlayer);
				}
				if (Input.GetKeyDown(InventoryKey.Value))
				{
					HandleInventoryInput(localPlayer);
				}
			}
		}

		private void HandleInventoryInput(Player player)
		{
			GameObject hoverObject = ((Humanoid)player).GetHoverObject();
			if ((Object)(object)hoverObject == (Object)null)
			{
				return;
			}
			Character componentInParent = hoverObject.GetComponentInParent<Character>();
			DvergrCompanion dvergrCompanion = ((componentInParent != null) ? ((Component)componentInParent).GetComponent<DvergrCompanion>() : null);
			if ((Object)(object)dvergrCompanion == (Object)null)
			{
				return;
			}
			if (!dvergrCompanion.IsOwner(player))
			{
				MessageHud.instance.ShowMessage((MessageType)2, "This companion answers to another.", 0, (Sprite)null, false);
				return;
			}
			CompanionInventory companionInventory = ((Component)dvergrCompanion).GetComponent<CompanionInventory>();
			if ((Object)(object)companionInventory == (Object)null)
			{
				companionInventory = ((Component)dvergrCompanion).gameObject.AddComponent<CompanionInventory>();
			}
			CompanionInventoryGui.Open(dvergrCompanion, companionInventory);
		}

		private void HandleCommunionInput(Player player)
		{
			GameObject hoverObject = ((Humanoid)player).GetHoverObject();
			if ((Object)(object)hoverObject == (Object)null)
			{
				return;
			}
			Character componentInParent = hoverObject.GetComponentInParent<Character>();
			if ((Object)(object)componentInParent == (Object)null)
			{
				return;
			}
			DvergrCompanion component = ((Component)componentInParent).GetComponent<DvergrCompanion>();
			if ((Object)(object)component != (Object)null)
			{
				bool flag = component.IsOwner(player);
				if (MeadFeedingService.TryFeed(componentInParent, player))
				{
					MessageHud.instance.ShowMessage((MessageType)2, flag ? "Your ally drinks deep." : (component.DisplayName + " drinks deep."), 0, (Sprite)null, false);
				}
				else
				{
					MessageHud.instance.ShowMessage((MessageType)2, "You have no health mead to offer.", 0, (Sprite)null, false);
				}
				return;
			}
			if (!CommunionService.IsSubduedDvergr(componentInParent))
			{
				MessageHud.instance.ShowMessage((MessageType)2, "It is not yet ready for Communion.", 0, (Sprite)null, false);
				return;
			}
			DvergrCaste dvergrCaste = CommunionService.DetectCaste(componentInParent);
			Log.LogInfo((object)$"[recruit] '{((Object)componentInParent).name}' detected as caste {dvergrCaste}.");
			if (CommunionService.TryRecruit(componentInParent, player, dvergrCaste))
			{
				MessageHud.instance.ShowMessage((MessageType)2, "The shadow's grip loosens — a " + dvergrCaste.Display() + " joins you.", 0, (Sprite)null, false);
			}
		}

		private void HandleChoreAssignInput(Player player)
		{
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			GameObject hoverObject = ((Humanoid)player).GetHoverObject();
			if ((Object)(object)hoverObject == (Object)null)
			{
				return;
			}
			Character componentInParent = hoverObject.GetComponentInParent<Character>();
			DvergrCompanion dvergrCompanion = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).GetComponent<DvergrCompanion>() : null);
			if ((Object)(object)dvergrCompanion != (Object)null)
			{
				if (!dvergrCompanion.IsOwner(player))
				{
					MessageHud.instance.ShowMessage((MessageType)2, "This companion answers to another.", 0, (Sprite)null, false);
					return;
				}
				ChoreAI component = ((Component)dvergrCompanion).GetComponent<ChoreAI>();
				if ((Object)(object)component != (Object)null && component.IsAssigned)
				{
					component.Unassign();
					MessageHud.instance.ShowMessage((MessageType)2, "Ally returns to your side.", 0, (Sprite)null, false);
				}
				else
				{
					MessageHud.instance.ShowMessage((MessageType)2, "This ally has no chore to leave.", 0, (Sprite)null, false);
				}
				return;
			}
			Smelter componentInParent2 = hoverObject.GetComponentInParent<Smelter>();
			Fermenter val = (((Object)(object)componentInParent2 == (Object)null) ? hoverObject.GetComponentInParent<Fermenter>() : null);
			CookingStation val2 = (((Object)(object)componentInParent2 == (Object)null && (Object)(object)val == (Object)null) ? hoverObject.GetComponentInParent<CookingStation>() : null);
			Pickable val3 = (((Object)(object)componentInParent2 == (Object)null && (Object)(object)val == (Object)null && (Object)(object)val2 == (Object)null) ? hoverObject.GetComponentInParent<Pickable>() : null);
			ItemStand val4 = null;
			Character val5 = null;
			Container val6 = null;
			if ((Object)(object)componentInParent2 == (Object)null && (Object)(object)val == (Object)null && (Object)(object)val2 == (Object)null && (Object)(object)val3 == (Object)null)
			{
				ItemStand componentInParent3 = hoverObject.GetComponentInParent<ItemStand>();
				if ((Object)(object)componentInParent3 != (Object)null && componentInParent3.HaveAttachment() && componentInParent3.GetAttachedItem() == "Cultivator")
				{
					val4 = componentInParent3;
				}
				if ((Object)(object)val4 == (Object)null)
				{
					Character componentInParent4 = hoverObject.GetComponentInParent<Character>();
					if ((Object)(object)componentInParent4 != (Object)null && componentInParent4.IsTamed() && (Object)(object)((Component)componentInParent4).GetComponent<DvergrCompanion>() == (Object)null)
					{
						val5 = componentInParent4;
					}
					if ((Object)(object)val5 == (Object)null)
					{
						val6 = hoverObject.GetComponentInParent<Container>();
					}
				}
			}
			if ((Object)(object)componentInParent2 == (Object)null && (Object)(object)val == (Object)null && (Object)(object)val2 == (Object)null && (Object)(object)val3 == (Object)null && (Object)(object)val4 == (Object)null && (Object)(object)val5 == (Object)null && (Object)(object)val6 == (Object)null)
			{
				return;
			}
			ChoreAI choreAI = ChoreAI.ClaimantOf(((Object)(object)componentInParent2 != (Object)null) ? ((Component)componentInParent2).gameObject : (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : (((Object)(object)val2 != (Object)null) ? ((Component)val2).gameObject : (((Object)(object)val3 != (Object)null) ? ((Component)val3).gameObject : (((Object)(object)val4 != (Object)null) ? ((Component)val4).gameObject : (((Object)(object)val5 != (Object)null) ? ((Component)val5).gameObject : (((Object)(object)val6 != (Object)null) ? ((Component)val6).gameObject : null)))))));
			if ((Object)(object)choreAI == (Object)null && (Object)(object)val5 != (Object)null)
			{
				choreAI = ChoreAI.FeederCovering(((Component)val5).transform.position);
			}
			if ((Object)(object)choreAI != (Object)null)
			{
				DvergrCompanion component2 = ((Component)choreAI).GetComponent<DvergrCompanion>();
				if ((Object)(object)component2 != (Object)null && component2.IsOwner(player))
				{
					choreAI.Unassign();
					MessageHud.instance.ShowMessage((MessageType)2, "Ally returns to your side.", 0, (Sprite)null, false);
				}
				else
				{
					MessageHud.instance.ShowMessage((MessageType)2, choreAI.WorkerName + " is already working here.", 0, (Sprite)null, false);
				}
				return;
			}
			DvergrCaste? requiredCaste = (((Object)(object)componentInParent2 != (Object)null) ? ChoreRules.RequiredCaste(componentInParent2) : new DvergrCaste?((!((Object)(object)val6 != (Object)null)) ? DvergrCaste.SupportMage : DvergrCaste.Rogue));
			DvergrCompanion dvergrCompanion2 = FindNearestRecruitedCompanion(((Component)player).transform.position, ChoreAssignRadius.Value, requiredCaste, player, freeOnly: true);
			if ((Object)(object)dvergrCompanion2 == (Object)null)
			{
				string text = (requiredCaste.HasValue ? ("Only your own free " + ChoreRules.DisplayName(requiredCaste.Value) + " can do this — none nearby.") : "No free ally of yours nearby to assign.");
				MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false);
				return;
			}
			ChoreAI choreAI2 = ((Component)dvergrCompanion2).GetComponent<ChoreAI>();
			if ((Object)(object)choreAI2 == (Object)null)
			{
				choreAI2 = ((Component)dvergrCompanion2).gameObject.AddComponent<ChoreAI>();
			}
			if ((Object)(object)componentInParent2 != (Object)null)
			{
				choreAI2.AssignToSmelter(componentInParent2);
				MessageHud.instance.ShowMessage((MessageType)2, "Ally tends the station.", 0, (Sprite)null, false);
			}
			else if ((Object)(object)val != (Object)null)
			{
				choreAI2.AssignToFermenter(val);
				MessageHud.instance.ShowMessage((MessageType)2, "Ally tends the brew.", 0, (Sprite)null, false);
			}
			else if ((Object)(object)val2 != (Object)null)
			{
				choreAI2.AssignToCooking(val2);
				MessageHud.instance.ShowMessage((MessageType)2, "Ally tends the cookfire.", 0, (Sprite)null, false);
			}
			else if ((Object)(object)val3 != (Object)null || (Object)(object)val4 != (Object)null)
			{
				choreAI2.AssignToFarm(((Object)(object)val3 != (Object)null) ? ((Component)val3).gameObject : ((Component)val4).gameObject);
				MessageHud.instance.ShowMessage((MessageType)2, "Ally tends the field.", 0, (Sprite)null, false);
			}
			else if ((Object)(object)val5 != (Object)null)
			{
				choreAI2.AssignToFeedAnimals(((Component)val5).gameObject);
				MessageHud.instance.ShowMessage((MessageType)2, "Ally tends the animals.", 0, (Sprite)null, false);
			}
			else
			{
				choreAI2.AssignToHaul(val6);
				MessageHud.instance.ShowMessage((MessageType)2, "Ally hauls to this chest.", 0, (Sprite)null, false);
			}
		}

		private void HandleDuelInput(Player player)
		{
			GameObject hoverObject = ((Humanoid)player).GetHoverObject();
			if (!((Object)(object)hoverObject == (Object)null))
			{
				Character componentInParent = hoverObject.GetComponentInParent<Character>();
				DvergrCompanion dvergrCompanion = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).GetComponent<DvergrCompanion>() : null);
				if ((Object)(object)dvergrCompanion == (Object)null)
				{
					MessageHud.instance.ShowMessage((MessageType)2, "That is not an ally you can pit in a duel.", 0, (Sprite)null, false);
				}
				else if (!dvergrCompanion.IsOwner(player))
				{
					MessageHud.instance.ShowMessage((MessageType)2, "Only its owner can send this companion to duel.", 0, (Sprite)null, false);
				}
				else if (dvergrCompanion.DuelMode)
				{
					dvergrCompanion.ExitDuelMode(DvergrCompanion.DuelExitReason.OwnerStopped);
				}
				else if (!dvergrCompanion.EnterDuelMode())
				{
					MessageHud.instance.ShowMessage((MessageType)2, "This companion cannot duel right now — unassign its chore first.", 0, (Sprite)null, false);
				}
			}
		}

		private void HandleStanceCycleInput(Player player)
		{
			GameObject hoverObject = ((Humanoid)player).GetHoverObject();
			if ((Object)(object)hoverObject == (Object)null)
			{
				return;
			}
			Character componentInParent = hoverObject.GetComponentInParent<Character>();
			DvergrCompanion dvergrCompanion = ((componentInParent != null) ? ((Component)componentInParent).GetComponent<DvergrCompanion>() : null);
			if ((Object)(object)dvergrCompanion == (Object)null)
			{
				return;
			}
			if (!dvergrCompanion.IsOwner(player))
			{
				MessageHud.instance.ShowMessage((MessageType)2, "This companion answers to another.", 0, (Sprite)null, false);
				return;
			}
			ChoreAI component = ((Component)componentInParent).GetComponent<ChoreAI>();
			if ((component != null && component.IsAssigned) || dvergrCompanion.DuelMode)
			{
				MessageHud.instance.ShowMessage((MessageType)2, "Ally is busy — unassign it first.", 0, (Sprite)null, false);
				return;
			}
			CompanionStance companionStance = ((dvergrCompanion.Stance == CompanionStance.Follow) ? CompanionStance.Guard : ((dvergrCompanion.Stance == CompanionStance.Guard) ? CompanionStance.Standby : CompanionStance.Follow));
			dvergrCompanion.SetStance(companionStance, ((Component)player).gameObject);
			MessageHud.instance.ShowMessage((MessageType)2, "Ally stance: " + companionStance switch
			{
				CompanionStance.Guard => "Guard", 
				CompanionStance.Follow => "Follow", 
				_ => "Standby", 
			} + ".", 0, (Sprite)null, false);
		}

		private static DvergrCompanion FindNearestRecruitedCompanion(Vector3 origin, float radius, DvergrCaste? requiredCaste = null, Player owner = null, bool freeOnly = false)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			List<Character> list = new List<Character>();
			Character.GetCharactersInRange(origin, radius, list);
			DvergrCompanion result = null;
			float num = float.MaxValue;
			foreach (Character item in list)
			{
				DvergrCompanion component = ((Component)item).GetComponent<DvergrCompanion>();
				if ((Object)(object)component == (Object)null || (requiredCaste.HasValue && component.Caste != requiredCaste.Value) || ((Object)(object)owner != (Object)null && !component.IsOwner(owner)))
				{
					continue;
				}
				if (freeOnly)
				{
					ChoreAI component2 = ((Component)item).GetComponent<ChoreAI>();
					if (component2 != null && component2.IsAssigned)
					{
						continue;
					}
				}
				float num2 = Vector3.Distance(origin, ((Component)item).transform.position);
				if (num2 < num)
				{
					num = num2;
					result = component;
				}
			}
			return result;
		}
	}
}
namespace LostScrollsII.Integration
{
	public static class ServerGuideBridge
	{
		private const string ServerGuideGuid = "com.valheimserverguide";

		public static bool IsLoaded => Chainloader.PluginInfos.ContainsKey("com.valheimserverguide");

		public static void RaiseRecruited(DvergrCaste caste)
		{
			if (!IsLoaded)
			{
				return;
			}
			try
			{
				RaiseRecruitedInternal(caste);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"ServerGuide integration (dvergr_recruited) failed: {arg}");
			}
		}

		public static void RaiseLevelUp(DvergrCaste caste, int level)
		{
			if (!IsLoaded)
			{
				return;
			}
			try
			{
				RaiseLevelUpInternal(caste, level);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"ServerGuide integration (dvergr_level_up) failed: {arg}");
			}
		}

		public static void RaiseDuelWon(DvergrCaste winner, DvergrCaste loser)
		{
			if (!IsLoaded)
			{
				return;
			}
			try
			{
				RaiseDuelWonInternal(winner, loser);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"ServerGuide integration (dvergr_duel_won) failed: {arg}");
			}
		}

		private static void RaiseRecruitedInternal(DvergrCaste caste)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			GuidanceDispatcher.Raise(new TriggerEvent
			{
				Type = "dvergr_recruited",
				Subject = caste.ToString()
			});
		}

		private static void RaiseLevelUpInternal(DvergrCaste caste, int level)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			GuidanceDispatcher.Raise(new TriggerEvent
			{
				Type = "dvergr_level_up",
				Subject = $"{caste}:{level}"
			});
		}

		private static void RaiseDuelWonInternal(DvergrCaste winner, DvergrCaste loser)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			GuidanceDispatcher.Raise(new TriggerEvent
			{
				Type = "dvergr_duel_won",
				Subject = winner.ToString(),
				Extra = new Dictionary<string, object> { 
				{
					"loserCaste",
					loser.ToString()
				} }
			});
		}
	}
}
namespace LostScrollsII.Companions
{
	public class ChoreAI : MonoBehaviour
	{
		public enum ChoreKind
		{
			None,
			Smelter,
			Farm,
			FeedAnimals,
			Fermenter,
			Cooking,
			Haul
		}

		public const string ZdoKeyChoreKind = "DE_ChoreKind";

		public const string ZdoKeyChorePos = "DE_ChorePos";

		private const float RestoreResolveRadius = 3f;

		private static readonly Dictionary<GameObject, ChoreAI> s_claims = new Dictionary<GameObject, ChoreAI>();

		private const float ArrivalRange = 4.5f;

		private const float ContainerSearchRadius = 8f;

		private const float WorkRadius = 10f;

		private const float FeedInterval = 5f;

		private const float NotifyInterval = 60f;

		private const float NotifyRange = 20f;

		private Humanoid _humanoid;

		private MonsterAI _ai;

		private DvergrCompanion _companion;

		private ZNetView _znv;

		private float _lastSayTime = -999f;

		private bool _pendingRestore;

		private ChoreKind _restoreKind;

		private Vector3 _restorePos;

		private float _restoreTimer;

		private Container _openChest;

		private float _closeChestTime;

		private ChoreKind _kind;

		private Smelter _station;

		private Fermenter _fermenter;

		private CookingStation _cooker;

		private Container _haulChest;

		private GameObject _anchorObject;

		private GameObject _claimedAnchor;

		private float _feedTimer;

		public string WorkerName
		{
			get
			{
				if (!((Object)(object)_companion != (Object)null))
				{
					if (!((Object)(object)_humanoid != (Object)null))
					{
						return "An ally";
					}
					return ((Character)_humanoid).GetHoverName();
				}
				return _companion.DisplayName;
			}
		}

		public bool IsAssigned => _kind != ChoreKind.None;

		public static ChoreAI ClaimantOf(GameObject anchor)
		{
			if ((Object)(object)anchor == (Object)null)
			{
				return null;
			}
			if (s_claims.TryGetValue(anchor, out var value))
			{
				if ((Object)(object)value != (Object)null && value.IsAssigned)
				{
					return value;
				}
				s_claims.Remove(anchor);
			}
			return null;
		}

		public static ChoreAI FeederCovering(Vector3 pos)
		{
			//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)
			foreach (DvergrCompanion item in DvergrCompanion.All)
			{
				if (!((Object)(object)item == (Object)null))
				{
					ChoreAI component = ((Component)item).GetComponent<ChoreAI>();
					if ((Object)(object)component != (Object)null && component.IsAssigned && component._kind == ChoreKind.FeedAnimals && Vector3.Distance(component.CurrentCenter(), pos) <= 10f)
					{
						return component;
					}
				}
			}
			return null;
		}

		private void Awake()
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			_humanoid = ((Component)this).GetComponent<Humanoid>();
			_ai = ((Component)this).GetComponent<MonsterAI>();
			_companion = ((Component)this).GetComponent<DvergrCompanion>();
			_znv = ((Component)this).GetComponent<ZNetView>();
			if ((Object)(object)_znv != (Object)null && _znv.IsValid())
			{
				int num = _znv.GetZDO().GetInt("DE_ChoreKind", 0);
				if (num != 0)
				{
					_restoreKind = (ChoreKind)num;
					_restorePos = _znv.GetZDO().GetVec3("DE_ChorePos", ((Component)this).transform.position);
					_pendingRestore = true;
				}
			}
		}

		public static bool HasPersistedChore(ZNetView znv)
		{
			if ((Object)(object)znv != (Object)null && znv.IsValid())
			{
				return znv.GetZDO().GetInt("DE_ChoreKind", 0) != 0;
			}
			return false;
		}

		public void AssignToSmelter(Smelter station)
		{
			_kind = ChoreKind.Smelter;
			_station = station;
			BeginChore(((Object)(object)station != (Object)null) ? ((Component)station).gameObject : null);
		}

		public void AssignToFarm(GameObject cropAnchor)
		{
			_kind = ChoreKind.Farm;
			BeginChore(cropAnchor);
		}

		public void AssignToFeedAnimals(GameObject animalAnchor)
		{
			_kind = ChoreKind.FeedAnimals;
			BeginChore(animalAnchor);
		}

		public void AssignToFermenter(Fermenter fermenter)
		{
			_kind = ChoreKind.Fermenter;
			_fermenter = fermenter;
			BeginChore(((Object)(object)fermenter != (Object)null) ? ((Component)fermenter).gameObject : null);
		}

		public void AssignToCooking(CookingStation cooker)
		{
			_kind = ChoreKind.Cooking;
			_cooker = cooker;
			BeginChore(((Object)(object)cooker != (Object)null) ? ((Component)cooker).gameObject : null);
		}

		public void AssignToHaul(Container chest)
		{
			_kind = ChoreKind.Haul;
			_haulChest = chest;
			BeginChore(((Object)(object)chest != (Object)null) ? ((Component)chest).gameObject : null);
		}

		private void BeginChore(GameObject anchor)
		{
			_anchorObject = anchor;
			_feedTimer = 0f;
			Claim(anchor);
			PersistChore(anchor);
			if ((Object)(object)_ai != (Object)null && (Object)(object)anchor != (Object)null)
			{
				_ai.SetFollowTarget(anchor);
			}
			if ((Object)(object)_companion != (Object)null)
			{
				_companion.ChoreActive = true;
				_companion.SetPassive(passive: true);
			}
		}

		private void PersistChore(GameObject anchor)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_znv == (Object)null) && _znv.IsValid())
			{
				ZDO zDO = _znv.GetZDO();
				zDO.Set("DE_ChoreKind", (int)_kind);
				zDO.Set("DE_ChorePos", ((Object)(object)anchor != (Object)null) ? anchor.transform.position : ((Component)this).transform.position);
			}
		}

		private void ClearPersistedChore()
		{
			if (!((Object)(object)_znv == (Object)null) && _znv.IsValid())
			{
				_znv.GetZDO().Set("DE_ChoreKind", 0);
			}
		}

		private void TryRestore()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			GameObject val = FindRestoreTarget(_restoreKind, _restorePos);
			if ((Object)(object)val != (Object)null)
			{
				_pendingRestore = false;
				ResumeChore(_restoreKind, val);
				return;
			}
			_restoreTimer += Time.deltaTime;
			if (_restoreTimer > 60f)
			{
				_pendingRestore = false;
				ClearPersistedChore();
			}
		}

		private GameObject FindRestoreTarget(ChoreKind kind, Vector3 pos)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			float num = ((kind == ChoreKind.Farm || kind == ChoreKind.FeedAnimals) ? 10f : 3f);
			Collider[] array = Physics.OverlapSphere(pos, num);
			foreach (Collider val in array)
			{
				switch (kind)
				{
				case ChoreKind.Smelter:
				{
					Smelter componentInParent2 = ((Component)val).GetComponentInParent<Smelter>();
					if ((Object)(object)componentInParent2 != (Object)null)
					{
						return ((Component)componentInParent2).gameObject;
					}
					break;
				}
				case ChoreKind.Fermenter:
				{
					Fermenter componentInParent4 = ((Component)val).GetComponentInParent<Fermenter>();
					if ((Object)(object)componentInParent4 != (Object)null)
					{
						return ((Component)componentInParent4).gameObject;
					}
					break;
				}
				case ChoreKind.Cooking:
				{
					CookingStation componentInParent8 = ((Component)val).GetComponentInParent<CookingStation>();
					if ((Object)(object)componentInParent8 != (Object)null)
					{
						return ((Component)componentInParent8).gameObject;
					}
					break;
				}
				case ChoreKind.Haul:
				{
					Container componentInParent3 = ((Component)val).GetComponentInParent<Container>();
					if ((Object)(object)componentInParent3 != (Object)null)
					{
						return ((Component)componentInParent3).gameObject;
					}
					break;
				}
				case ChoreKind.Farm:
				{
					ItemStand componentInParent5 = ((Component)val).GetComponentInParent<ItemStand>();
					if ((Object)(object)componentInParent5 != (Object)null && componentInParent5.HaveAttachment() && componentInParent5.GetAttachedItem() == "Cultivator")
					{
						return ((Component)componentInParent5).gameObject;
					}
					Pickable componentInParent6 = ((Component)val).GetComponentInParent<Pickable>();
					if ((Object)(object)componentInParent6 != (Object)null)
					{
						return ((Component)componentInParent6).gameObject;
					}
					Plant componentInParent7 = ((Component)val).GetComponentInParent<Plant>();
					if ((Object)(object)componentInParent7 != (Object)null)
					{
						return ((Component)componentInParent7).gameObject;
					}
					break;
				}
				case ChoreKind.FeedAnimals:
				{
					Character componentInParent = ((Component)val).GetComponentInParent<Character>();
					if ((Object)(object)componentInParent != (Object)null && componentInParent.IsTamed() && (Object)(object)((Component)componentInParent).GetComponent<DvergrCompanion>() == (Object)null)
					{
						return ((Component)componentInParent).gameObject;
					}
					break;
				}
				}
			}
			return null;
		}

		private void ResumeChore(ChoreKind kind, GameObject go)
		{
			switch (kind)
			{
			case ChoreKind.Smelter:
			{
				Smelter componentInParent4 = go.GetComponentInParent<Smelter>();
				if ((Object)(object)componentInParent4 != (Object)null)
				{
					AssignToSmelter(componentInParent4);
				}
				break;
			}
			case ChoreKind.Fermenter:
			{
				Fermenter componentInParent2 = go.GetComponentInParent<Fermenter>();
				if ((Object)(object)componentInParent2 != (Object)null)
				{
					AssignToFermenter(componentInParent2);
				}
				break;
			}
			case ChoreKind.Cooking:
			{
				CookingStation componentInParent3 = go.GetComponentInParent<CookingStation>();
				if ((Object)(object)componentInParent3 != (Object)null)
				{
					AssignToCooking(componentInParent3);
				}
				break;
			}
			case ChoreKind.Haul:
			{
				Container componentInParent = go.GetComponentInParent<Container>();
				if ((Object)(object)componentInParent != (Object)null)
				{
					AssignToHaul(componentInParent);
				}
				break;
			}
			case ChoreKind.Farm:
				AssignToFarm(go);
				break;
			case ChoreKind.FeedAnimals:
				AssignToFeedAnimals(go);
				break;
			}
			if (!IsAssigned)
			{
				ClearPersistedChore();
			}
		}

		private void Claim(GameObject anchor)
		{
			ReleaseClaim();
			if (!((Object)(object)anchor == (Object)null))
			{
				s_claims[anchor] = this;
				_claimedAnchor = anchor;
			}
		}

		private void ReleaseClaim()
		{
			if (!((Object)(object)_claimedAnchor == (Object)null))
			{
				if (s_claims.TryGetValue(_claimedAnchor, out var value) && (Object)(object)value == (Object)(object)this)
				{
					s_claims.Remove(_claimedAnchor);
				}
				_claimedAnchor = null;
			}
		}

		private void OnDisable()
		{
			ReleaseClaim();
		}

		public void Unassign()
		{
			_kind = ChoreKind.None;
			_station = null;
			_fermenter = null;
			_cooker = null;
			_haulChest = null;
			_anchorObject = null;
			_pendingRestore = false;
			ReleaseClaim();
			ClearPersistedChore();
			ClearSpeech();
			CloseChest();
			if ((Object)(object)_companion != (Object)null)
			{
				_companion.ChoreActive = false;
				DvergrCompanion companion = _companion;
				Player obj = _companion.OwnerPlayer();
				companion.SetStance(CompanionStance.Follow, (obj != null) ? ((Component)obj).gameObject : null);
			}
			else if ((Object)(object)_ai != (Object)null)
			{
				_ai.SetFollowTarget((GameObject)null);
			}
		}

		private void FaceToward(Vector3 pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = pos - ((Component)this).transform.position;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude > 0.01f && (Object)(object)_humanoid != (Object)null)
			{
				((Character)_humanoid).SetLookDir(((Vector3)(ref val)).normalized, 0f);
			}
		}

		private void OpenChest(Container c)
		{
			if (!((Object)(object)c == (Object)null))
			{
				if ((Object)(object)_openChest != (Object)(object)c)
				{
					CloseChest();
					c.SetInUse(true);
					_openChest = c;
				}
				_closeChestTime = Time.time + 1.5f;
			}
		}

		private void CloseChest()
		{
			if ((Object)(object)_openChest != (Object)null)
			{
				_openChest.SetInUse(false);
				_openChest = null;
			}
		}

		private Vector3 CurrentCenter()
		{
			//IL_0022: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			if (_kind == ChoreKind.Smelter && (Object)(object)_station != (Object)null)
			{
				return ((Component)_station).transform.position;
			}
			if (_kind == ChoreKind.Fermenter && (Object)(object)_fermenter != (Object)null)
			{
				return ((Component)_fermenter).transform.position;
			}
			if (_kind == ChoreKind.Cooking && (Object)(object)_cooker != (Object)null)
			{
				return ((Component)_cooker).transform.position;
			}
			if (_kind == ChoreKind.Haul && (Object)(object)_haulChest != (Object)null)
			{
				return ((Component)_haulChest).transform.position;
			}
			if ((Object)(object)_anchorObject != (Object)null)
			{
				return _anchorObject.transform.position;
			}
			return ((Component)this).transform.position;
		}

		private void Update()
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_openChest != (Object)null && Time.time > _closeChestTime)
			{
				CloseChest();
			}
			if (_pendingRestore)
			{
				TryRestore();
			}
			else
			{
				if (_kind == ChoreKind.None || (Object)(object)_humanoid == (Object)null || ((Object)(object)_znv != (Object)null && _znv.IsValid() && !_znv.IsOwner()))
				{
					return;
				}
				if ((Object)(object)_anchorObject == (Object)null)
				{
					Unassign();
					return;
				}
				_feedTimer += Time.deltaTime;
				if (_feedTimer < 5f)
				{
					return;
				}
				_feedTimer = 0f;
				if (Vector3.Distance(((Component)this).transform.position, CurrentCenter()) > 4.5f)
				{
					Say((_kind == ChoreKind.Farm) ? "I can't reach the field!" : ((_kind == ChoreKind.FeedAnimals) ? "I can't reach the pen!" : ((_kind == ChoreKind.Haul) ? "I can't reach the chest!" : "I can't reach my station!")));
					return;
				}
				switch (_kind)
				{
				case ChoreKind.Smelter:
					ServiceStation();
					break;
				case ChoreKind.Farm:
					ServiceFarm();
					break;
				case ChoreKind.FeedAnimals:
					ServiceAnimals();
					break;
				case ChoreKind.Fermenter:
					ServiceFermenter();
					break;
				case ChoreKind.Cooking:
					ServiceCooking();
					break;
				case ChoreKind.Haul:
					ServiceHaul();
					break;
				}
			}
		}

		private void ServiceStation()
		{
			//IL_009a: 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_0208: Unknown result type (might be due to invalid IL or missing references)
			bool flag = _station.GetQueueSize() < _station.m_maxOre;
			bool flag2 = (Object)(object)_station.m_fuelItem != (Object)null && _station.GetFuel() < (float)_station.m_maxFuel;
			if (!flag && !flag2)
			{
				ClearSpeech();
				return;
			}
			string text = (((Object)(object)_station.m_fuelItem != (Object)null) ? ((Object)_station.m_fuelItem).name : null);
			bool fuelMissing = flag2;
			bool oreMissing = flag;
			Inventory inventory = _humanoid.GetInventory();
			Collider[] array = Physics.OverlapSphere(((Component)_station).transform.position, 8f);
			bool flag3 = false;
			Collider[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				Container componentInParent = ((Component)array2[i]).GetComponentInParent<Container>();
				Inventory val = (((Object)(object)componentInParent != (Object)null) ? componentInParent.GetInventory() : null);
				if (val == null)
				{
					continue;
				}
				flag3 = true;
				foreach (ItemData item in new List<ItemData>(val.GetAllItems()))
				{
					string text2 = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : null);
					if (text2 == null)
					{
						continue;
					}
					if (flag2 && text2 == text)
					{
						if (val.RemoveItem(item, 1))
						{
							inventory.AddItem(item.Clone());
							OpenChest(componentInParent);
							FaceToward(((Component)_station).transform.position);
							_station.SetFuel(_station.GetFuel() + 1f);
							PlayEffects(_station.m_fuelAddedEffects, ((Component)_station).transform);
							flag2 = false;
							fuelMissing = false;
						}
					}
					else if (flag && _station.GetItemConversion(text2) != null && val.RemoveItem(item, 1))
					{
						inventory.AddItem(item.Clone());
						OpenChest(componentInParent);
						FaceToward(((Component)_station).transform.position);
						_station.QueueOre(text2);
						PlayEffects(_station.m_oreAddedEffects, ((Component)_station).transform);
						flag = false;
						oreMissing = false;
					}
				}
				if (!flag && !flag2)
				{
					break;
				}
			}
			if (!flag3)
			{
				Say("I have no chest to draw from!");
			}
			else
			{
				ReportMissing(oreMissing, fuelMissing);
			}
		}

		private string InputNames()
		{
			HashSet<string> hashSet = new HashSet<string>();
			if ((Object)(object)_station != (Object)null && _station.m_conversion != null)
			{
				foreach (ItemConversion item in _station.m_conversion)
				{
					if (item != null && (Object)(object)item.m_from != (Object)null && item.m_from.m_itemData != null && item.m_from.m_itemData.m_shared != null)
					{
						hashSet.Add(Localization.instance.Localize(item.m_from.m_itemData.m_shared.m_name));
					}
				}
			}
			if (hashSet.Count <= 0)
			{
				return "materials";
			}
			return string.Join(" or ", hashSet);
		}

		private string FuelName()
		{
			if ((Object)(object)_station != (Object)null && (Object)(object)_station.m_fuelItem != (Object)null && _station.m_fuelItem.m_itemData != null && _station.m_fuelItem.m_itemData.m_shared != null)
			{
				return Localization.instance.Localize(_station.m_fuelItem.m_itemData.m_shared.m_name);
			}
			return "fuel";
		}

		private void ServiceFarm()
		{
			//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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: 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_0199: 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_01be: 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_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: 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_01ff: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = CurrentCenter();
			Inventory val2 = FirstContainerInventory(val);
			Collider[] array = Physics.OverlapSphere(val, 10f);
			for (int i = 0; i < array.Length; i++)
			{
				Pickable componentInParent = ((Component)array[i]).GetComponentInParent<Pickable>();
				if ((Object)(object)componentInParent == (Object)null || !componentInParent.CanBePicked())
				{
					continue;
				}
				if (val2 == null)
				{
					Say("I have no chest for the harvest.");
					return;
				}
				GameObject itemPrefab = componentInParent.m_itemPrefab;
				int num = Mathf.Max(1, componentInParent.m_amount);
				if (!((Object)(object)itemPrefab == (Object)null))
				{
					if (!val2.CanAddItem(itemPrefab, num))
					{
						Say("The harvest chest is full!");
						return;
					}
					val2.AddItem(itemPrefab, num);
					componentInParent.SetPicked(true);
					FaceToward(((Component)componentInParent).transform.position);
					PlayEffects(componentInParent.m_pickEffector, null, ((Component)componentInParent).transform.position);
					ClearSpeech();
					return;
				}
			}
			if (val2 == null)
			{
				Say("I have no chest for the seeds.");
				return;
			}
			ItemData val3 = null;
			GameObject val4 = null;
			bool flag = false;
			foreach (ItemData allItem in val2.GetAllItems())
			{
				if (PlantingCatalog.TryGetSapling(((Object)(object)allItem.m_dropPrefab != (Object)null) ? ((Object)allItem.m_dropPrefab).name : null, out var sapling))
				{
					if (CanGrowInBiome(sapling.GetComponent<Plant>(), val))
					{
						val3 = allItem;
						val4 = sapling;
						break;
					}
					flag = true;
				}
			}
			Vector3 spot;
			if ((Object)(object)val4 == (Object)null)
			{
				Say(flag ? "These seeds won't grow in this land." : "No crops are ready, and no seeds to plant.");
			}
			else if (!TryFindPlantSpot(val, val4, out spot))
			{
				Say("There's no room left to plant.");
			}
			else if (val2.RemoveItem(val3, 1))
			{
				Object.Instantiate<GameObject>(val4, spot, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f));
				Piece component = val4.GetComponent<Piece>();
				if ((Object)(object)component != (Object)null)
				{
					PlayEffects(component.m_placeEffect, null, spot);
				}
				FaceToward(spot);
				Plugin.Log.LogInfo((object)$"[farm] planted '{((Object)val4).name}' at {spot} (biome {CurrentBiome(spot)}).");
				ClearSpeech();
			}
		}

		private bool TryFindPlantSpot(Vector3 center, GameObject sapling, out Vector3 spot)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			spot = center;
			Plant component = sapling.GetComponent<Plant>();
			float radius = (((Object)(object)component != (Object)null) ? Mathf.Max(component.m_growRadius, 0.5f) : 1f);
			ZoneSystem instance = ZoneSystem.instance;
			Vector3 val2 = default(Vector3);
			for (int i = 0; i < 24; i++)
			{
				Vector2 val = Random.insideUnitCircle * 8.5f;
				((Vector3)(ref val2))..ctor(center.x + val.x, center.y, center.z + val.y);
				if ((Object)(object)instance != (Object)null)
				{
					val2.y = instance.GetGroundHeight(val2);
				}
				Heightmap val3 = Heightmap.FindHeightmap(val2);
				if (!((Object)(object)val3 == (Object)null) && val3.IsCultivated(val2) && CanGrowInBiome(component, val2) && IsSpotClear(val2, radius))
				{
					spot = val2;
					return true;
				}
			}
			return false;
		}

		private static bool IsSpotClear(Vector3 p, float radius)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			Collider[] array = Physics.OverlapSphere(p, radius);
			foreach (Collider val in array)
			{
				if ((Object)(object)((Component)val).GetComponentInParent<Plant>() != (Object)null)
				{
					return false;
				}
				Pickable componentInParent = ((Component)val).GetComponentInParent<Pickable>();
				if ((Object)(object)componentInParent != (Object)null && !componentInParent.GetPicked())
				{
					return false;
				}
			}
			return true;
		}

		private static bool CanGrowInBiome(Plant plant, Vector3 pos)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			if ((Object)(object)plant == (Object)null)
			{
				return true;
			}
			if (WorldGenerator.instance == null)
			{
				return true;
			}
			Biome biome = WorldGenerator.instance.GetBiome(pos);
			return (plant.m_biome & biome) > 0;
		}

		private static Biome CurrentBiome(Vector3 pos)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (WorldGenerator.instance == null)
			{
				return (Biome)0;
			}
			return WorldGenerator.instance.GetBiome(pos);
		}

		private void ServiceAnimals()
		{
			//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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: 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_014c: 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_0156: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = CurrentCenter();
			List<Character> list = new List<Character>();
			Collider[] array = Physics.OverlapSphere(val, 10f);
			for (int i = 0; i < array.Length; i++)
			{
				Character componentInParent = ((Component)array[i]).GetComponentInParent<Character>();
				if (!((Object)(object)componentInParent == (Object)null) && componentInParent.IsTamed() && !((Object)(object)((Component)componentInParent).GetComponent<DvergrCompanion>() != (Object)null))
				{
					Tameable component = ((Component)componentInParent).GetComponent<Tameable>();
					if ((Object)(object)component != (Object)null && component.IsHungry() && !list.Contains(componentInParent))
					{
						list.Add(componentInParent);
					}
				}
			}
			if (list.Count == 0)
			{
				Say("The animals aren't hungry.");
				return;
			}
			Inventory val2 = FirstContainerInventory(val);
			if (val2 == null)
			{
				Say("I have no food chest nearby.");
				return;
			}
			foreach (Character item in list)
			{
				MonsterAI component2 = ((Component)item).GetComponent<MonsterAI>();
				if (!((Object)(object)component2 == (Object)null) && component2.m_consumeItems != null && !ItemAlreadyDroppedNear(((Component)item).transform.position))
				{
					ItemData val3 = FindAcceptedFood(val2, component2.m_consumeItems);
					if (val3 == null)
					{
						Say("I have no food to give.");
						return;
					}
					if (val2.RemoveItem(val3, 1))
					{
						ItemData obj = val3.Clone();
						obj.m_stack = 1;
						ItemDrop.DropItem(obj, 1, ((Component)item).transform.position + Vector3.up * 0.3f, Quaternion.identity);
						ClearSpeech();
						return;
					}
				}
			}
			ClearSpeech();
		}

		private static ItemData FindAcceptedFood(Inventory chest, List<ItemDrop> consumeItems)
		{
			foreach (ItemData allItem in chest.GetAllItems())
			{
				string text = (((Object)(object)allItem.m_dropPrefab != (Object)null) ? ((Object)allItem.m_dropPrefab).name : null);
				if (text == null)
				{
					continue;
				}
				foreach (ItemDrop consumeItem in consumeItems)
				{
					if ((Object)(object)consumeItem != (Object)null && ((Object)consumeItem).name == text)
					{
						return allItem;
					}
				}
			}
			return null;
		}

		private static bool ItemAlreadyDroppedNear(Vector3 pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			Collider[] array = Physics.OverlapSphere(pos, 2f);
			for (int i = 0; i < array.Length; i++)
			{
				if ((Object)(object)((Component)array[i]).GetComponentInParent<ItemDrop>() != (Object)null)
				{
					return true;
				}
			}
			return false;
		}

		private void ServiceFermenter()
		{
			//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_000c: 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_0020: Expected I4, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			Status status = _fermenter.GetStatus();
			switch (status - 1)
			{
			case 2:
				_fermenter.Interact(_humanoid, false, false);
				ClearSpeech();
				return;
			case 0:
				ClearSpeech();
				return;
			case 1:
				Say("The brew is exposed to the sky!");
				return;
			}
			Inventory val = FirstContainerInventory(CurrentCenter());
			if (val == null)
			{
				Say("I have no chest to brew from!");
				return;
			}
			foreach (ItemData item in new List<ItemData>(val.GetAllItems()))
			{
				string text = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : null);
				if (text != null && _fermenter.IsItemAllowed(text) && val.RemoveItem(item, 1))
				{
					ItemData val2 = item.Clone();
					val2.m_stack = 1;
					_humanoid.GetInventory().AddItem(val2);
					if (_fermenter.AddItem(_humanoid, val2))
					{
						ClearSpeech();
						return;
					}
				}
			}
			Say("I have nothing to brew!");
		}

		private void ServiceCooking()
		{
			//IL_005a: 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)
			if (_cooker.HaveDoneItem())
			{
				_cooker.OnInteract(_humanoid);
				ClearSpeech();
				return;
			}
			if ((Object)(object)_cooker.m_fuelItem != (Object)null && _cooker.GetFuel() < (float)_cooker.m_maxFuel)
			{
				Inventory val = FirstContainerInventory(CurrentCenter());
				string name = ((Object)_cooker.m_fuelItem).name;
				if (val != null)
				{
					foreach (ItemData item in new List<ItemData>(val.GetAllItems()))
					{
						if (!((((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : null) != name) && val.RemoveItem(item, 1))
						{
							_humanoid.GetInventory().AddItem(item.Clone());
							_cooker.SetFuel(_cooker.GetFuel() + 1f);
							ClearSpeech();
							return;
						}
					}
				}
			}
			if (_cooker.m_requireFire && !_cooker.IsFireLit())
			{
				Say("The cooking fire is out!");
				return;
			}
			if (_cooker.GetFreeSlot() < 0)
			{
				ClearSpeech();
				return;
			}
			Inventory val2 = FirstContainerInventory(CurrentCenter());
			if (val2 == null)
			{
				Say("I have no chest to cook from!");
				return;
			}
			foreach (ItemData item2 in new List<ItemData>(val2.GetAllItems()))
			{
				string text = (((Object)(object)item2.m_dropPrefab != (Object)null) ? ((Object)item2.m_dropPrefab).name : null);
				if (text != null && _cooker.GetItemConversion(text) != null && val2.RemoveItem(item2, 1))
				{
					ItemData val3 = item2.Clone();
					val3.m_stack = 1;
					_humanoid.GetInventory().AddItem(val3);
					if (_cooker.CookItem(_humanoid, val3))
					{
						ClearSpeech();
						return;
					}
				}
			}
			Say("I have nothing to cook!");
		}

		private void ServiceHaul()
		{
			//IL_0022: 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)
			Inventory val = (((Object)(object)_haulChest != (Object)null) ? _haulChest.GetInventory() : null);
			if (val == null)
			{
				return;
			}
			Collider[] array = Physics.OverlapSphere(CurrentCenter(), 10f);
			for (int i = 0; i < array.Length; i++)
			{
				ItemDrop componentInParent = ((Component)array[i]).GetComponentInParent<ItemDrop>();
				if ((Object)(object)componentInParent == (Object)null || !componentInParent.CanPickup(false))
				{
					continue;
				}
				ZNetView component = ((Component)componentInParent).GetComponent<ZNetView>();
				if ((Object)(object)component == (Object)null || !component.IsValid())
				{
					continue;
				}
				ItemData itemData = componentInParent.m_itemData;
				if (itemData != null)
				{
					if (!val.CanAddItem(itemData, itemData.m_stack))
					{
						Say("The haul chest is full!");
						return;
					}
					val.AddItem(itemData.Clone());
					OpenChest(_haulChest);
					FaceToward(((Component)_haulChest).transform.position);
					component.ClaimOwnership();
					ZNetScene.instance.Destroy(((Component)componentInParent).gameObject);
					ClearSpeech();
					return;
				}
			}
			ClearSpeech();
		}

		private Inventory FirstContainerInventory(Vector3 center)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			Collider[] array = Physics.OverlapSphere(center, 8f);
			for (int i = 0; i < array.Length; i++)
			{
				Container componentInParent = ((Component)array[i]).GetComponentInParent<Container>();
				Inventory val = (((Object)(object)componentInParent != (Object)null) ? componentInParent.GetInventory() : null);
				if (val != null)
				{
					return val;
				}
			}
			return null;
		}

		private void PlayEffects(EffectList effects, Transform parent, Vector3? at = null)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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_0026: 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)
			if (effects != null)
			{
				Vector3 val = (Vector3)(((??)at) ?? (((Object)(object)parent != (Object)null) ? parent.position : ((Component)this).transform.position));
				effects.Create(val, Quaternion.identity, parent, 1f, -1);
			}
		}

		private void ReportMissing(bool oreMissing, bool fuelMissing)
		{
			string text = ((oreMissing && fuelMissing) ? ("I need more " + InputNames() + " and " + FuelName() + "!") : (fuelMissing ? ("I need more " + FuelName() + "!") : (oreMissing ? ("I need more " + InputNames() + "!") : null)));
			if (text == null)
			{
				ClearSpeech();
			}
			else
			{
				Say(text);
			}
		}

		private void Say(string text)
		{
			//IL_0059: 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)
			if (!((Object)(object)Chat.instance == (Object)null) && !((Object)(object)_companion == (Object)null) && _companion.IsOwnerNear(20f) && !(Time.time - _lastSayTime < 60f))
			{
				_lastSayTime = Time.time;
				Chat.instance.SetNpcText(((Component)this).gameObject, Vector3.up * 2.2f, 20f, 8f, string.Empty, text, false);
			}
		}

		private void ClearSpeech()
		{
			if ((Object)(object)Chat.instance != (Object)null)
			{
				Chat.instance.ClearNpcText(((Component)this).gameObject);
			}
		}
	}
	public static class ChoreRules
	{
		public static DvergrCaste? RequiredCaste(Smelter station)
		{
			string text = (((Object)(object)station != (Object)null) ? ((Object)station).name.ToLowerInvariant() : string.Empty);
			if (text.Contains("smelter") || text.Contains("blast") || text.Contains("charcoal"))
			{
				return DvergrCaste.FireMage;
			}
			if (text.Contains("eitr") || text.Contains("spinning") || text.Contains("windmill"))
			{
				return DvergrCaste.IceMage;
			}
			return null;
		}

		public static string DisplayName(DvergrCaste caste)
		{
			return caste.Display();
		}
	}
	public static class CommunionService
	{
		public const float SubdueHealthThreshold = 0.2f;

		public static DvergrCaste DetectCaste(Character target, bool log = true)
		{
			if ((Object)(object)target == (Object)null)
			{
				return DvergrCaste.Rogue;
			}
			Humanoid component = ((Component)target).GetComponent<Humanoid>();
			if ((Object)(object)component != (Object)null)
			{
				string[] array = new string[5]
				{
					ItemName(component.GetCurrentWeapon()),
					ItemName(component.m_rightItem),
					ItemName(component.m_hiddenRightItem),
					ItemName(component.m_leftItem),
					ItemName(component.m_hiddenLeftItem)
				};
				foreach (string text in array)
				{
					DvergrCaste? dvergrCaste = ClassifyByElement(text);
					if (dvergrCaste.HasValue)
					{
						if (log)
						{
							Plugin.Log.LogInfo((object)$"[recruit] caste {dvergrCaste.Value} from weapon slot '{text}'.");
						}
						return dvergrCaste.Value;
					}
				}
				Inventory inventory = component.GetInventory();
				if (inventory != null)
				{
					foreach (ItemData allItem in inventory.GetAllItems())
					{
						string text2 = ItemName(allItem);
						DvergrCaste? dvergrCaste2 = ((text2 != null && text2.ToLowerInvariant().Contains("staff")) ? ClassifyByElement(text2) : ((DvergrCaste?)null));
						if (dvergrCaste2.HasValue)
						{
							if (log)
							{
								Plugin.Log.LogInfo((object)$"[recruit] caste {dvergrCaste2.Value} from inventory item '{text2}'.");
							}
							return dvergrCaste2.Value;
						}
					}
				}
			}
			string name = ((Object)target).name;
			if (!string.IsNullOrEmpty(name))
			{
				if (name.IndexOf("Fire", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return DvergrCaste.FireMage;
				}
				if (name.IndexOf("Ice", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return DvergrCaste.IceMage;
				}
				if (name.IndexOf("Support", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return DvergrCaste.SupportMage;
				}
			}
			if (log)
			{
				LogDetectionMiss(target, component);
			}
			return DvergrCaste.Rogue;
		}

		private static DvergrCaste? ClassifyByElement(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return null;
			}
			string text = name.ToLowerInvariant();
			if (text.Contains("fire"))
			{
				return DvergrCaste.FireMage;
			}
			if (text.Contains("ice") || text.Contains("frost"))
			{
				return DvergrCaste.IceMage;
			}
			if (text.Contains("support") || text.Contains("heal") || text.Contains("nova") || text.Contains("blocker") || text.Contains("shield"))
			{
				return DvergrCaste.SupportMage;
			}
			return null;
		}

		private static string ItemName(ItemData item)
		{
			if (item == null)
			{
				return null;
			}
			if ((Object)(object)item.m_dropPrefab != (Object)null)
			{
				return ((Object)item.m_dropPrefab).name;
			}
			if (item.m_shared == null)
			{
				return null;
			}
			return item.m_shared.m_name;
		}

		private static void LogDetectionMiss(Character target, Humanoid humanoid)
		{
			string text = "(none)";
			if ((Object)(object)humanoid != (Object)null && humanoid.GetInventory() != null)
			{
				List<string> list = new List<string>();
				foreach (ItemData allItem in humanoid.GetInventory().GetAllItems())
				{
					list.Add(ItemName(allItem));
				}
				if (list.Count > 0)
				{
					text = string.Join(", ", list);
				}
			}
			Plugin.Log.LogInfo((object)("[recruit] No staff detected -> Rogue. prefab='" + ((Object)target).name + "', slots[" + Slots() + "], inventory=[" + text + "]."));
			string Slots()
			{
				if ((Object)(object)humanoid == (Object)null)
				{
					return "(no humanoid)";
				}
				return "cur='" + ItemName(humanoid.GetCurrentWeapon()) + "', right='" + ItemName(humanoid.m_rightItem) + "', hiddenRight='" + ItemName(humanoid.m_hiddenRightItem) + "', left='" + ItemName(humanoid.m_leftItem) + "', hiddenLeft='" + ItemName(humanoid.m_hiddenLeftItem) + "'";
			}
		}

		public static GameObject SpawnRecruited(DvergrCaste caste, int level, Player owner, Vector3 pos, float xp = 0f)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return null;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab(CastePrefab(caste));
			if ((Object)(object)prefab == (Object)null && caste != DvergrCaste.Rogue)
			{
				prefab = ZNetScene.instance.GetPrefab("DvergerMage");
			}
			if ((Object)(object)prefab == (Object)null)
			{
				prefab = ZNetScene.instance.GetPrefab("Dverger");
			}
			if ((Object)(object)prefab == (Object)null)
			{
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(prefab, pos, Quaternion.identity);
			Character component = val.GetComponent<Character>();
			ZNetView component2 = val.GetComponent<ZNetView>();
			if ((Object)(object)component2 != (Object)null && component2.IsValid())
			{
				ZDO zDO = component2.GetZDO();
				zDO.Set("DE_Recruited", true);
				zDO.Set("DE_Caste", (int)caste);
				zDO.Set("DE_Level", Mathf.Clamp(level, 1, 10));
				zDO.Set("DE_Xp", Mathf.Max(0f, xp));
				if ((Object)(object)owner != (Object)null)
				{
					zDO.Set("DE_Owner", owner.GetPlayerID());
					zDO.Set("DE_OwnerName", owner.GetPlayerName());
				}
			}
			if ((Object)(object)component != (Object)null)
			{
				ApplyFreedState(component, ((Object)(object)owner != (Object)null) ? ((Component)owner).gameObject : null);
			}
			if ((Object)(object)val.GetComponent<DvergrCompanion>() == (Object)null)
			{
				val.AddComponent<DvergrCompanion>();
			}
			if ((Object)(object)val.GetComponent<ShipRideAI>() == (Object)null)
			{
				val.AddComponent<ShipRideAI>();
			}
			if ((Object)(object)val.GetComponent<CompanionInventory>() == (Object)null)
			{
				val.AddComponent<CompanionInventory>();
			}
			Plugin.Log.LogInfo((object)string.Format("[admin] Spawned recruited {0} (lv {1}) for {2}.", caste, level, ((Object)(object)owner != (Object)null) ? owner.GetPlayerName() : "?"));
			return val;
		}

		private static string CastePrefab(DvergrCaste caste)
		{
			return caste switch
			{
				DvergrCaste.FireMage => "DvergerMageFire", 
				DvergrCaste.IceMage => "DvergerMageIce", 
				DvergrCaste.SupportMage => "DvergerMageSupport", 
				_ => "Dverger", 
			};
		}

		public static bool IsSubduedDvergr(Character target)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			if ((Object)(object)target == (Object)null)
			{
				return false;
			}
			if ((int)target.m_faction != 10)
			{
				return false;
			}
			if (target.IsDead())
			{
				return false;
			}
			return target.GetHealthPercentage() <= 0.2f;
		}

		public static bool TryRecruit(Character target, Player recruiter, DvergrCaste caste)
		{
			if (!IsSubduedDvergr(target))
			{
				return false;
			}
			ApplyFreedState(target, ((Object)(object)recruiter != (Object)null) ? ((Component)recruiter).gameObject : null);
			DvergrCompanion dvergrCompanion = ((Component)target).GetComponent<DvergrCompanion>();
			if ((Object)(object)dvergrCompanion == (Object)null)
			{
				dvergrCompanion = ((Component)target).gameObject.AddComponent<DvergrCompanion>();
			}
			if ((Object)(object)((Component)target).GetComponent<ShipRideAI>() == (Object)null)
			{
				((Component)target).gameObject.AddComponent<ShipRideAI>();
			}
			if ((Object)(object)((Component)target).GetComponent<CompanionInventory>() == (Object)null)
			{
				((Component)target).gameObject.AddComponent<CompanionInventory>();
			}
			dvergrCompanion.SetCaste(caste);
			if ((Object)(object)recruiter != (Object)null)
			{
				dvergrCompanion.SetOwner(recruiter.GetPlayerID());
				dvergrCompanion.SetOwnerName(recruiter.GetPlayerName());
			}
			ZNetView component = ((Component)target).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null && component.IsValid())
			{
				component.GetZDO().Set("DE_Recruited", true);
			}
			Plugin.Log.LogInfo((object)string.Format("Dvergr {0} recruited by {1}.", caste, ((Object)(object)recruiter != (Object)null) ? recruiter.GetPlayerName() : "unknown"));
			ServerGuideBridge.RaiseRecruited(caste);
			dvergrCompanion.AnnounceCapability();
			return true;
		}

		public static void RestoreCompanion(Character target)
		{
			if ((Object)(object)target == (Object)null)
			{
				return;
			}
			ZNetView component = ((Component)target).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid() && component.GetZDO().GetBool("DE_Recruited", false))
			{
				ApplyFreedState(target, null);
				if ((Object)(object)((Component)target).GetComponent<DvergrCompanion>() == (Object)null)
				{
					((Component)target).gameObject.AddComponent<DvergrCompanion>();
				}
				if ((Object)(object)((Component)target).GetComponent<ShipRideAI>() == (Object)null)
				{
					((Component)target).gameObject.AddComponent<ShipRideAI>();
				}
				if ((Object)(object)((Component)target).GetComponent<CompanionInventory>() == (Object)null)
				{
					((Component)target).gameObject.AddComponent<CompanionInventory>();
				}
				if (ChoreAI.HasPersistedChore(component) && (Object)(object)((Component)target).GetComponent<ChoreAI>() == (Object)null)
				{
					((Component)target).gameObject.AddComponent<ChoreAI>();
				}
			}
		}

		private static void ApplyFreedState(Character target, GameObject followTarget)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			target.m_faction = (Faction)0;
			NpcTalk component = ((Component)target).GetComponent<NpcTalk>();
			if ((Object)(object)component != (Object)null)
			{
				((Behaviour)component).enabled = false;
			}
			MonsterAI component2 = ((Component)target).GetComponent<MonsterAI>();
			if (!((Object)(object)component2 == (Object)null))
			{
				((BaseAI)component2).SetAggravated(false, (AggravatedReason)0);
				((BaseAI)component2).m_aggravatable = false;
				component2.m_attackPlayerObjects = false;
				component2.m_targetStatic = null;
				((BaseAI)component2).m_avoidWater = true;
				component2.SetTarget((Character)null);
				((BaseAI)component2).SetAlerted(false);
				((BaseAI)component2).SetHuntPlayer(false);
				if ((Object)(object)followTarget != (Object)null)
				{
					component2.SetFollowTarget(followTarget);
				}
			}
		}
	}
	public enum ConsumableKind
	{
		None,
		Food,
		HealthMead,
		ResistMead
	}
	public static class CompanionConsumables
	{
		public static ConsumableKind Classify(ItemData item)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			if (item?.m_shared == null)
			{
				return ConsumableKind.None;
			}
			if ((int)item.m_shared.m_itemType != 2)
			{
				return ConsumableKind.None;
			}
			if (item.m_shared.m_food > 0f)
			{
				return ConsumableKind.Food;
			}
			StatusEffect consumeStatusEffect = item.m_shared.m_consumeStatusEffect;
			SE_Stats val = (SE_Stats)(object)((consumeStatusEffect is SE_Stats) ? consumeStatusEffect : null);
			if ((Object)(object)val == (Object)null)
			{
				return ConsumableKind.None;
			}
			if (val.m_healthUpFront + val.m_healthOverTime > 0f)
			{
				return ConsumableKind.HealthMead;
			}
			if (GrantsResistance(val))
			{
				return ConsumableKind.ResistMead;
			}
			return ConsumableKind.None;
		}

		public static float HealAmount(ItemData item)
		{
			StatusEffect obj = item?.m_shared?.m_consumeStatusEffect;
			SE_Stats val = (SE_Stats)(object)((obj is SE_Stats) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				return 0f;
			}
			return Mathf.Max(0f, val.m_healthUpFront + val.m_healthOverTime);
		}

		public static StatusEffect ConsumeEffect(ItemData item)
		{
			if (item?.m_shared == null)
			{
				return null;
			}
			return item.m_shared.m_consumeStatusEffect;
		}

		private static bool GrantsResistance(SE_Stats stats)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected I4, but got Unknown
			if (stats.m_mods == null)
			{
				return false;
			}
			foreach (DamageModPair mod in stats.m_mods)
			{
				DamageModifier modifier = mod.m_modifier;
				switch (modifier - 1)
				{
				case 0:
				case 2:
				case 4:
					return true;
				}
			}
			return false;
		}

		public static List<StatusEffect> ActiveResistEffects(Character c)
		{
			List<StatusEffect> list = new List<StatusEffect>();
			SEMan val = (((Object)(object)c != (Object)null) ? c.GetSEMan() : null);
			if (val == null)
			{
				return list;
			}
			foreach (StatusEffect statusEffect in val.GetStatusEffects())
			{
				SE_Stats val2 = (SE_Stats)(object)((statusEffect is SE_Stats) ? statusEffect : null);
				if (val2 != null && GrantsResistance(val2))
				{
					list.Add(statusEffect);
				}
			}
			return list;
		}
	}
	[RequireComponent(typeof(DvergrCompanion))]
	public class CompanionInventory : MonoBehaviour
	{
		public const int Columns = 4;

		public const int Rows = 2;

		public const float MaxWeight = 150f;

		private Container _container;

		private DvergrCompanion _companion;

		public Container Container => _container;

		public Inventory Inventory
		{
			get
			{
				if (!((Object)(object)_container != (Object)null))
				{
					return null;
				}
				return _container.GetInventory();
			}
		}

		public bool IsOverCapacity => TotalWeight() > 150f;

		public bool IsEmpty
		{
			get
			{
				if (Inventory != null)
				{
					return Inventory.NrOfItems() == 0;
				}
				return true;
			}
		}

		private void Awake()
		{
			_companion = ((Component)this).GetComponent<DvergrCompanion>();
			EnsureContainer();
			if ((Object)(object)((Component)this).GetComponent<CompanionInventoryAI>() == (Object)null)
			{
				((Component)this).gameObject.AddComponent<CompanionInventoryAI>();
			}
		}

		public void EnsureContainer()
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			if (!((Object)(object)_container != (Object)null) || _container.GetInventory() == null)
			{
				_container = ((Component)this).GetComponent<Container>() ?? ((Component)this).gameObject.AddComponent<Container>();
				_container.m_name = InventoryTitle();
				_container.m_width = 4;
				_container.m_height = 2;
				_container.m_checkGuardStone = false;
				_container.m_autoDestroyEmpty = false;
				ZNetView component = ((Component)this).GetComponent<ZNetView>();
				if ((Object)(object)component != (Object)null && component.IsValid())
				{
					Inventory val = new Inventory(_container.m_name, (Sprite)null, 4, 2);
					val.m_onChanged = _container.OnContainerChanged;
					_container.m_inventory = val;
					_container.Load();
				}
			}
		}

		public string InventoryTitle()
		{
			return (((Object)(object)_companion != (Object)null) ? _companion.DisplayName : "Dvergr") + "'s pack";
		}

		public void RefreshTitle()
		{
			if ((Object)(object)_container != (Object)null)
			{
				_container.m_name = InventoryTitle();
			}
		}

		public float TotalWeight()
		{
			if (Inventory == null)
			{
				return 0f;
			}
			return Inventory.GetTotalWeight();
		}

		public bool Holds(ItemData item)
		{
			if (item?.m_shared == null || Inventory == null)
			{
				return false;
			}
			foreach (ItemData allItem in Inventory.GetAllItems())
			{
				if (allItem?.m_shared != null && allItem.m_shared.m_name == item.m_shared.m_name)
				{
					return true;
				}
			}
			return false;
		}

		public ItemData FindItem(Func<ItemData, bool> match)
		{
			if (Inventory == null)
			{
				return null;
			}
			foreach (ItemData allItem in Inventory.GetAllItems())
			{
				if (allItem != null && match(allItem))
				{
					return allItem;
				}
			}
			return null;
		}

		public List<ItemData> Items()
		{
			if (Inventory == null)
			{
				return new List<ItemData>();
			}
			return Inventory.GetAllItems();
		}

		public bool ConsumeOne(ItemData item)
		{
			if (item == null || Inventory == null)
			{
				return false;
			}
			return Inventory.RemoveItem(item, 1);
		}
	}
	[RequireComponent(typeof(DvergrCompanion))]
	[RequireComponent(typeof(CompanionInventory))]
	public class CompanionInventoryAI : MonoBehaviour
	{
		private const float TickInterval = 1f;

		private const float PickupRange = 8f;

		private const float MeadHealBelowFraction = 0.35f;

		private const float MeadHealUntilFraction = 0.9f;

		private DvergrCompanion _companion;

		private CompanionInventory _inv;

		private Character _character;

		private MonsterAI _ai;

		private ZNetView _znv;

		private float _tick;

		private float _foodPeak;

		private float _foodApplied;

		private float _foodDuration;

		private float _foodElapsed;

		private bool _healing;

		private void Awake()
		{
			_companion = ((Component)this).GetComponent<DvergrCompanion>();
			_inv = ((Component)this).GetComponent<CompanionInventory>();
			_character = ((Component)this).GetComponent<Character>();
			_ai = ((Component)this).GetComponent<MonsterAI>();
			_znv = ((Component)this).GetComponent<ZNetView>();
		}

		private void Update()
		{
			if ((Object)(object)_character == (Object)null || _character.IsDead())
			{
				return;
			}
			if (!((Object)(object)_znv == (Object)null) && _znv.IsValid() && !_znv.IsOwner())
			{
				if ((Object)(object)_companion != (Object)null && (Object)(object)_inv != (Object)null)
				{
					_companion.IsEncumbered = _inv.IsOverCapacity;
				}
				return;
			}
			TickFoodBuff(Time.deltaTime);
			bool isOverCapacity = _inv.IsOverCapacity;
			if (_companion.DuelMode)
			{
				_companion.IsEncumbered = isOverCapacity;
			}
			else
			{
				_companion.ApplyEncumbrance(isOverCapacity);
			}
			_tick += Time.deltaTime;
			if (!(_tick < 1f))
			{
				_tick = 0f;
				TickConsumption();
				if (!isOverCapacity && (!((Object)(object)_ai != (Object)null) || (!((BaseAI)_ai).IsAlerted() && !((BaseAI)_ai).HaveTarget())) && !_companion.ChoreActive && !_companion.DuelMode && !_inv.IsEmpty)
				{
					TickPickup();
				}
			}
		}

		private void TickPickup()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			Inventory inventory = _inv.Inventory;
			if (inventory == null)
			{
				return;
			}
			Collider[] array = Physics.OverlapSphere(((Component)this).transform.position, 8f);
			foreach (Collider val in array)
			{
				ItemDrop val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInParent<ItemDrop>() : null);
				if ((Object)(object)val2 == (Object)null || !val2.CanPickup(false))
				{
					continue;
				}
				ZNetView component = ((Component)val2).GetComponent<ZNetView>();
				if ((Object)(object)component == (Object)null || !component.IsValid())
				{
					continue;
				}
				ItemData itemData = val2.m_itemData;
				if (itemData?.m_shared != null && _inv.Holds(itemData))
				{
					if (inventory.CanAddItem(itemData, itemData.m_stack))
					{
						inventory.AddItem(itemData.Clone());
						component.ClaimOwnership();
						ZNetScene.instance.Destroy(((Component)val2).gameObject);
					}
					break;
				}
			}
		}

		private void TickConsumption()
		{
			if (_inv.Inventory == null)
			{
				return;
			}
			ItemData val = _inv.FindItem((ItemData it) => CompanionConsumables.Classify(it) == ConsumableKind.ResistMead && !HasEffect(CompanionConsumables.ConsumeEffect(it)));
			if (val != null)
			{
				DrinkStatusMead(val);
				return;
			}
			float healthPercentage = _character.GetHealthPercentage();
			if (healthPercentage < 0.35f)
			{
				_healing = true;
			}
			else if (healthPercentage > 0.9f)
			{
				_healing = false;
			}
			if (_healing)
			{
				ItemData val2 = _inv.FindItem((ItemData it) => CompanionConsumables.Classify(it) == ConsumableKind.HealthMead);
				if (val2 != null)
				{
					float num = CompanionConsumables.HealAmount(val2);
					if (_inv.ConsumeOne(val2))
					{
						_character.Heal(num, true);
						PlayConsumeEffects(val2);
					}
					return;
				}
				_healing = false;
			}
			if (_foodApplied <= 0f && _foodElapsed >= _foodDuration)
			{
				ItemData val3 = _inv.FindItem((ItemData it) => CompanionConsumables.Classify(it) == ConsumableKind.Food);
				if (val3 != null)
				{
					EatFood(val3);
				}
			}
		}

		private void DrinkStatusMead(ItemData mead)
		{
			StatusEffect val = CompanionConsumables.ConsumeEffect(mead);
			if (!((Object)(object)val == (Object)null) && _inv.ConsumeOne(mead))
			{
				_character.GetSEMan().AddStatusEffect(val, true, 0, 0f);
				PlayConsumeEffects(mead);
			}
		}

		private bool HasEffect(StatusEffect se)
		{
			if ((Object)(object)se == (Object)null || (Object)(object)_character == (Object)null)
			{
				return false;
			}
			return _character.GetSEMan().HaveStatusEffect(se.NameHash());
		}

		private void PlayConsumeEffects(ItemData item)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			StatusEffect val = CompanionConsumables.ConsumeEffect(item);
			EffectList val2 = (((Object)(object)val != (Object)null) ? val.m_startEffects : null);
			if (val2 != null)
			{
				val2.Create(((Component)this).transform.position, ((Component)this).transform.rotation, ((Component)this).transform, 1f, -1);
			}
		}

		private void EatFood(ItemData food)
		{
			if (_inv.ConsumeOne(food))
			{
				_foodPeak = food.m_shared.m_food;
				_foodDuration = Mathf.Max(1f, food.m_shared.m_foodBurnTime);
				_foodElapsed = 0f;
				ApplyFoodBonus(_foodPeak);
				_companion.IsFed = true;
				_companion.FedIcon = ((food.m_shared.m_icons != null && food.m_shared.m_icons.Length != 0) ? food.m_shared.m_icons[0] : null);
				PlayConsumeEffects(food);
			}
		}

		private void TickFoodBuff(float dt)
		{
			if (!(_foodApplied <= 0f) || !(_foodElapsed >= _foodDuration))
			{
				_foodElapsed += dt;
				if (_foodElapsed >= _foodDuration)
				{
					ExpireFood();
					return;
				}
				float num = _foodElapsed / _foodDuration;
				float num2 = ((num <= 0.5f) ? 1f : Mathf.Clamp01(1f - (num - 0.5f) / 0.5f));
				ApplyFoodBonus(_foodPeak * num2);
			}
		}

		private void ApplyFoodBonus(float target)
		{
			if ((Object)(object)_character == (Object)null)
			{
				return;
			}
			float num = target - _foodApplied;
			if (!(Mathf.Abs(num) < 0.01f))
			{
				float num2 = Mathf.Max(1f, _character.GetMaxHealth() + num);
				_character.SetMaxHealth(num2);
				if (num > 0f)
				{
					_character.Heal(num, false);
				}
				else if (_character.GetHealth() > num2)
				{
					_character.SetHealth(num2);
				}
				_foodApplied = target;
			}
		}

		private void ExpireFood()
		{
			if (_foodApplied > 0f && (Object)(object)_character != (Object)null)
			{
				float num = Mathf.Max(1f, _character.GetMaxHealth() - _foodApplied);
				_character.SetMaxHealth(num);
				if (_character.GetHealth() > num)
				{
					_character.SetHealth(num);
				}
			}
			_foodApplied = 0f;
			_foodPeak = 0f;
			_foodElapsed = 0f;
			_foodDuration = 0f;
			if ((Object)(object)_companion != (Object)null)
			{
				_companion.IsFed = false;
				_companion.FedIcon = null;
			}
		}
	}
	public class CompanionInventoryGui : MonoBehaviour
	{
		private static CompanionInventoryGui _instance;

		private DvergrCompanion _openCompanion;

		private CompanionInventory _openInventory;

		private Character _openCharacter;

		private TMP_InputField _nameField;

		private TMP_Text _hpText;

		private bool _cloneFailed;

		private const int VanillaInventoryHeight = 4;

		private const float ContainerClearancePx = 22f;

		private static float _baseContainerY = float.NaN;

		public static bool IsTyping
		{
			get
			{
				if ((Object)(object)_instance != (Object)null && (Object)(object)_instance._nameField != (Object)null)
				{
					return _instance._nameField.isFocused;
				}
				return false;
			}
		}

		public static void Open(DvergrCompanion companion, CompanionInventory inventory)
		{
			if (!((Object)(object)_instance == (Object)null) && !((Object)(object)companion == (Object)null) && !((Object)(object)inventory == (Object)null) && !((Object)(object)InventoryGui.instance == (Object)null))
			{
				inventory.EnsureContainer();
				inventory.RefreshTitle();
				if (!((Object)(object)inventory.Container == (Object)null))
				{
					InventoryGui.instance.Show(inventory.Container, 0);
					_instance._openCompanion = companion;
					_instance._openInventory = inventory;
					_instance._openCharacter = ((Component)companion).GetComponent<Character>();
					_instance.BuildWidgets();
					_instance.ShowWidgets(show: true);
					_instance.Refresh();
				}
			}
		}

		private void Awake()
		{
			_instance = this;
		}

		private void Update()
		{
			if (!((Object)(object)_openCompanion == (Object)null))
			{
				InventoryGui instance = InventoryGui.instance;
				if (!((Object)(object)instance != (Object)null) || !InventoryGui.IsVisible() || !((Object)(object)instance.m_currentContainer != (Object)null) || !((Object)(object)_openInventory != (Object)null) || !((Object)(object)instance.m_currentContainer == (Object)(object)_openInventory.Container) || !((Object)(object)_openCharacter != (Object)null) || _openCharacter.IsDead())
				{
					ShowWidgets(show: false);
					RestoreContainerShift();
					_openCompanion = null;
					_openInventory = null;
					_openCharacter = null;
				}
				else
				{
					Refresh();
				}
			}
		}

		private void Refresh()
		{
			ApplyContainerShift();
			if ((Object)(object)_nameField != (Object)null && !_nameField.isFocused)
			{
				_nameField.SetTextWithoutNotify(_openCompanion.DisplayName);
			}
			if ((Object)(object)_hpText != (Object)null && (Object)(object)_openCharacter != (Object)null)
			{
				float num = Mathf.Ceil(_openCharacter.GetHealth());
				float num2 = Mathf.Ceil(_openCharacter.GetMaxHealth());
				string arg = (_openCompanion.IsFed ? "#FFD24A" : "#FFFFFF");
				_hpText.text = $"<color={arg}>HP {num:0} / {num2:0}</color>";
			}
		}

		private void ApplyContainerShift()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			InventoryGui instance = InventoryGui.instance;
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)localPlayer == (Object)null) && !((Object)(object)instance.m_container == (Object)null) && !((Object)(object)instance.m_playerGrid == (Object)null))
			{
				RectTransform container = instance.m_container;
				if (float.IsNaN(_baseContainerY))
				{
					_baseContainerY = container.anchoredPosition.y;
				}
				float num = (float)Mathf.Max(0, ((Humanoid)localPlayer).GetInventory().GetHeight() - 4) * instance.m_playerGrid.m_elementSpace;
				float num2 = ((num > 0f) ? 22f : 0f);
				Vector2 anchoredPosition = container.anchoredPosition;
				anchoredPosition.y = _baseContainerY - num - num2;
				container.anchoredPosition = anchoredPosition;
			}
		}

		private void RestoreContainerShift()
		{
			//IL_0033: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			if (!float.IsNaN(_baseContainerY))
			{
				RectTransform val = (((Object)(object)InventoryGui.instance != (Object)null) ? InventoryGui.instance.m_container : null);
				if (!((Object)(object)val == (Object)null))
				{
					Vector2 anchoredPosition = val.anchoredPosition;
					anchoredPosition.y = _baseContainerY;
					val.anchoredPosition = anchoredPosition;
				}
			}
		}

		private void BuildWidgets()
		{
			if (_cloneFailed)
			{
				return;
			}
			RectTransform val = (((Object)(object)InventoryGui.instance != (Object)null) ? InventoryGui.instance.m_container : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			try
			{
				EnsureNameField(val);
				EnsureHpText(val);
			}
			catch (Exception ex)
			{
				_cloneFailed = true;
				Plugin.Log.LogWarning((object)("[inventory] Could not build companion panel widgets: " + ex.Message));
			}
		}

		private void EnsureNameField(RectTransform panel)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_nameField != (Object)null)
			{
				return;
			}
			GuiInputField val = (((Object)(object)TextInput.instance != (Object)null) ? TextInput.instance.m_inputField : null);
			if (!((Object)(object)val == (Object)null))
			{
				GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, (Transform)(object)panel);
				((Object)val2).name = "CompanionNameField";
				RectTransform component = val2.GetComponent<RectTransform>();
				if ((Object)(object)component != (Object)null)
				{
					Park(component, new Vector2(18f, -44f), new Vector2(210f, 28f));
				}
				_nameField = val2.GetComponent<TMP_InputField>();
				if ((Object)(object)_nameField == (Object)null)
				{
					Object.Destroy((Object)(object)val2);
					return;
				}
				((UnityEventBase)_nameField.onEndEdit).RemoveAllListeners();
				((UnityEvent<string>)(object)_nameField.onEndEdit).AddListener((UnityAction<string>)OnNameSubmitted);
				_nameField.characterLimit = 24;
			}
		}

		private void EnsureHpText(RectTransform panel)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_hpText != (Object)null)
			{
				return;
			}
			TMP_Text val = (((Object)(object)InventoryGui.instance != (Object)null) ? InventoryGui.instance.m_containerWeight : null);
			if (!((Object)(object)val == (Object)null))
			{
				GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, (Transform)(object)panel);
				((Object)val2).name = "CompanionHpText";
				RectTransform component = val2.GetComponent<RectTransform>();
				if ((Object)(object)component != (Object)null)
				{
					Park(component, new Vector2(236f, -44f), new Vector2(210f, 28f));
				}
				_hpText = val2.GetComponent<TMP_Text>();
				if ((Object)(object)_hpText != (Object)null)
				{
					_hpText.alignment = (TextAlignmentOptions)513;
					_hpText.enableAutoSizing = false;
					_hpText.fontSize = 18f;
					_hpText.richText = true;
				}
			}
		}

		private static void Park(RectTransform rt, Vector2 anchoredPos, Vector2 size)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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)
			rt.anchorMin = new Vector2(0f, 1f);
			rt.anchorMax = new Vector2(0f, 1f);
			rt.pivot = new Vector2(0f, 1f);
			rt.anchoredPosition = anchoredPos;
			rt.sizeDelta = size;
		}

		private void ShowWidgets(bool show)
		{
			if ((Object)(object)_nameField != (Object)null)
			{
				((Component)_nameField).gameObject.SetActive(show);
			}
			if ((Object)(object)_hpText != (Object)null)
			{
				((Component)_hpText).gameObject.SetActive(show);
			}
		}

		private void OnNameSubmitted(string text)
		{
			if (!((Object)(object)_openCompanion == (Object)null) && !string.IsNullOrWhiteSpace(text) && !(text == _openCompanion.DisplayName))
			{
				_openCompanion.SetName(text);
				if ((Object)(object)_openInventory != (Object)null)
				{
					_openInventory.RefreshTitle();
				}
			}
		}
	}
	public class CompanionMapPins : MonoBehaviour
	{
		private const float UpdateInterval = 0.25f;

		private readonly Dictionary<DvergrCompanion, PinData> _pins = new Dictionary<DvergrCompanion, PinData>();

		private readonly HashSet<DvergrCompanion> _seen = new HashSet<DvergrCompanion>();

		private readonly List<DvergrCompanion> _stale = new List<DvergrCompanion>();

		private Minimap _boundMap;

		private float _timer;

		private void Update()
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: 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_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: 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_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			Minimap instance = Minimap.instance;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null || !Plugin.ShowMapPins.Value)
			{
				if (_pins.Count > 0)
				{
					if ((Object)(object)instance == (Object)null)
					{
						_pins.Clear();
					}
					else
					{
						RemoveAll(instance);
					}
				}
				_boundMap = instance;
				return;
			}
			if ((Object)(object)_boundMap != (Object)(object)instance)
			{
				_pins.Clear();
				_boundMap = instance;
			}
			_timer += Time.deltaTime;
			if (_timer < 0.25f)
			{
				return;
			}
			_timer = 0f;
			PinType val = PinIcon();
			_seen.Clear();
			foreach (DvergrCompanion item in DvergrCompanion.All)
			{
				if ((Object)(object)item == (Object)null || item.OwnerId == 0L || !item.IsOwner(localPlayer))
				{
					continue;
				}
				_seen.Add(item);
				if (_pins.TryGetValue(item, out var value) && value != null)
				{
					value.m_pos = ((Component)item).transform.position;
					if (value.m_name != item.DisplayName)
					{
						value.m_name = item.DisplayName;
					}
					if (value.m_type != val)
					{
						value.m_type = val;
					}
				}
				else
				{
					_pins[item] = instance.AddPin(((Component)item).transform.position, val, item.DisplayName, false, false, 0L, default(PlatformUserID));
				}
			}
			_stale.Clear();
			foreach (KeyValuePair<DvergrCompanion, PinData> pin in _pins)
			{
				if (!_seen.Contains(pin.Key))
				{
					_stale.Add(pin.Key);
				}
			}
			foreach (DvergrCompanion item2 in _stale)
			{
				if (_pins.TryGetValue(item2, out var value2) && value2 != null)
				{
					instance.RemovePin(value2);
				}
				_pins.Remove(item2);
			}
		}

		private void RemoveAll(Minimap map)
		{
			foreach (KeyValuePair<DvergrCompanion, PinData> pin in _pins)
			{
				if (pin.Value != null)
				{
					map.RemovePin(pin.Value);
				}
			}
			_pins.Clear();
		}

		private static PinType PinIcon()
		{
			return (PinType)(Mathf.Clamp(Plugin.MapPinIcon.Value, 0, 4) switch
			{
				0 => 0, 
				1 => 1, 
				2 => 2, 
				4 => 6, 
				_ => 3, 
			});
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "Teleport")]
	public static class CompanionPortalPatch
	{
		public static void Postfix(Player player, bool __runOriginal)
		{
			if (__runOriginal && !((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer) && ((Character)player).IsTeleporting())
			{
				CompanionTeleport.FollowOwnerThroughPortal(player);
			}
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "Teleport")]
	public static class CompanionPortalBlockPatch
	{
		private static float _lastMsg = -999f;

		public static bool Prefix(TeleportWorld __instance, Player player)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if ((Object)(object)__instance == (Object)null || ((Object)__instance).name.IndexOf("portal_wood", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return true;
			}
			if (CompanionTeleport.TryFindPortalBlocker(player, out var companionName, out var itemName))
			{
				if (Time.time - _lastMsg > 2.5f)
				{
					_lastMsg = Time.time;
					((Character)player).Message((MessageType)2, companionName + " is carrying " + itemName + " — you can't take it through the portal.", 0, (Sprite)null);
				}
				return false;
			}
			return true;
		}
	}
	internal static class CompanionTeleport
	{
		private const float GatherRange = 60f;

		public static bool TryFindPortalBlocker(Player owner, out string companionName, out string itemName)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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)
			companionName = null;
			itemName = null;
			if ((Object)(object)owner == (Object)null)
			{
				return false;
			}
			long playerID = owner.GetPlayerID();
			Vector3 position = ((Component)owner).transform.position;
			foreach (DvergrCompanion item in DvergrCompanion.All)
			{
				if ((Object)(object)item == (Object)null || item.Stance != CompanionStance.Follow || item.OwnerId == 0L || item.OwnerId != playerID || item.ChoreActive || item.DuelMode || item.IsFeral)
				{
					continue;
				}
				Character component = ((Component)item).GetComponent<Character>();
				if ((Object)(object)component == (Object)null || component.IsDead() || Vector3.Distance(((Component)component).transform.position, position) > 60f)
				{
					continue;
				}
				CompanionInventory component2 = ((Component)item).GetComponent<CompanionInventory>();
				Inventory val = (((Object)(object)component2 != (Object)null) ? component2.Inventory : null);
				if (val == null)
				{
					continue;
				}
				foreach (ItemData allItem in val.GetAllItems())
				{
					if (allItem?.m_shared != null && !allItem.m_shared.m_teleportable)
					{
						companionName = item.DisplayName;
						itemName = ((Localization.instance != null) ? Localization.instance.Localize(allItem.m_shared.m_name) : allItem.m_shared.m_name);
						return true;
					}
				}
			}
			return false;
		}

		public static void FollowOwnerThroughPortal(Player owner)
		{
			//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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			Vector3 teleportTargetPos = owner.m_teleportTargetPos;
			Quaternion teleportTargetRot = owner.m_teleportTargetRot;
			Vector3 teleportFromPos = owner.m_teleportFromPos;
			long playerID = owner.GetPlayerID();
			int num = 0;
			foreach (DvergrCompanion item in DvergrCompanion.All)
			{
				if (!((Object)(object)item == (Object)null) && item.Stance == CompanionStance.Follow && item.OwnerId != 0L && item.OwnerId == playerID && !item.ChoreActive && !item.DuelMode && !item.IsFeral)
				{
					Character component = ((Component)item).GetComponent<Character>();
					if (!((Object)(object)component == (Object)null) && !component.IsDead() && !(Vector3.Distance(((Component)component).transform.position, teleportFromPos) > 60f))
					{
						TeleportCompanion(component, teleportTargetPos + SpreadOffset(num), teleportTargetRot);
						num++;
					}
				}
			}
			if (num > 0)
			{
				Plugin.Log.LogInfo((object)$"[portal] Brought {num} companion(s) through the portal for {owner.GetPlayerName()}.");
			}
		}

		private static void TeleportCompanion(Character ch, Vector3 pos, Quaternion rot)
		{
			//IL_0030: Unknown result ty