Decompiled source of Byname v0.3.2

plugins/Byname.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using Byname.Commands;
using Byname.Config;
using Byname.Net;
using Byname.Stats;
using Byname.Titles;
using Byname.Titles.Catalog;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: AssemblyCompany("RAGEmedia")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A Valheim mod.")]
[assembly: AssemblyFileVersion("0.3.2.0")]
[assembly: AssemblyInformationalVersion("0.3.2+3d2524af24af9a6a1a03fed59080c23479836c8c")]
[assembly: AssemblyProduct("Byname")]
[assembly: AssemblyTitle("Byname")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.3.2.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 Byname
{
	[BepInPlugin("com.ragemedia.byname", "Byname", "0.3.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class BynamePlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.ragemedia.byname";

		public const string PluginName = "Byname";

		public const string PluginVersion = "0.3.2";

		internal static BynamePlugin Instance;

		private readonly Harmony _harmony = new Harmony("com.ragemedia.byname");

		private void Awake()
		{
			Instance = this;
			BindConfig();
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			VerifyPatches();
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new BynameCommand());
			LogInfo("Registered /byname.");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void BindConfig()
		{
			BynameConfig.Bind(((BaseUnityPlugin)this).Config);
		}

		private void VerifyPatches()
		{
			List<MethodBase> list = _harmony.GetPatchedMethods().ToList();
			LogInfo($"Harmony bound {list.Count} target(s):");
			foreach (MethodBase item in list)
			{
				LogInfo("  bound  " + item.DeclaringType?.FullName + "." + item.Name);
			}
			int num = 0;
			foreach (Type item2 in from t in Assembly.GetExecutingAssembly().GetTypes()
				where t.GetCustomAttributes(typeof(HarmonyPatch), inherit: true).Any()
				select t)
			{
				List<HarmonyMethod> list2 = (from HarmonyPatch a in item2.GetCustomAttributes(typeof(HarmonyPatch), inherit: true)
					select ((HarmonyAttribute)a).info).ToList();
				HarmonyMethod val;
				try
				{
					val = HarmonyMethod.Merge(list2);
				}
				catch (Exception ex)
				{
					LogError("  UNRESOLVED  " + item2.Name + ": could not merge patch attributes: " + ex.Message);
					num++;
					continue;
				}
				if (!(val?.declaringType == null) && !string.IsNullOrEmpty(val.methodName) && AccessTools.Method(val.declaringType, val.methodName, val.argumentTypes, (Type[])null) == null)
				{
					num++;
					LogError("  UNRESOLVED  " + item2.Name + " -> " + val.declaringType.Name + "." + val.methodName + " does not exist. This patch will never run. The game version likely changed; re-check the method against the decompiled source.");
				}
			}
			if (num > 0)
			{
				LogError(string.Format("{0}: {1} patch target(s) failed to resolve. ", "Byname", num) + "This mod is loaded but not fully functional.");
			}
			else if (list.Count == 0)
			{
				LogWarning("Byname: loaded, but bound zero patches. Expected if this mod only adds content via Jotunn.");
			}
			else
			{
				LogInfo("Byname v0.3.2 ready.");
			}
		}

		internal static void LogInfo(string msg)
		{
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)("[Byname] " + msg));
		}

		internal static void LogWarning(string msg)
		{
			((BaseUnityPlugin)Instance).Logger.LogWarning((object)("[Byname] " + msg));
		}

		internal static void LogError(string msg)
		{
			((BaseUnityPlugin)Instance).Logger.LogError((object)("[Byname] " + msg));
		}

		internal static void LogVerbose(string msg)
		{
			if (BynameConfig.VerboseLogging != null && BynameConfig.VerboseLogging.Value)
			{
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)("[Byname] " + msg));
			}
		}
	}
}
namespace Byname.Titles
{
	internal static class FragmentCatalog
	{
		private static readonly List<TitleFragment> AllFragments = FateFragments.All.Concat(WarFragments.All).Concat(WildFragments.All).Concat(HearthFragments.All)
			.Concat(BeastFragments.All)
			.Concat(TierFragments.All)
			.Concat(EarlyFragments.All)
			.Concat(DoomFragments.All)
			.ToList();

		private static readonly List<TitleTemplate> Patterns = new List<TitleTemplate>
		{
			new TitleTemplate("{epithet} {noun}"),
			new TitleTemplate("the {epithet}"),
			new TitleTemplate("the {epithet} {noun}", 1),
			new TitleTemplate("{noun} of the {domain}", 2),
			new TitleTemplate("{epithet} {noun} of the {domain}", 4)
		};

		internal static IReadOnlyList<TitleFragment> Fragments => AllFragments;

		internal static IReadOnlyList<TitleTemplate> Templates => Patterns;

		internal static IReadOnlyList<PlayerStatType> TrackedStats => AllFragments.SelectMany((TitleFragment f) => f.Reads).Distinct().ToList();
	}
	internal static class TitleEngine
	{
		private const float PoolDepth = 1f;

		private const float SlotCost = 1.5f;

		private const float RepeatedCategoryCost = 1f;

		private const float OnlyFallbacksCost = 100f;

		internal static ComposedTitle Compose(IStatSource stats, long playerId, int epoch)
		{
			int seed = Seed(playerId, epoch);
			List<TitleFragment> qualifying = Qualifying(stats);
			if (BynameConfig.VerboseLogging.Value)
			{
				LogEvaluation(stats, qualifying, seed);
			}
			Dictionary<TitleSlot, List<TitleFragment>> ranked = BuildPools(qualifying, seed, epoch);
			int value = BynameConfig.MaxTitleLength.Value;
			ComposedTitle composedTitle = null;
			bool bStrict = false;
			int bFlourish = 0;
			int bTie = 0;
			foreach (TitleTemplate template in FragmentCatalog.Templates)
			{
				bool[] array = new bool[2] { true, false };
				foreach (bool flag in array)
				{
					Dictionary<TitleSlot, TitleFragment> chosen = TryFill(template, ranked, flag, playerId);
					if (chosen == null)
					{
						continue;
					}
					string text = template.Render(chosen, playerId);
					if (text.Length <= value)
					{
						List<TitleFragment> list = template.Slots.Select((TitleSlot sl) => chosen[sl]).ToList();
						List<string> words = list.Select((TitleFragment f) => f.TextFor(playerId)).ToList();
						Rarity rarity = (Rarity)list.Max((TitleFragment f) => (int)f.Rarity);
						ComposedTitle composedTitle2 = new ComposedTitle(text, rarity, list, words, Score(list));
						int num = TieBreak(template.Pattern, seed);
						if (composedTitle == null || Beats(composedTitle2, flag, template.Flourish, num, composedTitle, bStrict, bFlourish, bTie))
						{
							composedTitle = composedTitle2;
							bStrict = flag;
							bFlourish = template.Flourish;
							bTie = num;
						}
					}
				}
			}
			return composedTitle;
		}

		private static float Score(IReadOnlyList<TitleFragment> parts)
		{
			int num = parts.Count - parts.Select((TitleFragment f) => f.Category).Distinct().Count();
			float num2 = parts.Sum((TitleFragment f) => f.Score) - 1.5f * (float)parts.Count - 1f * (float)num;
			if (!parts.All((TitleFragment f) => f.IsFallback))
			{
				return num2;
			}
			return num2 - 100f;
		}

		private static bool Beats(ComposedTitle a, bool aStrict, int aFlourish, int aTie, ComposedTitle b, bool bStrict, int bFlourish, int bTie)
		{
			if (a.Score > b.Score + 0.001f)
			{
				return true;
			}
			if (a.Score < b.Score - 0.001f)
			{
				return false;
			}
			if (aStrict != bStrict)
			{
				return aStrict;
			}
			if (aFlourish != bFlourish)
			{
				return aFlourish > bFlourish;
			}
			return aTie < bTie;
		}

		private static Dictionary<TitleSlot, List<TitleFragment>> BuildPools(IEnumerable<TitleFragment> qualifying, int seed, int epoch)
		{
			Dictionary<TitleSlot, List<TitleFragment>> dictionary = new Dictionary<TitleSlot, List<TitleFragment>>();
			foreach (IGrouping<TitleSlot, TitleFragment> item in from f in qualifying
				group f by f.Slot)
			{
				List<TitleFragment> earned = (item.Any((TitleFragment f) => !f.IsFallback) ? item.Where((TitleFragment f) => !f.IsFallback).ToList() : item.ToList());
				List<TitleFragment> list = (from f in earned.Where((TitleFragment f) => !earned.Any((TitleFragment g) => g.Rarity > f.Rarity && SameDeed(f, g))).ToList()
					orderby f.Score descending, TieBreak(f.Id, seed)
					select f).ToList();
				float best = list[0].Score;
				List<TitleFragment> list2 = list.Where((TitleFragment f) => f.Score >= best - 1f).ToList();
				List<TitleFragment> second = list.Skip(list2.Count).ToList();
				int count = ((list2.Count > 0) ? ((epoch % list2.Count + list2.Count) % list2.Count) : 0);
				List<TitleFragment> first = list2.Skip(count).Concat(list2.Take(count)).ToList();
				dictionary[item.Key] = first.Concat(second).ToList();
			}
			return dictionary;
		}

		private static bool SameDeed(TitleFragment a, TitleFragment b)
		{
			if (a.SourceKeys.Count == b.SourceKeys.Count)
			{
				return !a.SourceKeys.Except(b.SourceKeys).Any();
			}
			return false;
		}

		private static Dictionary<TitleSlot, TitleFragment> TryFill(TitleTemplate template, IReadOnlyDictionary<TitleSlot, List<TitleFragment>> ranked, bool strict, long playerId)
		{
			Dictionary<TitleSlot, TitleFragment> dictionary = new Dictionary<TitleSlot, TitleFragment>();
			HashSet<TitleCategory> usedCategories = new HashSet<TitleCategory>();
			HashSet<string> usedSources = new HashSet<string>();
			HashSet<string> usedWords = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			foreach (TitleSlot slot in template.Slots)
			{
				if (!ranked.TryGetValue(slot, out var value))
				{
					return null;
				}
				TitleFragment titleFragment = value.FirstOrDefault((TitleFragment f) => !f.SourceKeys.Any(usedSources.Contains) && !usedWords.Contains(f.TextFor(playerId)) && (!strict || !usedCategories.Contains(f.Category)));
				if (titleFragment == null)
				{
					return null;
				}
				dictionary[slot] = titleFragment;
				usedCategories.Add(titleFragment.Category);
				usedWords.Add(titleFragment.TextFor(playerId));
				foreach (string sourceKey in titleFragment.SourceKeys)
				{
					usedSources.Add(sourceKey);
				}
			}
			return dictionary;
		}

		internal static List<TitleFragment> Qualifying(IStatSource stats)
		{
			return (from f in FragmentCatalog.Fragments
				where BynameConfig.CategoryEnabled(f.Category)
				where !BynameConfig.IsBlocked(f.Id)
				where f.Qualifies(stats)
				select f).ToList();
		}

		internal static List<KeyValuePair<TitleFragment, float>> NearMisses(IStatSource stats, int count, float floor = 0.25f)
		{
			HashSet<string> earned = new HashSet<string>(from f in Qualifying(stats)
				select f.Id);
			return (from f in FragmentCatalog.Fragments
				where !earned.Contains(f.Id) && !f.IsFallback
				where BynameConfig.CategoryEnabled(f.Category) && !BynameConfig.IsBlocked(f.Id)
				select new KeyValuePair<TitleFragment, float>(f, f.Progress(stats)) into x
				where x.Value > floor && x.Value < 1f
				orderby x.Value descending
				select x).Take(count).ToList();
		}

		private static void LogEvaluation(IStatSource stats, List<TitleFragment> qualifying, int seed)
		{
			BynamePlugin.LogVerbose($"evaluating with seed {seed}: {qualifying.Count} qualifying fragment(s) " + "[" + string.Join(", ", qualifying.Select((TitleFragment f) => f.Id).ToArray()) + "]");
			foreach (KeyValuePair<TitleFragment, float> item in NearMisses(stats, 5, 0.5f))
			{
				BynamePlugin.LogVerbose($"  near miss: {item.Key.Id} at {item.Value:P0}");
			}
		}

		private static int Seed(long playerId, int epoch)
		{
			return (int)(playerId ^ (playerId >> 32)) * 397 + epoch;
		}

		private static int TieBreak(string id, int seed)
		{
			return TitleFragment.StableHash(id, seed);
		}
	}
	internal enum TitleSlot
	{
		Epithet,
		Noun,
		Domain
	}
	internal enum TitleCategory
	{
		Combat,
		Bosses,
		Building,
		Death,
		Harvest,
		Travel,
		Exploration,
		Taming,
		Fishing,
		Cooking,
		Crafting,
		Misc
	}
	internal enum Rarity
	{
		Common = 1,
		Uncommon,
		Rare,
		Epic,
		Legendary
	}
	internal sealed class TitleFragment
	{
		private readonly Func<IStatSource, bool> _qualifies;

		private readonly Func<IStatSource, float> _progress;

		private readonly Func<IStatSource, string> _describe;

		internal string Id { get; }

		internal TitleSlot Slot { get; }

		internal TitleCategory Category { get; }

		internal Rarity Rarity { get; }

		internal IReadOnlyList<string> Texts { get; }

		internal string Text => Texts[0];

		internal IReadOnlyList<PlayerStatType> Reads { get; }

		internal bool IsFallback { get; }

		internal IReadOnlyCollection<string> SourceKeys { get; }

		internal float Score => (float)Rarity * BynameConfig.Weight(Category);

		internal unsafe TitleFragment(string id, TitleSlot slot, TitleCategory category, Rarity rarity, string text, Func<IStatSource, bool> qualifies, IReadOnlyList<PlayerStatType> reads, Func<IStatSource, float> progress = null, bool isFallback = false, Func<IStatSource, string> describe = null, IReadOnlyCollection<string> sourceKeys = null)
		{
			Id = id;
			Slot = slot;
			Category = category;
			Rarity = rarity;
			Texts = (from t in text.Split(new char[1] { '|' })
				select t.Trim() into t
				where t.Length > 0
				select t).ToArray();
			_qualifies = qualifies;
			Reads = reads ?? Array.Empty<PlayerStatType>();
			_progress = progress;
			IsFallback = isFallback;
			_describe = describe;
			SourceKeys = (IReadOnlyCollection<string>)(((object)sourceKeys) ?? ((object)Reads.Select((PlayerStatType r) => ((object)(*(PlayerStatType*)(&r))/*cast due to .constrained prefix*/).ToString()).ToArray()));
		}

		internal string TextFor(long playerId)
		{
			if (Texts.Count == 1)
			{
				return Texts[0];
			}
			int seed = (int)(playerId ^ (playerId >> 32));
			return Texts[StableHash(Id, seed) % Texts.Count];
		}

		internal bool Qualifies(IStatSource stats)
		{
			try
			{
				return _qualifies(stats);
			}
			catch (Exception ex)
			{
				BynamePlugin.LogError("fragment '" + Id + "' threw while evaluating: " + ex.Message);
				return false;
			}
		}

		internal float Progress(IStatSource stats)
		{
			if (_progress == null)
			{
				return 0f;
			}
			try
			{
				return Math.Max(0f, Math.Min(1f, _progress(stats)));
			}
			catch
			{
				return 0f;
			}
		}

