Decompiled source of ValheimQuest v1.1.0

Valheimquest.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
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.demonforge.valheimquest", "Valheim Quest", "1.1.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
public class ValheimQuest : BaseUnityPlugin
{
	public const string PluginGUID = "com.demonforge.valheimquest";

	public const string PluginName = "Valheim Quest";

	public const string PluginVersion = "1.1.0";

	public static ManualLogSource Log;

	private readonly Harmony harmony = new Harmony("com.demonforge.valheimquest");

	private void Awake()
	{
		Log = ((BaseUnityPlugin)this).Logger;
		Log.LogInfo((object)"Valheim Quest 1.1.0 loading...");
		try
		{
			harmony.PatchAll();
		}
		catch (Exception arg)
		{
			Log.LogError((object)$"Harmony patching failed: {arg}");
		}
		PrefabManager.OnVanillaPrefabsAvailable += RegisterAll;
		PrefabManager.OnPrefabsRegistered += ValidatePrefabNames;
	}

	private void RegisterAll()
	{
		Log.LogInfo((object)"Registering quest objects...");
		QuestGiver.Register();
		PrefabManager.OnVanillaPrefabsAvailable -= RegisterAll;
	}

	private void ValidatePrefabNames()
	{
		PrefabManager.OnPrefabsRegistered -= ValidatePrefabNames;
		List<string> list = new List<string>();
		foreach (string enemyPrefabName in QuestGiverInteract.GetEnemyPrefabNames())
		{
			if (!PrefabExists(enemyPrefabName))
			{
				list.Add("enemy: " + enemyPrefabName);
			}
		}
		foreach (string rewardPrefabName in QuestGiverInteract.GetRewardPrefabNames())
		{
			if (!PrefabExists(rewardPrefabName))
			{
				list.Add("reward: " + rewardPrefabName);
			}
		}
		if (list.Count == 0)
		{
			Log.LogInfo((object)"Prefab check passed - all quest targets and rewards resolved.");
			return;
		}
		Log.LogWarning((object)$"Prefab check found {list.Count} unresolved name(s):");
		foreach (string item in list)
		{
			Log.LogWarning((object)("  " + item));
		}
	}

	private static bool PrefabExists(string name)
	{
		if (PrefabManager.Instance != null && (Object)(object)PrefabManager.Instance.GetPrefab(name) != (Object)null)
		{
			return true;
		}
		if ((Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ZNetScene.instance.GetPrefab(name) != (Object)null)
		{
			return true;
		}
		return false;
	}
}
public class QuestGiver
{
	private const string BasePrefab = "darkwood_raven";

	public static void Register()
	{
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Expected O, but got Unknown
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Expected O, but got Unknown
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Expected O, but got Unknown
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Expected O, but got Unknown
		GameObject val = PrefabManager.Instance.CreateClonedPrefab("QuestGiverRaven", "darkwood_raven");
		if ((Object)(object)val == (Object)null)
		{
			ManualLogSource log = ValheimQuest.Log;
			if (log != null)
			{
				log.LogError((object)"Failed to clone 'darkwood_raven' - the Raven Oracle will not be available. The base prefab may have been renamed or removed.");
			}
			return;
		}
		Interactable[] componentsInChildren = val.GetComponentsInChildren<Interactable>(true);
		foreach (Interactable val2 in componentsInChildren)
		{
			Object.DestroyImmediate((Object)(object)((val2 is Object) ? val2 : null), true);
		}
		Hoverable[] componentsInChildren2 = val.GetComponentsInChildren<Hoverable>(true);
		foreach (Hoverable val3 in componentsInChildren2)
		{
			Object.DestroyImmediate((Object)(object)((val3 is Object) ? val3 : null), true);
		}
		QuestGiverInteract questGiverInteract = val.AddComponent<QuestGiverInteract>();
		if ((Object)(object)questGiverInteract == (Object)null)
		{
			ManualLogSource log2 = ValheimQuest.Log;
			if (log2 != null)
			{
				log2.LogError((object)"Failed to add QuestGiverInteract component! This usually means an interface member is missing.");
			}
		}
		PieceConfig val4 = new PieceConfig();
		val4.Name = "Raven Oracle";
		val4.Description = "Place your own Oracle to begin your personal quest chain. Each player must place their own.";
		val4.PieceTable = "Hammer";
		val4.AddRequirement(new RequirementConfig("Wood", 50, 0, true));
		val4.AddRequirement(new RequirementConfig("Stone", 20, 0, true));
		PieceManager.Instance.AddPiece(new CustomPiece(val, false, val4));
		ManualLogSource log3 = ValheimQuest.Log;
		if (log3 != null)
		{
			log3.LogInfo((object)("Raven Oracle registered. " + $"Interact component present: {(Object)(object)val.GetComponent<QuestGiverInteract>() != (Object)null}"));
		}
	}
}
public class QuestGiverInteract : MonoBehaviour, Interactable, Hoverable
{
	private struct QuestData
	{
		public string enemy;

