Decompiled source of Clanheim Treasure Table v1.0.5

ClanheimTreasureTable.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ClanheimTreasureTable")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ClanheimTreasureTable")]
[assembly: AssemblyTitle("ClanheimTreasureTable")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 ClanheimTreasureTable
{
	[BepInPlugin("com.clanheim.treasuretable", "Clanheim Treasure Table", "1.0.5")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class ClanheimTreasureTablePlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.clanheim.treasuretable";

		public const string PluginName = "Clanheim Treasure Table";

		public const string PluginVersion = "1.0.5";

		internal static ClanheimTreasureTablePlugin Instance;

		internal static void LogInfo(string message)
		{
			ClanheimTreasureTablePlugin instance = Instance;
			if (instance != null)
			{
				((BaseUnityPlugin)instance).Logger.LogInfo((object)message);
			}
		}

		internal static void LogWarning(string message)
		{
			ClanheimTreasureTablePlugin instance = Instance;
			if (instance != null)
			{
				((BaseUnityPlugin)instance).Logger.LogWarning((object)message);
			}
		}

		private void Awake()
		{
			Instance = this;
			PrefabManager.OnVanillaPrefabsAvailable += RegisterContent;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Clanheim Treasure Table 1.0.5 loading.");
		}

		private void RegisterContent()
		{
			try
			{
				RegisterTable();
				RegisterLocalization();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Clanheim Treasure Table registered.");
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"Registration failed: {arg}");
			}
			finally
			{
				PrefabManager.OnVanillaPrefabsAvailable -= RegisterContent;
			}
		}

		private void RegisterTable()
		{
			//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_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			PieceConfig val = new PieceConfig
			{
				Name = "$clanheim_tt_name",
				Description = "$clanheim_tt_desc",
				PieceTable = "_HammerPieceTable",
				Category = "Misc",
				CraftingStation = "piece_workbench"
			};
			val.AddRequirement(new RequirementConfig("FineWood", 20, 0, true));
			val.AddRequirement(new RequirementConfig("Bronze", 10, 0, true));
			val.AddRequirement(new RequirementConfig("SurtlingCore", 5, 0, true));
			val.AddRequirement(new RequirementConfig("DeerHide", 10, 0, true));
			val.AddRequirement(new RequirementConfig("AncientSeed", 1, 0, true));
			CustomPiece val2 = new CustomPiece("piece_clanheim_treasure_table", "piece_cartographytable", val);
			GameObject piecePrefab = val2.PiecePrefab;
			if ((Object)(object)piecePrefab != (Object)null)
			{
				MapTable[] componentsInChildren = piecePrefab.GetComponentsInChildren<MapTable>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					Object.Destroy((Object)(object)componentsInChildren[i]);
				}
				if ((Object)(object)piecePrefab.GetComponent<TreasureTableBehaviour>() == (Object)null)
				{
					piecePrefab.AddComponent<TreasureTableBehaviour>();
				}
			}
			PieceManager.Instance.AddPiece(val2);
		}

		private void RegisterLocalization()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			LocalizationConfig val = new LocalizationConfig("English");
			val.Translations["clanheim_tt_name"] = "Clanheim Treasure Table";
			val.Translations["clanheim_tt_desc"] = "A Viking war table that binds its treasure hunt to the Viking who placed it.";
			LocalizationManager.Instance.AddLocalization(val);
		}
	}
	public sealed class TreasureTableBehaviour : MonoBehaviour, Hoverable, Interactable
	{
		private ZNetView _nview;

		private Piece _piece;

		private const string OwnerIdKey = "ctt_owner_id";

		private const string OwnerNameKey = "ctt_owner_name";

		private const string StageKey = "ctt_stage";

		private const string CompleteKey = "ctt_complete";

		private void Awake()
		{
			_nview = ((Component)this).GetComponent<ZNetView>();
			_piece = ((Component)this).GetComponent<Piece>();
		}

		private void Start()
		{
			TryBindToCreator();
		}

		private ZDO GetZdo()
		{
			if (!((Object)(object)_nview != (Object)null) || !_nview.IsValid())
			{
				return null;
			}
			return _nview.GetZDO();
		}

		private void TryBindToCreator()
		{
			ZDO zdo = GetZdo();
			if (zdo == null || !string.IsNullOrEmpty(zdo.GetString("ctt_owner_id", "")))
			{
				return;
			}
			long num = 0L;
			try
			{
				if ((Object)(object)_piece != (Object)null)
				{
					MethodInfo method = typeof(Piece).GetMethod("GetCreator");
					if (method != null)
					{
						object obj = method.Invoke(_piece, null);
						if (obj != null)
						{
							num = Convert.ToInt64(obj);
						}
					}
				}
			}
			catch (Exception ex)
			{
				ClanheimTreasureTablePlugin.LogWarning("Could not read table creator yet: " + ex.Message);
			}
			if (num != 0L)
			{
				zdo.Set("ctt_owner_id", num.ToString());
				zdo.Set("ctt_stage", 1);
				zdo.Set("ctt_complete", false);
				if ((Object)(object)Player.m_localPlayer != (Object)null && GetLocalPlayerId() == num.ToString())
				{
					zdo.Set("ctt_owner_name", Player.m_localPlayer.GetPlayerName());
				}
			}
		}

		public string GetHoverName()
		{
			return "$clanheim_tt_name";
		}

		public float GetHoverOffset()
		{
			return 1.2f;
		}

		public string GetHoverText()
		{
			ZDO zdo = GetZdo();
			if (zdo == null)
			{
				return "";
			}
			TryBindToCreator();
			string text = zdo.GetString("ctt_owner_name", "");
			string text2 = zdo.GetString("ctt_owner_id", "");
			int num = Math.Max(1, zdo.GetInt("ctt_stage", 1));
			if (text2 == GetLocalPlayerId() && string.IsNullOrEmpty(text) && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				text = Player.m_localPlayer.GetPlayerName();
				zdo.Set("ctt_owner_name", text);
			}
			string text3 = (string.IsNullOrEmpty(text) ? "Unknown Viking" : text);
			if (zdo.GetBool("ctt_complete", false))
			{
				return "Clanheim Treasure Table\nOwner: " + text3 + "\nTreasure Hunt Complete";
			}
			if (text2 == GetLocalPlayerId())
			{
				return $"Clanheim Treasure Table\nOwner: {text3}\nStage {num}/8\n" + "[<color=yellow><b>$KEY_Use</b></color>] View quest\n[<color=yellow><b>Alt + $KEY_Use</b></color>] Submit quest";
			}
			return "Clanheim Treasure Table\nOwner: " + text3;
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (!hold)
			{
				Player val = (Player)(object)((user is Player) ? user : null);
				if (val != null)
				{
					ZDO zdo = GetZdo();
					if (zdo == null)
					{
						return false;
					}
					TryBindToCreator();
					string localPlayerId = GetLocalPlayerId();
					string text = zdo.GetString("ctt_owner_id", "");
					if (string.IsNullOrEmpty(text))
					{
						text = localPlayerId;
						zdo.Set("ctt_owner_id", text);
						zdo.Set("ctt_owner_name", val.GetPlayerName());
						zdo.Set("ctt_stage", 1);
					}
					if (text != localPlayerId)
					{
						MessageHud instance = MessageHud.instance;
						if (instance != null)
						{
							instance.ShowMessage((MessageType)2, "This Treasure Table belongs to " + zdo.GetString("ctt_owner_name", "another Viking") + ".", 0, (Sprite)null, false, true);
						}
						return true;
					}
					if (string.IsNullOrEmpty(zdo.GetString("ctt_owner_name", "")))
					{
						zdo.Set("ctt_owner_name", val.GetPlayerName());
					}
					if (zdo.GetBool("ctt_complete", false))
					{
						MessageHud instance2 = MessageHud.instance;
						if (instance2 != null)
						{
							instance2.ShowMessage((MessageType)1, "CLANHEIM TREASURE HUNT\n\nComplete.\nThe old hoard has yielded to you.", 0, (Sprite)null, false, true);
						}
						return true;
					}
					if (alt)
					{
						TrySubmit(val, zdo);
					}
					else
					{
						ShowQuest(val, zdo);
					}
					return true;
				}
			}
			return false;
		}

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

		private void ShowQuest(Player player, ZDO zdo)
		{
			int num = Math.Max(1, zdo.GetInt("ctt_stage", 1));
			TreasureQuest treasureQuest = QuestDatabase.Get(num);
			if (treasureQuest != null)
			{
				string text = "CLANHEIM TREASURE HUNT\n" + $"Stage {num}/8 — {treasureQuest.Title}\n\n" + treasureQuest.Lore + "\n\nREQUIRED OFFERINGS\n" + treasureQuest.ProgressText(player) + "\n\nREWARD\n" + treasureQuest.RewardText + "\n\n" + treasureQuest.Clue + "\n\nAlt + Use to submit the complete offering.";
				MessageHud instance = MessageHud.instance;
				if (instance != null)
				{
					instance.ShowMessage((MessageType)1, text, 0, (Sprite)null, false, true);
				}
			}
		}

		private void TrySubmit(Player player, ZDO zdo)
		{
			int num = Math.Max(1, zdo.GetInt("ctt_stage", 1));
			TreasureQuest treasureQuest = QuestDatabase.Get(num);
			if (treasureQuest == null)
			{
				return;
			}
			List<string> list = new List<string>();
			foreach (QuestRequirement requirement in treasureQuest.Requirements)
			{
				int num2 = InventoryUtil.Count(((Humanoid)player).GetInventory(), requirement.Prefab);
				if (num2 < requirement.Amount)
				{
					list.Add($"{requirement.Display}: {num2}/{requirement.Amount}");
				}
			}
			if (list.Count > 0)
			{
				MessageHud instance = MessageHud.instance;
				if (instance != null)
				{
					instance.ShowMessage((MessageType)1, $"STAGE {num} INCOMPLETE\n\nMissing:\n- " + string.Join("\n- ", list.ToArray()), 0, (Sprite)null, false, true);
				}
				return;
			}
			foreach (QuestRequirement requirement2 in treasureQuest.Requirements)
			{
				InventoryUtil.Remove(((Humanoid)player).GetInventory(), requirement2.Prefab, requirement2.Amount);
			}
			foreach (QuestReward reward in treasureQuest.Rewards)
			{
				RewardUtil.Give(player, reward.Prefab, reward.Amount);
			}
			if (num >= 8)
			{
				zdo.Set("ctt_complete", true);
				MessageHud instance2 = MessageHud.instance;
				if (instance2 != null)
				{
					instance2.ShowMessage((MessageType)1, "THE HOARD OF CLANHEIM — COMPLETE\n\nEvery mark has been followed and every offering made.\nYou have completed the Clanheim Treasure Hunt.\n\n" + treasureQuest.RewardText, 0, (Sprite)null, false, true);
				}
			}
			else
			{
				zdo.Set("ctt_stage", num + 1);
				TreasureQuest treasureQuest2 = QuestDatabase.Get(num + 1);
				MessageHud instance3 = MessageHud.instance;
				if (instance3 != null)
				{
					instance3.ShowMessage((MessageType)1, "QUEST COMPLETE — " + treasureQuest.Title + "\n\nReward:\n" + treasureQuest.RewardText + "\n\n" + treasureQuest.Clue + "\n\n" + $"Stage {num + 1} unlocked: {treasureQuest2?.Title}", 0, (Sprite)null, false, true);
				}
			}
			ClanheimTreasureTablePlugin.LogInfo($"Treasure Table: {player.GetPlayerName()} completed Stage {num}.");
		}

		private static string GetLocalPlayerId()
		{
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				return "";
			}
			try
			{
				return Player.m_localPlayer.GetPlayerID().ToString();
			}
			catch
			{
				return Player.m_localPlayer.GetPlayerName();
			}
		}
	}
	public static class InventoryUtil
	{
		public static int Count(Inventory inventory, string prefabName)
		{
			if (inventory == null)
			{
				return 0;
			}
			int num = 0;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if ((Object)(object)allItem?.m_dropPrefab != (Object)null && string.Equals(((Object)allItem.m_dropPrefab).name, prefabName, StringComparison.OrdinalIgnoreCase))
				{
					num += allItem.m_stack;
				}
			}
			return num;
		}

		public static bool Remove(Inventory inventory, string prefabName, int amount)
		{
			if (inventory == null || amount <= 0)
			{
				return false;
			}
			int num = amount;
			foreach (ItemData item in new List<ItemData>(inventory.GetAllItems()))
			{
				if (num <= 0)
				{
					break;
				}
				if (!((Object)(object)item?.m_dropPrefab == (Object)null) && string.Equals(((Object)item.m_dropPrefab).name, prefabName, StringComparison.OrdinalIgnoreCase))
				{
					int num2 = Math.Min(item.m_stack, num);
					inventory.RemoveItem(item, num2);
					num -= num2;
				}
			}
			return num <= 0;
		}
	}
	public static class RewardUtil
	{
		public static void Give(Player player, string prefabName, int amount)
		{
			//IL_0082: 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)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || amount <= 0 || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabName);
			if ((Object)(object)itemPrefab == (Object)null)
			{
				ClanheimTreasureTablePlugin.LogWarning("Reward prefab not found: " + prefabName);
				return;
			}
			ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			int val = Math.Max(1, component.m_itemData.m_shared.m_maxStackSize);
			int num = amount;
			int num2 = 0;
			while (num > 0)
			{
				int num3 = Math.Min(val, num);
				Vector3 val2 = ((Component)player).transform.forward * (1f + (float)num2 * 0.15f) + Vector3.up * 0.8f;
				ItemDrop component2 = Object.Instantiate<GameObject>(itemPrefab, ((Component)player).transform.position + val2, Quaternion.identity).GetComponent<ItemDrop>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.m_itemData.m_stack = num3;
				}
				num -= num3;
				num2++;
			}
		}
	}
	public sealed class QuestRequirement
	{
		public string Prefab;

		public string Display;

		public int Amount;

		public QuestRequirement(string prefab, string display, int amount)
		{
			Prefab = prefab;
			Display = display;
			Amount = amount;
		}
	}
	public sealed class QuestReward
	{
		public string Prefab;

		public int Amount;

		public QuestReward(string prefab, int amount)
		{
			Prefab = prefab;
			Amount = amount;
		}
	}
	public sealed class TreasureQuest
	{
		public int Stage;

		public string Title;

		public string Lore;

		public string Clue;

		public string RewardText;

		public List<QuestRequirement> Requirements = new List<QuestRequirement>();

		public List<QuestReward> Rewards = new List<QuestReward>();

		public string ProgressText(Player player)
		{
			List<string> list = new List<string>();
			foreach (QuestRequirement requirement in Requirements)
			{
				int num = InventoryUtil.Count(((Humanoid)player).GetInventory(), requirement.Prefab);
				list.Add(string.Format("{0} {1}: {2}/{3}", (num >= requirement.Amount) ? "✓" : "•", requirement.Display, num, requirement.Amount));
			}
			return string.Join("\n", list.ToArray());
		}
	}
	public static class QuestDatabase
	{
		private static readonly Dictionary<int, TreasureQuest> Q = new Dictionary<int, TreasureQuest>
		{
			[1] = new TreasureQuest
			{
				Stage = 1,
				Title = "The First Mark",
				Lore = "Before the old paths open, the table demands proof that its owner can survive beyond the firelight.",
				Clue = "The next mark lies where the pines swallow the sun.",
				RewardText = "150 Coins\n10 Fine Wood\n1 Amber",
				Requirements = new List<QuestRequirement>
				{
					R("DeerHide", "Deer Hide", 20),
					R("RawMeat", "Raw Meat", 15),
					R("TrophyEikthyr", "Eikthyr Trophy", 1)
				},
				Rewards = new List<QuestReward>
				{
					G("Coins", 150),
					G("FineWood", 10),
					G("Amber", 1)
				}
			},
			[2] = new TreasureQuest
			{
				Stage = 2,
				Title = "Whispers Beneath the Pines",
				Lore = "The first mark points beneath the Black Forest canopy, where bronze and ancient roots guard the second secret.",
				Clue = "The dead keep what the living have forgotten.",
				RewardText = "250 Coins\n10 Bronze\n1 AmberPearl",
				Requirements = new List<QuestRequirement>
				{
					R("Copper", "Copper", 20),
					R("Tin", "Tin", 20),
					R("TrollHide", "Troll Hide", 10),
					R("TrophyTheElder", "The Elder Trophy", 1)
				},
				Rewards = new List<QuestReward>
				{
					G("Coins", 250),
					G("Bronze", 10),
					G("AmberPearl", 1)
				}
			},
			[3] = new TreasureQuest
			{
				Stage = 3,
				Title = "The Drowned Warrior",
				Lore = "A drowned warrior carried the third mark into the Swamp. Only an offering from the dead will call it back.",
				Clue = "Where stone reaches toward the frozen sky, the fourth mark waits beneath the silver.",
				RewardText = "350 Coins\n10 Iron\n1 Ruby",
				Requirements = new List<QuestRequirement>
				{
					R("Iron", "Iron", 25),
					R("Bloodbag", "Bloodbag", 15),
					R("Guck", "Guck", 10),
					R("TrophyBonemass", "Bonemass Trophy", 1)
				},
				Rewards = new List<QuestReward>
				{
					G("Coins", 350),
					G("Iron", 10),
					G("Ruby", 1)
				}
			},
			[4] = new TreasureQuest
			{
				Stage = 4,
				Title = "Silver Under Snow",
				Lore = "The fourth rune was carried above the clouds. Wolves, drakes and silver guard the mountain path.",
				Clue = "Beyond the mountains lies a field where even kings burn.",
				RewardText = "450 Coins\n10 Silver\n5 Crystal",
				Requirements = new List<QuestRequirement>
				{
					R("Silver", "Silver", 25),
					R("WolfPelt", "Wolf Pelt", 15),
					R("FreezeGland", "Freeze Gland", 10),
					R("TrophyDragonQueen", "Moder Trophy", 1)
				},
				Rewards = new List<QuestReward>
				{
					G("Coins", 450),
					G("Silver", 10),
					G("Crystal", 5)
				}
			},
			[5] = new TreasureQuest
			{
				Stage = 5,
				Title = "The Fallen Banner",
				Lore = "A king's broken banner marks the fifth road. The Plains demand black metal and proof of a fallen ruler.",
				Clue = "Mist hides the road, but not from those who carry light.",
				RewardText = "550 Coins\n10 Black Metal\n10 Needle",
				Requirements = new List<QuestRequirement>
				{
					R("BlackMetal", "Black Metal", 30),
					R("LoxPelt", "Lox Pelt", 15),
					R("Tar", "Tar", 15),
					R("TrophyGoblinKing", "Yagluth Trophy", 1)
				},
				Rewards = new List<QuestReward>
				{
					G("Coins", 550),
					G("BlackMetal", 10),
					G("Needle", 10)
				}
			},
			[6] = new TreasureQuest
			{
				Stage = 6,
				Title = "Eyes in the Mist",
				Lore = "The sixth mark is hidden where the world itself disappears. Bring the things that only Mistlands travellers know.",
				Clue = "The fragments form a key, but an old debt still remains.",
				RewardText = "700 Coins\n10 Black Marble\n10 Royal Jelly",
				Requirements = new List<QuestRequirement>
				{
					R("BlackMarble", "Black Marble", 30),
					R("Softtissue", "Soft Tissue", 15),
					R("Carapace", "Carapace", 20),
					R("TrophySeekerQueen", "Seeker Queen Trophy", 1)
				},
				Rewards = new List<QuestReward>
				{
					G("Coins", 700),
					G("BlackMarble", 10),
					G("RoyalJelly", 10)
				}
			},
			[7] = new TreasureQuest
			{
				Stage = 7,
				Title = "The Seven Seals",
				Lore = "Seven seals once guarded the hoard. The final seal is not won by one biome, but by proving every road behind you was truly walked.",
				Clue = "Return the trophies of the old rulers. Only then will the final path reveal itself.",
				RewardText = "900 Coins\n20 Yggdrasil Wood\n20 Black Marble",
				Requirements = new List<QuestRequirement>
				{
					R("TrophyEikthyr", "Eikthyr Trophy", 1),
					R("TrophyTheElder", "The Elder Trophy", 1),
					R("TrophyBonemass", "Bonemass Trophy", 1),
					R("TrophyDragonQueen", "Moder Trophy", 1),
					R("TrophyGoblinKing", "Yagluth Trophy", 1),
					R("TrophySeekerQueen", "Seeker Queen Trophy", 1)
				},
				Rewards = new List<QuestReward>
				{
					G("Coins", 900),
					G("YggdrasilWood", 20),
					G("BlackMarble", 20)
				}
			},
			[8] = new TreasureQuest
			{
				Stage = 8,
				Title = "The Hoard of Clanheim",
				Lore = "Every fragment points home. The last offering is not wealth, but the materials of every age laid together before the old table.",
				Clue = "The old hoard recognises its keeper.",
				RewardText = "2000 Coins\n30 Iron\n30 Silver\n30 Black Metal\n10 Ruby\nCompletion prestige",
				Requirements = new List<QuestRequirement>
				{
					R("FineWood", "Fine Wood", 50),
					R("Bronze", "Bronze", 20),
					R("Iron", "Iron", 30),
					R("Silver", "Silver", 30),
					R("BlackMetal", "Black Metal", 30),
					R("BlackMarble", "Black Marble", 30)
				},
				Rewards = new List<QuestReward>
				{
					G("Coins", 2000),
					G("Iron", 30),
					G("Silver", 30),
					G("BlackMetal", 30),
					G("Ruby", 10)
				}
			}
		};

		private static QuestRequirement R(string prefab, string display, int amount)
		{
			return new QuestRequirement(prefab, display, amount);
		}

		private static QuestReward G(string prefab, int amount)
		{
			return new QuestReward(prefab, amount);
		}

		public static TreasureQuest Get(int stage)
		{
			if (!Q.TryGetValue(stage, out var value))
			{
				return null;
			}
			return value;
		}
	}
}