Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of TameMate v0.2.5
plugins/TameMate.dll
Decompiled 20 hours ago
The result has been truncated due to the large size, download it to view full contents!
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()