Decompiled source of GK2 Thoughtful Week v0.5.3

GK2ThoughtfulWeek.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GK2.Framework;
using HarmonyLib;
using LazyBearTechnology;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Rewired;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
internal sealed class ConfigurationManagerAttributes
{
	public delegate void CustomHotkeyDrawerFunc(ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput);

	public bool? ShowRangeAsPercent;

	public Action<ConfigEntryBase> CustomDrawer;

	public CustomHotkeyDrawerFunc CustomHotkeyDrawer;

	public bool? Browsable;

	public string Category;

	public object DefaultValue;

	public bool? HideDefaultButton;

	public bool? HideSettingName;

	public string Description;

	public string DispName;

	public int? Order;

	public bool? ReadOnly;

	public bool? IsAdvanced;

	public Func<object, string> ObjToStr;

	public Func<string, object> StrToObj;
}
namespace GK2DayPlanner
{
	internal static class Sec
	{
		public const string Morning = "1 Morning";

		public const string Evening = "2 Evening";

		public const string Week = "3 Week window";

		public const string Hud = "4 HUD";

		public const string Gamepad = "Gamepad";

		public const string Language = "Language";

		public const string Internal = "Internal";
	}
	internal static class CfgMigrate
	{
		public static void Run(ConfigFile cfg)
		{
			string[] array = new string[6] { "Enabled", "OnLoad", "OpenPanel", "ShowEvents", "ShowOrders", "OnlyWhenSomethingToDo" };
			foreach (string text in array)
			{
				Carry(cfg, "Morning", text, "1 Morning", text);
			}
			Carry(cfg, "Hotkeys", "ThoughtKey", "1 Morning", "ThoughtKey");
			array = new string[7] { "Enabled", "Sermon", "Resurrection", "Orders", "PrMachine", "Battle", "Tears" };
			foreach (string text2 in array)
			{
				Carry(cfg, "Evening", text2, "2 Evening", text2);
			}
			Carry(cfg, "Hotkeys", "ToggleWindow", "3 Week window", "ToggleWindow");
			Carry(cfg, "Window", "Scale", "3 Week window", "Scale");
			Carry(cfg, "Window", "PauseGame", "3 Week window", "PauseGame");
			Carry(cfg, "General", "Language", "Language", "Language");
			Hours(cfg, "Morning", "TimeOfDay", "1 Morning", "Hour");
			Hours(cfg, "Evening", "TimeOfDay", "2 Evening", "Hour");
		}

		private static void Hours(ConfigFile cfg, string oldSection, string oldKey, string newSection, string newKey)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			try
			{
				Dictionary<ConfigDefinition, string> dictionary = Orphans(cfg);
				ConfigDefinition key = new ConfigDefinition(oldSection, oldKey);
				ConfigDefinition key2 = new ConfigDefinition(newSection, newKey);
				if (dictionary != null && dictionary.TryGetValue(key, out var value))
				{
					if (!dictionary.ContainsKey(key2) && float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
					{
						dictionary[key2] = (result * 24f).ToString("0.##", CultureInfo.InvariantCulture);
					}
					dictionary.Remove(key);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Settings: could not carry " + oldSection + "." + oldKey + " over: " + ex.Message));
			}
		}

		private static void Carry(ConfigFile cfg, string oldSection, string oldKey, string newSection, string newKey)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			try
			{
				ConfigDefinition key = new ConfigDefinition(oldSection, oldKey);
				ConfigDefinition key2 = new ConfigDefinition(newSection, newKey);
				Dictionary<ConfigDefinition, string> dictionary = Orphans(cfg);
				if (dictionary != null && dictionary.TryGetValue(key, out var value))
				{
					if (!dictionary.ContainsKey(key2))
					{
						dictionary[key2] = value;
					}
					dictionary.Remove(key);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Settings: could not carry " + oldSection + "." + oldKey + " over: " + ex.Message));
			}
		}

		private static Dictionary<ConfigDefinition, string> Orphans(ConfigFile cfg)
		{
			PropertyInfo property = typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (!(property != null))
			{
				return null;
			}
			return property.GetValue(cfg, null) as Dictionary<ConfigDefinition, string>;
		}

		private static void Drop(ConfigFile cfg, string section, string key)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			try
			{
				Orphans(cfg)?.Remove(new ConfigDefinition(section, key));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Settings: could not drop " + section + "." + key + ": " + ex.Message));
			}
		}
	}
	internal static class Clock
	{
		public const float DayStart = 0.25f;

		public const float NightStart = 0.75f;

		private static readonly FieldInfo EngineCache = AccessTools.Field(typeof(EnvironmentData), "envEngineCache");

		private static float _lastT = -1f;

		private static float _lastReal;

		private static float _rate = -1f;

		private static float _sinceMove;

		private static Sprite _sun;

		private static Sprite _moon;

		private static readonly string[] SunPixels = new string[9] { "....#....", ".#.....#.", "...###...", "..#####..", "#.#####.#", "..#####..", "...###...", ".#.....#.", "....#...." };

		private static readonly string[] MoonPixels = new string[9] { "...###...", "..###....", ".###.....", ".###.....", ".###.....", ".###.....", ".####....", "..#####..", "...###..." };

		public static bool TryRead(out float t, out float realDayMinutes)
		{
			t = 0f;
			realDayMinutes = 0f;
			try
			{
				EnvironmentData val = (((Object)(object)MainGame.Instance != (Object)null) ? MainGame.Instance.GameSave : null)?.environmentData;
				if (val == null)
				{
					return false;
				}
				t = Mathf.Repeat(val.TimeOfDay, 1f);
				EnvironmentEngine val2 = (EnvironmentEngine)((EngineCache != null) ? /*isinst with value type is only supported in some contexts*/: null);
				if ((Object)(object)val2 != (Object)null)
				{
					realDayMinutes = Traverse.Create((object)val2).Field("gameplayDayInMinutes").GetValue<float>();
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		public static void Sample()
		{
			if (!TryRead(out var t, out var _))
			{
				_lastT = -1f;
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (_lastT < 0f)
			{
				_lastT = t;
				_lastReal = unscaledTime;
				return;
			}
			float num = unscaledTime - _lastReal;
			if (num < 2f)
			{
				return;
			}
			float num2 = t - _lastT;
			if (num2 < -0.5f)
			{
				num2 += 1f;
			}
			if (num2 < 0f || num2 > 0.2f)
			{
				_lastT = t;
				_lastReal = unscaledTime;
				_rate = -1f;
				return;
			}
			float num3 = num2 / num;
			if (num3 <= 0f)
			{
				_sinceMove += num;
			}
			else
			{
				_sinceMove = 0f;
				_rate = ((_rate < 0f) ? num3 : Mathf.Lerp(_rate, num3, 0.5f));
			}
			_lastT = t;
			_lastReal = unscaledTime;
		}

		private static float RealSecondsPerDay(float dayMin)
		{
			if (_sinceMove > 0f)
			{
				return -1f;
			}
			if (_rate > 0f)
			{
				return 1f / _rate;
			}
			if (dayMin > 0.01f)
			{
				return dayMin * 60f / Mathf.Max(Time.timeScale, 0.01f);
			}
			return -1f;
		}

		public static bool IsDay(float t)
		{
			if (t >= 0.25f)
			{
				return t < 0.75f;
			}
			return false;
		}

		public static string Hhmm(float fraction)
		{
			int num = Mathf.FloorToInt(Mathf.Repeat(fraction, 1f) * 1440f);
			return (num / 60).ToString("00") + ":" + (num % 60).ToString("00");
		}

		public static bool Read(out string time, out bool day, out string left)
		{
			time = "";
			left = "";
			day = true;
			if (!TryRead(out var t, out var realDayMinutes))
			{
				return false;
			}
			day = IsDay(t);
			float num = Mathf.Repeat((day ? 0.75f : 0.25f) - t, 1f);
			time = Hhmm(t);
			left = Hhmm(num);
			float num2 = RealSecondsPerDay(realDayMinutes);
			if (num2 > 0f)
			{
				float num3 = num * num2 / 60f;
				left = left + " · " + ((num3 < 1f) ? L10n.T("RealLessMin") : L10n.F("RealMin", Mathf.RoundToInt(num3)));
			}
			return true;
		}

		public static Sprite NextIcon(bool day)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (day)
			{
				return _moon ?? (_moon = Draw(MoonPixels, new Color32((byte)216, (byte)224, (byte)244, byte.MaxValue)));
			}
			return _sun ?? (_sun = Draw(SunPixels, new Color32((byte)245, (byte)197, (byte)66, byte.MaxValue)));
		}

		private static Sprite Draw(string[] rows, Color32 ink)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				int num = rows.Length;
				int length = rows[0].Length;
				Texture2D val = new Texture2D(length, num, (TextureFormat)4, false)
				{
					filterMode = (FilterMode)0,
					wrapMode = (TextureWrapMode)1
				};
				Color32 val2 = default(Color32);
				((Color32)(ref val2))..ctor((byte)0, (byte)0, (byte)0, (byte)0);
				for (int i = 0; i < num; i++)
				{
					for (int j = 0; j < length; j++)
					{
						val.SetPixel(j, num - 1 - i, (rows[i][j] == '#') ? Color32.op_Implicit(ink) : Color32.op_Implicit(val2));
					}
				}
				val.Apply();
				return Sprite.Create(val, new Rect(0f, 0f, (float)length, (float)num), new Vector2(0.5f, 0.5f), 100f);
			}
			catch
			{
				return null;
			}
		}
	}
	internal static class Cm
	{
		public static ConfigDescription D(string description, string name, int order, bool advanced = false, AcceptableValueBase range = null, bool browsable = true)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes
			{
				DispName = name,
				Order = 1000 - order
			};
			if (advanced)
			{
				configurationManagerAttributes.IsAdvanced = true;
			}
			if (!browsable)
			{
				configurationManagerAttributes.Browsable = false;
			}
			return new ConfigDescription(description, range, new object[1] { configurationManagerAttributes });
		}
	}
	internal static class Diag
	{
		private const string Tag = "[Diag] ";

		private const float RecheckAfter = 10f;

		private static readonly string[] Others = new string[16]
		{
			"gk2.ZombieChores", "gk2.StockLimits", "gk2.Almanac", "gk2.BuildTools", "gk2.StorageAccess", "gk2.ClerkDesk", "gk2.ReporterDesk", "gk2.ZombieCare", "gk2.UnofficialPatch", "gk2.SmartBags",
			"gk2.SealedDepths", "gk2.NoSleepNoTomorrow", "gk2.CarouselVeterans", "gk2.SortedChests", "gk2.KeyboardComfort", "gk2.BattleComfort"
		};

		internal static ConfigEntry<bool> Setting;

		private static string[] _ownKeys = new string[0];

		private static string _wheelMod;

		private static string _wheelId;

		private static readonly object Gate = new object();

		private static string _last;

		private static readonly HashSet<string> Seen = new HashSet<string>();

		private static readonly Dictionary<string, string> Values = new Dictionary<string, string>();

		private static bool _started;

		private static bool _wasIn;

		private static float _due;

		internal static bool On
		{
			get
			{
				try
				{
					return Setting != null && Setting.Value;
				}
				catch
				{
					return false;
				}
			}
		}

		internal static void Bind(ConfigFile cfg)
		{
			Setting = cfg.Bind<bool>("Debug", "Diagnostics", false, Cm.D("Writes \"[Diag]\" lines to the log: which of the other mods are loaded, which shared records exist, and the decisions this mod takes next to them. Never every frame. Meant for a compatibility test.", "Diagnostic log", 90, advanced: true));
		}

		internal static void Own(string[] recordKeys, string wheelMod, string wheelId)
		{
			_ownKeys = recordKeys ?? new string[0];
			_wheelMod = wheelMod;
			_wheelId = wheelId;
		}

		internal static void Log(string text)
		{
			if (!On || text == null)
			{
				return;
			}
			string text2 = "[Diag] " + text;
			lock (Gate)
			{
				if (text2 == _last)
				{
					return;
				}
				_last = text2;
			}
			try
			{
				Plugin.Log.LogInfo((object)text2);
			}
			catch
			{
			}
		}

		internal static void Once(string key, string text)
		{
			if (!On)
			{
				return;
			}
			lock (Gate)
			{
				if (!Seen.Add(key))
				{
					return;
				}
			}
			Log(text);
		}

		internal static void Changed(string key, string value, string text)
		{
			if (!On)
			{
				return;
			}
			lock (Gate)
			{
				if (Values.TryGetValue(key, out var value2) && value2 == value)
				{
					return;
				}
				Values[key] = value;
			}
			Log(text);
		}

		internal static bool Reset(string key)
		{
			if (!On)
			{
				return false;
			}
			lock (Gate)
			{
				bool result = Values.Remove(key);
				Seen.Remove(key);
				return result;
			}
		}

