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 Lost Scrolls II v0.2.0
LostScrollsII.dll
Decompiled 17 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.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using GUIFramework; using HarmonyLib; using LostScrollsII.Companions; using LostScrollsII.Integration; using Microsoft.CodeAnalysis; using Splatform; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; using ValheimServerGuide.Triggers; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("LostScrollsII")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.2.0.0")] [assembly: AssemblyInformationalVersion("0.2.0+66965495cf4375659e26678c299e75e011841e2f")] [assembly: AssemblyProduct("LostScrollsII")] [assembly: AssemblyTitle("LostScrollsII")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.2.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace LostScrollsII { [BepInPlugin("com.lostscrollsii", "Lost Scrolls II", "0.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.lostscrollsii"; public const string PluginName = "Lost Scrolls II"; public const string PluginVersion = "0.2.0"; private Harmony _harmony; public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } public static ConfigEntry<KeyCode> CommunionKey { get; private set; } public static ConfigEntry<KeyCode> ChoreAssignKey { get; private set; } public static ConfigEntry<float> ChoreAssignRadius { get; private set; } public static ConfigEntry<KeyCode> DuelSelectKey { get; private set; } public static ConfigEntry<KeyCode> StanceCycleKey { get; private set; } public static ConfigEntry<KeyCode> InventoryKey { get; private set; } public static ConfigEntry<bool> ShowMapPins { get; private set; } public static ConfigEntry<int> MapPinIcon { get; private set; } private void Awake() { //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; CommunionKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Recruitment", "CommunionKey", (KeyCode)103, "Key held while hovering a subdued Dvergr to perform the Communion Rite and recruit it."); ChoreAssignKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Chores", "ChoreAssignKey", (KeyCode)104, "Key pressed while hovering a workstation (Smelter-family), a ripe crop, or a tamed animal to assign/unassign the nearest matching-caste companion to that chore."); ChoreAssignRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Chores", "ChoreAssignRadius", 10f, "Max distance from the player to look for a recruited companion to assign to a chore."); DuelSelectKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Duels", "DuelSelectKey", (KeyCode)106, "Press while hovering your own recruited companion to toggle its duel mode. A duel-mode companion fights other players' duel-mode companions and ignores everyone else."); StanceCycleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Companions", "StanceCycleKey", (KeyCode)101, "Press while hovering your companion to cycle its stance: Follow -> Guard -> Standby."); InventoryKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Companions", "InventoryKey", (KeyCode)121, "Press while hovering your companion to open its inventory (a chest-like panel that also lets you rename it)."); ShowMapPins = ((BaseUnityPlugin)this).Config.Bind<bool>("Companions", "ShowMapPins", true, "Show a live minimap pin at each of your own recruited companions. Pins are client-side — other players never see your companions, and you never see theirs."); MapPinIcon = ((BaseUnityPlugin)this).Config.Bind<int>("Companions", "MapPinIcon", 3, "Which vanilla map-pin icon (0-4) to use for companion pins."); _harmony = new Harmony("com.lostscrollsii"); _harmony.PatchAll(); ((Component)this).gameObject.AddComponent<CompanionMapPins>(); ((Component)this).gameObject.AddComponent<CompanionInventoryGui>(); Log.LogInfo((object)"Lost Scrolls II v0.2.0 loaded."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void Update() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !TextInput.IsVisible() && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !CompanionInventoryGui.IsTyping) { if (Input.GetKeyDown(CommunionKey.Value)) { HandleCommunionInput(localPlayer); } if (Input.GetKeyDown(ChoreAssignKey.Value)) { HandleChoreAssignInput(localPlayer); } if (Input.GetKeyDown(DuelSelectKey.Value)) { HandleDuelInput(localPlayer); } if (Input.GetKeyDown(StanceCycleKey.Value)) { HandleStanceCycleInput(localPlayer); } if (Input.GetKeyDown(InventoryKey.Value)) { HandleInventoryInput(localPlayer); } } } private void HandleInventoryInput(Player player) { GameObject hoverObject = ((Humanoid)player).GetHoverObject(); if ((Object)(object)hoverObject == (Object)null) { return; } Character componentInParent = hoverObject.GetComponentInParent<Character>(); DvergrCompanion dvergrCompanion = ((componentInParent != null) ? ((Component)componentInParent).GetComponent<DvergrCompanion>() : null); if ((Object)(object)dvergrCompanion == (Object)null) { return; } if (!dvergrCompanion.IsOwner(player)) { MessageHud.instance.ShowMessage((MessageType)2, "This companion answers to another.", 0, (Sprite)null, false); return; } CompanionInventory companionInventory = ((Component)dvergrCompanion).GetComponent<CompanionInventory>(); if ((Object)(object)companionInventory == (Object)null) { companionInventory = ((Component)dvergrCompanion).gameObject.AddComponent<CompanionInventory>(); } CompanionInventoryGui.Open(dvergrCompanion, companionInventory); } private void HandleCommunionInput(Player player) { GameObject hoverObject = ((Humanoid)player).GetHoverObject(); if ((Object)(object)hoverObject == (Object)null) { return; } Character componentInParent = hoverObject.GetComponentInParent<Character>(); if ((Object)(object)componentInParent == (Object)null) { return; } DvergrCompanion component = ((Component)componentInParent).GetComponent<DvergrCompanion>(); if ((Object)(object)component != (Object)null) { bool flag = component.IsOwner(player); if (MeadFeedingService.TryFeed(componentInParent, player)) { MessageHud.instance.ShowMessage((MessageType)2, flag ? "Your ally drinks deep." : (component.DisplayName + " drinks deep."), 0, (Sprite)null, false); } else { MessageHud.instance.ShowMessage((MessageType)2, "You have no health mead to offer.", 0, (Sprite)null, false); } return; } if (!CommunionService.IsSubduedDvergr(componentInParent)) { MessageHud.instance.ShowMessage((MessageType)2, "It is not yet ready for Communion.", 0, (Sprite)null, false); return; } DvergrCaste dvergrCaste = CommunionService.DetectCaste(componentInParent); Log.LogInfo((object)$"[recruit] '{((Object)componentInParent).name}' detected as caste {dvergrCaste}."); if (CommunionService.TryRecruit(componentInParent, player, dvergrCaste)) { MessageHud.instance.ShowMessage((MessageType)2, "The shadow's grip loosens — a " + dvergrCaste.Display() + " joins you.", 0, (Sprite)null, false); } } private void HandleChoreAssignInput(Player player) { //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) GameObject hoverObject = ((Humanoid)player).GetHoverObject(); if ((Object)(object)hoverObject == (Object)null) { return; } Character componentInParent = hoverObject.GetComponentInParent<Character>(); DvergrCompanion dvergrCompanion = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).GetComponent<DvergrCompanion>() : null); if ((Object)(object)dvergrCompanion != (Object)null) { if (!dvergrCompanion.IsOwner(player)) { MessageHud.instance.ShowMessage((MessageType)2, "This companion answers to another.", 0, (Sprite)null, false); return; } ChoreAI component = ((Component)dvergrCompanion).GetComponent<ChoreAI>(); if ((Object)(object)component != (Object)null && component.IsAssigned) { component.Unassign(); MessageHud.instance.ShowMessage((MessageType)2, "Ally returns to your side.", 0, (Sprite)null, false); } else { MessageHud.instance.ShowMessage((MessageType)2, "This ally has no chore to leave.", 0, (Sprite)null, false); } return; } Smelter componentInParent2 = hoverObject.GetComponentInParent<Smelter>(); Fermenter val = (((Object)(object)componentInParent2 == (Object)null) ? hoverObject.GetComponentInParent<Fermenter>() : null); CookingStation val2 = (((Object)(object)componentInParent2 == (Object)null && (Object)(object)val == (Object)null) ? hoverObject.GetComponentInParent<CookingStation>() : null); Pickable val3 = (((Object)(object)componentInParent2 == (Object)null && (Object)(object)val == (Object)null && (Object)(object)val2 == (Object)null) ? hoverObject.GetComponentInParent<Pickable>() : null); ItemStand val4 = null; Character val5 = null; Container val6 = null; if ((Object)(object)componentInParent2 == (Object)null && (Object)(object)val == (Object)null && (Object)(object)val2 == (Object)null && (Object)(object)val3 == (Object)null) { ItemStand componentInParent3 = hoverObject.GetComponentInParent<ItemStand>(); if ((Object)(object)componentInParent3 != (Object)null && componentInParent3.HaveAttachment() && componentInParent3.GetAttachedItem() == "Cultivator") { val4 = componentInParent3; } if ((Object)(object)val4 == (Object)null) { Character componentInParent4 = hoverObject.GetComponentInParent<Character>(); if ((Object)(object)componentInParent4 != (Object)null && componentInParent4.IsTamed() && (Object)(object)((Component)componentInParent4).GetComponent<DvergrCompanion>() == (Object)null) { val5 = componentInParent4; } if ((Object)(object)val5 == (Object)null) { val6 = hoverObject.GetComponentInParent<Container>(); } } } if ((Object)(object)componentInParent2 == (Object)null && (Object)(object)val == (Object)null && (Object)(object)val2 == (Object)null && (Object)(object)val3 == (Object)null && (Object)(object)val4 == (Object)null && (Object)(object)val5 == (Object)null && (Object)(object)val6 == (Object)null) { return; } ChoreAI choreAI = ChoreAI.ClaimantOf(((Object)(object)componentInParent2 != (Object)null) ? ((Component)componentInParent2).gameObject : (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : (((Object)(object)val2 != (Object)null) ? ((Component)val2).gameObject : (((Object)(object)val3 != (Object)null) ? ((Component)val3).gameObject : (((Object)(object)val4 != (Object)null) ? ((Component)val4).gameObject : (((Object)(object)val5 != (Object)null) ? ((Component)val5).gameObject : (((Object)(object)val6 != (Object)null) ? ((Component)val6).gameObject : null))))))); if ((Object)(object)choreAI == (Object)null && (Object)(object)val5 != (Object)null) { choreAI = ChoreAI.FeederCovering(((Component)val5).transform.position); } if ((Object)(object)choreAI != (Object)null) { DvergrCompanion component2 = ((Component)choreAI).GetComponent<DvergrCompanion>(); if ((Object)(object)component2 != (Object)null && component2.IsOwner(player)) { choreAI.Unassign(); MessageHud.instance.ShowMessage((MessageType)2, "Ally returns to your side.", 0, (Sprite)null, false); } else { MessageHud.instance.ShowMessage((MessageType)2, choreAI.WorkerName + " is already working here.", 0, (Sprite)null, false); } return; } DvergrCaste? requiredCaste = (((Object)(object)componentInParent2 != (Object)null) ? ChoreRules.RequiredCaste(componentInParent2) : new DvergrCaste?((!((Object)(object)val6 != (Object)null)) ? DvergrCaste.SupportMage : DvergrCaste.Rogue)); DvergrCompanion dvergrCompanion2 = FindNearestRecruitedCompanion(((Component)player).transform.position, ChoreAssignRadius.Value, requiredCaste, player, freeOnly: true); if ((Object)(object)dvergrCompanion2 == (Object)null) { string text = (requiredCaste.HasValue ? ("Only your own free " + ChoreRules.DisplayName(requiredCaste.Value) + " can do this — none nearby.") : "No free ally of yours nearby to assign."); MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false); return; } ChoreAI choreAI2 = ((Component)dvergrCompanion2).GetComponent<ChoreAI>(); if ((Object)(object)choreAI2 == (Object)null) { choreAI2 = ((Component)dvergrCompanion2).gameObject.AddComponent<ChoreAI>(); } if ((Object)(object)componentInParent2 != (Object)null) { choreAI2.AssignToSmelter(componentInParent2); MessageHud.instance.ShowMessage((MessageType)2, "Ally tends the station.", 0, (Sprite)null, false); } else if ((Object)(object)val != (Object)null) { choreAI2.AssignToFermenter(val); MessageHud.instance.ShowMessage((MessageType)2, "Ally tends the brew.", 0, (Sprite)null, false); } else if ((Object)(object)val2 != (Object)null) { choreAI2.AssignToCooking(val2); MessageHud.instance.ShowMessage((MessageType)2, "Ally tends the cookfire.", 0, (Sprite)null, false); } else if ((Object)(object)val3 != (Object)null || (Object)(object)val4 != (Object)null) { choreAI2.AssignToFarm(((Object)(object)val3 != (Object)null) ? ((Component)val3).gameObject : ((Component)val4).gameObject); MessageHud.instance.ShowMessage((MessageType)2, "Ally tends the field.", 0, (Sprite)null, false); } else if ((Object)(object)val5 != (Object)null) { choreAI2.AssignToFeedAnimals(((Component)val5).gameObject); MessageHud.instance.ShowMessage((MessageType)2, "Ally tends the animals.", 0, (Sprite)null, false); } else { choreAI2.AssignToHaul(val6); MessageHud.instance.ShowMessage((MessageType)2, "Ally hauls to this chest.", 0, (Sprite)null, false); } } private void HandleDuelInput(Player player) { GameObject hoverObject = ((Humanoid)player).GetHoverObject(); if (!((Object)(object)hoverObject == (Object)null)) { Character componentInParent = hoverObject.GetComponentInParent<Character>(); DvergrCompanion dvergrCompanion = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).GetComponent<DvergrCompanion>() : null); if ((Object)(object)dvergrCompanion == (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, "That is not an ally you can pit in a duel.", 0, (Sprite)null, false); } else if (!dvergrCompanion.IsOwner(player)) { MessageHud.instance.ShowMessage((MessageType)2, "Only its owner can send this companion to duel.", 0, (Sprite)null, false); } else if (dvergrCompanion.DuelMode) { dvergrCompanion.ExitDuelMode(DvergrCompanion.DuelExitReason.OwnerStopped); } else if (!dvergrCompanion.EnterDuelMode()) { MessageHud.instance.ShowMessage((MessageType)2, "This companion cannot duel right now — unassign its chore first.", 0, (Sprite)null, false); } } } private void HandleStanceCycleInput(Player player) { GameObject hoverObject = ((Humanoid)player).GetHoverObject(); if ((Object)(object)hoverObject == (Object)null) { return; } Character componentInParent = hoverObject.GetComponentInParent<Character>(); DvergrCompanion dvergrCompanion = ((componentInParent != null) ? ((Component)componentInParent).GetComponent<DvergrCompanion>() : null); if ((Object)(object)dvergrCompanion == (Object)null) { return; } if (!dvergrCompanion.IsOwner(player)) { MessageHud.instance.ShowMessage((MessageType)2, "This companion answers to another.", 0, (Sprite)null, false); return; } ChoreAI component = ((Component)componentInParent).GetComponent<ChoreAI>(); if ((component != null && component.IsAssigned) || dvergrCompanion.DuelMode) { MessageHud.instance.ShowMessage((MessageType)2, "Ally is busy — unassign it first.", 0, (Sprite)null, false); return; } CompanionStance companionStance = ((dvergrCompanion.Stance == CompanionStance.Follow) ? CompanionStance.Guard : ((dvergrCompanion.Stance == CompanionStance.Guard) ? CompanionStance.Standby : CompanionStance.Follow)); dvergrCompanion.SetStance(companionStance, ((Component)player).gameObject); MessageHud.instance.ShowMessage((MessageType)2, "Ally stance: " + companionStance switch { CompanionStance.Guard => "Guard", CompanionStance.Follow => "Follow", _ => "Standby", } + ".", 0, (Sprite)null, false); } private static DvergrCompanion FindNearestRecruitedCompanion(Vector3 origin, float radius, DvergrCaste? requiredCaste = null, Player owner = null, bool freeOnly = false) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) List<Character> list = new List<Character>(); Character.GetCharactersInRange(origin, radius, list); DvergrCompanion result = null; float num = float.MaxValue; foreach (Character item in list) { DvergrCompanion component = ((Component)item).GetComponent<DvergrCompanion>(); if ((Object)(object)component == (Object)null || (requiredCaste.HasValue && component.Caste != requiredCaste.Value) || ((Object)(object)owner != (Object)null && !component.IsOwner(owner))) { continue; } if (freeOnly) { ChoreAI component2 = ((Component)item).GetComponent<ChoreAI>(); if (component2 != null && component2.IsAssigned) { continue; } } float num2 = Vector3.Distance(origin, ((Component)item).transform.position); if (num2 < num) { num = num2; result = component; } } return result; } } } namespace LostScrollsII.Integration { public static class ServerGuideBridge { private const string ServerGuideGuid = "com.valheimserverguide"; public static bool IsLoaded => Chainloader.PluginInfos.ContainsKey("com.valheimserverguide"); public static void RaiseRecruited(DvergrCaste caste) { if (!IsLoaded) { return; } try { RaiseRecruitedInternal(caste); } catch (Exception arg) { Plugin.Log.LogWarning((object)$"ServerGuide integration (dvergr_recruited) failed: {arg}"); } } public static void RaiseLevelUp(DvergrCaste caste, int level) { if (!IsLoaded) { return; } try { RaiseLevelUpInternal(caste, level); } catch (Exception arg) { Plugin.Log.LogWarning((object)$"ServerGuide integration (dvergr_level_up) failed: {arg}"); } } public static void RaiseDuelWon(DvergrCaste winner, DvergrCaste loser) { if (!IsLoaded) { return; } try { RaiseDuelWonInternal(winner, loser); } catch (Exception arg) { Plugin.Log.LogWarning((object)$"ServerGuide integration (dvergr_duel_won) failed: {arg}"); } } private static void RaiseRecruitedInternal(DvergrCaste caste) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown GuidanceDispatcher.Raise(new TriggerEvent { Type = "dvergr_recruited", Subject = caste.ToString() }); } private static void RaiseLevelUpInternal(DvergrCaste caste, int level) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown GuidanceDispatcher.Raise(new TriggerEvent { Type = "dvergr_level_up", Subject = $"{caste}:{level}" }); } private static void RaiseDuelWonInternal(DvergrCaste winner, DvergrCaste loser) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown GuidanceDispatcher.Raise(new TriggerEvent { Type = "dvergr_duel_won", Subject = winner.ToString(), Extra = new Dictionary<string, object> { { "loserCaste", loser.ToString() } } }); } } } namespace LostScrollsII.Companions { public class ChoreAI : MonoBehaviour { public enum ChoreKind { None, Smelter, Farm, FeedAnimals, Fermenter, Cooking, Haul } public const string ZdoKeyChoreKind = "DE_ChoreKind"; public const string ZdoKeyChorePos = "DE_ChorePos"; private const float RestoreResolveRadius = 3f; private static readonly Dictionary<GameObject, ChoreAI> s_claims = new Dictionary<GameObject, ChoreAI>(); private const float ArrivalRange = 4.5f; private const float ContainerSearchRadius = 8f; private const float WorkRadius = 10f; private const float FeedInterval = 5f; private const float NotifyInterval = 60f; private const float NotifyRange = 20f; private Humanoid _humanoid; private MonsterAI _ai; private DvergrCompanion _companion; private ZNetView _znv; private float _lastSayTime = -999f; private bool _pendingRestore; private ChoreKind _restoreKind; private Vector3 _restorePos; private float _restoreTimer; private Container _openChest; private float _closeChestTime; private ChoreKind _kind; private Smelter _station; private Fermenter _fermenter; private CookingStation _cooker; private Container _haulChest; private GameObject _anchorObject; private GameObject _claimedAnchor; private float _feedTimer; public string WorkerName { get { if (!((Object)(object)_companion != (Object)null)) { if (!((Object)(object)_humanoid != (Object)null)) { return "An ally"; } return ((Character)_humanoid).GetHoverName(); } return _companion.DisplayName; } } public bool IsAssigned => _kind != ChoreKind.None; public static ChoreAI ClaimantOf(GameObject anchor) { if ((Object)(object)anchor == (Object)null) { return null; } if (s_claims.TryGetValue(anchor, out var value)) { if ((Object)(object)value != (Object)null && value.IsAssigned) { return value; } s_claims.Remove(anchor); } return null; } public static ChoreAI FeederCovering(Vector3 pos) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) foreach (DvergrCompanion item in DvergrCompanion.All) { if (!((Object)(object)item == (Object)null)) { ChoreAI component = ((Component)item).GetComponent<ChoreAI>(); if ((Object)(object)component != (Object)null && component.IsAssigned && component._kind == ChoreKind.FeedAnimals && Vector3.Distance(component.CurrentCenter(), pos) <= 10f) { return component; } } } return null; } private void Awake() { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) _humanoid = ((Component)this).GetComponent<Humanoid>(); _ai = ((Component)this).GetComponent<MonsterAI>(); _companion = ((Component)this).GetComponent<DvergrCompanion>(); _znv = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)_znv != (Object)null && _znv.IsValid()) { int num = _znv.GetZDO().GetInt("DE_ChoreKind", 0); if (num != 0) { _restoreKind = (ChoreKind)num; _restorePos = _znv.GetZDO().GetVec3("DE_ChorePos", ((Component)this).transform.position); _pendingRestore = true; } } } public static bool HasPersistedChore(ZNetView znv) { if ((Object)(object)znv != (Object)null && znv.IsValid()) { return znv.GetZDO().GetInt("DE_ChoreKind", 0) != 0; } return false; } public void AssignToSmelter(Smelter station) { _kind = ChoreKind.Smelter; _station = station; BeginChore(((Object)(object)station != (Object)null) ? ((Component)station).gameObject : null); } public void AssignToFarm(GameObject cropAnchor) { _kind = ChoreKind.Farm; BeginChore(cropAnchor); } public void AssignToFeedAnimals(GameObject animalAnchor) { _kind = ChoreKind.FeedAnimals; BeginChore(animalAnchor); } public void AssignToFermenter(Fermenter fermenter) { _kind = ChoreKind.Fermenter; _fermenter = fermenter; BeginChore(((Object)(object)fermenter != (Object)null) ? ((Component)fermenter).gameObject : null); } public void AssignToCooking(CookingStation cooker) { _kind = ChoreKind.Cooking; _cooker = cooker; BeginChore(((Object)(object)cooker != (Object)null) ? ((Component)cooker).gameObject : null); } public void AssignToHaul(Container chest) { _kind = ChoreKind.Haul; _haulChest = chest; BeginChore(((Object)(object)chest != (Object)null) ? ((Component)chest).gameObject : null); } private void BeginChore(GameObject anchor) { _anchorObject = anchor; _feedTimer = 0f; Claim(anchor); PersistChore(anchor); if ((Object)(object)_ai != (Object)null && (Object)(object)anchor != (Object)null) { _ai.SetFollowTarget(anchor); } if ((Object)(object)_companion != (Object)null) { _companion.ChoreActive = true; _companion.SetPassive(passive: true); } } private void PersistChore(GameObject anchor) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_znv == (Object)null) && _znv.IsValid()) { ZDO zDO = _znv.GetZDO(); zDO.Set("DE_ChoreKind", (int)_kind); zDO.Set("DE_ChorePos", ((Object)(object)anchor != (Object)null) ? anchor.transform.position : ((Component)this).transform.position); } } private void ClearPersistedChore() { if (!((Object)(object)_znv == (Object)null) && _znv.IsValid()) { _znv.GetZDO().Set("DE_ChoreKind", 0); } } private void TryRestore() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNetScene.instance == (Object)null) { return; } GameObject val = FindRestoreTarget(_restoreKind, _restorePos); if ((Object)(object)val != (Object)null) { _pendingRestore = false; ResumeChore(_restoreKind, val); return; } _restoreTimer += Time.deltaTime; if (_restoreTimer > 60f) { _pendingRestore = false; ClearPersistedChore(); } } private GameObject FindRestoreTarget(ChoreKind kind, Vector3 pos) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) float num = ((kind == ChoreKind.Farm || kind == ChoreKind.FeedAnimals) ? 10f : 3f); Collider[] array = Physics.OverlapSphere(pos, num); foreach (Collider val in array) { switch (kind) { case ChoreKind.Smelter: { Smelter componentInParent2 = ((Component)val).GetComponentInParent<Smelter>(); if ((Object)(object)componentInParent2 != (Object)null) { return ((Component)componentInParent2).gameObject; } break; } case ChoreKind.Fermenter: { Fermenter componentInParent4 = ((Component)val).GetComponentInParent<Fermenter>(); if ((Object)(object)componentInParent4 != (Object)null) { return ((Component)componentInParent4).gameObject; } break; } case ChoreKind.Cooking: { CookingStation componentInParent8 = ((Component)val).GetComponentInParent<CookingStation>(); if ((Object)(object)componentInParent8 != (Object)null) { return ((Component)componentInParent8).gameObject; } break; } case ChoreKind.Haul: { Container componentInParent3 = ((Component)val).GetComponentInParent<Container>(); if ((Object)(object)componentInParent3 != (Object)null) { return ((Component)componentInParent3).gameObject; } break; } case ChoreKind.Farm: { ItemStand componentInParent5 = ((Component)val).GetComponentInParent<ItemStand>(); if ((Object)(object)componentInParent5 != (Object)null && componentInParent5.HaveAttachment() && componentInParent5.GetAttachedItem() == "Cultivator") { return ((Component)componentInParent5).gameObject; } Pickable componentInParent6 = ((Component)val).GetComponentInParent<Pickable>(); if ((Object)(object)componentInParent6 != (Object)null) { return ((Component)componentInParent6).gameObject; } Plant componentInParent7 = ((Component)val).GetComponentInParent<Plant>(); if ((Object)(object)componentInParent7 != (Object)null) { return ((Component)componentInParent7).gameObject; } break; } case ChoreKind.FeedAnimals: { Character componentInParent = ((Component)val).GetComponentInParent<Character>(); if ((Object)(object)componentInParent != (Object)null && componentInParent.IsTamed() && (Object)(object)((Component)componentInParent).GetComponent<DvergrCompanion>() == (Object)null) { return ((Component)componentInParent).gameObject; } break; } } } return null; } private void ResumeChore(ChoreKind kind, GameObject go) { switch (kind) { case ChoreKind.Smelter: { Smelter componentInParent4 = go.GetComponentInParent<Smelter>(); if ((Object)(object)componentInParent4 != (Object)null) { AssignToSmelter(componentInParent4); } break; } case ChoreKind.Fermenter: { Fermenter componentInParent2 = go.GetComponentInParent<Fermenter>(); if ((Object)(object)componentInParent2 != (Object)null) { AssignToFermenter(componentInParent2); } break; } case ChoreKind.Cooking: { CookingStation componentInParent3 = go.GetComponentInParent<CookingStation>(); if ((Object)(object)componentInParent3 != (Object)null) { AssignToCooking(componentInParent3); } break; } case ChoreKind.Haul: { Container componentInParent = go.GetComponentInParent<Container>(); if ((Object)(object)componentInParent != (Object)null) { AssignToHaul(componentInParent); } break; } case ChoreKind.Farm: AssignToFarm(go); break; case ChoreKind.FeedAnimals: AssignToFeedAnimals(go); break; } if (!IsAssigned) { ClearPersistedChore(); } } private void Claim(GameObject anchor) { ReleaseClaim(); if (!((Object)(object)anchor == (Object)null)) { s_claims[anchor] = this; _claimedAnchor = anchor; } } private void ReleaseClaim() { if (!((Object)(object)_claimedAnchor == (Object)null)) { if (s_claims.TryGetValue(_claimedAnchor, out var value) && (Object)(object)value == (Object)(object)this) { s_claims.Remove(_claimedAnchor); } _claimedAnchor = null; } } private void OnDisable() { ReleaseClaim(); } public void Unassign() { _kind = ChoreKind.None; _station = null; _fermenter = null; _cooker = null; _haulChest = null; _anchorObject = null; _pendingRestore = false; ReleaseClaim(); ClearPersistedChore(); ClearSpeech(); CloseChest(); if ((Object)(object)_companion != (Object)null) { _companion.ChoreActive = false; DvergrCompanion companion = _companion; Player obj = _companion.OwnerPlayer(); companion.SetStance(CompanionStance.Follow, (obj != null) ? ((Component)obj).gameObject : null); } else if ((Object)(object)_ai != (Object)null) { _ai.SetFollowTarget((GameObject)null); } } private void FaceToward(Vector3 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) Vector3 val = pos - ((Component)this).transform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude > 0.01f && (Object)(object)_humanoid != (Object)null) { ((Character)_humanoid).SetLookDir(((Vector3)(ref val)).normalized, 0f); } } private void OpenChest(Container c) { if (!((Object)(object)c == (Object)null)) { if ((Object)(object)_openChest != (Object)(object)c) { CloseChest(); c.SetInUse(true); _openChest = c; } _closeChestTime = Time.time + 1.5f; } } private void CloseChest() { if ((Object)(object)_openChest != (Object)null) { _openChest.SetInUse(false); _openChest = null; } } private Vector3 CurrentCenter() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) if (_kind == ChoreKind.Smelter && (Object)(object)_station != (Object)null) { return ((Component)_station).transform.position; } if (_kind == ChoreKind.Fermenter && (Object)(object)_fermenter != (Object)null) { return ((Component)_fermenter).transform.position; } if (_kind == ChoreKind.Cooking && (Object)(object)_cooker != (Object)null) { return ((Component)_cooker).transform.position; } if (_kind == ChoreKind.Haul && (Object)(object)_haulChest != (Object)null) { return ((Component)_haulChest).transform.position; } if ((Object)(object)_anchorObject != (Object)null) { return _anchorObject.transform.position; } return ((Component)this).transform.position; } private void Update() { //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_openChest != (Object)null && Time.time > _closeChestTime) { CloseChest(); } if (_pendingRestore) { TryRestore(); } else { if (_kind == ChoreKind.None || (Object)(object)_humanoid == (Object)null || ((Object)(object)_znv != (Object)null && _znv.IsValid() && !_znv.IsOwner())) { return; } if ((Object)(object)_anchorObject == (Object)null) { Unassign(); return; } _feedTimer += Time.deltaTime; if (_feedTimer < 5f) { return; } _feedTimer = 0f; if (Vector3.Distance(((Component)this).transform.position, CurrentCenter()) > 4.5f) { Say((_kind == ChoreKind.Farm) ? "I can't reach the field!" : ((_kind == ChoreKind.FeedAnimals) ? "I can't reach the pen!" : ((_kind == ChoreKind.Haul) ? "I can't reach the chest!" : "I can't reach my station!"))); return; } switch (_kind) { case ChoreKind.Smelter: ServiceStation(); break; case ChoreKind.Farm: ServiceFarm(); break; case ChoreKind.FeedAnimals: ServiceAnimals(); break; case ChoreKind.Fermenter: ServiceFermenter(); break; case ChoreKind.Cooking: ServiceCooking(); break; case ChoreKind.Haul: ServiceHaul(); break; } } } private void ServiceStation() { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) bool flag = _station.GetQueueSize() < _station.m_maxOre; bool flag2 = (Object)(object)_station.m_fuelItem != (Object)null && _station.GetFuel() < (float)_station.m_maxFuel; if (!flag && !flag2) { ClearSpeech(); return; } string text = (((Object)(object)_station.m_fuelItem != (Object)null) ? ((Object)_station.m_fuelItem).name : null); bool fuelMissing = flag2; bool oreMissing = flag; Inventory inventory = _humanoid.GetInventory(); Collider[] array = Physics.OverlapSphere(((Component)_station).transform.position, 8f); bool flag3 = false; Collider[] array2 = array; for (int i = 0; i < array2.Length; i++) { Container componentInParent = ((Component)array2[i]).GetComponentInParent<Container>(); Inventory val = (((Object)(object)componentInParent != (Object)null) ? componentInParent.GetInventory() : null); if (val == null) { continue; } flag3 = true; foreach (ItemData item in new List<ItemData>(val.GetAllItems())) { string text2 = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : null); if (text2 == null) { continue; } if (flag2 && text2 == text) { if (val.RemoveItem(item, 1)) { inventory.AddItem(item.Clone()); OpenChest(componentInParent); FaceToward(((Component)_station).transform.position); _station.SetFuel(_station.GetFuel() + 1f); PlayEffects(_station.m_fuelAddedEffects, ((Component)_station).transform); flag2 = false; fuelMissing = false; } } else if (flag && _station.GetItemConversion(text2) != null && val.RemoveItem(item, 1)) { inventory.AddItem(item.Clone()); OpenChest(componentInParent); FaceToward(((Component)_station).transform.position); _station.QueueOre(text2); PlayEffects(_station.m_oreAddedEffects, ((Component)_station).transform); flag = false; oreMissing = false; } } if (!flag && !flag2) { break; } } if (!flag3) { Say("I have no chest to draw from!"); } else { ReportMissing(oreMissing, fuelMissing); } } private string InputNames() { HashSet<string> hashSet = new HashSet<string>(); if ((Object)(object)_station != (Object)null && _station.m_conversion != null) { foreach (ItemConversion item in _station.m_conversion) { if (item != null && (Object)(object)item.m_from != (Object)null && item.m_from.m_itemData != null && item.m_from.m_itemData.m_shared != null) { hashSet.Add(Localization.instance.Localize(item.m_from.m_itemData.m_shared.m_name)); } } } if (hashSet.Count <= 0) { return "materials"; } return string.Join(" or ", hashSet); } private string FuelName() { if ((Object)(object)_station != (Object)null && (Object)(object)_station.m_fuelItem != (Object)null && _station.m_fuelItem.m_itemData != null && _station.m_fuelItem.m_itemData.m_shared != null) { return Localization.instance.Localize(_station.m_fuelItem.m_itemData.m_shared.m_name); } return "fuel"; } private void ServiceFarm() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) Vector3 val = CurrentCenter(); Inventory val2 = FirstContainerInventory(val); Collider[] array = Physics.OverlapSphere(val, 10f); for (int i = 0; i < array.Length; i++) { Pickable componentInParent = ((Component)array[i]).GetComponentInParent<Pickable>(); if ((Object)(object)componentInParent == (Object)null || !componentInParent.CanBePicked()) { continue; } if (val2 == null) { Say("I have no chest for the harvest."); return; } GameObject itemPrefab = componentInParent.m_itemPrefab; int num = Mathf.Max(1, componentInParent.m_amount); if (!((Object)(object)itemPrefab == (Object)null)) { if (!val2.CanAddItem(itemPrefab, num)) { Say("The harvest chest is full!"); return; } val2.AddItem(itemPrefab, num); componentInParent.SetPicked(true); FaceToward(((Component)componentInParent).transform.position); PlayEffects(componentInParent.m_pickEffector, null, ((Component)componentInParent).transform.position); ClearSpeech(); return; } } if (val2 == null) { Say("I have no chest for the seeds."); return; } ItemData val3 = null; GameObject val4 = null; bool flag = false; foreach (ItemData allItem in val2.GetAllItems()) { if (PlantingCatalog.TryGetSapling(((Object)(object)allItem.m_dropPrefab != (Object)null) ? ((Object)allItem.m_dropPrefab).name : null, out var sapling)) { if (CanGrowInBiome(sapling.GetComponent<Plant>(), val)) { val3 = allItem; val4 = sapling; break; } flag = true; } } Vector3 spot; if ((Object)(object)val4 == (Object)null) { Say(flag ? "These seeds won't grow in this land." : "No crops are ready, and no seeds to plant."); } else if (!TryFindPlantSpot(val, val4, out spot)) { Say("There's no room left to plant."); } else if (val2.RemoveItem(val3, 1)) { Object.Instantiate<GameObject>(val4, spot, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f)); Piece component = val4.GetComponent<Piece>(); if ((Object)(object)component != (Object)null) { PlayEffects(component.m_placeEffect, null, spot); } FaceToward(spot); Plugin.Log.LogInfo((object)$"[farm] planted '{((Object)val4).name}' at {spot} (biome {CurrentBiome(spot)})."); ClearSpeech(); } } private bool TryFindPlantSpot(Vector3 center, GameObject sapling, out Vector3 spot) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) spot = center; Plant component = sapling.GetComponent<Plant>(); float radius = (((Object)(object)component != (Object)null) ? Mathf.Max(component.m_growRadius, 0.5f) : 1f); ZoneSystem instance = ZoneSystem.instance; Vector3 val2 = default(Vector3); for (int i = 0; i < 24; i++) { Vector2 val = Random.insideUnitCircle * 8.5f; ((Vector3)(ref val2))..ctor(center.x + val.x, center.y, center.z + val.y); if ((Object)(object)instance != (Object)null) { val2.y = instance.GetGroundHeight(val2); } Heightmap val3 = Heightmap.FindHeightmap(val2); if (!((Object)(object)val3 == (Object)null) && val3.IsCultivated(val2) && CanGrowInBiome(component, val2) && IsSpotClear(val2, radius)) { spot = val2; return true; } } return false; } private static bool IsSpotClear(Vector3 p, float radius) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Collider[] array = Physics.OverlapSphere(p, radius); foreach (Collider val in array) { if ((Object)(object)((Component)val).GetComponentInParent<Plant>() != (Object)null) { return false; } Pickable componentInParent = ((Component)val).GetComponentInParent<Pickable>(); if ((Object)(object)componentInParent != (Object)null && !componentInParent.GetPicked()) { return false; } } return true; } private static bool CanGrowInBiome(Plant plant, Vector3 pos) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 if ((Object)(object)plant == (Object)null) { return true; } if (WorldGenerator.instance == null) { return true; } Biome biome = WorldGenerator.instance.GetBiome(pos); return (plant.m_biome & biome) > 0; } private static Biome CurrentBiome(Vector3 pos) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (WorldGenerator.instance == null) { return (Biome)0; } return WorldGenerator.instance.GetBiome(pos); } private void ServiceAnimals() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) Vector3 val = CurrentCenter(); List<Character> list = new List<Character>(); Collider[] array = Physics.OverlapSphere(val, 10f); for (int i = 0; i < array.Length; i++) { Character componentInParent = ((Component)array[i]).GetComponentInParent<Character>(); if (!((Object)(object)componentInParent == (Object)null) && componentInParent.IsTamed() && !((Object)(object)((Component)componentInParent).GetComponent<DvergrCompanion>() != (Object)null)) { Tameable component = ((Component)componentInParent).GetComponent<Tameable>(); if ((Object)(object)component != (Object)null && component.IsHungry() && !list.Contains(componentInParent)) { list.Add(componentInParent); } } } if (list.Count == 0) { Say("The animals aren't hungry."); return; } Inventory val2 = FirstContainerInventory(val); if (val2 == null) { Say("I have no food chest nearby."); return; } foreach (Character item in list) { MonsterAI component2 = ((Component)item).GetComponent<MonsterAI>(); if (!((Object)(object)component2 == (Object)null) && component2.m_consumeItems != null && !ItemAlreadyDroppedNear(((Component)item).transform.position)) { ItemData val3 = FindAcceptedFood(val2, component2.m_consumeItems); if (val3 == null) { Say("I have no food to give."); return; } if (val2.RemoveItem(val3, 1)) { ItemData obj = val3.Clone(); obj.m_stack = 1; ItemDrop.DropItem(obj, 1, ((Component)item).transform.position + Vector3.up * 0.3f, Quaternion.identity); ClearSpeech(); return; } } } ClearSpeech(); } private static ItemData FindAcceptedFood(Inventory chest, List<ItemDrop> consumeItems) { foreach (ItemData allItem in chest.GetAllItems()) { string text = (((Object)(object)allItem.m_dropPrefab != (Object)null) ? ((Object)allItem.m_dropPrefab).name : null); if (text == null) { continue; } foreach (ItemDrop consumeItem in consumeItems) { if ((Object)(object)consumeItem != (Object)null && ((Object)consumeItem).name == text) { return allItem; } } } return null; } private static bool ItemAlreadyDroppedNear(Vector3 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Collider[] array = Physics.OverlapSphere(pos, 2f); for (int i = 0; i < array.Length; i++) { if ((Object)(object)((Component)array[i]).GetComponentInParent<ItemDrop>() != (Object)null) { return true; } } return false; } private void ServiceFermenter() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected I4, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) Status status = _fermenter.GetStatus(); switch (status - 1) { case 2: _fermenter.Interact(_humanoid, false, false); ClearSpeech(); return; case 0: ClearSpeech(); return; case 1: Say("The brew is exposed to the sky!"); return; } Inventory val = FirstContainerInventory(CurrentCenter()); if (val == null) { Say("I have no chest to brew from!"); return; } foreach (ItemData item in new List<ItemData>(val.GetAllItems())) { string text = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : null); if (text != null && _fermenter.IsItemAllowed(text) && val.RemoveItem(item, 1)) { ItemData val2 = item.Clone(); val2.m_stack = 1; _humanoid.GetInventory().AddItem(val2); if (_fermenter.AddItem(_humanoid, val2)) { ClearSpeech(); return; } } } Say("I have nothing to brew!"); } private void ServiceCooking() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) if (_cooker.HaveDoneItem()) { _cooker.OnInteract(_humanoid); ClearSpeech(); return; } if ((Object)(object)_cooker.m_fuelItem != (Object)null && _cooker.GetFuel() < (float)_cooker.m_maxFuel) { Inventory val = FirstContainerInventory(CurrentCenter()); string name = ((Object)_cooker.m_fuelItem).name; if (val != null) { foreach (ItemData item in new List<ItemData>(val.GetAllItems())) { if (!((((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : null) != name) && val.RemoveItem(item, 1)) { _humanoid.GetInventory().AddItem(item.Clone()); _cooker.SetFuel(_cooker.GetFuel() + 1f); ClearSpeech(); return; } } } } if (_cooker.m_requireFire && !_cooker.IsFireLit()) { Say("The cooking fire is out!"); return; } if (_cooker.GetFreeSlot() < 0) { ClearSpeech(); return; } Inventory val2 = FirstContainerInventory(CurrentCenter()); if (val2 == null) { Say("I have no chest to cook from!"); return; } foreach (ItemData item2 in new List<ItemData>(val2.GetAllItems())) { string text = (((Object)(object)item2.m_dropPrefab != (Object)null) ? ((Object)item2.m_dropPrefab).name : null); if (text != null && _cooker.GetItemConversion(text) != null && val2.RemoveItem(item2, 1)) { ItemData val3 = item2.Clone(); val3.m_stack = 1; _humanoid.GetInventory().AddItem(val3); if (_cooker.CookItem(_humanoid, val3)) { ClearSpeech(); return; } } } Say("I have nothing to cook!"); } private void ServiceHaul() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) Inventory val = (((Object)(object)_haulChest != (Object)null) ? _haulChest.GetInventory() : null); if (val == null) { return; } Collider[] array = Physics.OverlapSphere(CurrentCenter(), 10f); for (int i = 0; i < array.Length; i++) { ItemDrop componentInParent = ((Component)array[i]).GetComponentInParent<ItemDrop>(); if ((Object)(object)componentInParent == (Object)null || !componentInParent.CanPickup(false)) { continue; } ZNetView component = ((Component)componentInParent).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { continue; } ItemData itemData = componentInParent.m_itemData; if (itemData != null) { if (!val.CanAddItem(itemData, itemData.m_stack)) { Say("The haul chest is full!"); return; } val.AddItem(itemData.Clone()); OpenChest(_haulChest); FaceToward(((Component)_haulChest).transform.position); component.ClaimOwnership(); ZNetScene.instance.Destroy(((Component)componentInParent).gameObject); ClearSpeech(); return; } } ClearSpeech(); } private Inventory FirstContainerInventory(Vector3 center) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Collider[] array = Physics.OverlapSphere(center, 8f); for (int i = 0; i < array.Length; i++) { Container componentInParent = ((Component)array[i]).GetComponentInParent<Container>(); Inventory val = (((Object)(object)componentInParent != (Object)null) ? componentInParent.GetInventory() : null); if (val != null) { return val; } } return null; } private void PlayEffects(EffectList effects, Transform parent, Vector3? at = null) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (effects != null) { Vector3 val = (Vector3)(((??)at) ?? (((Object)(object)parent != (Object)null) ? parent.position : ((Component)this).transform.position)); effects.Create(val, Quaternion.identity, parent, 1f, -1); } } private void ReportMissing(bool oreMissing, bool fuelMissing) { string text = ((oreMissing && fuelMissing) ? ("I need more " + InputNames() + " and " + FuelName() + "!") : (fuelMissing ? ("I need more " + FuelName() + "!") : (oreMissing ? ("I need more " + InputNames() + "!") : null))); if (text == null) { ClearSpeech(); } else { Say(text); } } private void Say(string text) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Chat.instance == (Object)null) && !((Object)(object)_companion == (Object)null) && _companion.IsOwnerNear(20f) && !(Time.time - _lastSayTime < 60f)) { _lastSayTime = Time.time; Chat.instance.SetNpcText(((Component)this).gameObject, Vector3.up * 2.2f, 20f, 8f, string.Empty, text, false); } } private void ClearSpeech() { if ((Object)(object)Chat.instance != (Object)null) { Chat.instance.ClearNpcText(((Component)this).gameObject); } } } public static class ChoreRules { public static DvergrCaste? RequiredCaste(Smelter station) { string text = (((Object)(object)station != (Object)null) ? ((Object)station).name.ToLowerInvariant() : string.Empty); if (text.Contains("smelter") || text.Contains("blast") || text.Contains("charcoal")) { return DvergrCaste.FireMage; } if (text.Contains("eitr") || text.Contains("spinning") || text.Contains("windmill")) { return DvergrCaste.IceMage; } return null; } public static string DisplayName(DvergrCaste caste) { return caste.Display(); } } public static class CommunionService { public const float SubdueHealthThreshold = 0.2f; public static DvergrCaste DetectCaste(Character target, bool log = true) { if ((Object)(object)target == (Object)null) { return DvergrCaste.Rogue; } Humanoid component = ((Component)target).GetComponent<Humanoid>(); if ((Object)(object)component != (Object)null) { string[] array = new string[5] { ItemName(component.GetCurrentWeapon()), ItemName(component.m_rightItem), ItemName(component.m_hiddenRightItem), ItemName(component.m_leftItem), ItemName(component.m_hiddenLeftItem) }; foreach (string text in array) { DvergrCaste? dvergrCaste = ClassifyByElement(text); if (dvergrCaste.HasValue) { if (log) { Plugin.Log.LogInfo((object)$"[recruit] caste {dvergrCaste.Value} from weapon slot '{text}'."); } return dvergrCaste.Value; } } Inventory inventory = component.GetInventory(); if (inventory != null) { foreach (ItemData allItem in inventory.GetAllItems()) { string text2 = ItemName(allItem); DvergrCaste? dvergrCaste2 = ((text2 != null && text2.ToLowerInvariant().Contains("staff")) ? ClassifyByElement(text2) : ((DvergrCaste?)null)); if (dvergrCaste2.HasValue) { if (log) { Plugin.Log.LogInfo((object)$"[recruit] caste {dvergrCaste2.Value} from inventory item '{text2}'."); } return dvergrCaste2.Value; } } } } string name = ((Object)target).name; if (!string.IsNullOrEmpty(name)) { if (name.IndexOf("Fire", StringComparison.OrdinalIgnoreCase) >= 0) { return DvergrCaste.FireMage; } if (name.IndexOf("Ice", StringComparison.OrdinalIgnoreCase) >= 0) { return DvergrCaste.IceMage; } if (name.IndexOf("Support", StringComparison.OrdinalIgnoreCase) >= 0) { return DvergrCaste.SupportMage; } } if (log) { LogDetectionMiss(target, component); } return DvergrCaste.Rogue; } private static DvergrCaste? ClassifyByElement(string name) { if (string.IsNullOrEmpty(name)) { return null; } string text = name.ToLowerInvariant(); if (text.Contains("fire")) { return DvergrCaste.FireMage; } if (text.Contains("ice") || text.Contains("frost")) { return DvergrCaste.IceMage; } if (text.Contains("support") || text.Contains("heal") || text.Contains("nova") || text.Contains("blocker") || text.Contains("shield")) { return DvergrCaste.SupportMage; } return null; } private static string ItemName(ItemData item) { if (item == null) { return null; } if ((Object)(object)item.m_dropPrefab != (Object)null) { return ((Object)item.m_dropPrefab).name; } if (item.m_shared == null) { return null; } return item.m_shared.m_name; } private static void LogDetectionMiss(Character target, Humanoid humanoid) { string text = "(none)"; if ((Object)(object)humanoid != (Object)null && humanoid.GetInventory() != null) { List<string> list = new List<string>(); foreach (ItemData allItem in humanoid.GetInventory().GetAllItems()) { list.Add(ItemName(allItem)); } if (list.Count > 0) { text = string.Join(", ", list); } } Plugin.Log.LogInfo((object)("[recruit] No staff detected -> Rogue. prefab='" + ((Object)target).name + "', slots[" + Slots() + "], inventory=[" + text + "].")); string Slots() { if ((Object)(object)humanoid == (Object)null) { return "(no humanoid)"; } return "cur='" + ItemName(humanoid.GetCurrentWeapon()) + "', right='" + ItemName(humanoid.m_rightItem) + "', hiddenRight='" + ItemName(humanoid.m_hiddenRightItem) + "', left='" + ItemName(humanoid.m_leftItem) + "', hiddenLeft='" + ItemName(humanoid.m_hiddenLeftItem) + "'"; } } public static GameObject SpawnRecruited(DvergrCaste caste, int level, Player owner, Vector3 pos, float xp = 0f) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNetScene.instance == (Object)null) { return null; } GameObject prefab = ZNetScene.instance.GetPrefab(CastePrefab(caste)); if ((Object)(object)prefab == (Object)null && caste != DvergrCaste.Rogue) { prefab = ZNetScene.instance.GetPrefab("DvergerMage"); } if ((Object)(object)prefab == (Object)null) { prefab = ZNetScene.instance.GetPrefab("Dverger"); } if ((Object)(object)prefab == (Object)null) { return null; } GameObject val = Object.Instantiate<GameObject>(prefab, pos, Quaternion.identity); Character component = val.GetComponent<Character>(); ZNetView component2 = val.GetComponent<ZNetView>(); if ((Object)(object)component2 != (Object)null && component2.IsValid()) { ZDO zDO = component2.GetZDO(); zDO.Set("DE_Recruited", true); zDO.Set("DE_Caste", (int)caste); zDO.Set("DE_Level", Mathf.Clamp(level, 1, 10)); zDO.Set("DE_Xp", Mathf.Max(0f, xp)); if ((Object)(object)owner != (Object)null) { zDO.Set("DE_Owner", owner.GetPlayerID()); zDO.Set("DE_OwnerName", owner.GetPlayerName()); } } if ((Object)(object)component != (Object)null) { ApplyFreedState(component, ((Object)(object)owner != (Object)null) ? ((Component)owner).gameObject : null); } if ((Object)(object)val.GetComponent<DvergrCompanion>() == (Object)null) { val.AddComponent<DvergrCompanion>(); } if ((Object)(object)val.GetComponent<ShipRideAI>() == (Object)null) { val.AddComponent<ShipRideAI>(); } if ((Object)(object)val.GetComponent<CompanionInventory>() == (Object)null) { val.AddComponent<CompanionInventory>(); } Plugin.Log.LogInfo((object)string.Format("[admin] Spawned recruited {0} (lv {1}) for {2}.", caste, level, ((Object)(object)owner != (Object)null) ? owner.GetPlayerName() : "?")); return val; } private static string CastePrefab(DvergrCaste caste) { return caste switch { DvergrCaste.FireMage => "DvergerMageFire", DvergrCaste.IceMage => "DvergerMageIce", DvergrCaste.SupportMage => "DvergerMageSupport", _ => "Dverger", }; } public static bool IsSubduedDvergr(Character target) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 if ((Object)(object)target == (Object)null) { return false; } if ((int)target.m_faction != 10) { return false; } if (target.IsDead()) { return false; } return target.GetHealthPercentage() <= 0.2f; } public static bool TryRecruit(Character target, Player recruiter, DvergrCaste caste) { if (!IsSubduedDvergr(target)) { return false; } ApplyFreedState(target, ((Object)(object)recruiter != (Object)null) ? ((Component)recruiter).gameObject : null); DvergrCompanion dvergrCompanion = ((Component)target).GetComponent<DvergrCompanion>(); if ((Object)(object)dvergrCompanion == (Object)null) { dvergrCompanion = ((Component)target).gameObject.AddComponent<DvergrCompanion>(); } if ((Object)(object)((Component)target).GetComponent<ShipRideAI>() == (Object)null) { ((Component)target).gameObject.AddComponent<ShipRideAI>(); } if ((Object)(object)((Component)target).GetComponent<CompanionInventory>() == (Object)null) { ((Component)target).gameObject.AddComponent<CompanionInventory>(); } dvergrCompanion.SetCaste(caste); if ((Object)(object)recruiter != (Object)null) { dvergrCompanion.SetOwner(recruiter.GetPlayerID()); dvergrCompanion.SetOwnerName(recruiter.GetPlayerName()); } ZNetView component = ((Component)target).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { component.GetZDO().Set("DE_Recruited", true); } Plugin.Log.LogInfo((object)string.Format("Dvergr {0} recruited by {1}.", caste, ((Object)(object)recruiter != (Object)null) ? recruiter.GetPlayerName() : "unknown")); ServerGuideBridge.RaiseRecruited(caste); dvergrCompanion.AnnounceCapability(); return true; } public static void RestoreCompanion(Character target) { if ((Object)(object)target == (Object)null) { return; } ZNetView component = ((Component)target).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid() && component.GetZDO().GetBool("DE_Recruited", false)) { ApplyFreedState(target, null); if ((Object)(object)((Component)target).GetComponent<DvergrCompanion>() == (Object)null) { ((Component)target).gameObject.AddComponent<DvergrCompanion>(); } if ((Object)(object)((Component)target).GetComponent<ShipRideAI>() == (Object)null) { ((Component)target).gameObject.AddComponent<ShipRideAI>(); } if ((Object)(object)((Component)target).GetComponent<CompanionInventory>() == (Object)null) { ((Component)target).gameObject.AddComponent<CompanionInventory>(); } if (ChoreAI.HasPersistedChore(component) && (Object)(object)((Component)target).GetComponent<ChoreAI>() == (Object)null) { ((Component)target).gameObject.AddComponent<ChoreAI>(); } } } private static void ApplyFreedState(Character target, GameObject followTarget) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) target.m_faction = (Faction)0; NpcTalk component = ((Component)target).GetComponent<NpcTalk>(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; } MonsterAI component2 = ((Component)target).GetComponent<MonsterAI>(); if (!((Object)(object)component2 == (Object)null)) { ((BaseAI)component2).SetAggravated(false, (AggravatedReason)0); ((BaseAI)component2).m_aggravatable = false; component2.m_attackPlayerObjects = false; component2.m_targetStatic = null; ((BaseAI)component2).m_avoidWater = true; component2.SetTarget((Character)null); ((BaseAI)component2).SetAlerted(false); ((BaseAI)component2).SetHuntPlayer(false); if ((Object)(object)followTarget != (Object)null) { component2.SetFollowTarget(followTarget); } } } } public enum ConsumableKind { None, Food, HealthMead, ResistMead } public static class CompanionConsumables { public static ConsumableKind Classify(ItemData item) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 if (item?.m_shared == null) { return ConsumableKind.None; } if ((int)item.m_shared.m_itemType != 2) { return ConsumableKind.None; } if (item.m_shared.m_food > 0f) { return ConsumableKind.Food; } StatusEffect consumeStatusEffect = item.m_shared.m_consumeStatusEffect; SE_Stats val = (SE_Stats)(object)((consumeStatusEffect is SE_Stats) ? consumeStatusEffect : null); if ((Object)(object)val == (Object)null) { return ConsumableKind.None; } if (val.m_healthUpFront + val.m_healthOverTime > 0f) { return ConsumableKind.HealthMead; } if (GrantsResistance(val)) { return ConsumableKind.ResistMead; } return ConsumableKind.None; } public static float HealAmount(ItemData item) { StatusEffect obj = item?.m_shared?.m_consumeStatusEffect; SE_Stats val = (SE_Stats)(object)((obj is SE_Stats) ? obj : null); if ((Object)(object)val == (Object)null) { return 0f; } return Mathf.Max(0f, val.m_healthUpFront + val.m_healthOverTime); } public static StatusEffect ConsumeEffect(ItemData item) { if (item?.m_shared == null) { return null; } return item.m_shared.m_consumeStatusEffect; } private static bool GrantsResistance(SE_Stats stats) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected I4, but got Unknown if (stats.m_mods == null) { return false; } foreach (DamageModPair mod in stats.m_mods) { DamageModifier modifier = mod.m_modifier; switch (modifier - 1) { case 0: case 2: case 4: return true; } } return false; } public static List<StatusEffect> ActiveResistEffects(Character c) { List<StatusEffect> list = new List<StatusEffect>(); SEMan val = (((Object)(object)c != (Object)null) ? c.GetSEMan() : null); if (val == null) { return list; } foreach (StatusEffect statusEffect in val.GetStatusEffects()) { SE_Stats val2 = (SE_Stats)(object)((statusEffect is SE_Stats) ? statusEffect : null); if (val2 != null && GrantsResistance(val2)) { list.Add(statusEffect); } } return list; } } [RequireComponent(typeof(DvergrCompanion))] public class CompanionInventory : MonoBehaviour { public const int Columns = 4; public const int Rows = 2; public const float MaxWeight = 150f; private Container _container; private DvergrCompanion _companion; public Container Container => _container; public Inventory Inventory { get { if (!((Object)(object)_container != (Object)null)) { return null; } return _container.GetInventory(); } } public bool IsOverCapacity => TotalWeight() > 150f; public bool IsEmpty { get { if (Inventory != null) { return Inventory.NrOfItems() == 0; } return true; } } private void Awake() { _companion = ((Component)this).GetComponent<DvergrCompanion>(); EnsureContainer(); if ((Object)(object)((Component)this).GetComponent<CompanionInventoryAI>() == (Object)null) { ((Component)this).gameObject.AddComponent<CompanionInventoryAI>(); } } public void EnsureContainer() { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown if (!((Object)(object)_container != (Object)null) || _container.GetInventory() == null) { _container = ((Component)this).GetComponent<Container>() ?? ((Component)this).gameObject.AddComponent<Container>(); _container.m_name = InventoryTitle(); _container.m_width = 4; _container.m_height = 2; _container.m_checkGuardStone = false; _container.m_autoDestroyEmpty = false; ZNetView component = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { Inventory val = new Inventory(_container.m_name, (Sprite)null, 4, 2); val.m_onChanged = _container.OnContainerChanged; _container.m_inventory = val; _container.Load(); } } } public string InventoryTitle() { return (((Object)(object)_companion != (Object)null) ? _companion.DisplayName : "Dvergr") + "'s pack"; } public void RefreshTitle() { if ((Object)(object)_container != (Object)null) { _container.m_name = InventoryTitle(); } } public float TotalWeight() { if (Inventory == null) { return 0f; } return Inventory.GetTotalWeight(); } public bool Holds(ItemData item) { if (item?.m_shared == null || Inventory == null) { return false; } foreach (ItemData allItem in Inventory.GetAllItems()) { if (allItem?.m_shared != null && allItem.m_shared.m_name == item.m_shared.m_name) { return true; } } return false; } public ItemData FindItem(Func<ItemData, bool> match) { if (Inventory == null) { return null; } foreach (ItemData allItem in Inventory.GetAllItems()) { if (allItem != null && match(allItem)) { return allItem; } } return null; } public List<ItemData> Items() { if (Inventory == null) { return new List<ItemData>(); } return Inventory.GetAllItems(); } public bool ConsumeOne(ItemData item) { if (item == null || Inventory == null) { return false; } return Inventory.RemoveItem(item, 1); } } [RequireComponent(typeof(DvergrCompanion))] [RequireComponent(typeof(CompanionInventory))] public class CompanionInventoryAI : MonoBehaviour { private const float TickInterval = 1f; private const float PickupRange = 8f; private const float MeadHealBelowFraction = 0.35f; private const float MeadHealUntilFraction = 0.9f; private DvergrCompanion _companion; private CompanionInventory _inv; private Character _character; private MonsterAI _ai; private ZNetView _znv; private float _tick; private float _foodPeak; private float _foodApplied; private float _foodDuration; private float _foodElapsed; private bool _healing; private void Awake() { _companion = ((Component)this).GetComponent<DvergrCompanion>(); _inv = ((Component)this).GetComponent<CompanionInventory>(); _character = ((Component)this).GetComponent<Character>(); _ai = ((Component)this).GetComponent<MonsterAI>(); _znv = ((Component)this).GetComponent<ZNetView>(); } private void Update() { if ((Object)(object)_character == (Object)null || _character.IsDead()) { return; } if (!((Object)(object)_znv == (Object)null) && _znv.IsValid() && !_znv.IsOwner()) { if ((Object)(object)_companion != (Object)null && (Object)(object)_inv != (Object)null) { _companion.IsEncumbered = _inv.IsOverCapacity; } return; } TickFoodBuff(Time.deltaTime); bool isOverCapacity = _inv.IsOverCapacity; if (_companion.DuelMode) { _companion.IsEncumbered = isOverCapacity; } else { _companion.ApplyEncumbrance(isOverCapacity); } _tick += Time.deltaTime; if (!(_tick < 1f)) { _tick = 0f; TickConsumption(); if (!isOverCapacity && (!((Object)(object)_ai != (Object)null) || (!((BaseAI)_ai).IsAlerted() && !((BaseAI)_ai).HaveTarget())) && !_companion.ChoreActive && !_companion.DuelMode && !_inv.IsEmpty) { TickPickup(); } } } private void TickPickup() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = _inv.Inventory; if (inventory == null) { return; } Collider[] array = Physics.OverlapSphere(((Component)this).transform.position, 8f); foreach (Collider val in array) { ItemDrop val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInParent<ItemDrop>() : null); if ((Object)(object)val2 == (Object)null || !val2.CanPickup(false)) { continue; } ZNetView component = ((Component)val2).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { continue; } ItemData itemData = val2.m_itemData; if (itemData?.m_shared != null && _inv.Holds(itemData)) { if (inventory.CanAddItem(itemData, itemData.m_stack)) { inventory.AddItem(itemData.Clone()); component.ClaimOwnership(); ZNetScene.instance.Destroy(((Component)val2).gameObject); } break; } } } private void TickConsumption() { if (_inv.Inventory == null) { return; } ItemData val = _inv.FindItem((ItemData it) => CompanionConsumables.Classify(it) == ConsumableKind.ResistMead && !HasEffect(CompanionConsumables.ConsumeEffect(it))); if (val != null) { DrinkStatusMead(val); return; } float healthPercentage = _character.GetHealthPercentage(); if (healthPercentage < 0.35f) { _healing = true; } else if (healthPercentage > 0.9f) { _healing = false; } if (_healing) { ItemData val2 = _inv.FindItem((ItemData it) => CompanionConsumables.Classify(it) == ConsumableKind.HealthMead); if (val2 != null) { float num = CompanionConsumables.HealAmount(val2); if (_inv.ConsumeOne(val2)) { _character.Heal(num, true); PlayConsumeEffects(val2); } return; } _healing = false; } if (_foodApplied <= 0f && _foodElapsed >= _foodDuration) { ItemData val3 = _inv.FindItem((ItemData it) => CompanionConsumables.Classify(it) == ConsumableKind.Food); if (val3 != null) { EatFood(val3); } } } private void DrinkStatusMead(ItemData mead) { StatusEffect val = CompanionConsumables.ConsumeEffect(mead); if (!((Object)(object)val == (Object)null) && _inv.ConsumeOne(mead)) { _character.GetSEMan().AddStatusEffect(val, true, 0, 0f); PlayConsumeEffects(mead); } } private bool HasEffect(StatusEffect se) { if ((Object)(object)se == (Object)null || (Object)(object)_character == (Object)null) { return false; } return _character.GetSEMan().HaveStatusEffect(se.NameHash()); } private void PlayConsumeEffects(ItemData item) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) StatusEffect val = CompanionConsumables.ConsumeEffect(item); EffectList val2 = (((Object)(object)val != (Object)null) ? val.m_startEffects : null); if (val2 != null) { val2.Create(((Component)this).transform.position, ((Component)this).transform.rotation, ((Component)this).transform, 1f, -1); } } private void EatFood(ItemData food) { if (_inv.ConsumeOne(food)) { _foodPeak = food.m_shared.m_food; _foodDuration = Mathf.Max(1f, food.m_shared.m_foodBurnTime); _foodElapsed = 0f; ApplyFoodBonus(_foodPeak); _companion.IsFed = true; _companion.FedIcon = ((food.m_shared.m_icons != null && food.m_shared.m_icons.Length != 0) ? food.m_shared.m_icons[0] : null); PlayConsumeEffects(food); } } private void TickFoodBuff(float dt) { if (!(_foodApplied <= 0f) || !(_foodElapsed >= _foodDuration)) { _foodElapsed += dt; if (_foodElapsed >= _foodDuration) { ExpireFood(); return; } float num = _foodElapsed / _foodDuration; float num2 = ((num <= 0.5f) ? 1f : Mathf.Clamp01(1f - (num - 0.5f) / 0.5f)); ApplyFoodBonus(_foodPeak * num2); } } private void ApplyFoodBonus(float target) { if ((Object)(object)_character == (Object)null) { return; } float num = target - _foodApplied; if (!(Mathf.Abs(num) < 0.01f)) { float num2 = Mathf.Max(1f, _character.GetMaxHealth() + num); _character.SetMaxHealth(num2); if (num > 0f) { _character.Heal(num, false); } else if (_character.GetHealth() > num2) { _character.SetHealth(num2); } _foodApplied = target; } } private void ExpireFood() { if (_foodApplied > 0f && (Object)(object)_character != (Object)null) { float num = Mathf.Max(1f, _character.GetMaxHealth() - _foodApplied); _character.SetMaxHealth(num); if (_character.GetHealth() > num) { _character.SetHealth(num); } } _foodApplied = 0f; _foodPeak = 0f; _foodElapsed = 0f; _foodDuration = 0f; if ((Object)(object)_companion != (Object)null) { _companion.IsFed = false; _companion.FedIcon = null; } } } public class CompanionInventoryGui : MonoBehaviour { private static CompanionInventoryGui _instance; private DvergrCompanion _openCompanion; private CompanionInventory _openInventory; private Character _openCharacter; private TMP_InputField _nameField; private TMP_Text _hpText; private bool _cloneFailed; private const int VanillaInventoryHeight = 4; private const float ContainerClearancePx = 22f; private static float _baseContainerY = float.NaN; public static bool IsTyping { get { if ((Object)(object)_instance != (Object)null && (Object)(object)_instance._nameField != (Object)null) { return _instance._nameField.isFocused; } return false; } } public static void Open(DvergrCompanion companion, CompanionInventory inventory) { if (!((Object)(object)_instance == (Object)null) && !((Object)(object)companion == (Object)null) && !((Object)(object)inventory == (Object)null) && !((Object)(object)InventoryGui.instance == (Object)null)) { inventory.EnsureContainer(); inventory.RefreshTitle(); if (!((Object)(object)inventory.Container == (Object)null)) { InventoryGui.instance.Show(inventory.Container, 0); _instance._openCompanion = companion; _instance._openInventory = inventory; _instance._openCharacter = ((Component)companion).GetComponent<Character>(); _instance.BuildWidgets(); _instance.ShowWidgets(show: true); _instance.Refresh(); } } } private void Awake() { _instance = this; } private void Update() { if (!((Object)(object)_openCompanion == (Object)null)) { InventoryGui instance = InventoryGui.instance; if (!((Object)(object)instance != (Object)null) || !InventoryGui.IsVisible() || !((Object)(object)instance.m_currentContainer != (Object)null) || !((Object)(object)_openInventory != (Object)null) || !((Object)(object)instance.m_currentContainer == (Object)(object)_openInventory.Container) || !((Object)(object)_openCharacter != (Object)null) || _openCharacter.IsDead()) { ShowWidgets(show: false); RestoreContainerShift(); _openCompanion = null; _openInventory = null; _openCharacter = null; } else { Refresh(); } } } private void Refresh() { ApplyContainerShift(); if ((Object)(object)_nameField != (Object)null && !_nameField.isFocused) { _nameField.SetTextWithoutNotify(_openCompanion.DisplayName); } if ((Object)(object)_hpText != (Object)null && (Object)(object)_openCharacter != (Object)null) { float num = Mathf.Ceil(_openCharacter.GetHealth()); float num2 = Mathf.Ceil(_openCharacter.GetMaxHealth()); string arg = (_openCompanion.IsFed ? "#FFD24A" : "#FFFFFF"); _hpText.text = $"<color={arg}>HP {num:0} / {num2:0}</color>"; } } private void ApplyContainerShift() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) InventoryGui instance = InventoryGui.instance; Player localPlayer = Player.m_localPlayer; if (!((Object)(object)instance == (Object)null) && !((Object)(object)localPlayer == (Object)null) && !((Object)(object)instance.m_container == (Object)null) && !((Object)(object)instance.m_playerGrid == (Object)null)) { RectTransform container = instance.m_container; if (float.IsNaN(_baseContainerY)) { _baseContainerY = container.anchoredPosition.y; } float num = (float)Mathf.Max(0, ((Humanoid)localPlayer).GetInventory().GetHeight() - 4) * instance.m_playerGrid.m_elementSpace; float num2 = ((num > 0f) ? 22f : 0f); Vector2 anchoredPosition = container.anchoredPosition; anchoredPosition.y = _baseContainerY - num - num2; container.anchoredPosition = anchoredPosition; } } private void RestoreContainerShift() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (!float.IsNaN(_baseContainerY)) { RectTransform val = (((Object)(object)InventoryGui.instance != (Object)null) ? InventoryGui.instance.m_container : null); if (!((Object)(object)val == (Object)null)) { Vector2 anchoredPosition = val.anchoredPosition; anchoredPosition.y = _baseContainerY; val.anchoredPosition = anchoredPosition; } } } private void BuildWidgets() { if (_cloneFailed) { return; } RectTransform val = (((Object)(object)InventoryGui.instance != (Object)null) ? InventoryGui.instance.m_container : null); if ((Object)(object)val == (Object)null) { return; } try { EnsureNameField(val); EnsureHpText(val); } catch (Exception ex) { _cloneFailed = true; Plugin.Log.LogWarning((object)("[inventory] Could not build companion panel widgets: " + ex.Message)); } } private void EnsureNameField(RectTransform panel) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_nameField != (Object)null) { return; } GuiInputField val = (((Object)(object)TextInput.instance != (Object)null) ? TextInput.instance.m_inputField : null); if (!((Object)(object)val == (Object)null)) { GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, (Transform)(object)panel); ((Object)val2).name = "CompanionNameField"; RectTransform component = val2.GetComponent<RectTransform>(); if ((Object)(object)component != (Object)null) { Park(component, new Vector2(18f, -44f), new Vector2(210f, 28f)); } _nameField = val2.GetComponent<TMP_InputField>(); if ((Object)(object)_nameField == (Object)null) { Object.Destroy((Object)(object)val2); return; } ((UnityEventBase)_nameField.onEndEdit).RemoveAllListeners(); ((UnityEvent<string>)(object)_nameField.onEndEdit).AddListener((UnityAction<string>)OnNameSubmitted); _nameField.characterLimit = 24; } } private void EnsureHpText(RectTransform panel) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_hpText != (Object)null) { return; } TMP_Text val = (((Object)(object)InventoryGui.instance != (Object)null) ? InventoryGui.instance.m_containerWeight : null); if (!((Object)(object)val == (Object)null)) { GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, (Transform)(object)panel); ((Object)val2).name = "CompanionHpText"; RectTransform component = val2.GetComponent<RectTransform>(); if ((Object)(object)component != (Object)null) { Park(component, new Vector2(236f, -44f), new Vector2(210f, 28f)); } _hpText = val2.GetComponent<TMP_Text>(); if ((Object)(object)_hpText != (Object)null) { _hpText.alignment = (TextAlignmentOptions)513; _hpText.enableAutoSizing = false; _hpText.fontSize = 18f; _hpText.richText = true; } } } private static void Park(RectTransform rt, Vector2 anchoredPos, Vector2 size) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) rt.anchorMin = new Vector2(0f, 1f); rt.anchorMax = new Vector2(0f, 1f); rt.pivot = new Vector2(0f, 1f); rt.anchoredPosition = anchoredPos; rt.sizeDelta = size; } private void ShowWidgets(bool show) { if ((Object)(object)_nameField != (Object)null) { ((Component)_nameField).gameObject.SetActive(show); } if ((Object)(object)_hpText != (Object)null) { ((Component)_hpText).gameObject.SetActive(show); } } private void OnNameSubmitted(string text) { if (!((Object)(object)_openCompanion == (Object)null) && !string.IsNullOrWhiteSpace(text) && !(text == _openCompanion.DisplayName)) { _openCompanion.SetName(text); if ((Object)(object)_openInventory != (Object)null) { _openInventory.RefreshTitle(); } } } } public class CompanionMapPins : MonoBehaviour { private const float UpdateInterval = 0.25f; private readonly Dictionary<DvergrCompanion, PinData> _pins = new Dictionary<DvergrCompanion, PinData>(); private readonly HashSet<DvergrCompanion> _seen = new HashSet<DvergrCompanion>(); private readonly List<DvergrCompanion> _stale = new List<DvergrCompanion>(); private Minimap _boundMap; private float _timer; private void Update() { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) Minimap instance = Minimap.instance; Player localPlayer = Player.m_localPlayer; if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null || !Plugin.ShowMapPins.Value) { if (_pins.Count > 0) { if ((Object)(object)instance == (Object)null) { _pins.Clear(); } else { RemoveAll(instance); } } _boundMap = instance; return; } if ((Object)(object)_boundMap != (Object)(object)instance) { _pins.Clear(); _boundMap = instance; } _timer += Time.deltaTime; if (_timer < 0.25f) { return; } _timer = 0f; PinType val = PinIcon(); _seen.Clear(); foreach (DvergrCompanion item in DvergrCompanion.All) { if ((Object)(object)item == (Object)null || item.OwnerId == 0L || !item.IsOwner(localPlayer)) { continue; } _seen.Add(item); if (_pins.TryGetValue(item, out var value) && value != null) { value.m_pos = ((Component)item).transform.position; if (value.m_name != item.DisplayName) { value.m_name = item.DisplayName; } if (value.m_type != val) { value.m_type = val; } } else { _pins[item] = instance.AddPin(((Component)item).transform.position, val, item.DisplayName, false, false, 0L, default(PlatformUserID)); } } _stale.Clear(); foreach (KeyValuePair<DvergrCompanion, PinData> pin in _pins) { if (!_seen.Contains(pin.Key)) { _stale.Add(pin.Key); } } foreach (DvergrCompanion item2 in _stale) { if (_pins.TryGetValue(item2, out var value2) && value2 != null) { instance.RemovePin(value2); } _pins.Remove(item2); } } private void RemoveAll(Minimap map) { foreach (KeyValuePair<DvergrCompanion, PinData> pin in _pins) { if (pin.Value != null) { map.RemovePin(pin.Value); } } _pins.Clear(); } private static PinType PinIcon() { return (PinType)(Mathf.Clamp(Plugin.MapPinIcon.Value, 0, 4) switch { 0 => 0, 1 => 1, 2 => 2, 4 => 6, _ => 3, }); } } [HarmonyPatch(typeof(TeleportWorld), "Teleport")] public static class CompanionPortalPatch { public static void Postfix(Player player, bool __runOriginal) { if (__runOriginal && !((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer) && ((Character)player).IsTeleporting()) { CompanionTeleport.FollowOwnerThroughPortal(player); } } } [HarmonyPatch(typeof(TeleportWorld), "Teleport")] public static class CompanionPortalBlockPatch { private static float _lastMsg = -999f; public static bool Prefix(TeleportWorld __instance, Player player) { if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return true; } if ((Object)(object)__instance == (Object)null || ((Object)__instance).name.IndexOf("portal_wood", StringComparison.OrdinalIgnoreCase) < 0) { return true; } if (CompanionTeleport.TryFindPortalBlocker(player, out var companionName, out var itemName)) { if (Time.time - _lastMsg > 2.5f) { _lastMsg = Time.time; ((Character)player).Message((MessageType)2, companionName + " is carrying " + itemName + " — you can't take it through the portal.", 0, (Sprite)null); } return false; } return true; } } internal static class CompanionTeleport { private const float GatherRange = 60f; public static bool TryFindPortalBlocker(Player owner, out string companionName, out string itemName) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) companionName = null; itemName = null; if ((Object)(object)owner == (Object)null) { return false; } long playerID = owner.GetPlayerID(); Vector3 position = ((Component)owner).transform.position; foreach (DvergrCompanion item in DvergrCompanion.All) { if ((Object)(object)item == (Object)null || item.Stance != CompanionStance.Follow || item.OwnerId == 0L || item.OwnerId != playerID || item.ChoreActive || item.DuelMode || item.IsFeral) { continue; } Character component = ((Component)item).GetComponent<Character>(); if ((Object)(object)component == (Object)null || component.IsDead() || Vector3.Distance(((Component)component).transform.position, position) > 60f) { continue; } CompanionInventory component2 = ((Component)item).GetComponent<CompanionInventory>(); Inventory val = (((Object)(object)component2 != (Object)null) ? component2.Inventory : null); if (val == null) { continue; } foreach (ItemData allItem in val.GetAllItems()) { if (allItem?.m_shared != null && !allItem.m_shared.m_teleportable) { companionName = item.DisplayName; itemName = ((Localization.instance != null) ? Localization.instance.Localize(allItem.m_shared.m_name) : allItem.m_shared.m_name); return true; } } } return false; } public static void FollowOwnerThroughPortal(Player owner) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) Vector3 teleportTargetPos = owner.m_teleportTargetPos; Quaternion teleportTargetRot = owner.m_teleportTargetRot; Vector3 teleportFromPos = owner.m_teleportFromPos; long playerID = owner.GetPlayerID(); int num = 0; foreach (DvergrCompanion item in DvergrCompanion.All) { if (!((Object)(object)item == (Object)null) && item.Stance == CompanionStance.Follow && item.OwnerId != 0L && item.OwnerId == playerID && !item.ChoreActive && !item.DuelMode && !item.IsFeral) { Character component = ((Component)item).GetComponent<Character>(); if (!((Object)(object)component == (Object)null) && !component.IsDead() && !(Vector3.Distance(((Component)component).transform.position, teleportFromPos) > 60f)) { TeleportCompanion(component, teleportTargetPos + SpreadOffset(num), teleportTargetRot); num++; } } } if (num > 0) { Plugin.Log.LogInfo((object)$"[portal] Brought {num} companion(s) through the portal for {owner.GetPlayerName()}."); } } private static void TeleportCompanion(Character ch, Vector3 pos, Quaternion rot) { //IL_0030: Unknown result ty