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 ValheimQuest v1.0.2
Valheimquest.dll
Decompiled 4 days agousing System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Valheimquest")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Valheimquest")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("25bf4d3e-bb53-4126-8370-18af0311e6c7")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace ValheimQuest; [BepInPlugin("com.yourname.valheimquest", "Valheim Quest", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class ValheimQuest : BaseUnityPlugin { private readonly Harmony harmony = new Harmony("com.yourname.valheimquest"); private void Awake() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Valheim Quest mod loaded!"); harmony.PatchAll(); PrefabManager.OnVanillaPrefabsAvailable += RegisterAll; } private void RegisterAll() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Registering quest objects..."); QuestGiver.Register(); PrefabManager.OnVanillaPrefabsAvailable -= RegisterAll; } } public class QuestGiver { public static void Register() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown GameObject val = PrefabManager.Instance.CreateClonedPrefab("QuestGiverRaven", "darkwood_raven"); if ((Object)(object)val == (Object)null) { Debug.LogError((object)"Failed to clone raven prefab!"); return; } val.AddComponent<QuestGiverInteract>(); PieceConfig val2 = new PieceConfig(); val2.Name = "Raven Oracle"; val2.Description = "An ancient raven carving that speaks of quests."; val2.PieceTable = "Hammer"; val2.AddRequirement(new RequirementConfig("FineWood", 5, 0, true)); val2.AddRequirement(new RequirementConfig("GreydwarfEye", 2, 0, true)); PieceManager.Instance.AddPiece(new CustomPiece(val, false, val2)); Debug.Log((object)"Quest Giver registered!"); } } public class QuestGiverInteract : MonoBehaviour, Interactable, Hoverable { private enum QuestState { NoQuest, Quest1Active, Quest1Complete, Quest2Active, Quest2Complete, Quest3Active, Quest3Complete, Quest4Active, Quest4Complete, Quest5Active, Quest5Complete, Quest6Active, Quest6Complete, Quest7Active, Quest7Complete, Quest8Active, Quest8Complete, Quest9Active, Quest9Complete, Quest10Active, Quest10Complete, Quest11Active, Quest11Complete, Quest12Active, Quest12Complete, Quest13Active, Quest13Complete, Quest14Active, Quest14Complete, Quest15Active, Quest15Complete, Quest16Active, Quest16Complete, Quest17Active, Quest17Complete, Quest18Active, Quest18Complete, AllComplete } private struct QuestData { public string enemy; public int count; public string startMessage; public string progressMessage; public string completeMessage; } private static QuestState state; private static int currentQuest; private QuestData[] quests = new QuestData[18] { new QuestData { enemy = "Boar", count = 5, startMessage = "Slay 5 boars that plague these lands.", progressMessage = "boars", completeMessage = "The boars are dealt with. Take these supplies!" }, new QuestData { enemy = "Greydwarf", count = 10, startMessage = "Now slay 10 Greydwarfs lurking in the forest.", progressMessage = "Greydwarfs", completeMessage = "The forest is safer. Here are your Surtling Cores!" }, new QuestData { enemy = "Troll", count = 2, startMessage = "Prove your strength. Slay 2 Trolls.", progressMessage = "Trolls", completeMessage = "Impressive! Take this bronze and gold." }, new QuestData { enemy = "Draugr", count = 10, startMessage = "The dead walk. Slay 10 Draugr.", progressMessage = "Draugr", completeMessage = "The dead rest now. Take your reward." }, new QuestData { enemy = "Blob", count = 3, startMessage = "Slay 3 Slimes from the swamp.", progressMessage = "Slimes", completeMessage = "The swamp is cleaner. Here is your Guck." }, new QuestData { enemy = "Wraith", count = 3, startMessage = "Face the darkness. Slay 3 Wraiths.", progressMessage = "Wraiths", completeMessage = "The spirits are vanquished. Take these chains." }, new QuestData { enemy = "Wolf", count = 10, startMessage = "The mountains are dangerous. Slay 10 Wolves.", progressMessage = "Wolves", completeMessage = "The mountains are safer. Take this iron." }, new QuestData { enemy = "Hatchling", count = 5, startMessage = "Slay 5 Drakes from the mountain peaks.", progressMessage = "Drakes", completeMessage = "The skies are clear. Take this trophy and gold." }, new QuestData { enemy = "Fenring", count = 1, startMessage = "Face the beast of the night. Slay 1 Fenring.", progressMessage = "Fenrings", completeMessage = "You are truly brave. Take this crystal and gold." }, new QuestData { enemy = "Goblin", count = 20, startMessage = "The plains are overrun. Slay 20 Fulings.", progressMessage = "Fulings", completeMessage = "The plains breathe again. Take this silver and gold." }, new QuestData { enemy = "Deathsquito", count = 10, startMessage = "Slay 10 Deathsquitos from the plains.", progressMessage = "Deathsquitos", completeMessage = "No more buzzing. Take this Lox pelt and gold." }, new QuestData { enemy = "Lox", count = 5, startMessage = "Slay 5 Lox from the plains.", progressMessage = "Lox", completeMessage = "Mighty warrior! Take this gold." }, new QuestData { enemy = "Tick", count = 10, startMessage = "Slay 10 Ticks from the Mistlands.", progressMessage = "Ticks", completeMessage = "The Mistlands are safer. Take these Black Cores." }, new QuestData { enemy = "Seeker", count = 10, startMessage = "Slay 10 Seekers in the Mistlands.", progressMessage = "Seekers", completeMessage = "The seekers fall. Take these Magecaps and gold." }, new QuestData { enemy = "Gjall", count = 1, startMessage = "Face the great Gjall. Slay 1 of them.", progressMessage = "Gjalls", completeMessage = "Legendary! Take this gold and sap." }, new QuestData { enemy = "Charred_Melee", count = 10, startMessage = "Slay 10 Charred Warriors in the Ashlands.", progressMessage = "Charred Warriors", completeMessage = "The ash settles. Take your reward." }, new QuestData { enemy = "Charred_Twitcher", count = 10, startMessage = "Slay 10 Charred Twitchers.", progressMessage = "Charred Twitchers", completeMessage = "They twitch no more. Take your reward." }, new QuestData { enemy = "Charred_Archer", count = 10, startMessage = "Slay 10 Charred Marksmen.", progressMessage = "Charred Marksmen", completeMessage = "Their arrows fly no more. Take your final reward!" } }; public static void LoadState(int savedState, int savedQuest) { state = (QuestState)savedState; currentQuest = savedQuest; if (IsActiveState()) { QuestGiverInteract questGiverInteract = Object.FindFirstObjectByType<QuestGiverInteract>(); if ((Object)(object)questGiverInteract != (Object)null) { QuestData questData = questGiverInteract.quests[currentQuest]; QuestTracker.StartTracking(questData.enemy, questData.count); } } } public static int GetStateAsInt() { return (int)state; } public static int GetCurrentQuest() { return currentQuest; } public bool Interact(Humanoid user, bool hold, bool alt) { if (hold) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val == (Object)null) { return false; } if (state == QuestState.AllComplete) { MessageHud.instance.ShowMessage((MessageType)2, "Raven Oracle: You have completed all my quests. You are a legend!", 0, (Sprite)null, false); return true; } if (state == QuestState.NoQuest || IsCompleteState()) { if (IsCompleteState() && currentQuest < quests.Length - 1) { currentQuest++; } else if (IsCompleteState() && currentQuest >= quests.Length - 1) { state = QuestState.AllComplete; QuestSaveData.Save(GetStateAsInt(), QuestTracker.GetKillCount(), currentQuest); return true; } QuestData questData = quests[currentQuest]; MessageHud.instance.ShowMessage((MessageType)2, "Raven Oracle: " + questData.startMessage, 0, (Sprite)null, false); QuestTracker.StartTracking(questData.enemy, questData.count); SetActiveState(); QuestSaveData.Save(GetStateAsInt(), 0, currentQuest); } else if (IsActiveState()) { QuestData questData2 = quests[currentQuest]; int killCount = QuestTracker.GetKillCount(); if (killCount >= questData2.count) { MessageHud.instance.ShowMessage((MessageType)2, "Raven Oracle: " + questData2.completeMessage, 0, (Sprite)null, false); GiveReward(val, currentQuest); SetCompleteState(); QuestSaveData.Save(GetStateAsInt(), killCount, currentQuest); } else { MessageHud.instance.ShowMessage((MessageType)2, $"Raven Oracle: You have slain {killCount}/{questData2.count} {questData2.progressMessage}. Keep going!", 0, (Sprite)null, false); } } return true; } private static bool IsActiveState() { return (int)state % 2 == 1; } private static bool IsCompleteState() { return state != 0 && (int)state % 2 == 0 && state != QuestState.AllComplete; } private void SetActiveState() { state = (QuestState)(currentQuest * 2 + 1); } private void SetCompleteState() { state = (QuestState)(currentQuest * 2 + 2); } private void GiveReward(Player player, int questIndex) { switch (questIndex) { case 0: ((Humanoid)player).GetInventory().AddItem("CookedMeat", 10, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("Bread", 5, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("Coins", 20, 1, 0, 0L, "", false); break; case 1: ((Humanoid)player).GetInventory().AddItem("SurtlingCore", 5, 1, 0, 0L, "", false); break; case 2: ((Humanoid)player).GetInventory().AddItem("Bronze", 10, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("Coins", 200, 1, 0, 0L, "", false); break; case 3: ((Humanoid)player).GetInventory().AddItem("SurtlingCore", 5, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("Coins", 100, 1, 0, 0L, "", false); break; case 4: ((Humanoid)player).GetInventory().AddItem("Guck", 10, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("Coins", 60, 1, 0, 0L, "", false); break; case 5: ((Humanoid)player).GetInventory().AddItem("Chain", 5, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("Coins", 150, 1, 0, 0L, "", false); break; case 6: ((Humanoid)player).GetInventory().AddItem("Iron", 20, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("Coins", 100, 1, 0, 0L, "", false); break; case 7: ((Humanoid)player).GetInventory().AddItem("TrophyHatchling", 1, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("Coins", 50, 1, 0, 0L, "", false); break; case 8: ((Humanoid)player).GetInventory().AddItem("Coins", 100, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("Crystal", 20, 1, 0, 0L, "", false); break; case 9: ((Humanoid)player).GetInventory().AddItem("Silver", 20, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("Coins", 200, 1, 0, 0L, "", false); break; case 10: ((Humanoid)player).GetInventory().AddItem("LoxPelt", 10, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("Coins", 50, 1, 0, 0L, "", false); break; case 11: ((Humanoid)player).GetInventory().AddItem("Coins", 300, 1, 0, 0L, "", false); break; case 12: ((Humanoid)player).GetInventory().AddItem("Coins", 100, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("BlackCore", 3, 1, 0, 0L, "", false); break; case 13: ((Humanoid)player).GetInventory().AddItem("Coins", 200, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("Magecap", 10, 1, 0, 0L, "", false); break; case 14: ((Humanoid)player).GetInventory().AddItem("Coins", 200, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("Sap", 20, 1, 0, 0L, "", false); break; case 15: ((Humanoid)player).GetInventory().AddItem("Coins", 200, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("BlackCore", 3, 1, 0, 0L, "", false); break; case 16: ((Humanoid)player).GetInventory().AddItem("Coins", 300, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("BlackCore", 3, 1, 0, 0L, "", false); break; case 17: ((Humanoid)player).GetInventory().AddItem("Coins", 400, 1, 0, 0L, "", false); ((Humanoid)player).GetInventory().AddItem("MoltenCore", 5, 1, 0, 0L, "", false); break; } } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetHoverText() { if (state == QuestState.NoQuest || IsCompleteState()) { return "Raven Oracle\n[E] Speak"; } if (IsActiveState()) { QuestData questData = quests[currentQuest]; return $"Raven Oracle\n[E] Check Progress ({QuestTracker.GetKillCount()}/{questData.count} {questData.progressMessage})"; } return "Raven Oracle\n[E] Speak"; } public string GetHoverName() { return "Raven Oracle"; } } public class QuestSaveData { private const string QuestStateKey = "ValheimQuest_State"; private const string KillCountKey = "ValheimQuest_KillCount"; private const string CurrentQuestKey = "ValheimQuest_CurrentQuest"; public static void Save(int questState, int killCount, int currentQuest) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { localPlayer.m_customData["ValheimQuest_State"] = questState.ToString(); localPlayer.m_customData["ValheimQuest_KillCount"] = killCount.ToString(); localPlayer.m_customData["ValheimQuest_CurrentQuest"] = currentQuest.ToString(); Debug.Log((object)$"Quest progress saved! State: {questState} Kills: {killCount} Quest: {currentQuest}"); } } public static bool Load(out int questState, out int killCount, out int currentQuest) { questState = 0; killCount = 0; currentQuest = 0; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } if (!localPlayer.m_customData.ContainsKey("ValheimQuest_State")) { return false; } questState = int.Parse(localPlayer.m_customData["ValheimQuest_State"]); killCount = int.Parse(localPlayer.m_customData["ValheimQuest_KillCount"]); currentQuest = int.Parse(localPlayer.m_customData["ValheimQuest_CurrentQuest"]); Debug.Log((object)$"Quest progress loaded! State: {questState} Kills: {killCount} Quest: {currentQuest}"); return true; } } [HarmonyPatch(typeof(Player), "OnSpawned")] public class PlayerSpawnPatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && QuestSaveData.Load(out var questState, out var killCount, out var currentQuest)) { QuestTracker.LoadState(killCount); QuestGiverInteract.LoadState(questState, currentQuest); Debug.Log((object)"Quest state restored!"); } } } public class QuestTracker { private static int killCount = 0; private static bool isTracking = false; private static string targetEnemy = ""; private static int killsRequired = 0; private static HashSet<int> countedKills = new HashSet<int>(); public static void StartTracking(string enemyName, int required) { killCount = 0; isTracking = true; targetEnemy = enemyName; killsRequired = required; countedKills.Clear(); Debug.Log((object)("Quest started! Tracking " + enemyName + " kills...")); } public static void LoadState(int savedKillCount) { killCount = savedKillCount; isTracking = true; Debug.Log((object)$"Kill count loaded: {killCount}"); } public static int GetKillCount() { return killCount; } public static void AddKill(int instanceId, string enemyName) { if (isTracking && enemyName.Contains(targetEnemy) && !countedKills.Contains(instanceId)) { countedKills.Add(instanceId); killCount++; Debug.Log((object)$"{targetEnemy} killed! Total: {killCount}/{killsRequired}"); MessageHud.instance.ShowMessage((MessageType)1, $"{targetEnemy}s slain: {killCount}/{killsRequired}", 0, (Sprite)null, false); QuestSaveData.Save(QuestGiverInteract.GetStateAsInt(), killCount, QuestGiverInteract.GetCurrentQuest()); } } } [HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")] public class EnemyDeathPatch { private static void Postfix(CharacterDrop __instance) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Player.m_localPlayer == (Object)null)) { float num = Vector3.Distance(((Component)__instance).transform.position, ((Component)Player.m_localPlayer).transform.position); if (num < 30f) { QuestTracker.AddKill(((Object)((Component)__instance).gameObject).GetInstanceID(), ((Object)((Component)__instance).gameObject).name); } } } }