Decompiled source of TameMate v0.2.5

plugins/TameMate.dll

Decompiled 20 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Extensions;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Splatform;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("TameMate")]
[assembly: AssemblyDescription("Companion & Riding Overhaul for Valheim")]
[assembly: AssemblyCompany("MitsurugiCM")]
[assembly: AssemblyProduct("TameMate")]
[assembly: ComVisible(false)]
[assembly: AssemblyFileVersion("0.2.5.0")]
[assembly: AssemblyVersion("0.2.5.0")]
[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 TameMate
{
	internal static class FeedingRegistry
	{
		internal static readonly List<Container> Containers = new List<Container>();
	}
	[HarmonyPatch(typeof(Container), "Awake")]
	internal static class ContainerRegisterPatch
	{
		private static void Postfix(Container __instance)
		{
			if (Object.op_Implicit((Object)(object)__instance) && !FeedingRegistry.Containers.Contains(__instance))
			{
				FeedingRegistry.Containers.Add(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(MonsterAI), "FindClosestConsumableItem")]
	internal static class ChestFeedingPatch
	{
		private static void Postfix(MonsterAI __instance, float maxRange, ref ItemDrop __result)
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: 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_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)__result) || !Object.op_Implicit((Object)(object)__instance))
			{
				return;
			}
			Character component = ((Component)__instance).GetComponent<Character>();
			Tameable component2 = ((Component)__instance).GetComponent<Tameable>();
			if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component2) || !component.IsOwner() || !component2.IsHungry() || !ChestFeedingEnabled(component))
			{
				return;
			}
			float value = TameMateConfig.ChestFeedingRange.Value;
			Container val = null;
			ItemData val2 = null;
			float num = value * value;
			for (int num2 = FeedingRegistry.Containers.Count - 1; num2 >= 0; num2--)
			{
				Container val3 = FeedingRegistry.Containers[num2];
				if (!Object.op_Implicit((Object)(object)val3))
				{
					FeedingRegistry.Containers.RemoveAt(num2);
				}
				else
				{
					Piece component3 = ((Component)val3).GetComponent<Piece>();
					if (Object.op_Implicit((Object)(object)component3) && component3.IsPlacedByPlayer())
					{
						float num3 = Vector3.SqrMagnitude(((Component)val3).transform.position - ((Component)__instance).transform.position);
						if (!(num3 > num))
						{
							Inventory inventory = val3.GetInventory();
							if (inventory != null && (!TameMateConfig.OnlyFoodChests.Value || ContainsOnlyAcceptedFood(__instance, inventory)))
							{
								foreach (ItemData allItem in inventory.GetAllItems())
								{
									if (CanConsume(__instance, allItem))
									{
										val = val3;
										val2 = allItem;
										num = num3;
										break;
									}
								}
							}
						}
					}
				}
			}
			if (Object.op_Implicit((Object)(object)val) && val2 != null && !((Object)(object)val2.m_dropPrefab == (Object)null))
			{
				ZNetView component4 = ((Component)val).GetComponent<ZNetView>();
				if (Object.op_Implicit((Object)(object)component4) && component4.IsValid() && !component4.IsOwner())
				{
					component4.ClaimOwnership();
				}
				if ((!Object.op_Implicit((Object)(object)component4) || !component4.IsValid() || component4.IsOwner()) && val.GetInventory().RemoveOneItem(val2))
				{
					GameObject val4 = Object.Instantiate<GameObject>(val2.m_dropPrefab, ((Component)__instance).transform.position + Vector3.up * 0.4f, Quaternion.identity);
					__result = (Object.op_Implicit((Object)(object)val4) ? val4.GetComponent<ItemDrop>() : null);
				}
			}
		}

		private static bool ChestFeedingEnabled(Character character)
		{
			if (!character.IsTamed())
			{
				return TameMateConfig.WildChestFeeding.Value;
			}
			return TameMateConfig.TameChestFeeding.Value;
		}

		private static bool ContainsOnlyAcceptedFood(MonsterAI ai, Inventory inventory)
		{
			List<ItemData> allItems = inventory.GetAllItems();
			if (allItems == null || allItems.Count == 0)
			{
				return false;
			}
			foreach (ItemData item in allItems)
			{
				if (!CanConsume(ai, item))
				{
					return false;
				}
			}
			return true;
		}

		private static bool CanConsume(MonsterAI ai, ItemData item)
		{
			if (item == null || (Object)(object)item.m_dropPrefab == (Object)null)
			{
				return false;
			}
			foreach (ItemDrop consumeItem in ai.m_consumeItems)
			{
				if (Object.op_Implicit((Object)(object)consumeItem) && consumeItem.m_itemData.m_shared.m_name == item.m_shared.m_name)
				{
					return true;
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Procreation), "Awake")]
	internal static class ProcreationTunePatch
	{
		private static void Prefix(Procreation __instance)
		{
			__instance.m_requiredLovePoints = 3;
			__instance.m_pregnancyDuration = Mathf.Max(60f, TameMateConfig.GrowthMinutes.Value * 30f);
		}
	}
	[HarmonyPatch(typeof(Tameable), "IsHungry")]
	internal static class FoodDurationPatch
	{
		private static void Prefix(Tameable __instance, out float __state)
		{
			__state = __instance.m_fedDuration;
			Character component = ((Component)__instance).GetComponent<Character>();
			if (Object.op_Implicit((Object)(object)component) && component.IsTamed())
			{
				__instance.m_fedDuration *= 1f + (float)CompanionState.Stat(component, CompanionStat.Food) * 0.04f;
			}
		}

		private static void Postfix(Tameable __instance, float __state)
		{
			__instance.m_fedDuration = __state;
		}
	}
	[HarmonyPatch(typeof(Player), "TeleportTo")]
	internal static class CompanionTeleportPatch
	{
		private static void Prefix(Player __instance, Vector3 pos, out List<Character> __state)
		{
			__state = new List<Character>();
			if (!Object.op_Implicit((Object)(object)__instance) || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			foreach (Character item in CompanionRuntime.Nearby(12f))
			{
				if (CompanionState.Order(item) == CompanionOrder.Follow && CompanionState.Owner(item) == __instance.GetPlayerID())
				{
					__state.Add(item);
				}
			}
		}

		private static void Postfix(Player __instance, Vector3 pos, bool __result, List<Character> __state)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (__result && __state != null && __state.Count != 0 && !((Object)(object)Plugin.Instance == (Object)null))
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(MoveFollowers(__state, pos));
			}
		}

		private static IEnumerator MoveFollowers(List<Character> followers, Vector3 position)
		{
			//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)
			yield return (object)new WaitForSeconds(2f);
			for (int i = 0; i < followers.Count; i++)
			{
				Character val = followers[i];
				if (Object.op_Implicit((Object)(object)val) && val.IsOwner())
				{
					Vector3 val2 = Quaternion.Euler(0f, (float)i * 137.5f, 0f) * Vector3.forward * (2f + (float)i * 0.35f);
					val.TeleportTo(position + val2, ((Component)val).transform.rotation, true);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Tameable), "GetHoverText")]
	internal static class TameHoverPatch
	{
		private static void Postfix(Tameable __instance, ref string __result)
		{
			if (CommandWheel.IsOpen)
			{
				__result = "";
				return;
			}
			Character val = (Object.op_Implicit((Object)(object)__instance) ? ((Component)__instance).GetComponent<Character>() : null);
			if (Object.op_Implicit((Object)(object)val) && val.IsTamed())
			{
				BaseAI baseAI = val.GetBaseAI();
				if (CompanionState.Order(val) == CompanionOrder.Attack || CompanionState.Stance(val) == CompanionStance.Aggressive || (CompanionState.Stance(val) == CompanionStance.Defensive && Object.op_Implicit((Object)(object)baseAI) && CompanionRuntime.IsHostileCandidate(val, baseAI.GetTargetCreature())))
				{
					__result = __result.Replace("asustado", "en combate").Replace("asustada", "en combate").Replace("Asustado", "En combate")
						.Replace("Asustada", "En combate")
						.Replace("frightened", "engaged")
						.Replace("Frightened", "Engaged");
				}
				int num = CompanionState.Level(val);
				int num2 = CompanionState.Xp(val);
				int num3 = CompanionState.Points(val);
				__result += $"\n<color=#E8C673>TameMate</color> · Nv. {num} · XP {num2}/{CompanionState.XpForLevel(num)}";
				__result += $"\nSalud {Mathf.CeilToInt(val.GetHealth())}/{Mathf.CeilToInt(val.GetMaxHealth())} · Grupo {CompanionState.Group(val)}";
				__result = __result + " · " + StanceName(CompanionState.Stance(val)) + " · " + OrderName(CompanionState.Order(val));
				if (num3 > 0)
				{
					__result += string.Format("\n<color=#76C7FF>{0} punto{1} disponible{2} en Atributos</color>", num3, (num3 == 1) ? "" : "s", (num3 == 1) ? "" : "s");
				}
				__result += $"\nAtributos: Salud {CompanionState.Stat(val, CompanionStat.Health)} · Aguante {CompanionState.Stat(val, CompanionStat.Stamina)} · Daño {CompanionState.Stat(val, CompanionStat.Damage)}";
				__result += $"\nDefensa {CompanionState.Stat(val, CompanionStat.Defense)} · Velocidad {CompanionState.Stat(val, CompanionStat.Speed)} · Alimento {CompanionState.Stat(val, CompanionStat.Food)}";
				if (CompanionState.Recovering(val))
				{
					__result += $"\nRecuperándose: {Mathf.CeilToInt(CompanionState.RecoveryRemaining(val))} s";
				}
				string text = CataclysmIntegration.Describe(val);
				if (!string.IsNullOrEmpty(text))
				{
					__result = __result + "\n" + text;
				}
			}
		}

		private static string OrderName(CompanionOrder order)
		{
			return order switch
			{
				CompanionOrder.Follow => "Sígueme", 
				CompanionOrder.Stay => "Quédate", 
				CompanionOrder.MoveTo => "Ve allí", 
				CompanionOrder.Guard => "Protege", 
				CompanionOrder.Patrol => "Patrulla", 
				CompanionOrder.Home => "A casa", 
				CompanionOrder.Attack => "Ataca", 
				_ => order.ToString(), 
			};
		}

		private static string StanceName(CompanionStance stance)
		{
			return stance switch
			{
				CompanionStance.Passive => "Pasivo", 
				CompanionStance.Flee => "Huir", 
				CompanionStance.Defensive => "Defensivo", 
				CompanionStance.Neutral => "Neutral", 
				CompanionStance.Aggressive => "Agresivo", 
				_ => stance.ToString(), 
			};
		}
	}
	internal sealed class CataclysmIntegration : MonoBehaviour
	{
		private static object manager;

		private static PropertyInfo phaseProperty;

		private static PropertyInfo eventProperty;

		private static float nextResolve;

		private float nextTick;

		internal static string ActiveEvent { get; private set; } = "";

		private void Update()
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			Resolve();
			if (Time.time < nextTick)
			{
				return;
			}
			nextTick = Time.time + 1f;
			if (string.IsNullOrEmpty(ActiveEvent))
			{
				return;
			}
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if (!Object.op_Implicit((Object)(object)allCharacter) || !allCharacter.IsTamed() || allCharacter.IsBoss() || !allCharacter.IsOwner() || Character.InInterior(((Component)allCharacter).transform.position))
				{
					continue;
				}
				if (ActiveEvent == "MagicalAurora")
				{
					allCharacter.Heal(0.75f, false);
					continue;
				}
				Tameable component = ((Component)allCharacter).GetComponent<Tameable>();
				Sadle val = (Object.op_Implicit((Object)(object)component) ? component.m_saddle : null);
				if (Object.op_Implicit((Object)(object)val) && val.HaveValidUser())
				{
					float num = ((ActiveEvent == "Hurricane") ? 6f : ((ActiveEvent == "Blizzard") ? 4f : ((ActiveEvent == "ToxicFog") ? 3f : ((ActiveEvent == "MeteorShower") ? 3f : 1f))));
					AccessTools.Method(typeof(Sadle), "UseStamina", (Type[])null, (Type[])null)?.Invoke(val, new object[1] { num });
				}
			}
		}

		private static void Resolve()
		{
			if (!TameMateConfig.CataclysmPenalties.Value || !CompatibilityAudit.HasWorldCataclysms)
			{
				ActiveEvent = "";
			}
			else
			{
				if (Time.time < nextResolve)
				{
					return;
				}
				nextResolve = Time.time + 0.5f;
				try
				{
					if (manager == null)
					{
						Type? type = Type.GetType("WorldCataclysms.Core.WorldEventManager, WorldCataclysms");
						manager = type?.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null, null);
						phaseProperty = type?.GetProperty("Phase", BindingFlags.Instance | BindingFlags.Public);
						eventProperty = type?.GetProperty("EventType", BindingFlags.Instance | BindingFlags.Public);
					}
					ActiveEvent = ((!(phaseProperty?.GetValue(manager, null)?.ToString() == "Active")) ? "" : (eventProperty?.GetValue(manager, null)?.ToString() ?? ""));
				}
				catch
				{
					ActiveEvent = "";
					manager = null;
				}
			}
		}

		internal static float SpeedMultiplier(Character c)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)c) || Character.InInterior(((Component)c).transform.position))
			{
				return 1f;
			}
			return ActiveEvent switch
			{
				"Hurricane" => 0.7f, 
				"Blizzard" => 0.68f, 
				"ToxicFog" => 0.84f, 
				"MeteorShower" => 0.88f, 
				"Tsunami" => 0.78f, 
				"Thunderstorm" => 0.9f, 
				_ => 1f, 
			};
		}

		internal static string Describe(Character c)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(ActiveEvent))
			{
				return "";
			}
			if (Character.InInterior(((Component)c).transform.position))
			{
				return "WorldCataclysms: protegido";
			}
			return ActiveEvent switch
			{
				"Hurricane" => "Huracán: control y resistencia reducidos", 
				"Blizzard" => "Ventisca: frío y movimiento reducido", 
				"ToxicFog" => "Niebla tóxica: sin regeneración", 
				"MeteorShower" => "Calor extremo: recuperación reducida", 
				"Tsunami" => "Maremoto: arrastre y agotamiento", 
				"Thunderstorm" => "Tormenta: mojado y vulnerable a rayos", 
				"MagicalAurora" => "Aurora: calma y recuperación", 
				_ => ActiveEvent, 
			};
		}

		internal static float HealingMultiplier(Character c)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)c) || !c.IsTamed() || Character.InInterior(((Component)c).transform.position))
			{
				return 1f;
			}
			if (ActiveEvent == "ToxicFog")
			{
				return 0f;
			}
			if (ActiveEvent == "Blizzard" || ActiveEvent == "MeteorShower")
			{
				return 0.25f;
			}
			return 1f;
		}
	}
	[HarmonyPatch(typeof(Character), "Heal")]
	internal static class CataclysmHealPatch
	{
		private static void Prefix(Character __instance, ref float hp)
		{
			hp *= CataclysmIntegration.HealingMultiplier(__instance);
		}
	}
	internal enum WheelPage
	{
		Main,
		Orders,
		Behavior,
		Formation,
		Groups,
		MoreGroups,
		Stats
	}
	internal enum CommandScope
	{
		Individual,
		Nearby,
		SelectedGroup
	}
	internal sealed class CommandWheel : MonoBehaviour
	{
		private static readonly string[] Main = new string[8] { "Órdenes", "Conducta", "Formación", "Grupo y alcance", "Atributos", "Montar", "Reunir", "Cerrar" };

		private static readonly string[] Orders = new string[8] { "Sígueme", "Quédate", "Ve allí", "Ataca", "Protege", "A casa", "Patrulla", "Volver" };

		private static readonly string[] Behavior = new string[8] { "Pasivo", "Huir", "Defensivo", "Neutral", "Agresivo", "Cancela ataque", "Volver", "Cerrar" };

		private static readonly string[] Formation = new string[8] { "Libre", "Cuña", "Línea", "Círculo", "Cerca 3 m", "Media 7 m", "Lejos 12 m", "Volver" };

		private static readonly string[] Groups = new string[8] { "Sólo este", "Cercanos", "Mi grupo", "Sin grupo", "Grupo 1", "Grupo 2", "Más grupos", "Volver" };

		private static readonly string[] MoreGroups = new string[8] { "Grupo 3", "Grupo 4", "Grupo 5", "Grupo 6", "Grupo 7", "Grupo 8", "Volver", "Cerrar" };

		private static readonly string[] Stats = new string[8] { "Salud +", "Resistencia +", "Daño +", "Defensa +", "Velocidad +", "Alimento +", "Volver", "Cerrar" };

		private WheelPage page;

		private CommandScope scope;

		private int selected = -1;

		private int selectedGroup;

		private Character lockedTarget;

		private Vector2 center;

		private bool previousCursorVisible;

		private CursorLockMode previousLockMode;

		private GUIStyle optionStyle;

		private GUIStyle centerStyle;

		internal static bool IsOpen { get; private set; }

		private void Update()
		{
			//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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				Close();
				return;
			}
			if (!Input.GetKeyDown((KeyCode)117))
			{
				KeyboardShortcut value = TameMateConfig.WheelKey.Value;
				if (!((KeyboardShortcut)(ref value)).IsDown())
				{
					goto IL_0053;
				}
			}
			if (!Hud.InRadial() && !InventoryGui.IsVisible())
			{
				if (IsOpen)
				{
					Close();
				}
				else
				{
					Open();
				}
				return;
			}
			goto IL_0053;
			IL_0053:
			if (!IsOpen)
			{
				return;
			}
			Character.SetTakeInputDelay(0.15f);
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
			Vector2 val = new Vector2(Input.mousePosition.x, (float)Screen.height - Input.mousePosition.y) - center;
			if (((Vector2)(ref val)).magnitude > 42f)
			{
				float num = Mathf.Atan2(val.y, val.x) * 57.29578f + 90f;
				if (num < 0f)
				{
					num += 360f;
				}
				selected = Mathf.RoundToInt(num / 45f) % 8;
			}
			if (Input.GetKeyDown((KeyCode)276) || Input.GetKeyDown((KeyCode)273))
			{
				StepSelection(-1);
			}
			if (Input.GetKeyDown((KeyCode)275) || Input.GetKeyDown((KeyCode)274))
			{
				StepSelection(1);
			}
			for (int i = 0; i < 8; i++)
			{
				if (Input.GetKeyDown((KeyCode)(49 + i)))
				{
					selected = i;
					Select(selected);
					return;
				}
			}
			if ((Input.GetMouseButtonDown(1) || Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271)) && selected >= 0)
			{
				Select(selected);
			}
			else if (Input.GetKeyDown((KeyCode)27))
			{
				Close();
			}
		}

		private void StepSelection(int direction)
		{
			if (selected < 0)
			{
				selected = ((direction <= 0) ? 7 : 0);
			}
			else
			{
				selected = (selected + direction + 8) % 8;
			}
		}

		private void Open()
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			IsOpen = true;
			lockedTarget = CompanionRuntime.Selected;
			page = WheelPage.Main;
			scope = ((!Object.op_Implicit((Object)(object)lockedTarget)) ? CommandScope.Nearby : CommandScope.Individual);
			selectedGroup = (Object.op_Implicit((Object)(object)lockedTarget) ? CompanionState.Group(lockedTarget) : 0);
			selected = -1;
			previousCursorVisible = Cursor.visible;
			previousLockMode = Cursor.lockState;
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
			center = new Vector2((float)Screen.width * 0.5f, (float)Screen.height * 0.5f);
		}

		private void Close()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (IsOpen)
			{
				IsOpen = false;
				selected = -1;
				lockedTarget = null;
				Cursor.visible = previousCursorVisible;
				Cursor.lockState = previousLockMode;
			}
		}

		private void OnDisable()
		{
			Close();
		}

		private void Select(int index)
		{
			switch (page)
			{
			case WheelPage.Main:
				SelectMain(index);
				break;
			case WheelPage.Orders:
				SelectOrder(index);
				break;
			case WheelPage.Behavior:
				SelectBehavior(index);
				break;
			case WheelPage.Formation:
				SelectFormation(index);
				break;
			case WheelPage.Groups:
				SelectGroup(index);
				break;
			case WheelPage.MoreGroups:
				SelectMoreGroup(index);
				break;
			case WheelPage.Stats:
				SelectStat(index);
				break;
			}
		}

		private void SelectMain(int index)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (index <= 3)
			{
				page = (WheelPage)(index + 1);
				selected = -1;
				return;
			}
			switch (index)
			{
			case 4:
				page = WheelPage.Stats;
				selected = -1;
				break;
			case 5:
			{
				Character val = CurrentTarget();
				if (!Object.op_Implicit((Object)(object)val) || !VirtualMount.Mount(val))
				{
					Notify("Esta criatura no puede montarse");
				}
				else
				{
					WhistleAudio.Emit(WhistleKind.Generic);
				}
				Close();
				break;
			}
			case 6:
				ApplyOrder(CompanionOrder.Follow, WhistleKind.Regroup, ((Component)Player.m_localPlayer).transform.position, "Reunir");
				Close();
				break;
			default:
				Close();
				break;
			}
		}

		private void SelectOrder(int index)
		{
			//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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			if (index == 7)
			{
				page = WheelPage.Main;
				selected = -1;
				return;
			}
			CompanionOrder order = CompanionOrder.Follow;
			WhistleKind whistle = WhistleKind.Generic;
			string label = Orders[index];
			Vector3 point = LookPoint();
			switch (index)
			{
			case 0:
				order = CompanionOrder.Follow;
				whistle = WhistleKind.Follow;
				point = ((Component)Player.m_localPlayer).transform.position;
				break;
			case 1:
				order = CompanionOrder.Stay;
				whistle = WhistleKind.Stay;
				break;
			case 2:
				order = CompanionOrder.MoveTo;
				whistle = WhistleKind.Move;
				break;
			case 3:
				order = CompanionOrder.Attack;
				whistle = WhistleKind.Attack;
				break;
			case 4:
				order = CompanionOrder.Guard;
				whistle = WhistleKind.Stay;
				break;
			case 5:
				order = CompanionOrder.Home;
				whistle = WhistleKind.Regroup;
				break;
			case 6:
				order = CompanionOrder.Patrol;
				whistle = WhistleKind.Move;
				break;
			}
			ApplyOrder(order, whistle, point, label);
			Close();
		}

		private void SelectBehavior(int index)
		{
			//IL_007a: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			switch (index)
			{
			case 6:
				page = WheelPage.Main;
				selected = -1;
				return;
			case 7:
				Close();
				return;
			}
			List<Character> list = Targets();
			foreach (Character item in list)
			{
				if (index == 5)
				{
					CompanionNet.CancelAttack(item);
					continue;
				}
				CompanionStance stance = ((index == 5) ? CompanionState.Stance(item) : ((CompanionStance)index));
				CompanionOrder order = ((index == 5) ? CompanionOrder.Follow : CompanionState.Order(item));
				Vector3 point = ((index == 5) ? ((Component)Player.m_localPlayer).transform.position : ((Component)item).transform.position);
				CompanionNet.Command(item, order, stance, point);
			}
			if (list.Count > 0)
			{
				WhistleAudio.Emit((index == 5) ? WhistleKind.Regroup : WhistleKind.Generic);
			}
			Notify($"{Behavior[index]} ({list.Count})");
			Close();
		}

		private void SelectFormation(int index)
		{
			if (index == 7)
			{
				page = WheelPage.Main;
				selected = -1;
				return;
			}
			List<Character> list = Targets();
			foreach (Character item in list)
			{
				CompanionFormation formation = ((index <= 3) ? ((CompanionFormation)index) : CompanionState.Formation(item));
				CompanionNet.SetFormation(item, formation, index switch
				{
					6 => 12f, 
					5 => 7f, 
					4 => 3f, 
					_ => CompanionState.FollowDistance(item), 
				});
			}
			if (list.Count > 0)
			{
				WhistleAudio.Emit(WhistleKind.Generic);
			}
			Notify($"{Formation[index]} ({list.Count})");
			Close();
		}

		private void SelectGroup(int index)
		{
			switch (index)
			{
			case 0:
				scope = CommandScope.Individual;
				Notify("Alcance: sólo este compañero");
				page = WheelPage.Main;
				break;
			case 1:
				scope = CommandScope.Nearby;
				Notify("Alcance: compañeros cercanos");
				page = WheelPage.Main;
				break;
			case 2:
			{
				Character val = CurrentTarget();
				selectedGroup = (Object.op_Implicit((Object)(object)val) ? CompanionState.Group(val) : selectedGroup);
				scope = CommandScope.SelectedGroup;
				Notify($"Alcance: grupo {selectedGroup}");
				page = WheelPage.Main;
				break;
			}
			case 3:
				AssignGroup(0);
				break;
			case 4:
				AssignGroup(1);
				break;
			case 5:
				AssignGroup(2);
				break;
			case 6:
				page = WheelPage.MoreGroups;
				selected = -1;
				break;
			default:
				page = WheelPage.Main;
				selected = -1;
				break;
			}
		}

		private void SelectMoreGroup(int index)
		{
			if (index <= 5)
			{
				AssignGroup(index + 3);
			}
			else if (index == 6)
			{
				page = WheelPage.Groups;
				selected = -1;
			}
			else
			{
				Close();
			}
		}

		private void AssignGroup(int group)
		{
			Character val = CurrentTarget();
			if (!Object.op_Implicit((Object)(object)val))
			{
				Notify("Apunta a un compañero para asignarlo");
				page = WheelPage.Main;
				return;
			}
			CompanionNet.SetGroup(val, group);
			selectedGroup = group;
			scope = CommandScope.SelectedGroup;
			Notify($"{val.GetHoverName()}: grupo {group}");
			page = WheelPage.Main;
		}

		private void SelectStat(int index)
		{
			switch (index)
			{
			case 6:
				page = WheelPage.Main;
				selected = -1;
				return;
			case 7:
				Close();
				return;
			}
			Character val = CurrentTarget();
			if (!Object.op_Implicit((Object)(object)val))
			{
				Notify("Apunta a un compañero antes de abrir la rueda");
				page = WheelPage.Main;
				selected = -1;
			}
			else if (CompanionState.Points(val) <= 0)
			{
				Notify(val.GetHoverName() + ": no tiene puntos disponibles");
				selected = -1;
			}
			else
			{
				CompanionNet.Spend(val, (CompanionStat)index);
				Notify(val.GetHoverName() + ": " + Stats[index] + " solicitado");
				selected = -1;
			}
		}

		private void ApplyOrder(CompanionOrder order, WhistleKind whistle, Vector3 point, string label)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			List<Character> list = Targets();
			foreach (Character item in list)
			{
				Vector3 point2 = point;
				if (order == CompanionOrder.Stay)
				{
					point2 = ((Component)item).transform.position;
				}
				if (order == CompanionOrder.Home)
				{
					point2 = CompanionState.Home(item);
				}
				if (order == CompanionOrder.Guard)
				{
					point2 = ((Component)item).transform.position;
				}
				CompanionNet.Command(item, order, CompanionState.Stance(item), point2);
			}
			if (list.Count > 0)
			{
				WhistleAudio.Emit(whistle);
			}
			Notify($"{label} ({list.Count})");
		}

		private List<Character> Targets()
		{
			Character val = CurrentTarget();
			if (scope == CommandScope.Individual)
			{
				if (!Object.op_Implicit((Object)(object)val))
				{
					return new List<Character>();
				}
				return new List<Character> { val };
			}
			if (scope == CommandScope.SelectedGroup)
			{
				return CompanionRuntime.Nearby(TameMateConfig.CommandRange.Value, selectedGroup);
			}
			return CompanionRuntime.Nearby(TameMateConfig.CommandRange.Value);
		}

		private Character CurrentTarget()
		{
			if (!Object.op_Implicit((Object)(object)lockedTarget))
			{
				return CompanionRuntime.Selected;
			}
			return lockedTarget;
		}

		private static Vector3 LookPoint()
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			RaycastHit val = default(RaycastHit);
			if (Object.op_Implicit((Object)(object)GameCamera.instance) && Physics.Raycast(((Component)GameCamera.instance).transform.position, ((Component)GameCamera.instance).transform.forward, ref val, 100f, -1, (QueryTriggerInteraction)1))
			{
				return ((RaycastHit)(ref val)).point;
			}
			return ((Component)Player.m_localPlayer).transform.position + ((Component)Player.m_localPlayer).transform.forward * 10f;
		}

		private static void Notify(string message)
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, "TameMate: " + message, 0, (Sprite)null, false);
			}
		}

		private string[] Labels()
		{
			return page switch
			{
				WheelPage.Orders => Orders, 
				WheelPage.Behavior => Behavior, 
				WheelPage.Formation => Formation, 
				WheelPage.Groups => Groups, 
				WheelPage.MoreGroups => MoreGroups, 
				WheelPage.Stats => Stats, 
				_ => Main, 
			};
		}

		private void OnGUI()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			if (IsOpen)
			{
				EnsureStyles();
				string[] array = Labels();
				for (int i = 0; i < array.Length; i++)
				{
					float num = ((float)i * 45f - 90f) * ((float)Math.PI / 180f);
					Vector2 val = center + new Vector2(Mathf.Cos(num), Mathf.Sin(num)) * 154f;
					Rect val2 = new Rect(val.x - 62f, val.y - 25f, 124f, 50f);
					Color backgroundColor = GUI.backgroundColor;
					GUI.backgroundColor = ((i == selected) ? new Color(0.9f, 0.6f, 0.16f) : new Color(0.08f, 0.11f, 0.12f));
					GUI.Box(val2, $"{i + 1}\n{DynamicLabel(array[i], i)}", optionStyle);
					GUI.backgroundColor = backgroundColor;
				}
				Character val3 = CurrentTarget();
				string text = (Object.op_Implicit((Object)(object)val3) ? val3.GetHoverName() : "Compañeros");
				string text2 = ((scope == CommandScope.Individual) ? "Sólo este" : ((scope == CommandScope.Nearby) ? "Cercanos" : ("Grupo " + selectedGroup)));
				string text3 = ((page == WheelPage.Stats) ? StatSummary(val3) : (Object.op_Implicit((Object)(object)val3) ? $"{PageTitle()} · {text2}\nNv. {CompanionState.Level(val3)} · {CompanionState.Stance(val3)} · {CompanionState.Order(val3)}" : (PageTitle() + " · " + text2)));
				GUI.Box(new Rect(center.x - 126f, center.y - 70f, 252f, 140f), text + "\n" + text3 + "\nMouse o flechas: elegir\nDerecho o Enter: confirmar\nU / Esc: cerrar", centerStyle);
			}
		}

		private string DynamicLabel(string label, int index)
		{
			Character val = CurrentTarget();
			if (page != WheelPage.Stats || index >= 6 || !Object.op_Implicit((Object)(object)val))
			{
				return label;
			}
			return $"{label}  [{CompanionState.Stat(val, (CompanionStat)index)}]";
		}

		private static string StatSummary(Character target)
		{
			if (!Object.op_Implicit((Object)(object)target))
			{
				return "Atributos · sin compañero seleccionado";
			}
			return $"Nivel {CompanionState.Level(target)} · XP {CompanionState.Xp(target)}\nPuntos disponibles: {CompanionState.Points(target)}";
		}

		private string PageTitle()
		{
			switch (page)
			{
			case WheelPage.Orders:
				return "Órdenes";
			case WheelPage.Behavior:
				return "Conducta";
			case WheelPage.Formation:
				return "Formación";
			case WheelPage.Groups:
			case WheelPage.MoreGroups:
				return "Grupos";
			case WheelPage.Stats:
				return "Atributos";
			default:
				return "Silbidos";
			}
		}

		private void EnsureStyles()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0028: 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)
			//IL_003b: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			if (optionStyle == null)
			{
				optionStyle = new GUIStyle(GUI.skin.box)
				{
					alignment = (TextAnchor)4,
					fontSize = 14,
					fontStyle = (FontStyle)1,
					wordWrap = true
				};
				optionStyle.normal.textColor = Color.white;
				centerStyle = new GUIStyle(optionStyle)
				{
					fontSize = 14
				};
			}
		}
	}
	internal sealed class CompanionMapPins : MonoBehaviour
	{
		private readonly Dictionary<ZDOID, PinData> pins = new Dictionary<ZDOID, PinData>();

		private static readonly FieldInfo PinUpdateField = AccessTools.Field(typeof(Minimap), "m_pinUpdateRequired");

		private Minimap activeMap;

		private float nextUpdate;

		private Texture2D pawTexture;

		private Sprite pawIcon;

		private void Update()
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < nextUpdate)
			{
				return;
			}
			nextUpdate = Time.time + 2f;
			Minimap instance = Minimap.instance;
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)localPlayer))
			{
				return;
			}
			if ((Object)(object)activeMap != (Object)(object)instance)
			{
				ResetMap(instance);
			}
			long playerID = localPlayer.GetPlayerID();
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if (!Object.op_Implicit((Object)(object)allCharacter))
				{
					continue;
				}
				ZDO val = CompanionState.Zdo(allCharacter);
				if (val == null)
				{
					continue;
				}
				ZDOID uid = val.m_uid;
				bool flag = allCharacter.IsTamed() && CompanionState.Owner(allCharacter) == playerID;
				if (CompatibilityAudit.HasRideOnTroll && ExternalMountBridge.Supports(allCharacter))
				{
					flag = false;
				}
				if (!flag)
				{
					if (pins.TryGetValue(uid, out var value))
					{
						instance.RemovePin(value);
						pins.Remove(uid);
					}
					continue;
				}
				string text = $"TameMate: {allCharacter.GetHoverName()} · Grupo {CompanionState.Group(allCharacter)}";
				if (!pins.TryGetValue(uid, out var value2))
				{
					value2 = instance.AddPin(((Component)allCharacter).transform.position, (PinType)3, text, false, false, playerID, default(PlatformUserID));
					if (value2 == null)
					{
						continue;
					}
					EnsureIcon();
					value2.m_icon = pawIcon;
					value2.m_doubleSize = true;
					pins[uid] = value2;
				}
				value2.m_pos = ((Component)allCharacter).transform.position;
				value2.m_name = text;
			}
			PinUpdateField?.SetValue(instance, true);
		}

		private void ResetMap(Minimap map)
		{
			if (Object.op_Implicit((Object)(object)activeMap))
			{
				foreach (PinData value in pins.Values)
				{
					if (value != null)
					{
						activeMap.RemovePin(value);
					}
				}
			}
			pins.Clear();
			activeMap = map;
		}

		private void EnsureIcon()
		{
			//IL_0015: 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_002a: Expected O, but got Unknown
			//IL_0071: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)pawIcon))
			{
				pawTexture = new Texture2D(32, 32, (TextureFormat)4, false)
				{
					name = "TameMate_PawPin"
				};
				Color val = default(Color);
				((Color)(ref val))..ctor(0f, 0f, 0f, 0f);
				Color color = default(Color);
				((Color)(ref color))..ctor(0.95f, 0.69f, 0.2f, 1f);
				Color[] array = (Color[])(object)new Color[1024];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = val;
				}
				PaintCircle(array, 16, 18, 8, color);
				PaintCircle(array, 8, 9, 4, color);
				PaintCircle(array, 14, 6, 4, color);
				PaintCircle(array, 21, 7, 4, color);
				PaintCircle(array, 26, 12, 4, color);
				pawTexture.SetPixels(array);
				pawTexture.Apply(false, true);
				pawIcon = Sprite.Create(pawTexture, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f), 32f);
				((Object)pawIcon).name = "TameMate_PawPin";
			}
		}

		private static void PaintCircle(Color[] pixels, int cx, int cy, int radius, Color color)
		{
			//IL_0035: 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)
			int num = radius * radius;
			for (int i = Mathf.Max(0, cy - radius); i <= Mathf.Min(31, cy + radius); i++)
			{
				for (int j = Mathf.Max(0, cx - radius); j <= Mathf.Min(31, cx + radius); j++)
				{
					if ((j - cx) * (j - cx) + (i - cy) * (i - cy) <= num)
					{
						pixels[i * 32 + j] = color;
					}
				}
			}
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)activeMap))
			{
				foreach (PinData value in pins.Values)
				{
					if (value != null)
					{
						activeMap.RemovePin(value);
					}
				}
			}
			pins.Clear();
			if (Object.op_Implicit((Object)(object)pawIcon))
			{
				Object.Destroy((Object)(object)pawIcon);
			}
			if (Object.op_Implicit((Object)(object)pawTexture))
			{
				Object.Destroy((Object)(object)pawTexture);
			}
		}
	}
	internal static class CompanionNet
	{
		private const string RpcCommand = "TM_Command";

		private const string RpcStat = "TM_Stat";

		private const string RpcGroup = "TM_Group";

		private const string RpcFormation = "TM_Formation";

		private const string RpcCancelAttack = "TM_CancelAttack";

		private static readonly MethodInfo SetTargetMethod = AccessTools.Method(typeof(MonsterAI), "SetTarget", (Type[])null, (Type[])null);

		private static readonly MethodInfo SetAlertedMethod = AccessTools.Method(typeof(MonsterAI), "SetAlerted", (Type[])null, (Type[])null);

		internal static void Register(Tameable tame)
		{
			ZNetView view = (Object.op_Implicit((Object)(object)tame) ? ((Component)tame).GetComponent<ZNetView>() : null);
			if (!Object.op_Implicit((Object)(object)view) || !view.IsValid())
			{
				return;
			}
			view.Register<int, int, Vector3, long>("TM_Command", (Method<int, int, Vector3, long>)delegate(long sender, int order, int stance, Vector3 point, long playerId)
			{
				//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
				if (view.IsOwner())
				{
					Character component = ((Component)tame).GetComponent<Character>();
					if (Object.op_Implicit((Object)(object)component) && component.IsTamed())
					{
						long num = CompanionState.Owner(component);
						if (num == 0L || num == playerId)
						{
							if (num == 0L)
							{
								view.GetZDO().Set(CompanionState.OwnerKey, playerId);
							}
							view.GetZDO().Set(CompanionState.OrderKey, Mathf.Clamp(order, 0, 6), false);
							view.GetZDO().Set(CompanionState.StanceKey, Mathf.Clamp(stance, 0, 4), false);
							view.GetZDO().Set(CompanionState.TargetKey, point);
							view.GetZDO().Set(CompanionState.CommandActiveKey, 1, false);
							if (order == 5 || order == 3)
							{
								view.GetZDO().Set(CompanionState.HomeKey, point);
							}
							CompanionOrder companionOrder = (CompanionOrder)Mathf.Clamp(order, 0, 6);
							if (companionOrder == CompanionOrder.Follow || companionOrder == CompanionOrder.Stay || companionOrder == CompanionOrder.MoveTo || companionOrder == CompanionOrder.Home)
							{
								ClearCombat(component);
							}
						}
					}
				}
			});
			view.Register<int, long>("TM_Stat", (Action<long, int, long>)delegate(long sender, int stat, long playerId)
			{
				if (view.IsOwner())
				{
					Character component = ((Component)tame).GetComponent<Character>();
					if (Object.op_Implicit((Object)(object)component))
					{
						long num = CompanionState.Owner(component);
						if (num == 0L || num == playerId)
						{
							if (num == 0L)
							{
								view.GetZDO().Set(CompanionState.OwnerKey, playerId);
							}
							CompanionState.SpendPoint(component, (CompanionStat)Mathf.Clamp(stat, 0, 5));
						}
					}
				}
			});
			view.Register<int, long>("TM_Group", (Action<long, int, long>)delegate(long sender, int group, long playerId)
			{
				if (view.IsOwner())
				{
					Character component = ((Component)tame).GetComponent<Character>();
					if (Object.op_Implicit((Object)(object)component))
					{
						long num = CompanionState.Owner(component);
						if (num == 0L || num == playerId)
						{
							if (num == 0L)
							{
								view.GetZDO().Set(CompanionState.OwnerKey, playerId);
							}
							view.GetZDO().Set(CompanionState.GroupKey, Mathf.Clamp(group, 0, 8), false);
						}
					}
				}
			});
			view.Register<int, float, long>("TM_Formation", (Action<long, int, float, long>)delegate(long sender, int formation, float distance, long playerId)
			{
				if (view.IsOwner())
				{
					Character component = ((Component)tame).GetComponent<Character>();
					if (Object.op_Implicit((Object)(object)component) && (CompanionState.Owner(component) == 0L || CompanionState.Owner(component) == playerId))
					{
						view.GetZDO().Set(CompanionState.FormationKey, Mathf.Clamp(formation, 0, 3), false);
						view.GetZDO().Set(CompanionState.FollowDistanceKey, Mathf.Clamp(distance, 2f, 15f));
					}
				}
			});
			view.Register<long>("TM_CancelAttack", (Action<long, long>)delegate(long sender, long playerId)
			{
				if (view.IsOwner())
				{
					Character component = ((Component)tame).GetComponent<Character>();
					if (Object.op_Implicit((Object)(object)component) && (CompanionState.Owner(component) == 0L || CompanionState.Owner(component) == playerId))
					{
						ClearCombat(component);
					}
				}
			});
		}

		internal static void Command(Character c, CompanionOrder order, CompanionStance stance, Vector3 point)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			ZNetView val = (Object.op_Implicit((Object)(object)c) ? ((Component)c).GetComponent<ZNetView>() : null);
			if (Object.op_Implicit((Object)(object)val) && val.IsValid() && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				val.InvokeRPC(ZNetView.Everybody, "TM_Command", new object[4]
				{
					(int)order,
					(int)stance,
					point,
					Player.m_localPlayer.GetPlayerID()
				});
			}
		}

		internal static void Spend(Character c, CompanionStat stat)
		{
			ZNetView val = (Object.op_Implicit((Object)(object)c) ? ((Component)c).GetComponent<ZNetView>() : null);
			if (Object.op_Implicit((Object)(object)val) && val.IsValid() && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				val.InvokeRPC(ZNetView.Everybody, "TM_Stat", new object[2]
				{
					(int)stat,
					Player.m_localPlayer.GetPlayerID()
				});
			}
		}

		internal static void SetGroup(Character c, int group)
		{
			ZNetView val = (Object.op_Implicit((Object)(object)c) ? ((Component)c).GetComponent<ZNetView>() : null);
			if (Object.op_Implicit((Object)(object)val) && val.IsValid() && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				val.InvokeRPC(ZNetView.Everybody, "TM_Group", new object[2]
				{
					Mathf.Clamp(group, 0, 8),
					Player.m_localPlayer.GetPlayerID()
				});
			}
		}

		internal static void SetFormation(Character c, CompanionFormation formation, float distance)
		{
			ZNetView val = (Object.op_Implicit((Object)(object)c) ? ((Component)c).GetComponent<ZNetView>() : null);
			if (Object.op_Implicit((Object)(object)val) && val.IsValid() && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				val.InvokeRPC(ZNetView.Everybody, "TM_Formation", new object[3]
				{
					(int)formation,
					distance,
					Player.m_localPlayer.GetPlayerID()
				});
			}
		}

		internal static void CancelAttack(Character c)
		{
			ZNetView val = (Object.op_Implicit((Object)(object)c) ? ((Component)c).GetComponent<ZNetView>() : null);
			if (Object.op_Implicit((Object)(object)val) && val.IsValid() && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				val.InvokeRPC(ZNetView.Everybody, "TM_CancelAttack", new object[1] { Player.m_localPlayer.GetPlayerID() });
			}
		}

		private static void ClearCombat(Character c)
		{
			MonsterAI val = (Object.op_Implicit((Object)(object)c) ? ((Component)c).GetComponent<MonsterAI>() : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				SetTargetMethod?.Invoke(val, new object[1]);
				SetAlertedMethod?.Invoke(val, new object[1] { false });
			}
		}
	}
	[HarmonyPatch(typeof(Tameable), "Awake")]
	internal static class TameableAwakePatch
	{
		private static void Postfix(Tameable __instance)
		{
			__instance.m_commandable = true;
			Character component = ((Component)__instance).GetComponent<Character>();
			if (Object.op_Implicit((Object)(object)component) && component.IsTamed())
			{
				CompanionState.Initialize(component);
				CompanionNet.Register(__instance);
				if (!Object.op_Implicit((Object)(object)((Component)component).GetComponent<CompanionMotor>()))
				{
					((Component)component).gameObject.AddComponent<CompanionMotor>();
				}
				if (!Object.op_Implicit((Object)(object)((Component)component).GetComponent<MountedExperience>()))
				{
					((Component)component).gameObject.AddComponent<MountedExperience>();
				}
			}
		}
	}
	[HarmonyPatch(typeof(Character), "SetTamed")]
	internal static class CharacterSetTamedPatch
	{
		private static void Postfix(Character __instance, bool tamed)
		{
			if (!tamed || !Object.op_Implicit((Object)(object)__instance))
			{
				return;
			}
			Tameable component = ((Component)__instance).GetComponent<Tameable>();
			if (Object.op_Implicit((Object)(object)component))
			{
				component.m_commandable = true;
				CompanionState.Initialize(__instance);
				CompanionNet.Register(component);
				if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<CompanionMotor>()))
				{
					((Component)__instance).gameObject.AddComponent<CompanionMotor>();
				}
				if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<MountedExperience>()))
				{
					((Component)__instance).gameObject.AddComponent<MountedExperience>();
				}
			}
		}
	}
	internal sealed class CompanionRuntime : MonoBehaviour
	{
		private sealed class FormationCache
		{
			internal float Expires;

			internal readonly List<Character> Members = new List<Character>();
		}

		private float nextSelection;

		private float nextRecovery;

		private static readonly Dictionary<long, FormationCache> FormationCaches = new Dictionary<long, FormationCache>();

		private static readonly List<Character> HostileCandidates = new List<Character>();

		private static float hostileCandidatesExpire;

		internal static Character Selected { get; private set; }

		private void Update()
		{
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				Selected = null;
				return;
			}
			if (Time.time >= nextSelection)
			{
				nextSelection = Time.time + 0.15f;
				Selected = FindLookedAtTame();
			}
			if (Object.op_Implicit((Object)(object)Selected) && (Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307)))
			{
				for (int i = 0; i <= 8; i++)
				{
					if (Input.GetKeyDown((KeyCode)((i == 0) ? 48 : (49 + (i - 1)))))
					{
						CompanionNet.SetGroup(Selected, i);
						((Character)Player.m_localPlayer).Message((MessageType)2, $"TameMate: grupo {i}", 0, (Sprite)null, false);
					}
				}
			}
			if (Time.time >= nextRecovery)
			{
				nextRecovery = Time.time + 1f;
				UpdateRecovery();
			}
		}

		private static Character FindLookedAtTame()
		{
			GameObject hoverObject = ((Humanoid)Player.m_localPlayer).GetHoverObject();
			Character val = (Object.op_Implicit((Object)(object)hoverObject) ? hoverObject.GetComponentInParent<Character>() : null);
			if (!Object.op_Implicit((Object)(object)val) || !val.IsTamed())
			{
				return null;
			}
			return val;
		}

		internal static List<Character> Nearby(float range, int group = -1)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			List<Character> list = new List<Character>();
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				return list;
			}
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if (Object.op_Implicit((Object)(object)allCharacter) && allCharacter.IsTamed() && !allCharacter.IsBoss() && !(Vector3.SqrMagnitude(((Component)allCharacter).transform.position - ((Component)Player.m_localPlayer).transform.position) > range * range) && (group < 0 || CompanionState.Group(allCharacter) == group))
				{
					list.Add(allCharacter);
				}
			}
			return list;
		}

		internal static Player FindPlayer(long id)
		{
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if (Object.op_Implicit((Object)(object)allPlayer) && allPlayer.GetPlayerID() == id)
				{
					return allPlayer;
				}
			}
			return null;
		}

		internal static List<Character> FormationMembers(Player owner, int group)
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			long key = owner.GetPlayerID() * 16 + group;
			if (!FormationCaches.TryGetValue(key, out var value))
			{
				value = new FormationCache();
				FormationCaches[key] = value;
			}
			if (Time.time < value.Expires)
			{
				return value.Members;
			}
			value.Expires = Time.time + 1f;
			value.Members.Clear();
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if (Object.op_Implicit((Object)(object)allCharacter) && allCharacter.IsTamed() && !allCharacter.IsBoss() && CompanionState.Group(allCharacter) == group && CompanionState.Owner(allCharacter) == owner.GetPlayerID() && CompanionState.Order(allCharacter) == CompanionOrder.Follow && Vector3.SqrMagnitude(((Component)allCharacter).transform.position - ((Component)owner).transform.position) <= 6400f)
				{
					value.Members.Add(allCharacter);
				}
			}
			value.Members.Sort((Character a, Character b) => ((Object)a).GetInstanceID().CompareTo(((Object)b).GetInstanceID()));
			return value.Members;
		}

		internal static bool IsHostileCandidate(Character source, Character target)
		{
			if (!Object.op_Implicit((Object)(object)source) || !Object.op_Implicit((Object)(object)target) || (Object)(object)source == (Object)(object)target || target.GetHealth() <= 0f)
			{
				return false;
			}
			if (BaseAI.IsEnemy(source, target))
			{
				return true;
			}
			if (!target.IsTamed() && !(target is Player))
			{
				return Object.op_Implicit((Object)(object)target.GetBaseAI());
			}
			return false;
		}

		internal static Character FindHostileTarget(Character source, Vector3 center, float range)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			Character val = BaseAI.FindClosestEnemy(source, center, range);
			if (IsHostileCandidate(source, val))
			{
				return val;
			}
			if (Time.time >= hostileCandidatesExpire)
			{
				hostileCandidatesExpire = Time.time + 1f;
				HostileCandidates.Clear();
				foreach (Character allCharacter in Character.GetAllCharacters())
				{
					if (Object.op_Implicit((Object)(object)allCharacter) && !allCharacter.IsTamed() && !(allCharacter is Player) && Object.op_Implicit((Object)(object)allCharacter.GetBaseAI()))
					{
						HostileCandidates.Add(allCharacter);
					}
				}
			}
			Character result = null;
			float num = range * range;
			foreach (Character hostileCandidate in HostileCandidates)
			{
				if (IsHostileCandidate(source, hostileCandidate))
				{
					float num2 = Vector3.SqrMagnitude(((Component)hostileCandidate).transform.position - center);
					if (!(num2 >= num))
					{
						num = num2;
						result = hostileCandidate;
					}
				}
			}
			return result;
		}

		private static void UpdateRecovery()
		{
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if (!Object.op_Implicit((Object)(object)allCharacter) || !allCharacter.IsTamed() || CompanionState.Recovering(allCharacter))
				{
					continue;
				}
				ZDO val = CompanionState.Zdo(allCharacter);
				if (val != null && val.GetLong(CompanionState.RecoverUntilKey, 0L) != 0L)
				{
					val.Set(CompanionState.RecoverUntilKey, 0L);
					allCharacter.SetHealth(allCharacter.GetMaxHealth());
					BaseAI baseAI = allCharacter.GetBaseAI();
					if (baseAI != null)
					{
						baseAI.SetAggravated(false, (AggravatedReason)0);
					}
				}
			}
		}
	}
	internal sealed class CompanionMotor : MonoBehaviour
	{
		private static readonly Dictionary<MonsterAI, CompanionMotor> ActiveMotors = new Dictionary<MonsterAI, CompanionMotor>();

		private Character character;

		private MonsterAI ai;

		private float baseSpeed;

		private float baseWalk;

		private float baseRun;

		private float baseFlySlow;

		private float baseFlyFast;

		private float nextTick;

		private GameObject orderAnchor;

		private bool anchorAssigned;

		private bool externalMountSupported;

		private Character attackTarget;

		private float nextPriorityEnforcement;

		private float nextFollowRecoveryCheck;

		private float followStuckSince;

		private float lastFollowDistance;

		private bool hasFollowSample;

		private bool baseAfraidOfFire;

		private bool baseAvoidFire;

		private bool fearSuppressed;

		private static readonly FieldInfo TargetCreatureField = AccessTools.Field(typeof(MonsterAI), "m_targetCreature");

		private static readonly FieldInfo TargetStaticField = AccessTools.Field(typeof(MonsterAI), "m_targetStatic");

		private static readonly FieldInfo ConsumeTargetField = AccessTools.Field(typeof(MonsterAI), "m_consumeTarget");

		private static readonly MethodInfo SetTargetMethod = AccessTools.Method(typeof(MonsterAI), "SetTarget", (Type[])null, (Type[])null);

		private void Awake()
		{
			character = ((Component)this).GetComponent<Character>();
			ai = ((Component)this).GetComponent<MonsterAI>();
			if (Object.op_Implicit((Object)(object)character))
			{
				baseSpeed = character.m_speed;
				baseWalk = character.m_walkSpeed;
				baseRun = character.m_runSpeed;
				baseFlySlow = character.m_flySlowSpeed;
				baseFlyFast = character.m_flyFastSpeed;
			}
			if (Object.op_Implicit((Object)(object)ai))
			{
				baseAfraidOfFire = ((BaseAI)ai).m_afraidOfFire;
				baseAvoidFire = ((BaseAI)ai).m_avoidFire;
			}
			if (Object.op_Implicit((Object)(object)ai))
			{
				ActiveMotors[ai] = this;
			}
			externalMountSupported = Object.op_Implicit((Object)(object)character) && ExternalMountBridge.Supports(character);
		}

		private void Update()
		{
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)character) || !character.IsTamed())
			{
				Object.Destroy((Object)(object)this);
			}
			else
			{
				if (Time.time < nextTick)
				{
					return;
				}
				nextTick = Time.time + 0.25f;
				ApplySpeed();
				if (!Object.op_Implicit((Object)(object)ai) || !character.IsOwner())
				{
					SetFearSuppressed(suppressed: false);
					return;
				}
				if (character.HaveRider() || (externalMountSupported && ExternalMountBridge.IsMounted(character)))
				{
					SetFearSuppressed(suppressed: false);
					SuspendAnchor();
					return;
				}
				if (CompanionState.Recovering(character))
				{
					SetFearSuppressed(suppressed: false);
					ClearTargets();
					((BaseAI)ai).StopMoving();
					return;
				}
				CompanionOrder companionOrder = CompanionState.Order(character);
				CompanionStance companionStance = CompanionState.Stance(character);
				if (!ValidEnemy(attackTarget) || (companionOrder != CompanionOrder.Attack && companionStance != CompanionStance.Aggressive && companionStance != CompanionStance.Defensive))
				{
					attackTarget = null;
				}
				if (companionOrder != CompanionOrder.Follow)
				{
					hasFollowSample = false;
					followStuckSince = 0f;
				}
				ZDO val = CompanionState.Zdo(character);
				if (val == null)
				{
					return;
				}
				Player val2 = CompanionRuntime.FindPlayer(CompanionState.Owner(character));
				SetFearSuppressed(companionOrder == CompanionOrder.Attack || companionStance == CompanionStance.Aggressive || (companionStance == CompanionStance.Defensive && ValidEnemy(((BaseAI)ai).GetTargetCreature())));
				switch (companionOrder)
				{
				case CompanionOrder.Follow:
					if (Object.op_Implicit((Object)(object)val2))
					{
						RecoverFollower(val2);
						int num = CompanionState.Group(character);
						if (num <= 0 || CompanionState.Formation(character) == CompanionFormation.Free)
						{
							ClearAnchor();
							ai.SetFollowTarget(((Component)val2).gameObject);
						}
						else
						{
							SetAnchor(FormationPoint(val2, num));
						}
					}
					break;
				case CompanionOrder.Stay:
					SetAnchor(val.GetVec3(CompanionState.TargetKey, ((Component)this).transform.position));
					break;
				case CompanionOrder.MoveTo:
					SetAnchor(val.GetVec3(CompanionState.TargetKey, ((Component)this).transform.position));
					break;
				case CompanionOrder.Home:
					SetAnchor(CompanionState.Home(character));
					break;
				case CompanionOrder.Guard:
					SetAnchor(CompanionState.Home(character));
					break;
				case CompanionOrder.Patrol:
				{
					Vector3 val3 = CompanionState.Home(character);
					Vector3 vec = val.GetVec3(CompanionState.TargetKey, val3);
					bool flag = val.GetInt(CompanionState.PatrolLegKey, 0) != 0;
					Vector3 val4 = (flag ? vec : val3);
					if (Vector3.Distance(((Component)this).transform.position, val4) < 2.5f)
					{
						flag = !flag;
						val.Set(CompanionState.PatrolLegKey, flag ? 1 : 0, false);
						val4 = (flag ? vec : val3);
					}
					SetAnchor(val4);
					break;
				}
				case CompanionOrder.Attack:
					ClearAnchor();
					AttackAt(val.GetVec3(CompanionState.TargetKey, ((Component)this).transform.position));
					break;
				}
				if (companionOrder == CompanionOrder.Attack)
				{
					return;
				}
				switch (companionStance)
				{
				case CompanionStance.Passive:
					ClearTargets();
					break;
				case CompanionStance.Flee:
				{
					Character targetCreature = ((BaseAI)ai).GetTargetCreature();
					if (Object.op_Implicit((Object)(object)targetCreature))
					{
						MonsterAI obj = ai;
						Vector3 val5 = ((Component)this).transform.position - ((Component)targetCreature).transform.position;
						((BaseAI)obj).MoveTowards(((Vector3)(ref val5)).normalized, true);
					}
					break;
				}
				case CompanionStance.Aggressive:
					((BaseAI)ai).Alert();
					break;
				}
				if (companionStance == CompanionStance.Aggressive)
				{
					AcquireAggressiveTarget();
				}
			}
		}

		private void LateUpdate()
		{
			EnforceCommandPriority();
		}

		private void MoveTo(Vector3 point, bool run)
		{
			//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_0040: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = point - ((Component)this).transform.position;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude < 4f)
			{
				((BaseAI)ai).StopMoving();
			}
			else
			{
				((BaseAI)ai).MoveTowards(((Vector3)(ref val)).normalized, run);
			}
		}

		private void SetAnchor(Vector3 point)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)orderAnchor))
			{
				orderAnchor = new GameObject("TameMate_OrderAnchor");
				((Object)orderAnchor).hideFlags = (HideFlags)61;
				anchorAssigned = false;
			}
			orderAnchor.transform.position = point;
			if (!anchorAssigned)
			{
				ai.SetFollowTarget(orderAnchor);
				anchorAssigned = true;
			}
		}

		private void ClearAnchor()
		{
			if (Object.op_Implicit((Object)(object)orderAnchor))
			{
				if (Object.op_Implicit((Object)(object)ai))
				{
					ai.SetFollowTarget((GameObject)null);
				}
				Object.Destroy((Object)(object)orderAnchor);
				orderAnchor = null;
				anchorAssigned = false;
			}
		}

		private void SuspendAnchor()
		{
			if (anchorAssigned && Object.op_Implicit((Object)(object)ai))
			{
				ai.SetFollowTarget((GameObject)null);
				anchorAssigned = false;
			}
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)ai))
			{
				ActiveMotors.Remove(ai);
			}
			SetFearSuppressed(suppressed: false);
			ClearAnchor();
		}

		private void ClearTargets()
		{
			TargetCreatureField?.SetValue(ai, null);
			TargetStaticField?.SetValue(ai, null);
		}

		private void AttackAt(Vector3 point)
		{
			//IL_0015: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			if (!ValidEnemy(attackTarget))
			{
				attackTarget = CompanionRuntime.FindHostileTarget(character, point, 18f);
			}
			if (!ValidEnemy(attackTarget))
			{
				attackTarget = CompanionRuntime.FindHostileTarget(character, ((Component)this).transform.position, 40f);
			}
			if (ValidEnemy(attackTarget))
			{
				SetTargetMethod?.Invoke(ai, new object[1] { attackTarget });
				if (!((BaseAI)ai).IsAlerted())
				{
					((BaseAI)ai).Alert();
				}
			}
			else
			{
				MoveTo(point, run: true);
			}
		}

		private void AcquireAggressiveTarget()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (ValidEnemy(((BaseAI)ai).GetTargetCreature()))
			{
				return;
			}
			Character val = CompanionRuntime.FindHostileTarget(character, ((Component)this).transform.position, Mathf.Max(35f, ai.m_alertRange));
			if (ValidEnemy(val))
			{
				attackTarget = val;
				SetTargetMethod?.Invoke(ai, new object[1] { val });
				if (!((BaseAI)ai).IsAlerted())
				{
					((BaseAI)ai).Alert();
				}
			}
		}

		private bool ValidEnemy(Character target)
		{
			return CompanionRuntime.IsHostileCandidate(character, target);
		}

		internal void OnAttacked(Character attacker)
		{
			if (!Object.op_Implicit((Object)(object)character) || !Object.op_Implicit((Object)(object)ai) || !character.IsOwner() || !ValidEnemy(attacker))
			{
				return;
			}
			CompanionStance companionStance = CompanionState.Stance(character);
			if (CompanionState.Order(character) == CompanionOrder.Attack || companionStance == CompanionStance.Defensive || companionStance == CompanionStance.Aggressive)
			{
				attackTarget = attacker;
				SetFearSuppressed(suppressed: true);
				SetTargetMethod?.Invoke(ai, new object[1] { attacker });
				if (!((BaseAI)ai).IsAlerted())
				{
					((BaseAI)ai).Alert();
				}
			}
		}

		private bool RestoreCommittedTarget()
		{
			if (!Object.op_Implicit((Object)(object)character) || !Object.op_Implicit((Object)(object)ai) || !character.IsOwner() || !ValidEnemy(attackTarget))
			{
				return false;
			}
			CompanionOrder num = CompanionState.Order(character);
			CompanionStance companionStance = CompanionState.Stance(character);
			if (num != CompanionOrder.Attack && companionStance != CompanionStance.Aggressive && companionStance != CompanionStance.Defensive)
			{
				return false;
			}
			if ((Object)(object)((BaseAI)ai).GetTargetCreature() != (Object)(object)attackTarget)
			{
				SetTargetMethod?.Invoke(ai, new object[1] { attackTarget });
			}
			if (!((BaseAI)ai).IsAlerted())
			{
				((BaseAI)ai).Alert();
			}
			return true;
		}

		internal static bool RestoreCommittedTarget(MonsterAI ai)
		{
			if (Object.op_Implicit((Object)(object)ai) && ActiveMotors.TryGetValue(ai, out var value))
			{
				return value.RestoreCommittedTarget();
			}
			return false;
		}

		private void SetFearSuppressed(bool suppressed)
		{
			if (Object.op_Implicit((Object)(object)ai) && fearSuppressed != suppressed)
			{
				fearSuppressed = suppressed;
				((BaseAI)ai).m_afraidOfFire = !suppressed && baseAfraidOfFire;
				((BaseAI)ai).m_avoidFire = !suppressed && baseAvoidFire;
			}
		}

		private void RecoverFollower(Player owner)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < nextFollowRecoveryCheck)
			{
				return;
			}
			nextFollowRecoveryCheck = Time.time + 1f;
			float num = Vector3.Distance(((Component)this).transform.position, ((Component)owner).transform.position);
			float num2 = Mathf.Max(12f, CompanionState.FollowDistance(character) + 6f);
			bool flag = !hasFollowSample || num < lastFollowDistance - 0.35f;
			lastFollowDistance = num;
			hasFollowSample = true;
			if (num > num2 && !flag)
			{
				if (followStuckSince <= 0f)
				{
					followStuckSince = Time.time;
				}
			}
			else
			{
				followStuckSince = 0f;
			}
			if (!(num < 45f) || (!(followStuckSince <= 0f) && !(Time.time - followStuckSince < 8f)))
			{
				float num3 = (float)Mathf.Abs(((Object)character).GetInstanceID() % 12) * 30f;
				Vector3 val = Quaternion.Euler(0f, num3, 0f) * Vector3.back * 3.5f;
				character.TeleportTo(((Component)owner).transform.position + val, ((Component)owner).transform.rotation, true);
				followStuckSince = 0f;
				lastFollowDistance = 3.5f;
				ClearAnchor();
				ai.SetFollowTarget(((Component)owner).gameObject);
			}
		}

		internal void EnforceCommandPriority()
		{
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: 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_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < nextPriorityEnforcement || !Object.op_Implicit((Object)(object)character) || !Object.op_Implicit((Object)(object)ai) || !character.IsOwner() || !CompanionState.CommandActive(character))
			{
				return;
			}
			nextPriorityEnforcement = Time.time + 0.1f;
			if (character.HaveRider() || (externalMountSupported && ExternalMountBridge.IsMounted(character)) || CompanionState.Recovering(character))
			{
				return;
			}
			CompanionOrder companionOrder = CompanionState.Order(character);
			CompanionStance companionStance = CompanionState.Stance(character);
			SetFearSuppressed(companionOrder == CompanionOrder.Attack || companionStance == CompanionStance.Aggressive || (companionStance == CompanionStance.Defensive && ValidEnemy(((BaseAI)ai).GetTargetCreature())));
			if (companionOrder == CompanionOrder.Attack)
			{
				ZDO obj = CompanionState.Zdo(character);
				AttackAt((obj != null) ? obj.GetVec3(CompanionState.TargetKey, ((Component)this).transform.position) : ((Component)this).transform.position);
				return;
			}
			switch (companionStance)
			{
			case CompanionStance.Passive:
				ClearTargets();
				break;
			case CompanionStance.Aggressive:
				AcquireAggressiveTarget();
				break;
			}
			if ((companionStance != CompanionStance.Passive && ValidEnemy(((BaseAI)ai).GetTargetCreature())) || companionStance == CompanionStance.Flee)
			{
				return;
			}
			object? obj2 = ConsumeTargetField?.GetValue(ai);
			ItemDrop val = (ItemDrop)((obj2 is ItemDrop) ? obj2 : null);
			if (Object.op_Implicit((Object)(object)val) && Vector3.SqrMagnitude(((Component)val).transform.position - ((Component)this).transform.position) > 2.25f)
			{
				ConsumeTargetField.SetValue(ai, null);
			}
			float num = 1.5f;
			ZDO val2 = CompanionState.Zdo(character);
			if (val2 == null)
			{
				return;
			}
			Vector3 val4;
			switch (companionOrder)
			{
			default:
				return;
			case CompanionOrder.Follow:
			{
				Player val5 = CompanionRuntime.FindPlayer(CompanionState.Owner(character));
				if (!Object.op_Implicit((Object)(object)val5))
				{
					return;
				}
				int num2 = CompanionState.Group(character);
				val4 = ((num2 <= 0 || CompanionState.Formation(character) == CompanionFormation.Free) ? ((Component)val5).transform.position : FormationPoint(val5, num2));
				num = CompanionState.FollowDistance(character);
				break;
			}
			case CompanionOrder.Stay:
				val4 = val2.GetVec3(CompanionState.TargetKey, ((Component)this).transform.position);
				break;
			case CompanionOrder.MoveTo:
				val4 = val2.GetVec3(CompanionState.TargetKey, ((Component)this).transform.position);
				break;
			case CompanionOrder.Guard:
			case CompanionOrder.Home:
				val4 = CompanionState.Home(character);
				break;
			case CompanionOrder.Patrol:
			{
				Vector3 val3 = CompanionState.Home(character);
				Vector3 vec = val2.GetVec3(CompanionState.TargetKey, val3);
				val4 = ((val2.GetInt(CompanionState.PatrolLegKey, 0) != 0) ? vec : val3);
				break;
			}
			}
			if (Vector3.Distance(((Component)this).transform.position, val4) > num)
			{
				MonsterAI obj3 = ai;
				Vector3 val6 = val4 - ((Component)this).transform.position;
				((BaseAI)obj3).MoveTowards(((Vector3)(ref val6)).normalized, true);
			}
			else if (companionOrder != CompanionOrder.Patrol)
			{
				((BaseAI)ai).StopMoving();
			}
		}

		private Vector3 FormationPoint(Player owner, int group)
		{
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			List<Character> list = CompanionRuntime.FormationMembers(owner, group);
			int num = Mathf.Max(0, list.IndexOf(character));
			float num2 = CompanionState.FollowDistance(character);
			Vector3 val = default(Vector3);
			switch (CompanionState.Formation(character))
			{
			case CompanionFormation.Line:
				((Vector3)(ref val))..ctor(((float)num - (float)(list.Count - 1) * 0.5f) * num2, 0f, 0f - num2);
				break;
			case CompanionFormation.Circle:
			{
				float num5 = (float)num * (float)Math.PI * 2f / (float)Mathf.Max(1, list.Count);
				val = new Vector3(Mathf.Cos(num5), 0f, Mathf.Sin(num5)) * num2;
				break;
			}
			default:
			{
				int num3 = Mathf.FloorToInt(Mathf.Sqrt((float)num));
				int num4 = num - num3 * num3;
				((Vector3)(ref val))..ctor((float)(num4 - num3) * num2 * 0.65f, 0f, (float)(-(num3 + 1)) * num2);
				break;
			}
			}
			return ((Component)owner).transform.TransformPoint(val);
		}

		private void ApplySpeed()
		{
			float num = (1f + (float)Mathf.Min(10, CompanionState.Stat(character, CompanionStat.Speed)) * 0.01f) * CataclysmIntegration.SpeedMultiplier(character) * MountedExperience.SpeedMultiplier(character);
			character.m_speed = baseSpeed * num;
			character.m_walkSpeed = baseWalk * num;
			character.m_runSpeed = baseRun * num;
			character.m_flySlowSpeed = baseFlySlow * num;
			character.m_flyFastSpeed = baseFlyFast * num;
		}
	}
	[HarmonyPatch(typeof(MonsterAI), "UpdateTarget")]
	internal static class CompanionForcedTargetPatch
	{
		private static void Postfix(MonsterAI __instance, ref bool canHearTarget, ref bool canSeeTarget)
		{
			if (CompanionMotor.RestoreCommittedTarget(__instance))
			{
				canHearTarget = true;
				canSeeTarget = true;
			}
		}
	}
	internal enum CompanionOrder
	{
		Stay,
		Follow,
		MoveTo,
		Guard,
		Patrol,
		Home,
		Attack
	}
	internal enum CompanionStance
	{
		Passive,
		Flee,
		Defensive,
		Neutral,
		Aggressive
	}
	internal enum CompanionStat
	{
		Health,
		Stamina,
		Damage,
		Defense,
		Speed,
		Food
	}
	internal enum CompanionFormation
	{
		Free,
		Wedge,
		Line,
		Circle
	}
	internal static class CompanionState
	{
		internal static readonly int LevelKey = StringExtensionMethods.GetStableHashCode("tm_level");

		internal static readonly int XpKey = StringExtensionMethods.GetStableHashCode("tm_xp");

		internal static readonly int PointsKey = StringExtensionMethods.GetStableHashCode("tm_points");

		internal static readonly int OwnerKey = StringExtensionMethods.GetStableHashCode("tm_owner");

		internal static readonly int GroupKey = StringExtensionMethods.GetStableHashCode("tm_group");

		internal static readonly int OrderKey = StringExtensionMethods.GetStableHashCode("tm_order");

		internal static readonly int StanceKey = StringExtensionMethods.GetStableHashCode("tm_stance");

		internal static readonly int TargetKey = StringExtensionMethods.GetStableHashCode("tm_target");

		internal static readonly int HomeKey = StringExtensionMethods.GetStableHashCode("tm_home");

		internal static readonly int RecoverUntilKey = StringExtensionMethods.GetStableHashCode("tm_recover_until");

		internal static readonly int PatrolLegKey = StringExtensionMethods.GetStableHashCode("tm_patrol_leg");

		internal static readonly int FormationKey = StringExtensionMethods.GetStableHashCode("tm_formation");

		internal static readonly int FollowDistanceKey = StringExtensionMethods.GetStableHashCode("tm_follow_distance");

		internal static readonly int CommandActiveKey = StringExtensionMethods.GetStableHashCode("tm_command_active");

		internal static readonly int HealthKey = StringExtensionMethods.GetStableHashCode("tm_stat_health");

		internal static readonly int StaminaKey = StringExtensionMethods.GetStableHashCode("tm_stat_stamina");

		internal static readonly int DamageKey = StringExtensionMethods.GetStableHashCode("tm_stat_damage");

		internal static readonly int DefenseKey = StringExtensionMethods.GetStableHashCode("tm_stat_defense");

		internal static readonly int SpeedKey = StringExtensionMethods.GetStableHashCode("tm_stat_speed");

		internal static readonly int FoodKey = StringExtensionMethods.GetStableHashCode("tm_stat_food");

		internal static ZDO Zdo(Character c)
		{
			if (!Object.op_Implicit((Object)(object)c))
			{
				return null;
			}
			ZNetView component = ((Component)c).GetComponent<ZNetView>();
			if (component == null)
			{
				return null;
			}
			return component.GetZDO();
		}

		internal static int Level(Character c)
		{
			ZDO obj = Zdo(c);
			return Mathf.Max(1, (obj == null) ? 1 : obj.GetInt(LevelKey, 1));
		}

		internal static int Xp(Character c)
		{
			ZDO obj = Zdo(c);
			return Mathf.Max(0, (obj != null) ? obj.GetInt(XpKey, 0) : 0);
		}

		internal static int Points(Character c)
		{
			ZDO obj = Zdo(c);
			return Mathf.Max(0, (obj != null) ? obj.GetInt(PointsKey, 0) : 0);
		}

		internal static int Group(Character c)
		{
			ZDO obj = Zdo(c);
			return Mathf.Clamp((obj != null) ? obj.GetInt(GroupKey, 0) : 0, 0, 8);
		}

		internal static CompanionOrder Order(Character c)
		{
			ZDO obj = Zdo(c);
			return (CompanionOrder)Mathf.Clamp((obj != null) ? obj.GetInt(OrderKey, 0) : 0, 0, 6);
		}

		internal static CompanionStance Stance(Character c)
		{
			ZDO obj = Zdo(c);
			return (CompanionStance)Mathf.Clamp((obj != null) ? obj.GetInt(StanceKey, 2) : 2, 0, 4);
		}

		internal static long Owner(Character c)
		{
			ZDO obj = Zdo(c);
			if (obj == null)
			{
				return 0L;
			}
			return obj.GetLong(OwnerKey, 0L);
		}

		internal static CompanionFormation Formation(Character c)
		{
			ZDO obj = Zdo(c);
			return (CompanionFormation)Mathf.Clamp((obj == null) ? 1 : obj.GetInt(FormationKey, 1), 0, 3);
		}

		internal static float FollowDistance(Character c)
		{
			ZDO obj = Zdo(c);
			return Mathf.Clamp((obj != null) ? obj.GetFloat(FollowDistanceKey, 5f) : 5f, 2f, 15f);
		}

		internal static bool CommandActive(Character c)
		{
			ZDO obj = Zdo(c);
			return obj != null && obj.GetInt(CommandActiveKey, 0) != 0;
		}

		internal static Vector3 Home(Character c)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			ZDO obj = Zdo(c);
			if (obj == null)
			{
				return Vector3.zero;
			}
			return obj.GetVec3(HomeKey, Object.op_Implicit((Object)(object)c) ? ((Component)c).transform.position : Vector3.zero);
		}

		internal static bool Recovering(Character c)
		{
			ZDO obj = Zdo(c);
			return ((obj != null) ? obj.GetLong(RecoverUntilKey, 0L) : 0) > NowMs();
		}

		internal static float RecoveryRemaining(Character c)
		{
			ZDO obj = Zdo(c);
			return Mathf.Max(0f, (float)(((obj != null) ? obj.GetLong(RecoverUntilKey, 0L) : 0) - NowMs()) / 1000f);
		}

		internal static int Stat(Character c, CompanionStat stat)
		{
			ZDO val = Zdo(c);
			if (val == null)
			{
				return 0;
			}
			return Mathf.Max(0, val.GetInt(Key(stat), 0));
		}

		internal static int XpForLevel(int level)
		{
			return Mathf.RoundToInt(75f * (float)level * (float)level + 125f * (float)level);
		}

		internal static float XpProgress(Character c)
		{
			int num = Level(c);
			int num2 = ((num > 1) ? XpForLevel(num - 1) : 0);
			int num3 = XpForLevel(num);
			return Mathf.Clamp01((float)(Xp(c) - num2) / (float)Mathf.Max(1, num3 - num2));
		}

		internal static void Initialize(Character c)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			ZDO val = Zdo(c);
			if (val == null)
			{
				return;
			}
			ZNetView component = ((Component)c).GetComponent<ZNetView>();
			if (!((Object)(object)component != (Object)null) || component.IsOwner())
			{
				if (val.GetInt(LevelKey, 0) <= 0)
				{
					val.Set(LevelKey, 1, false);
				}
				if (val.GetInt(StanceKey, -1) < 0)
				{
					val.Set(StanceKey, 2, false);
				}
				if (val.GetVec3(HomeKey, Vector3.zero) == Vector3.zero)
				{
					val.Set(HomeKey, ((Component)c).transform.position);
				}
			}
		}

		internal static void AddXp(Character c, int amount)
		{
			ZDO val = Zdo(c);
			if (val != null && amount > 0)
			{
				int num = Mathf.Max(0, val.GetInt(XpKey, 0) + Mathf.RoundToInt((float)amount * TameMateConfig.XpMultiplier.Value));
				int num2 = Mathf.Max(1, val.GetInt(LevelKey, 1));
				int num3 = 0;
				while (num2 < TameMateConfig.MaxLevel.Value && num >= XpForLevel(num2))
				{
					num2++;
					num3++;
				}
				val.Set(XpKey, num, false);
				val.Set(LevelKey, num2, false);
				if (num3 > 0)
				{
					val.Set(PointsKey, val.GetInt(PointsKey, 0) + num3, false);
					c.Heal(c.GetMaxHealth(), true);
				}
			}
		}

		internal static bool SpendPoint(Character c, CompanionStat stat)
		{
			ZDO val = Zdo(c);
			if (val == null || val.GetInt(PointsKey, 0) <= 0)
			{
				return false;
			}
			val.Set(PointsKey, val.GetInt(PointsKey, 0) - 1, false);
			int num = Key(stat);
			val.Set(num, val.GetInt(num, 0) + 1, false);
			return true;
		}

		internal static int Key(CompanionStat stat)
		{
			return stat switch
			{
				CompanionStat.Health => HealthKey, 
				CompanionStat.Stamina => StaminaKey, 
				CompanionStat.Damage => DamageKey, 
				CompanionStat.Defense => DefenseKey, 
				CompanionStat.Speed => SpeedKey, 
				_ => FoodKey, 
			};
		}

		internal static long NowMs()
		{
			if (!Object.op_Implicit((Object)(object)ZNet.instance))
			{
				return (long)(Time.realtimeSinceStartup * 1000f);
			}
			return (long)(ZNet.instance.GetTimeSeconds() * 1000.0);
		}
	}
	internal static class CompatibilityAudit
	{
		internal static bool HasWorldCataclysms => Chainloader.PluginInfos.ContainsKey("mitsu.worldcataclysms");

		internal static bool HasMyLittleUI => Chainloader.PluginInfos.ContainsKey("shudnal.MyLittleUI");

		internal static bool HasRideOnTroll => AccessTools.TypeByName("TrollTamerMod.TrollRideManager") != null;

		internal static void LogInstalledMods()
		{
			if (Chainloader.PluginInfos.ContainsKey("xtav1m.BetterTames"))
			{
				Plugin.Log.LogWarning((object)"BetterTames está activo. Desactívalo al probar las funciones equivalentes de TameMate para evitar órdenes y cuidados duplicados.");
			}
			if (Chainloader.PluginInfos.ContainsKey("Ygg.BetterRiding"))
			{
				Plugin.Log.LogWarning((object)"BetterRiding está activo. TameMate conservará compatibilidad, pero ambos pueden competir por controles de montura.");
			}
			if (HasMyLittleUI)
			{
				Plugin.Log.LogInfo((object)"My Little UI detectado: la información de TameMate se integra al texto normal de la criatura sin crear otro panel.");
			}
			if (HasWorldCataclysms)
			{
				Plugin.Log.LogInfo((object)"WorldCataclysms detectado: integración ambiental habilitada.");
			}
			if (HasRideOnTroll)
			{
				Plugin.Log.LogInfo((object)"RideOnTroll detectado: la orden Montar de TameMate usará su controlador nativo para los trolls.");
			}
		}
	}
	internal sealed class MountedCombat : MonoBehaviour
	{
		private float nextAttack;

		private Vector3 lastPosition;

		private float distance;

		private static readonly MethodInfo HaveStaminaMethod = AccessTools.Method(typeof(Sadle), "HaveStamina", (Type[])null, (Type[])null);

		private static readonly MethodInfo UseStaminaMethod = AccessTools.Method(typeof(Sadle), "UseStamina", (Type[])null, (Type[])null);

		private static Character cachedLocalMount;

		private static float nextMountScan;

		internal static bool AimMode { get; private set; }

		private void Update()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || InventoryGui.IsVisible() || Hud.InRadial() || CommandWheel.IsOpen)
			{
				return;
			}
			Character val = FindLocalMount();
			if (!Object.op_Implicit((Object)(object)val))
			{
				distance = 0f;
				lastPosition = Vector3.zero;
				AimMode = false;
				return;
			}
			bool num = ExternalMountBridge.IsMounted(val);
			if (num)
			{
				AimMode = false;
			}
			if (!num && Input.GetKeyDown(TameMateConfig.AimToggleKey.Value))
			{
				AimMode = !AimMode;
				((Character)Player.m_localPlayer).Message((MessageType)2, AimMode ? "TameMate: apuntado de montura activado" : "TameMate: apuntado de montura desactivado", 0, (Sprite)null, false);
			}
			if (AimMode && Object.op_Implicit((Object)(object)GameCamera.instance))
			{
				Vector3 forward = ((Component)GameCamera.instance).transform.forward;
				if (!val.IsFlying())
				{
					forward.y = 0f;
				}
				if (((Vector3)(ref forward)).sqrMagnitude > 0.01f)
				{
					val.SetLookDir(((Vector3)(ref forward)).normalized, 0.2f);
				}
			}
			distance += Vector3.Distance((lastPosition == Vector3.zero) ? ((Component)val).transform.position : lastPosition, ((Component)val).transform.position);
			lastPosition = ((Component)val).transform.position;
			if (distance >= 100f)
			{
				distance -= 100f;
				CompanionState.AddXp(val, 8);
			}
			if (num)
			{
				return;
			}
			Tameable component = ((Component)val).GetComponent<Tameable>();
			Sadle val2 = (Object.op_Implicit((Object)(object)component) ? component.m_saddle : null);
			if (TameMateConfig.MountedJump.Value && !val.IsFlying() && Input.GetKeyDown((KeyCode)32) && Object.op_Implicit((Object)(object)val2) && val.IsOnGround())
			{
				float value = TameMateConfig.JumpStaminaCost.Value;
				if (HasStamina(val2, value))
				{
					val.Jump(true);
					SpendStamina(val2, value);
				}
			}
			if (!(Time.time < nextAttack))
			{
				if (Input.GetMouseButtonDown(0))
				{
					TryAttack(val, val2, secondary: false, TameMateConfig.PrimaryAttackStaminaCost.Value);
				}
				else if (Input.GetMouseButtonDown(2))
				{
					TryAttack(val, val2, secondary: true, TameMateConfig.SecondaryAttackStaminaCost.Value);
				}
			}
		}

		private void TryAttack(Character mount, Sadle saddle, bool secondary, float staminaCost)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)saddle) || !HasStamina(saddle, staminaCost))
			{
				return;
			}
			if (AimMode && Object.op_Implicit((Object)(object)GameCamera.instance))
			{
				Vector3 forward = ((Component)GameCamera.instance).transform.forward;
				if (!mount.IsFlying())
				{
					forward.y = 0f;
				}
				if (((Vector3)(ref forward)).sqrMagnitude > 0.01f)
				{
					mount.SetLookDir(((Vector3)(ref forward)).normalized, 1f);
				}
			}
			if (mount.StartAttack((Character)null, secondary))
			{
				SpendStamina(saddle, staminaCost);
				nextAttack = Time.time + TameMateConfig.MountedAttackCooldown.Value;
			}
		}

		private static bool HasStamina(Sadle saddle, float amount)
		{
			if (!(amount <= 0f) && !(HaveStaminaMethod == null))
			{
				return (bool)HaveStaminaMethod.Invoke(saddle, new object[1] { amount });
			}
			return true;
		}

		private static void SpendStamina(Sadle saddle, float amount)
		{
			if (amount > 0f && UseStaminaMethod != null)
			{
				UseStaminaMethod.Invoke(saddle, new object[1] { amount });
			}
		}

		internal static Character FindLocalMount()
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				cachedLocalMount = null;
				return null;
			}
			if (Time.time < nextMountScan)
			{
				return cachedLocalMount;
			}
			nextMountScan = Time.time + 0.15f;
			cachedLocalMount = null;
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if (Object.op_Implicit((Object)(object)allCharacter) && allCharacter.IsTamed() && (allCharacter.HaveRider() || ExternalMountBridge.IsMounted(allCharacter)) && Vector3.SqrMagnitude(((Component)allCharacter).transform.position - ((Component)Player.m_localPlayer).transform.position) < 144f)
				{
					cachedLocalMount = allCharacter;
					break;
				}
			}
			return cachedLocalMount;
		}
	}
	internal enum MountWeightClass
	{
		Agile,
		Standard,
		Heavy
	}
	internal sealed class MountedExperience : MonoBehaviour
	{
		private Character character;

		private float baseAcceleration;

		private float baseTurnSpeed;

		private float baseRunTurnSpeed;

		private float baseAirControl;

		private bool adjusted;

		private float nextMountedCheck;

		internal MountWeightClass WeightClass { get; private set; }

		internal float CameraDistance { get; private set; }

		internal string Description
		{
			get
			{
				if (WeightClass != MountWeightClass.Agile)
				{
					if (WeightClass != MountWeightClass.Heavy)
					{
						return "Equilibrada";
					}
					return "Pesada";
				}
				return "Ágil";
			}
		}

		private void Awake()
		{
			character = ((Component)this).GetComponent<Character>();
			if (!Object.op_Implicit((Object)(object)character))
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			baseAcceleration = character.m_acceleration;
			baseTurnSpeed = character.m_turnSpeed;
			baseRunTurnSpeed = character.m_runTurnSpeed;
			baseAirControl = character.m_airControl;
			float num = Mathf.Max(character.GetHeight(), character.GetRadius() * 2f);
			WeightClass = ((!(num < 1.9f)) ? ((!(num > 3.2f)) ? MountWeightClass.Standard : MountWeightClass.Heavy) : MountWeightClass.Agile);
			CameraDistance = Mathf.Clamp(7f + character.GetHeight() * 2f + character.GetRadius() * 1.5f, 10f, TameMateConfig.MountedCameraDistance.Value);
		}

		private void Update()
		{
			if (!(Time.time < nextMountedCheck))
			{
				nextMountedCheck = Time.time + 0.2f;
				bool flag = Object.op_Implicit((Object)(object)character) && character.HaveRider();
				if (flag && !adjusted)
				{
					ApplyHandling();
				}
				else if (!flag && adjusted)
				{
					RestoreHandling();
				}
			}
		}

		private void ApplyHandling()
		{
			adjusted = true;
			if (TameMateConfig.SizeBasedHandling.Value)
			{
				float num = ((WeightClass == MountWeightClass.Agile) ? 1.22f : ((WeightClass == MountWeightClass.Heavy) ? 0.68f : 1f));
				float num2 = ((WeightClass == MountWeightClass.Agile) ? 1.18f : ((WeightClass == MountWeightClass.Heavy) ? 0.72f : 1f));
				character.m_acceleration = baseAcceleration * num;
				character.m_turnSpeed = baseTurnSpeed * num2;
				character.m_runTurnSpeed = baseRunTurnSpeed * num2;
				character.m_airControl = baseAirControl * ((WeightClass == MountWeightClass.Heavy) ? 0.65f : 1f);
			}
		}

		private void RestoreHandling()