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 The Lyngvi Wardens v1.0.0
TheLyngviWardens.dll
Decompiled 11 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using BepInEx; using HarmonyLib; using Jotunn; using Jotunn.Managers; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Soulbound Companion")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Soulbound Companion")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("1.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] namespace SoulboundCompanion; internal enum WardenRole { Tank, Berserker, Archer } [BepInPlugin("com.forlore.soulboundcompanion", "The Lyngvi Wardens", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] internal class SoulboundCompanionPlugin : BaseUnityPlugin { private sealed class WardenState { public int Slot; public WardenRole Role; public GameObject Object; public MonsterAI AI; public bool Spawned; public float SpawnDelay; public bool RespawnPending; public float RespawnTimer; public long RespawnOwnerId; public bool ReportedPersistentSearch; public float MovementCheckTimer; public float StuckTime; public Vector3 LastPosition; public float PatrolTimer; public Vector3 PatrolAnchor; public bool HasPatrolPoint; public bool WasInCombat; public bool SoftLeashIssued; public WardenState(int slot, WardenRole role) { Slot = slot; Role = role; } } private sealed class ProgressionPower { public int Stage; public int Level; public float ElementalDamage; public string Name; public ProgressionPower(int stage, int level, float elementalDamage, string name) { Stage = stage; Level = level; ElementalDamage = elementalDamage; Name = name; } } [HarmonyPatch(typeof(Character), "OnDeath")] private static class WardenDeathPatch { private static void Prefix(Character __instance) { if ((Object)(object)__instance == (Object)null) { return; } LyngviWardenMarker component = ((Component)__instance).GetComponent<LyngviWardenMarker>(); if ((Object)(object)component == (Object)null) { return; } ZNetView component2 = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component2 == (Object)null || !component2.IsValid()) { return; } ZDO zDO = component2.GetZDO(); if (zDO == null) { return; } long num = zDO.GetLong("SoulboundCompanion_OwnerId", 0L); Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && num == localPlayer.GetPlayerID()) { int slot = zDO.GetInt("SoulboundCompanion_Slot", component.Slot); zDO.Set("SoulboundCompanion_IsSoulbound", false); if ((Object)(object)Instance != (Object)null) { Instance.ScheduleRespawn(slot, num); } } } } [HarmonyPatch(typeof(Character), "Damage", new Type[] { typeof(HitData) })] private static class WardenElementalDamagePatch { private static void Prefix(HitData hit) { if (hit == null || !hit.HaveAttacker()) { return; } Character attacker = hit.GetAttacker(); if ((Object)(object)attacker == (Object)null) { return; } LyngviWardenMarker component = ((Component)attacker).GetComponent<LyngviWardenMarker>(); if ((Object)(object)component == (Object)null) { return; } float elementalDamage = component.ElementalDamage; if (!(elementalDamage <= 0f)) { switch (component.Slot) { case 0: hit.m_damage.m_poison += elementalDamage; break; case 1: hit.m_damage.m_fire += elementalDamage; break; case 2: hit.m_damage.m_frost += elementalDamage; break; } } } } [HarmonyPatch(typeof(MonsterAI), "Awake")] private static class MonsterAIAwakePatch { private static void Postfix(MonsterAI __instance) { if ((Object)(object)__instance == (Object)null) { return; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } ZDO zDO = component.GetZDO(); if (zDO == null || !zDO.GetBool("SoulboundCompanion_IsSoulbound", false)) { return; } int num = zDO.GetInt("SoulboundCompanion_Slot", -1); if (num >= 0 && num <= 2) { WardenRole role = (WardenRole)zDO.GetInt("SoulboundCompanion_Role", num); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && zDO.GetLong("SoulboundCompanion_OwnerId", 0L) == localPlayer.GetPlayerID()) { EnsureWardenState(((Component)__instance).gameObject, num, role, localPlayer); } else { EnsureWardenState(((Component)__instance).gameObject, num, role, null); } } } } public const string PluginGUID = "com.forlore.soulboundcompanion"; public const string PluginName = "The Lyngvi Wardens"; public const string PluginVersion = "1.0.0"; public const string BodvarName = "Bodvar"; public const string StarkadName = "Starkad"; public const string OrvarName = "Orvar"; private const float BodvarBaseHealth = 70f; private const float StarkadBaseHealth = 45f; private const float OrvarBaseHealth = 40f; public const float RespawnDelaySeconds = 20f; public const float RegenerationPercentPerSecond = 0.02f; public const float RegenerationTickInterval = 1f; private const float ProgressionCheckInterval = 2f; private float _progressionCheckTimer; private int _activeProgressionStage = -1; private const float MeleePatrolMinDistance = 8f; private const float MeleePatrolMaxDistance = 14f; private const float ArcherPatrolMinDistance = 11f; private const float ArcherPatrolMaxDistance = 17f; private const float InteriorMeleePatrolMinDistance = 3f; private const float InteriorMeleePatrolMaxDistance = 5f; private const float InteriorArcherPatrolMinDistance = 4f; private const float InteriorArcherPatrolMaxDistance = 6f; private const float PatrolTimeMin = 8f; private const float PatrolTimeMax = 14f; private const float PatrolRecenterDistance = 12f; private const float SoftLeashDistance = 30f; private const float SoftLeashReleaseDistance = 24f; private const float HardTeleportDistance = 70f; private const float StuckCheckDistance = 32f; private const float MovementCheckInterval = 1f; private const float MinimumMovement = 0.35f; private const float StuckTimeBeforeTeleport = 8f; private const float InteriorCheckInterval = 0.25f; private const float InteriorTransferDelay = 0.6f; private const float PostInteriorTransferGrace = 2f; private float _interiorCheckTimer; private bool _hasInteriorState; private bool _playerWasInInterior; private bool _interiorTransferPending; private bool _pendingInteriorState; private float _interiorTransferTimer; private float _postInteriorTransferGraceTimer; private const string BodvarPrefabName = "LyngviWarden_Bodvar"; private const string StarkadPrefabName = "LyngviWarden_Starkad"; private const string OrvarPrefabName = "LyngviWarden_Orvar"; private const string LegacyWarriorPrefabName = "SoulboundCompanion_Warrior"; private const string LegacyArcherPrefabName = "SoulboundCompanion_Archer"; private const string AncientLegacyPrefabName = "Skeleton_NoArcher"; private bool _legacyMigrationDone; private bool _prefabsReady; internal const string ZdoSoulbound = "SoulboundCompanion_IsSoulbound"; internal const string ZdoOwnerId = "SoulboundCompanion_OwnerId"; internal const string ZdoOwnerName = "SoulboundCompanion_OwnerName"; internal const string ZdoSlot = "SoulboundCompanion_Slot"; internal const string ZdoRole = "SoulboundCompanion_Role"; internal const string ZdoScaledLevel = "SoulboundCompanion_ScaledLevel"; internal const string ZdoElementalDamage = "SoulboundCompanion_ElementalDamage"; internal static SoulboundCompanionPlugin Instance; private Harmony _harmony; private Player _currentPlayer; private WardenState[] _wardens; private void Awake() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown Instance = this; _wardens = new WardenState[3] { new WardenState(0, WardenRole.Tank), new WardenState(1, WardenRole.Berserker), new WardenState(2, WardenRole.Archer) }; _harmony = new Harmony("com.forlore.soulboundcompanion"); _harmony.PatchAll(); PrefabManager.OnVanillaPrefabsAvailable += CreateWardenPrefabs; Logger.LogInfo((object)"The Lyngvi Wardens have awakened!"); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } PrefabManager.OnVanillaPrefabsAvailable -= CreateWardenPrefabs; if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void CreateWardenPrefabs() { CreateBodvarPrefab(); CreateStarkadPrefab(); CreateOrvarPrefab(); _prefabsReady = (Object)(object)PrefabManager.Instance.GetPrefab("LyngviWarden_Bodvar") != (Object)null && (Object)(object)PrefabManager.Instance.GetPrefab("LyngviWarden_Starkad") != (Object)null && (Object)(object)PrefabManager.Instance.GetPrefab("LyngviWarden_Orvar") != (Object)null; if (_prefabsReady) { Logger.LogInfo((object)"Bodvar, Starkad and Orvar prefabs are ready."); PrefabManager.OnVanillaPrefabsAvailable -= CreateWardenPrefabs; } } private void CreateBodvarPrefab() { GameObject prefab = PrefabManager.Instance.GetPrefab("LyngviWarden_Bodvar"); if ((Object)(object)prefab != (Object)null) { return; } prefab = PrefabManager.Instance.CreateClonedPrefab("LyngviWarden_Bodvar", "Skeleton_Poison"); if ((Object)(object)prefab == (Object)null) { Logger.LogError((object)"Failed to create Bodvar from Skeleton_Poison."); return; } Humanoid component = prefab.GetComponent<Humanoid>(); Character component2 = prefab.GetComponent<Character>(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null) { Logger.LogError((object)"Bodvar prefab is missing Humanoid/Character."); return; } component.m_defaultItems = (GameObject[])(object)new GameObject[0]; component.m_randomWeapon = ResolvePrefabs("skeleton_mace"); component.m_randomArmor = (GameObject[])(object)new GameObject[0]; component.m_randomShield = ResolvePrefabs("ShieldBronzeBuckler"); component2.m_name = "Bodvar"; component2.m_health = 70f; component2.m_boss = false; DisableDrops(prefab); PrefabManager.Instance.AddPrefab(prefab); Logger.LogInfo((object)"Created Bodvar: Rancid Remains body, mace + bronze buckler."); } private void CreateStarkadPrefab() { GameObject prefab = PrefabManager.Instance.GetPrefab("LyngviWarden_Starkad"); if ((Object)(object)prefab != (Object)null) { return; } prefab = PrefabManager.Instance.CreateClonedPrefab("LyngviWarden_Starkad", "Skeleton_Hildir"); if ((Object)(object)prefab == (Object)null) { Logger.LogError((object)"Failed to create Starkad from Skeleton_Hildir."); return; } Humanoid component = prefab.GetComponent<Humanoid>(); Character component2 = prefab.GetComponent<Character>(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null) { Logger.LogError((object)"Starkad prefab is missing Humanoid/Character."); return; } component.m_defaultItems = (GameObject[])(object)new GameObject[0]; component.m_randomWeapon = ResolvePrefabs("skeleton_sword_hildir"); component.m_randomArmor = (GameObject[])(object)new GameObject[0]; component.m_randomShield = (GameObject[])(object)new GameObject[0]; component2.m_name = "Starkad"; component2.m_health = 45f; component2.m_boss = false; DisableDrops(prefab); PrefabManager.Instance.AddPrefab(prefab); Logger.LogInfo((object)"Created Starkad: burning Brenna body, fixed flaming sword, no fire nova."); } private void CreateOrvarPrefab() { GameObject prefab = PrefabManager.Instance.GetPrefab("LyngviWarden_Orvar"); if ((Object)(object)prefab != (Object)null) { return; } prefab = PrefabManager.Instance.CreateClonedPrefab("LyngviWarden_Orvar", "Skeleton"); if ((Object)(object)prefab == (Object)null) { Logger.LogError((object)"Failed to create Orvar from Skeleton."); return; } Humanoid component = prefab.GetComponent<Humanoid>(); Character component2 = prefab.GetComponent<Character>(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null) { Logger.LogError((object)"Orvar prefab is missing Humanoid/Character."); return; } component.m_defaultItems = (GameObject[])(object)new GameObject[0]; component.m_randomWeapon = ResolvePrefabs("skeleton_bow"); component.m_randomArmor = (GameObject[])(object)new GameObject[0]; component.m_randomShield = (GameObject[])(object)new GameObject[0]; component2.m_name = "Orvar"; component2.m_health = 40f; component2.m_boss = false; DisableDrops(prefab); PrefabManager.Instance.AddPrefab(prefab); Logger.LogInfo((object)"Created Orvar: fixed bow loadout."); } private void DisableDrops(GameObject prefab) { CharacterDrop component = prefab.GetComponent<CharacterDrop>(); if ((Object)(object)component != (Object)null) { component.m_dropsEnabled = false; } } private GameObject[] ResolvePrefabs(params string[] prefabNames) { List<GameObject> list = new List<GameObject>(); foreach (string text in prefabNames) { GameObject prefab = PrefabManager.Instance.GetPrefab(text); if ((Object)(object)prefab != (Object)null) { list.Add(prefab); } else { Logger.LogWarning((object)("Could not resolve prefab '" + text + "'.")); } } return list.ToArray(); } private void Update() { if ((Object)(object)Player.m_localPlayer == (Object)null) { ResetRuntimeStateForNoPlayer(); } else { if (!_prefabsReady) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)_currentPlayer != (Object)(object)localPlayer) { InitializeForPlayer(localPlayer); } if (_legacyMigrationDone || TryMigrateLegacyEntourage(localPlayer)) { UpdateProgressionScaling(localPlayer, forceImmediate: false); UpdateInteriorTracking(localPlayer); UpdatePendingInteriorTransfer(localPlayer); WardenState[] wardens = _wardens; foreach (WardenState state in wardens) { UpdateWardenSlot(state, localPlayer); } } } } private void ResetRuntimeStateForNoPlayer() { _currentPlayer = null; _legacyMigrationDone = false; _activeProgressionStage = -1; _progressionCheckTimer = 0f; _hasInteriorState = false; _interiorTransferPending = false; _interiorTransferTimer = 0f; _postInteriorTransferGraceTimer = 0f; if (_wardens != null) { WardenState[] wardens = _wardens; foreach (WardenState wardenState in wardens) { ClearLoadedInstance(wardenState); wardenState.ReportedPersistentSearch = false; } } } private void InitializeForPlayer(Player player) { //IL_00e4: Unknown result type (might be due to invalid IL or missing references) _currentPlayer = player; _legacyMigrationDone = false; long playerID = player.GetPlayerID(); WardenState[] wardens = _wardens; foreach (WardenState wardenState in wardens) { ClearLoadedInstance(wardenState); wardenState.SpawnDelay = 3f; wardenState.StuckTime = 0f; wardenState.ReportedPersistentSearch = false; wardenState.PatrolTimer = 0f; wardenState.HasPatrolPoint = false; wardenState.WasInCombat = false; wardenState.SoftLeashIssued = false; if (wardenState.RespawnPending && wardenState.RespawnOwnerId != playerID) { wardenState.RespawnPending = false; wardenState.RespawnTimer = 0f; wardenState.RespawnOwnerId = 0L; } } _activeProgressionStage = -1; _progressionCheckTimer = 0f; UpdateProgressionScaling(player, forceImmediate: true); bool flag = Character.InInterior(((Component)player).transform.position); _hasInteriorState = true; _playerWasInInterior = flag; _pendingInteriorState = flag; _interiorTransferPending = false; _interiorTransferTimer = 0f; _interiorCheckTimer = 0f; _postInteriorTransferGraceTimer = 0f; Logger.LogInfo((object)$"Player detected. Interior: {flag}. Preparing the Lyngvi Wardens..."); } private bool TryMigrateLegacyEntourage(Player player) { if ((Object)(object)player == (Object)null || ZDOMan.instance == null) { return false; } long playerID = player.GetPlayerID(); int num = 0; num += RemoveLegacyPrefab("SoulboundCompanion_Warrior", playerID); num += RemoveLegacyPrefab("SoulboundCompanion_Archer", playerID); num += RemoveLegacyPrefab("Skeleton_NoArcher", playerID); _legacyMigrationDone = true; if (num > 0) { Logger.LogInfo((object)$"Migrated from the old Soulbound Companion system. Removed {num} legacy companion(s)."); } return true; } private int RemoveLegacyPrefab(string prefabName, long playerId) { //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) int num = 0; List<ZDO> allZDOsWithPrefab = GetAllZDOsWithPrefab(prefabName); foreach (ZDO item in allZDOsWithPrefab) { if (item == null || !item.IsValid() || !item.GetBool("SoulboundCompanion_IsSoulbound", false) || item.GetLong("SoulboundCompanion_OwnerId", 0L) != playerId) { continue; } item.Set("SoulboundCompanion_IsSoulbound", false); try { GameObject val = null; if ((Object)(object)ZNetScene.instance != (Object)null) { val = ZNetScene.instance.FindInstance(item.m_uid); } if ((Object)(object)val != (Object)null && (Object)(object)ZNetScene.instance != (Object)null) { ZNetScene.instance.Destroy(val); } else { item.SetOwner(ZDOMan.GetSessionID()); ZDOMan.instance.DestroyZDO(item); } num++; } catch (Exception ex) { Logger.LogWarning((object)$"Could not completely destroy legacy ZDO {item.m_uid}: {ex.Message}"); } } return num; } private void UpdateProgressionScaling(Player player, bool forceImmediate) { if ((Object)(object)player == (Object)null) { return; } if (!forceImmediate) { _progressionCheckTimer -= Time.deltaTime; if (_progressionCheckTimer > 0f) { return; } } _progressionCheckTimer = 2f; ProgressionPower progressionPower = GetProgressionPower(player); if (forceImmediate || progressionPower.Stage != _activeProgressionStage) { _activeProgressionStage = progressionPower.Stage; Logger.LogInfo((object)$"Lyngvi Warden progression: {progressionPower.Name} | Level {progressionPower.Level} | Elemental bonus +{progressionPower.ElementalDamage:0}"); ApplyProgressionScalingToLoadedWardens(); } } private static ProgressionPower GetProgressionPower(Player player) { if ((Object)(object)player == (Object)null) { return GetProgressionPowerForStage(0); } List<string> uniqueKeys = player.GetUniqueKeys(); HashSet<string> hashSet = ((uniqueKeys != null) ? new HashSet<string>(uniqueKeys) : new HashSet<string>()); if (hashSet.Contains("defeated_fader")) { return GetProgressionPowerForStage(7); } if (hashSet.Contains("defeated_queen")) { return GetProgressionPowerForStage(6); } if (hashSet.Contains("defeated_goblinking")) { return GetProgressionPowerForStage(5); } if (hashSet.Contains("defeated_dragon")) { return GetProgressionPowerForStage(4); } if (hashSet.Contains("defeated_bonemass")) { return GetProgressionPowerForStage(3); } if (hashSet.Contains("defeated_gdking")) { return GetProgressionPowerForStage(2); } if (hashSet.Contains("defeated_eikthyr")) { return GetProgressionPowerForStage(1); } return GetProgressionPowerForStage(0); } private static ProgressionPower GetProgressionPowerForStage(int stage) { return stage switch { 0 => new ProgressionPower(0, 2, 10f, "Meadows / Unproven"), 1 => new ProgressionPower(1, 5, 15f, "Black Forest / Eikthyr defeated"), 2 => new ProgressionPower(2, 7, 20f, "Swamp / Elder defeated"), 3 => new ProgressionPower(3, 9, 25f, "Mountain / Bonemass defeated"), 4 => new ProgressionPower(4, 11, 30f, "Plains / Moder defeated"), 5 => new ProgressionPower(5, 13, 35f, "Mistlands / Yagluth defeated"), 6 => new ProgressionPower(6, 15, 40f, "Ashlands / Queen defeated"), _ => new ProgressionPower(7, 17, 45f, "Deep North / Fader defeated"), }; } private ProgressionPower GetActiveProgressionPower() { if (_activeProgressionStage < 0) { if ((Object)(object)Player.m_localPlayer != (Object)null) { return GetProgressionPower(Player.m_localPlayer); } return GetProgressionPowerForStage(0); } return GetProgressionPowerForStage(_activeProgressionStage); } private void ApplyProgressionScalingToLoadedWardens() { if (_wardens == null) { return; } WardenState[] wardens = _wardens; foreach (WardenState wardenState in wardens) { if (wardenState.Spawned && !((Object)(object)wardenState.Object == (Object)null)) { ApplyProgressionPower(wardenState.Object, preserveHealthPercentage: true); } } } private void ApplyProgressionPower(GameObject warden, bool preserveHealthPercentage) { if ((Object)(object)warden == (Object)null) { return; } Character component = warden.GetComponent<Character>(); if ((Object)(object)component == (Object)null || component.IsDead()) { return; } ZNetView component2 = warden.GetComponent<ZNetView>(); if ((Object)(object)component2 != (Object)null && component2.IsValid() && !component2.IsOwner()) { LyngviWardenMarker component3 = warden.GetComponent<LyngviWardenMarker>(); ZDO zDO = component2.GetZDO(); if ((Object)(object)component3 != (Object)null && zDO != null) { component3.SetElementalDamage(zDO.GetFloat("SoulboundCompanion_ElementalDamage", 10f)); } return; } ProgressionPower activeProgressionPower = GetActiveProgressionPower(); float num = 1f; float maxHealth = component.GetMaxHealth(); float health = component.GetHealth(); if (preserveHealthPercentage && maxHealth > 0f && health > 0f) { num = Mathf.Clamp01(health / maxHealth); } component.SetLevel(activeProgressionPower.Level); float maxHealth2 = component.GetMaxHealth(); if (preserveHealthPercentage) { component.SetHealth(Mathf.Max(1f, maxHealth2 * num)); } else { component.SetHealth(maxHealth2); } LyngviWardenMarker component4 = warden.GetComponent<LyngviWardenMarker>(); if ((Object)(object)component4 != (Object)null) { component4.SetElementalDamage(activeProgressionPower.ElementalDamage); } if ((Object)(object)component2 != (Object)null && component2.IsValid()) { ZDO zDO2 = component2.GetZDO(); if (zDO2 != null) { zDO2.Set("SoulboundCompanion_ScaledLevel", activeProgressionPower.Level); zDO2.Set("SoulboundCompanion_ElementalDamage", activeProgressionPower.ElementalDamage); } } } private void UpdateInteriorTracking(Player player) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return; } _interiorCheckTimer -= Time.deltaTime; if (!(_interiorCheckTimer > 0f)) { _interiorCheckTimer = 0.25f; bool flag = Character.InInterior(((Component)player).transform.position); if (!_hasInteriorState) { _hasInteriorState = true; _playerWasInInterior = flag; } else if (flag != _playerWasInInterior) { _playerWasInInterior = flag; _pendingInteriorState = flag; _interiorTransferPending = true; _interiorTransferTimer = 0.6f; Logger.LogInfo((object)(flag ? "Player entered an interior. Lyngvi Wardens transfer scheduled." : "Player left an interior. Lyngvi Wardens transfer scheduled.")); } else if (!_interiorTransferPending) { EnsureLoadedWardensMatchInterior(player, flag); } } } private void UpdatePendingInteriorTransfer(Player player) { if (_postInteriorTransferGraceTimer > 0f) { _postInteriorTransferGraceTimer -= Time.deltaTime; } if (_interiorTransferPending) { _interiorTransferTimer -= Time.deltaTime; if (!(_interiorTransferTimer > 0f)) { _interiorTransferPending = false; _interiorTransferTimer = 0f; TransferEntireEntourageAcrossInteriorBoundary(player, _pendingInteriorState); _postInteriorTransferGraceTimer = 2f; } } } private void EnsureLoadedWardensMatchInterior(Player player, bool playerInside) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) WardenState[] wardens = _wardens; foreach (WardenState wardenState in wardens) { if (!wardenState.RespawnPending && !((Object)(object)wardenState.Object == (Object)null)) { bool flag = Character.InInterior(wardenState.Object.transform.position); if (flag != playerInside) { Logger.LogInfo((object)(GetDisplayName(wardenState.Slot) + " is on the wrong side of an interior boundary. Correcting...")); Vector3 returnPosition = GetReturnPosition(player, wardenState.Slot, playerInside); TransferLoadedWarden(wardenState, player, returnPosition); } } } } private void TransferEntireEntourageAcrossInteriorBoundary(Player player, bool targetInside) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return; } long playerID = player.GetPlayerID(); int num = 0; int num2 = 0; WardenState[] wardens = _wardens; foreach (WardenState wardenState in wardens) { if (wardenState.RespawnPending) { continue; } Vector3 returnPosition = GetReturnPosition(player, wardenState.Slot, targetInside); if ((Object)(object)wardenState.Object != (Object)null) { TransferLoadedWarden(wardenState, player, returnPosition); num++; continue; } ZDO val = FindSavedWardenZdo(wardenState, playerID, ((Component)player).transform.position); if (val == null) { wardenState.SpawnDelay = 0.5f; continue; } StampWardenIdentity(val, wardenState, player); GameObject val2 = null; if ((Object)(object)ZNetScene.instance != (Object)null) { val2 = ZNetScene.instance.FindInstance(val.m_uid); } if ((Object)(object)val2 != (Object)null) { AdoptWarden(wardenState, val2, player); TransferLoadedWarden(wardenState, player, returnPosition); num++; continue; } val.SetPosition(returnPosition); val.Set(ZDOVars.s_follow, string.Empty); ZDOMan instance = ZDOMan.instance; if (instance != null) { instance.ForceSendZDO(val.m_uid); } wardenState.SpawnDelay = 0.5f; wardenState.ReportedPersistentSearch = false; num2++; } Logger.LogInfo((object)$"Lyngvi Wardens interior transfer completed. Loaded moved: {num}, saved/unloaded moved: {num2}."); } private void TransferLoadedWarden(WardenState state, Player player, Vector3 targetPosition) { //IL_002e: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)state.Object == (Object)null || (Object)(object)player == (Object)null) { return; } state.Object.transform.position = targetPosition; state.Object.transform.rotation = ((Component)player).transform.rotation; ZNetView component = state.Object.GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { ZDO zDO = component.GetZDO(); if (zDO != null) { StampWardenIdentity(zDO, state, player); zDO.SetPosition(targetPosition); zDO.Set(ZDOVars.s_follow, string.Empty); ZDOMan instance = ZDOMan.instance; if (instance != null) { instance.ForceSendZDO(zDO.m_uid); } } } if ((Object)(object)state.AI == (Object)null) { state.AI = state.Object.GetComponent<MonsterAI>(); } if ((Object)(object)state.AI != (Object)null) { ((Behaviour)state.AI).enabled = true; } state.LastPosition = targetPosition; state.StuckTime = 0f; state.MovementCheckTimer = 1f; state.SoftLeashIssued = false; AssignNewPatrolPoint(state, player, immediate: true); } private bool IsWardenInCombat(WardenState state) { if (state == null || (Object)(object)state.AI == (Object)null) { return false; } BaseAI aI = (BaseAI)(object)state.AI; return aI.IsAlerted() || aI.HaveTarget(); } private void AssignNewPatrolPoint(WardenState state, Player player, bool immediate) { //IL_003c: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) if (state == null || (Object)(object)state.Object == (Object)null || (Object)(object)state.AI == (Object)null || (Object)(object)player == (Object)null) { return; } bool insideInterior = Character.InInterior(((Component)player).transform.position); Vector3 patrolPosition = GetPatrolPosition(player, state.Slot, insideInterior); state.AI.SetFollowTarget((GameObject)null); BaseAI aI = (BaseAI)(object)state.AI; aI.ResetPatrolPoint(); aI.SetPatrolPoint(patrolPosition); ZNetView component = state.Object.GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { ZDO zDO = component.GetZDO(); if (zDO != null) { zDO.Set(ZDOVars.s_follow, string.Empty); } } state.PatrolAnchor = ((Component)player).transform.position; state.HasPatrolPoint = true; state.PatrolTimer = (immediate ? Random.Range(4f, 7f) : Random.Range(8f, 14f)); } private void UpdatePeacefulPatrol(WardenState state, Player player, float distanceFromPlayer) { //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) if (state == null || (Object)(object)state.Object == (Object)null || (Object)(object)state.AI == (Object)null || (Object)(object)player == (Object)null) { return; } if (IsWardenInCombat(state)) { state.WasInCombat = true; state.StuckTime = 0f; return; } if (state.WasInCombat) { state.WasInCombat = false; state.PatrolTimer = 0f; state.SoftLeashIssued = false; } if (distanceFromPlayer <= 24f) { state.SoftLeashIssued = false; } if (distanceFromPlayer > 30f && !state.SoftLeashIssued) { state.SoftLeashIssued = true; AssignNewPatrolPoint(state, player, immediate: true); return; } state.MovementCheckTimer -= Time.deltaTime; if (state.MovementCheckTimer <= 0f) { state.MovementCheckTimer = 1f; float num = Vector3.Distance(state.Object.transform.position, state.LastPosition); if (distanceFromPlayer >= 32f && num < 0.35f) { state.StuckTime += 1f; } else { state.StuckTime = 0f; } state.LastPosition = state.Object.transform.position; if (state.StuckTime >= 8f) { CatchUpToPlayer(state, player, "stuck far from player"); return; } } state.PatrolTimer -= Time.deltaTime; bool flag = !state.HasPatrolPoint || Vector3.Distance(((Component)player).transform.position, state.PatrolAnchor) >= 12f; if (state.PatrolTimer <= 0f || flag) { AssignNewPatrolPoint(state, player, immediate: false); } } private static Vector3 GetPatrolPosition(Player player, int slot, bool insideInterior) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0193: 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_018f: Unknown result type (might be due to invalid IL or missing references) float num; float num2; if (insideInterior) { if (slot == 2) { num = 4f; num2 = 6f; } else { num = 3f; num2 = 5f; } } else if (slot == 2) { num = 11f; num2 = 17f; } else { num = 8f; num2 = 14f; } float num3 = Random.Range(num, num2); float num4 = slot switch { 0 => -90f, 1 => 90f, _ => 180f, } + Random.Range(-65f, 65f); Vector3 val = Quaternion.AngleAxis(num4, Vector3.up) * ((Component)player).transform.forward; val.y = 0f; ((Vector3)(ref val)).Normalize(); Vector3 val2 = ((Component)player).transform.position + val * num3; if (insideInterior) { val2.y = ((Component)player).transform.position.y + 0.1f; return val2; } Vector3 val3 = val2 + Vector3.up * 5f; RaycastHit val4 = default(RaycastHit); if (Physics.Raycast(val3, Vector3.down, ref val4, 15f)) { val2 = ((RaycastHit)(ref val4)).point + Vector3.up * 0.2f; } else { val2.y = ((Component)player).transform.position.y + 0.5f; } return val2; } private void UpdateWardenSlot(WardenState state, Player player) { if (_interiorTransferPending) { return; } if (state.RespawnPending) { state.RespawnTimer -= Time.deltaTime; if (!(state.RespawnTimer > 0f)) { state.RespawnPending = false; state.RespawnTimer = 0f; state.RespawnOwnerId = 0L; Logger.LogInfo((object)(GetDisplayName(state.Slot) + "'s soul has reformed.")); SpawnNewWarden(state, player); } } else if (state.Spawned && (Object)(object)state.Object == (Object)null) { ClearLoadedInstance(state); state.SpawnDelay = 0.5f; } else if (state.Spawned) { UpdateWardenMovement(state, player); } else { state.SpawnDelay -= Time.deltaTime; if (!(state.SpawnDelay > 0f) && !TryReconnectExistingWarden(state, player)) { SpawnNewWarden(state, player); } } } internal void ScheduleRespawn(int slot, long ownerId) { WardenState state = GetState(slot); if (state != null && !state.RespawnPending) { state.RespawnPending = true; state.RespawnTimer = 20f; state.RespawnOwnerId = ownerId; ClearLoadedInstance(state); Logger.LogInfo((object)$"{GetDisplayName(slot)} was destroyed. Soul reforming in {20f} seconds."); } } private WardenState GetState(int slot) { if (_wardens == null) { return null; } WardenState[] wardens = _wardens; foreach (WardenState wardenState in wardens) { if (wardenState.Slot == slot) { return wardenState; } } return null; } private static string GetPrefabNameForSlot(int slot) { return slot switch { 0 => "LyngviWarden_Bodvar", 1 => "LyngviWarden_Starkad", 2 => "LyngviWarden_Orvar", _ => "LyngviWarden_Bodvar", }; } private List<ZDO> GetCandidateZdosForState(WardenState state) { return GetAllZDOsWithPrefab(GetPrefabNameForSlot(state.Slot)); } private ZDO FindSavedWardenZdo(WardenState state, long playerId, Vector3 referencePosition) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) List<ZDO> candidateZdosForState = GetCandidateZdosForState(state); ZDO result = null; float num = float.MaxValue; foreach (ZDO item in candidateZdosForState) { if (DoesZdoBelongToSlot(item, state, playerId)) { float num2 = Vector3.Distance(item.GetPosition(), referencePosition); if (num2 < num) { num = num2; result = item; } } } return result; } private bool TryReconnectExistingWarden(WardenState state, Player player) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null) { state.SpawnDelay = 1f; return true; } long playerID = player.GetPlayerID(); bool flag = Character.InInterior(((Component)player).transform.position); LyngviWardenMarker[] array = Object.FindObjectsByType<LyngviWardenMarker>((FindObjectsSortMode)0); LyngviWardenMarker[] array2 = array; foreach (LyngviWardenMarker lyngviWardenMarker in array2) { if ((Object)(object)lyngviWardenMarker == (Object)null) { continue; } ZNetView component = ((Component)lyngviWardenMarker).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { continue; } ZDO zDO = component.GetZDO(); if (!DoesZdoBelongToSlot(zDO, state, playerID)) { continue; } Character component2 = ((Component)lyngviWardenMarker).GetComponent<Character>(); if (!((Object)(object)component2 != (Object)null) || !component2.IsDead()) { StampWardenIdentity(zDO, state, player); AdoptWarden(state, ((Component)lyngviWardenMarker).gameObject, player); bool flag2 = Character.InInterior(((Component)lyngviWardenMarker).transform.position); if (flag2 != flag) { Vector3 returnPosition = GetReturnPosition(player, state.Slot, flag); TransferLoadedWarden(state, player, returnPosition); } return true; } } List<ZDO> candidateZdosForState = GetCandidateZdosForState(state); ZDO val = null; int num = 0; float num2 = float.MaxValue; foreach (ZDO item in candidateZdosForState) { if (DoesZdoBelongToSlot(item, state, playerID)) { num++; float num3 = Vector3.Distance(item.GetPosition(), ((Component)player).transform.position); if (num3 < num2) { num2 = num3; val = item; } } } if (num > 1) { Logger.LogWarning((object)$"Found {num} saved copies of {GetDisplayName(state.Slot)}. Using the closest."); } if (val == null) { return false; } StampWardenIdentity(val, state, player); GameObject val2 = ZNetScene.instance.FindInstance(val.m_uid); if ((Object)(object)val2 != (Object)null) { AdoptWarden(state, val2, player); bool flag3 = Character.InInterior(val2.transform.position); if (flag3 != flag) { Vector3 returnPosition2 = GetReturnPosition(player, state.Slot, flag); TransferLoadedWarden(state, player, returnPosition2); } return true; } Vector3 returnPosition3 = GetReturnPosition(player, state.Slot, flag); val.SetPosition(returnPosition3); val.Set(ZDOVars.s_follow, string.Empty); ZDOMan.instance.ForceSendZDO(val.m_uid); if (!state.ReportedPersistentSearch) { Logger.LogInfo((object)("Saved " + GetDisplayName(state.Slot) + " found. Calling them back...")); state.ReportedPersistentSearch = true; } state.SpawnDelay = 0.5f; return true; } private static bool DoesZdoBelongToSlot(ZDO zdo, WardenState state, long playerId) { if (zdo == null || !zdo.IsValid()) { return false; } if (!zdo.GetBool("SoulboundCompanion_IsSoulbound", false)) { return false; } if (zdo.GetLong("SoulboundCompanion_OwnerId", 0L) != playerId) { return false; } return zdo.GetInt("SoulboundCompanion_Slot", -1) == state.Slot; } private static void StampWardenIdentity(ZDO zdo, WardenState state, Player player) { if (zdo != null) { zdo.Set("SoulboundCompanion_IsSoulbound", true); zdo.Set("SoulboundCompanion_Slot", state.Slot); zdo.Set("SoulboundCompanion_Role", (int)state.Role); if ((Object)(object)player != (Object)null) { zdo.Set("SoulboundCompanion_OwnerId", player.GetPlayerID()); zdo.Set("SoulboundCompanion_OwnerName", player.GetPlayerName()); } zdo.Set(ZDOVars.s_follow, string.Empty); zdo.Set(ZDOVars.s_tamed, true); zdo.Persistent = true; } } private static List<ZDO> GetAllZDOsWithPrefab(string prefabName) { List<ZDO> list = new List<ZDO>(); if (ZDOMan.instance == null) { return list; } List<ZDO> list2 = new List<ZDO>(); int num = 0; bool flag = false; while (!flag) { list2.Clear(); flag = ZDOMan.instance.GetAllZDOsWithPrefabIterative(prefabName, list2, ref num); foreach (ZDO item in list2) { if (item != null) { list.Add(item); } } } return list; } private void SpawnNewWarden(WardenState state, Player player) { //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_009e: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return; } string prefabNameForSlot = GetPrefabNameForSlot(state.Slot); GameObject prefab = PrefabManager.Instance.GetPrefab(prefabNameForSlot); if ((Object)(object)prefab == (Object)null) { Logger.LogError((object)("Could not find prefab '" + prefabNameForSlot + "' for " + GetDisplayName(state.Slot) + ".")); state.SpawnDelay = 5f; return; } bool insideInterior = Character.InInterior(((Component)player).transform.position); Vector3 returnPosition = GetReturnPosition(player, state.Slot, insideInterior); GameObject val = Object.Instantiate<GameObject>(prefab, returnPosition, ((Component)player).transform.rotation); if ((Object)(object)val == (Object)null) { state.SpawnDelay = 5f; return; } ZNetView component = val.GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { Object.Destroy((Object)(object)val); state.SpawnDelay = 5f; return; } ZDO zDO = component.GetZDO(); if (zDO == null) { Object.Destroy((Object)(object)val); state.SpawnDelay = 5f; return; } component.m_persistent = true; StampWardenIdentity(zDO, state, player); EnsureWardenState(val, state.Slot, state.Role, player); AdoptWarden(state, val, player); ProgressionPower activeProgressionPower = GetActiveProgressionPower(); Logger.LogInfo((object)$"{GetDisplayName(state.Slot)} manifested at {activeProgressionPower.Name}: level {activeProgressionPower.Level}, elemental bonus +{activeProgressionPower.ElementalDamage:0}."); } private static void EnsureWardenState(GameObject warden, int slot, WardenRole role, Player player) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)warden == (Object)null) { return; } Character component = warden.GetComponent<Character>(); MonsterAI component2 = warden.GetComponent<MonsterAI>(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null) { return; } component.m_name = GetDisplayName(slot); component.m_faction = (Faction)0; component.m_tamed = true; component.SetTamed(true); component.m_boss = false; LyngviWardenMarker lyngviWardenMarker = warden.GetComponent<LyngviWardenMarker>(); if ((Object)(object)lyngviWardenMarker == (Object)null) { lyngviWardenMarker = warden.AddComponent<LyngviWardenMarker>(); } lyngviWardenMarker.Configure(slot, role); CharacterDrop component3 = warden.GetComponent<CharacterDrop>(); if ((Object)(object)component3 != (Object)null) { component3.m_dropsEnabled = false; } ZNetView component4 = warden.GetComponent<ZNetView>(); if ((Object)(object)component4 != (Object)null && component4.IsValid()) { ZDO zDO = component4.GetZDO(); if (zDO != null) { component4.m_persistent = true; zDO.Persistent = true; zDO.Set("SoulboundCompanion_IsSoulbound", true); zDO.Set("SoulboundCompanion_Slot", slot); zDO.Set("SoulboundCompanion_Role", (int)role); zDO.Set(ZDOVars.s_tamed, true); zDO.Set(ZDOVars.s_follow, string.Empty); if ((Object)(object)player != (Object)null) { zDO.Set("SoulboundCompanion_OwnerId", player.GetPlayerID()); zDO.Set("SoulboundCompanion_OwnerName", player.GetPlayerName()); } lyngviWardenMarker.SetElementalDamage(zDO.GetFloat("SoulboundCompanion_ElementalDamage", 10f)); } } if ((Object)(object)Instance != (Object)null) { Instance.ApplyProgressionPower(warden, preserveHealthPercentage: true); } ((Behaviour)component2).enabled = true; component2.SetFollowTarget((GameObject)null); } private void AdoptWarden(WardenState state, GameObject warden, Player player) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) state.Object = warden; state.AI = warden.GetComponent<MonsterAI>(); if ((Object)(object)state.AI == (Object)null) { state.Spawned = false; return; } EnsureWardenState(warden, state.Slot, state.Role, player); state.LastPosition = warden.transform.position; state.MovementCheckTimer = 1f; state.StuckTime = 0f; state.Spawned = true; state.ReportedPersistentSearch = false; state.WasInCombat = false; state.SoftLeashIssued = false; state.HasPatrolPoint = false; AssignNewPatrolPoint(state, player, immediate: true); } private static void ClearLoadedInstance(WardenState state) { state.Object = null; state.AI = null; state.Spawned = false; state.StuckTime = 0f; state.MovementCheckTimer = 0f; state.HasPatrolPoint = false; state.PatrolTimer = 0f; state.WasInCombat = false; state.SoftLeashIssued = false; } private void UpdateWardenMovement(WardenState state, Player player) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)state.Object == (Object)null || (Object)(object)state.AI == (Object)null || (Object)(object)player == (Object)null || _postInteriorTransferGraceTimer > 0f) { return; } bool flag = Character.InInterior(((Component)player).transform.position); bool flag2 = Character.InInterior(state.Object.transform.position); if (flag != flag2) { Vector3 returnPosition = GetReturnPosition(player, state.Slot, flag); TransferLoadedWarden(state, player, returnPosition); return; } float num = Vector3.Distance(state.Object.transform.position, ((Component)player).transform.position); if (num >= 70f) { CatchUpToPlayer(state, player, "more than 70 m away"); } else { UpdatePeacefulPatrol(state, player, num); } } private void CatchUpToPlayer(WardenState state, Player player, string reason) { //IL_0007: 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_0023: Unknown result type (might be due to invalid IL or missing references) bool insideInterior = Character.InInterior(((Component)player).transform.position); Vector3 patrolPosition = GetPatrolPosition(player, state.Slot, insideInterior); TransferLoadedWarden(state, player, patrolPosition); Logger.LogInfo((object)(GetDisplayName(state.Slot) + " caught up because they were " + reason + ".")); } private static Vector3 GetReturnPosition(Player player, int slot, bool insideInterior) { //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: 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_0032: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: 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_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: 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) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: 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_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) if (insideInterior) { return (Vector3)(slot switch { 0 => ((Component)player).transform.position - ((Component)player).transform.forward * 1.5f - ((Component)player).transform.right * 0.9f, 1 => ((Component)player).transform.position - ((Component)player).transform.forward * 1.5f + ((Component)player).transform.right * 0.9f, _ => ((Component)player).transform.position - ((Component)player).transform.forward * 2.5f, }) + Vector3.up * 0.1f; } Vector3 val = (Vector3)(slot switch { 0 => ((Component)player).transform.position - ((Component)player).transform.forward * 3f - ((Component)player).transform.right * 2.5f, 1 => ((Component)player).transform.position - ((Component)player).transform.forward * 3f + ((Component)player).transform.right * 2.5f, _ => ((Component)player).transform.position - ((Component)player).transform.forward * 5f, }); Vector3 val2 = val + Vector3.up * 5f; RaycastHit val3 = default(RaycastHit); return (!Physics.Raycast(val2, Vector3.down, ref val3, 15f)) ? (val + Vector3.up * 0.5f) : (((RaycastHit)(ref val3)).point + Vector3.up * 0.2f); } internal static string GetDisplayName(int slot) { return slot switch { 0 => "Bodvar", 1 => "Starkad", 2 => "Orvar", _ => "Lyngvi Warden", }; } } internal class LyngviWardenMarker : MonoBehaviour { private Character _character; private ZNetView _nview; private float _regenerationTimer; public int Slot { get; private set; } = -1; public WardenRole Role { get; private set; } = WardenRole.Tank; public float ElementalDamage { get; private set; } = 10f; private void Awake() { _character = ((Component)this).GetComponent<Character>(); _nview = ((Component)this).GetComponent<ZNetView>(); _regenerationTimer = 1f; } public void Configure(int slot, WardenRole role) { Slot = slot; Role = role; if ((Object)(object)_character == (Object)null) { _character = ((Component)this).GetComponent<Character>(); } if ((Object)(object)_nview == (Object)null) { _nview = ((Component)this).GetComponent<ZNetView>(); } if ((Object)(object)_nview != (Object)null && _nview.IsValid()) { ZDO zDO = _nview.GetZDO(); if (zDO != null) { ElementalDamage = zDO.GetFloat("SoulboundCompanion_ElementalDamage", ElementalDamage); } } } public void SetElementalDamage(float damage) { ElementalDamage = damage; } private void Update() { if ((Object)(object)_character == (Object)null || _character.IsDead() || ((Object)(object)_nview != (Object)null && _nview.IsValid() && !_nview.IsOwner())) { return; } _regenerationTimer -= Time.deltaTime; if (!(_regenerationTimer > 0f)) { _regenerationTimer = 1f; float maxHealth = _character.GetMaxHealth(); float health = _character.GetHealth(); if (!(maxHealth <= 0f) && !(health <= 0f) && !(health >= maxHealth)) { float num = maxHealth * 0.02f; _character.SetHealth(Mathf.Min(maxHealth, health + num)); } } } }