		internal static void Forget(string prefix)
		{
			lock (Gate)
			{
				List<string> list = new List<string>();
				foreach (string key in Values.Keys)
				{
					if (key.StartsWith(prefix, StringComparison.Ordinal))
					{
						list.Add(key);
					}
				}
				foreach (string item in list)
				{
					Values.Remove(item);
				}
				Seen.RemoveWhere((string k) => k.StartsWith(prefix, StringComparison.Ordinal));
			}
		}

		internal static string R(Rect r)
		{
			return "x " + Math.Round(((Rect)(ref r)).x, 1) + " y " + Math.Round(((Rect)(ref r)).y, 1) + " w " + Math.Round(((Rect)(ref r)).width, 1) + " h " + Math.Round(((Rect)(ref r)).height, 1);
		}

		internal static string VersionOf(string guid)
		{
			try
			{
				string version;
				return Find(Chainloader.PluginInfos, guid, out version) ? version : null;
			}
			catch
			{
				return null;
			}
		}

		internal static string Presence(string label, string guid)
		{
			string text = VersionOf(guid);
			if (text != null)
			{
				return label + " " + text + " is loaded";
			}
			return label + " is not loaded";
		}

		internal static void Start()
		{
			if (!_started)
			{
				_started = true;
				if (On)
				{
					Plugins();
					Records("at start");
				}
			}
		}

		internal static void Tick()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			if (!On)
			{
				return;
			}
			try
			{
				MainGame instance = MainGame.Instance;
				bool flag = (Object)(object)instance != (Object)null && (int)instance.gameState == 1;
				if (flag && !_wasIn)
				{
					_wasIn = true;
					_due = Time.realtimeSinceStartup + 10f;
				}
				else if (!flag && _wasIn)
				{
					_wasIn = false;
					_due = 0f;
				}
				if (_due > 0f && Time.realtimeSinceStartup >= _due)
				{
					_due = 0f;
					Records("10 s after the game loaded");
				}
			}
			catch
			{
			}
		}

		private static void Plugins()
		{
			try
			{
				Dictionary<string, PluginInfo> pluginInfos = Chainloader.PluginInfos;
				List<string> list = new List<string>();
				List<string> list2 = new List<string>();
				HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
				string[] others = Others;
				foreach (string text in others)
				{
					hashSet.Add(text);
					if (Find(pluginInfos, text, out var version))
					{
						list.Add(text + " " + version);
					}
					else
					{
						list2.Add(text);
					}
				}
				List<string> list3 = new List<string>();
				foreach (KeyValuePair<string, PluginInfo> item in pluginInfos)
				{
					if (!hashSet.Contains(item.Key) && !item.Key.Equals("gk2.thoughtfulweek", StringComparison.OrdinalIgnoreCase))
					{
						string text2 = "?";
						try
						{
							text2 = item.Value.Metadata.Version.ToString();
						}
						catch
						{
						}
						list3.Add(item.Key + " " + text2);
					}
				}
				Log(Name() + " plugins loaded: " + ((list.Count == 0) ? "none of the other family's" : string.Join(", ", list.ToArray())) + " | not loaded: " + ((list2.Count == 0) ? "none" : string.Join(", ", list2.ToArray())));
				Log(Name() + " other plugins: " + ((list3.Count == 0) ? "none" : string.Join(", ", list3.ToArray())));
			}
			catch (Exception ex)
			{
				Log(Name() + " plugin list failed: " + ex.Message);
			}
		}

		private static bool Find(IDictionary<string, PluginInfo> infos, string guid, out string version)
		{
			version = "";
			foreach (KeyValuePair<string, PluginInfo> info in infos)
			{
				if (info.Key.Equals(guid, StringComparison.OrdinalIgnoreCase))
				{
					try
					{
						version = info.Value.Metadata.Version.ToString();
					}
					catch
					{
						version = "?";
					}
					return true;
				}
			}
			return false;
		}

		private static string Name()
		{
			return "[gk2.thoughtfulweek 0.5.3]";
		}