		internal string Describe(IStatSource stats)
		{
			if (_describe == null)
			{
				return Text;
			}
			try
			{
				return _describe(stats);
			}
			catch
			{
				return Text;
			}
		}

		internal unsafe static string Humanize(PlayerStatType stat)
		{
			string text = ((object)(*(PlayerStatType*)(&stat))/*cast due to .constrained prefix*/).ToString();
			if (text.StartsWith("BuildCluster"))
			{
				return "largest " + text.Substring("BuildCluster".Length).ToLowerInvariant() + " cluster";
			}
			StringBuilder stringBuilder = new StringBuilder(text.Length + 8);
			for (int i = 0; i < text.Length; i++)
			{
				char c = text[i];
				if (i > 0 && char.IsUpper(c) && !char.IsUpper(text[i - 1]))
				{
					stringBuilder.Append(' ');
				}
				stringBuilder.Append(char.ToLowerInvariant(c));
			}
			return stringBuilder.ToString();
		}

		internal static float Scaled(TitleCategory category, float threshold)
		{
			if (threshold <= 0f)
			{
				return threshold;
			}
			return (float)Math.Ceiling(threshold * BynameConfig.ThresholdScale(category));
		}

		internal static int StableHash(string id, int seed)
		{
			uint num = (uint)(seed * -2128831035);
			foreach (char c in id)
			{
				num ^= c;
				num *= 16777619;
			}
			return (int)(num & 0x7FFFFFFF);
		}

		internal static string Number(float v)
		{
			if (!(v >= 1000f))
			{
				return v.ToString("0.##");
			}
			return v.ToString("N0");
		}

		internal static TitleFragment Threshold(string id, TitleSlot slot, TitleCategory category, Rarity rarity, string text, PlayerStatType stat, float threshold)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_002c: Expected I4, but got Unknown
			PlayerStatType[] reads = (PlayerStatType[])(object)new PlayerStatType[1] { (PlayerStatType)(int)stat };
			return new TitleFragment(id, slot, category, rarity, text, (IStatSource s) => s.Get(stat) >= Scaled(category, threshold), reads, (IStatSource s) => Progress(s.Get(stat), Scaled(category, threshold)), isFallback: false, (IStatSource s) => Humanize(stat) + ": " + Number(s.Get(stat)) + " (needed " + Number(Scaled(category, threshold)) + ")");
		}

		internal static TitleFragment Enemy(string id, TitleSlot slot, Rarity rarity, string text, string enemyToken, float threshold)
		{
			return new TitleFragment(id, slot, TitleCategory.Combat, rarity, text, (IStatSource s) => s.GetEnemyKills(enemyToken, (KillModifiers)0) >= Scaled(TitleCategory.Combat, threshold), Array.Empty<PlayerStatType>(), (IStatSource s) => Progress(s.GetEnemyKills(enemyToken, (KillModifiers)0), Scaled(TitleCategory.Combat, threshold)), isFallback: false, (IStatSource s) => CreatureName(enemyToken) + " kills: " + Number(s.GetEnemyKills(enemyToken, (KillModifiers)0)) + " (needed " + Number(Scaled(TitleCategory.Combat, threshold)) + ")", (IReadOnlyCollection<string>)(object)new string[1] { enemyToken });
		}

		internal static TitleFragment KilledBy(string id, TitleSlot slot, Rarity rarity, string text, float threshold, params string[] creatureTokens)
		{
			return new TitleFragment(id, slot, TitleCategory.Death, rarity, text, (IStatSource s) => Count(s) >= Scaled(TitleCategory.Death, threshold), Array.Empty<PlayerStatType>(), (IStatSource s) => Progress(Count(s), Scaled(TitleCategory.Death, threshold)), isFallback: false, (IStatSource s) => "killed by " + CreatureName(creatureTokens[0]) + ": " + Number(Count(s)) + " (needed " + Number(Scaled(TitleCategory.Death, threshold)) + ")", (IReadOnlyCollection<string>)(object)creatureTokens.Select((string t) => "killedby:" + t).ToArray());
			float Count(IStatSource s)
			{
				return creatureTokens.Sum((string t) => s.GetDeathsBy(t));
			}
		}

		internal static TitleFragment DiedIn(string id, TitleSlot slot, Rarity rarity, string text, string biome, float threshold)
		{
			return new TitleFragment(id, slot, TitleCategory.Death, rarity, text, (IStatSource s) => s.GetDeathsIn(biome) >= Scaled(TitleCategory.Death, threshold), Array.Empty<PlayerStatType>(), (IStatSource s) => Progress(s.GetDeathsIn(biome), Scaled(TitleCategory.Death, threshold)), isFallback: false, (IStatSource s) => "deaths in the " + BiomeName(biome) + ": " + Number(s.GetDeathsIn(biome)) + " (needed " + Number(Scaled(TitleCategory.Death, threshold)) + ")", (IReadOnlyCollection<string>)(object)new string[1] { "diedin:" + biome });
		}

		private static float Progress(float value, float threshold)
		{
			if (!(threshold <= 0f))
			{
				return value / threshold;
			}
			return 1f;
		}

		private static string CreatureName(string token)
		{
			if (!token.StartsWith("$enemy_"))
			{
				return token;
			}
			return token.Substring("$enemy_".Length).Replace('_', ' ');
		}

		private static string BiomeName(string biome)
		{
			return biome switch
			{
				"BlackForest" => "black forest", 
				"AshLands" => "ashlands", 
				"DeepNorth" => "deep north", 
				_ => biome.ToLowerInvariant(), 
			};
		}

		internal static TitleFragment Always(string id, TitleSlot slot, TitleCategory category, string text)
		{
			return new TitleFragment(id, slot, category, Rarity.Common, text, (IStatSource _) => true, Array.Empty<PlayerStatType>(), (IStatSource _) => 1f, isFallback: true, (IStatSource _) => "you have yet to earn anything else");
		}
	}
	internal sealed class TitleTemplate
	{
		internal string Pattern { get; }

		internal IReadOnlyList<TitleSlot> Slots { get; }

		internal int Flourish { get; }

		internal TitleTemplate(string pattern, int flourish = 0)
		{
			Pattern = pattern;
			Flourish = flourish;
			Slots = ParseSlots(pattern);
		}

		internal string Render(IReadOnlyDictionary<TitleSlot, TitleFragment> chosen)
		{
			return Render(chosen, (TitleFragment f) => f.Text);
		}

		internal string Render(IReadOnlyDictionary<TitleSlot, TitleFragment> chosen, long playerId)
		{
			return Render(chosen, (TitleFragment f) => f.TextFor(playerId));
		}

		private string Render(IReadOnlyDictionary<TitleSlot, TitleFragment> chosen, Func<TitleFragment, string> word)
		{
			string text = Pattern;
			foreach (KeyValuePair<TitleSlot, TitleFragment> item in chosen)
			{
				text = text.Replace(Token(item.Key), word(item.Value));
			}
			return Capitalize(text);
		}

		private static string Capitalize(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return text;
			}
			if (!char.IsLetter(text[0]) || char.IsUpper(text[0]))
			{
				return text;
			}
			return char.ToUpperInvariant(text[0]) + text.Substring(1);
		}

		private static string Token(TitleSlot slot)
		{
			return "{" + slot.ToString().ToLowerInvariant() + "}";
		}

		private static IReadOnlyList<TitleSlot> ParseSlots(string pattern)
		{
			List<TitleSlot> list = new List<TitleSlot>();
			foreach (TitleSlot value in Enum.GetValues(typeof(TitleSlot)))
			{
				if (pattern.Contains(Token(value)))
				{
					list.Add(value);
				}
			}
			return list;
		}
	}
	internal sealed class ComposedTitle
	{
		internal string Text { get; }

		internal Rarity Rarity { get; }

		internal IReadOnlyList<TitleFragment> Parts { get; }

		internal IReadOnlyList<string> Words { get; }

		internal float Score { get; }

		internal ComposedTitle(string text, Rarity rarity, IReadOnlyList<TitleFragment> parts, IReadOnlyList<string> words, float score)
		{
			Text = text;
			Rarity = rarity;
			Parts = parts;
			Words = words;
			Score = score;
		}

		internal string Describe()
		{
			return $"\"{Text}\" [{Rarity}, score {Score:0.##}] from " + string.Join(" + ", Parts.Select((TitleFragment p) => p.Id).ToArray());
		}
	}
	internal static class CategoryDefaults
	{
		internal static float Weight(TitleCategory category)
		{
			return category switch
			{
				TitleCategory.Building => 0.85f, 
				TitleCategory.Travel => 0.85f, 
				TitleCategory.Harvest => 0.9f, 
				TitleCategory.Death => 1.2f, 
				_ => 1f, 
			};
		}
	}
	internal static class TitleService
	{
		private static readonly Dictionary<Rarity, string> RarityColors = new Dictionary<Rarity, string>
		{
			{
				Rarity.Common,
				"#C8C8C8"
			},
			{
				Rarity.Uncommon,
				"#7FC77F"
			},
			{
				Rarity.Rare,
				"#6FA8DC"
			},
			{
				Rarity.Epic,
				"#B490D9"
			},
			{
				Rarity.Legendary,
				"#E0A44C"
			}
		};

		internal static void Evaluate(Player player, string reason)
		{
			if (!BynameConfig.Enabled.Value || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)Game.instance == (Object)null)
			{
				return;
			}
			try
			{
				EvaluateCore(player, reason);
			}
			catch (Exception arg)
			{
				BynamePlugin.LogError($"title evaluation failed on '{reason}': {arg}");
			}
		}

		private static void EvaluateCore(Player player, string reason)
		{
			IStatSource stats = BuildStatSource(player);
			int num = (((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.GetDay() : 0);
			int lastChangeDay = TitleState.GetLastChangeDay(player);
			int num2 = TitleState.GetEpoch(player);
			int value = BynameConfig.StalenessDays.Value;
			bool flag = value > 0 && lastChangeDay >= 0 && num - lastChangeDay >= value;
			if (flag)
			{
				num2++;
			}
			ComposedTitle composedTitle = TitleEngine.Compose(stats, player.GetPlayerID(), num2);
			if (composedTitle == null)
			{
				BynamePlugin.LogVerbose(reason + ": no title could be composed");
				return;
			}
			string title = TitleState.GetTitle(player);
			bool flag2 = !string.Equals(title, composedTitle.Text, StringComparison.Ordinal);
			TitleNet.Publish(player, composedTitle.Text, (int)composedTitle.Rarity);
			if (!flag2 && !flag)
			{
				BynamePlugin.LogVerbose(reason + ": title unchanged (" + composedTitle.Describe() + ")");
				return;
			}
			TitleState.SetEpoch(player, num2);
			TitleState.SetLastChangeDay(player, num);
			TitleState.SetTitle(player, composedTitle.Text, (int)composedTitle.Rarity);
			if (!flag2)
			{
				BynamePlugin.LogVerbose(reason + ": stale reroll landed on the same title");
				return;
			}
			BynamePlugin.LogInfo(reason + ": " + ((title == null) ? "first title" : ("retitled from \"" + title + "\"")) + " -> " + composedTitle.Describe());
			Announce(player, composedTitle, title == null);
		}

		internal static IStatSource BuildStatSource(Player player)
		{
			LifetimeStatSource lifetimeStatSource = new LifetimeStatSource(Game.instance.GetPlayerProfile(), DeathLedger.Read(player, null));
			if (BynameConfig.Scope.Value != StatScope.World)
			{
				return lifetimeStatSource;
			}
			long num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldUID() : 0);
			IReadOnlyDictionary<PlayerStatType, float> readOnlyDictionary = TitleState.GetBaseline(player, num);
			if (readOnlyDictionary == null)
			{
				TitleState.SetBaseline(player, num, FragmentCatalog.TrackedStats, lifetimeStatSource);
				readOnlyDictionary = TitleState.GetBaseline(player, num) ?? new Dictionary<PlayerStatType, float>();
				BynamePlugin.LogInfo($"World scope: baselined {readOnlyDictionary.Count} stat(s) for world {num}.");
			}
			return new WorldStatSource(lifetimeStatSource, readOnlyDictionary, DeathLedger.Read(player, num));
		}

		internal static List<string> Explain(Player player)
		{
			List<string> list = new List<string>();
			if (!BynameConfig.Enabled.Value)
			{
				list.Add("Byname is disabled on this server.");
				return list;
			}
			if ((Object)(object)player == (Object)null || (Object)(object)Game.instance == (Object)null)
			{
				list.Add("No character loaded.");
				return list;
			}
			IStatSource stats = BuildStatSource(player);
			int epoch = TitleState.GetEpoch(player);
			string title = TitleState.GetTitle(player);
			ComposedTitle composedTitle = TitleEngine.Compose(stats, player.GetPlayerID(), epoch);
			if (composedTitle == null)
			{
				list.Add("You have no title yet.");
				return list;
			}
			string text = title ?? composedTitle.Text;
			list.Add($"You are {Decorate(text, TitleState.GetRarity(player))}  ({composedTitle.Rarity})");
			if (title != null && !string.Equals(title, composedTitle.Text, StringComparison.Ordinal))
			{
				list.Add("  You have earned a new one since: next update makes you " + composedTitle.Text + ".");
			}
			list.Add("");
			for (int i = 0; i < composedTitle.Parts.Count; i++)
			{
				list.Add($"  {composedTitle.Words[i],-18} {composedTitle.Parts[i].Describe(stats)}");
			}
			int num = (((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.GetDay() : 0);
			int lastChangeDay = TitleState.GetLastChangeDay(player);
			int value = BynameConfig.StalenessDays.Value;
			if (lastChangeDay >= 0 && value > 0)
			{
				int num2 = lastChangeDay + value;
				list.Add("");
				list.Add((num2 > num) ? $"Standing since day {lastChangeDay} — rerolls on day {num2} if nothing changes." : $"Standing since day {lastChangeDay} — due to reroll at your next spawn or sleep.");
			}
			return list;
		}

		private static void Announce(Player player, ComposedTitle composed, bool firstEver)
		{
			string text = (firstEver ? "You are known as" : "You are now known as") + " " + Decorate(composed);
			if (BynameConfig.ShowChangeToast.Value)
			{
				((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
			if (BynameConfig.ShowChangeInChat.Value)
			{
				if ((Object)(object)Chat.instance != (Object)null)
				{
					((Terminal)Chat.instance).AddString(text);
				}
				else
				{
					BynamePlugin.LogVerbose("chat line skipped: Chat.instance not ready yet");
				}
			}
		}

		internal static string Decorate(ComposedTitle composed)
		{
			return Decorate(composed.Text, (int)composed.Rarity);
		}

		internal static string Decorate(string text, int rarity)
		{
			if (string.IsNullOrEmpty(text))
			{
				return text;
			}
			if (!BynameConfig.ShowRarityColor.Value)
			{
				return text;
			}
			Rarity key = (Rarity)Mathf.Clamp(rarity, 1, 5);
			if (!RarityColors.TryGetValue(key, out var value))
			{
				return text;
			}
			return "<color=" + value + ">" + text + "</color>";
		}
	}
}
namespace Byname.Titles.Catalog
{
	internal static class BeastFragments
	{
		internal static IEnumerable<TitleFragment> All => Firsts.Concat(Ladders);

		private static IEnumerable<TitleFragment> Ladders => Ladder("greyling", "Greyling", "$enemy_greyling", Rarity.Common, 400f, 1000f, 2500f).Concat(Ladder("boar", "Boar", "$enemy_boar", Rarity.Common, 250f, 600f, 1500f)).Concat(Ladder("deer", "Deer", "$enemy_deer", Rarity.Common, 200f, 500f, 1200f)).Concat(Ladder("neck", "Neck", "$enemy_neck", Rarity.Common, 250f, 600f, 1500f))
			.Concat(Ladder("greydwarf", "Greydwarf", "$enemy_greydwarf", Rarity.Uncommon, 1500f, 4000f, 10000f))
			.Concat(Ladder("skeleton", "Skeleton", "$enemy_skeleton", Rarity.Uncommon, 800f, 2000f, 5000f))
			.Concat(Ladder("troll", "Troll", "$enemy_troll", Rarity.Rare, 150f, 400f))
			.Concat(Ladder("draugr", "Draugr", "$enemy_draugr", Rarity.Uncommon, 800f, 2000f, 5000f))
			.Concat(Ladder("blob", "Blob", "$enemy_blob", Rarity.Uncommon, 500f, 1500f, 4000f))
			.Concat(Ladder("surtling", "Surtling", "$enemy_surtling", Rarity.Uncommon, 200f, 600f, 1500f))
			.Concat(Ladder("leech", "Leech", "$enemy_leech", Rarity.Rare, 400f, 1000f))
			.Concat(Ladder("wraith", "Wraith", "$enemy_wraith", Rarity.Rare, 120f, 300f))
			.Concat(Ladder("abomination", "Abomination", "$enemy_abomination", Rarity.Epic, 50f))
			.Concat(Ladder("wolf", "Wolf", "$enemy_wolf", Rarity.Rare, 500f, 1200f))
			.Concat(Ladder("drake", "Drake", "$enemy_drake", Rarity.Rare, 250f, 700f))
			.Concat(Ladder("fenring", "Fenring", "$enemy_fenring", Rarity.Epic, 200f))
			.Concat(Ladder("stonegolem", "Golem", "$enemy_stonegolem", Rarity.Epic, 80f))
			.Concat(Ladder("ulv", "Ulv", "$enemy_ulv", Rarity.Epic, 100f))
			.Concat(Ladder("deathsquito", "Squito", "$enemy_deathsquito", Rarity.Rare, 300f, 800f))
			.Concat(Ladder("fuling", "Fuling", "$enemy_goblin", Rarity.Rare, 700f, 2000f))
			.Concat(Ladder("lox", "Lox", "$enemy_lox", Rarity.Epic, 150f))
			.Concat(Ladder("serpent", "Serpent", "$enemy_serpent", Rarity.Epic, 50f))
			.Concat(Ladder("seeker", "Seeker", "$enemy_seeker", Rarity.Epic, 400f))
			.Concat(Ladder("seekerbrute", "Soldier", "$enemy_seekerbrute", Rarity.Epic, 80f))
			.Concat(Ladder("tick", "Tick", "$enemy_tick", Rarity.Rare, 200f, 500f))
			.Concat(Ladder("gjall", "Gjall", "$enemy_gjall", Rarity.Epic, 75f))
			.Concat(Ladder("dvergr", "Dvergr", "$enemy_dvergr", Rarity.Epic, 150f))
			.Concat(Ladder("charred", "Charred", "$enemy_charred", Rarity.Epic, 600f))
			.Concat(Ladder("asksvin", "Asksvin", "$enemy_asksvin", Rarity.Epic, 200f))
			.Concat(Ladder("morgen", "Morgen", "$enemy_morgen", Rarity.Epic, 100f))
			.Concat(Ladder("valkyrie", "Valkyrie", "$enemy_fallenvalkyrie", Rarity.Epic, 50f));

		private static IEnumerable<TitleFragment> Firsts => new TitleFragment[36]
		{
			TitleFragment.Enemy("greyling_bane", TitleSlot.Noun, Rarity.Common, "Greyling-Bane|Greyling-Swatter", "$enemy_greyling", 100f),
			TitleFragment.Enemy("boar_hunter", TitleSlot.Noun, Rarity.Common, "Boar-Hunter|Boar-Sticker|Tusk-Taker", "$enemy_boar", 60f),
			TitleFragment.Enemy("deer_stalker", TitleSlot.Noun, Rarity.Common, "Deer-Stalker|Stag-Hunter|Antler-Taker", "$enemy_deer", 40f),
			TitleFragment.Enemy("neck_catcher", TitleSlot.Noun, Rarity.Common, "Neck-Catcher|Neck-Wringer", "$enemy_neck", 80f),
			TitleFragment.Enemy("greydwarf_bane", TitleSlot.Noun, Rarity.Uncommon, "Greydwarf-Bane|Greydwarf-Breaker", "$enemy_greydwarf", 400f),
			TitleFragment.Enemy("skeleton_breaker", TitleSlot.Noun, Rarity.Uncommon, "Bone-Breaker|Skull-Cracker", "$enemy_skeleton", 200f),
			TitleFragment.Enemy("troll_slayer", TitleSlot.Noun, Rarity.Rare, "Troll-Slayer|Troll-Feller|Troll-Toppler", "$enemy_troll", 50f),
			TitleFragment.Enemy("draugr_bane", TitleSlot.Noun, Rarity.Uncommon, "Draugr-Bane|Draugr-Unmaker|Barrow-Breaker", "$enemy_draugr", 250f),
			TitleFragment.Enemy("blob_render", TitleSlot.Noun, Rarity.Uncommon, "Blob-Render|Ooze-Popper", "$enemy_blob", 150f),
			TitleFragment.Enemy("leech_puller", TitleSlot.Noun, Rarity.Rare, "Leech-Puller|Leech-Burner", "$enemy_leech", 120f),
			TitleFragment.Enemy("wraith_banisher", TitleSlot.Noun, Rarity.Rare, "Wraith-Banisher|Ghost-Cutter", "$enemy_wraith", 40f),
			TitleFragment.Enemy("abomination_feller", TitleSlot.Noun, Rarity.Epic, "Root-Cutter|Bog-Feller", "$enemy_abomination", 15f),
			TitleFragment.Enemy("surtling_snuffer", TitleSlot.Noun, Rarity.Uncommon, "Surtling-Snuffer|Ember-Quencher", "$enemy_surtling", 60f),
			TitleFragment.Enemy("wolf_breaker", TitleSlot.Noun, Rarity.Rare, "Wolf-Breaker|Wolf-Hunter|Pelt-Taker", "$enemy_wolf", 150f),
			TitleFragment.Enemy("drake_downer", TitleSlot.Noun, Rarity.Rare, "Drake-Downer|Drake-Hunter", "$enemy_drake", 80f),
			TitleFragment.Enemy("fenring_hunter", TitleSlot.Noun, Rarity.Epic, "Fenring-Hunter|Moon-Hunter", "$enemy_fenring", 60f),
			TitleFragment.Enemy("stone_golem_breaker", TitleSlot.Noun, Rarity.Epic, "Golem-Breaker|Crystal-Cracker", "$enemy_stonegolem", 25f),
			TitleFragment.Enemy("ulv_hunter", TitleSlot.Noun, Rarity.Epic, "Ulv-Hunter|Ulv-Bane", "$enemy_ulv", 30f),
			TitleFragment.Enemy("deathsquito_swatter", TitleSlot.Noun, Rarity.Rare, "Squito-Swatter|Needle-Breaker", "$enemy_deathsquito", 100f),
			TitleFragment.Enemy("fuling_bane", TitleSlot.Noun, Rarity.Rare, "Fuling-Bane|Fuling-Smasher|Goblin-Bane", "$enemy_goblin", 200f),
			TitleFragment.Enemy("lox_feller", TitleSlot.Noun, Rarity.Epic, "Lox-Feller|Lox-Toppler", "$enemy_lox", 50f),
			TitleFragment.Enemy("serpent_slayer", TitleSlot.Noun, Rarity.Epic, "Serpent-Slayer|Wyrm-Gaffer", "$enemy_serpent", 15f),
			TitleFragment.Enemy("seeker_render", TitleSlot.Noun, Rarity.Epic, "Seeker-Render|Bug-Crusher", "$enemy_seeker", 100f),
			TitleFragment.Enemy("seeker_brute_breaker", TitleSlot.Noun, Rarity.Epic, "Soldier-Breaker|Carapace-Cracker", "$enemy_seekerbrute", 25f),
			TitleFragment.Enemy("tick_squasher", TitleSlot.Noun, Rarity.Rare, "Tick-Squasher|Tick-Picker", "$enemy_tick", 50f),
			TitleFragment.Enemy("gjall_downer", TitleSlot.Noun, Rarity.Epic, "Gjall-Downer|Sky-Gutter", "$enemy_gjall", 25f),
			TitleFragment.Enemy("dvergr_breaker", TitleSlot.Noun, Rarity.Epic, "Dvergr-Breaker|Dwarf-Wronger", "$enemy_dvergr", 40f),
			TitleFragment.Enemy("charred_bane", TitleSlot.Noun, Rarity.Epic, "Charred-Bane|Ash-Sweeper", "$enemy_charred", 150f),
			TitleFragment.Enemy("asksvin_hunter", TitleSlot.Noun, Rarity.Epic, "Asksvin-Hunter|Scale-Taker", "$enemy_asksvin", 50f),
			TitleFragment.Enemy("morgen_breaker", TitleSlot.Noun, Rarity.Epic, "Morgen-Breaker|Morgen-Bane", "$enemy_morgen", 30f),
			TitleFragment.Enemy("valkyrie_feller", TitleSlot.Noun, Rarity.Epic, "Valkyrie-Feller|Wing-Clipper", "$enemy_fallenvalkyrie", 15f),
			TitleFragment.Enemy("troll_worn", TitleSlot.Epithet, Rarity.Rare, "Troll-Worn|Troll-Tested", "$enemy_troll", 30f),
			TitleFragment.Enemy("wolf_bitten", TitleSlot.Epithet, Rarity.Rare, "Wolf-Bitten|Wolf-Scarred", "$enemy_wolf", 100f),
			TitleFragment.Enemy("serpent_touched", TitleSlot.Epithet, Rarity.Epic, "Serpent-Touched|Wyrm-Blooded", "$enemy_serpent", 10f),
			TitleFragment.Enemy("greydwarf_weary", TitleSlot.Epithet, Rarity.Common, "Greydwarf-Weary|Pinecone-Pelted", "$enemy_greydwarf", 150f),
			TitleFragment.Enemy("draugr_haunted", TitleSlot.Epithet, Rarity.Uncommon, "Draugr-Haunted|Crypt-Hardened", "$enemy_draugr", 120f)
		};

		private static IEnumerable<TitleFragment> Ladder(string stem, string creature, string token, Rarity first, params float[] thresholds)
		{
			Rarity rarity = first;
			foreach (float threshold in thresholds)
			{
				if (rarity < Rarity.Legendary)
				{
					rarity++;
				}
				yield return TitleFragment.Enemy(stem + "_" + rarity.ToString().ToLowerInvariant(), TitleSlot.Noun, rarity, RungWords(creature, rarity), token, threshold);
			}
		}

		private static string RungWords(string creature, Rarity rarity)
		{
			return rarity switch
			{
				Rarity.Uncommon => creature + "-Harrier|" + creature + "-Culler", 
				Rarity.Rare => creature + "-Scourge|" + creature + "-Butcher", 
				Rarity.Epic => creature + "-Reaper|" + creature + "-Ruin", 
				_ => creature + "-Doom|" + creature + "-Ender", 
			};
		}
	}
	internal static class DoomFragments
	{
		internal static IEnumerable<TitleFragment> All => new TitleFragment[55]
		{
			TitleFragment.Threshold("tooth_marked", TitleSlot.Epithet, TitleCategory.Death, Rarity.Uncommon, "Tooth-Marked|Claw-Raked|Oft-Mauled", (PlayerStatType)56, 5f),
			TitleFragment.Threshold("much_mauled", TitleSlot.Epithet, TitleCategory.Death, Rarity.Rare, "Much-Mauled|Beast-Bitten|Monster-Fed", (PlayerStatType)56, 25f),
			TitleFragment.Threshold("fodder", TitleSlot.Noun, TitleCategory.Death, Rarity.Uncommon, "Fodder|Easy-Meat|Carrion", (PlayerStatType)56, 10f),
			TitleFragment.Threshold("last_stand", TitleSlot.Domain, TitleCategory.Death, Rarity.Uncommon, "Last Stand|Losing Fight|Red Snow", (PlayerStatType)56, 8f),
			TitleFragment.DiedIn("meadow_felled", TitleSlot.Epithet, Rarity.Uncommon, "Meadow-Felled|Grass-Stained", "Meadows", 4f),
			TitleFragment.DiedIn("forest_taken", TitleSlot.Epithet, Rarity.Uncommon, "Forest-Taken|Pine-Shadowed|Moss-Covered", "BlackForest", 3f),
			TitleFragment.DiedIn("dark_wood", TitleSlot.Domain, Rarity.Rare, "Dark Wood|Black Pines", "BlackForest", 6f),
			TitleFragment.DiedIn("mire_taken", TitleSlot.Epithet, Rarity.Uncommon, "Mire-Taken|Bog-Claimed|Swamp-Sunk", "Swamp", 3f),
			TitleFragment.DiedIn("bog_body", TitleSlot.Noun, Rarity.Rare, "Bog-Body|Mire-Wight|Swamp-Thing", "Swamp", 6f),
			TitleFragment.DiedIn("the_mire", TitleSlot.Domain, Rarity.Uncommon, "Mire|Bog|Rotting Fen", "Swamp", 4f),
			TitleFragment.DiedIn("peak_fallen", TitleSlot.Epithet, Rarity.Uncommon, "Peak-Fallen|Snow-Buried", "Mountain", 3f),
			TitleFragment.DiedIn("high_snows", TitleSlot.Domain, Rarity.Rare, "High Snows|Cold Peaks", "Mountain", 6f),
			TitleFragment.DiedIn("dust_taken", TitleSlot.Epithet, Rarity.Uncommon, "Dust-Taken|Field-Fallen", "Plains", 3f),
			TitleFragment.DiedIn("yellow_grass", TitleSlot.Domain, Rarity.Rare, "Yellow Grass|Golden Fields", "Plains", 6f),
			TitleFragment.DiedIn("sea_taken", TitleSlot.Epithet, Rarity.Uncommon, "Sea-Taken|Salt-Buried", "Ocean", 3f),
			TitleFragment.DiedIn("whale_road", TitleSlot.Domain, Rarity.Rare, "Salt Grave|Cold Sea", "Ocean", 6f),
			TitleFragment.DiedIn("mist_lost", TitleSlot.Epithet, Rarity.Uncommon, "Mist-Lost|Fog-Swallowed", "Mistlands", 3f),
			TitleFragment.DiedIn("grey_mist", TitleSlot.Domain, Rarity.Rare, "Grey Mist|Hollow Mist", "Mistlands", 6f),
			TitleFragment.DiedIn("ash_claimed", TitleSlot.Epithet, Rarity.Rare, "Ash-Claimed|Cinder-Taken", "AshLands", 3f),
			TitleFragment.DiedIn("ash_wastes", TitleSlot.Domain, Rarity.Epic, "Ash Wastes|Burning Shore", "AshLands", 6f),
			TitleFragment.DiedIn("ice_claimed", TitleSlot.Epithet, Rarity.Rare, "Ice-Claimed|Frost-Graved", "DeepNorth", 3f),
			TitleFragment.KilledBy("boar_gored", TitleSlot.Epithet, Rarity.Epic, "Boar-Gored|Pig-Bested", 1f, "$enemy_boar"),
			TitleFragment.KilledBy("greyling_bested", TitleSlot.Epithet, Rarity.Epic, "Greyling-Bested|Twig-Beaten", 1f, "$enemy_greyling"),
			TitleFragment.KilledBy("neck_nibbled", TitleSlot.Epithet, Rarity.Epic, "Neck-Nibbled|Lizard-Licked", 1f, "$enemy_neck"),
			TitleFragment.KilledBy("greydwarf_pelted", TitleSlot.Epithet, Rarity.Uncommon, "Greydwarf-Pelted|Stone-Pelted", 3f, "$enemy_greydwarf", "$enemy_greydwarfbrute", "$enemy_greydwarfshaman"),
			TitleFragment.KilledBy("troll_stomped", TitleSlot.Epithet, Rarity.Uncommon, "Troll-Stomped|Troll-Flattened|Club-Struck", 2f, "$enemy_troll", "$enemy_trollfrost"),
			TitleFragment.KilledBy("bone_beaten", TitleSlot.Epithet, Rarity.Uncommon, "Bone-Beaten|Crypt-Taken", 3f, "$enemy_skeleton", "$enemy_skeletonpoison", "$enemy_skeletonfire"),
			TitleFragment.KilledBy("draugr_fodder", TitleSlot.Epithet, Rarity.Uncommon, "Draugr-Hewn|Draugr-Felled|Barrow-Taken", 3f, "$enemy_draugr", "$enemy_draugrelite"),
			TitleFragment.KilledBy("draugr_meat", TitleSlot.Noun, Rarity.Rare, "Draugr-Fodder|Draugr-Meat", 6f, "$enemy_draugr", "$enemy_draugrelite"),
			TitleFragment.KilledBy("ooze_choked", TitleSlot.Epithet, Rarity.Uncommon, "Ooze-Choked|Blob-Smothered|Slime-Drowned", 3f, "$enemy_blob", "$enemy_blobelite"),
			TitleFragment.KilledBy("leech_drained", TitleSlot.Epithet, Rarity.Uncommon, "Leech-Drained|Leech-Supped", 2f, "$enemy_leech"),
			TitleFragment.KilledBy("wraith_taken", TitleSlot.Epithet, Rarity.Rare, "Wraith-Taken|Ghost-Chilled", 2f, "$enemy_wraith"),
			TitleFragment.KilledBy("root_crushed", TitleSlot.Epithet, Rarity.Rare, "Root-Crushed|Log-Walloped", 2f, "$enemy_abomination"),
			TitleFragment.KilledBy("wolf_eaten", TitleSlot.Epithet, Rarity.Uncommon, "Wolf-Eaten|Wolf-Torn|Pack-Hunted", 3f, "$enemy_wolf", "$enemy_ulv"),
			TitleFragment.KilledBy("drake_frozen", TitleSlot.Epithet, Rarity.Uncommon, "Drake-Frozen|Ice-Spat", 3f, "$enemy_drake"),
			TitleFragment.KilledBy("fenring_torn", TitleSlot.Epithet, Rarity.Rare, "Fenring-Torn|Moon-Mauled", 2f, "$enemy_fenring", "$enemy_fenringcultist"),
			TitleFragment.KilledBy("golem_pounded", TitleSlot.Epithet, Rarity.Rare, "Golem-Pounded|Crystal-Crushed", 2f, "$enemy_stonegolem"),
			TitleFragment.KilledBy("squito_stung", TitleSlot.Epithet, Rarity.Rare, "Squito-Stung|Needle-Struck", 2f, "$enemy_deathsquito"),
			TitleFragment.KilledBy("fuling_clubbed", TitleSlot.Epithet, Rarity.Uncommon, "Fuling-Clubbed|Fuling-Felled", 3f, "$enemy_goblin", "$enemy_goblinbrute", "$enemy_goblinshaman"),
			TitleFragment.KilledBy("lox_trampled", TitleSlot.Epithet, Rarity.Rare, "Lox-Trampled|Lox-Flattened", 2f, "$enemy_lox"),
			TitleFragment.KilledBy("serpent_swallowed", TitleSlot.Epithet, Rarity.Rare, "Serpent-Eaten|Wyrm-Swallowed", 2f, "$enemy_serpent"),
			TitleFragment.KilledBy("seeker_stung", TitleSlot.Epithet, Rarity.Uncommon, "Seeker-Stung|Bug-Bitten", 3f, "$enemy_seeker", "$enemy_seekerbrute"),
			TitleFragment.KilledBy("gjall_bombed", TitleSlot.Epithet, Rarity.Rare, "Gjall-Bombed|Sky-Spat", 2f, "$enemy_gjall"),
			TitleFragment.KilledBy("tick_drained", TitleSlot.Epithet, Rarity.Rare, "Tick-Drained|Tick-Supped", 2f, "$enemy_tick"),
			TitleFragment.KilledBy("dvergr_wronged", TitleSlot.Epithet, Rarity.Rare, "Dvergr-Wronged|Dwarf-Blasted", 2f, "$enemy_dvergr", "$enemy_dvergr_mage"),
			TitleFragment.KilledBy("charred_cut", TitleSlot.Epithet, Rarity.Uncommon, "Charred-Cut|Ash-Felled", 3f, "$enemy_charred", "$enemy_charred_melee", "$enemy_charred_archer", "$enemy_charred_mage", "$enemy_charred_twitcher"),
			TitleFragment.KilledBy("morgen_mauled", TitleSlot.Epithet, Rarity.Rare, "Morgen-Mauled|Morgen-Torn", 2f, "$enemy_morgen"),
			TitleFragment.KilledBy("valkyrie_taken", TitleSlot.Epithet, Rarity.Epic, "Valkyrie-Taken|Valkyrie-Chosen", 1f, "$enemy_fallenvalkyrie"),
			TitleFragment.KilledBy("stag_struck", TitleSlot.Epithet, Rarity.Rare, "Stag-Struck|Antler-Lit", 2f, "$enemy_eikthyr"),
			TitleFragment.KilledBy("elder_crushed", TitleSlot.Epithet, Rarity.Rare, "Elder-Crushed|Root-Bound", 2f, "$enemy_gdking"),
			TitleFragment.KilledBy("bonemass_taken", TitleSlot.Epithet, Rarity.Rare, "Bone-Mashed|Rot-Smothered", 2f, "$enemy_bonemass"),
			TitleFragment.KilledBy("moder_frozen", TitleSlot.Epithet, Rarity.Rare, "Moder-Frozen|Wing-Chilled", 2f, "$enemy_dragon"),
			TitleFragment.KilledBy("yagluth_burned", TitleSlot.Epithet, Rarity.Epic, "King-Burned|Yagluth-Scorched", 2f, "$enemy_goblinking"),
			TitleFragment.KilledBy("queen_stung", TitleSlot.Epithet, Rarity.Epic, "Queen-Stung|Hive-Taken", 2f, "$enemy_seekerqueen"),
			TitleFragment.KilledBy("fader_scorched", TitleSlot.Epithet, Rarity.Epic, "Fader-Scorched|Fire-Unmade", 2f, "$enemy_fader")
		};
	}
	internal static class EarlyFragments
	{
		internal static IEnumerable<TitleFragment> All => new TitleFragment[37]
		{
			TitleFragment.Threshold("new_landed", TitleSlot.Epithet, TitleCategory.Misc, Rarity.Common, "New-Landed|Raven-Brought|Fresh-Landed", (PlayerStatType)151, 1f),
			TitleFragment.Threshold("hearth_lit", TitleSlot.Epithet, TitleCategory.Building, Rarity.Common, "Hearth-Lit|Turf-Roofed|Smoke-Rising", (PlayerStatType)168, 50f),
			TitleFragment.Threshold("first_footed", TitleSlot.Epithet, TitleCategory.Travel, Rarity.Common, "First-Footed|Trail-Dusted|Mud-Booted", (PlayerStatType)17, 5000f),
			TitleFragment.Threshold("hungry", TitleSlot.Epithet, TitleCategory.Cooking, Rarity.Common, "Well-Meaning|Broth-Warmed|Crumb-Bearded", (PlayerStatType)49, 50f),
			TitleFragment.Threshold("hand_worn", TitleSlot.Epithet, TitleCategory.Crafting, Rarity.Common, "Hand-Worn|Blister-Palmed|Callus-Handed", (PlayerStatType)13, 40f),
			TitleFragment.Threshold("rough_handed", TitleSlot.Epithet, TitleCategory.Harvest, Rarity.Common, "Rough-Handed|Bark-Scuffed|Sap-Sticky", (PlayerStatType)27, 300f),
			TitleFragment.Threshold("wave_shy", TitleSlot.Epithet, TitleCategory.Travel, Rarity.Common, "Wave-Shy|Raft-Faring|Shore-Hugging", (PlayerStatType)19, 2000f),
			TitleFragment.Threshold("night_worn", TitleSlot.Epithet, TitleCategory.Misc, Rarity.Common, "Night-Worn|Bed-Warmed|Dream-Fed", (PlayerStatType)23, 5f),
			TitleFragment.Threshold("twice_fallen", TitleSlot.Epithet, TitleCategory.Death, Rarity.Common, "Twice-Fallen|Still-Rising|Ill-Starred", (PlayerStatType)0, 2f),
			TitleFragment.Threshold("settler", TitleSlot.Noun, TitleCategory.Building, Rarity.Common, "Settler|Homesteader|Crofter", (PlayerStatType)168, 100f),
			TitleFragment.Threshold("gatherer", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Common, "Gatherer|Scrounger|Gleaner", (PlayerStatType)12, 500f),
			TitleFragment.Threshold("walker", TitleSlot.Noun, TitleCategory.Travel, Rarity.Common, "Walker|Rambler|Footslogger", (PlayerStatType)17, 15000f),
			TitleFragment.Threshold("digger", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Common, "Digger|Mudlark|Ditch-Digger", (PlayerStatType)37, 500f),
			TitleFragment.Threshold("apprentice", TitleSlot.Noun, TitleCategory.Crafting, Rarity.Common, "Apprentice|Tinkerer|Journeyman", (PlayerStatType)1, 100f),
			TitleFragment.Threshold("thrall", TitleSlot.Noun, TitleCategory.Misc, Rarity.Common, "Thrall|Bounder|Hopper", (PlayerStatType)3, 300f),
			TitleFragment.Threshold("first_camp", TitleSlot.Domain, TitleCategory.Building, Rarity.Common, "First Camp|Lean-To|Rough Camp", (PlayerStatType)168, 80f),
			TitleFragment.Threshold("near_shore", TitleSlot.Domain, TitleCategory.Travel, Rarity.Common, "Near Shore|Shallows|Home Waters", (PlayerStatType)19, 4000f),
			TitleFragment.Threshold("open_road", TitleSlot.Domain, TitleCategory.Travel, Rarity.Common, "Open Road|Beaten Path|Muddy Track", (PlayerStatType)17, 20000f),
			TitleFragment.Threshold("beast_calling", TitleSlot.Epithet, TitleCategory.Taming, Rarity.Common, "Beast-Calling|Feed-Tossing", (PlayerStatType)48, 2f),
			TitleFragment.Threshold("well_heeded", TitleSlot.Epithet, TitleCategory.Taming, Rarity.Uncommon, "Well-Heeded|Well-Obeyed", (PlayerStatType)192, 200f),
			TitleFragment.Threshold("soft_spoken", TitleSlot.Epithet, TitleCategory.Taming, Rarity.Epic, "Soft-Spoken|Beast-Beloved", (PlayerStatType)191, 800f),
			TitleFragment.Threshold("herder", TitleSlot.Noun, TitleCategory.Taming, Rarity.Common, "Herder|Swineherd|Drover", (PlayerStatType)48, 4f),
			TitleFragment.Threshold("houndmaster", TitleSlot.Noun, TitleCategory.Taming, Rarity.Rare, "Houndmaster|Packleader", (PlayerStatType)192, 500f),
			TitleFragment.Threshold("warm_stable", TitleSlot.Domain, TitleCategory.Taming, Rarity.Rare, "Warm Stable|Full Pen|Warm Byre", (PlayerStatType)191, 250f),
			TitleFragment.Threshold("float_watcher", TitleSlot.Noun, TitleCategory.Fishing, Rarity.Common, "Float-Watcher|Bobber-Gazer|Line-Dangler", (PlayerStatType)158, 30f),
			TitleFragment.Threshold("baited", TitleSlot.Epithet, TitleCategory.Fishing, Rarity.Uncommon, "Bait-Handed|Worm-Fingered", (PlayerStatType)121, 100f),
			TitleFragment.Threshold("slack_lined", TitleSlot.Epithet, TitleCategory.Fishing, Rarity.Common, "Slack-Lined|Line-Snapped", (PlayerStatType)159, 25f),
			TitleFragment.Threshold("hoard_keeping", TitleSlot.Epithet, TitleCategory.Building, Rarity.Rare, "Hoard-Keeping|Chest-Proud|Dragon-Hoarding", (PlayerStatType)181, 80f),
			TitleFragment.Threshold("floor_layer", TitleSlot.Noun, TitleCategory.Building, Rarity.Uncommon, "Floor-Layer|Plank-Setter|Boardwright", (PlayerStatType)174, 350f),
			TitleFragment.Threshold("floorwright", TitleSlot.Noun, TitleCategory.Building, Rarity.Rare, "Floorwright|Hall-Floorer|Deckwright", (PlayerStatType)174, 800f),
			TitleFragment.Threshold("gatewarden", TitleSlot.Noun, TitleCategory.Building, Rarity.Uncommon, "Gatewarden|Doorward|Porter", (PlayerStatType)189, 20f),
			TitleFragment.Threshold("cartwright", TitleSlot.Noun, TitleCategory.Building, Rarity.Rare, "Cartwright|Wainwright", (PlayerStatType)182, 15f),
			TitleFragment.Threshold("well_stocked", TitleSlot.Epithet, TitleCategory.Building, Rarity.Uncommon, "Well-Stocked|Larder-Proud|Full-Pantried", (PlayerStatType)183, 25f),
			TitleFragment.Threshold("wreath_hanger", TitleSlot.Epithet, TitleCategory.Building, Rarity.Epic, "Wreath-Hanging|Yule-Merry", (PlayerStatType)190, 20f),
			TitleFragment.Threshold("workshop", TitleSlot.Domain, TitleCategory.Building, Rarity.Uncommon, "Workshop|Workbench|Tool Loft", (PlayerStatType)172, 20f),
			TitleFragment.Threshold("homebound", TitleSlot.Epithet, TitleCategory.Misc, Rarity.Uncommon, "Homebound|Hearth-Bound|Door-Hugging", (PlayerStatType)21, 200000f),
			TitleFragment.Threshold("seldom_home", TitleSlot.Epithet, TitleCategory.Misc, Rarity.Rare, "Seldom-Home|Long-Absent|Hearthless", (PlayerStatType)22, 500000f)
		};
	}
	internal static class FateFragments
	{
		internal static IEnumerable<TitleFragment> All => new TitleFragment[56]
		{
			TitleFragment.Always("unproven", TitleSlot.Epithet, TitleCategory.Misc, "Unproven|Untested|Untried"),
			TitleFragment.Always("stranger", TitleSlot.Noun, TitleCategory.Misc, "Stranger|Newcomer|Outlander"),
			TitleFragment.Threshold("sodden", TitleSlot.Epithet, TitleCategory.Death, Rarity.Uncommon, "Sodden|Waterlogged|Brine-Lunged", (PlayerStatType)59, 3f),
			TitleFragment.Threshold("deep_drowned", TitleSlot.Epithet, TitleCategory.Death, Rarity.Epic, "Deep-Drowned|Sea-Claimed", (PlayerStatType)59, 15f),
			TitleFragment.Threshold("timber_struck", TitleSlot.Epithet, TitleCategory.Death, Rarity.Rare, "Timber-Struck|Tree-Flattened", (PlayerStatType)68, 1f),
			TitleFragment.Threshold("oft_felled", TitleSlot.Epithet, TitleCategory.Death, Rarity.Epic, "Oft-Felled|Forest-Hated", (PlayerStatType)68, 4f),
			TitleFragment.Threshold("ember_scarred", TitleSlot.Epithet, TitleCategory.Death, Rarity.Uncommon, "Ember-Scarred|Smoke-Blackened|Twice-Singed", (PlayerStatType)60, 3f),
			TitleFragment.Threshold("frost_bitten", TitleSlot.Epithet, TitleCategory.Death, Rarity.Uncommon, "Frost-Bitten|Rime-Touched|Blue-Lipped", (PlayerStatType)61, 3f),
			TitleFragment.Threshold("venom_touched", TitleSlot.Epithet, TitleCategory.Death, Rarity.Uncommon, "Venom-Touched|Poison-Veined|Green-Gilled", (PlayerStatType)62, 4f),
			TitleFragment.Threshold("smoke_choked", TitleSlot.Epithet, TitleCategory.Death, Rarity.Rare, "Smoke-Choked|Soot-Lunged", (PlayerStatType)63, 3f),
			TitleFragment.Threshold("cliff_fallen", TitleSlot.Epithet, TitleCategory.Death, Rarity.Uncommon, "Cliff-Fallen|Ledge-Leaping|Gravity-Scorned", (PlayerStatType)58, 5f),
			TitleFragment.Threshold("cart_crushed", TitleSlot.Epithet, TitleCategory.Death, Rarity.Rare, "Cart-Crushed|Wheel-Pressed", (PlayerStatType)67, 1f),
			TitleFragment.Threshold("keel_hauled", TitleSlot.Epithet, TitleCategory.Death, Rarity.Rare, "Keel-Hauled|Hull-Struck", (PlayerStatType)72, 1f),
			TitleFragment.Threshold("self_undone", TitleSlot.Epithet, TitleCategory.Death, Rarity.Rare, "Self-Undone|Self-Slain", (PlayerStatType)69, 3f),
			TitleFragment.Threshold("spike_struck", TitleSlot.Epithet, TitleCategory.Death, Rarity.Epic, "Spike-Struck|Ceiling-Speared", (PlayerStatType)73, 1f),
			TitleFragment.Threshold("lava_kissed", TitleSlot.Epithet, TitleCategory.Death, Rarity.Epic, "Lava-Kissed|Magma-Bathed", (PlayerStatType)204, 1f),
			TitleFragment.Threshold("hollow_eyed", TitleSlot.Epithet, TitleCategory.Death, Rarity.Rare, "Hollow-Eyed|Oft-Buried|Grave-Familiar", (PlayerStatType)0, 50f),
			TitleFragment.Threshold("much_mourned", TitleSlot.Epithet, TitleCategory.Death, Rarity.Epic, "Much-Mourned|Hel-Weary", (PlayerStatType)0, 150f),
			TitleFragment.Threshold("stone_crushed", TitleSlot.Epithet, TitleCategory.Death, Rarity.Rare, "Stone-Crushed|Roof-Buried", (PlayerStatType)70, 2f),
			TitleFragment.Threshold("cinder_burnt", TitleSlot.Epithet, TitleCategory.Death, Rarity.Rare, "Cinder-Burnt|Ash-Rained", (PlayerStatType)106, 1f),
			TitleFragment.Threshold("sea_boiled", TitleSlot.Epithet, TitleCategory.Death, Rarity.Rare, "Sea-Boiled|Boil-Drowned", (PlayerStatType)107, 1f),
			TitleFragment.Threshold("bolt_pinned", TitleSlot.Epithet, TitleCategory.Death, Rarity.Epic, "Bolt-Pinned|Ballista-Struck", (PlayerStatType)71, 1f),
			TitleFragment.Threshold("catapult_struck", TitleSlot.Epithet, TitleCategory.Death, Rarity.Epic, "Catapult-Struck|Siege-Flattened", (PlayerStatType)105, 1f),
			TitleFragment.Threshold("friend_slain", TitleSlot.Epithet, TitleCategory.Death, Rarity.Rare, "Friend-Slain|Kin-Struck|Back-Stabbed", (PlayerStatType)57, 1f),
			TitleFragment.Threshold("worlds_edge", TitleSlot.Epithet, TitleCategory.Death, Rarity.Legendary, "World's-Edge|Edge-Fallen", (PlayerStatType)65, 1f),
			TitleFragment.Threshold("gate_crushed", TitleSlot.Epithet, TitleCategory.Death, Rarity.Legendary, "Gate-Crushed|Drawbridge-Flat", (PlayerStatType)203, 1f),
			TitleFragment.Threshold("obliterated", TitleSlot.Epithet, TitleCategory.Death, Rarity.Legendary, "Obliterated|Incinerated", (PlayerStatType)108, 1f),
			TitleFragment.Threshold("gravewalker", TitleSlot.Noun, TitleCategory.Death, Rarity.Uncommon, "Gravewalker|Corpse-Walker|Grave-Returner", (PlayerStatType)0, 30f),
			TitleFragment.Threshold("revenant", TitleSlot.Noun, TitleCategory.Death, Rarity.Epic, "Revenant|Wight|Hel-Walker", (PlayerStatType)0, 120f),
			TitleFragment.Threshold("drowned", TitleSlot.Noun, TitleCategory.Death, Rarity.Rare, "Drowned|Kelp-Crown", (PlayerStatType)59, 8f),
			TitleFragment.Threshold("graverobber", TitleSlot.Noun, TitleCategory.Death, Rarity.Rare, "Graverobber|Grave-Picker", (PlayerStatType)53, 1f),
			TitleFragment.Threshold("corpse_runner", TitleSlot.Noun, TitleCategory.Death, Rarity.Uncommon, "Corpse-Runner|Grave-Fetcher|Kit-Chaser", (PlayerStatType)52, 15f),
			TitleFragment.Threshold("the_deep", TitleSlot.Domain, TitleCategory.Death, Rarity.Uncommon, "Deep|Depths|Undertow", (PlayerStatType)59, 1f),
			TitleFragment.Threshold("cold_ground", TitleSlot.Domain, TitleCategory.Death, Rarity.Uncommon, "Cold Ground|Shallow Grave|Barrow", (PlayerStatType)0, 20f),
			TitleFragment.Threshold("long_fall", TitleSlot.Domain, TitleCategory.Death, Rarity.Uncommon, "Long Fall|Sudden Drop", (PlayerStatType)58, 3f),
			TitleFragment.Threshold("pyre", TitleSlot.Domain, TitleCategory.Death, Rarity.Rare, "Pyre|Bonfire", (PlayerStatType)60, 5f),
			new TitleFragment("undying", TitleSlot.Epithet, TitleCategory.Death, Rarity.Legendary, "Undying|Hel-Denied", (IStatSource s) => s.Get((PlayerStatType)0) == 0f && s.Get((PlayerStatType)6) >= TitleFragment.Scaled(TitleCategory.Death, 200f), (IReadOnlyList<PlayerStatType>)(object)new PlayerStatType[2]
			{
				default(PlayerStatType),
				(PlayerStatType)6
			}, (IStatSource s) => s.Get((PlayerStatType)6) / TitleFragment.Scaled(TitleCategory.Death, 200f), isFallback: false, (IStatSource s) => TitleFragment.Number(s.Get((PlayerStatType)6)) + " kills and not one death (needed " + TitleFragment.Number(TitleFragment.Scaled(TitleCategory.Death, 200f)) + " kills, 0 deaths)"),
			new TitleFragment("scarce_mourned", TitleSlot.Epithet, TitleCategory.Death, Rarity.Epic, "Scarce-Mourned|Death-Dodging", (IStatSource s) => s.Get((PlayerStatType)0) <= 2f && s.Get((PlayerStatType)129) >= TitleFragment.Scaled(TitleCategory.Death, 50f), (IReadOnlyList<PlayerStatType>)(object)new PlayerStatType[2]
			{
				default(PlayerStatType),
				(PlayerStatType)129
			}, (IStatSource s) => s.Get((PlayerStatType)129) / TitleFragment.Scaled(TitleCategory.Death, 50f), isFallback: false, (IStatSource s) => TitleFragment.Number(s.Get((PlayerStatType)129)) + " days survived unbroken, only " + TitleFragment.Number(s.Get((PlayerStatType)0)) + " deaths (needed " + TitleFragment.Number(TitleFragment.Scaled(TitleCategory.Death, 50f)) + " days, at most 2)"),
			TitleFragment.Threshold("long_lived", TitleSlot.Epithet, TitleCategory.Misc, Rarity.Epic, "Long-Lived|Grey-Bearded", (PlayerStatType)129, 100f),
			TitleFragment.Threshold("well_rested", TitleSlot.Epithet, TitleCategory.Misc, Rarity.Uncommon, "Well-Rested|Sleep-Glad|Bed-Loving", (PlayerStatType)23, 250f),
			TitleFragment.Threshold("raven_spoken", TitleSlot.Epithet, TitleCategory.Misc, Rarity.Rare, "Raven-Spoken|Munin-Heeding", (PlayerStatType)46, 30f),
			TitleFragment.Threshold("leap_glad", TitleSlot.Epithet, TitleCategory.Misc, Rarity.Uncommon, "Leap-Glad|Spring-Heeled", (PlayerStatType)3, 5000f),
			TitleFragment.Threshold("portal_worn", TitleSlot.Epithet, TitleCategory.Misc, Rarity.Uncommon, "Portal-Worn|Rift-Stepping|Gate-Hopping", (PlayerStatType)15, 500f),
			TitleFragment.Threshold("door_minded", TitleSlot.Epithet, TitleCategory.Misc, Rarity.Rare, "Door-Minded|Draught-Hating", (PlayerStatType)75, 500f),
			TitleFragment.Threshold("raven_striking", TitleSlot.Epithet, TitleCategory.Misc, Rarity.Epic, "Raven-Striking|Munin-Swatting", (PlayerStatType)45, 1f),
			TitleFragment.Threshold("trophy_proud", TitleSlot.Epithet, TitleCategory.Misc, Rarity.Uncommon, "Trophy-Proud|Head-Hanging", (PlayerStatType)24, 30f),
			TitleFragment.Threshold("armor_proud", TitleSlot.Epithet, TitleCategory.Misc, Rarity.Uncommon, "Armor-Proud|Mail-Displaying", (PlayerStatType)25, 20f),
			TitleFragment.Threshold("tidy_handed", TitleSlot.Epithet, TitleCategory.Misc, Rarity.Uncommon, "Tidy-Handed|Chest-Sorting", (PlayerStatType)82, 300f),
			TitleFragment.Threshold("skald", TitleSlot.Noun, TitleCategory.Misc, Rarity.Uncommon, "Skald|Saga-Teller|Rune-Reader", (PlayerStatType)46, 10f),
			TitleFragment.Threshold("hoarder", TitleSlot.Noun, TitleCategory.Misc, Rarity.Rare, "Hoarder|Packrat|Magpie", (PlayerStatType)12, 10000f),
			TitleFragment.Threshold("sleeper", TitleSlot.Noun, TitleCategory.Misc, Rarity.Rare, "Sleeper|Dreamer|Slugabed", (PlayerStatType)23, 500f),
			TitleFragment.Threshold("elder", TitleSlot.Noun, TitleCategory.Misc, Rarity.Epic, "Elder|Greybeard|Old-Timer", (PlayerStatType)129, 150f),
			TitleFragment.Threshold("trophy_keeper", TitleSlot.Noun, TitleCategory.Misc, Rarity.Rare, "Trophy-Keeper|Head-Collector", (PlayerStatType)24, 80f),
			TitleFragment.Threshold("long_night", TitleSlot.Domain, TitleCategory.Misc, Rarity.Uncommon, "Long Night|Dark Hours", (PlayerStatType)23, 150f),
			TitleFragment.Threshold("old_ways", TitleSlot.Domain, TitleCategory.Misc, Rarity.Rare, "Old Ways|Old Gods", (PlayerStatType)129, 50f),
			TitleFragment.Threshold("trophy_wall", TitleSlot.Domain, TitleCategory.Misc, Rarity.Rare, "Trophy Wall|Mounted Heads", (PlayerStatType)24, 50f)
		};
	}
	internal static class HearthFragments
	{
		internal static IEnumerable<TitleFragment> All => new TitleFragment[57]
		{
			TitleFragment.Threshold("hall_raising", TitleSlot.Epithet, TitleCategory.Building, Rarity.Uncommon, "Hall-Raising|Beam-Lifting|Ever-Building", (PlayerStatType)168, 3000f),
			TitleFragment.Threshold("stone_setting", TitleSlot.Epithet, TitleCategory.Building, Rarity.Uncommon, "Wall-Raising|Stone-Setting|Plank-Nailing", (PlayerStatType)175, 350f),
			TitleFragment.Threshold("rampart_raising", TitleSlot.Epithet, TitleCategory.Building, Rarity.Rare, "Rampart-Raising|Fortress-Minded", (PlayerStatType)175, 900f),
			TitleFragment.Threshold("high_building", TitleSlot.Epithet, TitleCategory.Building, Rarity.Epic, "High-Building|Tower-Raising|Sky-Reaching", (PlayerStatType)130, 40f),
			TitleFragment.Threshold("well_lit", TitleSlot.Epithet, TitleCategory.Building, Rarity.Uncommon, "Well-Lit|Torch-Lining|Lamp-Hanging", (PlayerStatType)179, 60f),
			TitleFragment.Threshold("well_housed", TitleSlot.Epithet, TitleCategory.Building, Rarity.Rare, "Well-Housed|Comfort-Wise|Cushion-Proud", (PlayerStatType)132, 17f),
			TitleFragment.Threshold("ever_mending", TitleSlot.Epithet, TitleCategory.Building, Rarity.Rare, "Ever-Mending|Never-Satisfied|Oft-Rebuilding", (PlayerStatType)170, 2000f),
			TitleFragment.Threshold("well_adorned", TitleSlot.Epithet, TitleCategory.Building, Rarity.Rare, "Well-Adorned|Rug-Proud|Banner-Hanging", (PlayerStatType)180, 60f),
			TitleFragment.Threshold("housecarl", TitleSlot.Noun, TitleCategory.Building, Rarity.Uncommon, "Housecarl|Joiner|Builder", (PlayerStatType)168, 1500f),
			TitleFragment.Threshold("thatcher", TitleSlot.Noun, TitleCategory.Building, Rarity.Uncommon, "Thatcher|Roofer|Shingler", (PlayerStatType)176, 200f),
			TitleFragment.Threshold("hallwright", TitleSlot.Noun, TitleCategory.Building, Rarity.Rare, "Hallwright|Roof-Raiser|Rafter-Master", (PlayerStatType)176, 450f),
			TitleFragment.Threshold("stonewright", TitleSlot.Noun, TitleCategory.Building, Rarity.Rare, "Stonewright|Mason|Pillar-Setter", (PlayerStatType)177, 200f),
			TitleFragment.Threshold("hearthkeeper", TitleSlot.Noun, TitleCategory.Building, Rarity.Uncommon, "Hearthkeeper|Homemaker|Bench-Carver", (PlayerStatType)178, 60f),
			TitleFragment.Threshold("wallwarden", TitleSlot.Noun, TitleCategory.Building, Rarity.Rare, "Wallwarden|Palisader|Stake-Setter", (PlayerStatType)186, 150f),
			TitleFragment.Threshold("stairwright", TitleSlot.Noun, TitleCategory.Building, Rarity.Epic, "Stairwright|Step-Cutter", (PlayerStatType)188, 80f),
			TitleFragment.Threshold("jarl", TitleSlot.Noun, TitleCategory.Building, Rarity.Legendary, "Jarl|Chieftain|Hall-King", (PlayerStatType)168, 20000f),
			TitleFragment.Threshold("quiet_hearth", TitleSlot.Domain, TitleCategory.Building, Rarity.Uncommon, "Quiet Hearth|Warm Hall|Long Bench", (PlayerStatType)178, 40f),
			TitleFragment.Threshold("high_hall", TitleSlot.Domain, TitleCategory.Building, Rarity.Rare, "High Hall|Tall Tower", (PlayerStatType)130, 28f),
			TitleFragment.Threshold("long_wall", TitleSlot.Domain, TitleCategory.Building, Rarity.Rare, "Long Wall|Great Wall|High Ramparts", (PlayerStatType)175, 700f),
			TitleFragment.Threshold("bee_tending", TitleSlot.Epithet, TitleCategory.Harvest, Rarity.Uncommon, "Bee-Tending|Honey-Handed|Hive-Minded", (PlayerStatType)76, 100f),
			TitleFragment.Threshold("sap_drawing", TitleSlot.Epithet, TitleCategory.Harvest, Rarity.Rare, "Sap-Drawing|Root-Tapping", (PlayerStatType)77, 200f),
			TitleFragment.Threshold("green_thumbed", TitleSlot.Epithet, TitleCategory.Harvest, Rarity.Uncommon, "Green-Thumbed|Soil-Blessed|Seed-Sowing", (PlayerStatType)123, 500f),
			TitleFragment.Threshold("berry_stained", TitleSlot.Epithet, TitleCategory.Harvest, Rarity.Uncommon, "Berry-Stained|Bramble-Scratched", (PlayerStatType)124, 500f),
			TitleFragment.Threshold("wood_wise", TitleSlot.Epithet, TitleCategory.Harvest, Rarity.Rare, "Wood-Wise|Mushroom-Mad|Toadstool-Wise", (PlayerStatType)125, 400f),
			TitleFragment.Threshold("beekeeper", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Uncommon, "Beekeeper|Hive-Warden|Honey-Taker", (PlayerStatType)76, 50f),
			TitleFragment.Threshold("tiller", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Uncommon, "Tiller|Farmer|Ploughman", (PlayerStatType)123, 200f),
			TitleFragment.Threshold("forager", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Common, "Forager|Berry-Picker", (PlayerStatType)124, 150f),
			TitleFragment.Threshold("sapwright", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Rare, "Sapwright|Sap-Tapper", (PlayerStatType)77, 100f),
			TitleFragment.Threshold("limbhewer", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Uncommon, "Limbhewer|Axeman|Lumberjack", (PlayerStatType)27, 5000f),
			TitleFragment.Threshold("stonebreaker", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Uncommon, "Stonebreaker|Rockhewer|Quarryman", (PlayerStatType)38, 1500f),
			TitleFragment.Threshold("oakfeller", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Epic, "Oakfeller|Oak-Toppler", (PlayerStatType)194, 100f),
			TitleFragment.Threshold("green_hall", TitleSlot.Domain, TitleCategory.Harvest, Rarity.Rare, "Green Hall|Tilled Field|Turnip Rows", (PlayerStatType)123, 400f),
			TitleFragment.Threshold("deep_wood", TitleSlot.Domain, TitleCategory.Harvest, Rarity.Uncommon, "Deep Wood|Tall Timber|Stump Field", (PlayerStatType)28, 800f),
			TitleFragment.Threshold("black_vein", TitleSlot.Domain, TitleCategory.Harvest, Rarity.Rare, "Black Vein|Deep Seam", (PlayerStatType)38, 2500f),
			TitleFragment.Threshold("well_fed", TitleSlot.Epithet, TitleCategory.Cooking, Rarity.Uncommon, "Well-Fed|Stout-Bellied|Hearty", (PlayerStatType)49, 800f),
			TitleFragment.Threshold("ale_warmed", TitleSlot.Epithet, TitleCategory.Cooking, Rarity.Rare, "Ale-Warmed|Mead-Soaked", (PlayerStatType)184, 20f),
			TitleFragment.Threshold("smoke_touched", TitleSlot.Epithet, TitleCategory.Cooking, Rarity.Uncommon, "Smoke-Touched|Spit-Turning|Grease-Fingered", (PlayerStatType)111, 300f),
			TitleFragment.Threshold("ash_tongued", TitleSlot.Epithet, TitleCategory.Cooking, Rarity.Rare, "Ash-Tongued|Char-Loving|Burnt-Offering", (PlayerStatType)112, 100f),
			TitleFragment.Threshold("cook", TitleSlot.Noun, TitleCategory.Cooking, Rarity.Common, "Cook|Pot-Stirrer|Broth-Maker", (PlayerStatType)109, 200f),
			TitleFragment.Threshold("firetender", TitleSlot.Noun, TitleCategory.Cooking, Rarity.Uncommon, "Firetender|Grillmaster|Spit-Turner", (PlayerStatType)111, 150f),
			TitleFragment.Threshold("meadwright", TitleSlot.Noun, TitleCategory.Cooking, Rarity.Rare, "Meadwright|Brewer|Mead-Brewer", (PlayerStatType)184, 10f),
			TitleFragment.Threshold("feastgiver", TitleSlot.Noun, TitleCategory.Cooking, Rarity.Epic, "Feastgiver|Feast-Host", (PlayerStatType)185, 8f),
			TitleFragment.Threshold("long_table", TitleSlot.Domain, TitleCategory.Cooking, Rarity.Rare, "Long Table|Mead Bench", (PlayerStatType)185, 5f),
			TitleFragment.Threshold("full_board", TitleSlot.Domain, TitleCategory.Cooking, Rarity.Uncommon, "Full Board|Groaning Board|Stewpot", (PlayerStatType)49, 500f),
			TitleFragment.Threshold("iron_handed", TitleSlot.Epithet, TitleCategory.Crafting, Rarity.Uncommon, "Iron-Handed|Anvil-Ringing", (PlayerStatType)114, 100f),
			TitleFragment.Threshold("ever_bettering", TitleSlot.Epithet, TitleCategory.Crafting, Rarity.Rare, "Ever-Bettering|Whetstone-Keen", (PlayerStatType)14, 300f),
			TitleFragment.Threshold("well_girded", TitleSlot.Epithet, TitleCategory.Crafting, Rarity.Uncommon, "Well-Girded|Mail-Stitching", (PlayerStatType)115, 60f),
			TitleFragment.Threshold("torch_bearing", TitleSlot.Epithet, TitleCategory.Crafting, Rarity.Rare, "Torch-Bearing|Pitch-Stained", (PlayerStatType)120, 200f),
			TitleFragment.Threshold("smith", TitleSlot.Noun, TitleCategory.Crafting, Rarity.Common, "Smith|Hammerer|Forgehand", (PlayerStatType)13, 300f),
			TitleFragment.Threshold("weaponwright", TitleSlot.Noun, TitleCategory.Crafting, Rarity.Rare, "Weaponwright|Bladesmith|Edge-Maker", (PlayerStatType)114, 200f),
			TitleFragment.Threshold("fletcher", TitleSlot.Noun, TitleCategory.Crafting, Rarity.Uncommon, "Fletcher|Arrowsmith", (PlayerStatType)117, 300f),
			TitleFragment.Threshold("charmwright", TitleSlot.Noun, TitleCategory.Crafting, Rarity.Epic, "Charmwright|Trinket-Maker", (PlayerStatType)116, 25f),
			TitleFragment.Threshold("toolwright", TitleSlot.Noun, TitleCategory.Crafting, Rarity.Uncommon, "Toolwright|Tool-Maker", (PlayerStatType)119, 40f),
			TitleFragment.Threshold("refiner", TitleSlot.Noun, TitleCategory.Crafting, Rarity.Uncommon, "Refiner|Alloy-Maker", (PlayerStatType)118, 300f),
			TitleFragment.Threshold("masterwright", TitleSlot.Noun, TitleCategory.Crafting, Rarity.Legendary, "Masterwright|Master-Smith", (PlayerStatType)1, 2500f),
			TitleFragment.Threshold("forge", TitleSlot.Domain, TitleCategory.Crafting, Rarity.Uncommon, "Forge|Anvil|Smithy", (PlayerStatType)13, 500f),
			TitleFragment.Threshold("keen_edge", TitleSlot.Domain, TitleCategory.Crafting, Rarity.Rare, "Keen Edge|Bright Blade", (PlayerStatType)114, 150f)
		};
	}
	internal static class TierFragments
	{
		internal static IEnumerable<TitleFragment> All => new TitleFragment[28]
		{
			TitleFragment.Threshold("softwood_hewer", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Common, "Woodcutter|Kindling-Maker|Log-Splitter", (PlayerStatType)29, 200f),
			TitleFragment.Threshold("hardwood_hewer", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Uncommon, "Hardwood-Hewer|Hardwood-Feller", (PlayerStatType)31, 150f),
			TitleFragment.Threshold("ironwood_hewer", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Rare, "Ironwood-Hewer|Heartwood-Hewer", (PlayerStatType)32, 100f),
			TitleFragment.Threshold("ancient_hewer", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Epic, "Ancient-Hewer|Elderwood-Hewer", (PlayerStatType)33, 60f),
			TitleFragment.Threshold("world_hewer", TitleSlot.Epithet, TitleCategory.Harvest, Rarity.Legendary, "World-Hewing|Root-Severing", (PlayerStatType)34, 40f),
			TitleFragment.Threshold("fir_feller", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Common, "Fir-Feller|Needle-Shedder", (PlayerStatType)193, 150f),
			TitleFragment.Threshold("birch_breaker", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Uncommon, "Birch-Breaker|Birch-Feller", (PlayerStatType)200, 120f),
			TitleFragment.Threshold("mire_hewer", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Rare, "Mire-Hewer|Bog-Logger", (PlayerStatType)198, 150f),
			TitleFragment.Threshold("shoot_hewer", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Legendary, "Shoot-Hewer|Yggdrasil-Pruner", (PlayerStatType)197, 25f),
			TitleFragment.Threshold("ash_hewer", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Epic, "Ash-Hewer|Cinderwood-Cutter", (PlayerStatType)196, 80f),
			TitleFragment.Threshold("pine_feller", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Uncommon, "Pine-Feller|Pine-Toppler", (PlayerStatType)195, 150f),
			TitleFragment.Threshold("snowline", TitleSlot.Domain, TitleCategory.Harvest, Rarity.Rare, "Snowline|Frost Pines", (PlayerStatType)201, 100f),
			TitleFragment.Threshold("stone_knapper", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Common, "Stoneknapper|Pebble-Cracker", (PlayerStatType)39, 300f),
			TitleFragment.Threshold("iron_delver", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Uncommon, "Iron-Delver|Ore-Delver", (PlayerStatType)41, 200f),
			TitleFragment.Threshold("deep_hewer", TitleSlot.Epithet, TitleCategory.Harvest, Rarity.Rare, "Deep-Hewing|Vein-Chasing", (PlayerStatType)42, 150f),
			TitleFragment.Threshold("blackmetal_delver", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Epic, "Black-Delver|Dark-Delver", (PlayerStatType)43, 100f),
			TitleFragment.Threshold("flametal_delver", TitleSlot.Noun, TitleCategory.Harvest, Rarity.Legendary, "Flame-Delver|Flametal-Seeker", (PlayerStatType)44, 60f),
			TitleFragment.Threshold("small_catch", TitleSlot.Noun, TitleCategory.Fishing, Rarity.Common, "Minnow-Taker|Sprat-Catcher", (PlayerStatType)161, 40f),
			TitleFragment.Threshold("fair_catch", TitleSlot.Epithet, TitleCategory.Fishing, Rarity.Uncommon, "Sure-Handed|Steady-Lined", (PlayerStatType)162, 30f),
			TitleFragment.Threshold("fine_catch", TitleSlot.Noun, TitleCategory.Fishing, Rarity.Rare, "Deep-Catcher|Fine-Catcher", (PlayerStatType)163, 25f),
			TitleFragment.Threshold("great_catch", TitleSlot.Noun, TitleCategory.Fishing, Rarity.Epic, "Great-Catcher|Trophy-Angler", (PlayerStatType)164, 15f),
			TitleFragment.Threshold("legend_catch", TitleSlot.Epithet, TitleCategory.Fishing, Rarity.Legendary, "Deep-Favoured|Njord-Blessed", (PlayerStatType)165, 10f),
			TitleFragment.Threshold("cold_current", TitleSlot.Domain, TitleCategory.Fishing, Rarity.Rare, "Cold Current|Dark Water", (PlayerStatType)163, 12f),
			TitleFragment.Threshold("sapling_struck", TitleSlot.Epithet, TitleCategory.Death, Rarity.Rare, "Sapling-Struck|Twig-Felled", (PlayerStatType)152, 1f),
			TitleFragment.Threshold("hardwood_struck", TitleSlot.Epithet, TitleCategory.Death, Rarity.Rare, "Hardwood-Struck|Hardwood-Humbled", (PlayerStatType)154, 1f),
			TitleFragment.Threshold("ironwood_struck", TitleSlot.Epithet, TitleCategory.Death, Rarity.Epic, "Ironwood-Struck|Heartwood-Humbled", (PlayerStatType)155, 1f),
			TitleFragment.Threshold("ancient_struck", TitleSlot.Epithet, TitleCategory.Death, Rarity.Legendary, "Ancient-Struck|Root-Crowned", (PlayerStatType)157, 1f),
			TitleFragment.Threshold("fallen_timber", TitleSlot.Domain, TitleCategory.Death, Rarity.Rare, "Fallen Timber|Toppled Tree", (PlayerStatType)68, 2f)
		};
	}
	internal static class WarFragments
	{
		internal static IEnumerable<TitleFragment> All => new TitleFragment[37]
		{
			Style("bare_fisted", Rarity.Legendary, "Bare-Fisted|Knuckle-Bloodied", (KillModifiers)1, "unarmed", 100f),
			Style("far_shooting", Rarity.Rare, "Far-Shooting|Keen-Eyed|Long-Aiming", (KillModifiers)3, "ranged", 200f),
			Style("rune_handed", Rarity.Epic, "Rune-Handed|Staff-Wielding|Galdr-Wise", (KillModifiers)2, "magic", 200f),
			Style("close_fighting", Rarity.Uncommon, "Close-Fighting|Shield-Pressing|Toe-to-Toe", (KillModifiers)4, "melee", 300f),
			TitleFragment.Threshold("blood_worn", TitleSlot.Epithet, TitleCategory.Combat, Rarity.Uncommon, "Blood-Worn|Blade-Weary|Gore-Spattered", (PlayerStatType)6, 500f),
			TitleFragment.Threshold("much_feared", TitleSlot.Epithet, TitleCategory.Combat, Rarity.Rare, "Much-Feared|Dread-Named|Grim-Famed", (PlayerStatType)6, 2500f),
			TitleFragment.Threshold("red_handed", TitleSlot.Epithet, TitleCategory.Combat, Rarity.Epic, "Red-Handed|Slaughter-Glad", (PlayerStatType)6, 7500f),
			TitleFragment.Threshold("shield_worn", TitleSlot.Epithet, TitleCategory.Combat, Rarity.Uncommon, "Shield-Worn|Dent-Helmed|Bruise-Hided", (PlayerStatType)10, 2000f),
			TitleFragment.Threshold("arrow_glad", TitleSlot.Epithet, TitleCategory.Combat, Rarity.Uncommon, "Arrow-Glad|Quiver-Light", (PlayerStatType)51, 2000f),
			TitleFragment.Threshold("bone_calling", TitleSlot.Epithet, TitleCategory.Combat, Rarity.Rare, "Bone-Calling|Grave-Stirring", (PlayerStatType)50, 50f),
			TitleFragment.Threshold("trap_setting", TitleSlot.Epithet, TitleCategory.Combat, Rarity.Uncommon, "Trap-Setting|Snare-Minded", (PlayerStatType)80, 20f),
			TitleFragment.Threshold("slayer", TitleSlot.Noun, TitleCategory.Combat, Rarity.Common, "Slayer|Reaver|Brawler", (PlayerStatType)6, 200f),
			TitleFragment.Threshold("hunter", TitleSlot.Noun, TitleCategory.Combat, Rarity.Uncommon, "Hunter|Stalker|Tracker", (PlayerStatType)7, 500f),
			TitleFragment.Threshold("bowman", TitleSlot.Noun, TitleCategory.Combat, Rarity.Uncommon, "Bowman|Archer|Bowyer", (PlayerStatType)51, 1000f),
			TitleFragment.Threshold("shieldbearer", TitleSlot.Noun, TitleCategory.Combat, Rarity.Rare, "Shieldbearer|Shieldwall|Bulwark", (PlayerStatType)10, 5000f),
			TitleFragment.Threshold("bonecaller", TitleSlot.Noun, TitleCategory.Combat, Rarity.Epic, "Bonecaller|Necromancer", (PlayerStatType)50, 150f),
			TitleFragment.Threshold("trapper", TitleSlot.Noun, TitleCategory.Combat, Rarity.Rare, "Trapper|Snarer", (PlayerStatType)81, 25f),
			TitleFragment.Threshold("ballista_keeper", TitleSlot.Noun, TitleCategory.Combat, Rarity.Uncommon, "Ballista-Keeper|Bolt-Loader", (PlayerStatType)78, 200f),
			TitleFragment.Threshold("kinslayer", TitleSlot.Noun, TitleCategory.Combat, Rarity.Rare, "Kinslayer|Oathbreaker|Backstabber", (PlayerStatType)9, 3f),
			TitleFragment.Threshold("red_field", TitleSlot.Domain, TitleCategory.Combat, Rarity.Uncommon, "Red Field|Blood Moor|Battlefield", (PlayerStatType)6, 1000f),
			TitleFragment.Threshold("long_war", TitleSlot.Domain, TitleCategory.Combat, Rarity.Rare, "Long War|Endless Fray", (PlayerStatType)5, 20000f),
			TitleFragment.Threshold("crown_breaking", TitleSlot.Epithet, TitleCategory.Bosses, Rarity.Rare, "Crown-Breaking|King-Toppling|Throne-Breaking", (PlayerStatType)85, 5f),
			TitleFragment.Threshold("god_touched", TitleSlot.Epithet, TitleCategory.Bosses, Rarity.Epic, "God-Touched|Power-Wielding|Altar-Blessed", (PlayerStatType)96, 200f),
			TitleFragment.Threshold("alone_going", TitleSlot.Epithet, TitleCategory.Bosses, Rarity.Epic, "Alone-Going|Lone-Standing|Unaided", (PlayerStatType)147, 3f),
			TitleFragment.Threshold("oath_bound", TitleSlot.Epithet, TitleCategory.Bosses, Rarity.Uncommon, "Oath-Bound|Kin-Fighting|War-Banded", (PlayerStatType)146, 4f),
			TitleFragment.Threshold("bane", TitleSlot.Noun, TitleCategory.Bosses, Rarity.Uncommon, "Bane|Horn-Taker|Crown-Taker|Beast-Queller", (PlayerStatType)85, 3f),
			TitleFragment.Threshold("lone_slayer", TitleSlot.Noun, TitleCategory.Bosses, Rarity.Legendary, "Lone-Slayer|Lone-Wolf", (PlayerStatType)147, 5f),
			TitleFragment.Threshold("kingsbane", TitleSlot.Noun, TitleCategory.Bosses, Rarity.Legendary, "Kingsbane|Godsbane|Throne-Ender", (PlayerStatType)85, 8f),
			TitleFragment.Threshold("deathbringer", TitleSlot.Noun, TitleCategory.Bosses, Rarity.Epic, "Deathbringer|Finisher|Last-Striker", (PlayerStatType)86, 3f),
			TitleFragment.Threshold("nine_crowns", TitleSlot.Domain, TitleCategory.Bosses, Rarity.Legendary, "Nine Crowns|Fallen Gods", (PlayerStatType)85, 8f),
			TitleFragment.Threshold("stag_horn", TitleSlot.Domain, TitleCategory.Bosses, Rarity.Uncommon, "Stag's Horn|Storm Stag", (PlayerStatType)97, 25f),
			TitleFragment.Threshold("elder_wood", TitleSlot.Domain, TitleCategory.Bosses, Rarity.Rare, "Elder Wood|Old Root", (PlayerStatType)98, 25f),
			TitleFragment.Threshold("frozen_peak", TitleSlot.Domain, TitleCategory.Bosses, Rarity.Rare, "Frozen Peak|Dragon's Breath", (PlayerStatType)100, 25f),
			TitleFragment.Threshold("black_mire", TitleSlot.Domain, TitleCategory.Bosses, Rarity.Rare, "Black Mire|Bone Heap", (PlayerStatType)99, 25f),
			TitleFragment.Threshold("ashen_crown", TitleSlot.Domain, TitleCategory.Bosses, Rarity.Epic, "Ashen Crown|Fallen King", (PlayerStatType)101, 25f),
			TitleFragment.Threshold("hive_queen", TitleSlot.Domain, TitleCategory.Bosses, Rarity.Epic, "Hive Queen|Seeker Hive", (PlayerStatType)102, 25f),
			TitleFragment.Threshold("last_fire", TitleSlot.Domain, TitleCategory.Bosses, Rarity.Epic, "Last Fire|Burning Ring", (PlayerStatType)103, 25f)
		};

		private static TitleFragment Style(string id, Rarity rarity, string text, KillModifiers style, string styleName, float kills)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			return new TitleFragment(id, TitleSlot.Epithet, TitleCategory.Combat, rarity, text, (IStatSource s) => s.DominantKillStyle() == style && s.Get((PlayerStatType)6) >= TitleFragment.Scaled(TitleCategory.Combat, kills), (IReadOnlyList<PlayerStatType>)(object)new PlayerStatType[1] { (PlayerStatType)6 }, null, isFallback: false, (IStatSource s) => "most of your " + TitleFragment.Number(s.Get((PlayerStatType)6)) + " kills are " + styleName + " (needed " + TitleFragment.Number(TitleFragment.Scaled(TitleCategory.Combat, kills)) + "+, and a clear majority)");
		}
	}
	internal static class WildFragments
	{
		internal static IEnumerable<TitleFragment> All
		{
			get
			{
				TitleFragment[] obj = new TitleFragment[37]
				{
					TitleFragment.Threshold("far_walking", TitleSlot.Epithet, TitleCategory.Travel, Rarity.Uncommon, "Far-Walking|Long-Striding|Sore-Footed", (PlayerStatType)17, 150000f),
					TitleFragment.Threshold("swift_footed", TitleSlot.Epithet, TitleCategory.Travel, Rarity.Uncommon, "Swift-Footed|Fleet-Footed|Hare-Quick", (PlayerStatType)18, 120000f),
					TitleFragment.Threshold("salt_worn", TitleSlot.Epithet, TitleCategory.Travel, Rarity.Rare, "Salt-Worn|Sea-Weathered|Brine-Crusted", (PlayerStatType)19, 120000f),
					TitleFragment.Threshold("wind_borne", TitleSlot.Epithet, TitleCategory.Travel, Rarity.Rare, "Wind-Borne|Seldom-Grounded", (PlayerStatType)20, 60000f),
					TitleFragment.Threshold("road_weary", TitleSlot.Epithet, TitleCategory.Travel, Rarity.Rare, "Road-Weary|World-Worn|Mile-Eating", (PlayerStatType)16, 800000f),
					TitleFragment.Threshold("wanderer", TitleSlot.Noun, TitleCategory.Travel, Rarity.Common, "Wanderer|Roamer|Drifter", (PlayerStatType)16, 50000f),
					TitleFragment.Threshold("wayfarer", TitleSlot.Noun, TitleCategory.Travel, Rarity.Uncommon, "Wayfarer|Journeyer|Strider", (PlayerStatType)16, 350000f),
					TitleFragment.Threshold("helmsman", TitleSlot.Noun, TitleCategory.Travel, Rarity.Rare, "Helmsman|Steersman|Skipper", (PlayerStatType)150, 80000f),
					TitleFragment.Threshold("ferryman", TitleSlot.Noun, TitleCategory.Travel, Rarity.Uncommon, "Ferryman|Oarsman|Boatman", (PlayerStatType)19, 40000f),
					TitleFragment.Threshold("long_road", TitleSlot.Domain, TitleCategory.Travel, Rarity.Uncommon, "Long Road|Winding Path", (PlayerStatType)18, 80000f),
					TitleFragment.Threshold("nine_waves", TitleSlot.Domain, TitleCategory.Travel, Rarity.Rare, "Nine Waves|Whale Road|Swan Road", (PlayerStatType)19, 100000f),
					TitleFragment.Threshold("open_sky", TitleSlot.Domain, TitleCategory.Travel, Rarity.Uncommon, "Open Sky|Empty Air|High Leap", (PlayerStatType)20, 25000f),
					TitleFragment.Threshold("north_going", TitleSlot.Epithet, TitleCategory.Exploration, Rarity.Rare, "North-Going|North-Bound|Pole-Seeking", (PlayerStatType)138, 8000f),
					TitleFragment.Threshold("south_going", TitleSlot.Epithet, TitleCategory.Exploration, Rarity.Rare, "South-Going|South-Bound", (PlayerStatType)139, 8000f),
					TitleFragment.Threshold("east_going", TitleSlot.Epithet, TitleCategory.Exploration, Rarity.Rare, "East-Going|Dawn-Chasing", (PlayerStatType)140, 8000f),
					TitleFragment.Threshold("west_going", TitleSlot.Epithet, TitleCategory.Exploration, Rarity.Rare, "West-Going|Sunset-Chasing", (PlayerStatType)141, 8000f),
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null
				};
				Func<IStatSource, bool> qualifies = (IStatSource s) => MaxNoMap(s) >= TitleFragment.Scaled(TitleCategory.Exploration, 5000f);
				PlayerStatType[] array = new PlayerStatType[4];
				RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
				obj[16] = new TitleFragment("chartless", TitleSlot.Epithet, TitleCategory.Exploration, Rarity.Legendary, "Chartless|Map-Scorning", qualifies, (IReadOnlyList<PlayerStatType>)(object)array, (IStatSource s) => MaxNoMap(s) / TitleFragment.Scaled(TitleCategory.Exploration, 5000f), isFallback: false, (IStatSource s) => "time at the world's edge with no map: " + TitleFragment.Number(MaxNoMap(s)) + " (needed " + TitleFragment.Number(TitleFragment.Scaled(TitleCategory.Exploration, 5000f)) + ")");
				obj[17] = TitleFragment.Threshold("deep_delving", TitleSlot.Epithet, TitleCategory.Exploration, Rarity.Rare, "Deep-Delving|Crypt-Crawling|Tomb-Haunting", (PlayerStatType)83, 50f);
				obj[18] = TitleFragment.Threshold("pathfinder", TitleSlot.Noun, TitleCategory.Exploration, Rarity.Uncommon, "Pathfinder|Trailblazer|Scout", (PlayerStatType)135, 15f);
				obj[19] = TitleFragment.Threshold("delver", TitleSlot.Noun, TitleCategory.Exploration, Rarity.Rare, "Delver|Tomb-Robber|Crypt-Looter", (PlayerStatType)134, 20f);
				obj[20] = TitleFragment.Threshold("cairnbreaker", TitleSlot.Noun, TitleCategory.Exploration, Rarity.Rare, "Cairnbreaker|Barrow-Digger|Hoard-Finder", (PlayerStatType)133, 25f);
				obj[21] = TitleFragment.Threshold("leviathan_waker", TitleSlot.Noun, TitleCategory.Exploration, Rarity.Epic, "Leviathan-Waker|Leviathan-Rider", (PlayerStatType)136, 3f);
				obj[22] = TitleFragment.Threshold("hollow_hills", TitleSlot.Domain, TitleCategory.Exploration, Rarity.Rare, "Hollow Hills|Dark Crypts|Burial Mounds", (PlayerStatType)83, 30f);
				obj[23] = TitleFragment.Threshold("far_shore", TitleSlot.Domain, TitleCategory.Exploration, Rarity.Rare, "Far Shore|World's Rim", (PlayerStatType)141, 6000f);
				obj[24] = TitleFragment.Threshold("kindly", TitleSlot.Epithet, TitleCategory.Taming, Rarity.Uncommon, "Kindly|Gentle-Handed|Ear-Scratching", (PlayerStatType)191, 100f);
				obj[25] = TitleFragment.Threshold("beast_gentling", TitleSlot.Epithet, TitleCategory.Taming, Rarity.Rare, "Beast-Gentling|Wild-Taming", (PlayerStatType)48, 25f);
				obj[26] = TitleFragment.Threshold("tamer", TitleSlot.Noun, TitleCategory.Taming, Rarity.Uncommon, "Tamer|Wrangler|Beast-Breaker", (PlayerStatType)48, 10f);
				obj[27] = TitleFragment.Threshold("beastfriend", TitleSlot.Noun, TitleCategory.Taming, Rarity.Rare, "Beastfriend|Wolf-Friend|Lox-Friend", (PlayerStatType)191, 400f);
				obj[28] = TitleFragment.Threshold("herdmaster", TitleSlot.Noun, TitleCategory.Taming, Rarity.Epic, "Herdmaster|Stockmaster", (PlayerStatType)48, 60f);
				obj[29] = TitleFragment.Threshold("quiet_herd", TitleSlot.Domain, TitleCategory.Taming, Rarity.Uncommon, "Quiet Herd|Wolf Pack", (PlayerStatType)48, 15f);
				obj[30] = TitleFragment.Threshold("line_wise", TitleSlot.Epithet, TitleCategory.Fishing, Rarity.Uncommon, "Line-Wise|Hook-Clever", (PlayerStatType)160, 50f);
				obj[31] = TitleFragment.Threshold("patient", TitleSlot.Epithet, TitleCategory.Fishing, Rarity.Rare, "Patient|Still-Waiting|Tide-Watching", (PlayerStatType)158, 300f);
				obj[32] = TitleFragment.Threshold("oft_cheated", TitleSlot.Epithet, TitleCategory.Fishing, Rarity.Rare, "Oft-Cheated|Fish-Mocked", (PlayerStatType)159, 100f);
				obj[33] = TitleFragment.Threshold("angler", TitleSlot.Noun, TitleCategory.Fishing, Rarity.Uncommon, "Angler|Fisher|Rod-Holder", (PlayerStatType)160, 25f);
				obj[34] = TitleFragment.Threshold("fishwright", TitleSlot.Noun, TitleCategory.Fishing, Rarity.Rare, "Fishwright|Fishmonger", (PlayerStatType)160, 200f);
				obj[35] = TitleFragment.Threshold("netmaster", TitleSlot.Noun, TitleCategory.Fishing, Rarity.Epic, "Netmaster|Sea-Harvester", (PlayerStatType)160, 500f);
				obj[36] = TitleFragment.Threshold("still_water", TitleSlot.Domain, TitleCategory.Fishing, Rarity.Uncommon, "Still Water|Quiet Pool|Deep Pool", (PlayerStatType)160, 60f);
				return obj;
			}
		}

		private static float MaxNoMap(IStatSource s)
		{
			return Math.Max(Math.Max(s.Get((PlayerStatType)142), s.Get((PlayerStatType)143)), Math.Max(s.Get((PlayerStatType)144), s.Get((PlayerStatType)145)));
		}
	}
}
namespace Byname.Stats
{
	internal sealed class DeathLedger
	{
		private const string Prefix = "byname.died.";

		private const string ByPart = "by.";

		private const string InPart = "in.";

		internal static readonly DeathLedger Empty = new DeathLedger(new Dictionary<string, float>());

		private readonly Dictionary<string, float> _counts;

		private DeathLedger(Dictionary<string, float> counts)
		{
			_counts = counts;
		}

		internal static DeathLedger Read(Player player, long? worldUid)
		{
			if ((Object)(object)player == (Object)null)
			{
				return Empty;
			}
			string text = Scope(worldUid);
			Dictionary<string, float> dictionary = new Dictionary<string, float>(StringComparer.Ordinal);
			foreach (KeyValuePair<string, string> customDatum in player.m_customData)
			{
				if (customDatum.Key.StartsWith(text, StringComparison.Ordinal))
				{
					string text2 = customDatum.Key.Substring(text.Length);
					if ((text2.StartsWith("by.", StringComparison.Ordinal) || text2.StartsWith("in.", StringComparison.Ordinal)) && float.TryParse(customDatum.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
					{
						dictionary[text2] = result;
					}
				}
			}
			return new DeathLedger(dictionary);
		}

		internal float By(string creatureToken)
		{
			if (string.IsNullOrEmpty(creatureToken))
			{
				return 0f;
			}
			if (_counts.TryGetValue("by." + creatureToken, out var value))
			{
				return value;
			}
			string text = ((creatureToken[0] == '$') ? creatureToken.Substring(1) : ("$" + creatureToken));
			if (!_counts.TryGetValue("by." + text, out var value2))
			{
				return 0f;
			}
			return value2;
		}

		internal float In(string biome)
		{
			if (!_counts.TryGetValue("in." + biome, out var value))
			{
				return 0f;
			}
			return value;
		}

		internal unsafe static void Record(Player player, long worldUid, string killerToken, Biome biome)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			string[] array = new string[2]
			{
				Scope(null),
				Scope(worldUid)
			};
			foreach (string text in array)
			{
				if (!string.IsNullOrEmpty(killerToken))
				{
					Increment(player, text + "by." + killerToken);
				}
				if ((int)biome != 0)
				{
					Increment(player, text + "in." + ((object)(*(Biome*)(&biome))/*cast due to .constrained prefix*/).ToString());
				}
			}
		}

		private static string Scope(long? worldUid)
		{
			if (!worldUid.HasValue)
			{
				return "byname.died.";
			}
			return "byname.died.w" + worldUid.Value.ToString(CultureInfo.InvariantCulture) + ".";
		}

		private static void Increment(Player player, string key)
		{
			player.m_customData.TryGetValue(key, out var value);
			float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result);
			player.m_customData[key] = (result + 1f).ToString(CultureInfo.InvariantCulture);
		}
	}
	internal interface IStatSource
	{
		float Get(PlayerStatType stat);

		float GetEnemyKills(string prefabName, KillModifiers modifier = (KillModifiers)0);

		string TopEnemy();

		KillModifiers DominantKillStyle(float minimumShare = 0.6f);

		float GetDeathsBy(string creatureToken);

		float GetDeathsIn(string biome);
	}
	internal sealed class LifetimeStatSource : IStatSource
	{
		private readonly PlayerStats _stats;

		private readonly DeathLedger _deaths;

		internal PlayerStats Raw => _stats;

		internal LifetimeStatSource(PlayerProfile profile, DeathLedger deaths)
		{
			_stats = profile.m_playerStats[0];
			_deaths = deaths ?? DeathLedger.Empty;
		}

		public float Get(PlayerStatType stat)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (!_stats.m_stats.TryGetValue(stat, out var value))
			{
				return 0f;
			}
			return value;
		}

		public float GetEnemyKills(string prefabName, KillModifiers modifier = (KillModifiers)0)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Expected I4, but got Unknown
			int num = (int)modifier;
			if (num < 0 || num >= _stats.m_enemyStats.Length)
			{
				return 0f;
			}
			Dictionary<string, float> dictionary = _stats.m_enemyStats[num];
			if (dictionary == null || string.IsNullOrEmpty(prefabName))
			{
				return 0f;
			}
			if (dictionary.TryGetValue(prefabName, out var value))
			{
				return value;
			}
			string key = ((prefabName[0] == '$') ? prefabName.Substring(1) : ("$" + prefabName));
			if (!dictionary.TryGetValue(key, out var value2))
			{
				return 0f;
			}
			return value2;
		}

		public string TopEnemy()
		{
			Dictionary<string, float> dictionary = _stats.m_enemyStats[0];
			if (dictionary == null || dictionary.Count == 0)
			{
				return null;
			}
			string result = null;
			float num = 0f;
			foreach (KeyValuePair<string, float> item in dictionary)
			{
				if (item.Value > num)
				{
					num = item.Value;
					result = item.Key;
				}
			}
			return result;
		}

		public KillModifiers DominantKillStyle(float minimumShare = 0.6f)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			KillModifiers[] array = new KillModifiers[4];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			Dictionary<KillModifiers, float> dictionary = ((IEnumerable<KillModifiers>)(object)array).ToDictionary((KillModifiers s) => s, (KillModifiers s) => Sum(_stats.m_enemyStats[s]));
			float num = dictionary.Values.Sum();
			if (num <= 0f)
			{
				return (KillModifiers)0;
			}
			KeyValuePair<KillModifiers, float> keyValuePair = dictionary.OrderByDescending((KeyValuePair<KillModifiers, float> p) => p.Value).First();
			if (!(keyValuePair.Value / num >= minimumShare))
			{
				return (KillModifiers)0;
			}
			return keyValuePair.Key;
		}

		public float GetDeathsBy(string creatureToken)
		{
			return _deaths.By(creatureToken);
		}

		public float GetDeathsIn(string biome)
		{
			return _deaths.In(biome);
		}

		private static float Sum(Dictionary<string, float> d)
		{
			if (d == null)
			{
				return 0f;
			}
			float num = 0f;
			foreach (float value in d.Values)
			{
				num += value;
			}
			return num;
		}
	}
	internal sealed class WorldStatSource : IStatSource
	{
		private readonly LifetimeStatSource _lifetime;

		private readonly IReadOnlyDictionary<PlayerStatType, float> _baseline;

		private readonly DeathLedger _worldDeaths;

		internal WorldStatSource(LifetimeStatSource lifetime, IReadOnlyDictionary<PlayerStatType, float> baseline, DeathLedger worldDeaths)
		{
			_lifetime = lifetime;
			_baseline = baseline;
			_worldDeaths = worldDeaths ?? DeathLedger.Empty;
		}

		public float Get(PlayerStatType stat)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			float num = _lifetime.Get(stat);
			float value;
			float num2 = (_baseline.TryGetValue(stat, out value) ? value : 0f);
			float num3 = num - num2;
			if (!(num3 > 0f))
			{
				return 0f;
			}
			return num3;
		}

		public float GetEnemyKills(string prefabName, KillModifiers modifier = (KillModifiers)0)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return _lifetime.GetEnemyKills(prefabName, modifier);
		}

		public string TopEnemy()
		{
			return _lifetime.TopEnemy();
		}

		public KillModifiers DominantKillStyle(float minimumShare = 0.6f)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return _lifetime.DominantKillStyle(minimumShare);
		}

		public float GetDeathsBy(string creatureToken)
		{
			return _worldDeaths.By(creatureToken);
		}

		public float GetDeathsIn(string biome)
		{
			return _worldDeaths.In(biome);
		}
	}
	internal static class TitleState
	{
		private const string KeyEpoch = "byname.epoch";

		private const string KeyDay = "byname.day";

		private const string KeyTitle = "byname.title";

		private const string KeyRarity = "byname.rarity";

		private const string BaselinePrefix = "byname.base.";

		internal static int GetEpoch(Player player)
		{
			return ReadInt(player, "byname.epoch", 0);
		}

		internal static void SetEpoch(Player player, int epoch)
		{
			Write(player, "byname.epoch", epoch.ToString(CultureInfo.InvariantCulture));
		}

		internal static int GetLastChangeDay(Player player)
		{
			return ReadInt(player, "byname.day", -1);
		}

		internal static void SetLastChangeDay(Player player, int day)
		{
			Write(player, "byname.day", day.ToString(CultureInfo.InvariantCulture));
		}

		internal static string GetTitle(Player player)
		{
			if (!((Object)(object)player != (Object)null) || !player.m_customData.TryGetValue("byname.title", out var value))
			{
				return null;
			}
			return value;
		}

		internal static int GetRarity(Player player)
		{
			return ReadInt(player, "byname.rarity", 1);
		}

		internal static void SetTitle(Player player, string title, int rarity)
		{
			Write(player, "byname.title", title ?? "");
			Write(player, "byname.rarity", rarity.ToString(CultureInfo.InvariantCulture));
		}

		internal static IReadOnlyDictionary<PlayerStatType, float> GetBaseline(Player player, long worldUid)
		{
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			if (!player.m_customData.TryGetValue("byname.base." + worldUid, out var value))
			{
				return null;
			}
			Dictionary<PlayerStatType, float> dictionary = new Dictionary<PlayerStatType, float>();
			string[] array = value.Split(new char[1] { ';' });
			foreach (string text in array)
			{
				if (text.Length != 0)
				{
					string[] array2 = text.Split(new char[1] { ':' });
					if (array2.Length == 2 && int.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && float.TryParse(array2[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
					{
						dictionary[(PlayerStatType)result] = result2;
					}
				}
			}
			return dictionary;
		}

		internal static void SetBaseline(Player player, long worldUid, IEnumerable<PlayerStatType> tracked, LifetimeStatSource lifetime)
		{
			if (!((Object)(object)player == (Object)null))
			{
				IEnumerable<string> source = from s in tracked.Distinct()
					select ((int)s).ToString(CultureInfo.InvariantCulture) + ":" + lifetime.Get(s).ToString("R", CultureInfo.InvariantCulture);
				Write(player, "byname.base." + worldUid, string.Join(";", source.ToArray()));
			}
		}

		private static int ReadInt(Player player, string key, int fallback)
		{
			if ((Object)(object)player == (Object)null)
			{
				return fallback;
			}
			if (!player.m_customData.TryGetValue(key, out var value) || !int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return fallback;
			}
			return result;
		}

		private static void Write(Player player, string key, string value)
		{
			if (!((Object)(object)player == (Object)null))
			{
				player.m_customData[key] = value;
			}
		}
	}
}
namespace Byname.Patches
{
	[HarmonyPatch(typeof(InventoryGui), "UpdateCharacterStats")]
	internal static class CharacterPanelPatch
	{
		private static void Postfix(InventoryGui __instance, Player player)
		{
			if (BynameConfig.Enabled.Value && BynameConfig.ShowOnCharacterPanel.Value && !((Object)(object)__instance.m_playerName == (Object)null) && !((Object)(object)player == (Object)null))
			{
				int rarity;
				string text = TitleNet.Read(player, out rarity);
				if (!string.IsNullOrEmpty(text))
				{
					TMP_Text playerName = __instance.m_playerName;
					playerName.text = playerName.text + "\n<size=70%>" + TitleService.Decorate(text, rarity) + "</size>";
				}
			}
		}
	}
	[HarmonyPatch(typeof(Character), "ApplyDamage")]
	internal static class RecentAttackerTracker
	{
		internal const float BlameWindowSeconds = 45f;

		internal static string LastToken;

		internal static float LastTime = float.NegativeInfinity;

		private static void Prefix(Character __instance, HitData hit)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && hit != null)
			{
				Character attacker = hit.GetAttacker();
				if (!((Object)(object)attacker == (Object)null) && !attacker.IsPlayer())
				{
					LastToken = attacker.m_name;
					LastTime = Time.time;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "OnDeath")]
	internal static class DeathRecorder
	{
		private static void Prefix(Player __instance)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)((Character)__instance).m_nview == (Object)null || !((Character)__instance).m_nview.IsOwner())
			{
				return;
			}
			try
			{
				string text = ResolveKiller(__instance);
				Biome currentBiome = __instance.GetCurrentBiome();
				long worldUid = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldUID() : 0);
				DeathLedger.Record(__instance, worldUid, text, currentBiome);
				RecentAttackerTracker.LastTime = float.NegativeInfinity;
				BynamePlugin.LogVerbose(string.Format("death recorded: killer {0}, biome {1}", text ?? "<none>", currentBiome));
			}
			catch (Exception ex)
			{
				BynamePlugin.LogError("could not record death: " + ex.Message);
			}