using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_guiutils")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("Valheim Overhaul")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Consumable Hearthstone that channels you back to your bound bed. Comfort tool, not a portal replacement.")] [assembly: AssemblyFileVersion("1.2.0.0")] [assembly: AssemblyInformationalVersion("1.2.0")] [assembly: AssemblyProduct("Hearthstone")] [assembly: AssemblyTitle("Hearthstone")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.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 Hearthstone { internal static class HearthstoneCaster { internal const string ProgressToken = "$hud_hearthstone_casting"; private static ItemData _activeItem; private static float _vfxTimer; private static float _startedAt; private static GameObject _vfxPrefab; internal static bool IsCasting => _activeItem != null; internal static bool TryBegin(Player player, ItemData item) { //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_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_013b: 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_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Expected O, but got Unknown if (!HearthstoneConfig.EnableMod.Value || (Object)(object)player == (Object)null || item == null) { return false; } if ((Object)(object)player != (Object)(object)Player.m_localPlayer) { return false; } if (IsCasting) { return false; } if (((Character)player).IsDead() || ((Character)player).InCutscene() || ((Character)player).IsTeleporting()) { return false; } if (!HearthstoneItem.IsHearthstone(item)) { return false; } if (!HearthstoneItem.IsOwnedBy(item, player)) { ((Character)player).Message((MessageType)2, "$msg_hearthstone_notowner", 0, (Sprite)null); return false; } if (HearthstoneCooldown.IsOnCooldown(player, out var remainingSeconds)) { ((Character)player).Message((MessageType)2, Localization.instance.Localize("$msg_hearthstone_cooldown", new string[1] { HearthstoneCooldown.FormatRemaining(remainingSeconds) }), 0, (Sprite)null); return false; } if (!HearthstoneTeleport.TryGetDestination(player, out var _, out var failToken)) { ((Character)player).Message((MessageType)2, failToken ?? "$msg_hearthstone_nobed", 0, (Sprite)null); return false; } if (!HearthstoneTeleport.CanTeleportInventory(player, out var failToken2)) { ((Character)player).Message((MessageType)2, failToken2 ?? "$msg_noteleport", 0, (Sprite)null); return false; } HearthstoneItem.ClaimOwnership(item, player); ((Humanoid)player).ClearActionQueue(); StopActionAnimation(player); if ((Object)(object)InventoryGui.instance != (Object)null && InventoryGui.IsVisible()) { InventoryGui.instance.Hide(); } float duration = Mathf.Max(0.51f, HearthstoneConfig.CastTime.Value); MinorActionData item2 = new MinorActionData { m_item = item, m_type = (ActionType)2, m_duration = duration, m_time = 0f, m_progressText = "$hud_hearthstone_casting", m_animation = string.Empty }; player.m_actionQueue.Add(item2); _activeItem = item; _vfxTimer = 0f; _startedAt = Time.time; PlayWishbonePulse(player); return true; } internal static void Cancel(Player player, bool showMessage) { if (!IsCasting && ((Object)(object)player == (Object)null || !HasQueuedCast(player))) { return; } ItemData activeItem = _activeItem; _activeItem = null; _vfxTimer = 0f; if ((Object)(object)player != (Object)null) { if (activeItem != null) { ((Humanoid)player).RemoveEquipAction(activeItem); } else { RemoveQueuedCast(player); } StopActionAnimation(player); if (showMessage) { ((Character)player).Message((MessageType)2, "$msg_hearthstone_cancelled", 0, (Sprite)null); } } } internal static bool IsOurAction(MinorActionData action) { if (action != null && action.m_progressText == "$hud_hearthstone_casting") { return HearthstoneItem.IsHearthstone(action.m_item); } return false; } internal static bool HasQueuedCast(Player player) { if (player?.m_actionQueue == null) { return false; } foreach (MinorActionData item in player.m_actionQueue) { if (IsOurAction(item)) { return true; } } return false; } internal static bool TryUpdateActionQueue(Player player, float dt) { if ((Object)(object)player == (Object)null || player.m_actionQueue == null || player.m_actionQueue.Count == 0) { return false; } MinorActionData val = player.m_actionQueue[0]; if (!IsOurAction(val)) { return false; } if (player.m_actionQueuePause > 0f) { player.m_actionQueuePause -= dt; return true; } if (((Character)player).InAttack()) { return true; } val.m_time += dt; if (val.m_time <= val.m_duration) { return true; } ItemData item = val.m_item; player.m_actionQueue.RemoveAt(0); player.m_actionQueuePause = 0.05f; CompleteFromActionQueue(player, item); return true; } internal static void Update(Player player, float dt) { if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || (!IsCasting && !HasQueuedCast(player))) { return; } if (!HearthstoneConfig.EnableMod.Value || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || _activeItem == null || !((Humanoid)player).GetInventory().ContainsItem(_activeItem)) { Cancel(player, showMessage: false); return; } if (!HasQueuedCast(player)) { _activeItem = null; StopActionAnimation(player); return; } if (Time.time - _startedAt > 0.35f && ShouldCancel(player)) { Cancel(player, showMessage: true); return; } _vfxTimer += dt; if (_vfxTimer >= 1.25f) { _vfxTimer = 0f; PlayWishbonePulse(player); } } internal static void CompleteFromActionQueue(Player player, ItemData item) { _activeItem = null; _vfxTimer = 0f; StopActionAnimation(player); if (!((Object)(object)player == (Object)null) && item != null && ((Humanoid)player).GetInventory().ContainsItem(item) && HearthstoneTeleport.TryTeleport(player)) { HearthstoneItem.ConsumeOneUse(player, item); HearthstoneCooldown.Start(player); PlayWishbonePulse(player); } } internal static void EnsureActionBarVisible(Player player) { if (!IsCasting || (Object)(object)player == (Object)null || (Object)(object)Hud.instance == (Object)null) { return; } string text = default(string); float value = default(float); MinorActionData val = default(MinorActionData); player.GetActionProgress(ref text, ref value, ref val); if (val == null || !IsOurAction(val)) { text = "$hud_hearthstone_casting"; if (_activeItem != null && player.m_actionQueue != null) { foreach (MinorActionData item in player.m_actionQueue) { if (IsOurAction(item)) { value = ((item.m_duration > 0f) ? Mathf.Clamp01(item.m_time / item.m_duration) : 0f); val = item; break; } } } } if (val != null && !(val.m_duration <= 0.5f)) { Hud.instance.m_actionBarRoot.SetActive(true); Hud.instance.m_actionProgress.SetValue(value); Hud.instance.m_actionName.text = Localization.instance.Localize(string.IsNullOrEmpty(text) ? "$hud_hearthstone_casting" : text); } } private static void RemoveQueuedCast(Player player) { if (player?.m_actionQueue == null) { return; } for (int num = player.m_actionQueue.Count - 1; num >= 0; num--) { if (IsOurAction(player.m_actionQueue[num])) { player.m_actionQueue.RemoveAt(num); } } } private static void StopActionAnimation(Player player) { if ((Object)(object)((Character)(player?)).m_zanim == (Object)null) { return; } if (!string.IsNullOrEmpty(player.m_actionAnimation)) { ((Character)player).m_zanim.SetBool(player.m_actionAnimation, false); player.m_actionAnimation = null; } try { ((Character)player).m_zanim.SetBool("equipping", false); } catch { } } private static bool ShouldCancel(Player player) { if (HearthstoneConfig.CancelOnDodge.Value && ((Character)player).InDodge()) { return true; } if (HearthstoneConfig.CancelOnJump.Value && IsJumping(player)) { return true; } if (HearthstoneConfig.CancelOnMove.Value && IsMoving(player)) { return true; } return false; } private static bool IsMoving(Player player) { //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) Vector3 moveDir = ((Character)player).GetMoveDir(); if (((Vector3)(ref moveDir)).sqrMagnitude > 0.01f) { return true; } try { if (ZInput.GetButton("Forward") || ZInput.GetButton("Backward") || ZInput.GetButton("Left") || ZInput.GetButton("Right") || ZInput.GetButton("JoyForward") || ZInput.GetButton("JoyBackward") || ZInput.GetButton("JoyLeft") || ZInput.GetButton("JoyRight")) { return true; } } catch { } return ((Character)player).IsRunning(); } private static bool IsJumping(Player player) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (!((Character)player).IsOnGround() && ((Character)player).GetVelocity().y > 0.5f) { return true; } try { if (ZInput.GetButtonDown("Jump") || ZInput.GetButtonDown("JoyJump")) { return true; } } catch { } return false; } private static void PlayWishbonePulse(Player player) { //IL_0050: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player == (Object)null)) { if ((Object)(object)_vfxPrefab == (Object)null && (Object)(object)ZNetScene.instance != (Object)null) { _vfxPrefab = ZNetScene.instance.GetPrefab("vfx_WishbonePing"); } if ((Object)(object)_vfxPrefab != (Object)null) { Object.Instantiate(_vfxPrefab, ((Component)player).transform.position + Vector3.up * 0.5f, Quaternion.identity); } } } } internal static class HearthstoneConfig { internal static ConfigEntry EnableMod; internal static ConfigEntry Uses; internal static ConfigEntry CastTime; internal static ConfigEntry CooldownMinutes; internal static ConfigEntry Weight; internal static ConfigEntry RequireBoundBed; internal static ConfigEntry CancelOnDamage; internal static ConfigEntry CancelOnDodge; internal static ConfigEntry CancelOnJump; internal static ConfigEntry CancelOnMove; internal static ConfigEntry AllowTeleportWithRestrictedItems; internal static void Bind(ConfigFile config) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Expected O, but got Unknown EnableMod = config.Bind("General", "Enable Mod", true, "Enable or disable the Hearthstone mod."); Uses = config.Bind("Hearthstone", "Uses", 10, new ConfigDescription("Number of successful teleports before the Hearthstone is destroyed.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 100), Array.Empty())); CastTime = config.Bind("Hearthstone", "Cast Time", 10f, new ConfigDescription("Channel duration in seconds before teleporting.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 60f), Array.Empty())); CooldownMinutes = config.Bind("Hearthstone", "Cooldown Minutes", 7f, new ConfigDescription("Cooldown after a successful teleport, in minutes. Persists across logout.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 120f), Array.Empty())); Weight = config.Bind("Hearthstone", "Weight", 0.2f, new ConfigDescription("Item weight.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 20f), Array.Empty())); RequireBoundBed = config.Bind("Hearthstone", "Require Bound Bed", true, "If true, casting requires a currently bound bed (same spawn used on death)."); CancelOnDamage = config.Bind("Hearthstone", "Cancel On Damage", true, "Cancel channeling when taking damage. Does not consume a use or start cooldown."); CancelOnDodge = config.Bind("Hearthstone", "Cancel On Dodge", true, "Cancel channeling when dodging / rolling."); CancelOnJump = config.Bind("Hearthstone", "Cancel On Jump", true, "Cancel channeling when jumping."); CancelOnMove = config.Bind("Hearthstone", "Cancel On Move", true, "Cancel channeling when walking, running, or otherwise moving."); AllowTeleportWithRestrictedItems = config.Bind("Hearthstone", "Allow Teleport With Restricted Items", false, "If false (default), uses Inventory.IsTeleportable() exactly like portals — including Adventure Backpacks. If true, bypasses that check."); } } internal static class HearthstoneCooldown { internal static bool IsOnCooldown(Player player, out float remainingSeconds) { remainingSeconds = 0f; if (player?.m_customData == null) { return false; } if (!player.m_customData.TryGetValue("valheimoverhaul.hearthstone.cooldownUntil", out var value) || string.IsNullOrEmpty(value)) { return false; } if (!long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return false; } long ticks = DateTime.UtcNow.Ticks; if (result <= ticks) { player.m_customData.Remove("valheimoverhaul.hearthstone.cooldownUntil"); return false; } remainingSeconds = (float)TimeSpan.FromTicks(result - ticks).TotalSeconds; return remainingSeconds > 0f; } internal static void Start(Player player) { if (player?.m_customData != null) { float num = Math.Max(0f, HearthstoneConfig.CooldownMinutes.Value); if (num <= 0f) { player.m_customData.Remove("valheimoverhaul.hearthstone.cooldownUntil"); return; } DateTime dateTime = DateTime.UtcNow.AddMinutes(num); player.m_customData["valheimoverhaul.hearthstone.cooldownUntil"] = dateTime.Ticks.ToString(CultureInfo.InvariantCulture); } } internal static string FormatRemaining(float seconds) { if (seconds < 0f) { seconds = 0f; } int num = (int)Math.Ceiling(seconds); int num2 = num / 60; int num3 = num % 60; if (num2 <= 0) { return string.Format(CultureInfo.InvariantCulture, "{0}s", num3); } return string.Format(CultureInfo.InvariantCulture, "{0}m {1:D2}s", num2, num3); } internal static string FormatCompact(float seconds) { if (seconds < 0f) { seconds = 0f; } int num = (int)Math.Ceiling(seconds); int num2 = num / 60; int num3 = num % 60; if (num2 <= 0) { return string.Format(CultureInfo.InvariantCulture, "{0}", num3); } return string.Format(CultureInfo.InvariantCulture, "{0}:{1:D2}", num2, num3); } } internal static class HearthstoneItem { internal static GameObject Prefab; internal static Recipe Recipe; private static bool _prefabCreated; private static readonly string[] MeshPrefabCandidates = new string[7] { "SurtlingCore", "Thunderstone", "Crystal", "Ruby", "Amber", "Flint", "Wishbone" }; internal static bool IsHearthstone(ItemData item) { if (item?.m_shared == null) { return false; } if (item.m_shared.m_name == "$item_hearthstone") { return true; } if ((Object)(object)item.m_dropPrefab != (Object)null && !((object)item.m_dropPrefab).Equals((object?)null)) { return ((Object)item.m_dropPrefab).name == "VO_Hearthstone"; } return false; } internal static int CountInInventory(Player player) { if (((player != null) ? ((Humanoid)player).GetInventory() : null) == null) { return 0; } int num = 0; foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems()) { if (IsHearthstone(allItem)) { num++; } } return num; } internal static bool IsOwnedBy(ItemData item, Player player) { if (item == null || (Object)(object)player == (Object)null) { return false; } if (item.m_crafterID == 0L) { return true; } return item.m_crafterID == player.GetPlayerID(); } internal static void ClaimOwnership(ItemData item, Player player) { if (item != null && !((Object)(object)player == (Object)null) && item.m_crafterID == 0L) { item.m_crafterID = player.GetPlayerID(); item.m_crafterName = player.GetPlayerName(); } } internal static void TryRegister(ObjectDB odb) { if ((Object)(object)odb == (Object)null || !IsObjectDbReady(odb)) { return; } try { SanitizeObjectDb(odb); if ((Object)(object)Prefab == (Object)null || ((object)Prefab).Equals((object?)null)) { Prefab = FindExisting(odb); _prefabCreated = (Object)(object)Prefab != (Object)null; } if ((Object)(object)Prefab != (Object)null && !((object)Prefab).Equals((object?)null) && ShouldRebuildPrefab(odb)) { odb.m_items.Remove(Prefab); Object.Destroy((Object)(object)Prefab); Prefab = null; _prefabCreated = false; } if ((Object)(object)Prefab == (Object)null || ((object)Prefab).Equals((object?)null)) { if (!CreatePrefab(odb)) { return; } } else { ItemDrop component = Prefab.GetComponent(); if (component?.m_itemData != null) { EnsureUniqueShared(component); ApplyItemStats(component.m_itemData.m_shared); component.m_itemData.m_dropPrefab = Prefab; ((Object)component).name = "VO_Hearthstone"; ((Object)Prefab).name = "VO_Hearthstone"; } if (!odb.m_items.Contains(Prefab)) { odb.m_items.Add(Prefab); } } EnsureRecipe(odb); RegisterInLookups(odb); if ((Object)(object)ZNetScene.instance != (Object)null) { TryRegisterZNetScene(ZNetScene.instance); } } catch (Exception ex) { Plugin.Log.LogError((object)("TryRegister failed (non-fatal): " + ex)); } } internal static void TryRegisterZNetScene(ZNetScene scene) { if ((Object)(object)scene == (Object)null || (Object)(object)Prefab == (Object)null || ((object)Prefab).Equals((object?)null)) { return; } int stableHashCode = StringExtensionMethods.GetStableHashCode("VO_Hearthstone"); if (scene.m_namedPrefabs == null || !scene.m_namedPrefabs.ContainsKey(stableHashCode)) { if (scene.m_prefabs != null && !scene.m_prefabs.Contains(Prefab)) { scene.m_prefabs.Add(Prefab); } if (scene.m_namedPrefabs != null) { scene.m_namedPrefabs[stableHashCode] = Prefab; } } } internal static void UnlockKnownRecipe(Player player) { if (player?.m_knownRecipes != null && !player.m_knownRecipes.Contains("$item_hearthstone")) { player.m_knownRecipes.Add("$item_hearthstone"); } } internal static void EnsureAvailable(Player player, List available) { if ((Object)(object)player == (Object)null || available == null || (Object)(object)Recipe == (Object)null || (Object)(object)Recipe.m_item == (Object)null) { return; } UnlockKnownRecipe(player); if ((Object)(object)Recipe.m_craftingStation == (Object)null && (Object)(object)ObjectDB.instance != (Object)null) { EnsureRecipe(ObjectDB.instance); } if ((Object)(object)Recipe.m_craftingStation == (Object)null) { Plugin.Log.LogWarning((object)"Hearthstone recipe still has no crafting station."); return; } CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); if ((Object)(object)currentCraftingStation == (Object)null || !IsWorkbenchStation(currentCraftingStation)) { return; } if ((Object)(object)Recipe.m_craftingStation == (Object)null || Recipe.m_craftingStation.m_name != currentCraftingStation.m_name) { Recipe.m_craftingStation = currentCraftingStation; } for (int i = 0; i < available.Count; i++) { if ((Object)(object)available[i] == (Object)(object)Recipe || ((Object)(object)available[i] != (Object)null && (Object)(object)available[i].m_item != (Object)null && available[i].m_item.m_itemData != null && available[i].m_item.m_itemData.m_shared != null && available[i].m_item.m_itemData.m_shared.m_name == "$item_hearthstone")) { return; } } available.Add(Recipe); Plugin.Log.LogInfo((object)("Injected Hearthstone into craft list at station " + currentCraftingStation.m_name)); } private static bool IsWorkbenchStation(CraftingStation station) { if ((Object)(object)station == (Object)null) { return false; } string obj = station.m_name ?? string.Empty; string text = ((Object)station).name ?? string.Empty; if (obj.IndexOf("workbench", StringComparison.OrdinalIgnoreCase) < 0) { return text.IndexOf("workbench", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } internal static void GiveToPlayer(Player player) { if ((Object)(object)player == (Object)null) { return; } if (((Object)(object)Prefab == (Object)null || ((object)Prefab).Equals((object?)null)) && (Object)(object)ObjectDB.instance != (Object)null) { TryRegister(ObjectDB.instance); } if ((Object)(object)Prefab == (Object)null || ((object)Prefab).Equals((object?)null)) { Plugin.Log.LogWarning((object)"Cannot give Hearthstone — prefab missing."); return; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory != null) { ItemData val = Prefab.GetComponent().m_itemData.Clone(); val.m_stack = 1; val.m_quality = 1; val.m_durability = val.m_shared.m_maxDurability; val.m_crafterID = player.GetPlayerID(); val.m_crafterName = player.GetPlayerName(); val.m_dropPrefab = Prefab; val.m_equipped = false; EnsureDropPrefab(val); if (!inventory.AddItem(val)) { ((Character)player).Message((MessageType)2, "Inventory full", 0, (Sprite)null); } else { ((Character)player).Message((MessageType)2, "$item_hearthstone", 0, (Sprite)null); } } } internal static void ApplyItemStats(SharedData shared) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (shared != null) { shared.m_name = "$item_hearthstone"; shared.m_description = "$item_hearthstone_desc"; shared.m_subtitle = "$item_hearthstone_subtitle"; shared.m_weight = HearthstoneConfig.Weight.Value; shared.m_maxStackSize = 1; shared.m_maxQuality = 1; shared.m_itemType = (ItemType)16; shared.m_teleportable = true; shared.m_equipDuration = 0f; shared.m_useDurability = true; shared.m_maxDurability = Mathf.Max(1, HearthstoneConfig.Uses.Value); shared.m_useDurabilityDrain = 0f; shared.m_durabilityDrain = 0f; shared.m_destroyBroken = true; shared.m_canBeReparied = false; shared.m_food = 0f; shared.m_foodStamina = 0f; shared.m_foodEitr = 0f; shared.m_foodBurnTime = 0f; shared.m_consumeStatusEffect = null; shared.m_equipStatusEffect = null; shared.m_questItem = false; shared.m_dlc = string.Empty; HearthstoneVisuals.ApplyIcon(shared); } } internal static void EnsureDropPrefab(ItemData item) { if (item != null) { if (((Object)(object)Prefab == (Object)null || ((object)Prefab).Equals((object?)null)) && (Object)(object)ObjectDB.instance != (Object)null) { TryRegister(ObjectDB.instance); } if ((Object)(object)Prefab != (Object)null && !((object)Prefab).Equals((object?)null)) { item.m_dropPrefab = Prefab; } } } internal static string BuildTooltip(ItemData item) { EnsureDropPrefab(item); int num = ((item != null) ? Mathf.Max(0, Mathf.CeilToInt(item.m_durability)) : 0); int num2 = ((item?.m_shared != null) ? Mathf.Max(1, Mathf.CeilToInt(item.m_shared.m_maxDurability)) : HearthstoneConfig.Uses.Value); string text = Localization.instance.Localize("$item_hearthstone_flavor"); string text2 = Localization.instance.Localize("$item_hearthstone_desc"); string text3 = Localization.instance.Localize("$item_hearthstone_uses", new string[2] { num.ToString(), num2.ToString() }); string text4 = Localization.instance.Localize("$item_hearthstone_usetip"); string text5 = ((item != null) ? item.GetWeight(-1).ToString("0.0") : HearthstoneConfig.Weight.Value.ToString("0.0")); return text + "\n\n" + text2 + "\n\n" + text3 + "\n" + text4 + "\n$item_weight: " + text5 + ""; } internal static void ConsumeOneUse(Player player, ItemData item) { if ((Object)(object)player == (Object)null || item == null) { return; } item.m_durability = Mathf.Max(0f, item.m_durability - 1f); Inventory inventory = ((Humanoid)player).GetInventory(); if (item.m_durability > 0f) { if (inventory != null) { inventory.Changed(); } } else if (inventory != null) { inventory.RemoveItem(item); } } private static void EnsureUniqueShared(ItemDrop itemDrop) { if (itemDrop?.m_itemData?.m_shared != null) { object? obj = ((object)itemDrop.m_itemData.m_shared).GetType().GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(itemDrop.m_itemData.m_shared, null); SharedData val = (SharedData)((obj is SharedData) ? obj : null); if (val != null) { itemDrop.m_itemData.m_shared = val; } } } private static bool ShouldRebuildPrefab(ObjectDB odb) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Invalid comparison between Unknown and I4 if ((Object)(object)Prefab == (Object)null || ((object)Prefab).Equals((object?)null)) { return false; } GameObject itemPrefab = odb.GetItemPrefab("SurtlingCore"); if ((Object)(object)itemPrefab == (Object)null || ((object)itemPrefab).Equals((object?)null)) { return false; } ItemDrop component = Prefab.GetComponent(); if (component?.m_itemData?.m_shared == null) { return true; } if ((int)component.m_itemData.m_shared.m_itemType != 16) { return true; } if (component.m_itemData.m_shared.m_name != "$item_hearthstone") { return true; } return false; } private static GameObject FindExisting(ObjectDB odb) { try { GameObject itemPrefab = odb.GetItemPrefab("VO_Hearthstone"); if ((Object)(object)itemPrefab != (Object)null && !((object)itemPrefab).Equals((object?)null)) { return itemPrefab; } } catch { } if (odb.m_items == null) { return null; } foreach (GameObject item in odb.m_items) { if ((Object)(object)item != (Object)null && !((object)item).Equals((object?)null) && ((Object)item).name == "VO_Hearthstone") { return item; } } return null; } internal static void SanitizeObjectDb(ObjectDB odb) { if (odb?.m_items != null) { int num = odb.m_items.RemoveAll((GameObject go) => (Object)(object)go == (Object)null || ((object)go).Equals((object?)null)); if (num > 0) { Plugin.Log.LogWarning((object)("Removed " + num + " null prefab(s) from ObjectDB.m_items.")); } } } private static void RegisterInLookups(ObjectDB odb) { if (!((Object)(object)odb == (Object)null) && !((Object)(object)Prefab == (Object)null) && !((object)Prefab).Equals((object?)null)) { int stableHashCode = StringExtensionMethods.GetStableHashCode("VO_Hearthstone"); if (odb.m_itemByHash != null) { odb.m_itemByHash[stableHashCode] = Prefab; } ItemDrop component = Prefab.GetComponent(); if (component?.m_itemData?.m_shared != null && odb.m_itemByData != null) { odb.m_itemByData[component.m_itemData.m_shared] = Prefab; } } } private static bool CreatePrefab(ObjectDB odb) { //IL_01f0: Unknown result type (might be due to invalid IL or missing references) if (_prefabCreated && (Object)(object)Prefab != (Object)null && !((object)Prefab).Equals((object?)null)) { return true; } GameObject val = null; string text = null; string[] meshPrefabCandidates = MeshPrefabCandidates; foreach (string text2 in meshPrefabCandidates) { val = odb.GetItemPrefab(text2); if ((Object)(object)val != (Object)null && !((object)val).Equals((object?)null)) { text = text2; break; } } if ((Object)(object)val == (Object)null) { Plugin.Log.LogError((object)"No suitable vanilla item prefab found to clone for Hearthstone."); return false; } bool activeSelf = val.activeSelf; val.SetActive(false); Prefab = Object.Instantiate(val); val.SetActive(activeSelf); ((Object)Prefab).name = "VO_Hearthstone"; Prefab.SetActive(false); Object.DontDestroyOnLoad((Object)(object)Prefab); if (((Object)Prefab).name.EndsWith("(Clone)", StringComparison.Ordinal)) { ((Object)Prefab).name = "VO_Hearthstone"; } ItemDrop component = Prefab.GetComponent(); if ((Object)(object)component == (Object)null) { Plugin.Log.LogError((object)("Cloned prefab has no ItemDrop (" + text + ").")); Object.Destroy((Object)(object)Prefab); Prefab = null; return false; } EnsureUniqueShared(component); ApplyItemStats(component.m_itemData.m_shared); component.m_itemData.m_durability = component.m_itemData.m_shared.m_maxDurability; component.m_itemData.m_quality = 1; component.m_itemData.m_stack = 1; component.m_itemData.m_crafterID = 0L; component.m_itemData.m_crafterName = string.Empty; component.m_itemData.m_dropPrefab = Prefab; component.m_itemData.m_equipped = false; component.m_autoPickup = true; component.m_autoDestroy = true; ((Object)component).name = "VO_Hearthstone"; ZNetView component2 = Prefab.GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.m_persistent = true; component2.m_distant = false; component2.m_type = (ObjectType)0; } Piece component3 = Prefab.GetComponent(); if ((Object)(object)component3 != (Object)null) { Object.Destroy((Object)(object)component3); } if (!odb.m_items.Contains(Prefab)) { odb.m_items.Add(Prefab); } _prefabCreated = true; Plugin.Log.LogInfo((object)("Created Hearthstone prefab from " + text + " (own SharedData + ZNet hash 'VO_Hearthstone').")); return true; } private static void EnsureRecipe(ObjectDB odb) { if ((Object)(object)Prefab == (Object)null || ((object)Prefab).Equals((object?)null)) { return; } ItemDrop component = Prefab.GetComponent(); if ((Object)(object)component == (Object)null) { return; } string text = "Recipe_VO_Hearthstone"; Recipe val = Recipe; if ((Object)(object)val == (Object)null && odb.m_recipes != null) { foreach (Recipe recipe in odb.m_recipes) { if ((Object)(object)recipe != (Object)null && ((Object)recipe).name == text) { val = recipe; break; } } } CraftingStation val2 = FindWorkbench(odb); if ((Object)(object)val == (Object)null) { GameObject itemPrefab = odb.GetItemPrefab("FineWood"); GameObject itemPrefab2 = odb.GetItemPrefab("Resin"); GameObject itemPrefab3 = odb.GetItemPrefab("GreydwarfEye"); GameObject itemPrefab4 = odb.GetItemPrefab("SurtlingCore"); if ((Object)(object)itemPrefab == (Object)null || (Object)(object)itemPrefab2 == (Object)null || (Object)(object)itemPrefab3 == (Object)null || (Object)(object)itemPrefab4 == (Object)null) { Plugin.Log.LogWarning((object)"Missing recipe materials for Hearthstone."); return; } val = ScriptableObject.CreateInstance(); ((Object)val).name = text; val.m_item = component; val.m_amount = 1; val.m_enabled = true; val.m_resources = (Requirement[])(object)new Requirement[4] { NewReq(itemPrefab, 10), NewReq(itemPrefab2, 10), NewReq(itemPrefab3, 5), NewReq(itemPrefab4, 2) }; odb.m_recipes.Add(val); Plugin.Log.LogInfo((object)"Added Hearthstone recipe."); } val.m_item = component; val.m_enabled = true; val.m_minStationLevel = 1; if ((Object)(object)val2 != (Object)null) { val.m_craftingStation = val2; } if (odb.m_recipes != null && !odb.m_recipes.Contains(val)) { odb.m_recipes.Add(val); } Recipe = val; string text2 = (((Object)(object)val2 != (Object)null) ? (((Object)val2).name + " / " + val2.m_name) : "NULL"); Plugin.Log.LogInfo((object)("Hearthstone recipe OK. Station=" + text2)); } private static Requirement NewReq(GameObject prefab, int amount) { //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_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0027: Expected O, but got Unknown return new Requirement { m_resItem = prefab.GetComponent(), m_amount = amount, m_amountPerLevel = 0, m_recover = false }; } private static CraftingStation FindWorkbench(ObjectDB odb) { if ((Object)(object)ZNetScene.instance != (Object)null) { GameObject prefab = ZNetScene.instance.GetPrefab("piece_workbench"); if ((Object)(object)prefab != (Object)null) { CraftingStation component = prefab.GetComponent(); if ((Object)(object)component != (Object)null) { return component; } } } if (odb?.m_recipes == null) { return null; } foreach (Recipe recipe in odb.m_recipes) { if (!((Object)(object)recipe?.m_craftingStation == (Object)null)) { string name = ((Object)recipe.m_craftingStation).name; string text = recipe.m_craftingStation.m_name ?? string.Empty; if (name == "piece_workbench" || name.IndexOf("workbench", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("workbench", StringComparison.OrdinalIgnoreCase) >= 0) { return recipe.m_craftingStation; } } } return null; } private static bool IsObjectDbReady(ObjectDB odb) { if (odb.m_items != null && odb.m_items.Count > 0) { return (Object)(object)odb.GetItemPrefab("Amber") != (Object)null; } return false; } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class ObjectDB_Awake_Patch { private static void Postfix(ObjectDB __instance) { HearthstoneItem.TryRegister(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class ObjectDB_CopyOtherDB_Patch { private static void Prefix(ObjectDB other) { HearthstoneItem.SanitizeObjectDb(other); } private static void Postfix(ObjectDB __instance) { HearthstoneItem.TryRegister(__instance); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ZNetScene_Awake_Patch { private static void Postfix(ZNetScene __instance) { if ((Object)(object)ObjectDB.instance != (Object)null) { HearthstoneItem.TryRegister(ObjectDB.instance); } HearthstoneItem.TryRegisterZNetScene(__instance); } } [HarmonyPatch(typeof(Player), "UpdateKnownRecipesList")] internal static class Player_UpdateKnownRecipesList_Patch { private static void Postfix(Player __instance) { HearthstoneItem.UnlockKnownRecipe(__instance); } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class Player_OnSpawned_Patch { private static void Postfix(Player __instance) { HearthstoneItem.UnlockKnownRecipe(__instance); if (((__instance != null) ? ((Humanoid)__instance).GetInventory() : null) == null) { return; } foreach (ItemData allItem in ((Humanoid)__instance).GetInventory().GetAllItems()) { if (HearthstoneItem.IsHearthstone(allItem)) { HearthstoneItem.EnsureDropPrefab(allItem); } } } } [HarmonyPatch(typeof(Player), "GetAvailableRecipes")] internal static class Player_GetAvailableRecipes_Patch { private static void Postfix(Player __instance, ref List available) { if (HearthstoneConfig.EnableMod.Value) { HearthstoneItem.EnsureAvailable(__instance, available); } } } internal static class HearthstoneTeleport { internal static bool TryGetDestination(Player player, out Vector3 position, out string failToken) { //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_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_0079: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; failToken = null; if ((Object)(object)player == (Object)null || (Object)(object)Game.instance == (Object)null) { failToken = "$msg_hearthstone_nobed"; return false; } PlayerProfile playerProfile = Game.instance.GetPlayerProfile(); if (playerProfile == null) { failToken = "$msg_hearthstone_nobed"; return false; } if (HearthstoneConfig.RequireBoundBed.Value) { if (!playerProfile.HaveCustomSpawnPoint()) { failToken = "$msg_hearthstone_nobed"; return false; } position = playerProfile.GetCustomSpawnPoint(); return true; } if (playerProfile.HaveCustomSpawnPoint()) { position = playerProfile.GetCustomSpawnPoint(); return true; } position = playerProfile.GetHomePoint(); return true; } internal static bool CanTeleportInventory(Player player, out string failToken) { failToken = null; if ((Object)(object)player == (Object)null) { return false; } if (HearthstoneConfig.AllowTeleportWithRestrictedItems.Value) { return true; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return true; } if (inventory.IsTeleportable()) { return true; } failToken = "$msg_noteleport"; return false; } internal static bool TryTeleport(Player player) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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_004c: Unknown result type (might be due to invalid IL or missing references) if (!TryGetDestination(player, out var position, out var failToken)) { if (!string.IsNullOrEmpty(failToken)) { ((Character)player).Message((MessageType)2, failToken, 0, (Sprite)null); } return false; } if (!CanTeleportInventory(player, out var failToken2)) { if (!string.IsNullOrEmpty(failToken2)) { ((Character)player).Message((MessageType)2, failToken2, 0, (Sprite)null); } return false; } Quaternion rotation = ((Component)player).transform.rotation; if (!((Character)player).TeleportTo(position, rotation, true)) { ((Character)player).Message((MessageType)2, "$msg_hearthstone_blocked", 0, (Sprite)null); return false; } return true; } } internal static class HearthstoneVisuals { private static Sprite _icon; private static MethodInfo _loadImage; internal static Sprite GetIcon() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_0087: 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) if ((Object)(object)_icon != (Object)null) { return _icon; } byte[] array = LoadEmbeddedPng(); if (array == null || array.Length == 0) { Plugin.Log.LogWarning((object)"Hearthstone icon resource missing."); return null; } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!TryLoadImage(val, array)) { Plugin.Log.LogWarning((object)"Failed to LoadImage hearthstone icon."); return null; } ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; ((Object)val).name = "VO_Hearthstone_Icon"; _icon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); ((Object)_icon).name = "VO_Hearthstone_Icon"; return _icon; } internal static void ApplyIcon(SharedData shared) { Sprite icon = GetIcon(); if (shared != null && !((Object)(object)icon == (Object)null)) { shared.m_icons = (Sprite[])(object)new Sprite[1] { icon }; } } private static bool TryLoadImage(Texture2D tex, byte[] bytes) { if (_loadImage == null) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType("UnityEngine.ImageConversion"); if (!(type == null)) { _loadImage = type.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(Texture2D), typeof(byte[]) }, null); if (_loadImage != null) { break; } } } } if (_loadImage == null) { return false; } object obj = _loadImage.Invoke(null, new object[2] { tex, bytes }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } private static byte[] LoadEmbeddedPng() { Assembly assembly = typeof(HearthstoneVisuals).Assembly; string text = null; string[] manifestResourceNames = assembly.GetManifestResourceNames(); foreach (string text2 in manifestResourceNames) { if (text2.EndsWith("hearthstone_icon.png", StringComparison.OrdinalIgnoreCase)) { text = text2; break; } } if (text == null) { return null; } using Stream stream = assembly.GetManifestResourceStream(text); if (stream == null) { return null; } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); return memoryStream.ToArray(); } } [HarmonyPatch(typeof(Localization), "SetupLanguage")] internal static class Localization_SetupLanguage_Patch { private static void Postfix(Localization __instance, string language) { Inject(__instance, language); } internal static void Inject(Localization loc, string language) { if (loc != null) { if (language != null && (language.StartsWith("Spanish") || language == "Español" || language == "es" || language.IndexOf("Spanish", StringComparison.OrdinalIgnoreCase) >= 0)) { Add(loc, "item_hearthstone", "Piedra del hogar"); Add(loc, "item_hearthstone_subtitle", "Reliquia del hogar"); Add(loc, "item_hearthstone_flavor", "«Return to thy hearth and home.»"); Add(loc, "item_hearthstone_desc", "Una piedra cálida que recuerda el fuego de tu cama vinculada.\nCanalízala con clic derecho para volver a casa."); Add(loc, "item_hearthstone_uses", "Usos: $1 / $2"); Add(loc, "item_hearthstone_usetip", "Quédate quieto mientras canalizas. Moverte cancela el ritual."); Add(loc, "hud_hearthstone_casting", "Canalizando el hogar"); Add(loc, "msg_hearthstone_nobed", "No tienes una cama vinculada."); Add(loc, "msg_hearthstone_cooldown", "La Piedra del hogar se está recuperando ($1)"); Add(loc, "msg_hearthstone_notowner", "Esta Piedra del hogar pertenece a otro vikingo."); Add(loc, "msg_hearthstone_alreadyhave", "Ya posees una Piedra del hogar."); Add(loc, "msg_hearthstone_cancelled", "Canalización cancelada."); Add(loc, "msg_hearthstone_casting", "Canalizando el hogar..."); Add(loc, "msg_hearthstone_blocked", "No se puede teletransportar ahora."); } else { Add(loc, "item_hearthstone", "Hearthstone"); Add(loc, "item_hearthstone_subtitle", "Hearth relic"); Add(loc, "item_hearthstone_flavor", "«Return to thy hearth and home.»"); Add(loc, "item_hearthstone_desc", "A warm stone that remembers the fire of your bound bed.\nRight-click to channel and return home."); Add(loc, "item_hearthstone_uses", "Uses: $1 / $2"); Add(loc, "item_hearthstone_usetip", "Stand still while channeling. Moving cancels the ritual."); Add(loc, "hud_hearthstone_casting", "Channeling home"); Add(loc, "msg_hearthstone_nobed", "You have no bound bed."); Add(loc, "msg_hearthstone_cooldown", "Hearthstone is recovering ($1)"); Add(loc, "msg_hearthstone_notowner", "This Hearthstone belongs to another viking."); Add(loc, "msg_hearthstone_alreadyhave", "You already have a Hearthstone."); Add(loc, "msg_hearthstone_cancelled", "Channel cancelled."); Add(loc, "msg_hearthstone_casting", "Channeling home..."); Add(loc, "msg_hearthstone_blocked", "Cannot teleport right now."); } } } private static void Add(Localization loc, string key, string value) { loc.AddWord(key, value); } } [HarmonyPatch(typeof(FejdStartup), "Awake")] internal static class FejdStartup_Localization_Patch { private static void Postfix() { if (Localization.instance != null) { Localization_SetupLanguage_Patch.Inject(Localization.instance, Localization.instance.GetSelectedLanguage()); } } } [HarmonyPatch(typeof(Humanoid), "UseItem")] internal static class Humanoid_UseItem_Patch { private static bool Prefix(Humanoid __instance, ItemData item) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return true; } if (!HearthstoneConfig.EnableMod.Value || !HearthstoneItem.IsHearthstone(item)) { return true; } HearthstoneItem.EnsureDropPrefab(item); HearthstoneCaster.TryBegin(val, item); return false; } } [HarmonyPatch(typeof(Humanoid), "DropItem")] internal static class Humanoid_DropItem_Patch { private static void Prefix(ItemData item) { if (HearthstoneItem.IsHearthstone(item)) { HearthstoneItem.EnsureDropPrefab(item); } } } [HarmonyPatch(typeof(ItemDrop), "DropItem")] internal static class ItemDrop_DropItem_Patch { private static void Prefix(ItemData item) { if (HearthstoneItem.IsHearthstone(item)) { HearthstoneItem.EnsureDropPrefab(item); } } private static void Postfix(ItemDrop __result) { if ((Object)(object)__result == (Object)null) { return; } if (!((Component)__result).gameObject.activeSelf) { ((Component)__result).gameObject.SetActive(true); } if (HearthstoneItem.IsHearthstone(__result.m_itemData)) { __result.m_itemData.m_dropPrefab = HearthstoneItem.Prefab; ((Object)__result).name = "VO_Hearthstone"; if ((Object)(object)ZNetScene.instance != (Object)null) { HearthstoneItem.TryRegisterZNetScene(ZNetScene.instance); } } } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int) })] internal static class ItemData_GetTooltip_Static_Patch { private static bool Prefix(ItemData item, ref string __result) { if (!HearthstoneConfig.EnableMod.Value || !HearthstoneItem.IsHearthstone(item)) { return true; } __result = HearthstoneItem.BuildTooltip(item); return false; } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(int) })] internal static class ItemData_GetTooltip_Instance_Patch { private static bool Prefix(ItemData __instance, ref string __result) { if (!HearthstoneConfig.EnableMod.Value || !HearthstoneItem.IsHearthstone(__instance)) { return true; } __result = HearthstoneItem.BuildTooltip(__instance); return false; } } [HarmonyPatch(typeof(Player), "UpdateActionQueue")] internal static class Player_UpdateActionQueue_Patch { private static bool Prefix(Player __instance, float dt) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } return !HearthstoneCaster.TryUpdateActionQueue(__instance, dt); } } [HarmonyPatch(typeof(Hud), "UpdateActionProgress")] internal static class Hud_UpdateActionProgress_Patch { private static void Postfix(Player player) { if (!((Object)(object)player != (Object)(object)Player.m_localPlayer) && HearthstoneCaster.IsCasting) { HearthstoneCaster.EnsureActionBarVisible(player); } } } [HarmonyPatch(typeof(Humanoid), "EquipItem")] internal static class Humanoid_EquipItem_Patch { private static bool Prefix(ItemData item) { return !HearthstoneItem.IsHearthstone(item); } } [HarmonyPatch(typeof(Player), "SetWeaponLoaded")] internal static class Player_SetWeaponLoaded_Patch { private static bool Prefix(Player __instance, ItemData item) { if (!HearthstoneItem.IsHearthstone(item)) { return true; } if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && HearthstoneCaster.IsCasting) { HearthstoneCaster.CompleteFromActionQueue(__instance, item); } return false; } } [HarmonyPatch(typeof(Player), "Update")] internal static class Player_Update_Patch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { HearthstoneCaster.Update(__instance, Time.deltaTime); } } } [HarmonyPatch(typeof(Player), "OnDamaged")] internal static class Player_OnDamaged_Patch { private static void Prefix(Player __instance, HitData hit) { if (HearthstoneConfig.EnableMod.Value && HearthstoneConfig.CancelOnDamage.Value && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && HearthstoneCaster.IsCasting && hit != null && !(hit.GetTotalDamage() <= 0f)) { HearthstoneCaster.Cancel(__instance, showMessage: true); } } } [HarmonyPatch(typeof(Character), "Jump")] internal static class Character_Jump_Patch { private static void Prefix(Character __instance) { if (HearthstoneConfig.EnableMod.Value && HearthstoneConfig.CancelOnJump.Value) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && HearthstoneCaster.IsCasting) { HearthstoneCaster.Cancel(val, showMessage: true); } } } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class InventoryGui_DoCrafting_Patch { private static bool Prefix(Player player) { if (!HearthstoneConfig.EnableMod.Value || (Object)(object)player == (Object)null) { return true; } InventoryGui instance = InventoryGui.instance; Recipe val = (((Object)(object)instance != (Object)null) ? instance.m_craftRecipe : null); if (val?.m_item?.m_itemData == null) { return true; } if (!HearthstoneItem.IsHearthstone(val.m_item.m_itemData)) { return true; } if (HearthstoneItem.CountInInventory(player) <= 0) { return true; } ((Character)player).Message((MessageType)2, "$msg_hearthstone_alreadyhave", 0, (Sprite)null); return false; } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] internal static class InventoryGrid_UpdateGui_Patch { private static void Postfix(InventoryGrid __instance, Player player) { HearthstoneInventoryUi.ApplyCooldownOverlays(__instance, player); } } [HarmonyPatch(typeof(HotkeyBar), "UpdateIcons")] internal static class HotkeyBar_UpdateIcons_Patch { private static void Postfix(HotkeyBar __instance, Player player) { HearthstoneInventoryUi.ApplyHotkeyCooldown(__instance, player); } } [HarmonyPatch(typeof(Terminal), "InitTerminal")] internal static class Terminal_InitTerminal_Patch { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__0_0; internal void b__0_0(ConsoleEventArgs args) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { Terminal context = args.Context; if (context != null) { context.AddString("No local player."); } return; } HearthstoneItem.GiveToPlayer(localPlayer); Terminal context2 = args.Context; if (context2 != null) { context2.AddString("Gave Hearthstone."); } } } private static void Postfix() { //IL_0032: 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) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown object obj = <>c.<>9__0_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { Terminal context = args.Context; if (context != null) { context.AddString("No local player."); } } else { HearthstoneItem.GiveToPlayer(localPlayer); Terminal context2 = args.Context; if (context2 != null) { context2.AddString("Gave Hearthstone."); } } }; <>c.<>9__0_0 = val; obj = (object)val; } new ConsoleCommand("hearthstone", "Give yourself a Hearthstone (cheat)", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, true); } } internal static class HearthstoneInventoryUi { private static readonly Dictionary OriginalIconColors = new Dictionary(); internal static void ApplyCooldownOverlays(InventoryGrid grid, Player player) { if ((Object)(object)grid == (Object)null || (Object)(object)player == (Object)null || !HearthstoneConfig.EnableMod.Value || !HearthstoneCooldown.IsOnCooldown(player, out var remainingSeconds)) { return; } string label = HearthstoneCooldown.FormatCompact(remainingSeconds); float cooldownFill = GetCooldownFill(remainingSeconds); List elements = grid.m_elements; if (elements == null) { return; } Inventory inventory = grid.m_inventory; if (inventory == null) { return; } foreach (Element item in elements) { if (item != null && item.m_pos.x >= 0 && HearthstoneItem.IsHearthstone(inventory.GetItemAt(item.m_pos.x, item.m_pos.y))) { ApplyElementCooldown(item.m_icon, item.m_amount, item.m_durability, label, cooldownFill); } } } internal static void ApplyHotkeyCooldown(HotkeyBar bar, Player player) { if ((Object)(object)bar == (Object)null || (Object)(object)player == (Object)null || !HearthstoneConfig.EnableMod.Value || !HearthstoneCooldown.IsOnCooldown(player, out var remainingSeconds)) { return; } string label = HearthstoneCooldown.FormatCompact(remainingSeconds); float cooldownFill = GetCooldownFill(remainingSeconds); if (bar.m_elements == null || bar.m_items == null) { return; } for (int i = 0; i < bar.m_elements.Count && i < bar.m_items.Count; i++) { if (HearthstoneItem.IsHearthstone(bar.m_items[i])) { ElementData val = bar.m_elements[i]; if (val != null) { ApplyElementCooldown(val.m_icon, val.m_amount, val.m_durability, label, cooldownFill); } } } } private static void ApplyElementCooldown(Image icon, TMP_Text amount, GuiBar durability, string label, float fill) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)amount != (Object)null) { ((Component)amount).gameObject.SetActive(true); amount.text = label; ((Graphic)amount).color = new Color(1f, 0.85f, 0.35f, 1f); } if ((Object)(object)icon != (Object)null) { if (!OriginalIconColors.ContainsKey(icon)) { OriginalIconColors[icon] = ((Graphic)icon).color; } Color val = OriginalIconColors[icon]; ((Graphic)icon).color = new Color(val.r * 0.45f, val.g * 0.45f, val.b * 0.45f, val.a); } if ((Object)(object)durability != (Object)null) { ((Component)durability).gameObject.SetActive(true); durability.SetValue(Mathf.Clamp01(fill)); } } private static float GetCooldownFill(float remainingSeconds) { float num = Mathf.Max(1f, HearthstoneConfig.CooldownMinutes.Value * 60f); return Mathf.Clamp01(1f - remainingSeconds / num); } } [BepInPlugin("valheimoverhaul.hearthstone", "Hearthstone", "1.4.1")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "valheimoverhaul.hearthstone"; public const string PluginName = "Hearthstone"; public const string PluginVersion = "1.4.1"; internal const string PrefabName = "VO_Hearthstone"; internal const string ItemToken = "$item_hearthstone"; internal const string CooldownCustomDataKey = "valheimoverhaul.hearthstone.cooldownUntil"; internal static Plugin Instance; internal static ManualLogSource Log; private void Awake() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; HearthstoneConfig.Bind(((BaseUnityPlugin)this).Config); new Harmony("valheimoverhaul.hearthstone").PatchAll(); Log.LogInfo((object)"Hearthstone 1.4.1 loaded."); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }