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 Hearthstone v1.4.1
Hearthstone.dll
Decompiled 9 hours agousing 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<GameObject>(_vfxPrefab, ((Component)player).transform.position + Vector3.up * 0.5f, Quaternion.identity); } } } } internal static class HearthstoneConfig { internal static ConfigEntry<bool> EnableMod; internal static ConfigEntry<int> Uses; internal static ConfigEntry<float> CastTime; internal static ConfigEntry<float> CooldownMinutes; internal static ConfigEntry<float> Weight; internal static ConfigEntry<bool> RequireBoundBed; internal static ConfigEntry<bool> CancelOnDamage; internal static ConfigEntry<bool> CancelOnDodge; internal static ConfigEntry<bool> CancelOnJump; internal static ConfigEntry<bool> CancelOnMove; internal static ConfigEntry<bool> 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<bool>("General", "Enable Mod", true, "Enable or disable the Hearthstone mod."); Uses = config.Bind<int>("Hearthstone", "Uses", 10, new ConfigDescription("Number of successful teleports before the Hearthstone is destroyed.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); CastTime = config.Bind<float>("Hearthstone", "Cast Time", 10f, new ConfigDescription("Channel duration in seconds before teleporting.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>())); CooldownMinutes = config.Bind<float>("Hearthstone", "Cooldown Minutes", 7f, new ConfigDescription("Cooldown after a successful teleport, in minutes. Persists across logout.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), Array.Empty<object>())); Weight = config.Bind<float>("Hearthstone", "Weight", 0.2f, new ConfigDescription("Item weight.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 20f), Array.Empty<object>())); RequireBoundBed = config.Bind<bool>("Hearthstone", "Require Bound Bed", true, "If true, casting requires a currently bound bed (same spawn used on death)."); CancelOnDamage = config.Bind<bool>("Hearthstone", "Cancel On Damage", true, "Cancel channeling when taking damage. Does not consume a use or start cooldown."); CancelOnDodge = config.Bind<bool>("Hearthstone", "Cancel On Dodge", true, "Cancel channeling when dodging / rolling."); CancelOnJump = config.Bind<bool>("Hearthstone", "Cancel On Jump", true, "Cancel channeling when jumping."); CancelOnMove = config.Bind<bool>("Hearthstone", "Cancel On Move", true, "Cancel channeling when walking, running, or otherwise moving."); AllowTeleportWithRestrictedItems = config.Bind<bool>("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<ItemDrop>(); 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<Recipe> 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<ItemDrop>().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: <color=orange>" + text5 + "</color>"; } 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<ItemDrop>(); 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<ItemDrop>(); 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<GameObject>(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<ItemDrop>(); 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<ZNetView>(); if ((Object)(object)component2 != (Object)null) { component2.m_persistent = true; component2.m_distant = false; component2.m_type = (ObjectType)0; } Piece component3 = Prefab.GetComponent<Piece>(); 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<ItemDrop>(); 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<Recipe>(); ((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<ItemDrop>(), 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<CraftingStation>(); 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<Recipe> 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", "<color=#E8C56B><i>«Return to thy hearth and home.»</i></color>"); Add(loc, "item_hearthstone_desc", "Una piedra cálida que recuerda el fuego de tu cama vinculada.\nCanalízala con <color=orange>clic derecho</color> para volver a casa."); Add(loc, "item_hearthstone_uses", "Usos: <color=orange>$1 / $2</color>"); Add(loc, "item_hearthstone_usetip", "<color=yellow>Quédate quieto mientras canalizas. Moverte cancela el ritual.</color>"); 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", "<color=#E8C56B><i>«Return to thy hearth and home.»</i></color>"); Add(loc, "item_hearthstone_desc", "A warm stone that remembers the fire of your bound bed.\n<color=orange>Right-click</color> to channel and return home."); Add(loc, "item_hearthstone_uses", "Uses: <color=orange>$1 / $2</color>"); Add(loc, "item_hearthstone_usetip", "<color=yellow>Stand still while channeling. Moving cancels the ritual.</color>"); 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 <Postfix>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<Image, Color> OriginalIconColors = new Dictionary<Image, Color>(); 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<Element> 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) { } } }