Decompiled source of TheObituaries v0.3.2

BepInEx/plugins/TheObituaries.dll

Decompiled 10 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("TheObituaries")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.2.0")]
[assembly: AssemblyInformationalVersion("0.3.2+57d12112994262a5fa5a971f138957a74e207fa1")]
[assembly: AssemblyProduct("TheObituaries")]
[assembly: AssemblyTitle("TheObituaries")]
[assembly: AssemblyVersion("0.3.2.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TheObituaries
{
	public static class Api
	{
		private const float Grace = 3f;

		private static string _line;

		private static float _claimedAt;

		public static void NextDeath(string line)
		{
			_line = (string.IsNullOrEmpty(line) ? null : line);
			_claimedAt = Time.time;
		}

		internal static string Take()
		{
			string line = _line;
			_line = null;
			if (line == null)
			{
				return null;
			}
			if (!(Time.time - _claimedAt <= 3f))
			{
				return null;
			}
			return line;
		}
	}
	internal static class AttackerMemory
	{
		internal sealed class Entry
		{
			public string Description;

			public string Prefab;

			public string Weapon;

			public bool IsPlayer;

			public bool Poison;

			public bool Fire;

			public bool Blast;

			public float Time;
		}

		private const float Retention = 120f;

		private static readonly Dictionary<ZDOID, Entry> Recent = new Dictionary<ZDOID, Entry>();

		private static float _lastPrune;

		internal static void Clear()
		{
			Recent.Clear();
		}

		internal static void Record(HitData hit)
		{
			//IL_000d: 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)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			if (hit == null || !hit.HaveAttacker())
			{
				return;
			}
			ZDOID attacker = hit.m_attacker;
			Character attacker2 = hit.GetAttacker();
			Entry entry;
			if ((Object)(object)attacker2 != (Object)null)
			{
				entry = new Entry
				{
					Description = Obituary.Describe(attacker2),
					Prefab = Obituary.PrefabName(attacker2),
					Weapon = Obituary.WeaponName(attacker2),
					IsPlayer = (attacker2 is Player)
				};
			}
			else
			{
				entry = Obituary.DescribeById(attacker);
				if (entry == null)
				{
					return;
				}
			}
			entry.Poison = hit.m_damage.m_poison > 0f;
			entry.Fire = hit.m_damage.m_fire > 0f;
			entry.Blast = hit.m_radius > 0f;
			entry.Time = Time.time;
			Recent[attacker] = entry;
			Prune();
		}

		internal static Entry Lookup(ZDOID id)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: 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)
			if (id == ZDOID.None || !Recent.TryGetValue(id, out var value))
			{
				return null;
			}
			if (!(Time.time - value.Time <= 120f))
			{
				return null;
			}
			return value;
		}

		internal static Entry LastWhere(Func<Entry, bool> test, float maxAge)
		{
			Entry entry = null;
			float time = Time.time;
			foreach (Entry value in Recent.Values)
			{
				if (!(time - value.Time > maxAge) && test(value) && (entry == null || value.Time > entry.Time))
				{
					entry = value;
				}
			}
			return entry;
		}

		private static void Prune()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			float time = Time.time;
			if (time - _lastPrune < 30f)
			{
				return;
			}
			_lastPrune = time;
			List<ZDOID> list = new List<ZDOID>();
			foreach (KeyValuePair<ZDOID, Entry> item in Recent)
			{
				if (time - item.Value.Time > 120f)
				{
					list.Add(item.Key);
				}
			}
			foreach (ZDOID item2 in list)
			{
				Recent.Remove(item2);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "ApplyDamage")]
	internal static class Character_ApplyDamage_Patch
	{
		[HarmonyPrefix]
		private static void Prefix(Character __instance, HitData hit)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || hit == null || !hit.HaveAttacker() || hit.m_attacker == __instance.GetZDOID())
			{
				return;
			}
			try
			{
				AttackerMemory.Record(hit);
			}
			catch (Exception ex)
			{
				TheObituariesMod.Log.LogDebug((object)("Could not remember an attacker: " + ex.Message));
			}
		}
	}
	internal static class Commands
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__0_0;

			public static ConsoleOptionsFetcher <>9__0_1;

			internal void <Register>b__0_0(ConsoleEventArgs args)
			{
				string[] args2 = args.Args;
				string cause = ((args2.Length > 1) ? args2[1] : "");
				string weapon = ((args2.Length > 2) ? args2[2] : "");
				string[] array = Run(cause, weapon).Split(new char[1] { '\n' });
				foreach (string text in array)
				{
					Terminal context = args.Context;
					if (context != null)
					{
						context.AddString(text);
					}
				}
			}

			internal List<string> <Register>b__0_1()
			{
				List<string> list = new List<string> { "all", "causes", "pvp" };
				string[] names = Enum.GetNames(typeof(HitType));
				foreach (string text in names)
				{
					list.Add(text.ToLowerInvariant());
				}
				foreach (string item in Obituary.KnownCreatures())
				{
					list.Add(item.ToLowerInvariant());
				}
				return list;
			}
		}

		private static readonly Random Rng = new Random();

		internal static void Register()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			object obj = <>c.<>9__0_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					string[] args2 = args.Args;
					string cause = ((args2.Length > 1) ? args2[1] : "");
					string weapon = ((args2.Length > 2) ? args2[2] : "");
					string[] array = Run(cause, weapon).Split(new char[1] { '\n' });
					foreach (string text in array)
					{
						Terminal context = args.Context;
						if (context != null)
						{
							context.AddString(text);
						}
					}
				};
				<>c.<>9__0_0 = val;
				obj = (object)val;
			}
			object obj2 = <>c.<>9__0_1;
			if (obj2 == null)
			{
				ConsoleOptionsFetcher val2 = delegate
				{
					List<string> list = new List<string> { "all", "causes", "pvp" };
					string[] names = Enum.GetNames(typeof(HitType));
					foreach (string text in names)
					{
						list.Add(text.ToLowerInvariant());
					}
					foreach (string item in Obituary.KnownCreatures())
					{
						list.Add(item.ToLowerInvariant());
					}
					return list;
				};
				<>c.<>9__0_1 = val2;
				obj2 = (object)val2;
			}
			new ConsoleCommand("obituary", "The Obituaries: 'obituary' previews a random death line here only, 'obituary <cause> [weapon]' previews one cause (fall, drowning, troll, draugr bow, pvp club, ...), 'obituary all' previews every hit type, 'obituary causes' lists them", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)obj2, false, false, false);
		}

		private static string Run(string cause, string weapon)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return "The Obituaries: load into a world first.";
			}
			if (cause.Equals("causes", StringComparison.OrdinalIgnoreCase))
			{
				StringBuilder stringBuilder = new StringBuilder("Hit types: ");
				stringBuilder.Append(string.Join(", ", Enum.GetNames(typeof(HitType))).ToLowerInvariant());
				stringBuilder.Append("\nCreatures: ");
				stringBuilder.Append(string.Join(", ", Obituary.KnownCreatures()).ToLowerInvariant());
				stringBuilder.Append("\nWeapons (second word, optional): ");
				stringBuilder.Append(string.Join(", ", Enum.GetNames(typeof(WeaponKind))).ToLowerInvariant());
				stringBuilder.Append("\nAnd: pvp");
				return stringBuilder.ToString();
			}
			if (cause.Equals("all", StringComparison.OrdinalIgnoreCase))
			{
				int num = 0;
				string[] names = Enum.GetNames(typeof(HitType));
				for (int i = 0; i < names.Length; i++)
				{
					Notice notice = Obituary.Sample(names[i], "", localPlayer);
					if (notice != null)
					{
						DeathNetwork.Show(notice);
						num++;
					}
				}
				names = new string[3] { "pvp", "troll", "draugr" };
				for (int i = 0; i < names.Length; i++)
				{
					Notice notice2 = Obituary.Sample(names[i], "", localPlayer);
					if (notice2 != null)
					{
						DeathNetwork.Show(notice2);
						num++;
					}
				}
				return $"Previewed {num} obituaries (shown here only).";
			}
			if (cause.Length == 0)
			{
				List<string> list = new List<string> { "pvp" };
				string[] names = Enum.GetNames(typeof(HitType));
				foreach (string item in names)
				{
					list.Add(item);
				}
				foreach (string item2 in Obituary.KnownCreatures())
				{
					list.Add(item2);
				}
				cause = list[Rng.Next(list.Count)];
			}
			Notice notice3 = Obituary.Sample(cause, weapon, localPlayer);
			if (notice3 == null)
			{
				return "Unknown cause or weapon '" + cause + " " + weapon + "'. Try a hit type (fall, drowning, self, ...), a creature (troll, draugr, ...) or pvp, with an optional weapon (bow, axe, club, ...); 'obituary causes' lists them.";
			}
			DeathNetwork.Show(notice3);
			return "Previewed (shown here only): " + notice3.Plain();
		}
	}
	internal static class DeathNetwork
	{
		private const string RpcName = "DM_Obituary";

		private static readonly FieldRef<Chat, float> HideTimer = AccessTools.FieldRefAccess<Chat, float>("m_hideTimer");

		private static Coroutine _centerRepeat;

		private static bool _sendingOwn;

		private const float FadeSeconds = 4f;

		internal static void Register()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null)
			{
				instance.Register<ZPackage>("DM_Obituary", (Action<long, ZPackage>)RPC_Obituary);
			}
		}

		internal static void Send(Notice notice)
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance == null || notice == null)
			{
				return;
			}
			_sendingOwn = true;
			try
			{
				instance.InvokeRoutedRPC(0L, "DM_Obituary", new object[1] { notice.Pack() });
			}
			finally
			{
				_sendingOwn = false;
			}
		}

		private static void RPC_Obituary(long sender, ZPackage pkg)
		{
			try
			{
				Notice notice = Notice.Unpack(pkg);
				if (notice != null)
				{
					Show(notice, _sendingOwn);
				}
			}
			catch (Exception ex)
			{
				TheObituariesMod.Log.LogWarning((object)("Could not show an obituary: " + ex));
			}
		}

		internal static void Show(Notice notice, bool own = false)
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			float seconds = (own ? TheObituariesMod.CenterSeconds.Value : TheObituariesMod.CenterSecondsOthers.Value);
			if (!TheObituariesMod.ModEnabled.Value)
			{
				return;
			}
			if (TheObituariesMod.ShowInChat.Value && (Object)(object)Chat.instance != (Object)null)
			{
				((Terminal)Chat.instance).AddString(notice.Rich(sized: true));
				float num = Mathf.Max(0f, TheObituariesMod.ChatSeconds.Value);
				HideTimer.Invoke(Chat.instance) = Mathf.Min(0f, Chat.instance.m_hideDelay - num);
			}
			MessageHud instance = MessageHud.instance;
			if ((Object)(object)instance != (Object)null)
			{
				string text = notice.Rich(sized: false);
				switch (TheObituariesMod.OnScreen.Value)
				{
				case TheObituariesMod.ScreenSpot.TopLeft:
					instance.ShowMessage((MessageType)1, text, 0, (Sprite)null, false, true);
					break;
				case TheObituariesMod.ScreenSpot.Center:
					ShowCenter(text, seconds);
					break;
				}
				if (TheObituariesMod.YouFragged.Value && notice.KillerIsPlayer && (Object)(object)Player.m_localPlayer != (Object)null && notice.KillerId != ZDOID.None && notice.KillerId == ((Character)Player.m_localPlayer).GetZDOID())
				{
					ShowCenter("You fragged " + TheObituariesMod.Colored(TheObituariesMod.Bold(notice.Victim), TheObituariesMod.VictimColor), TheObituariesMod.CenterSecondsOthers.Value);
				}
			}
			if (TheObituariesMod.LogObituaries.Value)
			{
				TheObituariesMod.Log.LogInfo((object)notice.Plain());
			}
		}

		private static void ShowCenter(string text, float seconds)
		{
			MessageHud instance = MessageHud.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, true);
			TheObituariesMod instance2 = TheObituariesMod.Instance;
			if (!((Object)(object)instance2 == (Object)null) && !(seconds <= 4f))
			{
				if (_centerRepeat != null)
				{
					((MonoBehaviour)instance2).StopCoroutine(_centerRepeat);
				}
				_centerRepeat = ((MonoBehaviour)instance2).StartCoroutine(HoldCenter(text, seconds));
			}
		}

		private static IEnumerator HoldCenter(string text, float seconds)
		{
			yield return (object)new WaitForSecondsRealtime(0.25f);
			TMP_Text label = (((Object)(object)MessageHud.instance != (Object)null) ? MessageHud.instance.m_messageCenterText : null);
			if ((Object)(object)label == (Object)null || label.text != text)
			{
				_centerRepeat = null;
				yield break;
			}
			((Graphic)label).CrossFadeAlpha(1f, 0f, true);
			float hold = seconds - 4f - 0.25f;
			float elapsed = 0f;
			while (elapsed < hold)
			{
				yield return null;
				elapsed += Time.unscaledDeltaTime;
				if (label.text != text)
				{
					_centerRepeat = null;
					yield break;
				}
			}
			((Graphic)label).CrossFadeAlpha(0f, 4f, true);
			_centerRepeat = null;
		}
	}
	internal sealed class Notice
	{
		private const byte Version = 1;

		public string Victim = "";

		public string Killer = "";

		public bool KillerIsPlayer;

		public ZDOID KillerId = ZDOID.None;

		public string Template = "{v} died";

		public ZPackage Pack()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write((byte)1);
			val.Write(Victim ?? "");
			val.Write(Killer ?? "");
			val.Write(KillerIsPlayer);
			val.Write(KillerId);
			val.Write(Template ?? "");
			return val;
		}

		public static Notice Unpack(ZPackage pkg)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (pkg == null)
			{
				return null;
			}
			if (pkg.ReadByte() != 1)
			{
				return null;
			}
			return new Notice
			{
				Victim = pkg.ReadString(),
				Killer = pkg.ReadString(),
				KillerIsPlayer = pkg.ReadBool(),
				KillerId = pkg.ReadZDOID(),
				Template = pkg.ReadString()
			};
		}

		public string Plain()
		{
			return Fill(Victim, Killer);
		}

		public string Rich(bool sized)
		{
			string text = Fill(TheObituariesMod.Colored(TheObituariesMod.Bold(Victim), TheObituariesMod.VictimColor), TheObituariesMod.Colored(TheObituariesMod.Bold(Killer), TheObituariesMod.KillerColor));
			text = TheObituariesMod.Colored(text, TheObituariesMod.LineColor);
			if (sized)
			{
				int value = TheObituariesMod.TextSize.Value;
				if (value != 100)
				{
					text = "<size=" + value + "%>" + text + "</size>";
				}
			}
			return text;
		}

		private string Fill(string victim, string killer)
		{
			return (Template ?? "").Replace("{v}", victim ?? "").Replace("{k}", killer ?? "");
		}
	}
	internal enum WeaponKind
	{
		Unknown,
		Bow,
		Sword,
		Axe,
		Club,
		Spear,
		Knife,
		Fire,
		Frost,
		Lightning,
		Poison,
		Spirit,
		Bite,
		Punch,
		Log,
		Rock,
		Magic,
		Pickaxe,
		Blast
	}
	internal static class Obituary
	{
		private static readonly Random Rng = new Random();

		private static readonly Dictionary<HitType, string[]> Environment = new Dictionary<HitType, string[]>
		{
			{
				(HitType)0,
				new string[1] { "{v} died" }
			},
			{
				(HitType)1,
				new string[2] { "{v} died", "{v} got jacked up by something" }
			},
			{
				(HitType)2,
				new string[1] { "{v} died" }
			},
			{
				(HitType)3,
				new string[3] { "{v} cratered", "{v} fell to {his} death", "{v} learned about gravity the hard way" }
			},
			{
				(HitType)4,
				new string[5] { "{v} sank like a rock", "{v} sleeps with the fishes", "{v} went for a swim and never came back", "{v} drowned", "{v} thought {he} could breathe water" }
			},
			{
				(HitType)5,
				new string[3] { "{v} burnt to a crisp", "{v} was fried", "{v} burst into flames" }
			},
			{
				(HitType)6,
				new string[4] { "{v} was frozen solid", "{v} should have brought a coat", "{v} turned to ice", "{v} turned into an ice cube" }
			},
			{
				(HitType)7,
				new string[3] { "{v} was poisoned to death", "{v} died from poisoning", "{v} can't exist on slime alone" }
			},
			{
				(HitType)8,
				new string[2] { "{v} sank like a rock", "{v} sleeps with the fishes" }
			},
			{
				(HitType)9,
				new string[2] { "{v} was smoked out", "{v} thought {he} could breathe smoke like air" }
			},
			{
				(HitType)10,
				new string[3] { "{v} tried to leave", "{v} found a way out", "{v} was in the wrong place" }
			},
			{
				(HitType)11,
				new string[2] { "{v} learned about gravity the hard way", "{v} was squished" }
			},
			{
				(HitType)12,
				new string[5] { "{v} was squished by a cart", "{v} was run over by a cart", "{v} was crushed by a cart", "{v} was flattened by a cart", "{v} lost a fight with a cart" }
			},
			{
				(HitType)13,
				new string[3] { "{v} was squished by a tree", "{v} took on a tree and lost", "{v} should have yelled timber" }
			},
			{
				(HitType)14,
				new string[7] { "{v} suicides", "{v} becomes bored with life", "{v} killed {himself}", "{v} was fed up with this cruel world", "{v} was tired of life", "{v} wanted to see what it's like on the other side", "{v} had seen enough" }
			},
			{
				(HitType)15,
				new string[2] { "{v} was squished by a building", "{v} was buried by {his} own building" }
			},
			{
				(HitType)16,
				new string[2] { "{v} was gunned down by a ballista", "{v} was railed by a ballista" }
			},
			{
				(HitType)17,
				new string[3] { "{v} was keelhauled", "{v} was squished by a boat", "{v} ate a boat" }
			},
			{
				(HitType)18,
				new string[1] { "{v} was spiked" }
			},
			{
				(HitType)19,
				new string[3] { "{v} rode a catapult shot", "{v} caught a catapult shot", "{v} ate a catapult shot" }
			},
			{
				(HitType)20,
				new string[2] { "{v} burst into flames", "{v} visits the Volcano God" }
			},
			{
				(HitType)21,
				new string[2] { "{v} heats up the water", "{v} was boiled alive" }
			},
			{
				(HitType)22,
				new string[2] { "{v} does a back flip into the lava", "{v} visits the Volcano God" }
			},
			{
				(HitType)23,
				new string[2] { "{v} saw the light", "{v} was recycled" }
			},
			{
				(HitType)24,
				new string[3] { "{v} was squished by a drawbridge", "{v} was crushed by a drawbridge", "{v} didn't realize how dangerous a drawbridge can be" }
			}
		};

		private static readonly string[] SelfInflicted = new string[3] { "{v} blew {himself} up", "{v} tripped on {his} own bomb", "{v} should have used a smaller gun" };

		private static readonly Dictionary<WeaponKind, string[]> ByKind = new Dictionary<WeaponKind, string[]>
		{
			{
				WeaponKind.Bow,
				new string[7] { "{v} accepted {k}'s shaft", "{v} ate {k}'s arrow", "{v} was railed by {k}", "{v} was turned into a pincushion by {k}", "{v} caught {k}'s arrow with {his} face", "{v} almost dodged {k}'s arrow", "{v} was perforated by {k}" }
			},
			{
				WeaponKind.Sword,
				new string[6] { "{v} was run through by {k}", "{v} was impaled on {k}'s sword", "{v} was sliced in half by {k}", "{v} was carved up by {k}", "{v} was slashed to ribbons by {k}", "{v} was cut down by {k}" }
			},
			{
				WeaponKind.Axe,
				new string[5] { "{v} was sliced in half by {k}", "{v} was ax-murdered by {k}", "{v} was chopped down by {k}", "{v} was split like firewood by {k}", "{v} was hacked to pieces by {k}" }
			},
			{
				WeaponKind.Club,
				new string[6] { "{v} got {his} head bashed in by {k}", "{v} got {his} skull crushed by {k}", "{v} was pummeled by {k}", "{v} was clubbed like a seal by {k}", "{v} was beaten to a pulp by {k}", "{v} was bludgeoned by {k}" }
			},
			{
				WeaponKind.Spear,
				new string[5] { "{v} was skewered by {k}", "{v} was run through by {k}", "{v} ate {k}'s spear", "{v} was spitted like a boar by {k}", "{v} was impaled by {k}" }
			},
			{
				WeaponKind.Knife,
				new string[4] { "{v} was knifed by {k}", "{v} was shanked by {k}", "{v} was perforated by {k}", "{v} was gutted by {k}" }
			},
			{
				WeaponKind.Fire,
				new string[6] { "{v} was fried by {k}", "{v} was toasted by {k}", "{v} was burnt to a crisp by {k}", "{v} was set on fire by {k}", "{v} was roasted by {k}", "{v} was melted by {k}" }
			},
			{
				WeaponKind.Frost,
				new string[3] { "{v} was frozen solid by {k}", "{v} was turned into an ice cube by {k}", "{v} was put on ice by {k}" }
			},
			{
				WeaponKind.Lightning,
				new string[4] { "{v} was electrocuted by {k}", "{v} was zapped by {k}", "{v} accepted {k}'s discharge", "{v} was fried by {k}'s lightning" }
			},
			{
				WeaponKind.Poison,
				new string[4] { "{v} was slimed by {k}", "{v} was poisoned by {k}", "{v} was vomited on by {k}", "{v} can't exist on {k}'s slime alone" }
			},
			{
				WeaponKind.Spirit,
				new string[2] { "{v} was scragged by {k}", "{v} had {his} soul drained by {k}" }
			},
			{
				WeaponKind.Bite,
				new string[6] { "{v} was mauled by {k}", "{v} was chewed up by {k}", "{v} was eviscerated by {k}", "{v} was torn apart by {k}", "{v} was gored by {k}", "{v} was ripped to shreds by {k}" }
			},
			{
				WeaponKind.Punch,
				new string[6] { "{v} was smashed by {k}", "{v} was flattened by {k}", "{v} was pummeled by {k}", "{v} was stomped into the ground by {k}", "{v} was squashed like a bug by {k}", "{v} was pounded into paste by {k}" }
			},
			{
				WeaponKind.Log,
				new string[4] { "{v} was swatted by {k}'s log", "{v} was clubbed with a tree by {k}", "{v} got {his} head bashed in with a log by {k}", "{v} was batted into next week by {k}" }
			},
			{
				WeaponKind.Rock,
				new string[3] { "{v} was stoned by {k}", "{v} caught {k}'s rock with {his} face", "{v} was brained with a boulder by {k}" }
			},
			{
				WeaponKind.Magic,
				new string[4] { "{v} was melted by {k}'s staff", "{v} saw the pretty lights from {k}'s staff", "{v} was hexed by {k}", "{v} was blasted by {k}" }
			},
			{
				WeaponKind.Pickaxe,
				new string[2] { "{v} was mined by {k}", "{v} was pickaxed by {k}" }
			},
			{
				WeaponKind.Blast,
				new string[6] { "{v} was blown up by {k}", "{v} was caught in {k}'s blast", "{v} stood too close to {k}", "{v} should have backed away from {k}", "{v} was blown to bits by {k}", "{v} didn't see {k} coming apart" }
			}
		};

		private static readonly string[] ByAnything = new string[6] { "{v} was killed by {k}", "{v} was slain by {k}", "{v} got jacked up by {k}", "{v} was wrecked by {k}", "{v} was destroyed by {k}", "{v} got owned by {k}" };

		private static readonly (string prefix, string[] lines)[] Creatures = new(string, string[])[58]
		{
			("Eikthyr", new string[2] { "{v} was electrocuted by {k}", "{v} became one with {k}" }),
			("gd_king", new string[2] { "{v} was smashed by {k}", "{v} became one with {k}" }),
			("Bonemass", new string[2] { "{v} was slimed by {k}", "{v} became one with {k}" }),
			("Dragon", new string[2] { "{v} was frozen solid by {k}", "{v} became one with {k}" }),
			("GoblinKing", new string[2] { "{v} was fried by {k}", "{v} became one with {k}" }),
			("SeekerQueen", new string[2] { "{v} was eviscerated by {k}", "{v} became one with {k}" }),
			("Fader", new string[2] { "{v} was incinerated by {k}", "{v} became one with {k}" }),
			("Boar", new string[3] { "{v} was gored by {k}", "{v} was mauled by {k}", "{v} was tusked by {k}" }),
			("Neck", new string[1] { "{v} was nibbled to death by {k}" }),
			("Greyling", new string[1] { "{v} was scragged by {k}" }),
			("Greydwarf_Shaman", new string[1] { "{v} was vomited on by {k}" }),
			("Greydwarf_Elite", new string[1] { "{v} was mauled by {k}" }),
			("Greydwarf", new string[1] { "{v} was scragged by {k}" }),
			("Troll", new string[1] { "{v} was smashed by {k}" }),
			("Skeleton_Poison", new string[1] { "{v} was slimed by {k}" }),
			("Skeleton", new string[1] { "{v} joins the Skeletons" }),
			("Ghost", new string[1] { "{v} became one with {k}" }),
			("Wraith", new string[1] { "{v} was scragged by {k}" }),
			("BlobTar", new string[1] { "{v} was tarred by {k}" }),
			("BlobLava", new string[1] { "{v} was melted by {k}" }),
			("Blob", new string[1] { "{v} was slimed by {k}" }),
			("Draugr", new string[1] { "{v} joins the Draugr" }),
			("Leech", new string[1] { "{v} was fed to the leeches" }),
			("Surtling", new string[1] { "{v} was fried by {k}" }),
			("Abomination", new string[1] { "{v} was destroyed by {k}" }),
			("Wolf", new string[1] { "{v} was mauled by {k}" }),
			("Fenring_Cultist", new string[1] { "{v} was fried by {k}" }),
			("Fenring", new string[1] { "{v} was mauled by {k}" }),
			("Ulv", new string[1] { "{v} was mauled by {k}" }),
			("Hatchling", new string[1] { "{v} was frozen solid by {k}" }),
			("StoneGolem", new string[1] { "{v} was smashed by {k}" }),
			("Bat", new string[1] { "{v} was swarmed by {k}" }),
			("Deathsquito", new string[2] { "{v} was perforated by {k}", "{v} was turned into a pincushion by {k}" }),
			("Lox", new string[1] { "{v} was trampled by {k}" }),
			("GoblinShaman", new string[1] { "{v} was fried by {k}" }),
			("GoblinBrute", new string[1] { "{v} was destroyed by {k}" }),
			("GoblinArcher", new string[1] { "{v} was gunned down by {k}" }),
			("Goblin", new string[1] { "{v} was slain by {k}" }),
			("BonemawSerpent", new string[1] { "{v} was fed to the Bonemaw" }),
			("Serpent", new string[2] { "{v} was fed to the Serpent", "{v} sleeps with the fishes" }),
			("SeekerBrute", new string[1] { "{v} was smashed by {k}" }),
			("SeekerBrood", new string[1] { "{v} was nibbled to death by {k}" }),
			("Seeker", new string[1] { "{v} was eviscerated by {k}" }),
			("Tick", new string[1] { "{v} was drained by {k}" }),
			("Gjall", new string[1] { "{v} was exploded by {k}" }),
			("DvergerArbalest", new string[1] { "{v} was railed by {k}" }),
			("DvergerMageFire", new string[1] { "{v} was fried by {k}" }),
			("DvergerMageIce", new string[1] { "{v} was frozen solid by {k}" }),
			("Dverger", new string[1] { "{v} was blasted by {k}" }),
			("Charred_Archer", new string[1] { "{v} was perforated by {k}" }),
			("Charred_Mage", new string[1] { "{v} was blasted by {k}" }),
			("Charred_Twitcher", new string[1] { "{v} was scragged by {k}" }),
			("Charred", new string[1] { "{v} was slain by {k}" }),
			("Morgen", new string[1] { "{v} was destroyed by {k}" }),
			("FallenValkyrie", new string[1] { "{v} was slain by {k}" }),
			("Volture", new string[1] { "{v} was fried by {k}" }),
			("Asksvin", new string[1] { "{v} was trampled by {k}" }),
			("Writh", new string[3] { "{v} delivered the final blow to {k} from too close", "{v} didn't back away from {k}", "{v} was blown up by {k}" })
		};

		private static readonly (string prefix, WeaponKind kind)[] KindOverrides = new(string, WeaponKind)[5]
		{
			("Boar", WeaponKind.Bite),
			("Neck", WeaponKind.Bite),
			("Wolf", WeaponKind.Bite),
			("Ulv", WeaponKind.Bite),
			("Bat", WeaponKind.Bite)
		};

		public static Notice Compose(Player victim, HitData hit, out string facts)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Invalid comparison between Unknown and I4
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Invalid comparison between Unknown and I4
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Invalid comparison between Unknown and I4
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Invalid comparison between Unknown and I4
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Invalid comparison between Unknown and I4
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Invalid comparison between Unknown and I4
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Invalid comparison between Unknown and I4
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			Notice notice = new Notice
			{
				Victim = (((Object)(object)victim != (Object)null) ? victim.GetPlayerName() : "")
			};
			if (string.IsNullOrEmpty(notice.Victim))
			{
				notice.Victim = "Someone";
			}
			HitType val = (HitType)((hit != null) ? ((int)hit.m_hitType) : 0);
			ZDOID val2 = hit?.m_attacker ?? ZDOID.None;
			Character val3 = ((hit != null) ? hit.GetAttacker() : null);
			AttackerMemory.Entry entry = AttackerMemory.Lookup(val2);
			string credit = null;
			if ((Object)(object)val3 == (Object)null && entry == null && val2 != ZDOID.None)
			{
				entry = DescribeById(val2);
				if (entry != null)
				{
					credit = "from its ZDO";
				}
			}
			WeaponKind kind;
			if ((Object)(object)val3 == (Object)null && entry == null && hit != null && ((int)val == 7 || (int)val == 5))
			{
				bool poison = (int)val == 7;
				entry = AttackerMemory.LastWhere((AttackerMemory.Entry e) => (!poison) ? e.Fire : e.Poison, 60f);
				if (entry != null)
				{
					val = (HitType)1;
					credit = (poison ? "last to poison us" : "last to burn us");
				}
				kind = (poison ? WeaponKind.Poison : WeaponKind.Fire);
			}
			else if ((Object)(object)val3 == (Object)null && entry == null && hit != null && val2 == ZDOID.None && (int)val == 1 && hit.m_radius > 0f)
			{
				entry = AttackerMemory.LastWhere((AttackerMemory.Entry e) => !e.IsPlayer, 10f);
				if (entry != null)
				{
					credit = "last to hit us, before an ownerless blast";
				}
				kind = WeaponKind.Blast;
			}
			else
			{
				string weapon = entry?.Weapon ?? WeaponName(val3);
				kind = Classify(hit, weapon, val3 is Player || (entry?.IsPlayer ?? false));
			}
			facts = Facts(val, val3, entry, entry?.Weapon ?? WeaponName(val3), kind, hit, credit);
			string text = Api.Take();
			if (text != null)
			{
				notice.Template = Pronouns.Fill(text, Pronouns.For(victim));
				return notice;
			}
			if (val2 != ZDOID.None && (Object)(object)victim != (Object)null && val2 == ((Character)victim).GetZDOID())
			{
				notice.Template = Pick(((int)val == 14) ? Environment[(HitType)14] : SelfInflicted);
			}
			else if (((int)val == 1 || (int)val == 2) && ((Object)(object)val3 != (Object)null || entry != null))
			{
				bool flag = (((Object)(object)val3 != (Object)null) ? (val3 is Player) : entry.IsPlayer);
				string prefab = (((Object)(object)val3 != (Object)null) ? PrefabName(val3) : entry.Prefab);
				notice.Killer = (((Object)(object)val3 != (Object)null) ? Describe(val3) : entry.Description);
				notice.KillerId = val2;
				notice.KillerIsPlayer = flag;
				notice.Template = Pick(flag ? PlayerLines(kind) : CreatureLines(prefab, kind));
			}
			else
			{
				notice.Template = Pick(EnvironmentLines(val));
			}
			notice.Template = Pronouns.Fill(notice.Template, Pronouns.For(victim));
			return notice;
		}

		internal static string[] EnvironmentLines(HitType type)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (!Environment.TryGetValue(type, out var value))
			{
				return Environment[(HitType)0];
			}
			return value;
		}

		internal static string[] PlayerLines(WeaponKind kind)
		{
			if (!ByKind.TryGetValue(kind, out var value))
			{
				return ByAnything;
			}
			return value;
		}

		internal static string[] CreatureLines(string prefab, WeaponKind kind)
		{
			prefab = prefab ?? "";
			(string, WeaponKind)[] kindOverrides = KindOverrides;
			for (int i = 0; i < kindOverrides.Length; i++)
			{
				var (value, weaponKind) = kindOverrides[i];
				if (prefab.StartsWith(value, StringComparison.OrdinalIgnoreCase))
				{
					kind = weaponKind;
					break;
				}
			}
			List<string> list = new List<string>();
			(string, string[])[] creatures = Creatures;
			for (int i = 0; i < creatures.Length; i++)
			{
				var (value2, collection) = creatures[i];
				if (prefab.StartsWith(value2, StringComparison.OrdinalIgnoreCase))
				{
					list.AddRange(collection);
					break;
				}
			}
			list.AddRange(ByKind.TryGetValue(kind, out var value3) ? value3 : ByAnything);
			return list.ToArray();
		}

		internal static string WeaponName(Character attacker)
		{
			try
			{
				Character obj = ((attacker is Humanoid) ? attacker : null);
				ItemData val = ((obj != null) ? ((Humanoid)obj).GetCurrentWeapon() : null);
				if (val == null)
				{
					return "";
				}
				if ((Object)(object)val.m_dropPrefab != (Object)null)
				{
					return ((Object)val.m_dropPrefab).name ?? "";
				}
				return val.m_shared?.m_name ?? "";
			}
			catch
			{
				return "";
			}
		}

		internal static WeaponKind Classify(HitData hit, string weapon, bool byPlayer)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected I4, but got Unknown
			if (byPlayer && hit != null)
			{
				SkillType skill = hit.m_skill;
				switch (skill - 1)
				{
				case 0:
					return WeaponKind.Sword;
				case 6:
					return WeaponKind.Axe;
				case 2:
					return WeaponKind.Club;
				case 3:
				case 4:
					return WeaponKind.Spear;
				case 1:
					return WeaponKind.Knife;
				case 7:
				case 13:
					return WeaponKind.Bow;
				case 10:
					return WeaponKind.Punch;
				case 11:
					return WeaponKind.Pickaxe;
				case 9:
					return WeaponKind.Magic;
				case 8:
				{
					WeaponKind weaponKind = ByDamage(hit, ranged: true);
					if (weaponKind != WeaponKind.Fire && weaponKind != WeaponKind.Frost && weaponKind != WeaponKind.Lightning)
					{
						return WeaponKind.Magic;
					}
					return weaponKind;
				}
				}
			}
			string s = (weapon ?? "").ToLowerInvariant();
			if (Has(s, "bow", "arbalest", "crossbow", "arrow", "bolt"))
			{
				return WeaponKind.Bow;
			}
			if (Has(s, "sword", "dyrnwyn"))
			{
				return WeaponKind.Sword;
			}
			if (Has(s, "axe"))
			{
				return WeaponKind.Axe;
			}
			if (Has(s, "mace", "club", "hammer", "sledge"))
			{
				return WeaponKind.Club;
			}
			if (Has(s, "spear", "polearm", "atgeir", "pike"))
			{
				return WeaponKind.Spear;
			}
			if (Has(s, "knife", "dagger"))
			{
				return WeaponKind.Knife;
			}
			if (Has(s, "log"))
			{
				return WeaponKind.Log;
			}
			if (Has(s, "torch", "fire", "flame", "lava", "cinder", "meteor"))
			{
				return WeaponKind.Fire;
			}
			if (Has(s, "ice", "frost", "cold"))
			{
				return WeaponKind.Frost;
			}
			if (Has(s, "throw", "rock", "stone", "boulder"))
			{
				return WeaponKind.Rock;
			}
			if (Has(s, "poison", "spit", "vomit", "acid"))
			{
				return WeaponKind.Poison;
			}
			if (Has(s, "staff"))
			{
				return WeaponKind.Magic;
			}
			return ByDamage(hit, hit?.m_ranged ?? false);
		}

		private static bool Has(string s, params string[] keys)
		{
			foreach (string value in keys)
			{
				if (s.Contains(value))
				{
					return true;
				}
			}
			return false;
		}

		private static WeaponKind ByDamage(HitData hit, bool ranged)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (hit == null)
			{
				return WeaponKind.Unknown;
			}
			DamageTypes damage = hit.m_damage;
			WeaponKind best = WeaponKind.Unknown;
			float most = 0f;
			Consider(damage.m_fire, WeaponKind.Fire);
			Consider(damage.m_frost, WeaponKind.Frost);
			Consider(damage.m_lightning, WeaponKind.Lightning);
			Consider(damage.m_poison, WeaponKind.Poison);
			Consider(damage.m_spirit, WeaponKind.Spirit);
			Consider(damage.m_pierce, ranged ? WeaponKind.Bow : WeaponKind.Bite);
			Consider(damage.m_slash, WeaponKind.Bite);
			Consider(damage.m_blunt, (hit.m_radius > 0f) ? WeaponKind.Blast : (ranged ? WeaponKind.Rock : WeaponKind.Punch));
			return best;
			void Consider(float amount, WeaponKind k)
			{
				if (amount > most)
				{
					most = amount;
					best = k;
				}
			}
		}

		private static string Facts(HitType type, Character killer, AttackerMemory.Entry remembered, string weapon, WeaponKind kind, HitData hit, string credit)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder sb = new StringBuilder("Killing hit: ");
			sb.Append(hit?.m_hitType ?? type);
			string value = (((Object)(object)killer != (Object)null) ? PrefabName(killer) : remembered?.Prefab);
			if (!string.IsNullOrEmpty(value))
			{
				sb.Append(" by ").Append(value).Append(((Object)(object)killer == (Object)null) ? (" (" + (credit ?? "from memory") + ")") : "");
			}
			else if (hit != null && hit.m_attacker != ZDOID.None)
			{
				sb.Append(" by an attacker nothing is known about");
			}
			if (!string.IsNullOrEmpty(weapon))
			{
				sb.Append(" with ").Append(weapon);
			}
			sb.Append(" -> ").Append(kind);
			if (hit != null && hit.m_radius > 0f)
			{
				sb.Append("; area ").Append(hit.m_radius.ToString("0.#")).Append(" m");
			}
			if (hit != null)
			{
				sb.Append("; skill ").Append(hit.m_skill).Append(hit.m_ranged ? ", ranged" : "");
				DamageTypes damage = hit.m_damage;
				sb.Append("; dmg");
				Add("blunt", damage.m_blunt);
				Add("slash", damage.m_slash);
				Add("pierce", damage.m_pierce);
				Add("chop", damage.m_chop);
				Add("pickaxe", damage.m_pickaxe);
				Add("fire", damage.m_fire);
				Add("frost", damage.m_frost);
				Add("lightning", damage.m_lightning);
				Add("poison", damage.m_poison);
				Add("spirit", damage.m_spirit);
				Add("plain", damage.m_damage);
			}
			return sb.ToString();
			void Add(string name, float v)
			{
				if (v > 0f)
				{
					sb.Append(' ').Append(name).Append(' ')
						.Append(Mathf.RoundToInt(v));
				}
			}
		}

		internal static string Describe(Character killer)
		{
			Player val = (Player)(object)((killer is Player) ? killer : null);
			if (val != null)
			{
				string playerName = val.GetPlayerName();
				if (!string.IsNullOrEmpty(playerName))
				{
					return playerName;
				}
				return "someone";
			}
			string text = Localization.instance.Localize(killer.m_name ?? "").Trim();
			if (text.Length == 0)
			{
				text = PrefabName(killer);
			}
			if (killer.IsTamed())
			{
				string text2 = "";
				if (TheObituariesMod.TameNames.Value)
				{
					ZNetView component = ((Component)killer).GetComponent<ZNetView>();
					if ((Object)(object)component != (Object)null && component.IsValid())
					{
						text2 = (component.GetZDO().GetString(ZDOVars.s_tamedName, "") ?? "").Trim();
					}
				}
				if (text2.Length <= 0)
				{
					return "a tame " + text;
				}
				return text2 + " the " + text;
			}
			if (killer.IsBoss())
			{
				return text;
			}
			int level = killer.GetLevel();
			if (level > 1 && TheObituariesMod.LevelStars.Value)
			{
				text = level - 1 + "-star " + text;
			}
			return Article(text) + " " + text;
		}

		internal static AttackerMemory.Entry DescribeById(ZDOID id)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (id == ZDOID.None || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null)
				{
					return null;
				}
				ZDO zDO = ZDOMan.instance.GetZDO(id);
				if (zDO == null)
				{
					return null;
				}
				GameObject prefab = ZNetScene.instance.GetPrefab(zDO.GetPrefab());
				if ((Object)(object)prefab == (Object)null)
				{
					return null;
				}
				AttackerMemory.Entry entry = new AttackerMemory.Entry
				{
					Prefab = (((Object)prefab).name ?? ""),
					Weapon = ""
				};
				if ((Object)(object)prefab.GetComponent<Player>() != (Object)null)
				{
					string text = zDO.GetString(ZDOVars.s_playerName, "");
					entry.Description = (string.IsNullOrEmpty(text) ? "someone" : text);
					entry.IsPlayer = true;
					return entry;
				}
				Character component = prefab.GetComponent<Character>();
				string text2 = (((Object)(object)component != (Object)null) ? Localization.instance.Localize(component.m_name ?? "").Trim() : "");
				if (text2.Length == 0)
				{
					text2 = entry.Prefab;
				}
				if (zDO.GetBool(ZDOVars.s_tamed, false))
				{
					string text3 = (TheObituariesMod.TameNames.Value ? (zDO.GetString(ZDOVars.s_tamedName, "") ?? "").Trim() : "");
					entry.Description = ((text3.Length > 0) ? (text3 + " the " + text2) : ("a tame " + text2));
					return entry;
				}
				if ((Object)(object)component != (Object)null && component.m_boss)
				{
					entry.Description = text2;
					return entry;
				}
				int num = zDO.GetInt(ZDOVars.s_level, 1);
				if (num > 1 && TheObituariesMod.LevelStars.Value)
				{
					text2 = num - 1 + "-star " + text2;
				}
				entry.Description = Article(text2) + " " + text2;
				return entry;
			}
			catch
			{
				return null;
			}
		}

		internal static string Article(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return "a";
			}
			if ("aeiouAEIOU".IndexOf(name[0]) < 0)
			{
				return "a";
			}
			return "an";
		}

		internal static string PrefabName(Character c)
		{
			if ((Object)(object)c == (Object)null)
			{
				return "";
			}
			string text = ((Object)((Component)c).gameObject).name ?? "";
			int num = text.IndexOf("(Clone)", StringComparison.Ordinal);
			if (num < 0)
			{
				return text;
			}
			return text.Substring(0, num);
		}

		internal static string Pick(string[] lines)
		{
			if (lines == null || lines.Length == 0)
			{
				return "{v} died";
			}
			return lines[Rng.Next(lines.Length)];
		}

		internal static IEnumerable<string> KnownCreatures()
		{
			(string prefix, string[] lines)[] creatures = Creatures;
			for (int i = 0; i < creatures.Length; i++)
			{
				yield return creatures[i].prefix;
			}
		}

		internal static Notice Sample(string cause, string weaponKind, Player victim)
		{
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			Notice notice = new Notice
			{
				Victim = (((Object)(object)victim != (Object)null) ? victim.GetPlayerName() : "You")
			};
			if (string.IsNullOrEmpty(notice.Victim))
			{
				notice.Victim = "You";
			}
			WeaponKind result;
			if (string.IsNullOrEmpty(weaponKind))
			{
				WeaponKind[] array = (WeaponKind[])Enum.GetValues(typeof(WeaponKind));
				result = array[Rng.Next(array.Length)];
			}
			else if (!Enum.TryParse<WeaponKind>(weaponKind, ignoreCase: true, out result))
			{
				return null;
			}
			HitType result2;
			if (cause.Equals("pvp", StringComparison.OrdinalIgnoreCase))
			{
				notice.Killer = "Ragnar";
				notice.KillerIsPlayer = true;
				notice.Template = Pick(PlayerLines(result));
			}
			else if (cause.Equals("self", StringComparison.OrdinalIgnoreCase) && Rng.Next(2) == 0)
			{
				notice.Template = Pick(SelfInflicted);
			}
			else if (Enum.TryParse<HitType>(cause, ignoreCase: true, out result2))
			{
				notice.Template = Pick(EnvironmentLines(result2));
			}
			else
			{
				string text = null;
				(string, string[])[] creatures = Creatures;
				for (int i = 0; i < creatures.Length; i++)
				{
					string item = creatures[i].Item1;
					if (item.Equals(cause, StringComparison.OrdinalIgnoreCase))
					{
						text = item;
						break;
					}
				}
				if (text == null)
				{
					return null;
				}
				string text2 = text.Replace("_", " ");
				notice.Killer = Article(text2) + " " + text2;
				notice.Template = Pick(CreatureLines(text, result));
			}
			notice.Template = Pronouns.Fill(notice.Template, Pronouns.For(victim));
			return notice;
		}
	}
	[HarmonyPatch(typeof(Game), "Start")]
	internal static class Game_Start_Patch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			AttackerMemory.Clear();
			DeathNetwork.Register();
		}
	}
	[HarmonyPatch(typeof(Player), "OnDeath")]
	internal static class Player_OnDeath_Patch
	{
		private static readonly FieldRef<Character, HitData> LastHit = AccessTools.FieldRefAccess<Character, HitData>("m_lastHit");

		[HarmonyPostfix]
		private static void Postfix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !TheObituariesMod.ModEnabled.Value)
			{
				return;
			}
			try
			{
				HitData hit = LastHit.Invoke((Character)(object)__instance);
				string facts;
				Notice notice = Obituary.Compose(__instance, hit, out facts);
				if (TheObituariesMod.LogKillingHit.Value)
				{
					TheObituariesMod.Log.LogInfo((object)facts);
				}
				DeathNetwork.Send(notice);
			}
			catch (Exception ex)
			{
				TheObituariesMod.Log.LogWarning((object)("Could not announce the death: " + ex));
			}
		}
	}
	internal static class Pronouns
	{
		internal enum Set
		{
			He,
			She,
			They
		}

		internal static Set For(Player victim)
		{
			switch (TheObituariesMod.PronounChoice.Value)
			{
			case TheObituariesMod.PronounMode.He:
				return Set.He;
			case TheObituariesMod.PronounMode.She:
				return Set.She;
			case TheObituariesMod.PronounMode.They:
				return Set.They;
			default:
				if ((Object)(object)victim == (Object)null)
				{
					return Set.They;
				}
				if (victim.GetPlayerModel() != 1)
				{
					return Set.He;
				}
				return Set.She;
			}
		}

		internal static string Fill(string template, Set set)
		{
			if (string.IsNullOrEmpty(template))
			{
				return template;
			}
			string newValue;
			string newValue2;
			string newValue3;
			string newValue4;
			switch (set)
			{
			case Set.He:
				newValue = "he";
				newValue2 = "him";
				newValue3 = "his";
				newValue4 = "himself";
				break;
			case Set.She:
				newValue = "she";
				newValue2 = "her";
				newValue3 = "her";
				newValue4 = "herself";
				break;
			default:
				newValue = "they";
				newValue2 = "them";
				newValue3 = "their";
				newValue4 = "themself";
				break;
			}
			return template.Replace("{himself}", newValue4).Replace("{his}", newValue3).Replace("{him}", newValue2)
				.Replace("{he}", newValue);
		}
	}
	[BepInPlugin("DeathMonger.TheObituaries", "The Obituaries", "0.3.2")]
	[BepInProcess("valheim.exe")]
	public class TheObituariesMod : BaseUnityPlugin
	{
		internal enum ScreenSpot
		{
			Off,
			TopLeft,
			Center
		}

		internal enum PronounMode
		{
			Auto,
			He,
			She,
			They
		}

		public const string ModGuid = "DeathMonger.TheObituaries";

		public const string ModName = "The Obituaries";

		public const string ModVersion = "0.3.2";

		internal static ConfigEntry<bool> ModEnabled;

		internal static ConfigEntry<bool> LogObituaries;

		internal static ConfigEntry<bool> LogKillingHit;

		internal static ConfigEntry<bool> ShowInChat;

		internal static ConfigEntry<float> ChatSeconds;

		internal static ConfigEntry<int> TextSize;

		internal static ConfigEntry<ScreenSpot> OnScreen;

		internal static ConfigEntry<float> CenterSeconds;

		internal static ConfigEntry<float> CenterSecondsOthers;

		internal static ConfigEntry<bool> YouFragged;

		internal static ConfigEntry<PronounMode> PronounChoice;

		internal static ConfigEntry<bool> LevelStars;

		internal static ConfigEntry<bool> TameNames;

		internal static ConfigEntry<string> LineColor;

		internal static ConfigEntry<string> VictimColor;

		internal static ConfigEntry<string> KillerColor;

		private Harmony _harmony;

		internal static ManualLogSource Log { get; private set; }

		internal static TheObituariesMod Instance { get; private set; }

		private void Awake()
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Expected O, but got Unknown
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Expected O, but got Unknown
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Expected O, but got Unknown
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Mod Enabled", true, "Master switch. Off means your deaths are not announced and other players' obituaries are not shown. Takes effect immediately.");
			LogObituaries = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Log Obituaries", true, "Also write every obituary you see to the BepInEx log, plain text.");
			LogKillingHit = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Log Killing Hit", true, "When you die, write what the game said about the killing hit to the BepInEx log: the creature, the weapon it held, the damage types. This is how a creature or weapon that reads wrong gets its own line in a later version; send the line along.");
			ShowInChat = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "Show In Chat", true, "Add the obituary to the chat window, the way Quake printed it in the console notify area. The window pops up for it like it does for a chat message.");
			ChatSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Chat Seconds", 30f, new ConfigDescription("How long the chat window stays up after an obituary. The game's own chat messages keep it up for 10 seconds; anything at or below that gives the game's stay.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), Array.Empty<object>()));
			TextSize = ((BaseUnityPlugin)this).Config.Bind<int>("Display", "Text Size", 115, new ConfigDescription("Size of the obituary in the chat window, as a percentage of the chat's normal text.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(50, 200), Array.Empty<object>()));
			OnScreen = ((BaseUnityPlugin)this).Config.Bind<ScreenSpot>("Display", "On Screen", ScreenSpot.Center, "Also show the obituary as an on-screen message: Center (big, in the middle of the screen), TopLeft (the small messages next to the minimap), or Off.");
			CenterSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Center Seconds", 15f, new ConfigDescription("How long a center message stays on screen. The game's own center messages fade out over 4 seconds; this holds it up and fades it out at the end. For your own death: you lie there 10 seconds before the respawn starts, and a loading screen covers the rest.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(4f, 60f), Array.Empty<object>()));
			CenterSecondsOthers = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Center Seconds Others", 5f, new ConfigDescription("How long another player's obituary stays in the center of your screen. Shorter than your own: you are lying there anyway, they are busy. Also the stay of 'You fragged'.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(4f, 60f), Array.Empty<object>()));
			YouFragged = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "You Fragged", true, "When you kill another player, show Quake III's 'You fragged <name>' in the center of your screen.");
			PronounChoice = ((BaseUnityPlugin)this).Config.Bind<PronounMode>("Wording", "Pronouns", PronounMode.Auto, "The pronouns used for you in your own obituaries ('got his head bashed in', 'fell to her death'). Auto picks from your character's body type; He, She or They override it.");
			LevelStars = ((BaseUnityPlugin)this).Config.Bind<bool>("Wording", "Level Stars", true, "Name a starred creature by its stars: 'a 2-star Troll' instead of 'a Troll'.");
			TameNames = ((BaseUnityPlugin)this).Config.Bind<bool>("Wording", "Tame Names", true, "Name a tamed creature by its pet name: 'Fluffy the Wolf' instead of 'a Wolf'.");
			LineColor = ((BaseUnityPlugin)this).Config.Bind<string>("Colors", "Line Color", "#ff8c1a", "Color of the whole obituary line, as an HTML color (#rrggbb or a name such as orange or yellow). Empty leaves it the chat's normal white.");
			VictimColor = ((BaseUnityPlugin)this).Config.Bind<string>("Colors", "Victim Color", "#ffe66d", "Color of the dead player's name, as an HTML color. Empty for the line color.");
			KillerColor = ((BaseUnityPlugin)this).Config.Bind<string>("Colors", "Killer Color", "#ff5e5e", "Color of the killer's name, as an HTML color. Empty for the line color.");
			MigrateOldDefaults();
			_harmony = new Harmony("DeathMonger.TheObituaries");
			_harmony.PatchAll();
			Commands.Register();
			Log.LogInfo((object)"The Obituaries 0.3.2 loaded.");
		}

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

		private void MigrateOldDefaults()
		{
			ConfigEntry<int> val = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Config Version", 0, "Which version's defaults this file was last brought up to. Internal; leave it alone.");
			if (val.Value >= 2)
			{
				return;
			}
			if (val.Value < 1)
			{
				if (OnScreen.Value == ScreenSpot.TopLeft)
				{
					OnScreen.Value = ScreenSpot.Center;
				}
				if (VictimColor.Value == "#ffa640")
				{
					VictimColor.Value = "#ffe66d";
				}
			}
			if (CenterSeconds.Value == 8f || CenterSeconds.Value == 10f)
			{
				CenterSeconds.Value = 15f;
			}
			val.Value = 2;
		}

		internal static string Colored(string text, ConfigEntry<string> color)
		{
			if (string.IsNullOrEmpty(text))
			{
				return text ?? "";
			}
			string text2 = color?.Value?.Trim() ?? "";
			Color val = default(Color);
			if (text2.Length == 0 || !ColorUtility.TryParseHtmlString(text2, ref val))
			{
				return text;
			}
			return "<color=" + text2 + ">" + text + "</color>";
		}

		internal static string Bold(string text)
		{
			if (!string.IsNullOrEmpty(text))
			{
				return "<b>" + text + "</b>";
			}
			return text ?? "";
		}
	}
}