		public int count;

		public string startMessage;

		public string progressMessage;

		public string completeMessage;

		public (string item, int amount)[] rewards;
	}

	private const int StateNoQuest = 0;

	private static int state = 0;

	private static int currentQuest = 0;

	private static readonly 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!",
			rewards = new(string, int)[3]
			{
				("CookedMeat", 10),
				("Bread", 5),
				("Coins", 20)
			}
		},
		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!",
			rewards = new(string, int)[1] { ("SurtlingCore", 5) }
		},
		new QuestData
		{
			enemy = "Troll",
			count = 2,
			startMessage = "Prove your strength. Slay 2 Trolls.",
			progressMessage = "Trolls",
			completeMessage = "Impressive! Take this bronze and gold.",
			rewards = new(string, int)[2]
			{
				("Bronze", 10),
				("Coins", 200)
			}
		},
		new QuestData
		{
			enemy = "Draugr",
			count = 10,
			startMessage = "The dead walk. Slay 10 Draugr.",
			progressMessage = "Draugr",
			completeMessage = "The dead rest now. Take your reward.",
			rewards = new(string, int)[2]
			{
				("SurtlingCore", 5),
				("Coins", 100)
			}
		},
		new QuestData
		{
			enemy = "Blob",
			count = 3,
			startMessage = "Slay 3 Slimes from the swamp.",
			progressMessage = "Slimes",
			completeMessage = "The swamp is cleaner. Here is your Guck.",
			rewards = new(string, int)[2]
			{
				("Guck", 10),
				("Coins", 60)
			}
		},
		new QuestData
		{
			enemy = "Wraith",
			count = 3,
			startMessage = "Face the darkness. Slay 3 Wraiths.",
			progressMessage = "Wraiths",
			completeMessage = "The spirits are vanquished. Take these chains.",
			rewards = new(string, int)[2]
			{
				("Chain", 5),
				("Coins", 150)
			}
		},
		new QuestData
		{
			enemy = "Wolf",
			count = 10,
			startMessage = "The mountains are dangerous. Slay 10 Wolves.",
			progressMessage = "Wolves",
			completeMessage = "The mountains are safer. Take this iron.",
			rewards = new(string, int)[2]
			{
				("Iron", 20),
				("Coins", 100)
			}
		},
		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.",
			rewards = new(string, int)[2]
			{
				("TrophyHatchling", 1),
				("Coins", 50)
			}
		},
		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.",
			rewards = new(string, int)[2]
			{
				("Coins", 100),
				("Crystal", 20)
			}
		},
		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.",
			rewards = new(string, int)[2]
			{
				("Silver", 20),
				("Coins", 200)
			}
		},
		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.",
			rewards = new(string, int)[2]
			{
				("LoxPelt", 10),
				("Coins", 50)
			}
		},
		new QuestData
		{
			enemy = "Lox",
			count = 5,
			startMessage = "Slay 5 Lox from the plains.",
			progressMessage = "Lox",
			completeMessage = "Mighty warrior! Take this gold.",
			rewards = new(string, int)[1] { ("Coins", 300) }
		},
		new QuestData
		{
			enemy = "Tick",
			count = 10,
			startMessage = "Slay 10 Ticks from the Mistlands.",
			progressMessage = "Ticks",
			completeMessage = "The Mistlands are safer. Take these Black Cores.",
			rewards = new(string, int)[2]
			{
				("Coins", 100),
				("BlackCore", 3)
			}
		},
		new QuestData
		{
			enemy = "Seeker",
			count = 10,
			startMessage = "Slay 10 Seekers in the Mistlands.",
			progressMessage = "Seekers",
			completeMessage = "The seekers fall. Take these Magecaps and gold.",
			rewards = new(string, int)[2]
			{
				("Coins", 200),
				("Magecap", 10)
			}
		},
		new QuestData
		{
			enemy = "Gjall",
			count = 1,
			startMessage = "Face the great Gjall. Slay 1 of them.",
			progressMessage = "Gjalls",
			completeMessage = "Legendary! Take this gold and sap.",
			rewards = new(string, int)[2]
			{
				("Coins", 200),
				("Sap", 20)
			}
		},
		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.",
			rewards = new(string, int)[2]
			{
				("Coins", 200),
				("BlackCore", 3)
			}
		},
		new QuestData
		{
			enemy = "Charred_Twitcher",
			count = 10,
			startMessage = "Slay 10 Charred Twitchers.",
			progressMessage = "Charred Twitchers",
			completeMessage = "They twitch no more. Take your reward.",
			rewards = new(string, int)[2]
			{
				("Coins", 300),
				("BlackCore", 3)
			}
		},
		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!",
			rewards = new(string, int)[2]
			{
				("Coins", 400),
				("MoltenCore", 5)
			}
		}
	};

	private static int StateAllComplete => Quests.Length * 2 + 1;

	public static IEnumerable<string> GetEnemyPrefabNames()
	{
		QuestData[] quests = Quests;
		for (int i = 0; i < quests.Length; i++)
		{
			QuestData quest = quests[i];
			yield return quest.enemy;
		}
	}

	public static IEnumerable<string> GetRewardPrefabNames()
	{
		HashSet<string> seen = new HashSet<string>();
		QuestData[] quests = Quests;
		for (int i = 0; i < quests.Length; i++)
		{
			QuestData quest = quests[i];
			if (quest.rewards == null)
			{
				continue;
			}
			(string item, int amount)[] rewards = quest.rewards;
			for (int j = 0; j < rewards.Length; j++)
			{
				(string item, int amount) reward = rewards[j];
				if (seen.Add(reward.item))
				{
					yield return reward.item;
				}
			}
		}
	}

	public static void LoadState(int savedState, int savedQuest)
	{
		state = savedState;
		currentQuest = Mathf.Clamp(savedQuest, 0, Quests.Length - 1);
		if (IsActiveState())
		{
			QuestData questData = Quests[currentQuest];
			QuestTracker.StartTracking(questData.enemy, questData.count);
		}
	}

	public static void ResetState()
	{
		state = 0;
		currentQuest = 0;
		ManualLogSource log = ValheimQuest.Log;
		if (log != null)
		{
			log.LogInfo((object)"Quest state reset (no saved progress for this character).");
		}
	}

	public static int GetStateAsInt()
	{
		return state;
	}

	public static int GetCurrentQuest()
	{
		return currentQuest;
	}

	private static bool IsActiveState()
	{
		if (state == 0 || state == StateAllComplete)
		{
			return false;
		}
		return state % 2 == 1;
	}

	private static bool IsCompleteState()
	{
		if (state == 0 || state == StateAllComplete)
		{
			return false;
		}
		return state % 2 == 0;
	}

	private static void SetActiveState()
	{
		state = currentQuest * 2 + 1;
	}

	private static void SetCompleteState()
	{
		state = currentQuest * 2 + 2;
	}

	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 == StateAllComplete)
		{
			Message("Raven Oracle: You have completed all my quests. You are a legend!");
			return true;
		}
		if (state == 0 || IsCompleteState())
		{
			if (IsCompleteState())
			{
				if (currentQuest >= Quests.Length - 1)
				{
					state = StateAllComplete;
					Message("Raven Oracle: You have completed all my quests. You are a legend!");
					QuestTracker.StopTracking();
					QuestSaveData.Save(GetStateAsInt(), QuestTracker.GetKillCount(), currentQuest);
					return true;
				}
				currentQuest++;
			}
			QuestData questData = Quests[currentQuest];
			Message("Raven Oracle: " + questData.startMessage);
			QuestTracker.StartTracking(questData.enemy, questData.count);
			SetActiveState();
			QuestSaveData.Save(GetStateAsInt(), 0, currentQuest);
		}
		else if (IsActiveState())
		{
			QuestData quest = Quests[currentQuest];
			int killCount = QuestTracker.GetKillCount();
			if (killCount < quest.count)
			{
				Message($"Raven Oracle: You have slain {killCount}/{quest.count} {quest.progressMessage}. Keep going!");
				return true;
			}
			if (!HasRoomForReward(val, quest))
			{
				Message("Raven Oracle: You have no room to carry your reward. Return when your pack is lighter.");
				return true;
			}
			Message("Raven Oracle: " + quest.completeMessage);
			GiveReward(val, quest);
			SetCompleteState();
			QuestSaveData.Save(GetStateAsInt(), killCount, currentQuest);
		}
		return true;
	}

	public bool UseItem(Humanoid user, ItemData item)
	{
		return false;
	}

	public string GetHoverText()
	{
		if (state == StateAllComplete)
		{
			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 float GetHoverOffset()
	{
		return 0f;
	}

	private static bool HasRoomForReward(Player player, QuestData quest)
	{
		if (quest.rewards == null)
		{
			return true;
		}
		(string, int)[] rewards = quest.rewards;
		for (int i = 0; i < rewards.Length; i++)
		{
			(string, int) tuple = rewards[i];
			GameObject val = ResolvePrefab(tuple.Item1);
			if ((Object)(object)val == (Object)null)
			{
				ManualLogSource log = ValheimQuest.Log;
				if (log != null)
				{
					log.LogError((object)("Reward prefab '" + tuple.Item1 + "' could not be resolved."));
				}
			}
			else if (!((Humanoid)player).GetInventory().CanAddItem(val, tuple.Item2))
			{
				return false;
			}
		}
		return true;
	}

	private static void GiveReward(Player player, QuestData quest)
	{
		if (quest.rewards == null)
		{
			return;
		}
		(string, int)[] rewards = quest.rewards;
		for (int i = 0; i < rewards.Length; i++)
		{
			(string, int) tuple = rewards[i];
			if (!TryGiveItem(player, tuple.Item1, tuple.Item2))
			{
				ManualLogSource log = ValheimQuest.Log;
				if (log != null)
				{
					log.LogWarning((object)$"Failed to grant reward {tuple.Item1} x{tuple.Item2}");
				}
			}
		}
	}

	private static bool TryGiveItem(Player player, string prefabName, int amount)
	{
		GameObject val = ResolvePrefab(prefabName);
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		ItemDrop component = val.GetComponent<ItemDrop>();
		if ((Object)(object)component == (Object)null)
		{
			return false;
		}
		Inventory inventory = ((Humanoid)player).GetInventory();
		int num = Mathf.Max(1, component.m_itemData.m_shared.m_maxStackSize);
		int num2 = amount;
		while (num2 > 0)
		{
			int num3 = Mathf.Min(num2, num);
			ItemData val2 = component.m_itemData.Clone();
			val2.m_stack = num3;
			val2.m_dropPrefab = val;
			if (!inventory.AddItem(val2))
			{
				return num2 < amount;
			}
			num2 -= num3;
		}
		return true;
	}

	private static GameObject ResolvePrefab(string prefabName)
	{
		GameObject val = null;
		if (PrefabManager.Instance != null)
		{
			val = PrefabManager.Instance.GetPrefab(prefabName);
		}
		if ((Object)(object)val == (Object)null && (Object)(object)ZNetScene.instance != (Object)null)
		{
			val = ZNetScene.instance.GetPrefab(prefabName);
		}
		return val;
	}

	private static void Message(string text)
	{
		if ((Object)(object)MessageHud.instance != (Object)null)
		{
			MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, true);
		}
	}
}
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();
			ManualLogSource log = ValheimQuest.Log;
			if (log != null)
			{
				log.LogInfo((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 || localPlayer.m_customData == null)
		{
			return false;
		}
		if (!localPlayer.m_customData.ContainsKey("ValheimQuest_State"))
		{
			return false;
		}
		questState = ReadInt(localPlayer, "ValheimQuest_State");
		killCount = ReadInt(localPlayer, "ValheimQuest_KillCount");
		currentQuest = ReadInt(localPlayer, "ValheimQuest_CurrentQuest");
		ManualLogSource log = ValheimQuest.Log;
		if (log != null)
		{
			log.LogInfo((object)$"Quest progress loaded - state {questState}, kills {killCount}, quest {currentQuest}");
		}
		return true;
	}

	private static int ReadInt(Player player, string key)
	{
		if (!player.m_customData.TryGetValue(key, out var value))
		{
			return 0;
		}
		int result;
		return int.TryParse(value, out result) ? result : 0;
	}
}
[HarmonyPatch(typeof(Player), "OnSpawned")]
public class PlayerSpawnPatch
{
	private static bool Prepare()
	{
		bool flag = AccessTools.Method(typeof(Player), "OnSpawned", (Type[])null, (Type[])null) != null;
		if (!flag)
		{
			ManualLogSource log = ValheimQuest.Log;
			if (log != null)
			{
				log.LogError((object)"Player.OnSpawned not found - quest progress will not load.");
			}
		}
		return flag;
	}

	private static void Postfix(Player __instance)
	{
		if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
		{
			return;
		}
		if (QuestSaveData.Load(out var questState, out var killCount, out var currentQuest))
		{
			QuestTracker.LoadState(killCount);
			QuestGiverInteract.LoadState(questState, currentQuest);
			ManualLogSource log = ValheimQuest.Log;
			if (log != null)
			{
				log.LogInfo((object)"Quest state restored.");
			}
		}
		else
		{
			QuestTracker.ResetState();
			QuestGiverInteract.ResetState();
		}
	}
}
public class QuestTracker
{
	private const float KillCreditRange = 60f;

	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();
		ManualLogSource log = ValheimQuest.Log;
		if (log != null)
		{
			log.LogInfo((object)$"Quest started - tracking {enemyName} kills (need {required}).");
		}
	}

	public static void LoadState(int savedKillCount)
	{
		killCount = savedKillCount;
		isTracking = true;
		countedKills.Clear();
		ManualLogSource log = ValheimQuest.Log;
		if (log != null)
		{
			log.LogInfo((object)$"Kill count loaded: {killCount}");
		}
	}

	public static void ResetState()
	{
		killCount = 0;
		isTracking = false;
		targetEnemy = "";
		killsRequired = 0;
		countedKills.Clear();
	}

	public static void StopTracking()
	{
		isTracking = false;
	}

	public static int GetKillCount()
	{
		return killCount;
	}

	public static string GetTargetEnemy()
	{
		return targetEnemy;
	}

	public static bool IsTracking()
	{
		return isTracking;
	}

	public static void AddKill(int instanceId, string enemyName)
	{
		if (isTracking && !string.IsNullOrEmpty(targetEnemy) && enemyName.Contains(targetEnemy) && countedKills.Add(instanceId))
		{
			killCount++;
			ManualLogSource log = ValheimQuest.Log;
			if (log != null)
			{
				log.LogInfo((object)$"{targetEnemy} killed - total {killCount}/{killsRequired}");
			}
			if ((Object)(object)MessageHud.instance != (Object)null)
			{
				MessageHud.instance.ShowMessage((MessageType)1, $"{targetEnemy}s slain: {killCount}/{killsRequired}", 0, (Sprite)null, false, true);
			}
			QuestSaveData.Save(QuestGiverInteract.GetStateAsInt(), killCount, QuestGiverInteract.GetCurrentQuest());
		}
	}
}
[HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")]
public class EnemyDeathPatch
{
	private static bool Prepare()
	{
		bool flag = AccessTools.Method(typeof(CharacterDrop), "GenerateDropList", (Type[])null, (Type[])null) != null;
		if (!flag)
		{
			ManualLogSource log = ValheimQuest.Log;
			if (log != null)
			{
				log.LogError((object)"CharacterDrop.GenerateDropList not found - kills will not be counted.");
			}
		}
		return flag;
	}

	private static void Postfix(CharacterDrop __instance)
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)Player.m_localPlayer == (Object)null) && QuestTracker.IsTracking() && !((Object)(object)__instance == (Object)null))
		{
			float num = Vector3.Distance(((Component)__instance).transform.position, ((Component)Player.m_localPlayer).transform.position);
			if (!(num > 60f))
			{
				QuestTracker.AddKill(((Object)((Component)__instance).gameObject).GetInstanceID(), ((Object)((Component)__instance).gameObject).name);
			}
		}
	}
}