		internal static void Records(string when)
		{
			if (!On)
			{
				return;
			}
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.Append(Name()).Append(" records ").Append(when)
					.Append(": ");
				stringBuilder.Append("jobs.v1 ").Append(Jobs()).Append(" | ");
				stringBuilder.Append("zombieChores.v1 ").Append(ZombieChores()).Append(" | ");
				stringBuilder.Append("stockLimits.v1 ").Append(StockLimits()).Append(" | ");
				stringBuilder.Append("wheel.v1 ").Append(Wheel()).Append(" | ");
				stringBuilder.Append("hub.v1 ").Append(Hub());
				Log(stringBuilder.ToString());
				Log(Name() + " published " + when + ": " + Published());
			}
			catch (Exception ex)
			{
				Log(Name() + " records failed: " + ex.Message);
			}
		}

		private static object Get(string key)
		{
			try
			{
				return AppDomain.CurrentDomain.GetData(key);
			}
			catch
			{
				return null;
			}
		}

		private static string Jobs()
		{
			object obj = Get("gk2kit.jobs.v1");
			if (obj == null)
			{
				return "absent";
			}
			if (!(obj is IDictionary dictionary))
			{
				return "present, unexpected type " + obj.GetType().Name;
			}
			SortedDictionary<string, int> sortedDictionary = new SortedDictionary<string, int>();
			int count;
			lock (dictionary)
			{
				count = dictionary.Count;
				foreach (DictionaryEntry item in dictionary)
				{
					string text = (item.Value as string) ?? "?";
					int num = text.IndexOf(':');
					string key = ((num > 0) ? text.Substring(0, num) : text);
					sortedDictionary.TryGetValue(key, out var value);
					sortedDictionary[key] = value + 1;
				}
			}
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, int> item2 in sortedDictionary)
			{
				list.Add(item2.Key + " " + item2.Value);
			}
			return "present, " + count + " held" + ((list.Count > 0) ? (" (" + string.Join(", ", list.ToArray()) + ")") : "");
		}

		private static string ZombieChores()
		{
			object obj = Get("gk2kit.zombieChores.v1");
			if (obj == null)
			{
				return "absent";
			}
			if (!(obj is IDictionary<string, object> dictionary))
			{
				return "present, unexpected type " + obj.GetType().Name;
			}
			Func<bool> func = null;
			Func<string[]> func2 = null;
			string text;
			lock (dictionary)
			{
				text = string.Join(",", new List<string>(dictionary.Keys).ToArray());
				if (dictionary.TryGetValue("on", out var value))
				{
					func = value as Func<bool>;
				}
				if (dictionary.TryGetValue("chores", out value))
				{
					func2 = value as Func<string[]>;
				}
			}
			string text2 = "no on()";
			string text3 = "no chores()";
			if (func != null)
			{
				try
				{
					text2 = "on=" + func();
				}
				catch (Exception ex)
				{
					text2 = "on() threw " + ex.GetType().Name;
				}
			}
			if (func2 != null)
			{
				try
				{
					string[] array = func2();
					text3 = ((array == null) ? "chores()=null" : ("chores=[" + string.Join(",", array) + "]"));
				}
				catch (Exception ex2)
				{
					text3 = "chores() threw " + ex2.GetType().Name;
				}
			}
			return "present, " + text2 + ", " + text3 + " (fields " + text + ")";
		}

		private static string StockLimits()
		{
			object obj = Get("gk2kit.stockLimits.v1");
			if (obj == null)
			{
				return "absent";
			}
			if (!(obj is IDictionary<string, object> dictionary))
			{
				return "present, unexpected type " + obj.GetType().Name;
			}
			lock (dictionary)
			{
				return "present (fields " + string.Join(",", new List<string>(dictionary.Keys).ToArray()) + ")";
			}
		}

		private static string Wheel()
		{
			object obj = Get("gk2kit.wheel.v1");
			if (obj == null)
			{
				return "absent";
			}
			if (!(obj is IList list))
			{
				return "present, unexpected type " + obj.GetType().Name;
			}
			List<string> list2 = new List<string>();
			lock (list)
			{
				foreach (object item in list)
				{
					if (!(item is IDictionary<string, object> dictionary))
					{
						list2.Add("?");
						continue;
					}
					dictionary.TryGetValue("mod", out var value);
					dictionary.TryGetValue("id", out var value2);
					list2.Add(((value as string) ?? "?") + "/" + ((value2 as string) ?? "?"));
				}
			}
			return list2.Count + " entries" + ((list2.Count > 0) ? (" (" + string.Join(", ", list2.ToArray()) + ")") : "");
		}

		private static string Hub()
		{
			object obj = Get("gk2kit.hub.v1");
			if (obj == null)
			{
				return "absent";
			}
			if (!(obj is IDictionary<string, object> dictionary))
			{
				return "present, unexpected type " + obj.GetType().Name;
			}
			object value = null;
			lock (dictionary)
			{
				dictionary.TryGetValue("host", out value);
			}
			string text = value as string;
			return "present, host " + ((text == null) ? "(none)" : ((text.Length == 0) ? "\"\" (none left)" : text));
		}

		private static string Published()
		{
			List<string> list = new List<string>();
			string[] ownKeys = _ownKeys;
			foreach (string text in ownKeys)
			{
				object obj = Get(text);
				IDictionary<string, object> dictionary = obj as IDictionary<string, object>;
				if (obj == null)
				{
					list.Add(text + " not published");
					continue;
				}
				if (dictionary == null)
				{
					list.Add(text + " published (" + obj.GetType().Name + ")");
					continue;
				}
				lock (dictionary)
				{
					list.Add(text + " published, " + dictionary.Count + " fields (" + string.Join(",", new List<string>(dictionary.Keys).ToArray()) + ")");
				}
			}
			if (_wheelMod != null)
			{
				bool flag = false;
				if (Get("gk2kit.wheel.v1") is IList list2)
				{
					lock (list2)
					{
						foreach (object item in list2)
						{
							if (item is IDictionary<string, object> dictionary2 && dictionary2.TryGetValue("mod", out var value) && dictionary2.TryGetValue("id", out var value2) && _wheelMod.Equals(value as string) && _wheelId.Equals(value2 as string))
							{
								flag = true;
								break;
							}
						}
					}
				}
				list.Add("wheel entry " + _wheelMod + "/" + _wheelId + (flag ? " in the list" : " NOT in the list"));
			}
			if (list.Count != 0)
			{
				return string.Join("; ", list.ToArray());
			}
			return "nothing";
		}
	}
	internal static class Evening
	{
		private static int _sermonDay = int.MinValue;

		private static int _raiseDay = int.MinValue;

		private static int _battleDay = int.MinValue;

		private static int _corpsesDay = int.MinValue;

		private const string CorpseAnswer = "nun_asking_about_corpses_";

		private static int _shownDay = int.MinValue;

		private static string _shownSlot;

		private static List<string> _notes;

		private static readonly Regex MapBattle = new Regex("^fight_[A-RT-Z][0-9]+_[0-9]+$");

		private static bool _lastFinishWon;

		private static void Note(string kind, string result)
		{
			if (_notes != null)
			{
				_notes.Add(kind + ": " + result);
			}
		}

		public static void Patch(Harmony h)
		{
			Post(h, typeof(UIPrayWindowData), "OnPrayFinished", "SermonDone");
			Post(h, AccessTools.TypeByName("GK2.FlowCanvasNodes.Flow_StartResurrection"), "StartResurrection", "RaiseDone");
			Pre(h, typeof(FightingGameController), "FinishAsWon", "WonPre");
			Pre(h, typeof(FightingGameController), "FinishAsLost", "LostPre");
			Post(h, typeof(FightingGameController), "FinishAsWon", "BattleDone");
			Post(h, typeof(FightingGameController), "FinishAsLost", "BattleDone");
			Post(h, typeof(GlobalEventsSystem), "FireTrigger", "TriggerFired");
		}

		private static void Pre(Harmony h, Type t, string method, string patch)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = ((t != null) ? AccessTools.Method(t, method, (Type[])null, (Type[])null) : null);
				if (methodInfo != null)
				{
					h.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Evening), patch, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Evening: patch " + method + ": " + ex.Message));
			}
		}

		private static void Post(Harmony h, Type t, string method, string patch)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = ((t != null) ? AccessTools.Method(t, method, (Type[])null, (Type[])null) : null);
				if (methodInfo != null)
				{
					h.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Evening), patch, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					return;
				}
				Plugin.Log.LogWarning((object)("Evening: " + ((t != null) ? t.Name : "?") + "." + method + " not found; that reminder reads the game's state only"));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Evening: patch " + method + ": " + ex.Message));
			}
		}

		private static void SermonDone()
		{
			_sermonDay = Orders.AbsDay();
			Diag.Log("sermon finished on day " + _sermonDay + ": its reminder is done");
		}

		private static void RaiseDone()
		{
			_raiseDay = Orders.AbsDay();
			Diag.Log("resurrection ritual finished on day " + _raiseDay + ": its reminder is done");
		}

		private static void BattleDone(FightingGameController __instance)
		{
			string text = null;
			try
			{
				text = (((Object)(object)__instance != (Object)null) ? __instance.CurrentLevelId : null);
			}
			catch
			{
			}
			if (!IsSlothBattle(text))
			{
				if (text != null)
				{
					Plugin.Log.LogInfo((object)("Evening: fight " + text + " is not the Sloth battle"));
				}
				Diag.Log("fight " + text + " finished: ignored by the battle reminder (" + ((text == null) ? "no level id" : (text.StartsWith("sd_floor", StringComparison.Ordinal) ? "Sealed Depths floor" : (text.StartsWith("fight_AR", StringComparison.Ordinal) ? "arena" : ((text.StartsWith("fight_S", StringComparison.Ordinal) || text.StartsWith("sewer", StringComparison.Ordinal)) ? "sewer brawl" : (MapBattle.IsMatch(text) ? "part I of a two-part battle" : "not a map battle"))))) + ")");
			}
			else
			{
				Diag.Log("fight " + text + " finished: counts as the Sloth battle of day " + Orders.AbsDay());
				_battleDay = Orders.AbsDay();
				Remember(((Object)(object)Plugin.Instance != (Object)null) ? Plugin.Instance.BattleDoneOn : null, _battleDay);
			}
		}

		private static bool IsSlothBattle(string id)
		{
			if (string.IsNullOrEmpty(id) || !MapBattle.IsMatch(id))
			{
				return false;
			}
			try
			{
				FightDef dataOrNull = ((GameBalanceBase)GameBalance.Me).GetDataOrNull<FightDef>(id);
				if (dataOrNull != null && !string.IsNullOrEmpty(dataOrNull.onWinNextFightId) && _lastFinishWon)
				{
					return false;
				}
			}
			catch
			{
			}
			return true;
		}

		private static void WonPre()
		{
			_lastFinishWon = true;
		}

		private static void LostPre()
		{
			_lastFinishWon = false;
		}

		private static void TriggerFired(Type type, string id)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			if ((int)type == 15 && id != null && id.StartsWith("nun_asking_about_corpses_", StringComparison.Ordinal) && id != "nun_asking_about_corpses_ask")
			{
				_corpsesDay = Orders.AbsDay();
				Diag.Log("Agatha's corpse answer " + id + " on day " + _corpsesDay + ": its reminder is done");
				Remember(((Object)(object)Plugin.Instance != (Object)null) ? Plugin.Instance.CorpsesDoneOn : null, _corpsesDay);
			}
		}

		public static void Reset()
		{
			_sermonDay = (_raiseDay = (_battleDay = (_corpsesDay = int.MinValue)));
			_shownDay = int.MinValue;
			_shownSlot = null;
		}

		public static void Tick(int day, string slot, bool free)
		{
			Plugin instance = Plugin.Instance;
			if ((Object)(object)instance == (Object)null || !instance.EveningPopup.Value || day < 0 || (day == _shownDay && slot == _shownSlot))
			{
				return;
			}
			float num;
			try
			{
				num = Mathf.Repeat(MainGame.Instance.GameSave.environmentData.TimeOfDay, 1f);
			}
			catch
			{
				return;
			}
			if (num < Mathf.Clamp(instance.EveningHour.Value, 7f, 23.25f) / 24f || num >= 0.99f || !free)
			{
				return;
			}
			_shownDay = day;
			_shownSlot = slot;
			_notes = (Diag.On ? new List<string>() : null);
			string text = null;
			try
			{
				text = Text(day);
			}
			finally
			{
				if (_notes != null)
				{
					Diag.Log("evening reminder day " + day + " (" + ((Week.TodayPlan() != null) ? Week.TodayPlan().DayId : "?") + "): " + ((_notes.Count == 0) ? "no kind applies today" : string.Join("; ", _notes.ToArray())) + " => " + ((text == null) ? "nothing said" : "said"));
					_notes = null;
				}
			}
			if (text != null)
			{
				Plugin.Log.LogInfo((object)("Evening reminder: " + text.Replace("\n", " / ")));
				Thought.Say(text);
			}
		}

		private static string Text(int day)
		{
			Plugin instance = Plugin.Instance;
			DayPlan dayPlan = Week.TodayPlan();
			if (dayPlan == null)
			{
				return null;
			}
			List<string> list = new List<string>();
			bool flag = dayPlan.Known && !dayPlan.EveryDay;
			switch (dayPlan.DayId)
			{
			case "day_wrath":
				if (instance.EveSermon.Value && flag && _sermonDay != day && Res("sermon_ready") >= 1f)
				{
					list.Add(L10n.F("EveSermon", dayPlan.Sin));
				}
				Note("sermon", (!instance.EveSermon.Value) ? "off (switch)" : ((!flag) ? "quiet (not known yet, or another mod opens it every day)" : ((_sermonDay == day) ? "quiet (done today)" : ((Res("sermon_ready") < 1f) ? "quiet (sermon_ready is 0)" : "reminded"))));
				if (instance.EveCorpses.Value && _corpsesDay != day && !Remembered(instance.CorpsesDoneOn, day) && dayPlan.Extras.Exists((DayExtra x) => x.Key == "ActCorpses"))
				{
					list.Add(L10n.F("EveCorpses", dayPlan.Sin));
				}
				Note("corpse count", (!instance.EveCorpses.Value) ? "off (switch)" : ((_corpsesDay == day || Remembered(instance.CorpsesDoneOn, day)) ? "quiet (answered today)" : ((!dayPlan.Extras.Exists((DayExtra x) => x.Key == "ActCorpses")) ? "quiet (not offered)" : "reminded")));
				break;
			case "day_envy":
				if (instance.EveResurrection.Value && flag && _raiseDay != day && Res("resurrection_has_power") >= 1f)
				{
					list.Add(L10n.F("EveResurrection", dayPlan.Sin));
				}
				Note("resurrection", (!instance.EveResurrection.Value) ? "off (switch)" : ((!flag) ? "quiet (not known yet, or another mod opens it every day)" : ((_raiseDay == day) ? "quiet (done today)" : ((Res("resurrection_has_power") < 1f) ? "quiet (no power)" : "reminded"))));
				break;
			case "day_pride":
				if (instance.EveOrders.Value && Res("chalk_board_enabled") >= 1f && Orders.UnlockedVendors().Count > 0)
				{
					int num = Orders.FreeSlots();
					if (num > 0)
					{
						list.Add(string.Format(L10n.T("EveOrders"), dayPlan.Sin, num));
					}
				}
				Note("orders", (!instance.EveOrders.Value) ? "off (switch)" : ((Res("chalk_board_enabled") < 1f) ? "quiet (board closed)" : ((Orders.UnlockedVendors().Count == 0) ? "quiet (no vendor unlocked)" : ((Orders.FreeSlots() > 0) ? ("reminded (" + Orders.FreeSlots() + " free)") : "quiet (no free slot)"))));
				break;
			case "day_gluttony":
				if (instance.EvePrMachine.Value && dayPlan.Known && !PrMachineRunning())
				{
					list.Add(L10n.F("EvePrMachine", dayPlan.Sin));
				}
				Note("PR machine", (!instance.EvePrMachine.Value) ? "off (switch)" : ((!dayPlan.Known) ? "quiet (not known yet)" : (PrMachineRunning() ? "quiet (running)" : "reminded")));
				break;
			case "day_sloth":
				if (instance.EveBattle.Value && dayPlan.Known && _battleDay != day && !Remembered(instance.BattleDoneOn, day) && Res("battle_ready") >= 1f)
				{
					list.Add(L10n.F("EveBattle", dayPlan.Sin));
				}
				Note("battle", (!instance.EveBattle.Value) ? "off (switch)" : ((!dayPlan.Known) ? "quiet (not known yet)" : ((_battleDay == day || Remembered(instance.BattleDoneOn, day)) ? "quiet (battle done today)" : ((Res("battle_ready") < 1f) ? "quiet (battle_ready is 0, no fight offered)" : "reminded"))));
				break;
			case "day_lust":
				if (instance.EveTears.Value && Week.Tears() == Week.TearsState.Waiting)
				{
					list.Add(L10n.T("EveTears"));
				}
				Note("crystals", (!instance.EveTears.Value) ? "off (switch)" : ((Week.Tears() != Week.TearsState.Waiting) ? ("quiet (" + Week.Tears().ToString() + ")") : "reminded"));
				break;
			}
			if (dayPlan.DayId != "day_pride" && instance.EveRewards.Value && !OtherMods.ClerkCollects)
			{
				int count = Orders.Current().FindAll((OrderInfo o) => o.Finished).Count;
				if (count > 0)
				{
					list.Add(L10n.F("EveRewards", count));
				}
				Note("order rewards", (count > 0) ? ("reminded (" + count + " waiting)") : "quiet (none waiting)");
			}
			else
			{
				Note("order rewards", (dayPlan.DayId == "day_pride") ? "quiet (the Pride orders line counts them)" : ((!instance.EveRewards.Value) ? "off (switch)" : "quiet (Clerk Desk's clerk collects them)"));
			}
			if (list.Count == 0)
			{
				return null;
			}
			return Week.DayIcon(dayPlan.DayId) + " " + string.Join("\n", list.ToArray());
		}

		private static void Remember(ConfigEntry<string> entry, int day)
		{
			try
			{
				if (entry != null && day >= 0)
				{
					entry.Value = GameApi.SlotKey() + "|" + day;
				}
			}
			catch
			{
			}
		}

		private static bool Remembered(ConfigEntry<string> entry, int day)
		{
			try
			{
				return entry != null && day >= 0 && entry.Value == GameApi.SlotKey() + "|" + day;
			}
			catch
			{
				return false;
			}
		}

		private static float Res(string id)
		{
			try
			{
				return MainGame.PlayerData.GetRes(id, 0f);
			}
			catch
			{
				return 0f;
			}
		}

		private static bool PrMachineRunning()
		{
			if (Res("panic_reduction_duration") > 0f)
			{
				return true;
			}
			try
			{
				WorldFacts worldFacts = WorldFacts.Read();
				if (worldFacts.Error != null)
				{
					throw new Exception(worldFacts.Error);
				}
				if (worldFacts.NoWorld)
				{
					return true;
				}
				foreach (WgoData prMachine in worldFacts.PrMachines)
				{
					CraftComponent craftComponent = prMachine.CraftComponent;
					if (craftComponent != null && (craftComponent.IsStarted || craftComponent.CurrentCraftElement != null))
					{
						return true;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.LogThrottled("Evening: PR machine: " + ex.Message);
				return true;
			}
			return false;
		}
	}
	internal static class GameLang
	{
		private static string _stable;

		private static string _seen;

		private static float _seenAt;

		private const float Settle = 0.6f;

		public static string Code()
		{
			string text = null;
			try
			{
				if (LLBase.IsCurrentLangLoaded)
				{
					text = LLBase.CurrentLang;
				}
			}
			catch
			{
			}
			if (string.IsNullOrEmpty(text))
			{
				return _stable ?? "";
			}
			if (_stable == null)
			{
				_stable = (_seen = text);
				return text;
			}
			if (text == _stable)
			{
				_seen = text;
				return text;
			}
			float unscaledTime = Time.unscaledTime;
			if (text != _seen)
			{
				_seen = text;
				_seenAt = unscaledTime;
			}
			else if (unscaledTime - _seenAt >= 0.6f)
			{
				_stable = text;
			}
			return _stable;
		}
	}
	internal static class ExtLoc
	{
		public static string Override = "";

		private static readonly Dictionary<string, Dictionary<string, string>> Loaded = new Dictionary<string, Dictionary<string, string>>();

		public static string Lang()
		{
			string text = (Override ?? "").Trim();
			if (text.Length > 0)
			{
				return text.ToLowerInvariant();
			}
			string text2 = GameLang.Code();
			return ((text2.Length > 0) ? text2 : "en").ToLowerInvariant();
		}

		public static bool TryGet(string key, out string text)
		{
			return TryGet(Lang(), key, out text);
		}

		public static bool TryGet(string lang, string key, out string text)
		{
			text = null;
			if (key == null)
			{
				return false;
			}
			Dictionary<string, string> dictionary = For(lang);
			if (dictionary != null && dictionary.TryGetValue(key, out text))
			{
				return !string.IsNullOrEmpty(text);
			}
			return false;
		}

		public static string ModDir()
		{
			return SaHelp.ModDir("GK2ThoughtfulWeek");
		}

		public static string Folder()
		{
			try
			{
				return Path.Combine(ModDir(), "Localization");
			}
			catch
			{
				return null;
			}
		}

		private static Dictionary<string, string> For(string lang)
		{
			lang = (lang ?? "en").Trim().ToLowerInvariant();
			if (Loaded.TryGetValue(lang, out var value))
			{
				return value;
			}
			value = null;
			try
			{
				string text = Folder();
				if (text != null && Directory.Exists(text))
				{
					foreach (string item in Candidates(lang))
					{
						string text2 = Path.Combine(text, item + ".json");
						if (File.Exists(text2))
						{
							value = Parse(File.ReadAllText(text2, Encoding.UTF8));
							Plugin.Log.LogInfo((object)("Localization: " + value.Count + " text(s) for '" + lang + "' from " + text2));
							break;
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Localization: could not read the file for '" + lang + "': " + ex.Message));
				value = null;
			}
			Loaded[lang] = value;
			return value;
		}

		private static IEnumerable<string> Candidates(string lang)
		{
			HashSet<string> seen = new HashSet<string>();
			string[] array = new string[4]
			{
				lang,
				lang.Replace('_', '-'),
				lang.Replace('-', '_'),
				(lang.Length > 2) ? lang.Substring(0, 2) : lang
			};
			foreach (string text in array)
			{
				if (text.Length > 0 && seen.Add(text))
				{
					yield return text;
				}
			}
		}

		private static Dictionary<string, string> Parse(string s)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			int i = 0;
			Ws(s, ref i);
			if (i >= s.Length || s[i] != '{')
			{
				throw new FormatException("the file must be a JSON object { \"key\": \"text\", ... }");
			}
			i++;
			while (true)
			{
				Ws(s, ref i);
				if (i >= s.Length)
				{
					throw new FormatException("unexpected end of file");
				}
				if (s[i] == '}')
				{
					break;
				}
				if (s[i] == ',')
				{
					i++;
					continue;
				}
				string text = Str(s, ref i);
				Ws(s, ref i);
				if (i >= s.Length || s[i] != ':')
				{
					throw new FormatException("':' expected after \"" + text + "\"");
				}
				i++;
				Ws(s, ref i);
				if (i < s.Length && s[i] == '"')
				{
					dictionary[text] = Str(s, ref i);
				}
				else
				{
					Skip(s, ref i);
				}
			}
			return dictionary;
		}

		private static void Ws(string s, ref int i)
		{
			while (i < s.Length && (char.IsWhiteSpace(s[i]) || s[i] == '\ufeff'))
			{
				i++;
			}
		}

		private static string Str(string s, ref int i)
		{
			if (i >= s.Length || s[i] != '"')
			{
				throw new FormatException("a \"quoted\" string expected at " + i);
			}
			i++;
			StringBuilder stringBuilder = new StringBuilder();
			while (i < s.Length)
			{
				char c = s[i++];
				switch (c)
				{
				case '"':
					return stringBuilder.ToString();
				default:
					stringBuilder.Append(c);
					continue;
				case '\\':
					break;
				}
				if (i >= s.Length)
				{
					break;
				}
				char c2 = s[i++];
				switch (c2)
				{
				case 'n':
					stringBuilder.Append('\n');
					break;
				case 't':
					stringBuilder.Append('\t');
					break;
				case 'r':
					stringBuilder.Append('\r');
					break;
				case 'b':
					stringBuilder.Append('\b');
					break;
				case 'f':
					stringBuilder.Append('\f');
					break;
				case 'u':
					if (i + 4 > s.Length)
					{
						throw new FormatException("bad \\u escape");
					}
					stringBuilder.Append((char)Convert.ToInt32(s.Substring(i, 4), 16));
					i += 4;
					break;
				default:
					stringBuilder.Append(c2);
					break;
				}
			}
			throw new FormatException("unterminated string");
		}

		private static void Skip(string s, ref int i)
		{
			int num = 0;
			while (i < s.Length)
			{
				switch (s[i])
				{
				case '"':
					Str(s, ref i);
					if (num != 0)
					{
						continue;
					}
					return;
				case '[':
				case '{':
					num++;
					break;
				case ']':
				case '}':
					if (num == 0)
					{
						return;
					}
					num--;
					break;
				case ',':
					if (num == 0)
					{
						return;
					}
					break;
				}
				i++;
			}
		}
	}
	internal static class Framework
	{
		private sealed class Entry : Gk2ModBase
		{
			private readonly Gk2ModMetadata _meta = new Gk2ModMetadata("gk2.thoughtfulweek", "GK2 Thoughtful Week", "SaintArchI", "0.5.3", FwText.L("A morning thought on what the day of the week is good for, plus your town orders at a glance. Inspired by p1xel8ted's Thoughtful Reminders for Graveyard Keeper."), false, false);

			private readonly IReadOnlyList<Gk2ModDependency> _deps = (IReadOnlyList<Gk2ModDependency>)(object)new Gk2ModDependency[1]
			{
				new Gk2ModDependency("ru.superman4eg.gk2.framework", "0.1.0", "0.2.0", false)
			};

			public override Gk2ModMetadata Metadata => _meta;

			public override IReadOnlyList<Gk2ModDependency> Dependencies => _deps;

			public override void OnRegister(Gk2ModContext context)
			{
				Gk2Settings settings = context.Settings;
				Plugin instance = Plugin.Instance;
				Toggle(settings, instance.MorningPopup);
				Toggle(settings, instance.MorningShowEvents);
				Toggle(settings, instance.MorningShowOrders);
				Toggle(settings, instance.MorningOnlyWhenSomething);
				Toggle(settings, instance.MorningOnLoad);
				Toggle(settings, instance.MorningOpensPanel);
				Slider(settings, instance.MorningHour, 0.25f);
				Key(settings, instance.ThoughtKey);
				Toggle(settings, instance.EveningPopup);
				Toggle(settings, instance.EveSermon);
				Toggle(settings, instance.EveResurrection);
				Toggle(settings, instance.EveOrders);
				Toggle(settings, instance.EvePrMachine);
				Toggle(settings, instance.EveBattle);
				Toggle(settings, instance.EveTears);
				Toggle(settings, instance.EveCorpses);
				Toggle(settings, instance.EveRewards);
				Slider(settings, instance.EveningHour, 0.25f);
				Key(settings, instance.ToggleWindowKey);
				Slider(settings, instance.WindowScale, 0.05f);
				Toggle(settings, instance.PauseGame);
				Toggle(settings, instance.HudDayClock);
				Toggle(settings, instance.HudWeekButton);
				Text(settings, instance.PadWindowKey);
				Text(settings, instance.PadThoughtKey);
				Toggle(settings, instance.PadL3WithLantern);
				Text(settings, instance.Language);
			}

			private static string Name(ConfigEntryBase e)
			{
				ConfigurationManagerAttributes configurationManagerAttributes = Attrs(e);
				return FwText.L((configurationManagerAttributes != null && configurationManagerAttributes.DispName != null) ? configurationManagerAttributes.DispName : e.Definition.Key);
			}

			private static string Desc(ConfigEntryBase e)
			{
				return FwText.L((e.Description != null) ? e.Description.Description : "");
			}

			private static int Order(ConfigEntryBase e)
			{
				ConfigurationManagerAttributes configurationManagerAttributes = Attrs(e);
				if (configurationManagerAttributes == null || !configurationManagerAttributes.Order.HasValue)
				{
					return 0;
				}
				return 1000 - configurationManagerAttributes.Order.Value;
			}

			private static ConfigurationManagerAttributes Attrs(ConfigEntryBase e)
			{
				if (e.Description == null || e.Description.Tags == null)
				{
					return null;
				}
				object[] tags = e.Description.Tags;
				for (int i = 0; i < tags.Length; i++)
				{
					if (tags[i] is ConfigurationManagerAttributes result)
					{
						return result;
					}
				}
				return null;
			}

			private static void Toggle(Gk2Settings s, ConfigEntry<bool> e)
			{
				s.AddToggle(((ConfigEntryBase)e).Definition.Section, ((ConfigEntryBase)e).Definition.Key, (bool)((ConfigEntryBase)e).DefaultValue, Name((ConfigEntryBase)(object)e), Desc((ConfigEntryBase)(object)e), Order((ConfigEntryBase)(object)e));
			}

			private static void Slider(Gk2Settings s, ConfigEntry<float> e, float step)
			{
				AcceptableValueRange<float> val = ((ConfigEntryBase)e).Description.AcceptableValues as AcceptableValueRange<float>;
				s.AddFloatSlider(((ConfigEntryBase)e).Definition.Section, ((ConfigEntryBase)e).Definition.Key, (float)((ConfigEntryBase)e).DefaultValue, val?.MinValue ?? 0f, val?.MaxValue ?? 1f, Name((ConfigEntryBase)(object)e), Desc((ConfigEntryBase)(object)e), step, Order((ConfigEntryBase)(object)e));
			}

			private static void Key(Gk2Settings s, ConfigEntry<KeyboardShortcut> e)
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				s.AddKeybind(((ConfigEntryBase)e).Definition.Section, ((ConfigEntryBase)e).Definition.Key, (KeyboardShortcut)((ConfigEntryBase)e).DefaultValue, Name((ConfigEntryBase)(object)e), Desc((ConfigEntryBase)(object)e), Order((ConfigEntryBase)(object)e));
			}

			private static void Text(Gk2Settings s, ConfigEntry<string> e)
			{
				s.AddText(((ConfigEntryBase)e).Definition.Section, ((ConfigEntryBase)e).Definition.Key, (string)((ConfigEntryBase)e).DefaultValue, Name((ConfigEntryBase)(object)e), Desc((ConfigEntryBase)(object)e), Order((ConfigEntryBase)(object)e));
			}
		}

		public const string FrameworkGuid = "ru.superman4eg.gk2.framework";

		public static void TryRegister(BaseUnityPlugin plugin)
		{
			try
			{
				if (AppDomain.CurrentDomain.GetAssemblies().Any((Assembly a) => a.GetName().Name == "GK2.Framework"))
				{
					Register(plugin);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogInfo((object)("Mod Framework not used: " + ex.Message));
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void Register(BaseUnityPlugin plugin)
		{
			foreach (RegisteredMod mod in FrameworkApi.Mods)
			{
				if (mod != null && mod.Metadata != null && string.Equals(mod.Metadata.Id, "gk2.thoughtfulweek", StringComparison.OrdinalIgnoreCase))
				{
					return;
				}
			}
			SectionNames.Install();
			FrameworkApi.RegisterMod((IGk2Mod)(object)new Entry(), plugin.Config);
			Plugin.Log.LogInfo((object)"Registered in GK2 Mod Framework");
		}
	}
	internal static class FwText
	{
		private static readonly string[] Langs = new string[10] { "ru", "de", "fr", "es", "pt", "pl", "tr", "ja", "zh", "ko" };

		private static int _idx = -2;

		private static readonly Dictionary<string, string[]> Table = new Dictionary<string, string[]>
		{
			{
				"Pause the game",
				new string[10] { "Ставить игру на паузу", "Spiel pausieren", "Mettre le jeu en pause", "Pausar el juego", "Pausar o jogo", "Pauzuj grę", "Oyunu duraklat", "ゲームを一時停止", "暂停游戏", "게임 일시정지" }
			},
			{
				"The game stands still while the week window is open, as it does for its own windows.",
				new string[10] { "Пока открыто окно недели, игра стоит на паузе, как и при её собственных окнах.", "Das Spiel hält an, solange das Wochenfenster offen ist, wie bei seinen eigenen Fenstern.", "Le jeu est en pause tant que la fenêtre de la semaine est ouverte, comme pour ses propres fenêtres.", "El juego se detiene mientras la ventana de la semana está abierta, como con sus propias ventanas.", "O jogo fica parado enquanto a janela da semana está aberta, como nas janelas do próprio jogo.", "Gra stoi, dopóki okno tygodnia jest otwarte, tak jak przy jej własnych oknach.", "Hafta penceresi açıkken oyun, kendi pencerelerinde olduğu gibi durur.", "週のウィンドウを開いている間は、ゲーム自身のウィンドウと同じように時間が止まります。", "打开周窗口时游戏会暂停,就像游戏自己的窗口一样。", "주간 창이 열려 있는 동안 게임 자체 창처럼 게임이 멈춥니다." }
			},
			{
				"Window size",
				new string[10] { "Размер окна", "Fenstergröße", "Taille de la fenêtre", "Tamaño de la ventana", "Tamanho da janela", "Rozmiar okna", "Pencere boyutu", "ウィンドウの大きさ", "窗口大小", "창 크기" }
			},
			{
				"Size of the week window, text included. 1 is the size of the game's own windows.",
				new string[10] { "Размер окна недели вместе с текстом. 1 — размер собственных окон игры.", "Größe des Wochenfensters samt Text. 1 ist die Größe der spieleigenen Fenster.", "Taille de la fenêtre de la semaine, texte compris. 1 correspond aux fenêtres du jeu.", "Tamaño de la ventana de la semana, texto incluido. 1 es el tamaño de las ventanas del juego.", "Tamanho da janela da semana, texto incluído. 1 é o tamanho das janelas do próprio jogo.", "Rozmiar okna tygodnia razem z tekstem. 1 to rozmiar okien samej gry.", "Metin dahil hafta penceresinin boyutu. 1, oyunun kendi pencerelerinin boyutudur.", "週ウィンドウの大きさ(文字を含む)。1はゲーム本来のウィンドウの大きさです。", "一周窗口的大小(含文字)。1 为游戏自身窗口的大小。", "주간 창의 크기(글자 포함). 1은 게임 자체 창의 크기입니다." }
			},
			{
				"Open the week",
				new string[10] { "Открыть неделю", "Woche öffnen", "Ouvrir la semaine", "Abrir la semana", "Abrir a semana", "Otwórz tydzień", "Haftayı aç", "週を開く", "打开本周", "주간 열기" }
			},
			{
				"Only when there is something",
				new string[10] { "Только если есть дела", "Nur wenn etwas ansteht", "Seulement s'il y a quelque chose", "Solo si hay algo", "Só se houver algo", "Tylko gdy jest coś do zrobienia", "Yalnızca yapılacak bir şey varsa", "用事がある日だけ", "仅在有事时", "할 일이 있을 때만" }
			},
			{
				"Evening reminder",
				new string[10] { "Вечернее напоминание", "Abend-Erinnerung", "Rappel du soir", "Recordatorio de la tarde", "Lembrete da noite", "Wieczorne przypomnienie", "Akşam hatırlatması", "夕方のリマインダー", "傍晚提醒", "저녁 알림" }
			},
			{
				"Late in a day whose weekly thing you haven't done yet, a thought bubble reminds you while there is still time.",
				new string[10] { "Если к вечеру дело, которое бывает раз в неделю, ещё не сделано, мысль над головой напомнит о нём, пока есть время.", "Wenn das wöchentliche Ereignis des Tages abends noch nicht erledigt ist, erinnert dich eine Gedankenblase, solange noch Zeit ist.", "Si la chose de la semaine prévue ce jour n'est pas faite le soir, une bulle de pensée vous le rappelle tant qu'il est encore temps.", "Si al atardecer aún no has hecho lo semanal de ese día, un pensamiento te lo recuerda mientras haya tiempo.", "Se à tarde ainda não fez a tarefa semanal do dia, um pensamento lembra você enquanto há tempo.", "Gdy wieczorem cotygodniowa sprawa tego dnia nie jest jeszcze zrobiona, myśl nad głową przypomni o niej, póki jest czas.", "Günün haftalık işi akşama kadar yapılmadıysa, vakit varken bir düşünce balonu hatırlatır.", "その曜日の週一の用事が夕方までに済んでいなければ、間に合ううちに吹き出しで知らせます。", "如果当天每周一次的事到傍晚还没做,会趁还来得及用想法气泡提醒你。", "그날의 주간 일을 저녁까지 하지 않았다면, 아직 시간이 있을 때 생각 말풍선으로 알려 줍니다." }
			},
			{
				"Day and time on the HUD",
				new string[10] { "День и время на экране", "Tag und Uhrzeit im HUD", "Jour et heure à l'écran", "Día y hora en pantalla", "Dia e hora na tela", "Dzień i godzina na ekranie", "Gün ve saat ekranda", "画面に曜日と時刻", "屏幕上显示日子和时间", "화면에 요일과 시간" }
			},
			{
				"Today's day and the time on a small plate under the likes counter.",
				new string[10] { "День недели и время на маленькой табличке под счётчиком лайков.", "Wochentag und Uhrzeit auf einem kleinen Schild unter dem Likes-Zähler.", "Le jour et l'heure sur une petite plaque sous le compteur de likes.", "El día y la hora en una placa bajo el contador de Me gusta.", "O dia e a hora numa plaquinha sob o contador de likes.", "Dzień i godzina na tabliczce pod licznikiem lajków.", "Gün ve saat, beğeni sayacının altındaki küçük levhada.", "いいねカウンターの下の小さな札に曜日と時刻。", "点赞计数下方的小牌子显示日子和时间。", "좋아요 카운터 아래 작은 판에 요일과 시간." }
			},
			{
				"Click it to open the week",
				new string[10] { "Клик открывает неделю", "Klick öffnet die Woche", "Un clic ouvre la semaine", "Un clic abre la semana", "Um clique abre a semana", "Kliknięcie otwiera tydzień", "Tıklayınca hafta açılır", "クリックで週を開く", "点击打开一周", "클릭하면 한 주 열기" }
			},
			{
				"Clicking the day and time plate opens the week. The plate is only there while the day and time on the HUD are on.",
				new string[10] { "Щелчок по плашке с днём и временем открывает неделю. Плашка есть, только пока включены день и время на экране.", "Ein Klick auf das Schild mit Tag und Uhrzeit öffnet die Woche. Das Schild gibt es nur, solange Tag und Uhrzeit im HUD eingeschaltet sind.", "Un clic sur la plaque du jour et de l'heure ouvre la semaine. La plaque n'existe que tant que le jour et l'heure à l'écran sont activés.", "Un clic en la placa del día y la hora abre la semana. La placa solo está mientras el día y la hora en pantalla estén activados.", "Um clique na placa do dia e da hora abre a semana. A placa só existe enquanto o dia e a hora na tela estiverem ativados.", "Kliknięcie tabliczki z dniem i godziną otwiera tydzień. Tabliczka jest tylko wtedy, gdy dzień i godzina na ekranie są włączone.", "Gün ve saat levhasına tıklamak haftayı açar. Levha yalnızca ekranda gün ve saat açıkken vardır.", "曜日と時刻の札をクリックすると週を開きます。札は「画面に曜日と時刻」がオンの間だけ表示されます。", "点击日子和时间的牌子打开一周。只有开启“屏幕上显示日子和时间”时才有这块牌子。", "요일과 시간 판을 클릭하면 한 주가 열립니다. 판은 화면에 요일과 시간을 켜 둔 동안에만 있습니다." }
			},
			{
				"Mention the orders",
				new string[10] { "Упоминать заказы", "Aufträge erwähnen", "Parler des commandes", "Mencionar los pedidos", "Mencionar os pedidos", "Wspominaj zlecenia", "Siparişlerden bahset", "注文にも触れる", "提及订单", "주문 언급" }
			},
			{
				"Say what the day allows",
				new string[10] { "Говорить, что можно сделать", "Sagen, was der Tag erlaubt", "Dire ce que permet le jour", "Decir qué permite el día", "Dizer o que o dia permite", "Mów, na co pozwala dzień", "Günün neye izin verdiğini söyle", "その日にできることを言う", "说明今天能做什么", "그날 할 수 있는 것 알려주기" }
			},
			{
				"Off leaves just the name of the day.",
				new string[10] { "Если выключено, остаётся только название дня.", "Aus lässt nur den Namen des Tages.", "Désactivé, seul le nom du jour reste.", "Desactivado, solo queda el nombre del día.", "Desligado, fica só o nome do dia.", "Wyłączone zostawia tylko nazwę dnia.", "Kapalıyken yalnızca günün adı kalır.", "オフにすると曜日名だけになります。", "关闭后只显示当天的名称。", "끄면 요일 이름만 남습니다." }
			},
			{
				"Open the panel instead",
				new string[10] { "Открывать окно вместо мысли", "Stattdessen das Fenster öffnen", "Ouvrir le panneau à la place", "Abrir el panel en su lugar", "Abrir o painel em vez disso", "Zamiast tego otwórz panel", "Bunun yerine paneli aç", "代わりにパネルを開く", "改为打开面板", "대신 패널 열기" }
			},
			{
				"Open the full week panel in the morning instead of the bubble.",
				new string[10] { "Утром открывать окно недели вместо мысли над головой.", "Morgens das ganze Wochenfenster öffnen statt der Gedankenblase.", "Le matin, ouvrir le panneau de la semaine au lieu de la bulle.", "Por la mañana, abrir el panel de la semana en vez de la burbuja.", "De manhã, abrir o painel da semana em vez do balão.", "Rano otwieraj panel tygodnia zamiast dymka.", "Sabah balon yerine tüm hafta panelini açın.", "朝、吹き出しの代わりに週のパネルを開きます。", "早上打开整周面板,而不是气泡。", "아침에 말풍선 대신 주간 패널을 엽니다." }
			},
			{
				"After loading a save",
				new string[10] { "После загрузки сохранения", "Nach dem Laden eines Spielstands", "Après le chargement d'une partie", "Tras cargar una partida", "Depois de carregar um jogo", "Po wczytaniu zapisu", "Kayıt yüklendikten sonra", "セーブを読み込んだ後", "读取存档后", "저장 불러온 후" }
			},
			{
				"Also show the reminder a few seconds after you load a save, so you know where you are in the week.",
				new string[10] { "Показывать напоминание и через пару секунд после загрузки сохранения, чтобы сразу понять, какой сейчас день недели.", "Die Erinnerung auch ein paar Sekunden nach dem Laden eines Spielstands zeigen, damit du weißt, wo du in der Woche stehst.", "Afficher aussi le rappel quelques secondes après le chargement d'une partie, pour savoir où vous en êtes dans la semaine.", "Mostrar también el recordatorio unos segundos después de cargar una partida, para saber en qué día de la semana estás.", "Mostrar o lembrete também alguns segundos depois de carregar um jogo, para saber em que dia da semana você está.", "Pokazuj przypomnienie także kilka sekund po wczytaniu zapisu, by wiedzieć, jaki to dzień tygodnia.", "Kayıt yüklendikten birkaç saniye sonra da hatırlatmayı gösterin, böylece haftanın hangi gününde olduğunu bilirsiniz.", "セーブを読み込んだ数秒後にもお知らせを出し、今が週のどの日かわかるようにします。", "读取存档几秒后也显示提醒,让你知道现在是一周中的哪一天。", "저장을 불러온 몇 초 뒤에도 알림을 띄워, 지금이 주중 어느 날인지 알 수 있게 합니다." }
			},
			{
				"Think about today",
				new string[10] { "Подумать о сегодняшнем дне", "Über heute nachdenken", "Penser à aujourd'hui", "Pensar en el día de hoy", "Pensar no dia de hoje", "Pomyśl o dzisiejszym dniu", "Bugünü düşün", "今日のことを考える", "想想今天", "오늘 생각하기" }
			},
			{
				"Shows today's thought bubble right now, whatever the time.",
				new string[10] { "Показывает облачко с мыслью о сегодняшнем дне прямо сейчас, в любое время.", "Zeigt die Gedankenblase zum heutigen Tag sofort, egal zu welcher Uhrzeit.", "Affiche tout de suite la bulle de pensée du jour, quelle que soit l'heure.", "Muestra ahora mismo la burbuja de pensamiento del día, sea la hora que sea.", "Mostra agora mesmo o balão de pensamento do dia, a qualquer hora.", "Pokazuje dymek z myślą o dzisiejszym dniu od razu, o dowolnej porze.", "Bugünün düşünce balonunu saat kaç olursa olsun hemen gösterir.", "時間に関係なく、今日の考えの吹き出しをすぐに表示します。", "无论何时,立即显示今天的思考气泡。", "시간과 상관없이 오늘의 생각 말풍선을 바로 보여 줍니다." }
			},
			{
				"Morning reminder",
				new string[10] { "Утреннее напоминание", "Morgendliche Erinnerung", "Rappel du matin", "Recordatorio matutino", "Lembrete da manhã", "Poranne przypomnienie", "Sabah hatırlatması", "朝のお知らせ", "早晨提醒", "아침 알림" }
			},
			{
				"A thought bubble over your head when a new day starts, saying what the day is good for.",
				new string[10] { "Мысль над головой в начале нового дня: для чего этот день подходит.", "Eine Gedankenblase über deinem Kopf zu Beginn eines neuen Tages, die sagt, wofür der Tag gut ist.", "Une bulle de pensée au-dessus de votre tête au début d'un nouveau jour, qui dit à quoi il est bon.", "Una burbuja de pensamiento sobre tu cabeza al empezar un día, que dice para qué sirve.", "Um balão de pensamento sobre sua cabeça no início de um novo dia, dizendo para que ele serve.", "Dymek myśli nad głową na początku nowego dnia, mówiący, do czego ten dzień się nadaje.", "Yeni bir gün başladığında başınızın üstünde, günün neye uygun olduğunu söyleyen bir düşünce balonu.", "新しい日の始まりに、その日に向いていることを頭上の吹き出しで知らせます。", "新的一天开始时,头顶出现想法气泡,说明今天适合做什么。", "새 날이 시작되면 머리 위 생각 말풍선으로 그날 하기 좋은 일을 알려줍니다." }
			},
			{
				"Opens and closes the week panel.",
				new string[10] { "Открывает и закрывает окно недели.", "Öffnet und schließt das Wochenfenster.", "Ouvre et ferme le panneau de la semaine.", "Abre y cierra el panel de la semana.", "Abre e fecha o painel da semana.", "Otwiera i zamyka panel tygodnia.", "Hafta panelini açar ve kapatır.", "週のパネルを開閉します。", "打开和关闭本周面板。", "주간 패널을 열고 닫습니다." }
			},
			{
				"A morning thought on what the day of the week is good for, plus your town orders at a glance. Inspired by p1xel8ted's Thoughtful Reminders for Graveyard Keeper.",
				new string[10] { "Утренняя мысль о том, для чего подходит этот день недели, и ваши городские заказы одним взглядом. По мотивам Thoughtful Reminders от p1xel8ted для Graveyard Keeper.", "Ein morgendlicher Gedanke dazu, wofür der Wochentag gut ist, und deine Stadtaufträge auf einen Blick. Inspiriert von p1xel8teds Thoughtful Reminders für Graveyard Keeper.", "Une pensée du matin sur ce à quoi sert le jour de la semaine, et vos commandes de la ville d'un coup d'œil. Inspiré de Thoughtful Reminders de p1xel8ted pour Graveyard Keeper.", "Un pensamiento matutino sobre para qué sirve el día de la semana, y tus pedidos de la ciudad de un vistazo. Inspirado en Thoughtful Reminders de p1xel8ted para Graveyard Keeper.", "Um pensamento matinal sobre para que serve o dia da semana, e seus pedidos do povoado num relance. Inspirado em Thoughtful Reminders, de p1xel8ted, para Graveyard Keeper.", "Poranna myśl o tym, do czego nadaje się dzień tygodnia, i zlecenia miasta w skrócie. Na podstawie Thoughtful Reminders autorstwa p1xel8ted dla Graveyard Keeper.", "Haftanın gününün neye uygun olduğuna dair bir sabah düşüncesi ve kasaba siparişlerine hızlı bakış. p1xel8ted'in Graveyard Keeper için yaptığı Thoughtful Reminders'tan esinlenmiştir.", "その曜日に向いていることを朝の吹き出しで知らせ、町の注文もひと目で確認できます。p1xel8ted 作の Graveyard Keeper 用 MOD「Thoughtful Reminders」に着想を得ています。", "早晨提示这一天适合做什么,并一眼看到你的城镇订单。灵感来自 p1xel8ted 为 Graveyard Keeper 制作的 Thoughtful Reminders。", "아침마다 그 요일에 하기 좋은 일을 알려주고, 마을 주문을 한눈에 보여줍니다. p1xel8ted의 Graveyard Keeper용 모드 Thoughtful Reminders에서 영감을 받았습니다." }
			},
			{
				"Add a line when a finished town order waits at the order board for its reward.",
				new string[10] { "Добавлять строку, когда выполненный городской заказ ждёт награды у доски заказов.", "Eine Zeile, wenn ein fertiger Stadtauftrag an der Auftragstafel auf seine Belohnung wartet.", "Ajoute une ligne quand une commande de la ville terminée attend sa récompense au tableau.", "Añade una línea cuando un pedido de la ciudad terminado espera su recompensa en el tablón.", "Adiciona uma linha quando um pedido do povoado concluído espera a recompensa no quadro.", "Dodaje wiersz, gdy wykonane zlecenie miasta czeka na nagrodę przy tablicy.", "Tamamlanmış bir kasaba siparişi panoda ödülünü beklerken bir satır ekler.", "完了した町の注文が注文ボードで報酬を待っているとき、一行加える。", "当已完成的城镇订单在订单板等待领奖时,加一行提示。", "완료된 마을 주문이 주문 게시판에서 보상을 기다리면 한 줄 추가." }
			},
			{
				"Skip the reminder on a day that allows nothing and has no order ready to hand in.",
				new string[10] { "Не напоминать в день, когда ничего не открыто и нет готовых к сдаче заказов.", "Keine Erinnerung an einem Tag, der nichts erlaubt und keinen fertigen Auftrag hat.", "Pas de rappel un jour qui ne permet rien et sans commande prête à rendre.", "Sin recordatorio un día que no permite nada y sin pedido listo para entregar.", "Sem lembrete num dia que não permite nada e sem pedido pronto para entregar.", "Bez przypomnienia w dzień, który nic nie umożliwia i nie ma gotowego zlecenia.", "Hiçbir şeye izin vermeyen ve teslime hazır siparişi olmayan günde hatırlatma yok.", "何もできず、渡せる注文もない日は知らせない。", "当天没有可做的事、也没有可交付的订单时不提醒。", "할 일이 없고 넘길 주문도 없는 날은 알리지 않음." }
			},
			{
				"When in the morning (game hour)",
				new string[10] { "Когда утром (час игры)", "Wann am Morgen (Spielstunde)", "Quand le matin (heure du jeu)", "Cuándo por la mañana (hora del juego)", "Quando de manhã (hora do jogo)", "Kiedy rano (godzina w grze)", "Sabah ne zaman (oyun saati)", "朝のいつ(ゲーム内の時刻)", "早晨何时(游戏时间)", "아침 언제(게임 시간)" }
			},
			{
				"Game hour after midnight when the thought appears, e.g. 1.2 = 01:12. Asleep then? It comes when you wake up.",
				new string[10] { "Час игры после полуночи, когда появляется мысль, например 1.2 = 01:12. Если вы спите, она придёт, когда проснётесь.", "Spielstunde nach Mitternacht, zu der der Gedanke kommt, z. B. 1.2 = 01:12. Schläfst du dann, kommt er beim Aufwachen.", "Heure du jeu après minuit où la pensée apparaît, p. ex. 1.2 = 01:12. Endormi à ce moment ? Elle vient au réveil.", "Hora del juego tras la medianoche en que aparece el pensamiento, p. ej. 1.2 = 01:12. ¿Dormido? Llega al despertar.", "Hora do jogo depois da meia-noite em que o pensamento aparece, ex. 1.2 = 01:12. Dormindo? Ele vem quando você acordar.", "Godzina w grze po północy, gdy pojawia się myśl, np. 1.2 = 01:12. Śpisz? Przyjdzie po przebudzeniu.", "Düşüncenin geldiği gece yarısından sonraki oyun saati, ör. 1.2 = 01:12. Uyuyorsanız uyandığınızda gelir.", "考えが浮かぶ真夜中過ぎのゲーム内の時刻(例: 1.2 = 01:12)。寝ていれば起きたときに出る。", "午夜后想法出现的游戏时间,例如 1.2 = 01:12。那时在睡觉?醒来时出现。", "자정 이후 생각이 떠오르는 게임 시간, 예: 1.2 = 01:12. 자고 있으면 깨어날 때 나옴." }
			},
			{
				"Remind: no sermon yet (Wrath)",
				new string[10] { "Напомнить: проповеди ещё не было (Гнев)", "Erinnern: noch keine Predigt (Zorn)", "Rappel : pas encore de sermon (Colère)", "Recordar: aún no hubo sermón (Ira)", "Lembrar: ainda sem sermão (Ira)", "Przypomnij: jeszcze bez kazania (Gniew)", "Hatırlat: henüz vaaz yok (Öfke)", "知らせる:まだ説教していない(憤怒)", "提醒:还没布道(愤怒)", "알림: 아직 설교 안 함(분노)" }
			},
			{
				"Late on Wrath, if you haven't held this week's sermon at the church yet.",
				new string[10] { "Вечером в Гнев, если вы ещё не провели проповедь в церкви на этой неделе.", "Spät am Zorn-Tag, wenn du die Predigt dieser Woche in der Kirche noch nicht gehalten hast.", "Tard le jour de Colère, si vous n'avez pas encore fait le sermon de la semaine à l'église.", "Tarde en Ira, si aún no has dado el sermón de la semana en la iglesia.", "No fim da Ira, se você ainda não fez o sermão da semana na igreja.", "Późno w Gniew, jeśli nie wygłosiłeś jeszcze kazania w tym tygodniu.", "Öfke günü geç saatte, bu haftanın vaazını kilisede henüz vermediyseniz.", "憤怒の日の遅く、今週の説教を教会でまだしていなければ。", "愤怒日傍晚,若本周还没在教堂布道。", "분노의 날 늦게, 이번 주 설교를 아직 교회에서 하지 않았으면." }
			},
			{
				"Remind: no one raised yet (Envy)",
				new string[10] { "Напомнить: никого не воскресили (Зависть)", "Erinnern: noch niemand erweckt (Neid)", "Rappel : personne ressuscité (Jalousie)", "Recordar: nadie resucitado (Envidia)", "Lembrar: ninguém ressuscitado (Inveja)", "Przypomnij: nikt nie wskrzeszony (Zawiść)", "Hatırlat: kimse diriltilmedi (Kıskançlık)", "知らせる:まだ誰も復活させていない(嫉妬)", "提醒:还没复活任何人(嫉妒)", "알림: 아직 아무도 부활 안 함(질투)" }
			},
			{
				"Late on Envy, if you haven't used the resurrection device yet; it has power only that day.",
				new string[10] { "Вечером в Зависть, если вы ещё не воспользовались устройством для воскрешения: энергия у него только в этот день.", "Spät am Neid-Tag, wenn du das Wiederbelebungsgerät noch nicht benutzt hast; es hat nur an diesem Tag Strom.", "Tard le jour de Jalousie, si vous n'avez pas encore utilisé le dispositif de résurrection ; il n'a du courant que ce jour-là.", "Tarde en Envidia, si aún no has usado el dispositivo de resurrección; solo tiene energía ese día.", "No fim da Inveja, se você ainda não usou o dispositivo de ressurreição; ele só tem energia nesse dia.", "Późno w Zawiść, jeśli nie użyłeś jeszcze urządzenia do wskrzeszania; ma zasilanie tylko tego dnia.", "Kıskançlık günü geç saatte, diriltme cihazını henüz kullanmadıysanız; yalnızca o gün enerjisi var.", "嫉妬の日の遅く、復活装置をまだ使っていなければ。電力はその日だけ。", "嫉妒日傍晚,若还没用复活装置;它只有那天有电。", "질투의 날 늦게, 부활 장치를 아직 쓰지 않았으면. 그날만 전력이 있음." }
			},
			{
				"Remind: free order slots (Pride)",
				new string[10] { "Напомнить: есть свободные места для заказов (Гордыня)", "Erinnern: freie Auftragsplätze (Stolz)", "Rappel : emplacements de commande libres (Orgueil)", "Recordar: huecos de pedido libres (Orgullo)", "Lembrar: vagas de pedido livres (Orgulho)", "Przypomnij: wolne miejsca na zlecenia (Pycha)", "Hatırlat: boş sipariş yeri (Kibir)", "知らせる:注文枠が空いている(傲慢)", "提醒:有空闲订单位(傲慢)", "알림: 빈 주문 칸(자만)" }
			},
			{
				"Late on Pride, if order slots are still free; new town orders can be taken only on Pride.",
				new string[10] { "Вечером в Гордыню, если остались свободные места: новые городские заказы берут только в Гордыню.", "Spät am Stolz-Tag, wenn noch Auftragsplätze frei sind; neue Stadtaufträge gibt es nur an diesem Tag.", "Tard le jour d'Orgueil, s'il reste des emplacements libres ; les commandes ne se prennent que ce jour-là.", "Tarde en Orgullo, si quedan huecos libres; los pedidos de la ciudad solo se aceptan ese día.", "No fim do Orgulho, se ainda há vagas livres; pedidos do povoado só são aceitos nesse dia.", "Późno w Pychę, jeśli są wolne miejsca; nowe zlecenia miasta przyjmuje się tylko tego dnia.", "Kibir günü geç saatte, boş sipariş yeri varsa; yeni kasaba siparişleri yalnızca o gün alınır.", "傲慢の日の遅く、注文枠が空いていれば。新しい町の注文はその日しか受けられない。", "傲慢日傍晚,若还有空闲订单位;新的城镇订单只能在那天接。", "자만의 날 늦게, 주문 칸이 비어 있으면. 새 마을 주문은 그날만 받을 수 있음." }
			},
			{
				"Remind: PR Machine not running (Gluttony)",
				new string[10] { "Напомнить: ПиАР-машина не запущена (Чревоугодие)", "Erinnern: PR-Maschine läuft nicht (Völlerei)", "Rappel : machine de RP à l'arrêt (Gourmandise)", "Recordar: máquina de RR. PP. parada (Gula)", "Lembrar: máquina de RP parada (Gula)", "Przypomnij: maszyna PR nie działa (Łakomstwo)", "Hatırlat: PR makinesi çalışmıyor (Oburluk)", "知らせる:PRマシンが止まっている(暴食)", "提醒:恐慌消减机没运转(暴食)", "알림: PR 장치 멈춤(식욕)" }
			},
			{
				"Late on Gluttony, if the PR Machine isn't running; it can be loaded only that day.",
				new string[10] { "Вечером в Чревоугодие, если ПиАР-машина не запущена: загрузить её можно только в этот день.", "Spät am Völlerei-Tag, wenn die PR-Maschine nicht läuft; beladen lässt sie sich nur an diesem Tag.", "Tard le jour de Gourmandise, si la machine de RP ne tourne pas ; on ne peut la charger que ce jour-là.", "Tarde en Gula, si la máquina de RR. PP. no está en marcha; solo se puede cargar ese día.", "No fim da Gula, se a máquina de RP não está ligada; só dá para carregá-la nesse dia.", "Późno w Łakomstwo, jeśli maszyna PR nie działa; załadować ją można tylko tego dnia.", "Oburluk günü geç saatte, PR makinesi çalışmıyorsa; yalnızca o gün yüklenebilir.", "暴食の日の遅く、PRマシンが動いていなければ。装填できるのはその日だけ。", "暴食日傍晚,若恐慌消减机没运转;只有那天能装填。", "식욕의 날 늦게, PR 장치가 돌아가지 않으면. 그날만 채울 수 있음." }
			},
			{
				"Remind: no battle yet (Sloth)",
				new string[10] { "Напомнить: битвы ещё не было (Уныние)", "Erinnern: noch keine Schlacht (Trägheit)", "Rappel : pas encore de bataille (Paresse)", "Recordar: aún sin batalla (Pereza)", "Lembrar: ainda sem batalha (Preguiça)", "Przypomnij: jeszcze bez bitwy (Lenistwo)", "Hatırlat: henüz savaş yok (Tembellik)", "知らせる:まだ戦っていない(怠惰)", "提醒:还没战斗(懒惰)", "알림: 아직 전투 안 함(나태)" }
			},
			{
				"Late on Sloth, if the map offers a battle and you haven't fought it.",
				new string[10] { "Вечером в Уныние, если на карте есть битва, а вы ещё не сражались.", "Spät am Trägheit-Tag, wenn die Karte eine Schlacht anbietet und du sie nicht geschlagen hast.", "Tard le jour de Paresse, si la carte propose une bataille et que vous ne l'avez pas livrée.", "Tarde en Pereza, si el mapa ofrece una batalla y no la has librado.", "No fim da Preguiça, se o mapa oferece uma batalha e você não lutou.", "Późno w Lenistwo, jeśli mapa oferuje bitwę, a ty jej nie stoczyłeś.", "Tembellik günü geç saatte, haritada savaş varsa ve henüz savaşmadıysanız.", "怠惰の日の遅く、地図に戦闘があり、まだ戦っていなければ。", "懒惰日傍晚,若地图上有战斗而你还没打。", "나태의 날 늦게, 지도에 전투가 있는데 아직 싸우지 않았으면." }
			},
			{
				"Remind: blue crystals still lying (Lust)",
				new string[10] { "Напомнить: синие кристаллы ещё лежат (Похоть)", "Erinnern: blaue Kristalle liegen noch (Lust)", "Rappel : cristaux bleus toujours là (Luxure)", "Recordar: cristales azules aún ahí (Lujuria)", "Lembrar: cristais azuis ainda lá (Luxúria)", "Przypomnij: niebieskie kryształy wciąż leżą (Nieczystość)", "Hatırlat: mavi kristaller hâlâ duruyor (Şehvet)", "知らせる:青い結晶が残っている(色欲)", "提醒:蓝水晶还在(色欲)", "알림: 푸른 수정이 아직 있음(색욕)" }
			},
			{
				"Late on Lust, if the Goddess's blue crystals still lie by her statue; she weeps new ones on Envy only after they're picked up.",
				new string[10] { "Вечером в Похоть, если синие кристаллы Богини ещё лежат у статуи: новые она плачет в Зависть, только когда эти заберут.", "Spät am Lust-Tag, wenn die blauen Kristalle der Göttin noch bei ihrer Statue liegen; neue weint sie am Neid-Tag erst, wenn diese aufgehoben sind.", "Tard le jour de Luxure, si les cristaux bleus de la Déesse sont encore près de sa statue ; elle n'en pleure de nouveaux le jour de Jalousie qu'une fois ceux-ci ramassés.", "Tarde en Lujuria, si los cristales azules de la Diosa siguen junto a su estatua; solo llora nuevos en Envidia cuando se recogen.", "No fim da Luxúria, se os cristais azuis da Deusa ainda estão junto à estátua; ela só chora novos na Inveja depois que forem recolhidos.", "Późno w Nieczystość, jeśli niebieskie kryształy Bogini wciąż leżą przy posągu; nowe wypłacze w Zawiść dopiero po ich zabraniu.", "Şehvet günü geç saatte, Tanrıça'nın mavi kristalleri hâlâ heykelin yanındaysa; yenilerini Kıskançlık günü ancak bunlar alınınca döker.", "色欲の日の遅く、女神の青い結晶がまだ像のそばにあれば。拾うまで嫉妬の日に新しい結晶は出ない。", "色欲日傍晚,若女神的蓝水晶还在雕像旁;拿走后她才会在嫉妒日流出新的。", "색욕의 날 늦게, 여신의 푸른 수정이 아직 석상 옆에 있으면. 주워야 질투의 날에 새로 흘림." }
			},
			{
				"Remind: corpse count (Wrath)",
				new string[10] { "Напомнить: число трупов (Гнев)", "Erinnern: Leichenzahl (Zorn)", "Rappel : nombre de cadavres (Colère)", "Recordar: número de cadáveres (Ira)", "Lembrar: número de corpos (Ira)", "Przypomnij: liczba zwłok (Gniew)", "Hatırlat: ceset sayısı (Öfke)", "知らせる:死体の数(憤怒)", "提醒:尸体数量(愤怒)", "알림: 시체 수(분노)" }
			},
			{
				"Late on Wrath, if you haven't told Agatha how many corpses you need; only possible on Wrath, and her answer stays until you change it.",
				new string[10] { "Вечером в Гнев, если вы не сказали Агате, сколько трупов нужно: это можно только в Гнев, и её ответ действует, пока вы его не измените.", "Spät am Zorn-Tag, wenn du Agatha nicht gesagt hast, wie viele Leichen du brauchst; das geht nur an Zorn, und ihre Antwort gilt, bis du sie änderst.", "Tard le jour de Colère, si vous n'avez pas dit à Agatha combien de cadavres il vous faut ; possible seulement ce jour-là, et sa réponse reste jusqu'à ce que vous la changiez.", "Tarde en Ira, si no le has dicho a Ágata cuántos cadáveres necesitas; solo se puede en Ira y su respuesta se mantiene hasta que la cambies.", "No fim da Ira, se você não disse à Agatha quantos corpos precisa; só dá na Ira, e a resposta dela vale até você mudar.", "Późno w Gniew, jeśli nie powiedziałeś Agacie, ile zwłok potrzebujesz; można tylko w Gniew, a jej odpowiedź obowiązuje, dopóki jej nie zmienisz.", "Öfke günü geç saatte, Agatha'ya kaç ceset gerektiğini söylemediyseniz; yalnızca Öfke günü olur ve cevabı siz değiştirene kadar geçerli.", "憤怒の日の遅く、アガサに必要な死体の数を伝えていなければ。憤怒の日だけで、答えは変えるまで続く。", "愤怒日傍晚,若还没告诉阿加莎你需要多少尸体;只能在愤怒日,她的答复在你更改前一直有效。", "분노의 날 늦게, 애거서에게 필요한 시체 수를 말하지 않았으면. 분노의 날만 가능하고, 바꾸기 전까지 그 답이 유지됨." }
			},
			{
				"Remind: rewards at the order board",
				new string[10] { "Напомнить: награды у доски заказов", "Erinnern: Belohnungen an der Auftragstafel", "Rappel : récompenses au tableau", "Recordar: recompensas en el tablón", "Lembrar: recompensas no quadro", "Przypomnij: nagrody przy tablicy", "Hatırlat: panodaki ödüller", "知らせる:注文ボードの報酬", "提醒:订单板上的奖励", "알림: 주문 게시판의 보상" }
			},
			{
				"Late on any day, if finished town orders wait at the order board for their reward. Quiet while Clerk Desk's clerk collects them.",
				new string[10] { "Вечером в любой день, если выполненные заказы ждут награды у доски заказов. Молчит, пока награды забирает клерк из Clerk Desk.", "Spät an jedem Tag, wenn fertige Stadtaufträge an der Auftragstafel auf ihre Belohnung warten. Still, solange der Schreiber von Clerk Desk sie abholt.", "Tard chaque jour, si des commandes terminées attendent leur récompense au tableau. Silencieux tant que le commis de Clerk Desk les récupère.", "Tarde cualquier día, si pedidos terminados esperan su recompensa en el tablón. Calla mientras el oficinista de Clerk Desk las recoge.", "No fim de qualquer dia, se pedidos concluídos esperam a recompensa no quadro. Fica quieto enquanto o escriturário do Clerk Desk as recolhe.", "Późno każdego dnia, jeśli wykonane zlecenia czekają na nagrodę przy tablicy. Milczy, gdy nagrody odbiera urzędnik z Clerk Desk.", "Her gün geç saatte, tamamlanan siparişler panoda ödülünü bekliyorsa. Clerk Desk'in katibi topluyorsa sessiz kalır.", "毎日遅く、完了した注文が注文ボードで報酬を待っていれば。Clerk Deskの事務員が受け取る間は表示しない。", "任意一天傍晚,若已完成的订单在订单板等待领奖。Clerk Desk 的文员代领时不提醒。", "매일 늦게, 완료된 주문이 주문 게시판에서 보상을 기다리면. Clerk Desk의 사무원이 수령하는 동안은 알리지 않음." }
			},
			{
				"When in the evening (game hour)",
				new string[10] { "Когда вечером (час игры)", "Wann am Abend (Spielstunde)", "Quand le soir (heure du jeu)", "Cuándo por la tarde (hora del juego)", "Quando à noite (hora do jogo)", "Kiedy wieczorem (godzina w grze)", "Akşam ne zaman (oyun saati)", "夕方のいつ(ゲーム内の時刻)", "傍晚何时(游戏时间)", "저녁 언제(게임 시간)" }
			},
			{
				"Game hour of the evening reminder, e.g. 17 = 17:00; night falls at 18:00 and the day ends at midnight.",
				new string[10] { "Час игры для вечернего напоминания, например 17 = 17:00; ночь наступает в 18:00, день кончается в полночь.", "Spielstunde der Abend-Erinnerung, z. B. 17 = 17:00; die Nacht beginnt um 18:00, der Tag endet um Mitternacht.", "Heure du jeu du rappel du soir, p. ex. 17 = 17:00 ; la nuit tombe à 18:00 et le jour finit à minuit.", "Hora del juego del recordatorio de la tarde, p. ej. 17 = 17:00; anochece a las 18:00 y el día acaba a medianoche.", "Hora do jogo do lembrete da noite, ex. 17 = 17:00; a noite cai às 18:00 e o dia acaba à meia-noite.", "Godzina w grze wieczornego przypomnienia, np. 17 = 17:00; noc zapada o 18:00, a dzień kończy się o północy.", "Akşam hatırlatmasının oyun saati, ör. 17 = 17:00; gece 18:00'de başlar, gün gece yarısı biter.", "夕方のリマインダーのゲーム内の時刻(例: 17 = 17:00)。18:00に夜になり、真夜中に一日が終わる。", "傍晚提醒的游戏时间,例如 17 = 17:00;18:00 入夜,午夜一天结束。", "저녁 알림의 게임 시간, 예: 17 = 17:00. 18:00에 밤이 되고 자정에 하루가 끝남." }
			},
			{
				"Gamepad action that opens and closes the week, by the game's own name (LeftTrigger+LeftStick is L2+L3; None = unbound). All names: Settings.txt.",
				new string[10] { "Действие геймпада, которое открывает и закрывает неделю, по названию игры (LeftTrigger+LeftStick — это L2+L3; None — не назначено). Все названия: Settings.txt.", "Gamepad-Aktion, die die Woche öffnet und schließt, mit dem Namen des Spiels (LeftTrigger+LeftStick ist L2+L3; None = frei). Alle Namen: Settings.txt.", "Action de manette qui ouvre et ferme la semaine, par son nom dans le jeu (LeftTrigger+LeftStick = L2+L3 ; None = aucune). Tous les noms : Settings.txt.", "Acción del mando que abre y cierra la semana, con el nombre del juego (LeftTrigger+LeftStick es L2+L3; None = sin asignar). Todos los nombres: Settings.txt.", "Ação do controle que abre e fecha a semana, pelo nome do jogo (LeftTrigger+LeftStick é L2+L3; None = sem atribuição). Todos os nomes: Settings.txt.", "Akcja pada, która otwiera i zamyka tydzień, wg nazwy z gry (LeftTrigger+LeftStick to L2+L3; None = brak). Wszystkie nazwy: Settings.txt.", "Haftayı açıp kapatan oyun kolu eylemi, oyundaki adıyla (LeftTrigger+LeftStick = L2+L3; None = atanmamış). Tüm adlar: Settings.txt.", "週を開閉するゲームパッドの操作(ゲーム内の名前。LeftTrigger+LeftStick は L2+L3、None は割り当てなし)。全名称: Settings.txt。", "打开和关闭一周的手柄操作,用游戏里的名称(LeftTrigger+LeftStick 即 L2+L3;None 为不绑定)。全部名称见 Settings.txt。", "한 주를 여닫는 게임패드 동작, 게임 속 이름으로(LeftTrigger+LeftStick은 L2+L3, None은 미지정). 모든 이름: Settings.txt." }
			},
			{
				"Gamepad action that shows today's thought bubble (None = unbound). All names: Settings.txt.",
				new string[10] { "Действие геймпада, которое показывает мысль о сегодняшнем дне (None — не назначено). Все названия: Settings.txt.", "Gamepad-Aktion, die den Gedanken zu heute zeigt (None = frei). Alle Namen: Settings.txt.", "Action de manette qui montre la pensée du jour (None = aucune). Tous les noms : Settings.txt.", "Acción del mando que muestra el pensamiento del día (None = sin asignar). Todos los nombres: Settings.txt.", "Ação do controle que mostra o pensamento do dia (None = sem atribuição). Todos os nomes: Settings.txt.", "Akcja pada, która pokazuje myśl o dzisiejszym dniu (None = brak). Wszystkie nazwy: Settings.txt.", "Bugünün düşünce balonunu gösteren oyun kolu eylemi (None = atanmamış). Tüm adlar: Settings.txt.", "今日の考えの吹き出しを出すゲームパッドの操作(None は割り当てなし)。全名称: Settings.txt。", "显示今日想法气泡的手柄操作(None 为不绑定)。全部名称见 Settings.txt。", "오늘의 생각 말풍선을 띄우는 게임패드 동작(None은 미지정). 모든 이름: Settings.txt." }
			},
			{
				"Language",
				new string[10] { "Язык", "Sprache", "Langue", "Idioma", "Idioma", "Język", "Dil", "言語", "语言", "언어" }
			},
			{
				"Language of this mod's texts: a code such as en, ru, pt-br, zh_cn, or your own with a file in the mod's Localization folder. Empty follows the game.",
				new string[10] { "Язык текстов этого мода: код вроде en, ru, pt-br, zh_cn или свой, если в папке Localization мода есть файл. Пусто — язык игры.", "Sprache der Texte dieses Mods: ein Code wie en, ru, pt-br, zh_cn oder ein eigener, wenn der Ordner Localization des Mods eine Datei dafür hat. Leer folgt dem Spiel.", "Langue des textes de ce mod : un code comme en, ru, pt-br, zh_cn, ou le vôtre si le dossier Localization du mod contient un fichier. Vide : la langue du jeu.", "Idioma de los textos de este mod: un código como en, ru, pt-br, zh_cn, o el tuyo si la carpeta Localization del mod tiene un archivo. Vacío sigue al juego.", "Idioma dos textos deste mod: um código como en, ru, pt-br, zh_cn, ou o seu, se a pasta Localization do mod tiver um arquivo. Vazio segue o jogo.", "Język tekstów tego moda: kod jak en, ru, pt-br, zh_cn albo własny, jeśli folder Localization moda ma plik. Puste – język gry.", "Bu modun metinlerinin dili: en, ru, pt-br, zh_cn gibi bir kod ya da modun Localization klasöründe dosyası olan kendi kodunuz. Boşsa oyunun dilini izler.", "このModの文章の言語。en、ru、pt-br、zh_cn などのコード、またはModのLocalizationフォルダにファイルがある独自のコード。空ならゲームの言語に従います。", "本模组文字的语言:如 en、ru、pt-br、zh_cn 的代码,或模组 Localization 文件夹中有对应文件的自定义代码。留空则跟随游戏。", "이 모드 문구의 언어: en, ru, pt-br, zh_cn 같은 코드, 또는 모드의 Localization 폴더에 파일이 있는 자신의 코드. 비워 두면 게임을 따릅니다." }
			},
			{
				"Keep L3 with Keeper's Lantern",
				new string[10] { "Оставить L3 при Keeper's Lantern", "L3 trotz Keeper's Lantern behalten", "Garder L3 avec Keeper's Lantern", "Mantener L3 con Keeper's Lantern", "Manter L3 com Keeper's Lantern", "Zostaw L3 przy Keeper's Lantern", "Keeper's Lantern varken L3'ü koru", "Keeper's Lantern があってもL3を使う", "有 Keeper's Lantern 时仍用 L3", "Keeper's Lantern이 있어도 L3 유지" }
			},
			{
				"With Keeper's Lantern (Travalgard's mods) its wheel is on L3 and reacts to any L3 press, so our bindings that use L3 stay off. On keeps them anyway.",
				new string[10] { "С Keeper's Lantern (моды Travalgard) на L3 его колесо, и оно реагирует на любое нажатие L3, поэтому наши привязки с L3 выключены. Включите, чтобы оставить их.", "Mit Keeper's Lantern (Travalgards Mods) liegt sein Rad auf L3 und reagiert auf jeden L3-Druck, darum bleiben unsere L3-Belegungen aus. An behält sie trotzdem.", "Avec Keeper's Lantern (mods de Travalgard), sa roue est sur L3 et réagit à tout appui sur L3 : nos raccourcis avec L3 restent coupés. Activé les garde quand même.", "Con Keeper's Lantern (mods de Travalgard) su rueda está en L3 y responde a cualquier pulsación de L3, así que nuestras asignaciones con L3 quedan apagadas. Activado las mantiene.", "Com o Keeper's Lantern (mods do Travalgard) a roda dele fica no L3 e reage a qualquer toque no L3, então nossos atalhos com L3 ficam desligados. Ligado os mantém.", "Z Keeper's Lantern (mody Travalgarda) jego koło jest na L3 i reaguje na każde wciśnięcie L3, więc nasze przypisania z L3 są wyłączone. Włączone je zostawia.", "Keeper's Lantern (Travalgard'ın modları) varken onun çarkı L3'te ve her L3 basışına tepki verir; bu yüzden L3 kullanan atamalarımız kapalı. Açık, yine de korur.", "Keeper's Lantern(Travalgardのmod)があると、そのホイールがL3にあり、どのL3入力にも反応するため、L3を使う割り当ては止まる。オンでそれでも使う。", "装有 Keeper's Lantern(Travalgard 的模组)时,它的轮盘在 L3 上,任何 L3 按下都会响应,所以我们用 L3 的绑定会关闭。打开则仍然保留。", "Keeper's Lantern(Travalgard의 모드)이 있으면 그 휠이 L3에 있고 모든 L3 입력에 반응하므로 L3를 쓰는 우리 지정은 꺼짐. 켜면 그래도 유지." }
			}
		};

		private static int Index
		{
			get
			{
				if (_idx != -2)
				{
					return _idx;
				}
				string text = null;
				text = FileLang();
				text = (text ?? "en").ToLowerInvariant();
				_idx = -1;
				for (int i = 0; i < Langs.Length; i++)
				{
					if (text.StartsWith(Langs[i]))
					{
						_idx = i;
						break;
					}
				}
				return _idx;
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static string FrameworkLanguage()
		{
			return FrameworkLocalization.CurrentLanguage;
		}

		private static string FileLang()
		{
			string text = (ExtLoc.Override ?? "").Trim();
			if (text.Length > 0)
			{
				return text;
			}
			string text2 = null;
			try
			{
				text2 = FrameworkLanguage();
			}
			catch
			{
			}
			return text2 ?? "en";
		}

		public static string At(string en, string lang)
		{
			if (en != null && ExtLoc.TryGet(lang, en, out var text))
			{
				return text;
			}
			int num = IndexOf(lang);
			if (num < 0 || en == null || !Table.TryGetValue(en, out var value) || num >= value.Length || string.IsNullOrEmpty(value[num]))
			{
				return en;
			}
			return value[num];
		}

		private static int IndexOf(string lang)
		{
			lang = (lang ?? "en").ToLowerInvariant();
			for (int i = 0; i < Langs.Length; i++)
			{
				if (lang.StartsWith(Langs[i]))
				{
					return i;
				}
			}
			return -1;
		}

		public static string L(string en)
		{
			if (en != null && ExtLoc.TryGet(FileLang(), en, out var text))
			{
				return text;
			}
			int index = Index;
			if (index < 0 || en == null || !Table.TryGetValue(en, out var value) || index >= value.Length || string.IsNullOrEmpty(value[index]))
			{
				return en;
			}
			return value[index];
		}
	}
	internal static class GameApi
	{
		public static bool InGame()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			try
			{
				MainGame instance = MainGame.Instance;
				return (Object)(object)instance != (Object)null && (int)instance.gameState == 1 && MainGame.PlayerData != null;
			}
			catch
			{
				return false;
			}
		}

		public static string SlotKey()
		{
			try
			{
				string text = (((Object)(object)MainGame.Instance != (Object)null) ? MainGame.Instance.SaveSlotData : null)?.slotName;
				if (string.IsNullOrEmpty(text))
				{
					return null;
				}
				return Regex.Replace(text, "_backup_\\d+$", "");
			}
			catch
			{
				return null;
			}
		}

		public static string Lang()
		{
			return GameLang.Code();
		}

		public static string L(string key)
		{
			try
			{
				return LLBase.HasL(key) ? LLBase.L(key) : null;
			}
			catch
			{
				return null;
			}
		}

		public static ItemDef ItemDef(string id)
		{
			try
			{
				return ((GameBalanceBase)GameBalance.Me).GetDataOrNull<ItemDef>(id);
			}
			catch
			{
				return null;
			}
		}

		public static string ItemName(string id, bool isGroup)
		{
			ItemDef val = ItemDef(id);
			if (val != null)
			{
				try
				{
					string header = val.GetHeader();
					if (!string.IsNullOrEmpty(header))
					{
						return header;
					}
				}
				catch
				{
				}
			}
			return L(id) ?? id;
		}

		public static string ItemIcon(string id, bool isGroup)
		{
			return ItemDef(id)?.iconId;
		}

		public static Sprite Sprite(string iconId)
		{
			if (string.IsNullOrEmpty(iconId))
			{
				return null;
			}
			try
			{
				return LazySingletonSO<EasySpritesCollection>.Instance.GetSprite(iconId, (string)null);
			}
			catch
			{
				return null;
			}
		}

		public static List<ItemDef> GroupDefs(string groupNeedId)
		{
			return new List<ItemDef>();
		}

		public static string IconTag(string id)
		{
			if (string.IsNullOrEmpty(id))
			{
				return "";
			}
			try
			{
				return UIExtensions.FontIcon(id) ?? "";
			}
			catch
			{
				return "";
			}
		}
	}
	internal static class GameKeys
	{
		private static HashSet<KeyCode> _bound;

		private static float _readAt = -100f;

		private static readonly HashSet<KeyCode> _warned = new HashSet<KeyCode>();

		public static bool Blocks(KeyboardShortcut k)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref k)).MainKey == 0)
			{
				return false;
			}
			bool flag = false;
			using (IEnumerator<KeyCode> enumerator = ((KeyboardShortcut)(ref k)).Modifiers.GetEnumerator())
			{
				if (enumerator.MoveNext())
				{
					_ = enumerator.Current;
					flag = true;
				}
			}
			if (flag)
			{
				return false;
			}
			if (!Bound().Contains(((KeyboardShortcut)(ref k)).MainKey))
			{
				return false;
			}
			if (_warned.Add(((KeyboardShortcut)(ref k)).MainKey))
			{
				Plugin.Log.LogInfo((object)("Hotkey " + ((object)((KeyboardShortcut)(ref k)).MainKey/*cast due to .constrained prefix*/).ToString() + " is also a game key here, so it is ignored. Pick another one (or add a modifier) in the settings."));
			}
			return true;
		}

		private static HashSet<KeyCode> Bound()
		{
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: 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)
			if (_bound != null && Time.unscaledTime - _readAt < 5f)
			{
				return _bound;
			}
			_readAt = Time.unscaledTime;
			HashSet<KeyCode> hashSet = new HashSet<KeyCode>();
			try
			{
				if (ReInput.isReady)
				{
					foreach (Player allPlayer in ReInput.players.AllPlayers)
					{
						if (allPlayer == null)
						{
							continue;
						}
						foreach (ControllerMap allMap in allPlayer.controllers.maps.GetAllMaps((ControllerType)0))
						{
							if (allMap == null)
							{
								continue;
							}
							foreach (ActionElementMap allMap2 in allMap.AllMaps)
							{
								if (allMap2 != null && (int)allMap2.keyCode != 0)
								{
									hashSet.Add(allMap2.keyCode);
								}
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Reading the game's keys: " + ex.Message));
			}
			try
			{
				GameBindings gameBindings = LazyInput.GameBindings;
				List<KeyBinding> list = (((Object)(object)gameBindings != (Object)null) ? gameBindings.keyBindings : null);
				if (list != null)
				{
					foreach (KeyBinding item in list)